@basemaps/lambda-tiler 7.4.0 → 7.6.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 +36 -0
- package/build/__tests__/config.data.d.ts +2 -0
- package/build/__tests__/config.data.js +24 -1
- package/build/__tests__/config.data.js.map +1 -1
- package/build/__tests__/index.test.js +1 -2
- package/build/__tests__/index.test.js.map +1 -1
- package/build/__tests__/tile.style.json.test.js +2 -2
- package/build/__tests__/tile.style.json.test.js.map +1 -1
- package/build/__tests__/wmts.capability.test.js +5 -2
- package/build/__tests__/wmts.capability.test.js.map +1 -1
- package/build/__tests__/xyz.util.js.map +1 -1
- package/build/cli/render.preview.js +5 -2
- package/build/cli/render.preview.js.map +1 -1
- package/build/cli/render.tile.js +1 -1
- package/build/cli/render.tile.js.map +1 -1
- package/build/index.js +1 -1
- package/build/index.js.map +1 -1
- package/build/routes/__tests__/attribution.test.js +1 -1
- package/build/routes/__tests__/attribution.test.js.map +1 -1
- package/build/routes/__tests__/health.test.js +1 -1
- package/build/routes/__tests__/health.test.js.map +1 -1
- package/build/routes/__tests__/imagery.test.js.map +1 -1
- package/build/routes/__tests__/memory.fs.d.ts +0 -2
- package/build/routes/__tests__/memory.fs.js +1 -1
- package/build/routes/__tests__/memory.fs.js.map +1 -1
- package/build/routes/__tests__/preview.index.test.js +1 -1
- package/build/routes/__tests__/preview.index.test.js.map +1 -1
- package/build/routes/__tests__/tile.json.test.js.map +1 -1
- package/build/routes/__tests__/tile.style.json.test.js +144 -11
- package/build/routes/__tests__/tile.style.json.test.js.map +1 -1
- package/build/routes/__tests__/wmts.test.js +18 -2
- package/build/routes/__tests__/wmts.test.js.map +1 -1
- package/build/routes/attribution.d.ts +0 -1
- package/build/routes/config.js +1 -1
- package/build/routes/config.js.map +1 -1
- package/build/routes/health.d.ts +0 -1
- package/build/routes/ping.js +2 -2
- package/build/routes/ping.js.map +1 -1
- package/build/routes/preview.index.js +2 -1
- package/build/routes/preview.index.js.map +1 -1
- package/build/routes/preview.js +5 -3
- package/build/routes/preview.js.map +1 -1
- package/build/routes/sprites.js.map +1 -1
- package/build/routes/tile.style.json.d.ts +2 -2
- package/build/routes/tile.style.json.js +61 -10
- package/build/routes/tile.style.json.js.map +1 -1
- package/build/routes/tile.wmts.js +1 -0
- package/build/routes/tile.wmts.js.map +1 -1
- package/build/routes/tile.xyz.raster.d.ts +0 -1
- package/build/routes/tile.xyz.raster.js +6 -5
- package/build/routes/tile.xyz.raster.js.map +1 -1
- package/build/routes/version.js +2 -2
- package/build/routes/version.js.map +1 -1
- package/build/util/__test__/config.loader.test.js +12 -12
- package/build/util/__test__/config.loader.test.js.map +1 -1
- package/build/util/assets.provider.d.ts +0 -2
- package/build/util/config.cache.d.ts +0 -1
- package/build/util/config.cache.js.map +1 -1
- package/build/util/cotar.serve.d.ts +0 -2
- package/build/util/source.cache.d.ts +0 -1
- package/build/util/source.cache.js +5 -4
- package/build/util/source.cache.js.map +1 -1
- package/build/util/validate.js +1 -1
- package/build/util/validate.js.map +1 -1
- package/build/wmts.capability.d.ts +8 -4
- package/build/wmts.capability.js +18 -8
- package/build/wmts.capability.js.map +1 -1
- package/package.json +10 -10
- package/src/__tests__/config.data.ts +31 -2
- package/src/__tests__/index.test.ts +2 -3
- package/src/__tests__/tile.style.json.test.ts +2 -5
- package/src/__tests__/wmts.capability.test.ts +13 -10
- package/src/__tests__/xyz.util.ts +4 -4
- package/src/cli/render.preview.ts +5 -2
- package/src/cli/render.tile.ts +1 -1
- package/src/routes/__tests__/attribution.test.ts +7 -7
- package/src/routes/__tests__/health.test.ts +3 -3
- package/src/routes/__tests__/imagery.test.ts +1 -1
- package/src/routes/__tests__/memory.fs.ts +2 -2
- package/src/routes/__tests__/preview.index.test.ts +3 -3
- package/src/routes/__tests__/tile.json.test.ts +1 -1
- package/src/routes/__tests__/tile.style.json.test.ts +175 -15
- package/src/routes/__tests__/wmts.test.ts +23 -3
- package/src/routes/config.ts +1 -1
- package/src/routes/ping.ts +2 -2
- package/src/routes/preview.index.ts +2 -1
- package/src/routes/preview.ts +7 -5
- package/src/routes/sprites.ts +1 -1
- package/src/routes/tile.style.json.ts +73 -9
- package/src/routes/tile.wmts.ts +1 -0
- package/src/routes/tile.xyz.raster.ts +8 -6
- package/src/routes/version.ts +2 -2
- package/src/util/__test__/config.loader.test.ts +17 -20
- package/src/util/config.cache.ts +2 -1
- package/src/util/source.cache.ts +6 -4
- package/src/util/validate.ts +1 -1
- package/src/wmts.capability.ts +17 -9
- package/tsconfig.json +10 -10
- package/tsconfig.tsbuildinfo +1 -1
|
@@ -1,11 +1,12 @@
|
|
|
1
1
|
import assert from 'node:assert';
|
|
2
2
|
import { afterEach, before, beforeEach, describe, it } from 'node:test';
|
|
3
3
|
|
|
4
|
-
import { ConfigProviderMemory, StyleJson } from '@basemaps/config';
|
|
4
|
+
import { ConfigProviderMemory, SourceRaster, StyleJson } from '@basemaps/config';
|
|
5
|
+
import { Terrain } from '@basemaps/config/src/config/vector.style.js';
|
|
5
6
|
import { Env } from '@basemaps/shared';
|
|
6
7
|
import { createSandbox } from 'sinon';
|
|
7
8
|
|
|
8
|
-
import { FakeData } from '../../__tests__/config.data.js';
|
|
9
|
+
import { FakeData, TileSetAerial, TileSetElevation } from '../../__tests__/config.data.js';
|
|
9
10
|
import { Api, mockRequest, mockUrlRequest } from '../../__tests__/xyz.util.js';
|
|
10
11
|
import { handler } from '../../index.js';
|
|
11
12
|
import { ConfigLoader } from '../../util/config.loader.js';
|
|
@@ -48,6 +49,10 @@ describe('/v1/styles', () => {
|
|
|
48
49
|
type: 'raster',
|
|
49
50
|
tiles: [`/raster/{z}/{x}/{y}.webp`], // Shouldn't encode the {}
|
|
50
51
|
},
|
|
52
|
+
basemaps_terrain: {
|
|
53
|
+
type: 'raster-dem',
|
|
54
|
+
tiles: [`/elevation/{z}/{x}/{y}.png?pipeline=terrain-rgb`],
|
|
55
|
+
},
|
|
51
56
|
test_vector: {
|
|
52
57
|
type: 'vector',
|
|
53
58
|
url: 'vector.url.co.nz',
|
|
@@ -127,6 +132,11 @@ describe('/v1/styles', () => {
|
|
|
127
132
|
tiles: [`${host}/raster/{z}/{x}/{y}.webp?api=${Api.key}`],
|
|
128
133
|
};
|
|
129
134
|
|
|
135
|
+
fakeStyle.sources['basemaps_terrain'] = {
|
|
136
|
+
type: 'raster-dem',
|
|
137
|
+
tiles: [`${host}/elevation/{z}/{x}/{y}.png?pipeline=terrain-rgb&api=${Api.key}`],
|
|
138
|
+
};
|
|
139
|
+
|
|
130
140
|
fakeStyle.sprite = `${host}/sprite`;
|
|
131
141
|
fakeStyle.glyphs = `${host}/glyphs`;
|
|
132
142
|
|
|
@@ -174,14 +184,16 @@ describe('/v1/styles', () => {
|
|
|
174
184
|
const res = await handler.router.handle(request);
|
|
175
185
|
assert.equal(res.status, 200, res.statusDescription);
|
|
176
186
|
|
|
177
|
-
const body = JSON.parse(Buffer.from(res.body, 'base64').toString());
|
|
187
|
+
const body = JSON.parse(Buffer.from(res.body, 'base64').toString()) as StyleJson;
|
|
178
188
|
|
|
179
189
|
assert.equal(body.version, 8);
|
|
180
|
-
|
|
181
|
-
|
|
190
|
+
|
|
191
|
+
const aerialSource = body.sources['basemaps-aerial'] as SourceRaster;
|
|
192
|
+
assert.deepEqual(aerialSource.type, 'raster');
|
|
193
|
+
assert.deepEqual(aerialSource.tiles, [
|
|
182
194
|
`https://tiles.test/v1/tiles/aerial/WebMercatorQuad/{z}/{x}/{y}.webp?api=${Api.key}`,
|
|
183
195
|
]);
|
|
184
|
-
assert.deepEqual(
|
|
196
|
+
assert.deepEqual(aerialSource.tileSize, 256);
|
|
185
197
|
assert.deepEqual(body.layers, [{ id: 'basemaps-aerial', type: 'raster', source: 'basemaps-aerial' }]);
|
|
186
198
|
});
|
|
187
199
|
|
|
@@ -192,14 +204,16 @@ describe('/v1/styles', () => {
|
|
|
192
204
|
const res = await handler.router.handle(request);
|
|
193
205
|
assert.equal(res.status, 200, res.statusDescription);
|
|
194
206
|
|
|
195
|
-
const body = JSON.parse(Buffer.from(res.body, 'base64').toString());
|
|
207
|
+
const body = JSON.parse(Buffer.from(res.body, 'base64').toString()) as StyleJson;
|
|
196
208
|
|
|
197
209
|
assert.equal(body.version, 8);
|
|
198
|
-
|
|
199
|
-
|
|
210
|
+
const aerialSource = body.sources['basemaps-aerial'] as unknown as SourceRaster;
|
|
211
|
+
|
|
212
|
+
assert.deepEqual(aerialSource.type, 'raster');
|
|
213
|
+
assert.deepEqual(aerialSource.tiles, [
|
|
200
214
|
`https://tiles.test/v1/tiles/aerial/NZTM2000Quad/{z}/{x}/{y}.jpeg?api=${Api.key}`,
|
|
201
215
|
]);
|
|
202
|
-
assert.deepEqual(
|
|
216
|
+
assert.deepEqual(aerialSource.tileSize, 256);
|
|
203
217
|
assert.deepEqual(body.layers, [{ id: 'basemaps-aerial', type: 'raster', source: 'basemaps-aerial' }]);
|
|
204
218
|
});
|
|
205
219
|
|
|
@@ -210,14 +224,160 @@ describe('/v1/styles', () => {
|
|
|
210
224
|
const res = await handler.router.handle(request);
|
|
211
225
|
assert.equal(res.status, 200, res.statusDescription);
|
|
212
226
|
|
|
213
|
-
const body = JSON.parse(Buffer.from(res.body, 'base64').toString());
|
|
227
|
+
const body = JSON.parse(Buffer.from(res.body, 'base64').toString()) as StyleJson;
|
|
228
|
+
body.sources['basemaps-aerial'];
|
|
229
|
+
body.sources['basemaps-aerial'];
|
|
230
|
+
body.sources['basemaps-aerial'];
|
|
231
|
+
const aerialSource = body.sources['basemaps-aerial'] as unknown as SourceRaster;
|
|
214
232
|
|
|
215
|
-
assert.
|
|
216
|
-
assert.deepEqual(
|
|
217
|
-
assert.deepEqual(body.sources['basemaps-aerial'].tiles, [
|
|
233
|
+
assert.deepEqual(aerialSource.type, 'raster');
|
|
234
|
+
assert.deepEqual(aerialSource.tiles, [
|
|
218
235
|
`https://tiles.test/v1/tiles/aerial/WebMercatorQuad/{z}/{x}/{y}.webp?api=${Api.key}&config=${configId}`,
|
|
219
236
|
]);
|
|
220
|
-
assert.deepEqual(
|
|
237
|
+
assert.deepEqual(aerialSource.tileSize, 256);
|
|
221
238
|
assert.deepEqual(body.layers, [{ id: 'basemaps-aerial', type: 'raster', source: 'basemaps-aerial' }]);
|
|
222
239
|
});
|
|
240
|
+
|
|
241
|
+
it('should create individual raster styles with terrain', async () => {
|
|
242
|
+
const configId = FakeData.bundle([FakeData.tileSetRaster('christchurch-urban-2020-2021-0.075m'), TileSetElevation]);
|
|
243
|
+
const request = mockUrlRequest(
|
|
244
|
+
'/v1/styles/christchurch-urban-2020-2021-0.075m.json',
|
|
245
|
+
`?config=${configId}`,
|
|
246
|
+
Api.header,
|
|
247
|
+
);
|
|
248
|
+
|
|
249
|
+
const res = await handler.router.handle(request);
|
|
250
|
+
assert.equal(res.status, 200, res.statusDescription);
|
|
251
|
+
|
|
252
|
+
const body = JSON.parse(Buffer.from(res.body, 'base64').toString()) as StyleJson;
|
|
253
|
+
|
|
254
|
+
assert.equal(body.version, 8);
|
|
255
|
+
const rasterSource = body.sources['basemaps-christchurch-urban-2020-2021-0.075m'] as unknown as SourceRaster;
|
|
256
|
+
|
|
257
|
+
assert.deepEqual(rasterSource.type, 'raster');
|
|
258
|
+
assert.deepEqual(rasterSource.tiles, [
|
|
259
|
+
`https://tiles.test/v1/tiles/christchurch-urban-2020-2021-0.075m/WebMercatorQuad/{z}/{x}/{y}.webp?api=${Api.key}&config=${configId}`,
|
|
260
|
+
]);
|
|
261
|
+
assert.deepEqual(rasterSource.tileSize, 256);
|
|
262
|
+
assert.deepEqual(body.layers, [
|
|
263
|
+
{
|
|
264
|
+
id: 'basemaps-christchurch-urban-2020-2021-0.075m',
|
|
265
|
+
type: 'raster',
|
|
266
|
+
source: 'basemaps-christchurch-urban-2020-2021-0.075m',
|
|
267
|
+
},
|
|
268
|
+
]);
|
|
269
|
+
|
|
270
|
+
const rasterDemSource = body.sources['LINZ-Terrain'] as unknown as SourceRaster;
|
|
271
|
+
|
|
272
|
+
assert.deepEqual(rasterDemSource.type, 'raster-dem');
|
|
273
|
+
assert.deepEqual(rasterDemSource.tiles, [
|
|
274
|
+
`https://tiles.test/v1/tiles/elevation/WebMercatorQuad/{z}/{x}/{y}.png?api=${Api.key}&config=${configId}&pipeline=terrain-rgb`,
|
|
275
|
+
]);
|
|
276
|
+
});
|
|
277
|
+
|
|
278
|
+
const fakeVectorStyleConfig = {
|
|
279
|
+
id: 'test',
|
|
280
|
+
name: 'test',
|
|
281
|
+
sources: {
|
|
282
|
+
basemaps_vector: {
|
|
283
|
+
type: 'vector',
|
|
284
|
+
url: `/vector`,
|
|
285
|
+
},
|
|
286
|
+
},
|
|
287
|
+
layers: [
|
|
288
|
+
{
|
|
289
|
+
layout: {
|
|
290
|
+
visibility: 'visible',
|
|
291
|
+
},
|
|
292
|
+
paint: {
|
|
293
|
+
'background-color': 'rgba(206, 229, 242, 1)',
|
|
294
|
+
},
|
|
295
|
+
id: 'Background1',
|
|
296
|
+
type: 'background',
|
|
297
|
+
minzoom: 0,
|
|
298
|
+
},
|
|
299
|
+
],
|
|
300
|
+
};
|
|
301
|
+
|
|
302
|
+
const fakeVectorRecord = {
|
|
303
|
+
id: 'st_topolite',
|
|
304
|
+
name: 'topolite',
|
|
305
|
+
style: fakeVectorStyleConfig,
|
|
306
|
+
};
|
|
307
|
+
|
|
308
|
+
it('should ensure terrain for all style config', async () => {
|
|
309
|
+
const request = mockUrlRequest('/v1/styles/topolite.json', '?terrain=LINZ-Terrain', Api.header);
|
|
310
|
+
config.put(fakeVectorRecord);
|
|
311
|
+
config.put(TileSetElevation);
|
|
312
|
+
|
|
313
|
+
const res = await handler.router.handle(request);
|
|
314
|
+
assert.equal(res.status, 200, res.statusDescription);
|
|
315
|
+
|
|
316
|
+
const body = JSON.parse(Buffer.from(res.body, 'base64').toString()) as StyleJson;
|
|
317
|
+
const rasterDemSource = body.sources['LINZ-Terrain'] as unknown as SourceRaster;
|
|
318
|
+
|
|
319
|
+
assert.deepEqual(rasterDemSource.type, 'raster-dem');
|
|
320
|
+
assert.deepEqual(rasterDemSource.tiles, [
|
|
321
|
+
`https://tiles.test/v1/tiles/elevation/WebMercatorQuad/{z}/{x}/{y}.png?api=${Api.key}&pipeline=terrain-rgb`,
|
|
322
|
+
]);
|
|
323
|
+
});
|
|
324
|
+
|
|
325
|
+
const fakeAerialStyleConfig = {
|
|
326
|
+
id: 'test',
|
|
327
|
+
name: 'test',
|
|
328
|
+
sources: {
|
|
329
|
+
basemaps_raster: {
|
|
330
|
+
type: 'raster',
|
|
331
|
+
tiles: [`/raster/{z}/{x}/{y}.webp`],
|
|
332
|
+
},
|
|
333
|
+
basemaps_terrain: {
|
|
334
|
+
type: 'raster-dem',
|
|
335
|
+
tiles: [`/elevation/{z}/{x}/{y}.png?pipeline=terrain-rgb`],
|
|
336
|
+
},
|
|
337
|
+
},
|
|
338
|
+
layers: [
|
|
339
|
+
{
|
|
340
|
+
layout: {
|
|
341
|
+
visibility: 'visible',
|
|
342
|
+
},
|
|
343
|
+
paint: {
|
|
344
|
+
'background-color': 'rgba(206, 229, 242, 1)',
|
|
345
|
+
},
|
|
346
|
+
id: 'Background1',
|
|
347
|
+
type: 'background',
|
|
348
|
+
minzoom: 0,
|
|
349
|
+
},
|
|
350
|
+
],
|
|
351
|
+
};
|
|
352
|
+
|
|
353
|
+
const fakeAerialRecord = {
|
|
354
|
+
id: 'st_aerial',
|
|
355
|
+
name: 'aerial',
|
|
356
|
+
style: fakeAerialStyleConfig,
|
|
357
|
+
};
|
|
358
|
+
|
|
359
|
+
it('should set terrain via parameter for style config', async () => {
|
|
360
|
+
const request = mockUrlRequest('/v1/styles/aerial.json', '?terrain=basemaps_terrain', Api.header);
|
|
361
|
+
config.put(fakeAerialRecord);
|
|
362
|
+
const res = await handler.router.handle(request);
|
|
363
|
+
assert.equal(res.status, 200, res.statusDescription);
|
|
364
|
+
|
|
365
|
+
const body = JSON.parse(Buffer.from(res.body, 'base64').toString()) as StyleJson;
|
|
366
|
+
const terrain = body.terrain as unknown as Terrain;
|
|
367
|
+
assert.deepEqual(terrain.source, 'basemaps_terrain');
|
|
368
|
+
assert.deepEqual(terrain.exaggeration, 1.2);
|
|
369
|
+
});
|
|
370
|
+
|
|
371
|
+
it('should set terrain via parameter for tileSet config', async () => {
|
|
372
|
+
config.put(TileSetAerial);
|
|
373
|
+
config.put(TileSetElevation);
|
|
374
|
+
const request = mockUrlRequest('/v1/styles/aerial.json', `?terrain=LINZ-Terrain`, Api.header);
|
|
375
|
+
const res = await handler.router.handle(request);
|
|
376
|
+
assert.equal(res.status, 200, res.statusDescription);
|
|
377
|
+
|
|
378
|
+
const body = JSON.parse(Buffer.from(res.body, 'base64').toString()) as StyleJson;
|
|
379
|
+
const terrain = body.terrain as unknown as Terrain;
|
|
380
|
+
assert.deepEqual(terrain.source, 'LINZ-Terrain');
|
|
381
|
+
assert.deepEqual(terrain.exaggeration, 1.2);
|
|
382
|
+
});
|
|
223
383
|
});
|
|
@@ -4,7 +4,7 @@ import { afterEach, beforeEach, describe, it } from 'node:test';
|
|
|
4
4
|
import { ConfigProviderMemory, ConfigTileSetRaster } from '@basemaps/config';
|
|
5
5
|
import { Env } from '@basemaps/shared';
|
|
6
6
|
|
|
7
|
-
import { Imagery2193, Imagery3857, Provider, TileSetAerial } from '../../__tests__/config.data.js';
|
|
7
|
+
import { Imagery2193, Imagery3857, Provider, TileSetAerial, TileSetElevation } from '../../__tests__/config.data.js';
|
|
8
8
|
import { Api, mockUrlRequest } from '../../__tests__/xyz.util.js';
|
|
9
9
|
import { handler } from '../../index.js';
|
|
10
10
|
import { ConfigLoader } from '../../util/config.loader.js';
|
|
@@ -27,6 +27,28 @@ describe('WMTSRouting', () => {
|
|
|
27
27
|
config.objects.clear();
|
|
28
28
|
});
|
|
29
29
|
|
|
30
|
+
it('should support pipeline', async (t) => {
|
|
31
|
+
t.mock.method(Env, 'get', (arg: string) => {
|
|
32
|
+
if (arg === Env.PublicUrlBase) return 'https://tiles.test';
|
|
33
|
+
return process.env[arg];
|
|
34
|
+
});
|
|
35
|
+
config.put(TileSetElevation);
|
|
36
|
+
t.mock.method(ConfigLoader, 'load', () => Promise.resolve(config));
|
|
37
|
+
const req = mockUrlRequest(
|
|
38
|
+
'/v1/tiles/elevation/WebMercatorQuad/WMTSCapabilities.xml',
|
|
39
|
+
`tileFormat=png&api=${Api.key}&config=s3://linz-basemaps/config.json&pipeline=terrain-rgb`,
|
|
40
|
+
);
|
|
41
|
+
const res = await handler.router.handle(req);
|
|
42
|
+
|
|
43
|
+
assert.equal(res.status, 200);
|
|
44
|
+
const lines = Buffer.from(res.body, 'base64').toString().split('\n');
|
|
45
|
+
const resourceUrl = lines.find((f) => f.includes('ResourceURL'))?.trim();
|
|
46
|
+
|
|
47
|
+
assert.ok(resourceUrl);
|
|
48
|
+
assert.ok(resourceUrl.includes('amp;pipeline=terrain-rgb'), `includes pipeline=terrain-rgb in ${resourceUrl}`);
|
|
49
|
+
assert.ok(resourceUrl.includes('.png'), `includes .png in ${resourceUrl}`);
|
|
50
|
+
});
|
|
51
|
+
|
|
30
52
|
it('should default to the aerial layer', async (t) => {
|
|
31
53
|
t.mock.method(Env, 'get', (arg: string) => {
|
|
32
54
|
if (arg === Env.PublicUrlBase) return 'https://tiles.test';
|
|
@@ -68,8 +90,6 @@ describe('WMTSRouting', () => {
|
|
|
68
90
|
|
|
69
91
|
config.put({ ...TileSetAerial, id: 'ts_all', name: 'all', layers: [] } as ConfigTileSetRaster);
|
|
70
92
|
|
|
71
|
-
config.createVirtualTileSets;
|
|
72
|
-
|
|
73
93
|
const req = mockUrlRequest(
|
|
74
94
|
'/v1/tiles/all/WMTSCapabilities.xml',
|
|
75
95
|
`format=png&api=${Api.key}&config=s3://linz-basemaps/config.json`,
|
package/src/routes/config.ts
CHANGED
|
@@ -6,7 +6,7 @@ import { ConfigLoader } from '../util/config.loader.js';
|
|
|
6
6
|
import { Etag } from '../util/etag.js';
|
|
7
7
|
import { NotFound, NotModified } from '../util/response.js';
|
|
8
8
|
|
|
9
|
-
|
|
9
|
+
function sendJson(req: LambdaHttpRequest, toSend: unknown): LambdaHttpResponse {
|
|
10
10
|
const data = Buffer.from(JSON.stringify(toSend));
|
|
11
11
|
|
|
12
12
|
const cacheKey = Etag.key(data);
|
package/src/routes/ping.ts
CHANGED
|
@@ -3,6 +3,6 @@ import { HttpHeader, LambdaHttpResponse } from '@linzjs/lambda';
|
|
|
3
3
|
const OkResponse = new LambdaHttpResponse(200, 'ok');
|
|
4
4
|
OkResponse.header(HttpHeader.CacheControl, 'no-store');
|
|
5
5
|
|
|
6
|
-
export
|
|
7
|
-
return OkResponse;
|
|
6
|
+
export function pingGet(): Promise<LambdaHttpResponse> {
|
|
7
|
+
return Promise.resolve(OkResponse);
|
|
8
8
|
}
|
|
@@ -1,6 +1,7 @@
|
|
|
1
1
|
import { promisify } from 'node:util';
|
|
2
2
|
import { gunzip } from 'node:zlib';
|
|
3
3
|
|
|
4
|
+
import { TileSetType } from '@basemaps/config';
|
|
4
5
|
import { GoogleTms, LocationUrl, LonLatZoom, TileMatrixSets } from '@basemaps/geo';
|
|
5
6
|
import { Env, fsa, getPreviewQuery } from '@basemaps/shared';
|
|
6
7
|
import { HttpHeader, LambdaHttpRequest, LambdaHttpResponse } from '@linzjs/lambda';
|
|
@@ -95,7 +96,7 @@ export async function previewIndexGet(req: LambdaHttpRequest<PreviewIndexGet>):
|
|
|
95
96
|
const tileSet = await config.TileSet.get(config.TileSet.id(query.style));
|
|
96
97
|
req.timer.end('tileset:load');
|
|
97
98
|
if (tileSet == null) return loadAndServeIndexHtml(req, loc);
|
|
98
|
-
if (tileSet.type !==
|
|
99
|
+
if (tileSet.type !== TileSetType.Raster) return loadAndServeIndexHtml(req, loc);
|
|
99
100
|
|
|
100
101
|
let tileMatrix = TileMatrixSets.find(query.tileMatrix);
|
|
101
102
|
if (tileMatrix == null) tileMatrix = GoogleTms;
|
package/src/routes/preview.ts
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
|
-
import { ConfigTileSetRaster, ConfigTileSetRasterOutput } from '@basemaps/config';
|
|
1
|
+
import { ConfigTileSetRaster, ConfigTileSetRasterOutput, TileSetType } from '@basemaps/config';
|
|
2
2
|
import { Bounds, LatLon, Projection, TileMatrixSet } from '@basemaps/geo';
|
|
3
3
|
import { CompositionTiff, TileMakerContext, Tiler } from '@basemaps/tiler';
|
|
4
|
-
import {
|
|
4
|
+
import { TileMakerSharp } from '@basemaps/tiler-sharp';
|
|
5
5
|
import { HttpHeader, LambdaHttpRequest, LambdaHttpResponse } from '@linzjs/lambda';
|
|
6
6
|
import sharp from 'sharp';
|
|
7
7
|
|
|
@@ -62,7 +62,7 @@ export async function tilePreviewGet(req: LambdaHttpRequest<PreviewGet>): Promis
|
|
|
62
62
|
req.timer.end('tileset:load');
|
|
63
63
|
if (tileSet == null) return new LambdaHttpResponse(404, 'Tileset not found');
|
|
64
64
|
// Only raster previews are supported
|
|
65
|
-
if (tileSet.type !==
|
|
65
|
+
if (tileSet.type !== TileSetType.Raster) return new LambdaHttpResponse(404, 'Preview invalid tile set type');
|
|
66
66
|
|
|
67
67
|
const pipeline = req.query.get('pipeline');
|
|
68
68
|
|
|
@@ -161,12 +161,14 @@ export async function renderPreview(req: LambdaHttpRequest, ctx: PreviewRenderCo
|
|
|
161
161
|
|
|
162
162
|
// Load all the tiff tiles and resize/them into the correct locations
|
|
163
163
|
req.timer.start('compose:overlay');
|
|
164
|
-
|
|
164
|
+
// Remove with typescript >=5.5.0
|
|
165
|
+
|
|
166
|
+
const overlays = await Promise.all(
|
|
165
167
|
compositions.map((comp) => {
|
|
166
168
|
if (tileContext.pipeline) return TilerSharp.composeTilePipeline(comp, tileContext);
|
|
167
169
|
return TilerSharp.composeTileTiff(comp, tileContext.resizeKernel);
|
|
168
170
|
}),
|
|
169
|
-
).then((items) => items.filter((f) => f != null))
|
|
171
|
+
).then((items) => items.filter((f) => f != null));
|
|
170
172
|
req.timer.end('compose:overlay');
|
|
171
173
|
|
|
172
174
|
// Create the output image and render all the individual pieces into them
|
package/src/routes/sprites.ts
CHANGED
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import { ConfigTileSetRaster, Layer, Sources, StyleJson, TileSetType } from '@basemaps/config';
|
|
1
|
+
import { ConfigId, ConfigPrefix, ConfigTileSetRaster, Layer, Sources, StyleJson, TileSetType } from '@basemaps/config';
|
|
2
2
|
import { GoogleTms, TileMatrixSet, TileMatrixSets } from '@basemaps/geo';
|
|
3
3
|
import { Env, toQueryString } from '@basemaps/shared';
|
|
4
4
|
import { HttpHeader, LambdaHttpRequest, LambdaHttpResponse } from '@linzjs/lambda';
|
|
@@ -44,10 +44,12 @@ export function convertStyleJson(
|
|
|
44
44
|
config: string | null,
|
|
45
45
|
layers?: Layer[],
|
|
46
46
|
): StyleJson {
|
|
47
|
-
const sources
|
|
47
|
+
const sources = JSON.parse(JSON.stringify(style.sources)) as Sources;
|
|
48
48
|
for (const [key, value] of Object.entries(sources)) {
|
|
49
49
|
if (value.type === 'vector') {
|
|
50
|
-
if (tileMatrix !== GoogleTms)
|
|
50
|
+
if (tileMatrix !== GoogleTms) {
|
|
51
|
+
throw new LambdaHttpResponse(400, `TileMatrix is not supported for the vector source ${value.url}.`);
|
|
52
|
+
}
|
|
51
53
|
value.url = convertRelativeUrl(value.url, tileMatrix, apiKey, config);
|
|
52
54
|
} else if ((value.type === 'raster' || value.type === 'raster-dem') && Array.isArray(value.tiles)) {
|
|
53
55
|
for (let i = 0; i < value.tiles.length; i++) {
|
|
@@ -68,6 +70,7 @@ export function convertStyleJson(
|
|
|
68
70
|
if (style.metadata) styleJson.metadata = style.metadata;
|
|
69
71
|
if (style.glyphs) styleJson.glyphs = convertRelativeUrl(style.glyphs, undefined, undefined, config);
|
|
70
72
|
if (style.sprite) styleJson.sprite = convertRelativeUrl(style.sprite, undefined, undefined, config);
|
|
73
|
+
if (style.sky) styleJson.sky = style.sky;
|
|
71
74
|
|
|
72
75
|
return styleJson;
|
|
73
76
|
}
|
|
@@ -78,11 +81,41 @@ export interface StyleGet {
|
|
|
78
81
|
};
|
|
79
82
|
}
|
|
80
83
|
|
|
84
|
+
function setStyleTerrain(style: StyleJson, terrain: string): void {
|
|
85
|
+
const source = Object.keys(style.sources).find((s) => s === terrain);
|
|
86
|
+
if (source == null) throw new LambdaHttpResponse(400, `Terrain: ${terrain} is not exists in the style source.`);
|
|
87
|
+
style.terrain = {
|
|
88
|
+
source,
|
|
89
|
+
exaggeration: 1.2,
|
|
90
|
+
};
|
|
91
|
+
}
|
|
92
|
+
|
|
93
|
+
async function ensureTerrain(
|
|
94
|
+
req: LambdaHttpRequest<StyleGet>,
|
|
95
|
+
tileMatrix: TileMatrixSet,
|
|
96
|
+
apiKey: string,
|
|
97
|
+
style: StyleJson,
|
|
98
|
+
): Promise<void> {
|
|
99
|
+
const config = await ConfigLoader.load(req);
|
|
100
|
+
const terrain = await config.TileSet.get('ts_elevation');
|
|
101
|
+
if (terrain) {
|
|
102
|
+
const configLocation = ConfigLoader.extract(req);
|
|
103
|
+
const elevationQuery = toQueryString({ config: configLocation, api: apiKey, pipeline: 'terrain-rgb' });
|
|
104
|
+
style.sources['LINZ-Terrain'] = {
|
|
105
|
+
type: 'raster-dem',
|
|
106
|
+
tileSize: 256,
|
|
107
|
+
maxzoom: 18,
|
|
108
|
+
tiles: [convertRelativeUrl(`/v1/tiles/elevation/${tileMatrix.identifier}/{z}/{x}/{y}.png${elevationQuery}`)],
|
|
109
|
+
};
|
|
110
|
+
}
|
|
111
|
+
}
|
|
112
|
+
|
|
81
113
|
export async function tileSetToStyle(
|
|
82
114
|
req: LambdaHttpRequest<StyleGet>,
|
|
83
115
|
tileSet: ConfigTileSetRaster,
|
|
84
116
|
tileMatrix: TileMatrixSet,
|
|
85
117
|
apiKey: string,
|
|
118
|
+
terrain?: string,
|
|
86
119
|
): Promise<LambdaHttpResponse> {
|
|
87
120
|
const [tileFormat] = Validate.getRequestedFormats(req) ?? ['webp'];
|
|
88
121
|
if (tileFormat == null) return new LambdaHttpResponse(400, 'Invalid image format');
|
|
@@ -98,11 +131,20 @@ export async function tileSetToStyle(
|
|
|
98
131
|
`/v1/tiles/${tileSet.name}/${tileMatrix.identifier}/{z}/{x}/{y}.${tileFormat}${query}`;
|
|
99
132
|
|
|
100
133
|
const styleId = `basemaps-${tileSet.name}`;
|
|
101
|
-
const style = {
|
|
134
|
+
const style: StyleJson = {
|
|
135
|
+
id: ConfigId.prefix(ConfigPrefix.Style, tileSet.name),
|
|
136
|
+
name: tileSet.name,
|
|
102
137
|
version: 8,
|
|
103
138
|
sources: { [styleId]: { type: 'raster', tiles: [tileUrl], tileSize: 256 } },
|
|
104
139
|
layers: [{ id: styleId, type: 'raster', source: styleId }],
|
|
105
140
|
};
|
|
141
|
+
|
|
142
|
+
// Ensure elevation for individual tilesets
|
|
143
|
+
await ensureTerrain(req, tileMatrix, apiKey, style);
|
|
144
|
+
|
|
145
|
+
// Add terrain in style
|
|
146
|
+
if (terrain) setStyleTerrain(style, terrain);
|
|
147
|
+
|
|
106
148
|
const data = Buffer.from(JSON.stringify(style));
|
|
107
149
|
|
|
108
150
|
const cacheKey = Etag.key(data);
|
|
@@ -121,6 +163,7 @@ export async function tileSetOutputToStyle(
|
|
|
121
163
|
tileSet: ConfigTileSetRaster,
|
|
122
164
|
tileMatrix: TileMatrixSet,
|
|
123
165
|
apiKey: string,
|
|
166
|
+
terrain?: string,
|
|
124
167
|
): Promise<LambdaHttpResponse> {
|
|
125
168
|
const configLocation = ConfigLoader.extract(req);
|
|
126
169
|
const query = toQueryString({ config: configLocation, api: apiKey });
|
|
@@ -171,19 +214,31 @@ export async function tileSetOutputToStyle(
|
|
|
171
214
|
}
|
|
172
215
|
}
|
|
173
216
|
|
|
174
|
-
const style = {
|
|
217
|
+
const style: StyleJson = {
|
|
218
|
+
id: ConfigId.prefix(ConfigPrefix.Style, tileSet.name),
|
|
219
|
+
name: tileSet.name,
|
|
220
|
+
version: 8,
|
|
221
|
+
sources,
|
|
222
|
+
layers,
|
|
223
|
+
};
|
|
224
|
+
|
|
225
|
+
// Ensure elevation for style json config
|
|
226
|
+
await ensureTerrain(req, tileMatrix, apiKey, style);
|
|
227
|
+
|
|
228
|
+
// Add terrain in style
|
|
229
|
+
if (terrain) setStyleTerrain(style, terrain);
|
|
175
230
|
|
|
176
231
|
const data = Buffer.from(JSON.stringify(style));
|
|
177
232
|
|
|
178
233
|
const cacheKey = Etag.key(data);
|
|
179
|
-
if (Etag.isNotModified(req, cacheKey)) return NotModified();
|
|
234
|
+
if (Etag.isNotModified(req, cacheKey)) return Promise.resolve(NotModified());
|
|
180
235
|
|
|
181
236
|
const response = new LambdaHttpResponse(200, 'ok');
|
|
182
237
|
response.header(HttpHeader.ETag, cacheKey);
|
|
183
238
|
response.header(HttpHeader.CacheControl, 'no-store');
|
|
184
239
|
response.buffer(data, 'application/json');
|
|
185
240
|
req.set('bytes', data.byteLength);
|
|
186
|
-
return response;
|
|
241
|
+
return Promise.resolve(response);
|
|
187
242
|
}
|
|
188
243
|
|
|
189
244
|
export async function styleJsonGet(req: LambdaHttpRequest<StyleGet>): Promise<LambdaHttpResponse> {
|
|
@@ -193,6 +248,7 @@ export async function styleJsonGet(req: LambdaHttpRequest<StyleGet>): Promise<La
|
|
|
193
248
|
const excluded = new Set(excludeLayers.map((l) => l.toLowerCase()));
|
|
194
249
|
const tileMatrix = TileMatrixSets.find(req.query.get('tileMatrix') ?? GoogleTms.identifier);
|
|
195
250
|
if (tileMatrix == null) return new LambdaHttpResponse(400, 'Invalid tile matrix');
|
|
251
|
+
const terrain = req.query.get('terrain') ?? undefined;
|
|
196
252
|
|
|
197
253
|
// Get style Config from db
|
|
198
254
|
const config = await ConfigLoader.load(req);
|
|
@@ -203,8 +259,8 @@ export async function styleJsonGet(req: LambdaHttpRequest<StyleGet>): Promise<La
|
|
|
203
259
|
const tileSet = await config.TileSet.get(config.TileSet.id(styleName));
|
|
204
260
|
if (tileSet == null) return NotFound();
|
|
205
261
|
if (tileSet.type !== TileSetType.Raster) return NotFound();
|
|
206
|
-
if (tileSet.outputs) return tileSetOutputToStyle(req, tileSet, tileMatrix, apiKey);
|
|
207
|
-
else return tileSetToStyle(req, tileSet, tileMatrix, apiKey);
|
|
262
|
+
if (tileSet.outputs) return await tileSetOutputToStyle(req, tileSet, tileMatrix, apiKey, terrain);
|
|
263
|
+
else return await tileSetToStyle(req, tileSet, tileMatrix, apiKey, terrain);
|
|
208
264
|
}
|
|
209
265
|
|
|
210
266
|
// Prepare sources and add linz source
|
|
@@ -215,6 +271,14 @@ export async function styleJsonGet(req: LambdaHttpRequest<StyleGet>): Promise<La
|
|
|
215
271
|
ConfigLoader.extract(req),
|
|
216
272
|
styleConfig.style.layers.filter((f) => !excluded.has(f.id.toLowerCase())),
|
|
217
273
|
);
|
|
274
|
+
|
|
275
|
+
// Ensure elevation for style json config
|
|
276
|
+
// TODO: We should remove this after adding terrain source into style configs. PR-916
|
|
277
|
+
await ensureTerrain(req, tileMatrix, apiKey, style);
|
|
278
|
+
|
|
279
|
+
// Add terrain in style
|
|
280
|
+
if (terrain) setStyleTerrain(style, terrain);
|
|
281
|
+
|
|
218
282
|
const data = Buffer.from(JSON.stringify(style));
|
|
219
283
|
|
|
220
284
|
const cacheKey = Etag.key(data);
|
package/src/routes/tile.wmts.ts
CHANGED
|
@@ -69,6 +69,7 @@ export async function wmtsCapabilitiesGet(req: LambdaHttpRequest<WmtsCapabilitie
|
|
|
69
69
|
imagery,
|
|
70
70
|
formats: Validate.getRequestedFormats(req) ?? [],
|
|
71
71
|
layers: req.params.tileMatrix == null ? tileSet.layers : undefined,
|
|
72
|
+
pipeline: req.query.get('pipeline'),
|
|
72
73
|
});
|
|
73
74
|
|
|
74
75
|
const xml = wmts.toXml();
|
|
@@ -95,20 +95,22 @@ export const TileXyzRaster = {
|
|
|
95
95
|
toLoad.push(
|
|
96
96
|
LoadingQueue((): Promise<CloudArchive | null> => {
|
|
97
97
|
if (assetPath.pathname.endsWith('.tar.co')) {
|
|
98
|
-
return CoSources.getCotar(assetPath).catch((
|
|
99
|
-
req.log.warn({
|
|
98
|
+
return CoSources.getCotar(assetPath).catch((err: unknown) => {
|
|
99
|
+
req.log.warn({ err, tiff: assetPath }, 'Load:Cotar:Failed');
|
|
100
100
|
return null;
|
|
101
101
|
});
|
|
102
102
|
}
|
|
103
|
-
return CoSources.getCog(assetPath).catch((
|
|
104
|
-
req.log.warn({
|
|
103
|
+
return CoSources.getCog(assetPath).catch((err: unknown) => {
|
|
104
|
+
req.log.warn({ err, tiff: assetPath }, 'Load:Tiff:Failed');
|
|
105
105
|
return null;
|
|
106
106
|
});
|
|
107
107
|
}),
|
|
108
108
|
);
|
|
109
109
|
}
|
|
110
110
|
|
|
111
|
-
|
|
111
|
+
// Remove with typescript >=5.5.0
|
|
112
|
+
|
|
113
|
+
return (await Promise.all(toLoad)).filter((f) => f != null);
|
|
112
114
|
},
|
|
113
115
|
|
|
114
116
|
async getAssetsForTile(req: LambdaHttpRequest, tileSet: ConfigTileSetRaster, xyz: TileXyz): Promise<URL[]> {
|
|
@@ -128,7 +130,7 @@ export const TileXyzRaster = {
|
|
|
128
130
|
const assets = await TileXyzRaster.loadAssets(req, assetPaths);
|
|
129
131
|
|
|
130
132
|
const tiler = new Tiler(xyz.tileMatrix);
|
|
131
|
-
const layers =
|
|
133
|
+
const layers = tiler.tile(assets, xyz.tile.x, xyz.tile.y, xyz.tile.z);
|
|
132
134
|
|
|
133
135
|
const format = getImageFormat(xyz.tileType);
|
|
134
136
|
if (format == null) return new LambdaHttpResponse(400, 'Invalid image format: ' + xyz.tileType);
|
package/src/routes/version.ts
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
import { HttpHeader, LambdaHttpResponse } from '@linzjs/lambda';
|
|
2
2
|
|
|
3
|
-
export
|
|
3
|
+
export function versionGet(): Promise<LambdaHttpResponse> {
|
|
4
4
|
const response = new LambdaHttpResponse(200, 'ok');
|
|
5
5
|
response.header(HttpHeader.CacheControl, 'no-store');
|
|
6
6
|
response.json({
|
|
@@ -20,5 +20,5 @@ export async function versionGet(): Promise<LambdaHttpResponse> {
|
|
|
20
20
|
*/
|
|
21
21
|
buildId: process.env['BUILD_ID'],
|
|
22
22
|
});
|
|
23
|
-
return response;
|
|
23
|
+
return Promise.resolve(response);
|
|
24
24
|
}
|