@basemaps/lambda-tiler 6.40.0 → 6.41.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 (60) hide show
  1. package/CHANGELOG.md +27 -0
  2. package/build/__tests__/wmts.capability.test.js +98 -65
  3. package/build/__tests__/wmts.capability.test.js.map +1 -1
  4. package/build/cli/render.tile.js +13 -10
  5. package/build/cli/render.tile.js.map +1 -1
  6. package/build/routes/__tests__/attribution.test.js +2 -2
  7. package/build/routes/__tests__/attribution.test.js.map +1 -1
  8. package/build/routes/attribution.d.ts +1 -2
  9. package/build/routes/attribution.d.ts.map +1 -1
  10. package/build/routes/attribution.js +16 -14
  11. package/build/routes/attribution.js.map +1 -1
  12. package/build/routes/tile.wmts.d.ts.map +1 -1
  13. package/build/routes/tile.wmts.js +11 -8
  14. package/build/routes/tile.wmts.js.map +1 -1
  15. package/build/util/validate.d.ts.map +1 -1
  16. package/build/util/validate.js +4 -3
  17. package/build/util/validate.js.map +1 -1
  18. package/build/wmts.capability.d.ts +58 -28
  19. package/build/wmts.capability.d.ts.map +1 -1
  20. package/build/wmts.capability.js +167 -93
  21. package/build/wmts.capability.js.map +1 -1
  22. package/dist/index.js +110 -82
  23. package/dist/node_modules/.package-lock.json +10 -10
  24. package/dist/node_modules/detect-libc/README.md +4 -1
  25. package/dist/node_modules/detect-libc/index.d.ts +3 -0
  26. package/dist/node_modules/detect-libc/lib/detect-libc.js +105 -4
  27. package/dist/node_modules/detect-libc/lib/filesystem.js +41 -0
  28. package/dist/node_modules/detect-libc/lib/process.js +3 -0
  29. package/dist/node_modules/detect-libc/package.json +7 -3
  30. package/dist/node_modules/node-abi/.github/workflows/semantic.yml +26 -0
  31. package/dist/node_modules/node-abi/abi_registry.json +25 -1
  32. package/dist/node_modules/node-abi/package.json +1 -1
  33. package/dist/node_modules/node-abi/scripts/update-abi-registry.js +2 -2
  34. package/dist/node_modules/semver/README.md +70 -1
  35. package/dist/node_modules/semver/bin/semver.js +16 -2
  36. package/dist/node_modules/semver/classes/comparator.js +39 -34
  37. package/dist/node_modules/semver/classes/range.js +45 -28
  38. package/dist/node_modules/semver/classes/semver.js +32 -17
  39. package/dist/node_modules/semver/functions/coerce.js +1 -1
  40. package/dist/node_modules/semver/functions/diff.js +58 -16
  41. package/dist/node_modules/semver/functions/inc.js +3 -2
  42. package/dist/node_modules/semver/functions/parse.js +5 -22
  43. package/dist/node_modules/semver/index.js +1 -0
  44. package/dist/node_modules/semver/internal/constants.js +20 -2
  45. package/dist/node_modules/semver/internal/parse-options.js +14 -10
  46. package/dist/node_modules/semver/internal/re.js +34 -4
  47. package/dist/node_modules/semver/package.json +8 -7
  48. package/dist/node_modules/semver/ranges/intersects.js +1 -1
  49. package/dist/node_modules/semver/ranges/subset.js +6 -3
  50. package/dist/package-lock.json +11 -11
  51. package/dist/package.json +1 -2
  52. package/package.json +9 -10
  53. package/src/__tests__/wmts.capability.test.ts +110 -65
  54. package/src/cli/render.tile.ts +13 -10
  55. package/src/routes/__tests__/attribution.test.ts +2 -2
  56. package/src/routes/attribution.ts +16 -12
  57. package/src/routes/tile.wmts.ts +12 -7
  58. package/src/util/validate.ts +4 -3
  59. package/src/wmts.capability.ts +209 -121
  60. package/tsconfig.tsbuildinfo +1 -1
@@ -1,6 +1,6 @@
1
1
  import { ConfigImagery, ConfigLayer, ConfigTileSet, standardizeLayerName } from '@basemaps/config';
2
- import { Bounds, GoogleTms, ImageFormat, TileMatrixSet, WmtsProvider } from '@basemaps/geo';
3
- import { Projection, toQueryString, V, VNodeElement } from '@basemaps/shared';
2
+ import { Bounds, GoogleTms, ImageFormat, Projection, TileMatrixSet, WmtsProvider } from '@basemaps/geo';
3
+ import { toQueryString, V, VNodeElement } from '@basemaps/shared';
4
4
  import { ImageFormatOrder } from '@basemaps/tiler';
5
5
  import { BoundingBox } from '@cogeotiff/core';
6
6
  import { BBox } from '@linzjs/geojson';
@@ -20,28 +20,6 @@ function wgs84Extent(tileMatrix: TileMatrixSet, bbox: BoundingBox): BBox {
20
20
  return Projection.get(tileMatrix).boundsToWgs84BoundingBox(bbox);
21
21
  }
22
22
 
23
- export interface WmtsCapabilitiesParams {
24
- /** Base URL for tile server */
25
- httpBase: string;
26
- provider?: WmtsProvider;
27
- /** Tileset to export into WMTS */
28
- tileSet: ConfigTileSet;
29
- /** List of tile matrixes to output */
30
- tileMatrix: TileMatrixSet[];
31
- /** All the imagery used by the tileSet and tileMatrixes */
32
- imagery: Map<string, ConfigImagery>;
33
- /** API key to append to all resource urls */
34
- apiKey?: string;
35
- /** Limit the output to the following image formats other wise @see ImageFormatOrder */
36
- formats?: ImageFormat[] | null;
37
- /** Config location */
38
- config?: string | null;
39
- /** Specific layers to add to the WMTS */
40
- layers?: ConfigLayer[] | null;
41
- /** Specific DateRange filter for the wmts layers */
42
- filters?: Record<string, string | undefined>;
43
- }
44
-
45
23
  /** Number of decimal places to use in lat lng */
46
24
  const LngLatPrecision = 6;
47
25
  const MeterPrecision = 4;
@@ -54,35 +32,68 @@ function formatCoords(x: number, precision: number): string {
54
32
  function formatBbox(x: number, y: number, precision: number): string {
55
33
  return `${formatCoords(x, precision)} ${formatCoords(y, precision)}`;
56
34
  }
35
+ export interface WmtsBuilderParams {
36
+ /** Base URL for tile server */
37
+ httpBase: string;
38
+ /** API key to append to all resource urls */
39
+ apiKey?: string;
40
+ /** Config location */
41
+ config?: string | null;
42
+ /** Specific DateRange filter for the wmts layers */
43
+ filters?: Record<string, string | undefined>;
44
+ }
57
45
 
58
- export class WmtsCapabilities {
46
+ export class WmtsBuilder {
59
47
  httpBase: string;
60
- provider?: WmtsProvider;
61
- tileSet: ConfigTileSet;
62
48
  apiKey?: string;
63
49
  config?: string | null;
64
- tileMatrixSets = new Map<string, TileMatrixSet>();
65
- imagery: Map<string, ConfigImagery>;
66
- formats: ImageFormat[];
67
50
  filters?: Record<string, string | undefined>;
68
51
 
69
- minZoom = 0;
70
- maxZoom = 32;
71
- layers: ConfigLayer[] | null | undefined;
52
+ /** All the imagery used by the tileSet and tileMatrixes */
53
+ imagery: Map<string, ConfigImagery> = new Map();
54
+ formats: ImageFormat[] = [];
72
55
 
73
- constructor(params: WmtsCapabilitiesParams) {
56
+ tileMatrixSets = new Map<string, TileMatrixSet>();
57
+
58
+ constructor(params: WmtsBuilderParams) {
74
59
  this.httpBase = params.httpBase;
75
- this.provider = params.provider;
76
- this.tileSet = params.tileSet;
77
- this.config = params.config;
78
- for (const tms of params.tileMatrix) this.tileMatrixSets.set(tms.identifier, tms);
79
60
  this.apiKey = params.apiKey;
80
- this.formats = params.formats ?? ImageFormatOrder;
81
- this.imagery = params.imagery;
82
- this.layers = params.layers;
61
+ this.config = params.config;
83
62
  this.filters = params.filters;
84
63
  }
85
64
 
65
+ addImagery(...imagery: ConfigImagery[]): void {
66
+ for (const im of imagery) this.imagery.set(im.id, im);
67
+ }
68
+
69
+ addTileMatrix(...tileMatrix: TileMatrixSet[]): void {
70
+ for (const tms of tileMatrix) this.tileMatrixSets.set(tms.identifier, tms);
71
+ }
72
+
73
+ addFormats(...formats: ImageFormat[]): void {
74
+ for (const format of formats) this.formats.push(format);
75
+ }
76
+
77
+ getFormats(): ImageFormat[] {
78
+ if (this.formats.length) return this.formats;
79
+ return ImageFormatOrder;
80
+ }
81
+
82
+ getMatrixSets(tileSet: ConfigTileSet): Set<TileMatrixSet> {
83
+ const matrixSets = new Set<TileMatrixSet>();
84
+ for (const tms of this.tileMatrixSets.values()) {
85
+ if (tileSet.layers.find((f) => f[tms.projection.code] != null)) {
86
+ matrixSets.add(tms);
87
+ }
88
+ }
89
+ return matrixSets;
90
+ }
91
+
92
+ buildKeywords(tileSet: { category?: string }): VNodeElement {
93
+ if (tileSet.category == null) return V('ows:Keywords');
94
+ return V('ows:Keywords', [V('ows:Keyword', tileSet.category)]);
95
+ }
96
+
86
97
  buildWgs84BoundingBox(tms: TileMatrixSet, layers: Bounds[]): VNodeElement {
87
98
  let bbox: BBox;
88
99
  if (layers.length > 0) {
@@ -128,39 +139,16 @@ export class WmtsCapabilities {
128
139
  ]);
129
140
  }
130
141
 
131
- buildProvider(): VNodeElement[] {
132
- if (this.provider == null) return [];
133
- const { serviceIdentification, serviceProvider } = this.provider;
134
- const { contact } = serviceProvider;
135
- return [
136
- V('ows:ServiceIdentification', [
137
- V('ows:Title', serviceIdentification.title),
138
- V('ows:Abstract', serviceIdentification.description),
139
- V('ows:ServiceType', 'OGC WMTS'),
140
- V('ows:ServiceTypeVersion', '1.0.0'),
141
- V('ows:Fees', serviceIdentification.fees),
142
- V('ows:AccessConstraints', serviceIdentification.accessConstraints),
143
- ]),
142
+ buildStyle(): VNodeElement {
143
+ return V('Style', { isDefault: 'true' }, [V('ows:Title', 'Default Style'), V('ows:Identifier', 'default')]);
144
+ }
144
145
 
145
- V('ows:ServiceProvider', [
146
- V('ows:ProviderName', serviceProvider.name),
147
- V('ows:ProviderSite', { 'xlink:href': serviceProvider.site }),
148
- V('ows:ServiceContact', [
149
- V('ows:IndividualName', contact.individualName),
150
- V('ows:PositionName', contact.position),
151
- V('ows:ContactInfo', [
152
- V('ows:Phone', [V('ows:Voice', contact.phone)]),
153
- V('ows:Address', [
154
- V('ows:DeliveryPoint', contact.address.deliveryPoint),
155
- V('ows:City', contact.address.city),
156
- V('ows:PostalCode', contact.address.postalCode),
157
- V('ows:Country', contact.address.country),
158
- V('ows:ElectronicMailAddress', contact.address.email),
159
- ]),
160
- ]),
161
- ]),
162
- ]),
163
- ];
146
+ buildResourceUrl(tileSetId: string, suffix: string, addFilter = false): VNodeElement {
147
+ return V('ResourceURL', {
148
+ format: 'image/' + suffix,
149
+ resourceType: 'tile',
150
+ template: this.buildTileUrl(tileSetId, suffix, addFilter),
151
+ });
164
152
  }
165
153
 
166
154
  buildTileUrl(tileSetId: string, suffix: string, addFilter = false): string {
@@ -179,12 +167,18 @@ export class WmtsCapabilities {
179
167
  ].join('/');
180
168
  }
181
169
 
182
- buildResourceUrl(tileSetId: string, suffix: string, addFilter = false): VNodeElement {
183
- return V('ResourceURL', {
184
- format: 'image/' + suffix,
185
- resourceType: 'tile',
186
- template: this.buildTileUrl(tileSetId, suffix, addFilter),
187
- });
170
+ buildFormats(): VNodeElement[] {
171
+ return this.getFormats().map((fmt) => V('Format', 'image/' + fmt));
172
+ }
173
+
174
+ buildTileMatrixLink(tileSet: ConfigTileSet): VNodeElement[] {
175
+ const matrixSetNodes: VNodeElement[] = [];
176
+ for (const tms of this.tileMatrixSets.values()) {
177
+ if (tileSet.layers.find((f) => f[tms.projection.code] != null)) {
178
+ matrixSetNodes.push(V('TileMatrixSetLink', [V('TileMatrixSet', tms.identifier)]));
179
+ }
180
+ }
181
+ return matrixSetNodes;
188
182
  }
189
183
 
190
184
  buildLayerFromImagery(layer: ConfigLayer): VNodeElement | null {
@@ -216,56 +210,142 @@ export class WmtsCapabilities {
216
210
  }),
217
211
  this.buildWgs84BoundingBox(firstMatrix, [Bounds.fromJson(firstImg.bounds)]),
218
212
  this.buildStyle(),
219
- ...this.formats.map((fmt) => V('Format', 'image/' + fmt)),
213
+ ...this.getFormats().map((fmt) => V('Format', 'image/' + fmt)),
220
214
  ...matrixSetNodes,
221
- ...this.formats.map((fmt) => this.buildResourceUrl(layerNameId, fmt)),
215
+ ...this.getFormats().map((fmt) => this.buildResourceUrl(layerNameId, fmt)),
222
216
  ]);
223
217
  }
218
+ }
224
219
 
225
- buildLayer(layer: ConfigTileSet): VNodeElement {
226
- const matrixSets = new Set<TileMatrixSet>();
227
- const matrixSetNodes: VNodeElement[] = [];
228
- for (const tms of this.tileMatrixSets.values()) {
229
- if (layer.layers.find((f) => f[tms.projection.code] != null)) {
230
- matrixSetNodes.push(V('TileMatrixSetLink', [V('TileMatrixSet', tms.identifier)]));
231
- matrixSets.add(tms);
232
- }
233
- }
234
- const layerNameId = standardizeLayerName(layer.name);
220
+ export interface WmtsCapabilitiesParams {
221
+ provider?: WmtsProvider;
222
+ /** Tileset to export into WMTS */
223
+ tileSet: ConfigTileSet;
224
+ /** List of tile matrixes to output */
225
+ tileMatrix: TileMatrixSet[];
226
+ /** All the imagery used by the tileSet and tileMatrixes */
227
+ imagery: Map<string, ConfigImagery>;
228
+ /** Limit the output to the following image formats other wise @see ImageFormatOrder */
229
+ formats: ImageFormat[];
230
+ /** Specific layers to add to the WMTS */
231
+ layers?: ConfigLayer[];
232
+ }
233
+
234
+ /**
235
+ * WMTS Capabilities Builder
236
+ *
237
+ * /v1/tiles/:tileSet/:tileMatrix/WMTSCapabilities.xml
238
+ * /v1/tiles/:tileSet/WMTSCapabilities.xml
239
+ * /v1/tiles/WMTSCapabilities.xml
240
+ *
241
+ * @example
242
+ *
243
+ */
244
+ export class WmtsCapabilities extends WmtsBuilder {
245
+ minZoom = 0;
246
+ maxZoom = 32;
247
+ /** Wmts tileSet layer and imagery layers information */
248
+ tileSet: ConfigTileSet;
249
+ configLayers?: ConfigLayer[];
250
+
251
+ /** Wmts Provider information */
252
+ provider?: WmtsProvider;
253
+
254
+ constructor(params: WmtsBuilderParams) {
255
+ super(params);
256
+ }
257
+
258
+ addTileSet(tileSet: ConfigTileSet): void {
259
+ this.tileSet = tileSet;
260
+ }
261
+
262
+ addLayers(configLayers?: ConfigLayer[]): void {
263
+ this.configLayers = configLayers;
264
+ }
265
+
266
+ addProvider(provider?: WmtsProvider): void {
267
+ this.provider = provider;
268
+ }
269
+
270
+ toProviderVNode(provider?: WmtsProvider): VNodeElement[] | [] {
271
+ if (provider == null) return [];
272
+ const { serviceIdentification, serviceProvider } = provider;
273
+ const { contact } = serviceProvider;
274
+ return [
275
+ V('ows:ServiceIdentification', [
276
+ V('ows:Title', serviceIdentification.title),
277
+ V('ows:Abstract', serviceIdentification.description),
278
+ V('ows:ServiceType', 'OGC WMTS'),
279
+ V('ows:ServiceTypeVersion', '1.0.0'),
280
+ V('ows:Fees', serviceIdentification.fees),
281
+ V('ows:AccessConstraints', serviceIdentification.accessConstraints),
282
+ ]),
283
+
284
+ V('ows:ServiceProvider', [
285
+ V('ows:ProviderName', serviceProvider.name),
286
+ V('ows:ProviderSite', { 'xlink:href': serviceProvider.site }),
287
+ V('ows:ServiceContact', [
288
+ V('ows:IndividualName', contact.individualName),
289
+ V('ows:PositionName', contact.position),
290
+ V('ows:ContactInfo', [
291
+ V('ows:Phone', [V('ows:Voice', contact.phone)]),
292
+ V('ows:Address', [
293
+ V('ows:DeliveryPoint', contact.address.deliveryPoint),
294
+ V('ows:City', contact.address.city),
295
+ V('ows:PostalCode', contact.address.postalCode),
296
+ V('ows:Country', contact.address.country),
297
+ V('ows:ElectronicMailAddress', contact.address.email),
298
+ ]),
299
+ ]),
300
+ ]),
301
+ ]),
302
+ ];
303
+ }
304
+
305
+ toLayerVNode(tileSet: ConfigTileSet): VNodeElement {
306
+ const matrixSets = this.getMatrixSets(tileSet);
235
307
  const matrixSetList = [...matrixSets.values()];
236
308
  const firstMatrix = matrixSetList[0];
237
- if (firstMatrix == null) throw new Error('No matrix sets found for layer ' + layer.name);
309
+ if (firstMatrix == null) throw new Error('No matrix sets found for layer ' + tileSet.name);
238
310
 
239
311
  // Prefer using the web mercator tms for bounds
240
312
  const webMercatorOrFirst = matrixSetList.find((f) => f.identifier === GoogleTms.identifier) ?? firstMatrix;
241
313
  const bounds: Bounds[] = [];
242
- for (const l of layer.layers) {
314
+ for (const l of tileSet.layers) {
243
315
  const img = this.imagery.get(l[webMercatorOrFirst.projection.code] ?? '');
244
316
  if (img == null) continue;
245
317
  bounds.push(Bounds.fromJson(img.bounds));
246
318
  }
247
319
 
320
+ const layerNameId = standardizeLayerName(tileSet.name);
248
321
  return V('Layer', [
249
- V('ows:Title', layer.title),
250
- V('ows:Abstract', layer.description ?? ''),
322
+ V('ows:Title', tileSet.title),
323
+ V('ows:Abstract', tileSet.description ?? ''),
251
324
  V('ows:Identifier', layerNameId),
252
- this.buildKeywords(layer),
253
- ...[...matrixSets.values()].map((tms) => this.buildBoundingBoxFromImagery(tms, layer.layers)),
325
+ this.buildKeywords(tileSet),
326
+ ...[...matrixSets.values()].map((tms) => this.buildBoundingBoxFromImagery(tms, tileSet.layers)),
254
327
  this.buildWgs84BoundingBox(webMercatorOrFirst, bounds),
255
328
  this.buildStyle(),
256
- ...this.formats.map((fmt) => V('Format', 'image/' + fmt)),
257
- ...matrixSetNodes,
258
- ...this.formats.map((fmt) => this.buildResourceUrl(layerNameId, fmt, true)),
329
+ ...this.buildFormats(),
330
+ ...this.buildTileMatrixLink(tileSet),
331
+ ...this.getFormats().map((fmt) => this.buildResourceUrl(layerNameId, fmt, true)),
259
332
  ]);
260
333
  }
261
334
 
262
- buildKeywords(tileSet: { category?: string }): VNodeElement {
263
- if (tileSet.category == null) return V('ows:Keywords');
264
- return V('ows:Keywords', [V('ows:Keyword', tileSet.category)]);
265
- }
266
-
267
- buildStyle(): VNodeElement {
268
- return V('Style', { isDefault: 'true' }, [V('ows:Title', 'Default Style'), V('ows:Identifier', 'default')]);
335
+ toAllImageryLayersVNode(configLayers?: ConfigLayer[]): VNodeElement[] {
336
+ if (configLayers == null) return [];
337
+ const layersVNode: VNodeElement[] = [];
338
+ const layerByName = new Map<string, ConfigLayer>();
339
+ // Dedupe the layers by unique name
340
+ for (const img of configLayers) layerByName.set(standardizeLayerName(img.name), img);
341
+ const orderedLayers = Array.from(layerByName.values()).sort((a, b) =>
342
+ (a.title ?? a.name).localeCompare(b.title ?? b.name),
343
+ );
344
+ for (const img of orderedLayers) {
345
+ const layer = this.buildLayerFromImagery(img);
346
+ if (layer) layersVNode.push(layer);
347
+ }
348
+ return layersVNode;
269
349
  }
270
350
 
271
351
  buildTileMatrixSet(tms: TileMatrixSet): VNodeElement {
@@ -288,26 +368,34 @@ export class WmtsCapabilities {
288
368
  }),
289
369
  ]);
290
370
  }
371
+
291
372
  toVNode(): VNodeElement {
292
- const layers: (VNodeElement | null)[] = [];
293
- layers.push(this.buildLayer(this.tileSet));
294
-
295
- if (this.layers) {
296
- const layerByName = new Map<string, ConfigLayer>();
297
- // Dedupe the layers by unique name
298
- for (const img of this.layers) layerByName.set(standardizeLayerName(img.name), img);
299
- const orderedLayers = Array.from(layerByName.values()).sort((a, b) =>
300
- (a.title ?? a.name).localeCompare(b.title ?? b.name),
301
- );
302
- for (const img of orderedLayers) layers.push(this.buildLayerFromImagery(img));
303
- }
373
+ // Prepare provider vNode if exists
374
+ const provider = this.toProviderVNode(this.provider);
375
+
376
+ // Build TileSet Layer VNodes
377
+ const layers: VNodeElement[] = [];
378
+ layers.push(this.toLayerVNode(this.tileSet));
379
+ const contents = layers.concat(this.toAllImageryLayersVNode(this.configLayers));
304
380
 
305
- for (const tms of this.tileMatrixSets.values()) layers.push(this.buildTileMatrixSet(tms));
381
+ // Build TileMatrix Sets vNodes
382
+ for (const tms of this.tileMatrixSets.values()) contents.push(this.buildTileMatrixSet(tms));
306
383
 
307
- return V('Capabilities', CapabilitiesAttrs, [...this.buildProvider(), V('Contents', layers)]);
384
+ return V('Capabilities', CapabilitiesAttrs, [...provider, V('Contents', contents)]);
308
385
  }
309
386
 
310
387
  toXml(): string {
311
388
  return '<?xml version="1.0" encoding="utf-8"?>\n' + this.toVNode().toString();
312
389
  }
390
+
391
+ fromParams(params: WmtsCapabilitiesParams): void {
392
+ for (const tileMatrix of params.tileMatrix) this.addTileMatrix(tileMatrix);
393
+ for (const im of params.imagery.values()) this.addImagery(im);
394
+ for (const format of params.formats) this.addFormats(format);
395
+
396
+ // Build wmts capabilities
397
+ this.addTileSet(params.tileSet);
398
+ this.addLayers(params.layers);
399
+ this.addProvider(params.provider);
400
+ }
313
401
  }