tileblaster 0.4.8 → 1.0.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.
@@ -0,0 +1,261 @@
1
+ <?xml version="1.0" encoding="UTF-8" standalone="no"?>
2
+ <!-- Created with Inkscape (http://www.inkscape.org/) -->
3
+
4
+ <svg
5
+ width="150mm"
6
+ height="150mm"
7
+ viewBox="0 50 150 150"
8
+ version="1.1"
9
+ id="svg29401"
10
+ inkscape:version="1.2 (dc2aeda, 2022-05-15)"
11
+ sodipodi:docname="tileblaster.svg"
12
+ inkscape:export-filename="tileblaster.png"
13
+ inkscape:export-xdpi="86.698669"
14
+ inkscape:export-ydpi="86.698669"
15
+ xmlns:inkscape="http://www.inkscape.org/namespaces/inkscape"
16
+ xmlns:sodipodi="http://sodipodi.sourceforge.net/DTD/sodipodi-0.dtd"
17
+ xmlns:xlink="http://www.w3.org/1999/xlink"
18
+ xmlns="http://www.w3.org/2000/svg"
19
+ xmlns:svg="http://www.w3.org/2000/svg">
20
+ <sodipodi:namedview
21
+ id="namedview29403"
22
+ pagecolor="#505050"
23
+ bordercolor="#eeeeee"
24
+ borderopacity="1"
25
+ inkscape:showpageshadow="0"
26
+ inkscape:pageopacity="0"
27
+ inkscape:pagecheckerboard="0"
28
+ inkscape:deskcolor="#505050"
29
+ inkscape:document-units="mm"
30
+ showgrid="false"
31
+ showguides="true"
32
+ inkscape:zoom="1"
33
+ inkscape:cx="382.5"
34
+ inkscape:cy="333.5"
35
+ inkscape:window-width="1859"
36
+ inkscape:window-height="1027"
37
+ inkscape:window-x="61"
38
+ inkscape:window-y="229"
39
+ inkscape:window-maximized="0"
40
+ inkscape:current-layer="layer1">
41
+ <sodipodi:guide
42
+ position="74.999999,38.875"
43
+ orientation="-1,0"
44
+ id="guide32273"
45
+ inkscape:locked="false"
46
+ inkscape:label=""
47
+ inkscape:color="rgb(0,134,229)" />
48
+ <sodipodi:guide
49
+ position="24.694444,74.999999"
50
+ orientation="0,1"
51
+ id="guide34465"
52
+ inkscape:locked="false"
53
+ inkscape:label=""
54
+ inkscape:color="rgb(0,134,229)" />
55
+ <sodipodi:guide
56
+ position="104.51042,150"
57
+ orientation="0,-1"
58
+ id="guide35193"
59
+ inkscape:locked="false" />
60
+ <sodipodi:guide
61
+ position="94.368055,0"
62
+ orientation="0,-1"
63
+ id="guide35195"
64
+ inkscape:locked="false" />
65
+ <sodipodi:guide
66
+ position="0,54.309027"
67
+ orientation="1,0"
68
+ id="guide35197"
69
+ inkscape:locked="false" />
70
+ <sodipodi:guide
71
+ position="150,32.260416"
72
+ orientation="1,0"
73
+ id="guide35199"
74
+ inkscape:locked="false" />
75
+ </sodipodi:namedview>
76
+ <defs
77
+ id="defs29398">
78
+ <linearGradient
79
+ inkscape:collect="always"
80
+ xlink:href="#linearGradient29346-1"
81
+ id="linearGradient31371"
82
+ gradientUnits="userSpaceOnUse"
83
+ gradientTransform="matrix(2.9999997,2.3590334e-8,-2.3590334e-8,2.9999997,-800.00007,-894.07809)"
84
+ x1="400.00006"
85
+ y1="468.68973"
86
+ x2="325.00006"
87
+ y2="425.38846" />
88
+ <linearGradient
89
+ inkscape:collect="always"
90
+ id="linearGradient29346-1">
91
+ <stop
92
+ style="stop-color:#8332ff;stop-opacity:1;"
93
+ offset="0"
94
+ id="stop29342-0" />
95
+ <stop
96
+ style="stop-color:#e816ff;stop-opacity:0.99492383;"
97
+ offset="1"
98
+ id="stop29344-8" />
99
+ </linearGradient>
100
+ <filter
101
+ inkscape:collect="always"
102
+ style="color-interpolation-filters:sRGB"
103
+ id="filter35252"
104
+ x="-0.090126778"
105
+ y="-0.084742466"
106
+ width="1.1802536"
107
+ height="1.1694849">
108
+ <feGaussianBlur
109
+ inkscape:collect="always"
110
+ stdDeviation="3.6361132"
111
+ id="feGaussianBlur35254" />
112
+ </filter>
113
+ <filter
114
+ inkscape:collect="always"
115
+ style="color-interpolation-filters:sRGB"
116
+ id="filter35272"
117
+ x="-0.060782709"
118
+ y="-0.070185916"
119
+ width="1.1215654"
120
+ height="1.1403718">
121
+ <feGaussianBlur
122
+ inkscape:collect="always"
123
+ stdDeviation="11.396758"
124
+ id="feGaussianBlur35274" />
125
+ </filter>
126
+ </defs>
127
+ <g
128
+ inkscape:label="Ebene 1"
129
+ inkscape:groupmode="layer"
130
+ id="layer1"
131
+ transform="translate(179.53655,1.2883869)">
132
+ <g
133
+ id="g35304"
134
+ transform="matrix(1.1361953,0,0,1.1361953,14.238481,-16.847521)">
135
+ <path
136
+ style="fill:#191919;fill-opacity:1;stroke-width:1.17621;stroke-linecap:round"
137
+ d="m -160.68486,91.293103 -1e-5,64.834477 56.14832,32.41724 56.148303,-32.41724 1e-5,-64.834477 -56.148323,-32.417242 z"
138
+ id="path31292" />
139
+ <g
140
+ id="g35262"
141
+ transform="matrix(0.22459324,-0.12966896,0.12966896,0.22459324,-210.22972,70.313386)"
142
+ style="opacity:0.123762;mix-blend-mode:normal;fill:#31e2ff;fill-opacity:1;filter:url(#filter35272)">
143
+ <path
144
+ id="path35256"
145
+ style="fill:#31e2ff;fill-opacity:1;stroke-width:13.6062;stroke-linecap:round"
146
+ d="M 137.49989,187.23365 24.999997,382.08718 137.50003,576.943 l 149.99996,-4e-5 -37.49998,-64.95187 -75.00001,5e-5 -74.99999,-129.90395 37.49998,-64.95114 h 75.00002 l -37.50002,64.95113 74.99999,129.90235 150,10e-6 L 475,382.08718 399.99997,252.18485 H 324.99998 L 362.5,187.23369 287.49999,187.23368 250,252.18485 l -75.00002,10e-6 37.50004,-64.95117 z m 150.00001,129.90234 74.99999,-10e-6 37.5,64.95115 -37.49999,64.95117 -75.00001,-2e-5 -37.49997,-64.95115 z"
147
+ sodipodi:nodetypes="cccccccccccccccccccccccccccc" />
148
+ <path
149
+ id="path35258"
150
+ style="opacity:0.180328;fill:#31e2ff;fill-opacity:1;stroke:none;stroke-width:2;stroke-linecap:round;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1"
151
+ d="M 137.5,187.23242 25,382.08789 150,208.88281 212.5,187.23242 Z m 150,0 -37.5,64.95117 50,-43.30078 62.5,-21.64843 z" />
152
+ <path
153
+ id="path35260"
154
+ style="opacity:0.180328;fill:#31e2ff;fill-opacity:1;stroke:none;stroke-width:2;stroke-linecap:round;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1"
155
+ d="m 225,295.48438 -87.5,21.65039 h 75 z M 475,382.08789 387.5,490.33984 250,511.99023 H 400 Z M 275,555.29297 137.5,576.94336 h 150 z" />
156
+ </g>
157
+ <path
158
+ id="path29308"
159
+ style="fill:#840577;fill-opacity:0.399267;stroke-width:3.5286;stroke-linecap:round"
160
+ d="m -154.03095,95.1353 -2.6e-4,58.35052 50.53349,29.17555 33.688976,-19.45035 -16.844482,-9.72517 -16.844494,9.72519 -33.689,-19.45038 1e-4,-19.45018 16.8445,-9.72517 -1.1e-4,19.45017 33.688789,19.45003 33.688993,-19.45036 1.86e-4,-38.900359 -33.688797,-19.450003 -16.844481,9.725168 9e-5,-19.450177 -16.8445,9.725176 -8e-5,19.450179 -16.84451,9.725176 1.1e-4,-19.450187 z m 50.53329,9.72484 16.844493,-9.725173 16.844384,9.725003 -8.8e-5,19.45018 -16.844492,9.72516 -16.844397,-9.725 z"
161
+ sodipodi:nodetypes="cccccccccccccccccccccccccccc" />
162
+ <g
163
+ id="g31384"
164
+ transform="matrix(0.22459324,-0.12966896,0.12966896,0.22459324,-210.22972,70.313386)">
165
+ <path
166
+ id="path31363"
167
+ style="fill:url(#linearGradient31371);fill-opacity:1;stroke-width:13.6062;stroke-linecap:round"
168
+ d="M 137.49989,187.23365 24.999997,382.08718 137.50003,576.943 l 149.99996,-4e-5 -37.49998,-64.95187 -75.00001,5e-5 -74.99999,-129.90395 37.49998,-64.95114 h 75.00002 l -37.50002,64.95113 74.99999,129.90235 150,10e-6 L 475,382.08718 399.99997,252.18485 H 324.99998 L 362.5,187.23369 287.49999,187.23368 250,252.18485 l -75.00002,10e-6 37.50004,-64.95117 z m 150.00001,129.90234 74.99999,-10e-6 37.5,64.95115 -37.49999,64.95117 -75.00001,-2e-5 -37.49997,-64.95115 z"
169
+ sodipodi:nodetypes="cccccccccccccccccccccccccccc" />
170
+ <path
171
+ id="path31365"
172
+ style="opacity:0.180328;fill:#ffffff;fill-opacity:1;stroke:none;stroke-width:2;stroke-linecap:round;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1"
173
+ d="M 137.5,187.23242 25,382.08789 150,208.88281 212.5,187.23242 Z m 150,0 -37.5,64.95117 50,-43.30078 62.5,-21.64843 z" />
174
+ <path
175
+ id="path31373"
176
+ style="opacity:0.180328;fill:#000000;fill-opacity:1;stroke:none;stroke-width:2;stroke-linecap:round;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1"
177
+ d="m 225,295.48438 -87.5,21.65039 h 75 z M 475,382.08789 387.5,490.33984 250,511.99023 H 400 Z M 275,555.29297 137.5,576.94336 h 150 z" />
178
+ </g>
179
+ <path
180
+ id="path35201"
181
+ style="opacity:0.576733;mix-blend-mode:normal;fill:#010101;fill-opacity:1;stroke-width:0.23538;filter:url(#filter35252)"
182
+ d="m -71.411808,72.221289 -5.095817,2.941939 v 5.884913 l -15.288461,8.826334 h -10.192134 l -5.09633,2.942456 -5.09633,2.942456 -5.09581,2.94194 -8.28994,4.786273 -1.20147,0.6935 -0.70125,0.40462 -25.48062,14.71125 v 17.6537 l 5.09633,2.94246 10.19214,-5.8844 5.09633,2.94194 v 35.30689 l 5.09582,2.94246 20.3848,-11.76879 -5.09633,-2.94246 v -5.8844 -23.53809 l 10.19266,-5.8844 v -5.88439 -5.2e-4 l 5.095807,-2.94194 v -5.8844 l 5.096327,-2.94245 v -5.8844 l 35.672739,-20.595639 -5.096327,-2.942456 v -5.884396 l -5.095807,2.941939 z"
183
+ transform="matrix(0.98017487,0,0,0.98017487,-2.0724487,2.4525763)" />
184
+ <g
185
+ id="g29366"
186
+ transform="matrix(0.19980409,-0.11535694,0.11535694,0.19980409,-191.07133,74.765286)">
187
+ <path
188
+ style="fill:#949fab;fill-opacity:1"
189
+ d="m 75.000005,338.78592 12.499997,21.65063 -75,129.90381 12.500003,21.65064 H 125.00001 L 112.5,490.34036 200,338.78592 Z"
190
+ id="path25198"
191
+ sodipodi:nodetypes="cccccccc" />
192
+ <path
193
+ style="fill:#e6e9ed;fill-opacity:1;stroke-width:4.53543;stroke-linecap:round"
194
+ d="M 12.499997,317.13529 50,252.18338 h 250 l 37.5,21.65064 -37.5,64.9519 H 25.000006 Z"
195
+ id="path25379"
196
+ sodipodi:nodetypes="ccccccc" />
197
+ <path
198
+ style="fill:#ed5564;fill-opacity:1;stroke-width:4.53543;stroke-linecap:round"
199
+ d="m 187.5,360.43655 h 50 L 225,382.08719 h -50 z"
200
+ id="path25444"
201
+ sodipodi:nodetypes="ccccc" />
202
+ <path
203
+ style="fill:#8994a2;fill-opacity:1;stroke-width:4.53543;stroke-linecap:round"
204
+ d="M 300,252.18338 275,295.48465 262.5,273.83402 275,252.18338 H 250 L 225,295.48465 213.13802,274.9391 225,252.18338 h -25 l -25,43.30127 -12.35149,-21.39341 12.3515,-21.90786 H 275 Z"
205
+ id="path25509"
206
+ sodipodi:nodetypes="cccccccccccccc" />
207
+ <path
208
+ style="fill:#949fab;fill-opacity:1;stroke-width:4.53543;stroke-linecap:round"
209
+ d="m 337.5,273.83401 -12.5,21.65064 -12.5,21.65064 175,-10e-6 -12.5,-21.65063 12.5,-21.65063 z"
210
+ id="path26345"
211
+ sodipodi:nodetypes="ccccccc" />
212
+ <path
213
+ style="fill:#8994a2;fill-opacity:1;stroke-width:4.53543;stroke-linecap:round"
214
+ d="m 412.49999,273.83402 12.5,-21.65064 H 450 l 12.5,21.65064 h -50.00001"
215
+ id="path26420" />
216
+ <path
217
+ style="fill:#8994a2;fill-opacity:1;stroke-width:4.53543;stroke-linecap:round"
218
+ d="m 200,338.78591 75,10e-6 -12.50001,21.65063 H 187.5 Z"
219
+ id="path26432"
220
+ sodipodi:nodetypes="ccccc" />
221
+ <path
222
+ style="fill:#ffffff;fill-opacity:0.0967742;stroke-width:4.53543;stroke-linecap:round"
223
+ d="M 12.499997,317.13529 50,252.18338 H 300 L 62.500003,273.83402 Z"
224
+ id="path26937" />
225
+ <path
226
+ style="fill:#000000;fill-opacity:0.0967742;stroke-width:4.53543;stroke-linecap:round"
227
+ d="M 112.5,490.34036 99.999998,468.68973 175,338.78592 h 100 l -87.5,21.65063 z"
228
+ id="path28766" />
229
+ <path
230
+ style="fill:#ffffff;fill-opacity:0.0967742;stroke-width:4.53543;stroke-linecap:round"
231
+ d="m 325,295.48465 12.5,-21.65063 h 150 z"
232
+ id="path28831" />
233
+ <path
234
+ style="fill:#000000;fill-opacity:0.0967742;stroke-width:4.53543;stroke-linecap:round"
235
+ d="M 312.5,317.13529 475,295.48465 487.49999,317.13529 Z"
236
+ id="path28833" />
237
+ <path
238
+ style="fill:#000000;fill-opacity:0.0967742;stroke-width:4.53543;stroke-linecap:round"
239
+ d="M 337.5,273.83401 275,338.78592 h 25 z"
240
+ id="path28835" />
241
+ <path
242
+ style="fill:#ffffff;fill-opacity:0.0967742;stroke-width:4.53543;stroke-linecap:round"
243
+ d="M 87.500002,360.43655 25.000006,511.991 12.500002,490.34036 Z"
244
+ id="path28837"
245
+ sodipodi:nodetypes="cccc" />
246
+ <path
247
+ style="fill:#000000;fill-opacity:0.131086;stroke-width:4.53543;stroke-linecap:round"
248
+ d="m 175,382.08719 h -25 l 12.5,21.65063 h -25 l 12.5,21.65064 h -25 l 12.5,21.65063 h -25 l 12.5,21.65064 z"
249
+ id="path28914" />
250
+ <path
251
+ style="fill:#000000;fill-opacity:0.131086;stroke-width:4.53543;stroke-linecap:round"
252
+ d="m 175,382.08719 12.5,-21.65064 h 50 z"
253
+ id="path28979" />
254
+ <path
255
+ style="fill:#ffffff;fill-opacity:0.131086;stroke-width:4.53543;stroke-linecap:round"
256
+ d="m 412.5,273.83402 12.49999,-21.65064 H 450 Z"
257
+ id="path28981" />
258
+ </g>
259
+ </g>
260
+ </g>
261
+ </svg>
package/docs/todo.md ADDED
@@ -0,0 +1,140 @@
1
+ # Todo
2
+
3
+ ## Roadmap
4
+
5
+ ### 1.0 Release
6
+
7
+ * [x] Config format
8
+ * [x] Map format
9
+ * [x] Tasks fomat
10
+ * [x] HTTP Server, Port and Socket
11
+ * [x] Graceful shutdown
12
+ * [x] Debug Library → `lib/debug.js`
13
+ * [x] Optional Module Loader → `lib/load.js`
14
+ * [x] HTTPs Abstraction (~got or~ phin) → `lib/retrieve.js`
15
+ * [x] Plugin Interface / Task Runner
16
+ * [x] Builtins
17
+ * [x] CORS
18
+ * [x] Parse Request
19
+ * [x] Check Request
20
+ * [x] Tile Backends
21
+ * [x] ZXY Webtiles → `builtin/tileserver.js`
22
+ * [x] TMS Webtiles → `builtin/tileserver.js`
23
+ * [x] Versatiles
24
+ * [x] PMTiles
25
+ * [x] MBTiles
26
+ * [x] Optimization (optipng, mozjpeg, svgo?, pbfcrop?)
27
+ * [x] Modernize Raster Formats (png,jpeg → webp,avif)
28
+ * [x] Caching to Disk
29
+ * [x] Reading cached tile from Disk
30
+ * [x] Skipping Jobs
31
+ * [x] Etag Headers
32
+ * [x] Last-Modified Headers
33
+ * [x] Don't store if expired
34
+ * [x] Expires Headers
35
+ * [x] Don't update if already cached (in case of store-only)
36
+ * [x] ~Cache-Control Headers~ → Set via `deliver` builtin
37
+ * [x] Delivery
38
+ * [x] Debug Dump
39
+ * [x] Vectortile Editing
40
+ * [x] Full image manipulation for raster tiles → https://www.npmjs.com/package/sharp
41
+ * [x] Vectortiles Editor → https://www.npmjs.com/package/vtt
42
+ * [x] Cache Cleaning Worker
43
+ * [x] Documentation
44
+ * [x] What is Tileblaster, what is the benefit for the user
45
+ * [x] What can't tileblaster do
46
+ * [x] All config options
47
+ * [x] All builtins
48
+ * [x] Example Config
49
+ * [x] Example Nginx Config
50
+ * [x] How to use it, Standalone or behind Proxy
51
+ * [x] Core concepts explained (maps, work queue, builtins and plugins)
52
+ * [x] Examples
53
+ * [x] Caching proxy for a tileserver
54
+ * [x] Serve tiles from container
55
+ * [x] Raster editing: "Dark mode"
56
+ * [x] Vector editing: remove unused layers
57
+ * How to contribute, bug reports
58
+ * [x] CLI
59
+ * [x] Cluster Support
60
+ * [x] PM2 Integration
61
+ * [x] Rudimentary Dev Server
62
+ * [x] Request Queue to throttle unfulfilled requests
63
+ * [x] Fancy Default Page
64
+ * [x] Custom String Template function for {x} replacement instead of regex
65
+
66
+ ### Next
67
+
68
+ * [ ] Redirects
69
+ * [ ] Convert Geojson ↔ Topojson
70
+ * [ ] Map Web Interface, Configurable
71
+ * [ ] Configurable Index Page
72
+ * [ ] Support for Glyphs and Styles, tile.json proxy
73
+ * [ ] Better Error Handling
74
+ * [ ] Error wrapper (to pass along http status etc)?
75
+ * [ ] 404 for nonexistant tiles
76
+ * [ ] Render Vector Tiles with MapLibreGL-Native
77
+ * [ ] Improve Debug Consistency
78
+ * [ ] Documentation: How to write a plugin
79
+
80
+ ### Later
81
+
82
+ * [ ] Screencast
83
+ * [ ] Monitoring / Status / Statistics Interface
84
+ * [ ] Integration with Nginx-Cache
85
+ * [ ] Memcache → https://www.npmjs.com/package/iomem
86
+ * [ ] Backends
87
+ [ ] tilebase https://www.npmjs.com/package/tilebase
88
+ [ ] Geotiff?
89
+ [ ] PostGIS database via ST_AsMVT?
90
+ * [ ] Conversions
91
+ * [ ] pbf → svg
92
+ * [ ] svg → raster
93
+ * [ ] geotif → raster
94
+
95
+ ### Probably Never
96
+
97
+ * [ ] v0 Config Migration?
98
+ * [ ] use mbtiles database as cache?
99
+ * [ ] Standalone Logging?
100
+ * [ ] Config Web Interface
101
+ * [ ] Standalone Daemon with pid files?
102
+ * [ ] Cache: Store in MBTiles or similar?
103
+ * [ ] GDAL?
104
+ * [ ] Footprint
105
+ * [ ] Replace Phin?
106
+ * [ ] ~Nginx Cache Hydration~ (Problem: different file owners)
107
+
108
+ ## Format Support
109
+
110
+ * [x] Vector
111
+ * [x] mvt/pbf
112
+ * [ ] svg
113
+ * [x] Raster
114
+ * [x] png
115
+ * [x] jpeg
116
+ * [x] webp
117
+ * [x] avif
118
+ * [ ] geotif (readonly)
119
+ * [ ] Data
120
+ * [ ] GeoJSON
121
+ * [ ] TopoJSON
122
+ * [ ] JSON
123
+ * [ ] ArcJSON?
124
+ * [ ] WKT? → https://en.wikipedia.org/w/index.php?title=Well-known_text_representation_of_geometry
125
+
126
+ ## Conversions
127
+
128
+ * [ ] GeoJSON ↔ TopoJSON
129
+ * [ ] WKT → GeoJSON TopoJSON
130
+ * [ ] GeoJSON TopoJSON → SVG
131
+ * [ ] PNG JPEG WEBP AVIF TIF SVG → PNG JPEG WEBP AVIF
132
+ * [ ] MVT → SVG
133
+ * [ ] MVT → GeoJSON TopoJSON
134
+
135
+ ## Etag
136
+
137
+ ``` js
138
+ // nginx etag — for consistency
139
+ etag = util.format('"%s-%s"', Math.floor(mtimeMs/1000).toString(16), filesize.toString(16));
140
+ ```
package/lib/debug.js ADDED
@@ -0,0 +1,68 @@
1
+
2
+ // placeholder debug module
3
+
4
+ const colrz = require("colrz");
5
+ const path = require("node:path");
6
+ const format = require("node:util").format;
7
+
8
+ // enabled if env.DEBUG has tileblaster or *
9
+ const enabled = (process.env.DEBUG && process.env.DEBUG.split(/, ?/).find(function(debug){ return debug === "*" || debug.slice(0,11) === "tileblaster"; }) && true);
10
+
11
+ // time between outputs helper
12
+ let time = Date.now();
13
+ function since(){
14
+ let since = Date.now()-time;
15
+ time = Date.now();
16
+ if (since > 300000) return "+"+Math.round(since/60000)+"m";
17
+ if (since > 1000) return "+"+(since/1000).toFixed(1)+"s";
18
+ return "+"+since.toFixed(0)+"ms";
19
+ }
20
+
21
+ function prefix(){
22
+ if (!process.env.workerid) return "";
23
+ return format("#%s".magenta+" | ".grey, process.env.workerid.magenta);
24
+ };
25
+
26
+ // default: just print with since
27
+ module.exports = function(){
28
+ if (enabled) console.error(prefix()+"%s %s", format(...arguments), since());
29
+ }
30
+
31
+ // warnings with a yellow label
32
+ module.exports.warn = function(){
33
+ if (enabled) console.error(prefix()+"Warning:".yellow+" %s %s", format(...arguments), since().brightYellow);
34
+ };
35
+
36
+ // info with a blue label
37
+ module.exports.info = function(){
38
+ if (enabled) console.error(prefix()+"Info:".cyan+" %s %s", format(...arguments), since().brightBlue);
39
+ };
40
+
41
+ // errors with a red label and fancy printing of Error instances FIXME refactor
42
+ module.exports.error = function(){
43
+ if (!enabled) return;
44
+
45
+ let stacks = [];
46
+ arguments = Array.from(arguments).map(function(arg){
47
+ if (arg instanceof Error) {
48
+ if (arg.stack) stacks.push(arg.stack);
49
+ return arg.message;
50
+ }
51
+ return arg;
52
+ });
53
+
54
+ console.error(prefix()+"Error:".red+" %s %s", format(...arguments), since().brightRed);
55
+
56
+ // format and prettify stack (a little overkill)
57
+ stacks.forEach(function(stack){
58
+ const lines = stack.split("\n").slice(1);
59
+ if (lines.length === 0) return;
60
+ console.error("┏┉┉┉ ".brightRed+"Stack".red+" ┉┉┉".brightRed);
61
+ console.error("┋".brightRed);
62
+ lines.forEach(function(line){
63
+ console.error("┋".brightRed+" %s", line.trim());
64
+ });
65
+ console.error("┋".brightRed);
66
+ console.error("┗┉┉┉".brightRed);
67
+ });
68
+ };
@@ -0,0 +1,44 @@
1
+ const load = require("../lib/load");
2
+ const zlib = require("node:zlib");
3
+ const lzma = load("node-liblzma");
4
+ const zstd = load("fzstd");
5
+
6
+ const decompress = module.exports = function decompress(buf, compression, fn){
7
+
8
+ // promisify
9
+ if (!fn || typeof fn !== "function") return new Promise(function(resolve, reject){
10
+ decompress(buf, compression, function(err, buf){
11
+ if (err) return reject(err);
12
+ return resolve(buf);
13
+ });
14
+ });
15
+
16
+ switch (compression) {
17
+ case "gzip":
18
+ case "gz":
19
+ zlib.gunzip(buf, fn);
20
+ break;
21
+ case "brotli":
22
+ case "br":
23
+ zlib.brotliDecompress(buf, fn);
24
+ break;
25
+ case "inflate":
26
+ case "deflate":
27
+ zlib.inflate(buf, fn);
28
+ break;
29
+ case "lzma":
30
+ case "xz":
31
+ if (!lzma) return fn(new Error("Missing optional dependency: 'node-liblzma'"));
32
+ lzma.unxz(buf, fn);
33
+ break;
34
+ case "zstd":
35
+ if (!zstd) return fn(new Error("Missing optional dependency: 'fzstd'"));
36
+ try {
37
+ fn(null, fzstd.decompress(buf));
38
+ } catch (err) {
39
+ fn(err);
40
+ }
41
+ break;
42
+ default: return fn(null, buf); // pass through if unknown
43
+ }
44
+ };
package/lib/load.js ADDED
@@ -0,0 +1,26 @@
1
+
2
+ // require wrapper that doesn't throw errors
3
+ const load = function load(r){
4
+ return (r && typeof r === "string" && (load.has(r) || load.exists(r))) ? require(r) : undefined;
5
+ };
6
+
7
+ // cache
8
+ load.modules = {};
9
+
10
+ // check if module is known
11
+ load.has = function(r){
12
+ return load.modules.hasOwnProperty(r) ? load.modules[r] : false;
13
+ };
14
+
15
+ // check if module exists
16
+ load.exists = function(r){
17
+ try {
18
+ require.resolve(r);
19
+ } catch(err) {
20
+ return load.modules[r] = false;
21
+ }
22
+ return load.modules[r] = true;
23
+ };
24
+
25
+ // export
26
+ module.exports = load;
package/lib/mime.js ADDED
@@ -0,0 +1,51 @@
1
+ // file types and mime types
2
+
3
+ // look up mime type for extension
4
+ module.exports.mimetype = function(ext, dflt){
5
+ return mimetypes[ext] && mimetypes[ext][0] || dflt || "application/octet-stream";
6
+ };
7
+
8
+ // look up file type for mime type
9
+ module.exports.filetype = function(mimetype, dflt){
10
+ return filetypes[mimetype] && filetypes[mimetype][0] || dflt || "bin";
11
+ };
12
+
13
+ const mimetypes = {
14
+
15
+ // dflt unknown
16
+ bin: [ "application/octet-stream" ],
17
+
18
+ // raster
19
+ png: [ "image/png" ],
20
+ jpg: [ "image/jpeg" ],
21
+ jpeg: [ "image/jpeg" ],
22
+ gif: [ "image/gif" ],
23
+ webp: [ "image/webp" ],
24
+ avif: [ "image/aviv" ],
25
+ tif: [ "image/tiff" ],
26
+ tiff: [ "image/tiff" ],
27
+
28
+ // vector
29
+ svg: [ "image/svg+xml", "image/svg" ],
30
+ mvt: [ "application/vnd.mapbox-vector-tile", "application/x-protobuf", "application/protobuf", "application/vnd.google.protobuf", "application/octet-stream" ],
31
+ pbf: [ "application/x-protobuf", "application/protobuf", "application/vnd.google.protobuf", "application/octet-stream" ],
32
+
33
+ // data
34
+ json: [ "application/json", "text/json" ],
35
+ geojson: [ "application/geo+json", "application/json", "text/json" ],
36
+ topojson: [ "application/topo+json", "application/json", "text/json" ],
37
+
38
+ // containers
39
+ versatiles: [ "application/x-versatiles", "application/vnd.versatiles", "application/octet-stream" ],
40
+ cloudtiles: [ "application/x-cloudtiles", "application/vnd.cloudtiles", "application/octet-stream" ],
41
+ pmtiles: [ "application/x-pmtiles", "application/vnd.pmtiles", "application/octet-stream" ],
42
+ mbtiles: [ "application/vnd.sqlite3", "application/x-sqlite3", "application/sqlite3", "application/vnd.mbtiles", "application/x-mbtiles", "application/mbtiles", "application/octet-stream" ],
43
+
44
+ };
45
+
46
+ const filetypes = Object.entries(mimetypes).reduce(function(lookup, [ extension, types ]){
47
+ types.forEach(function(type){
48
+ lookup[type] = [ ...(lookup[type]||[]), extension ];
49
+ });
50
+ return lookup;
51
+ },{});