pmtiles-swarm 0.4.2 → 0.4.4

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/CHANGELOG.md CHANGED
@@ -7,6 +7,32 @@
7
7
  ### 🐞 Bug fixes
8
8
  - _...Add new stuff here..._
9
9
 
10
+ ## 0.4.4
11
+ ### 🐞 Bug fixes
12
+ - **The console no longer claims an `.incomplete` file that is not there.** The marker was a
13
+ literal in the page, drawn beside every unfinished archive, with a tooltip naming the file it
14
+ was supposedly on disk as. libtorrent renames nothing — the rename would have to happen in the
15
+ sidecar — so on the engine most people run, that named a file which did not exist, next to one
16
+ sitting under its final name at 25% downloaded. Each engine now says whether it marks
17
+ incomplete files, the composite answers for its primary since that is the engine writing the
18
+ bytes, and `/api/status` combines that with `incompleteSuffix` — which can also be empty — to
19
+ report the marker actually in use, or none. The console draws only what it is told.
20
+
21
+ ## 0.4.3
22
+ ### 🐞 Bug fixes
23
+ - **The lock file keeps the optional native builds `ws` asks for.** `bufferutil` and
24
+ `utf-8-validate` have now been stripped from it twice by a local `npm install` on a machine
25
+ that had already decided not to build them, and both times the release failed on `npm ci` —
26
+ which reproduces a lock exactly and will not improvise. Nothing local ever notices, because
27
+ they are optional and their absence costs only speed; the only thing that notices is a clean
28
+ install, which is what every release is. There is a test for it now, and it fails against the
29
+ lock that broke this release.
30
+ - **Requires the `pmtiles-torrent` that the resume fix actually needs.** The dependency said
31
+ `^0.3.0`, which an existing install already satisfies — so updating pmtiles-swarm left the
32
+ sidecar where it was, and half of a fix that lives in both halves does nothing. npm was right
33
+ and the declaration was wrong: 0.4.2's resume save reaches a sidecar that only writes resume
34
+ data from 0.3.2 onwards, so that is what it now asks for.
35
+
10
36
  ## 0.4.2
11
37
  ### 🐞 Bug fixes
12
38
  - **Resume data is saved on a node running more than one engine.** The periodic save is only
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "pmtiles-swarm",
3
- "version": "0.4.2",
3
+ "version": "0.4.4",
4
4
  "description": "BitTorrent distribution for PMTiles map archives: create torrents, watch folders, publish and subscribe to RSS feeds, and seed through qBittorrent or an embedded client",
5
5
  "type": "module",
6
6
  "main": "src/index.js",
@@ -39,7 +39,7 @@
39
39
  "maplibre-gl": "^6.2.0",
40
40
  "parse-torrent": "^11.0.24",
41
41
  "pmtiles": "^4.4.1",
42
- "pmtiles-torrent": "^0.3.0",
42
+ "pmtiles-torrent": "^0.3.2",
43
43
  "webtorrent": "^3.0.21"
44
44
  },
45
45
  "engines": {
package/src/api.js CHANGED
@@ -408,6 +408,14 @@ export function createApp({
408
408
  }
409
409
  res.json({
410
410
  version: VERSION,
411
+ // What an unfinished archive is actually called on disk, or null when
412
+ // nothing renames it. Both halves matter: the setting can be empty,
413
+ // and an engine can ignore it entirely. The console showed the marker
414
+ // for every unfinished archive regardless, which on libtorrent was a
415
+ // filename that did not exist.
416
+ incompleteMarker: engine.marksIncomplete
417
+ ? config.incompleteSuffix || null
418
+ : null,
411
419
  engine: { name: engine.name, ok: engineOk, error: engineError },
412
420
  archives: catalog.list().length,
413
421
  categories: catalog.categories(),
@@ -58,6 +58,9 @@ export class CompositeEngine {
58
58
  this.shareIntervalMs = Math.max(5, shareIntervalSeconds) * 1000;
59
59
  this.shareTimeoutMs = Math.max(60, shareTimeoutSeconds) * 1000;
60
60
  this.name = [primary.name, ...this.#secondaries.map((e) => e.name)].join('+');
61
+ // The primary is the one that writes the file. A secondary only ever
62
+ // receives an archive that is already whole, so it never marks anything.
63
+ this.marksIncomplete = primary.marksIncomplete ?? false;
61
64
  }
62
65
 
63
66
  /** The engine that owns the data. @returns {object} - The primary. */
@@ -78,6 +78,12 @@ export class LibtorrentEngine {
78
78
  throw new Error('libtorrent engine requires a savePath');
79
79
  }
80
80
  this.name = 'libtorrent';
81
+ // Whether `incompleteSuffix` means anything here: it does not. The rename
82
+ // would have to happen in the sidecar, so a partial archive sits under its
83
+ // final name from the first byte — which is why a web server must never be
84
+ // pointed at this engine's save path, and why the console must not claim
85
+ // a marker that is not there.
86
+ this.marksIncomplete = false;
81
87
  if (options.listen !== undefined && typeof options.listen !== 'string') {
82
88
  // Caught here because the alternative is a C++ converter error four
83
89
  // frames into a Python traceback, which says nothing about which setting
@@ -54,6 +54,9 @@ export class WebTorrentSeedEngine {
54
54
  throw new Error('WebTorrent engine requires a savePath');
55
55
  }
56
56
  this.name = 'webtorrent';
57
+ // Honoured, by replacing the store — the only thing that decides where
58
+ // bytes land.
59
+ this.marksIncomplete = true;
57
60
  this.#options = { readyTimeoutMs: 300000, ...options };
58
61
  }
59
62
 
@@ -725,6 +725,9 @@
725
725
  // ── Archives ──────────────────────────────────────────────────────────
726
726
  let archives = [];
727
727
  let selected = null;
728
+ // Null until /api/status says otherwise, so nothing claims a marker
729
+ // before the node has said whether its engine applies one.
730
+ let incompleteMarker = null;
728
731
  let activeTab = 'general';
729
732
 
730
733
  // What the header switch shows, so a click knows what it is toggling to.
@@ -882,6 +885,9 @@
882
885
  renderSpeed(speed);
883
886
  renderFetching(adds?.running);
884
887
  if (status.version) $('version').textContent = `v${status.version}`;
888
+ // What an unfinished archive is really called on disk, or null when
889
+ // nothing renames it. The engine decides, not the setting alone.
890
+ incompleteMarker = status.incompleteMarker ?? null;
885
891
  const engine = status.engine;
886
892
  $('status').innerHTML =
887
893
  `engine <b>${engine.name}</b> ${engine.ok ? 'ready' : 'unavailable'}` +
@@ -994,8 +1000,8 @@
994
1000
  <td class="sub">${
995
1001
  entry.paused ? 'paused' : escapeHtml(s.state ?? '—')
996
1002
  }${
997
- entry.complete === false && progress < 1
998
- ? `<div class="sub" title="on disk as ${escapeHtml(entry.name)}.incomplete until it is whole">.incomplete</div>`
1003
+ entry.complete === false && progress < 1 && incompleteMarker
1004
+ ? `<div class="sub" title="on disk as ${escapeHtml(entry.name)}${escapeHtml(incompleteMarker)} until it is whole">${escapeHtml(incompleteMarker)}</div>`
999
1005
  : ''
1000
1006
  }</td>`;
1001
1007
  tr.onclick = () => {