@shieldedtech/moth-wallet 0.2.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +62 -0
- package/dist/contract/args-parser.d.ts +29 -0
- package/dist/contract/args-parser.d.ts.map +1 -0
- package/dist/contract/args-parser.js +123 -0
- package/dist/contract/args-parser.js.map +1 -0
- package/dist/contract/artifact-loader.d.ts +26 -0
- package/dist/contract/artifact-loader.d.ts.map +1 -0
- package/dist/contract/artifact-loader.js +129 -0
- package/dist/contract/artifact-loader.js.map +1 -0
- package/dist/contract/call.d.ts +32 -0
- package/dist/contract/call.d.ts.map +1 -0
- package/dist/contract/call.js +245 -0
- package/dist/contract/call.js.map +1 -0
- package/dist/contract/deploy.d.ts +36 -0
- package/dist/contract/deploy.d.ts.map +1 -0
- package/dist/contract/deploy.js +388 -0
- package/dist/contract/deploy.js.map +1 -0
- package/dist/contract/fungible-token.d.ts +40 -0
- package/dist/contract/fungible-token.d.ts.map +1 -0
- package/dist/contract/fungible-token.js +88 -0
- package/dist/contract/fungible-token.js.map +1 -0
- package/dist/contract/initial-private-state.d.ts +18 -0
- package/dist/contract/initial-private-state.d.ts.map +1 -0
- package/dist/contract/initial-private-state.js +44 -0
- package/dist/contract/initial-private-state.js.map +1 -0
- package/dist/contract/maintenance.d.ts +72 -0
- package/dist/contract/maintenance.d.ts.map +1 -0
- package/dist/contract/maintenance.js +430 -0
- package/dist/contract/maintenance.js.map +1 -0
- package/dist/contract/state.d.ts +16 -0
- package/dist/contract/state.d.ts.map +1 -0
- package/dist/contract/state.js +18 -0
- package/dist/contract/state.js.map +1 -0
- package/dist/contract/witness-loader.d.ts +3 -0
- package/dist/contract/witness-loader.d.ts.map +1 -0
- package/dist/contract/witness-loader.js +27 -0
- package/dist/contract/witness-loader.js.map +1 -0
- package/dist/daemon/api-keys.d.ts +66 -0
- package/dist/daemon/api-keys.d.ts.map +1 -0
- package/dist/daemon/api-keys.js +222 -0
- package/dist/daemon/api-keys.js.map +1 -0
- package/dist/daemon/audit-log.d.ts +65 -0
- package/dist/daemon/audit-log.d.ts.map +1 -0
- package/dist/daemon/audit-log.js +73 -0
- package/dist/daemon/audit-log.js.map +1 -0
- package/dist/daemon/client.d.ts +63 -0
- package/dist/daemon/client.d.ts.map +1 -0
- package/dist/daemon/client.js +214 -0
- package/dist/daemon/client.js.map +1 -0
- package/dist/daemon/confirmation-queue.d.ts +46 -0
- package/dist/daemon/confirmation-queue.d.ts.map +1 -0
- package/dist/daemon/confirmation-queue.js +92 -0
- package/dist/daemon/confirmation-queue.js.map +1 -0
- package/dist/daemon/index.d.ts +23 -0
- package/dist/daemon/index.d.ts.map +1 -0
- package/dist/daemon/index.js +26 -0
- package/dist/daemon/index.js.map +1 -0
- package/dist/daemon/protocol.d.ts +40 -0
- package/dist/daemon/protocol.d.ts.map +1 -0
- package/dist/daemon/protocol.js +104 -0
- package/dist/daemon/protocol.js.map +1 -0
- package/dist/daemon/server.d.ts +158 -0
- package/dist/daemon/server.d.ts.map +1 -0
- package/dist/daemon/server.js +297 -0
- package/dist/daemon/server.js.map +1 -0
- package/dist/daemon/wallet-handlers.d.ts +37 -0
- package/dist/daemon/wallet-handlers.d.ts.map +1 -0
- package/dist/daemon/wallet-handlers.js +533 -0
- package/dist/daemon/wallet-handlers.js.map +1 -0
- package/dist/daemon/wallet-rpc-parsers.d.ts +14 -0
- package/dist/daemon/wallet-rpc-parsers.d.ts.map +1 -0
- package/dist/daemon/wallet-rpc-parsers.js +259 -0
- package/dist/daemon/wallet-rpc-parsers.js.map +1 -0
- package/dist/daemon/wallet-rpc-types.d.ts +138 -0
- package/dist/daemon/wallet-rpc-types.d.ts.map +1 -0
- package/dist/daemon/wallet-rpc-types.js +11 -0
- package/dist/daemon/wallet-rpc-types.js.map +1 -0
- package/dist/diagnostics/fs-timing-store.d.ts +29 -0
- package/dist/diagnostics/fs-timing-store.d.ts.map +1 -0
- package/dist/diagnostics/fs-timing-store.js +81 -0
- package/dist/diagnostics/fs-timing-store.js.map +1 -0
- package/dist/diagnostics/timings.d.ts +64 -0
- package/dist/diagnostics/timings.d.ts.map +1 -0
- package/dist/diagnostics/timings.js +100 -0
- package/dist/diagnostics/timings.js.map +1 -0
- package/dist/index.d.ts +37 -0
- package/dist/index.d.ts.map +1 -0
- package/dist/index.js +47 -0
- package/dist/index.js.map +1 -0
- package/dist/network/indexer-client.d.ts +66 -0
- package/dist/network/indexer-client.d.ts.map +1 -0
- package/dist/network/indexer-client.js +112 -0
- package/dist/network/indexer-client.js.map +1 -0
- package/dist/network/node-client.d.ts +27 -0
- package/dist/network/node-client.d.ts.map +1 -0
- package/dist/network/node-client.js +94 -0
- package/dist/network/node-client.js.map +1 -0
- package/dist/proof/client.d.ts +15 -0
- package/dist/proof/client.d.ts.map +1 -0
- package/dist/proof/client.js +77 -0
- package/dist/proof/client.js.map +1 -0
- package/dist/proof/provider.d.ts +12 -0
- package/dist/proof/provider.d.ts.map +1 -0
- package/dist/proof/provider.js +96 -0
- package/dist/proof/provider.js.map +1 -0
- package/dist/providers/index.d.ts +2 -0
- package/dist/providers/index.d.ts.map +1 -0
- package/dist/providers/index.js +2 -0
- package/dist/providers/index.js.map +1 -0
- package/dist/providers/midnight-provider.d.ts +11 -0
- package/dist/providers/midnight-provider.d.ts.map +1 -0
- package/dist/providers/midnight-provider.js +30 -0
- package/dist/providers/midnight-provider.js.map +1 -0
- package/dist/storage/adapter.d.ts +8 -0
- package/dist/storage/adapter.d.ts.map +1 -0
- package/dist/storage/adapter.js +2 -0
- package/dist/storage/adapter.js.map +1 -0
- package/dist/storage/fs-adapter.d.ts +14 -0
- package/dist/storage/fs-adapter.d.ts.map +1 -0
- package/dist/storage/fs-adapter.js +126 -0
- package/dist/storage/fs-adapter.js.map +1 -0
- package/dist/storage/safe-path.d.ts +13 -0
- package/dist/storage/safe-path.d.ts.map +1 -0
- package/dist/storage/safe-path.js +35 -0
- package/dist/storage/safe-path.js.map +1 -0
- package/dist/sync/activity.d.ts +53 -0
- package/dist/sync/activity.d.ts.map +1 -0
- package/dist/sync/activity.js +92 -0
- package/dist/sync/activity.js.map +1 -0
- package/dist/sync/dust-registration-estimate.d.ts +54 -0
- package/dist/sync/dust-registration-estimate.d.ts.map +1 -0
- package/dist/sync/dust-registration-estimate.js +103 -0
- package/dist/sync/dust-registration-estimate.js.map +1 -0
- package/dist/sync/node-sync-store.d.ts +10 -0
- package/dist/sync/node-sync-store.d.ts.map +1 -0
- package/dist/sync/node-sync-store.js +42 -0
- package/dist/sync/node-sync-store.js.map +1 -0
- package/dist/sync/operations.d.ts +138 -0
- package/dist/sync/operations.d.ts.map +1 -0
- package/dist/sync/operations.js +395 -0
- package/dist/sync/operations.js.map +1 -0
- package/dist/sync/preseed-parts.d.ts +18 -0
- package/dist/sync/preseed-parts.d.ts.map +1 -0
- package/dist/sync/preseed-parts.js +33 -0
- package/dist/sync/preseed-parts.js.map +1 -0
- package/dist/sync/preseed.d.ts +95 -0
- package/dist/sync/preseed.d.ts.map +1 -0
- package/dist/sync/preseed.js +365 -0
- package/dist/sync/preseed.js.map +1 -0
- package/dist/sync/progress.d.ts +45 -0
- package/dist/sync/progress.d.ts.map +1 -0
- package/dist/sync/progress.js +51 -0
- package/dist/sync/progress.js.map +1 -0
- package/dist/sync/sdk-dedup.d.ts +53 -0
- package/dist/sync/sdk-dedup.d.ts.map +1 -0
- package/dist/sync/sdk-dedup.js +134 -0
- package/dist/sync/sdk-dedup.js.map +1 -0
- package/dist/sync/sync-store.d.ts +33 -0
- package/dist/sync/sync-store.d.ts.map +1 -0
- package/dist/sync/sync-store.js +45 -0
- package/dist/sync/sync-store.js.map +1 -0
- package/dist/sync/wallet-sync.d.ts +153 -0
- package/dist/sync/wallet-sync.d.ts.map +1 -0
- package/dist/sync/wallet-sync.js +943 -0
- package/dist/sync/wallet-sync.js.map +1 -0
- package/dist/types/errors.d.ts +18 -0
- package/dist/types/errors.d.ts.map +1 -0
- package/dist/types/errors.js +33 -0
- package/dist/types/errors.js.map +1 -0
- package/dist/types/exit-codes.d.ts +8 -0
- package/dist/types/exit-codes.d.ts.map +1 -0
- package/dist/types/exit-codes.js +7 -0
- package/dist/types/exit-codes.js.map +1 -0
- package/dist/types/index.d.ts +6 -0
- package/dist/types/index.d.ts.map +1 -0
- package/dist/types/index.js +3 -0
- package/dist/types/index.js.map +1 -0
- package/dist/types/network.d.ts +65 -0
- package/dist/types/network.d.ts.map +1 -0
- package/dist/types/network.js +108 -0
- package/dist/types/network.js.map +1 -0
- package/dist/types/tokens.d.ts +3 -0
- package/dist/types/tokens.d.ts.map +1 -0
- package/dist/types/tokens.js +11 -0
- package/dist/types/tokens.js.map +1 -0
- package/dist/types/transaction.d.ts +13 -0
- package/dist/types/transaction.d.ts.map +1 -0
- package/dist/types/transaction.js +2 -0
- package/dist/types/transaction.js.map +1 -0
- package/dist/types/wallet.d.ts +82 -0
- package/dist/types/wallet.d.ts.map +1 -0
- package/dist/types/wallet.js +2 -0
- package/dist/types/wallet.js.map +1 -0
- package/dist/wallet/address-validate.d.ts +7 -0
- package/dist/wallet/address-validate.d.ts.map +1 -0
- package/dist/wallet/address-validate.js +28 -0
- package/dist/wallet/address-validate.js.map +1 -0
- package/dist/wallet/address.d.ts +32 -0
- package/dist/wallet/address.d.ts.map +1 -0
- package/dist/wallet/address.js +107 -0
- package/dist/wallet/address.js.map +1 -0
- package/dist/wallet/app-secret.d.ts +15 -0
- package/dist/wallet/app-secret.d.ts.map +1 -0
- package/dist/wallet/app-secret.js +45 -0
- package/dist/wallet/app-secret.js.map +1 -0
- package/dist/wallet/balance-format.d.ts +12 -0
- package/dist/wallet/balance-format.d.ts.map +1 -0
- package/dist/wallet/balance-format.js +51 -0
- package/dist/wallet/balance-format.js.map +1 -0
- package/dist/wallet/batch-transfer.d.ts +36 -0
- package/dist/wallet/batch-transfer.d.ts.map +1 -0
- package/dist/wallet/batch-transfer.js +93 -0
- package/dist/wallet/batch-transfer.js.map +1 -0
- package/dist/wallet/keystore.d.ts +16 -0
- package/dist/wallet/keystore.d.ts.map +1 -0
- package/dist/wallet/keystore.js +76 -0
- package/dist/wallet/keystore.js.map +1 -0
- package/dist/wallet/manager.d.ts +77 -0
- package/dist/wallet/manager.d.ts.map +1 -0
- package/dist/wallet/manager.js +474 -0
- package/dist/wallet/manager.js.map +1 -0
- package/dist/wallet/mnemonic.d.ts +5 -0
- package/dist/wallet/mnemonic.d.ts.map +1 -0
- package/dist/wallet/mnemonic.js +28 -0
- package/dist/wallet/mnemonic.js.map +1 -0
- package/dist/wallet/sign-message.d.ts +20 -0
- package/dist/wallet/sign-message.d.ts.map +1 -0
- package/dist/wallet/sign-message.js +58 -0
- package/dist/wallet/sign-message.js.map +1 -0
- package/package.json +55 -0
|
@@ -0,0 +1,214 @@
|
|
|
1
|
+
// Daemon client: opens a Unix-domain socket connection, performs the
|
|
2
|
+
// version handshake, exposes a typed call() interface and clean shutdown.
|
|
3
|
+
//
|
|
4
|
+
// connectDaemon() is intentionally forgiving — if there's no socket file,
|
|
5
|
+
// or the connect is refused, it returns null instead of throwing. Callers
|
|
6
|
+
// (the CLI) treat null as "no daemon available, run standalone", which
|
|
7
|
+
// keeps the daemon optional rather than a hard dependency.
|
|
8
|
+
import { createConnection } from 'node:net';
|
|
9
|
+
import { randomUUID } from 'node:crypto';
|
|
10
|
+
import { encodeFrame, FrameDecoder, PROTOCOL_VERSION, DaemonProtocolError, } from './protocol.js';
|
|
11
|
+
/**
|
|
12
|
+
* Try to connect to the daemon at the given Unix-socket path. Stage-1
|
|
13
|
+
* entry point — kept for backwards compatibility. For TCP transports
|
|
14
|
+
* use `connectDaemonTcp(host, port)` or the unified
|
|
15
|
+
* `connectDaemonBind(bind)`.
|
|
16
|
+
*
|
|
17
|
+
* Returns:
|
|
18
|
+
* - DaemonClient on successful connect + handshake
|
|
19
|
+
* - null if the file doesn't exist, the connect is refused, or the
|
|
20
|
+
* handshake reports an incompatible protocol version
|
|
21
|
+
*
|
|
22
|
+
* Throws only on genuinely-unexpected conditions (filesystem error,
|
|
23
|
+
* malformed daemon response). Network-style failures are folded into
|
|
24
|
+
* null so the CLI can fall back to standalone without a try/catch.
|
|
25
|
+
*/
|
|
26
|
+
export async function connectDaemon(socketPath, opts = {}) {
|
|
27
|
+
return connectDaemonBind({ transport: 'unix', socketPath }, opts);
|
|
28
|
+
}
|
|
29
|
+
/**
|
|
30
|
+
* Stage-2 entry point. Connect to a daemon listening on loopback TCP
|
|
31
|
+
* (or, at stage 3, a TLS-terminating reverse proxy in front of the
|
|
32
|
+
* daemon's loopback bind). Same fall-back-to-null semantics as
|
|
33
|
+
* `connectDaemon`.
|
|
34
|
+
*/
|
|
35
|
+
export async function connectDaemonTcp(host, port, opts = {}) {
|
|
36
|
+
return connectDaemonBind({ transport: 'tcp', host, port }, opts);
|
|
37
|
+
}
|
|
38
|
+
/**
|
|
39
|
+
* Transport-agnostic entry point. Both `connectDaemon` and
|
|
40
|
+
* `connectDaemonTcp` route through here. The handshake + dispatcher
|
|
41
|
+
* setup is identical across transports — only the underlying socket
|
|
42
|
+
* factory differs.
|
|
43
|
+
*/
|
|
44
|
+
export async function connectDaemonBind(bind, opts = {}) {
|
|
45
|
+
const log = opts.onLog ?? (() => { });
|
|
46
|
+
const defaultTimeoutMs = opts.defaultTimeoutMs ?? 10_000;
|
|
47
|
+
const sock = await openSocket(bind, log);
|
|
48
|
+
if (!sock)
|
|
49
|
+
return null;
|
|
50
|
+
const dispatcher = new ClientDispatcher(sock, defaultTimeoutMs, log);
|
|
51
|
+
let handshake;
|
|
52
|
+
try {
|
|
53
|
+
handshake = await dispatcher.call('version', undefined, {
|
|
54
|
+
timeoutMs: 2000,
|
|
55
|
+
});
|
|
56
|
+
}
|
|
57
|
+
catch (err) {
|
|
58
|
+
log('warn', `daemon handshake failed: ${err.message}`);
|
|
59
|
+
dispatcher.close();
|
|
60
|
+
return null;
|
|
61
|
+
}
|
|
62
|
+
if (handshake.protocol !== PROTOCOL_VERSION) {
|
|
63
|
+
log('warn', `daemon speaks protocol ${handshake.protocol}; client expects ${PROTOCOL_VERSION}`);
|
|
64
|
+
dispatcher.close();
|
|
65
|
+
return null;
|
|
66
|
+
}
|
|
67
|
+
// Stage-2 auth handshake. Only performed when the caller passes
|
|
68
|
+
// a token; daemons running without an auth handler (typical Unix
|
|
69
|
+
// case) will reject an `auth` call with METHOD_NOT_FOUND, so we
|
|
70
|
+
// gate on the token's presence rather than probing.
|
|
71
|
+
let apiKeyId;
|
|
72
|
+
if (opts.token) {
|
|
73
|
+
try {
|
|
74
|
+
const authResult = await dispatcher.call('auth', { token: opts.token }, { timeoutMs: 2000 });
|
|
75
|
+
apiKeyId = authResult.apiKeyId;
|
|
76
|
+
}
|
|
77
|
+
catch (err) {
|
|
78
|
+
const code = err instanceof DaemonProtocolError ? err.code : 'INTERNAL_ERROR';
|
|
79
|
+
log('warn', `daemon auth failed (${code}): ${err.message}`);
|
|
80
|
+
dispatcher.close();
|
|
81
|
+
return null;
|
|
82
|
+
}
|
|
83
|
+
}
|
|
84
|
+
return {
|
|
85
|
+
call: dispatcher.call.bind(dispatcher),
|
|
86
|
+
close: dispatcher.close.bind(dispatcher),
|
|
87
|
+
get closed() {
|
|
88
|
+
return dispatcher.closed;
|
|
89
|
+
},
|
|
90
|
+
daemonVersion: handshake.daemon,
|
|
91
|
+
apiKeyId,
|
|
92
|
+
};
|
|
93
|
+
}
|
|
94
|
+
function openSocket(bind, log) {
|
|
95
|
+
const target = bind.transport === 'unix'
|
|
96
|
+
? bind.socketPath
|
|
97
|
+
: `${bind.host}:${bind.port}`;
|
|
98
|
+
return new Promise((resolve) => {
|
|
99
|
+
const sock = bind.transport === 'unix'
|
|
100
|
+
? createConnection(bind.socketPath)
|
|
101
|
+
: createConnection({ host: bind.host, port: bind.port });
|
|
102
|
+
const onConnect = () => {
|
|
103
|
+
sock.off('error', onError);
|
|
104
|
+
resolve(sock);
|
|
105
|
+
};
|
|
106
|
+
const onError = (err) => {
|
|
107
|
+
sock.off('connect', onConnect);
|
|
108
|
+
sock.destroy();
|
|
109
|
+
// ENOENT (no socket file) and ECONNREFUSED (no listener) both
|
|
110
|
+
// mean "no daemon available" rather than a real error. Apply
|
|
111
|
+
// the same fall-back-to-null to both transports.
|
|
112
|
+
if (err.code === 'ENOENT' || err.code === 'ECONNREFUSED') {
|
|
113
|
+
log('info', `no daemon at ${target} (${err.code})`);
|
|
114
|
+
}
|
|
115
|
+
else {
|
|
116
|
+
log('warn', `daemon connect failed: ${err.message}`);
|
|
117
|
+
}
|
|
118
|
+
resolve(null);
|
|
119
|
+
};
|
|
120
|
+
sock.once('connect', onConnect);
|
|
121
|
+
sock.once('error', onError);
|
|
122
|
+
});
|
|
123
|
+
}
|
|
124
|
+
class ClientDispatcher {
|
|
125
|
+
closed = false;
|
|
126
|
+
sock;
|
|
127
|
+
defaultTimeoutMs;
|
|
128
|
+
decoder = new FrameDecoder();
|
|
129
|
+
pending = new Map();
|
|
130
|
+
log;
|
|
131
|
+
constructor(sock, defaultTimeoutMs, log) {
|
|
132
|
+
this.sock = sock;
|
|
133
|
+
this.defaultTimeoutMs = defaultTimeoutMs;
|
|
134
|
+
this.log = log;
|
|
135
|
+
sock.on('data', (chunk) => this.onData(chunk));
|
|
136
|
+
sock.on('close', () => this.failAllPending(new DaemonProtocolError('CLOSED', 'daemon connection closed')));
|
|
137
|
+
sock.on('error', (err) => {
|
|
138
|
+
this.log('warn', `daemon socket error: ${err.message}`);
|
|
139
|
+
this.failAllPending(new DaemonProtocolError('CLOSED', err.message));
|
|
140
|
+
});
|
|
141
|
+
}
|
|
142
|
+
call(method, params, opts = {}) {
|
|
143
|
+
if (this.closed) {
|
|
144
|
+
return Promise.reject(new DaemonProtocolError('CLOSED', 'daemon client is closed'));
|
|
145
|
+
}
|
|
146
|
+
const id = randomUUID();
|
|
147
|
+
const timeoutMs = opts.timeoutMs ?? this.defaultTimeoutMs;
|
|
148
|
+
return new Promise((resolve, reject) => {
|
|
149
|
+
const timer = setTimeout(() => {
|
|
150
|
+
this.pending.delete(id);
|
|
151
|
+
reject(new DaemonProtocolError('TIMEOUT', `call ${method} timed out after ${timeoutMs}ms`));
|
|
152
|
+
}, timeoutMs);
|
|
153
|
+
this.pending.set(id, {
|
|
154
|
+
resolve: resolve,
|
|
155
|
+
reject,
|
|
156
|
+
timer,
|
|
157
|
+
});
|
|
158
|
+
try {
|
|
159
|
+
this.sock.write(encodeFrame({ id, type: 'request', method, params }));
|
|
160
|
+
}
|
|
161
|
+
catch (err) {
|
|
162
|
+
clearTimeout(timer);
|
|
163
|
+
this.pending.delete(id);
|
|
164
|
+
reject(err);
|
|
165
|
+
}
|
|
166
|
+
});
|
|
167
|
+
}
|
|
168
|
+
close() {
|
|
169
|
+
if (this.closed)
|
|
170
|
+
return;
|
|
171
|
+
this.closed = true;
|
|
172
|
+
this.failAllPending(new DaemonProtocolError('CLOSED', 'client closed'));
|
|
173
|
+
this.sock.destroy();
|
|
174
|
+
}
|
|
175
|
+
onData(chunk) {
|
|
176
|
+
let frames;
|
|
177
|
+
try {
|
|
178
|
+
frames = this.decoder.push(chunk);
|
|
179
|
+
}
|
|
180
|
+
catch (err) {
|
|
181
|
+
this.log('warn', `daemon sent malformed frame: ${err.message}`);
|
|
182
|
+
this.close();
|
|
183
|
+
return;
|
|
184
|
+
}
|
|
185
|
+
for (const frame of frames) {
|
|
186
|
+
if (frame.type !== 'response') {
|
|
187
|
+
this.log('warn', `daemon sent unexpected frame type ${frame.type}`);
|
|
188
|
+
continue;
|
|
189
|
+
}
|
|
190
|
+
const waiter = this.pending.get(frame.id);
|
|
191
|
+
if (!waiter) {
|
|
192
|
+
// Unsolicited response — possible if a timeout already fired.
|
|
193
|
+
// Drop silently rather than warn; that's expected under timeout.
|
|
194
|
+
continue;
|
|
195
|
+
}
|
|
196
|
+
this.pending.delete(frame.id);
|
|
197
|
+
clearTimeout(waiter.timer);
|
|
198
|
+
if (frame.error) {
|
|
199
|
+
waiter.reject(new DaemonProtocolError(frame.error.code, frame.error.message));
|
|
200
|
+
}
|
|
201
|
+
else {
|
|
202
|
+
waiter.resolve(frame.result);
|
|
203
|
+
}
|
|
204
|
+
}
|
|
205
|
+
}
|
|
206
|
+
failAllPending(err) {
|
|
207
|
+
for (const [, waiter] of this.pending) {
|
|
208
|
+
clearTimeout(waiter.timer);
|
|
209
|
+
waiter.reject(err);
|
|
210
|
+
}
|
|
211
|
+
this.pending.clear();
|
|
212
|
+
}
|
|
213
|
+
}
|
|
214
|
+
//# sourceMappingURL=client.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"client.js","sourceRoot":"","sources":["../../src/daemon/client.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1,46 @@
|
|
|
1
|
+
export type ConfirmationRequest = {
|
|
2
|
+
readonly id: string;
|
|
3
|
+
readonly summary: string;
|
|
4
|
+
readonly details?: readonly string[];
|
|
5
|
+
};
|
|
6
|
+
export interface ConfirmationQueueOptions {
|
|
7
|
+
/**
|
|
8
|
+
* When true, every request() resolves immediately with true. Intended
|
|
9
|
+
* for non-interactive contexts (tests, server-mode daemons). The
|
|
10
|
+
* onAutoApprove callback, if provided, is invoked for each
|
|
11
|
+
* auto-approval so callers can log it.
|
|
12
|
+
*/
|
|
13
|
+
readonly autoApprove?: boolean;
|
|
14
|
+
/** Hook called for every auto-approved request — useful for audit. */
|
|
15
|
+
readonly onAutoApprove?: (req: ConfirmationRequest) => void;
|
|
16
|
+
}
|
|
17
|
+
export declare class ConfirmationQueue {
|
|
18
|
+
private readonly items;
|
|
19
|
+
private readonly listeners;
|
|
20
|
+
private readonly autoApprove;
|
|
21
|
+
private readonly onAutoApprove?;
|
|
22
|
+
constructor(opts?: ConfirmationQueueOptions);
|
|
23
|
+
/** Push a request and resolve once the user answers (or immediately
|
|
24
|
+
* if autoApprove is enabled). */
|
|
25
|
+
request(summary: string, details?: readonly string[]): Promise<boolean>;
|
|
26
|
+
/** Head of the queue, or null when empty. The modal uses this to
|
|
27
|
+
* decide whether to render. */
|
|
28
|
+
peek(): ConfirmationRequest | null;
|
|
29
|
+
/** Resolve the head with the given verdict and advance. No-op when
|
|
30
|
+
* empty. */
|
|
31
|
+
resolve(approved: boolean): void;
|
|
32
|
+
/** Resolve every pending request as denied. Used on shutdown so any
|
|
33
|
+
* in-flight RPC calls fail cleanly instead of hanging the daemon. */
|
|
34
|
+
drainAsDenied(): void;
|
|
35
|
+
/** Subscribe to "queue changed" notifications. Returns an
|
|
36
|
+
* unsubscribe function. */
|
|
37
|
+
subscribe(listener: () => void): () => void;
|
|
38
|
+
/** Current depth; primarily for tests and logs. */
|
|
39
|
+
get size(): number;
|
|
40
|
+
/** Whether the queue is in auto-approve mode. The audit log uses
|
|
41
|
+
* this to record `auto-approve` vs `user-approve` decisions on
|
|
42
|
+
* the same code path. */
|
|
43
|
+
get isAutoApprove(): boolean;
|
|
44
|
+
private notify;
|
|
45
|
+
}
|
|
46
|
+
//# sourceMappingURL=confirmation-queue.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"confirmation-queue.d.ts","sourceRoot":"","sources":["../../src/daemon/confirmation-queue.ts"],"names":[],"mappings":"AAoBA,MAAM,MAAM,mBAAmB,GAAG;IAChC,QAAQ,CAAC,EAAE,EAAE,MAAM,CAAC;IACpB,QAAQ,CAAC,OAAO,EAAE,MAAM,CAAC;IACzB,QAAQ,CAAC,OAAO,CAAC,EAAE,SAAS,MAAM,EAAE,CAAC;CACtC,CAAC;AAMF,MAAM,WAAW,wBAAwB;IACvC;;;;;OAKG;IACH,QAAQ,CAAC,WAAW,CAAC,EAAE,OAAO,CAAC;IAC/B,sEAAsE;IACtE,QAAQ,CAAC,aAAa,CAAC,EAAE,CAAC,GAAG,EAAE,mBAAmB,KAAK,IAAI,CAAC;CAC7D;AAED,qBAAa,iBAAiB;IAC5B,OAAO,CAAC,QAAQ,CAAC,KAAK,CAAyB;IAC/C,OAAO,CAAC,QAAQ,CAAC,SAAS,CAAyB;IACnD,OAAO,CAAC,QAAQ,CAAC,WAAW,CAAU;IACtC,OAAO,CAAC,QAAQ,CAAC,aAAa,CAAC,CAAqC;gBAExD,IAAI,GAAE,wBAA6B;IAK/C;sCACkC;IAClC,OAAO,CAAC,OAAO,EAAE,MAAM,EAAE,OAAO,CAAC,EAAE,SAAS,MAAM,EAAE,GAAG,OAAO,CAAC,OAAO,CAAC;IAYvE;oCACgC;IAChC,IAAI,IAAI,mBAAmB,GAAG,IAAI;IAKlC;iBACa;IACb,OAAO,CAAC,QAAQ,EAAE,OAAO,GAAG,IAAI;IAOhC;0EACsE;IACtE,aAAa,IAAI,IAAI;IAMrB;gCAC4B;IAC5B,SAAS,CAAC,QAAQ,EAAE,MAAM,IAAI,GAAG,MAAM,IAAI;IAO3C,mDAAmD;IACnD,IAAI,IAAI,IAAI,MAAM,CAEjB;IAED;;8BAE0B;IAC1B,IAAI,aAAa,IAAI,OAAO,CAE3B;IAED,OAAO,CAAC,MAAM;CASf"}
|
|
@@ -0,0 +1,92 @@
|
|
|
1
|
+
// FIFO queue of pending confirmation requests from the daemon's RPC
|
|
2
|
+
// handlers. A handler that needs human approval pushes an entry via
|
|
3
|
+
// request() and awaits the returned Promise. Two execution modes:
|
|
4
|
+
//
|
|
5
|
+
// - interactive (default): consumers like the TUI's ConfirmationModal
|
|
6
|
+
// subscribe to the queue, render the head entry, and resolve the
|
|
7
|
+
// promise once the user answers y/n.
|
|
8
|
+
//
|
|
9
|
+
// - auto-approve (test-only / Web2 service later): every request()
|
|
10
|
+
// resolves immediately with true. Used by `moth daemon serve
|
|
11
|
+
// --auto-approve` to run the daemon without a human in the loop.
|
|
12
|
+
// The summary + details are still emitted via the onAutoApprove
|
|
13
|
+
// callback so they can be logged for audit.
|
|
14
|
+
//
|
|
15
|
+
// Lives in @shieldedtech/moth-wallet so the TUI host and the
|
|
16
|
+
// headless serve command can both depend on it without crossing
|
|
17
|
+
// the TUI's React layer.
|
|
18
|
+
import { randomUUID } from 'node:crypto';
|
|
19
|
+
export class ConfirmationQueue {
|
|
20
|
+
items = [];
|
|
21
|
+
listeners = new Set();
|
|
22
|
+
autoApprove;
|
|
23
|
+
onAutoApprove;
|
|
24
|
+
constructor(opts = {}) {
|
|
25
|
+
this.autoApprove = opts.autoApprove ?? false;
|
|
26
|
+
this.onAutoApprove = opts.onAutoApprove;
|
|
27
|
+
}
|
|
28
|
+
/** Push a request and resolve once the user answers (or immediately
|
|
29
|
+
* if autoApprove is enabled). */
|
|
30
|
+
request(summary, details) {
|
|
31
|
+
if (this.autoApprove) {
|
|
32
|
+
const req = { id: randomUUID(), summary, details };
|
|
33
|
+
this.onAutoApprove?.(req);
|
|
34
|
+
return Promise.resolve(true);
|
|
35
|
+
}
|
|
36
|
+
return new Promise((resolve) => {
|
|
37
|
+
this.items.push({ id: randomUUID(), summary, details, resolve });
|
|
38
|
+
this.notify();
|
|
39
|
+
});
|
|
40
|
+
}
|
|
41
|
+
/** Head of the queue, or null when empty. The modal uses this to
|
|
42
|
+
* decide whether to render. */
|
|
43
|
+
peek() {
|
|
44
|
+
const head = this.items[0];
|
|
45
|
+
return head ? { id: head.id, summary: head.summary, details: head.details } : null;
|
|
46
|
+
}
|
|
47
|
+
/** Resolve the head with the given verdict and advance. No-op when
|
|
48
|
+
* empty. */
|
|
49
|
+
resolve(approved) {
|
|
50
|
+
const head = this.items.shift();
|
|
51
|
+
if (!head)
|
|
52
|
+
return;
|
|
53
|
+
head.resolve(approved);
|
|
54
|
+
this.notify();
|
|
55
|
+
}
|
|
56
|
+
/** Resolve every pending request as denied. Used on shutdown so any
|
|
57
|
+
* in-flight RPC calls fail cleanly instead of hanging the daemon. */
|
|
58
|
+
drainAsDenied() {
|
|
59
|
+
while (this.items.length > 0) {
|
|
60
|
+
this.resolve(false);
|
|
61
|
+
}
|
|
62
|
+
}
|
|
63
|
+
/** Subscribe to "queue changed" notifications. Returns an
|
|
64
|
+
* unsubscribe function. */
|
|
65
|
+
subscribe(listener) {
|
|
66
|
+
this.listeners.add(listener);
|
|
67
|
+
return () => {
|
|
68
|
+
this.listeners.delete(listener);
|
|
69
|
+
};
|
|
70
|
+
}
|
|
71
|
+
/** Current depth; primarily for tests and logs. */
|
|
72
|
+
get size() {
|
|
73
|
+
return this.items.length;
|
|
74
|
+
}
|
|
75
|
+
/** Whether the queue is in auto-approve mode. The audit log uses
|
|
76
|
+
* this to record `auto-approve` vs `user-approve` decisions on
|
|
77
|
+
* the same code path. */
|
|
78
|
+
get isAutoApprove() {
|
|
79
|
+
return this.autoApprove;
|
|
80
|
+
}
|
|
81
|
+
notify() {
|
|
82
|
+
for (const l of this.listeners) {
|
|
83
|
+
try {
|
|
84
|
+
l();
|
|
85
|
+
}
|
|
86
|
+
catch {
|
|
87
|
+
// listener errors must not affect other listeners or the queue
|
|
88
|
+
}
|
|
89
|
+
}
|
|
90
|
+
}
|
|
91
|
+
}
|
|
92
|
+
//# sourceMappingURL=confirmation-queue.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"confirmation-queue.js","sourceRoot":"","sources":["../../src/daemon/confirmation-queue.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1,23 @@
|
|
|
1
|
+
export { PROTOCOL_VERSION, MAX_FRAME_BYTES, DaemonProtocolError, encodeFrame, FrameDecoder, } from './protocol.js';
|
|
2
|
+
export type { Frame, RequestFrame, ResponseFrame, RpcErrorCode } from './protocol.js';
|
|
3
|
+
export { startDaemon } from './server.js';
|
|
4
|
+
export type { DaemonHandle, DaemonOptions, RpcHandler, ConnectionContext, DaemonBind, AuthHandler, AuthResult, Scope } from './server.js';
|
|
5
|
+
export { ApiKeyStore } from './api-keys.js';
|
|
6
|
+
export type { ApiKeyRecord, ApiKeyGenerated, ApiKeyAuthResult } from './api-keys.js';
|
|
7
|
+
export { connectDaemon, connectDaemonTcp, connectDaemonBind } from './client.js';
|
|
8
|
+
export type { DaemonClient, ConnectDaemonOptions } from './client.js';
|
|
9
|
+
export { ConfirmationQueue } from './confirmation-queue.js';
|
|
10
|
+
export type { ConfirmationRequest, ConfirmationQueueOptions } from './confirmation-queue.js';
|
|
11
|
+
export { buildWalletHandlers } from './wallet-handlers.js';
|
|
12
|
+
export type { WalletHandlerDeps } from './wallet-handlers.js';
|
|
13
|
+
export { AuditLog } from './audit-log.js';
|
|
14
|
+
export type { AuditEntry, AuditRpcEntry, AuditLifecycleEntry, AuditDecision, AuditLogOptions, } from './audit-log.js';
|
|
15
|
+
export { parseSubmitTransactionParams, parseTransferTokensParams, parseCallCircuitParams, parseDeployContractParams, parseDustRegisterParams, parseDustDeregisterParams, parseInsertVerifierKeyParams, parseInsertVerifierKeysBatchParams, shortenHex, shortenAddress, } from './wallet-rpc-parsers.js';
|
|
16
|
+
export type { DaemonGetStateResult, DaemonSubmitTransactionParams, DaemonSubmitTransactionResult, DaemonTransferTokensParams, DaemonTransferTokensResult, DaemonCallCircuitParams, DaemonCallCircuitResult, DaemonDeployContractParams, DaemonDeployContractResult, DaemonDustRegisterParams, DaemonDustRegisterResult, DaemonDustDeregisterParams, DaemonDustDeregisterResult, DaemonInsertVerifierKeyParams, DaemonInsertVerifierKeyResult, DaemonInsertVerifierKeysBatchParams, DaemonInsertVerifierKeysBatchResult, } from './wallet-rpc-types.js';
|
|
17
|
+
/**
|
|
18
|
+
* Canonical socket path for a (network, wallet) pair. Sits inside the same
|
|
19
|
+
* `~/.moth/sync/<network>/` directory tree that the wallet sync cache uses,
|
|
20
|
+
* so the L1 0700 directory perms protect both atomically.
|
|
21
|
+
*/
|
|
22
|
+
export declare function daemonSocketPath(networkId: string, walletName: string): string;
|
|
23
|
+
//# sourceMappingURL=index.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../src/daemon/index.ts"],"names":[],"mappings":"AAKA,OAAO,EACL,gBAAgB,EAChB,eAAe,EACf,mBAAmB,EACnB,WAAW,EACX,YAAY,GACb,MAAM,eAAe,CAAC;AAEvB,YAAY,EAAC,KAAK,EAAE,YAAY,EAAE,aAAa,EAAE,YAAY,EAAC,MAAM,eAAe,CAAC;AAEpF,OAAO,EAAC,WAAW,EAAC,MAAM,aAAa,CAAC;AACxC,YAAY,EAAC,YAAY,EAAE,aAAa,EAAE,UAAU,EAAE,iBAAiB,EAAE,UAAU,EAAE,WAAW,EAAE,UAAU,EAAE,KAAK,EAAC,MAAM,aAAa,CAAC;AAExI,OAAO,EAAC,WAAW,EAAC,MAAM,eAAe,CAAC;AAC1C,YAAY,EAAC,YAAY,EAAE,eAAe,EAAE,gBAAgB,EAAC,MAAM,eAAe,CAAC;AAEnF,OAAO,EAAC,aAAa,EAAE,gBAAgB,EAAE,iBAAiB,EAAC,MAAM,aAAa,CAAC;AAC/E,YAAY,EAAC,YAAY,EAAE,oBAAoB,EAAC,MAAM,aAAa,CAAC;AAEpE,OAAO,EAAC,iBAAiB,EAAC,MAAM,yBAAyB,CAAC;AAC1D,YAAY,EAAC,mBAAmB,EAAE,wBAAwB,EAAC,MAAM,yBAAyB,CAAC;AAK3F,OAAO,EAAC,mBAAmB,EAAC,MAAM,sBAAsB,CAAC;AACzD,YAAY,EAAC,iBAAiB,EAAC,MAAM,sBAAsB,CAAC;AAE5D,OAAO,EAAC,QAAQ,EAAC,MAAM,gBAAgB,CAAC;AACxC,YAAY,EACV,UAAU,EACV,aAAa,EACb,mBAAmB,EACnB,aAAa,EACb,eAAe,GAChB,MAAM,gBAAgB,CAAC;AACxB,OAAO,EACL,4BAA4B,EAC5B,yBAAyB,EACzB,sBAAsB,EACtB,yBAAyB,EACzB,uBAAuB,EACvB,yBAAyB,EACzB,4BAA4B,EAC5B,kCAAkC,EAClC,UAAU,EACV,cAAc,GACf,MAAM,yBAAyB,CAAC;AACjC,YAAY,EACV,oBAAoB,EACpB,6BAA6B,EAAE,6BAA6B,EAC5D,0BAA0B,EAAE,0BAA0B,EACtD,uBAAuB,EAAE,uBAAuB,EAChD,0BAA0B,EAAE,0BAA0B,EACtD,wBAAwB,EAAE,wBAAwB,EAClD,0BAA0B,EAAE,0BAA0B,EACtD,6BAA6B,EAAE,6BAA6B,EAC5D,mCAAmC,EAAE,mCAAmC,GACzE,MAAM,uBAAuB,CAAC;AAK/B;;;;GAIG;AACH,wBAAgB,gBAAgB,CAAC,SAAS,EAAE,MAAM,EAAE,UAAU,EAAE,MAAM,GAAG,MAAM,CAE9E"}
|
|
@@ -0,0 +1,26 @@
|
|
|
1
|
+
// Public surface of the wallet daemon module.
|
|
2
|
+
// L1 (filesystem perms) lives in server.ts; L3 (per-op confirmation) is the
|
|
3
|
+
// host application's responsibility — it composes its own modal-driven
|
|
4
|
+
// handlers and registers them with startDaemon().
|
|
5
|
+
export { PROTOCOL_VERSION, MAX_FRAME_BYTES, DaemonProtocolError, encodeFrame, FrameDecoder, } from './protocol.js';
|
|
6
|
+
export { startDaemon } from './server.js';
|
|
7
|
+
export { ApiKeyStore } from './api-keys.js';
|
|
8
|
+
export { connectDaemon, connectDaemonTcp, connectDaemonBind } from './client.js';
|
|
9
|
+
export { ConfirmationQueue } from './confirmation-queue.js';
|
|
10
|
+
// Shared RPC handler factory + wire types + parsers. Both the TUI
|
|
11
|
+
// host and the headless serve mode build their handler map by
|
|
12
|
+
// calling buildWalletHandlers(deps) with the same dependency bundle.
|
|
13
|
+
export { buildWalletHandlers } from './wallet-handlers.js';
|
|
14
|
+
export { AuditLog } from './audit-log.js';
|
|
15
|
+
export { parseSubmitTransactionParams, parseTransferTokensParams, parseCallCircuitParams, parseDeployContractParams, parseDustRegisterParams, parseDustDeregisterParams, parseInsertVerifierKeyParams, parseInsertVerifierKeysBatchParams, shortenHex, shortenAddress, } from './wallet-rpc-parsers.js';
|
|
16
|
+
import { join } from 'node:path';
|
|
17
|
+
import { homedir } from 'node:os';
|
|
18
|
+
/**
|
|
19
|
+
* Canonical socket path for a (network, wallet) pair. Sits inside the same
|
|
20
|
+
* `~/.moth/sync/<network>/` directory tree that the wallet sync cache uses,
|
|
21
|
+
* so the L1 0700 directory perms protect both atomically.
|
|
22
|
+
*/
|
|
23
|
+
export function daemonSocketPath(networkId, walletName) {
|
|
24
|
+
return join(homedir(), '.moth', 'sync', networkId, `${walletName}.sock`);
|
|
25
|
+
}
|
|
26
|
+
//# sourceMappingURL=index.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"index.js","sourceRoot":"","sources":["../../src/daemon/index.ts"],"names":[],"mappings":"AAAA,8CAA8C;AAC9C,4EAA4E;AAC5E,uEAAuE;AACvE,kDAAkD;AAElD,OAAO,EACL,gBAAgB,EAChB,eAAe,EACf,mBAAmB,EACnB,WAAW,EACX,YAAY,GACb,MAAM,eAAe,CAAC;AAIvB,OAAO,EAAC,WAAW,EAAC,MAAM,aAAa,CAAC;AAGxC,OAAO,EAAC,WAAW,EAAC,MAAM,eAAe,CAAC;AAG1C,OAAO,EAAC,aAAa,EAAE,gBAAgB,EAAE,iBAAiB,EAAC,MAAM,aAAa,CAAC;AAG/E,OAAO,EAAC,iBAAiB,EAAC,MAAM,yBAAyB,CAAC;AAG1D,kEAAkE;AAClE,8DAA8D;AAC9D,qEAAqE;AACrE,OAAO,EAAC,mBAAmB,EAAC,MAAM,sBAAsB,CAAC;AAGzD,OAAO,EAAC,QAAQ,EAAC,MAAM,gBAAgB,CAAC;AAQxC,OAAO,EACL,4BAA4B,EAC5B,yBAAyB,EACzB,sBAAsB,EACtB,yBAAyB,EACzB,uBAAuB,EACvB,yBAAyB,EACzB,4BAA4B,EAC5B,kCAAkC,EAClC,UAAU,EACV,cAAc,GACf,MAAM,yBAAyB,CAAC;AAajC,OAAO,EAAC,IAAI,EAAC,MAAM,WAAW,CAAC;AAC/B,OAAO,EAAC,OAAO,EAAC,MAAM,SAAS,CAAC;AAEhC;;;;GAIG;AACH,MAAM,UAAU,gBAAgB,CAAC,SAAiB,EAAE,UAAkB;IACpE,OAAO,IAAI,CAAC,OAAO,EAAE,EAAE,OAAO,EAAE,MAAM,EAAE,SAAS,EAAE,GAAG,UAAU,OAAO,CAAC,CAAC;AAC3E,CAAC"}
|
|
@@ -0,0 +1,40 @@
|
|
|
1
|
+
export declare const PROTOCOL_VERSION = "moth-wallet-daemon/1";
|
|
2
|
+
/** Bound on a single frame's payload size. Practical state snapshots are well
|
|
3
|
+
* under 1MB today; cap above lets the wire format grow without immediate
|
|
4
|
+
* ceiling changes. */
|
|
5
|
+
export declare const MAX_FRAME_BYTES: number;
|
|
6
|
+
export type RequestFrame = {
|
|
7
|
+
readonly id: string;
|
|
8
|
+
readonly type: 'request';
|
|
9
|
+
readonly method: string;
|
|
10
|
+
readonly params?: unknown;
|
|
11
|
+
};
|
|
12
|
+
export type ResponseFrame = {
|
|
13
|
+
readonly id: string;
|
|
14
|
+
readonly type: 'response';
|
|
15
|
+
readonly result?: unknown;
|
|
16
|
+
readonly error?: {
|
|
17
|
+
readonly code: string;
|
|
18
|
+
readonly message: string;
|
|
19
|
+
};
|
|
20
|
+
};
|
|
21
|
+
export type Frame = RequestFrame | ResponseFrame;
|
|
22
|
+
export type RpcErrorCode = 'METHOD_NOT_FOUND' | 'INVALID_REQUEST' | 'INVALID_PARAMS' | 'INTERNAL_ERROR' | 'CLOSED' | 'TIMEOUT' | 'UNAUTHORIZED';
|
|
23
|
+
export declare class DaemonProtocolError extends Error {
|
|
24
|
+
readonly code: RpcErrorCode;
|
|
25
|
+
constructor(code: RpcErrorCode, message: string);
|
|
26
|
+
}
|
|
27
|
+
export declare function encodeFrame(frame: Frame): Buffer;
|
|
28
|
+
/**
|
|
29
|
+
* Streaming decoder. push() accepts arbitrary chunks; complete frames come
|
|
30
|
+
* out in order, partial bytes stay buffered. Throws DaemonProtocolError on
|
|
31
|
+
* an over-large declared length so the caller can disconnect the peer
|
|
32
|
+
* before allocating.
|
|
33
|
+
*/
|
|
34
|
+
export declare class FrameDecoder {
|
|
35
|
+
private buffer;
|
|
36
|
+
push(chunk: Buffer): Frame[];
|
|
37
|
+
/** Bytes still buffered (incomplete frame). Useful for diagnostics/tests. */
|
|
38
|
+
get pending(): number;
|
|
39
|
+
}
|
|
40
|
+
//# sourceMappingURL=protocol.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"protocol.d.ts","sourceRoot":"","sources":["../../src/daemon/protocol.ts"],"names":[],"mappings":"AAYA,eAAO,MAAM,gBAAgB,yBAAyB,CAAC;AAEvD;;uBAEuB;AACvB,eAAO,MAAM,eAAe,QAAmB,CAAC;AAEhD,MAAM,MAAM,YAAY,GAAG;IACzB,QAAQ,CAAC,EAAE,EAAE,MAAM,CAAC;IACpB,QAAQ,CAAC,IAAI,EAAE,SAAS,CAAC;IACzB,QAAQ,CAAC,MAAM,EAAE,MAAM,CAAC;IACxB,QAAQ,CAAC,MAAM,CAAC,EAAE,OAAO,CAAC;CAC3B,CAAC;AAEF,MAAM,MAAM,aAAa,GAAG;IAC1B,QAAQ,CAAC,EAAE,EAAE,MAAM,CAAC;IACpB,QAAQ,CAAC,IAAI,EAAE,UAAU,CAAC;IAC1B,QAAQ,CAAC,MAAM,CAAC,EAAE,OAAO,CAAC;IAC1B,QAAQ,CAAC,KAAK,CAAC,EAAE;QAAC,QAAQ,CAAC,IAAI,EAAE,MAAM,CAAC;QAAC,QAAQ,CAAC,OAAO,EAAE,MAAM,CAAA;KAAC,CAAC;CACpE,CAAC;AAEF,MAAM,MAAM,KAAK,GAAG,YAAY,GAAG,aAAa,CAAC;AAEjD,MAAM,MAAM,YAAY,GACpB,kBAAkB,GAClB,iBAAiB,GACjB,gBAAgB,GAChB,gBAAgB,GAChB,QAAQ,GACR,SAAS,GACT,cAAc,CAAC;AAEnB,qBAAa,mBAAoB,SAAQ,KAAK;IAE1C,QAAQ,CAAC,IAAI,EAAE,YAAY;gBAAlB,IAAI,EAAE,YAAY,EAC3B,OAAO,EAAE,MAAM;CAKlB;AAED,wBAAgB,WAAW,CAAC,KAAK,EAAE,KAAK,GAAG,MAAM,CAWhD;AAED;;;;;GAKG;AACH,qBAAa,YAAY;IACvB,OAAO,CAAC,MAAM,CAA2B;IAEzC,IAAI,CAAC,KAAK,EAAE,MAAM,GAAG,KAAK,EAAE;IAuB5B,6EAA6E;IAC7E,IAAI,OAAO,IAAI,MAAM,CAEpB;CACF"}
|
|
@@ -0,0 +1,104 @@
|
|
|
1
|
+
// Length-prefixed JSON-over-stream framing for the moth wallet daemon.
|
|
2
|
+
//
|
|
3
|
+
// Wire format: 4-byte big-endian uint32 payload length, then that many bytes
|
|
4
|
+
// of UTF-8 JSON. Streams are bidirectional and full-duplex; either side may
|
|
5
|
+
// emit Request or Response frames at any time, correlated by `id`. There is
|
|
6
|
+
// no built-in keepalive — the underlying Unix stream socket detects
|
|
7
|
+
// peer-close cleanly and that's enough.
|
|
8
|
+
//
|
|
9
|
+
// All sizes are bounded. A frame larger than MAX_FRAME_BYTES is rejected
|
|
10
|
+
// without buffering, so a misbehaving peer can't drive the daemon into an
|
|
11
|
+
// unbounded allocation.
|
|
12
|
+
export const PROTOCOL_VERSION = 'moth-wallet-daemon/1';
|
|
13
|
+
/** Bound on a single frame's payload size. Practical state snapshots are well
|
|
14
|
+
* under 1MB today; cap above lets the wire format grow without immediate
|
|
15
|
+
* ceiling changes. */
|
|
16
|
+
export const MAX_FRAME_BYTES = 16 * 1024 * 1024;
|
|
17
|
+
export class DaemonProtocolError extends Error {
|
|
18
|
+
code;
|
|
19
|
+
constructor(code, message) {
|
|
20
|
+
super(message);
|
|
21
|
+
this.code = code;
|
|
22
|
+
this.name = 'DaemonProtocolError';
|
|
23
|
+
}
|
|
24
|
+
}
|
|
25
|
+
export function encodeFrame(frame) {
|
|
26
|
+
const json = Buffer.from(JSON.stringify(frame), 'utf-8');
|
|
27
|
+
if (json.length > MAX_FRAME_BYTES) {
|
|
28
|
+
throw new DaemonProtocolError('INVALID_REQUEST', `frame too large: ${json.length} bytes (max ${MAX_FRAME_BYTES})`);
|
|
29
|
+
}
|
|
30
|
+
const lenHeader = Buffer.alloc(4);
|
|
31
|
+
lenHeader.writeUInt32BE(json.length, 0);
|
|
32
|
+
return Buffer.concat([lenHeader, json]);
|
|
33
|
+
}
|
|
34
|
+
/**
|
|
35
|
+
* Streaming decoder. push() accepts arbitrary chunks; complete frames come
|
|
36
|
+
* out in order, partial bytes stay buffered. Throws DaemonProtocolError on
|
|
37
|
+
* an over-large declared length so the caller can disconnect the peer
|
|
38
|
+
* before allocating.
|
|
39
|
+
*/
|
|
40
|
+
export class FrameDecoder {
|
|
41
|
+
buffer = Buffer.alloc(0);
|
|
42
|
+
push(chunk) {
|
|
43
|
+
this.buffer = this.buffer.length === 0 ? chunk : Buffer.concat([this.buffer, chunk]);
|
|
44
|
+
const out = [];
|
|
45
|
+
while (this.buffer.length >= 4) {
|
|
46
|
+
const payloadLen = this.buffer.readUInt32BE(0);
|
|
47
|
+
if (payloadLen > MAX_FRAME_BYTES) {
|
|
48
|
+
throw new DaemonProtocolError('INVALID_REQUEST', `declared frame length ${payloadLen} exceeds max ${MAX_FRAME_BYTES}`);
|
|
49
|
+
}
|
|
50
|
+
if (this.buffer.length < 4 + payloadLen)
|
|
51
|
+
break;
|
|
52
|
+
const json = this.buffer.subarray(4, 4 + payloadLen).toString('utf-8');
|
|
53
|
+
this.buffer = this.buffer.subarray(4 + payloadLen);
|
|
54
|
+
const parsed = parseFrame(json);
|
|
55
|
+
out.push(parsed);
|
|
56
|
+
}
|
|
57
|
+
return out;
|
|
58
|
+
}
|
|
59
|
+
/** Bytes still buffered (incomplete frame). Useful for diagnostics/tests. */
|
|
60
|
+
get pending() {
|
|
61
|
+
return this.buffer.length;
|
|
62
|
+
}
|
|
63
|
+
}
|
|
64
|
+
function parseFrame(json) {
|
|
65
|
+
let raw;
|
|
66
|
+
try {
|
|
67
|
+
raw = JSON.parse(json);
|
|
68
|
+
}
|
|
69
|
+
catch (err) {
|
|
70
|
+
throw new DaemonProtocolError('INVALID_REQUEST', `frame is not valid JSON: ${err.message}`);
|
|
71
|
+
}
|
|
72
|
+
if (!raw || typeof raw !== 'object') {
|
|
73
|
+
throw new DaemonProtocolError('INVALID_REQUEST', 'frame is not a JSON object');
|
|
74
|
+
}
|
|
75
|
+
const f = raw;
|
|
76
|
+
if (typeof f.id !== 'string') {
|
|
77
|
+
throw new DaemonProtocolError('INVALID_REQUEST', 'frame.id must be a string');
|
|
78
|
+
}
|
|
79
|
+
if (f.type === 'request') {
|
|
80
|
+
if (typeof f.method !== 'string') {
|
|
81
|
+
throw new DaemonProtocolError('INVALID_REQUEST', 'request.method must be a string');
|
|
82
|
+
}
|
|
83
|
+
return { id: f.id, type: 'request', method: f.method, params: f.params };
|
|
84
|
+
}
|
|
85
|
+
if (f.type === 'response') {
|
|
86
|
+
if (f.error !== undefined && f.result !== undefined) {
|
|
87
|
+
throw new DaemonProtocolError('INVALID_REQUEST', 'response cannot carry both result and error');
|
|
88
|
+
}
|
|
89
|
+
if (f.error !== undefined) {
|
|
90
|
+
const e = f.error;
|
|
91
|
+
if (typeof e.code !== 'string' || typeof e.message !== 'string') {
|
|
92
|
+
throw new DaemonProtocolError('INVALID_REQUEST', 'response.error must have string code and message');
|
|
93
|
+
}
|
|
94
|
+
return {
|
|
95
|
+
id: f.id,
|
|
96
|
+
type: 'response',
|
|
97
|
+
error: { code: e.code, message: e.message },
|
|
98
|
+
};
|
|
99
|
+
}
|
|
100
|
+
return { id: f.id, type: 'response', result: f.result };
|
|
101
|
+
}
|
|
102
|
+
throw new DaemonProtocolError('INVALID_REQUEST', `frame.type must be "request" or "response", got ${String(f.type)}`);
|
|
103
|
+
}
|
|
104
|
+
//# sourceMappingURL=protocol.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"protocol.js","sourceRoot":"","sources":["../../src/daemon/protocol.ts"],"names":[],"mappings":"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"}
|