tileserver-gl-light 5.5.0-pre.5 → 5.5.0-pre.7
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 +4 -1
- package/docs/config.rst +11 -10
- package/docs/usage.rst +21 -0
- package/package.json +5 -5
- package/public/resources/maplibre-gl-inspect.js +12 -8
- package/public/resources/maplibre-gl-inspect.js.map +1 -1
- package/src/main.js +15 -3
- package/src/pmtiles_adapter.js +27 -3
- package/src/serve_data.js +22 -11
- package/src/serve_font.js +2 -2
- package/src/serve_rendered.js +84 -49
- package/src/serve_style.js +29 -8
- package/src/server.js +87 -35
- package/src/utils.js +1 -2
- package/test/tiles_data.js +1 -1
package/src/server.js
CHANGED
|
@@ -206,8 +206,9 @@ async function start(opts) {
|
|
|
206
206
|
const styleFileData = await fs.promises.readFile(styleFile);
|
|
207
207
|
styleJSON = JSON.parse(styleFileData);
|
|
208
208
|
}
|
|
209
|
-
} catch {
|
|
209
|
+
} catch (err) {
|
|
210
210
|
console.log(`Error getting style file "${item.style}"`);
|
|
211
|
+
console.error(err && err.stack ? err.stack : err);
|
|
211
212
|
return false;
|
|
212
213
|
}
|
|
213
214
|
|
|
@@ -225,13 +226,17 @@ async function start(opts) {
|
|
|
225
226
|
if (id === styleSourceId) {
|
|
226
227
|
// Style id was found in data ids, return that id
|
|
227
228
|
dataItemId = id;
|
|
229
|
+
break;
|
|
228
230
|
} else {
|
|
229
231
|
// eslint-disable-next-line security/detect-object-injection -- id is from Object.keys of data config
|
|
230
|
-
const
|
|
231
|
-
|
|
232
|
-
if (
|
|
233
|
-
|
|
232
|
+
const sourceData = data[id];
|
|
233
|
+
|
|
234
|
+
if (
|
|
235
|
+
(sourceData.pmtiles && sourceData.pmtiles === styleSourceId) ||
|
|
236
|
+
(sourceData.mbtiles && sourceData.mbtiles === styleSourceId)
|
|
237
|
+
) {
|
|
234
238
|
dataItemId = id;
|
|
239
|
+
break;
|
|
235
240
|
}
|
|
236
241
|
}
|
|
237
242
|
}
|
|
@@ -286,11 +291,21 @@ async function start(opts) {
|
|
|
286
291
|
function dataResolver(styleSourceId) {
|
|
287
292
|
let resolvedFileType;
|
|
288
293
|
let resolvedInputFile;
|
|
289
|
-
let resolvedSparse = false;
|
|
290
294
|
let resolvedS3Profile;
|
|
291
295
|
let resolvedRequestPayer;
|
|
292
296
|
let resolvedS3Region;
|
|
293
297
|
let resolvedS3UrlFormat;
|
|
298
|
+
let resolvedSparse;
|
|
299
|
+
|
|
300
|
+
// Debug logging to see what we're trying to match
|
|
301
|
+
if (opts.verbose >= 3) {
|
|
302
|
+
console.log(
|
|
303
|
+
`[dataResolver] Looking for styleSourceId: ${styleSourceId}`,
|
|
304
|
+
);
|
|
305
|
+
console.log(
|
|
306
|
+
`[dataResolver] Available data keys: ${Object.keys(data).join(', ')}`,
|
|
307
|
+
);
|
|
308
|
+
}
|
|
294
309
|
|
|
295
310
|
for (const id of Object.keys(data)) {
|
|
296
311
|
// eslint-disable-next-line security/detect-object-injection -- id is from Object.keys of data config
|
|
@@ -308,21 +323,31 @@ async function start(opts) {
|
|
|
308
323
|
}
|
|
309
324
|
|
|
310
325
|
if (currentFileType && currentInputFileValue) {
|
|
326
|
+
// Debug logging
|
|
327
|
+
if (opts.verbose >= 3) {
|
|
328
|
+
console.log(
|
|
329
|
+
`[dataResolver] Checking id="${id}", file="${currentInputFileValue}"`,
|
|
330
|
+
);
|
|
331
|
+
}
|
|
332
|
+
|
|
311
333
|
// Check if this source matches the styleSourceId
|
|
312
|
-
|
|
313
|
-
|
|
314
|
-
|
|
315
|
-
|
|
334
|
+
// Match by ID, by file path, or by base filename
|
|
335
|
+
const matchById = styleSourceId === id;
|
|
336
|
+
const matchByFile = styleSourceId === currentInputFileValue;
|
|
337
|
+
const matchByBasename =
|
|
338
|
+
styleSourceId.includes(currentInputFileValue) ||
|
|
339
|
+
currentInputFileValue.includes(styleSourceId);
|
|
340
|
+
|
|
341
|
+
if (matchById || matchByFile || matchByBasename) {
|
|
342
|
+
if (opts.verbose >= 2) {
|
|
343
|
+
console.log(
|
|
344
|
+
`[dataResolver] Match found for styleSourceId: ${styleSourceId}. (byId=${matchById}, byFile=${matchByFile}, byBasename=${matchByBasename})`,
|
|
345
|
+
);
|
|
346
|
+
}
|
|
347
|
+
|
|
316
348
|
resolvedFileType = currentFileType;
|
|
317
349
|
resolvedInputFile = currentInputFileValue;
|
|
318
350
|
|
|
319
|
-
// Get sparse if present
|
|
320
|
-
if (Object.hasOwn(sourceData, 'sparse')) {
|
|
321
|
-
resolvedSparse = !!sourceData.sparse;
|
|
322
|
-
} else {
|
|
323
|
-
resolvedSparse = false;
|
|
324
|
-
}
|
|
325
|
-
|
|
326
351
|
// Get s3Profile if present
|
|
327
352
|
if (Object.hasOwn(sourceData, 's3Profile')) {
|
|
328
353
|
resolvedS3Profile = sourceData.s3Profile;
|
|
@@ -343,6 +368,10 @@ async function start(opts) {
|
|
|
343
368
|
resolvedS3Region = sourceData.s3Region;
|
|
344
369
|
}
|
|
345
370
|
|
|
371
|
+
// Get sparse: per-source overrides global, default to true
|
|
372
|
+
resolvedSparse =
|
|
373
|
+
sourceData.sparse ?? options.sparse ?? true;
|
|
374
|
+
|
|
346
375
|
break; // Found our match, exit the outer loop
|
|
347
376
|
}
|
|
348
377
|
}
|
|
@@ -353,14 +382,23 @@ async function start(opts) {
|
|
|
353
382
|
console.warn(
|
|
354
383
|
`Data source not found for styleSourceId: ${styleSourceId}`,
|
|
355
384
|
);
|
|
385
|
+
console.warn(
|
|
386
|
+
`Available data sources: ${Object.keys(data)
|
|
387
|
+
.map((id) => {
|
|
388
|
+
// eslint-disable-next-line security/detect-object-injection
|
|
389
|
+
const src = data[id];
|
|
390
|
+
return `${id} -> ${src.pmtiles || src.mbtiles || 'unknown'}`;
|
|
391
|
+
})
|
|
392
|
+
.join(', ')}`,
|
|
393
|
+
);
|
|
356
394
|
return {
|
|
357
395
|
inputFile: undefined,
|
|
358
396
|
fileType: undefined,
|
|
359
|
-
sparse: false,
|
|
360
397
|
s3Profile: undefined,
|
|
361
398
|
requestPayer: false,
|
|
362
399
|
s3Region: undefined,
|
|
363
400
|
s3UrlFormat: undefined,
|
|
401
|
+
sparse: true,
|
|
364
402
|
};
|
|
365
403
|
}
|
|
366
404
|
|
|
@@ -388,11 +426,11 @@ async function start(opts) {
|
|
|
388
426
|
return {
|
|
389
427
|
inputFile: resolvedInputFile,
|
|
390
428
|
fileType: resolvedFileType,
|
|
391
|
-
sparse: resolvedSparse,
|
|
392
429
|
s3Profile: resolvedS3Profile,
|
|
393
430
|
requestPayer: resolvedRequestPayer,
|
|
394
431
|
s3Region: resolvedS3Region,
|
|
395
432
|
s3UrlFormat: resolvedS3UrlFormat,
|
|
433
|
+
sparse: resolvedSparse,
|
|
396
434
|
};
|
|
397
435
|
},
|
|
398
436
|
),
|
|
@@ -404,6 +442,8 @@ async function start(opts) {
|
|
|
404
442
|
return success;
|
|
405
443
|
}
|
|
406
444
|
|
|
445
|
+
// Collect style loading promises separately
|
|
446
|
+
const stylePromises = [];
|
|
407
447
|
for (const id of Object.keys(config.styles || {})) {
|
|
408
448
|
// eslint-disable-next-line security/detect-object-injection -- id is from Object.keys of config.styles
|
|
409
449
|
const item = config.styles[id];
|
|
@@ -411,26 +451,38 @@ async function start(opts) {
|
|
|
411
451
|
console.log(`Missing "style" property for ${id}`);
|
|
412
452
|
continue;
|
|
413
453
|
}
|
|
414
|
-
|
|
454
|
+
stylePromises.push(addStyle(id, item, true, true));
|
|
415
455
|
}
|
|
456
|
+
|
|
457
|
+
// Wait for styles to finish loading, then load data sources
|
|
458
|
+
// This ensures data sources added by styles are included
|
|
459
|
+
startupPromises.push(
|
|
460
|
+
Promise.all(stylePromises).then(() => {
|
|
461
|
+
const dataLoadPromises = [];
|
|
462
|
+
for (const id of Object.keys(data)) {
|
|
463
|
+
// eslint-disable-next-line security/detect-object-injection -- id is from Object.keys of data config
|
|
464
|
+
const item = data[id];
|
|
465
|
+
|
|
466
|
+
if (!item.pmtiles && !item.mbtiles) {
|
|
467
|
+
console.log(
|
|
468
|
+
`Missing "pmtiles" or "mbtiles" property for ${id} data source`,
|
|
469
|
+
);
|
|
470
|
+
continue;
|
|
471
|
+
}
|
|
472
|
+
|
|
473
|
+
dataLoadPromises.push(
|
|
474
|
+
serve_data.add(options, serving.data, item, id, opts),
|
|
475
|
+
);
|
|
476
|
+
}
|
|
477
|
+
return Promise.all(dataLoadPromises);
|
|
478
|
+
}),
|
|
479
|
+
);
|
|
480
|
+
|
|
416
481
|
startupPromises.push(
|
|
417
482
|
serve_font(options, serving.fonts, opts).then((sub) => {
|
|
418
483
|
app.use('/', sub);
|
|
419
484
|
}),
|
|
420
485
|
);
|
|
421
|
-
for (const id of Object.keys(data)) {
|
|
422
|
-
// eslint-disable-next-line security/detect-object-injection -- id is from Object.keys of data config
|
|
423
|
-
const item = data[id];
|
|
424
|
-
// eslint-disable-next-line security/detect-object-injection -- id is from Object.keys of data config
|
|
425
|
-
const fileType = Object.keys(data[id])[0];
|
|
426
|
-
if (!fileType || !(fileType === 'pmtiles' || fileType === 'mbtiles')) {
|
|
427
|
-
console.log(
|
|
428
|
-
`Missing "pmtiles" or "mbtiles" property for ${id} data source`,
|
|
429
|
-
);
|
|
430
|
-
continue;
|
|
431
|
-
}
|
|
432
|
-
startupPromises.push(serve_data.add(options, serving.data, item, id, opts));
|
|
433
|
-
}
|
|
434
486
|
if (options.serveAllStyles) {
|
|
435
487
|
fs.readdir(options.paths.styles, { withFileTypes: true }, (err, files) => {
|
|
436
488
|
if (err) {
|
|
@@ -606,7 +658,7 @@ async function start(opts) {
|
|
|
606
658
|
const content = fs.readFileSync(templateFile, 'utf-8');
|
|
607
659
|
const compiled = handlebars.compile(content.toString());
|
|
608
660
|
app.get(urlPath, (req, res, next) => {
|
|
609
|
-
if (opts.verbose) {
|
|
661
|
+
if (opts.verbose >= 1) {
|
|
610
662
|
console.log(`Serving template at path: ${urlPath}`);
|
|
611
663
|
}
|
|
612
664
|
let data = {};
|
|
@@ -626,7 +678,7 @@ async function start(opts) {
|
|
|
626
678
|
if (template === 'wmts') res.set('Content-Type', 'text/xml');
|
|
627
679
|
return res.status(200).send(compiled(data));
|
|
628
680
|
} else {
|
|
629
|
-
if (opts.verbose) {
|
|
681
|
+
if (opts.verbose >= 1) {
|
|
630
682
|
console.log(`Forwarding request for: ${urlPath} to next route`);
|
|
631
683
|
}
|
|
632
684
|
next('route');
|
package/src/utils.js
CHANGED
|
@@ -493,8 +493,7 @@ export async function fetchTileData(source, sourceType, z, x, y) {
|
|
|
493
493
|
} else if (sourceType === 'mbtiles') {
|
|
494
494
|
return new Promise((resolve) => {
|
|
495
495
|
source.getTile(z, x, y, (err, tileData, tileHeader) => {
|
|
496
|
-
if (err) {
|
|
497
|
-
console.error('Error fetching MBTiles tile:', err);
|
|
496
|
+
if (err || tileData == null) {
|
|
498
497
|
return resolve(null);
|
|
499
498
|
}
|
|
500
499
|
resolve({ data: tileData, headers: tileHeader });
|
package/test/tiles_data.js
CHANGED
|
@@ -23,6 +23,6 @@ describe('Vector tiles', function () {
|
|
|
23
23
|
testTile(prefix, 0, 1, 0, 404);
|
|
24
24
|
testTile(prefix, 0, 0, 1, 404);
|
|
25
25
|
|
|
26
|
-
testTile(prefix, 14, 0, 0, 204); // non existent tile
|
|
26
|
+
testTile(prefix, 14, 0, 0, 204); // non existent tile (vector tiles default to 204)
|
|
27
27
|
});
|
|
28
28
|
});
|