@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
package/src/routes/tile.etag.ts
DELETED
|
@@ -1,36 +0,0 @@
|
|
|
1
|
-
import { Composition } from '@basemaps/tiler';
|
|
2
|
-
import { createHash } from 'crypto';
|
|
3
|
-
import { TileDataXyz } from '@basemaps/shared';
|
|
4
|
-
import { HttpHeader, LambdaHttpRequest } from '@linzjs/lambda';
|
|
5
|
-
import { basename } from 'path';
|
|
6
|
-
|
|
7
|
-
export const TileEtag = {
|
|
8
|
-
// To force a full cache invalidation change this number
|
|
9
|
-
RenderId: 1,
|
|
10
|
-
|
|
11
|
-
key(object: Record<string, unknown>): string {
|
|
12
|
-
return createHash('sha256').update(JSON.stringify(object)).digest('base64');
|
|
13
|
-
},
|
|
14
|
-
|
|
15
|
-
/** Generate a unique ETag for this tile */
|
|
16
|
-
generate(compositions: Composition[], xyzData: TileDataXyz): string {
|
|
17
|
-
// We cannot serialize the CogTiff inside of composition so replace it with the source name
|
|
18
|
-
const layers = compositions.map((c) => {
|
|
19
|
-
return { ...c, tiff: basename(c.tiff.source.uri) };
|
|
20
|
-
});
|
|
21
|
-
|
|
22
|
-
const xyz = { ...xyzData, tileMatrix: xyzData.tileMatrix.identifier };
|
|
23
|
-
return TileEtag.key({ xyz, layers, RenderId: TileEtag.RenderId });
|
|
24
|
-
},
|
|
25
|
-
|
|
26
|
-
isNotModified(req: LambdaHttpRequest, cacheKey: string): boolean {
|
|
27
|
-
// If the user has supplied a IfNoneMatch Header and it contains the full sha256 sum for our
|
|
28
|
-
// etag this tile has not been modified.
|
|
29
|
-
const ifNoneMatch = req.header(HttpHeader.IfNoneMatch);
|
|
30
|
-
if (ifNoneMatch != null && ifNoneMatch.indexOf(cacheKey) > -1) {
|
|
31
|
-
req.set('cache', { key: cacheKey, hit: true, match: ifNoneMatch });
|
|
32
|
-
return true;
|
|
33
|
-
}
|
|
34
|
-
return false;
|
|
35
|
-
},
|
|
36
|
-
};
|
package/src/routes/tile.ts
DELETED
|
@@ -1,23 +0,0 @@
|
|
|
1
|
-
import { LambdaHttpRequest, LambdaHttpResponse } from '@linzjs/lambda';
|
|
2
|
-
import { isValidApiKey } from '../api.key.js';
|
|
3
|
-
import { Router } from '../router.js';
|
|
4
|
-
import { attribution } from './attribution.js';
|
|
5
|
-
import { NotFound } from './response.js';
|
|
6
|
-
import { tileJson } from './tile.json.js';
|
|
7
|
-
import { styleJson } from './tile.style.json.js';
|
|
8
|
-
import { wmts } from './tile.wmts.js';
|
|
9
|
-
import { tileXyz } from './tile.xyz.js';
|
|
10
|
-
|
|
11
|
-
export async function Tiles(req: LambdaHttpRequest): Promise<LambdaHttpResponse> {
|
|
12
|
-
const { rest } = Router.action(req);
|
|
13
|
-
if (rest.length < 1) return NotFound;
|
|
14
|
-
const apiKey = Router.apiKey(req);
|
|
15
|
-
if (!isValidApiKey(apiKey)) return new LambdaHttpResponse(400, 'Invalid API Key');
|
|
16
|
-
|
|
17
|
-
const fileName = rest[rest.length - 1].toLowerCase();
|
|
18
|
-
if (fileName === 'attribution.json') return attribution(req);
|
|
19
|
-
if (fileName === 'wmtscapabilities.xml') return wmts(req);
|
|
20
|
-
if (fileName === 'tile.json') return tileJson(req);
|
|
21
|
-
if (fileName.endsWith('json') && rest[rest.length - 2] === 'style') return styleJson(req, fileName);
|
|
22
|
-
return tileXyz(req);
|
|
23
|
-
}
|
package/src/tiff.cache.ts
DELETED
|
@@ -1,51 +0,0 @@
|
|
|
1
|
-
import { ChunkSourceBase } from '@chunkd/core';
|
|
2
|
-
import { CogTiff } from '@cogeotiff/core';
|
|
3
|
-
|
|
4
|
-
/** Limit the caching of tiffs */
|
|
5
|
-
export class TiffCache {
|
|
6
|
-
static cacheA: Map<string, CogTiff> = new Map();
|
|
7
|
-
static cacheB: Map<string, CogTiff> = new Map();
|
|
8
|
-
|
|
9
|
-
/** 256 MB Cache */
|
|
10
|
-
static MaxCacheSizeBytes = 256 * 1024 * 1024;
|
|
11
|
-
|
|
12
|
-
static get(id: string): CogTiff | null {
|
|
13
|
-
const cacheA = TiffCache.cacheA.get(id);
|
|
14
|
-
if (cacheA) return cacheA;
|
|
15
|
-
|
|
16
|
-
const cacheB = TiffCache.cacheB.get(id);
|
|
17
|
-
if (cacheB == null) return null;
|
|
18
|
-
// If a object is still useful move it into the main cache
|
|
19
|
-
TiffCache.cacheA.set(id, cacheB);
|
|
20
|
-
TiffCache.cacheB.delete(id);
|
|
21
|
-
return cacheB;
|
|
22
|
-
}
|
|
23
|
-
|
|
24
|
-
/** Reset the cache */
|
|
25
|
-
static clear(): void {
|
|
26
|
-
this.cacheA.clear();
|
|
27
|
-
this.cacheB.clear();
|
|
28
|
-
}
|
|
29
|
-
|
|
30
|
-
static set(id: string, tiff: CogTiff): void {
|
|
31
|
-
TiffCache.cacheA.set(id, tiff);
|
|
32
|
-
TiffCache.check();
|
|
33
|
-
}
|
|
34
|
-
|
|
35
|
-
/** Validate the size of the cache has not exploded */
|
|
36
|
-
static check(): void {
|
|
37
|
-
if (TiffCache.MaxCacheSizeBytes <= 0) return;
|
|
38
|
-
if (TiffCache.currentSize <= TiffCache.MaxCacheSizeBytes) return;
|
|
39
|
-
TiffCache.cacheB = TiffCache.cacheA;
|
|
40
|
-
TiffCache.cacheA = new Map();
|
|
41
|
-
}
|
|
42
|
-
|
|
43
|
-
/** Calculate the total number of bytes used by this tiff cache */
|
|
44
|
-
static get currentSize(): number {
|
|
45
|
-
let size = 0;
|
|
46
|
-
for (const value of TiffCache.cacheA.values()) {
|
|
47
|
-
size += value.source.chunkSize * (value.source as ChunkSourceBase).chunks.size;
|
|
48
|
-
}
|
|
49
|
-
return size;
|
|
50
|
-
}
|
|
51
|
-
}
|
package/src/tile.set.cache.ts
DELETED
|
@@ -1,111 +0,0 @@
|
|
|
1
|
-
import { TileSetNameParser, TileSetType } from '@basemaps/config';
|
|
2
|
-
import { TileMatrixSet, TileMatrixSets } from '@basemaps/geo';
|
|
3
|
-
import { Config } from '@basemaps/shared';
|
|
4
|
-
import { TileSet } from './tile.set.js';
|
|
5
|
-
import { TileSetRaster } from './tile.set.raster.js';
|
|
6
|
-
import { TileSetVector } from './tile.set.vector.js';
|
|
7
|
-
|
|
8
|
-
export class TileSetCache {
|
|
9
|
-
/** Duration to cache tile sets for */
|
|
10
|
-
CacheTime = 30_000;
|
|
11
|
-
|
|
12
|
-
/** Cache the fetch requests */
|
|
13
|
-
cache: Map<string, { time: number; value: Promise<TileSet | null> }> = new Map();
|
|
14
|
-
/** Cache initialized tile sets */
|
|
15
|
-
tileSets: Map<string, TileSet> = new Map();
|
|
16
|
-
|
|
17
|
-
id(tileSet: TileSet): string;
|
|
18
|
-
id(name: string, tileMatrix: TileMatrixSet): string;
|
|
19
|
-
id(name: string | TileSet, tileMatrix?: TileMatrixSet): string {
|
|
20
|
-
if (typeof name === 'string') {
|
|
21
|
-
const nameComp = TileSetNameParser.parse(name);
|
|
22
|
-
return `${TileSetNameParser.componentsToName(nameComp)}_${tileMatrix?.identifier}`;
|
|
23
|
-
}
|
|
24
|
-
|
|
25
|
-
return `${name.fullName}_${name.tileMatrix.identifier}`;
|
|
26
|
-
}
|
|
27
|
-
|
|
28
|
-
add(tileSet: TileSet, expiresAt = Date.now() + this.CacheTime): void {
|
|
29
|
-
const id = this.id(tileSet);
|
|
30
|
-
if (this.cache.has(id)) throw new Error('Trying to add duplicate tile set:' + id);
|
|
31
|
-
this.cache.set(id, { time: expiresAt, value: Promise.resolve(tileSet) });
|
|
32
|
-
}
|
|
33
|
-
|
|
34
|
-
get(name: string, tileMatrix: TileMatrixSet): Promise<TileSet | null> {
|
|
35
|
-
const tsId = this.id(name, tileMatrix);
|
|
36
|
-
let existing = this.cache.get(tsId);
|
|
37
|
-
// Validate the data is current every ~30 seconds
|
|
38
|
-
if (existing == null || Date.now() - existing.time > 0) {
|
|
39
|
-
const value = this.loadTileSet(name, tileMatrix);
|
|
40
|
-
existing = { time: Date.now(), value };
|
|
41
|
-
this.cache.set(tsId, existing);
|
|
42
|
-
}
|
|
43
|
-
return existing.value;
|
|
44
|
-
}
|
|
45
|
-
|
|
46
|
-
async loadTileSet(name: string, tileMatrix: TileMatrixSet): Promise<TileSet | null> {
|
|
47
|
-
const nameComp = TileSetNameParser.parse(name);
|
|
48
|
-
const tileSetId = this.id(name, tileMatrix);
|
|
49
|
-
|
|
50
|
-
if (nameComp.layer != null) {
|
|
51
|
-
const parentName = TileSetNameParser.componentsToName({ ...nameComp, layer: undefined });
|
|
52
|
-
const parent = await this.get(parentName, tileMatrix);
|
|
53
|
-
if (parent == null || parent.type === TileSetType.Vector) return null;
|
|
54
|
-
return parent.child(nameComp.layer);
|
|
55
|
-
}
|
|
56
|
-
|
|
57
|
-
const dbId = Config.TileSet.id(name);
|
|
58
|
-
const tileSet = await Config.TileSet.get(dbId);
|
|
59
|
-
if (tileSet == null) {
|
|
60
|
-
this.cache.delete(tileSetId);
|
|
61
|
-
return null;
|
|
62
|
-
}
|
|
63
|
-
|
|
64
|
-
// If we already have a copy and it hasn't been modified just return it
|
|
65
|
-
const existing = this.tileSets.get(tileSetId);
|
|
66
|
-
if (existing != null && existing?.tileSet.updatedAt === tileSet.updatedAt) {
|
|
67
|
-
return existing;
|
|
68
|
-
}
|
|
69
|
-
|
|
70
|
-
if (Config.isTileSetRaster(tileSet)) {
|
|
71
|
-
const ts = new TileSetRaster(name, tileMatrix);
|
|
72
|
-
await ts.init(tileSet);
|
|
73
|
-
this.tileSets.set(tileSetId, ts);
|
|
74
|
-
return ts;
|
|
75
|
-
}
|
|
76
|
-
|
|
77
|
-
const ts = new TileSetVector(name, tileMatrix);
|
|
78
|
-
await ts.init(tileSet);
|
|
79
|
-
this.tileSets.set(tileSetId, ts);
|
|
80
|
-
return ts;
|
|
81
|
-
}
|
|
82
|
-
|
|
83
|
-
async getAll(name: string, tileMatrix?: TileMatrixSet | null): Promise<TileSet[]> {
|
|
84
|
-
const nameComp = TileSetNameParser.parse(name);
|
|
85
|
-
const tileMatrices = tileMatrix == null ? Array.from(TileMatrixSets.Defaults.values()) : [tileMatrix];
|
|
86
|
-
|
|
87
|
-
const promises: Promise<TileSet | null>[] = [];
|
|
88
|
-
for (const tileMatrix of tileMatrices) promises.push(this.get(name, tileMatrix));
|
|
89
|
-
const tileMatrixSets = await Promise.all(promises);
|
|
90
|
-
|
|
91
|
-
const tileSets: TileSetRaster[] = [];
|
|
92
|
-
for (const parent of tileMatrixSets) {
|
|
93
|
-
if (parent == null) continue;
|
|
94
|
-
if (parent.type === TileSetType.Vector) continue;
|
|
95
|
-
|
|
96
|
-
tileSets.push(parent);
|
|
97
|
-
if (nameComp.layer != null) {
|
|
98
|
-
parent.components.name = nameComp.name;
|
|
99
|
-
} else if (parent.imagery != null && parent.imagery.size > 1) {
|
|
100
|
-
for (const imageId of parent.imagery.keys()) {
|
|
101
|
-
const childImg = parent.child(imageId);
|
|
102
|
-
if (childImg == null) continue;
|
|
103
|
-
tileSets.push(childImg);
|
|
104
|
-
}
|
|
105
|
-
}
|
|
106
|
-
}
|
|
107
|
-
return tileSets.sort((a, b) => a.title.localeCompare(b.title));
|
|
108
|
-
}
|
|
109
|
-
}
|
|
110
|
-
|
|
111
|
-
export const TileSets = new TileSetCache();
|
package/src/tile.set.raster.ts
DELETED
|
@@ -1,228 +0,0 @@
|
|
|
1
|
-
import {
|
|
2
|
-
ConfigImagery,
|
|
3
|
-
ConfigLayer,
|
|
4
|
-
ConfigTileSetRaster,
|
|
5
|
-
TileSetNameComponents,
|
|
6
|
-
TileSetNameParser,
|
|
7
|
-
TileSetType,
|
|
8
|
-
} from '@basemaps/config';
|
|
9
|
-
import { Bounds, Epsg, ImageFormat, Tile, TileMatrixSet, TileMatrixSets, VectorFormat } from '@basemaps/geo';
|
|
10
|
-
import { Config, Env, fsa, LogType, TileDataXyz, titleizeImageryName } from '@basemaps/shared';
|
|
11
|
-
import { Tiler } from '@basemaps/tiler';
|
|
12
|
-
import { TileMakerSharp } from '@basemaps/tiler-sharp';
|
|
13
|
-
import { CogTiff } from '@cogeotiff/core';
|
|
14
|
-
import { HttpHeader, LambdaHttpRequest, LambdaHttpResponse } from '@linzjs/lambda';
|
|
15
|
-
import { Metrics } from '@linzjs/metrics';
|
|
16
|
-
import pLimit from 'p-limit';
|
|
17
|
-
import { NotFound, NotModified } from './routes/response.js';
|
|
18
|
-
import { TileEtag } from './routes/tile.etag.js';
|
|
19
|
-
import { St } from './source.tracer.js';
|
|
20
|
-
import { TiffCache } from './tiff.cache.js';
|
|
21
|
-
import { TileSets } from './tile.set.cache.js';
|
|
22
|
-
|
|
23
|
-
const LoadingQueue = pLimit(Env.getNumber(Env.TiffConcurrency, 25));
|
|
24
|
-
|
|
25
|
-
export const TileComposer = new TileMakerSharp(256);
|
|
26
|
-
|
|
27
|
-
export interface TileSetResponse {
|
|
28
|
-
buffer: Buffer;
|
|
29
|
-
metrics: Metrics;
|
|
30
|
-
layersUsed: number;
|
|
31
|
-
layersTotal: number;
|
|
32
|
-
contentType: string;
|
|
33
|
-
}
|
|
34
|
-
|
|
35
|
-
const DefaultResizeKernel = { in: 'lanczos3', out: 'lanczos3' } as const;
|
|
36
|
-
const DefaultBackground = { r: 0, g: 0, b: 0, alpha: 0 };
|
|
37
|
-
|
|
38
|
-
export function getTiffName(name: string): string {
|
|
39
|
-
if (name.endsWith('.tif') || name.endsWith('.tiff')) return name;
|
|
40
|
-
return `${name}.tiff`;
|
|
41
|
-
}
|
|
42
|
-
|
|
43
|
-
export class TileSetRaster {
|
|
44
|
-
type: TileSetType.Raster = TileSetType.Raster;
|
|
45
|
-
|
|
46
|
-
tileMatrix: TileMatrixSet;
|
|
47
|
-
tiler: Tiler;
|
|
48
|
-
imagery: Map<string, ConfigImagery>;
|
|
49
|
-
extentOverride: Bounds;
|
|
50
|
-
|
|
51
|
-
components: TileSetNameComponents;
|
|
52
|
-
tileSet: ConfigTileSetRaster;
|
|
53
|
-
|
|
54
|
-
constructor(name: string, tileMatrix: TileMatrixSet) {
|
|
55
|
-
this.components = TileSetNameParser.parse(name);
|
|
56
|
-
this.tileMatrix = tileMatrix;
|
|
57
|
-
this.tiler = new Tiler(this.tileMatrix);
|
|
58
|
-
}
|
|
59
|
-
|
|
60
|
-
get id(): string {
|
|
61
|
-
return TileSets.id(this.fullName, this.tileMatrix);
|
|
62
|
-
}
|
|
63
|
-
|
|
64
|
-
get fullName(): string {
|
|
65
|
-
return TileSetNameParser.componentsToName(this.components);
|
|
66
|
-
}
|
|
67
|
-
|
|
68
|
-
get title(): string {
|
|
69
|
-
return this.tileSet?.title ?? this.components.name;
|
|
70
|
-
}
|
|
71
|
-
|
|
72
|
-
get description(): string {
|
|
73
|
-
return this.tileSet?.description ?? '';
|
|
74
|
-
}
|
|
75
|
-
|
|
76
|
-
get extent(): Bounds {
|
|
77
|
-
return this.extentOverride ?? this.tileMatrix.extent;
|
|
78
|
-
}
|
|
79
|
-
|
|
80
|
-
/** Preferred default imagery format */
|
|
81
|
-
get format(): ImageFormat {
|
|
82
|
-
return this.tileSet.format ?? ImageFormat.Webp;
|
|
83
|
-
}
|
|
84
|
-
|
|
85
|
-
async init(record: ConfigTileSetRaster): Promise<void> {
|
|
86
|
-
this.tileSet = record;
|
|
87
|
-
this.imagery = await Config.getAllImagery(this.tileSet.layers, this.tileMatrix.projection);
|
|
88
|
-
}
|
|
89
|
-
|
|
90
|
-
async initTiffs(tile: Tile, log: LogType): Promise<CogTiff[]> {
|
|
91
|
-
const tiffs = this.getTiffsForTile(tile, log);
|
|
92
|
-
let failed = false;
|
|
93
|
-
// Remove any tiffs that failed to load
|
|
94
|
-
const promises = tiffs.map((c) => {
|
|
95
|
-
return LoadingQueue(async () => {
|
|
96
|
-
try {
|
|
97
|
-
await c.init();
|
|
98
|
-
} catch (error) {
|
|
99
|
-
log.warn({ error, tiff: c.source.uri }, 'TiffLoadFailed');
|
|
100
|
-
failed = true;
|
|
101
|
-
}
|
|
102
|
-
});
|
|
103
|
-
});
|
|
104
|
-
await Promise.all(promises);
|
|
105
|
-
if (failed) return tiffs.filter((f) => f.images.length > 0);
|
|
106
|
-
return tiffs;
|
|
107
|
-
}
|
|
108
|
-
|
|
109
|
-
public async tile(req: LambdaHttpRequest, xyz: TileDataXyz): Promise<LambdaHttpResponse> {
|
|
110
|
-
if (xyz.ext === VectorFormat.MapboxVectorTiles) return NotFound;
|
|
111
|
-
const tiffs = await this.initTiffs(xyz, req.log);
|
|
112
|
-
const layers = await this.tiler.tile(tiffs, xyz.x, xyz.y, xyz.z);
|
|
113
|
-
|
|
114
|
-
// Generate a unique hash given the full URI, the layers used and a renderId
|
|
115
|
-
const cacheKey = TileEtag.generate(layers, xyz);
|
|
116
|
-
req.set('layers', layers.length);
|
|
117
|
-
if (TileEtag.isNotModified(req, cacheKey)) return NotModified;
|
|
118
|
-
|
|
119
|
-
const res = await TileComposer.compose({
|
|
120
|
-
layers,
|
|
121
|
-
format: xyz.ext,
|
|
122
|
-
background: this.tileSet.background ?? DefaultBackground,
|
|
123
|
-
resizeKernel: this.tileSet.resizeKernel ?? DefaultResizeKernel,
|
|
124
|
-
metrics: req.timer,
|
|
125
|
-
});
|
|
126
|
-
|
|
127
|
-
req.set('layersUsed', res.layers);
|
|
128
|
-
req.set('bytes', res.buffer.byteLength);
|
|
129
|
-
|
|
130
|
-
const response = new LambdaHttpResponse(200, 'ok');
|
|
131
|
-
response.header(HttpHeader.ETag, cacheKey);
|
|
132
|
-
response.header(HttpHeader.CacheControl, 'public, max-age=604800');
|
|
133
|
-
response.buffer(res.buffer, 'image/' + xyz.ext);
|
|
134
|
-
return response;
|
|
135
|
-
}
|
|
136
|
-
|
|
137
|
-
/**
|
|
138
|
-
* Get a list of tiffs in the rendering order that is needed to render the tile
|
|
139
|
-
* @param tms tile matrix set to describe the tiling scheme
|
|
140
|
-
* @param tile tile to render
|
|
141
|
-
*/
|
|
142
|
-
public getTiffsForTile(tile: Tile, log?: LogType): CogTiff[] {
|
|
143
|
-
const output: CogTiff[] = [];
|
|
144
|
-
const tileBounds = this.tileMatrix.tileToSourceBounds(tile);
|
|
145
|
-
|
|
146
|
-
// All zoom level config is stored as Google zoom levels
|
|
147
|
-
const filterZoom = TileMatrixSet.convertZoomLevel(tile.z, this.tileMatrix, TileMatrixSets.get(Epsg.Google));
|
|
148
|
-
for (const layer of this.tileSet.layers) {
|
|
149
|
-
if (layer.maxZoom != null && filterZoom > layer.maxZoom) continue;
|
|
150
|
-
if (layer.minZoom != null && filterZoom < layer.minZoom) continue;
|
|
151
|
-
|
|
152
|
-
const imgId = layer[this.tileMatrix.projection.code];
|
|
153
|
-
if (imgId == null) {
|
|
154
|
-
log?.warn({ layer: layer.name, projection: this.tileMatrix.projection.code }, 'Failed to lookup imagery');
|
|
155
|
-
continue;
|
|
156
|
-
}
|
|
157
|
-
|
|
158
|
-
const imagery = this.imagery.get(imgId);
|
|
159
|
-
if (imagery == null) {
|
|
160
|
-
log?.warn(
|
|
161
|
-
{ layer: layer.name, projection: this.tileMatrix.projection.code, imgId },
|
|
162
|
-
'Failed to lookup imagery',
|
|
163
|
-
);
|
|
164
|
-
continue;
|
|
165
|
-
}
|
|
166
|
-
if (!tileBounds.intersects(Bounds.fromJson(imagery.bounds))) continue;
|
|
167
|
-
|
|
168
|
-
for (const tiff of this.getCogsForTile(imagery, tileBounds)) output.push(tiff);
|
|
169
|
-
}
|
|
170
|
-
return output;
|
|
171
|
-
}
|
|
172
|
-
|
|
173
|
-
private getCogsForTile(record: ConfigImagery, tileBounds: Bounds): CogTiff[] {
|
|
174
|
-
const output: CogTiff[] = [];
|
|
175
|
-
for (const c of record.files) {
|
|
176
|
-
if (!tileBounds.intersects(Bounds.fromJson(c))) continue;
|
|
177
|
-
const tiffPath = fsa.join(record.uri, getTiffName(c.name));
|
|
178
|
-
|
|
179
|
-
let existing = TiffCache.get(tiffPath);
|
|
180
|
-
if (existing == null) {
|
|
181
|
-
const source = fsa.source(tiffPath);
|
|
182
|
-
if (source == null) {
|
|
183
|
-
throw new Error(`Failed to create CogSource from ${tiffPath}`);
|
|
184
|
-
}
|
|
185
|
-
|
|
186
|
-
St.trace(source);
|
|
187
|
-
existing = new CogTiff(source);
|
|
188
|
-
TiffCache.set(tiffPath, existing);
|
|
189
|
-
}
|
|
190
|
-
|
|
191
|
-
output.push(existing);
|
|
192
|
-
}
|
|
193
|
-
|
|
194
|
-
return output;
|
|
195
|
-
}
|
|
196
|
-
|
|
197
|
-
/** Look up imagery by imageryId or by image name */
|
|
198
|
-
findImagery(imgId: string): ConfigImagery | null {
|
|
199
|
-
const existing = this.imagery.get(imgId);
|
|
200
|
-
if (existing != null) return existing;
|
|
201
|
-
for (const img of this.imagery.values()) {
|
|
202
|
-
if (img.name === imgId) return img;
|
|
203
|
-
}
|
|
204
|
-
return null;
|
|
205
|
-
}
|
|
206
|
-
|
|
207
|
-
child(imgId: string): TileSetRaster | null {
|
|
208
|
-
const image = this.findImagery(imgId);
|
|
209
|
-
if (image == null) return null;
|
|
210
|
-
const childName = TileSetNameParser.componentsToName({ ...this.components, layer: image.name });
|
|
211
|
-
const child = new TileSetRaster(childName, this.tileMatrix);
|
|
212
|
-
// use parent data as prototype for child;
|
|
213
|
-
child.tileSet = { ...this.tileSet };
|
|
214
|
-
child.tileSet.background = undefined;
|
|
215
|
-
const title = this.tileSet?.title ?? this.tileSet?.name;
|
|
216
|
-
child.tileSet.title = `${title} ${titleizeImageryName(image.name)}`;
|
|
217
|
-
child.extentOverride = Bounds.fromJson(image.bounds);
|
|
218
|
-
|
|
219
|
-
const layer: ConfigLayer = { name: image.name, minZoom: 0, maxZoom: 100 };
|
|
220
|
-
layer[this.tileMatrix.projection.code] = image.id;
|
|
221
|
-
|
|
222
|
-
child.tileSet.layers = [layer];
|
|
223
|
-
child.imagery = new Map();
|
|
224
|
-
child.imagery.set(image.id, image);
|
|
225
|
-
|
|
226
|
-
return child;
|
|
227
|
-
}
|
|
228
|
-
}
|
package/src/tile.set.ts
DELETED
package/src/tile.set.vector.ts
DELETED
|
@@ -1,79 +0,0 @@
|
|
|
1
|
-
import { ConfigTileSetVector, TileSetNameComponents, TileSetNameParser, TileSetType } from '@basemaps/config';
|
|
2
|
-
import { GoogleTms, TileMatrixSet, VectorFormat } from '@basemaps/geo';
|
|
3
|
-
import { fsa, TileDataXyz } from '@basemaps/shared';
|
|
4
|
-
import { Cotar } from '@cotar/core';
|
|
5
|
-
import { HttpHeader, LambdaHttpRequest, LambdaHttpResponse } from '@linzjs/lambda';
|
|
6
|
-
import { NotFound } from './routes/response.js';
|
|
7
|
-
import { TileSets } from './tile.set.cache.js';
|
|
8
|
-
import { St } from './source.tracer.js';
|
|
9
|
-
|
|
10
|
-
class CotarCache {
|
|
11
|
-
cache = new Map<string, Promise<Cotar | null>>();
|
|
12
|
-
|
|
13
|
-
get(uri: string): Promise<Cotar | null> {
|
|
14
|
-
let cotar = this.cache.get(uri);
|
|
15
|
-
if (cotar == null) {
|
|
16
|
-
const source = fsa.source(uri);
|
|
17
|
-
St.trace(source);
|
|
18
|
-
cotar = Cotar.fromTar(source);
|
|
19
|
-
this.cache.set(uri, cotar);
|
|
20
|
-
}
|
|
21
|
-
return cotar;
|
|
22
|
-
}
|
|
23
|
-
}
|
|
24
|
-
|
|
25
|
-
export const Layers = new CotarCache();
|
|
26
|
-
|
|
27
|
-
export class TileSetVector {
|
|
28
|
-
type: TileSetType.Vector = TileSetType.Vector;
|
|
29
|
-
components: TileSetNameComponents;
|
|
30
|
-
tileMatrix: TileMatrixSet;
|
|
31
|
-
tileSet: ConfigTileSetVector;
|
|
32
|
-
constructor(name: string, tileMatrix: TileMatrixSet) {
|
|
33
|
-
this.components = TileSetNameParser.parse(name);
|
|
34
|
-
this.tileMatrix = tileMatrix;
|
|
35
|
-
}
|
|
36
|
-
|
|
37
|
-
async init(record: ConfigTileSetVector): Promise<void> {
|
|
38
|
-
this.tileSet = record;
|
|
39
|
-
}
|
|
40
|
-
|
|
41
|
-
/** What format does tile set use */
|
|
42
|
-
get format(): VectorFormat {
|
|
43
|
-
return VectorFormat.MapboxVectorTiles;
|
|
44
|
-
}
|
|
45
|
-
|
|
46
|
-
get id(): string {
|
|
47
|
-
return TileSets.id(this.fullName, this.tileMatrix);
|
|
48
|
-
}
|
|
49
|
-
|
|
50
|
-
get fullName(): string {
|
|
51
|
-
return TileSetNameParser.componentsToName(this.components);
|
|
52
|
-
}
|
|
53
|
-
|
|
54
|
-
async tile(req: LambdaHttpRequest, xyz: TileDataXyz): Promise<LambdaHttpResponse> {
|
|
55
|
-
if (xyz.ext !== VectorFormat.MapboxVectorTiles) return NotFound;
|
|
56
|
-
if (xyz.tileMatrix.identifier !== GoogleTms.identifier) return NotFound;
|
|
57
|
-
if (this.tileSet.layers.length > 1) return new LambdaHttpResponse(500, 'Too many layers in tileset');
|
|
58
|
-
const [layer] = this.tileSet.layers;
|
|
59
|
-
if (layer[3857] == null) return new LambdaHttpResponse(500, 'Layer url not found from tileset Config');
|
|
60
|
-
|
|
61
|
-
req.timer.start('cotar:load');
|
|
62
|
-
const cotar = await Layers.get(layer[3857]);
|
|
63
|
-
if (cotar == null) return new LambdaHttpResponse(500, 'Failed to load VectorTiles');
|
|
64
|
-
req.timer.end('cotar:load');
|
|
65
|
-
|
|
66
|
-
// Flip Y coordinate because MBTiles files are TMS.
|
|
67
|
-
const y = (1 << xyz.z) - 1 - xyz.y;
|
|
68
|
-
|
|
69
|
-
req.timer.start('cotar:tile');
|
|
70
|
-
const tile = await cotar.get(`tiles/${xyz.z}/${xyz.x}/${y}.pbf.gz`);
|
|
71
|
-
if (tile == null) return NotFound;
|
|
72
|
-
req.timer.end('cotar:tile');
|
|
73
|
-
|
|
74
|
-
const response = new LambdaHttpResponse(200, 'Ok');
|
|
75
|
-
response.buffer(Buffer.from(tile), 'application/x-protobuf');
|
|
76
|
-
response.header(HttpHeader.ContentEncoding, 'gzip');
|
|
77
|
-
return response;
|
|
78
|
-
}
|
|
79
|
-
}
|
package/src/validate.ts
DELETED
|
@@ -1,32 +0,0 @@
|
|
|
1
|
-
import { Projection, TileDataXyz } from '@basemaps/shared';
|
|
2
|
-
import { LambdaHttpRequest, LambdaHttpResponse } from '@linzjs/lambda';
|
|
3
|
-
|
|
4
|
-
export const ValidateTilePath = {
|
|
5
|
-
/**
|
|
6
|
-
* Validate that the tile request is somewhat valid
|
|
7
|
-
* - Valid projection
|
|
8
|
-
* - Valid range
|
|
9
|
-
*
|
|
10
|
-
* @throws LambdaHttpResponse for tile requests that are not valid
|
|
11
|
-
*
|
|
12
|
-
* @param req request to validate
|
|
13
|
-
* @param xyzData
|
|
14
|
-
*/
|
|
15
|
-
validate(req: LambdaHttpRequest, xyzData: TileDataXyz): void {
|
|
16
|
-
const { tileMatrix, x, y, z, ext } = xyzData;
|
|
17
|
-
req.set('xyz', { x, y, z });
|
|
18
|
-
req.set('projection', tileMatrix.projection.code);
|
|
19
|
-
req.set('tileMatrix', tileMatrix.identifier);
|
|
20
|
-
req.set('extension', ext);
|
|
21
|
-
req.set('tileSet', xyzData.name);
|
|
22
|
-
|
|
23
|
-
if (z > tileMatrix.maxZoom || z < 0) throw new LambdaHttpResponse(404, `Zoom not found: ${z}`);
|
|
24
|
-
|
|
25
|
-
const zoom = tileMatrix.zooms[z];
|
|
26
|
-
if (x < 0 || x > zoom.matrixWidth) throw new LambdaHttpResponse(404, `X not found: ${x}`);
|
|
27
|
-
if (y < 0 || y > zoom.matrixHeight) throw new LambdaHttpResponse(404, `Y not found: ${y}`);
|
|
28
|
-
|
|
29
|
-
const latLon = Projection.tileCenterToLatLon(tileMatrix, xyzData);
|
|
30
|
-
req.set('location', latLon);
|
|
31
|
-
},
|
|
32
|
-
};
|