tileserver-gl 5.5.0 → 5.6.0-pre.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/CHANGELOG.md +4 -0
- package/docs/usage.rst +1 -0
- package/package.json +6 -6
- package/src/main.js +5 -0
- package/src/serve_data.js +41 -21
- package/src/serve_style.js +21 -2
- package/src/server.js +45 -1
package/CHANGELOG.md
CHANGED
|
@@ -7,6 +7,10 @@
|
|
|
7
7
|
### 🐞 Bug fixes
|
|
8
8
|
- _...Add new stuff here..._
|
|
9
9
|
|
|
10
|
+
## 5.6.0-pre.0
|
|
11
|
+
### ✨ Features and improvements
|
|
12
|
+
- feat: Add ignore-missing-files cli option to avoid crashing at startup ([#1896](https://github.com/maptiler/tileserver-gl/pull/1896)) (by [andrewlaguna824](https://github.com/andrewlaguna824))
|
|
13
|
+
|
|
10
14
|
## 5.5.0
|
|
11
15
|
- Add S3 support for PMTiles with multiple AWS credential profiles (https://github.com/maptiler/tileserver-gl/pull/1779) by @acalcutt
|
|
12
16
|
- Create .aws directory passthrough folder in Dockerfile (https://github.com/maptiler/tileserver-gl/pull/1784) by @acalcutt
|
package/docs/usage.rst
CHANGED
|
@@ -20,6 +20,7 @@ Getting started
|
|
|
20
20
|
-C|--no-cors Disable Cross-origin resource sharing headers
|
|
21
21
|
-u|--public_url <url> Enable exposing the server on subpaths, not necessarily the root of the domain
|
|
22
22
|
--fetch-timeout <ms> Timeout in milliseconds for fetching remote tiles (default: 15000)
|
|
23
|
+
--ignore-missing-files Do not exit when referenced data files or remote sources are missing at startup; log a warning and continue running (useful when styles reference optional or not-yet-available sources)
|
|
23
24
|
-V, --verbose [level] More verbose output (level 1-3)
|
|
24
25
|
-V, --verbose, -V 1, or --verbose 1: Important operations
|
|
25
26
|
-V 2 or --verbose 2: Detailed operations
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "tileserver-gl",
|
|
3
|
-
"version": "5.
|
|
3
|
+
"version": "5.6.0-pre.0",
|
|
4
4
|
"description": "Map tile server for JSON GL styles - vector and server side generated raster tiles",
|
|
5
5
|
"main": "src/main.js",
|
|
6
6
|
"bin": {
|
|
@@ -37,7 +37,7 @@
|
|
|
37
37
|
"docker": "docker build . && docker run --rm -i -p 8080:8080 $(docker build -q .)"
|
|
38
38
|
},
|
|
39
39
|
"dependencies": {
|
|
40
|
-
"@aws-sdk/client-s3": "^3.
|
|
40
|
+
"@aws-sdk/client-s3": "^3.966.0",
|
|
41
41
|
"@jsse/pbfont": "^0.3.0",
|
|
42
42
|
"@mapbox/mapbox-gl-rtl-text": "0.3.0",
|
|
43
43
|
"@mapbox/mbtiles": "0.12.1",
|
|
@@ -72,10 +72,10 @@
|
|
|
72
72
|
"tileserver-gl-styles": "2.0.0"
|
|
73
73
|
},
|
|
74
74
|
"devDependencies": {
|
|
75
|
-
"@commitlint/cli": "^20.3.
|
|
75
|
+
"@commitlint/cli": "^20.3.1",
|
|
76
76
|
"@commitlint/config-conventional": "^20.3.0",
|
|
77
|
-
"@typescript-eslint/eslint-plugin": "^8.
|
|
78
|
-
"@typescript-eslint/parser": "^8.
|
|
77
|
+
"@typescript-eslint/eslint-plugin": "^8.52.0",
|
|
78
|
+
"@typescript-eslint/parser": "^8.52.0",
|
|
79
79
|
"chai": "6.2.2",
|
|
80
80
|
"cross-env": "^10.1.0",
|
|
81
81
|
"eslint": "^9.39.2",
|
|
@@ -89,7 +89,7 @@
|
|
|
89
89
|
"pixelmatch": "^7.1.0",
|
|
90
90
|
"prettier": "^3.7.4",
|
|
91
91
|
"should": "^13.2.3",
|
|
92
|
-
"supertest": "^7.
|
|
92
|
+
"supertest": "^7.2.2",
|
|
93
93
|
"yaml-lint": "^1.7.0"
|
|
94
94
|
},
|
|
95
95
|
"keywords": [
|
package/src/main.js
CHANGED
|
@@ -109,6 +109,10 @@ program
|
|
|
109
109
|
'-f|--log_format <format>',
|
|
110
110
|
'define the log format: https://github.com/expressjs/morgan#morganformat-options',
|
|
111
111
|
)
|
|
112
|
+
.option(
|
|
113
|
+
'--ignore-missing-files',
|
|
114
|
+
'Continue startup even if configured mbtiles/pmtiles files are missing',
|
|
115
|
+
)
|
|
112
116
|
.version(packageJson.version, '-v, --version');
|
|
113
117
|
program.parse(process.argv);
|
|
114
118
|
const opts = program.opts();
|
|
@@ -132,6 +136,7 @@ const startServer = (configPath, config) => {
|
|
|
132
136
|
logFormat: opts.log_format,
|
|
133
137
|
fetchTimeout: opts.fetchTimeout,
|
|
134
138
|
publicUrl,
|
|
139
|
+
ignoreMissingFiles: opts.ignoreMissingFiles,
|
|
135
140
|
});
|
|
136
141
|
};
|
|
137
142
|
|
package/src/serve_data.js
CHANGED
|
@@ -508,7 +508,7 @@ export const serve_data = {
|
|
|
508
508
|
* @returns {Promise<void>}
|
|
509
509
|
*/
|
|
510
510
|
add: async function (options, repo, params, id, programOpts) {
|
|
511
|
-
const { publicUrl, verbose } = programOpts;
|
|
511
|
+
const { publicUrl, verbose, ignoreMissingFiles } = programOpts;
|
|
512
512
|
let inputFile;
|
|
513
513
|
let inputType;
|
|
514
514
|
if (params.pmtiles) {
|
|
@@ -542,8 +542,18 @@ export const serve_data = {
|
|
|
542
542
|
|
|
543
543
|
// Only check file stats for local files, not remote URLs
|
|
544
544
|
if (!isValidRemoteUrl(inputFile)) {
|
|
545
|
-
|
|
546
|
-
|
|
545
|
+
try {
|
|
546
|
+
const inputFileStats = await fsp.stat(inputFile);
|
|
547
|
+
if (!inputFileStats.isFile() || inputFileStats.size === 0) {
|
|
548
|
+
throw Error(`Not valid input file: "${inputFile}"`);
|
|
549
|
+
}
|
|
550
|
+
} catch (err) {
|
|
551
|
+
if (ignoreMissingFiles) {
|
|
552
|
+
console.log(
|
|
553
|
+
`WARN: Data source '${id}' file not found: "${inputFile}" - skipping`,
|
|
554
|
+
);
|
|
555
|
+
return;
|
|
556
|
+
}
|
|
547
557
|
throw Error(`Not valid input file: "${inputFile}"`);
|
|
548
558
|
}
|
|
549
559
|
}
|
|
@@ -555,24 +565,34 @@ export const serve_data = {
|
|
|
555
565
|
tileJSON['encoding'] = params['encoding'];
|
|
556
566
|
tileJSON['tileSize'] = params['tileSize'];
|
|
557
567
|
|
|
558
|
-
|
|
559
|
-
|
|
560
|
-
|
|
561
|
-
|
|
562
|
-
|
|
563
|
-
|
|
564
|
-
|
|
565
|
-
|
|
566
|
-
|
|
567
|
-
|
|
568
|
-
|
|
569
|
-
|
|
570
|
-
|
|
571
|
-
|
|
572
|
-
|
|
573
|
-
|
|
574
|
-
|
|
575
|
-
|
|
568
|
+
try {
|
|
569
|
+
if (inputType === 'pmtiles') {
|
|
570
|
+
source = openPMtiles(
|
|
571
|
+
inputFile,
|
|
572
|
+
params.s3Profile,
|
|
573
|
+
params.requestPayer,
|
|
574
|
+
params.s3Region,
|
|
575
|
+
params.s3UrlFormat,
|
|
576
|
+
verbose,
|
|
577
|
+
);
|
|
578
|
+
sourceType = 'pmtiles';
|
|
579
|
+
const metadata = await getPMtilesInfo(source, inputFile);
|
|
580
|
+
Object.assign(tileJSON, metadata);
|
|
581
|
+
} else if (inputType === 'mbtiles') {
|
|
582
|
+
sourceType = 'mbtiles';
|
|
583
|
+
const mbw = await openMbTilesWrapper(inputFile);
|
|
584
|
+
const info = await mbw.getInfo();
|
|
585
|
+
source = mbw.getMbTiles();
|
|
586
|
+
Object.assign(tileJSON, info);
|
|
587
|
+
}
|
|
588
|
+
} catch (err) {
|
|
589
|
+
if (ignoreMissingFiles) {
|
|
590
|
+
console.log(
|
|
591
|
+
`WARN: Unable to open data source '${id}' from "${inputFile}": ${err.message} - skipping (requests will return 404)`,
|
|
592
|
+
);
|
|
593
|
+
return;
|
|
594
|
+
}
|
|
595
|
+
throw err;
|
|
576
596
|
}
|
|
577
597
|
|
|
578
598
|
delete tileJSON['filesize'];
|
package/src/serve_style.js
CHANGED
|
@@ -213,7 +213,7 @@ export const serve_style = {
|
|
|
213
213
|
reportTiles,
|
|
214
214
|
reportFont,
|
|
215
215
|
) {
|
|
216
|
-
const { publicUrl } = programOpts;
|
|
216
|
+
const { publicUrl, ignoreMissingFiles } = programOpts;
|
|
217
217
|
const styleFile = path.resolve(options.paths.styles, params.style);
|
|
218
218
|
const styleJSON = clone(style);
|
|
219
219
|
|
|
@@ -247,6 +247,9 @@ export const serve_style = {
|
|
|
247
247
|
return false;
|
|
248
248
|
}
|
|
249
249
|
|
|
250
|
+
// Track missing sources
|
|
251
|
+
const missingSources = [];
|
|
252
|
+
|
|
250
253
|
for (const name of Object.keys(styleJSON.sources)) {
|
|
251
254
|
// eslint-disable-next-line security/detect-object-injection -- name is from Object.keys of style sources
|
|
252
255
|
const source = styleJSON.sources[name];
|
|
@@ -270,7 +273,9 @@ export const serve_style = {
|
|
|
270
273
|
|
|
271
274
|
const identifier = reportTiles(dataId, protocol);
|
|
272
275
|
if (!identifier) {
|
|
273
|
-
|
|
276
|
+
// This datasource is missing or invalid in some way
|
|
277
|
+
missingSources.push(name);
|
|
278
|
+
continue;
|
|
274
279
|
}
|
|
275
280
|
source.url = `local://data/${identifier}.json`;
|
|
276
281
|
}
|
|
@@ -286,6 +291,20 @@ export const serve_style = {
|
|
|
286
291
|
}
|
|
287
292
|
}
|
|
288
293
|
|
|
294
|
+
// Check if any sources are missing after processing all of them
|
|
295
|
+
if (missingSources.length > 0) {
|
|
296
|
+
if (ignoreMissingFiles) {
|
|
297
|
+
console.log(
|
|
298
|
+
`WARN: Style '${id}' references ${missingSources.length} missing data source(s): [${missingSources.join(', ')}] - not adding style`,
|
|
299
|
+
);
|
|
300
|
+
} else {
|
|
301
|
+
console.log(
|
|
302
|
+
`ERROR: Style '${id}' references missing data source(s): [${missingSources.join(', ')}]`,
|
|
303
|
+
);
|
|
304
|
+
}
|
|
305
|
+
return false;
|
|
306
|
+
}
|
|
307
|
+
|
|
289
308
|
for (const obj of styleJSON.layers) {
|
|
290
309
|
if (obj['type'] === 'symbol') {
|
|
291
310
|
const fonts = (obj['layout'] || {})['text-font'];
|
package/src/server.js
CHANGED
|
@@ -241,7 +241,36 @@ async function start(opts) {
|
|
|
241
241
|
}
|
|
242
242
|
}
|
|
243
243
|
if (dataItemId) {
|
|
244
|
-
//
|
|
244
|
+
// Data source exists in config, now validate file exists
|
|
245
|
+
// eslint-disable-next-line security/detect-object-injection -- dataItemId is validated above
|
|
246
|
+
const dataSource = data[dataItemId];
|
|
247
|
+
const fileType = dataSource.pmtiles ? 'pmtiles' : 'mbtiles';
|
|
248
|
+
const fileName = dataSource[fileType];
|
|
249
|
+
|
|
250
|
+
// Skip validation for remote URLs
|
|
251
|
+
if (fileName && !isValidRemoteUrl(fileName)) {
|
|
252
|
+
const filePath = path.resolve(options.paths[fileType], fileName);
|
|
253
|
+
try {
|
|
254
|
+
const stats = fs.statSync(filePath);
|
|
255
|
+
if (!stats.isFile() || stats.size === 0) {
|
|
256
|
+
if (opts.ignoreMissingFiles) {
|
|
257
|
+
// File doesn't exist or is empty - return undefined to skip
|
|
258
|
+
return undefined;
|
|
259
|
+
}
|
|
260
|
+
// File missing but flag not set - let it fail later
|
|
261
|
+
return dataItemId;
|
|
262
|
+
}
|
|
263
|
+
} catch (err) {
|
|
264
|
+
// File doesn't exist
|
|
265
|
+
if (opts.ignoreMissingFiles) {
|
|
266
|
+
return undefined;
|
|
267
|
+
}
|
|
268
|
+
// File missing but flag not set - let it fail later
|
|
269
|
+
return dataItemId;
|
|
270
|
+
}
|
|
271
|
+
}
|
|
272
|
+
|
|
273
|
+
// File exists or is remote URL, return the id
|
|
245
274
|
return dataItemId;
|
|
246
275
|
} else {
|
|
247
276
|
if (!allowMoreData) {
|
|
@@ -257,6 +286,21 @@ async function start(opts) {
|
|
|
257
286
|
if (isValidRemoteUrl(styleSourceId)) {
|
|
258
287
|
id =
|
|
259
288
|
fnv1a(styleSourceId) + '_' + id.replace(/^.*\/(.*)$/, '$1');
|
|
289
|
+
} else {
|
|
290
|
+
try {
|
|
291
|
+
const stats = fs.statSync(styleSourceId);
|
|
292
|
+
if (!stats.isFile() || stats.size === 0) {
|
|
293
|
+
if (opts.ignoreMissingFiles) {
|
|
294
|
+
// File doesn't exist or is empty - return undefined to skip
|
|
295
|
+
return undefined;
|
|
296
|
+
}
|
|
297
|
+
}
|
|
298
|
+
} catch (err) {
|
|
299
|
+
// File doesn't exist
|
|
300
|
+
if (opts.ignoreMissingFiles) {
|
|
301
|
+
return undefined;
|
|
302
|
+
}
|
|
303
|
+
}
|
|
260
304
|
}
|
|
261
305
|
// eslint-disable-next-line security/detect-object-injection -- id is being checked for existence before modification
|
|
262
306
|
while (data[id]) id += '_'; //if the data source id already exists, add a "_" untill it doesn't
|