chiitiler 1.14.2 → 1.16.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 +258 -225
- package/dist/cache/gcs.d.ts +10 -0
- package/dist/cache/gcs.js +66 -0
- package/dist/cache/index.d.ts +2 -1
- package/dist/cache/index.js +2 -1
- package/dist/cli.js +26 -0
- package/dist/gcs.d.ts +7 -0
- package/dist/gcs.js +14 -0
- package/dist/index.d.ts +3 -1
- package/dist/index.js +6 -1
- package/dist/render/index.d.ts +14 -1
- package/dist/render/index.js +29 -2
- package/dist/server/index.d.ts +0 -2
- package/dist/server/index.js +28 -215
- package/dist/server/routes/camera.d.ts +36 -0
- package/dist/server/routes/camera.js +128 -0
- package/dist/server/routes/clip.d.ts +32 -0
- package/dist/server/routes/clip.js +104 -0
- package/dist/server/routes/tiles.d.ts +40 -0
- package/dist/server/routes/tiles.js +113 -0
- package/dist/server/utils.d.ts +7 -0
- package/dist/server/utils.js +28 -0
- package/dist/source/gcs.d.ts +2 -0
- package/dist/source/gcs.js +21 -0
- package/dist/source/index.js +3 -0
- package/dist/source/pmtiles.js +1 -2
- package/package.json +21 -17
package/README.md
CHANGED
|
@@ -1,281 +1,314 @@
|
|
|
1
|
-
# chiitiler
|
|
1
|
+
# chiitiler – Tiny MapLibre Server
|
|
2
2
|
|
|
3
3
|

|
|
4
|
-

|
|
5
|
+

|
|
6
6
|
[](https://codecov.io/gh/Kanahiro/chiitiler)
|
|
7
7
|
|
|
8
|
-

|
|
8
|
+

|
|
9
9
|
|
|
10
|
-
|
|
10
|
+
> Chiitiler is a tiny MapLibre server that renders raster tiles and map cut-outs from any MapLibre Style JSON, with built-in caching backends for source assets and a lightweight debug UI.
|
|
11
11
|
|
|
12
|
-
##
|
|
12
|
+
## Overview
|
|
13
13
|
|
|
14
|
-
|
|
15
|
-
- I want a server accept style.json-url and respond raster tile, inspired by [developmentseed/titiler](https://github.com/developmentseed/titiler)
|
|
14
|
+
Chiitiler accepts remote or local `style.json` definitions and serves raster tiles or bounding-box images on demand. It was inspired by [`maptiler/tileserver-gl`](https://github.com/maptiler/tileserver-gl) and [`developmentseed/titiler`](https://github.com/developmentseed/titiler) but is intentionally minimal, scriptable, and easy to self-host.
|
|
16
15
|
|
|
17
|
-
|
|
16
|
+
### Highlights
|
|
18
17
|
|
|
19
|
-
-
|
|
20
|
-
-
|
|
21
|
-
-
|
|
18
|
+
- Zero-config startup: point Chiitiler at a style URL or POST a style object to receive tiles.
|
|
19
|
+
- Optimized for ephemeral serverless runtimes such as AWS Lambda.
|
|
20
|
+
- Multiple cache adapters (`memory`, `file`, `s3`, `gcs`) to cache shared source assets (MVT tiles, glyphs, sprites) and reduce redundant fetches.
|
|
21
|
+
- Built-in `/debug` and `/editor` pages to preview styles during development.
|
|
22
22
|
|
|
23
|
-
|
|
23
|
+
### In Production
|
|
24
24
|
|
|
25
|
-
|
|
25
|
+
- [MIERUNE/tiles](https://github.com/MIERUNE/tiles) – see the live example [map](https://mierune.github.io/tiles/color.html#11.62/43.064/141.3375).
|
|
26
|
+
- [dayjournal/qgis-amazonlocationservice-plugin](https://github.com/dayjournal/qgis-amazonlocationservice-plugin) – powering QGIS integrations.
|
|
27
|
+
- [PLATEAU VIEW](https://plateauview.mlit.go.jp/) – serving Cesium.js imagery through the `/tiles` endpoint.
|
|
28
|
+
- [Allmaps Latest (Bluesky)](https://bsky.app/profile/latest.allmaps.org).
|
|
26
29
|
|
|
27
|
-
|
|
30
|
+
## Supported Data Protocols
|
|
28
31
|
|
|
29
|
-
|
|
30
|
-
http://localhost:3000/tiles/0/0/0.png?url=https://tile.openstreetmap.jp/styles/osm-bright/style.json
|
|
31
|
-
http://localhost:3000/tiles/0/0/0.webp?margin=100&url=https://tile.openstreetmap.jp/styles/maptiler-toner-en/style.json
|
|
32
|
-
http://localhost:3000/tiles/1/1/1.jpg?tileSize=256&quality=80&url=https://tile.openstreetmap.jp/styles/osm-bright/style.json
|
|
33
|
-
```
|
|
32
|
+
Chiitiler can load tiles, sprites, glyphs, and assets via:
|
|
34
33
|
|
|
35
|
-
|
|
34
|
+
- `http://` and `https://`
|
|
35
|
+
- `s3://` (AWS S3 or compatible endpoints)
|
|
36
|
+
- `gs://` (Google Cloud Storage)
|
|
37
|
+
- `file://`
|
|
38
|
+
- `mbtiles://`
|
|
39
|
+
- `pmtiles://`
|
|
40
|
+
- `cog://` (Cloud Optimized GeoTIFF, CRS must be `EPSG:3857`)
|
|
36
41
|
|
|
37
|
-
|
|
42
|
+
## Project Layout
|
|
38
43
|
|
|
39
|
-
```
|
|
40
|
-
|
|
41
|
-
|
|
42
|
-
#
|
|
43
|
-
|
|
44
|
-
#
|
|
45
|
-
|
|
44
|
+
```
|
|
45
|
+
src/
|
|
46
|
+
main.ts # CLI entry point and cluster bootstrap
|
|
47
|
+
cli.ts # Commander-based CLI definition
|
|
48
|
+
server/ # Hono HTTP server & debug UI
|
|
49
|
+
render/ # Rasterization and Sharp pipelines
|
|
50
|
+
cache/ # Cache adapters (none/memory/file/s3/gcs)
|
|
51
|
+
source/ # Helpers for reading external sources
|
|
52
|
+
tests/ # Vitest integration & benchmark suites
|
|
53
|
+
localdata/ # Sample styles and tiles for demos
|
|
54
|
+
cdk/ # AWS CDK deployment project
|
|
46
55
|
```
|
|
47
56
|
|
|
48
|
-
|
|
57
|
+
## Quick Start
|
|
49
58
|
|
|
50
|
-
|
|
59
|
+
### Requirements
|
|
51
60
|
|
|
52
|
-
|
|
61
|
+
- Node.js 20.10.0 or newer (`.node-version` is provided).
|
|
62
|
+
- System dependencies to support `sharp` (see [Dockerfile](./Dockerfile) for reference).
|
|
53
63
|
|
|
54
|
-
|
|
55
|
-
graph LR
|
|
56
|
-
subgraph sources
|
|
57
|
-
direction LR
|
|
58
|
-
A[style.json]
|
|
59
|
-
z/x/y.pbf
|
|
60
|
-
z/x/y.png/webp/jpg
|
|
61
|
-
sprite
|
|
62
|
-
glyphs
|
|
63
|
-
end
|
|
64
|
+
### Run From Source
|
|
64
65
|
|
|
65
|
-
|
|
66
|
-
|
|
67
|
-
|
|
68
|
-
|
|
69
|
-
|
|
66
|
+
```bash
|
|
67
|
+
git clone https://github.com/Kanahiro/chiitiler.git
|
|
68
|
+
cd chiitiler
|
|
69
|
+
npm install
|
|
70
|
+
npx tsx src/main.ts tile-server --port 3000 --debug
|
|
71
|
+
```
|
|
70
72
|
|
|
71
|
-
|
|
73
|
+
When the server starts you can request a tile:
|
|
72
74
|
|
|
73
|
-
|
|
75
|
+
```
|
|
76
|
+
http://localhost:3000/tiles/0/0/0.png?url=https://tile.openstreetmap.jp/styles/osm-bright/style.json
|
|
74
77
|
```
|
|
75
78
|
|
|
76
|
-
|
|
79
|
+
### Docker Image
|
|
77
80
|
|
|
78
|
-
|
|
81
|
+
```bash
|
|
82
|
+
docker pull ghcr.io/kanahiro/chiitiler:latest
|
|
83
|
+
docker run --rm -p 3000:3000 \
|
|
84
|
+
-e CHIITILER_CACHE_METHOD=memory \
|
|
85
|
+
-e CHIITILER_CACHE_TTL_SEC=600 \
|
|
86
|
+
ghcr.io/kanahiro/chiitiler:latest
|
|
87
|
+
```
|
|
79
88
|
|
|
80
|
-
|
|
81
|
-
docker pull ghcr.io/kanahiro/chiitiler
|
|
82
|
-
docker run -p 3000:3000 ghcr.io/kanahiro/chiitiler # -> tile-server
|
|
89
|
+
The container entrypoint wraps `node /app/build/main.cjs tile-server`, so command-line options can be provided via env vars or by overriding the container CMD explicitly.
|
|
83
90
|
|
|
84
|
-
|
|
85
|
-
|
|
86
|
-
-
|
|
87
|
-
-e CHIITILER_S3CACHE_BUCKET=bucketname \
|
|
88
|
-
-e CHIITILER_S3_REGION=ap-northeast-1 \
|
|
89
|
-
ghcr.io/kanahiro/chiitiler
|
|
90
|
-
```
|
|
91
|
+
#### docker-compose (local S3 + GCS emulation)
|
|
92
|
+
|
|
93
|
+
The included [`docker-compose.yml`](./docker-compose.yml) spins up MinIO and `fake-gcs-server`:
|
|
91
94
|
|
|
92
|
-
|
|
93
|
-
|
|
94
|
-
you can pass server options via environment variables
|
|
95
|
-
|
|
96
|
-
| env var | default | description |
|
|
97
|
-
| ---------------------------------- | -------- | ---------------------------------------------- |
|
|
98
|
-
| CHIITILER_PORT | 3000 | port number |
|
|
99
|
-
| CHIITILER_PROCESSES | 1 | num of chiitiler processes. 0 means all-CPUs |
|
|
100
|
-
| CHIITILER_DEBUG | false | debug mode |
|
|
101
|
-
| CHIITILER_STREAM_MODE | false | stream mode |
|
|
102
|
-
| CHIITILER_CACHE_METHOD | none | cache method, `none`, `memory`, `file` or `s3` |
|
|
103
|
-
| CHIITILER_CACHE_TTL_SEC | 3600 | cache ttl, effect to `memory` and `file` |
|
|
104
|
-
| CHIITILER_MEMORYCACHE_MAXITEMCOUNT | 1000 | max items for memorycache |
|
|
105
|
-
| CHIITILER_FILECACHE_DIR | .cache | filecache directory |
|
|
106
|
-
| CHIITILER_S3CACHE_BUCKET | | s3cache bucket name |
|
|
107
|
-
| CHIITILER_S3_REGION | us-east1 | s3 bucket region for caching/fetching |
|
|
108
|
-
| CHIITILER_S3_ENDPOINT | | s3 endpoint for caching/fetching |
|
|
109
|
-
| CHIITILER_S3_FORCE_PATH_STYLE | false | force path style for s3, needed for minio |
|
|
110
|
-
|
|
111
|
-
### debug page
|
|
112
|
-
|
|
113
|
-
- in debug mode, you can access:
|
|
114
|
-
- debug page: <http://localhost:3000/debug>
|
|
115
|
-
- You can pass style.json url: <http://localhost:3000/debug?url=https://tile.openstreetmap.jp/styles/osm-bright/style.json>
|
|
116
|
-
- editor page: <http://localhost:3000/editor>
|
|
117
|
-
|
|
118
|
-
## supported protocols in style.json
|
|
119
|
-
|
|
120
|
-
- `http://` or `https://` protocol are used in Style Specification
|
|
121
|
-
- In addition, chiitiler supports following protocols:
|
|
122
|
-
- `s3://` for S3 bucket
|
|
123
|
-
- `file://` for file system
|
|
124
|
-
- `mbtiles://` for MBTIles files
|
|
125
|
-
- `pmtiles://` for PMTiles, remote or local or s3
|
|
126
|
-
- `cog://` experimental, for Cloud Optimized GeoTIFF. CRS must be EPSG:3857.
|
|
127
|
-
- Only when `http://` and `https://` chiitiler cache them with a method you specified.
|
|
128
|
-
|
|
129
|
-
### example
|
|
130
|
-
|
|
131
|
-
[./localdata/style.json](./localdata/style.json)
|
|
132
|
-
|
|
133
|
-
```json
|
|
134
|
-
{
|
|
135
|
-
"version": "8",
|
|
136
|
-
"sources": {
|
|
137
|
-
"dir": {
|
|
138
|
-
"type": "vector",
|
|
139
|
-
"tiles": [
|
|
140
|
-
"file://localdata/tiles/{z}/{x}/{y}.pbf"
|
|
141
|
-
],
|
|
142
|
-
"maxzoom": 6
|
|
143
|
-
},
|
|
144
|
-
"mbtiles": {
|
|
145
|
-
"type": "vector",
|
|
146
|
-
"tiles": [
|
|
147
|
-
"mbtiles://localdata/school.mbtiles/{z}/{x}/{y}"
|
|
148
|
-
],
|
|
149
|
-
"maxzoom": 10
|
|
150
|
-
},
|
|
151
|
-
"pmtiles": {
|
|
152
|
-
"type": "vector",
|
|
153
|
-
"tiles": [
|
|
154
|
-
"pmtiles://localdata/school.pmtiles/{z}/{x}/{y}"
|
|
155
|
-
],
|
|
156
|
-
"maxzoom": 10
|
|
157
|
-
},
|
|
158
|
-
"s3": {
|
|
159
|
-
"type": "vector",
|
|
160
|
-
"tiles": [
|
|
161
|
-
"s3://tiles/{z}/{x}/{y}.pbf"
|
|
162
|
-
],
|
|
163
|
-
"maxzoom": 6
|
|
164
|
-
},
|
|
165
|
-
"cog": {
|
|
166
|
-
"type": "raster",
|
|
167
|
-
"tiles": [
|
|
168
|
-
"cog://https://sentinel-cogs.s3.us-west-2.amazonaws.com/sentinel-s2-l2a-cogs/54/T/WN/2024/9/S2A_54TWN_20240908_0_L2A/TCI.tif/{z}/{x}/{y}"
|
|
169
|
-
],
|
|
170
|
-
"tileSize": 256
|
|
171
|
-
}
|
|
172
|
-
},
|
|
173
|
-
"layers": [
|
|
174
|
-
{
|
|
175
|
-
"id": "dir",
|
|
176
|
-
"source": "dir",
|
|
177
|
-
"source-layer": "P2921",
|
|
178
|
-
"type": "circle",
|
|
179
|
-
"paint": {
|
|
180
|
-
"circle-radius": 10,
|
|
181
|
-
"circle-color": "red"
|
|
182
|
-
}
|
|
183
|
-
},
|
|
184
|
-
{
|
|
185
|
-
"id": "mbtiles",
|
|
186
|
-
"source": "mbtiles",
|
|
187
|
-
"source-layer": "P2921",
|
|
188
|
-
"type": "circle",
|
|
189
|
-
"paint": {
|
|
190
|
-
"circle-radius": 7,
|
|
191
|
-
"circle-color": "blue"
|
|
192
|
-
}
|
|
193
|
-
},
|
|
194
|
-
{
|
|
195
|
-
"id": "pmtiles",
|
|
196
|
-
"source": "pmtiles",
|
|
197
|
-
"source-layer": "P2921",
|
|
198
|
-
"type": "circle",
|
|
199
|
-
"paint": {
|
|
200
|
-
"circle-radius": 5,
|
|
201
|
-
"circle-color": "yellow"
|
|
202
|
-
}
|
|
203
|
-
},
|
|
204
|
-
{
|
|
205
|
-
"id": "s3",
|
|
206
|
-
"source": "s3",
|
|
207
|
-
"source-layer": "P2921",
|
|
208
|
-
"type": "circle",
|
|
209
|
-
"paint": {
|
|
210
|
-
"circle-radius": 3,
|
|
211
|
-
"circle-color": "green"
|
|
212
|
-
}
|
|
213
|
-
},
|
|
214
|
-
{
|
|
215
|
-
"id": "cog",
|
|
216
|
-
"source": "cog",
|
|
217
|
-
"type": "raster",
|
|
218
|
-
"paint": {
|
|
219
|
-
"raster-opacity": 0.5
|
|
220
|
-
}
|
|
221
|
-
}
|
|
222
|
-
]
|
|
223
|
-
}
|
|
95
|
+
```bash
|
|
96
|
+
docker compose up
|
|
224
97
|
```
|
|
225
98
|
|
|
226
|
-
|
|
99
|
+
Volumes mount `localdata/` and `.cache/` so test assets and cached source data persist between runs.
|
|
100
|
+
|
|
101
|
+
## HTTP API
|
|
102
|
+
|
|
103
|
+
| Method | Path Pattern | Description |
|
|
104
|
+
| ------ | ------------ | ----------- |
|
|
105
|
+
| GET/POST | `/tiles/{z}/{x}/{y}.{ext}` | Render a raster tile (`png`, `jpeg`, `jpg`, `webp`). |
|
|
106
|
+
| GET/POST | `/clip.{ext}` | Render a bounding box image (`png`, `jpeg`, `jpg`, `webp`). |
|
|
107
|
+
| GET/POST | `/static/{lon},{lat},{zoom}[@{bearing}][,{pitch}]/{width}x{height}.{ext}` | Render a static image (`png`, `jpeg`, `jpg`, `webp`). |
|
|
108
|
+
| GET | `/debug` | Style explorer UI (requires debug mode). |
|
|
109
|
+
| GET | `/editor` | Lightweight style editor (requires debug mode). |
|
|
227
110
|
|
|
228
|
-
|
|
229
|
-
- methods to render MapLibre Style are exposed from `chiitiler` package.
|
|
111
|
+
### Query Parameters
|
|
230
112
|
|
|
231
|
-
|
|
113
|
+
- `url` – Required when using GET. Points to a MapLibre Style JSON.
|
|
114
|
+
- `tileSize` – Tile size in pixels (default `512`).
|
|
115
|
+
- `quality` – JPEG/WebP quality (default `100`).
|
|
116
|
+
- `margin` – Tile edge margin (default `0`).
|
|
117
|
+
- `bbox` – Bounding box for `/clip` as `minLon,minLat,maxLon,maxLat`.
|
|
118
|
+
- `size` – Longest edge of `/clip` output (default `1024`).
|
|
232
119
|
|
|
233
|
-
|
|
234
|
-
|
|
120
|
+
POST requests accept the style object directly in the JSON body (`{ "style": { ... } }`).
|
|
121
|
+
|
|
122
|
+
### Streaming Responses
|
|
123
|
+
|
|
124
|
+
Enable streaming (Sharp pipeline without buffering) by setting `CHIITILER_STREAM_MODE=true` or passing `--stream`.
|
|
125
|
+
|
|
126
|
+
## CLI Reference
|
|
127
|
+
|
|
128
|
+
Chiitiler exposes a single command: `tile-server`.
|
|
129
|
+
|
|
130
|
+
```bash
|
|
131
|
+
npx tsx src/main.ts tile-server --help
|
|
235
132
|
```
|
|
236
133
|
|
|
237
|
-
|
|
134
|
+
| Option | Description | Environment Fallback | Default |
|
|
135
|
+
| ------ | ----------- | -------------------- | ------- |
|
|
136
|
+
| `--cache <none/memory/file/s3/gcs>` | Select cache backend. | `CHIITILER_CACHE_METHOD` | `none` |
|
|
137
|
+
| `--cache-ttl <seconds>` | TTL for memory/file caches. | `CHIITILER_CACHE_TTL_SEC` | `3600` |
|
|
138
|
+
| `--memory-cache-max-item-count <n>` | Max items in memory cache. | `CHIITILER_MEMORYCACHE_MAXITEMCOUNT` | `1000` |
|
|
139
|
+
| `--file-cache-dir <dir>` | Disk cache directory. | `CHIITILER_FILECACHE_DIR` | `./.cache` |
|
|
140
|
+
| `--s3-cache-bucket <name>` | S3 bucket for caching. | `CHIITILER_S3CACHE_BUCKET` | `""` |
|
|
141
|
+
| `--s3-region <region>` | S3 region used for requests. | `CHIITILER_S3_REGION` | `us-east1` |
|
|
142
|
+
| `--s3-endpoint <url>` | S3-compatible endpoint. | `CHIITILER_S3_ENDPOINT` | `""` |
|
|
143
|
+
| `--s3-force-path-style` | Force path-style requests. | `CHIITILER_S3_FORCE_PATH_STYLE` (`true/false`) | `false` |
|
|
144
|
+
| `--gcs-cache-bucket <name>` | GCS bucket for caching. | `CHIITILER_GCS_CACHE_BUCKET` | `""` |
|
|
145
|
+
| `--gcs-project-id <id>` | GCP project ID. | `CHIITILER_GCS_PROJECT_ID` | `""` |
|
|
146
|
+
| `--gcs-key-filename <path>` | Service account JSON. | `CHIITILER_GCS_KEY_FILENAME` | `""` |
|
|
147
|
+
| `--gcs-cache-prefix <prefix>` | GCS object prefix. | `CHIITILER_GCS_CACHE_PREFIX` | `""` |
|
|
148
|
+
| `--gcs-api-endpoint <url>` | Custom GCS endpoint. | `CHIITILER_GCS_API_ENDPOINT` | `""` |
|
|
149
|
+
| `--port <number>` | HTTP listen port. | `CHIITILER_PORT` | `3000` |
|
|
150
|
+
| `--stream` | Enable streaming mode. | `CHIITILER_STREAM_MODE` | `false` |
|
|
151
|
+
| `--debug` | Enable debug UI routes. | `CHIITILER_DEBUG` | `false` |
|
|
152
|
+
|
|
153
|
+
Set `CHIITILER_PROCESSES` to control clustering (`0` uses all CPUs). When `>1`, the primary process forks workers that all share the same cache adapter.
|
|
154
|
+
|
|
155
|
+
## Environment Variables
|
|
156
|
+
|
|
157
|
+
In addition to the CLI options above, the server respects:
|
|
158
|
+
|
|
159
|
+
| Variable | Default | Notes |
|
|
160
|
+
| -------- | ------- | ----- |
|
|
161
|
+
| `CHIITILER_PROCESSES` | `1` | Number of worker processes; `0` = `availableParallelism()`. |
|
|
162
|
+
| `AWS_ACCESS_KEY_ID` / `AWS_SECRET_ACCESS_KEY` | – | Used by the S3 cache adapter. |
|
|
163
|
+
| `AWS_REGION` | – | Overrides SDK default region if set. |
|
|
164
|
+
| `GOOGLE_APPLICATION_CREDENTIALS` | – | Path to a service account JSON used by the GCS adapter. |
|
|
165
|
+
|
|
166
|
+
## Cache Backends
|
|
167
|
+
|
|
168
|
+
Chiitiler caches the source material required for rendering (vector tiles, glyphs, sprites, spritesheets), not the final raster outputs. These cached assets are reused across requests to avoid refetching upstream sources.
|
|
169
|
+
|
|
170
|
+
- **none** – No caching; every request renders from scratch.
|
|
171
|
+
- **memory** – In-memory LRU cache with configurable TTL and max entries.
|
|
172
|
+
- **file** – Stores fetched source assets under `CHIITILER_FILECACHE_DIR`.
|
|
173
|
+
- **s3** – Uploads cached source assets to S3/MinIO; honors custom endpoint and path-style.
|
|
174
|
+
- **gcs** – Uploads cached source assets to Google Cloud Storage or `fake-gcs-server`.
|
|
175
|
+
|
|
176
|
+
Each adapter exposes the same `get`/`set` interface and can be reused when embedding Chiitiler as a library.
|
|
177
|
+
|
|
178
|
+
## Debug Tools
|
|
179
|
+
|
|
180
|
+
Run with `--debug` or `CHIITILER_DEBUG=true` to unlock:
|
|
181
|
+
|
|
182
|
+
- `/debug` – Inspect styles, test queries, and view response metadata.
|
|
183
|
+
- `/editor` – Lightweight MapLibre style editor with live preview.
|
|
184
|
+
|
|
185
|
+
## Development & Testing
|
|
186
|
+
|
|
187
|
+
```bash
|
|
188
|
+
npm run dev # Watch mode via tsx
|
|
189
|
+
npm run build # Bundle to build/main.cjs with esbuild
|
|
190
|
+
npm run test:unit # Vitest unit suite (src/**/*.test.ts)
|
|
191
|
+
npm run test:integration # End-to-end scenarios in tests/
|
|
192
|
+
npm run test:coverage # Unit coverage with V8 provider
|
|
193
|
+
npm run test:benchmark # Performance tests (see BENCHMARK.md)
|
|
194
|
+
```
|
|
195
|
+
|
|
196
|
+
Benchmark scenarios and recent measurements live in [BENCHMARK.md](./BENCHMARK.md).
|
|
238
197
|
|
|
239
|
-
|
|
198
|
+
## Library Usage
|
|
240
199
|
|
|
241
|
-
|
|
200
|
+
Chiitiler is also published as an npm library. Core helpers return Sharp instances or encoded buffers so you can integrate the renderer into other pipelines.
|
|
201
|
+
|
|
202
|
+
```ts
|
|
203
|
+
import { createWriteStream } from 'node:fs';
|
|
242
204
|
import {
|
|
243
|
-
getRenderedBboxBuffer,
|
|
244
205
|
getRenderedTileBuffer,
|
|
245
|
-
|
|
206
|
+
getRenderedBboxBuffer,
|
|
207
|
+
getRenderedImageBuffer,
|
|
208
|
+
getRenderedTileStream,
|
|
209
|
+
getRenderedBboxStream,
|
|
210
|
+
getRenderedImageStream,
|
|
211
|
+
ChiitilerCache,
|
|
246
212
|
} from 'chiitiler';
|
|
247
213
|
|
|
248
|
-
const
|
|
249
|
-
|
|
250
|
-
|
|
251
|
-
|
|
214
|
+
const cache = ChiitilerCache.fileCache({ dir: './.cache', ttl: 3600 });
|
|
215
|
+
|
|
216
|
+
const tile = await getRenderedTileBuffer({
|
|
217
|
+
stylejson: 'https://tile.openstreetmap.jp/styles/osm-bright/style.json',
|
|
218
|
+
z: 5,
|
|
219
|
+
x: 27,
|
|
220
|
+
y: 12,
|
|
221
|
+
tileSize: 512,
|
|
222
|
+
margin: 0,
|
|
223
|
+
ext: 'webp',
|
|
224
|
+
quality: 100,
|
|
225
|
+
cache,
|
|
226
|
+
});
|
|
227
|
+
|
|
228
|
+
const clip = await getRenderedBboxBuffer({
|
|
229
|
+
stylejson: 'file://localdata/style.json',
|
|
230
|
+
bbox: [123.4, 34.5, 124.5, 35.6],
|
|
231
|
+
size: 1024,
|
|
232
|
+
ext: 'png',
|
|
233
|
+
quality: 95,
|
|
234
|
+
cache: ChiitilerCache.noneCache(),
|
|
252
235
|
});
|
|
253
|
-
// credentials are loaded from environment variables: AWS_ACCESS_KEY_ID, AWS_SECRET_ACCESS_KEY
|
|
254
236
|
|
|
255
|
-
const
|
|
256
|
-
stylejson: '
|
|
257
|
-
|
|
258
|
-
|
|
259
|
-
|
|
237
|
+
const image = await getRenderedImageBuffer({
|
|
238
|
+
stylejson: 'file://localdata/style.json',
|
|
239
|
+
lat: 123.45,
|
|
240
|
+
lon: 67.89,
|
|
241
|
+
zoom: 10,
|
|
242
|
+
bearing: 180,
|
|
243
|
+
pitch: 60,
|
|
244
|
+
size: 1024,
|
|
245
|
+
ext: 'png',
|
|
246
|
+
quality: 95,
|
|
247
|
+
cache,
|
|
248
|
+
});
|
|
249
|
+
|
|
250
|
+
// you can get Sharp streams directly
|
|
251
|
+
const tileStream = await getRenderedTileStream({
|
|
252
|
+
stylejson: 'https://tile.openstreetmap.jp/styles/osm-bright/style.json',
|
|
253
|
+
z: 5,
|
|
254
|
+
x: 27,
|
|
255
|
+
y: 12,
|
|
260
256
|
tileSize: 512,
|
|
261
|
-
ext: 'webp', // png, webp, jpg
|
|
262
|
-
cache: s3Cache,
|
|
263
|
-
quality: 80,
|
|
264
257
|
margin: 0,
|
|
258
|
+
ext: 'png',
|
|
259
|
+
quality: 90,
|
|
260
|
+
cache,
|
|
265
261
|
});
|
|
266
262
|
|
|
267
|
-
const
|
|
268
|
-
stylejson: 'file://
|
|
263
|
+
const bboxStream = await getRenderedBboxStream({
|
|
264
|
+
stylejson: 'file://localdata/style.json',
|
|
269
265
|
bbox: [123.4, 34.5, 124.5, 35.6],
|
|
270
266
|
size: 1024,
|
|
271
|
-
|
|
272
|
-
|
|
273
|
-
|
|
267
|
+
ext: 'jpeg',
|
|
268
|
+
quality: 85,
|
|
269
|
+
cache,
|
|
274
270
|
});
|
|
275
271
|
|
|
276
|
-
|
|
272
|
+
const imageStream = await getRenderedImageStream({
|
|
273
|
+
stylejson: 'file://localdata/style.json',
|
|
274
|
+
lat: 123.4,
|
|
275
|
+
lon: 34.5,
|
|
276
|
+
zoom: 10,
|
|
277
|
+
bearing: 180,
|
|
278
|
+
pitch: 60,
|
|
279
|
+
size: 1024,
|
|
280
|
+
ext: 'png',
|
|
281
|
+
quality: 95,
|
|
282
|
+
cache,
|
|
283
|
+
})
|
|
277
284
|
```
|
|
278
285
|
|
|
279
|
-
##
|
|
286
|
+
## Deployment
|
|
287
|
+
|
|
288
|
+
- **AWS CDK** – The [`cdk/`](./cdk) directory contains an AWS CDK app for provisioning Chiitiler on ECS/Fargate. See `cdk/README.md` for stack details.
|
|
289
|
+
- **Docker** – The provided `Dockerfile` installs runtime dependencies for `sharp` and exposes `tile-server` as the default entrypoint.
|
|
290
|
+
- **Bench setups** – `docker-compose.yml` provisions MinIO, Fake GCS, and sample data for local smoke tests.
|
|
280
291
|
|
|
281
|
-
|
|
292
|
+
## Architecture
|
|
293
|
+
|
|
294
|
+
```mermaid
|
|
295
|
+
graph LR
|
|
296
|
+
subgraph sources
|
|
297
|
+
direction LR
|
|
298
|
+
A[style.json]
|
|
299
|
+
z/x/y.pbf
|
|
300
|
+
z/x/y.png/webp/jpg
|
|
301
|
+
sprite
|
|
302
|
+
glyphs
|
|
303
|
+
end
|
|
304
|
+
|
|
305
|
+
subgraph chiitiler
|
|
306
|
+
cache
|
|
307
|
+
render
|
|
308
|
+
server
|
|
309
|
+
end
|
|
310
|
+
|
|
311
|
+
sources --> cache --> render --> server --/tiles/z/x/y--> png/webp/jpg
|
|
312
|
+
|
|
313
|
+
cache <--get/set--> memory/file/S3
|
|
314
|
+
```
|
|
@@ -0,0 +1,10 @@
|
|
|
1
|
+
import { type Cache } from './index.js';
|
|
2
|
+
type GCSCacheOptions = {
|
|
3
|
+
bucket: string;
|
|
4
|
+
prefix?: string;
|
|
5
|
+
projectId?: string;
|
|
6
|
+
keyFilename?: string;
|
|
7
|
+
apiEndpoint?: string;
|
|
8
|
+
};
|
|
9
|
+
declare function gcsCache(options: GCSCacheOptions): Cache;
|
|
10
|
+
export { gcsCache };
|
|
@@ -0,0 +1,66 @@
|
|
|
1
|
+
import { getStorageClient } from '../gcs.js';
|
|
2
|
+
function gcsCache(options) {
|
|
3
|
+
if (options.prefix?.endsWith('/')) {
|
|
4
|
+
options.prefix = options.prefix.slice(0, -1);
|
|
5
|
+
}
|
|
6
|
+
const storageClient = getStorageClient({
|
|
7
|
+
projectId: options.projectId,
|
|
8
|
+
keyFilename: options.keyFilename,
|
|
9
|
+
apiEndpoint: options.apiEndpoint,
|
|
10
|
+
});
|
|
11
|
+
const bucket = storageClient.bucket(options.bucket);
|
|
12
|
+
function bucketFile(key) {
|
|
13
|
+
const name = escapeFileName(key);
|
|
14
|
+
const nameWithPrefix = options.prefix ? `${options.prefix}/${name}` : name;
|
|
15
|
+
return bucket.file(nameWithPrefix);
|
|
16
|
+
}
|
|
17
|
+
return {
|
|
18
|
+
name: 'gcs',
|
|
19
|
+
set: async function (key, value) {
|
|
20
|
+
const file = bucketFile(key);
|
|
21
|
+
try {
|
|
22
|
+
await file.save(value, {
|
|
23
|
+
resumable: false,
|
|
24
|
+
});
|
|
25
|
+
}
|
|
26
|
+
catch (e) {
|
|
27
|
+
console.log(`[error]: ${e}`);
|
|
28
|
+
}
|
|
29
|
+
},
|
|
30
|
+
get: async function (key) {
|
|
31
|
+
const file = bucketFile(key);
|
|
32
|
+
try {
|
|
33
|
+
const [content] = await file.download();
|
|
34
|
+
return Buffer.from(content);
|
|
35
|
+
}
|
|
36
|
+
catch {
|
|
37
|
+
// miss or any error
|
|
38
|
+
return undefined;
|
|
39
|
+
}
|
|
40
|
+
},
|
|
41
|
+
};
|
|
42
|
+
}
|
|
43
|
+
function escapeFileName(url) {
|
|
44
|
+
return url
|
|
45
|
+
.replace(/\//g, '_') // replace slashes with underscores
|
|
46
|
+
.replace(/\?/g, '-') // replace question marks with dashes
|
|
47
|
+
.replace(/&/g, '-') // replace ampersands with dashes
|
|
48
|
+
.replace(/=/g, '-') // replace equals signs with dashes
|
|
49
|
+
.replace(/%/g, '-') // replace percent signs with dashes
|
|
50
|
+
.replace(/#/g, '-') // replace hash signs with dashes
|
|
51
|
+
.replace(/:/g, '-') // replace colons with dashes
|
|
52
|
+
.replace(/\+/g, '-') // replace plus signs with dashes
|
|
53
|
+
.replace(/ /g, '-') // replace spaces with dashes
|
|
54
|
+
.replace(/</g, '-') // replace less than signs with dashes
|
|
55
|
+
.replace(/>/g, '-') // replace greater than signs with dashes
|
|
56
|
+
.replace(/\*/g, '-') // replace asterisks with dashes
|
|
57
|
+
.replace(/\|/g, '-') // replace vertical bars with dashes
|
|
58
|
+
.replace(/"/g, '-') // replace double quotes with dashes
|
|
59
|
+
.replace(/'/g, '-') // replace single quotes with dashes
|
|
60
|
+
.replace(/\?/g, '-') // replace question marks with dashes
|
|
61
|
+
.replace(/\./g, '-') // replace dots with dashes
|
|
62
|
+
.replace(/,/g, '-') // replace commas with dashes
|
|
63
|
+
.replace(/;/g, '-') // replace semicolons with dashes
|
|
64
|
+
.replace(/\\/g, '-'); // replace backslashes with dashes
|
|
65
|
+
}
|
|
66
|
+
export { gcsCache };
|
package/dist/cache/index.d.ts
CHANGED
|
@@ -1,5 +1,6 @@
|
|
|
1
1
|
import { memoryCache } from './memory.js';
|
|
2
2
|
import { s3Cache } from './s3.js';
|
|
3
|
+
import { gcsCache } from './gcs.js';
|
|
3
4
|
import { fileCache } from './file.js';
|
|
4
5
|
type Value = Buffer;
|
|
5
6
|
type Cache = {
|
|
@@ -8,4 +9,4 @@ type Cache = {
|
|
|
8
9
|
set: (key: string, value: Value) => Promise<void>;
|
|
9
10
|
};
|
|
10
11
|
declare const noneCache: () => Cache;
|
|
11
|
-
export { noneCache, memoryCache, s3Cache, fileCache, type Value, type Cache };
|
|
12
|
+
export { noneCache, memoryCache, s3Cache, gcsCache, fileCache, type Value, type Cache };
|
package/dist/cache/index.js
CHANGED
|
@@ -1,9 +1,10 @@
|
|
|
1
1
|
import { memoryCache } from './memory.js';
|
|
2
2
|
import { s3Cache } from './s3.js';
|
|
3
|
+
import { gcsCache } from './gcs.js';
|
|
3
4
|
import { fileCache } from './file.js';
|
|
4
5
|
const noneCache = () => ({
|
|
5
6
|
name: 'none',
|
|
6
7
|
get: async () => undefined,
|
|
7
8
|
set: async () => undefined,
|
|
8
9
|
});
|
|
9
|
-
export { noneCache, memoryCache, s3Cache, fileCache };
|
|
10
|
+
export { noneCache, memoryCache, s3Cache, gcsCache, fileCache };
|