@basemaps/lambda-tiler 6.29.0 → 6.32.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 +63 -0
- package/build/__tests__/config.data.d.ts +11 -0
- package/build/__tests__/config.data.d.ts.map +1 -0
- package/build/__tests__/config.data.js +112 -0
- package/build/__tests__/config.data.js.map +1 -0
- package/build/__tests__/index.test.js +5 -14
- package/build/__tests__/index.test.js.map +1 -0
- package/build/__tests__/tile.style.json.test.js +1 -0
- package/build/__tests__/tile.style.json.test.js.map +1 -0
- package/build/__tests__/wmts.capability.test.d.ts +1 -1
- package/build/__tests__/wmts.capability.test.d.ts.map +1 -1
- package/build/__tests__/wmts.capability.test.js +286 -125
- package/build/__tests__/wmts.capability.test.js.map +1 -0
- package/build/__tests__/xyz.util.d.ts +7 -11
- package/build/__tests__/xyz.util.d.ts.map +1 -1
- package/build/__tests__/xyz.util.js +14 -42
- package/build/__tests__/xyz.util.js.map +1 -0
- package/build/index.d.ts +0 -2
- package/build/index.d.ts.map +1 -1
- package/build/index.js +68 -41
- package/build/index.js.map +1 -0
- package/build/routes/__tests__/attribution.test.js +351 -399
- package/build/routes/__tests__/attribution.test.js.map +1 -0
- package/build/routes/__tests__/fonts.test.js +17 -3
- package/build/routes/__tests__/fonts.test.js.map +1 -0
- package/build/routes/__tests__/health.test.js +17 -13
- package/build/routes/__tests__/health.test.js.map +1 -0
- package/build/routes/__tests__/imagery.test.js +1 -0
- package/build/routes/__tests__/imagery.test.js.map +1 -0
- package/build/routes/__tests__/memory.fs.js +1 -0
- package/build/routes/__tests__/memory.fs.js.map +1 -0
- package/build/routes/__tests__/sprites.test.js +7 -0
- package/build/routes/__tests__/sprites.test.js.map +1 -0
- package/build/routes/__tests__/tile.json.test.d.ts +2 -0
- package/build/routes/__tests__/tile.json.test.d.ts.map +1 -0
- package/build/routes/__tests__/tile.json.test.js +124 -0
- package/build/routes/__tests__/tile.json.test.js.map +1 -0
- package/build/routes/__tests__/tile.style.json.test.d.ts +2 -0
- package/build/routes/__tests__/tile.style.json.test.d.ts.map +1 -0
- package/build/routes/__tests__/tile.style.json.test.js +95 -0
- package/build/routes/__tests__/tile.style.json.test.js.map +1 -0
- package/build/routes/__tests__/wmts.test.js +37 -27
- package/build/routes/__tests__/wmts.test.js.map +1 -0
- package/build/{__tests__ → routes/__tests__}/xyz.test.d.ts +0 -0
- package/build/routes/__tests__/xyz.test.d.ts.map +1 -0
- package/build/routes/__tests__/xyz.test.js +99 -0
- package/build/routes/__tests__/xyz.test.js.map +1 -0
- package/build/routes/attribution.d.ts +7 -5
- package/build/routes/attribution.d.ts.map +1 -1
- package/build/routes/attribution.js +50 -91
- package/build/routes/attribution.js.map +1 -0
- package/build/routes/fonts.d.ts +1 -1
- package/build/routes/fonts.d.ts.map +1 -1
- package/build/routes/fonts.js +33 -10
- package/build/routes/fonts.js.map +1 -0
- package/build/routes/health.d.ts +3 -3
- package/build/routes/health.d.ts.map +1 -1
- package/build/routes/health.js +16 -13
- package/build/routes/health.js.map +1 -0
- package/build/routes/imagery.d.ts +8 -1
- package/build/routes/imagery.d.ts.map +1 -1
- package/build/routes/imagery.js +17 -17
- package/build/routes/imagery.js.map +1 -0
- package/build/routes/ping.d.ts +3 -0
- package/build/routes/ping.d.ts.map +1 -0
- package/build/routes/ping.js +7 -0
- package/build/routes/ping.js.map +1 -0
- package/build/routes/sprites.d.ts.map +1 -1
- package/build/routes/sprites.js +22 -22
- package/build/routes/sprites.js.map +1 -0
- package/build/routes/tile.json.d.ts +7 -1
- package/build/routes/tile.json.d.ts.map +1 -1
- package/build/routes/tile.json.js +19 -22
- package/build/routes/tile.json.js.map +1 -0
- package/build/routes/tile.style.json.d.ts +6 -1
- package/build/routes/tile.style.json.d.ts.map +1 -1
- package/build/routes/tile.style.json.js +11 -13
- package/build/routes/tile.style.json.js.map +1 -0
- package/build/routes/tile.wmts.d.ts +9 -3
- package/build/routes/tile.wmts.d.ts.map +1 -1
- package/build/routes/tile.wmts.js +37 -50
- package/build/routes/tile.wmts.js.map +1 -0
- package/build/routes/tile.xyz.d.ts +14 -4
- package/build/routes/tile.xyz.d.ts.map +1 -1
- package/build/routes/tile.xyz.js +22 -17
- package/build/routes/tile.xyz.js.map +1 -0
- package/build/routes/tile.xyz.raster.d.ts +11 -0
- package/build/routes/tile.xyz.raster.d.ts.map +1 -0
- package/build/routes/tile.xyz.raster.js +90 -0
- package/build/routes/tile.xyz.raster.js.map +1 -0
- package/build/routes/tile.xyz.vector.d.ts +8 -0
- package/build/routes/tile.xyz.vector.d.ts.map +1 -0
- package/build/routes/tile.xyz.vector.js +46 -0
- package/build/routes/tile.xyz.vector.js.map +1 -0
- package/build/routes/version.d.ts +3 -0
- package/build/routes/version.d.ts.map +1 -0
- package/build/routes/version.js +9 -0
- package/build/routes/version.js.map +1 -0
- package/build/util/__test__/validate.test.d.ts +2 -0
- package/build/util/__test__/validate.test.d.ts.map +1 -0
- package/build/util/__test__/validate.test.js +66 -0
- package/build/util/__test__/validate.test.js.map +1 -0
- package/build/util/cotar.serve.d.ts +20 -0
- package/build/util/cotar.serve.d.ts.map +1 -0
- package/build/util/cotar.serve.js +41 -0
- package/build/util/cotar.serve.js.map +1 -0
- package/build/util/etag.d.ts +6 -0
- package/build/util/etag.d.ts.map +1 -0
- package/build/util/etag.js +20 -0
- package/build/util/etag.js.map +1 -0
- package/build/util/response.d.ts +4 -0
- package/build/util/response.d.ts.map +1 -0
- package/build/util/response.js +4 -0
- package/build/util/response.js.map +1 -0
- package/build/util/source.cache.d.ts +28 -0
- package/build/util/source.cache.d.ts.map +1 -0
- package/build/util/source.cache.js +53 -0
- package/build/util/source.cache.js.map +1 -0
- package/build/{source.tracer.d.ts → util/source.tracer.d.ts} +1 -0
- package/build/util/source.tracer.d.ts.map +1 -0
- package/build/{source.tracer.js → util/source.tracer.js} +4 -0
- package/build/util/source.tracer.js.map +1 -0
- package/build/util/swapping.lru.d.ts +21 -0
- package/build/util/swapping.lru.d.ts.map +1 -0
- package/build/util/swapping.lru.js +56 -0
- package/build/util/swapping.lru.js.map +1 -0
- package/build/util/validate.d.ts +46 -0
- package/build/util/validate.d.ts.map +1 -0
- package/build/util/validate.js +107 -0
- package/build/util/validate.js.map +1 -0
- package/build/wmts.capability.d.ts +27 -13
- package/build/wmts.capability.d.ts.map +1 -1
- package/build/wmts.capability.js +156 -55
- package/build/wmts.capability.js.map +1 -0
- package/dist/index.js +89 -73
- package/dist/node_modules/.package-lock.json +1 -1
- package/dist/package-lock.json +2 -2
- package/dist/package.json +1 -1
- package/package.json +10 -10
- package/src/__tests__/config.data.ts +120 -0
- package/src/__tests__/index.test.ts +4 -20
- package/src/__tests__/wmts.capability.test.ts +312 -139
- package/src/__tests__/xyz.util.ts +17 -45
- package/src/index.ts +75 -41
- package/src/routes/__tests__/attribution.test.ts +356 -403
- package/src/routes/__tests__/fonts.test.ts +18 -3
- package/src/routes/__tests__/health.test.ts +17 -13
- package/src/routes/__tests__/sprites.test.ts +6 -1
- package/src/routes/__tests__/tile.json.test.ts +145 -0
- package/src/routes/__tests__/tile.style.json.test.ts +105 -0
- package/src/routes/__tests__/wmts.test.ts +44 -34
- package/src/routes/__tests__/xyz.test.ts +119 -0
- package/src/routes/attribution.ts +59 -111
- package/src/routes/fonts.ts +32 -10
- package/src/routes/health.ts +17 -16
- package/src/routes/imagery.ts +18 -15
- package/src/routes/ping.ts +8 -0
- package/src/routes/sprites.ts +20 -22
- package/src/routes/tile.json.ts +24 -19
- package/src/routes/tile.style.json.ts +15 -12
- package/src/routes/tile.wmts.ts +41 -44
- package/src/routes/tile.xyz.raster.ts +106 -0
- package/src/routes/tile.xyz.ts +31 -16
- package/src/routes/tile.xyz.vector.ts +47 -0
- package/src/routes/version.ts +8 -0
- package/src/util/__test__/validate.test.ts +74 -0
- package/src/util/cotar.serve.ts +46 -0
- package/src/util/etag.ts +20 -0
- package/src/util/response.ts +4 -0
- package/src/util/source.cache.ts +71 -0
- package/src/{source.tracer.ts → util/source.tracer.ts} +4 -0
- package/src/util/swapping.lru.ts +63 -0
- package/src/util/validate.ts +126 -0
- package/src/wmts.capability.ts +170 -68
- package/tsconfig.tsbuildinfo +1 -1
- package/build/__tests__/route.test.d.ts +0 -2
- package/build/__tests__/route.test.d.ts.map +0 -1
- package/build/__tests__/route.test.js +0 -20
- package/build/__tests__/tiff.cache.test.d.ts +0 -2
- package/build/__tests__/tiff.cache.test.d.ts.map +0 -1
- package/build/__tests__/tiff.cache.test.js +0 -58
- package/build/__tests__/tile.cache.key.test.d.ts +0 -2
- package/build/__tests__/tile.cache.key.test.d.ts.map +0 -1
- package/build/__tests__/tile.cache.key.test.js +0 -48
- package/build/__tests__/tile.set.cache.test.d.ts +0 -2
- package/build/__tests__/tile.set.cache.test.d.ts.map +0 -1
- package/build/__tests__/tile.set.cache.test.js +0 -123
- package/build/__tests__/tile.set.test.d.ts +0 -2
- package/build/__tests__/tile.set.test.d.ts.map +0 -1
- package/build/__tests__/tile.set.test.js +0 -11
- package/build/__tests__/xyz.test.d.ts.map +0 -1
- package/build/__tests__/xyz.test.js +0 -306
- package/build/api.key.d.ts +0 -2
- package/build/api.key.d.ts.map +0 -1
- package/build/api.key.js +0 -23
- package/build/cli/dump.d.ts +0 -2
- package/build/cli/dump.d.ts.map +0 -1
- package/build/cli/dump.js +0 -47
- package/build/cli/tile.set.local.d.ts +0 -12
- package/build/cli/tile.set.local.d.ts.map +0 -1
- package/build/cli/tile.set.local.js +0 -39
- package/build/router.d.ts +0 -15
- package/build/router.d.ts.map +0 -1
- package/build/router.js +0 -49
- package/build/routes/api.d.ts +0 -5
- package/build/routes/api.d.ts.map +0 -1
- package/build/routes/api.js +0 -16
- package/build/routes/esri/rest.d.ts +0 -10
- package/build/routes/esri/rest.d.ts.map +0 -1
- package/build/routes/esri/rest.js +0 -87
- package/build/routes/response.d.ts +0 -4
- package/build/routes/response.d.ts.map +0 -1
- package/build/routes/response.js +0 -3
- package/build/routes/tile.d.ts +0 -3
- package/build/routes/tile.d.ts.map +0 -1
- package/build/routes/tile.etag.d.ts +0 -11
- package/build/routes/tile.etag.d.ts.map +0 -1
- package/build/routes/tile.etag.js +0 -29
- package/build/routes/tile.js +0 -27
- package/build/source.tracer.d.ts.map +0 -1
- package/build/tiff.cache.d.ts +0 -17
- package/build/tiff.cache.d.ts.map +0 -1
- package/build/tiff.cache.js +0 -45
- package/build/tile.set.cache.d.ts +0 -21
- package/build/tile.set.cache.d.ts.map +0 -1
- package/build/tile.set.cache.js +0 -100
- package/build/tile.set.d.ts +0 -4
- package/build/tile.set.d.ts.map +0 -1
- package/build/tile.set.js +0 -1
- package/build/tile.set.raster.d.ts +0 -49
- package/build/tile.set.raster.d.ts.map +0 -1
- package/build/tile.set.raster.js +0 -186
- package/build/tile.set.vector.d.ts +0 -25
- package/build/tile.set.vector.d.ts.map +0 -1
- package/build/tile.set.vector.js +0 -71
- package/build/validate.d.ts +0 -16
- package/build/validate.d.ts.map +0 -1
- package/build/validate.js +0 -31
- package/src/__tests__/route.test.ts +0 -24
- package/src/__tests__/tiff.cache.test.ts +0 -73
- package/src/__tests__/tile.cache.key.test.ts +0 -56
- package/src/__tests__/tile.set.cache.test.ts +0 -146
- package/src/__tests__/tile.set.test.ts +0 -12
- package/src/__tests__/xyz.test.ts +0 -362
- package/src/api.key.ts +0 -23
- package/src/cli/dump.ts +0 -61
- package/src/cli/tile.set.local.ts +0 -51
- package/src/router.ts +0 -58
- package/src/routes/api.ts +0 -19
- package/src/routes/esri/rest.ts +0 -90
- package/src/routes/response.ts +0 -4
- package/src/routes/tile.etag.ts +0 -36
- package/src/routes/tile.ts +0 -23
- package/src/tiff.cache.ts +0 -51
- package/src/tile.set.cache.ts +0 -111
- package/src/tile.set.raster.ts +0 -228
- package/src/tile.set.ts +0 -4
- package/src/tile.set.vector.ts +0 -79
- package/src/validate.ts +0 -32
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import {
|
|
1
|
+
import { ConfigTileSet, TileSetType } from '@basemaps/config';
|
|
2
2
|
import {
|
|
3
3
|
AttributionCollection,
|
|
4
4
|
AttributionItem,
|
|
@@ -7,32 +7,20 @@ import {
|
|
|
7
7
|
GoogleTms,
|
|
8
8
|
NamedBounds,
|
|
9
9
|
Stac,
|
|
10
|
-
StacCollection,
|
|
11
10
|
StacExtent,
|
|
12
11
|
TileMatrixSet,
|
|
13
12
|
} from '@basemaps/geo';
|
|
14
|
-
import {
|
|
15
|
-
CompositeError,
|
|
16
|
-
Config,
|
|
17
|
-
extractYearRangeFromName,
|
|
18
|
-
fsa,
|
|
19
|
-
Projection,
|
|
20
|
-
setNameAndProjection,
|
|
21
|
-
tileAttributionFromPath,
|
|
22
|
-
titleizeImageryName,
|
|
23
|
-
} from '@basemaps/shared';
|
|
13
|
+
import { Config, extractYearRangeFromName, Projection, titleizeImageryName } from '@basemaps/shared';
|
|
24
14
|
import { BBox, MultiPolygon, multiPolygonToWgs84, Pair, union, Wgs84 } from '@linzjs/geojson';
|
|
25
15
|
import { HttpHeader, LambdaHttpRequest, LambdaHttpResponse } from '@linzjs/lambda';
|
|
26
|
-
|
|
27
|
-
import {
|
|
28
|
-
import {
|
|
29
|
-
import {
|
|
16
|
+
|
|
17
|
+
import { Etag } from '../util/etag.js';
|
|
18
|
+
import { NotFound, NotModified } from '../util/response.js';
|
|
19
|
+
import { Validate } from '../util/validate.js';
|
|
30
20
|
|
|
31
21
|
/** Amount to pad imagery bounds to avoid fragmenting polygons */
|
|
32
22
|
const SmoothPadding = 1 + 1e-10; // about 1/100th of a millimeter at equator
|
|
33
23
|
|
|
34
|
-
const NotFound = new LambdaHttpResponse(404, 'Not Found');
|
|
35
|
-
|
|
36
24
|
const Precision = 10 ** 8;
|
|
37
25
|
|
|
38
26
|
/**
|
|
@@ -74,90 +62,38 @@ function createCoordinates(bbox: BBox, files: NamedBounds[], proj: Projection):
|
|
|
74
62
|
return multiPolygonToWgs84(coordinates, roundToWgs84);
|
|
75
63
|
}
|
|
76
64
|
|
|
77
|
-
async function readStac(uri: string): Promise<StacCollection | null> {
|
|
78
|
-
try {
|
|
79
|
-
return await fsa.readJson<StacCollection>(uri);
|
|
80
|
-
} catch (err) {
|
|
81
|
-
if (CompositeError.isCompositeError(err) && err.code < 500) {
|
|
82
|
-
return null;
|
|
83
|
-
}
|
|
84
|
-
throw err;
|
|
85
|
-
}
|
|
86
|
-
}
|
|
87
|
-
|
|
88
|
-
export function createAttributionCollection(
|
|
89
|
-
tileSet: TileSetRaster,
|
|
90
|
-
stac: StacCollection | null | undefined,
|
|
91
|
-
imagery: ConfigImagery,
|
|
92
|
-
layer: ConfigLayer,
|
|
93
|
-
host: ConfigProvider,
|
|
94
|
-
extent: StacExtent,
|
|
95
|
-
): AttributionCollection {
|
|
96
|
-
const tileMatrix = tileSet.tileMatrix;
|
|
97
|
-
return {
|
|
98
|
-
stac_version: Stac.Version,
|
|
99
|
-
license: stac?.license ?? Stac.License,
|
|
100
|
-
id: imagery.id,
|
|
101
|
-
providers: stac?.providers ?? [
|
|
102
|
-
{ name: host.serviceProvider.name, url: host.serviceProvider.site, roles: ['host'] },
|
|
103
|
-
],
|
|
104
|
-
title: stac?.title ?? titleizeImageryName(imagery.name),
|
|
105
|
-
description: stac?.description ?? 'No description',
|
|
106
|
-
extent,
|
|
107
|
-
links: [],
|
|
108
|
-
summaries: {
|
|
109
|
-
'linz:zoom': {
|
|
110
|
-
min: TileMatrixSet.convertZoomLevel(layer.minZoom ? layer.minZoom : 0, GoogleTms, tileMatrix, true),
|
|
111
|
-
max: TileMatrixSet.convertZoomLevel(layer.maxZoom ? layer.maxZoom : 32, GoogleTms, tileMatrix, true),
|
|
112
|
-
},
|
|
113
|
-
'linz:priority': [1000 + tileSet.tileSet.layers.indexOf(layer)],
|
|
114
|
-
},
|
|
115
|
-
};
|
|
116
|
-
}
|
|
117
|
-
|
|
118
65
|
/**
|
|
119
66
|
* Build a Single File STAC for the given TileSet.
|
|
120
67
|
*
|
|
121
68
|
* For now this is the minimal set required for attribution. This can be embellished later with
|
|
122
69
|
* links and assets for a more comprehensive STAC file.
|
|
123
70
|
*/
|
|
124
|
-
async function tileSetAttribution(
|
|
125
|
-
|
|
126
|
-
|
|
71
|
+
async function tileSetAttribution(
|
|
72
|
+
req: LambdaHttpRequest,
|
|
73
|
+
tileSet: ConfigTileSet,
|
|
74
|
+
tileMatrix: TileMatrixSet,
|
|
75
|
+
): Promise<AttributionStac | null> {
|
|
76
|
+
const proj = Projection.get(tileMatrix);
|
|
127
77
|
const cols: AttributionCollection[] = [];
|
|
128
78
|
const items: AttributionItem[] = [];
|
|
129
79
|
|
|
130
|
-
|
|
131
|
-
for (const layer of tileSet.tileSet.layers) {
|
|
132
|
-
const imgId = layer[proj.epsg.code];
|
|
133
|
-
if (imgId == null) continue;
|
|
134
|
-
const im = tileSet.imagery.get(imgId);
|
|
135
|
-
if (im == null) continue;
|
|
136
|
-
if (stacFiles.get(im.uri) == null) {
|
|
137
|
-
stacFiles.set(im.uri, readStac(fsa.join(im.uri, 'collection.json')));
|
|
138
|
-
}
|
|
139
|
-
}
|
|
80
|
+
const imagery = await Config.getAllImagery(tileSet.layers, [tileMatrix.projection]);
|
|
140
81
|
|
|
141
82
|
const host = await Config.Provider.get(Config.Provider.id('linz'));
|
|
142
83
|
if (host == null) return null;
|
|
143
84
|
|
|
144
|
-
for (const layer of tileSet.
|
|
85
|
+
for (const layer of tileSet.layers) {
|
|
145
86
|
const imgId = layer[proj.epsg.code];
|
|
146
87
|
if (imgId == null) continue;
|
|
147
|
-
const im =
|
|
88
|
+
const im = imagery.get(imgId);
|
|
148
89
|
if (im == null) continue;
|
|
149
|
-
const stac = await stacFiles.get(im.uri);
|
|
150
90
|
|
|
151
91
|
const bbox = proj.boundsToWgs84BoundingBox(im.bounds).map(roundNumber) as BBox;
|
|
152
92
|
|
|
153
|
-
|
|
154
|
-
if (
|
|
155
|
-
|
|
156
|
-
|
|
157
|
-
throw new Error('Missing date in imagery name: ' + im.name);
|
|
158
|
-
}
|
|
159
|
-
interval = [years.map((y) => `${y}-01-01T00:00:00Z`) as [string, string]];
|
|
160
|
-
}
|
|
93
|
+
const years = extractYearRangeFromName(im.name);
|
|
94
|
+
if (years[0] === -1) throw new Error('Missing date in imagery name: ' + im.name);
|
|
95
|
+
const interval = [years.map((y) => `${y}-01-01T00:00:00Z`) as [string, string]];
|
|
96
|
+
|
|
161
97
|
const extent: StacExtent = { spatial: { bbox: [bbox] }, temporal: { interval } };
|
|
162
98
|
|
|
163
99
|
items.push({
|
|
@@ -168,68 +104,80 @@ async function tileSetAttribution(tileSet: TileSetRaster): Promise<AttributionSt
|
|
|
168
104
|
assets: {},
|
|
169
105
|
links: [],
|
|
170
106
|
bbox,
|
|
171
|
-
geometry: {
|
|
172
|
-
type: 'MultiPolygon',
|
|
173
|
-
coordinates: createCoordinates(bbox, im.files, proj),
|
|
174
|
-
},
|
|
107
|
+
geometry: { type: 'MultiPolygon', coordinates: createCoordinates(bbox, im.files, proj) },
|
|
175
108
|
properties: {
|
|
176
|
-
title: titleizeImageryName(im.name),
|
|
109
|
+
title: im.title ?? titleizeImageryName(im.name),
|
|
110
|
+
category: im.category,
|
|
177
111
|
datetime: null,
|
|
178
112
|
start_datetime: interval[0][0],
|
|
179
113
|
end_datetime: interval[0][1],
|
|
180
114
|
},
|
|
181
115
|
});
|
|
182
116
|
|
|
183
|
-
|
|
117
|
+
const zoomMin = TileMatrixSet.convertZoomLevel(layer.minZoom ? layer.minZoom : 0, GoogleTms, tileMatrix, true);
|
|
118
|
+
const zoomMax = TileMatrixSet.convertZoomLevel(layer.maxZoom ? layer.maxZoom : 32, GoogleTms, tileMatrix, true);
|
|
119
|
+
cols.push({
|
|
120
|
+
stac_version: Stac.Version,
|
|
121
|
+
license: Stac.License,
|
|
122
|
+
id: im.id,
|
|
123
|
+
providers: [{ name: host.serviceProvider.name, url: host.serviceProvider.site, roles: ['host'] }],
|
|
124
|
+
title: im.title ?? titleizeImageryName(im.name),
|
|
125
|
+
description: 'No description',
|
|
126
|
+
extent,
|
|
127
|
+
links: [],
|
|
128
|
+
summaries: {
|
|
129
|
+
'linz:category': im.category,
|
|
130
|
+
'linz:zoom': { min: zoomMin, max: zoomMax },
|
|
131
|
+
'linz:priority': [1000 + tileSet.layers.indexOf(layer)],
|
|
132
|
+
},
|
|
133
|
+
});
|
|
184
134
|
}
|
|
185
135
|
return {
|
|
186
136
|
id: tileSet.id,
|
|
187
137
|
type: 'FeatureCollection',
|
|
188
138
|
stac_version: Stac.Version,
|
|
189
139
|
stac_extensions: ['single-file-stac'],
|
|
190
|
-
title: tileSet.title,
|
|
191
|
-
description: tileSet.description,
|
|
140
|
+
title: tileSet.title ?? 'No title',
|
|
141
|
+
description: tileSet.description ?? 'No Description',
|
|
192
142
|
features: items,
|
|
193
143
|
collections: cols,
|
|
194
144
|
links: [],
|
|
195
145
|
};
|
|
196
146
|
}
|
|
197
147
|
|
|
148
|
+
export interface TileAttributionGet {
|
|
149
|
+
Params: {
|
|
150
|
+
tileSet: string;
|
|
151
|
+
tileMatrix: string;
|
|
152
|
+
};
|
|
153
|
+
}
|
|
154
|
+
|
|
198
155
|
/**
|
|
199
156
|
* Create a LambdaHttpResponse for a attribution request
|
|
200
157
|
*/
|
|
201
|
-
export async function
|
|
202
|
-
const
|
|
203
|
-
|
|
204
|
-
if (data == null) return NotFound;
|
|
205
|
-
setNameAndProjection(req, data);
|
|
158
|
+
export async function tileAttributionGet(req: LambdaHttpRequest<TileAttributionGet>): Promise<LambdaHttpResponse> {
|
|
159
|
+
const tileMatrix = Validate.getTileMatrixSet(req.params.tileMatrix);
|
|
160
|
+
if (tileMatrix == null) throw new LambdaHttpResponse(404, 'Tile Matrix not found');
|
|
206
161
|
|
|
207
162
|
req.timer.start('tileset:load');
|
|
208
|
-
const tileSet = await
|
|
163
|
+
const tileSet = await Config.TileSet.get(Config.TileSet.id(req.params.tileSet));
|
|
209
164
|
req.timer.end('tileset:load');
|
|
210
|
-
if (tileSet == null || tileSet.type === TileSetType.Vector) return NotFound;
|
|
165
|
+
if (tileSet == null || tileSet.type === TileSetType.Vector) return NotFound();
|
|
211
166
|
|
|
212
|
-
const cacheKey =
|
|
213
|
-
|
|
214
|
-
const ifNoneMatch = req.header(HttpHeader.IfNoneMatch);
|
|
215
|
-
if (ifNoneMatch != null && ifNoneMatch.indexOf(cacheKey) > -1) {
|
|
216
|
-
req.set('cache', { key: cacheKey, hit: true, match: ifNoneMatch });
|
|
217
|
-
return new LambdaHttpResponse(304, 'Not modified');
|
|
218
|
-
}
|
|
167
|
+
const cacheKey = Etag.key(tileSet);
|
|
168
|
+
if (Etag.isNotModified(req, cacheKey)) return NotModified();
|
|
219
169
|
|
|
220
170
|
req.timer.start('stac:load');
|
|
221
|
-
const attributions = await tileSetAttribution(tileSet);
|
|
171
|
+
const attributions = await tileSetAttribution(req, tileSet, tileMatrix);
|
|
222
172
|
req.timer.end('stac:load');
|
|
223
173
|
|
|
224
|
-
if (attributions == null) return NotFound;
|
|
174
|
+
if (attributions == null) return NotFound();
|
|
225
175
|
|
|
226
176
|
const response = new LambdaHttpResponse(200, 'ok');
|
|
227
177
|
|
|
228
178
|
response.header(HttpHeader.ETag, cacheKey);
|
|
229
|
-
// Keep fresh for
|
|
230
|
-
response.header(HttpHeader.CacheControl, 'public, max-age=
|
|
231
|
-
|
|
179
|
+
// Keep fresh for 7 days; otherwise use cache but refresh cache for next time
|
|
180
|
+
response.header(HttpHeader.CacheControl, 'public, max-age=604800, stale-while-revalidate=86400');
|
|
232
181
|
response.json(attributions);
|
|
233
|
-
|
|
234
182
|
return response;
|
|
235
183
|
}
|
package/src/routes/fonts.ts
CHANGED
|
@@ -1,8 +1,10 @@
|
|
|
1
1
|
import { Env } from '@basemaps/shared';
|
|
2
2
|
import { fsa } from '@chunkd/fs';
|
|
3
|
-
import { LambdaHttpRequest, LambdaHttpResponse } from '@linzjs/lambda';
|
|
3
|
+
import { HttpHeader, LambdaHttpRequest, LambdaHttpResponse } from '@linzjs/lambda';
|
|
4
4
|
import path from 'path';
|
|
5
|
-
import {
|
|
5
|
+
import { isGzip, serveFromCotar } from '../util/cotar.serve.js';
|
|
6
|
+
import { Etag } from '../util/etag.js';
|
|
7
|
+
import { NotFound, NotModified } from '../util/response.js';
|
|
6
8
|
|
|
7
9
|
interface FontGet {
|
|
8
10
|
Params: { fontStack: string; range: string };
|
|
@@ -10,15 +12,27 @@ interface FontGet {
|
|
|
10
12
|
|
|
11
13
|
export async function fontGet(req: LambdaHttpRequest<FontGet>): Promise<LambdaHttpResponse> {
|
|
12
14
|
const assetLocation = Env.get(Env.AssetLocation);
|
|
13
|
-
if (assetLocation == null) return NotFound;
|
|
15
|
+
if (assetLocation == null) return NotFound();
|
|
16
|
+
|
|
17
|
+
const targetFile = path.join('fonts', req.params.fontStack, req.params.range) + '.pbf';
|
|
18
|
+
if (assetLocation.endsWith('.tar.co')) {
|
|
19
|
+
return serveFromCotar(req, assetLocation, targetFile, 'application/x-protobuf');
|
|
20
|
+
}
|
|
14
21
|
|
|
15
22
|
try {
|
|
16
|
-
const filePath = fsa.join(assetLocation,
|
|
23
|
+
const filePath = fsa.join(assetLocation, targetFile);
|
|
17
24
|
const buf = await fsa.read(filePath);
|
|
18
25
|
|
|
19
|
-
|
|
26
|
+
const cacheKey = Etag.key(buf);
|
|
27
|
+
if (Etag.isNotModified(req, cacheKey)) return NotModified();
|
|
28
|
+
|
|
29
|
+
const response = LambdaHttpResponse.ok().buffer(buf, 'application/x-protobuf');
|
|
30
|
+
response.header(HttpHeader.ETag, cacheKey);
|
|
31
|
+
response.header(HttpHeader.CacheControl, 'public, max-age=604800, stale-while-revalidate=86400');
|
|
32
|
+
if (isGzip(buf)) response.header(HttpHeader.ContentEncoding, 'gzip');
|
|
33
|
+
return response;
|
|
20
34
|
} catch (e: any) {
|
|
21
|
-
if (e.code === 404) return NotFound;
|
|
35
|
+
if (e.code === 404) return NotFound();
|
|
22
36
|
throw e;
|
|
23
37
|
}
|
|
24
38
|
}
|
|
@@ -38,17 +52,25 @@ export async function getFonts(fontPath: string): Promise<string[]> {
|
|
|
38
52
|
return [...fonts].sort();
|
|
39
53
|
}
|
|
40
54
|
|
|
41
|
-
export async function fontList(): Promise<LambdaHttpResponse> {
|
|
55
|
+
export async function fontList(req: LambdaHttpRequest): Promise<LambdaHttpResponse> {
|
|
42
56
|
const assetLocation = Env.get(Env.AssetLocation);
|
|
43
|
-
if (assetLocation == null) return NotFound;
|
|
57
|
+
if (assetLocation == null) return NotFound();
|
|
58
|
+
|
|
59
|
+
if (assetLocation.endsWith('.tar.co')) return serveFromCotar(req, assetLocation, 'fonts.json', 'application/json');
|
|
44
60
|
|
|
45
61
|
try {
|
|
46
62
|
const filePath = fsa.join(assetLocation, '/fonts');
|
|
47
63
|
const fonts = await getFonts(filePath);
|
|
48
64
|
|
|
49
|
-
|
|
65
|
+
const cacheKey = Etag.key(fonts);
|
|
66
|
+
if (Etag.isNotModified(req, cacheKey)) return NotModified();
|
|
67
|
+
|
|
68
|
+
const response = LambdaHttpResponse.ok().buffer(JSON.stringify(fonts), 'application/json');
|
|
69
|
+
response.header(HttpHeader.ETag, cacheKey);
|
|
70
|
+
response.header(HttpHeader.CacheControl, 'public, max-age=604800, stale-while-revalidate=86400');
|
|
71
|
+
return response;
|
|
50
72
|
} catch (e: any) {
|
|
51
|
-
if (e.code === 404) return NotFound;
|
|
73
|
+
if (e.code === 404) return NotFound();
|
|
52
74
|
throw e;
|
|
53
75
|
}
|
|
54
76
|
}
|
package/src/routes/health.ts
CHANGED
|
@@ -1,27 +1,29 @@
|
|
|
1
|
-
import {
|
|
2
|
-
import {
|
|
1
|
+
import { Config, ConfigTileSetRaster } from '@basemaps/config';
|
|
2
|
+
import { GoogleTms, ImageFormat, Nztm2000QuadTms } from '@basemaps/geo';
|
|
3
3
|
import { HttpHeader, LambdaHttpRequest, LambdaHttpResponse } from '@linzjs/lambda';
|
|
4
4
|
import * as fs from 'fs';
|
|
5
5
|
import * as path from 'path';
|
|
6
6
|
import PixelMatch from 'pixelmatch';
|
|
7
7
|
import Sharp from 'sharp';
|
|
8
8
|
import url from 'url';
|
|
9
|
-
import {
|
|
9
|
+
import { TileXyz } from '../util/validate.js';
|
|
10
|
+
import { TileXyzRaster } from './tile.xyz.raster.js';
|
|
10
11
|
|
|
11
|
-
interface TestTile extends
|
|
12
|
+
interface TestTile extends TileXyz {
|
|
12
13
|
buf?: Buffer;
|
|
13
14
|
}
|
|
14
15
|
|
|
15
16
|
export const TestTiles: TestTile[] = [
|
|
16
|
-
{
|
|
17
|
-
{
|
|
17
|
+
{ tileSet: 'health', tileMatrix: GoogleTms, tileType: ImageFormat.Png, tile: { x: 252, y: 156, z: 8 } },
|
|
18
|
+
{ tileSet: 'health', tileMatrix: Nztm2000QuadTms, tileType: ImageFormat.Png, tile: { x: 30, y: 33, z: 6 } },
|
|
18
19
|
];
|
|
19
20
|
const TileSize = 256;
|
|
20
21
|
|
|
21
22
|
export async function getTestBuffer(test: TestTile): Promise<Buffer> {
|
|
22
23
|
if (Buffer.isBuffer(test.buf)) return test.buf;
|
|
24
|
+
const tile = test.tile;
|
|
23
25
|
|
|
24
|
-
const expectedFile = `static/expected_tile_${test.tileMatrix.identifier}_${
|
|
26
|
+
const expectedFile = `static/expected_tile_${test.tileMatrix.identifier}_${tile.x}_${tile.y}_z${tile.z}.${test.tileType}`;
|
|
25
27
|
// Initiate test img buffer if not defined
|
|
26
28
|
try {
|
|
27
29
|
return await fs.promises.readFile(expectedFile);
|
|
@@ -33,7 +35,9 @@ export async function getTestBuffer(test: TestTile): Promise<Buffer> {
|
|
|
33
35
|
}
|
|
34
36
|
|
|
35
37
|
export async function updateExpectedTile(test: TestTile, newTileData: Buffer, difference: Buffer): Promise<void> {
|
|
36
|
-
const
|
|
38
|
+
const tile = test.tile;
|
|
39
|
+
|
|
40
|
+
const expectedFileName = `static/expected_tile_${test.tileMatrix.identifier}_${tile.x}_${tile.y}_z${tile.z}.${test.tileType}`;
|
|
37
41
|
await fs.promises.writeFile(expectedFileName, newTileData);
|
|
38
42
|
const imgPng = await Sharp(difference, { raw: { width: TileSize, height: TileSize, channels: 4 } })
|
|
39
43
|
.png()
|
|
@@ -48,12 +52,12 @@ export async function updateExpectedTile(test: TestTile, newTileData: Buffer, di
|
|
|
48
52
|
*
|
|
49
53
|
* @throws LambdaHttpResponse for failure health test
|
|
50
54
|
*/
|
|
51
|
-
export async function
|
|
55
|
+
export async function healthGet(req: LambdaHttpRequest): Promise<LambdaHttpResponse> {
|
|
56
|
+
const tileSet = await Config.TileSet.get(Config.TileSet.id('health'));
|
|
57
|
+
if (tileSet == null) throw new LambdaHttpResponse(500, 'TileSet: "health" not found');
|
|
52
58
|
for (const test of TestTiles) {
|
|
53
|
-
const tileSet = await TileSets.get('health', test.tileMatrix);
|
|
54
|
-
if (tileSet == null) throw new LambdaHttpResponse(500, 'TileSet: "health" not found');
|
|
55
59
|
// Get the parse response tile to raw buffer
|
|
56
|
-
const response = await
|
|
60
|
+
const response = await TileXyzRaster.tile(req, tileSet as ConfigTileSetRaster, test);
|
|
57
61
|
if (response.status !== 200) return new LambdaHttpResponse(500, response.statusDescription);
|
|
58
62
|
if (!Buffer.isBuffer(response._body)) throw new LambdaHttpResponse(500, 'Not a Buffer response content.');
|
|
59
63
|
const resImgBuffer = await Sharp(response._body).raw().toBuffer();
|
|
@@ -68,10 +72,7 @@ export async function Health(req: LambdaHttpRequest): Promise<LambdaHttpResponse
|
|
|
68
72
|
if (missMatchedPixels) {
|
|
69
73
|
/** Uncomment this to overwite the expected files */
|
|
70
74
|
// await updateExpectedTile(test, response._body as Buffer, outputBuffer);
|
|
71
|
-
req.log.error(
|
|
72
|
-
{ missMatchedPixels, projection: test.tileMatrix.identifier, xyz: { x: test.x, y: test.y, z: test.z } },
|
|
73
|
-
'Health:MissMatch',
|
|
74
|
-
);
|
|
75
|
+
req.log.error({ missMatchedPixels, projection: test.tileMatrix.identifier, xyz: test.tile }, 'Health:MissMatch');
|
|
75
76
|
return new LambdaHttpResponse(500, 'TileSet does not match.');
|
|
76
77
|
}
|
|
77
78
|
}
|
package/src/routes/imagery.ts
CHANGED
|
@@ -1,12 +1,11 @@
|
|
|
1
1
|
import { Config } from '@basemaps/config';
|
|
2
2
|
import { fsa } from '@basemaps/shared';
|
|
3
3
|
import { HttpHeader, LambdaHttpRequest, LambdaHttpResponse } from '@linzjs/lambda';
|
|
4
|
-
import { createHash } from 'crypto';
|
|
5
4
|
import { promisify } from 'util';
|
|
6
5
|
import { gzip } from 'zlib';
|
|
7
|
-
import {
|
|
8
|
-
import {
|
|
9
|
-
import {
|
|
6
|
+
import { isGzip } from '../util/cotar.serve.js';
|
|
7
|
+
import { Etag } from '../util/etag.js';
|
|
8
|
+
import { NotFound, NotModified } from '../util/response.js';
|
|
10
9
|
|
|
11
10
|
const gzipP = promisify(gzip);
|
|
12
11
|
|
|
@@ -17,6 +16,10 @@ export function isAllowedFile(f: string): boolean {
|
|
|
17
16
|
return false;
|
|
18
17
|
}
|
|
19
18
|
|
|
19
|
+
interface ImageryGet {
|
|
20
|
+
Params: { imageryId: string; fileName: string };
|
|
21
|
+
}
|
|
22
|
+
|
|
20
23
|
/**
|
|
21
24
|
* Get metadata around the imagery such as the source bounding box or the bounding box of the COGS
|
|
22
25
|
*
|
|
@@ -27,30 +30,30 @@ export function isAllowedFile(f: string): boolean {
|
|
|
27
30
|
* - /v1/imagery/:imageryId/collection.json - STAC Collection
|
|
28
31
|
* - /v1/imagery/:imageryId/15-32659-21603.json - STAC Item
|
|
29
32
|
*/
|
|
30
|
-
export async function
|
|
31
|
-
const
|
|
32
|
-
|
|
33
|
-
if (!isAllowedFile(requestType)) return new LambdaHttpResponse(404, 'Not found');
|
|
33
|
+
export async function imageryGet(req: LambdaHttpRequest<ImageryGet>): Promise<LambdaHttpResponse> {
|
|
34
|
+
const requestedFile = req.params.fileName;
|
|
35
|
+
if (!isAllowedFile(requestedFile)) return NotFound();
|
|
34
36
|
|
|
35
|
-
const imagery = await Config.Imagery.get(Config.Imagery.id(imageryId));
|
|
36
|
-
if (imagery == null) return
|
|
37
|
+
const imagery = await Config.Imagery.get(Config.Imagery.id(req.params.imageryId));
|
|
38
|
+
if (imagery == null) return NotFound();
|
|
37
39
|
|
|
38
|
-
const targetPath = fsa.join(imagery.uri,
|
|
40
|
+
const targetPath = fsa.join(imagery.uri, requestedFile);
|
|
39
41
|
|
|
40
42
|
try {
|
|
41
43
|
const buf = await fsa.read(targetPath);
|
|
42
|
-
const cacheKey = createHash('sha256').update(buf).digest('base64');
|
|
43
44
|
|
|
44
|
-
|
|
45
|
+
const cacheKey = Etag.key(buf);
|
|
46
|
+
if (Etag.isNotModified(req, cacheKey)) return NotModified();
|
|
45
47
|
|
|
46
48
|
const response = new LambdaHttpResponse(200, 'ok');
|
|
47
49
|
response.header(HttpHeader.ETag, cacheKey);
|
|
48
50
|
response.header(HttpHeader.ContentEncoding, 'gzip');
|
|
49
|
-
response.
|
|
51
|
+
response.header(HttpHeader.CacheControl, 'public, max-age=604800, stale-while-revalidate=86400');
|
|
52
|
+
response.buffer(isGzip(buf) ? buf : await gzipP(buf), 'application/json');
|
|
50
53
|
req.set('bytes', buf.byteLength);
|
|
51
54
|
return response;
|
|
52
55
|
} catch (e) {
|
|
53
56
|
req.log.warn({ targetPath }, 'ImageryMetadata:Failed');
|
|
54
|
-
return
|
|
57
|
+
return NotFound();
|
|
55
58
|
}
|
|
56
59
|
}
|
|
@@ -0,0 +1,8 @@
|
|
|
1
|
+
import { LambdaHttpResponse, HttpHeader } from '@linzjs/lambda';
|
|
2
|
+
|
|
3
|
+
const OkResponse = new LambdaHttpResponse(200, 'ok');
|
|
4
|
+
OkResponse.header(HttpHeader.CacheControl, 'no-store');
|
|
5
|
+
|
|
6
|
+
export async function pingGet(): Promise<LambdaHttpResponse> {
|
|
7
|
+
return OkResponse;
|
|
8
|
+
}
|
package/src/routes/sprites.ts
CHANGED
|
@@ -1,8 +1,10 @@
|
|
|
1
1
|
import { Env } from '@basemaps/shared';
|
|
2
2
|
import { fsa } from '@chunkd/fs';
|
|
3
3
|
import path from 'path';
|
|
4
|
-
import { LambdaHttpRequest, LambdaHttpResponse } from '@linzjs/lambda';
|
|
5
|
-
import { NotFound } from '
|
|
4
|
+
import { HttpHeader, LambdaHttpRequest, LambdaHttpResponse } from '@linzjs/lambda';
|
|
5
|
+
import { NotFound, NotModified } from '../util/response.js';
|
|
6
|
+
import { isGzip, serveFromCotar } from '../util/cotar.serve.js';
|
|
7
|
+
import { Etag } from '../util/etag.js';
|
|
6
8
|
|
|
7
9
|
interface SpriteGet {
|
|
8
10
|
Params: {
|
|
@@ -14,36 +16,32 @@ const Extensions = new Map();
|
|
|
14
16
|
Extensions.set('.png', 'image/png');
|
|
15
17
|
Extensions.set('.json', 'application/json');
|
|
16
18
|
|
|
17
|
-
/**
|
|
18
|
-
* Does a buffer look like a gzipped document instead of raw json
|
|
19
|
-
*
|
|
20
|
-
* Determined by checking the first two bytes are the gzip magic bytes `0x1f 0x8b`
|
|
21
|
-
*
|
|
22
|
-
* @see https://en.wikipedia.org/wiki/Gzip
|
|
23
|
-
*
|
|
24
|
-
*/
|
|
25
|
-
function isGzip(b: Buffer): boolean {
|
|
26
|
-
return b[0] === 0x1f && b[1] === 0x8b;
|
|
27
|
-
}
|
|
28
|
-
|
|
29
19
|
export async function spriteGet(req: LambdaHttpRequest<SpriteGet>): Promise<LambdaHttpResponse> {
|
|
30
|
-
const
|
|
31
|
-
if (
|
|
20
|
+
const assetLocation = Env.get(Env.AssetLocation);
|
|
21
|
+
if (assetLocation == null) return NotFound();
|
|
32
22
|
|
|
33
23
|
const extension = path.extname(req.params.spriteName);
|
|
34
24
|
const mimeType = Extensions.get(extension);
|
|
35
|
-
if (mimeType == null) return NotFound;
|
|
25
|
+
if (mimeType == null) return NotFound();
|
|
26
|
+
|
|
27
|
+
const targetFile = fsa.join('sprites', req.params.spriteName);
|
|
28
|
+
if (assetLocation.endsWith('.tar.co')) return serveFromCotar(req, assetLocation, targetFile, mimeType);
|
|
36
29
|
|
|
37
30
|
try {
|
|
38
|
-
const filePath = fsa.join(
|
|
31
|
+
const filePath = fsa.join(assetLocation, targetFile);
|
|
39
32
|
req.set('target', filePath);
|
|
40
33
|
|
|
41
34
|
const buf = await fsa.read(filePath);
|
|
42
|
-
const
|
|
43
|
-
if (
|
|
44
|
-
|
|
35
|
+
const cacheKey = Etag.key(buf);
|
|
36
|
+
if (Etag.isNotModified(req, cacheKey)) return NotModified();
|
|
37
|
+
|
|
38
|
+
const response = LambdaHttpResponse.ok().buffer(buf, mimeType);
|
|
39
|
+
response.header(HttpHeader.ETag, cacheKey);
|
|
40
|
+
response.header(HttpHeader.CacheControl, 'public, max-age=604800, stale-while-revalidate=86400');
|
|
41
|
+
if (isGzip(buf)) response.header(HttpHeader.ContentEncoding, 'gzip');
|
|
42
|
+
return response;
|
|
45
43
|
} catch (e: any) {
|
|
46
|
-
if (e.code === 404) return NotFound;
|
|
44
|
+
if (e.code === 404) return NotFound();
|
|
47
45
|
throw e;
|
|
48
46
|
}
|
|
49
47
|
}
|
package/src/routes/tile.json.ts
CHANGED
|
@@ -1,36 +1,41 @@
|
|
|
1
1
|
import { GoogleTms, TileJson, TileMatrixSet } from '@basemaps/geo';
|
|
2
|
-
import {
|
|
2
|
+
import { Config, Env } from '@basemaps/shared';
|
|
3
3
|
import { HttpHeader, LambdaHttpRequest, LambdaHttpResponse } from '@linzjs/lambda';
|
|
4
|
-
import {
|
|
5
|
-
import {
|
|
6
|
-
|
|
7
|
-
|
|
4
|
+
import { NotFound } from '../util/response.js';
|
|
5
|
+
import { Validate } from '../util/validate.js';
|
|
6
|
+
|
|
7
|
+
export interface TileJsonGet {
|
|
8
|
+
Params: {
|
|
9
|
+
tileSet: string;
|
|
10
|
+
tileMatrix: string;
|
|
11
|
+
};
|
|
12
|
+
}
|
|
8
13
|
|
|
9
|
-
export async function
|
|
10
|
-
const
|
|
11
|
-
if (
|
|
14
|
+
export async function tileJsonGet(req: LambdaHttpRequest<TileJsonGet>): Promise<LambdaHttpResponse> {
|
|
15
|
+
const tileMatrix = Validate.getTileMatrixSet(req.params.tileMatrix);
|
|
16
|
+
if (tileMatrix == null) return NotFound();
|
|
12
17
|
|
|
13
|
-
const
|
|
14
|
-
if (tileMatrix == null) return NotFound;
|
|
18
|
+
const apiKey = Validate.apiKey(req);
|
|
15
19
|
|
|
16
20
|
req.timer.start('tileset:load');
|
|
17
|
-
const tileSet = await
|
|
21
|
+
const tileSet = await Config.TileSet.get(Config.TileSet.id(req.params.tileSet));
|
|
18
22
|
req.timer.end('tileset:load');
|
|
19
|
-
if (tileSet == null) return NotFound;
|
|
23
|
+
if (tileSet == null) return NotFound();
|
|
24
|
+
|
|
25
|
+
const format = Validate.getRequestedFormats(req) ?? [tileSet.format];
|
|
20
26
|
|
|
21
|
-
const apiKey = Router.apiKey(req);
|
|
22
27
|
const host = Env.get(Env.PublicUrlBase) ?? '';
|
|
23
28
|
|
|
24
29
|
const tileUrl =
|
|
25
|
-
[host,
|
|
26
|
-
`.${
|
|
30
|
+
[host, 'v1', 'tiles', tileSet.name, tileMatrix.identifier, '{z}', '{x}', '{y}'].join('/') +
|
|
31
|
+
`.${format[0]}?api=${apiKey}`;
|
|
27
32
|
|
|
28
33
|
const tileJson: TileJson = { tiles: [tileUrl], tilejson: '3.0.0' };
|
|
29
|
-
const maxZoom = TileMatrixSet.convertZoomLevel(tileSet.
|
|
30
|
-
const minZoom = TileMatrixSet.convertZoomLevel(tileSet.
|
|
34
|
+
const maxZoom = TileMatrixSet.convertZoomLevel(tileSet.maxZoom ?? 30, GoogleTms, tileMatrix, true);
|
|
35
|
+
const minZoom = TileMatrixSet.convertZoomLevel(tileSet.minZoom ?? 0, GoogleTms, tileMatrix, true);
|
|
31
36
|
|
|
32
|
-
if (tileSet.
|
|
33
|
-
if (tileSet.
|
|
37
|
+
if (tileSet.maxZoom) tileJson.maxzoom = maxZoom;
|
|
38
|
+
if (tileSet.minZoom) tileJson.minzoom = minZoom;
|
|
34
39
|
|
|
35
40
|
const json = JSON.stringify(tileJson);
|
|
36
41
|
const data = Buffer.from(json);
|