@basemaps/lambda-tiler 6.29.0 → 6.30.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 (144) hide show
  1. package/CHANGELOG.md +25 -0
  2. package/build/__tests__/config.data.d.ts +6 -0
  3. package/build/__tests__/config.data.d.ts.map +1 -0
  4. package/build/__tests__/config.data.js +81 -0
  5. package/build/__tests__/config.data.js.map +1 -0
  6. package/build/__tests__/index.test.js +4 -3
  7. package/build/__tests__/index.test.js.map +1 -0
  8. package/build/__tests__/route.test.js +1 -0
  9. package/build/__tests__/route.test.js.map +1 -0
  10. package/build/__tests__/tiff.cache.test.js +1 -0
  11. package/build/__tests__/tiff.cache.test.js.map +1 -0
  12. package/build/__tests__/tile.cache.key.test.js +1 -0
  13. package/build/__tests__/tile.cache.key.test.js.map +1 -0
  14. package/build/__tests__/tile.set.cache.test.js +2 -53
  15. package/build/__tests__/tile.set.cache.test.js.map +1 -0
  16. package/build/__tests__/tile.set.test.js +1 -0
  17. package/build/__tests__/tile.set.test.js.map +1 -0
  18. package/build/__tests__/tile.style.json.test.js +1 -0
  19. package/build/__tests__/tile.style.json.test.js.map +1 -0
  20. package/build/__tests__/wmts.capability.test.d.ts +1 -1
  21. package/build/__tests__/wmts.capability.test.d.ts.map +1 -1
  22. package/build/__tests__/wmts.capability.test.js +207 -128
  23. package/build/__tests__/wmts.capability.test.js.map +1 -0
  24. package/build/__tests__/xyz.test.js +6 -37
  25. package/build/__tests__/xyz.test.js.map +1 -0
  26. package/build/__tests__/xyz.util.d.ts +0 -2
  27. package/build/__tests__/xyz.util.d.ts.map +1 -1
  28. package/build/__tests__/xyz.util.js +7 -29
  29. package/build/__tests__/xyz.util.js.map +1 -0
  30. package/build/api.key.js +1 -0
  31. package/build/api.key.js.map +1 -0
  32. package/build/cli/dump.js +1 -0
  33. package/build/cli/dump.js.map +1 -0
  34. package/build/cli/tile.set.local.js +1 -0
  35. package/build/cli/tile.set.local.js.map +1 -0
  36. package/build/cotar.cache.d.ts +25 -0
  37. package/build/cotar.cache.d.ts.map +1 -0
  38. package/build/cotar.cache.js +50 -0
  39. package/build/cotar.cache.js.map +1 -0
  40. package/build/index.d.ts.map +1 -1
  41. package/build/index.js +31 -35
  42. package/build/index.js.map +1 -0
  43. package/build/router.js +1 -0
  44. package/build/router.js.map +1 -0
  45. package/build/routes/__tests__/attribution.test.js +5 -3
  46. package/build/routes/__tests__/attribution.test.js.map +1 -0
  47. package/build/routes/__tests__/fonts.test.js +9 -1
  48. package/build/routes/__tests__/fonts.test.js.map +1 -0
  49. package/build/routes/__tests__/health.test.js +1 -0
  50. package/build/routes/__tests__/health.test.js.map +1 -0
  51. package/build/routes/__tests__/imagery.test.js +1 -0
  52. package/build/routes/__tests__/imagery.test.js.map +1 -0
  53. package/build/routes/__tests__/memory.fs.js +1 -0
  54. package/build/routes/__tests__/memory.fs.js.map +1 -0
  55. package/build/routes/__tests__/sprites.test.js +1 -0
  56. package/build/routes/__tests__/sprites.test.js.map +1 -0
  57. package/build/routes/__tests__/wmts.test.js +59 -10
  58. package/build/routes/__tests__/wmts.test.js.map +1 -0
  59. package/build/routes/api.d.ts +0 -1
  60. package/build/routes/api.d.ts.map +1 -1
  61. package/build/routes/api.js +1 -3
  62. package/build/routes/api.js.map +1 -0
  63. package/build/routes/attribution.js +1 -0
  64. package/build/routes/attribution.js.map +1 -0
  65. package/build/routes/esri/rest.js +1 -0
  66. package/build/routes/esri/rest.js.map +1 -0
  67. package/build/routes/fonts.d.ts.map +1 -1
  68. package/build/routes/fonts.js +9 -1
  69. package/build/routes/fonts.js.map +1 -0
  70. package/build/routes/health.js +1 -0
  71. package/build/routes/health.js.map +1 -0
  72. package/build/routes/imagery.d.ts +8 -1
  73. package/build/routes/imagery.d.ts.map +1 -1
  74. package/build/routes/imagery.js +6 -7
  75. package/build/routes/imagery.js.map +1 -0
  76. package/build/routes/response.js +1 -0
  77. package/build/routes/response.js.map +1 -0
  78. package/build/routes/sprites.d.ts.map +1 -1
  79. package/build/routes/sprites.js +8 -14
  80. package/build/routes/sprites.js.map +1 -0
  81. package/build/routes/tile.etag.js +1 -0
  82. package/build/routes/tile.etag.js.map +1 -0
  83. package/build/routes/tile.js +1 -0
  84. package/build/routes/tile.js.map +1 -0
  85. package/build/routes/tile.json.d.ts.map +1 -1
  86. package/build/routes/tile.json.js +2 -2
  87. package/build/routes/tile.json.js.map +1 -0
  88. package/build/routes/tile.style.json.js +1 -0
  89. package/build/routes/tile.style.json.js.map +1 -0
  90. package/build/routes/tile.wmts.d.ts.map +1 -1
  91. package/build/routes/tile.wmts.js +19 -23
  92. package/build/routes/tile.wmts.js.map +1 -0
  93. package/build/routes/tile.xyz.js +1 -0
  94. package/build/routes/tile.xyz.js.map +1 -0
  95. package/build/source.tracer.js +1 -0
  96. package/build/source.tracer.js.map +1 -0
  97. package/build/tiff.cache.js +1 -0
  98. package/build/tiff.cache.js.map +1 -0
  99. package/build/tile.set.cache.d.ts +0 -1
  100. package/build/tile.set.cache.d.ts.map +1 -1
  101. package/build/tile.set.cache.js +1 -29
  102. package/build/tile.set.cache.js.map +1 -0
  103. package/build/tile.set.js +1 -0
  104. package/build/tile.set.js.map +1 -0
  105. package/build/tile.set.raster.d.ts.map +1 -1
  106. package/build/tile.set.raster.js +6 -3
  107. package/build/tile.set.raster.js.map +1 -0
  108. package/build/tile.set.vector.d.ts +0 -7
  109. package/build/tile.set.vector.d.ts.map +1 -1
  110. package/build/tile.set.vector.js +3 -20
  111. package/build/tile.set.vector.js.map +1 -0
  112. package/build/validate.js +1 -0
  113. package/build/validate.js.map +1 -0
  114. package/build/wmts.capability.d.ts +26 -12
  115. package/build/wmts.capability.d.ts.map +1 -1
  116. package/build/wmts.capability.js +136 -51
  117. package/build/wmts.capability.js.map +1 -0
  118. package/dist/index.js +86 -72
  119. package/dist/node_modules/.package-lock.json +1 -1
  120. package/dist/package-lock.json +2 -2
  121. package/dist/package.json +1 -1
  122. package/package.json +7 -7
  123. package/src/__tests__/config.data.ts +82 -0
  124. package/src/__tests__/index.test.ts +3 -3
  125. package/src/__tests__/tile.set.cache.test.ts +1 -67
  126. package/src/__tests__/wmts.capability.test.ts +224 -154
  127. package/src/__tests__/xyz.test.ts +5 -49
  128. package/src/__tests__/xyz.util.ts +6 -31
  129. package/src/cotar.cache.ts +54 -0
  130. package/src/index.ts +30 -33
  131. package/src/routes/__tests__/attribution.test.ts +4 -4
  132. package/src/routes/__tests__/fonts.test.ts +10 -1
  133. package/src/routes/__tests__/wmts.test.ts +75 -15
  134. package/src/routes/api.ts +0 -4
  135. package/src/routes/fonts.ts +9 -1
  136. package/src/routes/imagery.ts +9 -7
  137. package/src/routes/sprites.ts +7 -15
  138. package/src/routes/tile.json.ts +1 -2
  139. package/src/routes/tile.wmts.ts +20 -22
  140. package/src/tile.set.cache.ts +1 -28
  141. package/src/tile.set.raster.ts +4 -2
  142. package/src/tile.set.vector.ts +3 -21
  143. package/src/wmts.capability.ts +143 -58
  144. package/tsconfig.tsbuildinfo +1 -1
@@ -1,12 +1,10 @@
1
- import { Bounds, Epsg, GoogleTms, ImageFormat, Nztm2000QuadTms, Nztm2000Tms } from '@basemaps/geo';
2
- import { TileSetName, V, VNodeElement } from '@basemaps/shared';
1
+ import { ConfigImagery } from '@basemaps/config';
2
+ import { GoogleTms, ImageFormat, Nztm2000QuadTms } from '@basemaps/geo';
3
+ import { V, VNodeElement } from '@basemaps/shared';
3
4
  import { roundNumbersInString } from '@basemaps/test/build/rounding.js';
4
- import { createHash } from 'crypto';
5
5
  import o from 'ospec';
6
6
  import { WmtsCapabilities } from '../wmts.capability.js';
7
- import { FakeTileSet, Provider } from './xyz.util.js';
8
-
9
- import 'source-map-support/register.js';
7
+ import { Imagery2193, Imagery3857, Provider, TileSetAerial } from './config.data.js';
10
8
 
11
9
  function tags(node: VNodeElement | null | undefined, tag: string): VNodeElement[] {
12
10
  if (node == null) return [];
@@ -18,16 +16,21 @@ function listTag(node: VNodeElement | null | undefined, tag: string): string[] {
18
16
 
19
17
  o.spec('WmtsCapabilities', () => {
20
18
  const apiKey = 'secret1234';
21
- const tileSet = new FakeTileSet(TileSetName.aerial, GoogleTms);
22
- const tileSetImagery = new FakeTileSet('01E7PJFR9AMQFJ05X9G7FQ3XMW', GoogleTms);
19
+
20
+ const allImagery = new Map();
21
+ allImagery.set(Imagery2193.id, Imagery2193);
22
+ allImagery.set(Imagery3857.id, Imagery3857);
23
23
 
24
24
  o('should output the requested formats', () => {
25
25
  const wmts = new WmtsCapabilities({
26
26
  httpBase: 'https://basemaps.test',
27
27
  provider: Provider,
28
- layers: [tileSet],
28
+ tileMatrix: [GoogleTms],
29
+ tileSet: TileSetAerial,
30
+ imagery: allImagery,
29
31
  apiKey,
30
32
  formats: [ImageFormat.Avif],
33
+ isIndividualLayers: false,
31
34
  }).toVNode();
32
35
 
33
36
  const urls = tags(wmts, 'ResourceURL');
@@ -38,12 +41,106 @@ o.spec('WmtsCapabilities', () => {
38
41
  );
39
42
  });
40
43
 
44
+ o('should be seting encoding to utf-8', () => {
45
+ const xml = new WmtsCapabilities({
46
+ httpBase: 'https://basemaps.test',
47
+ provider: Provider,
48
+ tileMatrix: [GoogleTms],
49
+ tileSet: TileSetAerial,
50
+ imagery: allImagery,
51
+ apiKey,
52
+ formats: [ImageFormat.Avif],
53
+ isIndividualLayers: false,
54
+ }).toXml();
55
+
56
+ o(xml.split('\n')[0]).deepEquals('<?xml version="1.0" encoding="utf-8"?>');
57
+ });
58
+
59
+ o('should support unicorns and rainbows', () => {
60
+ const tileSet = { ...TileSetAerial };
61
+ tileSet.name = '🦄_🌈_2022_0-5m';
62
+ tileSet.title = '🦄 🌈 Imagery (2022)';
63
+ tileSet.description = '🦄 🌈 Description';
64
+ const wmts = new WmtsCapabilities({
65
+ httpBase: 'https://basemaps.test',
66
+ provider: Provider,
67
+ tileMatrix: [GoogleTms],
68
+ tileSet,
69
+ imagery: allImagery,
70
+ apiKey,
71
+ formats: [ImageFormat.Avif],
72
+ isIndividualLayers: false,
73
+ }).toVNode();
74
+
75
+ const urls = tags(wmts, 'ResourceURL');
76
+ o(urls.length).equals(1);
77
+ o(urls[0].attrs.template).equals(
78
+ 'https://basemaps.test/v1/tiles/🦄-🌈-2022-0.5m/{TileMatrixSet}/{TileMatrix}/{TileCol}/{TileRow}.avif?api=secret1234',
79
+ );
80
+
81
+ const layer = tags(wmts, 'Layer')[0];
82
+
83
+ const title = layer.find('ows:Title')?.toString();
84
+ o(title).equals('<ows:Title>🦄 🌈 Imagery (2022)</ows:Title>');
85
+
86
+ const abstract = layer.find('ows:Abstract')?.toString();
87
+ o(abstract).equals('<ows:Abstract>🦄 🌈 Description</ows:Abstract>');
88
+
89
+ const identifier = layer.find('ows:Identifier')?.toString();
90
+ o(identifier).equals('<ows:Identifier>🦄-🌈-2022-0.5m</ows:Identifier>');
91
+ });
92
+
93
+ o('should sort the sub imagery layers', () => {
94
+ const imageryA = { ...Imagery3857 };
95
+ imageryA.id = 'im_a';
96
+ imageryA.name = 'aaaa';
97
+ imageryA.title = 'aaaa';
98
+
99
+ const imageryB = { ...Imagery3857 };
100
+ imageryB.id = 'im_b';
101
+ imageryB.name = 'bbbb';
102
+ imageryB.title = 'bbbb';
103
+
104
+ const imagery = new Map();
105
+ imagery.set(Imagery3857.id, Imagery3857);
106
+ imagery.set(imageryB.id, imageryB);
107
+ imagery.set(imageryA.id, imageryA);
108
+ const tileSet = {
109
+ ...TileSetAerial,
110
+ layers: [
111
+ ...TileSetAerial.layers,
112
+ { [3857]: imageryB.id, title: imageryB.title, name: imageryB.name },
113
+ { [3857]: imageryA.id, title: imageryA.title, name: imageryA.name },
114
+ ],
115
+ };
116
+
117
+ const wmts = new WmtsCapabilities({
118
+ httpBase: 'https://basemaps.test',
119
+ provider: Provider,
120
+ tileMatrix: [GoogleTms],
121
+ tileSet,
122
+ imagery,
123
+ apiKey,
124
+ isIndividualLayers: true,
125
+ }).toVNode();
126
+
127
+ const layers = tags(wmts, 'Layer').map((c) => c.find('ows:Title')?.textContent);
128
+
129
+ // The base layer "Aerial Imagery" should always be first then all sub layers after
130
+ o(layers).deepEquals(['Aerial Imagery', 'aaaa', 'bbbb', 'Ōtorohanga 0.1m Urban Aerial Photos (2021)']);
131
+ });
132
+
41
133
  o('should build capability xml for tileset and projection', () => {
134
+ const imagery = new Map();
135
+ imagery.set(Imagery3857.id, Imagery3857);
42
136
  const wmts = new WmtsCapabilities({
43
137
  httpBase: 'https://basemaps.test',
44
138
  provider: Provider,
45
- layers: [tileSet],
139
+ tileMatrix: [GoogleTms],
140
+ tileSet: TileSetAerial,
141
+ imagery,
46
142
  apiKey,
143
+ isIndividualLayers: false,
47
144
  });
48
145
 
49
146
  const raw = wmts.toVNode();
@@ -53,10 +150,10 @@ o.spec('WmtsCapabilities', () => {
53
150
  o(serviceId?.find('ows:Title')?.textContent).equals('the title');
54
151
 
55
152
  o(raw.find('TileMatrixSetLink')?.toString()).deepEquals(
56
- V('TileMatrixSetLink', [V('TileMatrixSet', 'EPSG:3857')]).toString(),
153
+ V('TileMatrixSetLink', [V('TileMatrixSet', 'WebMercatorQuad')]).toString(),
57
154
  );
58
155
 
59
- const layer = raw?.find('Contents', 'Layer');
156
+ const layer = raw.find('Contents', 'Layer');
60
157
 
61
158
  o(listTag(layer, 'Format')).deepEquals([
62
159
  V('Format', 'image/jpeg').toString(),
@@ -64,41 +161,47 @@ o.spec('WmtsCapabilities', () => {
64
161
  V('Format', 'image/png').toString(),
65
162
  ]);
66
163
 
67
- o(listTag(layer, 'ows:BoundingBox')).deepEquals([
68
- V('ows:BoundingBox', { crs: Epsg.Google.toUrn() }, [
69
- V('ows:LowerCorner', '-20037508.3427892 -20037508.3427892'),
70
- V('ows:UpperCorner', '20037508.3427892 20037508.3427892'),
71
- ]).toString(),
164
+ o(listTag(layer, 'ows:BoundingBox').map((s) => roundNumbersInString(s, 4))).deepEquals([
165
+ '<ows:BoundingBox crs="urn:ogc:def:crs:EPSG::3857">\n' +
166
+ ' <ows:LowerCorner>19457809.9203 -4609458.5537</ows:LowerCorner>\n' +
167
+ ' <ows:UpperCorner>19509787.0995 -4578883.7424</ows:UpperCorner>\n' +
168
+ '</ows:BoundingBox>',
72
169
  ]);
73
170
 
74
171
  o(listTag(layer, 'ows:WGS84BoundingBox').map((s) => roundNumbersInString(s, 4))).deepEquals([
75
172
  '<ows:WGS84BoundingBox crs="urn:ogc:def:crs:OGC:2:84">\n' +
76
- ' <ows:LowerCorner>-180 -85.0511</ows:LowerCorner>\n' +
77
- ' <ows:UpperCorner>180 85.0511</ows:UpperCorner>\n' +
173
+ ' <ows:LowerCorner>174.7925 -38.2123</ows:LowerCorner>\n' +
174
+ ' <ows:UpperCorner>175.2594 -37.9962</ows:UpperCorner>\n' +
78
175
  '</ows:WGS84BoundingBox>',
79
176
  ]);
80
177
 
81
- o(layer?.find('ows:Abstract')?.textContent).equals('aerial:description');
82
- o(layer?.find('ows:Title')?.textContent).equals('aerial:title');
83
178
  o(layer?.find('ows:Identifier')?.textContent).equals('aerial');
179
+ o(layer?.find('ows:Title')?.textContent).equals('Aerial Imagery');
180
+ o(layer?.find('ows:Abstract')?.textContent).equals('aerial__description');
84
181
 
85
182
  o(layer?.find('Style')?.toString()).equals(
86
183
  V('Style', { isDefault: 'true' }, [V('ows:Title', 'Default Style'), V('ows:Identifier', 'default')]).toString(),
87
184
  );
185
+ });
88
186
 
89
- const urls = tags(layer, 'ResourceURL');
90
- o(urls.length).equals(3);
91
- o(urls[2].toString()).deepEquals(
92
- '<ResourceURL format="image/png" resourceType="tile" ' +
93
- 'template="https://basemaps.test/v1/tiles/aerial/{TileMatrixSet}/{TileMatrix}/{TileCol}/{TileRow}.png?api=secret1234" />',
94
- );
187
+ o('should include output the correct TileMatrix', () => {
188
+ const raw = new WmtsCapabilities({
189
+ httpBase: 'https://basemaps.test',
190
+ provider: Provider,
191
+ tileMatrix: [GoogleTms],
192
+ tileSet: TileSetAerial,
193
+ imagery: allImagery,
194
+ apiKey,
195
+ isIndividualLayers: false,
196
+ }).toVNode();
197
+ const layer = raw.find('Contents', 'Layer');
95
198
 
96
- o(layer?.find('TileMatrixSetLink', 'TileMatrixSet')?.textContent).equals('EPSG:3857');
199
+ o(layer?.find('TileMatrixSetLink', 'TileMatrixSet')?.textContent).equals('WebMercatorQuad');
97
200
 
98
201
  const matrix = tags(raw, 'TileMatrixSet')[1];
99
202
  const matrixId = raw?.find('Contents', 'TileMatrixSet', 'ows:Identifier') ?? null;
100
203
  o(matrix.find('ows:Identifier')).equals(matrixId);
101
- o(matrixId?.textContent).equals('EPSG:3857');
204
+ o(matrixId?.textContent).equals('WebMercatorQuad');
102
205
 
103
206
  o(matrix.find('ows:SupportedCRS')?.textContent).deepEquals('urn:ogc:def:crs:EPSG::3857');
104
207
  o(matrix.find('WellKnownScaleSet')?.textContent).deepEquals(
@@ -123,46 +226,62 @@ o.spec('WmtsCapabilities', () => {
123
226
 
124
227
  compareMatrix(tileMatrices[0], '0', 1, 559082264.028717);
125
228
  compareMatrix(tileMatrices[10], '10', 1024, 545978.773465544);
126
-
127
- const xml = new WmtsCapabilities({
128
- httpBase: 'https://basemaps.test',
129
- provider: Provider,
130
- layers: [tileSet],
131
- apiKey,
132
- }).toXml();
133
-
134
- o(xml).deepEquals('<?xml version="1.0"?>\n' + raw?.toString());
135
-
136
- o(createHash('sha256').update(Buffer.from(xml)).digest('base64')).equals(
137
- 'beknYyMt8v74vK4p84AS3c1OnBSJ+ZE0kan+mMVQS1A=',
138
- );
139
229
  });
140
230
 
141
- o('should allow individual imagery sets', () => {
231
+ o('should output individual imagery sets', () => {
232
+ const imagery = new Map<string, ConfigImagery>();
233
+ imagery.set(Imagery3857.id, Imagery3857);
234
+ imagery.set(Imagery2193.id, Imagery2193);
142
235
  const raw = new WmtsCapabilities({
143
236
  httpBase: 'https://basemaps.test',
144
237
  provider: Provider,
145
- layers: [tileSetImagery],
238
+ tileMatrix: [GoogleTms],
239
+ tileSet: TileSetAerial,
240
+ imagery: imagery,
241
+ formats: [ImageFormat.Png],
242
+ isIndividualLayers: true,
146
243
  }).toVNode();
147
244
 
148
245
  const tms = raw?.find('TileMatrixSet', 'ows:Identifier');
149
246
 
150
- o(tms?.textContent).equals('EPSG:3857');
247
+ o(tms?.textContent).equals('WebMercatorQuad');
151
248
 
152
249
  const urls = Array.from(raw ? raw.tags('ResourceURL') : []);
153
- o(urls.length).equals(3);
154
- o(urls[2].toString()).deepEquals(
250
+ o(urls.length).equals(2);
251
+ o(urls[0].toString()).deepEquals(
155
252
  '<ResourceURL format="image/png" resourceType="tile" ' +
156
- 'template="https://basemaps.test/v1/tiles/01E7PJFR9AMQFJ05X9G7FQ3XMW/{TileMatrixSet}/{TileMatrix}/{TileCol}/{TileRow}.png" />',
253
+ 'template="https://basemaps.test/v1/tiles/aerial/{TileMatrixSet}/{TileMatrix}/{TileCol}/{TileRow}.png" />',
157
254
  );
255
+ o(urls[1].toString()).deepEquals(
256
+ '<ResourceURL format="image/png" resourceType="tile" ' +
257
+ 'template="https://basemaps.test/v1/tiles/ōtorohanga-urban-2021-0.1m/{TileMatrixSet}/{TileMatrix}/{TileCol}/{TileRow}.png" />',
258
+ );
259
+
260
+ const layers = [...raw.tags('Layer')];
261
+
262
+ o(layers.length).equals(2);
263
+ o(layers[0].find('ows:Title')?.textContent).equals('Aerial Imagery');
264
+
265
+ o(layers[1].find('ows:Title')?.textContent).equals('Ōtorohanga 0.1m Urban Aerial Photos (2021)');
266
+ o(layers[1].find('ows:Identifier')?.textContent).equals('ōtorohanga-urban-2021-0.1m');
267
+ o(layers[1].find('ows:Keywords', 'ows:Keyword')?.textContent).equals('Urban Aerial Photos');
158
268
  });
159
269
 
160
270
  o('should support multiple projections', () => {
161
- const ts = [new FakeTileSet(TileSetName.aerial, Nztm2000Tms), new FakeTileSet(TileSetName.aerial, GoogleTms)];
162
- const xml = new WmtsCapabilities({ httpBase: 'basemaps.test', provider: Provider, layers: ts });
163
- const nodes = xml.toVNode();
271
+ const imagery = new Map<string, ConfigImagery>();
272
+ imagery.set(Imagery3857.id, Imagery3857);
273
+ imagery.set(Imagery2193.id, Imagery2193);
274
+ const raw = new WmtsCapabilities({
275
+ httpBase: 'https://basemaps.test',
276
+ provider: Provider,
277
+ tileMatrix: [GoogleTms, Nztm2000QuadTms],
278
+ tileSet: TileSetAerial,
279
+ imagery: imagery,
280
+ formats: [ImageFormat.Png],
281
+ isIndividualLayers: false,
282
+ }).toVNode();
164
283
 
165
- const layers = tags(nodes, 'Layer');
284
+ const layers = tags(raw, 'Layer');
166
285
  o(layers.length).equals(1);
167
286
  const layer = layers[0];
168
287
 
@@ -171,126 +290,77 @@ o.spec('WmtsCapabilities', () => {
171
290
  'ows:Title',
172
291
  'ows:Abstract',
173
292
  'ows:Identifier',
293
+ 'ows:Keywords',
174
294
  'ows:BoundingBox',
175
295
  'ows:BoundingBox',
176
296
  'ows:WGS84BoundingBox',
177
297
  'Style',
178
298
  'Format',
179
- 'Format',
180
- 'Format',
181
299
  'TileMatrixSetLink',
182
300
  'TileMatrixSetLink',
183
301
  'ResourceURL',
184
- 'ResourceURL',
185
- 'ResourceURL',
186
302
  ]);
187
303
 
304
+ o(layer.find('ows:Title')?.textContent).equals('Aerial Imagery');
305
+ o(layer.find('ows:Keywords')?.toString()).equals(
306
+ '<ows:Keywords>\n <ows:Keyword>Basemap</ows:Keyword>\n</ows:Keywords>',
307
+ );
308
+ o(layer.find('ows:Identifier')?.textContent).equals('aerial');
309
+
188
310
  const sets = tags(layer, 'TileMatrixSet');
189
311
 
190
312
  o(sets.length).equals(2);
191
- o(sets[0].toString()).equals('<TileMatrixSet>EPSG:2193</TileMatrixSet>');
192
- o(sets[1].toString()).equals('<TileMatrixSet>EPSG:3857</TileMatrixSet>');
193
-
194
- const tms = tags(nodes, 'TileMatrixSet').filter((f) => f.find('ows:SupportedCRS') != null);
195
- o(tms.length).equals(2);
196
-
197
- o(tms[0].find('ows:Identifier')?.textContent).equals('EPSG:2193');
198
- o(tms[0].find('ows:SupportedCRS')?.textContent).equals('urn:ogc:def:crs:EPSG::2193');
199
-
200
- o(tms[1].find('ows:Identifier')?.textContent).equals('EPSG:3857');
201
- o(tms[1].find('ows:SupportedCRS')?.textContent).equals('urn:ogc:def:crs:EPSG::3857');
202
- });
203
-
204
- o('should support multiple tilesets', () => {
205
- const ts = [
206
- new FakeTileSet(TileSetName.aerial, Nztm2000Tms, 'aerial-title'),
207
- new FakeTileSet('01E7PJFR9AMQFJ05X9G7FQ3XMW', Nztm2000Tms, 'imagery-title'),
208
- ];
209
- const nodes = new WmtsCapabilities({ httpBase: 'basemaps.test', provider: Provider, layers: ts }).toVNode();
210
- const layers = tags(nodes, 'Layer');
211
- o(layers.length).equals(2);
212
-
213
- o(layers[0].find('ows:Title')?.textContent).equals('aerial-title');
214
- o(layers[0].find('TileMatrixSet')?.textContent).equals('EPSG:2193');
313
+ o(sets[0].toString()).equals('<TileMatrixSet>WebMercatorQuad</TileMatrixSet>');
314
+ o(sets[1].toString()).equals('<TileMatrixSet>NZTM2000Quad</TileMatrixSet>');
315
+
316
+ const boundingBoxes = tags(layer, 'ows:BoundingBox');
317
+ o(boundingBoxes.length).equals(2);
318
+ o(boundingBoxes[0].attrs.crs).equals('urn:ogc:def:crs:EPSG::3857');
319
+ o(boundingBoxes[0].children.map((c) => roundNumbersInString(c.textContent, 4))).deepEquals([
320
+ '19457809.9203 -4609458.5537',
321
+ '19509787.0995 -4578883.7424',
322
+ ]);
323
+ o(boundingBoxes[1].attrs.crs).equals('urn:ogc:def:crs:EPSG::2193');
324
+ o(boundingBoxes[1].children.map((c) => roundNumbersInString(c.textContent, 4))).deepEquals([
325
+ '5766358.9964 1757351.3045',
326
+ '5793264.8304 1798321.5516',
327
+ ]);
215
328
 
216
- o(layers[1].find('ows:Title')?.textContent).equals('imagery-title');
217
- o(layers[1].find('TileMatrixSet')?.textContent).equals('EPSG:2193');
329
+ const wgs84 = layer.find('ows:WGS84BoundingBox');
330
+ o(wgs84?.attrs.crs).equals('urn:ogc:def:crs:OGC:2:84');
331
+ o(wgs84?.children.map((c) => roundNumbersInString(c.textContent, 4))).deepEquals([
332
+ '174.7925 -38.2123',
333
+ '175.2594 -37.9962',
334
+ ]);
218
335
  });
219
336
 
220
- o('should support child tile sets', () => {
221
- const ts = [
222
- new FakeTileSet(
223
- `${TileSetName.aerial}:wairoa_urban_2014-2015_0-10m_RGBA`,
224
- Nztm2000Tms,
225
- 'wairoa_urban_2014-2015_0-10m_RGBA',
226
- ),
227
- new FakeTileSet(
228
- `${TileSetName.aerial}:west-coast_rural_2016-17_0-3m`,
229
- Nztm2000Tms,
230
- 'west-coast_rural_2016-17_0-3m',
231
- ),
232
- ];
233
- const nodes = new WmtsCapabilities({ httpBase: 'basemaps.test', provider: Provider, layers: ts }).toVNode();
234
- const layers = tags(nodes, 'Layer');
235
-
236
- o(layers.length).equals(2);
237
-
238
- const boundingBoxes = tags(layers[0], 'ows:BoundingBox');
239
- o(boundingBoxes.length).equals(1);
337
+ o('should only output imagery if exists', () => {
338
+ const imagery = new Map<string, ConfigImagery>();
339
+ const raw = new WmtsCapabilities({
340
+ httpBase: 'https://basemaps.test',
341
+ provider: Provider,
342
+ tileMatrix: [Nztm2000QuadTms],
343
+ tileSet: TileSetAerial,
344
+ imagery: imagery,
345
+ formats: [ImageFormat.Png],
346
+ isIndividualLayers: true,
347
+ }).toVNode();
240
348
 
241
- const firstTitle = layers[0].children[0].textContent;
242
- o(firstTitle).equals('wairoa_urban_2014-2015_0-10m_RGBA');
243
- const secondTitle = layers[1].children[0].textContent;
244
- o(secondTitle).equals('west-coast_rural_2016-17_0-3m');
245
- });
349
+ const layers = tags(raw, 'Layer');
350
+ o(layers.length).equals(1);
246
351
 
247
- o('should support multiple different projections on different tiles sets', () => {
248
- const ts = [
249
- new FakeTileSet(TileSetName.aerial, Nztm2000Tms, TileSetName.aerial),
250
- new FakeTileSet('01F75X9G7FQ3XMWPJFR9AMQFJ0', Nztm2000Tms, '01F75X9G7FQ3XMWPJFR9AMQFJ0'),
251
- new FakeTileSet('01E7PJFR9AMQFJ05X9G7FQ3XMW', GoogleTms, '01E7PJFR9AMQFJ05X9G7FQ3XMW'),
252
- new FakeTileSet('01E7PJFR9AMQFJ05X9G7FQ3XMW', Nztm2000QuadTms, '01E7PJFR9AMQFJ05X9G7FQ3XMW'),
253
- ];
254
- ts[1].extentOverride = new Bounds(1, 2, 2, 2);
255
-
256
- ts[2].tileSet.title = 'aerial_dunedin_urban';
257
- const nodes = new WmtsCapabilities({ httpBase: 'basemaps.test', provider: Provider, layers: ts }).toVNode();
258
-
259
- const allMatrixes = tags(nodes, 'TileMatrixSet');
260
-
261
- o(allMatrixes[0].children[0].textContent).equals('EPSG:2193');
262
- o(allMatrixes[1].children[0].textContent).equals('EPSG:2193');
263
- o(allMatrixes[2].children[0].textContent).equals('EPSG:3857');
264
- o(allMatrixes[3].children[0].textContent).equals('NZTM2000Quad');
265
-
266
- o(allMatrixes[4].find('ows:Identifier')?.textContent).equals('EPSG:2193');
267
- o(allMatrixes[5].find('ows:Identifier')?.textContent).equals('EPSG:3857');
268
- o(allMatrixes[6].find('ows:Identifier')?.textContent).equals('NZTM2000Quad');
269
- o(allMatrixes.length).equals(7);
270
-
271
- const layers = tags(nodes, 'Layer');
272
- o(layers.length).equals(3);
273
-
274
- o(layers[0].find('ows:Title')?.textContent).equals(TileSetName.aerial);
275
- o(layers[0].find('TileMatrixSet')?.textContent).equals('EPSG:2193');
276
-
277
- o(layers[1].find('ows:Identifier')?.textContent).equals('01F75X9G7FQ3XMWPJFR9AMQFJ0');
278
- o(layers[1].find('TileMatrixSet')?.textContent).equals('EPSG:2193');
279
- o(layers[1].find('ows:BoundingBox')?.toString()).equals(
280
- '<ows:BoundingBox crs="urn:ogc:def:crs:EPSG::2193">\n' +
281
- ' <ows:LowerCorner>2 1</ows:LowerCorner>\n' +
282
- ' <ows:UpperCorner>4 3</ows:UpperCorner>\n' +
283
- '</ows:BoundingBox>',
284
- );
352
+ imagery.set(Imagery3857.id, Imagery3857);
353
+ const rawB = new WmtsCapabilities({
354
+ httpBase: 'https://basemaps.test',
355
+ provider: Provider,
356
+ tileMatrix: [Nztm2000QuadTms],
357
+ tileSet: TileSetAerial,
358
+ imagery: imagery,
359
+ formats: [ImageFormat.Png],
360
+ isIndividualLayers: true,
361
+ }).toVNode();
285
362
 
286
- o(layers[2].find('ows:Title')?.textContent).equals('aerial_dunedin_urban');
287
- o(layers[2].find('ows:Identifier')?.textContent).equals('01E7PJFR9AMQFJ05X9G7FQ3XMW');
288
- o(layers[2].find('TileMatrixSet')?.textContent).equals('EPSG:3857');
289
- o(layers[2].find('ows:BoundingBox')?.toString()).equals(
290
- '<ows:BoundingBox crs="urn:ogc:def:crs:EPSG::3857">\n' +
291
- ' <ows:LowerCorner>-20037508.3427892 -20037508.3427892</ows:LowerCorner>\n' +
292
- ' <ows:UpperCorner>20037508.3427892 20037508.3427892</ows:UpperCorner>\n' +
293
- '</ows:BoundingBox>',
294
- );
363
+ const layersB = tags(rawB, 'Layer');
364
+ o(layersB.length).equals(1);
295
365
  });
296
366
  });
@@ -1,6 +1,6 @@
1
1
  import { ConfigProvider, StyleJson } from '@basemaps/config';
2
2
  import { GoogleTms, Nztm2000QuadTms, TileMatrixSets } from '@basemaps/geo';
3
- import { Config, Env, LogConfig, VNodeParser } from '@basemaps/shared';
3
+ import { Config, Env, LogConfig } from '@basemaps/shared';
4
4
  import { round } from '@basemaps/test/build/rounding.js';
5
5
  import o from 'ospec';
6
6
  import sinon from 'sinon';
@@ -8,7 +8,8 @@ import { handleRequest } from '../index.js';
8
8
  import { TileEtag } from '../routes/tile.etag.js';
9
9
  import { TileSets } from '../tile.set.cache.js';
10
10
  import { TileComposer } from '../tile.set.raster.js';
11
- import { FakeTileSet, FakeTileSetVector, mockRequest, Provider } from './xyz.util.js';
11
+ import { Provider } from './config.data.js';
12
+ import { FakeTileSet, FakeTileSetVector, mockRequest } from './xyz.util.js';
12
13
 
13
14
  const sandbox = sinon.createSandbox();
14
15
 
@@ -142,51 +143,6 @@ o.spec('LambdaXyz', () => {
142
143
  }
143
144
  });
144
145
 
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
146
  o.spec('tileJson', () => {
191
147
  o('should 404 if invalid url is given', async () => {
192
148
  const request = mockRequest('/v1/tiles/tile.json', 'get', apiKeyHeader);
@@ -217,7 +173,7 @@ o.spec('LambdaXyz', () => {
217
173
 
218
174
  const body = Buffer.from(res.body ?? '', 'base64').toString();
219
175
  o(JSON.parse(body)).deepEquals({
220
- tiles: [`https://tiles.test/v1/tiles/topographic/EPSG:3857/{z}/{x}/{y}.pbf?api=${apiKey}`],
176
+ tiles: [`https://tiles.test/v1/tiles/topographic/WebMercatorQuad/{z}/{x}/{y}.pbf?api=${apiKey}`],
221
177
  tilejson: '3.0.0',
222
178
  });
223
179
  });
@@ -234,7 +190,7 @@ o.spec('LambdaXyz', () => {
234
190
 
235
191
  const body = Buffer.from(res.body ?? '', 'base64').toString();
236
192
  o(JSON.parse(body)).deepEquals({
237
- tiles: [`https://tiles.test/v1/tiles/fake-vector/EPSG:3857/{z}/{x}/{y}.pbf?api=${apiKey}`],
193
+ tiles: [`https://tiles.test/v1/tiles/fake-vector/WebMercatorQuad/{z}/{x}/{y}.pbf?api=${apiKey}`],
238
194
  maxzoom: 15,
239
195
  minzoom: 3,
240
196
  tilejson: '3.0.0',
@@ -1,4 +1,3 @@
1
- import { ConfigProvider } from '@basemaps/config';
2
1
  import { TileMatrixSet } from '@basemaps/geo';
3
2
  import { LogConfig } from '@basemaps/shared';
4
3
  import { LambdaAlbRequest, LambdaHttpRequest } from '@linzjs/lambda';
@@ -24,7 +23,12 @@ export function mockRequest(path: string, method = 'get', headers: Record<string
24
23
  export class FakeTileSet extends TileSetRaster {
25
24
  constructor(name: string, tileMatrix: TileMatrixSet, title = `${name}:title`, description = `${name}:description`) {
26
25
  super(name, tileMatrix);
27
- this.tileSet = { title, description } as any;
26
+ this.tileSet = {
27
+ name,
28
+ title,
29
+ description,
30
+ layers: [{ name: `imagery_${name}`, [tileMatrix.projection.code]: `im_${title}` }],
31
+ } as any;
28
32
  }
29
33
  }
30
34
 
@@ -34,32 +38,3 @@ export class FakeTileSetVector extends TileSetVector {
34
38
  this.tileSet = {} as any;
35
39
  }
36
40
  }
37
-
38
- export const Provider: ConfigProvider = {
39
- name: 'main',
40
- id: 'pv_main_production',
41
- updatedAt: Date.now(),
42
- version: 1,
43
- serviceIdentification: {
44
- accessConstraints: 'the accessConstraints',
45
- description: 'the description',
46
- fees: 'the fees',
47
- title: 'the title',
48
- },
49
- serviceProvider: {
50
- contact: {
51
- address: {
52
- city: 'the city',
53
- country: 'the country',
54
- deliveryPoint: 'the deliveryPoint',
55
- email: 'email address',
56
- postalCode: 'the postalCode',
57
- },
58
- individualName: 'the contact name',
59
- phone: 'the phone',
60
- position: 'the position',
61
- },
62
- name: 'the name',
63
- site: 'https://example.provider.com',
64
- },
65
- };