@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
|
@@ -137,7 +137,7 @@ cs.get.hsl = function (string) {
|
|
|
137
137
|
return null;
|
|
138
138
|
}
|
|
139
139
|
|
|
140
|
-
var hsl = /^hsla?\(\s*([+-]?(?:\d{0,3}\.)?\d+)(?:deg)?\s*,?\s*([+-]?[\d\.]+)%\s*,?\s*([+-]?[\d\.]+)%\s*(?:[,|\/]\s*([+-]?[\d
|
|
140
|
+
var hsl = /^hsla?\(\s*([+-]?(?:\d{0,3}\.)?\d+)(?:deg)?\s*,?\s*([+-]?[\d\.]+)%\s*,?\s*([+-]?[\d\.]+)%\s*(?:[,|\/]\s*([+-]?(?=\.\d|\d)(?:0|[1-9]\d*)?(?:\.\d*)?(?:[eE][+-]?\d+)?)\s*)?\)$/;
|
|
141
141
|
var match = string.match(hsl);
|
|
142
142
|
|
|
143
143
|
if (match) {
|
|
@@ -158,7 +158,7 @@ cs.get.hwb = function (string) {
|
|
|
158
158
|
return null;
|
|
159
159
|
}
|
|
160
160
|
|
|
161
|
-
var hwb = /^hwb\(\s*([+-]?\d{0,3}(?:\.\d+)?)(?:deg)?\s*,\s*([+-]?[\d\.]+)%\s*,\s*([+-]?[\d\.]+)%\s*(?:,\s*([+-]?[\d
|
|
161
|
+
var hwb = /^hwb\(\s*([+-]?\d{0,3}(?:\.\d+)?)(?:deg)?\s*,\s*([+-]?[\d\.]+)%\s*,\s*([+-]?[\d\.]+)%\s*(?:,\s*([+-]?(?=\.\d|\d)(?:0|[1-9]\d*)?(?:\.\d*)?(?:[eE][+-]?\d+)?)\s*)?\)$/;
|
|
162
162
|
var match = string.match(hwb);
|
|
163
163
|
|
|
164
164
|
if (match) {
|
|
@@ -1,8 +1,8 @@
|
|
|
1
1
|
{
|
|
2
2
|
"_from": "color-string@^1.6.0",
|
|
3
|
-
"_id": "color-string@1.
|
|
3
|
+
"_id": "color-string@1.9.0",
|
|
4
4
|
"_inBundle": false,
|
|
5
|
-
"_integrity": "sha512-
|
|
5
|
+
"_integrity": "sha512-9Mrz2AQLefkH1UvASKj6v6hj/7eWgjnT/cVsR8CumieLoT+g900exWeNogqtweI8dxloXN9BDQTYro1oWu/5CQ==",
|
|
6
6
|
"_location": "/color-string",
|
|
7
7
|
"_phantomChildren": {},
|
|
8
8
|
"_requested": {
|
|
@@ -18,8 +18,8 @@
|
|
|
18
18
|
"_requiredBy": [
|
|
19
19
|
"/color"
|
|
20
20
|
],
|
|
21
|
-
"_resolved": "https://registry.npmjs.org/color-string/-/color-string-1.
|
|
22
|
-
"_shasum": "
|
|
21
|
+
"_resolved": "https://registry.npmjs.org/color-string/-/color-string-1.9.0.tgz",
|
|
22
|
+
"_shasum": "63b6ebd1bec11999d1df3a79a7569451ac2be8aa",
|
|
23
23
|
"_spec": "color-string@^1.6.0",
|
|
24
24
|
"_where": "/home/runner/work/basemaps/basemaps/packages/lambda-tiler/dist/node_modules/color",
|
|
25
25
|
"author": {
|
|
@@ -71,7 +71,7 @@
|
|
|
71
71
|
"pretest": "xo",
|
|
72
72
|
"test": "node test/basic.js"
|
|
73
73
|
},
|
|
74
|
-
"version": "1.
|
|
74
|
+
"version": "1.9.0",
|
|
75
75
|
"xo": {
|
|
76
76
|
"rules": {
|
|
77
77
|
"no-cond-assign": 0,
|
package/dist/package-lock.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@basemaps/lambda-tiler",
|
|
3
|
-
"version": "6.
|
|
3
|
+
"version": "6.19.0",
|
|
4
4
|
"lockfileVersion": 1,
|
|
5
5
|
"requires": true,
|
|
6
6
|
"dependencies": {
|
|
@@ -92,9 +92,9 @@
|
|
|
92
92
|
"integrity": "sha1-p9BVi9icQveV3UIyj3QIMcpTvCU="
|
|
93
93
|
},
|
|
94
94
|
"color-string": {
|
|
95
|
-
"version": "1.
|
|
96
|
-
"resolved": "https://registry.npmjs.org/color-string/-/color-string-1.
|
|
97
|
-
"integrity": "sha512-
|
|
95
|
+
"version": "1.9.0",
|
|
96
|
+
"resolved": "https://registry.npmjs.org/color-string/-/color-string-1.9.0.tgz",
|
|
97
|
+
"integrity": "sha512-9Mrz2AQLefkH1UvASKj6v6hj/7eWgjnT/cVsR8CumieLoT+g900exWeNogqtweI8dxloXN9BDQTYro1oWu/5CQ==",
|
|
98
98
|
"requires": {
|
|
99
99
|
"color-name": "^1.0.0",
|
|
100
100
|
"simple-swizzle": "^0.2.2"
|
package/dist/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@basemaps/lambda-tiler",
|
|
3
|
-
"version": "6.
|
|
3
|
+
"version": "6.19.0",
|
|
4
4
|
"repository": {
|
|
5
5
|
"type": "git",
|
|
6
6
|
"url": "https://github.com/linz/basemaps.git",
|
|
@@ -21,12 +21,12 @@
|
|
|
21
21
|
"types": "./build/index.d.ts",
|
|
22
22
|
"license": "MIT",
|
|
23
23
|
"dependencies": {
|
|
24
|
-
"@basemaps/config": "^6.
|
|
24
|
+
"@basemaps/config": "^6.18.0",
|
|
25
25
|
"@basemaps/geo": "^6.10.0",
|
|
26
26
|
"@basemaps/lambda": "^6.7.0",
|
|
27
|
-
"@basemaps/shared": "^6.
|
|
27
|
+
"@basemaps/shared": "^6.18.0",
|
|
28
28
|
"@basemaps/tiler": "^6.11.0",
|
|
29
|
-
"@basemaps/tiler-sharp": "^6.
|
|
29
|
+
"@basemaps/tiler-sharp": "^6.16.1",
|
|
30
30
|
"@chunkd/fs": "^7.3.1",
|
|
31
31
|
"@cogeotiff/core": "^6.0.2",
|
|
32
32
|
"@cotar/core": "^5.0.1",
|
|
@@ -51,7 +51,7 @@
|
|
|
51
51
|
"bundle": "./bundle.sh"
|
|
52
52
|
},
|
|
53
53
|
"devDependencies": {
|
|
54
|
-
"@basemaps/attribution": "^6.
|
|
54
|
+
"@basemaps/attribution": "^6.17.0",
|
|
55
55
|
"@types/aws-lambda": "^8.10.75",
|
|
56
56
|
"@types/express": "^4.17.11",
|
|
57
57
|
"@types/node": "^14.11.2",
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@basemaps/lambda-tiler",
|
|
3
|
-
"version": "6.
|
|
3
|
+
"version": "6.19.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": "^6.
|
|
25
|
+
"@basemaps/config": "^6.18.0",
|
|
26
26
|
"@basemaps/geo": "^6.10.0",
|
|
27
27
|
"@basemaps/lambda": "^6.7.0",
|
|
28
|
-
"@basemaps/shared": "^6.
|
|
28
|
+
"@basemaps/shared": "^6.18.0",
|
|
29
29
|
"@basemaps/tiler": "^6.11.0",
|
|
30
|
-
"@basemaps/tiler-sharp": "^6.
|
|
30
|
+
"@basemaps/tiler-sharp": "^6.16.1",
|
|
31
31
|
"@chunkd/fs": "^7.3.1",
|
|
32
32
|
"@cogeotiff/core": "^6.0.2",
|
|
33
33
|
"@cotar/core": "^5.0.1",
|
|
@@ -52,7 +52,7 @@
|
|
|
52
52
|
"bundle": "./bundle.sh"
|
|
53
53
|
},
|
|
54
54
|
"devDependencies": {
|
|
55
|
-
"@basemaps/attribution": "^6.
|
|
55
|
+
"@basemaps/attribution": "^6.17.0",
|
|
56
56
|
"@types/aws-lambda": "^8.10.75",
|
|
57
57
|
"@types/express": "^4.17.11",
|
|
58
58
|
"@types/node": "^14.11.2",
|
|
@@ -61,5 +61,5 @@
|
|
|
61
61
|
"express": "^4.17.1",
|
|
62
62
|
"pretty-json-log": "^1.0.0"
|
|
63
63
|
},
|
|
64
|
-
"gitHead": "
|
|
64
|
+
"gitHead": "87d778480368585d0f4a5a7546a2858882d8ab39"
|
|
65
65
|
}
|
package/src/__test__/xyz.test.ts
CHANGED
|
@@ -209,7 +209,7 @@ o.spec('LambdaXyz', () => {
|
|
|
209
209
|
o('should serve tile json for tile_set', async () => {
|
|
210
210
|
process.env[Env.PublicUrlBase] = 'https://tiles.test';
|
|
211
211
|
|
|
212
|
-
const request = mockRequest('/v1/tiles/
|
|
212
|
+
const request = mockRequest('/v1/tiles/topographic/Google/tile.json', 'get', apiKeyHeader);
|
|
213
213
|
|
|
214
214
|
const res = await handleRequest(request);
|
|
215
215
|
o(res.status).equals(200);
|
|
@@ -218,7 +218,7 @@ o.spec('LambdaXyz', () => {
|
|
|
218
218
|
|
|
219
219
|
const body = Buffer.from(res.body ?? '', 'base64').toString();
|
|
220
220
|
o(JSON.parse(body)).deepEquals({
|
|
221
|
-
tiles: [`https://tiles.test/v1/tiles/
|
|
221
|
+
tiles: [`https://tiles.test/v1/tiles/topographic/Google/{z}/{x}/{y}.pbf?api=${apiKey}`],
|
|
222
222
|
minzoom: 0,
|
|
223
223
|
maxzoom: 15,
|
|
224
224
|
format: 'pbf',
|
|
@@ -236,7 +236,7 @@ o.spec('LambdaXyz', () => {
|
|
|
236
236
|
o('should not found style json', async () => {
|
|
237
237
|
process.env[Env.PublicUrlBase] = 'https://tiles.test';
|
|
238
238
|
|
|
239
|
-
const request = mockRequest('/v1/tiles/
|
|
239
|
+
const request = mockRequest('/v1/tiles/topographic/Google/style/topographic.json', 'get', apiKeyHeader);
|
|
240
240
|
|
|
241
241
|
sandbox.stub(Config.Style, 'get').resolves(null);
|
|
242
242
|
|
|
@@ -248,24 +248,24 @@ o.spec('LambdaXyz', () => {
|
|
|
248
248
|
const host = 'https://tiles.test';
|
|
249
249
|
process.env[Env.PublicUrlBase] = host;
|
|
250
250
|
|
|
251
|
-
const request = mockRequest('/v1/tiles/
|
|
251
|
+
const request = mockRequest('/v1/tiles/topographic/Google/style/topographic.json', 'get', apiKeyHeader);
|
|
252
252
|
|
|
253
253
|
const fakeStyle: StyleJson = {
|
|
254
254
|
version: 8,
|
|
255
255
|
id: 'test',
|
|
256
|
-
name: '
|
|
256
|
+
name: 'topographic',
|
|
257
257
|
sources: {
|
|
258
258
|
basemaps_vector: {
|
|
259
259
|
type: 'vector',
|
|
260
|
-
url:
|
|
260
|
+
url: `/vector`,
|
|
261
261
|
},
|
|
262
262
|
basemaps_raster: {
|
|
263
263
|
type: 'raster',
|
|
264
|
-
tiles: [
|
|
264
|
+
tiles: [`/raster`],
|
|
265
265
|
},
|
|
266
266
|
basemaps_raster_encode: {
|
|
267
267
|
type: 'raster',
|
|
268
|
-
tiles: [
|
|
268
|
+
tiles: [`/raster/{z}/{x}/{y}.webp`], // Shouldn't encode the {}
|
|
269
269
|
},
|
|
270
270
|
test_vector: {
|
|
271
271
|
type: 'vector',
|
|
@@ -295,8 +295,8 @@ o.spec('LambdaXyz', () => {
|
|
|
295
295
|
};
|
|
296
296
|
|
|
297
297
|
const fakeRecord = {
|
|
298
|
-
id: '
|
|
299
|
-
name: '
|
|
298
|
+
id: 'st_topographic_production',
|
|
299
|
+
name: 'topographic',
|
|
300
300
|
style: fakeStyle,
|
|
301
301
|
};
|
|
302
302
|
|
|
@@ -305,7 +305,7 @@ o.spec('LambdaXyz', () => {
|
|
|
305
305
|
const res = await handleRequest(request);
|
|
306
306
|
o(res.status).equals(200);
|
|
307
307
|
o(res.header('content-type')).equals('application/json');
|
|
308
|
-
o(res.header('cache-control')).equals('
|
|
308
|
+
o(res.header('cache-control')).equals('no-store');
|
|
309
309
|
|
|
310
310
|
const body = Buffer.from(res.body ?? '', 'base64').toString();
|
|
311
311
|
fakeStyle.sources.basemaps_vector = {
|
package/src/index.ts
CHANGED
|
@@ -4,6 +4,8 @@ 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
|
|
|
8
10
|
const app = new Router();
|
|
9
11
|
|
|
@@ -11,6 +13,7 @@ app.get('ping', Ping);
|
|
|
11
13
|
app.get('health', Health);
|
|
12
14
|
app.get('version', Version);
|
|
13
15
|
app.get('tiles', Tiles);
|
|
16
|
+
app.get('imagery', Imagery);
|
|
14
17
|
|
|
15
18
|
let slowTimer: NodeJS.Timer | null = null;
|
|
16
19
|
export async function handleRequest(req: LambdaHttpRequest): Promise<LambdaHttpResponse> {
|
|
@@ -21,6 +24,11 @@ export async function handleRequest(req: LambdaHttpRequest): Promise<LambdaHttpR
|
|
|
21
24
|
|
|
22
25
|
req.set('name', 'LambdaTiler');
|
|
23
26
|
try {
|
|
27
|
+
const apiKey = Router.apiKey(req);
|
|
28
|
+
if (apiKey != null) {
|
|
29
|
+
const apiKeyHash = createHash('sha256').update(apiKey).digest('base64');
|
|
30
|
+
req.set('api', apiKeyHash);
|
|
31
|
+
}
|
|
24
32
|
return await app.handle(req);
|
|
25
33
|
} finally {
|
|
26
34
|
if (slowTimer) clearTimeout(slowTimer);
|
|
@@ -0,0 +1,50 @@
|
|
|
1
|
+
import { Config } from '@basemaps/config';
|
|
2
|
+
import { fsa } from '@basemaps/shared';
|
|
3
|
+
import { HttpHeader, LambdaHttpRequest, 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
|
+
|
|
11
|
+
const gzipP = promisify(gzip);
|
|
12
|
+
|
|
13
|
+
function isAllowedFile(f: string): boolean {
|
|
14
|
+
if (f.endsWith('.geojson')) return true;
|
|
15
|
+
if (f.endsWith('.json')) return true;
|
|
16
|
+
return false;
|
|
17
|
+
}
|
|
18
|
+
|
|
19
|
+
/**
|
|
20
|
+
* Get metadata around the imagery such as the source bounding box or the bounding box of the COGS
|
|
21
|
+
* - /v1/imagery/:imageryId/source.geojson
|
|
22
|
+
* - /v1/imagery/:imageryId/covering.geojson
|
|
23
|
+
*/
|
|
24
|
+
export async function Imagery(req: LambdaHttpRequest): Promise<LambdaHttpResponse> {
|
|
25
|
+
const { rest } = Router.action(req);
|
|
26
|
+
const [imageryId, requestType] = rest;
|
|
27
|
+
if (!isAllowedFile(requestType)) return new LambdaHttpResponse(404, 'Not found');
|
|
28
|
+
|
|
29
|
+
const imagery = await Config.Imagery.get(imageryId);
|
|
30
|
+
if (imagery == null) return new LambdaHttpResponse(404, 'Not found');
|
|
31
|
+
|
|
32
|
+
const targetPath = fsa.join(imagery.uri, requestType);
|
|
33
|
+
|
|
34
|
+
try {
|
|
35
|
+
const buf = await fsa.read(targetPath);
|
|
36
|
+
const cacheKey = createHash('sha256').update(buf).digest('base64');
|
|
37
|
+
|
|
38
|
+
if (TileEtag.isNotModified(req, cacheKey)) return NotModified;
|
|
39
|
+
|
|
40
|
+
const response = new LambdaHttpResponse(200, 'ok');
|
|
41
|
+
response.header(HttpHeader.ETag, cacheKey);
|
|
42
|
+
response.header(HttpHeader.ContentEncoding, 'gzip');
|
|
43
|
+
response.buffer(await gzipP(buf), 'application/json');
|
|
44
|
+
req.set('bytes', buf.byteLength);
|
|
45
|
+
return response;
|
|
46
|
+
} catch (e) {
|
|
47
|
+
req.log.warn({ targetPath }, 'ImageryMetadata:Failed');
|
|
48
|
+
return new LambdaHttpResponse(404, 'Not found');
|
|
49
|
+
}
|
|
50
|
+
}
|
package/src/routes/tile.ts
CHANGED
|
@@ -13,6 +13,7 @@ import { TileEtag } from './tile.etag.js';
|
|
|
13
13
|
import { Router } from '../router.js';
|
|
14
14
|
import { ValidateTilePath } from '../validate.js';
|
|
15
15
|
import { URL } from 'url';
|
|
16
|
+
import { fsa } from '@chunkd/fs';
|
|
16
17
|
|
|
17
18
|
export const TileComposer = new TileMakerSharp(256);
|
|
18
19
|
|
|
@@ -132,16 +133,16 @@ export const TileRoute = {
|
|
|
132
133
|
const sources: Sources = {};
|
|
133
134
|
for (const [key, value] of Object.entries(style.sources)) {
|
|
134
135
|
if (value.type === 'vector') {
|
|
135
|
-
if (value.url.
|
|
136
|
-
const url = new URL(value.url);
|
|
136
|
+
if (value.url.startsWith('/')) {
|
|
137
|
+
const url = new URL(fsa.join(host, value.url));
|
|
137
138
|
url.searchParams.set('api', apiKey);
|
|
138
139
|
value.url = url.toString().replace(/%7B/g, '{').replace(/%7D/g, '}');
|
|
139
140
|
}
|
|
140
141
|
} else if (value.type === 'raster' && Array.isArray(value.tiles)) {
|
|
141
142
|
for (let i = 0; i < value.tiles.length; i++) {
|
|
142
143
|
const tile = value.tiles[i];
|
|
143
|
-
if (tile.
|
|
144
|
-
const url = new URL(tile);
|
|
144
|
+
if (tile.startsWith('/')) {
|
|
145
|
+
const url = new URL(fsa.join(host, tile));
|
|
145
146
|
url.searchParams.set('api', apiKey);
|
|
146
147
|
value.tiles[i] = url.toString().replace(/%7B/g, '{').replace(/%7D/g, '}');
|
|
147
148
|
}
|
|
@@ -173,7 +174,7 @@ export const TileRoute = {
|
|
|
173
174
|
|
|
174
175
|
const response = new LambdaHttpResponse(200, 'ok');
|
|
175
176
|
response.header(HttpHeader.ETag, cacheKey);
|
|
176
|
-
response.header(HttpHeader.CacheControl, '
|
|
177
|
+
response.header(HttpHeader.CacheControl, 'no-store');
|
|
177
178
|
response.buffer(data, 'application/json');
|
|
178
179
|
req.set('bytes', data.byteLength);
|
|
179
180
|
return response;
|
|
@@ -183,10 +184,6 @@ export async function Tiles(req: LambdaHttpRequest): Promise<LambdaHttpResponse>
|
|
|
183
184
|
const { rest } = Router.action(req);
|
|
184
185
|
if (rest.length < 1) return NotFound;
|
|
185
186
|
const apiKey = Router.apiKey(req);
|
|
186
|
-
const apiKeyHash = createHash('sha256')
|
|
187
|
-
.update(apiKey ?? '')
|
|
188
|
-
.digest('base64');
|
|
189
|
-
req.set('api', apiKeyHash);
|
|
190
187
|
if (!isValidApiKey(apiKey)) return new LambdaHttpResponse(400, 'Invalid API Key');
|
|
191
188
|
|
|
192
189
|
const fileName = rest[rest.length - 1].toLowerCase();
|