@basemaps/lambda-tiler 6.32.1 → 6.34.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 +49 -0
- package/build/__tests__/xyz.util.d.ts +1 -1
- package/build/__tests__/xyz.util.d.ts.map +1 -1
- package/build/__tests__/xyz.util.js +2 -2
- package/build/__tests__/xyz.util.js.map +1 -1
- package/build/arcgis/__tests__/arcgis.style.json.test.d.ts +2 -0
- package/build/arcgis/__tests__/arcgis.style.json.test.d.ts.map +1 -0
- package/build/arcgis/__tests__/arcgis.style.json.test.js +128 -0
- package/build/arcgis/__tests__/arcgis.style.json.test.js.map +1 -0
- package/build/arcgis/__tests__/vector.tiler.server.test.d.ts +2 -0
- package/build/arcgis/__tests__/vector.tiler.server.test.d.ts.map +1 -0
- package/build/arcgis/__tests__/vector.tiler.server.test.js +47 -0
- package/build/arcgis/__tests__/vector.tiler.server.test.js.map +1 -0
- package/build/arcgis/arcgis.info.d.ts +3 -0
- package/build/arcgis/arcgis.info.d.ts.map +1 -0
- package/build/arcgis/arcgis.info.js +25 -0
- package/build/arcgis/arcgis.info.js.map +1 -0
- package/build/arcgis/arcgis.style.json.d.ts +9 -0
- package/build/arcgis/arcgis.style.json.d.ts.map +1 -0
- package/build/arcgis/arcgis.style.json.js +73 -0
- package/build/arcgis/arcgis.style.json.js.map +1 -0
- package/build/arcgis/vector.tile.server.d.ts +8 -0
- package/build/arcgis/vector.tile.server.d.ts.map +1 -0
- package/build/arcgis/vector.tile.server.js +71 -0
- package/build/arcgis/vector.tile.server.js.map +1 -0
- package/build/index.d.ts.map +1 -1
- package/build/index.js +22 -8
- package/build/index.js.map +1 -1
- package/build/routes/__tests__/fonts.test.js +14 -26
- package/build/routes/__tests__/fonts.test.js.map +1 -1
- package/build/routes/__tests__/sprites.test.js +7 -1
- package/build/routes/__tests__/sprites.test.js.map +1 -1
- package/build/routes/__tests__/xyz.test.js +1 -2
- package/build/routes/__tests__/xyz.test.js.map +1 -1
- package/build/routes/fonts.d.ts +0 -2
- package/build/routes/fonts.d.ts.map +1 -1
- package/build/routes/fonts.js +3 -66
- package/build/routes/fonts.js.map +1 -1
- package/build/routes/sprites.d.ts.map +1 -1
- package/build/routes/sprites.js +3 -29
- package/build/routes/sprites.js.map +1 -1
- package/build/routes/tile.xyz.vector.js +2 -2
- package/build/routes/tile.xyz.vector.js.map +1 -1
- package/build/util/assets.provider.d.ts +27 -0
- package/build/util/assets.provider.d.ts.map +1 -0
- package/build/util/assets.provider.js +56 -0
- package/build/util/assets.provider.js.map +1 -0
- package/build/util/config.cache.d.ts +16 -0
- package/build/util/config.cache.d.ts.map +1 -0
- package/build/util/config.cache.js +41 -0
- package/build/util/config.cache.js.map +1 -0
- package/build/util/response.d.ts +3 -1
- package/build/util/response.d.ts.map +1 -1
- package/build/util/response.js +2 -0
- package/build/util/response.js.map +1 -1
- package/build/util/source.cache.d.ts +1 -0
- package/build/util/source.cache.d.ts.map +1 -1
- package/build/util/source.cache.js +2 -1
- package/build/util/source.cache.js.map +1 -1
- package/build/util/swapping.lru.d.ts +1 -0
- package/build/util/swapping.lru.d.ts.map +1 -1
- package/build/util/swapping.lru.js +7 -0
- package/build/util/swapping.lru.js.map +1 -1
- package/build/util/validate.d.ts +0 -5
- package/build/util/validate.d.ts.map +1 -1
- package/build/util/validate.js +1 -23
- package/build/util/validate.js.map +1 -1
- package/dist/index.js +52 -52
- package/dist/node_modules/.package-lock.json +4 -4
- package/dist/node_modules/node-abi/abi_registry.json +8 -1
- package/dist/node_modules/node-abi/package.json +1 -1
- package/dist/package-lock.json +8 -8
- package/dist/package.json +1 -1
- package/package.json +4 -4
- package/src/__tests__/xyz.util.ts +7 -2
- package/src/arcgis/__tests__/arcgis.style.json.test.ts +153 -0
- package/src/arcgis/__tests__/vector.tiler.server.test.ts +61 -0
- package/src/arcgis/arcgis.info.ts +26 -0
- package/src/arcgis/arcgis.style.json.ts +81 -0
- package/src/arcgis/vector.tile.server.ts +78 -0
- package/src/index.ts +25 -8
- package/src/routes/__tests__/fonts.test.ts +14 -29
- package/src/routes/__tests__/sprites.test.ts +7 -2
- package/src/routes/__tests__/xyz.test.ts +2 -2
- package/src/routes/fonts.ts +4 -64
- package/src/routes/sprites.ts +4 -27
- package/src/routes/tile.xyz.vector.ts +2 -2
- package/src/util/assets.provider.ts +67 -0
- package/src/util/config.cache.ts +44 -0
- package/src/util/response.ts +4 -1
- package/src/util/source.cache.ts +2 -1
- package/src/util/swapping.lru.ts +7 -0
- package/src/util/validate.ts +1 -27
- package/tsconfig.json +1 -0
- package/tsconfig.tsbuildinfo +1 -1
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@basemaps/lambda-tiler",
|
|
3
|
-
"version": "6.
|
|
3
|
+
"version": "6.34.0",
|
|
4
4
|
"lockfileVersion": 2,
|
|
5
5
|
"requires": true,
|
|
6
6
|
"packages": {
|
|
@@ -226,9 +226,9 @@
|
|
|
226
226
|
"integrity": "sha512-ONmRUqK7zj7DWX0D9ADe03wbwOBZxNAfF20PlGfCWQcD3+/MakShIHrMqx9YwPTfxDdF1zLeL+RGZiR9kGMLdg=="
|
|
227
227
|
},
|
|
228
228
|
"node_modules/node-abi": {
|
|
229
|
-
"version": "3.
|
|
230
|
-
"resolved": "https://registry.npmjs.org/node-abi/-/node-abi-3.
|
|
231
|
-
"integrity": "sha512-
|
|
229
|
+
"version": "3.24.0",
|
|
230
|
+
"resolved": "https://registry.npmjs.org/node-abi/-/node-abi-3.24.0.tgz",
|
|
231
|
+
"integrity": "sha512-YPG3Co0luSu6GwOBsmIdGW6Wx0NyNDLg/hriIyDllVsNwnI6UeqaWShxC3lbH4LtEQUgoLP3XR1ndXiDAWvmRw==",
|
|
232
232
|
"dependencies": {
|
|
233
233
|
"semver": "^7.3.5"
|
|
234
234
|
},
|
|
@@ -202,9 +202,16 @@
|
|
|
202
202
|
},
|
|
203
203
|
{
|
|
204
204
|
"abi": "107",
|
|
205
|
-
"future":
|
|
205
|
+
"future": false,
|
|
206
206
|
"lts": false,
|
|
207
207
|
"runtime": "electron",
|
|
208
208
|
"target": "20.0.0-alpha.1"
|
|
209
|
+
},
|
|
210
|
+
{
|
|
211
|
+
"abi": "109",
|
|
212
|
+
"future": true,
|
|
213
|
+
"lts": false,
|
|
214
|
+
"runtime": "electron",
|
|
215
|
+
"target": "21.0.0-alpha.1"
|
|
209
216
|
}
|
|
210
217
|
]
|
package/dist/package-lock.json
CHANGED
|
@@ -1,12 +1,12 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@basemaps/lambda-tiler",
|
|
3
|
-
"version": "6.
|
|
3
|
+
"version": "6.34.0",
|
|
4
4
|
"lockfileVersion": 2,
|
|
5
5
|
"requires": true,
|
|
6
6
|
"packages": {
|
|
7
7
|
"": {
|
|
8
8
|
"name": "@basemaps/lambda-tiler",
|
|
9
|
-
"version": "6.
|
|
9
|
+
"version": "6.34.0",
|
|
10
10
|
"license": "MIT",
|
|
11
11
|
"dependencies": {
|
|
12
12
|
"sharp": "0.30.7"
|
|
@@ -237,9 +237,9 @@
|
|
|
237
237
|
"integrity": "sha512-ONmRUqK7zj7DWX0D9ADe03wbwOBZxNAfF20PlGfCWQcD3+/MakShIHrMqx9YwPTfxDdF1zLeL+RGZiR9kGMLdg=="
|
|
238
238
|
},
|
|
239
239
|
"node_modules/node-abi": {
|
|
240
|
-
"version": "3.
|
|
241
|
-
"resolved": "https://registry.npmjs.org/node-abi/-/node-abi-3.
|
|
242
|
-
"integrity": "sha512-
|
|
240
|
+
"version": "3.24.0",
|
|
241
|
+
"resolved": "https://registry.npmjs.org/node-abi/-/node-abi-3.24.0.tgz",
|
|
242
|
+
"integrity": "sha512-YPG3Co0luSu6GwOBsmIdGW6Wx0NyNDLg/hriIyDllVsNwnI6UeqaWShxC3lbH4LtEQUgoLP3XR1ndXiDAWvmRw==",
|
|
243
243
|
"dependencies": {
|
|
244
244
|
"semver": "^7.3.5"
|
|
245
245
|
},
|
|
@@ -647,9 +647,9 @@
|
|
|
647
647
|
"integrity": "sha512-ONmRUqK7zj7DWX0D9ADe03wbwOBZxNAfF20PlGfCWQcD3+/MakShIHrMqx9YwPTfxDdF1zLeL+RGZiR9kGMLdg=="
|
|
648
648
|
},
|
|
649
649
|
"node-abi": {
|
|
650
|
-
"version": "3.
|
|
651
|
-
"resolved": "https://registry.npmjs.org/node-abi/-/node-abi-3.
|
|
652
|
-
"integrity": "sha512-
|
|
650
|
+
"version": "3.24.0",
|
|
651
|
+
"resolved": "https://registry.npmjs.org/node-abi/-/node-abi-3.24.0.tgz",
|
|
652
|
+
"integrity": "sha512-YPG3Co0luSu6GwOBsmIdGW6Wx0NyNDLg/hriIyDllVsNwnI6UeqaWShxC3lbH4LtEQUgoLP3XR1ndXiDAWvmRw==",
|
|
653
653
|
"requires": {
|
|
654
654
|
"semver": "^7.3.5"
|
|
655
655
|
}
|
package/dist/package.json
CHANGED
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@basemaps/lambda-tiler",
|
|
3
|
-
"version": "6.
|
|
3
|
+
"version": "6.34.0",
|
|
4
4
|
"repository": {
|
|
5
5
|
"type": "git",
|
|
6
6
|
"url": "https://github.com/linz/basemaps.git",
|
|
@@ -22,10 +22,10 @@
|
|
|
22
22
|
"types": "./build/index.d.ts",
|
|
23
23
|
"license": "MIT",
|
|
24
24
|
"dependencies": {
|
|
25
|
-
"@basemaps/config": "^6.
|
|
25
|
+
"@basemaps/config": "^6.34.0",
|
|
26
26
|
"@basemaps/geo": "^6.32.1",
|
|
27
27
|
"@basemaps/lambda": "^6.7.0",
|
|
28
|
-
"@basemaps/shared": "^6.
|
|
28
|
+
"@basemaps/shared": "^6.34.0",
|
|
29
29
|
"@basemaps/tiler": "^6.32.1",
|
|
30
30
|
"@basemaps/tiler-sharp": "^6.32.1",
|
|
31
31
|
"@chunkd/fs": "^8.4.0",
|
|
@@ -59,5 +59,5 @@
|
|
|
59
59
|
"@types/sharp": "^0.30.3",
|
|
60
60
|
"pretty-json-log": "^1.0.0"
|
|
61
61
|
},
|
|
62
|
-
"gitHead": "
|
|
62
|
+
"gitHead": "1685fa12be66df74bc64d7f76b7355390980a43f"
|
|
63
63
|
}
|
|
@@ -17,10 +17,15 @@ export function mockRequest(path: string, method = 'get', headers: Record<string
|
|
|
17
17
|
);
|
|
18
18
|
}
|
|
19
19
|
|
|
20
|
-
export function mockUrlRequest(
|
|
20
|
+
export function mockUrlRequest(
|
|
21
|
+
path: string,
|
|
22
|
+
query = '',
|
|
23
|
+
headers: Record<string, unknown> = {},
|
|
24
|
+
method?: string,
|
|
25
|
+
): LambdaHttpRequest {
|
|
21
26
|
return new LambdaUrlRequest(
|
|
22
27
|
{
|
|
23
|
-
requestContext: { http: { method: 'GET' } },
|
|
28
|
+
requestContext: { http: { method: method ? method.toUpperCase() : 'GET' } },
|
|
24
29
|
headers,
|
|
25
30
|
rawPath: encodeURI(path),
|
|
26
31
|
rawQueryString: query,
|
|
@@ -0,0 +1,153 @@
|
|
|
1
|
+
import { Config, StyleJson } from '@basemaps/config';
|
|
2
|
+
import { Env } from '@basemaps/shared';
|
|
3
|
+
import o from 'ospec';
|
|
4
|
+
import { createSandbox } from 'sinon';
|
|
5
|
+
import { handler } from '../../index.js';
|
|
6
|
+
import { FakeData } from '../../__tests__/config.data.js';
|
|
7
|
+
import { Api, mockRequest, mockUrlRequest } from '../../__tests__/xyz.util.js';
|
|
8
|
+
|
|
9
|
+
o.spec('v1/arcgis/rest/services/', () => {
|
|
10
|
+
const host = 'https://tiles.test';
|
|
11
|
+
const sandbox = createSandbox();
|
|
12
|
+
|
|
13
|
+
o.before(() => {
|
|
14
|
+
process.env[Env.PublicUrlBase] = host;
|
|
15
|
+
});
|
|
16
|
+
o.afterEach(() => sandbox.restore());
|
|
17
|
+
o('should not found tile set', async () => {
|
|
18
|
+
const request = mockRequest('/v1/arcgis/rest/services/topographic/VectorTileServer/root.json', 'get', Api.header);
|
|
19
|
+
|
|
20
|
+
sandbox.stub(Config.TileSet, 'get').resolves(null);
|
|
21
|
+
|
|
22
|
+
const res = await handler.router.handle(request);
|
|
23
|
+
o(res.status).equals(404);
|
|
24
|
+
});
|
|
25
|
+
|
|
26
|
+
o('should not found style', async () => {
|
|
27
|
+
const request = mockRequest('/v1/arcgis/rest/services/topographic/VectorTileServer/root.json', 'get', Api.header);
|
|
28
|
+
|
|
29
|
+
sandbox.stub(Config.TileSet, 'get').resolves(FakeData.tileSetVector('topographic'));
|
|
30
|
+
sandbox.stub(Config.Style, 'get').resolves(null);
|
|
31
|
+
|
|
32
|
+
const res = await handler.router.handle(request);
|
|
33
|
+
o(res.status).equals(404);
|
|
34
|
+
});
|
|
35
|
+
|
|
36
|
+
const fakeStyle: StyleJson = {
|
|
37
|
+
version: 8,
|
|
38
|
+
id: 'test',
|
|
39
|
+
name: 'topographic',
|
|
40
|
+
sources: {
|
|
41
|
+
basemaps_vector: {
|
|
42
|
+
type: 'vector',
|
|
43
|
+
url: `/vector`,
|
|
44
|
+
},
|
|
45
|
+
basemaps_raster: {
|
|
46
|
+
type: 'raster',
|
|
47
|
+
tiles: [`/raster`],
|
|
48
|
+
},
|
|
49
|
+
},
|
|
50
|
+
layers: [
|
|
51
|
+
{
|
|
52
|
+
source: 'basemaps_vector',
|
|
53
|
+
layout: {
|
|
54
|
+
visibility: 'visible',
|
|
55
|
+
},
|
|
56
|
+
paint: {
|
|
57
|
+
'background-color': 'rgba(206, 229, 242, 1)',
|
|
58
|
+
},
|
|
59
|
+
id: 'Background-vector',
|
|
60
|
+
type: 'background',
|
|
61
|
+
minzoom: 0,
|
|
62
|
+
},
|
|
63
|
+
{
|
|
64
|
+
source: 'basemaps_raster',
|
|
65
|
+
layout: {
|
|
66
|
+
visibility: 'visible',
|
|
67
|
+
},
|
|
68
|
+
paint: {
|
|
69
|
+
'background-color': 'rgba(222, 229, 132, 1)',
|
|
70
|
+
},
|
|
71
|
+
id: 'Background-raster',
|
|
72
|
+
type: 'background',
|
|
73
|
+
minzoom: 0,
|
|
74
|
+
},
|
|
75
|
+
],
|
|
76
|
+
glyphs: '/glyphs',
|
|
77
|
+
sprite: '/sprite',
|
|
78
|
+
metadata: { id: 'test' },
|
|
79
|
+
};
|
|
80
|
+
|
|
81
|
+
const fakeRecord = {
|
|
82
|
+
id: 'st_topographic',
|
|
83
|
+
name: 'topographic',
|
|
84
|
+
style: fakeStyle,
|
|
85
|
+
};
|
|
86
|
+
|
|
87
|
+
o('should serve style json and remove the raster source and layers, then replace the vector url', async () => {
|
|
88
|
+
const request = mockRequest('/v1/arcgis/rest/services/topographic/VectorTileServer/root.json', 'get', Api.header);
|
|
89
|
+
|
|
90
|
+
sandbox.stub(Config.TileSet, 'get').resolves(FakeData.tileSetVector('topographic'));
|
|
91
|
+
sandbox.stub(Config.Style, 'get').resolves(fakeRecord as any);
|
|
92
|
+
|
|
93
|
+
const res = await handler.router.handle(request);
|
|
94
|
+
o(res.status).equals(200);
|
|
95
|
+
o(res.header('content-type')).equals('application/json');
|
|
96
|
+
o(res.header('cache-control')).equals('no-store');
|
|
97
|
+
|
|
98
|
+
const body = Buffer.from(res.body ?? '', 'base64').toString();
|
|
99
|
+
fakeStyle.sources.basemaps_vector = {
|
|
100
|
+
type: 'vector',
|
|
101
|
+
url: `${host}/v1/arcgis/rest/services/topographic/VectorTileServer?api=${Api.key}&f=json`,
|
|
102
|
+
};
|
|
103
|
+
delete fakeStyle.sources.basemaps_raster;
|
|
104
|
+
fakeStyle.layers = [fakeStyle.layers[0]];
|
|
105
|
+
|
|
106
|
+
fakeStyle.sprite = `${host}/sprite`;
|
|
107
|
+
fakeStyle.glyphs = `${host}/glyphs`;
|
|
108
|
+
|
|
109
|
+
o(JSON.parse(body)).deepEquals(fakeStyle);
|
|
110
|
+
});
|
|
111
|
+
|
|
112
|
+
o('should not found for raster tileset', async () => {
|
|
113
|
+
const request = mockRequest('/v1/arcgis/rest/services/raster/VectorTileServer/root.json', 'get', Api.header);
|
|
114
|
+
|
|
115
|
+
sandbox.stub(Config.TileSet, 'get').resolves(FakeData.tileSetRaster('raster'));
|
|
116
|
+
sandbox.stub(Config.Style, 'get').resolves(fakeRecord as any);
|
|
117
|
+
|
|
118
|
+
const res = await handler.router.handle(request);
|
|
119
|
+
o(res.status).equals(404);
|
|
120
|
+
});
|
|
121
|
+
|
|
122
|
+
o('should fine the new style with url query', async () => {
|
|
123
|
+
const request = mockUrlRequest(
|
|
124
|
+
'/v1/arcgis/rest/services/topographic/VectorTileServer/root.json',
|
|
125
|
+
'style=topolite',
|
|
126
|
+
Api.header,
|
|
127
|
+
);
|
|
128
|
+
|
|
129
|
+
sandbox.stub(Config.TileSet, 'get').resolves(FakeData.tileSetVector('topographic'));
|
|
130
|
+
sandbox
|
|
131
|
+
.stub(Config.Style, 'get')
|
|
132
|
+
.withArgs('st_topolite')
|
|
133
|
+
.resolves(fakeRecord as any);
|
|
134
|
+
|
|
135
|
+
const res = await handler.router.handle(request);
|
|
136
|
+
o(res.status).equals(200);
|
|
137
|
+
o(res.header('content-type')).equals('application/json');
|
|
138
|
+
o(res.header('cache-control')).equals('no-store');
|
|
139
|
+
|
|
140
|
+
const body = Buffer.from(res.body ?? '', 'base64').toString();
|
|
141
|
+
fakeStyle.sources.basemaps_vector = {
|
|
142
|
+
type: 'vector',
|
|
143
|
+
url: `${host}/v1/arcgis/rest/services/topographic/VectorTileServer?api=${Api.key}&f=json`,
|
|
144
|
+
};
|
|
145
|
+
delete fakeStyle.sources.basemaps_raster;
|
|
146
|
+
fakeStyle.layers = [fakeStyle.layers[0]];
|
|
147
|
+
|
|
148
|
+
fakeStyle.sprite = `${host}/sprite`;
|
|
149
|
+
fakeStyle.glyphs = `${host}/glyphs`;
|
|
150
|
+
|
|
151
|
+
o(JSON.parse(body)).deepEquals(fakeStyle);
|
|
152
|
+
});
|
|
153
|
+
});
|
|
@@ -0,0 +1,61 @@
|
|
|
1
|
+
import { Config } from '@basemaps/config';
|
|
2
|
+
import { Env } from '@basemaps/shared';
|
|
3
|
+
import o from 'ospec';
|
|
4
|
+
import { createSandbox } from 'sinon';
|
|
5
|
+
import { handler } from '../../index.js';
|
|
6
|
+
import { FakeData } from '../../__tests__/config.data.js';
|
|
7
|
+
import { Api, mockRequest, mockUrlRequest } from '../../__tests__/xyz.util.js';
|
|
8
|
+
|
|
9
|
+
o.spec('v1/arcgis/rest/services/', () => {
|
|
10
|
+
const host = 'https://tiles.test';
|
|
11
|
+
const sandbox = createSandbox();
|
|
12
|
+
|
|
13
|
+
o.before(() => {
|
|
14
|
+
process.env[Env.PublicUrlBase] = host;
|
|
15
|
+
});
|
|
16
|
+
o.afterEach(() => sandbox.restore());
|
|
17
|
+
o('should not found tile set', async () => {
|
|
18
|
+
const request = mockUrlRequest('/v1/arcgis/rest/services/topographic/VectorTileServer', 'f=json', Api.header);
|
|
19
|
+
|
|
20
|
+
sandbox.stub(Config.TileSet, 'get').resolves(null);
|
|
21
|
+
|
|
22
|
+
const res = await handler.router.handle(request);
|
|
23
|
+
o(res.status).equals(404);
|
|
24
|
+
});
|
|
25
|
+
o('should return the vector tile server', async () => {
|
|
26
|
+
const request = mockUrlRequest('/v1/arcgis/rest/services/topographic/VectorTileServer', 'f=json', Api.header);
|
|
27
|
+
|
|
28
|
+
sandbox.stub(Config.TileSet, 'get').resolves(FakeData.tileSetVector('topographic'));
|
|
29
|
+
|
|
30
|
+
const res = await handler.router.handle(request);
|
|
31
|
+
o(res.status).equals(200);
|
|
32
|
+
o(res.header('content-type')).equals('application/json');
|
|
33
|
+
o(res.header('cache-control')).equals('no-store');
|
|
34
|
+
|
|
35
|
+
const body = JSON.parse(Buffer.from(res.body ?? '', 'base64').toString());
|
|
36
|
+
o(body.tiles[0]).equals(`${host}/v1/tiles/topographic/WebMercatorQuad/{z}/{x}/{y}.pbf?api=${Api.key}`);
|
|
37
|
+
o(body.tileInfo.lods.length).equals(17);
|
|
38
|
+
});
|
|
39
|
+
o('should not return with no f=json query', async () => {
|
|
40
|
+
const request = mockRequest('/v1/arcgis/rest/services/topographic/VectorTileServer', 'get', Api.header);
|
|
41
|
+
|
|
42
|
+
sandbox.stub(Config.TileSet, 'get').resolves(FakeData.tileSetVector('topographic'));
|
|
43
|
+
|
|
44
|
+
const res = await handler.router.handle(request);
|
|
45
|
+
o(res.status).equals(404);
|
|
46
|
+
});
|
|
47
|
+
o('should return ok for post request', async () => {
|
|
48
|
+
const request = mockUrlRequest(
|
|
49
|
+
'/v1/arcgis/rest/services/topographic/VectorTileServer',
|
|
50
|
+
'f=json',
|
|
51
|
+
Api.header,
|
|
52
|
+
'POST',
|
|
53
|
+
);
|
|
54
|
+
|
|
55
|
+
sandbox.stub(Config.TileSet, 'get').resolves(FakeData.tileSetVector('topographic'));
|
|
56
|
+
|
|
57
|
+
const res = await handler.router.handle(request);
|
|
58
|
+
o(res.status).equals(200);
|
|
59
|
+
o(res.body).deepEquals(`{"id":"${request.id}","correlationId":"${request.correlationId}","message":"ok"}`);
|
|
60
|
+
});
|
|
61
|
+
});
|
|
@@ -0,0 +1,26 @@
|
|
|
1
|
+
import { Env } from '@basemaps/shared';
|
|
2
|
+
import { HttpHeader, LambdaHttpRequest, LambdaHttpResponse } from '@linzjs/lambda';
|
|
3
|
+
import { Etag } from '../util/etag.js';
|
|
4
|
+
import { NotFound, NotModified } from '../util/response.js';
|
|
5
|
+
|
|
6
|
+
export async function arcgisInfoGet(req: LambdaHttpRequest): Promise<LambdaHttpResponse> {
|
|
7
|
+
const host = Env.get(Env.PublicUrlBase);
|
|
8
|
+
if (host == null) return NotFound();
|
|
9
|
+
const info = {
|
|
10
|
+
currentVersion: 10.1,
|
|
11
|
+
fullVersion: '10.1',
|
|
12
|
+
owningSystemUrl: host,
|
|
13
|
+
};
|
|
14
|
+
|
|
15
|
+
const json = JSON.stringify(info);
|
|
16
|
+
const data = Buffer.from(json);
|
|
17
|
+
|
|
18
|
+
const cacheKey = Etag.key(data);
|
|
19
|
+
if (Etag.isNotModified(req, cacheKey)) return NotModified();
|
|
20
|
+
|
|
21
|
+
const response = new LambdaHttpResponse(200, 'ok');
|
|
22
|
+
response.header(HttpHeader.CacheControl, 'public, max-age=604800, stale-while-revalidate=86400');
|
|
23
|
+
response.buffer(data, 'application/json');
|
|
24
|
+
req.set('bytes', data.byteLength);
|
|
25
|
+
return response;
|
|
26
|
+
}
|
|
@@ -0,0 +1,81 @@
|
|
|
1
|
+
import { Config, Sources, StyleJson, TileSetType } from '@basemaps/config';
|
|
2
|
+
import { Env, fsa } from '@basemaps/shared';
|
|
3
|
+
import { HttpHeader, LambdaHttpRequest, LambdaHttpResponse } from '@linzjs/lambda';
|
|
4
|
+
import { convertRelativeUrl } from '../routes/tile.style.json.js';
|
|
5
|
+
import { Etag } from '../util/etag.js';
|
|
6
|
+
import { NotFound, NotModified } from '../util/response.js';
|
|
7
|
+
import { Validate } from '../util/validate.js';
|
|
8
|
+
|
|
9
|
+
interface StyleGet {
|
|
10
|
+
Params: {
|
|
11
|
+
tileSet: string;
|
|
12
|
+
};
|
|
13
|
+
}
|
|
14
|
+
|
|
15
|
+
function tileserverUrl(tileSet: string, apiKey: string): string {
|
|
16
|
+
const host = Env.get(Env.PublicUrlBase) ?? '';
|
|
17
|
+
const url = `/v1/arcgis/rest/services/${tileSet}/VectorTileServer`;
|
|
18
|
+
const fullUrl = new URL(fsa.join(host, url));
|
|
19
|
+
fullUrl.searchParams.set('api', apiKey);
|
|
20
|
+
fullUrl.searchParams.set('f', 'json');
|
|
21
|
+
return fullUrl.toString().replace(/%7B/g, '{').replace(/%7D/g, '}');
|
|
22
|
+
}
|
|
23
|
+
|
|
24
|
+
function convertStyleJson(tileSet: string, style: StyleJson, apiKey: string): StyleJson {
|
|
25
|
+
const sources: Sources = JSON.parse(JSON.stringify(style.sources));
|
|
26
|
+
// Only keep the vector layer and update the source url
|
|
27
|
+
for (const [key, value] of Object.entries(sources)) {
|
|
28
|
+
if (value.type === 'vector') {
|
|
29
|
+
value.url = tileserverUrl(tileSet, apiKey);
|
|
30
|
+
sources[key] = value;
|
|
31
|
+
} else {
|
|
32
|
+
delete sources[key];
|
|
33
|
+
}
|
|
34
|
+
}
|
|
35
|
+
|
|
36
|
+
// Remove all the not vector layers.
|
|
37
|
+
const layers = [];
|
|
38
|
+
for (const layer of style.layers) {
|
|
39
|
+
if (layer.source != null && !sources.hasOwnProperty(layer.source)) continue;
|
|
40
|
+
layers.push(layer);
|
|
41
|
+
}
|
|
42
|
+
|
|
43
|
+
return {
|
|
44
|
+
version: 8,
|
|
45
|
+
id: style.id,
|
|
46
|
+
name: style.name,
|
|
47
|
+
sources,
|
|
48
|
+
layers,
|
|
49
|
+
metadata: style.metadata ?? {},
|
|
50
|
+
glyphs: convertRelativeUrl(style.glyphs),
|
|
51
|
+
sprite: convertRelativeUrl(style.sprite),
|
|
52
|
+
} as StyleJson;
|
|
53
|
+
}
|
|
54
|
+
|
|
55
|
+
export async function arcgisStyleJsonGet(req: LambdaHttpRequest<StyleGet>): Promise<LambdaHttpResponse> {
|
|
56
|
+
const apiKey = Validate.apiKey(req);
|
|
57
|
+
const tileSet = await Config.TileSet.get(Config.TileSet.id(req.params.tileSet));
|
|
58
|
+
if (tileSet?.type !== TileSetType.Vector) return NotFound();
|
|
59
|
+
|
|
60
|
+
const style = req.query.get('style');
|
|
61
|
+
const styleName = style ? style : 'topographic'; // Defalut to topographic style
|
|
62
|
+
|
|
63
|
+
// Get style Config from db
|
|
64
|
+
const dbId = Config.Style.id(styleName);
|
|
65
|
+
const styleConfig = await Config.Style.get(dbId);
|
|
66
|
+
if (styleConfig == null) return NotFound();
|
|
67
|
+
|
|
68
|
+
// Prepare sources and add linz source
|
|
69
|
+
const styleJson = convertStyleJson(tileSet.name, styleConfig.style, apiKey);
|
|
70
|
+
const data = Buffer.from(JSON.stringify(styleJson));
|
|
71
|
+
|
|
72
|
+
const cacheKey = Etag.key(data);
|
|
73
|
+
if (Etag.isNotModified(req, cacheKey)) return NotModified();
|
|
74
|
+
|
|
75
|
+
const response = new LambdaHttpResponse(200, 'ok');
|
|
76
|
+
response.header(HttpHeader.ETag, cacheKey);
|
|
77
|
+
response.header(HttpHeader.CacheControl, 'no-store');
|
|
78
|
+
response.buffer(data, 'application/json');
|
|
79
|
+
req.set('bytes', data.byteLength);
|
|
80
|
+
return response;
|
|
81
|
+
}
|
|
@@ -0,0 +1,78 @@
|
|
|
1
|
+
import { Config, TileSetType } from '@basemaps/config';
|
|
2
|
+
import { GoogleTms } from '@basemaps/geo';
|
|
3
|
+
import { HttpHeader, LambdaHttpRequest, LambdaHttpResponse } from '@linzjs/lambda';
|
|
4
|
+
import { convertRelativeUrl } from '../routes/tile.style.json.js';
|
|
5
|
+
import { NotFound } from '../util/response.js';
|
|
6
|
+
import { Validate } from '../util/validate.js';
|
|
7
|
+
|
|
8
|
+
/** Zoom level for the tilematrix which will be slice by 1 during the covertion to arcgis tileserve lods */
|
|
9
|
+
const MaxTileMatrixZoom = 18;
|
|
10
|
+
const MinTileMatrixZoom = 1;
|
|
11
|
+
|
|
12
|
+
export interface VectorTileServer {
|
|
13
|
+
Params: {
|
|
14
|
+
tileSet: string;
|
|
15
|
+
};
|
|
16
|
+
}
|
|
17
|
+
|
|
18
|
+
export async function arcgisTileServerGet(req: LambdaHttpRequest<VectorTileServer>): Promise<LambdaHttpResponse> {
|
|
19
|
+
const tileSet = await Config.TileSet.get(Config.TileSet.id(req.params.tileSet));
|
|
20
|
+
if (tileSet?.type !== TileSetType.Vector) return NotFound();
|
|
21
|
+
const apiKey = Validate.apiKey(req);
|
|
22
|
+
const f = req.query.get('f');
|
|
23
|
+
if (f !== 'json') return NotFound();
|
|
24
|
+
const extent = {
|
|
25
|
+
xmin: GoogleTms.extent.x,
|
|
26
|
+
ymin: GoogleTms.extent.y,
|
|
27
|
+
xmax: GoogleTms.extent.right,
|
|
28
|
+
ymax: GoogleTms.extent.bottom,
|
|
29
|
+
// TODO where is wkid from
|
|
30
|
+
spatialReference: { wkid: 102100, latestWkid: GoogleTms.projection.code },
|
|
31
|
+
};
|
|
32
|
+
const vectorTileServer = {
|
|
33
|
+
currentVersion: 10.81,
|
|
34
|
+
name: tileSet.name,
|
|
35
|
+
capabilities: 'TilesOnly',
|
|
36
|
+
type: 'indexedVector',
|
|
37
|
+
defaultStyles: '',
|
|
38
|
+
tiles: [convertRelativeUrl(`/v1/tiles/${tileSet.name}/WebMercatorQuad/{z}/{x}/{y}.pbf`, apiKey)],
|
|
39
|
+
exportTilesAllowed: false,
|
|
40
|
+
maxExportTilesCount: 0,
|
|
41
|
+
initialExtent: extent,
|
|
42
|
+
fullExtent: extent,
|
|
43
|
+
minScale: 0.0,
|
|
44
|
+
maxScale: 0.0,
|
|
45
|
+
tileInfo: {
|
|
46
|
+
rows: 512,
|
|
47
|
+
cols: 512,
|
|
48
|
+
dpi: 96,
|
|
49
|
+
format: 'pbf',
|
|
50
|
+
origin: { x: GoogleTms.extent.x, y: GoogleTms.extent.bottom },
|
|
51
|
+
spatialReference: { wkid: 102100, latestWkid: GoogleTms.projection.code },
|
|
52
|
+
lods: GoogleTms.zooms.slice(MinTileMatrixZoom, MaxTileMatrixZoom).map((c, i) => {
|
|
53
|
+
return {
|
|
54
|
+
level: i,
|
|
55
|
+
resolution: c.scaleDenominator * 0.28e-3,
|
|
56
|
+
scale: c.scaleDenominator,
|
|
57
|
+
};
|
|
58
|
+
}),
|
|
59
|
+
},
|
|
60
|
+
maxzoom: 22,
|
|
61
|
+
minLOD: 0,
|
|
62
|
+
maxLOD: 15,
|
|
63
|
+
resourceInfo: {
|
|
64
|
+
styleVersion: 8,
|
|
65
|
+
tileCompression: 'gzip',
|
|
66
|
+
cacheInfo: { storageInfo: { packetSize: 128, storageFormat: 'compactV2' } },
|
|
67
|
+
},
|
|
68
|
+
};
|
|
69
|
+
|
|
70
|
+
const json = JSON.stringify(vectorTileServer, null, 2);
|
|
71
|
+
const data = Buffer.from(json);
|
|
72
|
+
|
|
73
|
+
const response = new LambdaHttpResponse(200, 'ok');
|
|
74
|
+
response.header(HttpHeader.CacheControl, 'no-store');
|
|
75
|
+
response.buffer(data, 'application/json');
|
|
76
|
+
req.set('bytes', data.byteLength);
|
|
77
|
+
return response;
|
|
78
|
+
}
|
package/src/index.ts
CHANGED
|
@@ -1,5 +1,8 @@
|
|
|
1
|
-
import { LogConfig } from '@basemaps/shared';
|
|
2
|
-
import { LambdaHttpResponse,
|
|
1
|
+
import { Env, LogConfig } from '@basemaps/shared';
|
|
2
|
+
import { LambdaHttpResponse, lf } from '@linzjs/lambda';
|
|
3
|
+
import { arcgisInfoGet } from './arcgis/arcgis.info.js';
|
|
4
|
+
import { arcgisStyleJsonGet } from './arcgis/arcgis.style.json.js';
|
|
5
|
+
import { arcgisTileServerGet } from './arcgis/vector.tile.server.js';
|
|
3
6
|
import { tileAttributionGet } from './routes/attribution.js';
|
|
4
7
|
import { fontGet, fontList } from './routes/fonts.js';
|
|
5
8
|
import { healthGet } from './routes/health.js';
|
|
@@ -11,7 +14,8 @@ import { styleJsonGet } from './routes/tile.style.json.js';
|
|
|
11
14
|
import { wmtsCapabilitiesGet } from './routes/tile.wmts.js';
|
|
12
15
|
import { tileXyzGet } from './routes/tile.xyz.js';
|
|
13
16
|
import { versionGet } from './routes/version.js';
|
|
14
|
-
import {
|
|
17
|
+
import { assetProvider } from './util/assets.provider.js';
|
|
18
|
+
import { NotFound, OkResponse } from './util/response.js';
|
|
15
19
|
import { CoSources } from './util/source.cache.js';
|
|
16
20
|
import { St } from './util/source.tracer.js';
|
|
17
21
|
|
|
@@ -20,11 +24,19 @@ export const handler = lf.http(LogConfig.get());
|
|
|
20
24
|
handler.router.hook('request', (req) => {
|
|
21
25
|
req.set('name', 'LambdaTiler');
|
|
22
26
|
|
|
27
|
+
// Set the asset location for asset provider
|
|
28
|
+
const assetLocation = Env.get(Env.AssetLocation);
|
|
29
|
+
assetProvider.set(assetLocation);
|
|
30
|
+
|
|
23
31
|
// Reset the request tracing before every request
|
|
24
32
|
St.reset();
|
|
25
33
|
});
|
|
26
34
|
|
|
35
|
+
let totalRequests = 0;
|
|
27
36
|
handler.router.hook('response', (req, res) => {
|
|
37
|
+
totalRequests++;
|
|
38
|
+
req.set('requestsTotal', totalRequests); // Number of requests served by this lambda
|
|
39
|
+
|
|
28
40
|
if (St.requests.length > 0) {
|
|
29
41
|
// TODO this could be relaxed to every say 5% of requests if logging gets too verbose.
|
|
30
42
|
req.set('requests', St.requests.slice(0, 100)); // limit to 100 requests (some tiles need 100s of requests)
|
|
@@ -36,17 +48,16 @@ handler.router.hook('response', (req, res) => {
|
|
|
36
48
|
misses: CoSources.cache.misses,
|
|
37
49
|
size: CoSources.cache.currentSize,
|
|
38
50
|
resets: CoSources.cache.resets,
|
|
51
|
+
clears: CoSources.cache.clears,
|
|
39
52
|
cacheA: CoSources.cache.cacheA.size,
|
|
40
53
|
cacheB: CoSources.cache.cacheB.size,
|
|
41
54
|
});
|
|
42
55
|
|
|
43
|
-
//
|
|
44
|
-
|
|
45
|
-
res.header('access-control-allow-origin', '*');
|
|
46
|
-
}
|
|
56
|
+
// Force access-control-allow-origin to everything
|
|
57
|
+
res.header('access-control-allow-origin', '*');
|
|
47
58
|
});
|
|
48
59
|
|
|
49
|
-
// CORS is handled by
|
|
60
|
+
// CORS is handled by response hook so just return ok if the route exists
|
|
50
61
|
handler.router.options('*', (req) => {
|
|
51
62
|
const route = handler.router.router.find('GET', req.path);
|
|
52
63
|
if (route == null) return NotFound();
|
|
@@ -91,3 +102,9 @@ handler.router.get('/v1/attribution/:tileSet/:tileMatrix/summary.json', tileAttr
|
|
|
91
102
|
handler.router.get('/v1/tiles/:tileSet/:tileMatrix/WMTSCapabilities.xml', wmtsCapabilitiesGet);
|
|
92
103
|
handler.router.get('/v1/tiles/:tileSet/WMTSCapabilities.xml', wmtsCapabilitiesGet);
|
|
93
104
|
handler.router.get('/v1/tiles/WMTSCapabilities.xml', wmtsCapabilitiesGet);
|
|
105
|
+
|
|
106
|
+
// Arcgis Vector
|
|
107
|
+
handler.router.get('/v1/arcgis/rest/services/:tileSet/VectorTileServer', arcgisTileServerGet);
|
|
108
|
+
handler.router.post('/v1/arcgis/rest/services/:tileSet/VectorTileServer', OkResponse);
|
|
109
|
+
handler.router.get('/v1/arcgis/rest/services/:tileSet/VectorTileServer/root.json', arcgisStyleJsonGet);
|
|
110
|
+
handler.router.get('/v1/arcgis/rest/info', arcgisInfoGet);
|