pmtiles-swarm 0.45.2 → 0.46.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 +40 -0
- package/package.json +1 -1
- package/src/api.js +21 -2
- package/src/web/index.html +9 -0
- package/src/web/public.html +57 -19
package/CHANGELOG.md
CHANGED
|
@@ -7,6 +7,46 @@
|
|
|
7
7
|
### 🐞 Bug fixes
|
|
8
8
|
- _...Add new stuff here..._
|
|
9
9
|
|
|
10
|
+
## 0.46.0
|
|
11
|
+
### ✨ Features and improvements
|
|
12
|
+
- **Each category endpoint on the public page is now offered the way it is used.** A `.torrent` is a
|
|
13
|
+
file, so it downloads. A preview is a page, so it opens. The rest are addresses that belong
|
|
14
|
+
somewhere else — a style, a torrent client, a feed reader — and following one here achieves
|
|
15
|
+
nothing, so TileJSON, magnet, RSS and the style URL copy instead.
|
|
16
|
+
|
|
17
|
+
The style URL is no longer printed. It is a TileJSON URL carrying a `.torrent` URL and a
|
|
18
|
+
percent-encoded magnet in its fragment, several hundred characters of it, and it was most of the
|
|
19
|
+
card — while being the one thing on the page nobody reads and everybody pastes. Every copy button
|
|
20
|
+
also carries its URL as a tooltip, since a browser on plain HTTP has no clipboard and a string
|
|
21
|
+
somebody can select beats a button that does nothing.
|
|
22
|
+
|
|
23
|
+
### 🐞 Bug fixes
|
|
24
|
+
|
|
25
|
+
## 0.45.4
|
|
26
|
+
### ✨ Features and improvements
|
|
27
|
+
|
|
28
|
+
### 🐞 Bug fixes
|
|
29
|
+
- **URLs shown in the console name the public port, not the admin one.** The console is served by the
|
|
30
|
+
admin listener, so every address it handed out named that listener — a TileJSON URL on `:8091`, a
|
|
31
|
+
`.torrent` on `:8091`, a style URL carrying both. Those are exactly the addresses that get pasted
|
|
32
|
+
into a style, a torrent client or another node, and none of them can reach the admin port: it binds
|
|
33
|
+
to localhost by default and serves nothing public even when it does not.
|
|
34
|
+
|
|
35
|
+
Only the port is corrected, and only when it is the admin one. The host stays whatever the request
|
|
36
|
+
arrived as, so a node behind a proxy still names itself correctly without anyone setting
|
|
37
|
+
`publicUrl` — and `publicUrl` still wins outright where it is set.
|
|
38
|
+
|
|
39
|
+
## 0.45.3
|
|
40
|
+
### ✨ Features and improvements
|
|
41
|
+
|
|
42
|
+
### 🐞 Bug fixes
|
|
43
|
+
- **The Copy and Open buttons on the Categories tab no longer sit off the edge of the page.** Table
|
|
44
|
+
cells are `nowrap`, which is right for the archive list where a wrapped number is worse than a wide
|
|
45
|
+
column — but a category cell holds a style URL and a paragraph explaining it, so nothing could
|
|
46
|
+
wrap and the table grew past the window, carrying the buttons at its end out of reach. The
|
|
47
|
+
endpoints table lays out fixed now: the label and button columns keep their width and the URL takes
|
|
48
|
+
what is left.
|
|
49
|
+
|
|
10
50
|
## 0.45.2
|
|
11
51
|
### ✨ Features and improvements
|
|
12
52
|
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "pmtiles-swarm",
|
|
3
|
-
"version": "0.
|
|
3
|
+
"version": "0.46.0",
|
|
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",
|
package/src/api.js
CHANGED
|
@@ -317,8 +317,27 @@ export function createApp({
|
|
|
317
317
|
// a torrent client handed the `torrent` link, another node syncing from
|
|
318
318
|
// the feed -- silently gets something it cannot use.
|
|
319
319
|
const configured = String(config.publicUrl ?? '').trim();
|
|
320
|
-
|
|
321
|
-
|
|
320
|
+
if (configured) return configured.replace(/\/$/, '');
|
|
321
|
+
|
|
322
|
+
// Never the admin port, whichever one the request came in on.
|
|
323
|
+
//
|
|
324
|
+
// The console lives on the admin listener, so every URL it showed named
|
|
325
|
+
// that listener — a TileJSON URL on :8091, a `.torrent` on :8091, a style
|
|
326
|
+
// URL carrying both. Those are the addresses people copy into a style, a
|
|
327
|
+
// torrent client or another node, and none of them can reach the admin
|
|
328
|
+
// port: it is bound to localhost by default and serves nothing public
|
|
329
|
+
// even when it is not. Half the addresses on a node pointing somewhere
|
|
330
|
+
// the other half do not is a confusion nobody should have to diagnose.
|
|
331
|
+
//
|
|
332
|
+
// The host is still whatever the request arrived as, so a node behind a
|
|
333
|
+
// proxy keeps naming itself correctly without anybody configuring
|
|
334
|
+
// `publicUrl`. Only the port is corrected, and only when it is the one
|
|
335
|
+
// port that is not for the public.
|
|
336
|
+
const host = onAdminPort(req)
|
|
337
|
+
? String(req.host).replace(/:\d+$/, '') +
|
|
338
|
+
(config.port ? `:${config.port}` : '')
|
|
339
|
+
: req.host;
|
|
340
|
+
return `${req.protocol}://${host}`.replace(/\/$/, '');
|
|
322
341
|
};
|
|
323
342
|
|
|
324
343
|
/**
|
package/src/web/index.html
CHANGED
|
@@ -224,6 +224,15 @@
|
|
|
224
224
|
}
|
|
225
225
|
.tag.on { background: var(--accent); color: #fff; border-color: var(--accent); }
|
|
226
226
|
#add-error { color: var(--bad); min-height: 1.2rem; }
|
|
227
|
+
/* Category endpoints. `th, td` is nowrap for the archive table, where a
|
|
228
|
+
wrapped number is worse than a wide one — but here the cell holds a
|
|
229
|
+
style URL and a paragraph explaining it, so nowrap pushed the table
|
|
230
|
+
wider than the window and took the Copy and Open buttons off the far
|
|
231
|
+
edge with it. Fixed layout keeps the two end columns where they are
|
|
232
|
+
and gives the middle whatever is left. */
|
|
233
|
+
#category-list table { table-layout: fixed; }
|
|
234
|
+
#category-list td { white-space: normal; }
|
|
235
|
+
#category-list code { word-break: break-all; }
|
|
227
236
|
/* Separates what acts on one archive from what acts on all of them. */
|
|
228
237
|
.bar-gap { flex: 1 1 1.5rem; min-width: 0.75rem; }
|
|
229
238
|
.tabs {
|
package/src/web/public.html
CHANGED
|
@@ -118,6 +118,19 @@
|
|
|
118
118
|
gap: 0.35rem 0.9rem;
|
|
119
119
|
font-size: 0.9rem;
|
|
120
120
|
}
|
|
121
|
+
/* A copy button reads as a link's sibling, not as a form control. */
|
|
122
|
+
.copy {
|
|
123
|
+
border: 1px solid var(--line);
|
|
124
|
+
border-radius: 999px;
|
|
125
|
+
background: none;
|
|
126
|
+
color: var(--muted);
|
|
127
|
+
font: inherit;
|
|
128
|
+
font-size: 0.74rem;
|
|
129
|
+
padding: 0 0.45rem;
|
|
130
|
+
cursor: pointer;
|
|
131
|
+
}
|
|
132
|
+
.copy:hover { color: var(--fg); border-color: var(--fg); }
|
|
133
|
+
.copy.done { border-color: currentColor; color: #3fb950; }
|
|
121
134
|
.urls {
|
|
122
135
|
margin-top: 0.7rem;
|
|
123
136
|
display: grid;
|
|
@@ -390,30 +403,55 @@
|
|
|
390
403
|
a.href = href;
|
|
391
404
|
links.append(a);
|
|
392
405
|
};
|
|
406
|
+
// What each endpoint is for decides how it is offered. A .torrent
|
|
407
|
+
// is a file to fetch, so it stays a link the browser downloads; a
|
|
408
|
+
// preview is a page to visit. The rest are addresses that belong
|
|
409
|
+
// somewhere else — a style, a torrent client, a feed reader — and
|
|
410
|
+
// following one here achieves nothing, so those copy.
|
|
411
|
+
const copy = (href, text) => {
|
|
412
|
+
const button = el('button', 'copy', text);
|
|
413
|
+
button.type = 'button';
|
|
414
|
+
const absolute = new URL(href, location.href).href;
|
|
415
|
+
// The URL either way: a browser on plain HTTP has no clipboard,
|
|
416
|
+
// and a tooltip somebody can select beats a button that does
|
|
417
|
+
// nothing.
|
|
418
|
+
button.title = absolute;
|
|
419
|
+
button.onclick = async () => {
|
|
420
|
+
try {
|
|
421
|
+
await navigator.clipboard.writeText(absolute);
|
|
422
|
+
button.classList.add('done');
|
|
423
|
+
button.textContent = 'copied';
|
|
424
|
+
setTimeout(() => {
|
|
425
|
+
button.classList.remove('done');
|
|
426
|
+
button.textContent = text;
|
|
427
|
+
}, 1200);
|
|
428
|
+
} catch {
|
|
429
|
+
button.textContent = 'copy failed — it is in the tooltip';
|
|
430
|
+
}
|
|
431
|
+
};
|
|
432
|
+
links.append(button);
|
|
433
|
+
};
|
|
434
|
+
|
|
393
435
|
const ends = entry.endpoints;
|
|
394
|
-
if (ends.tileJson)
|
|
436
|
+
if (ends.tileJson) copy(ends.tileJson, 'TileJSON');
|
|
395
437
|
// The newest build's preview, which is what "show me this
|
|
396
438
|
// category" means.
|
|
397
439
|
if (ends.preview) add(ends.preview, 'preview');
|
|
398
|
-
|
|
399
|
-
if (ends.
|
|
400
|
-
|
|
401
|
-
|
|
402
|
-
|
|
403
|
-
|
|
404
|
-
// The one worth copying: the TileJSON URL with the .torrent URL and
|
|
405
|
-
// the magnet in its fragment, which a plain client fetches over HTTP
|
|
406
|
-
// and a swarm-aware one joins directly.
|
|
407
|
-
if (ends.styleUrl) {
|
|
408
|
-
urls.append(
|
|
409
|
-
urlRow('style URL', new URL(ends.styleUrl, location.href).href),
|
|
410
|
-
);
|
|
411
|
-
} else if (ends.tileJson) {
|
|
412
|
-
urls.append(
|
|
413
|
-
urlRow('TileJSON', new URL(ends.tileJson, location.href).href),
|
|
414
|
-
);
|
|
440
|
+
// A file, so a link the browser saves rather than renders.
|
|
441
|
+
if (ends.torrent) {
|
|
442
|
+
const a = el('a', null, '.torrent');
|
|
443
|
+
a.href = ends.torrent;
|
|
444
|
+
a.download = '';
|
|
445
|
+
links.append(a);
|
|
415
446
|
}
|
|
416
|
-
if (
|
|
447
|
+
if (ends.magnet) copy(ends.magnet, 'magnet');
|
|
448
|
+
if (ends.feed) copy(ends.feed, 'RSS');
|
|
449
|
+
// The one worth copying and the one nobody wants to read: a TileJSON
|
|
450
|
+
// URL carrying the .torrent URL and a percent-encoded magnet in its
|
|
451
|
+
// fragment. Printed in full it was most of the card — several
|
|
452
|
+
// hundred characters of it — and it is never read, only pasted.
|
|
453
|
+
if (ends.styleUrl) copy(ends.styleUrl, 'style URL');
|
|
454
|
+
card.append(links);
|
|
417
455
|
|
|
418
456
|
host.append(card);
|
|
419
457
|
}
|