pmtiles-swarm 0.31.0 → 0.32.1

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,50 @@
7
7
  ### 🐞 Bug fixes
8
8
  - _...Add new stuff here..._
9
9
 
10
+ ## 0.32.1
11
+ ### ✨ Features and improvements
12
+ - _...Add new stuff here..._
13
+
14
+ ### 🐞 Bug fixes
15
+ - **Requires pmtiles-torrent 0.5.1, so the connection indicator and Recheck files actually work.**
16
+ Both features shipped against a dependency range that still allowed 0.4.6, which has neither
17
+ sidecar op. The declared requirement and the declared dependency disagreed, and the symptom was
18
+ a feature that looked built and did nothing: the indicator hid itself, because an engine that
19
+ cannot answer is deliberately not reported as unreachable, so there was nothing to see and
20
+ nothing to explain why.
21
+
22
+ - _...Add new stuff here..._
23
+
24
+ ## 0.32.0
25
+ ### ✨ Features and improvements
26
+ - _...Add new stuff here..._
27
+
28
+ ### 🐞 Bug fixes
29
+ - **A mutable magnet no longer carries a web seed.** A `ws=` URL names one build; a BEP 46 magnet
30
+ names a series. They disagree the moment the next build is published — and not harmlessly, which
31
+ was the part that was easy to miss. `tr=` and `ws=` live outside the info dictionary, so BEP 9
32
+ never replaces them: a client keeps the magnet's copies and merges them into whatever torrent it
33
+ resolved to. So the client that did exactly what the magnet asked — resolved the key, landed on
34
+ the current build — was handed a web seed for a previous one, and every piece it fetched from
35
+ there failed hash verification until the peer banned it. A client that *ignored* the key and
36
+ joined the pinned `xt=` was fine, because there the infohash and the web seed named the same
37
+ build.
38
+
39
+ Nothing is lost. The metainfo carries the right web seed for whichever build was actually
40
+ resolved, written into `url-list` when that torrent was created, and there are two ways to reach
41
+ it: the `torrent=` handle added to style URLs in 0.30.0, or BEP 9 from any peer. The magnet was
42
+ the third route and the only one that could be wrong.
43
+
44
+ Affects the category style URL, the feed's `pmtiles:mutable`, the TileJSON `torrent.mutable
45
+ .magnet` and the publisher's own magnet. Archives' immutable magnets still carry their web seeds,
46
+ since there `xt` and `ws` cannot drift apart. The parameter was removed from `mutableMagnet`
47
+ outright rather than dropped at each call site, so it cannot be reintroduced by a future caller.
48
+
49
+ **Restyle anything holding one.** A style carrying an older mutable magnet keeps working, but
50
+ carries the stale web seed until it is regenerated.
51
+
52
+ - _...Add new stuff here..._
53
+
10
54
  ## 0.31.0
11
55
  ### ✨ Features and improvements
12
56
  - **A Recheck files button, for when an archive's progress and its files disagree.** Every figure a
@@ -303,7 +303,7 @@ that publishes signs a DHT record naming whichever infohash is current, and the
303
303
  magnet then names the **category** rather than a build:
304
304
 
305
305
  ```
306
- magnet:?xs=urn:btpk:<public key>&s=openmaptiles&dn=…&ws=…
306
+ magnet:?xs=urn:btpk:<public key>&s=openmaptiles&dn=…
307
307
  ```
308
308
 
309
309
  No infohash anywhere, so nothing to go stale. A client resolves the record over
@@ -368,7 +368,7 @@ TileJSON documents from this server carry a non-standard `torrent` member:
368
368
  "publicKey": "7680dc95248eb807…",
369
369
  "salt": "openmaptiles",
370
370
  "seq": 1786108931,
371
- "magnet": "magnet:?xs=urn:btpk:7680dc95248eb807…&s=openmaptiles&ws=…"
371
+ "magnet": "magnet:?xs=urn:btpk:7680dc95248eb807…&s=openmaptiles"
372
372
  }
373
373
  }
374
374
  }
package/docs/tilejson.md CHANGED
@@ -77,13 +77,28 @@ serve this block — publishing is the only thing the secret is used for.
77
77
  `mutable.magnet` carries **both** identifiers:
78
78
 
79
79
  ```
80
- magnet:?xt=urn:btih:<current build>&xs=urn:btpk:<public key>&dn=…&s=…&ws=…
80
+ magnet:?xt=urn:btih:<current build>&xs=urn:btpk:<public key>&dn=…&s=…
81
81
  ```
82
82
 
83
83
  - `xs=urn:btpk:` is the public key. Resolving it through the DHT gives whichever
84
84
  infohash is current, now and after every future rebuild.
85
85
  - `xt=urn:btih:` is the build that was current when the document was generated.
86
86
 
87
+ **No `ws=`, and the omission is deliberate.** A web seed URL names one build;
88
+ this magnet names a series. They disagree the moment the next build is
89
+ published, and not harmlessly: `tr=` and `ws=` sit outside the info dictionary,
90
+ so BEP 9 never replaces them — a client keeps the magnet's copies and merges
91
+ them into whatever torrent it resolved to. A web seed attached to a build it
92
+ does not describe fails hash verification on every piece it serves, until the
93
+ peer banning it stops the waste.
94
+
95
+ Nothing is lost by leaving it out. `webseeds` above is the same list for the
96
+ build this document describes, and the metainfo for whichever build a client
97
+ resolves to carries its own — written into `url-list` when that torrent was
98
+ created, and reachable either from the `torrent=` handle in a style fragment or
99
+ over BEP 9 from any peer. The archive's own immutable magnet still carries web
100
+ seeds, because there `xt` and `ws` name the same build and cannot drift apart.
101
+
87
102
  A client reads whichever it understands. A DHT-capable one resolves the key and
88
103
  follows the series indefinitely; one without a DHT joins the infohash and gets a
89
104
  working archive immediately.
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "pmtiles-swarm",
3
- "version": "0.31.0",
3
+ "version": "0.32.1",
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",
@@ -46,7 +46,7 @@
46
46
  "maplibre-gl": "^6.2.0",
47
47
  "parse-torrent": "^11.0.24",
48
48
  "pmtiles": "^4.4.1",
49
- "pmtiles-torrent": "^0.4.6",
49
+ "pmtiles-torrent": "^0.5.1",
50
50
  "webtorrent": "^3.0.21"
51
51
  },
52
52
  "engines": {
package/src/api.js CHANGED
@@ -123,7 +123,6 @@ function styleUrlFor(category, newest, base) {
123
123
  salt: newest.mutable.salt ?? category,
124
124
  // The category, since that is what this magnet resolves to.
125
125
  name: newest.mutable.salt ?? category,
126
- webSeeds: newest.webSeeds,
127
126
  })
128
127
  : newest?.magnet;
129
128
  // Category-scoped rather than the newest build's immutable URL, for the same
package/src/feed.js CHANGED
@@ -147,7 +147,6 @@ ${
147
147
  infoHash: entry.infoHash,
148
148
  salt: entry.mutable.salt,
149
149
  name: entry.mutable.salt ?? entry.name,
150
- webSeeds: entry.webSeeds,
151
150
  }),
152
151
  )}</pmtiles:mutable>`
153
152
  : ''
package/src/mutable.js CHANGED
@@ -86,7 +86,6 @@ function rawPublicKey(publicKey) {
86
86
  * @param {string} [options.infoHash] - The build that is current, so a client with no DHT has somewhere to start.
87
87
  * @param {string} [options.name] - Display name for the archive.
88
88
  * @param {string[]} [options.trackers] - Tracker announce URLs.
89
- * @param {string[]} [options.webSeeds] - BEP 19 web seeds.
90
89
  * @param {string} [options.salt] - Salt, when one key publishes several archives.
91
90
  * @returns {string} - A BEP 46 magnet URI.
92
91
  */
@@ -129,12 +128,25 @@ export function mutableMagnet(publicKey, options = {}) {
129
128
  for (const tracker of options.trackers ?? []) {
130
129
  parts.push(`tr=${encodeURIComponent(tracker)}`);
131
130
  }
132
- // Carried because it is what makes a magnet useful with no peers at all: a
133
- // client can range-read the archive over HTTP and still be correct, which is
134
- // the difference between a slow first paint and a blank map.
135
- for (const seed of options.webSeeds ?? []) {
136
- parts.push(`ws=${encodeURIComponent(seed)}`);
137
- }
131
+ // No `ws=`, and the omission is the point.
132
+ //
133
+ // A web seed URL names one build. This magnet names a series, and a client
134
+ // that resolves the key lands on whatever build is current -- so the two
135
+ // disagree the moment the next one is published. They do not disagree
136
+ // harmlessly: `tr=` and `ws=` live outside the info dictionary, so BEP 9
137
+ // never replaces them, and a client keeps the magnet's copies and merges
138
+ // them into whatever torrent it ends up with. The result is a web seed
139
+ // attached to a build it does not describe, failing hash verification on
140
+ // every piece it serves until the peer bans it.
141
+ //
142
+ // Nothing is lost. The metainfo carries the right web seed for whichever
143
+ // build the client actually resolved -- it is written into `url-list` when
144
+ // that build's torrent is created -- and there are two ways to reach it: the
145
+ // `torrent=` handle in the style fragment, or BEP 9 from any peer. This was
146
+ // the third route, and the only one that could be wrong.
147
+ //
148
+ // An immutable magnet is a different case and still carries its web seeds:
149
+ // there, `xt` and `ws` name the same build and cannot drift apart.
138
150
  return parts.join('&');
139
151
  }
140
152
 
package/src/publisher.js CHANGED
@@ -211,7 +211,6 @@ export class MutablePublisher {
211
211
  // with the metadata and overrides it -- so nothing depends on this
212
212
  // beyond being honest about what the magnet identifies.
213
213
  name: category,
214
- webSeeds: entry?.webSeeds,
215
214
  });
216
215
  }
217
216
 
package/src/tilejson.js CHANGED
@@ -113,7 +113,6 @@ function buildTorrentBlock(entry, root) {
113
113
  // The category, not this build: the record resolves to whichever
114
114
  // archive is current, and `dn` is a label the metadata replaces.
115
115
  name: entry.mutable.salt,
116
- webSeeds: entry.webSeeds,
117
116
  }),
118
117
  };
119
118
  }