@basemaps/lambda-tiler 6.30.0 → 6.32.1

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 (276) hide show
  1. package/CHANGELOG.md +46 -0
  2. package/build/__tests__/config.data.d.ts +6 -1
  3. package/build/__tests__/config.data.d.ts.map +1 -1
  4. package/build/__tests__/config.data.js +33 -2
  5. package/build/__tests__/config.data.js.map +1 -1
  6. package/build/__tests__/index.test.js +3 -13
  7. package/build/__tests__/index.test.js.map +1 -1
  8. package/build/__tests__/wmts.capability.test.js +88 -6
  9. package/build/__tests__/wmts.capability.test.js.map +1 -1
  10. package/build/__tests__/xyz.util.d.ts +7 -9
  11. package/build/__tests__/xyz.util.d.ts.map +1 -1
  12. package/build/__tests__/xyz.util.js +14 -20
  13. package/build/__tests__/xyz.util.js.map +1 -1
  14. package/build/index.d.ts +0 -2
  15. package/build/index.d.ts.map +1 -1
  16. package/build/index.js +57 -26
  17. package/build/index.js.map +1 -1
  18. package/build/routes/__tests__/attribution.test.js +350 -400
  19. package/build/routes/__tests__/attribution.test.js.map +1 -1
  20. package/build/routes/__tests__/fonts.test.js +11 -5
  21. package/build/routes/__tests__/fonts.test.js.map +1 -1
  22. package/build/routes/__tests__/health.test.js +16 -13
  23. package/build/routes/__tests__/health.test.js.map +1 -1
  24. package/build/routes/__tests__/sprites.test.js +6 -0
  25. package/build/routes/__tests__/sprites.test.js.map +1 -1
  26. package/build/routes/__tests__/tile.json.test.d.ts +2 -0
  27. package/build/routes/__tests__/tile.json.test.d.ts.map +1 -0
  28. package/build/routes/__tests__/tile.json.test.js +124 -0
  29. package/build/routes/__tests__/tile.json.test.js.map +1 -0
  30. package/build/routes/__tests__/tile.style.json.test.d.ts +2 -0
  31. package/build/routes/__tests__/tile.style.json.test.d.ts.map +1 -0
  32. package/build/routes/__tests__/tile.style.json.test.js +95 -0
  33. package/build/routes/__tests__/tile.style.json.test.js.map +1 -0
  34. package/build/routes/__tests__/wmts.test.js +5 -44
  35. package/build/routes/__tests__/wmts.test.js.map +1 -1
  36. package/build/{__tests__ → routes/__tests__}/xyz.test.d.ts +0 -0
  37. package/build/routes/__tests__/xyz.test.d.ts.map +1 -0
  38. package/build/routes/__tests__/xyz.test.js +99 -0
  39. package/build/routes/__tests__/xyz.test.js.map +1 -0
  40. package/build/routes/attribution.d.ts +7 -5
  41. package/build/routes/attribution.d.ts.map +1 -1
  42. package/build/routes/attribution.js +49 -91
  43. package/build/routes/attribution.js.map +1 -1
  44. package/build/routes/fonts.d.ts +1 -1
  45. package/build/routes/fonts.d.ts.map +1 -1
  46. package/build/routes/fonts.js +30 -15
  47. package/build/routes/fonts.js.map +1 -1
  48. package/build/routes/health.d.ts +3 -3
  49. package/build/routes/health.d.ts.map +1 -1
  50. package/build/routes/health.js +15 -13
  51. package/build/routes/health.js.map +1 -1
  52. package/build/routes/imagery.d.ts.map +1 -1
  53. package/build/routes/imagery.js +11 -10
  54. package/build/routes/imagery.js.map +1 -1
  55. package/build/routes/ping.d.ts +3 -0
  56. package/build/routes/ping.d.ts.map +1 -0
  57. package/build/routes/ping.js +7 -0
  58. package/build/routes/ping.js.map +1 -0
  59. package/build/routes/sprites.d.ts.map +1 -1
  60. package/build/routes/sprites.js +16 -10
  61. package/build/routes/sprites.js.map +1 -1
  62. package/build/routes/tile.json.d.ts +7 -1
  63. package/build/routes/tile.json.d.ts.map +1 -1
  64. package/build/routes/tile.json.js +18 -21
  65. package/build/routes/tile.json.js.map +1 -1
  66. package/build/routes/tile.style.json.d.ts +6 -1
  67. package/build/routes/tile.style.json.d.ts.map +1 -1
  68. package/build/routes/tile.style.json.js +10 -13
  69. package/build/routes/tile.style.json.js.map +1 -1
  70. package/build/routes/tile.wmts.d.ts +9 -3
  71. package/build/routes/tile.wmts.d.ts.map +1 -1
  72. package/build/routes/tile.wmts.js +26 -35
  73. package/build/routes/tile.wmts.js.map +1 -1
  74. package/build/routes/tile.xyz.d.ts +14 -4
  75. package/build/routes/tile.xyz.d.ts.map +1 -1
  76. package/build/routes/tile.xyz.js +21 -17
  77. package/build/routes/tile.xyz.js.map +1 -1
  78. package/build/routes/tile.xyz.raster.d.ts +11 -0
  79. package/build/routes/tile.xyz.raster.d.ts.map +1 -0
  80. package/build/routes/tile.xyz.raster.js +90 -0
  81. package/build/routes/tile.xyz.raster.js.map +1 -0
  82. package/build/routes/tile.xyz.vector.d.ts +8 -0
  83. package/build/routes/tile.xyz.vector.d.ts.map +1 -0
  84. package/build/routes/tile.xyz.vector.js +46 -0
  85. package/build/routes/tile.xyz.vector.js.map +1 -0
  86. package/build/routes/version.d.ts +3 -0
  87. package/build/routes/version.d.ts.map +1 -0
  88. package/build/routes/version.js +9 -0
  89. package/build/routes/version.js.map +1 -0
  90. package/build/util/__test__/validate.test.d.ts +2 -0
  91. package/build/util/__test__/validate.test.d.ts.map +1 -0
  92. package/build/util/__test__/validate.test.js +66 -0
  93. package/build/util/__test__/validate.test.js.map +1 -0
  94. package/build/{cotar.cache.d.ts → util/cotar.serve.d.ts} +3 -8
  95. package/build/util/cotar.serve.d.ts.map +1 -0
  96. package/build/util/cotar.serve.js +41 -0
  97. package/build/util/cotar.serve.js.map +1 -0
  98. package/build/util/etag.d.ts +6 -0
  99. package/build/util/etag.d.ts.map +1 -0
  100. package/build/util/etag.js +20 -0
  101. package/build/util/etag.js.map +1 -0
  102. package/build/util/response.d.ts +4 -0
  103. package/build/util/response.d.ts.map +1 -0
  104. package/build/util/response.js +4 -0
  105. package/build/util/response.js.map +1 -0
  106. package/build/util/source.cache.d.ts +28 -0
  107. package/build/util/source.cache.d.ts.map +1 -0
  108. package/build/util/source.cache.js +53 -0
  109. package/build/util/source.cache.js.map +1 -0
  110. package/build/{source.tracer.d.ts → util/source.tracer.d.ts} +1 -0
  111. package/build/util/source.tracer.d.ts.map +1 -0
  112. package/build/{source.tracer.js → util/source.tracer.js} +3 -0
  113. package/build/util/source.tracer.js.map +1 -0
  114. package/build/util/swapping.lru.d.ts +21 -0
  115. package/build/util/swapping.lru.d.ts.map +1 -0
  116. package/build/util/swapping.lru.js +56 -0
  117. package/build/util/swapping.lru.js.map +1 -0
  118. package/build/util/validate.d.ts +46 -0
  119. package/build/util/validate.d.ts.map +1 -0
  120. package/build/util/validate.js +107 -0
  121. package/build/util/validate.js.map +1 -0
  122. package/build/wmts.capability.d.ts +1 -1
  123. package/build/wmts.capability.d.ts.map +1 -1
  124. package/build/wmts.capability.js +24 -8
  125. package/build/wmts.capability.js.map +1 -1
  126. package/dist/index.js +78 -76
  127. package/dist/node_modules/.package-lock.json +1 -1
  128. package/dist/package-lock.json +2 -2
  129. package/dist/package.json +1 -1
  130. package/package.json +10 -10
  131. package/src/__tests__/config.data.ts +41 -3
  132. package/src/__tests__/index.test.ts +3 -19
  133. package/src/__tests__/wmts.capability.test.ts +109 -6
  134. package/src/__tests__/xyz.util.ts +18 -21
  135. package/src/index.ts +66 -29
  136. package/src/routes/__tests__/attribution.test.ts +356 -403
  137. package/src/routes/__tests__/fonts.test.ts +11 -5
  138. package/src/routes/__tests__/health.test.ts +17 -13
  139. package/src/routes/__tests__/sprites.test.ts +6 -1
  140. package/src/routes/__tests__/tile.json.test.ts +145 -0
  141. package/src/routes/__tests__/tile.style.json.test.ts +105 -0
  142. package/src/routes/__tests__/wmts.test.ts +5 -55
  143. package/src/routes/__tests__/xyz.test.ts +119 -0
  144. package/src/routes/attribution.ts +59 -111
  145. package/src/routes/fonts.ts +29 -15
  146. package/src/routes/health.ts +17 -16
  147. package/src/routes/imagery.ts +10 -9
  148. package/src/routes/ping.ts +8 -0
  149. package/src/routes/sprites.ts +16 -10
  150. package/src/routes/tile.json.ts +24 -18
  151. package/src/routes/tile.style.json.ts +15 -12
  152. package/src/routes/tile.wmts.ts +30 -31
  153. package/src/routes/tile.xyz.raster.ts +106 -0
  154. package/src/routes/tile.xyz.ts +31 -16
  155. package/src/routes/tile.xyz.vector.ts +47 -0
  156. package/src/routes/version.ts +8 -0
  157. package/src/util/__test__/validate.test.ts +74 -0
  158. package/src/util/cotar.serve.ts +46 -0
  159. package/src/util/etag.ts +20 -0
  160. package/src/util/response.ts +4 -0
  161. package/src/util/source.cache.ts +71 -0
  162. package/src/{source.tracer.ts → util/source.tracer.ts} +4 -0
  163. package/src/util/swapping.lru.ts +63 -0
  164. package/src/util/validate.ts +126 -0
  165. package/src/wmts.capability.ts +30 -13
  166. package/tsconfig.tsbuildinfo +1 -1
  167. package/build/__tests__/route.test.d.ts +0 -2
  168. package/build/__tests__/route.test.d.ts.map +0 -1
  169. package/build/__tests__/route.test.js +0 -21
  170. package/build/__tests__/route.test.js.map +0 -1
  171. package/build/__tests__/tiff.cache.test.d.ts +0 -2
  172. package/build/__tests__/tiff.cache.test.d.ts.map +0 -1
  173. package/build/__tests__/tiff.cache.test.js +0 -59
  174. package/build/__tests__/tiff.cache.test.js.map +0 -1
  175. package/build/__tests__/tile.cache.key.test.d.ts +0 -2
  176. package/build/__tests__/tile.cache.key.test.d.ts.map +0 -1
  177. package/build/__tests__/tile.cache.key.test.js +0 -49
  178. package/build/__tests__/tile.cache.key.test.js.map +0 -1
  179. package/build/__tests__/tile.set.cache.test.d.ts +0 -2
  180. package/build/__tests__/tile.set.cache.test.d.ts.map +0 -1
  181. package/build/__tests__/tile.set.cache.test.js +0 -72
  182. package/build/__tests__/tile.set.cache.test.js.map +0 -1
  183. package/build/__tests__/tile.set.test.d.ts +0 -2
  184. package/build/__tests__/tile.set.test.d.ts.map +0 -1
  185. package/build/__tests__/tile.set.test.js +0 -12
  186. package/build/__tests__/tile.set.test.js.map +0 -1
  187. package/build/__tests__/xyz.test.d.ts.map +0 -1
  188. package/build/__tests__/xyz.test.js +0 -275
  189. package/build/__tests__/xyz.test.js.map +0 -1
  190. package/build/api.key.d.ts +0 -2
  191. package/build/api.key.d.ts.map +0 -1
  192. package/build/api.key.js +0 -24
  193. package/build/api.key.js.map +0 -1
  194. package/build/cli/dump.d.ts +0 -2
  195. package/build/cli/dump.d.ts.map +0 -1
  196. package/build/cli/dump.js +0 -48
  197. package/build/cli/dump.js.map +0 -1
  198. package/build/cli/tile.set.local.d.ts +0 -12
  199. package/build/cli/tile.set.local.d.ts.map +0 -1
  200. package/build/cli/tile.set.local.js +0 -40
  201. package/build/cli/tile.set.local.js.map +0 -1
  202. package/build/cotar.cache.d.ts.map +0 -1
  203. package/build/cotar.cache.js +0 -50
  204. package/build/cotar.cache.js.map +0 -1
  205. package/build/router.d.ts +0 -15
  206. package/build/router.d.ts.map +0 -1
  207. package/build/router.js +0 -50
  208. package/build/router.js.map +0 -1
  209. package/build/routes/api.d.ts +0 -4
  210. package/build/routes/api.d.ts.map +0 -1
  211. package/build/routes/api.js +0 -14
  212. package/build/routes/api.js.map +0 -1
  213. package/build/routes/esri/rest.d.ts +0 -10
  214. package/build/routes/esri/rest.d.ts.map +0 -1
  215. package/build/routes/esri/rest.js +0 -88
  216. package/build/routes/esri/rest.js.map +0 -1
  217. package/build/routes/response.d.ts +0 -4
  218. package/build/routes/response.d.ts.map +0 -1
  219. package/build/routes/response.js +0 -4
  220. package/build/routes/response.js.map +0 -1
  221. package/build/routes/tile.d.ts +0 -3
  222. package/build/routes/tile.d.ts.map +0 -1
  223. package/build/routes/tile.etag.d.ts +0 -11
  224. package/build/routes/tile.etag.d.ts.map +0 -1
  225. package/build/routes/tile.etag.js +0 -30
  226. package/build/routes/tile.etag.js.map +0 -1
  227. package/build/routes/tile.js +0 -28
  228. package/build/routes/tile.js.map +0 -1
  229. package/build/source.tracer.d.ts.map +0 -1
  230. package/build/source.tracer.js.map +0 -1
  231. package/build/tiff.cache.d.ts +0 -17
  232. package/build/tiff.cache.d.ts.map +0 -1
  233. package/build/tiff.cache.js +0 -46
  234. package/build/tiff.cache.js.map +0 -1
  235. package/build/tile.set.cache.d.ts +0 -20
  236. package/build/tile.set.cache.d.ts.map +0 -1
  237. package/build/tile.set.cache.js +0 -72
  238. package/build/tile.set.cache.js.map +0 -1
  239. package/build/tile.set.d.ts +0 -4
  240. package/build/tile.set.d.ts.map +0 -1
  241. package/build/tile.set.js +0 -2
  242. package/build/tile.set.js.map +0 -1
  243. package/build/tile.set.raster.d.ts +0 -49
  244. package/build/tile.set.raster.d.ts.map +0 -1
  245. package/build/tile.set.raster.js +0 -189
  246. package/build/tile.set.raster.js.map +0 -1
  247. package/build/tile.set.vector.d.ts +0 -18
  248. package/build/tile.set.vector.d.ts.map +0 -1
  249. package/build/tile.set.vector.js +0 -54
  250. package/build/tile.set.vector.js.map +0 -1
  251. package/build/validate.d.ts +0 -16
  252. package/build/validate.d.ts.map +0 -1
  253. package/build/validate.js +0 -32
  254. package/build/validate.js.map +0 -1
  255. package/src/__tests__/route.test.ts +0 -24
  256. package/src/__tests__/tiff.cache.test.ts +0 -73
  257. package/src/__tests__/tile.cache.key.test.ts +0 -56
  258. package/src/__tests__/tile.set.cache.test.ts +0 -80
  259. package/src/__tests__/tile.set.test.ts +0 -12
  260. package/src/__tests__/xyz.test.ts +0 -318
  261. package/src/api.key.ts +0 -23
  262. package/src/cli/dump.ts +0 -61
  263. package/src/cli/tile.set.local.ts +0 -51
  264. package/src/cotar.cache.ts +0 -54
  265. package/src/router.ts +0 -58
  266. package/src/routes/api.ts +0 -15
  267. package/src/routes/esri/rest.ts +0 -90
  268. package/src/routes/response.ts +0 -4
  269. package/src/routes/tile.etag.ts +0 -36
  270. package/src/routes/tile.ts +0 -23
  271. package/src/tiff.cache.ts +0 -51
  272. package/src/tile.set.cache.ts +0 -84
  273. package/src/tile.set.raster.ts +0 -230
  274. package/src/tile.set.ts +0 -4
  275. package/src/tile.set.vector.ts +0 -61
  276. package/src/validate.ts +0 -32
@@ -33,14 +33,16 @@ o.spec('/v1/fonts', () => {
33
33
  });
34
34
 
35
35
  o('should return empty list if no fonts found', async () => {
36
- const res = await fontList();
36
+ const res = await fontList(mockRequest('/v1/fonts.json'));
37
37
  o(res.status).equals(200);
38
38
  o(res.body).equals('[]');
39
+ o(res.header('etag')).notEquals(undefined);
40
+ o(res.header('cache-control')).equals('public, max-age=604800, stale-while-revalidate=86400');
39
41
  });
40
42
 
41
43
  o('should return 404 if no assets defined', async () => {
42
44
  delete process.env[Env.AssetLocation];
43
- const res = await fontList();
45
+ const res = await fontList(mockRequest('/v1/fonts.json'));
44
46
  o(res.status).equals(404);
45
47
  });
46
48
 
@@ -50,7 +52,7 @@ o.spec('/v1/fonts', () => {
50
52
  fsa.write('memory://fonts/Roboto Thin/256-512.pbf', Buffer.from('')),
51
53
  fsa.write('memory://fonts/Roboto Black/0-255.pbf', Buffer.from('')),
52
54
  ]);
53
- const res = await fontList();
55
+ const res = await fontList(mockRequest('/v1/fonts.json'));
54
56
  o(res.status).equals(200);
55
57
  o(res.header('content-type')).equals('application/json');
56
58
  o(res.header('content-encoding')).equals(undefined);
@@ -60,10 +62,12 @@ o.spec('/v1/fonts', () => {
60
62
  o('should get the correct font', async () => {
61
63
  await fsa.write('memory://fonts/Roboto Thin/0-255.pbf', Buffer.from(''));
62
64
 
63
- const res255 = await handler.router.handle(mockRequest(encodeURI('/v1/fonts/Roboto Thin/0-255.pbf')));
65
+ const res255 = await handler.router.handle(mockRequest('/v1/fonts/Roboto Thin/0-255.pbf'));
64
66
  o(res255.status).equals(200);
65
67
  o(res255.header('content-type')).equals('application/x-protobuf');
66
68
  o(res255.header('content-encoding')).equals(undefined);
69
+ o(res255.header('etag')).notEquals(undefined);
70
+ o(res255.header('cache-control')).equals('public, max-age=604800, stale-while-revalidate=86400');
67
71
 
68
72
  const res404 = await handler.router.handle(mockRequest('/v1/fonts/Roboto Thin/256-512.pbf'));
69
73
  o(res404.status).equals(404);
@@ -72,9 +76,11 @@ o.spec('/v1/fonts', () => {
72
76
  o('should get the correct utf8 font', async () => {
73
77
  await fsa.write('memory://fonts/🦄 🌈/0-255.pbf', Buffer.from(''));
74
78
 
75
- const res255 = await handler.router.handle(mockRequest(encodeURI('/v1/fonts/🦄 🌈/0-255.pbf')));
79
+ const res255 = await handler.router.handle(mockRequest('/v1/fonts/🦄 🌈/0-255.pbf'));
76
80
  o(res255.status).equals(200);
77
81
  o(res255.header('content-type')).equals('application/x-protobuf');
78
82
  o(res255.header('content-encoding')).equals(undefined);
83
+ o(res255.header('etag')).notEquals(undefined);
84
+ o(res255.header('cache-control')).equals('public, max-age=604800, stale-while-revalidate=86400');
79
85
  });
80
86
  });
@@ -1,12 +1,13 @@
1
- import { GoogleTms } from '@basemaps/geo';
1
+ import { Config, ConfigProviderMemory } from '@basemaps/config';
2
2
  import { LogConfig } from '@basemaps/shared';
3
3
  import { LambdaAlbRequest, LambdaHttpRequest, LambdaHttpResponse } from '@linzjs/lambda';
4
4
  import { Context } from 'aws-lambda';
5
5
  import o from 'ospec';
6
6
  import sinon from 'sinon';
7
- import { TileSets } from '../../tile.set.cache.js';
8
- import { TileSetRaster } from '../../tile.set.raster.js';
9
- import { getTestBuffer, Health, TestTiles } from '../health.js';
7
+ import { FakeData } from '../../__tests__/config.data.js';
8
+
9
+ import { getTestBuffer, healthGet, TestTiles } from '../health.js';
10
+ import { TileXyzRaster } from '../tile.xyz.raster.js';
10
11
 
11
12
  const ctx: LambdaHttpRequest = new LambdaAlbRequest(
12
13
  {
@@ -20,13 +21,16 @@ const ctx: LambdaHttpRequest = new LambdaAlbRequest(
20
21
  LogConfig.get(),
21
22
  );
22
23
 
23
- o.spec('health', async () => {
24
+ o.spec('/v1/health', async () => {
24
25
  o.specTimeout(1000);
25
26
  const sandbox = sinon.createSandbox();
27
+ const config = new ConfigProviderMemory();
26
28
 
27
- const tileSet = new TileSetRaster('health', GoogleTms);
29
+ const fakeTileSet = FakeData.tileSetRaster('health');
28
30
  o.beforeEach(() => {
29
- sandbox.stub(TileSets, 'get').resolves(tileSet);
31
+ config.objects.clear();
32
+ Config.setConfigProvider(config);
33
+ config.put(fakeTileSet);
30
34
  });
31
35
 
32
36
  o.afterEach(() => {
@@ -36,10 +40,10 @@ o.spec('health', async () => {
36
40
  o('Should return bad response', async () => {
37
41
  // Given ... a bad get tile response
38
42
  const BadResponse = new LambdaHttpResponse(500, 'Can not get Tile Set.');
39
- sandbox.stub(tileSet, 'tile').resolves(BadResponse);
43
+ sandbox.stub(TileXyzRaster, 'tile').resolves(BadResponse);
40
44
 
41
45
  // When ...
42
- const res = await Health(ctx);
46
+ const res = await healthGet(ctx);
43
47
 
44
48
  // Then ...
45
49
  o(res.status).equals(500);
@@ -59,12 +63,12 @@ o.spec('health', async () => {
59
63
 
60
64
  o('Should give a 200 response', async () => {
61
65
  // Given ... a series good get tile response
62
- const callback = sandbox.stub(tileSet, 'tile');
66
+ const callback = sandbox.stub(TileXyzRaster, 'tile');
63
67
  callback.onCall(0).resolves(Response1);
64
68
  callback.onCall(1).resolves(Response2);
65
69
 
66
70
  // When ...
67
- const res = await Health(ctx);
71
+ const res = await healthGet(ctx);
68
72
 
69
73
  // Then ...
70
74
  o(res.status).equals(200);
@@ -73,12 +77,12 @@ o.spec('health', async () => {
73
77
 
74
78
  o('Should return mis-match tile response', async () => {
75
79
  // Given ... a bad get tile response for second get tile
76
- const callback = sandbox.stub(tileSet, 'tile');
80
+ const callback = sandbox.stub(TileXyzRaster, 'tile');
77
81
  callback.onCall(0).resolves(Response1);
78
82
  callback.onCall(1).resolves(Response1);
79
83
 
80
84
  // When ...
81
- const res = await Health(ctx);
85
+ const res = await healthGet(ctx);
82
86
 
83
87
  // Then ...
84
88
  o(res.status).equals(500);
@@ -36,6 +36,8 @@ o.spec('/v1/sprites', () => {
36
36
  o(res.status).equals(200);
37
37
  o(res.header('content-type')).equals('application/json');
38
38
  o(res.header('content-encoding')).equals(undefined);
39
+ o(res.header('etag')).notEquals(undefined);
40
+ o(res.header('cache-control')).equals('public, max-age=604800, stale-while-revalidate=86400');
39
41
 
40
42
  o(JSON.parse(Buffer.from(res.body, 'base64').toString())).deepEquals({ test: true });
41
43
  });
@@ -48,6 +50,8 @@ o.spec('/v1/sprites', () => {
48
50
  const res = await handler.router.handle(mockRequest('/v1/sprites/topographic@2x.png'));
49
51
  o(res.status).equals(200);
50
52
  o(res.header('content-type')).equals('image/png');
53
+ o(res.header('etag')).notEquals(undefined);
54
+ o(res.header('cache-control')).equals('public, max-age=604800, stale-while-revalidate=86400');
51
55
  });
52
56
 
53
57
  o('should detect gziped files and set content-encoding', async () => {
@@ -58,7 +62,8 @@ o.spec('/v1/sprites', () => {
58
62
  o(res.status).equals(200);
59
63
  o(res.header('content-type')).equals('application/json');
60
64
  o(res.header('content-encoding')).equals('gzip');
61
-
65
+ o(res.header('etag')).notEquals(undefined);
66
+ o(res.header('cache-control')).equals('public, max-age=604800, stale-while-revalidate=86400');
62
67
  o(JSON.parse(gunzipSync(Buffer.from(res.body, 'base64')).toString())).deepEquals({ test: true });
63
68
  });
64
69
  });
@@ -0,0 +1,145 @@
1
+ import { Config, ConfigProviderMemory } from '@basemaps/config';
2
+ import { Env } from '@basemaps/shared';
3
+ import o from 'ospec';
4
+ import { handler } from '../../index.js';
5
+ import { CoSources } from '../../util/source.cache.js';
6
+ import { FakeData } from '../../__tests__/config.data.js';
7
+ import { Api, mockRequest, mockUrlRequest } from '../../__tests__/xyz.util.js';
8
+
9
+ o.spec('/v1/tiles/:tileSet/:tileMatrix/tile.json', () => {
10
+ const config = new ConfigProviderMemory();
11
+ o.before(() => {
12
+ process.env[Env.PublicUrlBase] = 'https://tiles.test';
13
+ Config.setConfigProvider(config);
14
+ });
15
+
16
+ o.beforeEach(() => {
17
+ config.objects.clear();
18
+ CoSources.cache.clear();
19
+ });
20
+
21
+ o('should 404 if invalid url is given', async () => {
22
+ const request = mockRequest('/v1/tiles/tile.json', 'get', Api.header);
23
+
24
+ const res = await handler.router.handle(request);
25
+ o(res.status).equals(404);
26
+ });
27
+
28
+ o('should support utf8 tilesets', async () => {
29
+ const request = mockUrlRequest('/v1/tiles/🦄 🌈/NZTM2000Quad/tile.json', `api=${Api.key}`);
30
+ o(request.path).equals('/v1/tiles/%F0%9F%A6%84%20%F0%9F%8C%88/NZTM2000Quad/tile.json');
31
+
32
+ const fakeTileSet = FakeData.tileSetRaster('🦄 🌈');
33
+ config.put(fakeTileSet);
34
+
35
+ const res = await handler.router.handle(request);
36
+ o(res.status).equals(200);
37
+ });
38
+
39
+ o('should serve tile json for tile_set', async () => {
40
+ const request = mockRequest('/v1/tiles/aerial/NZTM2000Quad/tile.json', 'get', Api.header);
41
+ const fakeTileSet = FakeData.tileSetRaster('aerial');
42
+ config.put(fakeTileSet);
43
+
44
+ const res = await handler.router.handle(request);
45
+ o(res.status).equals(200);
46
+ o(res.header('cache-control')).equals('no-store');
47
+
48
+ const body = Buffer.from(res.body ?? '', 'base64').toString();
49
+ o(JSON.parse(body)).deepEquals({
50
+ tiles: [`https://tiles.test/v1/tiles/aerial/NZTM2000Quad/{z}/{x}/{y}.webp?api=${Api.key}`],
51
+ tilejson: '3.0.0',
52
+ });
53
+ });
54
+
55
+ o('should use the correct format', async () => {
56
+ const request = mockRequest('/v1/tiles/aerial/NZTM2000Quad/tile.json', 'get', Api.header);
57
+ request.query.set('format', 'jpeg');
58
+
59
+ const fakeTileSet = FakeData.tileSetRaster('aerial');
60
+ config.put(fakeTileSet);
61
+
62
+ const res = await handler.router.handle(request);
63
+ o(res.status).equals(200);
64
+ o(res.header('cache-control')).equals('no-store');
65
+
66
+ const body = Buffer.from(res.body ?? '', 'base64').toString();
67
+ o(JSON.parse(body)).deepEquals({
68
+ tiles: [`https://tiles.test/v1/tiles/aerial/NZTM2000Quad/{z}/{x}/{y}.jpeg?api=${Api.key}`],
69
+ tilejson: '3.0.0',
70
+ });
71
+ });
72
+
73
+ o('should use the correct format when multiple set', async () => {
74
+ const request = mockRequest('/v1/tiles/aerial/NZTM2000Quad/tile.json', 'get', Api.header);
75
+ request.query.append('format', 'png');
76
+ request.query.append('format', 'jpeg');
77
+
78
+ const fakeTileSet = FakeData.tileSetRaster('aerial');
79
+ config.put(fakeTileSet);
80
+
81
+ const res = await handler.router.handle(request);
82
+ o(res.status).equals(200);
83
+ o(res.header('cache-control')).equals('no-store');
84
+
85
+ const body = Buffer.from(res.body ?? '', 'base64').toString();
86
+ o(JSON.parse(body)).deepEquals({
87
+ tiles: [`https://tiles.test/v1/tiles/aerial/NZTM2000Quad/{z}/{x}/{y}.png?api=${Api.key}`],
88
+ tilejson: '3.0.0',
89
+ });
90
+ });
91
+
92
+ o('should serve vector tiles', async () => {
93
+ const request = mockRequest('/v1/tiles/topographic/EPSG:3857/tile.json', 'get', Api.header);
94
+ const fakeTileSet = FakeData.tileSetVector('topographic');
95
+ config.put(fakeTileSet);
96
+
97
+ const res = await handler.router.handle(request);
98
+ o(res.status).equals(200);
99
+
100
+ const body = Buffer.from(res.body ?? '', 'base64').toString();
101
+ o(JSON.parse(body)).deepEquals({
102
+ tiles: [`https://tiles.test/v1/tiles/topographic/WebMercatorQuad/{z}/{x}/{y}.pbf?api=${Api.key}`],
103
+ tilejson: '3.0.0',
104
+ });
105
+ });
106
+
107
+ o('should serve vector tiles with min/max zoom', async () => {
108
+ const fakeTileSet = FakeData.tileSetVector('fake-vector');
109
+ fakeTileSet.maxZoom = 15;
110
+ fakeTileSet.minZoom = 3;
111
+ config.put(fakeTileSet);
112
+ const request = mockRequest('/v1/tiles/fake-vector/WebMercatorQuad/tile.json', 'get', Api.header);
113
+
114
+ const res = await handler.router.handle(request);
115
+ o(res.status).equals(200);
116
+
117
+ const body = Buffer.from(res.body ?? '', 'base64').toString();
118
+ o(JSON.parse(body)).deepEquals({
119
+ tiles: [`https://tiles.test/v1/tiles/fake-vector/WebMercatorQuad/{z}/{x}/{y}.pbf?api=${Api.key}`],
120
+ maxzoom: 15,
121
+ minzoom: 3,
122
+ tilejson: '3.0.0',
123
+ });
124
+ });
125
+
126
+ o('should serve convert zoom to tile matrix', async () => {
127
+ const fakeTileSet = FakeData.tileSetVector('fake-vector');
128
+ fakeTileSet.maxZoom = 15;
129
+ fakeTileSet.minZoom = 1;
130
+ config.put(fakeTileSet);
131
+
132
+ const request = mockRequest('/v1/tiles/fake-vector/NZTM2000Quad/tile.json', 'get', Api.header);
133
+
134
+ const res = await handler.router.handle(request);
135
+ o(res.status).equals(200);
136
+
137
+ const body = Buffer.from(res.body ?? '', 'base64').toString();
138
+ o(JSON.parse(body)).deepEquals({
139
+ tiles: [`https://tiles.test/v1/tiles/fake-vector/NZTM2000Quad/{z}/{x}/{y}.pbf?api=${Api.key}`],
140
+ maxzoom: 13,
141
+ minzoom: 0,
142
+ tilejson: '3.0.0',
143
+ });
144
+ });
145
+ });
@@ -0,0 +1,105 @@
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 { Api, mockRequest } from '../../__tests__/xyz.util.js';
7
+
8
+ o.spec('/v1/styles', () => {
9
+ const host = 'https://tiles.test';
10
+ const sandbox = createSandbox();
11
+
12
+ o.before(() => {
13
+ process.env[Env.PublicUrlBase] = host;
14
+ });
15
+ // o.beforeEach(() => {});
16
+ o.afterEach(() => sandbox.restore());
17
+ o('should not found style json', async () => {
18
+ const request = mockRequest('/v1/tiles/topographic/Google/style/topographic.json', 'get', Api.header);
19
+
20
+ sandbox.stub(Config.Style, 'get').resolves(null);
21
+
22
+ const res = await handler.router.handle(request);
23
+ o(res.status).equals(404);
24
+ });
25
+
26
+ o('should serve style json', async () => {
27
+ const request = mockRequest('/v1/tiles/topographic/Google/style/topographic.json', 'get', Api.header);
28
+
29
+ const fakeStyle: StyleJson = {
30
+ version: 8,
31
+ id: 'test',
32
+ name: 'topographic',
33
+ sources: {
34
+ basemaps_vector: {
35
+ type: 'vector',
36
+ url: `/vector`,
37
+ },
38
+ basemaps_raster: {
39
+ type: 'raster',
40
+ tiles: [`/raster`],
41
+ },
42
+ basemaps_raster_encode: {
43
+ type: 'raster',
44
+ tiles: [`/raster/{z}/{x}/{y}.webp`], // Shouldn't encode the {}
45
+ },
46
+ test_vector: {
47
+ type: 'vector',
48
+ url: 'vector.url.co.nz',
49
+ },
50
+ test_raster: {
51
+ type: 'raster',
52
+ tiles: ['raster.url.co.nz'],
53
+ },
54
+ },
55
+ layers: [
56
+ {
57
+ layout: {
58
+ visibility: 'visible',
59
+ },
60
+ paint: {
61
+ 'background-color': 'rgba(206, 229, 242, 1)',
62
+ },
63
+ id: 'Background',
64
+ type: 'background',
65
+ minzoom: 0,
66
+ },
67
+ ],
68
+ glyphs: '/glyphs',
69
+ sprite: '/sprite',
70
+ metadata: { id: 'test' },
71
+ };
72
+
73
+ const fakeRecord = {
74
+ id: 'st_topographic_production',
75
+ name: 'topographic',
76
+ style: fakeStyle,
77
+ };
78
+
79
+ sandbox.stub(Config.Style, 'get').resolves(fakeRecord as any);
80
+
81
+ const res = await handler.router.handle(request);
82
+ o(res.status).equals(200);
83
+ o(res.header('content-type')).equals('application/json');
84
+ o(res.header('cache-control')).equals('no-store');
85
+
86
+ const body = Buffer.from(res.body ?? '', 'base64').toString();
87
+ fakeStyle.sources.basemaps_vector = {
88
+ type: 'vector',
89
+ url: `${host}/vector?api=${Api.key}`,
90
+ };
91
+ fakeStyle.sources.basemaps_raster = {
92
+ type: 'raster',
93
+ tiles: [`${host}/raster?api=${Api.key}`],
94
+ };
95
+ fakeStyle.sources.basemaps_raster_encode = {
96
+ type: 'raster',
97
+ tiles: [`${host}/raster/{z}/{x}/{y}.webp?api=${Api.key}`],
98
+ };
99
+
100
+ fakeStyle.sprite = `${host}/sprite`;
101
+ fakeStyle.glyphs = `${host}/glyphs`;
102
+
103
+ o(JSON.parse(body)).deepEquals(fakeStyle);
104
+ });
105
+ });
@@ -1,59 +1,9 @@
1
- import { ImageFormat } from '@basemaps/geo';
2
- import { Config, LogConfig } from '@basemaps/shared';
3
- import { LambdaHttpRequest, LambdaUrlRequest } from '@linzjs/lambda';
4
- import { Context } from 'aws-lambda';
1
+ import { Config } from '@basemaps/shared';
5
2
  import o from 'ospec';
6
- import { handleRequest } from '../../index.js';
7
- import { ulid } from 'ulid';
8
- import { getImageFormats } from '../tile.wmts.js';
9
3
  import { createSandbox } from 'sinon';
4
+ import { handler } from '../../index.js';
10
5
  import { Imagery2193, Imagery3857, Provider, TileSetAerial } from '../../__tests__/config.data.js';
11
-
12
- function newRequest(path: string, query: string): LambdaHttpRequest {
13
- return new LambdaUrlRequest(
14
- {
15
- requestContext: { http: { method: 'GET' } },
16
- headers: {},
17
- rawPath: path,
18
- rawQueryString: query,
19
- isBase64Encoded: false,
20
- } as any,
21
- {} as Context,
22
- LogConfig.get(),
23
- );
24
- }
25
-
26
- o.spec('GetImageFormats', () => {
27
- o('should parse all formats', () => {
28
- const req = newRequest('/v1/blank', 'format=png&format=jpeg');
29
- const formats = getImageFormats(req);
30
- o(formats).deepEquals([ImageFormat.Png, ImageFormat.Jpeg]);
31
- });
32
-
33
- o('should ignore bad formats', () => {
34
- const req = newRequest('/v1/blank', 'format=fake&format=mvt');
35
- const formats = getImageFormats(req);
36
- o(formats).equals(undefined);
37
- });
38
-
39
- o('should de-dupe formats', () => {
40
- const req = newRequest('/v1/blank', 'format=png&format=jpeg&format=png&format=jpeg&format=png&format=jpeg');
41
- const formats = getImageFormats(req);
42
- o(formats).deepEquals([ImageFormat.Png, ImageFormat.Jpeg]);
43
- });
44
-
45
- o('should support "tileFormat" Alias all formats', () => {
46
- const req = newRequest('/v1/blank', 'tileFormat=png&format=jpeg');
47
- const formats = getImageFormats(req);
48
- o(formats).deepEquals([ImageFormat.Jpeg, ImageFormat.Png]);
49
- });
50
-
51
- o('should not duplicate "tileFormat" alias all formats', () => {
52
- const req = newRequest('/v1/blank', 'tileFormat=jpeg&format=jpeg');
53
- const formats = getImageFormats(req);
54
- o(formats).deepEquals([ImageFormat.Jpeg]);
55
- });
56
- });
6
+ import { Api, mockUrlRequest } from '../../__tests__/xyz.util.js';
57
7
 
58
8
  o.spec('WMTSRouting', () => {
59
9
  const sandbox = createSandbox();
@@ -70,8 +20,8 @@ o.spec('WMTSRouting', () => {
70
20
  const imageryStub = sandbox.stub(Config.Imagery, 'getAll').returns(Promise.resolve(imagery));
71
21
  const providerStub = sandbox.stub(Config.Provider, 'get').returns(Promise.resolve(Provider));
72
22
 
73
- const req = newRequest('/v1/tiles/WMTSCapabilities.xml', 'format=png&api=c' + ulid());
74
- const res = await handleRequest(req);
23
+ const req = mockUrlRequest('/v1/tiles/WMTSCapabilities.xml', `format=png&api=${Api.key}`);
24
+ const res = await handler.router.handle(req);
75
25
 
76
26
  o(tileSetStub.calledOnce).equals(true);
77
27
  o(tileSetStub.args[0][0]).equals('ts_aerial');
@@ -0,0 +1,119 @@
1
+ import { Config, ConfigProviderMemory } from '@basemaps/config';
2
+ import { LogConfig } from '@basemaps/shared';
3
+ import { round } from '@basemaps/test/build/rounding.js';
4
+ import o from 'ospec';
5
+ import sinon from 'sinon';
6
+ import { handler } from '../../index.js';
7
+ import { Etag } from '../../util/etag.js';
8
+ import { FakeData } from '../../__tests__/config.data.js';
9
+ import { Api, mockRequest } from '../../__tests__/xyz.util.js';
10
+
11
+ const sandbox = sinon.createSandbox();
12
+
13
+ const TileSetNames = ['aerial', 'aerial:ōtorohanga_urban_2021_0-1m_RGB', '01FYWKAJ86W9P7RWM1VB62KD0H'];
14
+ o.spec('/v1/tiles', () => {
15
+ const config = new ConfigProviderMemory();
16
+
17
+ o.beforeEach(() => {
18
+ LogConfig.get().level = 'silent';
19
+ Config.setConfigProvider(config);
20
+ config.objects.clear();
21
+
22
+ for (const tileSetName of TileSetNames) config.put(FakeData.tileSetRaster(tileSetName));
23
+
24
+ sandbox.stub(Etag, 'key').returns('fakeEtag');
25
+ });
26
+
27
+ o.afterEach(() => {
28
+ sandbox.restore();
29
+ });
30
+
31
+ o('should export handler', async () => {
32
+ const base = await import('../../index.js');
33
+ o(typeof base.handler).equals('function');
34
+ });
35
+
36
+ TileSetNames.forEach((tileSetName) => {
37
+ o(`should generate a tile/v1/tiles/${tileSetName}/global-mercator/0/0/0.png`, async () => {
38
+ const request = mockRequest(`/v1/tiles/${tileSetName}/global-mercator/0/0/0.png`, 'get', Api.header);
39
+ const res = await handler.router.handle(request);
40
+ o(res.status).equals(200);
41
+ o(res.header('content-type')).equals('image/png');
42
+ o(res.header('eTaG')).equals('fakeEtag');
43
+
44
+ // Validate the session information has been set correctly
45
+ o(request.logContext['tileSet']).equals(tileSetName);
46
+ o(request.logContext['xyz']).deepEquals({ x: 0, y: 0, z: 0 });
47
+ o(round(request.logContext['location'])).deepEquals({ lat: 0, lon: 0 });
48
+ });
49
+ });
50
+
51
+ o('should generate a tile 0,0,0 for webp', async () => {
52
+ const request = mockRequest('/v1/tiles/aerial/3857/0/0/0.webp', 'get', Api.header);
53
+ const res = await handler.router.handle(request);
54
+ o(res.status).equals(200);
55
+ o(res.header('content-type')).equals('image/webp');
56
+ o(res.header('eTaG')).equals('fakeEtag');
57
+ // o(res.body).equals(rasterMockBuffer.toString('base64'));
58
+
59
+ // Validate the session information has been set correctly
60
+ o(request.logContext['xyz']).deepEquals({ x: 0, y: 0, z: 0 });
61
+ o(round(request.logContext['location'])).deepEquals({ lat: 0, lon: 0 });
62
+ });
63
+
64
+ ['png', 'webp', 'jpeg', 'avif'].forEach((fmt) => {
65
+ o(`should 200 with empty ${fmt} if a tile is out of bounds`, async () => {
66
+ // tiler.tile = async () => [];
67
+ const res = await handler.router.handle(
68
+ mockRequest(`/v1/tiles/aerial/global-mercator/0/0/0.${fmt}`, 'get', Api.header),
69
+ );
70
+ o(res.status).equals(200);
71
+ o(res.header('content-type')).equals(`image/${fmt}`);
72
+ o(res.header('etag')).notEquals(undefined);
73
+ o(res.header('cache-control')).equals('public, max-age=604800, stale-while-revalidate=86400');
74
+ // o(rasterMock.calls.length).equals(1);
75
+ });
76
+ });
77
+
78
+ o('should 304 if a tile is not modified', async () => {
79
+ const key = 'fakeEtag';
80
+ const request = mockRequest('/v1/tiles/aerial/global-mercator/0/0/0.png', 'get', {
81
+ 'if-none-match': key,
82
+ ...Api.header,
83
+ });
84
+ const res = await handler.router.handle(request);
85
+ o(res.status).equals(304);
86
+ o(res.header('eTaG')).equals(undefined);
87
+
88
+ o(request.logContext['cache']).deepEquals({ match: key, hit: true });
89
+ });
90
+
91
+ o('should 404 if a tile is outside of the range', async () => {
92
+ const res = await handler.router.handle(
93
+ mockRequest('/v1/tiles/aerial/global-mercator/25/0/0.png', 'get', Api.header),
94
+ );
95
+ o(res.status).equals(404);
96
+
97
+ const resB = await handler.router.handle(mockRequest('/v1/tiles/aerial/2193/17/0/0.png', 'get', Api.header));
98
+ o(resB.status).equals(404);
99
+ });
100
+
101
+ o('should support utf8 tilesets', async () => {
102
+ const fakeTileSet = FakeData.tileSetRaster('🦄 🌈');
103
+ config.put(fakeTileSet);
104
+ const req = mockRequest('/v1/tiles/🦄 🌈/global-mercator/0/0/0.png', 'get', Api.header);
105
+ o(req.path).equals('/v1/tiles/%F0%9F%A6%84%20%F0%9F%8C%88/global-mercator/0/0/0.png');
106
+ const res = await handler.router.handle(req);
107
+ o(res.status).equals(200);
108
+ o(res.header('content-type')).equals('image/png');
109
+ o(res.header('etag')).notEquals(undefined);
110
+ o(res.header('cache-control')).equals('public, max-age=604800, stale-while-revalidate=86400');
111
+ });
112
+
113
+ ['/favicon.ico', '/index.html', '/foo/bar'].forEach((path) => {
114
+ o('should 404 on invalid paths: ' + path, async () => {
115
+ const res = await handler.router.handle(mockRequest(path, 'get', Api.header));
116
+ o(res.status).equals(404);
117
+ });
118
+ });
119
+ });