@basemaps/lambda-tiler 6.39.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.
- package/CHANGELOG.md +51 -0
- package/build/__tests__/config.data.d.ts.map +1 -1
- package/build/__tests__/config.data.js +142 -1
- package/build/__tests__/config.data.js.map +1 -1
- package/build/__tests__/wmts.capability.test.js +105 -79
- package/build/__tests__/wmts.capability.test.js.map +1 -1
- package/build/__tests__/xyz.util.d.ts.map +1 -1
- package/build/__tests__/xyz.util.js +6 -2
- package/build/__tests__/xyz.util.js.map +1 -1
- package/build/cli/render.tile.d.ts +2 -0
- package/build/cli/render.tile.d.ts.map +1 -0
- package/build/cli/render.tile.js +36 -0
- package/build/cli/render.tile.js.map +1 -0
- package/build/routes/__tests__/attribution.test.js +62 -2
- package/build/routes/__tests__/attribution.test.js.map +1 -1
- package/build/routes/__tests__/wmts.test.js +50 -8
- package/build/routes/__tests__/wmts.test.js.map +1 -1
- package/build/routes/attribution.d.ts +11 -0
- package/build/routes/attribution.d.ts.map +1 -1
- package/build/routes/attribution.js +32 -28
- package/build/routes/attribution.js.map +1 -1
- package/build/routes/tile.json.d.ts.map +1 -1
- package/build/routes/tile.json.js +2 -1
- package/build/routes/tile.json.js.map +1 -1
- package/build/routes/tile.style.json.d.ts.map +1 -1
- package/build/routes/tile.style.json.js +2 -1
- package/build/routes/tile.style.json.js.map +1 -1
- package/build/routes/tile.wmts.d.ts.map +1 -1
- package/build/routes/tile.wmts.js +12 -7
- package/build/routes/tile.wmts.js.map +1 -1
- package/build/routes/tile.xyz.raster.d.ts.map +1 -1
- package/build/routes/tile.xyz.raster.js +5 -1
- package/build/routes/tile.xyz.raster.js.map +1 -1
- package/build/util/__test__/filter.test.d.ts +2 -0
- package/build/util/__test__/filter.test.d.ts.map +1 -0
- package/build/util/__test__/filter.test.js +64 -0
- package/build/util/__test__/filter.test.js.map +1 -0
- package/build/util/config.loader.d.ts.map +1 -1
- package/build/util/config.loader.js +2 -3
- package/build/util/config.loader.js.map +1 -1
- package/build/util/filter.d.ts +15 -0
- package/build/util/filter.d.ts.map +1 -0
- package/build/util/filter.js +59 -0
- package/build/util/filter.js.map +1 -0
- package/build/util/validate.d.ts.map +1 -1
- package/build/util/validate.js +4 -3
- package/build/util/validate.js.map +1 -1
- package/build/wmts.capability.d.ts +61 -28
- package/build/wmts.capability.d.ts.map +1 -1
- package/build/wmts.capability.js +175 -99
- package/build/wmts.capability.js.map +1 -1
- package/dist/index.js +110 -82
- package/dist/node_modules/.package-lock.json +17 -17
- package/dist/node_modules/detect-libc/README.md +4 -1
- package/dist/node_modules/detect-libc/index.d.ts +3 -0
- package/dist/node_modules/detect-libc/lib/detect-libc.js +105 -4
- package/dist/node_modules/detect-libc/lib/filesystem.js +41 -0
- package/dist/node_modules/detect-libc/lib/process.js +3 -0
- package/dist/node_modules/detect-libc/package.json +7 -3
- package/dist/node_modules/minimist/.eslintrc +25 -50
- package/dist/node_modules/minimist/CHANGELOG.md +87 -1
- package/dist/node_modules/minimist/README.md +14 -10
- package/dist/node_modules/minimist/example/parse.js +2 -0
- package/dist/node_modules/minimist/index.js +256 -242
- package/dist/node_modules/minimist/package.json +73 -73
- package/dist/node_modules/minimist/test/all_bool.js +26 -24
- package/dist/node_modules/minimist/test/bool.js +146 -147
- package/dist/node_modules/minimist/test/dash.js +33 -21
- package/dist/node_modules/minimist/test/default_bool.js +26 -24
- package/dist/node_modules/minimist/test/dotted.js +13 -11
- package/dist/node_modules/minimist/test/kv_short.js +26 -10
- package/dist/node_modules/minimist/test/long.js +28 -26
- package/dist/node_modules/minimist/test/num.js +30 -28
- package/dist/node_modules/minimist/test/parse.js +169 -157
- package/dist/node_modules/minimist/test/parse_modified.js +7 -5
- package/dist/node_modules/minimist/test/proto.js +41 -37
- package/dist/node_modules/minimist/test/short.js +57 -55
- package/dist/node_modules/minimist/test/stop_early.js +10 -8
- package/dist/node_modules/minimist/test/unknown.js +83 -81
- package/dist/node_modules/minimist/test/whitespace.js +6 -4
- package/dist/node_modules/node-abi/.circleci/config.yml +2 -2
- package/dist/node_modules/node-abi/.github/CODEOWNERS +1 -0
- package/dist/node_modules/node-abi/.github/workflows/semantic.yml +26 -0
- package/dist/node_modules/node-abi/.github/workflows/update-abi.yml +5 -4
- package/dist/node_modules/node-abi/README.md +5 -3
- package/dist/node_modules/node-abi/abi_registry.json +32 -1
- package/dist/node_modules/node-abi/package.json +4 -4
- package/dist/node_modules/node-abi/scripts/update-abi-registry.js +2 -2
- package/dist/node_modules/readable-stream/README.md +1 -1
- package/dist/node_modules/readable-stream/lib/_stream_duplex.js +12 -25
- package/dist/node_modules/readable-stream/lib/_stream_passthrough.js +2 -4
- package/dist/node_modules/readable-stream/lib/_stream_readable.js +176 -273
- package/dist/node_modules/readable-stream/lib/_stream_transform.js +26 -37
- package/dist/node_modules/readable-stream/lib/_stream_writable.js +118 -174
- package/dist/node_modules/readable-stream/lib/internal/streams/async_iterator.js +10 -37
- package/dist/node_modules/readable-stream/lib/internal/streams/buffer_list.js +20 -47
- package/dist/node_modules/readable-stream/lib/internal/streams/destroy.js +8 -17
- package/dist/node_modules/readable-stream/lib/internal/streams/end-of-stream.js +1 -19
- package/dist/node_modules/readable-stream/lib/internal/streams/from.js +12 -24
- package/dist/node_modules/readable-stream/lib/internal/streams/pipeline.js +5 -16
- package/dist/node_modules/readable-stream/lib/internal/streams/state.js +2 -7
- package/dist/node_modules/readable-stream/package.json +1 -1
- package/dist/node_modules/semver/README.md +70 -1
- package/dist/node_modules/semver/bin/semver.js +16 -2
- package/dist/node_modules/semver/classes/comparator.js +39 -34
- package/dist/node_modules/semver/classes/range.js +45 -28
- package/dist/node_modules/semver/classes/semver.js +32 -17
- package/dist/node_modules/semver/functions/coerce.js +1 -1
- package/dist/node_modules/semver/functions/diff.js +58 -16
- package/dist/node_modules/semver/functions/inc.js +3 -2
- package/dist/node_modules/semver/functions/parse.js +5 -22
- package/dist/node_modules/semver/index.js +1 -0
- package/dist/node_modules/semver/internal/constants.js +20 -2
- package/dist/node_modules/semver/internal/parse-options.js +14 -10
- package/dist/node_modules/semver/internal/re.js +34 -4
- package/dist/node_modules/semver/package.json +8 -7
- package/dist/node_modules/semver/ranges/intersects.js +1 -1
- package/dist/node_modules/semver/ranges/subset.js +6 -3
- package/dist/package-lock.json +18 -349
- package/dist/package.json +1 -2
- package/package.json +9 -10
- package/src/__tests__/config.data.ts +142 -1
- package/src/__tests__/wmts.capability.test.ts +117 -79
- package/src/__tests__/xyz.util.ts +6 -2
- package/src/cli/render.tile.ts +41 -0
- package/src/routes/__tests__/attribution.test.ts +64 -2
- package/src/routes/__tests__/wmts.test.ts +70 -9
- package/src/routes/attribution.ts +28 -28
- package/src/routes/tile.json.ts +2 -1
- package/src/routes/tile.style.json.ts +2 -1
- package/src/routes/tile.wmts.ts +13 -6
- package/src/routes/tile.xyz.raster.ts +4 -1
- package/src/util/__test__/filter.test.ts +80 -0
- package/src/util/config.loader.ts +1 -2
- package/src/util/filter.ts +60 -0
- package/src/util/validate.ts +4 -3
- package/src/wmts.capability.ts +216 -123
- package/tsconfig.tsbuildinfo +1 -1
- package/test-dump.js +0 -6
- package/test-imagery.js +0 -3
|
@@ -6,17 +6,19 @@ import {
|
|
|
6
6
|
Bounds,
|
|
7
7
|
GoogleTms,
|
|
8
8
|
NamedBounds,
|
|
9
|
+
Projection,
|
|
9
10
|
Stac,
|
|
10
11
|
StacExtent,
|
|
11
12
|
StacProvider,
|
|
12
13
|
TileMatrixSet,
|
|
13
14
|
} from '@basemaps/geo';
|
|
14
|
-
import { extractYearRangeFromName, Projection, titleizeImageryName } from '@basemaps/shared';
|
|
15
15
|
import { BBox, MultiPolygon, multiPolygonToWgs84, Pair, union, Wgs84 } from '@linzjs/geojson';
|
|
16
|
+
import { extractYearRangeFromName, extractYearRangeFromTitle } from '@basemaps/shared';
|
|
16
17
|
import { HttpHeader, LambdaHttpRequest, LambdaHttpResponse } from '@linzjs/lambda';
|
|
17
18
|
import { ConfigLoader } from '../util/config.loader.js';
|
|
18
19
|
|
|
19
20
|
import { Etag } from '../util/etag.js';
|
|
21
|
+
import { filterLayers, yearRangeToInterval } from '../util/filter.js';
|
|
20
22
|
import { NotFound, NotModified } from '../util/response.js';
|
|
21
23
|
import { Validate } from '../util/validate.js';
|
|
22
24
|
|
|
@@ -44,23 +46,19 @@ function roundPair(p: Pair): Pair {
|
|
|
44
46
|
* @param files in target projection
|
|
45
47
|
* @return MultiPolygon in WGS84
|
|
46
48
|
*/
|
|
47
|
-
function createCoordinates(bbox: BBox, files: NamedBounds[], proj: Projection): MultiPolygon {
|
|
49
|
+
export function createCoordinates(bbox: BBox, files: NamedBounds[], proj: Projection): MultiPolygon {
|
|
48
50
|
if (Wgs84.delta(bbox[0], bbox[2]) <= 0) {
|
|
49
51
|
// This bounds spans more than half the globe which multiPolygonToWgs84 can't handle; just
|
|
50
52
|
// return bbox as polygon
|
|
51
53
|
return Wgs84.bboxToMultiPolygon(bbox);
|
|
52
54
|
}
|
|
53
55
|
|
|
54
|
-
|
|
55
|
-
|
|
56
|
+
const polygons: MultiPolygon = [];
|
|
56
57
|
// merge imagery bounds
|
|
57
|
-
for (const image of files)
|
|
58
|
-
|
|
59
|
-
coordinates = union(coordinates, poly);
|
|
60
|
-
}
|
|
58
|
+
for (const image of files) polygons.push(Bounds.fromJson(image).pad(SmoothPadding).toPolygon());
|
|
59
|
+
const coordinates = union(polygons);
|
|
61
60
|
|
|
62
61
|
const roundToWgs84 = (p: number[]): number[] => roundPair(proj.toWgs84(p) as Pair);
|
|
63
|
-
|
|
64
62
|
return multiPolygonToWgs84(coordinates, roundToWgs84);
|
|
65
63
|
}
|
|
66
64
|
|
|
@@ -86,30 +84,28 @@ async function tileSetAttribution(
|
|
|
86
84
|
|
|
87
85
|
const config = await ConfigLoader.load(req);
|
|
88
86
|
const imagery = await getAllImagery(config, tileSet.layers, [tileMatrix.projection]);
|
|
87
|
+
const filteredLayers = filterLayers(req, tileSet.layers);
|
|
89
88
|
|
|
90
89
|
const host = await config.Provider.get(config.Provider.id('linz'));
|
|
91
90
|
|
|
92
|
-
for (const layer of
|
|
91
|
+
for (const layer of filteredLayers) {
|
|
93
92
|
const imgId = layer[proj.epsg.code];
|
|
94
93
|
if (imgId == null) continue;
|
|
95
94
|
const im = imagery.get(imgId);
|
|
96
95
|
if (im == null) continue;
|
|
96
|
+
const title = im.title;
|
|
97
|
+
const years = extractYearRangeFromTitle(im.title) ?? extractYearRangeFromName(im.name);
|
|
98
|
+
if (years == null) continue;
|
|
99
|
+
const interval = yearRangeToInterval(years);
|
|
97
100
|
|
|
98
101
|
const bbox = proj.boundsToWgs84BoundingBox(im.bounds).map(roundNumber) as BBox;
|
|
99
102
|
|
|
100
|
-
const
|
|
101
|
-
|
|
102
|
-
|
|
103
|
-
|
|
104
|
-
years[0] = new Date().getUTCFullYear() + 1;
|
|
105
|
-
years[1] = years[0] + 1;
|
|
106
|
-
}
|
|
107
|
-
|
|
108
|
-
const interval = [years.map((y) => `${y}-01-01T00:00:00Z`) as [string, string]];
|
|
103
|
+
const extent: StacExtent = {
|
|
104
|
+
spatial: { bbox: [bbox] },
|
|
105
|
+
temporal: { interval: [[interval[0].toISOString(), interval[1].toISOString()]] },
|
|
106
|
+
};
|
|
109
107
|
|
|
110
|
-
const
|
|
111
|
-
|
|
112
|
-
items.push({
|
|
108
|
+
const item: AttributionItem = {
|
|
113
109
|
type: 'Feature',
|
|
114
110
|
stac_version: Stac.Version,
|
|
115
111
|
id: imgId + '_item',
|
|
@@ -119,22 +115,25 @@ async function tileSetAttribution(
|
|
|
119
115
|
bbox,
|
|
120
116
|
geometry: { type: 'MultiPolygon', coordinates: createCoordinates(bbox, im.files, proj) },
|
|
121
117
|
properties: {
|
|
122
|
-
title
|
|
118
|
+
title,
|
|
123
119
|
category: im.category,
|
|
124
120
|
datetime: null,
|
|
125
|
-
start_datetime: interval[0]
|
|
126
|
-
end_datetime: interval[
|
|
121
|
+
start_datetime: interval[0].toISOString(),
|
|
122
|
+
end_datetime: interval[1].toISOString(),
|
|
127
123
|
},
|
|
128
|
-
}
|
|
124
|
+
};
|
|
125
|
+
|
|
126
|
+
items.push(item);
|
|
129
127
|
|
|
130
|
-
const
|
|
128
|
+
const minZoom = layer.disabled ? 32 : layer.minZoom;
|
|
129
|
+
const zoomMin = TileMatrixSet.convertZoomLevel(minZoom ? minZoom : 0, GoogleTms, tileMatrix, true);
|
|
131
130
|
const zoomMax = TileMatrixSet.convertZoomLevel(layer.maxZoom ? layer.maxZoom : 32, GoogleTms, tileMatrix, true);
|
|
132
131
|
cols.push({
|
|
133
132
|
stac_version: Stac.Version,
|
|
134
133
|
license: Stac.License,
|
|
135
134
|
id: im.id,
|
|
136
135
|
providers: getHost(host),
|
|
137
|
-
title
|
|
136
|
+
title,
|
|
138
137
|
description: 'No description',
|
|
139
138
|
extent,
|
|
140
139
|
links: [],
|
|
@@ -142,6 +141,7 @@ async function tileSetAttribution(
|
|
|
142
141
|
'linz:category': im.category,
|
|
143
142
|
'linz:zoom': { min: zoomMin, max: zoomMax },
|
|
144
143
|
'linz:priority': [1000 + tileSet.layers.indexOf(layer)],
|
|
144
|
+
'linz:disabled': layer.disabled ? true : false,
|
|
145
145
|
},
|
|
146
146
|
});
|
|
147
147
|
}
|
package/src/routes/tile.json.ts
CHANGED
|
@@ -2,6 +2,7 @@ import { GoogleTms, TileJson, TileMatrixSet } from '@basemaps/geo';
|
|
|
2
2
|
import { Env, toQueryString } from '@basemaps/shared';
|
|
3
3
|
import { HttpHeader, LambdaHttpRequest, LambdaHttpResponse } from '@linzjs/lambda';
|
|
4
4
|
import { ConfigLoader } from '../util/config.loader.js';
|
|
5
|
+
import { getFilters } from '../util/filter.js';
|
|
5
6
|
import { NotFound } from '../util/response.js';
|
|
6
7
|
import { Validate } from '../util/validate.js';
|
|
7
8
|
|
|
@@ -31,7 +32,7 @@ export async function tileJsonGet(req: LambdaHttpRequest<TileJsonGet>): Promise<
|
|
|
31
32
|
|
|
32
33
|
const configLocation = ConfigLoader.extract(req);
|
|
33
34
|
|
|
34
|
-
const query = toQueryString({ api: apiKey, config: configLocation });
|
|
35
|
+
const query = toQueryString({ api: apiKey, config: configLocation, ...getFilters(req) });
|
|
35
36
|
|
|
36
37
|
const tileUrl =
|
|
37
38
|
[host, 'v1', 'tiles', tileSet.name, tileMatrix.identifier, '{z}', '{x}', '{y}'].join('/') + `.${format[0]}${query}`;
|
|
@@ -8,6 +8,7 @@ import { Validate } from '../util/validate.js';
|
|
|
8
8
|
import { Etag } from '../util/etag.js';
|
|
9
9
|
import { ConfigLoader } from '../util/config.loader.js';
|
|
10
10
|
import { GoogleTms, ImageFormat, TileMatrixSets } from '@basemaps/geo';
|
|
11
|
+
import { getFilters } from '../util/filter.js';
|
|
11
12
|
|
|
12
13
|
/**
|
|
13
14
|
* Convert relative URLS into a full hostname url
|
|
@@ -73,7 +74,7 @@ export async function tileSetToStyle(
|
|
|
73
74
|
if (tileFormat == null) return new LambdaHttpResponse(400, 'Invalid image format');
|
|
74
75
|
|
|
75
76
|
const configLocation = ConfigLoader.extract(req);
|
|
76
|
-
const query = toQueryString({ config: configLocation, api: apiKey });
|
|
77
|
+
const query = toQueryString({ config: configLocation, api: apiKey, ...getFilters(req) });
|
|
77
78
|
|
|
78
79
|
const tileUrl = fsa.join(
|
|
79
80
|
Env.get(Env.PublicUrlBase) ?? '',
|
package/src/routes/tile.wmts.ts
CHANGED
|
@@ -8,6 +8,7 @@ import { Validate } from '../util/validate.js';
|
|
|
8
8
|
import { WmtsCapabilities } from '../wmts.capability.js';
|
|
9
9
|
import { Etag } from '../util/etag.js';
|
|
10
10
|
import { ConfigLoader } from '../util/config.loader.js';
|
|
11
|
+
import { filterLayers, getFilters } from '../util/filter.js';
|
|
11
12
|
|
|
12
13
|
export interface WmtsCapabilitiesGet {
|
|
13
14
|
Params: {
|
|
@@ -54,17 +55,23 @@ export async function wmtsCapabilitiesGet(req: LambdaHttpRequest<WmtsCapabilitie
|
|
|
54
55
|
);
|
|
55
56
|
req.timer.end('imagery:load');
|
|
56
57
|
|
|
57
|
-
const
|
|
58
|
+
const wmts = new WmtsCapabilities({
|
|
58
59
|
httpBase: host,
|
|
60
|
+
apiKey,
|
|
61
|
+
config: ConfigLoader.extract(req),
|
|
62
|
+
filters: getFilters(req),
|
|
63
|
+
});
|
|
64
|
+
|
|
65
|
+
wmts.fromParams({
|
|
59
66
|
provider: provider ?? undefined,
|
|
60
67
|
tileSet,
|
|
61
68
|
tileMatrix,
|
|
62
|
-
isIndividualLayers: req.params.tileMatrix == null,
|
|
63
69
|
imagery,
|
|
64
|
-
|
|
65
|
-
|
|
66
|
-
|
|
67
|
-
|
|
70
|
+
formats: Validate.getRequestedFormats(req) ?? [],
|
|
71
|
+
layers: req.params.tileMatrix == null ? filterLayers(req, tileSet.layers) : undefined,
|
|
72
|
+
});
|
|
73
|
+
|
|
74
|
+
const xml = wmts.toXml();
|
|
68
75
|
if (xml == null) return NotFound();
|
|
69
76
|
|
|
70
77
|
const data = Buffer.from(xml);
|
|
@@ -9,6 +9,7 @@ import { HttpHeader, LambdaHttpRequest, LambdaHttpResponse } from '@linzjs/lambd
|
|
|
9
9
|
import pLimit from 'p-limit';
|
|
10
10
|
import { ConfigLoader } from '../util/config.loader.js';
|
|
11
11
|
import { Etag } from '../util/etag.js';
|
|
12
|
+
import { filterLayers } from '../util/filter.js';
|
|
12
13
|
import { NotFound, NotModified } from '../util/response.js';
|
|
13
14
|
import { CoSources } from '../util/source.cache.js';
|
|
14
15
|
import { TileXyz } from '../util/validate.js';
|
|
@@ -32,13 +33,15 @@ export const TileXyzRaster = {
|
|
|
32
33
|
async getAssetsForTile(req: LambdaHttpRequest, tileSet: ConfigTileSetRaster, xyz: TileXyz): Promise<string[]> {
|
|
33
34
|
const config = await ConfigLoader.load(req);
|
|
34
35
|
const imagery = await getAllImagery(config, tileSet.layers, [xyz.tileMatrix.projection]);
|
|
36
|
+
const filteredLayers = filterLayers(req, tileSet.layers);
|
|
35
37
|
|
|
36
38
|
const output: string[] = [];
|
|
37
39
|
const tileBounds = xyz.tileMatrix.tileToSourceBounds(xyz.tile);
|
|
38
40
|
|
|
39
41
|
// All zoom level config is stored as Google zoom levels
|
|
40
42
|
const filterZoom = TileMatrixSet.convertZoomLevel(xyz.tile.z, xyz.tileMatrix, TileMatrixSets.get(Epsg.Google));
|
|
41
|
-
for (const layer of
|
|
43
|
+
for (const layer of filteredLayers) {
|
|
44
|
+
if (layer.disabled) continue;
|
|
42
45
|
if (layer.maxZoom != null && filterZoom > layer.maxZoom) continue;
|
|
43
46
|
if (layer.minZoom != null && filterZoom < layer.minZoom) continue;
|
|
44
47
|
|
|
@@ -0,0 +1,80 @@
|
|
|
1
|
+
import { ConfigLayer } from '@basemaps/config';
|
|
2
|
+
import o from 'ospec';
|
|
3
|
+
import { mockUrlRequest } from '../../__tests__/xyz.util.js';
|
|
4
|
+
import { filterLayers } from '../filter.js';
|
|
5
|
+
|
|
6
|
+
o.spec('filterLayers', () => {
|
|
7
|
+
const sourceLayers: ConfigLayer[] = [
|
|
8
|
+
{
|
|
9
|
+
name: 'waikato-0_625m-snc12836-2004',
|
|
10
|
+
title: 'Waikato 0.625m SNC12836 (2004-2008)',
|
|
11
|
+
},
|
|
12
|
+
{
|
|
13
|
+
name: 'hawkes-bay--manawat-whanganui-0_75m-snc30001-2002',
|
|
14
|
+
title: 'Hawkes Bay / Manawatū-Whanganui 0.75m SNC30001 (2002)',
|
|
15
|
+
},
|
|
16
|
+
{
|
|
17
|
+
name: 'canterbury-0_75m-snc25054-2000-2001',
|
|
18
|
+
title: 'Canterbury 0.75m SNC25054 (2000-2001)',
|
|
19
|
+
},
|
|
20
|
+
{
|
|
21
|
+
name: 'otago-0_375m-sn3806-1975',
|
|
22
|
+
title: 'Otago 0.375m SN3806 (1975)',
|
|
23
|
+
},
|
|
24
|
+
];
|
|
25
|
+
|
|
26
|
+
o('should not filter with empty parameters', () => {
|
|
27
|
+
const layers = filterLayers(mockUrlRequest('/foo/bar,js'), sourceLayers);
|
|
28
|
+
o(layers).deepEquals(sourceLayers);
|
|
29
|
+
});
|
|
30
|
+
|
|
31
|
+
o('should filter date[after]', () => {
|
|
32
|
+
const dateAfter = '2003-12-31T23:59:59.999';
|
|
33
|
+
const layers = filterLayers(mockUrlRequest('/foo/bar,js', `?date[after]=${dateAfter}`), sourceLayers);
|
|
34
|
+
o(layers).deepEquals([sourceLayers[0]]);
|
|
35
|
+
});
|
|
36
|
+
|
|
37
|
+
o('should filter date[before]', () => {
|
|
38
|
+
const dateBefore = '2003-01-01T00:00:00.000Z';
|
|
39
|
+
const layers = filterLayers(mockUrlRequest('/foo/bar,js', `?date[before]=${dateBefore}`), sourceLayers);
|
|
40
|
+
o(layers).deepEquals(sourceLayers.slice(1));
|
|
41
|
+
});
|
|
42
|
+
|
|
43
|
+
o('should filter date[before] in between years', () => {
|
|
44
|
+
const dateBefore = '2026-01-01T00:00:00.000Z';
|
|
45
|
+
const layer = [{ name: '', title: 'Waikato 0.625m SNC12836 (2020-2028)' }];
|
|
46
|
+
const layers = filterLayers(mockUrlRequest('/foo/bar,js', `?date[before]=${dateBefore}`), layer);
|
|
47
|
+
o(layers).deepEquals(layer);
|
|
48
|
+
});
|
|
49
|
+
|
|
50
|
+
o('should filter date[after] in between years', () => {
|
|
51
|
+
const dateAfter = '2026-12-31T23:59:59.999Z';
|
|
52
|
+
const layer = [{ name: '', title: 'Waikato 0.625m SNC12836 (2020-2028)' }];
|
|
53
|
+
const layers = filterLayers(mockUrlRequest('/foo/bar,js', `?date[after]=${dateAfter}`), layer);
|
|
54
|
+
o(layers).deepEquals(layer);
|
|
55
|
+
});
|
|
56
|
+
|
|
57
|
+
o('should filter date[after] and date[before] in between years', () => {
|
|
58
|
+
const dateAfter = '2026-12-31T23:59:59.999Z';
|
|
59
|
+
const dateBefore = '2028-01-01T00:00:00.000Z';
|
|
60
|
+
|
|
61
|
+
const layer = [{ name: '', title: 'Waikato 0.625m SNC12836 (2020-2028)' }];
|
|
62
|
+
const layers = filterLayers(
|
|
63
|
+
mockUrlRequest('/foo/bar,js', `?date[after]=${dateAfter}&date[before]=${dateBefore}`),
|
|
64
|
+
layer,
|
|
65
|
+
);
|
|
66
|
+
o(layers).deepEquals(layer);
|
|
67
|
+
});
|
|
68
|
+
|
|
69
|
+
o('should filter date[after] and date[before] in between years with single year', () => {
|
|
70
|
+
const dateAfter = '2026-12-31T23:59:59.999Z';
|
|
71
|
+
const dateBefore = '2028-01-01T00:00:00.000Z';
|
|
72
|
+
|
|
73
|
+
const layer = [{ name: '', title: 'Waikato 0.625m SNC12836 (2028)' }];
|
|
74
|
+
const layers = filterLayers(
|
|
75
|
+
mockUrlRequest('/foo/bar,js', `?date[after]=${dateAfter}&date[before]=${dateBefore}`),
|
|
76
|
+
layer,
|
|
77
|
+
);
|
|
78
|
+
o(layers).deepEquals(layer);
|
|
79
|
+
});
|
|
80
|
+
});
|
|
@@ -15,8 +15,7 @@ export class ConfigLoader {
|
|
|
15
15
|
const config = getDefaultConfig();
|
|
16
16
|
if (config.assets == null) {
|
|
17
17
|
const cb = await config.ConfigBundle.get(config.ConfigBundle.id('latest'));
|
|
18
|
-
if (cb
|
|
19
|
-
config.assets = cb.assets;
|
|
18
|
+
if (cb) config.assets = cb.assets;
|
|
20
19
|
}
|
|
21
20
|
return config;
|
|
22
21
|
}
|
|
@@ -0,0 +1,60 @@
|
|
|
1
|
+
import { ConfigLayer } from '@basemaps/config';
|
|
2
|
+
import { extractYearRangeFromTitle } from '@basemaps/shared';
|
|
3
|
+
import { LambdaHttpRequest, LambdaHttpResponse } from '@linzjs/lambda';
|
|
4
|
+
|
|
5
|
+
export const FilterNames = {
|
|
6
|
+
DateBefore: 'date[before]',
|
|
7
|
+
DateAfter: 'date[after]',
|
|
8
|
+
};
|
|
9
|
+
|
|
10
|
+
export function getFilters(req: LambdaHttpRequest): Record<string, string | undefined> {
|
|
11
|
+
return {
|
|
12
|
+
[FilterNames.DateBefore]: req.query.get(FilterNames.DateBefore) ?? undefined,
|
|
13
|
+
[FilterNames.DateAfter]: req.query.get(FilterNames.DateAfter) ?? undefined,
|
|
14
|
+
};
|
|
15
|
+
}
|
|
16
|
+
/**
|
|
17
|
+
* Convert the year range into full ISO date year range
|
|
18
|
+
*
|
|
19
|
+
* Expand to the full year of jan 1st 00:00 -> Dec 31st 23:59
|
|
20
|
+
*/
|
|
21
|
+
export function yearRangeToInterval(x: [number] | [number, number]): [Date, Date] {
|
|
22
|
+
if (x.length === 1) return [new Date(`${x[0]}-01-01T00:00:00.000Z`), new Date(`${x[0]}-12-31T23:59:59.999Z`)];
|
|
23
|
+
return [new Date(`${x[0]}-01-01T00:00:00.000Z`), new Date(`${x[1]}-12-31T23:59:59.999Z`)];
|
|
24
|
+
}
|
|
25
|
+
|
|
26
|
+
function parseDateAsIso(s: string | null): Date | null {
|
|
27
|
+
if (s == null) return null;
|
|
28
|
+
const date = new Date(s);
|
|
29
|
+
if (isNaN(date.getTime())) throw new LambdaHttpResponse(400, `Invalid date format: "${s}"`);
|
|
30
|
+
return date;
|
|
31
|
+
}
|
|
32
|
+
|
|
33
|
+
export function filterLayers(req: LambdaHttpRequest, layers: ConfigLayer[]): ConfigLayer[] {
|
|
34
|
+
const dateAfterQuery = req.query.get(FilterNames.DateAfter);
|
|
35
|
+
const dateBeforeQuery = req.query.get(FilterNames.DateBefore);
|
|
36
|
+
|
|
37
|
+
if (dateAfterQuery == null && dateBeforeQuery == null) return layers;
|
|
38
|
+
const dateAfter = parseDateAsIso(dateAfterQuery);
|
|
39
|
+
const dateBefore = parseDateAsIso(dateBeforeQuery);
|
|
40
|
+
|
|
41
|
+
const filtered = layers.filter((l) => {
|
|
42
|
+
if (l.title == null) return false;
|
|
43
|
+
const yearRange = extractYearRangeFromTitle(l.title);
|
|
44
|
+
if (yearRange == null) return false;
|
|
45
|
+
|
|
46
|
+
const ranges = yearRangeToInterval(yearRange);
|
|
47
|
+
const startYear = ranges[0];
|
|
48
|
+
const endYear = ranges[1];
|
|
49
|
+
return (dateAfter == null || endYear >= dateAfter) && (dateBefore == null || startYear <= dateBefore);
|
|
50
|
+
});
|
|
51
|
+
|
|
52
|
+
// Trace that layers have been filtered
|
|
53
|
+
req.set('layerFilter', {
|
|
54
|
+
[FilterNames.DateBefore]: dateBefore?.toISOString(),
|
|
55
|
+
[FilterNames.DateAfter]: dateAfter?.toISOString(),
|
|
56
|
+
layerCount: layers.length,
|
|
57
|
+
filterCount: filtered.length,
|
|
58
|
+
});
|
|
59
|
+
return filtered;
|
|
60
|
+
}
|
package/src/util/validate.ts
CHANGED
|
@@ -1,5 +1,5 @@
|
|
|
1
|
-
import { ImageFormat, TileMatrixSet, TileMatrixSets, VectorFormat } from '@basemaps/geo';
|
|
2
|
-
import { Const, isValidApiKey,
|
|
1
|
+
import { ImageFormat, Projection, TileMatrixSet, TileMatrixSets, VectorFormat } from '@basemaps/geo';
|
|
2
|
+
import { Const, isValidApiKey, truncateApiKey } from '@basemaps/shared';
|
|
3
3
|
import { getImageFormat } from '@basemaps/tiler';
|
|
4
4
|
import { LambdaHttpRequest, LambdaHttpResponse } from '@linzjs/lambda';
|
|
5
5
|
import { TileXyzGet } from '../routes/tile.xyz';
|
|
@@ -25,7 +25,8 @@ export const Validate = {
|
|
|
25
25
|
const valid = isValidApiKey(apiKey);
|
|
26
26
|
|
|
27
27
|
if (!valid.valid) throw new LambdaHttpResponse(400, 'API Key Invalid: ' + valid.message);
|
|
28
|
-
|
|
28
|
+
// Truncate the API Key so we are not logging the full key
|
|
29
|
+
req.set('api', truncateApiKey(apiKey));
|
|
29
30
|
return apiKey as string;
|
|
30
31
|
},
|
|
31
32
|
|