@basemaps/lambda-tiler 8.2.0 → 8.5.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.
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@basemaps/lambda-tiler",
3
- "version": "8.2.0",
3
+ "version": "8.5.0",
4
4
  "lockfileVersion": 3,
5
5
  "requires": true,
6
6
  "packages": {
@@ -1,12 +1,12 @@
1
1
  {
2
2
  "name": "@basemaps/lambda-tiler",
3
- "version": "8.2.0",
3
+ "version": "8.5.0",
4
4
  "lockfileVersion": 3,
5
5
  "requires": true,
6
6
  "packages": {
7
7
  "": {
8
8
  "name": "@basemaps/lambda-tiler",
9
- "version": "8.2.0",
9
+ "version": "8.5.0",
10
10
  "license": "MIT",
11
11
  "dependencies": {
12
12
  "lerc": "4.0.4",
package/dist/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@basemaps/lambda-tiler",
3
- "version": "8.2.0",
3
+ "version": "8.5.0",
4
4
  "repository": {
5
5
  "type": "git",
6
6
  "url": "https://github.com/linz/basemaps.git",
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@basemaps/lambda-tiler",
3
- "version": "8.2.0",
3
+ "version": "8.5.0",
4
4
  "repository": {
5
5
  "type": "git",
6
6
  "url": "https://github.com/linz/basemaps.git",
@@ -22,12 +22,12 @@
22
22
  "types": "./build/index.d.ts",
23
23
  "license": "MIT",
24
24
  "dependencies": {
25
- "@basemaps/config": "^8.1.0",
26
- "@basemaps/config-loader": "^8.2.0",
27
- "@basemaps/geo": "^8.0.0",
28
- "@basemaps/shared": "^8.2.0",
29
- "@basemaps/tiler": "^8.0.0",
30
- "@basemaps/tiler-sharp": "^8.1.0",
25
+ "@basemaps/config": "^8.3.0",
26
+ "@basemaps/config-loader": "^8.5.0",
27
+ "@basemaps/geo": "^8.3.0",
28
+ "@basemaps/shared": "^8.5.0",
29
+ "@basemaps/tiler": "^8.3.0",
30
+ "@basemaps/tiler-sharp": "^8.3.0",
31
31
  "@linzjs/geojson": "^8.0.0",
32
32
  "@linzjs/lambda": "^4.0.0",
33
33
  "@mapbox/vector-tile": "^2.0.3",
@@ -50,11 +50,11 @@
50
50
  "bundle": "./bundle.sh"
51
51
  },
52
52
  "devDependencies": {
53
- "@basemaps/attribution": "^8.0.0",
53
+ "@basemaps/attribution": "^8.3.0",
54
54
  "@chunkd/fs": "^11.2.0",
55
55
  "@types/aws-lambda": "^8.10.75",
56
56
  "@types/pixelmatch": "^5.0.0",
57
57
  "pretty-json-log": "^1.0.0"
58
58
  },
59
- "gitHead": "69195be692efa914369fa854d3bae16355dc0dc8"
59
+ "gitHead": "4f6f3929b9117c3e112f7d156ab185cb98821796"
60
60
  }
package/src/index.ts CHANGED
@@ -3,6 +3,7 @@ import { LambdaHttpRequest, LambdaHttpResponse, lf } from '@linzjs/lambda';
3
3
 
4
4
  import { tileAttributionGet } from './routes/attribution.js';
5
5
  import { configImageryGet, configTileSetGet } from './routes/config.js';
6
+ import { exportTileSetGet } from './routes/export.tileset.js';
6
7
  import { fontGet, fontList } from './routes/fonts.js';
7
8
  import { healthGet } from './routes/health.js';
8
9
  import { imageryGet } from './routes/imagery.js';
@@ -116,3 +117,5 @@ handler.router.get('/v1/attribution/:tileSet/:tileMatrix/summary.json', tileAttr
116
117
  handler.router.get('/v1/tiles/:tileSet/:tileMatrix/WMTSCapabilities.xml', wmtsCapabilitiesGet);
117
118
  handler.router.get('/v1/tiles/:tileSet/WMTSCapabilities.xml', wmtsCapabilitiesGet);
118
119
  handler.router.get('/v1/tiles/WMTSCapabilities.xml', wmtsCapabilitiesGet);
120
+
121
+ handler.router.get('/v1/export/:tileSet/:tileMatrix.:extension', exportTileSetGet);
@@ -0,0 +1,55 @@
1
+ import { afterEach, beforeEach, describe, it } from 'node:test';
2
+
3
+ import { ConfigProviderMemory } from '@basemaps/config';
4
+ import { fsa, FsMemory, LogConfig, s3Config } from '@basemaps/shared';
5
+ import assert from 'assert';
6
+
7
+ import { FakeData } from '../../__tests__/config.data.js';
8
+ import { Api, mockUrlRequest } from '../../__tests__/xyz.util.js';
9
+ import { handler } from '../../index.js';
10
+ import { ConfigLoader } from '../../util/config.loader.js';
11
+
12
+ describe('tileset.export', () => {
13
+ const config = new ConfigProviderMemory();
14
+
15
+ beforeEach(() => {
16
+ LogConfig.get().level = 'silent';
17
+ fsa.register('s3://fake-memory/', new FsMemory());
18
+ });
19
+
20
+ afterEach(() => {
21
+ config.objects.clear();
22
+ });
23
+
24
+ it('should create presigned url', async (t) => {
25
+ t.mock.method(ConfigLoader, 'getDefaultConfig', () => Promise.resolve(config));
26
+
27
+ t.mock.method(s3Config, 'getSignedUrl', () => Promise.resolve('https://fake-s3-url.com/tileset.mbtiles'));
28
+
29
+ const topographic = FakeData.tileSetVector('topographic');
30
+ topographic.layers[0][2193] = 's3://fake-memory/fake-tiles.tar.co';
31
+ config.put(topographic);
32
+
33
+ await fsa.write(fsa.toUrl('s3://fake-memory/fake-tiles.mbtiles'), Buffer.from('ABC123'));
34
+
35
+ const res = await handler.router.handle(
36
+ mockUrlRequest('/v1/export/topographic/NZTM2000Quad.mbtiles', 'get', Api.header),
37
+ );
38
+ assert.equal(res.status, 302); // Temporary redirect
39
+ assert.equal(res.headers.get('location'), 'https://fake-s3-url.com/tileset.mbtiles');
40
+ });
41
+
42
+ it('should fail if mbtiles do not exist', async (t) => {
43
+ t.mock.method(ConfigLoader, 'getDefaultConfig', () => Promise.resolve(config));
44
+ t.mock.method(s3Config, 'getSignedUrl', () => Promise.resolve('https://fake-s3-url.com/tileset.mbtiles'));
45
+
46
+ const topographic = FakeData.tileSetVector('topographic');
47
+ topographic.layers[0][2193] = 's3://fake-memory/fake-tiles.tar.co';
48
+ config.put(topographic);
49
+
50
+ const res = await handler.router.handle(
51
+ mockUrlRequest('/v1/export/topographic/NZTM2000Quad.mbtiles', 'get', Api.header),
52
+ );
53
+ assert.equal(res.status, 404);
54
+ });
55
+ });
@@ -0,0 +1,61 @@
1
+ import { signS3Get } from '@basemaps/shared';
2
+ import { fsa } from '@chunkd/fs';
3
+ import { LambdaHttpRequest, LambdaHttpResponse } from '@linzjs/lambda';
4
+
5
+ import { ConfigLoader } from '../util/config.loader.js';
6
+ import { NotFound } from '../util/response.js';
7
+ import { Validate } from '../util/validate.js';
8
+
9
+ export interface TileSetExportGet {
10
+ Params: {
11
+ tileSet: string;
12
+ tileMatrix: string;
13
+ };
14
+ }
15
+
16
+ /**
17
+ * Export an MBTiles file
18
+ *
19
+ * /v1/export/:tileSet/:tileMatrixSet
20
+ *
21
+ * @example
22
+ * Vector Tileset `/v1/export/topographic/WebMercatorQuad.mbtiles`
23
+ *
24
+ */
25
+ export async function exportTileSetGet(req: LambdaHttpRequest<TileSetExportGet>): Promise<LambdaHttpResponse> {
26
+ Validate.apiKey(req);
27
+
28
+ req.set('tileSet', req.params.tileSet);
29
+
30
+ const tileMatrix = Validate.getTileMatrixSet(req.params.tileMatrix);
31
+ if (tileMatrix == null) throw new LambdaHttpResponse(404, 'Tile Matrix not found');
32
+
33
+ req.set('tileMatrix', tileMatrix.identifier);
34
+ req.set('projection', tileMatrix.projection.code);
35
+ const config = await ConfigLoader.load(req);
36
+
37
+ req.timer.start('tileset:load');
38
+ const tileSet = await config.TileSet.get(config.TileSet.id(req.params.tileSet));
39
+ req.timer.end('tileset:load');
40
+ if (tileSet == null) return NotFound();
41
+
42
+ // Vector tiles cannot be merged (yet!)
43
+ if (tileSet.layers.length > 1) {
44
+ return new LambdaHttpResponse(500, `Too many layers in vector tileset ${tileSet.layers.length}`);
45
+ }
46
+
47
+ const epsgCode = tileMatrix.projection.code;
48
+ const layerId = tileSet.layers[0][epsgCode];
49
+ if (layerId == null) return new LambdaHttpResponse(404, `No data found for tile matrix: ${tileMatrix.identifier}`);
50
+
51
+ if (!layerId.startsWith('s3://')) return new LambdaHttpResponse(400, `Unable to export tilesets not inside of S3`);
52
+ if (!layerId.endsWith('.tar.co')) return new LambdaHttpResponse(400, `Unable to export tileset`);
53
+
54
+ const target = new URL(layerId.replace('.tar.co', '.mbtiles'));
55
+ const exists = await fsa.exists(target);
56
+ if (!exists) return NotFound();
57
+
58
+ const presignedUrl = await signS3Get(target);
59
+
60
+ return new LambdaHttpResponse(302, 'Moved', { location: presignedUrl });
61
+ }