chiitiler 1.18.0 → 1.20.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
@@ -197,11 +197,11 @@ Chiitiler is also published as an npm library. Core helpers return Sharp instanc
197
197
  ```ts
198
198
  import {
199
199
  getRenderedTileBuffer,
200
- getRenderedBboxBuffer,
201
- getRenderedImageBuffer,
200
+ getRenderedClipBuffer,
201
+ getRenderedCameraBuffer,
202
202
  getRenderedTileStream,
203
- getRenderedBboxStream,
204
- getRenderedImageStream,
203
+ getRenderedClipStream,
204
+ getRenderedCameraStream,
205
205
  ChiitilerCache,
206
206
  } from 'chiitiler';
207
207
 
@@ -219,7 +219,7 @@ const tile = await getRenderedTileBuffer({
219
219
  cache,
220
220
  });
221
221
 
222
- const clip = await getRenderedBboxBuffer({
222
+ const clip = await getRenderedClipBuffer({
223
223
  stylejson: 'file://localdata/style.json',
224
224
  bbox: [123.4, 34.5, 124.5, 35.6],
225
225
  size: 1024,
@@ -228,7 +228,7 @@ const clip = await getRenderedBboxBuffer({
228
228
  cache: ChiitilerCache.noneCache(),
229
229
  });
230
230
 
231
- const image = await getRenderedImageBuffer({
231
+ const camera = await getRenderedCameraBuffer({
232
232
  stylejson: 'file://localdata/style.json',
233
233
  center: [139.69, 35.68],
234
234
  zoom: 10,
@@ -254,7 +254,7 @@ const tileStream = await getRenderedTileStream({
254
254
  cache,
255
255
  });
256
256
 
257
- const bboxStream = await getRenderedBboxStream({
257
+ const clipStream = await getRenderedClipStream({
258
258
  stylejson: 'file://localdata/style.json',
259
259
  bbox: [123.4, 34.5, 124.5, 35.6],
260
260
  size: 1024,
@@ -263,7 +263,7 @@ const bboxStream = await getRenderedBboxStream({
263
263
  cache,
264
264
  });
265
265
 
266
- const imageStream = await getRenderedImageStream({
266
+ const cameraStream = await getRenderedCameraStream({
267
267
  stylejson: 'file://localdata/style.json',
268
268
  center: [139.69, 35.68],
269
269
  zoom: 10,
package/dist/cli.js CHANGED
@@ -86,20 +86,20 @@ export function createProgram() {
86
86
  program
87
87
  .command('tile-server')
88
88
  .option('-c, --cache <type>', 'cache type', 'none')
89
- .option('-ctl --cache-ttl', 'cache ttl', '3600')
90
- .option('-mci --memory-cache-max-item-count', 'memory cache max item count', '1000')
91
- .option('-fcd --file-cache-dir <dir>', 'file cache directory', './.cache')
92
- .option('-s3r --s3-region <region-name>', 's3 bucket region for get/put', 'us-east-1')
93
- .option('-s3b --s3-cache-bucket <bucket-name>', 's3 cache bucket name', '')
94
- .option('-s3e --s3-endpoint <url>', 's3 endpoint url', '')
95
- .option('-3p --s3-force-path-style', 's3 force path style', '')
96
- .option('-gcsb --gcs-cache-bucket <bucket-name>', 'gcs cache bucket name', '')
97
- .option('-gcsp --gcs-project-id <project-id>', 'gcs project id', '')
98
- .option('-gcsk --gcs-key-filename <key-filename>', 'gcs key filename', '')
99
- .option('-gcsp --gcs-cache-prefix <prefix>', 'gcs cache prefix', '')
100
- .option('-gcse --gcs-api-endpoint <api-endpoint>', 'gcs api endpoint', '')
101
- .option('-p --port <port>', 'port number')
102
- .option('-D --debug', 'debug mode')
89
+ .option('--cache-ttl', 'cache ttl', '3600')
90
+ .option('--memory-cache-max-item-count', 'memory cache max item count', '1000')
91
+ .option('--file-cache-dir <dir>', 'file cache directory', './.cache')
92
+ .option('--s3-region <region-name>', 's3 bucket region for get/put', 'us-east-1')
93
+ .option('--s3-cache-bucket <bucket-name>', 's3 cache bucket name', '')
94
+ .option('--s3-endpoint <url>', 's3 endpoint url', '')
95
+ .option('--s3-force-path-style', 's3 force path style', '')
96
+ .option('--gcs-cache-bucket <bucket-name>', 'gcs cache bucket name', '')
97
+ .option('--gcs-project-id <project-id>', 'gcs project id', '')
98
+ .option('--gcs-key-filename <key-filename>', 'gcs key filename', '')
99
+ .option('--gcs-cache-prefix <prefix>', 'gcs cache prefix', '')
100
+ .option('--gcs-api-endpoint <api-endpoint>', 'gcs api endpoint', '')
101
+ .option('-p, --port <port>', 'port number')
102
+ .option('-D, --debug', 'debug mode')
103
103
  .action((options) => {
104
104
  const serverOptions = {
105
105
  cache: parseCacheStrategy(options.cache, {
package/dist/index.d.ts CHANGED
@@ -1,8 +1,8 @@
1
- import { getRenderedBbox, getRenderedTile, getRenderedImage, GetRenderedBboxOptions, GetRenderedTileOptions, GetRenderedImageOptions } from './render/index.js';
2
- export declare function getRenderedBboxBuffer(options: GetRenderedBboxOptions): Promise<Buffer>;
3
- export { getRenderedBbox as getRenderedBboxStream };
4
- export declare function getRenderedImageBuffer(options: GetRenderedImageOptions): Promise<Buffer>;
5
- export { getRenderedImage as getRenderedImageStream };
1
+ import { getRenderedClip, getRenderedTile, getRenderedCamera, GetRenderedClipOptions, GetRenderedTileOptions, GetRenderedCameraOptions } from './render/index.js';
2
+ export declare function getRenderedClipBuffer(options: GetRenderedClipOptions): Promise<Buffer>;
3
+ export { getRenderedClip as getRenderedClipStream };
4
+ export declare function getRenderedCameraBuffer(options: GetRenderedCameraOptions): Promise<Buffer>;
5
+ export { getRenderedCamera as getRenderedCameraStream };
6
6
  export declare function getRenderedTileBuffer(options: GetRenderedTileOptions): Promise<Buffer>;
7
7
  export { getRenderedTile as getRenderedTileStream };
8
8
  export * as ChiitilerCache from './cache/index.js';
package/dist/index.js CHANGED
@@ -1,14 +1,14 @@
1
- import { getRenderedBbox, getRenderedTile, getRenderedImage, } from './render/index.js';
2
- export async function getRenderedBboxBuffer(options) {
3
- const sharp = await getRenderedBbox(options);
1
+ import { getRenderedClip, getRenderedTile, getRenderedCamera, } from './render/index.js';
2
+ export async function getRenderedClipBuffer(options) {
3
+ const sharp = await getRenderedClip(options);
4
4
  return sharp.toBuffer();
5
5
  }
6
- export { getRenderedBbox as getRenderedBboxStream };
7
- export async function getRenderedImageBuffer(options) {
8
- const sharp = await getRenderedImage(options);
6
+ export { getRenderedClip as getRenderedClipStream };
7
+ export async function getRenderedCameraBuffer(options) {
8
+ const sharp = await getRenderedCamera(options);
9
9
  return sharp.toBuffer();
10
10
  }
11
- export { getRenderedImage as getRenderedImageStream };
11
+ export { getRenderedCamera as getRenderedCameraStream };
12
12
  export async function getRenderedTileBuffer(options) {
13
13
  const sharp = await getRenderedTile(options);
14
14
  return sharp.toBuffer();
@@ -14,7 +14,7 @@ type GetRenderedTileOptions = {
14
14
  };
15
15
  type SupportedFormat = 'png' | 'jpeg' | 'jpg' | 'webp';
16
16
  declare function getRenderedTile({ stylejson, z, x, y, tileSize, cache, margin, ext, quality, }: GetRenderedTileOptions): Promise<sharp.Sharp>;
17
- type GetRenderedBboxOptions = {
17
+ type GetRenderedClipOptions = {
18
18
  stylejson: string | StyleSpecification;
19
19
  bbox: [number, number, number, number];
20
20
  size: number;
@@ -22,8 +22,8 @@ type GetRenderedBboxOptions = {
22
22
  ext: SupportedFormat;
23
23
  quality: number;
24
24
  };
25
- declare function getRenderedBbox({ stylejson, bbox, size, cache, ext, quality, }: GetRenderedBboxOptions): Promise<sharp.Sharp>;
26
- type GetRenderedImageOptions = {
25
+ declare function getRenderedClip({ stylejson, bbox, size, cache, ext, quality, }: GetRenderedClipOptions): Promise<sharp.Sharp>;
26
+ type GetRenderedCameraOptions = {
27
27
  stylejson: string | StyleSpecification;
28
28
  cache: Cache;
29
29
  ext: SupportedFormat;
@@ -35,5 +35,5 @@ type GetRenderedImageOptions = {
35
35
  height: number;
36
36
  width: number;
37
37
  };
38
- declare function getRenderedImage(options: GetRenderedImageOptions): Promise<sharp.Sharp>;
39
- export { getRenderedTile, getRenderedBbox, getRenderedImage, type GetRenderedBboxOptions, type GetRenderedTileOptions, type GetRenderedImageOptions, type SupportedFormat, };
38
+ declare function getRenderedCamera(options: GetRenderedCameraOptions): Promise<sharp.Sharp>;
39
+ export { getRenderedTile, getRenderedClip, getRenderedCamera, type GetRenderedClipOptions, type GetRenderedTileOptions, type GetRenderedCameraOptions, type SupportedFormat, };
@@ -1,6 +1,5 @@
1
1
  import sharp from 'sharp';
2
- // @ts-ignore
3
- import SphericalMercator from '@mapbox/sphericalmercator';
2
+ import { SphericalMercator } from '@mapbox/sphericalmercator';
4
3
  const mercator = new SphericalMercator();
5
4
  import { LRUCache } from 'lru-cache';
6
5
  import { renderTile, render } from './rasterize.js';
@@ -112,7 +111,7 @@ const calcRenderingParams = (bbox, size) => {
112
111
  const center = mercator.ll(mercCenter, 25); // latlon
113
112
  return { zoom, width, height, center };
114
113
  };
115
- async function getRenderedBbox({ stylejson, bbox, size, cache, ext, quality, }) {
114
+ async function getRenderedClip({ stylejson, bbox, size, cache, ext, quality, }) {
116
115
  const style = await loadStyle(stylejson, cache);
117
116
  const { zoom, width, height, center } = calcRenderingParams(bbox, size);
118
117
  const pixels = await render(style, {
@@ -138,7 +137,7 @@ async function getRenderedBbox({ stylejson, bbox, size, cache, ext, quality, })
138
137
  return _sharp.webp({ quality, effort: 0 });
139
138
  }
140
139
  }
141
- async function getRenderedImage(options) {
140
+ async function getRenderedCamera(options) {
142
141
  const style = await loadStyle(options.stylejson, options.cache);
143
142
  const pixels = await render(style, {
144
143
  center: options.center,
@@ -165,4 +164,4 @@ async function getRenderedImage(options) {
165
164
  return _sharp.webp({ quality: options.quality, effort: 0 });
166
165
  }
167
166
  }
168
- export { getRenderedTile, getRenderedBbox, getRenderedImage, };
167
+ export { getRenderedTile, getRenderedClip, getRenderedCamera, };
@@ -1,5 +1,4 @@
1
- // @ts-ignore
2
- import SphericalMercator from '@mapbox/sphericalmercator';
1
+ import { SphericalMercator } from '@mapbox/sphericalmercator';
3
2
  import { getRenderPool } from './pool.js';
4
3
  function getTileCenter(z, x, y, tileSize = 256) {
5
4
  const mercator = new SphericalMercator({
@@ -1,6 +1,6 @@
1
1
  import { Hono } from 'hono';
2
2
  import { isSupportedFormat, isValidStylejson } from '../utils.js';
3
- import { getRenderedImage } from '../../render/index.js';
3
+ import { getRenderedCamera } from '../../render/index.js';
4
4
  function isValidCamera({ zoom, lat, lon, bearing, pitch, }) {
5
5
  if (Number.isNaN(lat) || lat < -90 || lat > 90)
6
6
  return false;
@@ -51,7 +51,7 @@ function createCameraRouter(options) {
51
51
  const quality = Number(c.req.query('quality') ?? 100);
52
52
  c.header('Content-Type', `image/${ext}`);
53
53
  try {
54
- const sharp = await getRenderedImage({
54
+ const sharp = await getRenderedCamera({
55
55
  stylejson: url,
56
56
  cache: options.cache,
57
57
  ext,
@@ -104,7 +104,7 @@ function createCameraRouter(options) {
104
104
  const quality = Number(c.req.query('quality') ?? 100);
105
105
  c.header('Content-Type', `image/${ext}`);
106
106
  try {
107
- const sharp = await getRenderedImage({
107
+ const sharp = await getRenderedCamera({
108
108
  stylejson: style,
109
109
  cache: options.cache,
110
110
  ext,
@@ -1,6 +1,6 @@
1
1
  import { Hono } from 'hono';
2
2
  import { isSupportedFormat, isValidStylejson } from '../utils.js';
3
- import { getRenderedBbox } from '../../render/index.js';
3
+ import { getRenderedClip } from '../../render/index.js';
4
4
  function createClipRouter(options) {
5
5
  const clip = new Hono()
6
6
  .get('/:filename_ext', async (c) => {
@@ -24,7 +24,7 @@ function createClipRouter(options) {
24
24
  const size = Number(c.req.query('size') ?? 1024);
25
25
  c.header('Content-Type', `image/${ext}`);
26
26
  try {
27
- const sharp = await getRenderedBbox({
27
+ const sharp = await getRenderedClip({
28
28
  stylejson: url,
29
29
  bbox: [minx, miny, maxx, maxy],
30
30
  size,
@@ -62,7 +62,7 @@ function createClipRouter(options) {
62
62
  const size = Number(c.req.query('size') ?? 1024);
63
63
  c.header('Content-Type', `image/${ext}`);
64
64
  try {
65
- const sharp = await getRenderedBbox({
65
+ const sharp = await getRenderedClip({
66
66
  stylejson: style,
67
67
  bbox: [minx, miny, maxx, maxy],
68
68
  size,
@@ -1,6 +1,8 @@
1
1
  import { Cache } from '../cache/index.js';
2
2
  /**
3
- * retrieve sources from the uri
3
+ * retrieve sources from the uri.
4
+ * Concurrent requests for the same uri share a single in-flight fetch
5
+ * (single-flight) to avoid duplicate downloads.
4
6
  * @param uri
5
7
  * @param cache {Cache} - Cache Strategy. Affect only for http(s) sources.
6
8
  * @returns
@@ -6,30 +6,40 @@ import { getS3Source } from './s3.js';
6
6
  import { getGCSSource } from './gcs.js';
7
7
  import { getCogSource } from './cog.js';
8
8
  import { noneCache } from '../cache/index.js';
9
+ async function fetchSource(uri, cache) {
10
+ if (uri.startsWith('http://') || uri.startsWith('https://'))
11
+ return getHttpSource(uri, cache);
12
+ if (uri.startsWith('file://'))
13
+ return getFilesystemSource(uri);
14
+ if (uri.startsWith('s3://'))
15
+ return getS3Source(uri);
16
+ if (uri.startsWith('gs://'))
17
+ return getGCSSource(uri);
18
+ if (uri.startsWith('mbtiles://'))
19
+ return getMbtilesSource(uri);
20
+ if (uri.startsWith('pmtiles://'))
21
+ return getPmtilesSource(uri, cache);
22
+ if (uri.startsWith('cog://'))
23
+ return getCogSource(uri);
24
+ return null;
25
+ }
26
+ const inFlight = new Map();
9
27
  /**
10
- * retrieve sources from the uri
28
+ * retrieve sources from the uri.
29
+ * Concurrent requests for the same uri share a single in-flight fetch
30
+ * (single-flight) to avoid duplicate downloads.
11
31
  * @param uri
12
32
  * @param cache {Cache} - Cache Strategy. Affect only for http(s) sources.
13
33
  * @returns
14
34
  */
15
35
  async function getSource(uri, cache = noneCache()) {
16
- let data = null;
17
- if (uri.startsWith('http://') || uri.startsWith('https://'))
18
- data = await getHttpSource(uri, cache);
19
- else if (uri.startsWith('file://'))
20
- data = await getFilesystemSource(uri);
21
- else if (uri.startsWith('s3://'))
22
- data = await getS3Source(uri);
23
- else if (uri.startsWith('gs://'))
24
- data = await getGCSSource(uri);
25
- else if (uri.startsWith('mbtiles://'))
26
- data = await getMbtilesSource(uri);
27
- else if (uri.startsWith('pmtiles://'))
28
- data = await getPmtilesSource(uri, cache);
29
- else if (uri.startsWith('cog://'))
30
- data = await getCogSource(uri);
31
- else
32
- return null;
33
- return data;
36
+ const existing = inFlight.get(uri);
37
+ if (existing !== undefined)
38
+ return existing;
39
+ const promise = fetchSource(uri, cache).finally(() => {
40
+ inFlight.delete(uri);
41
+ });
42
+ inFlight.set(uri, promise);
43
+ return promise;
34
44
  }
35
45
  export { getSource };
package/package.json CHANGED
@@ -1,7 +1,7 @@
1
1
  {
2
2
  "type": "module",
3
3
  "name": "chiitiler",
4
- "version": "1.18.0",
4
+ "version": "1.20.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",
@@ -24,33 +24,33 @@
24
24
  "url": "https://github.com/Kanahiro/chiitiler"
25
25
  },
26
26
  "devDependencies": {
27
- "@tsconfig/node24": "^24.0.0",
27
+ "@tsconfig/node24": "^24.0.4",
28
28
  "@types/better-sqlite3": "^7.6.13",
29
- "@types/node": "^24.0.0",
30
- "@vitest/coverage-v8": "^4.0.16",
31
- "esbuild": "^0.27.2",
32
- "image-size": "^1.1.1",
29
+ "@types/node": "^25.6.0",
30
+ "@vitest/coverage-v8": "^4.1.4",
31
+ "esbuild": "^0.28.0",
32
+ "image-size": "^2.0.2",
33
33
  "tsx": "^4.21.0",
34
- "typescript": "^5.9.3",
35
- "vitest": "^4.0.16"
34
+ "typescript": "^6.0.3",
35
+ "vitest": "^4.1.4"
36
36
  },
37
37
  "dependencies": {
38
- "@aws-sdk/client-s3": "^3.418.0",
39
- "@google-cloud/storage": "^7.15.2",
40
- "@hono/node-server": "^1.19.8",
41
- "@mapbox/sphericalmercator": "^1.2.0",
42
- "@mapbox/tilebelt": "^1.0.2",
43
- "@maplibre/maplibre-gl-native": "^6.3.0",
44
- "@maplibre/maplibre-gl-style-spec": "^24.4.1",
45
- "better-sqlite3": "12.6.0",
46
- "commander": "^11.0.0",
47
- "file-system-cache": "^2.4.4",
38
+ "@aws-sdk/client-s3": "^3.1032.0",
39
+ "@google-cloud/storage": "^7.19.0",
40
+ "@hono/node-server": "^1.19.14",
41
+ "@mapbox/sphericalmercator": "^2.0.2",
42
+ "@mapbox/tilebelt": "^2.0.3",
43
+ "@maplibre/maplibre-gl-native": "^6.4.1",
44
+ "@maplibre/maplibre-gl-style-spec": "^24.8.1",
45
+ "better-sqlite3": "12.9.0",
46
+ "commander": "^14.0.3",
47
+ "file-system-cache": "^2.4.7",
48
48
  "higuruma": "^0.1.6",
49
- "hono": "^4.11.3",
50
- "lightning-pool": "^4.2.2",
51
- "lru-cache": "^11.0.0",
52
- "maplibre-gl": "^5.15.0",
53
- "pmtiles": "^3.0.5",
49
+ "hono": "^4.12.14",
50
+ "lightning-pool": "^4.12.0",
51
+ "lru-cache": "^11.3.5",
52
+ "maplibre-gl": "^5.23.0",
53
+ "pmtiles": "^4.4.1",
54
54
  "sharp": "^0.34.5"
55
55
  }
56
56
  }