@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.
Files changed (95) hide show
  1. package/CHANGELOG.md +49 -0
  2. package/build/__tests__/xyz.util.d.ts +1 -1
  3. package/build/__tests__/xyz.util.d.ts.map +1 -1
  4. package/build/__tests__/xyz.util.js +2 -2
  5. package/build/__tests__/xyz.util.js.map +1 -1
  6. package/build/arcgis/__tests__/arcgis.style.json.test.d.ts +2 -0
  7. package/build/arcgis/__tests__/arcgis.style.json.test.d.ts.map +1 -0
  8. package/build/arcgis/__tests__/arcgis.style.json.test.js +128 -0
  9. package/build/arcgis/__tests__/arcgis.style.json.test.js.map +1 -0
  10. package/build/arcgis/__tests__/vector.tiler.server.test.d.ts +2 -0
  11. package/build/arcgis/__tests__/vector.tiler.server.test.d.ts.map +1 -0
  12. package/build/arcgis/__tests__/vector.tiler.server.test.js +47 -0
  13. package/build/arcgis/__tests__/vector.tiler.server.test.js.map +1 -0
  14. package/build/arcgis/arcgis.info.d.ts +3 -0
  15. package/build/arcgis/arcgis.info.d.ts.map +1 -0
  16. package/build/arcgis/arcgis.info.js +25 -0
  17. package/build/arcgis/arcgis.info.js.map +1 -0
  18. package/build/arcgis/arcgis.style.json.d.ts +9 -0
  19. package/build/arcgis/arcgis.style.json.d.ts.map +1 -0
  20. package/build/arcgis/arcgis.style.json.js +73 -0
  21. package/build/arcgis/arcgis.style.json.js.map +1 -0
  22. package/build/arcgis/vector.tile.server.d.ts +8 -0
  23. package/build/arcgis/vector.tile.server.d.ts.map +1 -0
  24. package/build/arcgis/vector.tile.server.js +71 -0
  25. package/build/arcgis/vector.tile.server.js.map +1 -0
  26. package/build/index.d.ts.map +1 -1
  27. package/build/index.js +22 -8
  28. package/build/index.js.map +1 -1
  29. package/build/routes/__tests__/fonts.test.js +14 -26
  30. package/build/routes/__tests__/fonts.test.js.map +1 -1
  31. package/build/routes/__tests__/sprites.test.js +7 -1
  32. package/build/routes/__tests__/sprites.test.js.map +1 -1
  33. package/build/routes/__tests__/xyz.test.js +1 -2
  34. package/build/routes/__tests__/xyz.test.js.map +1 -1
  35. package/build/routes/fonts.d.ts +0 -2
  36. package/build/routes/fonts.d.ts.map +1 -1
  37. package/build/routes/fonts.js +3 -66
  38. package/build/routes/fonts.js.map +1 -1
  39. package/build/routes/sprites.d.ts.map +1 -1
  40. package/build/routes/sprites.js +3 -29
  41. package/build/routes/sprites.js.map +1 -1
  42. package/build/routes/tile.xyz.vector.js +2 -2
  43. package/build/routes/tile.xyz.vector.js.map +1 -1
  44. package/build/util/assets.provider.d.ts +27 -0
  45. package/build/util/assets.provider.d.ts.map +1 -0
  46. package/build/util/assets.provider.js +56 -0
  47. package/build/util/assets.provider.js.map +1 -0
  48. package/build/util/config.cache.d.ts +16 -0
  49. package/build/util/config.cache.d.ts.map +1 -0
  50. package/build/util/config.cache.js +41 -0
  51. package/build/util/config.cache.js.map +1 -0
  52. package/build/util/response.d.ts +3 -1
  53. package/build/util/response.d.ts.map +1 -1
  54. package/build/util/response.js +2 -0
  55. package/build/util/response.js.map +1 -1
  56. package/build/util/source.cache.d.ts +1 -0
  57. package/build/util/source.cache.d.ts.map +1 -1
  58. package/build/util/source.cache.js +2 -1
  59. package/build/util/source.cache.js.map +1 -1
  60. package/build/util/swapping.lru.d.ts +1 -0
  61. package/build/util/swapping.lru.d.ts.map +1 -1
  62. package/build/util/swapping.lru.js +7 -0
  63. package/build/util/swapping.lru.js.map +1 -1
  64. package/build/util/validate.d.ts +0 -5
  65. package/build/util/validate.d.ts.map +1 -1
  66. package/build/util/validate.js +1 -23
  67. package/build/util/validate.js.map +1 -1
  68. package/dist/index.js +52 -52
  69. package/dist/node_modules/.package-lock.json +4 -4
  70. package/dist/node_modules/node-abi/abi_registry.json +8 -1
  71. package/dist/node_modules/node-abi/package.json +1 -1
  72. package/dist/package-lock.json +8 -8
  73. package/dist/package.json +1 -1
  74. package/package.json +4 -4
  75. package/src/__tests__/xyz.util.ts +7 -2
  76. package/src/arcgis/__tests__/arcgis.style.json.test.ts +153 -0
  77. package/src/arcgis/__tests__/vector.tiler.server.test.ts +61 -0
  78. package/src/arcgis/arcgis.info.ts +26 -0
  79. package/src/arcgis/arcgis.style.json.ts +81 -0
  80. package/src/arcgis/vector.tile.server.ts +78 -0
  81. package/src/index.ts +25 -8
  82. package/src/routes/__tests__/fonts.test.ts +14 -29
  83. package/src/routes/__tests__/sprites.test.ts +7 -2
  84. package/src/routes/__tests__/xyz.test.ts +2 -2
  85. package/src/routes/fonts.ts +4 -64
  86. package/src/routes/sprites.ts +4 -27
  87. package/src/routes/tile.xyz.vector.ts +2 -2
  88. package/src/util/assets.provider.ts +67 -0
  89. package/src/util/config.cache.ts +44 -0
  90. package/src/util/response.ts +4 -1
  91. package/src/util/source.cache.ts +2 -1
  92. package/src/util/swapping.lru.ts +7 -0
  93. package/src/util/validate.ts +1 -27
  94. package/tsconfig.json +1 -0
  95. package/tsconfig.tsbuildinfo +1 -1
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@basemaps/lambda-tiler",
3
- "version": "6.32.1",
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.22.0",
230
- "resolved": "https://registry.npmjs.org/node-abi/-/node-abi-3.22.0.tgz",
231
- "integrity": "sha512-u4uAs/4Zzmp/jjsD9cyFYDXeISfUWaAVWshPmDZOFOv4Xl4SbzTXm53I04C2uRueYJ+0t5PEtLH/owbn2Npf/w==",
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": true,
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
  ]
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "node-abi",
3
- "version": "3.22.0",
3
+ "version": "3.24.0",
4
4
  "description": "Get the Node ABI for a given target and runtime, and vice versa.",
5
5
  "main": "index.js",
6
6
  "scripts": {
@@ -1,12 +1,12 @@
1
1
  {
2
2
  "name": "@basemaps/lambda-tiler",
3
- "version": "6.32.1",
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.32.1",
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.22.0",
241
- "resolved": "https://registry.npmjs.org/node-abi/-/node-abi-3.22.0.tgz",
242
- "integrity": "sha512-u4uAs/4Zzmp/jjsD9cyFYDXeISfUWaAVWshPmDZOFOv4Xl4SbzTXm53I04C2uRueYJ+0t5PEtLH/owbn2Npf/w==",
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.22.0",
651
- "resolved": "https://registry.npmjs.org/node-abi/-/node-abi-3.22.0.tgz",
652
- "integrity": "sha512-u4uAs/4Zzmp/jjsD9cyFYDXeISfUWaAVWshPmDZOFOv4Xl4SbzTXm53I04C2uRueYJ+0t5PEtLH/owbn2Npf/w==",
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
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@basemaps/lambda-tiler",
3
- "version": "6.32.1",
3
+ "version": "6.34.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": "6.32.1",
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.32.1",
25
+ "@basemaps/config": "^6.34.0",
26
26
  "@basemaps/geo": "^6.32.1",
27
27
  "@basemaps/lambda": "^6.7.0",
28
- "@basemaps/shared": "^6.32.1",
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": "4544a7d98667c5274142f1bb6bf61f02e4e5f618"
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(path: string, query = '', headers: Record<string, unknown> = {}): LambdaHttpRequest {
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, LambdaUrlRequest, lf } from '@linzjs/lambda';
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 { NotFound } from './util/response.js';
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
- // FunctionURLs automatically inject CORS responses for us
44
- if (!(req instanceof LambdaUrlRequest) && req.headers.has('origin')) {
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 function url hook so just return ok if the route exists
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);