@ghostlytools/cli 1.3.1 → 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.
Files changed (60) hide show
  1. package/dist/assets/{api-TiB5QSG9.js → api-SYPJgFRU.js} +2 -2
  2. package/dist/assets/{api-Dq2QXQDk.js → api-aup3Amud.js} +9 -9
  3. package/dist/assets/{api-Dq2QXQDk.js.map → api-aup3Amud.js.map} +1 -1
  4. package/dist/assets/{apiKit-CA2x5GJF.js → apiKit-DYkVEs6r.js} +25 -29
  5. package/dist/assets/apiKit-DYkVEs6r.js.map +1 -0
  6. package/dist/assets/{apps-C-T8jeji.js → apps-DcZKu29s.js} +1 -1
  7. package/dist/assets/{apps-BxV9i_Y4.js → apps-Rbk2HHXb.js} +2 -2
  8. package/dist/assets/{apps-BxV9i_Y4.js.map → apps-Rbk2HHXb.js.map} +1 -1
  9. package/dist/assets/{arkade-C_qDmHnm.js → arkade-CuWlNnCz.js} +4 -4
  10. package/dist/assets/arkade-CuWlNnCz.js.map +1 -0
  11. package/dist/assets/{backup-CnMN2oUK.js → backup-CJWLDHuS.js} +4 -4
  12. package/dist/assets/{backup-CnMN2oUK.js.map → backup-CJWLDHuS.js.map} +1 -1
  13. package/dist/assets/{backup-Bugnn3Ue.js → backup-CSMw2GHv.js} +1 -1
  14. package/dist/assets/bark_ffi_wasm_bg-EY2uc0Bx.js.map +1 -1
  15. package/dist/assets/buttons-CGRqZ7z0.js +2 -0
  16. package/dist/assets/{buttons-CvNBzh2S.js → buttons-QEnAGWoC.js} +3 -3
  17. package/dist/assets/{buttons-CvNBzh2S.js.map → buttons-QEnAGWoC.js.map} +1 -1
  18. package/dist/assets/{envelope-WjingYSc.js → envelope-K27mzoyu.js} +2 -2
  19. package/dist/assets/{envelope-WjingYSc.js.map → envelope-K27mzoyu.js.map} +1 -1
  20. package/dist/assets/fedimint_client_wasm_bg-BtHHlFpp.js.map +1 -1
  21. package/dist/assets/{groupFiles-IEUW3DQz.js → groupFiles-DHTrTA4I.js} +43 -16
  22. package/dist/assets/groupFiles-DHTrTA4I.js.map +1 -0
  23. package/dist/assets/{host-CWt-jtqz.js → host-C7hA-Za7.js} +102 -34
  24. package/dist/assets/host-C7hA-Za7.js.map +1 -0
  25. package/dist/assets/{hyperdhtRelay-CPYwSLLS.js → hyperdhtRelay-BVoWY2ua.js} +2 -2
  26. package/dist/assets/{hyperdhtRelay-CPYwSLLS.js.map → hyperdhtRelay-BVoWY2ua.js.map} +1 -1
  27. package/dist/assets/{irohWeb-4oChIOIp.js → irohWeb-BJPk9bMn.js} +2 -2
  28. package/dist/assets/{irohWeb-4oChIOIp.js.map → irohWeb-BJPk9bMn.js.map} +1 -1
  29. package/dist/assets/{main-DbqcdShN.js → main-DC8cUkDx.js} +14 -14
  30. package/dist/assets/{main-DbqcdShN.js.map → main-DC8cUkDx.js.map} +1 -1
  31. package/dist/assets/{mainline-ZkiOnevs.js → mainline-CxbxpoU4.js} +2 -2
  32. package/dist/assets/{mainline-ZkiOnevs.js.map → mainline-CxbxpoU4.js.map} +1 -1
  33. package/dist/assets/{networkReason-CetKkTPo.js → networkReason-D42iNuUB.js} +2 -2
  34. package/dist/assets/{networkReason-CetKkTPo.js.map → networkReason-D42iNuUB.js.map} +1 -1
  35. package/dist/assets/{nwc-CgkqyvsE.js → nwc-Cm4sYgLv.js} +3 -3
  36. package/dist/assets/{nwc-CgkqyvsE.js.map → nwc-Cm4sYgLv.js.map} +1 -1
  37. package/dist/assets/{nwcProvider-4eVz_8HP.js → nwcProvider-0D7vdPDd.js} +2 -2
  38. package/dist/assets/{nwcProvider-4eVz_8HP.js.map → nwcProvider-0D7vdPDd.js.map} +1 -1
  39. package/dist/assets/{registry-OBJBnHVQ.js → registry-CLolR0kM.js} +1 -1
  40. package/dist/assets/{registry-DlAKO0Fy.js → registry-CVdSZW5l.js} +3 -3
  41. package/dist/assets/{registry-DlAKO0Fy.js.map → registry-CVdSZW5l.js.map} +1 -1
  42. package/dist/assets/{resolve-CouHhCpJ.js → resolve-BnlEajYz.js} +2 -2
  43. package/dist/assets/{resolve-CouHhCpJ.js.map → resolve-BnlEajYz.js.map} +1 -1
  44. package/dist/assets/{server-Ss0gJ-nw.js → server-CJNEKxzE.js} +112 -33
  45. package/dist/assets/server-CJNEKxzE.js.map +1 -0
  46. package/dist/assets/{src-DDzSERyc.js → src-yMUQvdyL.js} +157 -141
  47. package/dist/assets/src-yMUQvdyL.js.map +1 -0
  48. package/dist/assets/{turnRefs-B87dtrHM.js → turnRefs-B2a8to9q.js} +2 -2
  49. package/dist/assets/{turnRefs-B87dtrHM.js.map → turnRefs-B2a8to9q.js.map} +1 -1
  50. package/dist/assets/{usdt-Fj8CQO2z.js → usdt-DesFeDiG.js} +3 -3
  51. package/dist/assets/{usdt-Fj8CQO2z.js.map → usdt-DesFeDiG.js.map} +1 -1
  52. package/dist/ghostly.mjs +1 -1
  53. package/package.json +1 -1
  54. package/dist/assets/apiKit-CA2x5GJF.js.map +0 -1
  55. package/dist/assets/arkade-C_qDmHnm.js.map +0 -1
  56. package/dist/assets/buttons-Bj7Vf7Pn.js +0 -2
  57. package/dist/assets/groupFiles-IEUW3DQz.js.map +0 -1
  58. package/dist/assets/host-CWt-jtqz.js.map +0 -1
  59. package/dist/assets/server-Ss0gJ-nw.js.map +0 -1
  60. package/dist/assets/src-DDzSERyc.js.map +0 -1
@@ -1,12 +1,12 @@
1
- import { Go as answersOffer, Jo as callSignalHeardAt, Ko as buildSdpFromSignal, Oi as isPublicAddress, Uo as CALL_SIGNAL_MAX_AGE_MS, Wo as RTC_CONFIG, Xo as parseCallSignal, Yo as extractParamsFromSdp, Zc as setLinkTraceSink, Zo as signalHasVideo, gl as fromBase64Url, ii as checkPushEndpoint, qo as callRtcConfig } from "./src-DDzSERyc.js";
2
- import { a as fedimintSdkOn, r as irohRelayProblem } from "./irohWeb-4oChIOIp.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
3
  import { r as asCliError, t as CliError } from "./errors-DO5z6h_l.js";
4
- import { a as findChat } from "./apiKit-CA2x5GJF.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-Dq2QXQDk.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
6
  import { n as RESTORED_MARK, r as acquireLock } from "./profiles-BHc9pEYg.js";
7
7
  import { r as privateFolder, t as ownFolder } from "./privateFolder-Bk9C9oFv.js";
8
8
  import { createRequire } from "node:module";
9
- 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";
10
10
  import { readFile } from "node:fs/promises";
11
11
  import { dirname, join } from "node:path";
12
12
  import { createHash, randomBytes } from "node:crypto";
@@ -915,6 +915,8 @@ var CallManager = class {
915
915
  clearing = /* @__PURE__ */ new Map();
916
916
  /** Per chat: when this side's last call there ended before it was answered (`CALL_PACE_MS`). */
917
917
  unansweredAt = /* @__PURE__ */ new Map();
918
+ /** The early answers being made, those of ended calls too (MAX_EARLY_ANSWERS). */
919
+ makings = /* @__PURE__ */ new Set();
918
920
  auto;
919
921
  configPath;
920
922
  stopping = false;
@@ -1087,11 +1089,15 @@ var CallManager = class {
1087
1089
  */
1088
1090
  prepare(call) {
1089
1091
  if (this.host.answers === false || call.ended || call.state !== "ringing") return;
1092
+ this.stopEarly(call);
1090
1093
  call.earlyTimer = setTimeout(() => this.prepare(call), this.host.earlyAnswerMs ?? 3e4);
1091
1094
  call.earlyTimer.unref?.();
1092
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;
1093
1098
  const offer = call.offer;
1094
1099
  const making = {
1100
+ chat: call.chat,
1095
1101
  done: this.stack().then((stack) => EarlyAnswer.open(stack, offer, {
1096
1102
  iceServers: this.host.engine.getState().settings?.iceServers ?? [],
1097
1103
  log: (line) => process.stderr.write(`ghostly: call ${call.id}: ${line}\n`)
@@ -1103,15 +1109,19 @@ var CallManager = class {
1103
1109
  claimed: false
1104
1110
  };
1105
1111
  call.making = making;
1112
+ this.makings.add(making);
1106
1113
  making.done.then((early) => {
1114
+ this.makings.delete(making);
1107
1115
  if (call.making === making) call.making = null;
1108
- if (making.claimed || !early) return;
1109
- if (call.ended || call.state !== "ringing") {
1110
- early.close();
1111
- return;
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
+ }
1112
1122
  }
1113
- call.early?.close();
1114
- call.early = early;
1123
+ const next = this.byChat(making.chat);
1124
+ if (next && next !== call && next.direction === "in" && !next.making && !next.early) this.prepare(next);
1115
1125
  });
1116
1126
  }
1117
1127
  /** The answered call's early answer: the one made, if still good, or the one being made; none from then on. */
@@ -1562,6 +1572,8 @@ function readAuto(path) {
1562
1572
  return off;
1563
1573
  }
1564
1574
  }
1575
+ /** A journal past this is trimmed, and only this much of its end is ever read. */
1576
+ var JOURNAL_MAX_BYTES = 33554432;
1565
1577
  var SEEN_DB = "ghostly-cli";
1566
1578
  var SEEN = "seen";
1567
1579
  /**
@@ -1587,6 +1599,7 @@ var EventHub = class {
1587
1599
  seenDb;
1588
1600
  seq = 0;
1589
1601
  journalLines = 0;
1602
+ journalBytes = 0;
1590
1603
  listeners = /* @__PURE__ */ new Set();
1591
1604
  stateListeners = /* @__PURE__ */ new Set();
1592
1605
  callListeners = /* @__PURE__ */ new Set();
@@ -1623,13 +1636,24 @@ var EventHub = class {
1623
1636
  }
1624
1637
  /** Loads the journal's last seq and the seen set; call before `sink` is attached. */
1625
1638
  async open() {
1626
- if (existsSync(this.journalPath)) {
1627
- const lines = readFileSync(this.journalPath, "utf8").split("\n").filter(Boolean);
1628
- this.journalLines = lines.length;
1629
- for (let i = lines.length - 1; i >= 0; i--) try {
1630
- this.seq = JSON.parse(lines[i]).seq;
1631
- break;
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");
1632
1654
  } catch {}
1655
+ this.journalLines = 0;
1656
+ this.journalBytes = 0;
1633
1657
  }
1634
1658
  this.db = await new Promise((resolve, reject) => {
1635
1659
  const request = indexedDB.open(this.seenDb, 1);
@@ -1754,13 +1778,10 @@ var EventHub = class {
1754
1778
  replay(since) {
1755
1779
  if (!existsSync(this.journalPath) || since >= this.seq) return [];
1756
1780
  const out = [];
1757
- for (const line of readFileSync(this.journalPath, "utf8").split("\n")) {
1758
- if (!line) continue;
1759
- try {
1760
- const event = JSON.parse(line);
1761
- if (event.seq > since) out.push(event);
1762
- } catch {}
1763
- }
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 {}
1764
1785
  if (out.length && out[0].seq > since + 1) out.unshift({
1765
1786
  seq: since,
1766
1787
  id: `events.gap:${since}:${out[0].seq}`,
@@ -1783,18 +1804,29 @@ var EventHub = class {
1783
1804
  at: this.now(),
1784
1805
  ...fields
1785
1806
  };
1786
- appendFileSync(this.journalPath, JSON.stringify(event) + "\n", { mode: 384 });
1787
- if (++this.journalLines > 2e4) this.trimJournal();
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
+ }
1788
1815
  for (const listener of this.listeners) try {
1789
1816
  listener(event);
1790
1817
  } catch {}
1791
1818
  return event;
1792
1819
  }
1820
+ /** Keeps the last `JOURNAL_KEEP` events, and of them no more than `JOURNAL_KEEP_BYTES`. */
1793
1821
  trimJournal() {
1794
- const lines = readFileSync(this.journalPath, "utf8").split("\n").filter(Boolean).slice(-1e4);
1795
- writeFileSync(this.journalPath + ".tmp", lines.join("\n") + "\n", { mode: 384 });
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 });
1796
1827
  renameSync(this.journalPath + ".tmp", this.journalPath);
1797
- this.journalLines = lines.length;
1828
+ this.journalLines = kept.length;
1829
+ this.journalBytes = bytes;
1798
1830
  }
1799
1831
  handle(message) {
1800
1832
  switch (message.kind) {
@@ -2352,6 +2384,32 @@ function groupShape(group) {
2352
2384
  pin: group.pin ?? null
2353
2385
  };
2354
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
+ }
2355
2413
  //#endregion
2356
2414
  //#region src/runtime/fedimint.ts
2357
2415
  /**
@@ -4383,14 +4441,14 @@ async function startRuntime(paths, options = {}) {
4383
4441
  (await import("./ghostly_iroh_web-Dvzh3Y6E.js")).initSync({ module: irohWasmBytes() });
4384
4442
  const [{ registerFileBytes }, { NodeFileBytes }] = await Promise.all([import("./fileBytes-CgbibpbV.js"), import("./fileBytes-CfSXjTFa.js")]);
4385
4443
  registerFileBytes("native", async () => new NodeFileBytes(paths.files), true);
4386
- const [{ EngineServer }, { createHyperEndpoint }] = await Promise.all([import("./server-Ss0gJ-nw.js"), import("./endpoint-BOTFMpfS.js")]);
4444
+ const [{ EngineServer }, { createHyperEndpoint }] = await Promise.all([import("./server-CJNEKxzE.js"), import("./endpoint-BOTFMpfS.js")]);
4387
4445
  const network = hyperdhtNetwork();
4388
4446
  const dht = mainlineNetwork();
4389
- const mainline = dht.off ? null : new (await (import("./mainline-ZkiOnevs.js"))).Mainline({
4447
+ const mainline = dht.off ? null : new (await (import("./mainline-CxbxpoU4.js"))).Mainline({
4390
4448
  bootstrap: dht.bootstrap,
4391
4449
  host: dht.host
4392
4450
  });
4393
- const transport = mainline || pinned ? new (await (import("./mainline-ZkiOnevs.js"))).RelaysAndDht(mainline, pinned ? { relays: pinned } : {}, !!pinned) : null;
4451
+ const transport = mainline || pinned ? new (await (import("./mainline-CxbxpoU4.js"))).RelaysAndDht(mainline, pinned ? { relays: pinned } : {}, !!pinned) : null;
4394
4452
  const apps = servedApps(paths.dir).length > 0;
4395
4453
  const server = new EngineServer({
4396
4454
  ...transport ? { transport } : {},
@@ -4636,6 +4694,16 @@ function connection(ctx, socket) {
4636
4694
  if (request.method === "events.subscribe") {
4637
4695
  const params = request.params ?? {};
4638
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
+ }
4639
4707
  const queued = [];
4640
4708
  let replaying = true;
4641
4709
  unsubscribes.push(ctx.hub.onEvent((event) => {
@@ -4650,7 +4718,7 @@ function connection(ctx, socket) {
4650
4718
  }
4651
4719
  });
4652
4720
  let last = since;
4653
- for (const event of ctx.hub.replay(since)) {
4721
+ for (const event of replay) {
4654
4722
  write({ event });
4655
4723
  last = event.seq;
4656
4724
  }
@@ -4670,4 +4738,4 @@ function connection(ctx, socket) {
4670
4738
  //#endregion
4671
4739
  export { BASELINE_NEWEST, MAX_LINE, keepServing, openHost, serve };
4672
4740
 
4673
- //# sourceMappingURL=host-CWt-jtqz.js.map
4741
+ //# sourceMappingURL=host-C7hA-Za7.js.map