@rome-os/node-core 0.1.1 → 0.1.2
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +35 -1
- package/dist/actions.d.ts +4 -0
- package/dist/client.d.ts +4 -1
- package/dist/client.js +30 -1
- package/dist/connect.js +2 -3
- package/dist/connector.d.ts +10 -1
- package/dist/connector.js +129 -7
- package/dist/daemon-client.d.ts +8 -4
- package/dist/daemon-client.js +86 -2
- package/dist/daemon-control.js +13 -2
- package/dist/daemon-protocol.d.ts +22 -1
- package/dist/daemon-protocol.js +22 -1
- package/dist/daemon-rpc.d.ts +7 -2
- package/dist/daemon-rpc.js +49 -17
- package/dist/daemon.js +167 -21
- package/dist/executor.d.ts +4 -1
- package/dist/executor.js +180 -66
- package/dist/frame.d.ts +24 -0
- package/dist/frame.js +64 -0
- package/dist/index.d.ts +2 -1
- package/dist/index.js +1 -0
- package/dist/transfer.d.ts +102 -0
- package/dist/transfer.js +518 -0
- package/package.json +1 -1
package/dist/daemon-rpc.js
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
import WebSocket from "ws";
|
|
2
2
|
import { isRecord } from "./actions.js";
|
|
3
|
-
import { DAEMON_PROTOCOL_VERSION, parseDaemonStatus, } from "./daemon-protocol.js";
|
|
3
|
+
import { DAEMON_PROTOCOL_VERSION, encodeBinaryMessage, MAX_LOCAL_MESSAGE_BYTES, parseBinaryMessage, parseDaemonStatus, } from "./daemon-protocol.js";
|
|
4
4
|
export class DaemonVersionError extends Error {
|
|
5
5
|
constructor() {
|
|
6
6
|
super("The caller daemon uses an incompatible protocol. Stop it explicitly before restarting with this version.");
|
|
@@ -52,26 +52,47 @@ export class RpcConnection {
|
|
|
52
52
|
});
|
|
53
53
|
socket.on("message", (data, binary) => {
|
|
54
54
|
let message;
|
|
55
|
-
|
|
56
|
-
|
|
55
|
+
let body = new Uint8Array();
|
|
56
|
+
if (binary) {
|
|
57
|
+
const parsed = parseBinaryMessage(Buffer.isBuffer(data)
|
|
58
|
+
? data
|
|
59
|
+
: Array.isArray(data)
|
|
60
|
+
? Buffer.concat(data)
|
|
61
|
+
: Buffer.from(data));
|
|
62
|
+
if (!parsed) {
|
|
63
|
+
this.close();
|
|
64
|
+
return;
|
|
65
|
+
}
|
|
66
|
+
({ message, body } = parsed);
|
|
57
67
|
}
|
|
58
|
-
|
|
59
|
-
|
|
60
|
-
|
|
68
|
+
else {
|
|
69
|
+
try {
|
|
70
|
+
message = JSON.parse(data.toString());
|
|
71
|
+
}
|
|
72
|
+
catch {
|
|
73
|
+
this.close();
|
|
74
|
+
return;
|
|
75
|
+
}
|
|
61
76
|
}
|
|
62
|
-
if (
|
|
77
|
+
if (!isRecord(message) || message.jsonrpc !== "2.0") {
|
|
63
78
|
this.close();
|
|
64
79
|
return;
|
|
65
80
|
}
|
|
66
81
|
if (typeof message.method === "string" && !Object.hasOwn(message, "id")) {
|
|
67
|
-
|
|
82
|
+
const params = message.params;
|
|
83
|
+
if (message.method === "events.transfer") {
|
|
84
|
+
if (isRecord(params) && typeof params.requestId === "string")
|
|
85
|
+
this.pending.get(params.requestId)?.progress?.(params);
|
|
86
|
+
return;
|
|
87
|
+
}
|
|
88
|
+
this.onNotification?.(message.method, params);
|
|
68
89
|
return;
|
|
69
90
|
}
|
|
70
91
|
const pending = typeof message.id === "string" ? this.pending.get(message.id) : undefined;
|
|
71
92
|
if (!pending)
|
|
72
93
|
return;
|
|
73
94
|
if (Object.hasOwn(message, "result") && !Object.hasOwn(message, "error"))
|
|
74
|
-
pending.resolve(message.result);
|
|
95
|
+
pending.resolve(message.result, body);
|
|
75
96
|
else if (!Object.hasOwn(message, "result") &&
|
|
76
97
|
isRecord(message.error) &&
|
|
77
98
|
Number.isInteger(message.error.code) &&
|
|
@@ -84,11 +105,18 @@ export class RpcConnection {
|
|
|
84
105
|
get open() {
|
|
85
106
|
return this.socket.readyState === WebSocket.OPEN;
|
|
86
107
|
}
|
|
87
|
-
request(method, params = {}, timeoutMs = 85_000) {
|
|
108
|
+
async request(method, params = {}, timeoutMs = 85_000, progress) {
|
|
109
|
+
return (await this.submit(method, params, undefined, timeoutMs, progress)).result;
|
|
110
|
+
}
|
|
111
|
+
async requestBinary(method, params, body, timeoutMs = 85_000) {
|
|
112
|
+
return this.submit(method, params, body, timeoutMs);
|
|
113
|
+
}
|
|
114
|
+
submit(method, params, body, timeoutMs, progress) {
|
|
88
115
|
if (!this.open)
|
|
89
116
|
return Promise.reject(new DaemonRequestError());
|
|
90
117
|
const id = String(++this.nextId);
|
|
91
|
-
const
|
|
118
|
+
const message = { jsonrpc: "2.0", id, method, params };
|
|
119
|
+
const data = body ? encodeBinaryMessage(message, body) : JSON.stringify(message);
|
|
92
120
|
return new Promise((resolve, reject) => {
|
|
93
121
|
const finish = (error, value) => {
|
|
94
122
|
clearTimeout(timer);
|
|
@@ -98,13 +126,16 @@ export class RpcConnection {
|
|
|
98
126
|
else
|
|
99
127
|
resolve(value);
|
|
100
128
|
};
|
|
101
|
-
const timer =
|
|
129
|
+
const timer = Number.isFinite(timeoutMs)
|
|
130
|
+
? setTimeout(() => finish(new DaemonRequestError()), timeoutMs)
|
|
131
|
+
: undefined;
|
|
102
132
|
this.pending.set(id, {
|
|
103
|
-
resolve: (
|
|
133
|
+
resolve: (result, body) => finish(undefined, { result, body }),
|
|
104
134
|
reject: (error) => finish(error),
|
|
135
|
+
progress,
|
|
105
136
|
});
|
|
106
137
|
try {
|
|
107
|
-
this.socket.send(
|
|
138
|
+
this.socket.send(data, { binary: Boolean(body) }, (error) => {
|
|
108
139
|
if (error)
|
|
109
140
|
finish(new DaemonRequestError());
|
|
110
141
|
});
|
|
@@ -118,12 +149,13 @@ export class RpcConnection {
|
|
|
118
149
|
this.socket.terminate();
|
|
119
150
|
}
|
|
120
151
|
}
|
|
121
|
-
export async function connectRpc(state, signal) {
|
|
152
|
+
export async function connectRpc(state, signal, protocolVersion = DAEMON_PROTOCOL_VERSION) {
|
|
122
153
|
signal?.throwIfAborted();
|
|
123
154
|
const socket = new WebSocket(`ws://127.0.0.1:${state.port}/rpc`, {
|
|
124
155
|
headers: { authorization: `Bearer ${state.token}` },
|
|
125
156
|
handshakeTimeout: 1500,
|
|
126
157
|
perMessageDeflate: false,
|
|
158
|
+
maxPayload: MAX_LOCAL_MESSAGE_BYTES,
|
|
127
159
|
followRedirects: false,
|
|
128
160
|
});
|
|
129
161
|
const rpc = new RpcConnection(socket);
|
|
@@ -150,8 +182,8 @@ export async function connectRpc(state, signal) {
|
|
|
150
182
|
if (signal?.aborted)
|
|
151
183
|
abort();
|
|
152
184
|
});
|
|
153
|
-
const value = await rpc.request("daemon.hello", { protocolVersion
|
|
154
|
-
if (isRecord(value) && value.protocolVersion !==
|
|
185
|
+
const value = await rpc.request("daemon.hello", { protocolVersion }, 1500);
|
|
186
|
+
if (isRecord(value) && value.protocolVersion !== protocolVersion)
|
|
155
187
|
throw new DaemonVersionError();
|
|
156
188
|
const status = parseDaemonStatus(value);
|
|
157
189
|
if (!status || status.pid !== state.pid)
|
package/dist/daemon.js
CHANGED
|
@@ -1,13 +1,29 @@
|
|
|
1
1
|
import { randomBytes, timingSafeEqual } from "node:crypto";
|
|
2
2
|
import { createServer } from "node:http";
|
|
3
3
|
import WebSocket, { WebSocketServer } from "ws";
|
|
4
|
-
import { isRecord } from "./actions.js";
|
|
4
|
+
import { actionError, isRecord } from "./actions.js";
|
|
5
5
|
import { DeviceConnector } from "./connector.js";
|
|
6
6
|
import { daemonStatePath, readCallerCredential } from "./local.js";
|
|
7
7
|
import { writePrivateJson } from "./storage.js";
|
|
8
|
-
import { DAEMON_PROTOCOL_VERSION } from "./daemon-protocol.js";
|
|
8
|
+
import { DAEMON_PROTOCOL_VERSION, encodeBinaryMessage, MAX_LOCAL_MESSAGE_BYTES, parseBinaryMessage, } from "./daemon-protocol.js";
|
|
9
9
|
import { DeviceStatusReader } from "./devices-status.js";
|
|
10
10
|
import { RpcError } from "./daemon-rpc.js";
|
|
11
|
+
import { isAbsolute } from "node:path";
|
|
12
|
+
import { isUuid } from "./frame.js";
|
|
13
|
+
import { copyWithDevice, TRANSFER_VERSION, TransferError } from "./transfer.js";
|
|
14
|
+
function copyRequest(params) {
|
|
15
|
+
const { direction, localPath, deviceId, remotePath } = params;
|
|
16
|
+
if ((direction !== "push" && direction !== "pull") ||
|
|
17
|
+
typeof localPath !== "string" ||
|
|
18
|
+
!isAbsolute(localPath) ||
|
|
19
|
+
localPath.includes("\0") ||
|
|
20
|
+
!isUuid(deviceId) ||
|
|
21
|
+
typeof remotePath !== "string" ||
|
|
22
|
+
!remotePath ||
|
|
23
|
+
remotePath.includes("\0"))
|
|
24
|
+
return null;
|
|
25
|
+
return { direction, localPath, deviceId: deviceId.toLowerCase(), remotePath };
|
|
26
|
+
}
|
|
11
27
|
export async function serveDaemon(config, signal) {
|
|
12
28
|
if (signal.aborted)
|
|
13
29
|
return;
|
|
@@ -44,7 +60,11 @@ export async function serveDaemon(config, signal) {
|
|
|
44
60
|
res.writeHead(authorized(req) ? 426 : 401, { "cache-control": "no-store" }).end();
|
|
45
61
|
});
|
|
46
62
|
server.headersTimeout = 10_000;
|
|
47
|
-
const sockets = new WebSocketServer({
|
|
63
|
+
const sockets = new WebSocketServer({
|
|
64
|
+
noServer: true,
|
|
65
|
+
perMessageDeflate: false,
|
|
66
|
+
maxPayload: MAX_LOCAL_MESSAGE_BYTES,
|
|
67
|
+
});
|
|
48
68
|
server.on("upgrade", (req, socket, head) => {
|
|
49
69
|
if (closing || req.url !== "/rpc" || req.headers.origin || !authorized(req)) {
|
|
50
70
|
socket.end("HTTP/1.1 401 Unauthorized\r\nConnection: close\r\nContent-Length: 0\r\n\r\n");
|
|
@@ -60,12 +80,46 @@ export async function serveDaemon(config, signal) {
|
|
|
60
80
|
peer.socket.terminate();
|
|
61
81
|
});
|
|
62
82
|
}
|
|
83
|
+
function deliver(peer, reply) {
|
|
84
|
+
if (!reply.body) {
|
|
85
|
+
send(peer, reply.message);
|
|
86
|
+
return;
|
|
87
|
+
}
|
|
88
|
+
if (peer.socket.readyState !== WebSocket.OPEN)
|
|
89
|
+
return;
|
|
90
|
+
let data = encodeBinaryMessage(reply.message, reply.body);
|
|
91
|
+
if (data.byteLength > MAX_LOCAL_MESSAGE_BYTES) {
|
|
92
|
+
const id = isRecord(reply.message) ? reply.message.id : null;
|
|
93
|
+
data = encodeBinaryMessage({
|
|
94
|
+
jsonrpc: "2.0",
|
|
95
|
+
id,
|
|
96
|
+
result: actionError("message_too_large", "The response exceeds the local message limit. The action may have completed."),
|
|
97
|
+
}, new Uint8Array());
|
|
98
|
+
}
|
|
99
|
+
peer.socket.send(data, { binary: true }, (error) => {
|
|
100
|
+
if (error)
|
|
101
|
+
peer.socket.terminate();
|
|
102
|
+
});
|
|
103
|
+
}
|
|
63
104
|
function notify(peer) {
|
|
64
|
-
if (peer.
|
|
105
|
+
if (peer.eventBytes > 1024 * 1024) {
|
|
65
106
|
peer.socket.terminate();
|
|
66
107
|
return;
|
|
67
108
|
}
|
|
68
|
-
|
|
109
|
+
if (peer.socket.readyState !== WebSocket.OPEN)
|
|
110
|
+
return;
|
|
111
|
+
const text = JSON.stringify({
|
|
112
|
+
jsonrpc: "2.0",
|
|
113
|
+
method: "events.connection",
|
|
114
|
+
params: snapshot(),
|
|
115
|
+
});
|
|
116
|
+
const size = Buffer.byteLength(text);
|
|
117
|
+
peer.eventBytes += size;
|
|
118
|
+
peer.socket.send(text, (error) => {
|
|
119
|
+
peer.eventBytes -= size;
|
|
120
|
+
if (error)
|
|
121
|
+
peer.socket.terminate();
|
|
122
|
+
});
|
|
69
123
|
}
|
|
70
124
|
const close = () => {
|
|
71
125
|
if (closing)
|
|
@@ -86,7 +140,7 @@ export async function serveDaemon(config, signal) {
|
|
|
86
140
|
function error(id, code, message) {
|
|
87
141
|
return { jsonrpc: "2.0", id, error: { code, message } };
|
|
88
142
|
}
|
|
89
|
-
async function dispatch(peer, value) {
|
|
143
|
+
async function dispatch(peer, value, input) {
|
|
90
144
|
if (!isRecord(value) ||
|
|
91
145
|
value.jsonrpc !== "2.0" ||
|
|
92
146
|
typeof value.method !== "string" ||
|
|
@@ -94,7 +148,7 @@ export async function serveDaemon(config, signal) {
|
|
|
94
148
|
typeof value.id !== "string" &&
|
|
95
149
|
typeof value.id !== "number" &&
|
|
96
150
|
value.id !== null))
|
|
97
|
-
return error(null, -32600, "Invalid Request");
|
|
151
|
+
return { message: error(null, -32600, "Invalid Request") };
|
|
98
152
|
const hasId = Object.hasOwn(value, "id");
|
|
99
153
|
const id = value.id;
|
|
100
154
|
if (hasId && id !== null && peer.pending.has(id)) {
|
|
@@ -109,7 +163,10 @@ export async function serveDaemon(config, signal) {
|
|
|
109
163
|
const params = Object.hasOwn(value, "params") ? value.params : {};
|
|
110
164
|
if (!isRecord(params))
|
|
111
165
|
throw new RpcError(-32602, "Invalid params");
|
|
166
|
+
if ((value.method === "devices.runBinary") !== Boolean(input))
|
|
167
|
+
throw new RpcError(-32600, "Only devices.runBinary uses binary messages, and it requires one.");
|
|
112
168
|
let result;
|
|
169
|
+
let body;
|
|
113
170
|
if (value.method === "daemon.hello") {
|
|
114
171
|
if (params.protocolVersion !== DAEMON_PROTOCOL_VERSION)
|
|
115
172
|
throw new RpcError(-32002, "Incompatible daemon protocol.");
|
|
@@ -138,6 +195,68 @@ export async function serveDaemon(config, signal) {
|
|
|
138
195
|
throw new RpcError(-32602, "A device ID and action are required.");
|
|
139
196
|
result = await connector.run(params.deviceId, params.action, params.args ?? {});
|
|
140
197
|
break;
|
|
198
|
+
case "devices.runBinary": {
|
|
199
|
+
if (typeof params.deviceId !== "string" || typeof params.action !== "string")
|
|
200
|
+
throw new RpcError(-32602, "A device ID and action are required.");
|
|
201
|
+
const reply = await connector.runBinary(params.deviceId, params.action, params.args ?? {}, input ?? new Uint8Array());
|
|
202
|
+
result = reply.response;
|
|
203
|
+
body = reply.body;
|
|
204
|
+
break;
|
|
205
|
+
}
|
|
206
|
+
case "files.copy": {
|
|
207
|
+
const request = copyRequest(params);
|
|
208
|
+
if (!request)
|
|
209
|
+
throw new RpcError(-32602, "files.copy requires direction push or pull, an absolute localPath, a device UUID, and remotePath.");
|
|
210
|
+
const controller = new AbortController();
|
|
211
|
+
peer.copies.add(controller);
|
|
212
|
+
if (peer.socket.readyState !== WebSocket.OPEN)
|
|
213
|
+
controller.abort();
|
|
214
|
+
const canceled = () => actionError("canceled", "The client disconnected. The copy did not start.");
|
|
215
|
+
let last = 0;
|
|
216
|
+
try {
|
|
217
|
+
if (controller.signal.aborted) {
|
|
218
|
+
result = canceled();
|
|
219
|
+
break;
|
|
220
|
+
}
|
|
221
|
+
const info = await connector.run(request.deviceId, "system.info", {});
|
|
222
|
+
if (controller.signal.aborted) {
|
|
223
|
+
result = canceled();
|
|
224
|
+
break;
|
|
225
|
+
}
|
|
226
|
+
if (!info.ok) {
|
|
227
|
+
result = info;
|
|
228
|
+
break;
|
|
229
|
+
}
|
|
230
|
+
if (!isRecord(info.result) || info.result.transferVersion !== TRANSFER_VERSION) {
|
|
231
|
+
result = actionError("unsupported_device", "The device runs a rome-node version without file transfers. Update rome-node on that device.");
|
|
232
|
+
break;
|
|
233
|
+
}
|
|
234
|
+
const summary = await copyWithDevice((events) => connector.openChannel(request.deviceId, events), request, {
|
|
235
|
+
signal: controller.signal,
|
|
236
|
+
onProgress: ({ bytes, total }) => {
|
|
237
|
+
const now = Date.now();
|
|
238
|
+
if (now - last < 250 && bytes !== total)
|
|
239
|
+
return;
|
|
240
|
+
last = now;
|
|
241
|
+
send(peer, {
|
|
242
|
+
jsonrpc: "2.0",
|
|
243
|
+
method: "events.transfer",
|
|
244
|
+
params: { requestId: id, bytes, total },
|
|
245
|
+
});
|
|
246
|
+
},
|
|
247
|
+
});
|
|
248
|
+
result = { type: "response", ok: true, result: summary };
|
|
249
|
+
}
|
|
250
|
+
catch (cause) {
|
|
251
|
+
if (!(cause instanceof TransferError))
|
|
252
|
+
throw cause;
|
|
253
|
+
result = actionError(cause.code, cause.message);
|
|
254
|
+
}
|
|
255
|
+
finally {
|
|
256
|
+
peer.copies.delete(controller);
|
|
257
|
+
}
|
|
258
|
+
break;
|
|
259
|
+
}
|
|
141
260
|
case "events.subscribe":
|
|
142
261
|
case "events.unsubscribe":
|
|
143
262
|
if (params.topic !== "connection")
|
|
@@ -151,14 +270,16 @@ export async function serveDaemon(config, signal) {
|
|
|
151
270
|
throw new RpcError(-32601, "Method not found");
|
|
152
271
|
}
|
|
153
272
|
}
|
|
154
|
-
return hasId ? { jsonrpc: "2.0", id, result } : undefined;
|
|
273
|
+
return hasId ? { message: { jsonrpc: "2.0", id, result }, body } : undefined;
|
|
155
274
|
}
|
|
156
275
|
catch (cause) {
|
|
157
276
|
if (!hasId)
|
|
158
277
|
return;
|
|
159
|
-
return
|
|
160
|
-
|
|
161
|
-
|
|
278
|
+
return {
|
|
279
|
+
message: cause instanceof RpcError
|
|
280
|
+
? error(id, cause.code, cause.message)
|
|
281
|
+
: error(id, -32000, "The device service is unavailable."),
|
|
282
|
+
};
|
|
162
283
|
}
|
|
163
284
|
finally {
|
|
164
285
|
if (hasId && id !== null)
|
|
@@ -166,14 +287,41 @@ export async function serveDaemon(config, signal) {
|
|
|
166
287
|
}
|
|
167
288
|
}
|
|
168
289
|
sockets.on("connection", (socket) => {
|
|
169
|
-
const peer = {
|
|
290
|
+
const peer = {
|
|
291
|
+
socket,
|
|
292
|
+
ready: false,
|
|
293
|
+
subscribed: false,
|
|
294
|
+
alive: true,
|
|
295
|
+
pending: new Set(),
|
|
296
|
+
eventBytes: 0,
|
|
297
|
+
copies: new Set(),
|
|
298
|
+
};
|
|
170
299
|
peers.add(peer);
|
|
171
300
|
socket.on("error", () => socket.terminate());
|
|
172
|
-
socket.on("close", () =>
|
|
301
|
+
socket.on("close", () => {
|
|
302
|
+
peers.delete(peer);
|
|
303
|
+
for (const copy of peer.copies)
|
|
304
|
+
copy.abort();
|
|
305
|
+
});
|
|
173
306
|
socket.on("pong", () => {
|
|
174
307
|
peer.alive = true;
|
|
175
308
|
});
|
|
176
309
|
socket.on("message", (data, binary) => {
|
|
310
|
+
if (binary) {
|
|
311
|
+
const parsed = parseBinaryMessage(Buffer.isBuffer(data)
|
|
312
|
+
? data
|
|
313
|
+
: Array.isArray(data)
|
|
314
|
+
? Buffer.concat(data)
|
|
315
|
+
: Buffer.from(data));
|
|
316
|
+
if (!parsed) {
|
|
317
|
+
send(peer, error(null, -32600, "Invalid Request"));
|
|
318
|
+
return;
|
|
319
|
+
}
|
|
320
|
+
void dispatch(peer, parsed.message, parsed.body)
|
|
321
|
+
.then((reply) => reply && deliver(peer, reply))
|
|
322
|
+
.catch(() => socket.terminate());
|
|
323
|
+
return;
|
|
324
|
+
}
|
|
177
325
|
let request;
|
|
178
326
|
try {
|
|
179
327
|
request = JSON.parse(data.toString());
|
|
@@ -182,20 +330,18 @@ export async function serveDaemon(config, signal) {
|
|
|
182
330
|
send(peer, error(null, -32700, "Parse error"));
|
|
183
331
|
return;
|
|
184
332
|
}
|
|
185
|
-
if (binary) {
|
|
186
|
-
send(peer, error(null, -32600, "Invalid Request"));
|
|
187
|
-
return;
|
|
188
|
-
}
|
|
189
333
|
void (async () => {
|
|
190
334
|
if (Array.isArray(request) && request.length > 0) {
|
|
191
|
-
const responses = (await Promise.all(request.map((item) => dispatch(peer, item))))
|
|
335
|
+
const responses = (await Promise.all(request.map((item) => dispatch(peer, item))))
|
|
336
|
+
.filter((reply) => reply !== undefined)
|
|
337
|
+
.map((reply) => reply.message);
|
|
192
338
|
if (responses.length)
|
|
193
339
|
send(peer, responses);
|
|
194
340
|
}
|
|
195
341
|
else {
|
|
196
|
-
const
|
|
197
|
-
if (
|
|
198
|
-
send(peer,
|
|
342
|
+
const reply = await dispatch(peer, request);
|
|
343
|
+
if (reply !== undefined)
|
|
344
|
+
send(peer, reply.message);
|
|
199
345
|
}
|
|
200
346
|
})().catch(() => socket.terminate());
|
|
201
347
|
});
|
package/dist/executor.d.ts
CHANGED
|
@@ -1,5 +1,8 @@
|
|
|
1
|
+
import { type Frame } from "./frame.js";
|
|
1
2
|
import type { InboundEnvelope, OutboundEnvelope } from "./protocol.js";
|
|
2
|
-
export declare function
|
|
3
|
+
export declare function redactBytes(data: Buffer, secrets: string[]): Buffer;
|
|
4
|
+
export declare function createExecutor(name: string, send: (message: OutboundEnvelope) => boolean, secrets?: string[], sendFrame?: (frame: Frame) => boolean): {
|
|
3
5
|
receive(message: InboundEnvelope): Promise<void>;
|
|
6
|
+
receiveFrame(frame: Frame): Promise<void>;
|
|
4
7
|
disconnect(): void;
|
|
5
8
|
};
|