chiitiler 1.23.6 → 1.23.8

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
@@ -62,6 +62,10 @@ You're done. That same endpoint works as an XYZ tile source for Leaflet, MapLibr
62
62
  - **[Allmaps Latest](https://bsky.app/profile/latest.allmaps.org)** — Bluesky bot
63
63
  - **[Kumoy](https://www.kumoy.io/)** - used for thumbnail image of designed maps
64
64
 
65
+ ## Presentations
66
+
67
+ - [FOSS4G Hiroshima 2026 — Presentation slides](https://drive.google.com/file/d/122JW5gJbrxnUVCVsSlcQMb22StPTnZQV/view?usp=sharing)
68
+
65
69
  ## HTTP API
66
70
 
67
71
  | Method | Endpoint | Description |
@@ -108,6 +112,21 @@ const png = await getRenderedTileBuffer({
108
112
 
109
113
  Available renderers: `getRenderedTileBuffer`, `getRenderedClipBuffer`, `getRenderedCameraBuffer`, and their `*Stream` variants (`Sharp` instances for further piping).
110
114
 
115
+ For library use, explicitly call `prewarm(cache)` once per rendering process
116
+ during application startup, before accepting requests:
117
+
118
+ ```ts
119
+ import { prewarm, ChiitilerCache } from 'chiitiler';
120
+
121
+ const cache = ChiitilerCache.noneCache();
122
+ await prewarm(cache);
123
+ ```
124
+
125
+ The promise resolves after a minimal tile has been rendered and PNG-encoded.
126
+ It rejects if warmup fails; the application decides whether to continue startup.
127
+ Library imports do not automatically run prewarm, and `CHIITILER_PREWARM` only
128
+ controls the CLI server. Style-specific tiles, glyphs, and sprites are not preloaded.
129
+
111
130
  Types are re-exported as well, so you can annotate call sites without depending on
112
131
  `@maplibre/maplibre-gl-style-spec` resolution in your own tree:
113
132
 
@@ -139,7 +158,7 @@ All options can be set via CLI flag or environment variable.
139
158
  | `--port <n>` | `CHIITILER_PORT` | `3000` |
140
159
  | `--debug` | `CHIITILER_DEBUG` | `false` |
141
160
  | `--user-agent <ua>` | `CHIITILER_USER_AGENT` | (none) |
142
- | `--no-prewarm` | `CHIITILER_PREWARM` | `true` |
161
+ | — | `CHIITILER_PREWARM` | `true` |
143
162
  | — | `CHIITILER_PROCESSES` | `1` (set `0` for all CPUs) |
144
163
 
145
164
  Prewarm is enabled by default: one tile is rendered at startup **before** the server starts listening, moving shared renderer initialization work into startup. Either `--no-prewarm` or `CHIITILER_PREWARM=false` disables it. Style-specific tiles, glyphs, and sprites are not preloaded.
package/dist/index.d.ts CHANGED
@@ -7,6 +7,7 @@ export declare function getRenderedTileBuffer(options: GetRenderedTileOptions):
7
7
  export { getRenderedTile as getRenderedTileStream };
8
8
  export * as ChiitilerCache from './cache/index.js';
9
9
  export { setUserAgent } from './source/userAgent.js';
10
+ export { prewarm } from './render/warmup.js';
10
11
  export type { GetRenderedClipOptions, GetRenderedTileOptions, GetRenderedCameraOptions, SupportedFormat, } from './render/index.js';
11
12
  export type { Cache } from './cache/index.js';
12
13
  export type { StyleSpecification } from '@maplibre/maplibre-gl-style-spec';
package/dist/index.js CHANGED
@@ -16,3 +16,4 @@ export async function getRenderedTileBuffer(options) {
16
16
  export { getRenderedTile as getRenderedTileStream };
17
17
  export * as ChiitilerCache from './cache/index.js';
18
18
  export { setUserAgent } from './source/userAgent.js';
19
+ export { prewarm } from './render/warmup.js';
@@ -12,7 +12,8 @@ const mapPoolCache = new LRUCache({
12
12
  },
13
13
  });
14
14
  async function getRenderPool(style, cache, mode) {
15
- const cacheKey = JSON.stringify(style);
15
+ // A Map's mode is fixed at creation; tile and static requests cannot share it.
16
+ const cacheKey = `${mode}:${JSON.stringify(style)}`;
16
17
  const pool = mapPoolCache.get(cacheKey);
17
18
  if (pool !== undefined)
18
19
  return pool;
@@ -1,9 +1,9 @@
1
1
  import type { Cache } from '../cache/index.js';
2
2
  /**
3
- * Render one z0 tile ahead of the first request so that renderer
4
- * initialization happens at startup — on AWS Lambda (with Lambda Web
5
- * Adapter's readiness check) this moves the work into the INIT phase,
6
- * which runs with a full CPU boost.
3
+ * Render and PNG-encode a minimal tile to warm shared renderer initialization.
4
+ * Await once per rendering process during application startup, before accepting
5
+ * requests. This does not preload style-specific tiles, glyphs, or sprites.
6
+ * Resolves after encoding finishes; rejects if rendering or encoding fails.
7
7
  */
8
8
  declare function prewarm(cache: Cache): Promise<void>;
9
9
  export { prewarm };
@@ -13,10 +13,10 @@ const MINIMAL_STYLE = {
13
13
  ],
14
14
  };
15
15
  /**
16
- * Render one z0 tile ahead of the first request so that renderer
17
- * initialization happens at startup — on AWS Lambda (with Lambda Web
18
- * Adapter's readiness check) this moves the work into the INIT phase,
19
- * which runs with a full CPU boost.
16
+ * Render and PNG-encode a minimal tile to warm shared renderer initialization.
17
+ * Await once per rendering process during application startup, before accepting
18
+ * requests. This does not preload style-specific tiles, glyphs, or sprites.
19
+ * Resolves after encoding finishes; rejects if rendering or encoding fails.
20
20
  */
21
21
  async function prewarm(cache) {
22
22
  const sharp = await getRenderedTile({
@@ -1,5 +1,5 @@
1
1
  import * as fs from 'fs';
2
- import { PMTiles, FetchSource, ResolvedValueCache, } from 'pmtiles';
2
+ import { PMTiles, FetchSource, SharedPromiseCache, } from 'pmtiles';
3
3
  import { GetObjectCommand, } from '@aws-sdk/client-s3';
4
4
  import { LRUCache } from 'lru-cache';
5
5
  import { getS3Client } from '../s3.js';
@@ -82,13 +82,15 @@ async function getPmtilesSource(uri, cache = noneCache()) {
82
82
  const val = await cache.get(uri);
83
83
  if (val !== undefined)
84
84
  return val; // hit
85
+ // Another request may have created the archive while cache.get awaited.
86
+ pmtiles = pmtilesCache.get(pmtilesUri);
85
87
  if (pmtiles === undefined) {
86
88
  const userAgent = getUserAgent();
87
89
  const headers = new Headers();
88
90
  if (userAgent)
89
91
  headers.set('User-Agent', userAgent);
90
92
  const fetchSource = new FetchSource(pmtilesUri, headers);
91
- pmtiles = new PMTiles(fetchSource, new ResolvedValueCache());
93
+ pmtiles = new PMTiles(fetchSource, new SharedPromiseCache());
92
94
  pmtilesCache.set(pmtilesUri, pmtiles);
93
95
  }
94
96
  }
@@ -97,19 +99,25 @@ async function getPmtilesSource(uri, cache = noneCache()) {
97
99
  const bucket = pmtilesUri.replace('s3://', '').split('/')[0];
98
100
  const key = pmtilesUri.replace(`s3://${bucket}/`, '');
99
101
  const s3Source = new S3Source(bucket, key);
100
- pmtiles = new PMTiles(s3Source, new ResolvedValueCache());
102
+ pmtiles = new PMTiles(s3Source, new SharedPromiseCache());
101
103
  pmtilesCache.set(pmtilesUri, pmtiles);
102
104
  }
103
105
  }
104
106
  else {
105
107
  if (pmtiles === undefined) {
106
108
  const fileSource = new FilesystemSource(pmtilesUri);
107
- pmtiles = new PMTiles(fileSource, new ResolvedValueCache());
109
+ pmtiles = new PMTiles(fileSource, new SharedPromiseCache());
108
110
  pmtilesCache.set(pmtilesUri, pmtiles);
109
111
  }
110
112
  }
111
113
  const [z, x, y] = uri.replace(`pmtiles://${pmtilesUri}/`, '').split('/');
112
- const tile = await pmtiles.getZxy(Number(z), Number(x), Number(y));
114
+ const tile = await pmtiles.getZxy(Number(z), Number(x), Number(y)).catch((err) => {
115
+ // SharedPromiseCache retains rejected metadata promises. Rebuild after a
116
+ // failure, without evicting a replacement created by a newer request.
117
+ if (pmtilesCache.get(pmtilesUri) === pmtiles)
118
+ pmtilesCache.delete(pmtilesUri);
119
+ throw err;
120
+ });
113
121
  if (!tile)
114
122
  return null;
115
123
  const buf = Buffer.from(tile.data);
package/package.json CHANGED
@@ -1,7 +1,7 @@
1
1
  {
2
2
  "type": "module",
3
3
  "name": "chiitiler",
4
- "version": "1.23.6",
4
+ "version": "1.23.8",
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,31 +24,31 @@
24
24
  "url": "https://github.com/Kanahiro/chiitiler"
25
25
  },
26
26
  "devDependencies": {
27
- "@tsconfig/node24": "^24.0.4",
27
+ "@tsconfig/node24": "^24.0.5",
28
28
  "@types/autocannon": "^7.12.7",
29
- "@types/node": "^25.6.0",
29
+ "@types/node": "^25.9.6",
30
30
  "@vitest/coverage-v8": "^4.1.4",
31
31
  "autocannon": "^8.0.0",
32
- "esbuild": "^0.28.0",
32
+ "esbuild": "^0.28.2",
33
33
  "image-size": "^2.0.2",
34
- "tsx": "^4.21.0",
34
+ "tsx": "^4.23.13",
35
35
  "typescript": "^6.0.3",
36
36
  "vitest": "^4.1.4"
37
37
  },
38
38
  "dependencies": {
39
- "@aws-sdk/client-s3": "^3.1032.0",
40
- "@google-cloud/storage": "^7.19.0",
41
- "@hono/node-server": "^2.0.0",
39
+ "@aws-sdk/client-s3": "^3.1131.0",
40
+ "@google-cloud/storage": "^7.22.0",
41
+ "@hono/node-server": "^2.1.1",
42
42
  "@mapbox/tilebelt": "^2.0.3",
43
43
  "@maplibre/maplibre-gl-native": "^6.4.1",
44
44
  "@maplibre/maplibre-gl-style-spec": "^26.4.2",
45
45
  "commander": "^14.0.3",
46
46
  "file-system-cache": "^2.4.7",
47
47
  "higuruma": "^0.1.6",
48
- "hono": "^4.12.14",
49
- "lightning-pool": "^4.12.0",
50
- "lru-cache": "^11.3.5",
51
- "pmtiles": "^4.4.1",
52
- "sharp": "^0.35.3"
48
+ "hono": "^4.13.7",
49
+ "lightning-pool": "^4.14.0",
50
+ "lru-cache": "^11.5.2",
51
+ "pmtiles": "^4.5.0",
52
+ "sharp": "^0.35.4"
53
53
  }
54
54
  }