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/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 fileType = Object.keys(data[id])[0];
231
- // eslint-disable-next-line security/detect-object-injection -- id is from Object.keys of data config, fileType is from Object.keys
232
- if (data[id][fileType] === styleSourceId) {
233
- // Style id was found in data filename, return the id that filename belong to
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
- if (
313
- styleSourceId === id ||
314
- styleSourceId === currentInputFileValue
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
- startupPromises.push(addStyle(id, item, true, true));
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 });
@@ -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
  });