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 CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "tileserver-gl-light",
3
- "version": "4.13.0",
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.5",
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
- const instance = new MBTiles(inputFile + '?mode=ro', (err) => {
188
- if (err) {
189
- console.log('ERROR: Unable to open MBTiles.');
190
- console.log(`Make sure ${path.basename(inputFile)} is valid MBTiles.`);
191
- process.exit(1);
192
- }
193
-
194
- instance.getInfo(async (err, info) => {
195
- if (err || !info) {
196
- console.log('ERROR: Metadata missing in the MBTiles.');
197
- console.log(
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
- if (
205
- info.format === 'pbf' &&
206
- info.name.toLowerCase().indexOf('openmaptiles') > -1
207
- ) {
208
- config['data'][`v3`] = {
209
- mbtiles: path.basename(inputFile),
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
- const styles = await fsp.readdir(path.resolve(styleDir, 'styles'));
213
- for (const styleName of styles) {
214
- const styleFileRel = styleName + '/style.json';
215
- const styleFile = path.resolve(styleDir, 'styles', styleFileRel);
216
- if (await existsP(styleFile)) {
217
- config['styles'][styleName] = {
218
- style: styleFileRel,
219
- tilejson: {
220
- bounds,
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
- if (opts.verbose) {
235
- console.log(JSON.stringify(config, undefined, 2));
236
- } else {
237
- console.log('Run with --verbose to see the config file here.');
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
- return startServer(null, config);
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 sourceInfoPromise = new Promise((resolve, reject) => {
246
- source = new MBTiles(inputFile + '?mode=ro', (err) => {
247
- if (err) {
248
- reject(err);
249
- return;
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
- tileJSON['tilejson'] = '2.0.0';
262
- delete tileJSON['filesize'];
263
- delete tileJSON['mtime'];
264
- delete tileJSON['scheme'];
251
+ Object.assign(tileJSON, info);
265
252
 
266
- Object.assign(tileJSON, params.tilejson || {});
267
- fixTileJSONCenter(tileJSON);
253
+ tileJSON['tilejson'] = '2.0.0';
254
+ delete tileJSON['filesize'];
255
+ delete tileJSON['mtime'];
256
+ delete tileJSON['scheme'];
268
257
 
269
- if (options.dataDecoratorFunc) {
270
- tileJSON = options.dataDecoratorFunc(id, 'tilejson', tileJSON);
271
- }
272
- resolve();
273
- });
274
- });
275
- });
258
+ Object.assign(tileJSON, params.tilejson || {});
259
+ fixTileJSONCenter(tileJSON);
276
260
 
277
- await sourceInfoPromise;
261
+ if (options.dataDecoratorFunc) {
262
+ tileJSON = options.dataDecoratorFunc(id, 'tilejson', tileJSON);
263
+ }
278
264
  }
279
265
 
280
266
  repo[id] = {
@@ -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
- queue.push(
1209
- new Promise(async (resolve, reject) => {
1210
- inputFile = path.resolve(options.paths.mbtiles, inputFile);
1211
- const inputFileStats = await fsp.stat(inputFile);
1212
- if (!inputFileStats.isFile() || inputFileStats.size === 0) {
1213
- throw Error(`Not valid MBTiles file: "${inputFile}"`);
1214
- }
1215
- map.sources[name] = new MBTiles(inputFile + '?mode=ro', (err) => {
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
- const type = source.type;
1232
- Object.assign(source, info);
1233
- source.type = type;
1234
- source.tiles = [
1235
- // meta url which will be detected when requested
1236
- `mbtiles://${name}/{z}/{x}/{y}.${info.format || 'pbf'}`,
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
- if (
1249
- !attributionOverride &&
1250
- source.attribution &&
1251
- source.attribution.length > 0
1252
- ) {
1253
- if (!tileJSON.attribution.includes(source.attribution)) {
1254
- if (tileJSON.attribution.length > 0) {
1255
- tileJSON.attribution += ' | ';
1256
- }
1257
- tileJSON.attribution += source.attribution;
1258
- }
1259
- }
1260
- resolve();
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];