chiitiler 1.16.0 → 1.18.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 +12 -20
- package/dist/cli.js +2 -16
- package/dist/server/debug.d.ts +2 -2
- package/dist/server/debug.js +2 -2
- package/dist/server/index.d.ts +0 -1
- package/dist/server/index.js +3 -6
- package/dist/server/routes/camera.d.ts +217 -12
- package/dist/server/routes/camera.js +75 -74
- package/dist/server/routes/clip.d.ts +114 -7
- package/dist/server/routes/clip.js +4 -25
- package/dist/server/routes/tiles.d.ts +110 -7
- package/dist/server/routes/tiles.js +4 -25
- package/dist/server/utils.d.ts +1 -3
- package/dist/server/utils.js +1 -21
- package/dist/source/pmtiles.js +1 -1
- package/dist/source/s3.js +1 -1
- package/package.json +1 -1
package/README.md
CHANGED
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
# chiitiler –
|
|
1
|
+
# chiitiler – Lightweight Raster Tile Server for MapLibre Style
|
|
2
2
|
|
|
3
3
|

|
|
4
4
|

|
|
@@ -58,7 +58,7 @@ cdk/ # AWS CDK deployment project
|
|
|
58
58
|
|
|
59
59
|
### Requirements
|
|
60
60
|
|
|
61
|
-
- Node.js
|
|
61
|
+
- Node.js 24.12.0 or newer (`.node-version` is provided).
|
|
62
62
|
- System dependencies to support `sharp` (see [Dockerfile](./Dockerfile) for reference).
|
|
63
63
|
|
|
64
64
|
### Run From Source
|
|
@@ -104,7 +104,7 @@ Volumes mount `localdata/` and `.cache/` so test assets and cached source data p
|
|
|
104
104
|
| ------ | ------------ | ----------- |
|
|
105
105
|
| GET/POST | `/tiles/{z}/{x}/{y}.{ext}` | Render a raster tile (`png`, `jpeg`, `jpg`, `webp`). |
|
|
106
106
|
| GET/POST | `/clip.{ext}` | Render a bounding box image (`png`, `jpeg`, `jpg`, `webp`). |
|
|
107
|
-
| GET/POST | `/
|
|
107
|
+
| GET/POST | `/camera/{zoom}/{lat}/{lon}/{bearing}/{pitch}/{width}x{height}.{ext}` | Render a static image (`png`, `jpeg`, `jpg`, `webp`). |
|
|
108
108
|
| GET | `/debug` | Style explorer UI (requires debug mode). |
|
|
109
109
|
| GET | `/editor` | Lightweight style editor (requires debug mode). |
|
|
110
110
|
|
|
@@ -119,10 +119,6 @@ Volumes mount `localdata/` and `.cache/` so test assets and cached source data p
|
|
|
119
119
|
|
|
120
120
|
POST requests accept the style object directly in the JSON body (`{ "style": { ... } }`).
|
|
121
121
|
|
|
122
|
-
### Streaming Responses
|
|
123
|
-
|
|
124
|
-
Enable streaming (Sharp pipeline without buffering) by setting `CHIITILER_STREAM_MODE=true` or passing `--stream`.
|
|
125
|
-
|
|
126
122
|
## CLI Reference
|
|
127
123
|
|
|
128
124
|
Chiitiler exposes a single command: `tile-server`.
|
|
@@ -138,7 +134,7 @@ npx tsx src/main.ts tile-server --help
|
|
|
138
134
|
| `--memory-cache-max-item-count <n>` | Max items in memory cache. | `CHIITILER_MEMORYCACHE_MAXITEMCOUNT` | `1000` |
|
|
139
135
|
| `--file-cache-dir <dir>` | Disk cache directory. | `CHIITILER_FILECACHE_DIR` | `./.cache` |
|
|
140
136
|
| `--s3-cache-bucket <name>` | S3 bucket for caching. | `CHIITILER_S3CACHE_BUCKET` | `""` |
|
|
141
|
-
| `--s3-region <region>` | S3 region used for requests. | `CHIITILER_S3_REGION` | `us-
|
|
137
|
+
| `--s3-region <region>` | S3 region used for requests. | `CHIITILER_S3_REGION` | `us-east-1` |
|
|
142
138
|
| `--s3-endpoint <url>` | S3-compatible endpoint. | `CHIITILER_S3_ENDPOINT` | `""` |
|
|
143
139
|
| `--s3-force-path-style` | Force path-style requests. | `CHIITILER_S3_FORCE_PATH_STYLE` (`true/false`) | `false` |
|
|
144
140
|
| `--gcs-cache-bucket <name>` | GCS bucket for caching. | `CHIITILER_GCS_CACHE_BUCKET` | `""` |
|
|
@@ -147,7 +143,6 @@ npx tsx src/main.ts tile-server --help
|
|
|
147
143
|
| `--gcs-cache-prefix <prefix>` | GCS object prefix. | `CHIITILER_GCS_CACHE_PREFIX` | `""` |
|
|
148
144
|
| `--gcs-api-endpoint <url>` | Custom GCS endpoint. | `CHIITILER_GCS_API_ENDPOINT` | `""` |
|
|
149
145
|
| `--port <number>` | HTTP listen port. | `CHIITILER_PORT` | `3000` |
|
|
150
|
-
| `--stream` | Enable streaming mode. | `CHIITILER_STREAM_MODE` | `false` |
|
|
151
146
|
| `--debug` | Enable debug UI routes. | `CHIITILER_DEBUG` | `false` |
|
|
152
147
|
|
|
153
148
|
Set `CHIITILER_PROCESSES` to control clustering (`0` uses all CPUs). When `>1`, the primary process forks workers that all share the same cache adapter.
|
|
@@ -200,7 +195,6 @@ Benchmark scenarios and recent measurements live in [BENCHMARK.md](./BENCHMARK.m
|
|
|
200
195
|
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
196
|
|
|
202
197
|
```ts
|
|
203
|
-
import { createWriteStream } from 'node:fs';
|
|
204
198
|
import {
|
|
205
199
|
getRenderedTileBuffer,
|
|
206
200
|
getRenderedBboxBuffer,
|
|
@@ -236,12 +230,12 @@ const clip = await getRenderedBboxBuffer({
|
|
|
236
230
|
|
|
237
231
|
const image = await getRenderedImageBuffer({
|
|
238
232
|
stylejson: 'file://localdata/style.json',
|
|
239
|
-
|
|
240
|
-
lon: 67.89,
|
|
233
|
+
center: [139.69, 35.68],
|
|
241
234
|
zoom: 10,
|
|
242
235
|
bearing: 180,
|
|
243
236
|
pitch: 60,
|
|
244
|
-
|
|
237
|
+
width: 1024,
|
|
238
|
+
height: 1024,
|
|
245
239
|
ext: 'png',
|
|
246
240
|
quality: 95,
|
|
247
241
|
cache,
|
|
@@ -271,12 +265,12 @@ const bboxStream = await getRenderedBboxStream({
|
|
|
271
265
|
|
|
272
266
|
const imageStream = await getRenderedImageStream({
|
|
273
267
|
stylejson: 'file://localdata/style.json',
|
|
274
|
-
|
|
275
|
-
lon: 34.5,
|
|
268
|
+
center: [139.69, 35.68],
|
|
276
269
|
zoom: 10,
|
|
277
270
|
bearing: 180,
|
|
278
271
|
pitch: 60,
|
|
279
|
-
|
|
272
|
+
width: 1024,
|
|
273
|
+
height: 1024,
|
|
280
274
|
ext: 'png',
|
|
281
275
|
quality: 95,
|
|
282
276
|
cache,
|
|
@@ -285,9 +279,7 @@ const imageStream = await getRenderedImageStream({
|
|
|
285
279
|
|
|
286
280
|
## Deployment
|
|
287
281
|
|
|
288
|
-
|
|
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.
|
|
282
|
+
The [`cdk/`](./cdk) directory contains an AWS CDK app for running Chiitiler on Lambda with Web Adapter.
|
|
291
283
|
|
|
292
284
|
## Architecture
|
|
293
285
|
|
|
@@ -310,5 +302,5 @@ graph LR
|
|
|
310
302
|
|
|
311
303
|
sources --> cache --> render --> server --/tiles/z/x/y--> png/webp/jpg
|
|
312
304
|
|
|
313
|
-
cache <--get/set--> memory/file/
|
|
305
|
+
cache <--get/set--> memory/file/s3/gcs
|
|
314
306
|
```
|
package/dist/cli.js
CHANGED
|
@@ -44,7 +44,7 @@ function parseCacheStrategy(method, options) {
|
|
|
44
44
|
if (cacheEnv === 's3')
|
|
45
45
|
return caches.s3Cache({
|
|
46
46
|
bucket: process.env.CHIITILER_S3CACHE_BUCKET ?? '',
|
|
47
|
-
region: process.env.CHIITILER_S3_REGION ?? 'us-
|
|
47
|
+
region: process.env.CHIITILER_S3_REGION ?? 'us-east-1',
|
|
48
48
|
endpoint: process.env.CHIITILER_S3_ENDPOINT,
|
|
49
49
|
forcePathStyle: process.env.CHIITILER_S3_FORCE_PATH_STYLE === 'true',
|
|
50
50
|
});
|
|
@@ -81,17 +81,6 @@ function parseDebug(debug) {
|
|
|
81
81
|
// undefined or invalid
|
|
82
82
|
return false;
|
|
83
83
|
}
|
|
84
|
-
function parseStream(stream) {
|
|
85
|
-
// command-line option
|
|
86
|
-
if (stream)
|
|
87
|
-
return true;
|
|
88
|
-
// command-line is not specified or false -> try to read from env
|
|
89
|
-
const streamEnv = process.env.CHIITILER_STREAM_MODE;
|
|
90
|
-
if (streamEnv !== undefined)
|
|
91
|
-
return streamEnv === 'true';
|
|
92
|
-
// undefined or invalid
|
|
93
|
-
return false;
|
|
94
|
-
}
|
|
95
84
|
export function createProgram() {
|
|
96
85
|
const program = new Command();
|
|
97
86
|
program
|
|
@@ -100,7 +89,7 @@ export function createProgram() {
|
|
|
100
89
|
.option('-ctl --cache-ttl', 'cache ttl', '3600')
|
|
101
90
|
.option('-mci --memory-cache-max-item-count', 'memory cache max item count', '1000')
|
|
102
91
|
.option('-fcd --file-cache-dir <dir>', 'file cache directory', './.cache')
|
|
103
|
-
.option('-s3r --s3-region <region-name>', 's3 bucket region for get/put', 'us-
|
|
92
|
+
.option('-s3r --s3-region <region-name>', 's3 bucket region for get/put', 'us-east-1')
|
|
104
93
|
.option('-s3b --s3-cache-bucket <bucket-name>', 's3 cache bucket name', '')
|
|
105
94
|
.option('-s3e --s3-endpoint <url>', 's3 endpoint url', '')
|
|
106
95
|
.option('-3p --s3-force-path-style', 's3 force path style', '')
|
|
@@ -110,7 +99,6 @@ export function createProgram() {
|
|
|
110
99
|
.option('-gcsp --gcs-cache-prefix <prefix>', 'gcs cache prefix', '')
|
|
111
100
|
.option('-gcse --gcs-api-endpoint <api-endpoint>', 'gcs api endpoint', '')
|
|
112
101
|
.option('-p --port <port>', 'port number')
|
|
113
|
-
.option('-r --stream', 'stream mode')
|
|
114
102
|
.option('-D --debug', 'debug mode')
|
|
115
103
|
.action((options) => {
|
|
116
104
|
const serverOptions = {
|
|
@@ -130,14 +118,12 @@ export function createProgram() {
|
|
|
130
118
|
}),
|
|
131
119
|
port: parsePort(options.port),
|
|
132
120
|
debug: parseDebug(options.debug),
|
|
133
|
-
stream: parseStream(options.stream),
|
|
134
121
|
};
|
|
135
122
|
if (serverOptions.debug) {
|
|
136
123
|
console.log(`running server: http://localhost:${serverOptions.port}`);
|
|
137
124
|
console.log(`cache method: ${serverOptions.cache.name}`);
|
|
138
125
|
console.log(`debug page: http://localhost:${serverOptions.port}/debug`);
|
|
139
126
|
console.log(`editor page: http://localhost:${serverOptions.port}/editor`);
|
|
140
|
-
console.log('stream mode:', serverOptions.stream ? 'enabled' : 'disabled');
|
|
141
127
|
}
|
|
142
128
|
const { start } = initServer(serverOptions);
|
|
143
129
|
start();
|
package/dist/server/debug.d.ts
CHANGED
|
@@ -1,4 +1,4 @@
|
|
|
1
1
|
import { Context } from 'hono';
|
|
2
2
|
declare function getDebugPage(c: Context): Response;
|
|
3
|
-
declare function
|
|
4
|
-
export { getDebugPage,
|
|
3
|
+
declare function getEditorPage(c: Context): Response;
|
|
4
|
+
export { getDebugPage, getEditorPage };
|
package/dist/server/debug.js
CHANGED
|
@@ -64,7 +64,7 @@ function getDebugPage(c) {
|
|
|
64
64
|
</body>
|
|
65
65
|
</html>`);
|
|
66
66
|
}
|
|
67
|
-
function
|
|
67
|
+
function getEditorPage(c) {
|
|
68
68
|
return c.html(`<!DOCTYPE html>
|
|
69
69
|
<html>
|
|
70
70
|
<head>
|
|
@@ -198,4 +198,4 @@ function getEditorgPage(c) {
|
|
|
198
198
|
</body>
|
|
199
199
|
</html>`);
|
|
200
200
|
}
|
|
201
|
-
export { getDebugPage,
|
|
201
|
+
export { getDebugPage, getEditorPage };
|
package/dist/server/index.d.ts
CHANGED
package/dist/server/index.js
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
import { Hono } from 'hono/quick';
|
|
2
2
|
import { serve } from '@hono/node-server';
|
|
3
|
-
import { getDebugPage,
|
|
3
|
+
import { getDebugPage, getEditorPage } from './debug.js';
|
|
4
4
|
import { createClipRouter } from './routes/clip.js';
|
|
5
5
|
import { createTilesRouter } from './routes/tiles.js';
|
|
6
6
|
import { createCameraRouter } from './routes/camera.js';
|
|
@@ -8,20 +8,17 @@ function initServer(options) {
|
|
|
8
8
|
const hono = new Hono();
|
|
9
9
|
if (options.debug) {
|
|
10
10
|
hono.get('/debug', getDebugPage);
|
|
11
|
-
hono.get('/editor',
|
|
11
|
+
hono.get('/editor', getEditorPage);
|
|
12
12
|
}
|
|
13
13
|
hono.get('/health', (c) => c.text('OK'));
|
|
14
|
-
hono.route('/
|
|
14
|
+
hono.route('/camera', createCameraRouter({
|
|
15
15
|
cache: options.cache,
|
|
16
|
-
stream: options.stream,
|
|
17
16
|
}));
|
|
18
17
|
hono.route('/tiles', createTilesRouter({
|
|
19
18
|
cache: options.cache,
|
|
20
|
-
stream: options.stream,
|
|
21
19
|
}));
|
|
22
20
|
hono.route('/', createClipRouter({
|
|
23
21
|
cache: options.cache,
|
|
24
|
-
stream: options.stream,
|
|
25
22
|
}));
|
|
26
23
|
return {
|
|
27
24
|
app: hono,
|
|
@@ -1,36 +1,241 @@
|
|
|
1
1
|
import { Cache } from '../../cache/index.js';
|
|
2
2
|
declare function createCameraRouter(options: {
|
|
3
3
|
cache: Cache;
|
|
4
|
-
stream: boolean;
|
|
5
4
|
}): import("hono/hono-base").HonoBase<import("hono/types").BlankEnv, {
|
|
6
|
-
"/:
|
|
5
|
+
"/:zoom/:lat/:lon/:bearing/:pitch/:dimensions_ext": {
|
|
7
6
|
$get: {
|
|
8
7
|
input: {
|
|
9
8
|
param: {
|
|
10
|
-
|
|
9
|
+
zoom: string;
|
|
10
|
+
} & {
|
|
11
|
+
lat: string;
|
|
12
|
+
} & {
|
|
13
|
+
lon: string;
|
|
14
|
+
} & {
|
|
15
|
+
bearing: string;
|
|
16
|
+
} & {
|
|
17
|
+
pitch: string;
|
|
18
|
+
} & {
|
|
19
|
+
dimensions_ext: string;
|
|
20
|
+
};
|
|
21
|
+
};
|
|
22
|
+
output: "invalid format";
|
|
23
|
+
outputFormat: "body";
|
|
24
|
+
status: 400;
|
|
25
|
+
} | {
|
|
26
|
+
input: {
|
|
27
|
+
param: {
|
|
28
|
+
zoom: string;
|
|
29
|
+
} & {
|
|
30
|
+
lat: string;
|
|
31
|
+
} & {
|
|
32
|
+
lon: string;
|
|
33
|
+
} & {
|
|
34
|
+
bearing: string;
|
|
35
|
+
} & {
|
|
36
|
+
pitch: string;
|
|
37
|
+
} & {
|
|
38
|
+
dimensions_ext: string;
|
|
39
|
+
};
|
|
40
|
+
};
|
|
41
|
+
output: "url is required";
|
|
42
|
+
outputFormat: "body";
|
|
43
|
+
status: 400;
|
|
44
|
+
} | {
|
|
45
|
+
input: {
|
|
46
|
+
param: {
|
|
47
|
+
zoom: string;
|
|
48
|
+
} & {
|
|
49
|
+
lat: string;
|
|
50
|
+
} & {
|
|
51
|
+
lon: string;
|
|
52
|
+
} & {
|
|
53
|
+
bearing: string;
|
|
54
|
+
} & {
|
|
55
|
+
pitch: string;
|
|
56
|
+
} & {
|
|
57
|
+
dimensions_ext: string;
|
|
58
|
+
};
|
|
59
|
+
};
|
|
60
|
+
output: Uint8Array<ArrayBuffer>;
|
|
61
|
+
outputFormat: "body";
|
|
62
|
+
status: import("hono/utils/http-status").ContentfulStatusCode;
|
|
63
|
+
} | {
|
|
64
|
+
input: {
|
|
65
|
+
param: {
|
|
66
|
+
zoom: string;
|
|
67
|
+
} & {
|
|
68
|
+
lat: string;
|
|
69
|
+
} & {
|
|
70
|
+
lon: string;
|
|
71
|
+
} & {
|
|
72
|
+
bearing: string;
|
|
73
|
+
} & {
|
|
74
|
+
pitch: string;
|
|
75
|
+
} & {
|
|
76
|
+
dimensions_ext: string;
|
|
77
|
+
};
|
|
78
|
+
};
|
|
79
|
+
output: "invalid dimensions";
|
|
80
|
+
outputFormat: "body";
|
|
81
|
+
status: 400;
|
|
82
|
+
} | {
|
|
83
|
+
input: {
|
|
84
|
+
param: {
|
|
85
|
+
zoom: string;
|
|
86
|
+
} & {
|
|
87
|
+
lat: string;
|
|
88
|
+
} & {
|
|
89
|
+
lon: string;
|
|
90
|
+
} & {
|
|
91
|
+
bearing: string;
|
|
92
|
+
} & {
|
|
93
|
+
pitch: string;
|
|
94
|
+
} & {
|
|
95
|
+
dimensions_ext: string;
|
|
96
|
+
};
|
|
97
|
+
};
|
|
98
|
+
output: "invalid camera";
|
|
99
|
+
outputFormat: "body";
|
|
100
|
+
status: 400;
|
|
101
|
+
} | {
|
|
102
|
+
input: {
|
|
103
|
+
param: {
|
|
104
|
+
zoom: string;
|
|
105
|
+
} & {
|
|
106
|
+
lat: string;
|
|
107
|
+
} & {
|
|
108
|
+
lon: string;
|
|
109
|
+
} & {
|
|
110
|
+
bearing: string;
|
|
111
|
+
} & {
|
|
112
|
+
pitch: string;
|
|
11
113
|
} & {
|
|
12
114
|
dimensions_ext: string;
|
|
13
115
|
};
|
|
14
116
|
};
|
|
15
|
-
output:
|
|
16
|
-
outputFormat:
|
|
17
|
-
status:
|
|
117
|
+
output: "failed to render static image";
|
|
118
|
+
outputFormat: "body";
|
|
119
|
+
status: 400;
|
|
18
120
|
};
|
|
19
121
|
};
|
|
20
122
|
} & {
|
|
21
|
-
"/:
|
|
123
|
+
"/:zoom/:lat/:lon/:bearing/:pitch/:dimensions_ext": {
|
|
22
124
|
$post: {
|
|
23
125
|
input: {
|
|
24
126
|
param: {
|
|
25
|
-
|
|
127
|
+
zoom: string;
|
|
128
|
+
} & {
|
|
129
|
+
lat: string;
|
|
130
|
+
} & {
|
|
131
|
+
lon: string;
|
|
132
|
+
} & {
|
|
133
|
+
bearing: string;
|
|
134
|
+
} & {
|
|
135
|
+
pitch: string;
|
|
136
|
+
} & {
|
|
137
|
+
dimensions_ext: string;
|
|
138
|
+
};
|
|
139
|
+
};
|
|
140
|
+
output: "invalid format";
|
|
141
|
+
outputFormat: "body";
|
|
142
|
+
status: 400;
|
|
143
|
+
} | {
|
|
144
|
+
input: {
|
|
145
|
+
param: {
|
|
146
|
+
zoom: string;
|
|
147
|
+
} & {
|
|
148
|
+
lat: string;
|
|
149
|
+
} & {
|
|
150
|
+
lon: string;
|
|
151
|
+
} & {
|
|
152
|
+
bearing: string;
|
|
153
|
+
} & {
|
|
154
|
+
pitch: string;
|
|
155
|
+
} & {
|
|
156
|
+
dimensions_ext: string;
|
|
157
|
+
};
|
|
158
|
+
};
|
|
159
|
+
output: Uint8Array<ArrayBuffer>;
|
|
160
|
+
outputFormat: "body";
|
|
161
|
+
status: import("hono/utils/http-status").ContentfulStatusCode;
|
|
162
|
+
} | {
|
|
163
|
+
input: {
|
|
164
|
+
param: {
|
|
165
|
+
zoom: string;
|
|
166
|
+
} & {
|
|
167
|
+
lat: string;
|
|
168
|
+
} & {
|
|
169
|
+
lon: string;
|
|
170
|
+
} & {
|
|
171
|
+
bearing: string;
|
|
172
|
+
} & {
|
|
173
|
+
pitch: string;
|
|
174
|
+
} & {
|
|
175
|
+
dimensions_ext: string;
|
|
176
|
+
};
|
|
177
|
+
};
|
|
178
|
+
output: "invalid dimensions";
|
|
179
|
+
outputFormat: "body";
|
|
180
|
+
status: 400;
|
|
181
|
+
} | {
|
|
182
|
+
input: {
|
|
183
|
+
param: {
|
|
184
|
+
zoom: string;
|
|
185
|
+
} & {
|
|
186
|
+
lat: string;
|
|
187
|
+
} & {
|
|
188
|
+
lon: string;
|
|
189
|
+
} & {
|
|
190
|
+
bearing: string;
|
|
191
|
+
} & {
|
|
192
|
+
pitch: string;
|
|
193
|
+
} & {
|
|
194
|
+
dimensions_ext: string;
|
|
195
|
+
};
|
|
196
|
+
};
|
|
197
|
+
output: "invalid camera";
|
|
198
|
+
outputFormat: "body";
|
|
199
|
+
status: 400;
|
|
200
|
+
} | {
|
|
201
|
+
input: {
|
|
202
|
+
param: {
|
|
203
|
+
zoom: string;
|
|
204
|
+
} & {
|
|
205
|
+
lat: string;
|
|
206
|
+
} & {
|
|
207
|
+
lon: string;
|
|
208
|
+
} & {
|
|
209
|
+
bearing: string;
|
|
210
|
+
} & {
|
|
211
|
+
pitch: string;
|
|
212
|
+
} & {
|
|
213
|
+
dimensions_ext: string;
|
|
214
|
+
};
|
|
215
|
+
};
|
|
216
|
+
output: "failed to render static image";
|
|
217
|
+
outputFormat: "body";
|
|
218
|
+
status: 400;
|
|
219
|
+
} | {
|
|
220
|
+
input: {
|
|
221
|
+
param: {
|
|
222
|
+
zoom: string;
|
|
223
|
+
} & {
|
|
224
|
+
lat: string;
|
|
225
|
+
} & {
|
|
226
|
+
lon: string;
|
|
227
|
+
} & {
|
|
228
|
+
bearing: string;
|
|
229
|
+
} & {
|
|
230
|
+
pitch: string;
|
|
26
231
|
} & {
|
|
27
232
|
dimensions_ext: string;
|
|
28
233
|
};
|
|
29
234
|
};
|
|
30
|
-
output:
|
|
31
|
-
outputFormat:
|
|
32
|
-
status:
|
|
235
|
+
output: "invalid stylejson";
|
|
236
|
+
outputFormat: "body";
|
|
237
|
+
status: 400;
|
|
33
238
|
};
|
|
34
239
|
};
|
|
35
|
-
}, "/", "/:
|
|
240
|
+
}, "/", "/:zoom/:lat/:lon/:bearing/:pitch/:dimensions_ext">;
|
|
36
241
|
export { createCameraRouter };
|
|
@@ -1,31 +1,49 @@
|
|
|
1
1
|
import { Hono } from 'hono';
|
|
2
|
-
import {
|
|
3
|
-
import { isSupportedFormat, isValidCamera, isValidDimensions, isValidStylejson, } from '../utils.js';
|
|
2
|
+
import { isSupportedFormat, isValidStylejson } from '../utils.js';
|
|
4
3
|
import { getRenderedImage } from '../../render/index.js';
|
|
4
|
+
function isValidCamera({ zoom, lat, lon, bearing, pitch, }) {
|
|
5
|
+
if (Number.isNaN(lat) || lat < -90 || lat > 90)
|
|
6
|
+
return false;
|
|
7
|
+
if (Number.isNaN(lon) || lon < -180 || lon > 180)
|
|
8
|
+
return false;
|
|
9
|
+
if (Number.isNaN(zoom) || zoom < 0 || zoom > 24)
|
|
10
|
+
return false;
|
|
11
|
+
if (Number.isNaN(bearing) || bearing < 0 || bearing > 360)
|
|
12
|
+
return false;
|
|
13
|
+
if (Number.isNaN(pitch) || pitch < 0 || pitch > 180)
|
|
14
|
+
return false;
|
|
15
|
+
return true;
|
|
16
|
+
}
|
|
17
|
+
function isValidDimensions({ width, height, }) {
|
|
18
|
+
return !Number.isNaN(width) && !Number.isNaN(height);
|
|
19
|
+
}
|
|
5
20
|
function createCameraRouter(options) {
|
|
6
21
|
const camera = new Hono()
|
|
7
|
-
.get('/:
|
|
22
|
+
.get('/:zoom/:lat/:lon/:bearing/:pitch/:dimensions_ext', async (c) => {
|
|
8
23
|
// path params
|
|
9
|
-
const
|
|
10
|
-
.param('camera')
|
|
11
|
-
.match(/([\d.]+),([\d.]+),([\d.]+)(?:@(\d+)(?:,(\d+))?)?/);
|
|
24
|
+
const { zoom, lat, lon, bearing, pitch } = c.req.param();
|
|
12
25
|
const [_dimensions, ext] = c.req.param('dimensions_ext').split('.');
|
|
13
|
-
const dimensions = _dimensions.match(/(\d+)x(\d+)?/);
|
|
14
|
-
if (!camera || !isValidCamera(camera))
|
|
15
|
-
return c.body('invalid camera', 400);
|
|
16
|
-
if (!dimensions || !isValidDimensions(dimensions))
|
|
17
|
-
return c.body('invalid dimensions', 400);
|
|
18
26
|
if (!isSupportedFormat(ext))
|
|
19
27
|
return c.body('invalid format', 400);
|
|
20
|
-
const
|
|
21
|
-
const [,
|
|
22
|
-
const
|
|
23
|
-
const
|
|
24
|
-
const
|
|
25
|
-
const
|
|
26
|
-
const
|
|
27
|
-
const
|
|
28
|
-
const
|
|
28
|
+
const dimensions = _dimensions.split('x').map(Number);
|
|
29
|
+
const [width, height] = dimensions;
|
|
30
|
+
const _lat = Number(lat);
|
|
31
|
+
const _lon = Number(lon);
|
|
32
|
+
const _zoom = Number(zoom);
|
|
33
|
+
const _bearing = Number(bearing);
|
|
34
|
+
const _pitch = Number(pitch);
|
|
35
|
+
const _height = Number(height);
|
|
36
|
+
const _width = Number(width);
|
|
37
|
+
if (!isValidDimensions({ width: _width, height: _height }))
|
|
38
|
+
return c.body('invalid dimensions', 400);
|
|
39
|
+
if (!isValidCamera({
|
|
40
|
+
zoom: _zoom,
|
|
41
|
+
lat: _lat,
|
|
42
|
+
lon: _lon,
|
|
43
|
+
bearing: _bearing,
|
|
44
|
+
pitch: _pitch,
|
|
45
|
+
}))
|
|
46
|
+
return c.body('invalid camera', 400);
|
|
29
47
|
// query params
|
|
30
48
|
const url = c.req.query('url');
|
|
31
49
|
if (url === undefined)
|
|
@@ -38,57 +56,50 @@ function createCameraRouter(options) {
|
|
|
38
56
|
cache: options.cache,
|
|
39
57
|
ext,
|
|
40
58
|
quality,
|
|
41
|
-
center: [
|
|
42
|
-
zoom,
|
|
43
|
-
bearing,
|
|
44
|
-
pitch,
|
|
45
|
-
height,
|
|
46
|
-
width,
|
|
59
|
+
center: [_lon, _lat],
|
|
60
|
+
zoom: _zoom,
|
|
61
|
+
bearing: _bearing,
|
|
62
|
+
pitch: _pitch,
|
|
63
|
+
height: _height,
|
|
64
|
+
width: _width,
|
|
47
65
|
});
|
|
48
|
-
|
|
49
|
-
|
|
50
|
-
return stream(c, async (stream) => {
|
|
51
|
-
for await (const chunk of sharp) {
|
|
52
|
-
stream.write(chunk);
|
|
53
|
-
}
|
|
54
|
-
});
|
|
55
|
-
}
|
|
56
|
-
else {
|
|
57
|
-
const buf = await sharp.toBuffer();
|
|
58
|
-
return c.body(buf);
|
|
59
|
-
}
|
|
66
|
+
const buf = await sharp.toBuffer();
|
|
67
|
+
return c.body(buf);
|
|
60
68
|
}
|
|
61
69
|
catch (e) {
|
|
62
70
|
console.error(`render error: ${e}`);
|
|
63
71
|
return c.body('failed to render static image', 400);
|
|
64
72
|
}
|
|
65
73
|
})
|
|
66
|
-
.post('/:
|
|
74
|
+
.post('/:zoom/:lat/:lon/:bearing/:pitch/:dimensions_ext', async (c) => {
|
|
67
75
|
// body
|
|
68
76
|
const { style } = await c.req.json();
|
|
69
77
|
if (!isValidStylejson(style))
|
|
70
78
|
return c.body('invalid stylejson', 400);
|
|
71
79
|
// path params
|
|
72
|
-
const
|
|
73
|
-
.param('camera')
|
|
74
|
-
.match(/([\d.]+),([\d.]+),([\d.]+)(?:@(\d+)(?:,(\d+))?)?/);
|
|
80
|
+
const { zoom, lat, lon, bearing, pitch } = c.req.param();
|
|
75
81
|
const [_dimensions, ext] = c.req.param('dimensions_ext').split('.');
|
|
76
|
-
const dimensions = _dimensions.match(/(\d+)x(\d+)?/);
|
|
77
|
-
if (!camera || !isValidCamera(camera))
|
|
78
|
-
return c.body('invalid camera', 400);
|
|
79
|
-
if (!dimensions || !isValidDimensions(dimensions))
|
|
80
|
-
return c.body('invalid dimensions', 400);
|
|
81
82
|
if (!isSupportedFormat(ext))
|
|
82
83
|
return c.body('invalid format', 400);
|
|
83
|
-
const
|
|
84
|
-
const [,
|
|
85
|
-
const
|
|
86
|
-
const
|
|
87
|
-
const
|
|
88
|
-
const
|
|
89
|
-
const
|
|
90
|
-
const
|
|
91
|
-
const
|
|
84
|
+
const dimensions = _dimensions.split('x').map(Number);
|
|
85
|
+
const [width, height] = dimensions;
|
|
86
|
+
const _lat = Number(lat);
|
|
87
|
+
const _lon = Number(lon);
|
|
88
|
+
const _zoom = Number(zoom);
|
|
89
|
+
const _bearing = Number(bearing);
|
|
90
|
+
const _pitch = Number(pitch);
|
|
91
|
+
const _height = Number(height);
|
|
92
|
+
const _width = Number(width);
|
|
93
|
+
if (!isValidDimensions({ width: _width, height: _height }))
|
|
94
|
+
return c.body('invalid dimensions', 400);
|
|
95
|
+
if (!isValidCamera({
|
|
96
|
+
zoom: _zoom,
|
|
97
|
+
lat: _lat,
|
|
98
|
+
lon: _lon,
|
|
99
|
+
bearing: _bearing,
|
|
100
|
+
pitch: _pitch,
|
|
101
|
+
}))
|
|
102
|
+
return c.body('invalid camera', 400);
|
|
92
103
|
// query params
|
|
93
104
|
const quality = Number(c.req.query('quality') ?? 100);
|
|
94
105
|
c.header('Content-Type', `image/${ext}`);
|
|
@@ -98,25 +109,15 @@ function createCameraRouter(options) {
|
|
|
98
109
|
cache: options.cache,
|
|
99
110
|
ext,
|
|
100
111
|
quality,
|
|
101
|
-
center: [
|
|
102
|
-
zoom,
|
|
103
|
-
bearing,
|
|
104
|
-
pitch,
|
|
105
|
-
height,
|
|
106
|
-
width,
|
|
112
|
+
center: [_lon, _lat],
|
|
113
|
+
zoom: _zoom,
|
|
114
|
+
bearing: _bearing,
|
|
115
|
+
pitch: _pitch,
|
|
116
|
+
height: _height,
|
|
117
|
+
width: _width,
|
|
107
118
|
});
|
|
108
|
-
|
|
109
|
-
|
|
110
|
-
return stream(c, async (stream) => {
|
|
111
|
-
for await (const chunk of sharp) {
|
|
112
|
-
stream.write(chunk);
|
|
113
|
-
}
|
|
114
|
-
});
|
|
115
|
-
}
|
|
116
|
-
else {
|
|
117
|
-
const buf = await sharp.toBuffer();
|
|
118
|
-
return c.body(buf);
|
|
119
|
-
}
|
|
119
|
+
const buf = await sharp.toBuffer();
|
|
120
|
+
return c.body(buf);
|
|
120
121
|
}
|
|
121
122
|
catch (e) {
|
|
122
123
|
console.error(`render error: ${e}`);
|
|
@@ -1,7 +1,6 @@
|
|
|
1
1
|
import { Cache } from '../../cache/index.js';
|
|
2
2
|
declare function createClipRouter(options: {
|
|
3
3
|
cache: Cache;
|
|
4
|
-
stream: boolean;
|
|
5
4
|
}): import("hono/hono-base").HonoBase<import("hono/types").BlankEnv, {
|
|
6
5
|
"/:filename_ext": {
|
|
7
6
|
$get: {
|
|
@@ -10,9 +9,63 @@ declare function createClipRouter(options: {
|
|
|
10
9
|
filename_ext: string;
|
|
11
10
|
};
|
|
12
11
|
};
|
|
13
|
-
output:
|
|
14
|
-
outputFormat:
|
|
15
|
-
status:
|
|
12
|
+
output: "invalid format";
|
|
13
|
+
outputFormat: "body";
|
|
14
|
+
status: 400;
|
|
15
|
+
} | {
|
|
16
|
+
input: {
|
|
17
|
+
param: {
|
|
18
|
+
filename_ext: string;
|
|
19
|
+
};
|
|
20
|
+
};
|
|
21
|
+
output: "url is required";
|
|
22
|
+
outputFormat: "body";
|
|
23
|
+
status: 400;
|
|
24
|
+
} | {
|
|
25
|
+
input: {
|
|
26
|
+
param: {
|
|
27
|
+
filename_ext: string;
|
|
28
|
+
};
|
|
29
|
+
};
|
|
30
|
+
output: Uint8Array<ArrayBuffer>;
|
|
31
|
+
outputFormat: "body";
|
|
32
|
+
status: import("hono/utils/http-status").ContentfulStatusCode;
|
|
33
|
+
} | {
|
|
34
|
+
input: {
|
|
35
|
+
param: {
|
|
36
|
+
filename_ext: string;
|
|
37
|
+
};
|
|
38
|
+
};
|
|
39
|
+
output: "failed to render tile";
|
|
40
|
+
outputFormat: "body";
|
|
41
|
+
status: 400;
|
|
42
|
+
} | {
|
|
43
|
+
input: {
|
|
44
|
+
param: {
|
|
45
|
+
filename_ext: string;
|
|
46
|
+
};
|
|
47
|
+
};
|
|
48
|
+
output: "not found";
|
|
49
|
+
outputFormat: "body";
|
|
50
|
+
status: 404;
|
|
51
|
+
} | {
|
|
52
|
+
input: {
|
|
53
|
+
param: {
|
|
54
|
+
filename_ext: string;
|
|
55
|
+
};
|
|
56
|
+
};
|
|
57
|
+
output: "bbox is required";
|
|
58
|
+
outputFormat: "body";
|
|
59
|
+
status: 400;
|
|
60
|
+
} | {
|
|
61
|
+
input: {
|
|
62
|
+
param: {
|
|
63
|
+
filename_ext: string;
|
|
64
|
+
};
|
|
65
|
+
};
|
|
66
|
+
output: "invalid bbox";
|
|
67
|
+
outputFormat: "body";
|
|
68
|
+
status: 400;
|
|
16
69
|
};
|
|
17
70
|
};
|
|
18
71
|
} & {
|
|
@@ -23,9 +76,63 @@ declare function createClipRouter(options: {
|
|
|
23
76
|
filename_ext: string;
|
|
24
77
|
};
|
|
25
78
|
};
|
|
26
|
-
output:
|
|
27
|
-
outputFormat:
|
|
28
|
-
status:
|
|
79
|
+
output: "invalid format";
|
|
80
|
+
outputFormat: "body";
|
|
81
|
+
status: 400;
|
|
82
|
+
} | {
|
|
83
|
+
input: {
|
|
84
|
+
param: {
|
|
85
|
+
filename_ext: string;
|
|
86
|
+
};
|
|
87
|
+
};
|
|
88
|
+
output: Uint8Array<ArrayBuffer>;
|
|
89
|
+
outputFormat: "body";
|
|
90
|
+
status: import("hono/utils/http-status").ContentfulStatusCode;
|
|
91
|
+
} | {
|
|
92
|
+
input: {
|
|
93
|
+
param: {
|
|
94
|
+
filename_ext: string;
|
|
95
|
+
};
|
|
96
|
+
};
|
|
97
|
+
output: "failed to render tile";
|
|
98
|
+
outputFormat: "body";
|
|
99
|
+
status: 400;
|
|
100
|
+
} | {
|
|
101
|
+
input: {
|
|
102
|
+
param: {
|
|
103
|
+
filename_ext: string;
|
|
104
|
+
};
|
|
105
|
+
};
|
|
106
|
+
output: "not found";
|
|
107
|
+
outputFormat: "body";
|
|
108
|
+
status: 404;
|
|
109
|
+
} | {
|
|
110
|
+
input: {
|
|
111
|
+
param: {
|
|
112
|
+
filename_ext: string;
|
|
113
|
+
};
|
|
114
|
+
};
|
|
115
|
+
output: "bbox is required";
|
|
116
|
+
outputFormat: "body";
|
|
117
|
+
status: 400;
|
|
118
|
+
} | {
|
|
119
|
+
input: {
|
|
120
|
+
param: {
|
|
121
|
+
filename_ext: string;
|
|
122
|
+
};
|
|
123
|
+
};
|
|
124
|
+
output: "invalid bbox";
|
|
125
|
+
outputFormat: "body";
|
|
126
|
+
status: 400;
|
|
127
|
+
} | {
|
|
128
|
+
input: {
|
|
129
|
+
param: {
|
|
130
|
+
filename_ext: string;
|
|
131
|
+
};
|
|
132
|
+
};
|
|
133
|
+
output: "invalid stylejson";
|
|
134
|
+
outputFormat: "body";
|
|
135
|
+
status: 400;
|
|
29
136
|
};
|
|
30
137
|
};
|
|
31
138
|
}, "/", "/:filename_ext">;
|
|
@@ -1,5 +1,4 @@
|
|
|
1
1
|
import { Hono } from 'hono';
|
|
2
|
-
import { stream } from 'hono/streaming';
|
|
3
2
|
import { isSupportedFormat, isValidStylejson } from '../utils.js';
|
|
4
3
|
import { getRenderedBbox } from '../../render/index.js';
|
|
5
4
|
function createClipRouter(options) {
|
|
@@ -33,18 +32,8 @@ function createClipRouter(options) {
|
|
|
33
32
|
ext,
|
|
34
33
|
quality,
|
|
35
34
|
});
|
|
36
|
-
|
|
37
|
-
|
|
38
|
-
return stream(c, async (stream) => {
|
|
39
|
-
for await (const chunk of sharp) {
|
|
40
|
-
stream.write(chunk);
|
|
41
|
-
}
|
|
42
|
-
});
|
|
43
|
-
}
|
|
44
|
-
else {
|
|
45
|
-
const buf = await sharp.toBuffer();
|
|
46
|
-
return c.body(buf);
|
|
47
|
-
}
|
|
35
|
+
const buf = await sharp.toBuffer();
|
|
36
|
+
return c.body(buf);
|
|
48
37
|
}
|
|
49
38
|
catch (e) {
|
|
50
39
|
console.error(`render error: ${e}`);
|
|
@@ -81,18 +70,8 @@ function createClipRouter(options) {
|
|
|
81
70
|
ext,
|
|
82
71
|
quality,
|
|
83
72
|
});
|
|
84
|
-
|
|
85
|
-
|
|
86
|
-
return stream(c, async (stream) => {
|
|
87
|
-
for await (const chunk of sharp) {
|
|
88
|
-
stream.write(chunk);
|
|
89
|
-
}
|
|
90
|
-
});
|
|
91
|
-
}
|
|
92
|
-
else {
|
|
93
|
-
const buf = await sharp.toBuffer();
|
|
94
|
-
return c.body(buf);
|
|
95
|
-
}
|
|
73
|
+
const buf = await sharp.toBuffer();
|
|
74
|
+
return c.body(buf);
|
|
96
75
|
}
|
|
97
76
|
catch (e) {
|
|
98
77
|
console.error(`render error: ${e}`);
|
|
@@ -1,7 +1,6 @@
|
|
|
1
1
|
import { Cache } from '../../cache/index.js';
|
|
2
2
|
declare function createTilesRouter(options: {
|
|
3
3
|
cache: Cache;
|
|
4
|
-
stream: boolean;
|
|
5
4
|
}): import("hono/hono-base").HonoBase<import("hono/types").BlankEnv, {
|
|
6
5
|
"/:z/:x/:y_ext": {
|
|
7
6
|
$get: {
|
|
@@ -14,9 +13,61 @@ declare function createTilesRouter(options: {
|
|
|
14
13
|
y_ext: string;
|
|
15
14
|
};
|
|
16
15
|
};
|
|
17
|
-
output:
|
|
18
|
-
outputFormat:
|
|
19
|
-
status:
|
|
16
|
+
output: "invalid format";
|
|
17
|
+
outputFormat: "body";
|
|
18
|
+
status: 400;
|
|
19
|
+
} | {
|
|
20
|
+
input: {
|
|
21
|
+
param: {
|
|
22
|
+
z: string;
|
|
23
|
+
} & {
|
|
24
|
+
x: string;
|
|
25
|
+
} & {
|
|
26
|
+
y_ext: string;
|
|
27
|
+
};
|
|
28
|
+
};
|
|
29
|
+
output: "url is required";
|
|
30
|
+
outputFormat: "body";
|
|
31
|
+
status: 400;
|
|
32
|
+
} | {
|
|
33
|
+
input: {
|
|
34
|
+
param: {
|
|
35
|
+
z: string;
|
|
36
|
+
} & {
|
|
37
|
+
x: string;
|
|
38
|
+
} & {
|
|
39
|
+
y_ext: string;
|
|
40
|
+
};
|
|
41
|
+
};
|
|
42
|
+
output: Uint8Array<ArrayBuffer>;
|
|
43
|
+
outputFormat: "body";
|
|
44
|
+
status: import("hono/utils/http-status").ContentfulStatusCode;
|
|
45
|
+
} | {
|
|
46
|
+
input: {
|
|
47
|
+
param: {
|
|
48
|
+
z: string;
|
|
49
|
+
} & {
|
|
50
|
+
x: string;
|
|
51
|
+
} & {
|
|
52
|
+
y_ext: string;
|
|
53
|
+
};
|
|
54
|
+
};
|
|
55
|
+
output: "failed to render tile";
|
|
56
|
+
outputFormat: "body";
|
|
57
|
+
status: 400;
|
|
58
|
+
} | {
|
|
59
|
+
input: {
|
|
60
|
+
param: {
|
|
61
|
+
z: string;
|
|
62
|
+
} & {
|
|
63
|
+
x: string;
|
|
64
|
+
} & {
|
|
65
|
+
y_ext: string;
|
|
66
|
+
};
|
|
67
|
+
};
|
|
68
|
+
output: "invalid xyz";
|
|
69
|
+
outputFormat: "body";
|
|
70
|
+
status: 400;
|
|
20
71
|
};
|
|
21
72
|
};
|
|
22
73
|
} & {
|
|
@@ -31,9 +82,61 @@ declare function createTilesRouter(options: {
|
|
|
31
82
|
y_ext: string;
|
|
32
83
|
};
|
|
33
84
|
};
|
|
34
|
-
output:
|
|
35
|
-
outputFormat:
|
|
36
|
-
status:
|
|
85
|
+
output: "invalid format";
|
|
86
|
+
outputFormat: "body";
|
|
87
|
+
status: 400;
|
|
88
|
+
} | {
|
|
89
|
+
input: {
|
|
90
|
+
param: {
|
|
91
|
+
z: string;
|
|
92
|
+
} & {
|
|
93
|
+
x: string;
|
|
94
|
+
} & {
|
|
95
|
+
y_ext: string;
|
|
96
|
+
};
|
|
97
|
+
};
|
|
98
|
+
output: Uint8Array<ArrayBuffer>;
|
|
99
|
+
outputFormat: "body";
|
|
100
|
+
status: import("hono/utils/http-status").ContentfulStatusCode;
|
|
101
|
+
} | {
|
|
102
|
+
input: {
|
|
103
|
+
param: {
|
|
104
|
+
z: string;
|
|
105
|
+
} & {
|
|
106
|
+
x: string;
|
|
107
|
+
} & {
|
|
108
|
+
y_ext: string;
|
|
109
|
+
};
|
|
110
|
+
};
|
|
111
|
+
output: "failed to render tile";
|
|
112
|
+
outputFormat: "body";
|
|
113
|
+
status: 400;
|
|
114
|
+
} | {
|
|
115
|
+
input: {
|
|
116
|
+
param: {
|
|
117
|
+
z: string;
|
|
118
|
+
} & {
|
|
119
|
+
x: string;
|
|
120
|
+
} & {
|
|
121
|
+
y_ext: string;
|
|
122
|
+
};
|
|
123
|
+
};
|
|
124
|
+
output: "invalid xyz";
|
|
125
|
+
outputFormat: "body";
|
|
126
|
+
status: 400;
|
|
127
|
+
} | {
|
|
128
|
+
input: {
|
|
129
|
+
param: {
|
|
130
|
+
z: string;
|
|
131
|
+
} & {
|
|
132
|
+
x: string;
|
|
133
|
+
} & {
|
|
134
|
+
y_ext: string;
|
|
135
|
+
};
|
|
136
|
+
};
|
|
137
|
+
output: "invalid stylejson";
|
|
138
|
+
outputFormat: "body";
|
|
139
|
+
status: 400;
|
|
37
140
|
};
|
|
38
141
|
};
|
|
39
142
|
}, "/", "/:z/:x/:y_ext">;
|
|
@@ -1,5 +1,4 @@
|
|
|
1
1
|
import { Hono } from 'hono';
|
|
2
|
-
import { stream } from 'hono/streaming';
|
|
3
2
|
import { isSupportedFormat, isValidStylejson } from '../utils.js';
|
|
4
3
|
import { getRenderedTile } from '../../render/index.js';
|
|
5
4
|
function isValidXyz(x, y, z) {
|
|
@@ -41,18 +40,8 @@ function createTilesRouter(options) {
|
|
|
41
40
|
ext,
|
|
42
41
|
quality,
|
|
43
42
|
});
|
|
44
|
-
|
|
45
|
-
|
|
46
|
-
return stream(c, async (stream) => {
|
|
47
|
-
for await (const chunk of sharp) {
|
|
48
|
-
stream.write(chunk);
|
|
49
|
-
}
|
|
50
|
-
});
|
|
51
|
-
}
|
|
52
|
-
else {
|
|
53
|
-
const buf = await sharp.toBuffer();
|
|
54
|
-
return c.body(buf);
|
|
55
|
-
}
|
|
43
|
+
const buf = await sharp.toBuffer();
|
|
44
|
+
return c.body(buf);
|
|
56
45
|
}
|
|
57
46
|
catch (e) {
|
|
58
47
|
console.error(`render error: ${e}`);
|
|
@@ -90,18 +79,8 @@ function createTilesRouter(options) {
|
|
|
90
79
|
ext,
|
|
91
80
|
quality,
|
|
92
81
|
});
|
|
93
|
-
|
|
94
|
-
|
|
95
|
-
return stream(c, async (stream) => {
|
|
96
|
-
for await (const chunk of sharp) {
|
|
97
|
-
stream.write(chunk);
|
|
98
|
-
}
|
|
99
|
-
});
|
|
100
|
-
}
|
|
101
|
-
else {
|
|
102
|
-
const buf = await sharp.toBuffer();
|
|
103
|
-
return c.body(buf);
|
|
104
|
-
}
|
|
82
|
+
const buf = await sharp.toBuffer();
|
|
83
|
+
return c.body(buf);
|
|
105
84
|
}
|
|
106
85
|
catch (e) {
|
|
107
86
|
console.error(`render error: ${e}`);
|
package/dist/server/utils.d.ts
CHANGED
|
@@ -1,7 +1,5 @@
|
|
|
1
1
|
import { type StyleSpecification } from '@maplibre/maplibre-gl-style-spec';
|
|
2
2
|
import type { SupportedFormat } from '../render/index.js';
|
|
3
3
|
declare function isValidStylejson(stylejson: any): stylejson is StyleSpecification;
|
|
4
|
-
declare function isValidCamera([, lon, lat, zoom, bearing, pitch]: string[]): boolean;
|
|
5
|
-
declare function isValidDimensions([, width, height]: string[]): boolean;
|
|
6
4
|
declare function isSupportedFormat(ext: string | undefined): ext is SupportedFormat;
|
|
7
|
-
export { isValidStylejson,
|
|
5
|
+
export { isValidStylejson, isSupportedFormat };
|
package/dist/server/utils.js
CHANGED
|
@@ -2,27 +2,7 @@ import { validateStyleMin, } from '@maplibre/maplibre-gl-style-spec';
|
|
|
2
2
|
function isValidStylejson(stylejson) {
|
|
3
3
|
return validateStyleMin(stylejson).length === 0;
|
|
4
4
|
}
|
|
5
|
-
function isValidCamera([, lon, lat, zoom, bearing, pitch]) {
|
|
6
|
-
if (Number.isNaN(Number(lat)) || Number(lat) < -90 || Number(lat) > 90)
|
|
7
|
-
return false;
|
|
8
|
-
if (Number.isNaN(Number(lon)) || Number(lon) < -180 || Number(lon) > 180)
|
|
9
|
-
return false;
|
|
10
|
-
if (Number.isNaN(Number(zoom)) || Number(zoom) < 0 || Number(zoom) > 24)
|
|
11
|
-
return false;
|
|
12
|
-
if (bearing &&
|
|
13
|
-
(Number.isNaN(Number(bearing)) ||
|
|
14
|
-
Number(bearing) < 0 ||
|
|
15
|
-
Number(bearing) > 360))
|
|
16
|
-
return false;
|
|
17
|
-
if (pitch &&
|
|
18
|
-
(Number.isNaN(Number(pitch)) || Number(pitch) < 0 || Number(pitch) > 180))
|
|
19
|
-
return false;
|
|
20
|
-
return true;
|
|
21
|
-
}
|
|
22
|
-
function isValidDimensions([, width, height]) {
|
|
23
|
-
return !Number.isNaN(Number(width)) && !Number.isNaN(Number(height));
|
|
24
|
-
}
|
|
25
5
|
function isSupportedFormat(ext) {
|
|
26
6
|
return Boolean(ext && ['png', 'jpeg', 'jpg', 'webp'].includes(ext));
|
|
27
7
|
}
|
|
28
|
-
export { isValidStylejson,
|
|
8
|
+
export { isValidStylejson, isSupportedFormat };
|
package/dist/source/pmtiles.js
CHANGED
|
@@ -31,7 +31,7 @@ class S3Source {
|
|
|
31
31
|
this.bucket = bucket;
|
|
32
32
|
this.key = key;
|
|
33
33
|
this.s3Client = getS3Client({
|
|
34
|
-
region: process.env.CHIITILER_S3_REGION ?? 'us-
|
|
34
|
+
region: process.env.CHIITILER_S3_REGION ?? 'us-east-1',
|
|
35
35
|
endpoint: process.env.CHIITILER_S3_ENDPOINT,
|
|
36
36
|
forcePathStyle: process.env.CHIITILER_S3_FORCE_PATH_STYLE === 'true',
|
|
37
37
|
});
|
package/dist/source/s3.js
CHANGED
|
@@ -2,7 +2,7 @@ import { GetObjectCommand } from '@aws-sdk/client-s3';
|
|
|
2
2
|
import { getS3Client } from '../s3.js';
|
|
3
3
|
async function getS3Source(uri) {
|
|
4
4
|
const s3Client = getS3Client({
|
|
5
|
-
region: process.env.CHIITILER_S3_REGION ?? 'us-
|
|
5
|
+
region: process.env.CHIITILER_S3_REGION ?? 'us-east-1',
|
|
6
6
|
endpoint: process.env.CHIITILER_S3_ENDPOINT,
|
|
7
7
|
forcePathStyle: process.env.CHIITILER_S3_FORCE_PATH_STYLE === 'true',
|
|
8
8
|
});
|