chiitiler 1.22.1 → 1.23.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/README.md +1 -0
- package/dist/render/index.d.ts +4 -4
- package/dist/render/pool.js +7 -2
- package/dist/source/fs.d.ts +1 -1
- package/dist/source/fs.js +23 -13
- package/dist/source/gcs.js +6 -3
- package/dist/source/http.js +23 -14
- package/dist/source/pmtiles.js +4 -4
- package/dist/source/s3.js +7 -3
- package/package.json +2 -2
package/README.md
CHANGED
|
@@ -60,6 +60,7 @@ You're done. That same endpoint works as an XYZ tile source for Leaflet, MapLibr
|
|
|
60
60
|
- **[PLATEAU VIEW](https://plateauview.mlit.go.jp/)** — Cesium.js imagery via `/tiles`
|
|
61
61
|
- **[qgis-amazonlocationservice-plugin](https://github.com/dayjournal/qgis-amazonlocationservice-plugin)** — QGIS integration
|
|
62
62
|
- **[Allmaps Latest](https://bsky.app/profile/latest.allmaps.org)** — Bluesky bot
|
|
63
|
+
- **[Kumoy](https://www.kumoy.io/)** - used for thumbnail image of designed maps
|
|
63
64
|
|
|
64
65
|
## HTTP API
|
|
65
66
|
|
package/dist/render/index.d.ts
CHANGED
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import
|
|
1
|
+
import { type Sharp } from 'sharp';
|
|
2
2
|
import type { StyleSpecification } from '@maplibre/maplibre-gl-style-spec';
|
|
3
3
|
import type { Cache } from '../cache/index.js';
|
|
4
4
|
type GetRenderedTileOptions = {
|
|
@@ -13,7 +13,7 @@ type GetRenderedTileOptions = {
|
|
|
13
13
|
quality: number;
|
|
14
14
|
};
|
|
15
15
|
type SupportedFormat = 'png' | 'jpeg' | 'jpg' | 'webp';
|
|
16
|
-
declare function getRenderedTile({ stylejson, z, x, y, tileSize, cache, margin, ext, quality, }: GetRenderedTileOptions): Promise<
|
|
16
|
+
declare function getRenderedTile({ stylejson, z, x, y, tileSize, cache, margin, ext, quality, }: GetRenderedTileOptions): Promise<Sharp>;
|
|
17
17
|
type GetRenderedClipOptions = {
|
|
18
18
|
stylejson: string | StyleSpecification;
|
|
19
19
|
bbox: [number, number, number, number];
|
|
@@ -22,7 +22,7 @@ type GetRenderedClipOptions = {
|
|
|
22
22
|
ext: SupportedFormat;
|
|
23
23
|
quality: number;
|
|
24
24
|
};
|
|
25
|
-
declare function getRenderedClip({ stylejson, bbox, size, cache, ext, quality, }: GetRenderedClipOptions): Promise<
|
|
25
|
+
declare function getRenderedClip({ stylejson, bbox, size, cache, ext, quality, }: GetRenderedClipOptions): Promise<Sharp>;
|
|
26
26
|
type GetRenderedCameraOptions = {
|
|
27
27
|
stylejson: string | StyleSpecification;
|
|
28
28
|
cache: Cache;
|
|
@@ -35,5 +35,5 @@ type GetRenderedCameraOptions = {
|
|
|
35
35
|
height: number;
|
|
36
36
|
width: number;
|
|
37
37
|
};
|
|
38
|
-
declare function getRenderedCamera(options: GetRenderedCameraOptions): Promise<
|
|
38
|
+
declare function getRenderedCamera(options: GetRenderedCameraOptions): Promise<Sharp>;
|
|
39
39
|
export { getRenderedTile, getRenderedClip, getRenderedCamera, type GetRenderedClipOptions, type GetRenderedTileOptions, type GetRenderedCameraOptions, type SupportedFormat, };
|
package/dist/render/pool.js
CHANGED
|
@@ -30,8 +30,13 @@ async function getRenderPool(style, cache, mode) {
|
|
|
30
30
|
callback(undefined, EMPTY_RESPONSE);
|
|
31
31
|
}
|
|
32
32
|
})
|
|
33
|
-
.catch(() => {
|
|
34
|
-
|
|
33
|
+
.catch((err) => {
|
|
34
|
+
// 5xx/ネットワークエラー: 空タイルとして描画すると
|
|
35
|
+
// 欠損タイルがCDN等にキャッシュされうるので、
|
|
36
|
+
// エラーを渡してレンダリング自体を失敗させる
|
|
37
|
+
callback(err instanceof Error
|
|
38
|
+
? err
|
|
39
|
+
: new Error(String(err)));
|
|
35
40
|
});
|
|
36
41
|
},
|
|
37
42
|
ratio: 1,
|
package/dist/source/fs.d.ts
CHANGED
|
@@ -1,2 +1,2 @@
|
|
|
1
|
-
declare function getFilesystemSource(uri: string): Promise<Buffer
|
|
1
|
+
declare function getFilesystemSource(uri: string): Promise<Buffer | null>;
|
|
2
2
|
export { getFilesystemSource };
|
package/dist/source/fs.js
CHANGED
|
@@ -1,15 +1,25 @@
|
|
|
1
|
-
import fs from 'fs';
|
|
2
|
-
function getFilesystemSource(uri) {
|
|
3
|
-
|
|
4
|
-
|
|
5
|
-
|
|
6
|
-
|
|
7
|
-
|
|
8
|
-
|
|
9
|
-
|
|
10
|
-
|
|
11
|
-
|
|
12
|
-
|
|
13
|
-
}
|
|
1
|
+
import fs from 'node:fs/promises';
|
|
2
|
+
async function getFilesystemSource(uri) {
|
|
3
|
+
const path = uri.replace('file://', '');
|
|
4
|
+
const data = await fs.readFile(path).catch(() => null);
|
|
5
|
+
if (data !== null)
|
|
6
|
+
return data;
|
|
7
|
+
// maplibre-gl-native percent-encodes {fontstack} in glyphs URLs
|
|
8
|
+
// (e.g. "Noto Sans Regular" -> "Noto%20Sans%20Regular"),
|
|
9
|
+
// so retry with the percent-decoded path
|
|
10
|
+
let decodedPath;
|
|
11
|
+
try {
|
|
12
|
+
decodedPath = decodeURIComponent(path);
|
|
13
|
+
}
|
|
14
|
+
catch {
|
|
15
|
+
decodedPath = path;
|
|
16
|
+
}
|
|
17
|
+
if (decodedPath !== path) {
|
|
18
|
+
const decodedData = await fs.readFile(decodedPath).catch(() => null);
|
|
19
|
+
if (decodedData !== null)
|
|
20
|
+
return decodedData;
|
|
21
|
+
}
|
|
22
|
+
console.error(`[ERROR]: failed to read ${path}`);
|
|
23
|
+
return null;
|
|
14
24
|
}
|
|
15
25
|
export { getFilesystemSource };
|
package/dist/source/gcs.js
CHANGED
|
@@ -13,9 +13,12 @@ async function getGCSSource(uri) {
|
|
|
13
13
|
return buffer;
|
|
14
14
|
}
|
|
15
15
|
catch (e) {
|
|
16
|
-
|
|
17
|
-
|
|
18
|
-
|
|
16
|
+
// 404: オブジェクトが存在しない。空タイルとして扱わせる
|
|
17
|
+
if (e.code === 404)
|
|
18
|
+
return null;
|
|
19
|
+
// それ以外は有無が不明なのでthrowしてレンダリングを失敗させる
|
|
20
|
+
console.log(e);
|
|
21
|
+
throw e;
|
|
19
22
|
}
|
|
20
23
|
}
|
|
21
24
|
export { getGCSSource };
|
package/dist/source/http.js
CHANGED
|
@@ -8,27 +8,36 @@ async function getHttpSource(uri, cache = noneCache()) {
|
|
|
8
8
|
if (val !== undefined)
|
|
9
9
|
return val; // hit
|
|
10
10
|
// miss
|
|
11
|
+
let res;
|
|
11
12
|
try {
|
|
12
13
|
const userAgent = getUserAgent();
|
|
13
|
-
|
|
14
|
+
res = await fetch(uri, {
|
|
14
15
|
headers: userAgent ? { 'User-Agent': userAgent } : undefined,
|
|
15
16
|
});
|
|
16
|
-
if (!res.ok) {
|
|
17
|
-
console.log(`failed to fetch ${uri}`);
|
|
18
|
-
return null;
|
|
19
|
-
}
|
|
20
|
-
// 204/空ボディはキャッシュ汚染を避けるため書き込まずnullを返す
|
|
21
|
-
if (res.status === 204)
|
|
22
|
-
return null;
|
|
23
|
-
const buf = Buffer.from(await res.arrayBuffer());
|
|
24
|
-
if (buf.length === 0)
|
|
25
|
-
return null;
|
|
26
|
-
cache.set(uri, buf);
|
|
27
|
-
return buf;
|
|
28
17
|
}
|
|
29
18
|
catch (e) {
|
|
30
|
-
|
|
19
|
+
// ネットワークエラー: タイルの有無が不明なまま透明タイルを返すと
|
|
20
|
+
// CDN等に欠損タイルがキャッシュされうるので、throwしてレンダリングを失敗させる
|
|
21
|
+
console.error(`[ERROR] failed to fetch ${uri}: ${e}`);
|
|
22
|
+
throw new Error(`failed to fetch ${uri}: ${e}`);
|
|
23
|
+
}
|
|
24
|
+
if (res.status >= 500) {
|
|
25
|
+
// 5xx: 一時的な障害でタイルの有無は不明。ネットワークエラーと同様に扱う
|
|
26
|
+
console.error(`[ERROR] upstream error ${res.status} for ${uri}`);
|
|
27
|
+
throw new Error(`upstream error ${res.status} for ${uri}`);
|
|
28
|
+
}
|
|
29
|
+
if (!res.ok) {
|
|
30
|
+
// 4xx: タイルが存在しない(404など)。空タイルとして扱わせる
|
|
31
|
+
console.log(`failed to fetch ${uri}`);
|
|
31
32
|
return null;
|
|
32
33
|
}
|
|
34
|
+
// 204/空ボディはキャッシュ汚染を避けるため書き込まずnullを返す
|
|
35
|
+
if (res.status === 204)
|
|
36
|
+
return null;
|
|
37
|
+
const buf = Buffer.from(await res.arrayBuffer());
|
|
38
|
+
if (buf.length === 0)
|
|
39
|
+
return null;
|
|
40
|
+
cache.set(uri, buf);
|
|
41
|
+
return buf;
|
|
33
42
|
}
|
|
34
43
|
export { getHttpSource };
|
package/dist/source/pmtiles.js
CHANGED
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
import * as fs from 'fs';
|
|
2
|
-
import { PMTiles, FetchSource } from 'pmtiles';
|
|
2
|
+
import { PMTiles, FetchSource, ResolvedValueCache, } from 'pmtiles';
|
|
3
3
|
import { GetObjectCommand, } from '@aws-sdk/client-s3';
|
|
4
4
|
import { LRUCache } from 'lru-cache';
|
|
5
5
|
import { getS3Client } from '../s3.js';
|
|
@@ -88,7 +88,7 @@ async function getPmtilesSource(uri, cache = noneCache()) {
|
|
|
88
88
|
if (userAgent)
|
|
89
89
|
headers.set('User-Agent', userAgent);
|
|
90
90
|
const fetchSource = new FetchSource(pmtilesUri, headers);
|
|
91
|
-
pmtiles = new PMTiles(fetchSource);
|
|
91
|
+
pmtiles = new PMTiles(fetchSource, new ResolvedValueCache());
|
|
92
92
|
pmtilesCache.set(pmtilesUri, pmtiles);
|
|
93
93
|
}
|
|
94
94
|
}
|
|
@@ -97,14 +97,14 @@ async function getPmtilesSource(uri, cache = noneCache()) {
|
|
|
97
97
|
const bucket = pmtilesUri.replace('s3://', '').split('/')[0];
|
|
98
98
|
const key = pmtilesUri.replace(`s3://${bucket}/`, '');
|
|
99
99
|
const s3Source = new S3Source(bucket, key);
|
|
100
|
-
pmtiles = new PMTiles(s3Source);
|
|
100
|
+
pmtiles = new PMTiles(s3Source, new ResolvedValueCache());
|
|
101
101
|
pmtilesCache.set(pmtilesUri, pmtiles);
|
|
102
102
|
}
|
|
103
103
|
}
|
|
104
104
|
else {
|
|
105
105
|
if (pmtiles === undefined) {
|
|
106
106
|
const fileSource = new FilesystemSource(pmtilesUri);
|
|
107
|
-
pmtiles = new PMTiles(fileSource);
|
|
107
|
+
pmtiles = new PMTiles(fileSource, new ResolvedValueCache());
|
|
108
108
|
pmtilesCache.set(pmtilesUri, pmtiles);
|
|
109
109
|
}
|
|
110
110
|
}
|
package/dist/source/s3.js
CHANGED
|
@@ -20,9 +20,13 @@ async function getS3Source(uri) {
|
|
|
20
20
|
return buf;
|
|
21
21
|
}
|
|
22
22
|
catch (e) {
|
|
23
|
-
|
|
24
|
-
|
|
25
|
-
|
|
23
|
+
// NoSuchKey: オブジェクトが存在しない。空タイルとして扱わせる
|
|
24
|
+
if (e.name === 'NoSuchKey')
|
|
25
|
+
return null;
|
|
26
|
+
// それ以外(スロットリング・ネットワークエラー等)は有無が不明なので
|
|
27
|
+
// throwしてレンダリングを失敗させる
|
|
28
|
+
console.log(e);
|
|
29
|
+
throw e;
|
|
26
30
|
}
|
|
27
31
|
}
|
|
28
32
|
export { getS3Source };
|
package/package.json
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
{
|
|
2
2
|
"type": "module",
|
|
3
3
|
"name": "chiitiler",
|
|
4
|
-
"version": "1.
|
|
4
|
+
"version": "1.23.0",
|
|
5
5
|
"description": "Tiny map rendering server for MapLibre Style Spec",
|
|
6
6
|
"main": "./dist/index.js",
|
|
7
7
|
"types": "./dist/index.d.ts",
|
|
@@ -50,6 +50,6 @@
|
|
|
50
50
|
"lru-cache": "^11.3.5",
|
|
51
51
|
"maplibre-gl": "^5.23.0",
|
|
52
52
|
"pmtiles": "^4.4.1",
|
|
53
|
-
"sharp": "^0.
|
|
53
|
+
"sharp": "^0.35.3"
|
|
54
54
|
}
|
|
55
55
|
}
|