tileserver-gl-light 4.1.2 → 4.2.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/.eslintrc.cjs +32 -0
- package/.gitattributes +11 -0
- package/.husky/commit-msg +21 -0
- package/.husky/pre-push +4 -0
- package/Dockerfile +4 -1
- package/commitlint.config.cjs +3 -0
- package/docker-entrypoint.sh +1 -1
- package/docs/installation.rst +1 -1
- package/lint-staged.config.cjs +4 -0
- package/package.json +28 -11
- package/prettier.config.cjs +13 -0
- package/publish.js +17 -9
- package/run.sh +1 -1
- package/src/healthcheck.js +18 -0
- package/src/main.js +57 -65
- package/src/serve_data.js +99 -82
- package/src/serve_font.js +19 -10
- package/src/serve_light.js +5 -6
- package/src/serve_rendered.js +550 -309
- package/src/serve_style.js +31 -16
- package/src/server.js +248 -156
- package/src/utils.js +62 -43
- package/test/metadata.js +44 -43
- package/test/setup.js +8 -7
- package/test/static.js +127 -31
- package/test/style.js +31 -26
- package/test/tiles_data.js +5 -5
- package/test/tiles_rendered.js +7 -7
package/src/serve_data.js
CHANGED
|
@@ -10,97 +10,108 @@ import MBTiles from '@mapbox/mbtiles';
|
|
|
10
10
|
import Pbf from 'pbf';
|
|
11
11
|
import VectorTile from '@mapbox/vector-tile';
|
|
12
12
|
|
|
13
|
-
import {getTileUrls, fixTileJSONCenter} from './utils.js';
|
|
13
|
+
import { getTileUrls, fixTileJSONCenter } from './utils.js';
|
|
14
14
|
|
|
15
15
|
export const serve_data = {
|
|
16
16
|
init: (options, repo) => {
|
|
17
17
|
const app = express().disable('x-powered-by');
|
|
18
18
|
|
|
19
|
-
app.get(
|
|
20
|
-
|
|
21
|
-
|
|
22
|
-
|
|
23
|
-
|
|
24
|
-
|
|
25
|
-
|
|
26
|
-
|
|
27
|
-
|
|
28
|
-
|
|
29
|
-
|
|
30
|
-
format =
|
|
31
|
-
|
|
32
|
-
|
|
33
|
-
|
|
34
|
-
|
|
35
|
-
|
|
36
|
-
|
|
19
|
+
app.get(
|
|
20
|
+
'/:id/:z(\\d+)/:x(\\d+)/:y(\\d+).:format([\\w.]+)',
|
|
21
|
+
(req, res, next) => {
|
|
22
|
+
const item = repo[req.params.id];
|
|
23
|
+
if (!item) {
|
|
24
|
+
return res.sendStatus(404);
|
|
25
|
+
}
|
|
26
|
+
const tileJSONFormat = item.tileJSON.format;
|
|
27
|
+
const z = req.params.z | 0;
|
|
28
|
+
const x = req.params.x | 0;
|
|
29
|
+
const y = req.params.y | 0;
|
|
30
|
+
let format = req.params.format;
|
|
31
|
+
if (format === options.pbfAlias) {
|
|
32
|
+
format = 'pbf';
|
|
33
|
+
}
|
|
34
|
+
if (
|
|
35
|
+
format !== tileJSONFormat &&
|
|
36
|
+
!(format === 'geojson' && tileJSONFormat === 'pbf')
|
|
37
|
+
) {
|
|
38
|
+
return res.status(404).send('Invalid format');
|
|
39
|
+
}
|
|
40
|
+
if (
|
|
41
|
+
z < item.tileJSON.minzoom ||
|
|
42
|
+
0 ||
|
|
43
|
+
x < 0 ||
|
|
44
|
+
y < 0 ||
|
|
37
45
|
z > item.tileJSON.maxzoom ||
|
|
38
|
-
x >= Math.pow(2, z) ||
|
|
39
|
-
|
|
40
|
-
|
|
41
|
-
|
|
42
|
-
|
|
43
|
-
|
|
44
|
-
|
|
45
|
-
|
|
46
|
-
|
|
47
|
-
|
|
48
|
-
|
|
49
|
-
|
|
50
|
-
|
|
51
|
-
return res.status(404).send('Not found');
|
|
46
|
+
x >= Math.pow(2, z) ||
|
|
47
|
+
y >= Math.pow(2, z)
|
|
48
|
+
) {
|
|
49
|
+
return res.status(404).send('Out of bounds');
|
|
50
|
+
}
|
|
51
|
+
item.source.getTile(z, x, y, (err, data, headers) => {
|
|
52
|
+
let isGzipped;
|
|
53
|
+
if (err) {
|
|
54
|
+
if (/does not exist/.test(err.message)) {
|
|
55
|
+
return res.status(204).send();
|
|
56
|
+
} else {
|
|
57
|
+
return res.status(500).send(err.message);
|
|
58
|
+
}
|
|
52
59
|
} else {
|
|
53
|
-
if (
|
|
54
|
-
|
|
55
|
-
|
|
56
|
-
if (
|
|
60
|
+
if (data == null) {
|
|
61
|
+
return res.status(404).send('Not found');
|
|
62
|
+
} else {
|
|
63
|
+
if (tileJSONFormat === 'pbf') {
|
|
64
|
+
isGzipped =
|
|
65
|
+
data.slice(0, 2).indexOf(Buffer.from([0x1f, 0x8b])) === 0;
|
|
66
|
+
if (options.dataDecoratorFunc) {
|
|
67
|
+
if (isGzipped) {
|
|
68
|
+
data = zlib.unzipSync(data);
|
|
69
|
+
isGzipped = false;
|
|
70
|
+
}
|
|
71
|
+
data = options.dataDecoratorFunc(id, 'data', data, z, x, y);
|
|
72
|
+
}
|
|
73
|
+
}
|
|
74
|
+
if (format === 'pbf') {
|
|
75
|
+
headers['Content-Type'] = 'application/x-protobuf';
|
|
76
|
+
} else if (format === 'geojson') {
|
|
77
|
+
headers['Content-Type'] = 'application/json';
|
|
78
|
+
|
|
57
79
|
if (isGzipped) {
|
|
58
80
|
data = zlib.unzipSync(data);
|
|
59
81
|
isGzipped = false;
|
|
60
82
|
}
|
|
61
|
-
data = options.dataDecoratorFunc(id, 'data', data, z, x, y);
|
|
62
|
-
}
|
|
63
|
-
}
|
|
64
|
-
if (format === 'pbf') {
|
|
65
|
-
headers['Content-Type'] = 'application/x-protobuf';
|
|
66
|
-
} else if (format === 'geojson') {
|
|
67
|
-
headers['Content-Type'] = 'application/json';
|
|
68
|
-
|
|
69
|
-
if (isGzipped) {
|
|
70
|
-
data = zlib.unzipSync(data);
|
|
71
|
-
isGzipped = false;
|
|
72
|
-
}
|
|
73
83
|
|
|
74
|
-
|
|
75
|
-
|
|
76
|
-
|
|
77
|
-
|
|
78
|
-
|
|
79
|
-
|
|
80
|
-
|
|
81
|
-
|
|
82
|
-
|
|
83
|
-
|
|
84
|
-
|
|
85
|
-
|
|
84
|
+
const tile = new VectorTile(new Pbf(data));
|
|
85
|
+
const geojson = {
|
|
86
|
+
type: 'FeatureCollection',
|
|
87
|
+
features: [],
|
|
88
|
+
};
|
|
89
|
+
for (const layerName in tile.layers) {
|
|
90
|
+
const layer = tile.layers[layerName];
|
|
91
|
+
for (let i = 0; i < layer.length; i++) {
|
|
92
|
+
const feature = layer.feature(i);
|
|
93
|
+
const featureGeoJSON = feature.toGeoJSON(x, y, z);
|
|
94
|
+
featureGeoJSON.properties.layer = layerName;
|
|
95
|
+
geojson.features.push(featureGeoJSON);
|
|
96
|
+
}
|
|
86
97
|
}
|
|
98
|
+
data = JSON.stringify(geojson);
|
|
87
99
|
}
|
|
88
|
-
|
|
89
|
-
|
|
90
|
-
|
|
91
|
-
headers['Content-Encoding'] = 'gzip';
|
|
92
|
-
res.set(headers);
|
|
100
|
+
delete headers['ETag']; // do not trust the tile ETag -- regenerate
|
|
101
|
+
headers['Content-Encoding'] = 'gzip';
|
|
102
|
+
res.set(headers);
|
|
93
103
|
|
|
94
|
-
|
|
95
|
-
|
|
96
|
-
|
|
97
|
-
|
|
104
|
+
if (!isGzipped) {
|
|
105
|
+
data = zlib.gzipSync(data);
|
|
106
|
+
isGzipped = true;
|
|
107
|
+
}
|
|
98
108
|
|
|
99
|
-
|
|
109
|
+
return res.status(200).send(data);
|
|
110
|
+
}
|
|
100
111
|
}
|
|
101
|
-
}
|
|
102
|
-
}
|
|
103
|
-
|
|
112
|
+
});
|
|
113
|
+
},
|
|
114
|
+
);
|
|
104
115
|
|
|
105
116
|
app.get('/:id.json', (req, res, next) => {
|
|
106
117
|
const item = repo[req.params.id];
|
|
@@ -108,10 +119,16 @@ export const serve_data = {
|
|
|
108
119
|
return res.sendStatus(404);
|
|
109
120
|
}
|
|
110
121
|
const info = clone(item.tileJSON);
|
|
111
|
-
info.tiles = getTileUrls(
|
|
112
|
-
|
|
113
|
-
|
|
114
|
-
|
|
122
|
+
info.tiles = getTileUrls(
|
|
123
|
+
req,
|
|
124
|
+
info.tiles,
|
|
125
|
+
`data/${req.params.id}`,
|
|
126
|
+
info.format,
|
|
127
|
+
item.publicUrl,
|
|
128
|
+
{
|
|
129
|
+
pbf: options.pbfAlias,
|
|
130
|
+
},
|
|
131
|
+
);
|
|
115
132
|
return res.send(info);
|
|
116
133
|
});
|
|
117
134
|
|
|
@@ -120,7 +137,7 @@ export const serve_data = {
|
|
|
120
137
|
add: (options, repo, params, id, publicUrl) => {
|
|
121
138
|
const mbtilesFile = path.resolve(options.paths.mbtiles, params.mbtiles);
|
|
122
139
|
let tileJSON = {
|
|
123
|
-
|
|
140
|
+
tiles: params.domains || options.domains,
|
|
124
141
|
};
|
|
125
142
|
|
|
126
143
|
const mbtilesFileStats = fs.statSync(mbtilesFile);
|
|
@@ -129,7 +146,7 @@ export const serve_data = {
|
|
|
129
146
|
}
|
|
130
147
|
let source;
|
|
131
148
|
const sourceInfoPromise = new Promise((resolve, reject) => {
|
|
132
|
-
source = new MBTiles(mbtilesFile + '?mode=ro', err => {
|
|
149
|
+
source = new MBTiles(mbtilesFile + '?mode=ro', (err) => {
|
|
133
150
|
if (err) {
|
|
134
151
|
reject(err);
|
|
135
152
|
return;
|
|
@@ -164,8 +181,8 @@ export const serve_data = {
|
|
|
164
181
|
repo[id] = {
|
|
165
182
|
tileJSON,
|
|
166
183
|
publicUrl,
|
|
167
|
-
source
|
|
184
|
+
source,
|
|
168
185
|
};
|
|
169
186
|
});
|
|
170
|
-
}
|
|
187
|
+
},
|
|
171
188
|
};
|
package/src/serve_font.js
CHANGED
|
@@ -4,7 +4,7 @@ import express from 'express';
|
|
|
4
4
|
import fs from 'node:fs';
|
|
5
5
|
import path from 'path';
|
|
6
6
|
|
|
7
|
-
import {getFontsPbf} from './utils.js';
|
|
7
|
+
import { getFontsPbf } from './utils.js';
|
|
8
8
|
|
|
9
9
|
export const serve_font = (options, allowedFonts) => {
|
|
10
10
|
const app = express().disable('x-powered-by');
|
|
@@ -26,8 +26,10 @@ export const serve_font = (options, allowedFonts) => {
|
|
|
26
26
|
reject(err);
|
|
27
27
|
return;
|
|
28
28
|
}
|
|
29
|
-
if (
|
|
30
|
-
|
|
29
|
+
if (
|
|
30
|
+
stats.isDirectory() &&
|
|
31
|
+
fs.existsSync(path.join(fontPath, file, '0-255.pbf'))
|
|
32
|
+
) {
|
|
31
33
|
existingFonts[path.basename(file)] = true;
|
|
32
34
|
}
|
|
33
35
|
});
|
|
@@ -40,19 +42,26 @@ export const serve_font = (options, allowedFonts) => {
|
|
|
40
42
|
const fontstack = decodeURI(req.params.fontstack);
|
|
41
43
|
const range = req.params.range;
|
|
42
44
|
|
|
43
|
-
getFontsPbf(
|
|
44
|
-
|
|
45
|
-
|
|
46
|
-
|
|
47
|
-
|
|
48
|
-
|
|
45
|
+
getFontsPbf(
|
|
46
|
+
options.serveAllFonts ? null : allowedFonts,
|
|
47
|
+
fontPath,
|
|
48
|
+
fontstack,
|
|
49
|
+
range,
|
|
50
|
+
existingFonts,
|
|
51
|
+
).then(
|
|
52
|
+
(concated) => {
|
|
53
|
+
res.header('Content-type', 'application/x-protobuf');
|
|
54
|
+
res.header('Last-Modified', lastModified);
|
|
55
|
+
return res.send(concated);
|
|
56
|
+
},
|
|
57
|
+
(err) => res.status(400).send(err),
|
|
49
58
|
);
|
|
50
59
|
});
|
|
51
60
|
|
|
52
61
|
app.get('/fonts.json', (req, res, next) => {
|
|
53
62
|
res.header('Content-type', 'application/json');
|
|
54
63
|
return res.send(
|
|
55
|
-
|
|
64
|
+
Object.keys(options.serveAllFonts ? existingFonts : allowedFonts).sort(),
|
|
56
65
|
);
|
|
57
66
|
});
|
|
58
67
|
|
package/src/serve_light.js
CHANGED
|
@@ -1,10 +1,9 @@
|
|
|
1
|
+
/* eslint-disable @typescript-eslint/no-empty-function */
|
|
2
|
+
/* eslint-disable @typescript-eslint/no-unused-vars */
|
|
1
3
|
'use strict';
|
|
2
4
|
|
|
3
5
|
export const serve_rendered = {
|
|
4
|
-
init: (options, repo) => {
|
|
5
|
-
},
|
|
6
|
-
|
|
7
|
-
},
|
|
8
|
-
remove: (repo, id) => {
|
|
9
|
-
}
|
|
6
|
+
init: (options, repo) => {},
|
|
7
|
+
add: (options, repo, params, id, publicUrl, dataResolver) => {},
|
|
8
|
+
remove: (repo, id) => {},
|
|
10
9
|
};
|