@ghostlytools/cli 1.3.6 → 1.3.8
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 +15 -6
- package/SKILL.md +2 -0
- package/dist/assets/{api-Br3msjtR.js → api-CYG-sByy.js} +2 -2
- package/dist/assets/{api-z9mlywrn.js → api-Q6QZ0oIy.js} +51 -25
- package/dist/assets/api-Q6QZ0oIy.js.map +1 -0
- package/dist/assets/{apiKit-lX3Xx_hY.js → apiKit-C9lLXQwt.js} +2 -2
- package/dist/assets/{apiKit-lX3Xx_hY.js.map → apiKit-C9lLXQwt.js.map} +1 -1
- package/dist/assets/{apps-Dn7rCafG.js → apps-Bs8xpLGv.js} +1 -1
- package/dist/assets/{apps-BUK6bEKW.js → apps-tcynvhlC.js} +2 -2
- package/dist/assets/{apps-BUK6bEKW.js.map → apps-tcynvhlC.js.map} +1 -1
- package/dist/assets/{arkade-uqAXA5BT.js → arkade-BgmB0fUk.js} +2 -2
- package/dist/assets/{arkade-uqAXA5BT.js.map → arkade-BgmB0fUk.js.map} +1 -1
- package/dist/assets/{backup-_JnqeFZb.js → backup-OlEHNkqQ.js} +1 -1
- package/dist/assets/{backup-CJQK5Miu.js → backup-XtMACsQ0.js} +4 -4
- package/dist/assets/{backup-CJQK5Miu.js.map → backup-XtMACsQ0.js.map} +1 -1
- package/dist/assets/buttons-BoGOYSHb.js +2 -0
- package/dist/assets/{buttons-DDvTuViY.js → buttons-mdl2Gol2.js} +3 -3
- package/dist/assets/{buttons-DDvTuViY.js.map → buttons-mdl2Gol2.js.map} +1 -1
- package/dist/assets/daemonProof-B53VnZ1Z.js +100 -0
- package/dist/assets/daemonProof-B53VnZ1Z.js.map +1 -0
- package/dist/assets/{envelope-BqvBb6hC.js → envelope-DHf3mrHv.js} +2 -2
- package/dist/assets/{envelope-BqvBb6hC.js.map → envelope-DHf3mrHv.js.map} +1 -1
- package/dist/assets/{groupFiles-B1lL6wch.js → groupFiles-CqrujNN1.js} +7 -4
- package/dist/assets/groupFiles-CqrujNN1.js.map +1 -0
- package/dist/assets/{host-DFzlKU3P.js → host-Mz74S9cM.js} +50 -12
- package/dist/assets/host-Mz74S9cM.js.map +1 -0
- package/dist/assets/{hyperdhtRelay-DwlOY6aD.js → hyperdhtRelay-BnqdXvmv.js} +2 -2
- package/dist/assets/{hyperdhtRelay-DwlOY6aD.js.map → hyperdhtRelay-BnqdXvmv.js.map} +1 -1
- package/dist/assets/{irohWeb-DZDCyL9b.js → irohWeb-C8iKFl8d.js} +2 -2
- package/dist/assets/{irohWeb-DZDCyL9b.js.map → irohWeb-C8iKFl8d.js.map} +1 -1
- package/dist/assets/{main-DgbdDDif.js → main-BXwlJall.js} +149 -52
- package/dist/assets/main-BXwlJall.js.map +1 -0
- package/dist/assets/{mainline-BHE5-R3A.js → mainline-CbrPHUrZ.js} +2 -2
- package/dist/assets/{mainline-BHE5-R3A.js.map → mainline-CbrPHUrZ.js.map} +1 -1
- package/dist/assets/{networkReason-Btv4b2C4.js → networkReason-CrrB031Y.js} +2 -2
- package/dist/assets/{networkReason-Btv4b2C4.js.map → networkReason-CrrB031Y.js.map} +1 -1
- package/dist/assets/{nwc-z0pa5zql.js → nwc-Cu5zwrE8.js} +3 -3
- package/dist/assets/{nwc-z0pa5zql.js.map → nwc-Cu5zwrE8.js.map} +1 -1
- package/dist/assets/{nwcProvider-C1AhPoFW.js → nwcProvider-BVVFfJM5.js} +2 -2
- package/dist/assets/{nwcProvider-C1AhPoFW.js.map → nwcProvider-BVVFfJM5.js.map} +1 -1
- package/dist/assets/{registry-JrnwUWmh.js → registry-BKm8N_TI.js} +3 -3
- package/dist/assets/{registry-JrnwUWmh.js.map → registry-BKm8N_TI.js.map} +1 -1
- package/dist/assets/{registry-C09xXyx-.js → registry-CshC1EyV.js} +1 -1
- package/dist/assets/{resolve-Ssq1nDy4.js → resolve-DKGaPeMz.js} +2 -2
- package/dist/assets/{resolve-Ssq1nDy4.js.map → resolve-DKGaPeMz.js.map} +1 -1
- package/dist/assets/{server-D6FSznK5.js → server-CaDVxJKy.js} +53 -21
- package/dist/assets/{server-D6FSznK5.js.map → server-CaDVxJKy.js.map} +1 -1
- package/dist/assets/{src-XhjSWnp-.js → src-CVYir6mP.js} +152 -18
- package/dist/assets/src-CVYir6mP.js.map +1 -0
- package/dist/assets/{turnRefs-Cle33IoV.js → turnRefs-BeWsTX0o.js} +2 -2
- package/dist/assets/{turnRefs-Cle33IoV.js.map → turnRefs-BeWsTX0o.js.map} +1 -1
- package/dist/assets/{usdt-DO86yko2.js → usdt-C5Q0BWHr.js} +3 -3
- package/dist/assets/{usdt-DO86yko2.js.map → usdt-C5Q0BWHr.js.map} +1 -1
- package/dist/ghostly.mjs +1 -1
- package/package.json +1 -1
- package/dist/assets/api-z9mlywrn.js.map +0 -1
- package/dist/assets/buttons-DDB9Xdha.js +0 -2
- package/dist/assets/groupFiles-B1lL6wch.js.map +0 -1
- package/dist/assets/host-DFzlKU3P.js.map +0 -1
- package/dist/assets/main-DgbdDDif.js.map +0 -1
- package/dist/assets/privateFolder-Bk9C9oFv.js +0 -38
- package/dist/assets/privateFolder-Bk9C9oFv.js.map +0 -1
- package/dist/assets/src-XhjSWnp-.js.map +0 -1
|
@@ -1,9 +1,9 @@
|
|
|
1
|
-
import { $n as GROUP_FILE_LIMITS, Ja as PR_CHECKS, Xa as RUN_RESULTS, Ya as PR_STATES, Za as STATUS_CARD_LIMITS, qa as ITEM_STATES, to as cardUrl } from "./src-
|
|
2
|
-
import { a as SECRET_RESULTS, i as ENGINE_READS, r as ENGINE_METHODS, t as turnRef } from "./turnRefs-
|
|
1
|
+
import { $n as GROUP_FILE_LIMITS, Ja as PR_CHECKS, Xa as RUN_RESULTS, Ya as PR_STATES, Za as STATUS_CARD_LIMITS, qa as ITEM_STATES, to as cardUrl } from "./src-CVYir6mP.js";
|
|
2
|
+
import { a as SECRET_RESULTS, i as ENGINE_READS, r as ENGINE_METHODS, t as turnRef } from "./turnRefs-BeWsTX0o.js";
|
|
3
3
|
import { i as localFileError, n as EXIT, r as asCliError, t as CliError } from "./errors-B-zMxbcd.js";
|
|
4
|
-
import { t as CONTACT_KEY } from "./apiKit-
|
|
4
|
+
import { t as CONTACT_KEY } from "./apiKit-C9lLXQwt.js";
|
|
5
5
|
import { a as createProfile, c as listProfiles, d as profilePaths, f as selectProfile, i as checkProfileName, l as lockOwner, o as currentProfile, s as ghostlyHome, u as profileExists } from "./profiles-gPCjLOQq.js";
|
|
6
|
-
import {
|
|
6
|
+
import { a as provesDaemon, c as ownSocket, o as readDaemonSecret, r as newNonce, t as HELLO } from "./daemonProof-B53VnZ1Z.js";
|
|
7
7
|
import { accessSync, constants, existsSync, openSync, readFileSync, renameSync, rmSync, statSync, writeFileSync } from "node:fs";
|
|
8
8
|
import { dirname, resolve } from "node:path";
|
|
9
9
|
import { spawn } from "node:child_process";
|
|
@@ -12,7 +12,7 @@ import { createInterface } from "node:readline";
|
|
|
12
12
|
import { format } from "node:util";
|
|
13
13
|
var package_default = {
|
|
14
14
|
name: "@ghostlytools/cli",
|
|
15
|
-
version: "1.3.
|
|
15
|
+
version: "1.3.8",
|
|
16
16
|
type: "module",
|
|
17
17
|
description: "Ghostly for bots and terminals: the app's own engine, headless on Node, behind a daemon and a `ghostly` command with JSON output.",
|
|
18
18
|
license: "MIT",
|
|
@@ -230,18 +230,45 @@ function liftGlobals(argv) {
|
|
|
230
230
|
}
|
|
231
231
|
//#endregion
|
|
232
232
|
//#region src/client.ts
|
|
233
|
+
/** The id of the hello on every connection: a string, so it is never one of the calls' numbers. */
|
|
234
|
+
var HELLO_ID = "hello";
|
|
235
|
+
/** The refusal of a listener that did not prove it is the profile's daemon (`isNotTheDaemon` tells it apart). */
|
|
236
|
+
function notTheDaemon(socket) {
|
|
237
|
+
return new CliError("refused", `What answers on ${socket} did not prove it is this profile's daemon, so nothing was sent to it. A daemon of an older release cannot: \`ghostly daemon restart\` starts this one's`, { reason: "not-the-daemon" });
|
|
238
|
+
}
|
|
239
|
+
function isNotTheDaemon(error) {
|
|
240
|
+
return error instanceof CliError && error.code === "refused" && error.details?.reason === "not-the-daemon";
|
|
241
|
+
}
|
|
233
242
|
/**
|
|
234
243
|
* A connection to a profile's daemon over its socket (WISP 1100 § Local control API). `null` from `connectDaemon`
|
|
235
|
-
* means no daemon answers there: a one-shot command runs the profile itself.
|
|
244
|
+
* means no daemon answers there: a one-shot command runs the profile itself. *
|
|
245
|
+
* The first line on it is a `daemon.hello`, and no call is written until its answer proves the other end read the
|
|
246
|
+
* profile's daemon secret (`daemonProof.ts`): until then every call waits, and a listener that does not prove it gets
|
|
247
|
+
* every call refused (`refused`, `isNotTheDaemon`) having read nothing but the hello. Nothing it writes before that
|
|
248
|
+
* is read either.
|
|
236
249
|
*/
|
|
237
250
|
var DaemonClient = class {
|
|
238
251
|
socket;
|
|
252
|
+
address;
|
|
239
253
|
nextId = 1;
|
|
240
254
|
pending = /* @__PURE__ */ new Map();
|
|
241
255
|
eventListener = null;
|
|
242
256
|
closedListener = null;
|
|
243
|
-
|
|
257
|
+
verified = false;
|
|
258
|
+
refusal = null;
|
|
259
|
+
ready;
|
|
260
|
+
settle;
|
|
261
|
+
constructor(socket, address) {
|
|
244
262
|
this.socket = socket;
|
|
263
|
+
this.address = address;
|
|
264
|
+
this.ready = new Promise((resolve, reject) => {
|
|
265
|
+
this.settle = {
|
|
266
|
+
resolve,
|
|
267
|
+
reject
|
|
268
|
+
};
|
|
269
|
+
});
|
|
270
|
+
this.ready.catch(() => {});
|
|
271
|
+
const nonce = newNonce();
|
|
245
272
|
createInterface({
|
|
246
273
|
input: socket,
|
|
247
274
|
crlfDelay: Infinity
|
|
@@ -252,6 +279,17 @@ var DaemonClient = class {
|
|
|
252
279
|
} catch {
|
|
253
280
|
return;
|
|
254
281
|
}
|
|
282
|
+
if (!this.verified) {
|
|
283
|
+
if (this.refusal || message?.id !== HELLO_ID) return;
|
|
284
|
+
const secret = readDaemonSecret(this.address.dir);
|
|
285
|
+
if (!message.error && secret && provesDaemon(secret, nonce, message.result)) {
|
|
286
|
+
this.verified = true;
|
|
287
|
+
this.settle.resolve();
|
|
288
|
+
return;
|
|
289
|
+
}
|
|
290
|
+
this.refuse();
|
|
291
|
+
return;
|
|
292
|
+
}
|
|
255
293
|
if (message.event) {
|
|
256
294
|
this.eventListener?.(message.event);
|
|
257
295
|
return;
|
|
@@ -263,24 +301,41 @@ var DaemonClient = class {
|
|
|
263
301
|
else waiting.resolve(message.result);
|
|
264
302
|
});
|
|
265
303
|
socket.on("close", () => {
|
|
266
|
-
|
|
304
|
+
const why = this.refusal ?? new CliError("unavailable", "The daemon went away");
|
|
305
|
+
if (!this.verified) this.settle.reject(why);
|
|
306
|
+
for (const waiting of this.pending.values()) waiting.reject(why);
|
|
267
307
|
this.pending.clear();
|
|
268
308
|
this.closedListener?.();
|
|
269
309
|
});
|
|
270
310
|
socket.on("error", () => {});
|
|
311
|
+
socket.write(JSON.stringify({
|
|
312
|
+
id: HELLO_ID,
|
|
313
|
+
method: HELLO,
|
|
314
|
+
params: { nonce }
|
|
315
|
+
}) + "\n");
|
|
316
|
+
}
|
|
317
|
+
refuse() {
|
|
318
|
+
this.refusal = notTheDaemon(this.address.socket);
|
|
319
|
+
this.settle.reject(this.refusal);
|
|
320
|
+
this.socket.destroy();
|
|
271
321
|
}
|
|
272
322
|
call(method, params = {}) {
|
|
323
|
+
if (this.socket.destroyed && this.refusal) return Promise.reject(this.refusal);
|
|
273
324
|
const id = this.nextId++;
|
|
274
325
|
return new Promise((resolve, reject) => {
|
|
275
326
|
this.pending.set(id, {
|
|
276
327
|
resolve,
|
|
277
328
|
reject
|
|
278
329
|
});
|
|
279
|
-
this.
|
|
280
|
-
id
|
|
281
|
-
|
|
282
|
-
|
|
283
|
-
|
|
330
|
+
this.ready.then(() => {
|
|
331
|
+
if (this.pending.has(id) && !this.socket.destroyed) this.socket.write(JSON.stringify({
|
|
332
|
+
id,
|
|
333
|
+
method,
|
|
334
|
+
params
|
|
335
|
+
}) + "\n");
|
|
336
|
+
}, (error) => {
|
|
337
|
+
if (this.pending.delete(id)) reject(error);
|
|
338
|
+
});
|
|
284
339
|
});
|
|
285
340
|
}
|
|
286
341
|
/** Events after `since` (replayed from the journal), then every new one, until the connection closes. */
|
|
@@ -297,7 +352,12 @@ var DaemonClient = class {
|
|
|
297
352
|
this.socket.destroy();
|
|
298
353
|
}
|
|
299
354
|
};
|
|
300
|
-
|
|
355
|
+
/**
|
|
356
|
+
* `timeoutMs` bounds the connect only. The client it gives has sent its hello; whether the listener is the daemon is
|
|
357
|
+
* known at the first call (above).
|
|
358
|
+
*/
|
|
359
|
+
function connectDaemon(address, timeoutMs = 2e3) {
|
|
360
|
+
const path = address.socket;
|
|
301
361
|
if (!ownSocket(path)) return Promise.resolve(null);
|
|
302
362
|
return new Promise((resolve) => {
|
|
303
363
|
const socket = connect(path);
|
|
@@ -307,7 +367,7 @@ function connectDaemon(path, timeoutMs = 2e3) {
|
|
|
307
367
|
}, timeoutMs);
|
|
308
368
|
socket.once("connect", () => {
|
|
309
369
|
clearTimeout(timer);
|
|
310
|
-
resolve(new DaemonClient(socket));
|
|
370
|
+
resolve(new DaemonClient(socket, address));
|
|
311
371
|
});
|
|
312
372
|
socket.once("error", () => {
|
|
313
373
|
clearTimeout(timer);
|
|
@@ -882,7 +942,7 @@ var commands$8 = {
|
|
|
882
942
|
description: "Replace the three files when they are there"
|
|
883
943
|
}
|
|
884
944
|
},
|
|
885
|
-
run: async ({ options }, a) => (await import("./apps-
|
|
945
|
+
run: async ({ options }, a) => (await import("./apps-Bs8xpLGv.js")).initApp(a.dir, {
|
|
886
946
|
name: options.name,
|
|
887
947
|
title: options.title,
|
|
888
948
|
force: options.force === true
|
|
@@ -922,7 +982,7 @@ var commands$8 = {
|
|
|
922
982
|
description: "This version's sequence, higher than the bundle at --out's (default: one more than it)"
|
|
923
983
|
}
|
|
924
984
|
},
|
|
925
|
-
run: async ({ options }, a) => (await import("./apps-
|
|
985
|
+
run: async ({ options }, a) => (await import("./apps-Bs8xpLGv.js")).publishApp(a.dir, keyFile(options.key, "app publish <dir> --key <file> [--out <file>] [--sequence n]"), here(options.out), options.sequence)
|
|
926
986
|
},
|
|
927
987
|
"app revoke": {
|
|
928
988
|
method: "app.revoke",
|
|
@@ -955,7 +1015,7 @@ var commands$8 = {
|
|
|
955
1015
|
description: "Allow --up-to past the bundle's own sequence (versions published from elsewhere)"
|
|
956
1016
|
}
|
|
957
1017
|
},
|
|
958
|
-
run: async ({ options }, a) => (await import("./apps-
|
|
1018
|
+
run: async ({ options }, a) => (await import("./apps-Bs8xpLGv.js")).revokeApp(a.dir, keyFile(options.key, "app revoke <dir> --key <file> (--digest <digest>... | --up-to <sequence>) [--reason <text>]"), {
|
|
959
1019
|
digests: options.digest,
|
|
960
1020
|
upTo: options["up-to"],
|
|
961
1021
|
reason: options.reason,
|
|
@@ -1016,7 +1076,7 @@ var commands$8 = {
|
|
|
1016
1076
|
usage: "app verify <bundle|url>",
|
|
1017
1077
|
summary: "Check a .ghostlyapp as a client would, from a file or an https URL: its manifest and digest, or refused (exit 1) with the reason, revoked when the ghostly-revoke.json beside it revokes this version",
|
|
1018
1078
|
args: ["bundle"],
|
|
1019
|
-
run: async (_, a) => (await import("./apps-
|
|
1079
|
+
run: async (_, a) => (await import("./apps-Bs8xpLGv.js")).verifyApp(a.bundle)
|
|
1020
1080
|
},
|
|
1021
1081
|
"store sign": {
|
|
1022
1082
|
method: "store.sign",
|
|
@@ -1033,7 +1093,7 @@ var commands$8 = {
|
|
|
1033
1093
|
description: "The folder to write ghostly-store.json and ghostly-store.sig in (default: the index's)"
|
|
1034
1094
|
}
|
|
1035
1095
|
},
|
|
1036
|
-
run: async ({ options }, a) => (await import("./apps-
|
|
1096
|
+
run: async ({ options }, a) => (await import("./apps-Bs8xpLGv.js")).signStore(a.index, keyFile(options.key, "store sign <index> --key <file> [--out <dir>]"), here(options.out))
|
|
1037
1097
|
}
|
|
1038
1098
|
};
|
|
1039
1099
|
//#endregion
|
|
@@ -2223,20 +2283,22 @@ var commands$1 = {
|
|
|
2223
2283
|
},
|
|
2224
2284
|
"chat pay": {
|
|
2225
2285
|
method: "chat.pay",
|
|
2226
|
-
usage: "chat pay <chat> <sats> [--memo t] [--network testnet] [--confirm-real]",
|
|
2286
|
+
usage: "chat pay <chat> <sats> [--memo t] [--network testnet] [--confirm-real] [--force]",
|
|
2227
2287
|
summary: "Send ecash to a contact (Mainnet needs --confirm-real)",
|
|
2228
2288
|
args: ["chat", "amount"],
|
|
2229
2289
|
options: {
|
|
2230
2290
|
memo,
|
|
2231
2291
|
network: net,
|
|
2232
|
-
"confirm-real": confirmReal
|
|
2292
|
+
"confirm-real": confirmReal,
|
|
2293
|
+
force
|
|
2233
2294
|
},
|
|
2234
2295
|
params: ({ options }, a) => ({
|
|
2235
2296
|
chat: a.chat,
|
|
2236
2297
|
amount: sats(a.amount),
|
|
2237
2298
|
memo: options.memo,
|
|
2238
2299
|
network: options.network,
|
|
2239
|
-
confirmReal: options["confirm-real"] === true
|
|
2300
|
+
confirmReal: options["confirm-real"] === true,
|
|
2301
|
+
force: options.force === true
|
|
2240
2302
|
})
|
|
2241
2303
|
},
|
|
2242
2304
|
"chat pay-request": {
|
|
@@ -2267,7 +2329,7 @@ var commands$1 = {
|
|
|
2267
2329
|
},
|
|
2268
2330
|
"chat request": {
|
|
2269
2331
|
method: "chat.request",
|
|
2270
|
-
usage: "chat request <chat> <sats> [--memo t] [--method m] [--rail cashu|lightning] [--network testnet] [--card <id>]",
|
|
2332
|
+
usage: "chat request <chat> <sats> [--memo t] [--method m] [--rail cashu|lightning] [--network testnet] [--card <id>] [--force]",
|
|
2271
2333
|
summary: "Ask a contact to pay",
|
|
2272
2334
|
args: ["chat", "amount"],
|
|
2273
2335
|
options: {
|
|
@@ -2281,7 +2343,8 @@ var commands$1 = {
|
|
|
2281
2343
|
description: "cashu or lightning"
|
|
2282
2344
|
},
|
|
2283
2345
|
network: net,
|
|
2284
|
-
card
|
|
2346
|
+
card,
|
|
2347
|
+
force
|
|
2285
2348
|
},
|
|
2286
2349
|
params: ({ options }, a) => ({
|
|
2287
2350
|
chat: a.chat,
|
|
@@ -2290,7 +2353,8 @@ var commands$1 = {
|
|
|
2290
2353
|
method: options.method,
|
|
2291
2354
|
rail: options.rail,
|
|
2292
2355
|
network: options.network,
|
|
2293
|
-
card: options.card
|
|
2356
|
+
card: options.card,
|
|
2357
|
+
force: options.force === true
|
|
2294
2358
|
})
|
|
2295
2359
|
},
|
|
2296
2360
|
"lightning default": {
|
|
@@ -3061,10 +3125,20 @@ function runExec(command, event) {
|
|
|
3061
3125
|
child.stdin.end(JSON.stringify(event) + "\n");
|
|
3062
3126
|
});
|
|
3063
3127
|
}
|
|
3064
|
-
|
|
3065
|
-
|
|
3128
|
+
/** The longest wait between two tries of a webhook that is not answering. */
|
|
3129
|
+
var RETRY_MAX_MS = 6e4;
|
|
3130
|
+
/**
|
|
3131
|
+
* Posts one event; resolves true once the bridge took it, false when it refused it (a 4xx or a redirect, three times).
|
|
3132
|
+
* A bridge that is not there (refused connection, timeout, 5xx, 408, 429) has not handled the event: it is tried again,
|
|
3133
|
+
* waiting up to a minute between tries, for as long as it takes, so the cursor never moves past it. Before, three tries
|
|
3134
|
+
* in 3.5 s and the cursor moved on: a bridge restarting for longer lost every event of the time it was down, for good.
|
|
3135
|
+
*/
|
|
3136
|
+
async function post(url, event, retryMs) {
|
|
3137
|
+
let wait = retryMs, holding = false;
|
|
3138
|
+
for (let attempt = 0;; attempt++) {
|
|
3139
|
+
let down = true;
|
|
3066
3140
|
try {
|
|
3067
|
-
|
|
3141
|
+
const response = await fetch(url, {
|
|
3068
3142
|
method: "POST",
|
|
3069
3143
|
redirect: "manual",
|
|
3070
3144
|
headers: {
|
|
@@ -3074,11 +3148,22 @@ async function post(url, event) {
|
|
|
3074
3148
|
},
|
|
3075
3149
|
body: JSON.stringify(event),
|
|
3076
3150
|
signal: AbortSignal.timeout(1e4)
|
|
3077
|
-
})
|
|
3151
|
+
});
|
|
3152
|
+
response.body?.cancel().catch(() => {});
|
|
3153
|
+
if (response.ok) {
|
|
3154
|
+
if (holding) process.stderr.write(`ghostly: the webhook at ${url.href} answers again: event ${event.seq} taken\n`);
|
|
3155
|
+
return true;
|
|
3156
|
+
}
|
|
3157
|
+
down = response.status >= 500 || response.status === 408 || response.status === 429;
|
|
3078
3158
|
} catch {}
|
|
3079
|
-
|
|
3159
|
+
if (!down && attempt >= 2) return false;
|
|
3160
|
+
if (down && attempt >= 2 && !holding) {
|
|
3161
|
+
holding = true;
|
|
3162
|
+
process.stderr.write(`ghostly: the webhook at ${url.href} is not answering: holding event ${event.seq} (${event.type}) until it does\n`);
|
|
3163
|
+
}
|
|
3164
|
+
await new Promise((resolve) => setTimeout(resolve, wait));
|
|
3165
|
+
wait = Math.min(wait * 2, RETRY_MAX_MS);
|
|
3080
3166
|
}
|
|
3081
|
-
return false;
|
|
3082
3167
|
}
|
|
3083
3168
|
/**
|
|
3084
3169
|
* A handler that takes events in order, one at a time. A step that throws (the output closed, the allowlist's lookup,
|
|
@@ -3107,7 +3192,7 @@ function eventHandler(options) {
|
|
|
3107
3192
|
const code = await runExec(options.exec, event);
|
|
3108
3193
|
if (code !== 0) process.stderr.write(`ghostly: --exec exited ${code} on event ${event.seq} (${event.type})\n`);
|
|
3109
3194
|
}
|
|
3110
|
-
if (webhook && !await post(webhook, event)) process.stderr.write(`ghostly: the webhook did not take event ${event.seq} (${event.type})\n`);
|
|
3195
|
+
if (webhook && !await post(webhook, event, options.retryMs ?? 500)) process.stderr.write(`ghostly: the webhook did not take event ${event.seq} (${event.type})\n`);
|
|
3111
3196
|
if (full) await options.drained?.();
|
|
3112
3197
|
if (options.cursor) writeCursor(options.cursor, event.seq);
|
|
3113
3198
|
}).catch((error) => {
|
|
@@ -3241,8 +3326,8 @@ var VERSION = package_default.version;
|
|
|
3241
3326
|
* command a running daemon answers loads none of them, and starts about as fast as Node does. Statically imported, they
|
|
3242
3327
|
* cost every command ~100 ms before its socket was opened.
|
|
3243
3328
|
*/
|
|
3244
|
-
var engineApi = () => import("./api-
|
|
3245
|
-
var engineHost = () => import("./host-
|
|
3329
|
+
var engineApi = () => import("./api-CYG-sByy.js");
|
|
3330
|
+
var engineHost = () => import("./host-Mz74S9cM.js");
|
|
3246
3331
|
var pretty = false;
|
|
3247
3332
|
function print(value) {
|
|
3248
3333
|
process.stdout.write(JSON.stringify(value, null, pretty ? 2 : void 0) + "\n");
|
|
@@ -3338,7 +3423,7 @@ function readOnly(method, params) {
|
|
|
3338
3423
|
}
|
|
3339
3424
|
async function session(g, options) {
|
|
3340
3425
|
requireProfile(g);
|
|
3341
|
-
const client = await connectDaemon(g.paths
|
|
3426
|
+
const client = await connectDaemon(g.paths);
|
|
3342
3427
|
if (client) await warnVersion(client);
|
|
3343
3428
|
if (client) return {
|
|
3344
3429
|
mode: "daemon",
|
|
@@ -3706,7 +3791,7 @@ async function profileCommand(sub, argv) {
|
|
|
3706
3791
|
const [file, name] = parsed.positionals;
|
|
3707
3792
|
if (!file || !name) throw new CliError("usage", "ghostly profile restore <file> <new profile> [--passphrase-file f] [--use]");
|
|
3708
3793
|
noMoreThan(2, parsed.positionals, "profile restore <file> <new profile> [--passphrase-file f] [--use]");
|
|
3709
|
-
const { backupFileProtection, restoreProfile } = await import("./backup-
|
|
3794
|
+
const { backupFileProtection, restoreProfile } = await import("./backup-OlEHNkqQ.js");
|
|
3710
3795
|
const protection = await backupFileProtection(file);
|
|
3711
3796
|
const paths = await restoreProfile(g.home, checkProfileName(name), file, protection === "none" ? void 0 : backupPassphrase(parsed.options["passphrase-file"], RESTORE_PASSPHRASE));
|
|
3712
3797
|
if (parsed.options.use) selectProfile(g.home, name);
|
|
@@ -3769,7 +3854,7 @@ function backupPassphrase(file, missing = BACKUP_PASSPHRASE) {
|
|
|
3769
3854
|
}
|
|
3770
3855
|
async function runDaemon(g) {
|
|
3771
3856
|
requireProfile(g);
|
|
3772
|
-
if (await connectDaemon(g.paths
|
|
3857
|
+
if (await connectDaemon(g.paths)) throw new CliError("busy", `A daemon already runs profile ${g.profile}`);
|
|
3773
3858
|
const { keepServing, openHost, serve } = await engineHost();
|
|
3774
3859
|
const host = await openHost(g.paths, "daemon", VERSION);
|
|
3775
3860
|
let served;
|
|
@@ -3819,7 +3904,7 @@ async function daemonCommand(argv) {
|
|
|
3819
3904
|
].includes(sub)) noMoreThan(0, parsed.positionals, sub === "status" ? "daemon status" : sub ? `daemon ${sub} [--timeout s]` : "daemon [--detach] [--timeout s]");
|
|
3820
3905
|
if (sub === "status") {
|
|
3821
3906
|
knownProfile(g);
|
|
3822
|
-
const client = await connectDaemon(g.paths
|
|
3907
|
+
const client = await connectDaemon(g.paths);
|
|
3823
3908
|
if (!client) {
|
|
3824
3909
|
print({
|
|
3825
3910
|
running: false,
|
|
@@ -3842,7 +3927,7 @@ async function daemonCommand(argv) {
|
|
|
3842
3927
|
if (sub === "stop") {
|
|
3843
3928
|
knownProfile(g);
|
|
3844
3929
|
const stopFor = seconds(parsed, 20);
|
|
3845
|
-
const client = await connectDaemon(g.paths
|
|
3930
|
+
const client = await connectDaemon(g.paths);
|
|
3846
3931
|
if (!client) throw new CliError("not_found", `No daemon runs profile ${g.profile}`);
|
|
3847
3932
|
print({
|
|
3848
3933
|
stopped: true,
|
|
@@ -3852,7 +3937,7 @@ async function daemonCommand(argv) {
|
|
|
3852
3937
|
}
|
|
3853
3938
|
if (sub === "restart") {
|
|
3854
3939
|
const stopFor = seconds(parsed, 20), startFor = seconds(parsed, 60);
|
|
3855
|
-
const client = await connectDaemon(g.paths
|
|
3940
|
+
const client = await connectDaemon(g.paths);
|
|
3856
3941
|
const before = client ? (await client.call("status").catch(() => null))?.version ?? null : null;
|
|
3857
3942
|
print({
|
|
3858
3943
|
restarted: true,
|
|
@@ -3883,7 +3968,19 @@ function seconds(parsed, fallback) {
|
|
|
3883
3968
|
* the lock a moment before it exits); its pid.
|
|
3884
3969
|
*/
|
|
3885
3970
|
async function stopDaemon(g, client, seconds) {
|
|
3886
|
-
|
|
3971
|
+
let pid;
|
|
3972
|
+
try {
|
|
3973
|
+
({pid} = await client.call("daemon.stop"));
|
|
3974
|
+
} catch (error) {
|
|
3975
|
+
if (!isNotTheDaemon(error)) throw error;
|
|
3976
|
+
const holder = lockOwner(g.paths);
|
|
3977
|
+
if (holder === null) throw error;
|
|
3978
|
+
process.stderr.write(`ghostly: what answers on the socket did not prove it is this profile's daemon (an older release's cannot): stopping the process that holds the profile (${holder}) with SIGTERM\n`);
|
|
3979
|
+
pid = holder;
|
|
3980
|
+
try {
|
|
3981
|
+
process.kill(pid, "SIGTERM");
|
|
3982
|
+
} catch {}
|
|
3983
|
+
}
|
|
3887
3984
|
client.close();
|
|
3888
3985
|
const until = Date.now() + seconds * 1e3;
|
|
3889
3986
|
const running = () => lockOwner(g.paths) === pid || processAlive(pid);
|
|
@@ -3907,7 +4004,7 @@ function processAlive(pid) {
|
|
|
3907
4004
|
/** A daemon in the background, running this command's code, once its socket answers. */
|
|
3908
4005
|
async function startDetached(g, seconds) {
|
|
3909
4006
|
requireProfile(g);
|
|
3910
|
-
if (await connectDaemon(g.paths
|
|
4007
|
+
if (await connectDaemon(g.paths)) throw new CliError("busy", `A daemon already runs profile ${g.profile}`);
|
|
3911
4008
|
heldBy(g);
|
|
3912
4009
|
const log = openSync(g.paths.log, "a", 384);
|
|
3913
4010
|
const child = spawn(process.execPath, [
|
|
@@ -3932,7 +4029,7 @@ async function startDetached(g, seconds) {
|
|
|
3932
4029
|
while (!client && Date.now() < until) {
|
|
3933
4030
|
if (child.exitCode !== null) break;
|
|
3934
4031
|
await new Promise((resolve) => setTimeout(resolve, 200));
|
|
3935
|
-
client = await connectDaemon(g.paths
|
|
4032
|
+
client = await connectDaemon(g.paths, 500);
|
|
3936
4033
|
}
|
|
3937
4034
|
if (!client) {
|
|
3938
4035
|
heldBy(g, child.pid);
|
|
@@ -4030,11 +4127,11 @@ async function listenCommand(argv) {
|
|
|
4030
4127
|
});
|
|
4031
4128
|
};
|
|
4032
4129
|
requireProfile(g);
|
|
4033
|
-
const client = await connectDaemon(g.paths
|
|
4130
|
+
const client = await connectDaemon(g.paths);
|
|
4034
4131
|
if (client) await warnVersion(client);
|
|
4035
4132
|
if (client) {
|
|
4036
4133
|
const handle = await start((m, p) => client.call(m, p), async (chat) => {
|
|
4037
|
-
const c = await connectDaemon(g.paths
|
|
4134
|
+
const c = await connectDaemon(g.paths, 1e3);
|
|
4038
4135
|
if (!c) return null;
|
|
4039
4136
|
try {
|
|
4040
4137
|
return (await c.call("chat.get", { chat })).peer || null;
|
|
@@ -4051,7 +4148,7 @@ async function listenCommand(argv) {
|
|
|
4051
4148
|
await new Promise((resolve) => setTimeout(resolve, wait));
|
|
4052
4149
|
wait = 1e3;
|
|
4053
4150
|
if (current || feed.paused) return;
|
|
4054
|
-
const next = await connectDaemon(g.paths
|
|
4151
|
+
const next = await connectDaemon(g.paths, 1e3);
|
|
4055
4152
|
if (next) {
|
|
4056
4153
|
current = next;
|
|
4057
4154
|
await follow(next).catch(() => {
|
|
@@ -4233,7 +4330,7 @@ async function textCommand(name, argv) {
|
|
|
4233
4330
|
};
|
|
4234
4331
|
if (spec.target === "group") params.mentions = parsed.options.mention ?? [];
|
|
4235
4332
|
if (parsed.options.reply !== void 0) params.reply = parsed.options.reply;
|
|
4236
|
-
if (!spec.message) Object.assign(params, (await import("./buttons-
|
|
4333
|
+
if (!spec.message) Object.assign(params, (await import("./buttons-BoGOYSHb.js")).buttonsOf(parsed.options));
|
|
4237
4334
|
print(await withSession(g, (s) => {
|
|
4238
4335
|
if (spec.target === "chat") {
|
|
4239
4336
|
params.wait = parsed.options.wait ?? (s.mode === "one-shot" ? spec.message ? "confirmed" : "sent" : "none");
|
|
@@ -4291,10 +4388,10 @@ async function identityAddCommand(argv) {
|
|
|
4291
4388
|
if (event.type === "identity.approval" || event.type === "identity.progress") process.stderr.write(JSON.stringify(event) + "\n");
|
|
4292
4389
|
};
|
|
4293
4390
|
requireProfile(g);
|
|
4294
|
-
const client = await connectDaemon(g.paths
|
|
4391
|
+
const client = await connectDaemon(g.paths);
|
|
4295
4392
|
if (client) {
|
|
4296
4393
|
await warnVersion(client);
|
|
4297
|
-
const watcher = await connectDaemon(g.paths
|
|
4394
|
+
const watcher = await connectDaemon(g.paths);
|
|
4298
4395
|
await watcher?.subscribe(void 0, tell);
|
|
4299
4396
|
try {
|
|
4300
4397
|
print(await client.call("identity.add", params));
|
|
@@ -4369,7 +4466,7 @@ async function callPipeCommand(argv) {
|
|
|
4369
4466
|
const parsed = parseArgs(argv, {}, idSlot({ args: ["call...?"] }));
|
|
4370
4467
|
const g = globals(parsed);
|
|
4371
4468
|
const ref = parsed.positionals.join(" ") || void 0;
|
|
4372
|
-
const client = await connectDaemon(g.paths
|
|
4469
|
+
const client = await connectDaemon(g.paths);
|
|
4373
4470
|
if (!client) throw new CliError("unavailable", `No daemon runs profile ${g.profile}: calls need one (ghostly daemon --detach)`);
|
|
4374
4471
|
let call;
|
|
4375
4472
|
try {
|
|
@@ -4517,4 +4614,4 @@ async function run(argv) {
|
|
|
4517
4614
|
//#endregion
|
|
4518
4615
|
export { run };
|
|
4519
4616
|
|
|
4520
|
-
//# sourceMappingURL=main-
|
|
4617
|
+
//# sourceMappingURL=main-BXwlJall.js.map
|