tileserver-gl-light 5.0.0 → 5.1.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/.github/workflows/release.yml +69 -12
- package/CHANGELOG.md +13 -0
- package/Dockerfile +1 -1
- package/PUBLISHING.md +17 -11
- package/changelog_for_version.md +5 -0
- package/docs/config.rst +21 -3
- package/docs/endpoints.rst +8 -0
- package/package.json +5 -3
- package/public/resources/elevation-control.js +51 -0
- package/public/resources/index.css +1 -1
- package/public/templates/data.tmpl +121 -42
- package/public/templates/index.tmpl +18 -7
- package/src/main.js +6 -0
- package/src/serve_data.js +335 -140
- package/src/serve_font.js +76 -25
- package/src/serve_light.js +2 -2
- package/src/serve_rendered.js +569 -411
- package/src/serve_style.js +181 -56
- package/src/server.js +189 -92
- package/src/utils.js +251 -69
- package/test/setup.js +2 -2
- package/test/static.js +2 -2
- package/test/tiles_rendered.js +7 -7
package/src/serve_style.js
CHANGED
|
@@ -7,85 +7,209 @@ import clone from 'clone';
|
|
|
7
7
|
import express from 'express';
|
|
8
8
|
import { validateStyleMin } from '@maplibre/maplibre-gl-style-spec';
|
|
9
9
|
|
|
10
|
-
import {
|
|
10
|
+
import {
|
|
11
|
+
allowedSpriteScales,
|
|
12
|
+
allowedSpriteFormats,
|
|
13
|
+
fixUrl,
|
|
14
|
+
readFile,
|
|
15
|
+
} from './utils.js';
|
|
11
16
|
|
|
12
17
|
const httpTester = /^https?:\/\//i;
|
|
13
|
-
const allowedSpriteScales = allowedOptions(['', '@2x', '@3x']);
|
|
14
|
-
const allowedSpriteFormats = allowedOptions(['png', 'json']);
|
|
15
18
|
|
|
16
19
|
export const serve_style = {
|
|
17
|
-
|
|
20
|
+
/**
|
|
21
|
+
* Initializes the serve_style module.
|
|
22
|
+
* @param {object} options Configuration options.
|
|
23
|
+
* @param {object} repo Repository object.
|
|
24
|
+
* @param {object} programOpts - An object containing the program options.
|
|
25
|
+
* @returns {express.Application} The initialized Express application.
|
|
26
|
+
*/
|
|
27
|
+
init: function (options, repo, programOpts) {
|
|
28
|
+
const { verbose } = programOpts;
|
|
18
29
|
const app = express().disable('x-powered-by');
|
|
19
|
-
|
|
30
|
+
/**
|
|
31
|
+
* Handles requests for style.json files.
|
|
32
|
+
* @param {express.Request} req - Express request object.
|
|
33
|
+
* @param {express.Response} res - Express response object.
|
|
34
|
+
* @param {express.NextFunction} next - Express next function.
|
|
35
|
+
* @param {string} req.params.id - ID of the style.
|
|
36
|
+
* @returns {Promise<void>}
|
|
37
|
+
*/
|
|
20
38
|
app.get('/:id/style.json', (req, res, next) => {
|
|
21
|
-
const
|
|
22
|
-
if (
|
|
23
|
-
|
|
39
|
+
const { id } = req.params;
|
|
40
|
+
if (verbose) {
|
|
41
|
+
console.log(
|
|
42
|
+
'Handling style request for: /styles/%s/style.json',
|
|
43
|
+
String(id).replace(/\n|\r/g, ''),
|
|
44
|
+
);
|
|
24
45
|
}
|
|
25
|
-
|
|
26
|
-
|
|
27
|
-
|
|
28
|
-
|
|
29
|
-
if (typeof source.data == 'string') {
|
|
30
|
-
source.data = fixUrl(req, source.data, item.publicUrl);
|
|
46
|
+
try {
|
|
47
|
+
const item = repo[id];
|
|
48
|
+
if (!item) {
|
|
49
|
+
return res.sendStatus(404);
|
|
31
50
|
}
|
|
32
|
-
|
|
33
|
-
|
|
34
|
-
|
|
35
|
-
|
|
36
|
-
|
|
37
|
-
|
|
38
|
-
}
|
|
39
|
-
} else {
|
|
40
|
-
styleJSON_.sprite = fixUrl(req, styleJSON_.sprite, item.publicUrl);
|
|
51
|
+
const styleJSON_ = clone(item.styleJSON);
|
|
52
|
+
for (const name of Object.keys(styleJSON_.sources)) {
|
|
53
|
+
const source = styleJSON_.sources[name];
|
|
54
|
+
source.url = fixUrl(req, source.url, item.publicUrl);
|
|
55
|
+
if (typeof source.data == 'string') {
|
|
56
|
+
source.data = fixUrl(req, source.data, item.publicUrl);
|
|
57
|
+
}
|
|
41
58
|
}
|
|
59
|
+
if (styleJSON_.sprite) {
|
|
60
|
+
if (Array.isArray(styleJSON_.sprite)) {
|
|
61
|
+
styleJSON_.sprite.forEach((spriteItem) => {
|
|
62
|
+
spriteItem.url = fixUrl(req, spriteItem.url, item.publicUrl);
|
|
63
|
+
});
|
|
64
|
+
} else {
|
|
65
|
+
styleJSON_.sprite = fixUrl(req, styleJSON_.sprite, item.publicUrl);
|
|
66
|
+
}
|
|
67
|
+
}
|
|
68
|
+
if (styleJSON_.glyphs) {
|
|
69
|
+
styleJSON_.glyphs = fixUrl(req, styleJSON_.glyphs, item.publicUrl);
|
|
70
|
+
}
|
|
71
|
+
return res.send(styleJSON_);
|
|
72
|
+
} catch (e) {
|
|
73
|
+
next(e);
|
|
42
74
|
}
|
|
43
|
-
if (styleJSON_.glyphs) {
|
|
44
|
-
styleJSON_.glyphs = fixUrl(req, styleJSON_.glyphs, item.publicUrl);
|
|
45
|
-
}
|
|
46
|
-
return res.send(styleJSON_);
|
|
47
75
|
});
|
|
48
76
|
|
|
77
|
+
/**
|
|
78
|
+
* Handles GET requests for sprite images and JSON files.
|
|
79
|
+
* @param {express.Request} req - Express request object.
|
|
80
|
+
* @param {express.Response} res - Express response object.
|
|
81
|
+
* @param {express.NextFunction} next - Express next function.
|
|
82
|
+
* @param {string} req.params.id - ID of the sprite.
|
|
83
|
+
* @param {string} [req.params.spriteID='default'] - ID of the specific sprite image, defaults to 'default'.
|
|
84
|
+
* @param {string} [req.params.scale] - Scale of the sprite image, defaults to ''.
|
|
85
|
+
* @param {string} req.params.format - Format of the sprite file, 'png' or 'json'.
|
|
86
|
+
* @returns {Promise<void>}
|
|
87
|
+
*/
|
|
49
88
|
app.get(
|
|
50
|
-
|
|
51
|
-
(req, res, next) => {
|
|
52
|
-
const { spriteID = 'default', id } = req.params;
|
|
53
|
-
const
|
|
54
|
-
const
|
|
55
|
-
|
|
56
|
-
|
|
57
|
-
|
|
58
|
-
|
|
59
|
-
|
|
89
|
+
`/:id/sprite{/:spriteID}{@:scale}{.:format}`,
|
|
90
|
+
async (req, res, next) => {
|
|
91
|
+
const { spriteID = 'default', id, format, scale } = req.params;
|
|
92
|
+
const sanitizedId = String(id).replace(/\n|\r/g, '');
|
|
93
|
+
const sanitizedScale = scale ? String(scale).replace(/\n|\r/g, '') : '';
|
|
94
|
+
const sanitizedSpriteID = String(spriteID).replace(/\n|\r/g, '');
|
|
95
|
+
const sanitizedFormat = format
|
|
96
|
+
? '.' + String(format).replace(/\n|\r/g, '')
|
|
97
|
+
: '';
|
|
98
|
+
if (verbose) {
|
|
99
|
+
console.log(
|
|
100
|
+
`Handling sprite request for: /styles/%s/sprite/%s%s%s`,
|
|
101
|
+
sanitizedId,
|
|
102
|
+
sanitizedSpriteID,
|
|
103
|
+
sanitizedScale,
|
|
104
|
+
sanitizedFormat,
|
|
60
105
|
);
|
|
61
|
-
|
|
62
|
-
|
|
63
|
-
|
|
64
|
-
|
|
65
|
-
|
|
66
|
-
|
|
67
|
-
|
|
68
|
-
|
|
69
|
-
|
|
70
|
-
|
|
71
|
-
|
|
72
|
-
|
|
73
|
-
|
|
74
|
-
|
|
75
|
-
|
|
106
|
+
}
|
|
107
|
+
const item = repo[id];
|
|
108
|
+
const validatedFormat = allowedSpriteFormats(format);
|
|
109
|
+
if (!item || !validatedFormat) {
|
|
110
|
+
if (verbose)
|
|
111
|
+
console.error(
|
|
112
|
+
`Sprite item or format not found for: /styles/%s/sprite/%s%s%s`,
|
|
113
|
+
sanitizedId,
|
|
114
|
+
sanitizedSpriteID,
|
|
115
|
+
sanitizedScale,
|
|
116
|
+
sanitizedFormat,
|
|
117
|
+
);
|
|
118
|
+
return res.sendStatus(404);
|
|
119
|
+
}
|
|
120
|
+
const sprite = item.spritePaths.find(
|
|
121
|
+
(sprite) => sprite.id === spriteID,
|
|
122
|
+
);
|
|
123
|
+
const spriteScale = allowedSpriteScales(scale);
|
|
124
|
+
if (!sprite || spriteScale === null) {
|
|
125
|
+
if (verbose)
|
|
126
|
+
console.error(
|
|
127
|
+
`Bad Sprite ID or Scale for: /styles/%s/sprite/%s%s%s`,
|
|
128
|
+
sanitizedId,
|
|
129
|
+
sanitizedSpriteID,
|
|
130
|
+
sanitizedScale,
|
|
131
|
+
sanitizedFormat,
|
|
132
|
+
);
|
|
133
|
+
return res.status(400).send('Bad Sprite ID or Scale');
|
|
134
|
+
}
|
|
135
|
+
|
|
136
|
+
const modifiedSince = req.get('if-modified-since');
|
|
137
|
+
const cc = req.get('cache-control');
|
|
138
|
+
if (modifiedSince && (!cc || cc.indexOf('no-cache') === -1)) {
|
|
139
|
+
if (
|
|
140
|
+
new Date(item.lastModified).getTime() ===
|
|
141
|
+
new Date(modifiedSince).getTime()
|
|
142
|
+
) {
|
|
143
|
+
return res.sendStatus(304);
|
|
76
144
|
}
|
|
77
|
-
}
|
|
78
|
-
|
|
145
|
+
}
|
|
146
|
+
|
|
147
|
+
const sanitizedSpritePath = sprite.path.replace(/^(\.\.\/)+/, '');
|
|
148
|
+
const filename = `${sanitizedSpritePath}${spriteScale}.${validatedFormat}`;
|
|
149
|
+
if (verbose) console.log(`Loading sprite from: %s`, filename);
|
|
150
|
+
try {
|
|
151
|
+
const data = await readFile(filename);
|
|
152
|
+
|
|
153
|
+
if (validatedFormat === 'json') {
|
|
154
|
+
res.header('Content-type', 'application/json');
|
|
155
|
+
} else if (validatedFormat === 'png') {
|
|
156
|
+
res.header('Content-type', 'image/png');
|
|
157
|
+
}
|
|
158
|
+
if (verbose)
|
|
159
|
+
console.log(
|
|
160
|
+
`Responding with sprite data for /styles/%s/sprite/%s%s%s`,
|
|
161
|
+
sanitizedId,
|
|
162
|
+
sanitizedSpriteID,
|
|
163
|
+
sanitizedScale,
|
|
164
|
+
sanitizedFormat,
|
|
165
|
+
);
|
|
166
|
+
res.set({ 'Last-Modified': item.lastModified });
|
|
167
|
+
return res.send(data);
|
|
168
|
+
} catch (err) {
|
|
169
|
+
if (verbose) {
|
|
170
|
+
console.error(
|
|
171
|
+
'Sprite load error: %s, Error: %s',
|
|
172
|
+
filename,
|
|
173
|
+
String(err),
|
|
174
|
+
);
|
|
175
|
+
}
|
|
176
|
+
return res.sendStatus(404);
|
|
79
177
|
}
|
|
80
178
|
},
|
|
81
179
|
);
|
|
82
180
|
|
|
83
181
|
return app;
|
|
84
182
|
},
|
|
85
|
-
|
|
183
|
+
/**
|
|
184
|
+
* Removes an item from the repository.
|
|
185
|
+
* @param {object} repo Repository object.
|
|
186
|
+
* @param {string} id ID of the item to remove.
|
|
187
|
+
* @returns {void}
|
|
188
|
+
*/
|
|
189
|
+
remove: function (repo, id) {
|
|
86
190
|
delete repo[id];
|
|
87
191
|
},
|
|
88
|
-
|
|
192
|
+
/**
|
|
193
|
+
* Adds a new style to the repository.
|
|
194
|
+
* @param {object} options Configuration options.
|
|
195
|
+
* @param {object} repo Repository object.
|
|
196
|
+
* @param {object} params Parameters object containing style path
|
|
197
|
+
* @param {string} id ID of the style.
|
|
198
|
+
* @param {object} programOpts - An object containing the program options
|
|
199
|
+
* @param {Function} reportTiles Function for reporting tile sources.
|
|
200
|
+
* @param {Function} reportFont Function for reporting font usage
|
|
201
|
+
* @returns {boolean} true if add is succesful
|
|
202
|
+
*/
|
|
203
|
+
add: function (
|
|
204
|
+
options,
|
|
205
|
+
repo,
|
|
206
|
+
params,
|
|
207
|
+
id,
|
|
208
|
+
programOpts,
|
|
209
|
+
reportTiles,
|
|
210
|
+
reportFont,
|
|
211
|
+
) {
|
|
212
|
+
const { publicUrl } = programOpts;
|
|
89
213
|
const styleFile = path.resolve(options.paths.styles, params.style);
|
|
90
214
|
|
|
91
215
|
let styleFileData;
|
|
@@ -199,6 +323,7 @@ export const serve_style = {
|
|
|
199
323
|
spritePaths,
|
|
200
324
|
publicUrl,
|
|
201
325
|
name: styleJSON.name,
|
|
326
|
+
lastModified: new Date().toUTCString(),
|
|
202
327
|
};
|
|
203
328
|
|
|
204
329
|
return true;
|