tileblaster 0.4.9 → 1.0.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/docs/config.md ADDED
@@ -0,0 +1,343 @@
1
+ # tileblaster configuration
2
+
3
+ tileblaster configuration lives in a javascript (common js) file, that exports an object containing the configuration.
4
+
5
+ ## Example
6
+
7
+ See [config.dist.js](./config.dist.js)
8
+
9
+ ## Properties
10
+
11
+ #### `version`
12
+
13
+ config file format version. Always `1` fro now.
14
+
15
+ #### `id`
16
+
17
+ id of the tileblaster instance, in case you want to run more than one; default: `tileblaster`
18
+
19
+ #### `treads`
20
+
21
+ number of worker threads in cluster, default: 1
22
+
23
+ #### `queue`
24
+
25
+ number of concurrently processed tiles per worker, default: 12
26
+
27
+ #### `server.url`
28
+
29
+ public url including subdirectory
30
+
31
+ #### `server.mount`
32
+
33
+ mountpoint override, default: pathname of `config.paths.url`
34
+
35
+ #### `paths.work`
36
+
37
+ the base directory where files (sockets, logs, plugins, ...) go; default: `~/tileblaster`
38
+
39
+ #### `paths.data`
40
+
41
+ the directory in which cached tiles are saved; default: `${config.paths.work}/data`
42
+
43
+ #### `paths.logs`
44
+
45
+ the directory in which cached tiles are saved; default: `${config.paths.work}/logs`
46
+
47
+ #### `paths.plugins`
48
+
49
+ the directory from which plugins ar loaded; default: `${config.paths.work}/plugins`
50
+
51
+ #### `paths.sockets`
52
+
53
+ the directory i nwhich sockets are created; default: `${config.paths.work}/sockets`
54
+
55
+ ### `listen`
56
+
57
+ an array of server listen configurations. these contain either `port` or `socket`
58
+
59
+ ``` js
60
+ listen: [{
61
+ port: 8080, // required
62
+ host: "localhost", // default localhost
63
+ },{
64
+ socket: "test.socket", // required, absolute path or relative to ${config.paths.socket}
65
+ mode: 0o660, // change socket mode to this id
66
+ group: 1000, // change socket group to this is
67
+ }],
68
+ ```
69
+
70
+ ### `plugins`
71
+
72
+ plugins, relative or absolute paths for local files, npm module names otherwise
73
+
74
+ ``` js
75
+ plugins: {
76
+ resize: "./resize.js", // relative path, starting with ./
77
+ convert: "/path/to/convert.js", // absolute path
78
+ optimize: "someplugin", // npm module
79
+ },
80
+ ```
81
+
82
+ ### `maps`
83
+
84
+ each property of this object represents a map and its workflow. the workflow is an array
85
+ of `builtin` and `plugin` directives, that get processed in the order of their definition.
86
+
87
+ ``` js
88
+ {
89
+ // a map with id "example"
90
+ example: [{
91
+ // a builtin directive, processed first
92
+ builtin: "something",
93
+ // ...
94
+ },{
95
+ // a plugin directive, processed second
96
+ plugin: "some-plugin",
97
+ // ...
98
+ },{
99
+ // ...
100
+ }],
101
+ anoterMap: {
102
+ // ...
103
+ }
104
+ }
105
+ ```
106
+
107
+ ### Builtins
108
+
109
+ #### `cors`
110
+
111
+ Send [CORS](https://developer.mozilla.org/en-US/docs/Web/HTTP/CORS) Headers to the client. Can be limited by Origin.
112
+ You should do this in your reverse proxy though.
113
+
114
+ ``` js
115
+ {
116
+ builtin: "cors",
117
+ origins: [ "https://example.org/" ],
118
+ // origins: [ "*" ], // ← allow anyone
119
+ }
120
+ ```
121
+
122
+ #### `parse`
123
+
124
+ Parse a client request. You can override this with your own parse function in case
125
+ your client requires the use of a non-standard request uri or uses GET/POST data or whatever.
126
+
127
+ ``` js
128
+ {
129
+ builtin: "parse", // /z/x/y@r.ext, other formats need plugins; set params and dest
130
+ parse: function(req, next){ // override parse function, req is the raw request
131
+ // do things to get parameters from path
132
+ next(null, {
133
+ params: { param: "1" }, // deliver parameters
134
+ dest: "/path/to/tile/{param}/{param}/blub.{e}{c}", // template for destination
135
+ });
136
+ },
137
+ }
138
+ ```
139
+
140
+ #### `check`
141
+
142
+ Limits request dependent on parameters. You can deny access to tiles to certain zoom levels,
143
+ within a bounding box, to specific extensions and densities, or use your own check function.
144
+
145
+ ``` js
146
+ {
147
+ builtin: "check",
148
+ zoom: [ 0, 22 ], // min, max
149
+ bbox: [ -180, -90, 180, 90 ], // west, south, east, north
150
+ extensions: [ "png", "jpeg" ], // allowed extensions
151
+ density: [ "", "@2x", "@3x" ], // allowed density markeers
152
+ check: function(params, fn) { // override check function, params from parse
153
+ fn(new Error("Check failed")); // deliver error if check failed
154
+ }
155
+ }
156
+ ```
157
+
158
+ #### `cache`
159
+
160
+ Local tile cache.
161
+
162
+ ##### Retrieve cached tiles
163
+
164
+ When no main tile is availabe, try to load it from cache.
165
+
166
+ ``` js
167
+ {
168
+ builtin: "cache",
169
+ skipto: "deliver", // skip to this builtin when tile loaded from cache
170
+ }
171
+ ```
172
+
173
+ ##### Store tiles
174
+
175
+ If a tile is set, store it in the local cache.
176
+
177
+ ``` js
178
+ {
179
+ builtin: "cache",
180
+ expires: "30d", // duration or seconds or `true` or `false`
181
+ }
182
+ ```
183
+
184
+ * `expires: 300` - Expires after this amount of seconds
185
+ * `expires: "5y 2w 1d 5h 30m 4s"` - Expires after this [duration](https://www.npmjs.com/package/dur#user-content-time-units)
186
+ * `expires: false` - Expires never
187
+ * `expires: true` - Expires instantly
188
+
189
+ #### `noop`
190
+
191
+ Does nothing and has no real purpose.
192
+
193
+ #### `tileserver`
194
+
195
+ Fetch a tile from a tileserver via http(s).
196
+
197
+ ``` js
198
+ {
199
+ builtin: "tileserver",
200
+ url: "https://{s}.tileserver.example/test/{z}/{x}/{y}{r}.{e}",
201
+ subdomains: [ "a", "b", "x" ], // random chosen and passed in as {s}
202
+ tms: true, // y coordinate is inverted
203
+ headers: {}, // additional headers sent to the backend tileserver
204
+ status: [ 200 ], // expected status code(s)
205
+ mimetypes: [ "image/png", "image/jpeg" ], // expected mime types
206
+ mimetype: "image/png", // overwrite mime type from server
207
+ }
208
+ ```
209
+
210
+ #### `versatiles`
211
+
212
+ Fetch a tile from a local or remote [versatiles](https://versatiles.org) container.
213
+
214
+ *Pro Tip:* Don't pay MapBox or "Open"MapTiles for limited access to Open Data! You can get completely free Vectortiles in [Shortbread Schema](https://shortbread.geofabrik.de/schema/) at [download.versatiles.org](https://download.versatiles.org/).
215
+
216
+ ``` js
217
+ {
218
+ // get tile from versatiles container
219
+ builtin: "versatiles",
220
+ url: "https://cdn.example/planet.versatiles",
221
+ // url: "/path/to/planet.versatiles",
222
+ tms: false, // y coordinate is inverted
223
+ headers: { // headers sent to versatiles server
224
+ "X-Tileblaster": "True",
225
+ },
226
+ }
227
+ ```
228
+
229
+ #### `pmtiles`
230
+
231
+ Fetch a tile from a pmtiles container.
232
+
233
+ ``` js
234
+ {
235
+ // get tile from versatiles container
236
+ builtin: "pmtiles",
237
+ url: "https://cdn.example/planet.pmtiles",
238
+ // url: "/path/to/planet.pmtiles",
239
+ }
240
+ ```
241
+ #### `mbtiles`
242
+
243
+ Retrieve a tile from a mbtiles database.
244
+
245
+ ``` js
246
+ {
247
+ // get tile from versatiles container
248
+ builtin: "mbtiles",
249
+ file: "/path/to/planet.mbtiles",
250
+ }
251
+ ```
252
+
253
+ #### `edit`
254
+
255
+ Edit vectortiles
256
+
257
+ ``` js
258
+ {
259
+ builtin: "edit",
260
+ edit: function(layers){
261
+
262
+ // remove unused layer
263
+ layers = layers.filter(function(layer){
264
+ return (layer.name !== "unused-layer");
265
+ });
266
+
267
+ return layers;
268
+ },
269
+ }
270
+ ```
271
+
272
+ #### `resize`
273
+
274
+ **Not yet implemented** FIXME
275
+
276
+ #### `modernize`
277
+
278
+ Convert JPEG or PNG raster tiles to WebP or AVIF.
279
+ The resulting tile with the smallest size and a format the client supports becomes the main tile.
280
+
281
+ ``` js
282
+ {
283
+ builtin: "modernize",
284
+ webp: {
285
+ quality: 90,
286
+ effort: 4,
287
+ },
288
+ avif: {
289
+ quality: 90,
290
+ effort: 5,
291
+ },
292
+ }
293
+ ```
294
+
295
+ #### `optimize`
296
+
297
+ Optimise raster tiles with `mozjpeg` or `optipng`. Only results smaller than the original are kept.
298
+
299
+ ``` js
300
+ {
301
+ plugin: "optimize",
302
+ png: { o: 4 }, // true or opts for optipng
303
+ jpeg: true, // true or opts for mozjpeg
304
+ }
305
+ ```
306
+
307
+ #### `compress`
308
+
309
+ Compresses all `data.tiles` with brotli and/or gzip. The tile with the smallest size and a compression the client supports becomes the main tile.
310
+
311
+ ``` js
312
+ {
313
+ builtin: "compress",
314
+ brotli: 8, // true or <level> or {opts}
315
+ gzip: true, // true or <level> or {opts}
316
+ }
317
+ ```
318
+
319
+
320
+ #### `deliver`
321
+
322
+ Sends `data.tile` to the client. Adds configured response headers.
323
+
324
+ ``` js
325
+ {
326
+ "builtin": "deliver",
327
+ "headers": {
328
+ "X-My-Header": "This is a very good header"
329
+ }
330
+ }
331
+ ```
332
+
333
+ #### `dump`
334
+
335
+ Ends all processing and dumps the contents of `data` the console and browser.
336
+
337
+ Useful for debugging.
338
+
339
+ ``` js
340
+ {
341
+ "builtin": "dump"
342
+ }
343
+ ```
@@ -0,0 +1,257 @@
1
+ # Examples
2
+
3
+ ## Tileserver
4
+
5
+ Serve tiles from a tileserver
6
+
7
+ ``` js
8
+ {
9
+ example: [{
10
+ // takes a request for /map/0/1/2@2x.png and breaks it down into z=0, x=1, y=2, r=@2x and e=png
11
+ builtin: "parse",
12
+ /* but you can override this if you need to
13
+ parse: function(req, fn){
14
+ // `req` is the http request object
15
+ let fragments = req.url.split("/").pop().split(".");
16
+ // fn is a callback to deliver the pares parameters
17
+ fn(null, {
18
+ z: fragments[0], x: fragments[1], y: fragments[2],
19
+ e: fragments[3], // extension
20
+ r: "@2x", // density marker
21
+ d: 2, // density
22
+ w: 512, // tile width
23
+ });
24
+ }
25
+ */
26
+ },{
27
+ // source tileserver
28
+ builtin: "tileserver",
29
+ url: "https://{s}.tileserver.example/{z}/{x}/{y}{r}.{e}?access_token=YOUR_OPENDATAGRIFTBOXTILER_ACCESS_TOKEN",
30
+ // optional:
31
+ subdomains: [ "a", "b", "c" ], // random chosen and passed in as {s}
32
+ tms: false, // {y} is inverted
33
+ headers: { // additional headers sent to tileserver
34
+ "Origin": "https://totally-legit-website.example/",
35
+ "User-Agent": "uncoolest-mobile-map-app"
36
+ },
37
+ status: [ 200 ], // expected status code(s)
38
+ mimetypes: [ "image/png", "image/jpeg" ], // expected mime types
39
+ },{
40
+ builtin: "deliver"
41
+ }]
42
+ }
43
+ ```
44
+
45
+ ## Versatiles
46
+
47
+ Serve tiles from a versatiles container
48
+
49
+ ``` js
50
+ {
51
+ example: [{
52
+ builtin: "parse",
53
+ },{
54
+ builtin: "versatiles",
55
+ url: "https://cdn.example/planet.versatiles",
56
+ },{
57
+ builtin: "deliver"
58
+ }]
59
+ }
60
+ ```
61
+
62
+ ## PMTiles
63
+
64
+ Serve tiles from a pmtiles container
65
+
66
+ ``` js
67
+ {
68
+ example: [{
69
+ builtin: "parse",
70
+ },{
71
+ builtin: "pmtiles",
72
+ url: "https://cdn.example/planet.pmtiles",
73
+ },{
74
+ builtin: "deliver"
75
+ }]
76
+ }
77
+ ```
78
+
79
+ ## MBTiles
80
+
81
+ Serve tiles from an mbtile database
82
+
83
+ ``` js
84
+ {
85
+ example: [{
86
+ builtin: "parse",
87
+ },{
88
+ builtin: "mbtiles",
89
+ file: "/path/to/file.mbtiles",
90
+ },{
91
+ builtin: "deliver"
92
+ }]
93
+ }
94
+ ```
95
+
96
+ ## Check parameters
97
+
98
+ Limit access to tiles by zoom level, bbox, extension or density marker with `check` builtin
99
+
100
+ ``` js
101
+ {
102
+ example: [{
103
+ builtin: "parse",
104
+ },{
105
+ builtin: "check",
106
+ zoom: [ 0, 10 ], // min, max
107
+ bbox: [ -180, -85, 180, 85 ], // west, south, east, north
108
+ extensions: [ "png", "jpeg" ], // allowed extensions
109
+ density: [ "", "@2x" ], // allowed density markers
110
+ },{
111
+ // source tileserver
112
+ builtin: "tileserver",
113
+ url: "https://tileserver.example/{z}/{x}/{y}{r}.{e}",
114
+ },{
115
+ builtin: "deliver"
116
+ }]
117
+ }
118
+ ```
119
+
120
+ ## Raster tile optimization and conversion
121
+
122
+ `optimize` will attemt to reduce the raster tile size by applying image optimization, `mozjpeg` for `jpeg` tiles, `optipng` for `png` tiles.
123
+ `modernize` will convert raster tiles to `webp` and `avif` format (using `sharp`) and deliver those to capable clients.
124
+
125
+ ``` js
126
+ {
127
+ example: [{
128
+ builtin: "parse",
129
+ },{
130
+ // source tileserver
131
+ builtin: "tileserver",
132
+ url: "https://tileserver.example/{z}/{x}/{y}.{e}",
133
+ },{
134
+ builtin: "optimize",
135
+ jpeg: {}, // use mozjpeg via wasm for jpeg tiles
136
+ png: { o: "3", strip: "all" }, // use optipng via wasm for png tiles
137
+ },{
138
+ builtin: "modernize",
139
+ webp: {
140
+ quality: 85, // good enough quality
141
+ effort: 3, // don't use much effort
142
+ },
143
+ avif: {
144
+ quality: 100, // 100% quality
145
+ lossless: true, // lossless only
146
+ effort: 9, // a lot of effort
147
+ }
148
+ },{
149
+ builtin: "deliver"
150
+ }]
151
+ }
152
+ ```
153
+
154
+ ## Raster tile image manipulation
155
+
156
+ Use [sharp](https://www.npmjs.com/package/sharp) to manipulate raster tiles.
157
+ Example: convert a raster tile to "dark mode" by inverting the colors and rotating the hue.
158
+
159
+ ``` js
160
+ {
161
+ example: [{
162
+ builtin: "parse",
163
+ },{
164
+ // source tileserver
165
+ builtin: "tileserver",
166
+ url: "https://tileserver.example/{z}/{x}/{y}.png",
167
+ },{
168
+ builtin: "sharp", // use builtin sharp
169
+ negate: {}, // invert colors using sharp.negate()
170
+ modulate: { hue: 180 }, // rotate hue by 180° using sharp.modulate({ hue: 180 })
171
+ },{
172
+ builtin: "deliver"
173
+ }]
174
+ }
175
+ ```
176
+
177
+ ## Edit vector tiles
178
+
179
+ Use [vtt](https://npmjs.com/package/vtt) to edit vectortiles.
180
+
181
+ ``` js
182
+ {
183
+ example: [{
184
+ builtin: "parse",
185
+ },{
186
+ builtin: "tileserver",
187
+ url: "https://tileserver.example/{z}/{x}/{y}.pbf",
188
+ },{
189
+ builtin: "edit", // use builtin edit
190
+ edit: function(layers){
191
+ // `layers` is ja JSON representation of the layers in a tile
192
+ // return the edited `layers` data
193
+ return layers.filter(function(layer){
194
+ return layer.name !== "pois"; // remove "pois" layer
195
+ });
196
+ }
197
+ },{
198
+ builtin: "deliver"
199
+ }]
200
+ }
201
+ ```
202
+
203
+ ## Compression
204
+
205
+ Precompress tiles with brotli and gzip and deliver them to capable clients.
206
+ Use with compressible tiles (vectortiles, json, svg) and not raster tiles.
207
+
208
+ ``` js
209
+ {
210
+ example: [{
211
+ builtin: "parse",
212
+ },{
213
+ builtin: "tileserver",
214
+ url: "https://tileserver.example/{z}/{x}/{y}.pbf",
215
+ },{
216
+ builtin: "compress",
217
+ brotli: 6, // brotli compression level 6
218
+ gzip: 4, // gzip compression level 4
219
+ },{
220
+ builtin: "deliver"
221
+ }]
222
+ }
223
+ ```
224
+
225
+ ## Caching
226
+
227
+ ``` js
228
+ {
229
+ example: [{
230
+ builtin: "parse",
231
+ },{
232
+ builtin: "cache", // before tile retrieved: check if tile is in cache
233
+ skipto: "deliver", // skip to this builtin/plugin at cache hit
234
+ },{
235
+ // get tile from tileserver
236
+ builtin: "tileserver",
237
+ url: "https://tileserver.example/{z}/{x}/{y}",
238
+ },{
239
+ builtin: "cache", // after tile retrieved: store tile in cache
240
+ expires: "30d", // keep in cache for 30 days
241
+ },{
242
+ builtin: "deliver",
243
+ }]
244
+ }
245
+ ```
246
+
247
+ ## CORS
248
+
249
+ Allow Cross-origin resource sharing for certain domains
250
+
251
+ ``` js
252
+ {
253
+ builtin: "cors",
254
+ origins: [ "https://example.org/" ], // "*" for any domain
255
+ }
256
+ ```
257
+
Binary file