@basemaps/lambda-tiler 7.3.0 → 7.5.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 (91) hide show
  1. package/CHANGELOG.md +36 -0
  2. package/build/__tests__/config.data.d.ts +2 -0
  3. package/build/__tests__/config.data.js +24 -1
  4. package/build/__tests__/config.data.js.map +1 -1
  5. package/build/__tests__/index.test.js +1 -2
  6. package/build/__tests__/index.test.js.map +1 -1
  7. package/build/__tests__/tile.style.json.test.js +71 -16
  8. package/build/__tests__/tile.style.json.test.js.map +1 -1
  9. package/build/__tests__/wmts.capability.test.js +5 -2
  10. package/build/__tests__/wmts.capability.test.js.map +1 -1
  11. package/build/__tests__/xyz.util.js.map +1 -1
  12. package/build/cli/render.preview.js +5 -2
  13. package/build/cli/render.preview.js.map +1 -1
  14. package/build/cli/render.tile.js +1 -1
  15. package/build/cli/render.tile.js.map +1 -1
  16. package/build/index.js +1 -1
  17. package/build/index.js.map +1 -1
  18. package/build/routes/__tests__/attribution.test.js +1 -1
  19. package/build/routes/__tests__/attribution.test.js.map +1 -1
  20. package/build/routes/__tests__/health.test.js +1 -1
  21. package/build/routes/__tests__/health.test.js.map +1 -1
  22. package/build/routes/__tests__/imagery.test.js.map +1 -1
  23. package/build/routes/__tests__/memory.fs.js +1 -1
  24. package/build/routes/__tests__/memory.fs.js.map +1 -1
  25. package/build/routes/__tests__/preview.index.test.js +1 -1
  26. package/build/routes/__tests__/preview.index.test.js.map +1 -1
  27. package/build/routes/__tests__/tile.json.test.js.map +1 -1
  28. package/build/routes/__tests__/tile.style.json.test.js +144 -11
  29. package/build/routes/__tests__/tile.style.json.test.js.map +1 -1
  30. package/build/routes/__tests__/wmts.test.js +18 -2
  31. package/build/routes/__tests__/wmts.test.js.map +1 -1
  32. package/build/routes/config.js +1 -1
  33. package/build/routes/config.js.map +1 -1
  34. package/build/routes/ping.js +2 -2
  35. package/build/routes/ping.js.map +1 -1
  36. package/build/routes/preview.index.js +2 -1
  37. package/build/routes/preview.index.js.map +1 -1
  38. package/build/routes/preview.js +3 -1
  39. package/build/routes/preview.js.map +1 -1
  40. package/build/routes/sprites.js.map +1 -1
  41. package/build/routes/tile.style.json.d.ts +5 -4
  42. package/build/routes/tile.style.json.js +78 -24
  43. package/build/routes/tile.style.json.js.map +1 -1
  44. package/build/routes/tile.wmts.js +1 -0
  45. package/build/routes/tile.wmts.js.map +1 -1
  46. package/build/routes/tile.xyz.raster.js +6 -5
  47. package/build/routes/tile.xyz.raster.js.map +1 -1
  48. package/build/routes/version.js +2 -2
  49. package/build/routes/version.js.map +1 -1
  50. package/build/util/__test__/config.loader.test.js +12 -12
  51. package/build/util/__test__/config.loader.test.js.map +1 -1
  52. package/build/util/config.cache.js.map +1 -1
  53. package/build/util/source.cache.js +5 -4
  54. package/build/util/source.cache.js.map +1 -1
  55. package/build/util/validate.js +1 -1
  56. package/build/util/validate.js.map +1 -1
  57. package/build/wmts.capability.d.ts +8 -4
  58. package/build/wmts.capability.js +18 -8
  59. package/build/wmts.capability.js.map +1 -1
  60. package/package.json +10 -10
  61. package/src/__tests__/config.data.ts +31 -2
  62. package/src/__tests__/index.test.ts +2 -3
  63. package/src/__tests__/tile.style.json.test.ts +89 -16
  64. package/src/__tests__/wmts.capability.test.ts +13 -10
  65. package/src/__tests__/xyz.util.ts +4 -4
  66. package/src/cli/render.preview.ts +5 -2
  67. package/src/cli/render.tile.ts +1 -1
  68. package/src/routes/__tests__/attribution.test.ts +7 -7
  69. package/src/routes/__tests__/health.test.ts +3 -3
  70. package/src/routes/__tests__/imagery.test.ts +1 -1
  71. package/src/routes/__tests__/memory.fs.ts +2 -2
  72. package/src/routes/__tests__/preview.index.test.ts +3 -3
  73. package/src/routes/__tests__/tile.json.test.ts +1 -1
  74. package/src/routes/__tests__/tile.style.json.test.ts +175 -15
  75. package/src/routes/__tests__/wmts.test.ts +23 -3
  76. package/src/routes/config.ts +1 -1
  77. package/src/routes/ping.ts +2 -2
  78. package/src/routes/preview.index.ts +2 -1
  79. package/src/routes/preview.ts +4 -2
  80. package/src/routes/sprites.ts +1 -1
  81. package/src/routes/tile.style.json.ts +103 -24
  82. package/src/routes/tile.wmts.ts +1 -0
  83. package/src/routes/tile.xyz.raster.ts +7 -5
  84. package/src/routes/version.ts +2 -2
  85. package/src/util/__test__/config.loader.test.ts +17 -20
  86. package/src/util/config.cache.ts +2 -1
  87. package/src/util/source.cache.ts +6 -4
  88. package/src/util/validate.ts +1 -1
  89. package/src/wmts.capability.ts +17 -9
  90. package/tsconfig.json +10 -10
  91. package/tsconfig.tsbuildinfo +1 -1
@@ -1,5 +1,5 @@
1
- import { ConfigTileSetRaster, Layer, Sources, StyleJson, TileSetType } from '@basemaps/config';
2
- import { GoogleTms, TileMatrixSets } from '@basemaps/geo';
1
+ import { ConfigId, ConfigPrefix, ConfigTileSetRaster, Layer, Sources, StyleJson, TileSetType } from '@basemaps/config';
2
+ import { GoogleTms, TileMatrixSet, TileMatrixSets } from '@basemaps/geo';
3
3
  import { Env, toQueryString } from '@basemaps/shared';
4
4
  import { HttpHeader, LambdaHttpRequest, LambdaHttpResponse } from '@linzjs/lambda';
5
5
  import { URL } from 'url';
@@ -15,8 +15,14 @@ import { Validate } from '../util/validate.js';
15
15
  * @param apiKey ApiKey to append with ?api= if required
16
16
  * @returns Updated Url or empty string if url is empty
17
17
  */
18
- export function convertRelativeUrl(url?: string, apiKey?: string, config?: string | null): string {
18
+ export function convertRelativeUrl(
19
+ url?: string,
20
+ tileMatrix?: TileMatrixSet,
21
+ apiKey?: string,
22
+ config?: string | null,
23
+ ): string {
19
24
  if (url == null) return '';
25
+ if (tileMatrix) url = url.replace('{tileMatrix}', tileMatrix.identifier);
20
26
  const host = Env.get(Env.PublicUrlBase) ?? '';
21
27
  if (!url.startsWith('/')) return url; // Not relative ignore
22
28
  const fullUrl = new URL(url, host);
@@ -31,29 +37,41 @@ export function convertRelativeUrl(url?: string, apiKey?: string, config?: strin
31
37
  * @param apiKey api key to inject
32
38
  * @returns new stylejson
33
39
  */
34
- export function convertStyleJson(style: StyleJson, apiKey: string, config: string | null, layers?: Layer[]): StyleJson {
35
- const sources: Sources = JSON.parse(JSON.stringify(style.sources));
40
+ export function convertStyleJson(
41
+ style: StyleJson,
42
+ tileMatrix: TileMatrixSet,
43
+ apiKey: string,
44
+ config: string | null,
45
+ layers?: Layer[],
46
+ ): StyleJson {
47
+ const sources = JSON.parse(JSON.stringify(style.sources)) as Sources;
36
48
  for (const [key, value] of Object.entries(sources)) {
37
49
  if (value.type === 'vector') {
38
- value.url = convertRelativeUrl(value.url, apiKey, config);
39
- } else if (value.type === 'raster' && Array.isArray(value.tiles)) {
50
+ if (tileMatrix !== GoogleTms) {
51
+ throw new LambdaHttpResponse(400, `TileMatrix is not supported for the vector source ${value.url}.`);
52
+ }
53
+ value.url = convertRelativeUrl(value.url, tileMatrix, apiKey, config);
54
+ } else if ((value.type === 'raster' || value.type === 'raster-dem') && Array.isArray(value.tiles)) {
40
55
  for (let i = 0; i < value.tiles.length; i++) {
41
- value.tiles[i] = convertRelativeUrl(value.tiles[i], apiKey, config);
56
+ value.tiles[i] = convertRelativeUrl(value.tiles[i], tileMatrix, apiKey, config);
42
57
  }
43
58
  }
44
59
  sources[key] = value;
45
60
  }
46
61
 
47
- return {
62
+ const styleJson: StyleJson = {
48
63
  version: 8,
49
64
  id: style.id,
50
65
  name: style.name,
51
66
  sources,
52
67
  layers: layers ? layers : style.layers,
53
- metadata: style.metadata ?? {},
54
- glyphs: convertRelativeUrl(style.glyphs, undefined, config),
55
- sprite: convertRelativeUrl(style.sprite, undefined, config),
56
- } as StyleJson;
68
+ };
69
+
70
+ if (style.metadata) styleJson.metadata = style.metadata;
71
+ if (style.glyphs) styleJson.glyphs = convertRelativeUrl(style.glyphs, undefined, undefined, config);
72
+ if (style.sprite) styleJson.sprite = convertRelativeUrl(style.sprite, undefined, undefined, config);
73
+
74
+ return styleJson;
57
75
  }
58
76
 
59
77
  export interface StyleGet {
@@ -62,13 +80,42 @@ export interface StyleGet {
62
80
  };
63
81
  }
64
82
 
83
+ function setStyleTerrain(style: StyleJson, terrain: string): void {
84
+ const source = Object.keys(style.sources).find((s) => s === terrain);
85
+ if (source == null) throw new LambdaHttpResponse(400, `Terrain: ${terrain} is not exists in the style source.`);
86
+ style.terrain = {
87
+ source,
88
+ exaggeration: 1.2,
89
+ };
90
+ }
91
+
92
+ async function ensureTerrain(
93
+ req: LambdaHttpRequest<StyleGet>,
94
+ tileMatrix: TileMatrixSet,
95
+ apiKey: string,
96
+ style: StyleJson,
97
+ ): Promise<void> {
98
+ const config = await ConfigLoader.load(req);
99
+ const terrain = await config.TileSet.get('ts_elevation');
100
+ if (terrain) {
101
+ const configLocation = ConfigLoader.extract(req);
102
+ const elevationQuery = toQueryString({ config: configLocation, api: apiKey, pipeline: 'terrain-rgb' });
103
+ style.sources['LINZ-Terrain'] = {
104
+ type: 'raster-dem',
105
+ tileSize: 256,
106
+ maxzoom: 18,
107
+ tiles: [convertRelativeUrl(`/v1/tiles/elevation/${tileMatrix.identifier}/{z}/{x}/{y}.png${elevationQuery}`)],
108
+ };
109
+ }
110
+ }
111
+
65
112
  export async function tileSetToStyle(
66
113
  req: LambdaHttpRequest<StyleGet>,
67
114
  tileSet: ConfigTileSetRaster,
115
+ tileMatrix: TileMatrixSet,
68
116
  apiKey: string,
117
+ terrain?: string,
69
118
  ): Promise<LambdaHttpResponse> {
70
- const tileMatrix = TileMatrixSets.find(req.query.get('tileMatrix') ?? GoogleTms.identifier);
71
- if (tileMatrix == null) return new LambdaHttpResponse(400, 'Invalid tile matrix');
72
119
  const [tileFormat] = Validate.getRequestedFormats(req) ?? ['webp'];
73
120
  if (tileFormat == null) return new LambdaHttpResponse(400, 'Invalid image format');
74
121
 
@@ -83,11 +130,20 @@ export async function tileSetToStyle(
83
130
  `/v1/tiles/${tileSet.name}/${tileMatrix.identifier}/{z}/{x}/{y}.${tileFormat}${query}`;
84
131
 
85
132
  const styleId = `basemaps-${tileSet.name}`;
86
- const style = {
133
+ const style: StyleJson = {
134
+ id: ConfigId.prefix(ConfigPrefix.Style, tileSet.name),
135
+ name: tileSet.name,
87
136
  version: 8,
88
137
  sources: { [styleId]: { type: 'raster', tiles: [tileUrl], tileSize: 256 } },
89
138
  layers: [{ id: styleId, type: 'raster', source: styleId }],
90
139
  };
140
+
141
+ // Ensure elevation for individual tilesets
142
+ await ensureTerrain(req, tileMatrix, apiKey, style);
143
+
144
+ // Add terrain in style
145
+ if (terrain) setStyleTerrain(style, terrain);
146
+
91
147
  const data = Buffer.from(JSON.stringify(style));
92
148
 
93
149
  const cacheKey = Etag.key(data);
@@ -104,11 +160,10 @@ export async function tileSetToStyle(
104
160
  export async function tileSetOutputToStyle(
105
161
  req: LambdaHttpRequest<StyleGet>,
106
162
  tileSet: ConfigTileSetRaster,
163
+ tileMatrix: TileMatrixSet,
107
164
  apiKey: string,
165
+ terrain?: string,
108
166
  ): Promise<LambdaHttpResponse> {
109
- const tileMatrix = TileMatrixSets.find(req.query.get('tileMatrix') ?? GoogleTms.identifier);
110
- if (tileMatrix == null) return new LambdaHttpResponse(400, 'Invalid tile matrix');
111
-
112
167
  const configLocation = ConfigLoader.extract(req);
113
168
  const query = toQueryString({ config: configLocation, api: apiKey });
114
169
 
@@ -158,19 +213,31 @@ export async function tileSetOutputToStyle(
158
213
  }
159
214
  }
160
215
 
161
- const style = { version: 8, sources, layers };
216
+ const style: StyleJson = {
217
+ id: ConfigId.prefix(ConfigPrefix.Style, tileSet.name),
218
+ name: tileSet.name,
219
+ version: 8,
220
+ sources,
221
+ layers,
222
+ };
223
+
224
+ // Ensure elevation for style json config
225
+ await ensureTerrain(req, tileMatrix, apiKey, style);
226
+
227
+ // Add terrain in style
228
+ if (terrain) setStyleTerrain(style, terrain);
162
229
 
163
230
  const data = Buffer.from(JSON.stringify(style));
164
231
 
165
232
  const cacheKey = Etag.key(data);
166
- if (Etag.isNotModified(req, cacheKey)) return NotModified();
233
+ if (Etag.isNotModified(req, cacheKey)) return Promise.resolve(NotModified());
167
234
 
168
235
  const response = new LambdaHttpResponse(200, 'ok');
169
236
  response.header(HttpHeader.ETag, cacheKey);
170
237
  response.header(HttpHeader.CacheControl, 'no-store');
171
238
  response.buffer(data, 'application/json');
172
239
  req.set('bytes', data.byteLength);
173
- return response;
240
+ return Promise.resolve(response);
174
241
  }
175
242
 
176
243
  export async function styleJsonGet(req: LambdaHttpRequest<StyleGet>): Promise<LambdaHttpResponse> {
@@ -178,6 +245,9 @@ export async function styleJsonGet(req: LambdaHttpRequest<StyleGet>): Promise<La
178
245
  const styleName = req.params.styleName;
179
246
  const excludeLayers = req.query.getAll('exclude');
180
247
  const excluded = new Set(excludeLayers.map((l) => l.toLowerCase()));
248
+ const tileMatrix = TileMatrixSets.find(req.query.get('tileMatrix') ?? GoogleTms.identifier);
249
+ if (tileMatrix == null) return new LambdaHttpResponse(400, 'Invalid tile matrix');
250
+ const terrain = req.query.get('terrain') ?? undefined;
181
251
 
182
252
  // Get style Config from db
183
253
  const config = await ConfigLoader.load(req);
@@ -188,17 +258,26 @@ export async function styleJsonGet(req: LambdaHttpRequest<StyleGet>): Promise<La
188
258
  const tileSet = await config.TileSet.get(config.TileSet.id(styleName));
189
259
  if (tileSet == null) return NotFound();
190
260
  if (tileSet.type !== TileSetType.Raster) return NotFound();
191
- if (tileSet.outputs) return tileSetOutputToStyle(req, tileSet, apiKey);
192
- else return tileSetToStyle(req, tileSet, apiKey);
261
+ if (tileSet.outputs) return await tileSetOutputToStyle(req, tileSet, tileMatrix, apiKey, terrain);
262
+ else return await tileSetToStyle(req, tileSet, tileMatrix, apiKey, terrain);
193
263
  }
194
264
 
195
265
  // Prepare sources and add linz source
196
266
  const style = convertStyleJson(
197
267
  styleConfig.style,
268
+ tileMatrix,
198
269
  apiKey,
199
270
  ConfigLoader.extract(req),
200
271
  styleConfig.style.layers.filter((f) => !excluded.has(f.id.toLowerCase())),
201
272
  );
273
+
274
+ // Ensure elevation for style json config
275
+ // TODO: We should remove this after adding terrain source into style configs. PR-916
276
+ await ensureTerrain(req, tileMatrix, apiKey, style);
277
+
278
+ // Add terrain in style
279
+ if (terrain) setStyleTerrain(style, terrain);
280
+
202
281
  const data = Buffer.from(JSON.stringify(style));
203
282
 
204
283
  const cacheKey = Etag.key(data);
@@ -69,6 +69,7 @@ export async function wmtsCapabilitiesGet(req: LambdaHttpRequest<WmtsCapabilitie
69
69
  imagery,
70
70
  formats: Validate.getRequestedFormats(req) ?? [],
71
71
  layers: req.params.tileMatrix == null ? tileSet.layers : undefined,
72
+ pipeline: req.query.get('pipeline'),
72
73
  });
73
74
 
74
75
  const xml = wmts.toXml();
@@ -95,19 +95,21 @@ export const TileXyzRaster = {
95
95
  toLoad.push(
96
96
  LoadingQueue((): Promise<CloudArchive | null> => {
97
97
  if (assetPath.pathname.endsWith('.tar.co')) {
98
- return CoSources.getCotar(assetPath).catch((error) => {
99
- req.log.warn({ error, tiff: assetPath }, 'Load:Cotar:Failed');
98
+ return CoSources.getCotar(assetPath).catch((err: unknown) => {
99
+ req.log.warn({ err, tiff: assetPath }, 'Load:Cotar:Failed');
100
100
  return null;
101
101
  });
102
102
  }
103
- return CoSources.getCog(assetPath).catch((error) => {
104
- req.log.warn({ error, tiff: assetPath }, 'Load:Tiff:Failed');
103
+ return CoSources.getCog(assetPath).catch((err: unknown) => {
104
+ req.log.warn({ err, tiff: assetPath }, 'Load:Tiff:Failed');
105
105
  return null;
106
106
  });
107
107
  }),
108
108
  );
109
109
  }
110
110
 
111
+ // Remove with typescript >=5.5.0
112
+
111
113
  return (await Promise.all(toLoad)).filter((f) => f != null) as CloudArchive[];
112
114
  },
113
115
 
@@ -128,7 +130,7 @@ export const TileXyzRaster = {
128
130
  const assets = await TileXyzRaster.loadAssets(req, assetPaths);
129
131
 
130
132
  const tiler = new Tiler(xyz.tileMatrix);
131
- const layers = await tiler.tile(assets, xyz.tile.x, xyz.tile.y, xyz.tile.z);
133
+ const layers = tiler.tile(assets, xyz.tile.x, xyz.tile.y, xyz.tile.z);
132
134
 
133
135
  const format = getImageFormat(xyz.tileType);
134
136
  if (format == null) return new LambdaHttpResponse(400, 'Invalid image format: ' + xyz.tileType);
@@ -1,6 +1,6 @@
1
1
  import { HttpHeader, LambdaHttpResponse } from '@linzjs/lambda';
2
2
 
3
- export async function versionGet(): Promise<LambdaHttpResponse> {
3
+ export function versionGet(): Promise<LambdaHttpResponse> {
4
4
  const response = new LambdaHttpResponse(200, 'ok');
5
5
  response.header(HttpHeader.CacheControl, 'no-store');
6
6
  response.json({
@@ -20,5 +20,5 @@ export async function versionGet(): Promise<LambdaHttpResponse> {
20
20
  */
21
21
  buildId: process.env['BUILD_ID'],
22
22
  });
23
- return response;
23
+ return Promise.resolve(response);
24
24
  }
@@ -42,11 +42,11 @@ describe('ConfigLoader', () => {
42
42
  mockUrlRequest('/v1/tiles/🦄 🌈/NZTM2000Quad/tile.json', `?config=notapath`, Api.header),
43
43
  )
44
44
  .then(() => null)
45
- .catch((e) => e);
45
+ .catch((e) => e as LambdaHttpResponse);
46
46
 
47
47
  assert.equal(error instanceof LambdaHttpResponse, true);
48
- assert.equal((error as LambdaHttpResponse).status, 400);
49
- assert.equal((error as LambdaHttpResponse).statusDescription, 'Invalid configuration location protocol:file:');
48
+ assert.equal(error?.status, 400);
49
+ assert.equal(error?.statusDescription, 'Invalid configuration location protocol:file:');
50
50
  });
51
51
 
52
52
  it('should Not working with wrong protocol', async () => {
@@ -54,11 +54,11 @@ describe('ConfigLoader', () => {
54
54
  mockUrlRequest('/v1/tiles/🦄 🌈/NZTM2000Quad/tile.json', `?config=memory1://linz-basemaps/config`, Api.header),
55
55
  )
56
56
  .then(() => null)
57
- .catch((e) => e);
57
+ .catch((e) => e as LambdaHttpResponse);
58
58
 
59
59
  assert.equal(error instanceof LambdaHttpResponse, true);
60
- assert.equal((error as LambdaHttpResponse).status, 400);
61
- assert.equal((error as LambdaHttpResponse).statusDescription, 'Invalid configuration location protocol:memory1:');
60
+ assert.equal(error?.status, 400);
61
+ assert.equal(error?.statusDescription, 'Invalid configuration location protocol:memory1:');
62
62
  });
63
63
 
64
64
  it('should Not working with wrong s3 bucket', async () => {
@@ -66,28 +66,25 @@ describe('ConfigLoader', () => {
66
66
  mockUrlRequest('/v1/tiles/🦄 🌈/NZTM2000Quad/tile.json', `?config=s3://wrong-bucket/config`, Api.header),
67
67
  )
68
68
  .then(() => null)
69
- .catch((e) => e);
69
+ .catch((e) => e as LambdaHttpResponse);
70
70
 
71
71
  assert.equal(error instanceof LambdaHttpResponse, true);
72
- assert.equal((error as LambdaHttpResponse).status, 400);
73
- assert.equal(
74
- (error as LambdaHttpResponse).statusDescription,
75
- 'Bucket: "wrong-bucket" is not a allowed bucket location',
76
- );
72
+ assert.equal(error?.status, 400);
73
+ assert.equal(error?.statusDescription, 'Bucket: "wrong-bucket" is not a allowed bucket location');
77
74
  });
78
75
 
79
76
  const location = new URL('memory://linz-basemaps/config.json');
80
77
 
81
78
  it('should Not working with no file in the path', async () => {
82
79
  const error = await ConfigLoader.load(
83
- mockUrlRequest('/v1/tiles/🦄 🌈/NZTM2000Quad/tile.json', `?config=${location}`, Api.header),
80
+ mockUrlRequest('/v1/tiles/🦄 🌈/NZTM2000Quad/tile.json', `?config=${location.href}`, Api.header),
84
81
  )
85
82
  .then(() => null)
86
- .catch((e) => e);
83
+ .catch((e) => e as LambdaHttpResponse);
87
84
 
88
85
  assert.equal(error instanceof LambdaHttpResponse, true);
89
- assert.equal((error as LambdaHttpResponse).status, 400);
90
- assert.equal((error as LambdaHttpResponse).statusDescription, `Invalid config location at ${location}`);
86
+ assert.equal(error?.status, 400);
87
+ assert.equal(error?.statusDescription, `Invalid config location at ${location.href}`);
91
88
  });
92
89
 
93
90
  it('should get expected config file', async () => {
@@ -96,7 +93,7 @@ describe('ConfigLoader', () => {
96
93
  await fsa.write(location, Buffer.from(JSON.stringify(expectedConfig.toJson())));
97
94
 
98
95
  const provider = await ConfigLoader.load(
99
- mockUrlRequest('/v1/tiles/🦄 🌈/NZTM2000Quad/tile.json', `?config=${location}`, Api.header),
96
+ mockUrlRequest('/v1/tiles/🦄 🌈/NZTM2000Quad/tile.json', `?config=${location.href}`, Api.header),
100
97
  );
101
98
 
102
99
  assert.deepEqual(await provider.Imagery.get('aerial'), await expectedConfig.Imagery.get('aerial'));
@@ -124,10 +121,10 @@ describe('ConfigLoader', () => {
124
121
  mockUrlRequest('/v1/tiles/🦄 🌈/NZTM2000Quad/tile.json', `?config=${deletedLocation}`, Api.header),
125
122
  )
126
123
  .then(() => null)
127
- .catch((e) => e);
124
+ .catch((e) => e as LambdaHttpResponse);
128
125
 
129
126
  assert.equal(error instanceof LambdaHttpResponse, true);
130
- assert.equal((error as LambdaHttpResponse).status, 400);
131
- assert.equal((error as LambdaHttpResponse).statusDescription, `Invalid config location at ${deletedLocation}`);
127
+ assert.equal(error?.status, 400);
128
+ assert.equal(error?.statusDescription, `Invalid config location at ${deletedLocation}`);
132
129
  });
133
130
  });
@@ -1,5 +1,6 @@
1
1
  import { ConfigBundled, ConfigProviderMemory } from '@basemaps/config';
2
2
  import { fsa } from '@basemaps/shared';
3
+ import { FsError } from '@chunkd/fs';
3
4
 
4
5
  import { SwappingLru } from './swapping.lru.js';
5
6
 
@@ -15,7 +16,7 @@ class LruConfig {
15
16
  return configProvider;
16
17
  })
17
18
  .catch((e) => {
18
- if (e.code === 404) return null;
19
+ if ((e as FsError).code === 404) return null;
19
20
  throw e;
20
21
  });
21
22
  }
@@ -20,7 +20,9 @@ class LruStrutObj<T extends LruStrut> {
20
20
  ob: T;
21
21
  constructor(ob: T) {
22
22
  this.ob = ob;
23
- if (this.ob._value == null) this.ob.value.then((c) => (this.ob._value = c));
23
+ if (this.ob._value == null) {
24
+ void this.ob.value.then((c) => (this.ob._value = c));
25
+ }
24
26
  }
25
27
 
26
28
  size = 1;
@@ -37,7 +39,7 @@ export class SourceCache {
37
39
 
38
40
  if (existing != null) {
39
41
  if (existing.type === 'cog') return existing.value;
40
- throw new Error(`Existing object of type: ${existing.type} made for location: ${location}`);
42
+ throw new Error(`Existing object of type: ${existing.type} made for location: ${location.href}`);
41
43
  }
42
44
  const value = Tiff.create(fsa.source(location));
43
45
  this.cache.set(location.href, new LruStrutObj({ type: 'cog', value }));
@@ -48,8 +50,8 @@ export class SourceCache {
48
50
  const existing = this.cache.get(location.href)?.ob;
49
51
 
50
52
  if (existing != null) {
51
- if (existing.type === 'cotar') return existing.value as Promise<Cotar>;
52
- throw new Error(`Existing object of type: ${existing.type} made for location: ${location}`);
53
+ if (existing.type === 'cotar') return existing.value;
54
+ throw new Error(`Existing object of type: ${existing.type} made for location: ${location.href}`);
53
55
  }
54
56
  const value = Cotar.fromTar(fsa.source(location));
55
57
  this.cache.set(location.href, new LruStrutObj({ type: 'cotar', value }));
@@ -138,7 +138,7 @@ export const Validate = {
138
138
  }
139
139
  // If the tileset has pipelines defined the user MUST specify which one
140
140
  if (tileSet.outputs) {
141
- throw new LambdaHttpResponse(404, 'TileSet needs pipeline: ' + tileSet.outputs.map((f) => f.name));
141
+ throw new LambdaHttpResponse(404, 'TileSet needs pipeline: ' + tileSet.outputs.map((f) => f.name).join(', '));
142
142
  }
143
143
 
144
144
  // Generate a default RGBA configuration
@@ -38,14 +38,15 @@ export interface WmtsBuilderParams {
38
38
  apiKey?: string;
39
39
  /** Config location */
40
40
  config?: string | null;
41
- /** Specific DateRange filter for the wmts layers */
42
- filters?: Record<string, string | undefined>;
41
+ /** Default pipeline to use */
42
+ pipeline?: string;
43
43
  }
44
44
 
45
45
  export class WmtsBuilder {
46
46
  httpBase: string;
47
47
  apiKey?: string;
48
48
  config?: string | null;
49
+ pipeline?: string;
49
50
  filters?: Record<string, string | undefined>;
50
51
 
51
52
  /** All the imagery used by the tileSet and tileMatrixes */
@@ -58,7 +59,7 @@ export class WmtsBuilder {
58
59
  this.httpBase = params.httpBase;
59
60
  this.apiKey = params.apiKey;
60
61
  this.config = params.config;
61
- this.filters = params.filters;
62
+ this.pipeline = params.pipeline;
62
63
  }
63
64
 
64
65
  addImagery(...imagery: ConfigImagery[]): void {
@@ -153,17 +154,17 @@ export class WmtsBuilder {
153
154
  return V('Style', { isDefault: 'true' }, [V('ows:Title', 'Default Style'), V('ows:Identifier', 'default')]);
154
155
  }
155
156
 
156
- buildResourceUrl(tileSetId: string, suffix: string, addFilter = false): VNodeElement {
157
+ buildResourceUrl(tileSetId: string, suffix: string): VNodeElement {
157
158
  return V('ResourceURL', {
158
159
  format: 'image/' + suffix,
159
160
  resourceType: 'tile',
160
- template: this.buildTileUrl(tileSetId, suffix, addFilter),
161
+ template: this.buildTileUrl(tileSetId, suffix),
161
162
  });
162
163
  }
163
164
 
164
- buildTileUrl(tileSetId: string, suffix: string, addFilter = false): string {
165
- let query = { api: this.apiKey, config: this.config };
166
- if (addFilter) query = { api: this.apiKey, config: this.config, ...this.filters };
165
+ buildTileUrl(tileSetId: string, suffix: string): string {
166
+ // TODO this should restrict the output formats to supported formats in pipelines
167
+ const query = { api: this.apiKey, config: this.config, pipeline: this.pipeline };
167
168
 
168
169
  return [
169
170
  this.httpBase,
@@ -239,6 +240,8 @@ export interface WmtsCapabilitiesParams {
239
240
  formats: ImageFormat[];
240
241
  /** Specific layers to add to the WMTS */
241
242
  layers?: ConfigLayer[];
243
+ /** Default output pipeline to use */
244
+ pipeline?: string | null;
242
245
  }
243
246
 
244
247
  /**
@@ -277,6 +280,10 @@ export class WmtsCapabilities extends WmtsBuilder {
277
280
  this.provider = provider;
278
281
  }
279
282
 
283
+ addPipeline(pipeline: string): void {
284
+ this.pipeline = pipeline;
285
+ }
286
+
280
287
  toProviderVNode(provider?: WmtsProvider): VNodeElement[] | [] {
281
288
  if (provider == null) return [];
282
289
  const { serviceIdentification, serviceProvider } = provider;
@@ -338,7 +345,7 @@ export class WmtsCapabilities extends WmtsBuilder {
338
345
  this.buildStyle(),
339
346
  ...this.buildFormats(),
340
347
  ...this.buildTileMatrixLink(tileSet),
341
- ...this.getFormats().map((fmt) => this.buildResourceUrl(layerNameId, fmt, true)),
348
+ ...this.getFormats().map((fmt) => this.buildResourceUrl(layerNameId, fmt)),
342
349
  ]);
343
350
  }
344
351
 
@@ -408,5 +415,6 @@ export class WmtsCapabilities extends WmtsBuilder {
408
415
  this.addTileSet(params.tileSet);
409
416
  this.addLayers(params.layers);
410
417
  this.addProvider(params.provider);
418
+ if (params.pipeline) this.addPipeline(params.pipeline);
411
419
  }
412
420
  }
package/tsconfig.json CHANGED
@@ -1,17 +1,17 @@
1
1
  {
2
2
  "extends": "../../tsconfig.base.json",
3
3
  "compilerOptions": {
4
- "rootDir": "./src",
5
- "outDir": "./build"
4
+ "outDir": "./build",
5
+ "rootDir": "./src"
6
6
  },
7
- "include": ["src/**/*"],
7
+ "include": ["src"],
8
8
  "references": [
9
- { "path": "../config" },
10
- { "path": "../config-loader/" },
11
- { "path": "../shared" },
12
- { "path": "../geo" },
13
- { "path": "../tiler" },
14
- { "path": "../tiler-sharp" },
15
- { "path": "../attribution" }
9
+ { "path": "../config/tsconfig.json" },
10
+ { "path": "../config-loader/tsconfig.json" },
11
+ { "path": "../shared/tsconfig.json" },
12
+ { "path": "../geo/tsconfig.json" },
13
+ { "path": "../tiler/tsconfig.json" },
14
+ { "path": "../tiler-sharp/tsconfig.json" },
15
+ { "path": "../attribution/tsconfig.json" }
16
16
  ]
17
17
  }