@ghostlytools/cli 1.3.0 → 1.3.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 +9 -3
- package/dist/assets/{api-BiaX6l6f.js → api-SYPJgFRU.js} +2 -2
- package/dist/assets/{api-CrxVxtY1.js → api-aup3Amud.js} +141 -40
- package/dist/assets/api-aup3Amud.js.map +1 -0
- package/dist/assets/{apiKit-CajiDxdK.js → apiKit-DYkVEs6r.js} +30 -30
- package/dist/assets/apiKit-DYkVEs6r.js.map +1 -0
- package/dist/assets/{apps-t23gkc28.js → apps-DcZKu29s.js} +1 -1
- package/dist/assets/{apps-CbfiCSIw.js → apps-Rbk2HHXb.js} +3 -4
- package/dist/assets/{apps-CbfiCSIw.js.map → apps-Rbk2HHXb.js.map} +1 -1
- package/dist/assets/{arkade-D4BVJFEQ.js → arkade-CuWlNnCz.js} +4 -4
- package/dist/assets/arkade-CuWlNnCz.js.map +1 -0
- package/dist/assets/{backup-BAMi2lAq.js → backup-CJWLDHuS.js} +8 -8
- package/dist/assets/backup-CJWLDHuS.js.map +1 -0
- package/dist/assets/{backup-Cg52WeQi.js → backup-CSMw2GHv.js} +1 -1
- package/dist/assets/bark_ffi_wasm_bg-EY2uc0Bx.js.map +1 -1
- package/dist/assets/bitcoind-CZchoh43.js +349 -0
- package/dist/assets/bitcoind-CZchoh43.js.map +1 -0
- package/dist/assets/bitcoindProvider-DGw3xBSa.js +97 -0
- package/dist/assets/bitcoindProvider-DGw3xBSa.js.map +1 -0
- package/dist/assets/bitcoindevkit_bg-B-iLWrmX.js.map +1 -1
- package/dist/assets/buttons-CGRqZ7z0.js +2 -0
- package/dist/assets/{buttons-CX1pKB0j.js → buttons-QEnAGWoC.js} +4 -5
- package/dist/assets/{buttons-CX1pKB0j.js.map → buttons-QEnAGWoC.js.map} +1 -1
- package/dist/assets/{endpoint-Dn7H8qE1.js → endpoint-BOTFMpfS.js} +44 -12
- package/dist/assets/endpoint-BOTFMpfS.js.map +1 -0
- package/dist/assets/{envelope-BvU0fLEt.js → envelope-K27mzoyu.js} +2 -2
- package/dist/assets/{envelope-BvU0fLEt.js.map → envelope-K27mzoyu.js.map} +1 -1
- package/dist/assets/{errors-my6VJR_0.js → errors-DO5z6h_l.js} +29 -1
- package/dist/assets/errors-DO5z6h_l.js.map +1 -0
- package/dist/assets/fedimint_client_wasm_bg-BtHHlFpp.js.map +1 -1
- package/dist/assets/groupFiles-DHTrTA4I.js +3229 -0
- package/dist/assets/groupFiles-DHTrTA4I.js.map +1 -0
- package/dist/assets/{host-Cmd205Dc.js → host-C7hA-Za7.js} +135 -42
- package/dist/assets/host-C7hA-Za7.js.map +1 -0
- package/dist/assets/{hyperdhtRelay-CEmBpT0Q.js → hyperdhtRelay-BVoWY2ua.js} +2 -3
- package/dist/assets/{hyperdhtRelay-CEmBpT0Q.js.map → hyperdhtRelay-BVoWY2ua.js.map} +1 -1
- package/dist/assets/{irohWeb--YyEA-hX.js → irohWeb-BJPk9bMn.js} +2 -3
- package/dist/assets/{irohWeb--YyEA-hX.js.map → irohWeb-BJPk9bMn.js.map} +1 -1
- package/dist/assets/{main-BzNN6bkx.js → main-DC8cUkDx.js} +142 -35
- package/dist/assets/main-DC8cUkDx.js.map +1 -0
- package/dist/assets/{mainline-D5D5C-jT.js → mainline-CxbxpoU4.js} +2 -2
- package/dist/assets/{mainline-D5D5C-jT.js.map → mainline-CxbxpoU4.js.map} +1 -1
- package/dist/assets/{networkReason-DxZWHw6v.js → networkReason-D42iNuUB.js} +2 -2
- package/dist/assets/{networkReason-DxZWHw6v.js.map → networkReason-D42iNuUB.js.map} +1 -1
- package/dist/assets/nwc-Cm4sYgLv.js +612 -0
- package/dist/assets/nwc-Cm4sYgLv.js.map +1 -0
- package/dist/assets/nwcProvider-0D7vdPDd.js +77 -0
- package/dist/assets/nwcProvider-0D7vdPDd.js.map +1 -0
- package/dist/assets/{profiles-B6F4oa9K.js → profiles-BHc9pEYg.js} +2 -2
- package/dist/assets/{profiles-B6F4oa9K.js.map → profiles-BHc9pEYg.js.map} +1 -1
- package/dist/assets/registry-CLolR0kM.js +2 -0
- package/dist/assets/{groupFiles-BNTSDaoq.js → registry-CVdSZW5l.js} +19 -3911
- package/dist/assets/registry-CVdSZW5l.js.map +1 -0
- package/dist/assets/resolve-BnlEajYz.js +591 -0
- package/dist/assets/resolve-BnlEajYz.js.map +1 -0
- package/dist/assets/{server-CBCEYKMN.js → server-CJNEKxzE.js} +284 -1202
- package/dist/assets/server-CJNEKxzE.js.map +1 -0
- package/dist/assets/{src-DhfGgAUu.js → src-yMUQvdyL.js} +2264 -71
- package/dist/assets/src-yMUQvdyL.js.map +1 -0
- package/dist/assets/{turnRefs-ChEfgbSX.js → turnRefs-B2a8to9q.js} +2 -2
- package/dist/assets/{turnRefs-ChEfgbSX.js.map → turnRefs-B2a8to9q.js.map} +1 -1
- package/dist/assets/types-C4_KafL_.js +122 -0
- package/dist/assets/types-C4_KafL_.js.map +1 -0
- package/dist/assets/{usdt-C1Xao2xH.js → usdt-DesFeDiG.js} +3 -3
- package/dist/assets/{usdt-C1Xao2xH.js.map → usdt-DesFeDiG.js.map} +1 -1
- package/dist/ghostly.mjs +1 -1
- package/package.json +1 -1
- package/dist/assets/api-CrxVxtY1.js.map +0 -1
- package/dist/assets/apiKit-CajiDxdK.js.map +0 -1
- package/dist/assets/arkade-D4BVJFEQ.js.map +0 -1
- package/dist/assets/backup-BAMi2lAq.js.map +0 -1
- package/dist/assets/buttons-CWl2yNJu.js +0 -2
- package/dist/assets/endpoint-Dn7H8qE1.js.map +0 -1
- package/dist/assets/errors-my6VJR_0.js.map +0 -1
- package/dist/assets/groupFiles-BNTSDaoq.js.map +0 -1
- package/dist/assets/groupFiles-DBbjOLuD.js +0 -2088
- package/dist/assets/groupFiles-DBbjOLuD.js.map +0 -1
- package/dist/assets/host-Cmd205Dc.js.map +0 -1
- package/dist/assets/main-BzNN6bkx.js.map +0 -1
- package/dist/assets/server-CBCEYKMN.js.map +0 -1
- package/dist/assets/src-DhfGgAUu.js.map +0 -1
|
@@ -1,13 +1,12 @@
|
|
|
1
|
-
import {
|
|
2
|
-
import {
|
|
3
|
-
import {
|
|
4
|
-
import {
|
|
5
|
-
import {
|
|
6
|
-
import {
|
|
7
|
-
import { n as RESTORED_MARK, r as acquireLock } from "./profiles-B6F4oa9K.js";
|
|
1
|
+
import { $o as parseCallSignal, Jo as answersOffer, Ko as CALL_SIGNAL_MAX_AGE_MS, Qo as extractParamsFromSdp, Xo as callRtcConfig, Yo as buildSdpFromSignal, Zo as callSignalHeardAt, ai as checkPushEndpoint, el as setLinkTraceSink, es as signalHasVideo, ki as isPublicAddress, qo as RTC_CONFIG, yl as fromBase64Url } from "./src-yMUQvdyL.js";
|
|
2
|
+
import { a as fedimintSdkOn, r as irohRelayProblem } from "./irohWeb-BJPk9bMn.js";
|
|
3
|
+
import { r as asCliError, t as CliError } from "./errors-DO5z6h_l.js";
|
|
4
|
+
import { a as findChat } from "./apiKit-DYkVEs6r.js";
|
|
5
|
+
import { _ as flushCardUpdates, c as paymentJson, d as nodeLocalFetch, f as chatJson, g as resumeHolds, h as groupMessageJson, l as reportAppFrames, m as groupJson, p as chatMessageJson, r as callApi, u as servedApps } from "./api-aup3Amud.js";
|
|
6
|
+
import { n as RESTORED_MARK, r as acquireLock } from "./profiles-BHc9pEYg.js";
|
|
8
7
|
import { r as privateFolder, t as ownFolder } from "./privateFolder-Bk9C9oFv.js";
|
|
9
8
|
import { createRequire } from "node:module";
|
|
10
|
-
import { appendFileSync, chmodSync, closeSync, existsSync, fstatSync, fsyncSync, lstatSync, mkdirSync, openSync, readFileSync, readdirSync, renameSync, rmSync, statSync, writeFileSync, writeSync } from "node:fs";
|
|
9
|
+
import { appendFileSync, chmodSync, closeSync, existsSync, fstatSync, fsyncSync, lstatSync, mkdirSync, openSync, readFileSync, readSync, readdirSync, renameSync, rmSync, statSync, writeFileSync, writeSync } from "node:fs";
|
|
11
10
|
import { readFile } from "node:fs/promises";
|
|
12
11
|
import { dirname, join } from "node:path";
|
|
13
12
|
import { createHash, randomBytes } from "node:crypto";
|
|
@@ -910,8 +909,14 @@ var CallManager = class {
|
|
|
910
909
|
calls = /* @__PURE__ */ new Map();
|
|
911
910
|
/** Per chat: the timestamp of the last signal handled. */
|
|
912
911
|
lastSignal = /* @__PURE__ */ new Map();
|
|
912
|
+
/** Per chat: the timestamp of the last signal sent (`stamp`). */
|
|
913
|
+
lastSent = /* @__PURE__ */ new Map();
|
|
913
914
|
/** Per chat: the timer that clears the hang-up signal. */
|
|
914
915
|
clearing = /* @__PURE__ */ new Map();
|
|
916
|
+
/** Per chat: when this side's last call there ended before it was answered (`CALL_PACE_MS`). */
|
|
917
|
+
unansweredAt = /* @__PURE__ */ new Map();
|
|
918
|
+
/** The early answers being made, those of ended calls too (MAX_EARLY_ANSWERS). */
|
|
919
|
+
makings = /* @__PURE__ */ new Set();
|
|
915
920
|
auto;
|
|
916
921
|
configPath;
|
|
917
922
|
stopping = false;
|
|
@@ -924,6 +929,15 @@ var CallManager = class {
|
|
|
924
929
|
get now() {
|
|
925
930
|
return (this.host.now ?? Date.now)();
|
|
926
931
|
}
|
|
932
|
+
/**
|
|
933
|
+
* A new signal's timestamp in a chat: now, or 1 ms after the last one sent there. The contact drops a signal no
|
|
934
|
+
* newer than the last it heard, so a redial or a hang-up in the same millisecond as the signal before it would be lost.
|
|
935
|
+
*/
|
|
936
|
+
stamp(chat) {
|
|
937
|
+
const ts = Math.max(this.now, (this.lastSent.get(chat) ?? 0) + 1);
|
|
938
|
+
this.lastSent.set(chat, ts);
|
|
939
|
+
return ts;
|
|
940
|
+
}
|
|
927
941
|
/** A signal the contact's app sent in a chat (the engine's `call-signal`). */
|
|
928
942
|
onSignal(chat, json) {
|
|
929
943
|
if (this.stopping) return;
|
|
@@ -1035,7 +1049,7 @@ var CallManager = class {
|
|
|
1035
1049
|
try {
|
|
1036
1050
|
const stack = await this.stack();
|
|
1037
1051
|
if (!await this.connect(call, (media) => CallMedia.offer(stack, media))) return;
|
|
1038
|
-
call.offerTs = this.
|
|
1052
|
+
call.offerTs = this.stamp(call.chat);
|
|
1039
1053
|
call.offering = true;
|
|
1040
1054
|
await this.send(call.chat, {
|
|
1041
1055
|
t: "o",
|
|
@@ -1059,7 +1073,7 @@ var CallManager = class {
|
|
|
1059
1073
|
if (!await this.connect(call, (media) => CallMedia.answer(stack, offer, media))) return;
|
|
1060
1074
|
await this.send(call.chat, {
|
|
1061
1075
|
t: "a",
|
|
1062
|
-
ts: this.
|
|
1076
|
+
ts: this.stamp(call.chat),
|
|
1063
1077
|
o: offer.ts,
|
|
1064
1078
|
...call.media.local,
|
|
1065
1079
|
v: 0
|
|
@@ -1075,11 +1089,15 @@ var CallManager = class {
|
|
|
1075
1089
|
*/
|
|
1076
1090
|
prepare(call) {
|
|
1077
1091
|
if (this.host.answers === false || call.ended || call.state !== "ringing") return;
|
|
1092
|
+
this.stopEarly(call);
|
|
1078
1093
|
call.earlyTimer = setTimeout(() => this.prepare(call), this.host.earlyAnswerMs ?? 3e4);
|
|
1079
1094
|
call.earlyTimer.unref?.();
|
|
1080
1095
|
if (call.making) return;
|
|
1096
|
+
const held = [...this.calls.values()].filter((c) => c !== call && c.early).length;
|
|
1097
|
+
if (this.makings.size + held >= 4 || [...this.makings].some((m) => m.chat === call.chat)) return;
|
|
1081
1098
|
const offer = call.offer;
|
|
1082
1099
|
const making = {
|
|
1100
|
+
chat: call.chat,
|
|
1083
1101
|
done: this.stack().then((stack) => EarlyAnswer.open(stack, offer, {
|
|
1084
1102
|
iceServers: this.host.engine.getState().settings?.iceServers ?? [],
|
|
1085
1103
|
log: (line) => process.stderr.write(`ghostly: call ${call.id}: ${line}\n`)
|
|
@@ -1091,15 +1109,19 @@ var CallManager = class {
|
|
|
1091
1109
|
claimed: false
|
|
1092
1110
|
};
|
|
1093
1111
|
call.making = making;
|
|
1112
|
+
this.makings.add(making);
|
|
1094
1113
|
making.done.then((early) => {
|
|
1114
|
+
this.makings.delete(making);
|
|
1095
1115
|
if (call.making === making) call.making = null;
|
|
1096
|
-
if (making.claimed
|
|
1097
|
-
|
|
1098
|
-
|
|
1099
|
-
|
|
1116
|
+
if (!making.claimed && early) {
|
|
1117
|
+
if (call.ended || call.state !== "ringing") early.close();
|
|
1118
|
+
else {
|
|
1119
|
+
call.early?.close();
|
|
1120
|
+
call.early = early;
|
|
1121
|
+
}
|
|
1100
1122
|
}
|
|
1101
|
-
|
|
1102
|
-
call.
|
|
1123
|
+
const next = this.byChat(making.chat);
|
|
1124
|
+
if (next && next !== call && next.direction === "in" && !next.making && !next.early) this.prepare(next);
|
|
1103
1125
|
});
|
|
1104
1126
|
}
|
|
1105
1127
|
/** The answered call's early answer: the one made, if still good, or the one being made; none from then on. */
|
|
@@ -1122,6 +1144,7 @@ var CallManager = class {
|
|
|
1122
1144
|
async start(chat, options) {
|
|
1123
1145
|
const link = this.callable(chat);
|
|
1124
1146
|
if (this.byChat(link.id)) throw new CliError("busy", "A call is already on in this chat");
|
|
1147
|
+
this.paced(link.id);
|
|
1125
1148
|
const rate = rateOf(options.rate, this.auto.rate);
|
|
1126
1149
|
const stack = await this.stack();
|
|
1127
1150
|
if (this.byChat(link.id)) throw new CliError("busy", "A call is already on in this chat");
|
|
@@ -1130,7 +1153,7 @@ var CallManager = class {
|
|
|
1130
1153
|
await this.attach(call, (media) => CallMedia.offer(stack, media));
|
|
1131
1154
|
if (call.reason === "crossed") throw new CliError("busy", "The contact called at the same time: their call rings here");
|
|
1132
1155
|
if (call.ended) throw new CliError("unavailable", "The call ended before it was placed");
|
|
1133
|
-
call.offerTs = this.
|
|
1156
|
+
call.offerTs = this.stamp(link.id);
|
|
1134
1157
|
call.offering = true;
|
|
1135
1158
|
await this.send(link.id, {
|
|
1136
1159
|
t: "o",
|
|
@@ -1168,7 +1191,7 @@ var CallManager = class {
|
|
|
1168
1191
|
if (call.ended) throw new CliError("unavailable", "The call ended before it was answered");
|
|
1169
1192
|
await this.send(call.chat, {
|
|
1170
1193
|
t: "a",
|
|
1171
|
-
ts: this.
|
|
1194
|
+
ts: this.stamp(call.chat),
|
|
1172
1195
|
o: call.offer.ts,
|
|
1173
1196
|
...call.media.local,
|
|
1174
1197
|
v: 0
|
|
@@ -1388,6 +1411,7 @@ var CallManager = class {
|
|
|
1388
1411
|
this.disarm(call);
|
|
1389
1412
|
if (call.watcher) clearInterval(call.watcher);
|
|
1390
1413
|
this.calls.delete(call.id);
|
|
1414
|
+
if (call.direction === "out" && call.connectedAt === null && call.state === "ringing" && (reason === "hangup" || reason === "unanswered")) this.unansweredAt.set(call.chat, this.now);
|
|
1391
1415
|
if (report) process.stderr.write(`ghostly: call ${call.id}: ended (${reason})${call.media ? `, ice ${call.media.ice.state}` : ""}\n`);
|
|
1392
1416
|
call.media?.close();
|
|
1393
1417
|
this.stopEarly(call);
|
|
@@ -1397,7 +1421,7 @@ var CallManager = class {
|
|
|
1397
1421
|
if (tell) {
|
|
1398
1422
|
await this.send(call.chat, {
|
|
1399
1423
|
t: "h",
|
|
1400
|
-
ts: this.
|
|
1424
|
+
ts: this.stamp(call.chat)
|
|
1401
1425
|
}).catch(() => {});
|
|
1402
1426
|
if (!this.stopping) {
|
|
1403
1427
|
const timer = setTimeout(() => {
|
|
@@ -1416,6 +1440,17 @@ var CallManager = class {
|
|
|
1416
1440
|
...call.connectedAt !== null ? { duration: this.now - call.connectedAt } : {}
|
|
1417
1441
|
});
|
|
1418
1442
|
}
|
|
1443
|
+
/** Refuses a call placed too soon after this side's last unanswered one in the chat (`CALL_PACE_MS`). */
|
|
1444
|
+
paced(chat) {
|
|
1445
|
+
const pace = this.host.callPaceMs ?? 2e3, last = this.unansweredAt.get(chat);
|
|
1446
|
+
if (!pace || last === void 0) return;
|
|
1447
|
+
const left = last + pace - this.now;
|
|
1448
|
+
if (left <= 0) {
|
|
1449
|
+
this.unansweredAt.delete(chat);
|
|
1450
|
+
return;
|
|
1451
|
+
}
|
|
1452
|
+
throw new CliError("busy", `Your last call in this chat ended unanswered a moment ago: call again in ${Math.ceil(left / 100) / 10} s`, { retryAfterMs: left });
|
|
1453
|
+
}
|
|
1419
1454
|
arm(call, ms, reason, tell) {
|
|
1420
1455
|
this.disarm(call);
|
|
1421
1456
|
call.timer = setTimeout(() => void this.end(call, reason, tell), ms);
|
|
@@ -1537,6 +1572,8 @@ function readAuto(path) {
|
|
|
1537
1572
|
return off;
|
|
1538
1573
|
}
|
|
1539
1574
|
}
|
|
1575
|
+
/** A journal past this is trimmed, and only this much of its end is ever read. */
|
|
1576
|
+
var JOURNAL_MAX_BYTES = 33554432;
|
|
1540
1577
|
var SEEN_DB = "ghostly-cli";
|
|
1541
1578
|
var SEEN = "seen";
|
|
1542
1579
|
/**
|
|
@@ -1562,6 +1599,7 @@ var EventHub = class {
|
|
|
1562
1599
|
seenDb;
|
|
1563
1600
|
seq = 0;
|
|
1564
1601
|
journalLines = 0;
|
|
1602
|
+
journalBytes = 0;
|
|
1565
1603
|
listeners = /* @__PURE__ */ new Set();
|
|
1566
1604
|
stateListeners = /* @__PURE__ */ new Set();
|
|
1567
1605
|
callListeners = /* @__PURE__ */ new Set();
|
|
@@ -1598,13 +1636,24 @@ var EventHub = class {
|
|
|
1598
1636
|
}
|
|
1599
1637
|
/** Loads the journal's last seq and the seen set; call before `sink` is attached. */
|
|
1600
1638
|
async open() {
|
|
1601
|
-
|
|
1602
|
-
|
|
1603
|
-
|
|
1604
|
-
|
|
1605
|
-
this.
|
|
1606
|
-
|
|
1639
|
+
try {
|
|
1640
|
+
if (existsSync(this.journalPath)) {
|
|
1641
|
+
const { lines, size } = journalTail(this.journalPath);
|
|
1642
|
+
this.journalLines = lines.length;
|
|
1643
|
+
this.journalBytes = size;
|
|
1644
|
+
for (let i = lines.length - 1; i >= 0; i--) try {
|
|
1645
|
+
this.seq = JSON.parse(lines[i]).seq;
|
|
1646
|
+
break;
|
|
1647
|
+
} catch {}
|
|
1648
|
+
if (size > 33554432 || lines.length > 2e4) this.trimJournal();
|
|
1649
|
+
}
|
|
1650
|
+
} catch (error) {
|
|
1651
|
+
process.stderr.write(`ghostly: the event journal could not be read, a new one begins: ${error instanceof Error ? error.message : String(error)}\n`);
|
|
1652
|
+
try {
|
|
1653
|
+
renameSync(this.journalPath, this.journalPath + ".unreadable");
|
|
1607
1654
|
} catch {}
|
|
1655
|
+
this.journalLines = 0;
|
|
1656
|
+
this.journalBytes = 0;
|
|
1608
1657
|
}
|
|
1609
1658
|
this.db = await new Promise((resolve, reject) => {
|
|
1610
1659
|
const request = indexedDB.open(this.seenDb, 1);
|
|
@@ -1729,13 +1778,10 @@ var EventHub = class {
|
|
|
1729
1778
|
replay(since) {
|
|
1730
1779
|
if (!existsSync(this.journalPath) || since >= this.seq) return [];
|
|
1731
1780
|
const out = [];
|
|
1732
|
-
for (const line of
|
|
1733
|
-
|
|
1734
|
-
|
|
1735
|
-
|
|
1736
|
-
if (event.seq > since) out.push(event);
|
|
1737
|
-
} catch {}
|
|
1738
|
-
}
|
|
1781
|
+
for (const line of journalTail(this.journalPath).lines) try {
|
|
1782
|
+
const event = JSON.parse(line);
|
|
1783
|
+
if (event.seq > since) out.push(event);
|
|
1784
|
+
} catch {}
|
|
1739
1785
|
if (out.length && out[0].seq > since + 1) out.unshift({
|
|
1740
1786
|
seq: since,
|
|
1741
1787
|
id: `events.gap:${since}:${out[0].seq}`,
|
|
@@ -1758,18 +1804,29 @@ var EventHub = class {
|
|
|
1758
1804
|
at: this.now(),
|
|
1759
1805
|
...fields
|
|
1760
1806
|
};
|
|
1761
|
-
|
|
1762
|
-
|
|
1807
|
+
try {
|
|
1808
|
+
const line = JSON.stringify(event) + "\n";
|
|
1809
|
+
appendFileSync(this.journalPath, line, { mode: 384 });
|
|
1810
|
+
this.journalBytes += Buffer.byteLength(line);
|
|
1811
|
+
if (++this.journalLines > 2e4 || this.journalBytes > 33554432) this.trimJournal();
|
|
1812
|
+
} catch (error) {
|
|
1813
|
+
process.stderr.write(`ghostly: event journal error: ${error instanceof Error ? error.message : String(error)}\n`);
|
|
1814
|
+
}
|
|
1763
1815
|
for (const listener of this.listeners) try {
|
|
1764
1816
|
listener(event);
|
|
1765
1817
|
} catch {}
|
|
1766
1818
|
return event;
|
|
1767
1819
|
}
|
|
1820
|
+
/** Keeps the last `JOURNAL_KEEP` events, and of them no more than `JOURNAL_KEEP_BYTES`. */
|
|
1768
1821
|
trimJournal() {
|
|
1769
|
-
const lines =
|
|
1770
|
-
|
|
1822
|
+
const lines = journalTail(this.journalPath).lines.slice(-1e4);
|
|
1823
|
+
let start = lines.length, bytes = 0;
|
|
1824
|
+
while (start > 0 && bytes + Buffer.byteLength(lines[start - 1]) + 1 <= 16777216) bytes += Buffer.byteLength(lines[--start]) + 1;
|
|
1825
|
+
const kept = lines.slice(start);
|
|
1826
|
+
writeFileSync(this.journalPath + ".tmp", kept.length ? kept.join("\n") + "\n" : "", { mode: 384 });
|
|
1771
1827
|
renameSync(this.journalPath + ".tmp", this.journalPath);
|
|
1772
|
-
this.journalLines =
|
|
1828
|
+
this.journalLines = kept.length;
|
|
1829
|
+
this.journalBytes = bytes;
|
|
1773
1830
|
}
|
|
1774
1831
|
handle(message) {
|
|
1775
1832
|
switch (message.kind) {
|
|
@@ -2327,6 +2384,32 @@ function groupShape(group) {
|
|
|
2327
2384
|
pin: group.pin ?? null
|
|
2328
2385
|
};
|
|
2329
2386
|
}
|
|
2387
|
+
/**
|
|
2388
|
+
* The journal's whole lines within its last `JOURNAL_MAX_BYTES`, and its size: never the whole file as one string, so
|
|
2389
|
+
* a journal grown past what a string can hold (or a trim's bound) is still read, and in bounded time.
|
|
2390
|
+
*/
|
|
2391
|
+
function journalTail(path) {
|
|
2392
|
+
const fd = openSync(path, "r");
|
|
2393
|
+
try {
|
|
2394
|
+
const size = fstatSync(fd).size;
|
|
2395
|
+
const from = Math.max(0, size - JOURNAL_MAX_BYTES - 1);
|
|
2396
|
+
const buffer = Buffer.alloc(size - from);
|
|
2397
|
+
let read = 0;
|
|
2398
|
+
while (read < buffer.length) {
|
|
2399
|
+
const n = readSync(fd, buffer, read, buffer.length - read, from + read);
|
|
2400
|
+
if (!n) break;
|
|
2401
|
+
read += n;
|
|
2402
|
+
}
|
|
2403
|
+
const lines = buffer.toString("utf8", 0, read).split("\n");
|
|
2404
|
+
if (from > 0) lines.shift();
|
|
2405
|
+
return {
|
|
2406
|
+
lines: lines.filter(Boolean),
|
|
2407
|
+
size
|
|
2408
|
+
};
|
|
2409
|
+
} finally {
|
|
2410
|
+
closeSync(fd);
|
|
2411
|
+
}
|
|
2412
|
+
}
|
|
2330
2413
|
//#endregion
|
|
2331
2414
|
//#region src/runtime/fedimint.ts
|
|
2332
2415
|
/**
|
|
@@ -4358,14 +4441,14 @@ async function startRuntime(paths, options = {}) {
|
|
|
4358
4441
|
(await import("./ghostly_iroh_web-Dvzh3Y6E.js")).initSync({ module: irohWasmBytes() });
|
|
4359
4442
|
const [{ registerFileBytes }, { NodeFileBytes }] = await Promise.all([import("./fileBytes-CgbibpbV.js"), import("./fileBytes-CfSXjTFa.js")]);
|
|
4360
4443
|
registerFileBytes("native", async () => new NodeFileBytes(paths.files), true);
|
|
4361
|
-
const [{ EngineServer }, { createHyperEndpoint }] = await Promise.all([import("./server-
|
|
4444
|
+
const [{ EngineServer }, { createHyperEndpoint }] = await Promise.all([import("./server-CJNEKxzE.js"), import("./endpoint-BOTFMpfS.js")]);
|
|
4362
4445
|
const network = hyperdhtNetwork();
|
|
4363
4446
|
const dht = mainlineNetwork();
|
|
4364
|
-
const mainline = dht.off ? null : new (await (import("./mainline-
|
|
4447
|
+
const mainline = dht.off ? null : new (await (import("./mainline-CxbxpoU4.js"))).Mainline({
|
|
4365
4448
|
bootstrap: dht.bootstrap,
|
|
4366
4449
|
host: dht.host
|
|
4367
4450
|
});
|
|
4368
|
-
const transport = mainline || pinned ? new (await (import("./mainline-
|
|
4451
|
+
const transport = mainline || pinned ? new (await (import("./mainline-CxbxpoU4.js"))).RelaysAndDht(mainline, pinned ? { relays: pinned } : {}, !!pinned) : null;
|
|
4369
4452
|
const apps = servedApps(paths.dir).length > 0;
|
|
4370
4453
|
const server = new EngineServer({
|
|
4371
4454
|
...transport ? { transport } : {},
|
|
@@ -4611,6 +4694,16 @@ function connection(ctx, socket) {
|
|
|
4611
4694
|
if (request.method === "events.subscribe") {
|
|
4612
4695
|
const params = request.params ?? {};
|
|
4613
4696
|
const since = typeof params.since === "number" ? params.since : ctx.hub.lastSeq;
|
|
4697
|
+
let replay;
|
|
4698
|
+
try {
|
|
4699
|
+
replay = ctx.hub.replay(since);
|
|
4700
|
+
} catch (error) {
|
|
4701
|
+
write({
|
|
4702
|
+
id,
|
|
4703
|
+
error: asCliError(error).toJSON()
|
|
4704
|
+
});
|
|
4705
|
+
return;
|
|
4706
|
+
}
|
|
4614
4707
|
const queued = [];
|
|
4615
4708
|
let replaying = true;
|
|
4616
4709
|
unsubscribes.push(ctx.hub.onEvent((event) => {
|
|
@@ -4625,7 +4718,7 @@ function connection(ctx, socket) {
|
|
|
4625
4718
|
}
|
|
4626
4719
|
});
|
|
4627
4720
|
let last = since;
|
|
4628
|
-
for (const event of
|
|
4721
|
+
for (const event of replay) {
|
|
4629
4722
|
write({ event });
|
|
4630
4723
|
last = event.seq;
|
|
4631
4724
|
}
|
|
@@ -4645,4 +4738,4 @@ function connection(ctx, socket) {
|
|
|
4645
4738
|
//#endregion
|
|
4646
4739
|
export { BASELINE_NEWEST, MAX_LINE, keepServing, openHost, serve };
|
|
4647
4740
|
|
|
4648
|
-
//# sourceMappingURL=host-
|
|
4741
|
+
//# sourceMappingURL=host-C7hA-Za7.js.map
|