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 CHANGED
@@ -1,281 +1,314 @@
1
- # chiitiler - The Tiny MapLibre Server
1
+ # chiitiler Tiny MapLibre Server
2
2
 
3
3
  ![GitHub Release](https://img.shields.io/github/v/release/Kanahiro/chiitiler?label=ghcr.io/kanahiro/chiitiler)
4
- ![GitHub Actions Workflow Status](https://img.shields.io/github/actions/workflow/status/Kanahiro/chiitiler/test:unit.yml?label=unittest)
5
- ![GitHub Actions Workflow Status](https://img.shields.io/github/actions/workflow/status/Kanahiro/chiitiler/test:integration.yml?label=integrationtest)
4
+ ![Unit Tests](https://img.shields.io/github/actions/workflow/status/Kanahiro/chiitiler/test:unit.yml?label=unit%20tests)
5
+ ![Integration Tests](https://img.shields.io/github/actions/workflow/status/Kanahiro/chiitiler/test:integration.yml?label=integration)
6
6
  [![codecov](https://codecov.io/gh/Kanahiro/chiitiler/graph/badge.svg?token=9RVLAJG126)](https://codecov.io/gh/Kanahiro/chiitiler)
7
7
 
8
- ![](./logo.webp)*generated by DALL-E*
8
+ ![chiitiler logo](./logo.webp)
9
9
 
10
- chii-tiler: "tiny" in Japanese is "chiisai", shorten into "chii"
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
- ## motivation
12
+ ## Overview
13
13
 
14
- - In this type of server, there is a de-facto - [maptiler/tileserver-gl](https://github.com/maptiler/tileserver-gl), but this is too big for me.
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
- ## usecases
16
+ ### Highlights
18
17
 
19
- - [MIERUNE/tiles](https://github.com/MIERUNE/tiles) - You can find example [here](https://mierune.github.io/tiles/color.html#11.62/43.064/141.3375)
20
- - [dayjournal/qgis-amazonlocationservice-plugin](https://github.com/dayjournal/qgis-amazonlocationservice-plugin) - used in Maps feature
21
- - [Allmaps Latest - Bluesky](https://bsky.app/profile/latest.allmaps.org)
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
- ## features
23
+ ### In Production
24
24
 
25
- ### /tiles
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
- chiitiler provides you with an endpoint `/tiles`. Once server launched, you can use the endpoint like this:
30
+ ## Supported Data Protocols
28
31
 
29
- ```planetext
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
- ### /clip.png|webp|jpg|jpeg
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
- chiitiler provides you with `/clip.png|webp|jpg|jpeg` endpoint. Once server launched, you can use like this:
42
+ ## Project Layout
38
43
 
39
- ```planetext
40
- # default size is 1024, this is longer axis and shorter axis is calculated by aspect ratio
41
- http://localhost:3000/clip.png?bbox=100,30,150,60&url=https://path/to/style.json
42
- # specify size
43
- http://localhost:3000/clip.png?bbox=100,30,150,6&size=512&url=https://path/to/style.json
44
- # specify quality
45
- http://localhost:3000/clip.png?bbox=100,30,150,6&size=512&quality=80&url=https://path/to/style.json
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
- #### POST endpoint
57
+ ## Quick Start
49
58
 
50
- Each endpoint also supports POST method. You can pass style.json as a body. (then, url parameter is not needed)
59
+ ### Requirements
51
60
 
52
- ## architecture
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
- ```mermaid
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
- subgraph chiitiler
66
- cache
67
- render
68
- server
69
- end
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
- sources --> cache --> render --> server --/tiles/z/x/y--> png/webp/jpg
73
+ When the server starts you can request a tile:
72
74
 
73
- cache <--get/set--> memory/file/S3
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
- ## usage
79
+ ### Docker Image
77
80
 
78
- ### Container Image
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
- ```sh
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
- # recommended: you can use environment variables
85
- docker run -p 3000:3000 -d \
86
- -e CHIITILER_CACHE_METHOD=s3 \
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
- #### Environment Variables
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
- ## Library Mode
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
- - chiitiler can be used as a library to render MapLibre Style.
229
- - methods to render MapLibre Style are exposed from `chiitiler` package.
111
+ ### Query Parameters
230
112
 
231
- ### installation
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
- ```sh
234
- npm install chiitiler
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
- - chiitiler requires some dependencies in runtime, you can find them in [Dockerfile](./Dockerfile)
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
- ### Usage
198
+ ## Library Usage
240
199
 
241
- ```typescript
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
- ChiitilerCache
206
+ getRenderedBboxBuffer,
207
+ getRenderedImageBuffer,
208
+ getRenderedTileStream,
209
+ getRenderedBboxStream,
210
+ getRenderedImageStream,
211
+ ChiitilerCache,
246
212
  } from 'chiitiler';
247
213
 
248
- const s3Cache = ChiitilerCache.s3Cache({
249
- bucket: 'chiitiler',
250
- region: 'ap-northeast-1',
251
- endpoint: null,
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 tileBuf = await getRenderedTileBuffer({
256
- stylejson: 'https://example.com/style.json', // or StyleSpecification object
257
- z: 0,
258
- x: 0,
259
- y: 0,
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 bboxBuf = await getRenderedBboxBuffer({
268
- stylejson: 'file://path/to/style.json', // or StyleSpecification object
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
- cache: s3Cache,
272
- ext: 'webp',
273
- quality: 80,
267
+ ext: 'jpeg',
268
+ quality: 85,
269
+ cache,
274
270
  });
275
271
 
276
- // return value is Buffer - binary of each image
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
- ## development
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
- - run `docker compose up`
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 };
@@ -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 };
@@ -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 };