@basemaps/lambda-tiler 6.16.0 → 6.19.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 +45 -0
- package/build/__test__/xyz.test.js +11 -11
- package/build/index.d.ts.map +1 -1
- package/build/index.js +8 -0
- package/build/routes/imagery.d.ts +8 -0
- package/build/routes/imagery.d.ts.map +1 -0
- package/build/routes/imagery.js +48 -0
- package/build/routes/tile.d.ts.map +1 -1
- package/build/routes/tile.js +6 -9
- package/dist/index.js +2375 -303
- package/dist/node_modules/color-string/index.js +2 -2
- package/dist/node_modules/color-string/package.json +5 -5
- package/dist/package-lock.json +4 -4
- package/dist/package.json +5 -5
- package/package.json +6 -6
- package/src/__test__/xyz.test.ts +11 -11
- package/src/index.ts +8 -0
- package/src/routes/imagery.ts +50 -0
- package/src/routes/tile.ts +6 -9
- package/tsconfig.tsbuildinfo +1 -1
package/CHANGELOG.md
CHANGED
|
@@ -3,6 +3,51 @@
|
|
|
3
3
|
All notable changes to this project will be documented in this file.
|
|
4
4
|
See [Conventional Commits](https://conventionalcommits.org) for commit guidelines.
|
|
5
5
|
|
|
6
|
+
# [6.19.0](https://github.com/linz/basemaps/compare/v6.18.1...v6.19.0) (2021-12-20)
|
|
7
|
+
|
|
8
|
+
|
|
9
|
+
### Bug Fixes
|
|
10
|
+
|
|
11
|
+
* **lambda-tiler:** remove the host check to add api keys for all stylejson sources. ([#2032](https://github.com/linz/basemaps/issues/2032)) ([beab64c](https://github.com/linz/basemaps/commit/beab64c7f747dd5c1be06877b05b1173a95b1537))
|
|
12
|
+
|
|
13
|
+
|
|
14
|
+
### Features
|
|
15
|
+
|
|
16
|
+
* **lambda-tiler:** compress geojson output to prevent overflowing lambda ([#2034](https://github.com/linz/basemaps/issues/2034)) ([5d48524](https://github.com/linz/basemaps/commit/5d48524c0bf03c40e85cd661fd7f609bbdeed3dd))
|
|
17
|
+
* **tiler:** expose some of the metadata geojson via a /v1/imagery endpoint ([#2033](https://github.com/linz/basemaps/issues/2033)) ([b471209](https://github.com/linz/basemaps/commit/b471209a381dfdab1a25be4882e464c8ddea9064))
|
|
18
|
+
|
|
19
|
+
|
|
20
|
+
|
|
21
|
+
|
|
22
|
+
|
|
23
|
+
# [6.18.0](https://github.com/linz/basemaps/compare/v6.17.0...v6.18.0) (2021-12-14)
|
|
24
|
+
|
|
25
|
+
**Note:** Version bump only for package @basemaps/lambda-tiler
|
|
26
|
+
|
|
27
|
+
|
|
28
|
+
|
|
29
|
+
|
|
30
|
+
|
|
31
|
+
# [6.17.0](https://github.com/linz/basemaps/compare/v6.16.1...v6.17.0) (2021-12-05)
|
|
32
|
+
|
|
33
|
+
|
|
34
|
+
### Features
|
|
35
|
+
|
|
36
|
+
* **lambda-tiler:** Stop caching for the stylejson. ([#2011](https://github.com/linz/basemaps/issues/2011)) ([f29ae16](https://github.com/linz/basemaps/commit/f29ae16cd0b858fd9929a8cbcefa1c5113687bc9))
|
|
37
|
+
* **landing:** use topographic name not topolike ([#2008](https://github.com/linz/basemaps/issues/2008)) ([a281d87](https://github.com/linz/basemaps/commit/a281d874ae8211447282ad41dd497e96689ceb88))
|
|
38
|
+
|
|
39
|
+
|
|
40
|
+
|
|
41
|
+
|
|
42
|
+
|
|
43
|
+
## [6.16.1](https://github.com/linz/basemaps/compare/v6.16.0...v6.16.1) (2021-11-30)
|
|
44
|
+
|
|
45
|
+
**Note:** Version bump only for package @basemaps/lambda-tiler
|
|
46
|
+
|
|
47
|
+
|
|
48
|
+
|
|
49
|
+
|
|
50
|
+
|
|
6
51
|
# [6.16.0](https://github.com/linz/basemaps/compare/v6.15.0...v6.16.0) (2021-11-29)
|
|
7
52
|
|
|
8
53
|
|
|
@@ -172,14 +172,14 @@ o.spec('LambdaXyz', () => {
|
|
|
172
172
|
o('should serve tile json for tile_set', async () => {
|
|
173
173
|
var _a;
|
|
174
174
|
process.env[Env.PublicUrlBase] = 'https://tiles.test';
|
|
175
|
-
const request = mockRequest('/v1/tiles/
|
|
175
|
+
const request = mockRequest('/v1/tiles/topographic/Google/tile.json', 'get', apiKeyHeader);
|
|
176
176
|
const res = await handleRequest(request);
|
|
177
177
|
o(res.status).equals(200);
|
|
178
178
|
o(res.header('content-type')).equals('application/json');
|
|
179
179
|
o(res.header('cache-control')).equals('max-age=120');
|
|
180
180
|
const body = Buffer.from((_a = res.body) !== null && _a !== void 0 ? _a : '', 'base64').toString();
|
|
181
181
|
o(JSON.parse(body)).deepEquals({
|
|
182
|
-
tiles: [`https://tiles.test/v1/tiles/
|
|
182
|
+
tiles: [`https://tiles.test/v1/tiles/topographic/Google/{z}/{x}/{y}.pbf?api=${apiKey}`],
|
|
183
183
|
minzoom: 0,
|
|
184
184
|
maxzoom: 15,
|
|
185
185
|
format: 'pbf',
|
|
@@ -194,7 +194,7 @@ o.spec('LambdaXyz', () => {
|
|
|
194
194
|
});
|
|
195
195
|
o('should not found style json', async () => {
|
|
196
196
|
process.env[Env.PublicUrlBase] = 'https://tiles.test';
|
|
197
|
-
const request = mockRequest('/v1/tiles/
|
|
197
|
+
const request = mockRequest('/v1/tiles/topographic/Google/style/topographic.json', 'get', apiKeyHeader);
|
|
198
198
|
sandbox.stub(Config.Style, 'get').resolves(null);
|
|
199
199
|
const res = await handleRequest(request);
|
|
200
200
|
o(res.status).equals(404);
|
|
@@ -203,23 +203,23 @@ o.spec('LambdaXyz', () => {
|
|
|
203
203
|
var _a;
|
|
204
204
|
const host = 'https://tiles.test';
|
|
205
205
|
process.env[Env.PublicUrlBase] = host;
|
|
206
|
-
const request = mockRequest('/v1/tiles/
|
|
206
|
+
const request = mockRequest('/v1/tiles/topographic/Google/style/topographic.json', 'get', apiKeyHeader);
|
|
207
207
|
const fakeStyle = {
|
|
208
208
|
version: 8,
|
|
209
209
|
id: 'test',
|
|
210
|
-
name: '
|
|
210
|
+
name: 'topographic',
|
|
211
211
|
sources: {
|
|
212
212
|
basemaps_vector: {
|
|
213
213
|
type: 'vector',
|
|
214
|
-
url:
|
|
214
|
+
url: `/vector`,
|
|
215
215
|
},
|
|
216
216
|
basemaps_raster: {
|
|
217
217
|
type: 'raster',
|
|
218
|
-
tiles: [
|
|
218
|
+
tiles: [`/raster`],
|
|
219
219
|
},
|
|
220
220
|
basemaps_raster_encode: {
|
|
221
221
|
type: 'raster',
|
|
222
|
-
tiles: [
|
|
222
|
+
tiles: [`/raster/{z}/{x}/{y}.webp`], // Shouldn't encode the {}
|
|
223
223
|
},
|
|
224
224
|
test_vector: {
|
|
225
225
|
type: 'vector',
|
|
@@ -248,15 +248,15 @@ o.spec('LambdaXyz', () => {
|
|
|
248
248
|
metadata: { id: 'test' },
|
|
249
249
|
};
|
|
250
250
|
const fakeRecord = {
|
|
251
|
-
id: '
|
|
252
|
-
name: '
|
|
251
|
+
id: 'st_topographic_production',
|
|
252
|
+
name: 'topographic',
|
|
253
253
|
style: fakeStyle,
|
|
254
254
|
};
|
|
255
255
|
sandbox.stub(Config.Style, 'get').resolves(fakeRecord);
|
|
256
256
|
const res = await handleRequest(request);
|
|
257
257
|
o(res.status).equals(200);
|
|
258
258
|
o(res.header('content-type')).equals('application/json');
|
|
259
|
-
o(res.header('cache-control')).equals('
|
|
259
|
+
o(res.header('cache-control')).equals('no-store');
|
|
260
260
|
const body = Buffer.from((_a = res.body) !== null && _a !== void 0 ? _a : '', 'base64').toString();
|
|
261
261
|
fakeStyle.sources.basemaps_vector = {
|
|
262
262
|
type: 'vector',
|
package/build/index.d.ts.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"AAAA,OAAO,EAAM,iBAAiB,EAAE,kBAAkB,EAAE,MAAM,gBAAgB,CAAC;
|
|
1
|
+
{"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"AAAA,OAAO,EAAM,iBAAiB,EAAE,kBAAkB,EAAE,MAAM,gBAAgB,CAAC;AAkB3E,wBAAsB,aAAa,CAAC,GAAG,EAAE,iBAAiB,GAAG,OAAO,CAAC,kBAAkB,CAAC,CAkBvF;AAED,eAAO,MAAM,OAAO,2LAA0C,CAAC"}
|
package/build/index.js
CHANGED
|
@@ -4,11 +4,14 @@ import { Ping, Version } from './routes/api.js';
|
|
|
4
4
|
import { Health } from './routes/health.js';
|
|
5
5
|
import { Tiles } from './routes/tile.js';
|
|
6
6
|
import { Router } from './router.js';
|
|
7
|
+
import { createHash } from 'crypto';
|
|
8
|
+
import { Imagery } from './routes/imagery.js';
|
|
7
9
|
const app = new Router();
|
|
8
10
|
app.get('ping', Ping);
|
|
9
11
|
app.get('health', Health);
|
|
10
12
|
app.get('version', Version);
|
|
11
13
|
app.get('tiles', Tiles);
|
|
14
|
+
app.get('imagery', Imagery);
|
|
12
15
|
let slowTimer = null;
|
|
13
16
|
export async function handleRequest(req) {
|
|
14
17
|
// Warn if a request takes more than 10 seconds to process
|
|
@@ -18,6 +21,11 @@ export async function handleRequest(req) {
|
|
|
18
21
|
slowTimer.unref();
|
|
19
22
|
req.set('name', 'LambdaTiler');
|
|
20
23
|
try {
|
|
24
|
+
const apiKey = Router.apiKey(req);
|
|
25
|
+
if (apiKey != null) {
|
|
26
|
+
const apiKeyHash = createHash('sha256').update(apiKey).digest('base64');
|
|
27
|
+
req.set('api', apiKeyHash);
|
|
28
|
+
}
|
|
21
29
|
return await app.handle(req);
|
|
22
30
|
}
|
|
23
31
|
finally {
|
|
@@ -0,0 +1,8 @@
|
|
|
1
|
+
import { LambdaHttpRequest, LambdaHttpResponse } from '@linzjs/lambda';
|
|
2
|
+
/**
|
|
3
|
+
* Get metadata around the imagery such as the source bounding box or the bounding box of the COGS
|
|
4
|
+
* - /v1/imagery/:imageryId/source.geojson
|
|
5
|
+
* - /v1/imagery/:imageryId/covering.geojson
|
|
6
|
+
*/
|
|
7
|
+
export declare function Imagery(req: LambdaHttpRequest): Promise<LambdaHttpResponse>;
|
|
8
|
+
//# sourceMappingURL=imagery.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"imagery.d.ts","sourceRoot":"","sources":["../../src/routes/imagery.ts"],"names":[],"mappings":"AAEA,OAAO,EAAc,iBAAiB,EAAE,kBAAkB,EAAE,MAAM,gBAAgB,CAAC;AAgBnF;;;;GAIG;AACH,wBAAsB,OAAO,CAAC,GAAG,EAAE,iBAAiB,GAAG,OAAO,CAAC,kBAAkB,CAAC,CA0BjF"}
|
|
@@ -0,0 +1,48 @@
|
|
|
1
|
+
import { Config } from '@basemaps/config';
|
|
2
|
+
import { fsa } from '@basemaps/shared';
|
|
3
|
+
import { HttpHeader, LambdaHttpResponse } from '@linzjs/lambda';
|
|
4
|
+
import { createHash } from 'crypto';
|
|
5
|
+
import { promisify } from 'util';
|
|
6
|
+
import { gzip } from 'zlib';
|
|
7
|
+
import { Router } from '../router.js';
|
|
8
|
+
import { TileEtag } from './tile.etag.js';
|
|
9
|
+
import { NotModified } from './tile.js';
|
|
10
|
+
const gzipP = promisify(gzip);
|
|
11
|
+
function isAllowedFile(f) {
|
|
12
|
+
if (f.endsWith('.geojson'))
|
|
13
|
+
return true;
|
|
14
|
+
if (f.endsWith('.json'))
|
|
15
|
+
return true;
|
|
16
|
+
return false;
|
|
17
|
+
}
|
|
18
|
+
/**
|
|
19
|
+
* Get metadata around the imagery such as the source bounding box or the bounding box of the COGS
|
|
20
|
+
* - /v1/imagery/:imageryId/source.geojson
|
|
21
|
+
* - /v1/imagery/:imageryId/covering.geojson
|
|
22
|
+
*/
|
|
23
|
+
export async function Imagery(req) {
|
|
24
|
+
const { rest } = Router.action(req);
|
|
25
|
+
const [imageryId, requestType] = rest;
|
|
26
|
+
if (!isAllowedFile(requestType))
|
|
27
|
+
return new LambdaHttpResponse(404, 'Not found');
|
|
28
|
+
const imagery = await Config.Imagery.get(imageryId);
|
|
29
|
+
if (imagery == null)
|
|
30
|
+
return new LambdaHttpResponse(404, 'Not found');
|
|
31
|
+
const targetPath = fsa.join(imagery.uri, requestType);
|
|
32
|
+
try {
|
|
33
|
+
const buf = await fsa.read(targetPath);
|
|
34
|
+
const cacheKey = createHash('sha256').update(buf).digest('base64');
|
|
35
|
+
if (TileEtag.isNotModified(req, cacheKey))
|
|
36
|
+
return NotModified;
|
|
37
|
+
const response = new LambdaHttpResponse(200, 'ok');
|
|
38
|
+
response.header(HttpHeader.ETag, cacheKey);
|
|
39
|
+
response.header(HttpHeader.ContentEncoding, 'gzip');
|
|
40
|
+
response.buffer(await gzipP(buf), 'application/json');
|
|
41
|
+
req.set('bytes', buf.byteLength);
|
|
42
|
+
return response;
|
|
43
|
+
}
|
|
44
|
+
catch (e) {
|
|
45
|
+
req.log.warn({ targetPath }, 'ImageryMetadata:Failed');
|
|
46
|
+
return new LambdaHttpResponse(404, 'Not found');
|
|
47
|
+
}
|
|
48
|
+
}
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"tile.d.ts","sourceRoot":"","sources":["../../src/routes/tile.ts"],"names":[],"mappings":"AACA,OAAO,EAAE,aAAa,EAAE,MAAM,eAAe,CAAC;AAC9C,OAAO,EAAc,iBAAiB,EAAE,kBAAkB,EAAE,MAAM,gBAAgB,CAAC;AAEnF,OAAO,EAAE,cAAc,EAAE,MAAM,uBAAuB,CAAC;AAIvD,OAAO,EAAE,aAAa,EAAE,MAAM,uBAAuB,CAAC;
|
|
1
|
+
{"version":3,"file":"tile.d.ts","sourceRoot":"","sources":["../../src/routes/tile.ts"],"names":[],"mappings":"AACA,OAAO,EAAE,aAAa,EAAE,MAAM,eAAe,CAAC;AAC9C,OAAO,EAAc,iBAAiB,EAAE,kBAAkB,EAAE,MAAM,gBAAgB,CAAC;AAEnF,OAAO,EAAE,cAAc,EAAE,MAAM,uBAAuB,CAAC;AAIvD,OAAO,EAAE,aAAa,EAAE,MAAM,uBAAuB,CAAC;AAStD,eAAO,MAAM,YAAY,gBAA0B,CAAC;AAEpD,eAAO,MAAM,QAAQ,oBAA2C,CAAC;AACjE,eAAO,MAAM,WAAW,oBAA8C,CAAC;AAEvE,MAAM,WAAW,QAAQ;IACvB,KAAK,EAAE,MAAM,EAAE,CAAC;IAChB,OAAO,EAAE,MAAM,CAAC;IAChB,OAAO,EAAE,MAAM,CAAC;IAChB,MAAM,EAAE,MAAM,CAAC;IACf,QAAQ,EAAE,MAAM,CAAC;CAClB;AAED,eAAO,MAAM,SAAS;cACJ,iBAAiB,GAAG,QAAQ,kBAAkB,CAAC;2BAelC,MAAM,cAAc,aAAa,GAAG,IAAI,GAAG,QAAQ,aAAa,EAAE,CAAC;cAUhF,iBAAiB,GAAG,QAAQ,kBAAkB,CAAC;kBAiC3C,iBAAiB,GAAG,QAAQ,kBAAkB,CAAC;mBA8B9C,iBAAiB,YAAY,MAAM,GAAG,QAAQ,kBAAkB,CAAC;CA8DvF,CAAC;AACF,wBAAsB,KAAK,CAAC,GAAG,EAAE,iBAAiB,GAAG,OAAO,CAAC,kBAAkB,CAAC,CAY/E"}
|
package/build/routes/tile.js
CHANGED
|
@@ -10,6 +10,7 @@ import { TileEtag } from './tile.etag.js';
|
|
|
10
10
|
import { Router } from '../router.js';
|
|
11
11
|
import { ValidateTilePath } from '../validate.js';
|
|
12
12
|
import { URL } from 'url';
|
|
13
|
+
import { fsa } from '@chunkd/fs';
|
|
13
14
|
export const TileComposer = new TileMakerSharp(256);
|
|
14
15
|
export const NotFound = new LambdaHttpResponse(404, 'Not Found');
|
|
15
16
|
export const NotModified = new LambdaHttpResponse(304, 'Not modified');
|
|
@@ -113,8 +114,8 @@ export const TileRoute = {
|
|
|
113
114
|
const sources = {};
|
|
114
115
|
for (const [key, value] of Object.entries(style.sources)) {
|
|
115
116
|
if (value.type === 'vector') {
|
|
116
|
-
if (value.url.
|
|
117
|
-
const url = new URL(value.url);
|
|
117
|
+
if (value.url.startsWith('/')) {
|
|
118
|
+
const url = new URL(fsa.join(host, value.url));
|
|
118
119
|
url.searchParams.set('api', apiKey);
|
|
119
120
|
value.url = url.toString().replace(/%7B/g, '{').replace(/%7D/g, '}');
|
|
120
121
|
}
|
|
@@ -122,8 +123,8 @@ export const TileRoute = {
|
|
|
122
123
|
else if (value.type === 'raster' && Array.isArray(value.tiles)) {
|
|
123
124
|
for (let i = 0; i < value.tiles.length; i++) {
|
|
124
125
|
const tile = value.tiles[i];
|
|
125
|
-
if (tile.
|
|
126
|
-
const url = new URL(tile);
|
|
126
|
+
if (tile.startsWith('/')) {
|
|
127
|
+
const url = new URL(fsa.join(host, tile));
|
|
127
128
|
url.searchParams.set('api', apiKey);
|
|
128
129
|
value.tiles[i] = url.toString().replace(/%7B/g, '{').replace(/%7D/g, '}');
|
|
129
130
|
}
|
|
@@ -150,7 +151,7 @@ export const TileRoute = {
|
|
|
150
151
|
return NotModified;
|
|
151
152
|
const response = new LambdaHttpResponse(200, 'ok');
|
|
152
153
|
response.header(HttpHeader.ETag, cacheKey);
|
|
153
|
-
response.header(HttpHeader.CacheControl, '
|
|
154
|
+
response.header(HttpHeader.CacheControl, 'no-store');
|
|
154
155
|
response.buffer(data, 'application/json');
|
|
155
156
|
req.set('bytes', data.byteLength);
|
|
156
157
|
return response;
|
|
@@ -161,10 +162,6 @@ export async function Tiles(req) {
|
|
|
161
162
|
if (rest.length < 1)
|
|
162
163
|
return NotFound;
|
|
163
164
|
const apiKey = Router.apiKey(req);
|
|
164
|
-
const apiKeyHash = createHash('sha256')
|
|
165
|
-
.update(apiKey !== null && apiKey !== void 0 ? apiKey : '')
|
|
166
|
-
.digest('base64');
|
|
167
|
-
req.set('api', apiKeyHash);
|
|
168
165
|
if (!isValidApiKey(apiKey))
|
|
169
166
|
return new LambdaHttpResponse(400, 'Invalid API Key');
|
|
170
167
|
const fileName = rest[rest.length - 1].toLowerCase();
|