@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.
- package/CHANGELOG.md +36 -0
- package/build/__tests__/config.data.d.ts +2 -0
- package/build/__tests__/config.data.js +24 -1
- package/build/__tests__/config.data.js.map +1 -1
- package/build/__tests__/index.test.js +1 -2
- package/build/__tests__/index.test.js.map +1 -1
- package/build/__tests__/tile.style.json.test.js +71 -16
- package/build/__tests__/tile.style.json.test.js.map +1 -1
- package/build/__tests__/wmts.capability.test.js +5 -2
- package/build/__tests__/wmts.capability.test.js.map +1 -1
- package/build/__tests__/xyz.util.js.map +1 -1
- package/build/cli/render.preview.js +5 -2
- package/build/cli/render.preview.js.map +1 -1
- package/build/cli/render.tile.js +1 -1
- package/build/cli/render.tile.js.map +1 -1
- package/build/index.js +1 -1
- package/build/index.js.map +1 -1
- package/build/routes/__tests__/attribution.test.js +1 -1
- package/build/routes/__tests__/attribution.test.js.map +1 -1
- package/build/routes/__tests__/health.test.js +1 -1
- package/build/routes/__tests__/health.test.js.map +1 -1
- package/build/routes/__tests__/imagery.test.js.map +1 -1
- package/build/routes/__tests__/memory.fs.js +1 -1
- package/build/routes/__tests__/memory.fs.js.map +1 -1
- package/build/routes/__tests__/preview.index.test.js +1 -1
- package/build/routes/__tests__/preview.index.test.js.map +1 -1
- package/build/routes/__tests__/tile.json.test.js.map +1 -1
- package/build/routes/__tests__/tile.style.json.test.js +144 -11
- package/build/routes/__tests__/tile.style.json.test.js.map +1 -1
- package/build/routes/__tests__/wmts.test.js +18 -2
- package/build/routes/__tests__/wmts.test.js.map +1 -1
- package/build/routes/config.js +1 -1
- package/build/routes/config.js.map +1 -1
- package/build/routes/ping.js +2 -2
- package/build/routes/ping.js.map +1 -1
- package/build/routes/preview.index.js +2 -1
- package/build/routes/preview.index.js.map +1 -1
- package/build/routes/preview.js +3 -1
- package/build/routes/preview.js.map +1 -1
- package/build/routes/sprites.js.map +1 -1
- package/build/routes/tile.style.json.d.ts +5 -4
- package/build/routes/tile.style.json.js +78 -24
- package/build/routes/tile.style.json.js.map +1 -1
- package/build/routes/tile.wmts.js +1 -0
- package/build/routes/tile.wmts.js.map +1 -1
- package/build/routes/tile.xyz.raster.js +6 -5
- package/build/routes/tile.xyz.raster.js.map +1 -1
- package/build/routes/version.js +2 -2
- package/build/routes/version.js.map +1 -1
- package/build/util/__test__/config.loader.test.js +12 -12
- package/build/util/__test__/config.loader.test.js.map +1 -1
- package/build/util/config.cache.js.map +1 -1
- package/build/util/source.cache.js +5 -4
- package/build/util/source.cache.js.map +1 -1
- package/build/util/validate.js +1 -1
- package/build/util/validate.js.map +1 -1
- package/build/wmts.capability.d.ts +8 -4
- package/build/wmts.capability.js +18 -8
- package/build/wmts.capability.js.map +1 -1
- package/package.json +10 -10
- package/src/__tests__/config.data.ts +31 -2
- package/src/__tests__/index.test.ts +2 -3
- package/src/__tests__/tile.style.json.test.ts +89 -16
- package/src/__tests__/wmts.capability.test.ts +13 -10
- package/src/__tests__/xyz.util.ts +4 -4
- package/src/cli/render.preview.ts +5 -2
- package/src/cli/render.tile.ts +1 -1
- package/src/routes/__tests__/attribution.test.ts +7 -7
- package/src/routes/__tests__/health.test.ts +3 -3
- package/src/routes/__tests__/imagery.test.ts +1 -1
- package/src/routes/__tests__/memory.fs.ts +2 -2
- package/src/routes/__tests__/preview.index.test.ts +3 -3
- package/src/routes/__tests__/tile.json.test.ts +1 -1
- package/src/routes/__tests__/tile.style.json.test.ts +175 -15
- package/src/routes/__tests__/wmts.test.ts +23 -3
- package/src/routes/config.ts +1 -1
- package/src/routes/ping.ts +2 -2
- package/src/routes/preview.index.ts +2 -1
- package/src/routes/preview.ts +4 -2
- package/src/routes/sprites.ts +1 -1
- package/src/routes/tile.style.json.ts +103 -24
- package/src/routes/tile.wmts.ts +1 -0
- package/src/routes/tile.xyz.raster.ts +7 -5
- package/src/routes/version.ts +2 -2
- package/src/util/__test__/config.loader.test.ts +17 -20
- package/src/util/config.cache.ts +2 -1
- package/src/util/source.cache.ts +6 -4
- package/src/util/validate.ts +1 -1
- package/src/wmts.capability.ts +17 -9
- package/tsconfig.json +10 -10
- 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(
|
|
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(
|
|
35
|
-
|
|
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
|
-
|
|
39
|
-
|
|
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
|
-
|
|
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
|
-
|
|
54
|
-
|
|
55
|
-
|
|
56
|
-
|
|
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 = {
|
|
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);
|
package/src/routes/tile.wmts.ts
CHANGED
|
@@ -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((
|
|
99
|
-
req.log.warn({
|
|
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((
|
|
104
|
-
req.log.warn({
|
|
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 =
|
|
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);
|
package/src/routes/version.ts
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
import { HttpHeader, LambdaHttpResponse } from '@linzjs/lambda';
|
|
2
2
|
|
|
3
|
-
export
|
|
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(
|
|
49
|
-
assert.equal(
|
|
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(
|
|
61
|
-
assert.equal(
|
|
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(
|
|
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(
|
|
90
|
-
assert.equal(
|
|
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(
|
|
131
|
-
assert.equal(
|
|
127
|
+
assert.equal(error?.status, 400);
|
|
128
|
+
assert.equal(error?.statusDescription, `Invalid config location at ${deletedLocation}`);
|
|
132
129
|
});
|
|
133
130
|
});
|
package/src/util/config.cache.ts
CHANGED
|
@@ -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
|
}
|
package/src/util/source.cache.ts
CHANGED
|
@@ -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)
|
|
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
|
|
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 }));
|
package/src/util/validate.ts
CHANGED
|
@@ -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
|
package/src/wmts.capability.ts
CHANGED
|
@@ -38,14 +38,15 @@ export interface WmtsBuilderParams {
|
|
|
38
38
|
apiKey?: string;
|
|
39
39
|
/** Config location */
|
|
40
40
|
config?: string | null;
|
|
41
|
-
/**
|
|
42
|
-
|
|
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.
|
|
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
|
|
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
|
|
161
|
+
template: this.buildTileUrl(tileSetId, suffix),
|
|
161
162
|
});
|
|
162
163
|
}
|
|
163
164
|
|
|
164
|
-
buildTileUrl(tileSetId: string, suffix: string
|
|
165
|
-
|
|
166
|
-
|
|
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
|
|
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
|
-
"
|
|
5
|
-
"
|
|
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
|
}
|