@basemaps/lambda-tiler 6.29.0 → 6.32.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 (259) hide show
  1. package/CHANGELOG.md +63 -0
  2. package/build/__tests__/config.data.d.ts +11 -0
  3. package/build/__tests__/config.data.d.ts.map +1 -0
  4. package/build/__tests__/config.data.js +112 -0
  5. package/build/__tests__/config.data.js.map +1 -0
  6. package/build/__tests__/index.test.js +5 -14
  7. package/build/__tests__/index.test.js.map +1 -0
  8. package/build/__tests__/tile.style.json.test.js +1 -0
  9. package/build/__tests__/tile.style.json.test.js.map +1 -0
  10. package/build/__tests__/wmts.capability.test.d.ts +1 -1
  11. package/build/__tests__/wmts.capability.test.d.ts.map +1 -1
  12. package/build/__tests__/wmts.capability.test.js +286 -125
  13. package/build/__tests__/wmts.capability.test.js.map +1 -0
  14. package/build/__tests__/xyz.util.d.ts +7 -11
  15. package/build/__tests__/xyz.util.d.ts.map +1 -1
  16. package/build/__tests__/xyz.util.js +14 -42
  17. package/build/__tests__/xyz.util.js.map +1 -0
  18. package/build/index.d.ts +0 -2
  19. package/build/index.d.ts.map +1 -1
  20. package/build/index.js +68 -41
  21. package/build/index.js.map +1 -0
  22. package/build/routes/__tests__/attribution.test.js +351 -399
  23. package/build/routes/__tests__/attribution.test.js.map +1 -0
  24. package/build/routes/__tests__/fonts.test.js +17 -3
  25. package/build/routes/__tests__/fonts.test.js.map +1 -0
  26. package/build/routes/__tests__/health.test.js +17 -13
  27. package/build/routes/__tests__/health.test.js.map +1 -0
  28. package/build/routes/__tests__/imagery.test.js +1 -0
  29. package/build/routes/__tests__/imagery.test.js.map +1 -0
  30. package/build/routes/__tests__/memory.fs.js +1 -0
  31. package/build/routes/__tests__/memory.fs.js.map +1 -0
  32. package/build/routes/__tests__/sprites.test.js +7 -0
  33. package/build/routes/__tests__/sprites.test.js.map +1 -0
  34. package/build/routes/__tests__/tile.json.test.d.ts +2 -0
  35. package/build/routes/__tests__/tile.json.test.d.ts.map +1 -0
  36. package/build/routes/__tests__/tile.json.test.js +124 -0
  37. package/build/routes/__tests__/tile.json.test.js.map +1 -0
  38. package/build/routes/__tests__/tile.style.json.test.d.ts +2 -0
  39. package/build/routes/__tests__/tile.style.json.test.d.ts.map +1 -0
  40. package/build/routes/__tests__/tile.style.json.test.js +95 -0
  41. package/build/routes/__tests__/tile.style.json.test.js.map +1 -0
  42. package/build/routes/__tests__/wmts.test.js +37 -27
  43. package/build/routes/__tests__/wmts.test.js.map +1 -0
  44. package/build/{__tests__ → routes/__tests__}/xyz.test.d.ts +0 -0
  45. package/build/routes/__tests__/xyz.test.d.ts.map +1 -0
  46. package/build/routes/__tests__/xyz.test.js +99 -0
  47. package/build/routes/__tests__/xyz.test.js.map +1 -0
  48. package/build/routes/attribution.d.ts +7 -5
  49. package/build/routes/attribution.d.ts.map +1 -1
  50. package/build/routes/attribution.js +50 -91
  51. package/build/routes/attribution.js.map +1 -0
  52. package/build/routes/fonts.d.ts +1 -1
  53. package/build/routes/fonts.d.ts.map +1 -1
  54. package/build/routes/fonts.js +33 -10
  55. package/build/routes/fonts.js.map +1 -0
  56. package/build/routes/health.d.ts +3 -3
  57. package/build/routes/health.d.ts.map +1 -1
  58. package/build/routes/health.js +16 -13
  59. package/build/routes/health.js.map +1 -0
  60. package/build/routes/imagery.d.ts +8 -1
  61. package/build/routes/imagery.d.ts.map +1 -1
  62. package/build/routes/imagery.js +17 -17
  63. package/build/routes/imagery.js.map +1 -0
  64. package/build/routes/ping.d.ts +3 -0
  65. package/build/routes/ping.d.ts.map +1 -0
  66. package/build/routes/ping.js +7 -0
  67. package/build/routes/ping.js.map +1 -0
  68. package/build/routes/sprites.d.ts.map +1 -1
  69. package/build/routes/sprites.js +22 -22
  70. package/build/routes/sprites.js.map +1 -0
  71. package/build/routes/tile.json.d.ts +7 -1
  72. package/build/routes/tile.json.d.ts.map +1 -1
  73. package/build/routes/tile.json.js +19 -22
  74. package/build/routes/tile.json.js.map +1 -0
  75. package/build/routes/tile.style.json.d.ts +6 -1
  76. package/build/routes/tile.style.json.d.ts.map +1 -1
  77. package/build/routes/tile.style.json.js +11 -13
  78. package/build/routes/tile.style.json.js.map +1 -0
  79. package/build/routes/tile.wmts.d.ts +9 -3
  80. package/build/routes/tile.wmts.d.ts.map +1 -1
  81. package/build/routes/tile.wmts.js +37 -50
  82. package/build/routes/tile.wmts.js.map +1 -0
  83. package/build/routes/tile.xyz.d.ts +14 -4
  84. package/build/routes/tile.xyz.d.ts.map +1 -1
  85. package/build/routes/tile.xyz.js +22 -17
  86. package/build/routes/tile.xyz.js.map +1 -0
  87. package/build/routes/tile.xyz.raster.d.ts +11 -0
  88. package/build/routes/tile.xyz.raster.d.ts.map +1 -0
  89. package/build/routes/tile.xyz.raster.js +90 -0
  90. package/build/routes/tile.xyz.raster.js.map +1 -0
  91. package/build/routes/tile.xyz.vector.d.ts +8 -0
  92. package/build/routes/tile.xyz.vector.d.ts.map +1 -0
  93. package/build/routes/tile.xyz.vector.js +46 -0
  94. package/build/routes/tile.xyz.vector.js.map +1 -0
  95. package/build/routes/version.d.ts +3 -0
  96. package/build/routes/version.d.ts.map +1 -0
  97. package/build/routes/version.js +9 -0
  98. package/build/routes/version.js.map +1 -0
  99. package/build/util/__test__/validate.test.d.ts +2 -0
  100. package/build/util/__test__/validate.test.d.ts.map +1 -0
  101. package/build/util/__test__/validate.test.js +66 -0
  102. package/build/util/__test__/validate.test.js.map +1 -0
  103. package/build/util/cotar.serve.d.ts +20 -0
  104. package/build/util/cotar.serve.d.ts.map +1 -0
  105. package/build/util/cotar.serve.js +41 -0
  106. package/build/util/cotar.serve.js.map +1 -0
  107. package/build/util/etag.d.ts +6 -0
  108. package/build/util/etag.d.ts.map +1 -0
  109. package/build/util/etag.js +20 -0
  110. package/build/util/etag.js.map +1 -0
  111. package/build/util/response.d.ts +4 -0
  112. package/build/util/response.d.ts.map +1 -0
  113. package/build/util/response.js +4 -0
  114. package/build/util/response.js.map +1 -0
  115. package/build/util/source.cache.d.ts +28 -0
  116. package/build/util/source.cache.d.ts.map +1 -0
  117. package/build/util/source.cache.js +53 -0
  118. package/build/util/source.cache.js.map +1 -0
  119. package/build/{source.tracer.d.ts → util/source.tracer.d.ts} +1 -0
  120. package/build/util/source.tracer.d.ts.map +1 -0
  121. package/build/{source.tracer.js → util/source.tracer.js} +4 -0
  122. package/build/util/source.tracer.js.map +1 -0
  123. package/build/util/swapping.lru.d.ts +21 -0
  124. package/build/util/swapping.lru.d.ts.map +1 -0
  125. package/build/util/swapping.lru.js +56 -0
  126. package/build/util/swapping.lru.js.map +1 -0
  127. package/build/util/validate.d.ts +46 -0
  128. package/build/util/validate.d.ts.map +1 -0
  129. package/build/util/validate.js +107 -0
  130. package/build/util/validate.js.map +1 -0
  131. package/build/wmts.capability.d.ts +27 -13
  132. package/build/wmts.capability.d.ts.map +1 -1
  133. package/build/wmts.capability.js +156 -55
  134. package/build/wmts.capability.js.map +1 -0
  135. package/dist/index.js +89 -73
  136. package/dist/node_modules/.package-lock.json +1 -1
  137. package/dist/package-lock.json +2 -2
  138. package/dist/package.json +1 -1
  139. package/package.json +10 -10
  140. package/src/__tests__/config.data.ts +120 -0
  141. package/src/__tests__/index.test.ts +4 -20
  142. package/src/__tests__/wmts.capability.test.ts +312 -139
  143. package/src/__tests__/xyz.util.ts +17 -45
  144. package/src/index.ts +75 -41
  145. package/src/routes/__tests__/attribution.test.ts +356 -403
  146. package/src/routes/__tests__/fonts.test.ts +18 -3
  147. package/src/routes/__tests__/health.test.ts +17 -13
  148. package/src/routes/__tests__/sprites.test.ts +6 -1
  149. package/src/routes/__tests__/tile.json.test.ts +145 -0
  150. package/src/routes/__tests__/tile.style.json.test.ts +105 -0
  151. package/src/routes/__tests__/wmts.test.ts +44 -34
  152. package/src/routes/__tests__/xyz.test.ts +119 -0
  153. package/src/routes/attribution.ts +59 -111
  154. package/src/routes/fonts.ts +32 -10
  155. package/src/routes/health.ts +17 -16
  156. package/src/routes/imagery.ts +18 -15
  157. package/src/routes/ping.ts +8 -0
  158. package/src/routes/sprites.ts +20 -22
  159. package/src/routes/tile.json.ts +24 -19
  160. package/src/routes/tile.style.json.ts +15 -12
  161. package/src/routes/tile.wmts.ts +41 -44
  162. package/src/routes/tile.xyz.raster.ts +106 -0
  163. package/src/routes/tile.xyz.ts +31 -16
  164. package/src/routes/tile.xyz.vector.ts +47 -0
  165. package/src/routes/version.ts +8 -0
  166. package/src/util/__test__/validate.test.ts +74 -0
  167. package/src/util/cotar.serve.ts +46 -0
  168. package/src/util/etag.ts +20 -0
  169. package/src/util/response.ts +4 -0
  170. package/src/util/source.cache.ts +71 -0
  171. package/src/{source.tracer.ts → util/source.tracer.ts} +4 -0
  172. package/src/util/swapping.lru.ts +63 -0
  173. package/src/util/validate.ts +126 -0
  174. package/src/wmts.capability.ts +170 -68
  175. package/tsconfig.tsbuildinfo +1 -1
  176. package/build/__tests__/route.test.d.ts +0 -2
  177. package/build/__tests__/route.test.d.ts.map +0 -1
  178. package/build/__tests__/route.test.js +0 -20
  179. package/build/__tests__/tiff.cache.test.d.ts +0 -2
  180. package/build/__tests__/tiff.cache.test.d.ts.map +0 -1
  181. package/build/__tests__/tiff.cache.test.js +0 -58
  182. package/build/__tests__/tile.cache.key.test.d.ts +0 -2
  183. package/build/__tests__/tile.cache.key.test.d.ts.map +0 -1
  184. package/build/__tests__/tile.cache.key.test.js +0 -48
  185. package/build/__tests__/tile.set.cache.test.d.ts +0 -2
  186. package/build/__tests__/tile.set.cache.test.d.ts.map +0 -1
  187. package/build/__tests__/tile.set.cache.test.js +0 -123
  188. package/build/__tests__/tile.set.test.d.ts +0 -2
  189. package/build/__tests__/tile.set.test.d.ts.map +0 -1
  190. package/build/__tests__/tile.set.test.js +0 -11
  191. package/build/__tests__/xyz.test.d.ts.map +0 -1
  192. package/build/__tests__/xyz.test.js +0 -306
  193. package/build/api.key.d.ts +0 -2
  194. package/build/api.key.d.ts.map +0 -1
  195. package/build/api.key.js +0 -23
  196. package/build/cli/dump.d.ts +0 -2
  197. package/build/cli/dump.d.ts.map +0 -1
  198. package/build/cli/dump.js +0 -47
  199. package/build/cli/tile.set.local.d.ts +0 -12
  200. package/build/cli/tile.set.local.d.ts.map +0 -1
  201. package/build/cli/tile.set.local.js +0 -39
  202. package/build/router.d.ts +0 -15
  203. package/build/router.d.ts.map +0 -1
  204. package/build/router.js +0 -49
  205. package/build/routes/api.d.ts +0 -5
  206. package/build/routes/api.d.ts.map +0 -1
  207. package/build/routes/api.js +0 -16
  208. package/build/routes/esri/rest.d.ts +0 -10
  209. package/build/routes/esri/rest.d.ts.map +0 -1
  210. package/build/routes/esri/rest.js +0 -87
  211. package/build/routes/response.d.ts +0 -4
  212. package/build/routes/response.d.ts.map +0 -1
  213. package/build/routes/response.js +0 -3
  214. package/build/routes/tile.d.ts +0 -3
  215. package/build/routes/tile.d.ts.map +0 -1
  216. package/build/routes/tile.etag.d.ts +0 -11
  217. package/build/routes/tile.etag.d.ts.map +0 -1
  218. package/build/routes/tile.etag.js +0 -29
  219. package/build/routes/tile.js +0 -27
  220. package/build/source.tracer.d.ts.map +0 -1
  221. package/build/tiff.cache.d.ts +0 -17
  222. package/build/tiff.cache.d.ts.map +0 -1
  223. package/build/tiff.cache.js +0 -45
  224. package/build/tile.set.cache.d.ts +0 -21
  225. package/build/tile.set.cache.d.ts.map +0 -1
  226. package/build/tile.set.cache.js +0 -100
  227. package/build/tile.set.d.ts +0 -4
  228. package/build/tile.set.d.ts.map +0 -1
  229. package/build/tile.set.js +0 -1
  230. package/build/tile.set.raster.d.ts +0 -49
  231. package/build/tile.set.raster.d.ts.map +0 -1
  232. package/build/tile.set.raster.js +0 -186
  233. package/build/tile.set.vector.d.ts +0 -25
  234. package/build/tile.set.vector.d.ts.map +0 -1
  235. package/build/tile.set.vector.js +0 -71
  236. package/build/validate.d.ts +0 -16
  237. package/build/validate.d.ts.map +0 -1
  238. package/build/validate.js +0 -31
  239. package/src/__tests__/route.test.ts +0 -24
  240. package/src/__tests__/tiff.cache.test.ts +0 -73
  241. package/src/__tests__/tile.cache.key.test.ts +0 -56
  242. package/src/__tests__/tile.set.cache.test.ts +0 -146
  243. package/src/__tests__/tile.set.test.ts +0 -12
  244. package/src/__tests__/xyz.test.ts +0 -362
  245. package/src/api.key.ts +0 -23
  246. package/src/cli/dump.ts +0 -61
  247. package/src/cli/tile.set.local.ts +0 -51
  248. package/src/router.ts +0 -58
  249. package/src/routes/api.ts +0 -19
  250. package/src/routes/esri/rest.ts +0 -90
  251. package/src/routes/response.ts +0 -4
  252. package/src/routes/tile.etag.ts +0 -36
  253. package/src/routes/tile.ts +0 -23
  254. package/src/tiff.cache.ts +0 -51
  255. package/src/tile.set.cache.ts +0 -111
  256. package/src/tile.set.raster.ts +0 -228
  257. package/src/tile.set.ts +0 -4
  258. package/src/tile.set.vector.ts +0 -79
  259. package/src/validate.ts +0 -32
@@ -1,362 +0,0 @@
1
- import { ConfigProvider, StyleJson } from '@basemaps/config';
2
- import { GoogleTms, Nztm2000QuadTms, TileMatrixSets } from '@basemaps/geo';
3
- import { Config, Env, LogConfig, VNodeParser } from '@basemaps/shared';
4
- import { round } from '@basemaps/test/build/rounding.js';
5
- import o from 'ospec';
6
- import sinon from 'sinon';
7
- import { handleRequest } from '../index.js';
8
- import { TileEtag } from '../routes/tile.etag.js';
9
- import { TileSets } from '../tile.set.cache.js';
10
- import { TileComposer } from '../tile.set.raster.js';
11
- import { FakeTileSet, FakeTileSetVector, mockRequest, Provider } from './xyz.util.js';
12
-
13
- const sandbox = sinon.createSandbox();
14
-
15
- const TileSetNames = ['aerial', 'aerial@head', 'aerial@beta', '01E7PJFR9AMQFJ05X9G7FQ3XMW'];
16
- /* eslint-disable @typescript-eslint/explicit-function-return-type */
17
- o.spec('LambdaXyz', () => {
18
- const host = 'https://tiles.test';
19
- const origPublicUrlBase = process.env[Env.PublicUrlBase];
20
-
21
- /** Generate mock ALBEvent */
22
-
23
- let rasterMock = o.spy();
24
- const generateMock = o.spy(() => 'foo');
25
- const rasterMockBuffer = Buffer.from([1]);
26
- const origTileEtag = TileEtag.generate;
27
- const origCompose = TileComposer.compose;
28
-
29
- const apiKey = 'd01f7w7rnhdzg0p7fyrc9v9ard1';
30
- const apiKeyHeader = { 'x-linz-api-key': 'd01f7w7rnhdzg0p7fyrc9v9ard1' };
31
-
32
- o.beforeEach(() => {
33
- process.env[Env.PublicUrlBase] = host;
34
-
35
- LogConfig.disable();
36
- // tileMock = o.spy(() => tileMockData) as any;
37
- rasterMock = o.spy(() => {
38
- return {
39
- buffer: rasterMockBuffer,
40
- };
41
- }) as any;
42
-
43
- TileEtag.generate = generateMock;
44
- TileComposer.compose = rasterMock as any;
45
-
46
- const allMatrix = [...TileMatrixSets.All.values()];
47
- for (const tileSetName of TileSetNames) {
48
- for (const tileMatrix of allMatrix) {
49
- const tileSet = new FakeTileSet(tileSetName, tileMatrix);
50
- TileSets.add(tileSet);
51
- tileSet.getTiffsForTile = (): [] => [];
52
- tileSet.initTiffs = async () => [];
53
- }
54
- }
55
-
56
- TileSets.add(new FakeTileSetVector('topographic', GoogleTms));
57
-
58
- (Config.Provider as any).get = async (): Promise<ConfigProvider> => Provider;
59
- });
60
-
61
- o.afterEach(() => {
62
- TileSets.cache.clear();
63
- TileComposer.compose = origCompose;
64
- TileEtag.generate = origTileEtag;
65
- process.env[Env.PublicUrlBase] = origPublicUrlBase;
66
- sandbox.restore();
67
- });
68
-
69
- o('should export handler', async () => {
70
- const base = await import('../index.js');
71
- o(typeof base.handler).equals('function');
72
- });
73
-
74
- TileSetNames.forEach((tileSetName) => {
75
- o(`should generate a tile 0,0,0 for ${tileSetName}.png`, async () => {
76
- o.timeout(200);
77
- const request = mockRequest(`/v1/tiles/${tileSetName}/global-mercator/0/0/0.png`, 'get', apiKeyHeader);
78
- const res = await handleRequest(request);
79
- o(res.status).equals(200);
80
- o(res.header('content-type')).equals('image/png');
81
- o(res.header('eTaG')).equals('foo');
82
- o(res.body).equals(rasterMockBuffer.toString('base64'));
83
-
84
- // Validate the session information has been set correctly
85
- o(request.logContext['tileSet']).equals(tileSetName);
86
- o(request.logContext['xyz']).deepEquals({ x: 0, y: 0, z: 0 });
87
- o(round(request.logContext['location'])).deepEquals({ lat: 0, lon: 0 });
88
- });
89
- });
90
-
91
- o('should generate a tile 0,0,0 for webp', async () => {
92
- const request = mockRequest('/v1/tiles/aerial/3857/0/0/0.webp', 'get', apiKeyHeader);
93
- const res = await handleRequest(request);
94
- o(res.status).equals(200);
95
- o(res.header('content-type')).equals('image/webp');
96
- o(res.header('eTaG')).equals('foo');
97
- o(res.body).equals(rasterMockBuffer.toString('base64'));
98
-
99
- // Validate the session information has been set correctly
100
- o(request.logContext['xyz']).deepEquals({ x: 0, y: 0, z: 0 });
101
- o(round(request.logContext['location'])).deepEquals({ lat: 0, lon: 0 });
102
- });
103
-
104
- ['png', 'webp', 'jpeg'].forEach((fmt) => {
105
- o(`should 200 with empty ${fmt} if a tile is out of bounds`, async () => {
106
- // tiler.tile = async () => [];
107
- const res = await handleRequest(
108
- mockRequest(`/v1/tiles/aerial/global-mercator/0/0/0.${fmt}`, 'get', apiKeyHeader),
109
- );
110
- o(res.status).equals(200);
111
- o(res.header('content-type')).equals(`image/${fmt}`);
112
- o(rasterMock.calls.length).equals(1);
113
- });
114
- });
115
-
116
- o('should 304 if a tile is not modified', async () => {
117
- const key = 'foo';
118
- const request = mockRequest('/v1/tiles/aerial/global-mercator/0/0/0.png', 'get', {
119
- 'if-none-match': key,
120
- ...apiKeyHeader,
121
- });
122
- const res = await handleRequest(request);
123
- o(res.status).equals(304);
124
- o(res.header('eTaG')).equals(undefined);
125
-
126
- o(rasterMock.calls.length).equals(0);
127
- o(request.logContext['cache']).deepEquals({ key, match: key, hit: true });
128
- });
129
-
130
- o('should 404 if a tile is outside of the range', async () => {
131
- try {
132
- const res = await handleRequest(mockRequest('/v1/tiles/aerial/global-mercator/25/0/0.png', 'get', apiKeyHeader));
133
- o(res.status).equals(404);
134
- } catch (e: any) {
135
- o(e.status).equals(404);
136
- }
137
- try {
138
- const res = await handleRequest(mockRequest('/v1/tiles/aerial/2193/17/0/0.png', 'get', apiKeyHeader));
139
- o(res.status).equals(404);
140
- } catch (e: any) {
141
- o(e.status).equals(404);
142
- }
143
- });
144
-
145
- o.spec('WMTSCapabilities', () => {
146
- o('should 304 if a xml is not modified', async () => {
147
- delete process.env[Env.PublicUrlBase];
148
- o.timeout(1000);
149
- const key = 'NuirTK8fozzCJV1iG1FznmdHhKvk6WaWuDhhEA1d40c=';
150
- const request = mockRequest('/v1/tiles/WMTSCapabilities.xml', 'get', {
151
- 'if-none-match': key,
152
- ...apiKeyHeader,
153
- });
154
-
155
- const res = await handleRequest(request);
156
-
157
- if (res.status === 200) {
158
- o(res.header('eTaG')).equals(key); // this line is useful for discovering the new etag
159
- return;
160
- }
161
-
162
- o(res.status).equals(304);
163
- o(rasterMock.calls.length).equals(0);
164
-
165
- o(request.logContext['cache']).deepEquals({ key, match: key, hit: true });
166
- });
167
-
168
- o('should serve WMTSCapabilities for tile_set', async () => {
169
- const request = mockRequest('/v1/tiles/aerial@beta/WMTSCapabilities.xml', 'get', apiKeyHeader);
170
-
171
- const res = await handleRequest(request);
172
- o(res.status).equals(200);
173
- o(res.header('content-type')).equals('text/xml');
174
- o(res.header('cache-control')).equals('max-age=0');
175
-
176
- const body = Buffer.from(res.body ?? '', 'base64').toString();
177
- o(body.slice(0, 100)).equals(
178
- '<?xml version="1.0"?>\n' + '<Capabilities xmlns="http://www.opengis.net/wmts/1.0" xmlns:ows="http://www.op',
179
- );
180
-
181
- const vdom = await VNodeParser.parse(body);
182
- const url = vdom.tags('ResourceURL').next().value;
183
- o(url?.toString()).equals(
184
- '<ResourceURL format="image/jpeg" resourceType="tile" ' +
185
- `template="https://tiles.test/v1/tiles/aerial@beta/{TileMatrixSet}/{TileMatrix}/{TileCol}/{TileRow}.jpeg?api=${apiKey}" />`,
186
- );
187
- });
188
- });
189
-
190
- o.spec('tileJson', () => {
191
- o('should 404 if invalid url is given', async () => {
192
- const request = mockRequest('/v1/tiles/tile.json', 'get', apiKeyHeader);
193
-
194
- const res = await handleRequest(request);
195
- o(res.status).equals(404);
196
- });
197
-
198
- o('should serve tile json for tile_set', async () => {
199
- const request = mockRequest('/v1/tiles/aerial/NZTM2000Quad/tile.json', 'get', apiKeyHeader);
200
-
201
- const res = await handleRequest(request);
202
- o(res.status).equals(200);
203
- o(res.header('cache-control')).equals('no-store');
204
-
205
- const body = Buffer.from(res.body ?? '', 'base64').toString();
206
- o(JSON.parse(body)).deepEquals({
207
- tiles: [`https://tiles.test/v1/tiles/aerial/NZTM2000Quad/{z}/{x}/{y}.webp?api=${apiKey}`],
208
- tilejson: '3.0.0',
209
- });
210
- });
211
-
212
- o('should serve vector tiles', async () => {
213
- const request = mockRequest('/v1/tiles/topographic/WebMercatorQuad/tile.json', 'get', apiKeyHeader);
214
-
215
- const res = await handleRequest(request);
216
- o(res.status).equals(200);
217
-
218
- const body = Buffer.from(res.body ?? '', 'base64').toString();
219
- o(JSON.parse(body)).deepEquals({
220
- tiles: [`https://tiles.test/v1/tiles/topographic/EPSG:3857/{z}/{x}/{y}.pbf?api=${apiKey}`],
221
- tilejson: '3.0.0',
222
- });
223
- });
224
-
225
- o('should serve vector tiles with min/max zoom', async () => {
226
- const fakeTileSet = new FakeTileSetVector('fake-vector', GoogleTms);
227
- fakeTileSet.tileSet.maxZoom = 15;
228
- fakeTileSet.tileSet.minZoom = 3;
229
- TileSets.add(fakeTileSet);
230
- const request = mockRequest('/v1/tiles/fake-vector/WebMercatorQuad/tile.json', 'get', apiKeyHeader);
231
-
232
- const res = await handleRequest(request);
233
- o(res.status).equals(200);
234
-
235
- const body = Buffer.from(res.body ?? '', 'base64').toString();
236
- o(JSON.parse(body)).deepEquals({
237
- tiles: [`https://tiles.test/v1/tiles/fake-vector/EPSG:3857/{z}/{x}/{y}.pbf?api=${apiKey}`],
238
- maxzoom: 15,
239
- minzoom: 3,
240
- tilejson: '3.0.0',
241
- });
242
- });
243
-
244
- o('should serve convert zoom to tile matrix', async () => {
245
- const fakeTileSet = new FakeTileSetVector('fake-vector', Nztm2000QuadTms);
246
- fakeTileSet.tileSet.maxZoom = 15;
247
- fakeTileSet.tileSet.minZoom = 1;
248
- TileSets.add(fakeTileSet);
249
-
250
- const request = mockRequest('/v1/tiles/fake-vector/NZTM2000Quad/tile.json', 'get', apiKeyHeader);
251
-
252
- const res = await handleRequest(request);
253
- o(res.status).equals(200);
254
-
255
- const body = Buffer.from(res.body ?? '', 'base64').toString();
256
- o(JSON.parse(body)).deepEquals({
257
- tiles: [`https://tiles.test/v1/tiles/fake-vector/NZTM2000Quad/{z}/{x}/{y}.pbf?api=${apiKey}`],
258
- maxzoom: 13,
259
- minzoom: 0,
260
- tilejson: '3.0.0',
261
- });
262
- });
263
- });
264
-
265
- o.spec('styleJson', () => {
266
- o('should not found style json', async () => {
267
- const request = mockRequest('/v1/tiles/topographic/Google/style/topographic.json', 'get', apiKeyHeader);
268
-
269
- sandbox.stub(Config.Style, 'get').resolves(null);
270
-
271
- const res = await handleRequest(request);
272
- o(res.status).equals(404);
273
- });
274
-
275
- o('should serve style json', async () => {
276
- const request = mockRequest('/v1/tiles/topographic/Google/style/topographic.json', 'get', apiKeyHeader);
277
-
278
- const fakeStyle: StyleJson = {
279
- version: 8,
280
- id: 'test',
281
- name: 'topographic',
282
- sources: {
283
- basemaps_vector: {
284
- type: 'vector',
285
- url: `/vector`,
286
- },
287
- basemaps_raster: {
288
- type: 'raster',
289
- tiles: [`/raster`],
290
- },
291
- basemaps_raster_encode: {
292
- type: 'raster',
293
- tiles: [`/raster/{z}/{x}/{y}.webp`], // Shouldn't encode the {}
294
- },
295
- test_vector: {
296
- type: 'vector',
297
- url: 'vector.url.co.nz',
298
- },
299
- test_raster: {
300
- type: 'raster',
301
- tiles: ['raster.url.co.nz'],
302
- },
303
- },
304
- layers: [
305
- {
306
- layout: {
307
- visibility: 'visible',
308
- },
309
- paint: {
310
- 'background-color': 'rgba(206, 229, 242, 1)',
311
- },
312
- id: 'Background',
313
- type: 'background',
314
- minzoom: 0,
315
- },
316
- ],
317
- glyphs: '/glyphs',
318
- sprite: '/sprite',
319
- metadata: { id: 'test' },
320
- };
321
-
322
- const fakeRecord = {
323
- id: 'st_topographic_production',
324
- name: 'topographic',
325
- style: fakeStyle,
326
- };
327
-
328
- sandbox.stub(Config.Style, 'get').resolves(fakeRecord as any);
329
-
330
- const res = await handleRequest(request);
331
- o(res.status).equals(200);
332
- o(res.header('content-type')).equals('application/json');
333
- o(res.header('cache-control')).equals('no-store');
334
-
335
- const body = Buffer.from(res.body ?? '', 'base64').toString();
336
- fakeStyle.sources.basemaps_vector = {
337
- type: 'vector',
338
- url: `${host}/vector?api=${apiKey}`,
339
- };
340
- fakeStyle.sources.basemaps_raster = {
341
- type: 'raster',
342
- tiles: [`${host}/raster?api=${apiKey}`],
343
- };
344
- fakeStyle.sources.basemaps_raster_encode = {
345
- type: 'raster',
346
- tiles: [`${host}/raster/{z}/{x}/{y}.webp?api=${apiKey}`],
347
- };
348
-
349
- fakeStyle.sprite = `${host}/sprite`;
350
- fakeStyle.glyphs = `${host}/glyphs`;
351
-
352
- o(JSON.parse(body)).deepEquals(fakeStyle);
353
- });
354
- });
355
-
356
- ['/favicon.ico', '/index.html', '/foo/bar'].forEach((path) => {
357
- o('should error on invalid paths: ' + path, async () => {
358
- const res = await handleRequest(mockRequest(path, 'get', apiKeyHeader));
359
- o(res.status).equals(404);
360
- });
361
- });
362
- });
package/src/api.key.ts DELETED
@@ -1,23 +0,0 @@
1
- import * as ulid from 'ulid';
2
-
3
- const OneHourMs = 60 * 60 * 1000;
4
- const OneDayMs = 24 * OneHourMs;
5
- const MaxApiAgeMs = 91 * OneDayMs;
6
-
7
- export function isValidApiKey(apiKey?: string | null): boolean {
8
- if (apiKey == null) return false;
9
- if (!apiKey.startsWith('c') && !apiKey.startsWith('d')) return false;
10
- const ulidId = apiKey.slice(1).toUpperCase();
11
- try {
12
- const ulidTime = ulid.decodeTime(ulidId);
13
- if (apiKey.startsWith('d')) return true;
14
-
15
- if (Date.now() - ulidTime > MaxApiAgeMs) {
16
- return false;
17
- }
18
- } catch (e) {
19
- return false;
20
- }
21
-
22
- return true;
23
- }
package/src/cli/dump.ts DELETED
@@ -1,61 +0,0 @@
1
- import { Nztm2000Tms, ImageFormat } from '@basemaps/geo';
2
- import { LogConfig } from '@basemaps/shared';
3
- import { LambdaAlbRequest } from '@linzjs/lambda';
4
- import { Context } from 'aws-lambda';
5
- import { promises as fs } from 'fs';
6
- import { tileXyz } from '../routes/tile.xyz.js';
7
- import { TileSets } from '../tile.set.cache.js';
8
- import { TileSet } from '../tile.set.js';
9
- import { TileSetLocal } from './tile.set.local.js';
10
-
11
- const xyz = { x: 0, y: 0, z: 0 };
12
- const tileMatrix = Nztm2000Tms;
13
- const tileSetName = 'aerial';
14
- const ext = ImageFormat.Png;
15
-
16
- /** Load a tileset form a file path otherwise default to the hard coded one from AWS */
17
- async function getTileSet(filePath?: string): Promise<TileSet> {
18
- if (filePath != null) {
19
- const tileSet = new TileSetLocal('local', filePath);
20
- await tileSet.load();
21
- TileSets.add(tileSet);
22
- return tileSet;
23
- }
24
-
25
- const tileSet = await TileSets.get(tileSetName, tileMatrix);
26
- if (tileSet == null) throw new Error('Missing');
27
- return tileSet;
28
- }
29
-
30
- /**
31
- * Utility to render a single tile then save it as a png
32
- */
33
- async function main(): Promise<void> {
34
- const logger = LogConfig.get();
35
-
36
- const filePath = process.argv[2];
37
- const tileSet = await getTileSet(filePath);
38
-
39
- logger.info({ ...xyz, projection: tileMatrix.projection.code, tileMatrix: tileMatrix.identifier }, 'RenderTile');
40
-
41
- const ctx = new LambdaAlbRequest(
42
- {
43
- httpMethod: 'get',
44
- path: `/v1/tiles/${tileSet.fullName}/${tileMatrix.identifier}/${xyz.z}/${xyz.x}/${xyz.y}.${ext}`,
45
- } as any,
46
- {} as Context,
47
- logger,
48
- );
49
-
50
- const tileData = await tileXyz(ctx);
51
-
52
- const headers: Record<string, any> = {};
53
- for (const [key, value] of tileData.headers) headers[key] = value;
54
-
55
- logger.info({ ...tileData, _body: tileData.body?.length, headers }, 'Done');
56
- if (tileData._body != null) {
57
- await fs.writeFile(`output_${xyz.x}_${xyz.y}_z${xyz.z}.${ext}`, tileData._body);
58
- }
59
- }
60
-
61
- main().catch(console.error);
@@ -1,51 +0,0 @@
1
- import { Epsg, GoogleTms, TileMatrixSets } from '@basemaps/geo';
2
- import { fsa, LogConfig } from '@basemaps/shared';
3
- import { CogTiff, TiffTagGeo } from '@cogeotiff/core';
4
- import { TileSetRaster } from '../tile.set.raster.js';
5
-
6
- function isTiff(fileName: string): boolean {
7
- return fileName.toLowerCase().endsWith('.tif') || fileName.toLowerCase().endsWith('.tiff');
8
- }
9
-
10
- export class TileSetLocal extends TileSetRaster {
11
- tiffs: CogTiff[];
12
- filePath: string;
13
- tileSet = {} as any;
14
-
15
- constructor(name: string, path: string) {
16
- super(name, GoogleTms);
17
- this.filePath = path;
18
- this.tileSet.name = name;
19
- this.tileSet.title = name;
20
- this.tileSet.projection = GoogleTms.projection.code;
21
- }
22
-
23
- setTitle(name: string): void {
24
- this.tileSet.title = name;
25
- }
26
-
27
- async load(): Promise<boolean> {
28
- if (this.tiffs != null) return true;
29
-
30
- const fileList = isTiff(this.filePath) ? [this.filePath] : await fsa.toArray(fsa.list(this.filePath));
31
- const files = fileList.filter(isTiff);
32
- if (files.length === 0) throw new Error(`No tiff files found in ${this.filePath}`);
33
-
34
- this.tiffs = files.map((filePath) => new CogTiff(fsa.source(filePath)));
35
-
36
- // Read in the projection information
37
- const [firstTiff] = this.tiffs;
38
- await firstTiff.init(true);
39
- const projection = Epsg.get(firstTiff.getImage(0).valueGeo(TiffTagGeo.ProjectedCSTypeGeoKey) as number);
40
- this.tileMatrix = TileMatrixSets.get(projection);
41
- LogConfig.get().info(
42
- { path: this.filePath, count: this.tiffs.length, tileMatrix: this.tileMatrix.identifier },
43
- 'LoadedTiffs',
44
- );
45
- return true;
46
- }
47
-
48
- getTiffsForTile(): CogTiff[] {
49
- return this.tiffs;
50
- }
51
- }
package/src/router.ts DELETED
@@ -1,58 +0,0 @@
1
- import { Const } from '@basemaps/shared';
2
- import { HttpHeader, LambdaHttpRequest, LambdaHttpResponse } from '@linzjs/lambda';
3
-
4
- export type ReqCallback = (req: LambdaHttpRequest) => Promise<LambdaHttpResponse>;
5
-
6
- export interface ActionData {
7
- version: string;
8
- name: string;
9
- rest: string[];
10
- }
11
-
12
- export class Router {
13
- static action(req: LambdaHttpRequest): ActionData {
14
- const path = req.path;
15
- const [version, name, ...rest] = (path[0] === '/' ? path.slice(1) : path)
16
- .split('/')
17
- .map((c) => decodeURIComponent(c));
18
- if (name == null) return { version: 'v1', name: version, rest: [] };
19
- return { version, name: name, rest };
20
- }
21
-
22
- static apiKey(req: LambdaHttpRequest): string | undefined {
23
- const apiKey = req.query.get(Const.ApiKey.QueryString) ?? req.header('X-LINZ-Api-Key');
24
- if (apiKey != null && !Array.isArray(apiKey)) {
25
- req.set(Const.ApiKey.QueryString, this.apiKey);
26
- return apiKey;
27
- }
28
- return;
29
- }
30
-
31
- private handlers: Record<string, ReqCallback> = {};
32
-
33
- async handle(req: LambdaHttpRequest): Promise<LambdaHttpResponse> {
34
- // Allow cross origin requests
35
- if (req.method === 'options') {
36
- return new LambdaHttpResponse(200, 'Options', {
37
- [HttpHeader.Cors]: '*',
38
- 'Access-Control-Allow-Credentials': 'false',
39
- 'Access-Control-Allow-Methods': 'OPTIONS,GET,PUT,POST,DELETE',
40
- });
41
- }
42
-
43
- if (req.method !== 'GET') return new LambdaHttpResponse(405, 'Method not allowed');
44
-
45
- const action = Router.action(req);
46
- const handler = action.version === 'v1' ? this.handlers[action.name] : null;
47
- if (handler == null) return new LambdaHttpResponse(404, 'Not Found');
48
-
49
- const response = await handler(req);
50
- response.header(HttpHeader.Cors, '*');
51
- return response;
52
- }
53
-
54
- get(path: string, handler: ReqCallback): void {
55
- if (this.handlers[path] != null) throw new Error(path + ' already registered');
56
- this.handlers[path] = handler;
57
- }
58
- }
package/src/routes/api.ts DELETED
@@ -1,19 +0,0 @@
1
- import { LambdaHttpResponse, HttpHeader } from '@linzjs/lambda';
2
-
3
- const OkResponse = new LambdaHttpResponse(200, 'ok');
4
- OkResponse.header(HttpHeader.CacheControl, 'no-store');
5
-
6
- export async function Health(): Promise<LambdaHttpResponse> {
7
- return OkResponse;
8
- }
9
-
10
- export async function Ping(): Promise<LambdaHttpResponse> {
11
- return OkResponse;
12
- }
13
-
14
- export async function Version(): Promise<LambdaHttpResponse> {
15
- const response = new LambdaHttpResponse(200, 'ok');
16
- response.header(HttpHeader.CacheControl, 'no-store');
17
- response.json({ version: process.env.GIT_VERSION ?? 'dev', hash: process.env.GIT_HASH });
18
- return response;
19
- }
@@ -1,90 +0,0 @@
1
- import { GoogleTms, TileMatrixSet } from '@basemaps/geo';
2
- import { tileXyzFromPath } from '@basemaps/shared';
3
- import { LambdaHttpRequest, LambdaHttpResponse } from '@linzjs/lambda';
4
- import { Router } from '../../router.js';
5
- import { TileSets } from '../../tile.set.cache.js';
6
- import { NotFound } from '../response.js';
7
-
8
- export async function vectorTileServer(
9
- req: LambdaHttpRequest,
10
- layerId: string,
11
- tms: TileMatrixSet,
12
- ): Promise<LambdaHttpResponse> {
13
- if (tms.identifier !== GoogleTms.identifier) return NotFound;
14
- const extent = {
15
- xmin: tms.extent.x,
16
- ymin: tms.extent.y,
17
- xmax: tms.extent.right,
18
- ymax: tms.extent.bottom,
19
- // TODO where is wkid from
20
- spatialReference: { wkid: 102100, latestWkid: tms.projection.code },
21
- };
22
-
23
- const res = new LambdaHttpResponse(200, 'ok');
24
- res.json({
25
- currentVersion: 10.4,
26
- name: layerId,
27
- capabilities: 'TilesOnly',
28
- type: 'indexedVector',
29
- tileMap: 'tilemap',
30
- defaultStyles: 'resources/styles',
31
- tiles: ['tiles/{z}/{x}/{y}.pbf'],
32
- exportTilesAllowed: false,
33
- maxExportTilesCount: 0,
34
- initialExtent: extent,
35
- fullExtent: extent,
36
- minScale: tms.zooms[0].scaleDenominator,
37
- maxScale: tms.zooms[tms.zooms.length - 1].scaleDenominator,
38
- tileInfo: {
39
- // TODO are all the pbf 256x256?
40
- rows: 256,
41
- cols: 256,
42
- dpi: 96,
43
- format: 'pbf',
44
- origin: { x: tms.extent.x, y: tms.extent.bottom },
45
- spatialReference: { wkid: 102100, latestWkid: tms.projection.code },
46
- lods: tms.zooms.map((c, i) => {
47
- return {
48
- level: i,
49
- scale: c.scaleDenominator,
50
- resolution: c.scaleDenominator * 0.28e-3,
51
- };
52
- }),
53
- },
54
- resourceInfo: {
55
- styleVersion: 8,
56
- tileCompression: 'gzip',
57
- cacheInfo: { storageInfo: { packetSize: 128, storageFormat: 'compactV2' } },
58
- },
59
- });
60
- return res;
61
- }
62
-
63
- /**
64
- * /v1/esri/services/:layerId/VectorTileServer
65
- *
66
- * @example http://localhost:5000/v1/esri/services/topographic/VectorTileServer
67
- */
68
- export async function Esri(req: LambdaHttpRequest): Promise<LambdaHttpResponse> {
69
- const { rest } = Router.action(req);
70
- if (rest[0] !== 'services') return NotFound;
71
- const layerId = rest[1];
72
- if (layerId == null) return NotFound;
73
-
74
- const serviceId = rest[2];
75
- if (serviceId !== 'VectorTileServer') return NotFound;
76
- if (rest.length === 3) return vectorTileServer(req, layerId, GoogleTms);
77
-
78
- if (rest[rest.length - 1].endsWith('.pbf')) {
79
- const generatedPath = [layerId, GoogleTms.identifier, ...rest.slice(rest.length - 3)];
80
- const xyz = tileXyzFromPath(generatedPath);
81
- if (xyz == null) return NotFound;
82
- req.timer.start('tileset:load');
83
- const tileSet = await TileSets.get(xyz.name, xyz.tileMatrix);
84
- req.timer.end('tileset:load');
85
- if (tileSet == null) return NotFound;
86
- return await tileSet.tile(req, xyz);
87
- }
88
-
89
- return new LambdaHttpResponse(200, 'ok');
90
- }
@@ -1,4 +0,0 @@
1
- import { LambdaHttpResponse } from '@linzjs/lambda';
2
-
3
- export const NotFound = new LambdaHttpResponse(404, 'Not Found');
4
- export const NotModified = new LambdaHttpResponse(304, 'Not modified');