pmtiles-swarm 0.79.1 → 0.89.0

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,276 @@
7
7
  ### 🐞 Bug fixes
8
8
  - _...Add new stuff here..._
9
9
 
10
+ ## 0.89.0
11
+ ### ✨ Features and improvements
12
+ - **Both feeds are linked at the foot of the public page.** `RSS feed` is `archive RSS feed` now and
13
+ `stack RSS feed` is beside it. One name was unambiguous while there was one feed; with a second, a
14
+ reader following the old name would have got archives when they wanted recipes and had nothing on
15
+ the page to tell them otherwise.
16
+
17
+
18
+ ### 🐞 Bug fixes
19
+ - **A feed carrying every category.** `/categories.xml`, beside `/feed.xml` and `/stacks.xml` — the
20
+ set was inconsistent, and following all of a node's categories meant adding each by hand and
21
+ remembering to add the next one, which is not following its categories at all. It is what a
22
+ subscriber wants when they want everything this node files: including categories added later.
23
+
24
+ The items are archives, because a category has no bytes of its own and the build it resolves to is
25
+ what a subscriber would join — which also means every existing consumer already knows how to read
26
+ it, magnets and enclosures included. That is what separates it from the whole catalogue: `/feed.xml`
27
+ carries every build a node holds, and this carries the current one of each category. On a node
28
+ keeping four builds apiece the difference is fourfold.
29
+
30
+ In the footer of the public page it replaces `categories JSON`, which was the odd one out among
31
+ three feeds. `/latest/` is untouched and remains the JSON index.
32
+
33
+
34
+ ## 0.88.0
35
+ ### ✨ Features and improvements
36
+ - **An archive card is built like a category's.** Copy buttons for the addresses that belong
37
+ somewhere else — TileJSON, magnet, and a **source URL** of its own, the TileJSON URL with the
38
+ `.torrent` and magnet in its fragment, pinned to that build rather than following the category.
39
+ The preview, `.torrent` and download stay links, because a page is followed and a file is saved.
40
+ The printed TileJSON row went with the button that replaced it: an address in full beside a button
41
+ that copies it is the same fact twice, and it was the longest line on the card.
42
+
43
+
44
+ ### 🐞 Bug fixes
45
+ - **A terrain stack was offered no hillshade preview on the public page.** The listing reported its
46
+ encoding as whatever `output.encoding` restated, which for a recipe saying "same as the sources" —
47
+ the ordinary case — is nothing. So the page could not tell a terrain stack from an imagery one and
48
+ offered neither the raw preview nor the terrain one. It reports what the stack actually serves now,
49
+ and reports nothing for imagery, where a guess would have offered a hillshade of a photograph.
50
+
51
+ - **A stack whose sources disagreed about their encoding wrote tiles in more than one of them.** With
52
+ no `output.encoding`, the merge took the encoding of whichever source answered first — and which
53
+ source answers varies by tile, since the base is sparse in one place and the layer above covers in
54
+ another. One stack wrote one tile as mapbox and the next as terrarium, with the TileJSON in front
55
+ describing neither: correct in one place, a cliff face in another, for no reason the recipe showed.
56
+ It follows the base source now, which is a property of the recipe rather than of the tile, and the
57
+ listing and the merge are held to the same answer by a test.
58
+
59
+
60
+ ## 0.87.0
61
+ ### ✨ Features and improvements
62
+ - **A feed per stack, and an address to copy for it.** `/stacks/<id>.xml` carries one recipe, for
63
+ following a single map out of somebody's several rather than everything they publish. An **RSS**
64
+ button on the stack's row in the console and beside TileJSON and XYZ on the public page. Copied
65
+ rather than followed: the address is for another node's settings, and a browser shown an RSS
66
+ document mostly offers to download it. A stack this node adopted has no button and its feed 404s —
67
+ somebody else's recipe is theirs to publish.
68
+
69
+
70
+ ### 🐞 Bug fixes
71
+ - **The copied XYZ address came back percent-encoded.** `http://…/stacks/test/%7Bz%7D/%7Bx%7D/%7By%7D.png`
72
+ rather than `{z}/{x}/{y}`, which no client will take. The public page resolves a relative address
73
+ against the page's own URL to make it absolute, and `new URL` percent-encodes braces because they
74
+ are not legal in a path — and an XYZ template is very little but braces. The TileJSON link was
75
+ unaffected, having none. Resolving still happens; the two sequences it introduces are put back.
76
+
77
+
78
+ ## 0.86.0
79
+ ### ✨ Features and improvements
80
+ - _...Add new stuff here..._
81
+
82
+ - **Stack recipes travel between nodes.** `GET /stacks.xml` is this node's own stacks as a feed;
83
+ **Settings → Feeds → Stack feeds** follows another node's and adopts what it carries. Archives
84
+ already travelled by category — a builder feeding two tile servers gave them the same archives —
85
+ and this is how the recipes that combine them travel with them, so a stack is written once and
86
+ corrected once.
87
+
88
+ This section of the docs used to argue against a feed, on the grounds that a stack is a mutable
89
+ document and syncing one is about conflicts. That holds where two nodes both edit a recipe and is
90
+ not the arrangement anybody runs: one node authors, the rest follow. What survives from the
91
+ objection is handled directly — **a stack made on this node is never overwritten by one arriving
92
+ under the same name**, which is refused and said.
93
+
94
+ A recipe is adopted under the publisher's own id, so `planet-terrain` answers at the same URL on
95
+ the builder and on every replica; namespacing it would have given three nodes three URLs and
96
+ defeated the point. A recipe naming a source this node has not got is adopted anyway and reports
97
+ the missing source until it arrives — refusing it would mean a replica could not be set up until
98
+ every archive had finished downloading, which is backwards.
99
+
100
+ What happens when a feed stops carrying a stack is the feed's own setting: keep it and say so, or
101
+ remove it here too.
102
+
103
+ ### 🐞 Bug fixes
104
+ - _...Add new stuff here..._
105
+
106
+ ## 0.85.1
107
+ ### ✨ Features and improvements
108
+ - _...Add new stuff here..._
109
+
110
+ - **An export no longer pretends a stack has categories.** Both doors fell back to
111
+ `stack.categories` when none were given — a field the typedef never had, validation never checked,
112
+ the editor has no box for and nothing ever wrote. A category is what an *archive* is filed under,
113
+ and a stack has no bytes and no infohash for that to be about.
114
+
115
+ Left empty the archive is unfiled: held and seeded, in no category and no feed. The scheduled
116
+ export row says `unfiled` and the dialog says so in full, rather than offering a default that
117
+ could not exist.
118
+
119
+ ### 🐞 Bug fixes
120
+ - _...Add new stuff here..._
121
+
122
+ ## 0.85.0
123
+ ### ✨ Features and improvements
124
+ - _...Add new stuff here..._
125
+
126
+ - **A scheduled export can be served by the node that baked it.** The **Local file** choice, the same
127
+ one every other row under Feeds offers: http, http + web seed, http + catalog. It is worth more
128
+ here than anywhere else — a baked archive is already on this disk, so serving it costs a route
129
+ rather than a download, and without it a scheduled export produces something only peers can reach.
130
+ A nightly build behind a URL that is always current is usually the point of scheduling one.
131
+
132
+ `publishDir` and `webSeedBase` remain the other half of the same question, for a directory
133
+ something else already serves. The two are not exclusive: publishing to a served directory *and*
134
+ offering this node as a web seed gives a client two places to get the same bytes.
135
+
136
+ ### 🐞 Bug fixes
137
+ - _...Add new stuff here..._
138
+
139
+ ## 0.84.0
140
+ ### ✨ Features and improvements
141
+ - _...Add new stuff here..._
142
+
143
+ - **Scheduled exports are rows, like every other automation beside them.** `stackExports` in the
144
+ config, edited under Settings → Feeds with the same row editor the monitored folders and the
145
+ scheduled sources use: add a row, choose the stack from a dropdown, say when, and fill in the rest
146
+ — categories, builds to keep, keep for how many days, save location, publish directory, web seed
147
+ base, archive name, attribution, description.
148
+
149
+ **Several rows may name one stack.** That is what the two earlier shapes could not say: an `export`
150
+ block on the recipe, and then a table of one row per stack, both hold exactly one schedule — and a
151
+ nightly build to the fast disk beside a weekly one published elsewhere is an ordinary thing to
152
+ want. It also puts the schedule where the other automations already are: a watched folder says what
153
+ *this machine* does, not what a map is, and keeping it out of the recipe means a recipe copied to
154
+ another node does not quietly start baking there.
155
+
156
+ The export dialog no longer offers to repeat — a stack may have several schedules and a dialog
157
+ opened on the stack cannot say which it would edit. It exports once and points at the settings tab.
158
+ A stack's row in the Stacks view still shows the schedules aimed at it.
159
+
160
+ ### 🐞 Bug fixes
161
+ - _...Add new stuff here..._
162
+
163
+ ## 0.83.0
164
+ ### ✨ Features and improvements
165
+ - _...Add new stuff here..._
166
+
167
+ - **A scheduled export is set up like the other automations beside it.** The row under Settings →
168
+ Feeds is the whole of one now, not only the timer: categories, builds to keep, keep for how many
169
+ days, archive name, attribution, description, where the data lands, a publish directory and a web
170
+ seed base. Those are the manual export dialog's fields plus the two retention rules every other
171
+ automation on that tab already had, which is the point — a scheduled export is set up in one place
172
+ rather than half in a settings tab and half in a dialog.
173
+
174
+ Retirement is the part that needed something new underneath. `keep` and `keepDays` are applied by
175
+ the same code a watched folder uses, but retiring needs a *family* — which archives are builds of
176
+ the same map — and a bake marked nothing, so there was nothing to compare. An archive now records
177
+ `source.stack`, and the family is every archive that names this stack. Without it a nightly export
178
+ is a disk that fills at one archive a night.
179
+
180
+ ### 🐞 Bug fixes
181
+ - _...Add new stuff here..._
182
+
183
+ ## 0.82.0
184
+ ### ✨ Features and improvements
185
+ - _...Add new stuff here..._
186
+
187
+ - **Export schedules are set under Settings → Feeds.** Not only the two global settings that landed
188
+ there in 0.81.1 — the schedules themselves. **Scheduled exports** is a row per stack: never, every
189
+ day at a time, or every so many hours, saved onto that stack's recipe. Feeds is where somebody goes
190
+ to say when a thing runs, so it is where they are set; the export dialog's **Repeat** control still
191
+ writes the same schedule, for setting one while you are already there.
192
+
193
+ Turning a stack to _never_ pauses it with `enabled: false` rather than deleting the block. Where it
194
+ lands, what it is called and which categories it is filed under live in the same place, and those
195
+ should survive being paused.
196
+
197
+ ### 🐞 Bug fixes
198
+ - _...Add new stuff here..._
199
+
200
+ ## 0.81.1
201
+ ### ✨ Features and improvements
202
+ - _...Add new stuff here..._
203
+
204
+ - **The scheduled-export settings are under Settings → Feeds.** `stacks.scheduledExports` and
205
+ `stacks.exportIntervalHours` had no schema entry, so they were config-file-only and invisible in
206
+ the console. Feeds rather than a group of their own, because that tab is already where the
207
+ automations that bring a file in on a timer sit — a scheduled source watching an upstream
208
+ directory, a subscription following someone else's feed. A scheduled export is the same kind of
209
+ thing; it just produces the file here instead of fetching it, and it lands in a category and goes
210
+ out over the feed exactly as a fetched one does.
211
+
212
+ ### 🐞 Bug fixes
213
+ - _...Add new stuff here..._
214
+
215
+ ## 0.81.0
216
+ ### ✨ Features and improvements
217
+ - _...Add new stuff here..._
218
+
219
+ - **A stack can export itself on a schedule.** An archive is a snapshot: a stack over categories
220
+ follows a rebuild and a file baked from it does not, so it goes stale the moment its sources move
221
+ and somebody has to notice. An `export` block on the recipe says when — `at` for a time of day in
222
+ UTC, `everyHours` or `everyMinutes` for an interval, the same shape a scheduled source uses and
223
+ read by the same code — along with everything the export dialog collects. In the console, **Repeat**
224
+ turns the Export button into **Save schedule**, and the stack's row shows when it runs.
225
+
226
+ The hard part is remembering across a restart. The source poller keeps last-run times in memory,
227
+ which is fine when a missed poll costs one poll; here it would cost the whole bake, every restart,
228
+ for hours. So it is written to `stack-exports.json`, and written *before* the bake finishes — a
229
+ restart mid-export must not start it from the top, since the checkpoint is what carries it on.
230
+
231
+ A run whose sources have not moved is skipped: `bakeRevision` is recorded beside the time, and an
232
+ identical archive is the same map under a new infohash that then has to be seeded beside the one it
233
+ duplicates. It will not run two at once, will not start one over a bake already running, and does
234
+ not record a refusal as a run — a location that is full is something somebody fixes, and a schedule
235
+ that gave up quietly would hide that it ever ran. `stacks.scheduledExports: false` turns it off,
236
+ which is what a second node serving the same recipes wants.
237
+
238
+ ### 🐞 Bug fixes
239
+ - _...Add new stuff here..._
240
+
241
+ ## 0.80.0
242
+ ### ✨ Features and improvements
243
+ - **A stack can be a source in another stack.** `{ "stack": "jaxa-with-gebco" }` beside `category`
244
+ and `archive`. A base worked out once — terrain over bathymetry, masked at the coast and faded
245
+ across it — is a thing to reuse rather than retype, and a recipe that names it follows every later
246
+ correction to it, exactly as a source over a category follows a rebuild.
247
+
248
+ It is merged as **heights**: the inner stack is evaluated for the tile and handed straight to the
249
+ merge above, with no encode and decode in between. That saves two conversions per tile and, more
250
+ to the point, does not round a value on its way from one merge into the next. So a nested source
251
+ may say anything that acts on heights — `maskValues`, `maskRange`, `heightAdjustment`, `cutline`,
252
+ `bounds`, the fade, `opacity`, `blend` — and nothing that describes stored bytes. `encoding` and
253
+ its parameters are refused, and so is `maskColors`, which compares channels as an archive stored
254
+ them and has none to compare here.
255
+
256
+ A loop is refused by name on the way down, so a stack naming itself and a ring of three are the
257
+ same case and neither needs a depth counter to stop. The depth limit is separate and is four:
258
+ every level is a full merge of everything under it, so a tile's cost multiplies rather than adds.
259
+
260
+ Coverage folds in one level down, and the ETag carries the inner stack's own ETag rather than its
261
+ id — without that, editing the inner recipe would leave the outer one serving from a cache that
262
+ still believed in it, and propagation is the whole point of naming a stack instead of copying it.
263
+ The console offers held stacks in the source picker, alongside categories and archives.
264
+
265
+ - **An export can set its attribution, and starts with the right one.** An archive travels without
266
+ the style that loaded it — seeded, mirrored, opened by people who never saw the stack it came from
267
+ — so its own metadata is the only place the credit survives. The export dialog has an
268
+ **Attribution** field, filled in from the stack: its own where the recipe states one, otherwise
269
+ every source's joined. Editable, because an export may be published under terms the recipe does
270
+ not know; filled in rather than blank, because unlike the description it is not something only the
271
+ person exporting knows.
272
+
273
+ Joined with ` | ` rather than `, `, in the TileJSON as well as in the archive. These strings are
274
+ almost always HTML links and a comma between two anchors renders as part of the last one's text,
275
+ which is why MapLibre, Mapbox and OpenLayers all separate them this way.
276
+
277
+ ### 🐞 Bug fixes
278
+ - _...Add new stuff here..._
279
+
10
280
  ## 0.79.1
11
281
  ### ✨ Features and improvements
12
282
  - _...Add new stuff here..._
package/README.md CHANGED
@@ -66,7 +66,7 @@ been sending and receiving, kept in SQLite so it survives a restart; an indicato
66
66
  peers can reach this node at all; and a settings screen covering monitored folders, watched web
67
67
  locations, remote nodes, save locations, access tokens and the external-program hooks.
68
68
 
69
- **Publishes RSS.** `/feed.xml`, and `/feed/<category>.xml` per category. Plain RSS 2.0 with
69
+ **Publishes RSS.** `/feed.xml` for every archive, `/categories.xml` for the build each category currently resolves to, `/stacks.xml` for the stack recipes, and `/feed/<category>.xml` per category. Plain RSS 2.0 with
70
70
  torrent enclosures, so **qBittorrent's built-in RSS auto-downloader can subscribe today** with no
71
71
  new software. Items also carry a namespaced description of the map — format, zoom range, bounds,
72
72
  tile count — so a subscriber can decide whether it wants a 72 GiB download before starting one.
@@ -813,6 +813,8 @@ which the endpoint answers 501.
813
813
  | `GET` | `/stacks/:id/:size/:z/:x/:y.:ext` | The same tile at 256 or 512 px. A tile's coordinates are an extent rather than a pixel count, so this is the same ground on a finer or coarser grid |
814
814
  | `GET` | `/stacks/:id/:z/:x/:y.:ext` | One tile of a stack — **public**. Answered by the topmost source holding it; `X-Stack-Sources` says which were asked and what each said |
815
815
  | `GET` | `/feed.xml`, `/feed/:category.xml`, `/latest/:category.xml` | RSS — **public** |
816
+ | `GET` | `/categories.xml` | Every category, as the build each resolves to — **public** |
817
+ | `GET` | `/stacks.xml`, `/stacks/:id.xml` | Stack recipes, for another node to follow — **public** |
816
818
 
817
819
  Everything under `/api/` is guarded once a credential is configured; tiles, TileJSON and the feeds
818
820
  never are. A `peer` token may read but not change, and may be narrowed to some categories. See