@metamask-previews/wallet-cli 0.0.0-preview-4f4c98e → 0.0.0-preview-eb263b0ee
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/CHANGELOG.md +1 -2
- package/dist/commands/daemon/call.cjs +79 -0
- package/dist/commands/daemon/call.cjs.map +1 -0
- package/dist/commands/daemon/{call.d.ts → call.d.cts} +2 -2
- package/dist/commands/daemon/call.d.cts.map +1 -0
- package/dist/commands/daemon/call.d.mts +14 -0
- package/dist/commands/daemon/call.d.mts.map +1 -0
- package/dist/commands/daemon/{call.js → call.mjs} +6 -6
- package/dist/commands/daemon/call.mjs.map +1 -0
- package/dist/commands/daemon/list.cjs +48 -0
- package/dist/commands/daemon/list.cjs.map +1 -0
- package/dist/commands/daemon/{list.d.ts → list.d.cts} +2 -2
- package/dist/commands/daemon/list.d.cts.map +1 -0
- package/dist/commands/daemon/list.d.mts +7 -0
- package/dist/commands/daemon/list.d.mts.map +1 -0
- package/dist/commands/daemon/{list.js → list.mjs} +6 -6
- package/dist/commands/daemon/list.mjs.map +1 -0
- package/dist/commands/daemon/purge.cjs +58 -0
- package/dist/commands/daemon/purge.cjs.map +1 -0
- package/dist/commands/daemon/{purge.d.ts → purge.d.cts} +2 -2
- package/dist/commands/daemon/purge.d.cts.map +1 -0
- package/dist/commands/daemon/purge.d.mts +10 -0
- package/dist/commands/daemon/purge.d.mts.map +1 -0
- package/dist/commands/daemon/{purge.js → purge.mjs} +7 -7
- package/dist/commands/daemon/purge.mjs.map +1 -0
- package/dist/commands/daemon/start.cjs +52 -0
- package/dist/commands/daemon/start.cjs.map +1 -0
- package/dist/commands/daemon/{start.d.ts → start.d.cts} +2 -2
- package/dist/commands/daemon/start.d.cts.map +1 -0
- package/dist/commands/daemon/start.d.mts +12 -0
- package/dist/commands/daemon/start.d.mts.map +1 -0
- package/dist/commands/daemon/{start.js → start.mjs} +4 -4
- package/dist/commands/daemon/start.mjs.map +1 -0
- package/dist/commands/daemon/status.cjs +59 -0
- package/dist/commands/daemon/status.cjs.map +1 -0
- package/dist/commands/daemon/{status.d.ts → status.d.cts} +2 -2
- package/dist/commands/daemon/status.d.cts.map +1 -0
- package/dist/commands/daemon/status.d.mts +7 -0
- package/dist/commands/daemon/status.d.mts.map +1 -0
- package/dist/commands/daemon/{status.js → status.mjs} +6 -6
- package/dist/commands/daemon/status.mjs.map +1 -0
- package/dist/commands/daemon/stop.cjs +26 -0
- package/dist/commands/daemon/stop.cjs.map +1 -0
- package/dist/commands/daemon/{stop.d.ts → stop.d.cts} +2 -2
- package/dist/commands/daemon/stop.d.cts.map +1 -0
- package/dist/commands/daemon/stop.d.mts +7 -0
- package/dist/commands/daemon/stop.d.mts.map +1 -0
- package/dist/commands/daemon/{stop.js → stop.mjs} +6 -6
- package/dist/commands/daemon/stop.mjs.map +1 -0
- package/dist/commands/wallet/send.cjs +332 -0
- package/dist/commands/wallet/send.cjs.map +1 -0
- package/dist/commands/wallet/{send.d.ts → send.d.cts} +3 -3
- package/dist/commands/wallet/send.d.cts.map +1 -0
- package/dist/commands/wallet/send.d.mts +42 -0
- package/dist/commands/wallet/send.d.mts.map +1 -0
- package/dist/commands/wallet/{send.js → send.mjs} +9 -9
- package/dist/commands/wallet/send.mjs.map +1 -0
- package/dist/commands/wallet/unlock.cjs +75 -0
- package/dist/commands/wallet/unlock.cjs.map +1 -0
- package/dist/commands/wallet/{unlock.d.ts → unlock.d.cts} +2 -2
- package/dist/commands/wallet/unlock.d.cts.map +1 -0
- package/dist/commands/wallet/unlock.d.mts +11 -0
- package/dist/commands/wallet/unlock.d.mts.map +1 -0
- package/dist/commands/wallet/{unlock.js → unlock.mjs} +7 -7
- package/dist/commands/wallet/unlock.mjs.map +1 -0
- package/dist/daemon/auto-approval.cjs +86 -0
- package/dist/daemon/auto-approval.cjs.map +1 -0
- package/dist/daemon/{auto-approval.d.ts → auto-approval.d.cts} +3 -3
- package/dist/daemon/auto-approval.d.cts.map +1 -0
- package/dist/daemon/auto-approval.d.mts +22 -0
- package/dist/daemon/auto-approval.d.mts.map +1 -0
- package/dist/daemon/{auto-approval.js → auto-approval.mjs} +1 -1
- package/dist/daemon/auto-approval.mjs.map +1 -0
- package/dist/daemon/daemon-client.cjs +149 -0
- package/dist/daemon/daemon-client.cjs.map +1 -0
- package/dist/daemon/{daemon-client.d.ts → daemon-client.d.cts} +2 -2
- package/dist/daemon/daemon-client.d.cts.map +1 -0
- package/dist/daemon/daemon-client.d.mts +84 -0
- package/dist/daemon/daemon-client.d.mts.map +1 -0
- package/dist/daemon/{daemon-client.js → daemon-client.mjs} +6 -6
- package/dist/daemon/daemon-client.mjs.map +1 -0
- package/dist/daemon/daemon-entry.cjs +278 -0
- package/dist/daemon/daemon-entry.cjs.map +1 -0
- package/dist/daemon/daemon-entry.d.cts +2 -0
- package/dist/daemon/daemon-entry.d.cts.map +1 -0
- package/dist/daemon/daemon-entry.d.mts +2 -0
- package/dist/daemon/daemon-entry.d.mts.map +1 -0
- package/dist/daemon/{daemon-entry.js → daemon-entry.mjs} +12 -12
- package/dist/daemon/daemon-entry.mjs.map +1 -0
- package/dist/daemon/daemon-spawn.cjs +138 -0
- package/dist/daemon/daemon-spawn.cjs.map +1 -0
- package/dist/daemon/{daemon-spawn.d.ts → daemon-spawn.d.cts} +2 -2
- package/dist/daemon/daemon-spawn.d.cts.map +1 -0
- package/dist/daemon/daemon-spawn.d.mts +28 -0
- package/dist/daemon/daemon-spawn.d.mts.map +1 -0
- package/dist/daemon/{daemon-spawn.js → daemon-spawn.mjs} +7 -7
- package/dist/daemon/daemon-spawn.mjs.map +1 -0
- package/dist/daemon/data-dir.cjs +23 -0
- package/dist/daemon/data-dir.cjs.map +1 -0
- package/dist/daemon/{data-dir.d.ts → data-dir.d.cts} +1 -1
- package/dist/daemon/data-dir.d.cts.map +1 -0
- package/dist/daemon/data-dir.d.mts +14 -0
- package/dist/daemon/data-dir.d.mts.map +1 -0
- package/dist/daemon/{data-dir.js → data-dir.mjs} +3 -3
- package/dist/daemon/data-dir.mjs.map +1 -0
- package/dist/daemon/paths.cjs +20 -0
- package/dist/daemon/paths.cjs.map +1 -0
- package/dist/daemon/{paths.d.ts → paths.d.cts} +2 -2
- package/dist/daemon/paths.d.cts.map +1 -0
- package/dist/daemon/paths.d.mts +9 -0
- package/dist/daemon/paths.d.mts.map +1 -0
- package/dist/daemon/{paths.js → paths.mjs} +2 -2
- package/dist/daemon/paths.mjs.map +1 -0
- package/dist/daemon/prompts.cjs +55 -0
- package/dist/daemon/prompts.cjs.map +1 -0
- package/dist/daemon/{prompts.d.ts → prompts.d.cts} +1 -1
- package/dist/daemon/prompts.d.cts.map +1 -0
- package/dist/daemon/prompts.d.mts +31 -0
- package/dist/daemon/prompts.d.mts.map +1 -0
- package/dist/daemon/{prompts.js → prompts.mjs} +4 -4
- package/dist/daemon/prompts.mjs.map +1 -0
- package/dist/daemon/rpc-socket-server.cjs +284 -0
- package/dist/daemon/rpc-socket-server.cjs.map +1 -0
- package/dist/daemon/{rpc-socket-server.d.ts → rpc-socket-server.d.cts} +2 -2
- package/dist/daemon/rpc-socket-server.d.cts.map +1 -0
- package/dist/daemon/rpc-socket-server.d.mts +44 -0
- package/dist/daemon/rpc-socket-server.d.mts.map +1 -0
- package/dist/daemon/{rpc-socket-server.js → rpc-socket-server.mjs} +7 -7
- package/dist/daemon/rpc-socket-server.mjs.map +1 -0
- package/dist/daemon/secrets.cjs +137 -0
- package/dist/daemon/secrets.cjs.map +1 -0
- package/dist/daemon/{secrets.d.ts → secrets.d.cts} +1 -1
- package/dist/daemon/secrets.d.cts.map +1 -0
- package/dist/daemon/secrets.d.mts +72 -0
- package/dist/daemon/secrets.d.mts.map +1 -0
- package/dist/daemon/{secrets.js → secrets.mjs} +3 -3
- package/dist/daemon/secrets.mjs.map +1 -0
- package/dist/daemon/send-transaction.cjs +147 -0
- package/dist/daemon/send-transaction.cjs.map +1 -0
- package/dist/daemon/{send-transaction.d.ts → send-transaction.d.cts} +9 -9
- package/dist/daemon/send-transaction.d.cts.map +1 -0
- package/dist/daemon/send-transaction.d.mts +102 -0
- package/dist/daemon/send-transaction.d.mts.map +1 -0
- package/dist/daemon/{send-transaction.js → send-transaction.mjs} +3 -3
- package/dist/daemon/send-transaction.mjs.map +1 -0
- package/dist/daemon/socket-line.cjs +93 -0
- package/dist/daemon/socket-line.cjs.map +1 -0
- package/dist/daemon/{socket-line.d.ts → socket-line.d.cts} +5 -2
- package/dist/daemon/socket-line.d.cts.map +1 -0
- package/dist/daemon/socket-line.d.mts +21 -0
- package/dist/daemon/socket-line.d.mts.map +1 -0
- package/dist/daemon/{socket-line.js → socket-line.mjs} +1 -1
- package/dist/daemon/socket-line.mjs.map +1 -0
- package/dist/daemon/stop-daemon.cjs +117 -0
- package/dist/daemon/stop-daemon.cjs.map +1 -0
- package/dist/daemon/{stop-daemon.d.ts → stop-daemon.d.cts} +1 -1
- package/dist/daemon/stop-daemon.d.cts.map +1 -0
- package/dist/daemon/stop-daemon.d.mts +28 -0
- package/dist/daemon/stop-daemon.d.mts.map +1 -0
- package/dist/daemon/{stop-daemon.js → stop-daemon.mjs} +4 -4
- package/dist/daemon/stop-daemon.mjs.map +1 -0
- package/dist/daemon/types.cjs +20 -0
- package/dist/daemon/types.cjs.map +1 -0
- package/dist/daemon/{types.d.ts → types.d.cts} +4 -4
- package/dist/daemon/types.d.cts.map +1 -0
- package/dist/daemon/types.d.mts +94 -0
- package/dist/daemon/types.d.mts.map +1 -0
- package/dist/daemon/{types.js → types.mjs} +1 -1
- package/dist/daemon/types.mjs.map +1 -0
- package/dist/daemon/utils.cjs +172 -0
- package/dist/daemon/utils.cjs.map +1 -0
- package/dist/daemon/{utils.d.ts → utils.d.cts} +3 -2
- package/dist/daemon/utils.d.cts.map +1 -0
- package/dist/daemon/utils.d.mts +87 -0
- package/dist/daemon/utils.d.mts.map +1 -0
- package/dist/daemon/{utils.js → utils.mjs} +3 -3
- package/dist/daemon/utils.mjs.map +1 -0
- package/dist/daemon/wallet-factory.cjs +341 -0
- package/dist/daemon/wallet-factory.cjs.map +1 -0
- package/dist/daemon/{wallet-factory.d.ts → wallet-factory.d.cts} +4 -4
- package/dist/daemon/wallet-factory.d.cts.map +1 -0
- package/dist/daemon/wallet-factory.d.mts +64 -0
- package/dist/daemon/wallet-factory.d.mts.map +1 -0
- package/dist/daemon/{wallet-factory.js → wallet-factory.mjs} +11 -11
- package/dist/daemon/wallet-factory.mjs.map +1 -0
- package/dist/persistence/KeyValueStore.cjs +79 -0
- package/dist/persistence/KeyValueStore.cjs.map +1 -0
- package/dist/persistence/{KeyValueStore.d.ts → KeyValueStore.d.cts} +2 -2
- package/dist/persistence/KeyValueStore.d.cts.map +1 -0
- package/dist/persistence/KeyValueStore.d.mts +18 -0
- package/dist/persistence/KeyValueStore.d.mts.map +1 -0
- package/dist/persistence/{KeyValueStore.js → KeyValueStore.mjs} +9 -2
- package/dist/persistence/KeyValueStore.mjs.map +1 -0
- package/dist/persistence/persistence.cjs +204 -0
- package/dist/persistence/persistence.cjs.map +1 -0
- package/dist/persistence/{persistence.d.ts → persistence.d.cts} +5 -5
- package/dist/persistence/persistence.d.cts.map +1 -0
- package/dist/persistence/persistence.d.mts +45 -0
- package/dist/persistence/persistence.d.mts.map +1 -0
- package/dist/persistence/{persistence.js → persistence.mjs} +2 -2
- package/dist/persistence/persistence.mjs.map +1 -0
- package/dist/test/run-command.cjs +73 -0
- package/dist/test/run-command.cjs.map +1 -0
- package/dist/test/{run-command.d.ts → run-command.d.cts} +4 -4
- package/dist/test/run-command.d.cts.map +1 -0
- package/dist/test/run-command.d.mts +27 -0
- package/dist/test/run-command.d.mts.map +1 -0
- package/dist/test/{run-command.js → run-command.mjs} +3 -3
- package/dist/test/run-command.mjs.map +1 -0
- package/package.json +8 -12
- package/dist/commands/daemon/call.d.ts.map +0 -1
- package/dist/commands/daemon/call.js.map +0 -1
- package/dist/commands/daemon/list.d.ts.map +0 -1
- package/dist/commands/daemon/list.js.map +0 -1
- package/dist/commands/daemon/purge.d.ts.map +0 -1
- package/dist/commands/daemon/purge.js.map +0 -1
- package/dist/commands/daemon/start.d.ts.map +0 -1
- package/dist/commands/daemon/start.js.map +0 -1
- package/dist/commands/daemon/status.d.ts.map +0 -1
- package/dist/commands/daemon/status.js.map +0 -1
- package/dist/commands/daemon/stop.d.ts.map +0 -1
- package/dist/commands/daemon/stop.js.map +0 -1
- package/dist/commands/wallet/send.d.ts.map +0 -1
- package/dist/commands/wallet/send.js.map +0 -1
- package/dist/commands/wallet/unlock.d.ts.map +0 -1
- package/dist/commands/wallet/unlock.js.map +0 -1
- package/dist/daemon/auto-approval.d.ts.map +0 -1
- package/dist/daemon/auto-approval.js.map +0 -1
- package/dist/daemon/daemon-client.d.ts.map +0 -1
- package/dist/daemon/daemon-client.js.map +0 -1
- package/dist/daemon/daemon-entry.d.ts +0 -2
- package/dist/daemon/daemon-entry.d.ts.map +0 -1
- package/dist/daemon/daemon-entry.js.map +0 -1
- package/dist/daemon/daemon-spawn.d.ts.map +0 -1
- package/dist/daemon/daemon-spawn.js.map +0 -1
- package/dist/daemon/data-dir.d.ts.map +0 -1
- package/dist/daemon/data-dir.js.map +0 -1
- package/dist/daemon/paths.d.ts.map +0 -1
- package/dist/daemon/paths.js.map +0 -1
- package/dist/daemon/prompts.d.ts.map +0 -1
- package/dist/daemon/prompts.js.map +0 -1
- package/dist/daemon/rpc-socket-server.d.ts.map +0 -1
- package/dist/daemon/rpc-socket-server.js.map +0 -1
- package/dist/daemon/secrets.d.ts.map +0 -1
- package/dist/daemon/secrets.js.map +0 -1
- package/dist/daemon/send-transaction.d.ts.map +0 -1
- package/dist/daemon/send-transaction.js.map +0 -1
- package/dist/daemon/socket-line.d.ts.map +0 -1
- package/dist/daemon/socket-line.js.map +0 -1
- package/dist/daemon/stop-daemon.d.ts.map +0 -1
- package/dist/daemon/stop-daemon.js.map +0 -1
- package/dist/daemon/types.d.ts.map +0 -1
- package/dist/daemon/types.js.map +0 -1
- package/dist/daemon/utils.d.ts.map +0 -1
- package/dist/daemon/utils.js.map +0 -1
- package/dist/daemon/wallet-factory.d.ts.map +0 -1
- package/dist/daemon/wallet-factory.js.map +0 -1
- package/dist/persistence/KeyValueStore.d.ts.map +0 -1
- package/dist/persistence/KeyValueStore.js.map +0 -1
- package/dist/persistence/persistence.d.ts.map +0 -1
- package/dist/persistence/persistence.js.map +0 -1
- package/dist/test/run-command.d.ts.map +0 -1
- package/dist/test/run-command.js.map +0 -1
|
@@ -0,0 +1,138 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
+
exports.ensureDaemon = void 0;
|
|
4
|
+
const node_child_process_1 = require("node:child_process");
|
|
5
|
+
const node_fs_1 = require("node:fs");
|
|
6
|
+
const node_path_1 = require("node:path");
|
|
7
|
+
const daemon_client_js_1 = require("./daemon-client.cjs");
|
|
8
|
+
const data_dir_js_1 = require("./data-dir.cjs");
|
|
9
|
+
const paths_js_1 = require("./paths.cjs");
|
|
10
|
+
const POLL_INTERVAL_MS = 100;
|
|
11
|
+
const MAX_POLLS = 300; // 30 seconds
|
|
12
|
+
/**
|
|
13
|
+
* Ensure the daemon is running. If a responsive daemon already exists, return
|
|
14
|
+
* `'already-running'` (caller decides how to surface that). Otherwise spawn
|
|
15
|
+
* one as a detached process and wait until the socket becomes responsive.
|
|
16
|
+
*
|
|
17
|
+
* Refuses to spawn when pinging the existing socket fails with anything other
|
|
18
|
+
* than `ENOENT` (wedged or foreign daemon) — taking over could orphan the
|
|
19
|
+
* existing process and corrupt its PID file.
|
|
20
|
+
*
|
|
21
|
+
* @param config - Spawn configuration.
|
|
22
|
+
* @returns The state of the daemon and the socket path it's listening on.
|
|
23
|
+
*/
|
|
24
|
+
async function ensureDaemon(config) {
|
|
25
|
+
const { socketPath, logPath } = (0, paths_js_1.getDaemonPaths)(config.dataDir);
|
|
26
|
+
const initialPing = await (0, daemon_client_js_1.pingDaemon)(socketPath);
|
|
27
|
+
switch (initialPing.status) {
|
|
28
|
+
case 'responsive':
|
|
29
|
+
return { state: 'already-running', socketPath };
|
|
30
|
+
case 'unreachable':
|
|
31
|
+
if (initialPing.reason === 'permission') {
|
|
32
|
+
throw new Error(`Refusing to start: the socket at ${socketPath} is owned by another user. ` +
|
|
33
|
+
`Choose a different data directory (MM_DAEMON_DATA_DIR) or remove the socket manually. ` +
|
|
34
|
+
`(${initialPing.error.message})`);
|
|
35
|
+
}
|
|
36
|
+
throw new Error(`Refusing to start: a daemon socket already exists at ${socketPath} but is unresponsive. ` +
|
|
37
|
+
`Run \`mm daemon stop\` (or \`mm daemon purge\`) before starting a new daemon. ` +
|
|
38
|
+
`(${initialPing.error.message})`);
|
|
39
|
+
case 'absent':
|
|
40
|
+
break;
|
|
41
|
+
/* istanbul ignore next -- exhaustiveness guard; unreachable for the current PingResult union */
|
|
42
|
+
default: {
|
|
43
|
+
const exhaustiveCheck = initialPing;
|
|
44
|
+
throw new Error(`Unexpected daemon ping status: ${String(exhaustiveCheck)}`);
|
|
45
|
+
}
|
|
46
|
+
}
|
|
47
|
+
process.stderr.write('Starting daemon...\n');
|
|
48
|
+
const { entryPath, args } = resolveEntryPoint(config.packageRoot);
|
|
49
|
+
// Create the data directory before opening the log file inside it. The daemon
|
|
50
|
+
// entry also does this, but only after spawn — opening the log first would
|
|
51
|
+
// ENOENT on a fresh data directory.
|
|
52
|
+
await (0, data_dir_js_1.ensureOwnerOnlyDirectory)(config.dataDir);
|
|
53
|
+
// Redirect the detached daemon's stderr to its log file rather than
|
|
54
|
+
// discarding it, so a crash after startup stays diagnosable. stdout stays
|
|
55
|
+
// ignored — structured status goes through the file logger.
|
|
56
|
+
const logFileDescriptor = (0, node_fs_1.openSync)(logPath, 'a');
|
|
57
|
+
const childEnv = {
|
|
58
|
+
...process.env,
|
|
59
|
+
MM_DAEMON_DATA_DIR: config.dataDir,
|
|
60
|
+
MM_DAEMON_SOCKET_PATH: socketPath,
|
|
61
|
+
INFURA_PROJECT_ID: config.infuraProjectId,
|
|
62
|
+
MM_WALLET_SRP: config.srp.unwrap(),
|
|
63
|
+
};
|
|
64
|
+
// `childEnv` spreads `process.env`, so an inherited `MM_WALLET_PASSWORD`
|
|
65
|
+
// would otherwise leak into the child and unlock a daemon the caller meant
|
|
66
|
+
// to start locked. When no password was supplied, delete the inherited key
|
|
67
|
+
// so the daemon comes up locked; otherwise overwrite it with the supplied
|
|
68
|
+
// value.
|
|
69
|
+
if (config.password === undefined) {
|
|
70
|
+
delete childEnv.MM_WALLET_PASSWORD;
|
|
71
|
+
}
|
|
72
|
+
else {
|
|
73
|
+
childEnv.MM_WALLET_PASSWORD = config.password.unwrap();
|
|
74
|
+
}
|
|
75
|
+
const child = (0, node_child_process_1.spawn)(process.execPath, [...args, entryPath], {
|
|
76
|
+
detached: true,
|
|
77
|
+
stdio: ['ignore', 'ignore', logFileDescriptor],
|
|
78
|
+
env: childEnv,
|
|
79
|
+
});
|
|
80
|
+
// The child dup'd the file descriptor into its stderr, so drop the parent's
|
|
81
|
+
// copy. Safe on the success path: `spawn` reports failures via the 'error'
|
|
82
|
+
// event, not a synchronous throw.
|
|
83
|
+
(0, node_fs_1.closeSync)(logFileDescriptor);
|
|
84
|
+
// A failed spawn (bad interpreter, EACCES, ENOENT) emits 'error' and may
|
|
85
|
+
// never emit 'exit', so 'error' is recorded first and not overwritten by a
|
|
86
|
+
// later 'exit' — the loop surfaces the real cause instead of hanging.
|
|
87
|
+
const outcome = { current: { kind: 'pending' } };
|
|
88
|
+
child.on('error', (error) => {
|
|
89
|
+
process.stderr.write(`Failed to spawn daemon process: ${String(error)}\n`);
|
|
90
|
+
outcome.current = { kind: 'error', error };
|
|
91
|
+
});
|
|
92
|
+
child.on('exit', (code, signal) => {
|
|
93
|
+
if (outcome.current.kind === 'pending') {
|
|
94
|
+
outcome.current = { kind: 'exited', code, signal };
|
|
95
|
+
}
|
|
96
|
+
});
|
|
97
|
+
child.unref();
|
|
98
|
+
for (let i = 0; i < MAX_POLLS; i++) {
|
|
99
|
+
await new Promise((resolve) => setTimeout(resolve, POLL_INTERVAL_MS));
|
|
100
|
+
const settled = outcome.current;
|
|
101
|
+
if (settled.kind === 'error') {
|
|
102
|
+
throw new Error(`Failed to spawn daemon process: ${settled.error.message}. ` +
|
|
103
|
+
`Check the daemon log at ${logPath}.`);
|
|
104
|
+
}
|
|
105
|
+
if (settled.kind === 'exited') {
|
|
106
|
+
throw new Error(`Daemon process exited during startup (code=${String(settled.code)}, signal=${String(settled.signal)}). ` +
|
|
107
|
+
`Check the daemon log at ${logPath}.`);
|
|
108
|
+
}
|
|
109
|
+
const ping = await (0, daemon_client_js_1.pingDaemon)(socketPath);
|
|
110
|
+
if (ping.status === 'responsive') {
|
|
111
|
+
process.stderr.write('Daemon ready.\n');
|
|
112
|
+
return { state: 'started', socketPath };
|
|
113
|
+
}
|
|
114
|
+
}
|
|
115
|
+
throw new Error(`Daemon did not start within ${(MAX_POLLS * POLL_INTERVAL_MS) / 1000}s`);
|
|
116
|
+
}
|
|
117
|
+
exports.ensureDaemon = ensureDaemon;
|
|
118
|
+
/**
|
|
119
|
+
* Resolve the daemon entry point path and any extra Node.js args needed.
|
|
120
|
+
*
|
|
121
|
+
* In production, uses the compiled dist output. In development, uses tsx
|
|
122
|
+
* to run TypeScript source directly.
|
|
123
|
+
*
|
|
124
|
+
* @param packageRoot - The root directory of the wallet-cli package.
|
|
125
|
+
* @returns The entry path and any extra node args.
|
|
126
|
+
*/
|
|
127
|
+
function resolveEntryPoint(packageRoot) {
|
|
128
|
+
const distEntry = (0, node_path_1.join)(packageRoot, 'dist', 'daemon', 'daemon-entry.mjs');
|
|
129
|
+
if ((0, node_fs_1.existsSync)(distEntry)) {
|
|
130
|
+
return { entryPath: distEntry, args: [] };
|
|
131
|
+
}
|
|
132
|
+
const srcEntry = (0, node_path_1.join)(packageRoot, 'src', 'daemon', 'daemon-entry.ts');
|
|
133
|
+
return {
|
|
134
|
+
entryPath: srcEntry,
|
|
135
|
+
args: ['--import', 'tsx'],
|
|
136
|
+
};
|
|
137
|
+
}
|
|
138
|
+
//# sourceMappingURL=daemon-spawn.cjs.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"daemon-spawn.cjs","sourceRoot":"","sources":["../../src/daemon/daemon-spawn.ts"],"names":[],"mappings":"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","sourcesContent":["import { spawn } from 'node:child_process';\nimport { closeSync, existsSync, openSync } from 'node:fs';\nimport { join } from 'node:path';\n\nimport { pingDaemon } from './daemon-client.js';\nimport { ensureOwnerOnlyDirectory } from './data-dir.js';\nimport { getDaemonPaths } from './paths.js';\nimport type { DaemonSpawnConfig } from './types.js';\n\nconst POLL_INTERVAL_MS = 100;\nconst MAX_POLLS = 300; // 30 seconds\n\n/**\n * Outcome of {@link ensureDaemon}.\n *\n * - `'already-running'`: a responsive daemon was found at the configured\n * socket path. The supplied flags (`infuraProjectId`, `password`, `srp`)\n * were NOT applied to that daemon; the caller should surface this so a\n * user who is trying to change them isn't silently ignored.\n * - `'started'`: a new daemon was spawned and is now responsive.\n */\nexport type EnsureDaemonResult = {\n state: 'already-running' | 'started';\n socketPath: string;\n};\n\n/**\n * Ensure the daemon is running. If a responsive daemon already exists, return\n * `'already-running'` (caller decides how to surface that). Otherwise spawn\n * one as a detached process and wait until the socket becomes responsive.\n *\n * Refuses to spawn when pinging the existing socket fails with anything other\n * than `ENOENT` (wedged or foreign daemon) — taking over could orphan the\n * existing process and corrupt its PID file.\n *\n * @param config - Spawn configuration.\n * @returns The state of the daemon and the socket path it's listening on.\n */\nexport async function ensureDaemon(\n config: DaemonSpawnConfig,\n): Promise<EnsureDaemonResult> {\n const { socketPath, logPath } = getDaemonPaths(config.dataDir);\n\n const initialPing = await pingDaemon(socketPath);\n switch (initialPing.status) {\n case 'responsive':\n return { state: 'already-running', socketPath };\n case 'unreachable':\n if (initialPing.reason === 'permission') {\n throw new Error(\n `Refusing to start: the socket at ${socketPath} is owned by another user. ` +\n `Choose a different data directory (MM_DAEMON_DATA_DIR) or remove the socket manually. ` +\n `(${initialPing.error.message})`,\n );\n }\n throw new Error(\n `Refusing to start: a daemon socket already exists at ${socketPath} but is unresponsive. ` +\n `Run \\`mm daemon stop\\` (or \\`mm daemon purge\\`) before starting a new daemon. ` +\n `(${initialPing.error.message})`,\n );\n case 'absent':\n break;\n /* istanbul ignore next -- exhaustiveness guard; unreachable for the current PingResult union */\n default: {\n const exhaustiveCheck: never = initialPing;\n throw new Error(\n `Unexpected daemon ping status: ${String(exhaustiveCheck)}`,\n );\n }\n }\n\n process.stderr.write('Starting daemon...\\n');\n\n const { entryPath, args } = resolveEntryPoint(config.packageRoot);\n\n // Create the data directory before opening the log file inside it. The daemon\n // entry also does this, but only after spawn — opening the log first would\n // ENOENT on a fresh data directory.\n await ensureOwnerOnlyDirectory(config.dataDir);\n\n // Redirect the detached daemon's stderr to its log file rather than\n // discarding it, so a crash after startup stays diagnosable. stdout stays\n // ignored — structured status goes through the file logger.\n const logFileDescriptor = openSync(logPath, 'a');\n\n const childEnv: NodeJS.ProcessEnv = {\n ...process.env,\n MM_DAEMON_DATA_DIR: config.dataDir,\n MM_DAEMON_SOCKET_PATH: socketPath,\n INFURA_PROJECT_ID: config.infuraProjectId,\n MM_WALLET_SRP: config.srp.unwrap(),\n };\n // `childEnv` spreads `process.env`, so an inherited `MM_WALLET_PASSWORD`\n // would otherwise leak into the child and unlock a daemon the caller meant\n // to start locked. When no password was supplied, delete the inherited key\n // so the daemon comes up locked; otherwise overwrite it with the supplied\n // value.\n if (config.password === undefined) {\n delete childEnv.MM_WALLET_PASSWORD;\n } else {\n childEnv.MM_WALLET_PASSWORD = config.password.unwrap();\n }\n\n const child = spawn(process.execPath, [...args, entryPath], {\n detached: true,\n stdio: ['ignore', 'ignore', logFileDescriptor],\n env: childEnv,\n });\n // The child dup'd the file descriptor into its stderr, so drop the parent's\n // copy. Safe on the success path: `spawn` reports failures via the 'error'\n // event, not a synchronous throw.\n closeSync(logFileDescriptor);\n\n type StartupOutcome =\n | { kind: 'pending' }\n | { kind: 'error'; error: Error }\n | { kind: 'exited'; code: number | null; signal: NodeJS.Signals | null };\n\n // A failed spawn (bad interpreter, EACCES, ENOENT) emits 'error' and may\n // never emit 'exit', so 'error' is recorded first and not overwritten by a\n // later 'exit' — the loop surfaces the real cause instead of hanging.\n const outcome: { current: StartupOutcome } = { current: { kind: 'pending' } };\n\n child.on('error', (error: Error) => {\n process.stderr.write(`Failed to spawn daemon process: ${String(error)}\\n`);\n outcome.current = { kind: 'error', error };\n });\n child.on('exit', (code, signal) => {\n if (outcome.current.kind === 'pending') {\n outcome.current = { kind: 'exited', code, signal };\n }\n });\n child.unref();\n\n for (let i = 0; i < MAX_POLLS; i++) {\n await new Promise((resolve) => setTimeout(resolve, POLL_INTERVAL_MS));\n const settled = outcome.current;\n if (settled.kind === 'error') {\n throw new Error(\n `Failed to spawn daemon process: ${settled.error.message}. ` +\n `Check the daemon log at ${logPath}.`,\n );\n }\n if (settled.kind === 'exited') {\n throw new Error(\n `Daemon process exited during startup (code=${String(settled.code)}, signal=${String(settled.signal)}). ` +\n `Check the daemon log at ${logPath}.`,\n );\n }\n const ping = await pingDaemon(socketPath);\n if (ping.status === 'responsive') {\n process.stderr.write('Daemon ready.\\n');\n return { state: 'started', socketPath };\n }\n }\n\n throw new Error(\n `Daemon did not start within ${(MAX_POLLS * POLL_INTERVAL_MS) / 1000}s`,\n );\n}\n\n/**\n * Resolve the daemon entry point path and any extra Node.js args needed.\n *\n * In production, uses the compiled dist output. In development, uses tsx\n * to run TypeScript source directly.\n *\n * @param packageRoot - The root directory of the wallet-cli package.\n * @returns The entry path and any extra node args.\n */\nfunction resolveEntryPoint(packageRoot: string): {\n entryPath: string;\n args: string[];\n} {\n const distEntry = join(packageRoot, 'dist', 'daemon', 'daemon-entry.mjs');\n if (existsSync(distEntry)) {\n return { entryPath: distEntry, args: [] };\n }\n\n const srcEntry = join(packageRoot, 'src', 'daemon', 'daemon-entry.ts');\n return {\n entryPath: srcEntry,\n args: ['--import', 'tsx'],\n };\n}\n"]}
|
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import type { DaemonSpawnConfig } from
|
|
1
|
+
import type { DaemonSpawnConfig } from "./types.cjs";
|
|
2
2
|
/**
|
|
3
3
|
* Outcome of {@link ensureDaemon}.
|
|
4
4
|
*
|
|
@@ -25,4 +25,4 @@ export type EnsureDaemonResult = {
|
|
|
25
25
|
* @returns The state of the daemon and the socket path it's listening on.
|
|
26
26
|
*/
|
|
27
27
|
export declare function ensureDaemon(config: DaemonSpawnConfig): Promise<EnsureDaemonResult>;
|
|
28
|
-
//# sourceMappingURL=daemon-spawn.d.
|
|
28
|
+
//# sourceMappingURL=daemon-spawn.d.cts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"daemon-spawn.d.cts","sourceRoot":"","sources":["../../src/daemon/daemon-spawn.ts"],"names":[],"mappings":"AAOA,OAAO,KAAK,EAAE,iBAAiB,EAAE,oBAAmB;AAKpD;;;;;;;;GAQG;AACH,MAAM,MAAM,kBAAkB,GAAG;IAC/B,KAAK,EAAE,iBAAiB,GAAG,SAAS,CAAC;IACrC,UAAU,EAAE,MAAM,CAAC;CACpB,CAAC;AAEF;;;;;;;;;;;GAWG;AACH,wBAAsB,YAAY,CAChC,MAAM,EAAE,iBAAiB,GACxB,OAAO,CAAC,kBAAkB,CAAC,CAuH7B"}
|
|
@@ -0,0 +1,28 @@
|
|
|
1
|
+
import type { DaemonSpawnConfig } from "./types.mjs";
|
|
2
|
+
/**
|
|
3
|
+
* Outcome of {@link ensureDaemon}.
|
|
4
|
+
*
|
|
5
|
+
* - `'already-running'`: a responsive daemon was found at the configured
|
|
6
|
+
* socket path. The supplied flags (`infuraProjectId`, `password`, `srp`)
|
|
7
|
+
* were NOT applied to that daemon; the caller should surface this so a
|
|
8
|
+
* user who is trying to change them isn't silently ignored.
|
|
9
|
+
* - `'started'`: a new daemon was spawned and is now responsive.
|
|
10
|
+
*/
|
|
11
|
+
export type EnsureDaemonResult = {
|
|
12
|
+
state: 'already-running' | 'started';
|
|
13
|
+
socketPath: string;
|
|
14
|
+
};
|
|
15
|
+
/**
|
|
16
|
+
* Ensure the daemon is running. If a responsive daemon already exists, return
|
|
17
|
+
* `'already-running'` (caller decides how to surface that). Otherwise spawn
|
|
18
|
+
* one as a detached process and wait until the socket becomes responsive.
|
|
19
|
+
*
|
|
20
|
+
* Refuses to spawn when pinging the existing socket fails with anything other
|
|
21
|
+
* than `ENOENT` (wedged or foreign daemon) — taking over could orphan the
|
|
22
|
+
* existing process and corrupt its PID file.
|
|
23
|
+
*
|
|
24
|
+
* @param config - Spawn configuration.
|
|
25
|
+
* @returns The state of the daemon and the socket path it's listening on.
|
|
26
|
+
*/
|
|
27
|
+
export declare function ensureDaemon(config: DaemonSpawnConfig): Promise<EnsureDaemonResult>;
|
|
28
|
+
//# sourceMappingURL=daemon-spawn.d.mts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"daemon-spawn.d.mts","sourceRoot":"","sources":["../../src/daemon/daemon-spawn.ts"],"names":[],"mappings":"AAOA,OAAO,KAAK,EAAE,iBAAiB,EAAE,oBAAmB;AAKpD;;;;;;;;GAQG;AACH,MAAM,MAAM,kBAAkB,GAAG;IAC/B,KAAK,EAAE,iBAAiB,GAAG,SAAS,CAAC;IACrC,UAAU,EAAE,MAAM,CAAC;CACpB,CAAC;AAEF;;;;;;;;;;;GAWG;AACH,wBAAsB,YAAY,CAChC,MAAM,EAAE,iBAAiB,GACxB,OAAO,CAAC,kBAAkB,CAAC,CAuH7B"}
|
|
@@ -1,9 +1,9 @@
|
|
|
1
|
-
import { spawn } from
|
|
2
|
-
import { closeSync, existsSync, openSync } from
|
|
3
|
-
import { join } from
|
|
4
|
-
import { pingDaemon } from
|
|
5
|
-
import { ensureOwnerOnlyDirectory } from
|
|
6
|
-
import { getDaemonPaths } from
|
|
1
|
+
import { spawn } from "node:child_process";
|
|
2
|
+
import { closeSync, existsSync, openSync } from "node:fs";
|
|
3
|
+
import { join } from "node:path";
|
|
4
|
+
import { pingDaemon } from "./daemon-client.mjs";
|
|
5
|
+
import { ensureOwnerOnlyDirectory } from "./data-dir.mjs";
|
|
6
|
+
import { getDaemonPaths } from "./paths.mjs";
|
|
7
7
|
const POLL_INTERVAL_MS = 100;
|
|
8
8
|
const MAX_POLLS = 300; // 30 seconds
|
|
9
9
|
/**
|
|
@@ -131,4 +131,4 @@ function resolveEntryPoint(packageRoot) {
|
|
|
131
131
|
args: ['--import', 'tsx'],
|
|
132
132
|
};
|
|
133
133
|
}
|
|
134
|
-
//# sourceMappingURL=daemon-spawn.
|
|
134
|
+
//# sourceMappingURL=daemon-spawn.mjs.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"daemon-spawn.mjs","sourceRoot":"","sources":["../../src/daemon/daemon-spawn.ts"],"names":[],"mappings":"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","sourcesContent":["import { spawn } from 'node:child_process';\nimport { closeSync, existsSync, openSync } from 'node:fs';\nimport { join } from 'node:path';\n\nimport { pingDaemon } from './daemon-client.js';\nimport { ensureOwnerOnlyDirectory } from './data-dir.js';\nimport { getDaemonPaths } from './paths.js';\nimport type { DaemonSpawnConfig } from './types.js';\n\nconst POLL_INTERVAL_MS = 100;\nconst MAX_POLLS = 300; // 30 seconds\n\n/**\n * Outcome of {@link ensureDaemon}.\n *\n * - `'already-running'`: a responsive daemon was found at the configured\n * socket path. The supplied flags (`infuraProjectId`, `password`, `srp`)\n * were NOT applied to that daemon; the caller should surface this so a\n * user who is trying to change them isn't silently ignored.\n * - `'started'`: a new daemon was spawned and is now responsive.\n */\nexport type EnsureDaemonResult = {\n state: 'already-running' | 'started';\n socketPath: string;\n};\n\n/**\n * Ensure the daemon is running. If a responsive daemon already exists, return\n * `'already-running'` (caller decides how to surface that). Otherwise spawn\n * one as a detached process and wait until the socket becomes responsive.\n *\n * Refuses to spawn when pinging the existing socket fails with anything other\n * than `ENOENT` (wedged or foreign daemon) — taking over could orphan the\n * existing process and corrupt its PID file.\n *\n * @param config - Spawn configuration.\n * @returns The state of the daemon and the socket path it's listening on.\n */\nexport async function ensureDaemon(\n config: DaemonSpawnConfig,\n): Promise<EnsureDaemonResult> {\n const { socketPath, logPath } = getDaemonPaths(config.dataDir);\n\n const initialPing = await pingDaemon(socketPath);\n switch (initialPing.status) {\n case 'responsive':\n return { state: 'already-running', socketPath };\n case 'unreachable':\n if (initialPing.reason === 'permission') {\n throw new Error(\n `Refusing to start: the socket at ${socketPath} is owned by another user. ` +\n `Choose a different data directory (MM_DAEMON_DATA_DIR) or remove the socket manually. ` +\n `(${initialPing.error.message})`,\n );\n }\n throw new Error(\n `Refusing to start: a daemon socket already exists at ${socketPath} but is unresponsive. ` +\n `Run \\`mm daemon stop\\` (or \\`mm daemon purge\\`) before starting a new daemon. ` +\n `(${initialPing.error.message})`,\n );\n case 'absent':\n break;\n /* istanbul ignore next -- exhaustiveness guard; unreachable for the current PingResult union */\n default: {\n const exhaustiveCheck: never = initialPing;\n throw new Error(\n `Unexpected daemon ping status: ${String(exhaustiveCheck)}`,\n );\n }\n }\n\n process.stderr.write('Starting daemon...\\n');\n\n const { entryPath, args } = resolveEntryPoint(config.packageRoot);\n\n // Create the data directory before opening the log file inside it. The daemon\n // entry also does this, but only after spawn — opening the log first would\n // ENOENT on a fresh data directory.\n await ensureOwnerOnlyDirectory(config.dataDir);\n\n // Redirect the detached daemon's stderr to its log file rather than\n // discarding it, so a crash after startup stays diagnosable. stdout stays\n // ignored — structured status goes through the file logger.\n const logFileDescriptor = openSync(logPath, 'a');\n\n const childEnv: NodeJS.ProcessEnv = {\n ...process.env,\n MM_DAEMON_DATA_DIR: config.dataDir,\n MM_DAEMON_SOCKET_PATH: socketPath,\n INFURA_PROJECT_ID: config.infuraProjectId,\n MM_WALLET_SRP: config.srp.unwrap(),\n };\n // `childEnv` spreads `process.env`, so an inherited `MM_WALLET_PASSWORD`\n // would otherwise leak into the child and unlock a daemon the caller meant\n // to start locked. When no password was supplied, delete the inherited key\n // so the daemon comes up locked; otherwise overwrite it with the supplied\n // value.\n if (config.password === undefined) {\n delete childEnv.MM_WALLET_PASSWORD;\n } else {\n childEnv.MM_WALLET_PASSWORD = config.password.unwrap();\n }\n\n const child = spawn(process.execPath, [...args, entryPath], {\n detached: true,\n stdio: ['ignore', 'ignore', logFileDescriptor],\n env: childEnv,\n });\n // The child dup'd the file descriptor into its stderr, so drop the parent's\n // copy. Safe on the success path: `spawn` reports failures via the 'error'\n // event, not a synchronous throw.\n closeSync(logFileDescriptor);\n\n type StartupOutcome =\n | { kind: 'pending' }\n | { kind: 'error'; error: Error }\n | { kind: 'exited'; code: number | null; signal: NodeJS.Signals | null };\n\n // A failed spawn (bad interpreter, EACCES, ENOENT) emits 'error' and may\n // never emit 'exit', so 'error' is recorded first and not overwritten by a\n // later 'exit' — the loop surfaces the real cause instead of hanging.\n const outcome: { current: StartupOutcome } = { current: { kind: 'pending' } };\n\n child.on('error', (error: Error) => {\n process.stderr.write(`Failed to spawn daemon process: ${String(error)}\\n`);\n outcome.current = { kind: 'error', error };\n });\n child.on('exit', (code, signal) => {\n if (outcome.current.kind === 'pending') {\n outcome.current = { kind: 'exited', code, signal };\n }\n });\n child.unref();\n\n for (let i = 0; i < MAX_POLLS; i++) {\n await new Promise((resolve) => setTimeout(resolve, POLL_INTERVAL_MS));\n const settled = outcome.current;\n if (settled.kind === 'error') {\n throw new Error(\n `Failed to spawn daemon process: ${settled.error.message}. ` +\n `Check the daemon log at ${logPath}.`,\n );\n }\n if (settled.kind === 'exited') {\n throw new Error(\n `Daemon process exited during startup (code=${String(settled.code)}, signal=${String(settled.signal)}). ` +\n `Check the daemon log at ${logPath}.`,\n );\n }\n const ping = await pingDaemon(socketPath);\n if (ping.status === 'responsive') {\n process.stderr.write('Daemon ready.\\n');\n return { state: 'started', socketPath };\n }\n }\n\n throw new Error(\n `Daemon did not start within ${(MAX_POLLS * POLL_INTERVAL_MS) / 1000}s`,\n );\n}\n\n/**\n * Resolve the daemon entry point path and any extra Node.js args needed.\n *\n * In production, uses the compiled dist output. In development, uses tsx\n * to run TypeScript source directly.\n *\n * @param packageRoot - The root directory of the wallet-cli package.\n * @returns The entry path and any extra node args.\n */\nfunction resolveEntryPoint(packageRoot: string): {\n entryPath: string;\n args: string[];\n} {\n const distEntry = join(packageRoot, 'dist', 'daemon', 'daemon-entry.mjs');\n if (existsSync(distEntry)) {\n return { entryPath: distEntry, args: [] };\n }\n\n const srcEntry = join(packageRoot, 'src', 'daemon', 'daemon-entry.ts');\n return {\n entryPath: srcEntry,\n args: ['--import', 'tsx'],\n };\n}\n"]}
|
|
@@ -0,0 +1,23 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
+
exports.ensureOwnerOnlyDirectory = void 0;
|
|
4
|
+
const node_fs_1 = require("node:fs");
|
|
5
|
+
const promises_1 = require("node:fs/promises");
|
|
6
|
+
/**
|
|
7
|
+
* Create the daemon's data directory (if it does not exist) and restrict it to
|
|
8
|
+
* the owning user.
|
|
9
|
+
*
|
|
10
|
+
* The mode is `0o700` (owner-only). The daemon exposes the full wallet
|
|
11
|
+
* messenger over the socket inside this directory, so anyone who can traverse
|
|
12
|
+
* the dir can also `connect()` to the socket. Restricting to the owning user is
|
|
13
|
+
* the only access-control boundary. We `chmod` after `mkdir` because the `mode`
|
|
14
|
+
* option is ignored when the directory already exists.
|
|
15
|
+
*
|
|
16
|
+
* @param dataDir - The data directory to create and lock down.
|
|
17
|
+
*/
|
|
18
|
+
async function ensureOwnerOnlyDirectory(dataDir) {
|
|
19
|
+
(0, node_fs_1.mkdirSync)(dataDir, { recursive: true, mode: 0o700 });
|
|
20
|
+
await (0, promises_1.chmod)(dataDir, 0o700);
|
|
21
|
+
}
|
|
22
|
+
exports.ensureOwnerOnlyDirectory = ensureOwnerOnlyDirectory;
|
|
23
|
+
//# sourceMappingURL=data-dir.cjs.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"data-dir.cjs","sourceRoot":"","sources":["../../src/daemon/data-dir.ts"],"names":[],"mappings":";;;AAAA,qCAAoC;AACpC,+CAAyC;AAEzC;;;;;;;;;;;GAWG;AACI,KAAK,UAAU,wBAAwB,CAAC,OAAe;IAC5D,IAAA,mBAAS,EAAC,OAAO,EAAE,EAAE,SAAS,EAAE,IAAI,EAAE,IAAI,EAAE,KAAK,EAAE,CAAC,CAAC;IACrD,MAAM,IAAA,gBAAK,EAAC,OAAO,EAAE,KAAK,CAAC,CAAC;AAC9B,CAAC;AAHD,4DAGC","sourcesContent":["import { mkdirSync } from 'node:fs';\nimport { chmod } from 'node:fs/promises';\n\n/**\n * Create the daemon's data directory (if it does not exist) and restrict it to\n * the owning user.\n *\n * The mode is `0o700` (owner-only). The daemon exposes the full wallet\n * messenger over the socket inside this directory, so anyone who can traverse\n * the dir can also `connect()` to the socket. Restricting to the owning user is\n * the only access-control boundary. We `chmod` after `mkdir` because the `mode`\n * option is ignored when the directory already exists.\n *\n * @param dataDir - The data directory to create and lock down.\n */\nexport async function ensureOwnerOnlyDirectory(dataDir: string): Promise<void> {\n mkdirSync(dataDir, { recursive: true, mode: 0o700 });\n await chmod(dataDir, 0o700);\n}\n"]}
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"data-dir.d.cts","sourceRoot":"","sources":["../../src/daemon/data-dir.ts"],"names":[],"mappings":"AAGA;;;;;;;;;;;GAWG;AACH,wBAAsB,wBAAwB,CAAC,OAAO,EAAE,MAAM,GAAG,OAAO,CAAC,IAAI,CAAC,CAG7E"}
|
|
@@ -0,0 +1,14 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Create the daemon's data directory (if it does not exist) and restrict it to
|
|
3
|
+
* the owning user.
|
|
4
|
+
*
|
|
5
|
+
* The mode is `0o700` (owner-only). The daemon exposes the full wallet
|
|
6
|
+
* messenger over the socket inside this directory, so anyone who can traverse
|
|
7
|
+
* the dir can also `connect()` to the socket. Restricting to the owning user is
|
|
8
|
+
* the only access-control boundary. We `chmod` after `mkdir` because the `mode`
|
|
9
|
+
* option is ignored when the directory already exists.
|
|
10
|
+
*
|
|
11
|
+
* @param dataDir - The data directory to create and lock down.
|
|
12
|
+
*/
|
|
13
|
+
export declare function ensureOwnerOnlyDirectory(dataDir: string): Promise<void>;
|
|
14
|
+
//# sourceMappingURL=data-dir.d.mts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"data-dir.d.mts","sourceRoot":"","sources":["../../src/daemon/data-dir.ts"],"names":[],"mappings":"AAGA;;;;;;;;;;;GAWG;AACH,wBAAsB,wBAAwB,CAAC,OAAO,EAAE,MAAM,GAAG,OAAO,CAAC,IAAI,CAAC,CAG7E"}
|
|
@@ -1,5 +1,5 @@
|
|
|
1
|
-
import { mkdirSync } from
|
|
2
|
-
import { chmod } from
|
|
1
|
+
import { mkdirSync } from "node:fs";
|
|
2
|
+
import { chmod } from "node:fs/promises";
|
|
3
3
|
/**
|
|
4
4
|
* Create the daemon's data directory (if it does not exist) and restrict it to
|
|
5
5
|
* the owning user.
|
|
@@ -16,4 +16,4 @@ export async function ensureOwnerOnlyDirectory(dataDir) {
|
|
|
16
16
|
mkdirSync(dataDir, { recursive: true, mode: 0o700 });
|
|
17
17
|
await chmod(dataDir, 0o700);
|
|
18
18
|
}
|
|
19
|
-
//# sourceMappingURL=data-dir.
|
|
19
|
+
//# sourceMappingURL=data-dir.mjs.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"data-dir.mjs","sourceRoot":"","sources":["../../src/daemon/data-dir.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,SAAS,EAAE,gBAAgB;AACpC,OAAO,EAAE,KAAK,EAAE,yBAAyB;AAEzC;;;;;;;;;;;GAWG;AACH,MAAM,CAAC,KAAK,UAAU,wBAAwB,CAAC,OAAe;IAC5D,SAAS,CAAC,OAAO,EAAE,EAAE,SAAS,EAAE,IAAI,EAAE,IAAI,EAAE,KAAK,EAAE,CAAC,CAAC;IACrD,MAAM,KAAK,CAAC,OAAO,EAAE,KAAK,CAAC,CAAC;AAC9B,CAAC","sourcesContent":["import { mkdirSync } from 'node:fs';\nimport { chmod } from 'node:fs/promises';\n\n/**\n * Create the daemon's data directory (if it does not exist) and restrict it to\n * the owning user.\n *\n * The mode is `0o700` (owner-only). The daemon exposes the full wallet\n * messenger over the socket inside this directory, so anyone who can traverse\n * the dir can also `connect()` to the socket. Restricting to the owning user is\n * the only access-control boundary. We `chmod` after `mkdir` because the `mode`\n * option is ignored when the directory already exists.\n *\n * @param dataDir - The data directory to create and lock down.\n */\nexport async function ensureOwnerOnlyDirectory(dataDir: string): Promise<void> {\n mkdirSync(dataDir, { recursive: true, mode: 0o700 });\n await chmod(dataDir, 0o700);\n}\n"]}
|
|
@@ -0,0 +1,20 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
+
exports.getDaemonPaths = void 0;
|
|
4
|
+
const node_path_1 = require("node:path");
|
|
5
|
+
/**
|
|
6
|
+
* Resolve paths for daemon state files within the given data directory.
|
|
7
|
+
*
|
|
8
|
+
* @param dataDir - The base data directory (e.g. oclif config.dataDir).
|
|
9
|
+
* @returns Resolved paths for socket, PID file, log file, and database file.
|
|
10
|
+
*/
|
|
11
|
+
function getDaemonPaths(dataDir) {
|
|
12
|
+
return {
|
|
13
|
+
socketPath: (0, node_path_1.join)(dataDir, 'daemon.sock'),
|
|
14
|
+
pidPath: (0, node_path_1.join)(dataDir, 'daemon.pid'),
|
|
15
|
+
logPath: (0, node_path_1.join)(dataDir, 'daemon.log'),
|
|
16
|
+
dbPath: (0, node_path_1.join)(dataDir, 'wallet.db'),
|
|
17
|
+
};
|
|
18
|
+
}
|
|
19
|
+
exports.getDaemonPaths = getDaemonPaths;
|
|
20
|
+
//# sourceMappingURL=paths.cjs.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"paths.cjs","sourceRoot":"","sources":["../../src/daemon/paths.ts"],"names":[],"mappings":";;;AAAA,yCAAiC;AAIjC;;;;;GAKG;AACH,SAAgB,cAAc,CAAC,OAAe;IAC5C,OAAO;QACL,UAAU,EAAE,IAAA,gBAAI,EAAC,OAAO,EAAE,aAAa,CAAC;QACxC,OAAO,EAAE,IAAA,gBAAI,EAAC,OAAO,EAAE,YAAY,CAAC;QACpC,OAAO,EAAE,IAAA,gBAAI,EAAC,OAAO,EAAE,YAAY,CAAC;QACpC,MAAM,EAAE,IAAA,gBAAI,EAAC,OAAO,EAAE,WAAW,CAAC;KACnC,CAAC;AACJ,CAAC;AAPD,wCAOC","sourcesContent":["import { join } from 'node:path';\n\nimport type { DaemonPaths } from './types.js';\n\n/**\n * Resolve paths for daemon state files within the given data directory.\n *\n * @param dataDir - The base data directory (e.g. oclif config.dataDir).\n * @returns Resolved paths for socket, PID file, log file, and database file.\n */\nexport function getDaemonPaths(dataDir: string): DaemonPaths {\n return {\n socketPath: join(dataDir, 'daemon.sock'),\n pidPath: join(dataDir, 'daemon.pid'),\n logPath: join(dataDir, 'daemon.log'),\n dbPath: join(dataDir, 'wallet.db'),\n };\n}\n"]}
|
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import type { DaemonPaths } from
|
|
1
|
+
import type { DaemonPaths } from "./types.cjs";
|
|
2
2
|
/**
|
|
3
3
|
* Resolve paths for daemon state files within the given data directory.
|
|
4
4
|
*
|
|
@@ -6,4 +6,4 @@ import type { DaemonPaths } from './types.js';
|
|
|
6
6
|
* @returns Resolved paths for socket, PID file, log file, and database file.
|
|
7
7
|
*/
|
|
8
8
|
export declare function getDaemonPaths(dataDir: string): DaemonPaths;
|
|
9
|
-
//# sourceMappingURL=paths.d.
|
|
9
|
+
//# sourceMappingURL=paths.d.cts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"paths.d.cts","sourceRoot":"","sources":["../../src/daemon/paths.ts"],"names":[],"mappings":"AAEA,OAAO,KAAK,EAAE,WAAW,EAAE,oBAAmB;AAE9C;;;;;GAKG;AACH,wBAAgB,cAAc,CAAC,OAAO,EAAE,MAAM,GAAG,WAAW,CAO3D"}
|
|
@@ -0,0 +1,9 @@
|
|
|
1
|
+
import type { DaemonPaths } from "./types.mjs";
|
|
2
|
+
/**
|
|
3
|
+
* Resolve paths for daemon state files within the given data directory.
|
|
4
|
+
*
|
|
5
|
+
* @param dataDir - The base data directory (e.g. oclif config.dataDir).
|
|
6
|
+
* @returns Resolved paths for socket, PID file, log file, and database file.
|
|
7
|
+
*/
|
|
8
|
+
export declare function getDaemonPaths(dataDir: string): DaemonPaths;
|
|
9
|
+
//# sourceMappingURL=paths.d.mts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"paths.d.mts","sourceRoot":"","sources":["../../src/daemon/paths.ts"],"names":[],"mappings":"AAEA,OAAO,KAAK,EAAE,WAAW,EAAE,oBAAmB;AAE9C;;;;;GAKG;AACH,wBAAgB,cAAc,CAAC,OAAO,EAAE,MAAM,GAAG,WAAW,CAO3D"}
|
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import { join } from
|
|
1
|
+
import { join } from "node:path";
|
|
2
2
|
/**
|
|
3
3
|
* Resolve paths for daemon state files within the given data directory.
|
|
4
4
|
*
|
|
@@ -13,4 +13,4 @@ export function getDaemonPaths(dataDir) {
|
|
|
13
13
|
dbPath: join(dataDir, 'wallet.db'),
|
|
14
14
|
};
|
|
15
15
|
}
|
|
16
|
-
//# sourceMappingURL=paths.
|
|
16
|
+
//# sourceMappingURL=paths.mjs.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"paths.mjs","sourceRoot":"","sources":["../../src/daemon/paths.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,IAAI,EAAE,kBAAkB;AAIjC;;;;;GAKG;AACH,MAAM,UAAU,cAAc,CAAC,OAAe;IAC5C,OAAO;QACL,UAAU,EAAE,IAAI,CAAC,OAAO,EAAE,aAAa,CAAC;QACxC,OAAO,EAAE,IAAI,CAAC,OAAO,EAAE,YAAY,CAAC;QACpC,OAAO,EAAE,IAAI,CAAC,OAAO,EAAE,YAAY,CAAC;QACpC,MAAM,EAAE,IAAI,CAAC,OAAO,EAAE,WAAW,CAAC;KACnC,CAAC;AACJ,CAAC","sourcesContent":["import { join } from 'node:path';\n\nimport type { DaemonPaths } from './types.js';\n\n/**\n * Resolve paths for daemon state files within the given data directory.\n *\n * @param dataDir - The base data directory (e.g. oclif config.dataDir).\n * @returns Resolved paths for socket, PID file, log file, and database file.\n */\nexport function getDaemonPaths(dataDir: string): DaemonPaths {\n return {\n socketPath: join(dataDir, 'daemon.sock'),\n pidPath: join(dataDir, 'daemon.pid'),\n logPath: join(dataDir, 'daemon.log'),\n dbPath: join(dataDir, 'wallet.db'),\n };\n}\n"]}
|
|
@@ -0,0 +1,55 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
+
exports.promptPassword = exports.confirmSend = exports.confirmPurge = void 0;
|
|
4
|
+
/**
|
|
5
|
+
* Ask the user to confirm the destructive `daemon purge` operation.
|
|
6
|
+
*
|
|
7
|
+
* Wraps `@inquirer/confirm` in a dynamic import so this CommonJS-compiled
|
|
8
|
+
* package can interop with that ESM-only dependency, and so tests can mock
|
|
9
|
+
* the prompt without going through jest's ESM mock machinery.
|
|
10
|
+
*
|
|
11
|
+
* @returns True if the user confirmed.
|
|
12
|
+
*/
|
|
13
|
+
async function confirmPurge() {
|
|
14
|
+
const { default: confirm } = await import("@inquirer/confirm");
|
|
15
|
+
return confirm({
|
|
16
|
+
message: 'This will stop the daemon and delete all state. Continue?',
|
|
17
|
+
default: false,
|
|
18
|
+
});
|
|
19
|
+
}
|
|
20
|
+
exports.confirmPurge = confirmPurge;
|
|
21
|
+
/**
|
|
22
|
+
* Ask the user to confirm broadcasting a transaction. Used by `mm wallet send`
|
|
23
|
+
* when neither `--yes` nor `--dry-run` was passed. Same dynamic-import +
|
|
24
|
+
* ESM-interop pattern as {@link confirmPurge}. Defaults to `false` so an
|
|
25
|
+
* accidental bare Enter never broadcasts.
|
|
26
|
+
*
|
|
27
|
+
* @param summary - A human-readable description of the transaction to send
|
|
28
|
+
* (recipient, amount, network), shown above the prompt.
|
|
29
|
+
* @returns True if the user confirmed.
|
|
30
|
+
*/
|
|
31
|
+
async function confirmSend(summary) {
|
|
32
|
+
const { default: confirm } = await import("@inquirer/confirm");
|
|
33
|
+
return confirm({
|
|
34
|
+
message: `${summary}\nBroadcast this transaction?`,
|
|
35
|
+
default: false,
|
|
36
|
+
});
|
|
37
|
+
}
|
|
38
|
+
exports.confirmSend = confirmSend;
|
|
39
|
+
/**
|
|
40
|
+
* Prompt the user for the wallet password, with input masked. Used by
|
|
41
|
+
* `mm wallet unlock` when the user did not pass `--password` or set the
|
|
42
|
+
* `MM_WALLET_PASSWORD` env var. Same dynamic-import + ESM-interop pattern
|
|
43
|
+
* as {@link confirmPurge}.
|
|
44
|
+
*
|
|
45
|
+
* @returns The password the user typed.
|
|
46
|
+
*/
|
|
47
|
+
async function promptPassword() {
|
|
48
|
+
const { default: password } = await import("@inquirer/password");
|
|
49
|
+
return password({
|
|
50
|
+
message: 'Wallet password:',
|
|
51
|
+
mask: true,
|
|
52
|
+
});
|
|
53
|
+
}
|
|
54
|
+
exports.promptPassword = promptPassword;
|
|
55
|
+
//# sourceMappingURL=prompts.cjs.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"prompts.cjs","sourceRoot":"","sources":["../../src/daemon/prompts.ts"],"names":[],"mappings":";;;AAAA;;;;;;;;GAQG;AACI,KAAK,UAAU,YAAY;IAChC,MAAM,EAAE,OAAO,EAAE,OAAO,EAAE,GAAG,MAAM,MAAM,qBAAqB,CAAC;IAC/D,OAAO,OAAO,CAAC;QACb,OAAO,EAAE,2DAA2D;QACpE,OAAO,EAAE,KAAK;KACf,CAAC,CAAC;AACL,CAAC;AAND,oCAMC;AAED;;;;;;;;;GASG;AACI,KAAK,UAAU,WAAW,CAAC,OAAe;IAC/C,MAAM,EAAE,OAAO,EAAE,OAAO,EAAE,GAAG,MAAM,MAAM,qBAAqB,CAAC;IAC/D,OAAO,OAAO,CAAC;QACb,OAAO,EAAE,GAAG,OAAO,+BAA+B;QAClD,OAAO,EAAE,KAAK;KACf,CAAC,CAAC;AACL,CAAC;AAND,kCAMC;AAED;;;;;;;GAOG;AACI,KAAK,UAAU,cAAc;IAClC,MAAM,EAAE,OAAO,EAAE,QAAQ,EAAE,GAAG,MAAM,MAAM,sBAAsB,CAAC;IACjE,OAAO,QAAQ,CAAC;QACd,OAAO,EAAE,kBAAkB;QAC3B,IAAI,EAAE,IAAI;KACX,CAAC,CAAC;AACL,CAAC;AAND,wCAMC","sourcesContent":["/**\n * Ask the user to confirm the destructive `daemon purge` operation.\n *\n * Wraps `@inquirer/confirm` in a dynamic import so this CommonJS-compiled\n * package can interop with that ESM-only dependency, and so tests can mock\n * the prompt without going through jest's ESM mock machinery.\n *\n * @returns True if the user confirmed.\n */\nexport async function confirmPurge(): Promise<boolean> {\n const { default: confirm } = await import('@inquirer/confirm');\n return confirm({\n message: 'This will stop the daemon and delete all state. Continue?',\n default: false,\n });\n}\n\n/**\n * Ask the user to confirm broadcasting a transaction. Used by `mm wallet send`\n * when neither `--yes` nor `--dry-run` was passed. Same dynamic-import +\n * ESM-interop pattern as {@link confirmPurge}. Defaults to `false` so an\n * accidental bare Enter never broadcasts.\n *\n * @param summary - A human-readable description of the transaction to send\n * (recipient, amount, network), shown above the prompt.\n * @returns True if the user confirmed.\n */\nexport async function confirmSend(summary: string): Promise<boolean> {\n const { default: confirm } = await import('@inquirer/confirm');\n return confirm({\n message: `${summary}\\nBroadcast this transaction?`,\n default: false,\n });\n}\n\n/**\n * Prompt the user for the wallet password, with input masked. Used by\n * `mm wallet unlock` when the user did not pass `--password` or set the\n * `MM_WALLET_PASSWORD` env var. Same dynamic-import + ESM-interop pattern\n * as {@link confirmPurge}.\n *\n * @returns The password the user typed.\n */\nexport async function promptPassword(): Promise<string> {\n const { default: password } = await import('@inquirer/password');\n return password({\n message: 'Wallet password:',\n mask: true,\n });\n}\n"]}
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"prompts.d.cts","sourceRoot":"","sources":["../../src/daemon/prompts.ts"],"names":[],"mappings":"AAAA;;;;;;;;GAQG;AACH,wBAAsB,YAAY,IAAI,OAAO,CAAC,OAAO,CAAC,CAMrD;AAED;;;;;;;;;GASG;AACH,wBAAsB,WAAW,CAAC,OAAO,EAAE,MAAM,GAAG,OAAO,CAAC,OAAO,CAAC,CAMnE;AAED;;;;;;;GAOG;AACH,wBAAsB,cAAc,IAAI,OAAO,CAAC,MAAM,CAAC,CAMtD"}
|
|
@@ -0,0 +1,31 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Ask the user to confirm the destructive `daemon purge` operation.
|
|
3
|
+
*
|
|
4
|
+
* Wraps `@inquirer/confirm` in a dynamic import so this CommonJS-compiled
|
|
5
|
+
* package can interop with that ESM-only dependency, and so tests can mock
|
|
6
|
+
* the prompt without going through jest's ESM mock machinery.
|
|
7
|
+
*
|
|
8
|
+
* @returns True if the user confirmed.
|
|
9
|
+
*/
|
|
10
|
+
export declare function confirmPurge(): Promise<boolean>;
|
|
11
|
+
/**
|
|
12
|
+
* Ask the user to confirm broadcasting a transaction. Used by `mm wallet send`
|
|
13
|
+
* when neither `--yes` nor `--dry-run` was passed. Same dynamic-import +
|
|
14
|
+
* ESM-interop pattern as {@link confirmPurge}. Defaults to `false` so an
|
|
15
|
+
* accidental bare Enter never broadcasts.
|
|
16
|
+
*
|
|
17
|
+
* @param summary - A human-readable description of the transaction to send
|
|
18
|
+
* (recipient, amount, network), shown above the prompt.
|
|
19
|
+
* @returns True if the user confirmed.
|
|
20
|
+
*/
|
|
21
|
+
export declare function confirmSend(summary: string): Promise<boolean>;
|
|
22
|
+
/**
|
|
23
|
+
* Prompt the user for the wallet password, with input masked. Used by
|
|
24
|
+
* `mm wallet unlock` when the user did not pass `--password` or set the
|
|
25
|
+
* `MM_WALLET_PASSWORD` env var. Same dynamic-import + ESM-interop pattern
|
|
26
|
+
* as {@link confirmPurge}.
|
|
27
|
+
*
|
|
28
|
+
* @returns The password the user typed.
|
|
29
|
+
*/
|
|
30
|
+
export declare function promptPassword(): Promise<string>;
|
|
31
|
+
//# sourceMappingURL=prompts.d.mts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"prompts.d.mts","sourceRoot":"","sources":["../../src/daemon/prompts.ts"],"names":[],"mappings":"AAAA;;;;;;;;GAQG;AACH,wBAAsB,YAAY,IAAI,OAAO,CAAC,OAAO,CAAC,CAMrD;AAED;;;;;;;;;GASG;AACH,wBAAsB,WAAW,CAAC,OAAO,EAAE,MAAM,GAAG,OAAO,CAAC,OAAO,CAAC,CAMnE;AAED;;;;;;;GAOG;AACH,wBAAsB,cAAc,IAAI,OAAO,CAAC,MAAM,CAAC,CAMtD"}
|
|
@@ -8,7 +8,7 @@
|
|
|
8
8
|
* @returns True if the user confirmed.
|
|
9
9
|
*/
|
|
10
10
|
export async function confirmPurge() {
|
|
11
|
-
const { default: confirm } = await import(
|
|
11
|
+
const { default: confirm } = await import("@inquirer/confirm");
|
|
12
12
|
return confirm({
|
|
13
13
|
message: 'This will stop the daemon and delete all state. Continue?',
|
|
14
14
|
default: false,
|
|
@@ -25,7 +25,7 @@ export async function confirmPurge() {
|
|
|
25
25
|
* @returns True if the user confirmed.
|
|
26
26
|
*/
|
|
27
27
|
export async function confirmSend(summary) {
|
|
28
|
-
const { default: confirm } = await import(
|
|
28
|
+
const { default: confirm } = await import("@inquirer/confirm");
|
|
29
29
|
return confirm({
|
|
30
30
|
message: `${summary}\nBroadcast this transaction?`,
|
|
31
31
|
default: false,
|
|
@@ -40,10 +40,10 @@ export async function confirmSend(summary) {
|
|
|
40
40
|
* @returns The password the user typed.
|
|
41
41
|
*/
|
|
42
42
|
export async function promptPassword() {
|
|
43
|
-
const { default: password } = await import(
|
|
43
|
+
const { default: password } = await import("@inquirer/password");
|
|
44
44
|
return password({
|
|
45
45
|
message: 'Wallet password:',
|
|
46
46
|
mask: true,
|
|
47
47
|
});
|
|
48
48
|
}
|
|
49
|
-
//# sourceMappingURL=prompts.
|
|
49
|
+
//# sourceMappingURL=prompts.mjs.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"prompts.mjs","sourceRoot":"","sources":["../../src/daemon/prompts.ts"],"names":[],"mappings":"AAAA;;;;;;;;GAQG;AACH,MAAM,CAAC,KAAK,UAAU,YAAY;IAChC,MAAM,EAAE,OAAO,EAAE,OAAO,EAAE,GAAG,MAAM,MAAM,qBAAqB,CAAC;IAC/D,OAAO,OAAO,CAAC;QACb,OAAO,EAAE,2DAA2D;QACpE,OAAO,EAAE,KAAK;KACf,CAAC,CAAC;AACL,CAAC;AAED;;;;;;;;;GASG;AACH,MAAM,CAAC,KAAK,UAAU,WAAW,CAAC,OAAe;IAC/C,MAAM,EAAE,OAAO,EAAE,OAAO,EAAE,GAAG,MAAM,MAAM,qBAAqB,CAAC;IAC/D,OAAO,OAAO,CAAC;QACb,OAAO,EAAE,GAAG,OAAO,+BAA+B;QAClD,OAAO,EAAE,KAAK;KACf,CAAC,CAAC;AACL,CAAC;AAED;;;;;;;GAOG;AACH,MAAM,CAAC,KAAK,UAAU,cAAc;IAClC,MAAM,EAAE,OAAO,EAAE,QAAQ,EAAE,GAAG,MAAM,MAAM,sBAAsB,CAAC;IACjE,OAAO,QAAQ,CAAC;QACd,OAAO,EAAE,kBAAkB;QAC3B,IAAI,EAAE,IAAI;KACX,CAAC,CAAC;AACL,CAAC","sourcesContent":["/**\n * Ask the user to confirm the destructive `daemon purge` operation.\n *\n * Wraps `@inquirer/confirm` in a dynamic import so this CommonJS-compiled\n * package can interop with that ESM-only dependency, and so tests can mock\n * the prompt without going through jest's ESM mock machinery.\n *\n * @returns True if the user confirmed.\n */\nexport async function confirmPurge(): Promise<boolean> {\n const { default: confirm } = await import('@inquirer/confirm');\n return confirm({\n message: 'This will stop the daemon and delete all state. Continue?',\n default: false,\n });\n}\n\n/**\n * Ask the user to confirm broadcasting a transaction. Used by `mm wallet send`\n * when neither `--yes` nor `--dry-run` was passed. Same dynamic-import +\n * ESM-interop pattern as {@link confirmPurge}. Defaults to `false` so an\n * accidental bare Enter never broadcasts.\n *\n * @param summary - A human-readable description of the transaction to send\n * (recipient, amount, network), shown above the prompt.\n * @returns True if the user confirmed.\n */\nexport async function confirmSend(summary: string): Promise<boolean> {\n const { default: confirm } = await import('@inquirer/confirm');\n return confirm({\n message: `${summary}\\nBroadcast this transaction?`,\n default: false,\n });\n}\n\n/**\n * Prompt the user for the wallet password, with input masked. Used by\n * `mm wallet unlock` when the user did not pass `--password` or set the\n * `MM_WALLET_PASSWORD` env var. Same dynamic-import + ESM-interop pattern\n * as {@link confirmPurge}.\n *\n * @returns The password the user typed.\n */\nexport async function promptPassword(): Promise<string> {\n const { default: password } = await import('@inquirer/password');\n return password({\n message: 'Wallet password:',\n mask: true,\n });\n}\n"]}
|