@metamask-previews/wallet-cli 0.0.0-preview-8bfa290fb → 0.0.0-preview-e8a256c39

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 (264) hide show
  1. package/CHANGELOG.md +8 -4
  2. package/dist/commands/daemon/{call.d.mts → call.d.ts} +2 -2
  3. package/dist/commands/daemon/call.d.ts.map +1 -0
  4. package/dist/commands/daemon/{call.mjs → call.js} +30 -31
  5. package/dist/commands/daemon/call.js.map +1 -0
  6. package/dist/commands/daemon/{list.d.cts → list.d.ts} +2 -2
  7. package/dist/commands/daemon/list.d.ts.map +1 -0
  8. package/dist/commands/daemon/{list.mjs → list.js} +9 -10
  9. package/dist/commands/daemon/list.js.map +1 -0
  10. package/dist/commands/daemon/{purge.d.cts → purge.d.ts} +2 -2
  11. package/dist/commands/daemon/purge.d.ts.map +1 -0
  12. package/dist/commands/daemon/{purge.mjs → purge.js} +19 -20
  13. package/dist/commands/daemon/purge.js.map +1 -0
  14. package/dist/commands/daemon/{start.d.cts → start.d.ts} +2 -2
  15. package/dist/commands/daemon/start.d.ts.map +1 -0
  16. package/dist/commands/daemon/start.js +49 -0
  17. package/dist/commands/daemon/{start.cjs.map → start.js.map} +1 -1
  18. package/dist/commands/daemon/{status.d.cts → status.d.ts} +2 -2
  19. package/dist/commands/daemon/status.d.ts.map +1 -0
  20. package/dist/commands/daemon/{status.mjs → status.js} +10 -11
  21. package/dist/commands/daemon/status.js.map +1 -0
  22. package/dist/commands/daemon/{stop.d.cts → stop.d.ts} +2 -2
  23. package/dist/commands/daemon/stop.d.ts.map +1 -0
  24. package/dist/commands/daemon/{stop.mjs → stop.js} +9 -10
  25. package/dist/commands/daemon/stop.js.map +1 -0
  26. package/dist/commands/wallet/{send.d.cts → send.d.ts} +3 -3
  27. package/dist/commands/wallet/send.d.ts.map +1 -0
  28. package/dist/commands/wallet/{send.mjs → send.js} +111 -123
  29. package/dist/commands/wallet/send.js.map +1 -0
  30. package/dist/commands/wallet/{unlock.d.cts → unlock.d.ts} +2 -2
  31. package/dist/commands/wallet/unlock.d.ts.map +1 -0
  32. package/dist/commands/wallet/{unlock.mjs → unlock.js} +29 -30
  33. package/dist/commands/wallet/unlock.js.map +1 -0
  34. package/dist/daemon/{auto-approval.d.mts → auto-approval.d.ts} +3 -3
  35. package/dist/daemon/auto-approval.d.ts.map +1 -0
  36. package/dist/daemon/{auto-approval.mjs → auto-approval.js} +1 -1
  37. package/dist/daemon/auto-approval.js.map +1 -0
  38. package/dist/daemon/{daemon-client.d.mts → daemon-client.d.ts} +2 -2
  39. package/dist/daemon/daemon-client.d.ts.map +1 -0
  40. package/dist/daemon/{daemon-client.mjs → daemon-client.js} +8 -8
  41. package/dist/daemon/daemon-client.js.map +1 -0
  42. package/dist/daemon/daemon-entry.d.ts +2 -0
  43. package/dist/daemon/daemon-entry.d.ts.map +1 -0
  44. package/dist/daemon/{daemon-entry.mjs → daemon-entry.js} +12 -12
  45. package/dist/daemon/daemon-entry.js.map +1 -0
  46. package/dist/daemon/{daemon-spawn.d.mts → daemon-spawn.d.ts} +2 -2
  47. package/dist/daemon/daemon-spawn.d.ts.map +1 -0
  48. package/dist/daemon/{daemon-spawn.mjs → daemon-spawn.js} +7 -7
  49. package/dist/daemon/daemon-spawn.js.map +1 -0
  50. package/dist/daemon/{data-dir.d.cts → data-dir.d.ts} +1 -1
  51. package/dist/daemon/data-dir.d.ts.map +1 -0
  52. package/dist/daemon/{data-dir.mjs → data-dir.js} +3 -3
  53. package/dist/daemon/data-dir.js.map +1 -0
  54. package/dist/daemon/{paths.d.mts → paths.d.ts} +2 -2
  55. package/dist/daemon/paths.d.ts.map +1 -0
  56. package/dist/daemon/{paths.mjs → paths.js} +2 -2
  57. package/dist/daemon/paths.js.map +1 -0
  58. package/dist/daemon/{prompts.d.cts → prompts.d.ts} +1 -1
  59. package/dist/daemon/prompts.d.ts.map +1 -0
  60. package/dist/daemon/{prompts.mjs → prompts.js} +4 -4
  61. package/dist/daemon/prompts.js.map +1 -0
  62. package/dist/daemon/{rpc-socket-server.d.cts → rpc-socket-server.d.ts} +2 -2
  63. package/dist/daemon/rpc-socket-server.d.ts.map +1 -0
  64. package/dist/daemon/{rpc-socket-server.mjs → rpc-socket-server.js} +8 -8
  65. package/dist/daemon/rpc-socket-server.js.map +1 -0
  66. package/dist/daemon/{secrets.d.cts → secrets.d.ts} +1 -1
  67. package/dist/daemon/secrets.d.ts.map +1 -0
  68. package/dist/daemon/{secrets.mjs → secrets.js} +11 -23
  69. package/dist/daemon/secrets.js.map +1 -0
  70. package/dist/daemon/{send-transaction.d.cts → send-transaction.d.ts} +9 -9
  71. package/dist/daemon/send-transaction.d.ts.map +1 -0
  72. package/dist/daemon/{send-transaction.mjs → send-transaction.js} +3 -3
  73. package/dist/daemon/send-transaction.js.map +1 -0
  74. package/dist/daemon/{socket-line.d.cts → socket-line.d.ts} +2 -5
  75. package/dist/daemon/socket-line.d.ts.map +1 -0
  76. package/dist/daemon/{socket-line.mjs → socket-line.js} +1 -1
  77. package/dist/daemon/socket-line.js.map +1 -0
  78. package/dist/daemon/{stop-daemon.d.cts → stop-daemon.d.ts} +1 -1
  79. package/dist/daemon/stop-daemon.d.ts.map +1 -0
  80. package/dist/daemon/{stop-daemon.mjs → stop-daemon.js} +7 -7
  81. package/dist/daemon/stop-daemon.js.map +1 -0
  82. package/dist/daemon/{types.d.cts → types.d.ts} +4 -4
  83. package/dist/daemon/types.d.ts.map +1 -0
  84. package/dist/daemon/{types.mjs → types.js} +1 -1
  85. package/dist/daemon/types.js.map +1 -0
  86. package/dist/daemon/{utils.d.cts → utils.d.ts} +2 -3
  87. package/dist/daemon/utils.d.ts.map +1 -0
  88. package/dist/daemon/{utils.mjs → utils.js} +3 -3
  89. package/dist/daemon/utils.js.map +1 -0
  90. package/dist/daemon/{wallet-factory.d.cts → wallet-factory.d.ts} +4 -4
  91. package/dist/daemon/wallet-factory.d.ts.map +1 -0
  92. package/dist/daemon/{wallet-factory.mjs → wallet-factory.js} +12 -12
  93. package/dist/daemon/wallet-factory.js.map +1 -0
  94. package/dist/persistence/{KeyValueStore.d.cts → KeyValueStore.d.ts} +2 -2
  95. package/dist/persistence/KeyValueStore.d.ts.map +1 -0
  96. package/dist/persistence/KeyValueStore.js +59 -0
  97. package/dist/persistence/KeyValueStore.js.map +1 -0
  98. package/dist/persistence/{persistence.d.cts → persistence.d.ts} +5 -5
  99. package/dist/persistence/persistence.d.ts.map +1 -0
  100. package/dist/persistence/{persistence.mjs → persistence.js} +2 -2
  101. package/dist/persistence/persistence.js.map +1 -0
  102. package/dist/test/{run-command.d.cts → run-command.d.ts} +4 -4
  103. package/dist/test/run-command.d.ts.map +1 -0
  104. package/dist/test/{run-command.mjs → run-command.js} +3 -3
  105. package/dist/test/run-command.js.map +1 -0
  106. package/package.json +19 -15
  107. package/dist/commands/daemon/call.cjs +0 -79
  108. package/dist/commands/daemon/call.cjs.map +0 -1
  109. package/dist/commands/daemon/call.d.cts +0 -14
  110. package/dist/commands/daemon/call.d.cts.map +0 -1
  111. package/dist/commands/daemon/call.d.mts.map +0 -1
  112. package/dist/commands/daemon/call.mjs.map +0 -1
  113. package/dist/commands/daemon/list.cjs +0 -48
  114. package/dist/commands/daemon/list.cjs.map +0 -1
  115. package/dist/commands/daemon/list.d.cts.map +0 -1
  116. package/dist/commands/daemon/list.d.mts +0 -7
  117. package/dist/commands/daemon/list.d.mts.map +0 -1
  118. package/dist/commands/daemon/list.mjs.map +0 -1
  119. package/dist/commands/daemon/purge.cjs +0 -58
  120. package/dist/commands/daemon/purge.cjs.map +0 -1
  121. package/dist/commands/daemon/purge.d.cts.map +0 -1
  122. package/dist/commands/daemon/purge.d.mts +0 -10
  123. package/dist/commands/daemon/purge.d.mts.map +0 -1
  124. package/dist/commands/daemon/purge.mjs.map +0 -1
  125. package/dist/commands/daemon/start.cjs +0 -52
  126. package/dist/commands/daemon/start.d.cts.map +0 -1
  127. package/dist/commands/daemon/start.d.mts +0 -12
  128. package/dist/commands/daemon/start.d.mts.map +0 -1
  129. package/dist/commands/daemon/start.mjs +0 -50
  130. package/dist/commands/daemon/start.mjs.map +0 -1
  131. package/dist/commands/daemon/status.cjs +0 -59
  132. package/dist/commands/daemon/status.cjs.map +0 -1
  133. package/dist/commands/daemon/status.d.cts.map +0 -1
  134. package/dist/commands/daemon/status.d.mts +0 -7
  135. package/dist/commands/daemon/status.d.mts.map +0 -1
  136. package/dist/commands/daemon/status.mjs.map +0 -1
  137. package/dist/commands/daemon/stop.cjs +0 -26
  138. package/dist/commands/daemon/stop.cjs.map +0 -1
  139. package/dist/commands/daemon/stop.d.cts.map +0 -1
  140. package/dist/commands/daemon/stop.d.mts +0 -7
  141. package/dist/commands/daemon/stop.d.mts.map +0 -1
  142. package/dist/commands/daemon/stop.mjs.map +0 -1
  143. package/dist/commands/wallet/send.cjs +0 -332
  144. package/dist/commands/wallet/send.cjs.map +0 -1
  145. package/dist/commands/wallet/send.d.cts.map +0 -1
  146. package/dist/commands/wallet/send.d.mts +0 -42
  147. package/dist/commands/wallet/send.d.mts.map +0 -1
  148. package/dist/commands/wallet/send.mjs.map +0 -1
  149. package/dist/commands/wallet/unlock.cjs +0 -75
  150. package/dist/commands/wallet/unlock.cjs.map +0 -1
  151. package/dist/commands/wallet/unlock.d.cts.map +0 -1
  152. package/dist/commands/wallet/unlock.d.mts +0 -11
  153. package/dist/commands/wallet/unlock.d.mts.map +0 -1
  154. package/dist/commands/wallet/unlock.mjs.map +0 -1
  155. package/dist/daemon/auto-approval.cjs +0 -86
  156. package/dist/daemon/auto-approval.cjs.map +0 -1
  157. package/dist/daemon/auto-approval.d.cts +0 -22
  158. package/dist/daemon/auto-approval.d.cts.map +0 -1
  159. package/dist/daemon/auto-approval.d.mts.map +0 -1
  160. package/dist/daemon/auto-approval.mjs.map +0 -1
  161. package/dist/daemon/daemon-client.cjs +0 -149
  162. package/dist/daemon/daemon-client.cjs.map +0 -1
  163. package/dist/daemon/daemon-client.d.cts +0 -84
  164. package/dist/daemon/daemon-client.d.cts.map +0 -1
  165. package/dist/daemon/daemon-client.d.mts.map +0 -1
  166. package/dist/daemon/daemon-client.mjs.map +0 -1
  167. package/dist/daemon/daemon-entry.cjs +0 -278
  168. package/dist/daemon/daemon-entry.cjs.map +0 -1
  169. package/dist/daemon/daemon-entry.d.cts +0 -2
  170. package/dist/daemon/daemon-entry.d.cts.map +0 -1
  171. package/dist/daemon/daemon-entry.d.mts +0 -2
  172. package/dist/daemon/daemon-entry.d.mts.map +0 -1
  173. package/dist/daemon/daemon-entry.mjs.map +0 -1
  174. package/dist/daemon/daemon-spawn.cjs +0 -138
  175. package/dist/daemon/daemon-spawn.cjs.map +0 -1
  176. package/dist/daemon/daemon-spawn.d.cts +0 -28
  177. package/dist/daemon/daemon-spawn.d.cts.map +0 -1
  178. package/dist/daemon/daemon-spawn.d.mts.map +0 -1
  179. package/dist/daemon/daemon-spawn.mjs.map +0 -1
  180. package/dist/daemon/data-dir.cjs +0 -23
  181. package/dist/daemon/data-dir.cjs.map +0 -1
  182. package/dist/daemon/data-dir.d.cts.map +0 -1
  183. package/dist/daemon/data-dir.d.mts +0 -14
  184. package/dist/daemon/data-dir.d.mts.map +0 -1
  185. package/dist/daemon/data-dir.mjs.map +0 -1
  186. package/dist/daemon/paths.cjs +0 -20
  187. package/dist/daemon/paths.cjs.map +0 -1
  188. package/dist/daemon/paths.d.cts +0 -9
  189. package/dist/daemon/paths.d.cts.map +0 -1
  190. package/dist/daemon/paths.d.mts.map +0 -1
  191. package/dist/daemon/paths.mjs.map +0 -1
  192. package/dist/daemon/prompts.cjs +0 -55
  193. package/dist/daemon/prompts.cjs.map +0 -1
  194. package/dist/daemon/prompts.d.cts.map +0 -1
  195. package/dist/daemon/prompts.d.mts +0 -31
  196. package/dist/daemon/prompts.d.mts.map +0 -1
  197. package/dist/daemon/prompts.mjs.map +0 -1
  198. package/dist/daemon/rpc-socket-server.cjs +0 -284
  199. package/dist/daemon/rpc-socket-server.cjs.map +0 -1
  200. package/dist/daemon/rpc-socket-server.d.cts.map +0 -1
  201. package/dist/daemon/rpc-socket-server.d.mts +0 -44
  202. package/dist/daemon/rpc-socket-server.d.mts.map +0 -1
  203. package/dist/daemon/rpc-socket-server.mjs.map +0 -1
  204. package/dist/daemon/secrets.cjs +0 -137
  205. package/dist/daemon/secrets.cjs.map +0 -1
  206. package/dist/daemon/secrets.d.cts.map +0 -1
  207. package/dist/daemon/secrets.d.mts +0 -72
  208. package/dist/daemon/secrets.d.mts.map +0 -1
  209. package/dist/daemon/secrets.mjs.map +0 -1
  210. package/dist/daemon/send-transaction.cjs +0 -147
  211. package/dist/daemon/send-transaction.cjs.map +0 -1
  212. package/dist/daemon/send-transaction.d.cts.map +0 -1
  213. package/dist/daemon/send-transaction.d.mts +0 -102
  214. package/dist/daemon/send-transaction.d.mts.map +0 -1
  215. package/dist/daemon/send-transaction.mjs.map +0 -1
  216. package/dist/daemon/socket-line.cjs +0 -93
  217. package/dist/daemon/socket-line.cjs.map +0 -1
  218. package/dist/daemon/socket-line.d.cts.map +0 -1
  219. package/dist/daemon/socket-line.d.mts +0 -21
  220. package/dist/daemon/socket-line.d.mts.map +0 -1
  221. package/dist/daemon/socket-line.mjs.map +0 -1
  222. package/dist/daemon/stop-daemon.cjs +0 -117
  223. package/dist/daemon/stop-daemon.cjs.map +0 -1
  224. package/dist/daemon/stop-daemon.d.cts.map +0 -1
  225. package/dist/daemon/stop-daemon.d.mts +0 -28
  226. package/dist/daemon/stop-daemon.d.mts.map +0 -1
  227. package/dist/daemon/stop-daemon.mjs.map +0 -1
  228. package/dist/daemon/types.cjs +0 -20
  229. package/dist/daemon/types.cjs.map +0 -1
  230. package/dist/daemon/types.d.cts.map +0 -1
  231. package/dist/daemon/types.d.mts +0 -94
  232. package/dist/daemon/types.d.mts.map +0 -1
  233. package/dist/daemon/types.mjs.map +0 -1
  234. package/dist/daemon/utils.cjs +0 -172
  235. package/dist/daemon/utils.cjs.map +0 -1
  236. package/dist/daemon/utils.d.cts.map +0 -1
  237. package/dist/daemon/utils.d.mts +0 -87
  238. package/dist/daemon/utils.d.mts.map +0 -1
  239. package/dist/daemon/utils.mjs.map +0 -1
  240. package/dist/daemon/wallet-factory.cjs +0 -341
  241. package/dist/daemon/wallet-factory.cjs.map +0 -1
  242. package/dist/daemon/wallet-factory.d.cts.map +0 -1
  243. package/dist/daemon/wallet-factory.d.mts +0 -64
  244. package/dist/daemon/wallet-factory.d.mts.map +0 -1
  245. package/dist/daemon/wallet-factory.mjs.map +0 -1
  246. package/dist/persistence/KeyValueStore.cjs +0 -79
  247. package/dist/persistence/KeyValueStore.cjs.map +0 -1
  248. package/dist/persistence/KeyValueStore.d.cts.map +0 -1
  249. package/dist/persistence/KeyValueStore.d.mts +0 -18
  250. package/dist/persistence/KeyValueStore.d.mts.map +0 -1
  251. package/dist/persistence/KeyValueStore.mjs +0 -79
  252. package/dist/persistence/KeyValueStore.mjs.map +0 -1
  253. package/dist/persistence/persistence.cjs +0 -204
  254. package/dist/persistence/persistence.cjs.map +0 -1
  255. package/dist/persistence/persistence.d.cts.map +0 -1
  256. package/dist/persistence/persistence.d.mts +0 -45
  257. package/dist/persistence/persistence.d.mts.map +0 -1
  258. package/dist/persistence/persistence.mjs.map +0 -1
  259. package/dist/test/run-command.cjs +0 -73
  260. package/dist/test/run-command.cjs.map +0 -1
  261. package/dist/test/run-command.d.cts.map +0 -1
  262. package/dist/test/run-command.d.mts +0 -27
  263. package/dist/test/run-command.d.mts.map +0 -1
  264. package/dist/test/run-command.mjs.map +0 -1
@@ -1,172 +0,0 @@
1
- "use strict";
2
- Object.defineProperty(exports, "__esModule", { value: true });
3
- exports.waitFor = exports.sendSignal = exports.isProcessAlive = exports.readPidFile = exports.isStringArray = exports.emptyToUndefined = exports.formatJsonRpcError = exports.makeDaemonConnectionError = exports.isErrorWithCode = void 0;
4
- const utils_1 = require("@metamask/utils");
5
- const promises_1 = require("node:fs/promises");
6
- /**
7
- * Check whether an unknown error is a Node.js system error with the given code.
8
- *
9
- * @param error - The error to check.
10
- * @param code - The expected error code (e.g. 'ENOENT', 'EPERM').
11
- * @returns True if the error matches the code.
12
- */
13
- function isErrorWithCode(error, code) {
14
- return (0, utils_1.isErrorWithCode)(error) && error.code === code;
15
- }
16
- exports.isErrorWithCode = isErrorWithCode;
17
- /**
18
- * Turn an error thrown while contacting the daemon socket into a user-facing
19
- * message for `Command.error`, so every command reports the same failure the
20
- * same way. Distinguishes a stopped daemon (`ENOENT`/`ECONNREFUSED`), a
21
- * connection dropped mid-request (`ECONNRESET`), and a permission problem
22
- * (`EACCES`/`EPERM`), falling back to the raw error message.
23
- *
24
- * @param error - The value thrown while contacting the daemon.
25
- * @returns A human-readable explanation of the failure.
26
- */
27
- function makeDaemonConnectionError(error) {
28
- if (isErrorWithCode(error, 'ENOENT') ||
29
- isErrorWithCode(error, 'ECONNREFUSED')) {
30
- return 'Daemon is not running. Start it with `mm daemon start`.';
31
- }
32
- // A reset drops an already-established connection, so the daemon was running
33
- // — most likely it crashed mid-request. Don't tell the user to start it.
34
- if (isErrorWithCode(error, 'ECONNRESET')) {
35
- return ('Lost the connection to the daemon; it may have crashed while ' +
36
- 'handling the request. Check `mm daemon status` and the daemon log.');
37
- }
38
- if (isErrorWithCode(error, 'EACCES') || isErrorWithCode(error, 'EPERM')) {
39
- return ('Cannot connect to the daemon socket: permission denied. ' +
40
- 'The socket may be owned by another user, or MM_DAEMON_DATA_DIR ' +
41
- 'may point to a directory you cannot access.');
42
- }
43
- return error instanceof Error ? error.message : String(error);
44
- }
45
- exports.makeDaemonConnectionError = makeDaemonConnectionError;
46
- /**
47
- * Format the error of a JSON-RPC failure response into a user-facing message
48
- * for `Command.error`, so every command reports RPC failures the same way.
49
- *
50
- * @param error - The `error` field of a JSON-RPC failure response.
51
- * @returns The error message annotated with its numeric code.
52
- */
53
- function formatJsonRpcError(error) {
54
- return `${error.message} (code ${String(error.code)})`;
55
- }
56
- exports.formatJsonRpcError = formatJsonRpcError;
57
- /**
58
- * Treat an empty string the same as `undefined` — "no value supplied". Used
59
- * to normalise `--password ''` and `MM_WALLET_PASSWORD=''` so they trigger
60
- * the interactive prompt rather than sending an empty string to the keyring.
61
- *
62
- * @param value - The value to normalise.
63
- * @returns `undefined` if `value` is `undefined` or `''`; `value` otherwise.
64
- */
65
- function emptyToUndefined(value) {
66
- return value === '' ? undefined : value;
67
- }
68
- exports.emptyToUndefined = emptyToUndefined;
69
- /**
70
- * Check whether a value is an array of strings. Used to validate untyped RPC
71
- * results (e.g. the daemon's `listActions`) before treating them as `string[]`.
72
- *
73
- * @param value - The value to check.
74
- * @returns True if the value is an array whose every element is a string.
75
- */
76
- function isStringArray(value) {
77
- return (Array.isArray(value) && value.every((item) => typeof item === 'string'));
78
- }
79
- exports.isStringArray = isStringArray;
80
- /**
81
- * Read a PID from a file. The file may contain just the PID, or the PID on
82
- * the first line followed by additional metadata (e.g. start time written by
83
- * the daemon).
84
- *
85
- * @param pidPath - The PID file path.
86
- * @returns The PID, or undefined if the file is missing or its first line is
87
- * not a positive integer.
88
- */
89
- async function readPidFile(pidPath) {
90
- let contents;
91
- try {
92
- contents = await (0, promises_1.readFile)(pidPath, 'utf-8');
93
- }
94
- catch (error) {
95
- if (isErrorWithCode(error, 'ENOENT')) {
96
- return undefined;
97
- }
98
- throw error;
99
- }
100
- // String.prototype.split always returns at least one element, so [0] is safe.
101
- const pid = Number(contents.split('\n')[0].trim());
102
- return Number.isInteger(pid) && pid > 0 ? pid : undefined;
103
- }
104
- exports.readPidFile = readPidFile;
105
- /**
106
- * Check whether a process is alive by sending signal 0.
107
- *
108
- * Treats `ESRCH` as "process is gone", `EPERM` as "process exists but we
109
- * cannot signal it" (still alive from our perspective), and rethrows
110
- * anything else so the caller can surface unexpected failures rather than
111
- * silently assuming the process is dead.
112
- *
113
- * @param pid - The process ID to check.
114
- * @returns True if the process exists.
115
- */
116
- function isProcessAlive(pid) {
117
- try {
118
- process.kill(pid, 0);
119
- return true;
120
- }
121
- catch (error) {
122
- if (isErrorWithCode(error, 'ESRCH')) {
123
- return false;
124
- }
125
- if (isErrorWithCode(error, 'EPERM')) {
126
- return true;
127
- }
128
- throw error;
129
- }
130
- }
131
- exports.isProcessAlive = isProcessAlive;
132
- /**
133
- * Send a signal to a process. Returns true if the signal was sent, false if
134
- * the process does not exist (ESRCH). Re-throws on permission errors and
135
- * other failures.
136
- *
137
- * @param pid - The process ID.
138
- * @param signal - The signal to send.
139
- * @returns True if the signal was delivered, false if the process is gone.
140
- */
141
- function sendSignal(pid, signal) {
142
- try {
143
- process.kill(pid, signal);
144
- return true;
145
- }
146
- catch (error) {
147
- if (isErrorWithCode(error, 'ESRCH')) {
148
- return false;
149
- }
150
- throw error;
151
- }
152
- }
153
- exports.sendSignal = sendSignal;
154
- /**
155
- * Poll until a condition is met or the timeout elapses.
156
- *
157
- * @param check - A function that returns true when the condition is met.
158
- * @param timeoutMs - Maximum time to wait in milliseconds.
159
- * @returns True if the condition was met, false on timeout.
160
- */
161
- async function waitFor(check, timeoutMs) {
162
- const deadline = Date.now() + timeoutMs;
163
- while (Date.now() < deadline) {
164
- if (await check()) {
165
- return true;
166
- }
167
- await new Promise((resolve) => setTimeout(resolve, 250));
168
- }
169
- return false;
170
- }
171
- exports.waitFor = waitFor;
172
- //# sourceMappingURL=utils.cjs.map
@@ -1 +0,0 @@
1
- {"version":3,"file":"utils.cjs","sourceRoot":"","sources":["../../src/daemon/utils.ts"],"names":[],"mappings":"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","sourcesContent":["import type { JsonRpcError } from '@metamask/utils';\nimport { isErrorWithCode as hasErrorCode } from '@metamask/utils';\nimport { readFile } from 'node:fs/promises';\n\n/**\n * Check whether an unknown error is a Node.js system error with the given code.\n *\n * @param error - The error to check.\n * @param code - The expected error code (e.g. 'ENOENT', 'EPERM').\n * @returns True if the error matches the code.\n */\nexport function isErrorWithCode(error: unknown, code: string): boolean {\n return hasErrorCode(error) && error.code === code;\n}\n\n/**\n * Turn an error thrown while contacting the daemon socket into a user-facing\n * message for `Command.error`, so every command reports the same failure the\n * same way. Distinguishes a stopped daemon (`ENOENT`/`ECONNREFUSED`), a\n * connection dropped mid-request (`ECONNRESET`), and a permission problem\n * (`EACCES`/`EPERM`), falling back to the raw error message.\n *\n * @param error - The value thrown while contacting the daemon.\n * @returns A human-readable explanation of the failure.\n */\nexport function makeDaemonConnectionError(error: unknown): string {\n if (\n isErrorWithCode(error, 'ENOENT') ||\n isErrorWithCode(error, 'ECONNREFUSED')\n ) {\n return 'Daemon is not running. Start it with `mm daemon start`.';\n }\n // A reset drops an already-established connection, so the daemon was running\n // — most likely it crashed mid-request. Don't tell the user to start it.\n if (isErrorWithCode(error, 'ECONNRESET')) {\n return (\n 'Lost the connection to the daemon; it may have crashed while ' +\n 'handling the request. Check `mm daemon status` and the daemon log.'\n );\n }\n if (isErrorWithCode(error, 'EACCES') || isErrorWithCode(error, 'EPERM')) {\n return (\n 'Cannot connect to the daemon socket: permission denied. ' +\n 'The socket may be owned by another user, or MM_DAEMON_DATA_DIR ' +\n 'may point to a directory you cannot access.'\n );\n }\n return error instanceof Error ? error.message : String(error);\n}\n\n/**\n * Format the error of a JSON-RPC failure response into a user-facing message\n * for `Command.error`, so every command reports RPC failures the same way.\n *\n * @param error - The `error` field of a JSON-RPC failure response.\n * @returns The error message annotated with its numeric code.\n */\nexport function formatJsonRpcError(error: JsonRpcError): string {\n return `${error.message} (code ${String(error.code)})`;\n}\n\n/**\n * Treat an empty string the same as `undefined` — \"no value supplied\". Used\n * to normalise `--password ''` and `MM_WALLET_PASSWORD=''` so they trigger\n * the interactive prompt rather than sending an empty string to the keyring.\n *\n * @param value - The value to normalise.\n * @returns `undefined` if `value` is `undefined` or `''`; `value` otherwise.\n */\nexport function emptyToUndefined(\n value: string | undefined,\n): string | undefined {\n return value === '' ? undefined : value;\n}\n\n/**\n * Check whether a value is an array of strings. Used to validate untyped RPC\n * results (e.g. the daemon's `listActions`) before treating them as `string[]`.\n *\n * @param value - The value to check.\n * @returns True if the value is an array whose every element is a string.\n */\nexport function isStringArray(value: unknown): value is string[] {\n return (\n Array.isArray(value) && value.every((item) => typeof item === 'string')\n );\n}\n\n/**\n * Read a PID from a file. The file may contain just the PID, or the PID on\n * the first line followed by additional metadata (e.g. start time written by\n * the daemon).\n *\n * @param pidPath - The PID file path.\n * @returns The PID, or undefined if the file is missing or its first line is\n * not a positive integer.\n */\nexport async function readPidFile(\n pidPath: string,\n): Promise<number | undefined> {\n let contents: string;\n try {\n contents = await readFile(pidPath, 'utf-8');\n } catch (error: unknown) {\n if (isErrorWithCode(error, 'ENOENT')) {\n return undefined;\n }\n throw error;\n }\n // String.prototype.split always returns at least one element, so [0] is safe.\n const pid = Number(contents.split('\\n')[0].trim());\n return Number.isInteger(pid) && pid > 0 ? pid : undefined;\n}\n\n/**\n * Check whether a process is alive by sending signal 0.\n *\n * Treats `ESRCH` as \"process is gone\", `EPERM` as \"process exists but we\n * cannot signal it\" (still alive from our perspective), and rethrows\n * anything else so the caller can surface unexpected failures rather than\n * silently assuming the process is dead.\n *\n * @param pid - The process ID to check.\n * @returns True if the process exists.\n */\nexport function isProcessAlive(pid: number): boolean {\n try {\n process.kill(pid, 0);\n return true;\n } catch (error: unknown) {\n if (isErrorWithCode(error, 'ESRCH')) {\n return false;\n }\n if (isErrorWithCode(error, 'EPERM')) {\n return true;\n }\n throw error;\n }\n}\n\n/**\n * Send a signal to a process. Returns true if the signal was sent, false if\n * the process does not exist (ESRCH). Re-throws on permission errors and\n * other failures.\n *\n * @param pid - The process ID.\n * @param signal - The signal to send.\n * @returns True if the signal was delivered, false if the process is gone.\n */\nexport function sendSignal(pid: number, signal: NodeJS.Signals): boolean {\n try {\n process.kill(pid, signal);\n return true;\n } catch (error: unknown) {\n if (isErrorWithCode(error, 'ESRCH')) {\n return false;\n }\n throw error;\n }\n}\n\n/**\n * Poll until a condition is met or the timeout elapses.\n *\n * @param check - A function that returns true when the condition is met.\n * @param timeoutMs - Maximum time to wait in milliseconds.\n * @returns True if the condition was met, false on timeout.\n */\nexport async function waitFor(\n check: () => boolean | Promise<boolean>,\n timeoutMs: number,\n): Promise<boolean> {\n const deadline = Date.now() + timeoutMs;\n while (Date.now() < deadline) {\n if (await check()) {\n return true;\n }\n await new Promise((resolve) => setTimeout(resolve, 250));\n }\n return false;\n}\n"]}
@@ -1 +0,0 @@
1
- {"version":3,"file":"utils.d.cts","sourceRoot":"","sources":["../../src/daemon/utils.ts"],"names":[],"mappings":";AAAA,OAAO,KAAK,EAAE,YAAY,EAAE,wBAAwB;AAIpD;;;;;;GAMG;AACH,wBAAgB,eAAe,CAAC,KAAK,EAAE,OAAO,EAAE,IAAI,EAAE,MAAM,GAAG,OAAO,CAErE;AAED;;;;;;;;;GASG;AACH,wBAAgB,yBAAyB,CAAC,KAAK,EAAE,OAAO,GAAG,MAAM,CAuBhE;AAED;;;;;;GAMG;AACH,wBAAgB,kBAAkB,CAAC,KAAK,EAAE,YAAY,GAAG,MAAM,CAE9D;AAED;;;;;;;GAOG;AACH,wBAAgB,gBAAgB,CAC9B,KAAK,EAAE,MAAM,GAAG,SAAS,GACxB,MAAM,GAAG,SAAS,CAEpB;AAED;;;;;;GAMG;AACH,wBAAgB,aAAa,CAAC,KAAK,EAAE,OAAO,GAAG,KAAK,IAAI,MAAM,EAAE,CAI/D;AAED;;;;;;;;GAQG;AACH,wBAAsB,WAAW,CAC/B,OAAO,EAAE,MAAM,GACd,OAAO,CAAC,MAAM,GAAG,SAAS,CAAC,CAa7B;AAED;;;;;;;;;;GAUG;AACH,wBAAgB,cAAc,CAAC,GAAG,EAAE,MAAM,GAAG,OAAO,CAanD;AAED;;;;;;;;GAQG;AACH,wBAAgB,UAAU,CAAC,GAAG,EAAE,MAAM,EAAE,MAAM,EAAE,MAAM,CAAC,OAAO,GAAG,OAAO,CAUvE;AAED;;;;;;GAMG;AACH,wBAAsB,OAAO,CAC3B,KAAK,EAAE,MAAM,OAAO,GAAG,OAAO,CAAC,OAAO,CAAC,EACvC,SAAS,EAAE,MAAM,GAChB,OAAO,CAAC,OAAO,CAAC,CASlB"}
@@ -1,87 +0,0 @@
1
- /// <reference types="node" />
2
- import type { JsonRpcError } from "@metamask/utils";
3
- /**
4
- * Check whether an unknown error is a Node.js system error with the given code.
5
- *
6
- * @param error - The error to check.
7
- * @param code - The expected error code (e.g. 'ENOENT', 'EPERM').
8
- * @returns True if the error matches the code.
9
- */
10
- export declare function isErrorWithCode(error: unknown, code: string): boolean;
11
- /**
12
- * Turn an error thrown while contacting the daemon socket into a user-facing
13
- * message for `Command.error`, so every command reports the same failure the
14
- * same way. Distinguishes a stopped daemon (`ENOENT`/`ECONNREFUSED`), a
15
- * connection dropped mid-request (`ECONNRESET`), and a permission problem
16
- * (`EACCES`/`EPERM`), falling back to the raw error message.
17
- *
18
- * @param error - The value thrown while contacting the daemon.
19
- * @returns A human-readable explanation of the failure.
20
- */
21
- export declare function makeDaemonConnectionError(error: unknown): string;
22
- /**
23
- * Format the error of a JSON-RPC failure response into a user-facing message
24
- * for `Command.error`, so every command reports RPC failures the same way.
25
- *
26
- * @param error - The `error` field of a JSON-RPC failure response.
27
- * @returns The error message annotated with its numeric code.
28
- */
29
- export declare function formatJsonRpcError(error: JsonRpcError): string;
30
- /**
31
- * Treat an empty string the same as `undefined` — "no value supplied". Used
32
- * to normalise `--password ''` and `MM_WALLET_PASSWORD=''` so they trigger
33
- * the interactive prompt rather than sending an empty string to the keyring.
34
- *
35
- * @param value - The value to normalise.
36
- * @returns `undefined` if `value` is `undefined` or `''`; `value` otherwise.
37
- */
38
- export declare function emptyToUndefined(value: string | undefined): string | undefined;
39
- /**
40
- * Check whether a value is an array of strings. Used to validate untyped RPC
41
- * results (e.g. the daemon's `listActions`) before treating them as `string[]`.
42
- *
43
- * @param value - The value to check.
44
- * @returns True if the value is an array whose every element is a string.
45
- */
46
- export declare function isStringArray(value: unknown): value is string[];
47
- /**
48
- * Read a PID from a file. The file may contain just the PID, or the PID on
49
- * the first line followed by additional metadata (e.g. start time written by
50
- * the daemon).
51
- *
52
- * @param pidPath - The PID file path.
53
- * @returns The PID, or undefined if the file is missing or its first line is
54
- * not a positive integer.
55
- */
56
- export declare function readPidFile(pidPath: string): Promise<number | undefined>;
57
- /**
58
- * Check whether a process is alive by sending signal 0.
59
- *
60
- * Treats `ESRCH` as "process is gone", `EPERM` as "process exists but we
61
- * cannot signal it" (still alive from our perspective), and rethrows
62
- * anything else so the caller can surface unexpected failures rather than
63
- * silently assuming the process is dead.
64
- *
65
- * @param pid - The process ID to check.
66
- * @returns True if the process exists.
67
- */
68
- export declare function isProcessAlive(pid: number): boolean;
69
- /**
70
- * Send a signal to a process. Returns true if the signal was sent, false if
71
- * the process does not exist (ESRCH). Re-throws on permission errors and
72
- * other failures.
73
- *
74
- * @param pid - The process ID.
75
- * @param signal - The signal to send.
76
- * @returns True if the signal was delivered, false if the process is gone.
77
- */
78
- export declare function sendSignal(pid: number, signal: NodeJS.Signals): boolean;
79
- /**
80
- * Poll until a condition is met or the timeout elapses.
81
- *
82
- * @param check - A function that returns true when the condition is met.
83
- * @param timeoutMs - Maximum time to wait in milliseconds.
84
- * @returns True if the condition was met, false on timeout.
85
- */
86
- export declare function waitFor(check: () => boolean | Promise<boolean>, timeoutMs: number): Promise<boolean>;
87
- //# sourceMappingURL=utils.d.mts.map
@@ -1 +0,0 @@
1
- {"version":3,"file":"utils.d.mts","sourceRoot":"","sources":["../../src/daemon/utils.ts"],"names":[],"mappings":";AAAA,OAAO,KAAK,EAAE,YAAY,EAAE,wBAAwB;AAIpD;;;;;;GAMG;AACH,wBAAgB,eAAe,CAAC,KAAK,EAAE,OAAO,EAAE,IAAI,EAAE,MAAM,GAAG,OAAO,CAErE;AAED;;;;;;;;;GASG;AACH,wBAAgB,yBAAyB,CAAC,KAAK,EAAE,OAAO,GAAG,MAAM,CAuBhE;AAED;;;;;;GAMG;AACH,wBAAgB,kBAAkB,CAAC,KAAK,EAAE,YAAY,GAAG,MAAM,CAE9D;AAED;;;;;;;GAOG;AACH,wBAAgB,gBAAgB,CAC9B,KAAK,EAAE,MAAM,GAAG,SAAS,GACxB,MAAM,GAAG,SAAS,CAEpB;AAED;;;;;;GAMG;AACH,wBAAgB,aAAa,CAAC,KAAK,EAAE,OAAO,GAAG,KAAK,IAAI,MAAM,EAAE,CAI/D;AAED;;;;;;;;GAQG;AACH,wBAAsB,WAAW,CAC/B,OAAO,EAAE,MAAM,GACd,OAAO,CAAC,MAAM,GAAG,SAAS,CAAC,CAa7B;AAED;;;;;;;;;;GAUG;AACH,wBAAgB,cAAc,CAAC,GAAG,EAAE,MAAM,GAAG,OAAO,CAanD;AAED;;;;;;;;GAQG;AACH,wBAAgB,UAAU,CAAC,GAAG,EAAE,MAAM,EAAE,MAAM,EAAE,MAAM,CAAC,OAAO,GAAG,OAAO,CAUvE;AAED;;;;;;GAMG;AACH,wBAAsB,OAAO,CAC3B,KAAK,EAAE,MAAM,OAAO,GAAG,OAAO,CAAC,OAAO,CAAC,EACvC,SAAS,EAAE,MAAM,GAChB,OAAO,CAAC,OAAO,CAAC,CASlB"}
@@ -1 +0,0 @@
1
- {"version":3,"file":"utils.mjs","sourceRoot":"","sources":["../../src/daemon/utils.ts"],"names":[],"mappings":"AACA,OAAO,EAAE,eAAe,IAAI,YAAY,EAAE,wBAAwB;AAClE,OAAO,EAAE,QAAQ,EAAE,yBAAyB;AAE5C;;;;;;GAMG;AACH,MAAM,UAAU,eAAe,CAAC,KAAc,EAAE,IAAY;IAC1D,OAAO,YAAY,CAAC,KAAK,CAAC,IAAI,KAAK,CAAC,IAAI,KAAK,IAAI,CAAC;AACpD,CAAC;AAED;;;;;;;;;GASG;AACH,MAAM,UAAU,yBAAyB,CAAC,KAAc;IACtD,IACE,eAAe,CAAC,KAAK,EAAE,QAAQ,CAAC;QAChC,eAAe,CAAC,KAAK,EAAE,cAAc,CAAC,EACtC,CAAC;QACD,OAAO,yDAAyD,CAAC;IACnE,CAAC;IACD,6EAA6E;IAC7E,yEAAyE;IACzE,IAAI,eAAe,CAAC,KAAK,EAAE,YAAY,CAAC,EAAE,CAAC;QACzC,OAAO,CACL,+DAA+D;YAC/D,oEAAoE,CACrE,CAAC;IACJ,CAAC;IACD,IAAI,eAAe,CAAC,KAAK,EAAE,QAAQ,CAAC,IAAI,eAAe,CAAC,KAAK,EAAE,OAAO,CAAC,EAAE,CAAC;QACxE,OAAO,CACL,0DAA0D;YAC1D,iEAAiE;YACjE,6CAA6C,CAC9C,CAAC;IACJ,CAAC;IACD,OAAO,KAAK,YAAY,KAAK,CAAC,CAAC,CAAC,KAAK,CAAC,OAAO,CAAC,CAAC,CAAC,MAAM,CAAC,KAAK,CAAC,CAAC;AAChE,CAAC;AAED;;;;;;GAMG;AACH,MAAM,UAAU,kBAAkB,CAAC,KAAmB;IACpD,OAAO,GAAG,KAAK,CAAC,OAAO,UAAU,MAAM,CAAC,KAAK,CAAC,IAAI,CAAC,GAAG,CAAC;AACzD,CAAC;AAED;;;;;;;GAOG;AACH,MAAM,UAAU,gBAAgB,CAC9B,KAAyB;IAEzB,OAAO,KAAK,KAAK,EAAE,CAAC,CAAC,CAAC,SAAS,CAAC,CAAC,CAAC,KAAK,CAAC;AAC1C,CAAC;AAED;;;;;;GAMG;AACH,MAAM,UAAU,aAAa,CAAC,KAAc;IAC1C,OAAO,CACL,KAAK,CAAC,OAAO,CAAC,KAAK,CAAC,IAAI,KAAK,CAAC,KAAK,CAAC,CAAC,IAAI,EAAE,EAAE,CAAC,OAAO,IAAI,KAAK,QAAQ,CAAC,CACxE,CAAC;AACJ,CAAC;AAED;;;;;;;;GAQG;AACH,MAAM,CAAC,KAAK,UAAU,WAAW,CAC/B,OAAe;IAEf,IAAI,QAAgB,CAAC;IACrB,IAAI,CAAC;QACH,QAAQ,GAAG,MAAM,QAAQ,CAAC,OAAO,EAAE,OAAO,CAAC,CAAC;IAC9C,CAAC;IAAC,OAAO,KAAc,EAAE,CAAC;QACxB,IAAI,eAAe,CAAC,KAAK,EAAE,QAAQ,CAAC,EAAE,CAAC;YACrC,OAAO,SAAS,CAAC;QACnB,CAAC;QACD,MAAM,KAAK,CAAC;IACd,CAAC;IACD,8EAA8E;IAC9E,MAAM,GAAG,GAAG,MAAM,CAAC,QAAQ,CAAC,KAAK,CAAC,IAAI,CAAC,CAAC,CAAC,CAAC,CAAC,IAAI,EAAE,CAAC,CAAC;IACnD,OAAO,MAAM,CAAC,SAAS,CAAC,GAAG,CAAC,IAAI,GAAG,GAAG,CAAC,CAAC,CAAC,CAAC,GAAG,CAAC,CAAC,CAAC,SAAS,CAAC;AAC5D,CAAC;AAED;;;;;;;;;;GAUG;AACH,MAAM,UAAU,cAAc,CAAC,GAAW;IACxC,IAAI,CAAC;QACH,OAAO,CAAC,IAAI,CAAC,GAAG,EAAE,CAAC,CAAC,CAAC;QACrB,OAAO,IAAI,CAAC;IACd,CAAC;IAAC,OAAO,KAAc,EAAE,CAAC;QACxB,IAAI,eAAe,CAAC,KAAK,EAAE,OAAO,CAAC,EAAE,CAAC;YACpC,OAAO,KAAK,CAAC;QACf,CAAC;QACD,IAAI,eAAe,CAAC,KAAK,EAAE,OAAO,CAAC,EAAE,CAAC;YACpC,OAAO,IAAI,CAAC;QACd,CAAC;QACD,MAAM,KAAK,CAAC;IACd,CAAC;AACH,CAAC;AAED;;;;;;;;GAQG;AACH,MAAM,UAAU,UAAU,CAAC,GAAW,EAAE,MAAsB;IAC5D,IAAI,CAAC;QACH,OAAO,CAAC,IAAI,CAAC,GAAG,EAAE,MAAM,CAAC,CAAC;QAC1B,OAAO,IAAI,CAAC;IACd,CAAC;IAAC,OAAO,KAAc,EAAE,CAAC;QACxB,IAAI,eAAe,CAAC,KAAK,EAAE,OAAO,CAAC,EAAE,CAAC;YACpC,OAAO,KAAK,CAAC;QACf,CAAC;QACD,MAAM,KAAK,CAAC;IACd,CAAC;AACH,CAAC;AAED;;;;;;GAMG;AACH,MAAM,CAAC,KAAK,UAAU,OAAO,CAC3B,KAAuC,EACvC,SAAiB;IAEjB,MAAM,QAAQ,GAAG,IAAI,CAAC,GAAG,EAAE,GAAG,SAAS,CAAC;IACxC,OAAO,IAAI,CAAC,GAAG,EAAE,GAAG,QAAQ,EAAE,CAAC;QAC7B,IAAI,MAAM,KAAK,EAAE,EAAE,CAAC;YAClB,OAAO,IAAI,CAAC;QACd,CAAC;QACD,MAAM,IAAI,OAAO,CAAC,CAAC,OAAO,EAAE,EAAE,CAAC,UAAU,CAAC,OAAO,EAAE,GAAG,CAAC,CAAC,CAAC;IAC3D,CAAC;IACD,OAAO,KAAK,CAAC;AACf,CAAC","sourcesContent":["import type { JsonRpcError } from '@metamask/utils';\nimport { isErrorWithCode as hasErrorCode } from '@metamask/utils';\nimport { readFile } from 'node:fs/promises';\n\n/**\n * Check whether an unknown error is a Node.js system error with the given code.\n *\n * @param error - The error to check.\n * @param code - The expected error code (e.g. 'ENOENT', 'EPERM').\n * @returns True if the error matches the code.\n */\nexport function isErrorWithCode(error: unknown, code: string): boolean {\n return hasErrorCode(error) && error.code === code;\n}\n\n/**\n * Turn an error thrown while contacting the daemon socket into a user-facing\n * message for `Command.error`, so every command reports the same failure the\n * same way. Distinguishes a stopped daemon (`ENOENT`/`ECONNREFUSED`), a\n * connection dropped mid-request (`ECONNRESET`), and a permission problem\n * (`EACCES`/`EPERM`), falling back to the raw error message.\n *\n * @param error - The value thrown while contacting the daemon.\n * @returns A human-readable explanation of the failure.\n */\nexport function makeDaemonConnectionError(error: unknown): string {\n if (\n isErrorWithCode(error, 'ENOENT') ||\n isErrorWithCode(error, 'ECONNREFUSED')\n ) {\n return 'Daemon is not running. Start it with `mm daemon start`.';\n }\n // A reset drops an already-established connection, so the daemon was running\n // — most likely it crashed mid-request. Don't tell the user to start it.\n if (isErrorWithCode(error, 'ECONNRESET')) {\n return (\n 'Lost the connection to the daemon; it may have crashed while ' +\n 'handling the request. Check `mm daemon status` and the daemon log.'\n );\n }\n if (isErrorWithCode(error, 'EACCES') || isErrorWithCode(error, 'EPERM')) {\n return (\n 'Cannot connect to the daemon socket: permission denied. ' +\n 'The socket may be owned by another user, or MM_DAEMON_DATA_DIR ' +\n 'may point to a directory you cannot access.'\n );\n }\n return error instanceof Error ? error.message : String(error);\n}\n\n/**\n * Format the error of a JSON-RPC failure response into a user-facing message\n * for `Command.error`, so every command reports RPC failures the same way.\n *\n * @param error - The `error` field of a JSON-RPC failure response.\n * @returns The error message annotated with its numeric code.\n */\nexport function formatJsonRpcError(error: JsonRpcError): string {\n return `${error.message} (code ${String(error.code)})`;\n}\n\n/**\n * Treat an empty string the same as `undefined` — \"no value supplied\". Used\n * to normalise `--password ''` and `MM_WALLET_PASSWORD=''` so they trigger\n * the interactive prompt rather than sending an empty string to the keyring.\n *\n * @param value - The value to normalise.\n * @returns `undefined` if `value` is `undefined` or `''`; `value` otherwise.\n */\nexport function emptyToUndefined(\n value: string | undefined,\n): string | undefined {\n return value === '' ? undefined : value;\n}\n\n/**\n * Check whether a value is an array of strings. Used to validate untyped RPC\n * results (e.g. the daemon's `listActions`) before treating them as `string[]`.\n *\n * @param value - The value to check.\n * @returns True if the value is an array whose every element is a string.\n */\nexport function isStringArray(value: unknown): value is string[] {\n return (\n Array.isArray(value) && value.every((item) => typeof item === 'string')\n );\n}\n\n/**\n * Read a PID from a file. The file may contain just the PID, or the PID on\n * the first line followed by additional metadata (e.g. start time written by\n * the daemon).\n *\n * @param pidPath - The PID file path.\n * @returns The PID, or undefined if the file is missing or its first line is\n * not a positive integer.\n */\nexport async function readPidFile(\n pidPath: string,\n): Promise<number | undefined> {\n let contents: string;\n try {\n contents = await readFile(pidPath, 'utf-8');\n } catch (error: unknown) {\n if (isErrorWithCode(error, 'ENOENT')) {\n return undefined;\n }\n throw error;\n }\n // String.prototype.split always returns at least one element, so [0] is safe.\n const pid = Number(contents.split('\\n')[0].trim());\n return Number.isInteger(pid) && pid > 0 ? pid : undefined;\n}\n\n/**\n * Check whether a process is alive by sending signal 0.\n *\n * Treats `ESRCH` as \"process is gone\", `EPERM` as \"process exists but we\n * cannot signal it\" (still alive from our perspective), and rethrows\n * anything else so the caller can surface unexpected failures rather than\n * silently assuming the process is dead.\n *\n * @param pid - The process ID to check.\n * @returns True if the process exists.\n */\nexport function isProcessAlive(pid: number): boolean {\n try {\n process.kill(pid, 0);\n return true;\n } catch (error: unknown) {\n if (isErrorWithCode(error, 'ESRCH')) {\n return false;\n }\n if (isErrorWithCode(error, 'EPERM')) {\n return true;\n }\n throw error;\n }\n}\n\n/**\n * Send a signal to a process. Returns true if the signal was sent, false if\n * the process does not exist (ESRCH). Re-throws on permission errors and\n * other failures.\n *\n * @param pid - The process ID.\n * @param signal - The signal to send.\n * @returns True if the signal was delivered, false if the process is gone.\n */\nexport function sendSignal(pid: number, signal: NodeJS.Signals): boolean {\n try {\n process.kill(pid, signal);\n return true;\n } catch (error: unknown) {\n if (isErrorWithCode(error, 'ESRCH')) {\n return false;\n }\n throw error;\n }\n}\n\n/**\n * Poll until a condition is met or the timeout elapses.\n *\n * @param check - A function that returns true when the condition is met.\n * @param timeoutMs - Maximum time to wait in milliseconds.\n * @returns True if the condition was met, false on timeout.\n */\nexport async function waitFor(\n check: () => boolean | Promise<boolean>,\n timeoutMs: number,\n): Promise<boolean> {\n const deadline = Date.now() + timeoutMs;\n while (Date.now() < deadline) {\n if (await check()) {\n return true;\n }\n await new Promise((resolve) => setTimeout(resolve, 250));\n }\n return false;\n}\n"]}
@@ -1,341 +0,0 @@
1
- "use strict";
2
- Object.defineProperty(exports, "__esModule", { value: true });
3
- exports.createWallet = void 0;
4
- const analytics_controller_1 = require("@metamask/analytics-controller");
5
- const config_registry_controller_1 = require("@metamask/config-registry-controller");
6
- const messenger_1 = require("@metamask/messenger");
7
- const remote_feature_flag_controller_1 = require("@metamask/remote-feature-flag-controller");
8
- const storage_service_1 = require("@metamask/storage-service");
9
- const wallet_1 = require("@metamask/wallet");
10
- const promises_1 = require("node:fs/promises");
11
- const KeyValueStore_js_1 = require("../persistence/KeyValueStore.cjs");
12
- const persistence_js_1 = require("../persistence/persistence.cjs");
13
- const auto_approval_js_1 = require("./auto-approval.cjs");
14
- const IN_MEMORY_DATABASE_PATH = ':memory:';
15
- /**
16
- * Build the per-instance options the daemon's `Wallet` is constructed with.
17
- *
18
- * Returns a fresh set on every call so the metadata probe and the real wallet
19
- * never share adapter/service instances (the probe is destroyed, which may
20
- * tear those instances down).
21
- *
22
- * Only the slots wired on `@metamask/wallet` today are populated:
23
- * - `storageService` — backed by an in-memory adapter. This is the wallet's
24
- * large-blob store (snap source, caches), distinct from the SQLite
25
- * `KeyValueStore` that persists controller state; no wired controller
26
- * offloads durable data to it yet, so in-memory suffices.
27
- * - `connectivityController` — the `AlwaysOnlineAdapter` exported for
28
- * node-like hosts that have no platform connectivity signal.
29
- * - `networkController` — the Infura project ID used to reach Infura RPC
30
- * endpoints.
31
- * - `remoteFeatureFlagController` — a `ClientConfigApiService` fetching real
32
- * flags over the network.
33
- * - `approvalController` — a no-op `showApprovalRequest` (the daemon is
34
- * headless); pending requests are accepted separately by the auto-approval
35
- * subscription `createWallet` installs, not by this hook.
36
- * - `gasFeeController` — only `clientId: 'cli'` (sent as `X-Client-Id` to the
37
- * gas API); the API endpoints, poll interval, and compatibility callbacks are
38
- * left at the wallet package's platform-agnostic defaults (the default
39
- * `EIP1559APIEndpoint` is already the production URL, so the daemon does not
40
- * re-specify it).
41
- * - `transactionController` — swaps processing disabled and no client hooks;
42
- * see the slot's inline comment for why the daemon relies on the
43
- * controller's defaults for everything else.
44
- *
45
- * The optional `keyringController` slot is intentionally omitted so the
46
- * controller's built-in defaults (e.g. the PBKDF2 encryptor) apply.
47
- *
48
- * @param infuraProjectId - The Infura project ID for the `NetworkController`.
49
- * @returns The `instanceOptions` for the `Wallet` constructor.
50
- */
51
- function buildInstanceOptions(infuraProjectId) {
52
- return {
53
- configRegistryApiService: {
54
- env: config_registry_controller_1.ConfigRegistryApiEnv.PRD,
55
- },
56
- approvalController: {
57
- // The daemon is headless, so there is no UI to open: requests are
58
- // resolved by the auto-approval subscription (see `subscribeToAutoApproval`)
59
- // rather than by this hook, which stays a no-op.
60
- // TODO: surface approval requests over the daemon transport.
61
- showApprovalRequest: () => undefined,
62
- },
63
- connectivityController: {
64
- connectivityAdapter: new wallet_1.AlwaysOnlineAdapter(),
65
- },
66
- gasFeeController: {
67
- // Identifies the CLI to the gas estimation API via the `X-Client-Id`
68
- // header.
69
- clientId: 'cli',
70
- },
71
- networkController: {
72
- infuraProjectId,
73
- },
74
- remoteFeatureFlagController: {
75
- clientConfigApiService: new remote_feature_flag_controller_1.ClientConfigApiService({
76
- fetch: globalThis.fetch,
77
- config: {
78
- // TODO: switch to a CLI-specific `ClientType` once one exists; until
79
- // then `Extension` buckets feature flags as an extension client.
80
- client: remote_feature_flag_controller_1.ClientType.Extension,
81
- distribution: remote_feature_flag_controller_1.DistributionType.Main,
82
- environment: remote_feature_flag_controller_1.EnvironmentType.Production,
83
- },
84
- }),
85
- getMetaMetricsId: () => 'cli',
86
- clientVersion: '0.0.0',
87
- },
88
- storageService: {
89
- storage: new storage_service_1.InMemoryStorageAdapter(),
90
- },
91
- transactionController: {
92
- // The CLI exposes no swaps surface, so skip the swaps-specific
93
- // post-processing a full wallet client runs (mobile makes the same
94
- // choice; the extension keeps swaps enabled).
95
- disableSwaps: true,
96
- // No CLI-specific transaction hooks: the controller's built-in publish
97
- // path broadcasts through the wired `NetworkController` provider, and the
98
- // remaining hooks (metrics, notifications, gas-fee tokens) are client-UI
99
- // concerns the headless daemon has no equivalent for. Every other option
100
- // (`getPermittedAccounts`, `isSimulationEnabled`, `trace`, …) is left at
101
- // the controller's default.
102
- hooks: {},
103
- },
104
- };
105
- }
106
- /**
107
- * Register handlers for the `AnalyticsController` actions that
108
- * `NetworkController` calls to emit RPC service analytics. The daemon does not
109
- * report analytics, so these do nothing: `getState` returns an empty analytics
110
- * ID, which stops the controller before it tracks anything, and `trackEvent` is
111
- * a no-op. Registering them keeps those messenger calls from throwing.
112
- *
113
- * @param messenger - The wallet's root messenger.
114
- */
115
- function registerAnalyticsStubHandlers(messenger) {
116
- // Register on an `AnalyticsController`-namespaced messenger, not the root: a
117
- // messenger can only register handlers for its own namespace, and doing so
118
- // delegates them up to the root, where `NetworkController` can reach them.
119
- const analyticsMessenger = new messenger_1.Messenger({
120
- namespace: 'AnalyticsController',
121
- parent: messenger,
122
- });
123
- analyticsMessenger.registerActionHandler('AnalyticsController:getState', () => ({
124
- ...(0, analytics_controller_1.getDefaultAnalyticsControllerState)(),
125
- analyticsId: '',
126
- }));
127
- analyticsMessenger.registerActionHandler('AnalyticsController:trackEvent', () => undefined);
128
- }
129
- /**
130
- * Create a configured `Wallet` for daemon use, backed by a SQLite key-value
131
- * store for controller-state persistence.
132
- *
133
- * Loads any previously-persisted controller state from the store, seeds the
134
- * wallet with it, then subscribes the store to subsequent state changes so all
135
- * persist-flagged properties are written through.
136
- *
137
- * If the store does not yet contain a keyring vault (first run), the supplied
138
- * secret recovery phrase is imported using the supplied password. On
139
- * subsequent runs, the persisted vault is reused: when a password is
140
- * supplied, the wallet is unlocked via `KeyringController:submitPassword` so
141
- * keyring-bound messenger actions work immediately; when no password is
142
- * supplied, the wallet starts locked and the caller is expected to invoke
143
- * `mm wallet unlock` before any keyring-bound operation. First-run startup
144
- * without a password is rejected (the SRP cannot be imported without one).
145
- * On a subsequent run, a wrong password rejects startup with a `Failed to
146
- * unlock the persisted vault` error that wraps the `submitPassword` rejection.
147
- *
148
- * On any failure after the store is opened, the store is closed (and the wallet
149
- * destroyed, if constructed). On a first-run failure, the on-disk database is
150
- * also removed so a retry does not latch onto an orphaned partial vault — this
151
- * covers in-process failures only; a hard crash (SIGKILL/power loss) mid-import
152
- * can still leave a vault on disk.
153
- *
154
- * @param config - Wallet configuration.
155
- * @param config.databasePath - Path to the SQLite database file (or
156
- * `':memory:'` for ephemeral use).
157
- * @param config.password - The wallet password. Optional on subsequent runs;
158
- * when omitted, the daemon starts with a locked keyring. Required on first
159
- * run (to import the SRP).
160
- * @param config.srp - The secret recovery phrase (BIP-39 mnemonic). Used
161
- * only on first run.
162
- * @param config.infuraProjectId - The Infura project ID for the
163
- * `NetworkController`.
164
- * @param config.log - Optional logger for persistence-write and teardown
165
- * failures. Without it, failures fall back to `console.error` (which a detached
166
- * daemon's `stdio: 'ignore'` discards).
167
- * @returns The `Wallet` and a `dispose` handle that tears it down.
168
- */
169
- async function createWallet({ databasePath, password, srp, infuraProjectId, log, }) {
170
- const logFn = log ?? ((message) => console.error(message));
171
- const store = new KeyValueStore_js_1.KeyValueStore(databasePath);
172
- let wallet;
173
- let persistenceUnsubscribe;
174
- let autoApprovalUnsubscribe;
175
- let wasFirstRun = false;
176
- try {
177
- const state = await loadPersistedState(store, infuraProjectId, logFn);
178
- wasFirstRun = !hasPersistedKeyring(state);
179
- // Validate the first-run precondition BEFORE constructing the wallet,
180
- // so a doomed startup doesn't build a Wallet (and wire persistence
181
- // handlers) just to tear it down.
182
- if (wasFirstRun && password === undefined) {
183
- throw new Error('A password is required on first run to import the secret recovery phrase. ' +
184
- 'Pass `--password` (or `MM_WALLET_PASSWORD`) on `mm daemon start`.');
185
- }
186
- wallet = new wallet_1.Wallet({
187
- state,
188
- instanceOptions: buildInstanceOptions(infuraProjectId),
189
- });
190
- registerAnalyticsStubHandlers(wallet.messenger);
191
- persistenceUnsubscribe = (0, persistence_js_1.subscribeToChanges)(wallet.messenger, wallet.controllerMetadata, store, logFn);
192
- // Installed before `init` so any approval raised during initialization is covered.
193
- autoApprovalUnsubscribe = (0, auto_approval_js_1.subscribeToAutoApproval)(wallet.messenger, logFn);
194
- // Complete post-construction controller setup before serving requests —
195
- // e.g. `NetworkController.init` applies the selected network so a provider
196
- // is available. `init` settles every step independently; a rejected step
197
- // leaves the wallet only partially usable, so abort startup (the catch
198
- // below tears down and, on first run, removes the partial database) rather
199
- // than serving a degraded daemon.
200
- const initResults = await wallet.init();
201
- const initFailures = initResults.filter((result) => result.status === 'rejected');
202
- for (const failure of initFailures) {
203
- logFn(`Wallet init step failed: ${String(failure.reason)}`);
204
- }
205
- if (initFailures.length > 0) {
206
- const firstReason = String(initFailures[0].reason);
207
- throw new Error(`Wallet initialization failed (${initFailures.length} step(s)); refusing to serve a partially initialized wallet. First failure: ${firstReason}`);
208
- }
209
- if (wasFirstRun) {
210
- // The precondition check above throws when `wasFirstRun && password ===
211
- // undefined`, so `password` is defined here. TS does not correlate the
212
- // two separate variables, so it cannot narrow `password` from
213
- // `wasFirstRun` alone — hence the assertion.
214
- await (0, wallet_1.importSecretRecoveryPhrase)(wallet, password.unwrap(), srp.unwrap());
215
- }
216
- else if (password !== undefined) {
217
- try {
218
- await wallet.messenger.call('KeyringController:submitPassword', password.unwrap());
219
- }
220
- catch (error) {
221
- throw new Error(`Failed to unlock the persisted vault: ${String(error)}`);
222
- }
223
- }
224
- let disposePromise;
225
- return {
226
- wallet,
227
- dispose: async () => (disposePromise ?? (disposePromise = teardown(persistenceUnsubscribe, autoApprovalUnsubscribe, wallet, store, logFn))),
228
- };
229
- }
230
- catch (error) {
231
- await teardown(persistenceUnsubscribe, autoApprovalUnsubscribe, wallet, store, logFn);
232
- if (wasFirstRun && databasePath !== IN_MEMORY_DATABASE_PATH) {
233
- // Best-effort cleanup of the on-disk SQLite files (main, WAL, SHM) so a
234
- // partially-persisted KeyringController vault cannot mislead the next run
235
- // into skipping SRP import. Covers in-process failures only — a crash
236
- // (SIGKILL/power loss) mid-import leaves the vault on disk.
237
- await Promise.all([databasePath, `${databasePath}-wal`, `${databasePath}-shm`].map((path) => (0, promises_1.rm)(path, { force: true }).catch((rmError) => {
238
- logFn(`Failed to remove ${path} during first-run cleanup: ${String(rmError)}`);
239
- })));
240
- }
241
- throw error;
242
- }
243
- }
244
- exports.createWallet = createWallet;
245
- /**
246
- * Load persisted controller state, filtered to currently persist-flagged
247
- * properties.
248
- *
249
- * `loadState` filters against the live controller metadata, but that metadata
250
- * is only knowable from a constructed `Wallet` — and its output is what seeds
251
- * the real wallet. So this constructs a short-lived probe purely to read the
252
- * metadata, then tears it down.
253
- *
254
- * TODO: drop the probe once `@metamask/wallet` exposes controller metadata
255
- * without constructing a `Wallet`.
256
- *
257
- * @param store - The key-value store to read from.
258
- * @param infuraProjectId - The Infura project ID for the probe's
259
- * `NetworkController`.
260
- * @param logFn - Logger for a probe-teardown failure.
261
- * @returns The filtered persisted state, suitable for the `Wallet` `state`
262
- * option.
263
- */
264
- async function loadPersistedState(store, infuraProjectId, logFn) {
265
- const probe = new wallet_1.Wallet({
266
- instanceOptions: buildInstanceOptions(infuraProjectId),
267
- });
268
- registerAnalyticsStubHandlers(probe.messenger);
269
- try {
270
- return (0, persistence_js_1.loadState)(store, probe.controllerMetadata);
271
- }
272
- finally {
273
- await probe.destroy().catch((error) => {
274
- logFn(`Metadata probe destroy failed: ${String(error)}`);
275
- });
276
- }
277
- }
278
- /**
279
- * Best-effort unsubscribe: run the function if present, logging (and
280
- * swallowing) any error so a later teardown step still runs.
281
- *
282
- * @param unsubscribe - The unsubscribe function, if one was registered.
283
- * @param label - Human-readable subscription name for the failure log.
284
- * @param logFn - Logger for a failure.
285
- */
286
- function runUnsubscribe(unsubscribe, label, logFn) {
287
- if (!unsubscribe) {
288
- return;
289
- }
290
- try {
291
- unsubscribe();
292
- }
293
- catch (error) {
294
- logFn(`${label} unsubscribe failed during teardown — subscription may remain ` +
295
- `live until the process exits: ${String(error)}`);
296
- }
297
- }
298
- /**
299
- * Persistence-safe teardown of a wallet and its store; see {@link
300
- * CreateWalletResult.dispose} for the ordering rationale. Each step is
301
- * best-effort, so a failure is logged and the remaining steps still run.
302
- *
303
- * @param persistenceUnsubscribe - The persistence-subscription unsubscribe
304
- * function, if one was registered.
305
- * @param autoApprovalUnsubscribe - The auto-approval-subscription unsubscribe
306
- * function, if one was registered.
307
- * @param wallet - The wallet to destroy, if one was constructed.
308
- * @param store - The store to close.
309
- * @param logFn - Logger for step failures.
310
- */
311
- async function teardown(persistenceUnsubscribe, autoApprovalUnsubscribe, wallet, store, logFn) {
312
- runUnsubscribe(persistenceUnsubscribe, 'Persistence', logFn);
313
- runUnsubscribe(autoApprovalUnsubscribe, 'Auto-approval', logFn);
314
- if (wallet) {
315
- try {
316
- await wallet.destroy();
317
- }
318
- catch (error) {
319
- logFn(`wallet.destroy() failed during teardown: ${String(error)}`);
320
- }
321
- }
322
- try {
323
- store.close();
324
- }
325
- catch (error) {
326
- logFn(`store.close() failed during teardown: ${String(error)}`);
327
- }
328
- }
329
- /**
330
- * Determine whether the loaded state already contains a keyring vault.
331
- *
332
- * The KeyringController persists its `vault` once an SRP has been imported, so
333
- * its presence indicates that first-run setup completed before.
334
- *
335
- * @param state - The state loaded from the key-value store.
336
- * @returns True if a KeyringController vault string is present.
337
- */
338
- function hasPersistedKeyring(state) {
339
- return typeof state.KeyringController?.vault === 'string';
340
- }
341
- //# sourceMappingURL=wallet-factory.cjs.map