tileserver-gl-light 4.13.0 → 4.13.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/package.json +2 -2
- package/src/main.js +46 -53
- package/src/mbtiles_wrapper.js +46 -0
- package/src/serve_data.js +16 -30
- package/src/serve_rendered.js +41 -59
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "tileserver-gl-light",
|
|
3
|
-
"version": "4.13.
|
|
3
|
+
"version": "4.13.1",
|
|
4
4
|
"description": "Map tile server for JSON GL styles - serving vector tiles",
|
|
5
5
|
"main": "src/main.js",
|
|
6
6
|
"bin": "src/main.js",
|
|
@@ -25,7 +25,7 @@
|
|
|
25
25
|
"@maplibre/maplibre-gl-style-spec": "20.3.1",
|
|
26
26
|
"@sindresorhus/fnv1a": "3.1.0",
|
|
27
27
|
"advanced-pool": "0.3.3",
|
|
28
|
-
"axios": "^1.7.
|
|
28
|
+
"axios": "^1.7.6",
|
|
29
29
|
"chokidar": "3.6.0",
|
|
30
30
|
"clone": "2.1.2",
|
|
31
31
|
"color": "4.2.3",
|
package/src/main.js
CHANGED
|
@@ -8,9 +8,11 @@ import path from 'path';
|
|
|
8
8
|
import { fileURLToPath } from 'url';
|
|
9
9
|
import axios from 'axios';
|
|
10
10
|
import { server } from './server.js';
|
|
11
|
-
import MBTiles from '@mapbox/mbtiles';
|
|
12
11
|
import { isValidHttpUrl } from './utils.js';
|
|
13
12
|
import { openPMtiles, getPMtilesInfo } from './pmtiles_adapter.js';
|
|
13
|
+
import { program } from 'commander';
|
|
14
|
+
import { existsP } from './promises.js';
|
|
15
|
+
import { openMbTilesWrapper } from './mbtiles_wrapper.js';
|
|
14
16
|
|
|
15
17
|
const __filename = fileURLToPath(import.meta.url);
|
|
16
18
|
const __dirname = path.dirname(__filename);
|
|
@@ -23,8 +25,6 @@ if (args.length >= 3 && args[2][0] !== '-') {
|
|
|
23
25
|
args.splice(2, 0, '--mbtiles');
|
|
24
26
|
}
|
|
25
27
|
|
|
26
|
-
import { program } from 'commander';
|
|
27
|
-
import { existsP } from './promises.js';
|
|
28
28
|
program
|
|
29
29
|
.description('tileserver-gl startup options')
|
|
30
30
|
.usage('tileserver-gl [mbtiles] [options]')
|
|
@@ -184,62 +184,55 @@ const startWithInputFile = async (inputFile) => {
|
|
|
184
184
|
);
|
|
185
185
|
process.exit(1);
|
|
186
186
|
}
|
|
187
|
-
|
|
188
|
-
|
|
189
|
-
|
|
190
|
-
|
|
191
|
-
|
|
192
|
-
|
|
193
|
-
|
|
194
|
-
|
|
195
|
-
|
|
196
|
-
|
|
197
|
-
|
|
198
|
-
`Make sure ${path.basename(inputFile)} is valid MBTiles.`,
|
|
199
|
-
);
|
|
200
|
-
process.exit(1);
|
|
201
|
-
}
|
|
202
|
-
const bounds = info.bounds;
|
|
187
|
+
let info;
|
|
188
|
+
try {
|
|
189
|
+
const mbw = await openMbTilesWrapper(inputFile);
|
|
190
|
+
info = await mbw.getInfo();
|
|
191
|
+
if (!info) throw new Error('Metadata missing in the MBTiles.');
|
|
192
|
+
} catch (err) {
|
|
193
|
+
console.log('ERROR: Unable to open MBTiles or read metadata:', err);
|
|
194
|
+
console.log(`Make sure ${path.basename(inputFile)} is valid MBTiles.`);
|
|
195
|
+
process.exit(1);
|
|
196
|
+
}
|
|
197
|
+
const bounds = info.bounds;
|
|
203
198
|
|
|
204
|
-
|
|
205
|
-
|
|
206
|
-
|
|
207
|
-
|
|
208
|
-
|
|
209
|
-
|
|
210
|
-
|
|
199
|
+
if (
|
|
200
|
+
info.format === 'pbf' &&
|
|
201
|
+
info.name.toLowerCase().indexOf('openmaptiles') > -1
|
|
202
|
+
) {
|
|
203
|
+
config['data'][`v3`] = {
|
|
204
|
+
mbtiles: path.basename(inputFile),
|
|
205
|
+
};
|
|
211
206
|
|
|
212
|
-
|
|
213
|
-
|
|
214
|
-
|
|
215
|
-
|
|
216
|
-
|
|
217
|
-
|
|
218
|
-
|
|
219
|
-
|
|
220
|
-
|
|
221
|
-
|
|
222
|
-
};
|
|
223
|
-
}
|
|
224
|
-
}
|
|
225
|
-
} else {
|
|
226
|
-
console.log(
|
|
227
|
-
`WARN: MBTiles not in "openmaptiles" format. Serving raw data only...`,
|
|
228
|
-
);
|
|
229
|
-
config['data'][(info.id || 'mbtiles').replace(/[?/:]/g, '_')] = {
|
|
230
|
-
mbtiles: path.basename(inputFile),
|
|
207
|
+
const styles = await fsp.readdir(path.resolve(styleDir, 'styles'));
|
|
208
|
+
for (const styleName of styles) {
|
|
209
|
+
const styleFileRel = styleName + '/style.json';
|
|
210
|
+
const styleFile = path.resolve(styleDir, 'styles', styleFileRel);
|
|
211
|
+
if (await existsP(styleFile)) {
|
|
212
|
+
config['styles'][styleName] = {
|
|
213
|
+
style: styleFileRel,
|
|
214
|
+
tilejson: {
|
|
215
|
+
bounds,
|
|
216
|
+
},
|
|
231
217
|
};
|
|
232
218
|
}
|
|
219
|
+
}
|
|
220
|
+
} else {
|
|
221
|
+
console.log(
|
|
222
|
+
`WARN: MBTiles not in "openmaptiles" format. Serving raw data only...`,
|
|
223
|
+
);
|
|
224
|
+
config['data'][(info.id || 'mbtiles').replace(/[?/:]/g, '_')] = {
|
|
225
|
+
mbtiles: path.basename(inputFile),
|
|
226
|
+
};
|
|
227
|
+
}
|
|
233
228
|
|
|
234
|
-
|
|
235
|
-
|
|
236
|
-
|
|
237
|
-
|
|
238
|
-
|
|
229
|
+
if (opts.verbose) {
|
|
230
|
+
console.log(JSON.stringify(config, undefined, 2));
|
|
231
|
+
} else {
|
|
232
|
+
console.log('Run with --verbose to see the config file here.');
|
|
233
|
+
}
|
|
239
234
|
|
|
240
|
-
|
|
241
|
-
});
|
|
242
|
-
});
|
|
235
|
+
return startServer(null, config);
|
|
243
236
|
}
|
|
244
237
|
};
|
|
245
238
|
|
|
@@ -0,0 +1,46 @@
|
|
|
1
|
+
import MBTiles from '@mapbox/mbtiles';
|
|
2
|
+
import util from 'node:util';
|
|
3
|
+
|
|
4
|
+
/**
|
|
5
|
+
* Promise-ful wrapper around the MBTiles class.
|
|
6
|
+
*/
|
|
7
|
+
class MBTilesWrapper {
|
|
8
|
+
constructor(mbtiles) {
|
|
9
|
+
this._mbtiles = mbtiles;
|
|
10
|
+
this._getInfoP = util.promisify(mbtiles.getInfo.bind(mbtiles));
|
|
11
|
+
}
|
|
12
|
+
|
|
13
|
+
/**
|
|
14
|
+
* Get the underlying MBTiles object.
|
|
15
|
+
* @returns {MBTiles}
|
|
16
|
+
*/
|
|
17
|
+
getMbTiles() {
|
|
18
|
+
return this._mbtiles;
|
|
19
|
+
}
|
|
20
|
+
|
|
21
|
+
/**
|
|
22
|
+
* Get the MBTiles metadata object.
|
|
23
|
+
* @returns {Promise<object>}
|
|
24
|
+
*/
|
|
25
|
+
getInfo() {
|
|
26
|
+
return this._getInfoP();
|
|
27
|
+
}
|
|
28
|
+
}
|
|
29
|
+
|
|
30
|
+
/**
|
|
31
|
+
* Open the given MBTiles file and return a promise that resolves with a
|
|
32
|
+
* MBTilesWrapper instance.
|
|
33
|
+
* @param inputFile Input file
|
|
34
|
+
* @returns {Promise<MBTilesWrapper>}
|
|
35
|
+
*/
|
|
36
|
+
export function openMbTilesWrapper(inputFile) {
|
|
37
|
+
return new Promise((resolve, reject) => {
|
|
38
|
+
const mbtiles = new MBTiles(inputFile + '?mode=ro', (err) => {
|
|
39
|
+
if (err) {
|
|
40
|
+
reject(err);
|
|
41
|
+
return;
|
|
42
|
+
}
|
|
43
|
+
resolve(new MBTilesWrapper(mbtiles));
|
|
44
|
+
});
|
|
45
|
+
});
|
|
46
|
+
}
|
package/src/serve_data.js
CHANGED
|
@@ -5,7 +5,6 @@ import path from 'path';
|
|
|
5
5
|
|
|
6
6
|
import clone from 'clone';
|
|
7
7
|
import express from 'express';
|
|
8
|
-
import MBTiles from '@mapbox/mbtiles';
|
|
9
8
|
import Pbf from 'pbf';
|
|
10
9
|
import { VectorTile } from '@mapbox/vector-tile';
|
|
11
10
|
|
|
@@ -16,6 +15,7 @@ import {
|
|
|
16
15
|
openPMtiles,
|
|
17
16
|
} from './pmtiles_adapter.js';
|
|
18
17
|
import { gunzipP, gzipP } from './promises.js';
|
|
18
|
+
import { openMbTilesWrapper } from './mbtiles_wrapper.js';
|
|
19
19
|
|
|
20
20
|
export const serve_data = {
|
|
21
21
|
init: (options, repo) => {
|
|
@@ -242,39 +242,25 @@ export const serve_data = {
|
|
|
242
242
|
}
|
|
243
243
|
} else if (inputType === 'mbtiles') {
|
|
244
244
|
sourceType = 'mbtiles';
|
|
245
|
-
const
|
|
246
|
-
|
|
247
|
-
|
|
248
|
-
|
|
249
|
-
|
|
250
|
-
}
|
|
251
|
-
source.getInfo((err, info) => {
|
|
252
|
-
if (err) {
|
|
253
|
-
reject(err);
|
|
254
|
-
return;
|
|
255
|
-
}
|
|
256
|
-
tileJSON['name'] = id;
|
|
257
|
-
tileJSON['format'] = 'pbf';
|
|
258
|
-
|
|
259
|
-
Object.assign(tileJSON, info);
|
|
245
|
+
const mbw = await openMbTilesWrapper(inputFile);
|
|
246
|
+
const info = await mbw.getInfo();
|
|
247
|
+
source = mbw.getMbTiles();
|
|
248
|
+
tileJSON['name'] = id;
|
|
249
|
+
tileJSON['format'] = 'pbf';
|
|
260
250
|
|
|
261
|
-
|
|
262
|
-
delete tileJSON['filesize'];
|
|
263
|
-
delete tileJSON['mtime'];
|
|
264
|
-
delete tileJSON['scheme'];
|
|
251
|
+
Object.assign(tileJSON, info);
|
|
265
252
|
|
|
266
|
-
|
|
267
|
-
|
|
253
|
+
tileJSON['tilejson'] = '2.0.0';
|
|
254
|
+
delete tileJSON['filesize'];
|
|
255
|
+
delete tileJSON['mtime'];
|
|
256
|
+
delete tileJSON['scheme'];
|
|
268
257
|
|
|
269
|
-
|
|
270
|
-
|
|
271
|
-
}
|
|
272
|
-
resolve();
|
|
273
|
-
});
|
|
274
|
-
});
|
|
275
|
-
});
|
|
258
|
+
Object.assign(tileJSON, params.tilejson || {});
|
|
259
|
+
fixTileJSONCenter(tileJSON);
|
|
276
260
|
|
|
277
|
-
|
|
261
|
+
if (options.dataDecoratorFunc) {
|
|
262
|
+
tileJSON = options.dataDecoratorFunc(id, 'tilejson', tileJSON);
|
|
263
|
+
}
|
|
278
264
|
}
|
|
279
265
|
|
|
280
266
|
repo[id] = {
|
package/src/serve_rendered.js
CHANGED
|
@@ -24,7 +24,6 @@ import express from 'express';
|
|
|
24
24
|
import sanitize from 'sanitize-filename';
|
|
25
25
|
import SphericalMercator from '@mapbox/sphericalmercator';
|
|
26
26
|
import mlgl from '@maplibre/maplibre-gl-native';
|
|
27
|
-
import MBTiles from '@mapbox/mbtiles';
|
|
28
27
|
import polyline from '@mapbox/polyline';
|
|
29
28
|
import proj4 from 'proj4';
|
|
30
29
|
import axios from 'axios';
|
|
@@ -43,6 +42,7 @@ import {
|
|
|
43
42
|
import { renderOverlay, renderWatermark, renderAttribution } from './render.js';
|
|
44
43
|
import fsp from 'node:fs/promises';
|
|
45
44
|
import { gunzipP } from './promises.js';
|
|
45
|
+
import { openMbTilesWrapper } from './mbtiles_wrapper.js';
|
|
46
46
|
|
|
47
47
|
const FLOAT_PATTERN = '[+-]?(?:\\d+|\\d+.?\\d+)';
|
|
48
48
|
const PATH_PATTERN =
|
|
@@ -1131,7 +1131,6 @@ export const serve_rendered = {
|
|
|
1131
1131
|
};
|
|
1132
1132
|
repo[id] = repoobj;
|
|
1133
1133
|
|
|
1134
|
-
const queue = [];
|
|
1135
1134
|
for (const name of Object.keys(styleJSON.sources)) {
|
|
1136
1135
|
let sourceType;
|
|
1137
1136
|
let source = styleJSON.sources[name];
|
|
@@ -1205,69 +1204,52 @@ export const serve_rendered = {
|
|
|
1205
1204
|
}
|
|
1206
1205
|
}
|
|
1207
1206
|
} else {
|
|
1208
|
-
|
|
1209
|
-
|
|
1210
|
-
|
|
1211
|
-
|
|
1212
|
-
|
|
1213
|
-
|
|
1214
|
-
|
|
1215
|
-
|
|
1216
|
-
map.sources[name].getInfo((err, info) => {
|
|
1217
|
-
if (err) {
|
|
1218
|
-
console.error(err);
|
|
1219
|
-
return;
|
|
1220
|
-
}
|
|
1221
|
-
map.sourceTypes[name] = 'mbtiles';
|
|
1222
|
-
|
|
1223
|
-
if (!repoobj.dataProjWGStoInternalWGS && info.proj4) {
|
|
1224
|
-
// how to do this for multiple sources with different proj4 defs?
|
|
1225
|
-
const to3857 = proj4('EPSG:3857');
|
|
1226
|
-
const toDataProj = proj4(info.proj4);
|
|
1227
|
-
repoobj.dataProjWGStoInternalWGS = (xy) =>
|
|
1228
|
-
to3857.inverse(toDataProj.forward(xy));
|
|
1229
|
-
}
|
|
1207
|
+
const inputFileStats = await fsp.stat(inputFile);
|
|
1208
|
+
if (!inputFileStats.isFile() || inputFileStats.size === 0) {
|
|
1209
|
+
throw Error(`Not valid MBTiles file: "${inputFile}"`);
|
|
1210
|
+
}
|
|
1211
|
+
const mbw = await openMbTilesWrapper(inputFile);
|
|
1212
|
+
const info = await mbw.getInfo();
|
|
1213
|
+
map.sources[name] = mbw.getMbTiles();
|
|
1214
|
+
map.sourceTypes[name] = 'mbtiles';
|
|
1230
1215
|
|
|
1231
|
-
|
|
1232
|
-
|
|
1233
|
-
|
|
1234
|
-
|
|
1235
|
-
|
|
1236
|
-
|
|
1237
|
-
|
|
1238
|
-
delete source.scheme;
|
|
1239
|
-
|
|
1240
|
-
if (options.dataDecoratorFunc) {
|
|
1241
|
-
source = options.dataDecoratorFunc(
|
|
1242
|
-
name,
|
|
1243
|
-
'tilejson',
|
|
1244
|
-
source,
|
|
1245
|
-
);
|
|
1246
|
-
}
|
|
1216
|
+
if (!repoobj.dataProjWGStoInternalWGS && info.proj4) {
|
|
1217
|
+
// how to do this for multiple sources with different proj4 defs?
|
|
1218
|
+
const to3857 = proj4('EPSG:3857');
|
|
1219
|
+
const toDataProj = proj4(info.proj4);
|
|
1220
|
+
repoobj.dataProjWGStoInternalWGS = (xy) =>
|
|
1221
|
+
to3857.inverse(toDataProj.forward(xy));
|
|
1222
|
+
}
|
|
1247
1223
|
|
|
1248
|
-
|
|
1249
|
-
|
|
1250
|
-
|
|
1251
|
-
|
|
1252
|
-
|
|
1253
|
-
|
|
1254
|
-
|
|
1255
|
-
|
|
1256
|
-
|
|
1257
|
-
|
|
1258
|
-
|
|
1259
|
-
|
|
1260
|
-
|
|
1261
|
-
|
|
1262
|
-
|
|
1263
|
-
|
|
1264
|
-
|
|
1224
|
+
const type = source.type;
|
|
1225
|
+
Object.assign(source, info);
|
|
1226
|
+
source.type = type;
|
|
1227
|
+
source.tiles = [
|
|
1228
|
+
// meta url which will be detected when requested
|
|
1229
|
+
`mbtiles://${name}/{z}/{x}/{y}.${info.format || 'pbf'}`,
|
|
1230
|
+
];
|
|
1231
|
+
delete source.scheme;
|
|
1232
|
+
|
|
1233
|
+
if (options.dataDecoratorFunc) {
|
|
1234
|
+
source = options.dataDecoratorFunc(name, 'tilejson', source);
|
|
1235
|
+
}
|
|
1236
|
+
|
|
1237
|
+
if (
|
|
1238
|
+
!attributionOverride &&
|
|
1239
|
+
source.attribution &&
|
|
1240
|
+
source.attribution.length > 0
|
|
1241
|
+
) {
|
|
1242
|
+
if (!tileJSON.attribution.includes(source.attribution)) {
|
|
1243
|
+
if (tileJSON.attribution.length > 0) {
|
|
1244
|
+
tileJSON.attribution += ' | ';
|
|
1245
|
+
}
|
|
1246
|
+
tileJSON.attribution += source.attribution;
|
|
1247
|
+
}
|
|
1248
|
+
}
|
|
1265
1249
|
}
|
|
1266
1250
|
}
|
|
1267
1251
|
}
|
|
1268
1252
|
|
|
1269
|
-
await Promise.all(queue);
|
|
1270
|
-
|
|
1271
1253
|
// standard and @2x tiles are much more usual -> default to larger pools
|
|
1272
1254
|
const minPoolSizes = options.minRendererPoolSizes || [8, 4, 2];
|
|
1273
1255
|
const maxPoolSizes = options.maxRendererPoolSizes || [16, 8, 4];
|