styled-map-package-api 5.0.0-pre.2 → 5.0.0-pre.4
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 +94 -0
- package/dist/download.d.ts +11 -21
- package/dist/fallbacks.d.ts +32 -0
- package/dist/from-mbtiles.d.ts +1 -3
- package/dist/index.d.ts +11 -24
- package/dist/reader.d.ts +28 -12
- package/dist/server.d.ts +23 -14
- package/dist/style-downloader.d.ts +13 -19
- package/dist/tile-downloader.d.ts +13 -23
- package/dist/types.d.ts +61 -0
- package/dist/utils/errors.d.ts +2 -4
- package/dist/utils/fetch.d.ts +3 -8
- package/dist/utils/file-formats.d.ts +3 -10
- package/dist/utils/geo.d.ts +17 -9
- package/dist/utils/mapbox.d.ts +8 -10
- package/dist/utils/misc.d.ts +3 -5
- package/dist/utils/streams.d.ts +6 -10
- package/dist/utils/style.d.ts +27 -16
- package/dist/utils/templates.d.ts +30 -25
- package/dist/validator.d.ts +66 -0
- package/dist/writer.d.ts +157 -4
- package/lib/download.js +125 -0
- package/lib/fallbacks.js +157 -0
- package/lib/from-mbtiles.js +131 -0
- package/lib/index.js +12 -0
- package/lib/reader.js +360 -0
- package/lib/server.js +222 -0
- package/lib/style-downloader.js +369 -0
- package/lib/tile-downloader.js +189 -0
- package/lib/types.ts +99 -0
- package/lib/utils/errors.js +24 -0
- package/lib/utils/fetch.js +104 -0
- package/lib/utils/file-formats.js +92 -0
- package/lib/utils/geo.js +97 -0
- package/lib/utils/mapbox.js +155 -0
- package/{dist/utils/misc.d.cts → lib/utils/misc.js} +9 -5
- package/lib/utils/streams.js +101 -0
- package/lib/utils/style.js +206 -0
- package/lib/utils/templates.js +165 -0
- package/lib/validator.js +789 -0
- package/lib/writer.js +652 -0
- package/package.json +30 -78
- package/dist/download.cjs +0 -100
- package/dist/download.d.cts +0 -63
- package/dist/download.js +0 -76
- package/dist/from-mbtiles.cjs +0 -108
- package/dist/from-mbtiles.d.cts +0 -14
- package/dist/from-mbtiles.js +0 -84
- package/dist/index.cjs +0 -46
- package/dist/index.d.cts +0 -24
- package/dist/index.js +0 -16
- package/dist/reader.cjs +0 -287
- package/dist/reader.d.cts +0 -67
- package/dist/reader.js +0 -259
- package/dist/server.cjs +0 -73
- package/dist/server.d.cts +0 -45
- package/dist/server.js +0 -49
- package/dist/style-downloader.cjs +0 -314
- package/dist/style-downloader.d.cts +0 -118
- package/dist/style-downloader.js +0 -290
- package/dist/tile-downloader.cjs +0 -156
- package/dist/tile-downloader.d.cts +0 -82
- package/dist/tile-downloader.js +0 -124
- package/dist/types-qfyJk4ot.d.cts +0 -200
- package/dist/types-qfyJk4ot.d.ts +0 -200
- package/dist/utils/errors.cjs +0 -41
- package/dist/utils/errors.d.cts +0 -18
- package/dist/utils/errors.js +0 -16
- package/dist/utils/fetch.cjs +0 -97
- package/dist/utils/fetch.d.cts +0 -50
- package/dist/utils/fetch.js +0 -63
- package/dist/utils/file-formats.cjs +0 -96
- package/dist/utils/file-formats.d.cts +0 -32
- package/dist/utils/file-formats.js +0 -70
- package/dist/utils/geo.cjs +0 -84
- package/dist/utils/geo.d.cts +0 -46
- package/dist/utils/geo.js +0 -56
- package/dist/utils/mapbox.cjs +0 -121
- package/dist/utils/mapbox.d.cts +0 -43
- package/dist/utils/mapbox.js +0 -91
- package/dist/utils/misc.cjs +0 -39
- package/dist/utils/misc.js +0 -13
- package/dist/utils/streams.cjs +0 -99
- package/dist/utils/streams.d.cts +0 -49
- package/dist/utils/streams.js +0 -73
- package/dist/utils/style.cjs +0 -126
- package/dist/utils/style.d.cts +0 -66
- package/dist/utils/style.js +0 -98
- package/dist/utils/templates.cjs +0 -124
- package/dist/utils/templates.d.cts +0 -79
- package/dist/utils/templates.js +0 -85
- package/dist/writer.cjs +0 -539
- package/dist/writer.d.cts +0 -4
- package/dist/writer.js +0 -516
package/README.md
CHANGED
|
@@ -43,6 +43,53 @@ const server = createServer()
|
|
|
43
43
|
// server.fetch(request, reader) returns a WHATWG Response
|
|
44
44
|
```
|
|
45
45
|
|
|
46
|
+
### Fallback tiles and glyphs
|
|
47
|
+
|
|
48
|
+
When an SMP file doesn't contain every tile or glyph range that the style references, `createServer` can call fallback handlers instead of returning a 404. This is useful for previewing incomplete packages or packages that only cover a partial area/zoom range.
|
|
49
|
+
|
|
50
|
+
Built-in fallback handlers are provided:
|
|
51
|
+
|
|
52
|
+
```js
|
|
53
|
+
import {
|
|
54
|
+
emptyTileFallback,
|
|
55
|
+
emptyGlyphFallback,
|
|
56
|
+
} from 'styled-map-package-api/fallbacks'
|
|
57
|
+
import { createServer } from 'styled-map-package-api/server'
|
|
58
|
+
|
|
59
|
+
const server = createServer({
|
|
60
|
+
fallbackTile: emptyTileFallback,
|
|
61
|
+
fallbackGlyph: emptyGlyphFallback,
|
|
62
|
+
})
|
|
63
|
+
```
|
|
64
|
+
|
|
65
|
+
- **`emptyTileFallback(tileId, sourceInfo)`** — Returns an appropriate empty tile based on the source's tile format: empty gzipped MVT for vector sources, 1×1 transparent PNG/WebP for raster sources.
|
|
66
|
+
- **`emptyGlyphFallback(fontstack, range)`** — Returns an empty gzipped PBF (valid protobuf with no glyph entries), causing MapLibre to render missing characters as blank space instead of erroring on a 404.
|
|
67
|
+
|
|
68
|
+
For real glyph rendering with Noto Sans (80+ scripts), use the [`smp-noto-glyphs`](../glyphs/) package:
|
|
69
|
+
|
|
70
|
+
```js
|
|
71
|
+
import { notoGlyphFallback } from 'smp-noto-glyphs'
|
|
72
|
+
|
|
73
|
+
const server = createServer({
|
|
74
|
+
fallbackTile: emptyTileFallback,
|
|
75
|
+
fallbackGlyph: notoGlyphFallback,
|
|
76
|
+
})
|
|
77
|
+
```
|
|
78
|
+
|
|
79
|
+
You can also provide custom fallback handlers, for example to proxy missing tiles from an online source:
|
|
80
|
+
|
|
81
|
+
```js
|
|
82
|
+
const server = createServer({
|
|
83
|
+
fallbackTile: async (tileId, { sourceId, source }) => {
|
|
84
|
+
const url = `https://tiles.example.com/${tileId.z}/${tileId.x}/${tileId.y}.mvt`
|
|
85
|
+
return fetch(url)
|
|
86
|
+
},
|
|
87
|
+
fallbackGlyph: async (fontstack, range) => {
|
|
88
|
+
return fetch(`https://fonts.example.com/${fontstack}/${range}.pbf`)
|
|
89
|
+
},
|
|
90
|
+
})
|
|
91
|
+
```
|
|
92
|
+
|
|
46
93
|
### Downloading a map for offline use
|
|
47
94
|
|
|
48
95
|
```js
|
|
@@ -52,10 +99,13 @@ const stream = download({
|
|
|
52
99
|
styleUrl: 'https://demotiles.maplibre.org/style.json',
|
|
53
100
|
bbox: [-180, -80, 180, 80],
|
|
54
101
|
maxzoom: 5,
|
|
102
|
+
skipLocalGlyphs: true, // skip CJK/Hangul/Kana ranges rendered locally by MapLibre
|
|
55
103
|
})
|
|
56
104
|
// Pipe the ReadableStream to a file
|
|
57
105
|
```
|
|
58
106
|
|
|
107
|
+
The `skipLocalGlyphs` option skips downloading glyph ranges that MapLibre GL renders client-side via [`localIdeographFontFamily`](https://maplibre.org/maplibre-gl-js/docs/API/type-aliases/MapOptions/) (CJK, Hangul, Kana, Yi, and Halfwidth/Fullwidth Forms — 163 of 256 ranges). This significantly reduces download size for styles that use these scripts.
|
|
108
|
+
|
|
59
109
|
### Converting from MBTiles
|
|
60
110
|
|
|
61
111
|
> **Note:** MBTiles conversion requires Node >= 20 (uses `better-sqlite3` which dropped Node 18 support).
|
|
@@ -82,12 +132,56 @@ const stream = fromMBTiles(buffer)
|
|
|
82
132
|
| `styled-map-package-api/reader` | `Reader` class for reading `.smp` files |
|
|
83
133
|
| `styled-map-package-api/writer` | `Writer` class for creating `.smp` files |
|
|
84
134
|
| `styled-map-package-api/server` | `createServer()` — HTTP handler using WHATWG Request/Response |
|
|
135
|
+
| `styled-map-package-api/fallbacks` | `emptyTileFallback`, `emptyGlyphFallback` — built-in fallbacks |
|
|
85
136
|
| `styled-map-package-api/download` | `download()` — download an online map style for offline use |
|
|
86
137
|
| `styled-map-package-api/style-downloader` | `StyleDownloader` — downloads styles, sprites, and glyphs |
|
|
87
138
|
| `styled-map-package-api/tile-downloader` | `downloadTiles()` — downloads tile data |
|
|
88
139
|
| `styled-map-package-api/from-mbtiles` | `fromMBTiles()` — convert MBTiles to SMP stream |
|
|
140
|
+
| `styled-map-package-api/validator` | `validate()` — validate `.smp` files against the spec |
|
|
89
141
|
| `styled-map-package-api/utils/mapbox` | Mapbox URL detection and API utilities |
|
|
90
142
|
|
|
143
|
+
### Validating an SMP file
|
|
144
|
+
|
|
145
|
+
```js
|
|
146
|
+
import { validate } from 'styled-map-package-api/validator'
|
|
147
|
+
|
|
148
|
+
const result = await validate('path/to/map.smp')
|
|
149
|
+
|
|
150
|
+
if (!result.usable) {
|
|
151
|
+
console.error('File cannot be opened')
|
|
152
|
+
} else if (!result.valid) {
|
|
153
|
+
console.warn('File has issues but is usable')
|
|
154
|
+
}
|
|
155
|
+
|
|
156
|
+
for (const issue of result.issues) {
|
|
157
|
+
console.log(`[${issue.severity}] ${issue.message}`)
|
|
158
|
+
}
|
|
159
|
+
```
|
|
160
|
+
|
|
161
|
+
The validator checks an `.smp` file against the [SMP specification](../../spec/1.0/) and returns structured issues. Each issue has:
|
|
162
|
+
|
|
163
|
+
- **`kind`** — `'error'` (spec MUST violation) or `'warning'` (SHOULD/RECOMMENDED)
|
|
164
|
+
- **`severity`** — practical impact on the reader/renderer:
|
|
165
|
+
- `'fatal'` — the reader will fail to open the file
|
|
166
|
+
- `'rendering'` — the map opens but content will be visibly broken (missing tiles, glyphs, sprites)
|
|
167
|
+
- `'spec'` — non-compliance that doesn't affect practical use
|
|
168
|
+
- **`type`** — stable identifier for programmatic filtering (e.g. `'missing_tiles'`, `'incomplete_font_glyphs'`)
|
|
169
|
+
- **`message`** — human-readable description
|
|
170
|
+
- **`path`** — location context (e.g. `'sources.test.tiles'`, `'glyphs'`)
|
|
171
|
+
|
|
172
|
+
The result includes two convenience booleans:
|
|
173
|
+
|
|
174
|
+
- **`valid`** — `true` when there are no errors (spec-compliant)
|
|
175
|
+
- **`usable`** — `true` when there are no fatal issues (the file can be opened)
|
|
176
|
+
|
|
177
|
+
Accepts a file path (Node.js) or a `ZipReader` instance (browser). Options:
|
|
178
|
+
|
|
179
|
+
```js
|
|
180
|
+
const result = await validate('map.smp', {
|
|
181
|
+
maxEntries: 500_000, // max ZIP entries before aborting (default: 500,000)
|
|
182
|
+
})
|
|
183
|
+
```
|
|
184
|
+
|
|
91
185
|
### Browser support
|
|
92
186
|
|
|
93
187
|
All stream APIs use WHATWG `ReadableStream`, making the library compatible with both Node.js and browser environments. The `Reader` class accepts either a file path (Node.js) or a `ZipReader` instance (browser).
|
package/dist/download.d.ts
CHANGED
|
@@ -1,15 +1,3 @@
|
|
|
1
|
-
import { GlyphDownloadStats } from './style-downloader.js';
|
|
2
|
-
import { TileDownloadStats } from './tile-downloader.js';
|
|
3
|
-
import { D as DownloadStream } from './types-qfyJk4ot.js';
|
|
4
|
-
import { BBox } from './utils/geo.js';
|
|
5
|
-
import 'ky';
|
|
6
|
-
import '@maplibre/maplibre-gl-style-spec';
|
|
7
|
-
import './utils/fetch.js';
|
|
8
|
-
import './utils/streams.js';
|
|
9
|
-
import 'stream/web';
|
|
10
|
-
import 'geojson';
|
|
11
|
-
import 'type-fest';
|
|
12
|
-
|
|
13
1
|
/**
|
|
14
2
|
* @typedef {object} DownloadProgress
|
|
15
3
|
* @property {import('./tile-downloader.js').TileDownloadStats & { done: boolean }} tiles
|
|
@@ -25,22 +13,26 @@ import 'type-fest';
|
|
|
25
13
|
* containing all the resources needed to serve the style offline.
|
|
26
14
|
*
|
|
27
15
|
* @param {object} opts
|
|
28
|
-
* @param {import("./utils/geo.js").BBox} opts.bbox Bounding box to download tiles for
|
|
16
|
+
* @param {Readonly<import("./utils/geo.js").BBox>} opts.bbox Bounding box to download tiles for
|
|
29
17
|
* @param {number} opts.maxzoom Max zoom level to download tiles for
|
|
30
18
|
* @param {string} opts.styleUrl URL of the style to download
|
|
31
19
|
* @param { (progress: DownloadProgress) => void } [opts.onprogress] Optional callback for reporting progress
|
|
32
20
|
* @param {string} [opts.accessToken]
|
|
21
|
+
* @param {boolean} [opts.skipLocalGlyphs] Skip glyph ranges rendered client-side by MapLibre GL via localIdeographFontFamily (CJK, Hangul, Kana, Yi, etc.)
|
|
22
|
+
* @param {boolean} [opts.dedupe] When true, duplicate tiles are stored only once (see {@link Writer})
|
|
33
23
|
* @returns {import('./types.js').DownloadStream} Readable stream of the output styled map file
|
|
34
24
|
*/
|
|
35
|
-
|
|
36
|
-
bbox: BBox
|
|
25
|
+
export function download({ bbox, maxzoom, styleUrl, onprogress, accessToken, skipLocalGlyphs, dedupe, }: {
|
|
26
|
+
bbox: Readonly<import("./utils/geo.js").BBox>;
|
|
37
27
|
maxzoom: number;
|
|
38
28
|
styleUrl: string;
|
|
39
29
|
onprogress?: ((progress: DownloadProgress) => void) | undefined;
|
|
40
30
|
accessToken?: string | undefined;
|
|
41
|
-
|
|
42
|
-
|
|
43
|
-
|
|
31
|
+
skipLocalGlyphs?: boolean | undefined;
|
|
32
|
+
dedupe?: boolean | undefined;
|
|
33
|
+
}): import("./types.js").DownloadStream;
|
|
34
|
+
export type DownloadProgress = {
|
|
35
|
+
tiles: import("./tile-downloader.js").TileDownloadStats & {
|
|
44
36
|
done: boolean;
|
|
45
37
|
};
|
|
46
38
|
style: {
|
|
@@ -50,7 +42,7 @@ type DownloadProgress = {
|
|
|
50
42
|
downloaded: number;
|
|
51
43
|
done: boolean;
|
|
52
44
|
};
|
|
53
|
-
glyphs: GlyphDownloadStats & {
|
|
45
|
+
glyphs: import("./style-downloader.js").GlyphDownloadStats & {
|
|
54
46
|
done: boolean;
|
|
55
47
|
};
|
|
56
48
|
output: {
|
|
@@ -59,5 +51,3 @@ type DownloadProgress = {
|
|
|
59
51
|
};
|
|
60
52
|
elapsedMs: number;
|
|
61
53
|
};
|
|
62
|
-
|
|
63
|
-
export { type DownloadProgress, download };
|
|
@@ -0,0 +1,32 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Fallback tile handler for use with `createServer({ fallbackTile })`.
|
|
3
|
+
* Returns an appropriate empty tile based on the source's tile format:
|
|
4
|
+
* - vector sources → empty gzipped MVT
|
|
5
|
+
* - raster PNG sources → 1×1 transparent PNG
|
|
6
|
+
* - raster WebP sources → 1×1 transparent WebP
|
|
7
|
+
* - raster JPEG sources → 1×1 transparent PNG (no such thing as transparent JPEG)
|
|
8
|
+
*
|
|
9
|
+
* @param {{ x: number, y: number, z: number }} _tileId
|
|
10
|
+
* @param {{ sourceId: string, source: SMPSource }} sourceInfo
|
|
11
|
+
* @returns {Response}
|
|
12
|
+
*/
|
|
13
|
+
export function emptyTileFallback(_tileId: {
|
|
14
|
+
x: number;
|
|
15
|
+
y: number;
|
|
16
|
+
z: number;
|
|
17
|
+
}, { source }: {
|
|
18
|
+
sourceId: string;
|
|
19
|
+
source: SMPSource;
|
|
20
|
+
}): Response;
|
|
21
|
+
/**
|
|
22
|
+
* Fallback glyph handler for use with `createServer({ fallbackGlyph })`.
|
|
23
|
+
* Returns an empty gzipped PBF (valid protobuf with no glyph entries), which
|
|
24
|
+
* causes MapLibre to render missing characters as blank space instead of
|
|
25
|
+
* erroring on a 404.
|
|
26
|
+
*
|
|
27
|
+
* @param {string} _fontstack
|
|
28
|
+
* @param {string} _range
|
|
29
|
+
* @returns {Response}
|
|
30
|
+
*/
|
|
31
|
+
export function emptyGlyphFallback(_fontstack: string, _range: string): Response;
|
|
32
|
+
import type { SMPSource } from './types.js';
|
package/dist/from-mbtiles.d.ts
CHANGED
|
@@ -9,6 +9,4 @@
|
|
|
9
9
|
* (Node), OPFS path (browser Worker), or in-memory buffer.
|
|
10
10
|
* @returns {ReadableStream<Uint8Array>}
|
|
11
11
|
*/
|
|
12
|
-
|
|
13
|
-
|
|
14
|
-
export { fromMBTiles };
|
|
12
|
+
export function fromMBTiles(source: string | ArrayBuffer | Uint8Array): ReadableStream<Uint8Array>;
|
package/dist/index.d.ts
CHANGED
|
@@ -1,24 +1,11 @@
|
|
|
1
|
-
|
|
2
|
-
export {
|
|
3
|
-
export {
|
|
4
|
-
export {
|
|
5
|
-
export {
|
|
6
|
-
export {
|
|
7
|
-
export {
|
|
8
|
-
export {
|
|
9
|
-
import
|
|
10
|
-
import
|
|
11
|
-
|
|
12
|
-
import '@gmaclennan/zip-reader';
|
|
13
|
-
import 'itty-router';
|
|
14
|
-
import 'itty-router/IttyRouter';
|
|
15
|
-
import 'ky';
|
|
16
|
-
import './utils/geo.js';
|
|
17
|
-
import './utils/fetch.js';
|
|
18
|
-
import './utils/streams.js';
|
|
19
|
-
import 'stream/web';
|
|
20
|
-
|
|
21
|
-
type SMPSource = SMPSource$1;
|
|
22
|
-
type SMPStyle = SMPStyle$1;
|
|
23
|
-
|
|
24
|
-
export type { SMPSource, SMPStyle };
|
|
1
|
+
export { Reader } from "./reader.js";
|
|
2
|
+
export { Writer } from "./writer.js";
|
|
3
|
+
export { createServer } from "./server.js";
|
|
4
|
+
export { StyleDownloader } from "./style-downloader.js";
|
|
5
|
+
export { downloadTiles } from "./tile-downloader.js";
|
|
6
|
+
export { download } from "./download.js";
|
|
7
|
+
export { fromMBTiles } from "./from-mbtiles.js";
|
|
8
|
+
export { validate } from "./validator.js";
|
|
9
|
+
export type SMPSource = import("./types.js").SMPSource;
|
|
10
|
+
export type SMPStyle = import("./types.js").SMPStyle;
|
|
11
|
+
export { emptyTileFallback, emptyGlyphFallback } from "./fallbacks.js";
|
package/dist/reader.d.ts
CHANGED
|
@@ -1,9 +1,3 @@
|
|
|
1
|
-
import { a as SMPStyle } from './types-qfyJk4ot.js';
|
|
2
|
-
import * as _gmaclennan_zip_reader from '@gmaclennan/zip-reader';
|
|
3
|
-
import '@maplibre/maplibre-gl-style-spec';
|
|
4
|
-
import 'geojson';
|
|
5
|
-
import 'type-fest';
|
|
6
|
-
|
|
7
1
|
/**
|
|
8
2
|
* @typedef {object} Resource
|
|
9
3
|
* @property {string} resourceType
|
|
@@ -12,15 +6,25 @@ import 'type-fest';
|
|
|
12
6
|
* @property {ReadableStream<Uint8Array>} stream
|
|
13
7
|
* @property {'gzip'} [contentEncoding]
|
|
14
8
|
*/
|
|
9
|
+
/**
|
|
10
|
+
* @typedef {object} ReaderOptions
|
|
11
|
+
* @property {number} [maxEntries=500_000] Maximum number of ZIP entries to
|
|
12
|
+
* process. Exceeding this limit throws an error during `opened()`. Default is
|
|
13
|
+
* 500,000 (~a global z9 tileset).
|
|
14
|
+
* @property {number} [maxResourceSize=20 * 1024 * 1024] Maximum uncompressed
|
|
15
|
+
* size in bytes for a single resource returned by `getResource()`. Default is
|
|
16
|
+
* 20 MiB.
|
|
17
|
+
*/
|
|
15
18
|
/**
|
|
16
19
|
* A low-level reader for styled map packages. Returns resources in the package
|
|
17
20
|
* as readable streams, for serving over HTTP for example.
|
|
18
21
|
*/
|
|
19
|
-
|
|
22
|
+
export class Reader {
|
|
20
23
|
/**
|
|
21
24
|
* @param {string | import('@gmaclennan/zip-reader').ZipReader} filepathOrZip Path to styled map package (`.styledmap`) file, or a ZipReader instance
|
|
25
|
+
* @param {ReaderOptions} [options]
|
|
22
26
|
*/
|
|
23
|
-
constructor(filepathOrZip: string |
|
|
27
|
+
constructor(filepathOrZip: string | import("@gmaclennan/zip-reader").ZipReader, options?: ReaderOptions);
|
|
24
28
|
/**
|
|
25
29
|
* Resolves when the styled map package has been opened and the entries have
|
|
26
30
|
* been read. Throws any error that occurred during opening.
|
|
@@ -41,7 +45,7 @@ declare class Reader {
|
|
|
41
45
|
* @param {string | null} [baseUrl] Base URL where you plan to serve the resources in this styled map package, e.g. `http://localhost:3000/maps/styleA`
|
|
42
46
|
* @returns {Promise<import('./types.js').SMPStyle>}
|
|
43
47
|
*/
|
|
44
|
-
getStyle(baseUrl?: string | null): Promise<SMPStyle>;
|
|
48
|
+
getStyle(baseUrl?: string | null): Promise<import("./types.js").SMPStyle>;
|
|
45
49
|
/**
|
|
46
50
|
* Get a resource from the styled map package. The path should be relative to
|
|
47
51
|
* the root of the package.
|
|
@@ -56,12 +60,24 @@ declare class Reader {
|
|
|
56
60
|
close(): Promise<void>;
|
|
57
61
|
#private;
|
|
58
62
|
}
|
|
59
|
-
type Resource = {
|
|
63
|
+
export type Resource = {
|
|
60
64
|
resourceType: string;
|
|
61
65
|
contentType: string;
|
|
62
66
|
contentLength: number;
|
|
63
67
|
stream: ReadableStream<Uint8Array>;
|
|
64
68
|
contentEncoding?: "gzip" | undefined;
|
|
65
69
|
};
|
|
66
|
-
|
|
67
|
-
|
|
70
|
+
export type ReaderOptions = {
|
|
71
|
+
/**
|
|
72
|
+
* Maximum number of ZIP entries to
|
|
73
|
+
* process. Exceeding this limit throws an error during `opened()`. Default is
|
|
74
|
+
* 500,000 (~a global z9 tileset).
|
|
75
|
+
*/
|
|
76
|
+
maxEntries?: number | undefined;
|
|
77
|
+
/**
|
|
78
|
+
* Maximum uncompressed
|
|
79
|
+
* size in bytes for a single resource returned by `getResource()`. Default is
|
|
80
|
+
* 20 MiB.
|
|
81
|
+
*/
|
|
82
|
+
maxResourceSize?: number | undefined;
|
|
83
|
+
};
|
package/dist/server.d.ts
CHANGED
|
@@ -1,12 +1,3 @@
|
|
|
1
|
-
import { RequestLike } from 'itty-router';
|
|
2
|
-
import { Reader } from './reader.js';
|
|
3
|
-
import { IttyRouter } from 'itty-router/IttyRouter';
|
|
4
|
-
import './types-qfyJk4ot.js';
|
|
5
|
-
import '@maplibre/maplibre-gl-style-spec';
|
|
6
|
-
import 'geojson';
|
|
7
|
-
import 'type-fest';
|
|
8
|
-
import '@gmaclennan/zip-reader';
|
|
9
|
-
|
|
10
1
|
/**
|
|
11
2
|
* Create a server for serving styled map packages (SMP) over http. The server
|
|
12
3
|
* is a `fetch` handler that must be provided a WHATWG `Request` and a SMP
|
|
@@ -32,14 +23,32 @@ import '@gmaclennan/zip-reader';
|
|
|
32
23
|
*
|
|
33
24
|
* @param {object} [options]
|
|
34
25
|
* @param {string} [options.base='/'] Base path for the server routes
|
|
26
|
+
* @param {(tileId: { x: number, y: number, z: number }, sourceInfo: { sourceId: string, source: import('./types.js').SMPSource }) => Response | Promise<Response>} [options.fallbackTile] Called when a tile is missing from the SMP
|
|
27
|
+
* @param {(fontstack: string, range: string) => Response | Promise<Response>} [options.fallbackGlyph] Called when a glyph is missing from the SMP
|
|
35
28
|
* @returns {{ fetch: (request: RequestLike, reader: ReaderLike) => Promise<Response> }} server instance
|
|
36
29
|
*/
|
|
37
|
-
|
|
30
|
+
export function createServer({ base, fallbackTile, fallbackGlyph }?: {
|
|
38
31
|
base?: string | undefined;
|
|
32
|
+
fallbackTile?: ((tileId: {
|
|
33
|
+
x: number;
|
|
34
|
+
y: number;
|
|
35
|
+
z: number;
|
|
36
|
+
}, sourceInfo: {
|
|
37
|
+
sourceId: string;
|
|
38
|
+
source: import("./types.js").SMPSource;
|
|
39
|
+
}) => Response | Promise<Response>) | undefined;
|
|
40
|
+
fallbackGlyph?: ((fontstack: string, range: string) => Response | Promise<Response>) | undefined;
|
|
39
41
|
}): {
|
|
40
42
|
fetch: (request: RequestLike, reader: ReaderLike) => Promise<Response>;
|
|
41
43
|
};
|
|
42
|
-
type ReaderLike = Pick<Reader, keyof Reader>;
|
|
43
|
-
type RouterType = typeof IttyRouter<IRequestStrict, [ReaderLike], Response>;
|
|
44
|
-
|
|
45
|
-
|
|
44
|
+
export type ReaderLike = Pick<Reader, keyof Reader>;
|
|
45
|
+
export type RouterType = typeof IttyRouter<IRequestStrict, [ReaderLike], Response>;
|
|
46
|
+
export type TileMatcher = {
|
|
47
|
+
regex: RegExp;
|
|
48
|
+
sourceId: string;
|
|
49
|
+
source: import("./types.js").SMPSource;
|
|
50
|
+
};
|
|
51
|
+
import type { RequestLike } from 'itty-router';
|
|
52
|
+
import type { Reader } from './reader.js';
|
|
53
|
+
import { IttyRouter } from 'itty-router/IttyRouter';
|
|
54
|
+
import type { IRequestStrict } from 'itty-router';
|
|
@@ -1,14 +1,3 @@
|
|
|
1
|
-
import * as ky from 'ky';
|
|
2
|
-
import { BBox } from './utils/geo.js';
|
|
3
|
-
import { b as StyleInlinedSources, G as GlyphInfo, T as TileInfo } from './types-qfyJk4ot.js';
|
|
4
|
-
import { TileDownloadStats } from './tile-downloader.js';
|
|
5
|
-
import { StyleSpecification } from '@maplibre/maplibre-gl-style-spec';
|
|
6
|
-
import 'geojson';
|
|
7
|
-
import 'type-fest';
|
|
8
|
-
import './utils/fetch.js';
|
|
9
|
-
import './utils/streams.js';
|
|
10
|
-
import 'stream/web';
|
|
11
|
-
|
|
12
1
|
/** @import { SourceSpecification, StyleSpecification } from '@maplibre/maplibre-gl-style-spec' */
|
|
13
2
|
/** @import { TileInfo, GlyphInfo, GlyphRange } from './writer.js' */
|
|
14
3
|
/** @import { TileDownloadStats } from './tile-downloader.js' */
|
|
@@ -25,7 +14,7 @@ import 'stream/web';
|
|
|
25
14
|
* Download a style and its resources for offline use. Please check the terms of
|
|
26
15
|
* service of the map provider you are using before downloading any resources.
|
|
27
16
|
*/
|
|
28
|
-
|
|
17
|
+
export class StyleDownloader {
|
|
29
18
|
/**
|
|
30
19
|
* @param {string | StyleSpecification} style A url to a style JSON file or a style object
|
|
31
20
|
* @param {object} [opts]
|
|
@@ -71,10 +60,12 @@ declare class StyleDownloader {
|
|
|
71
60
|
*
|
|
72
61
|
* @param {object} opts
|
|
73
62
|
* @param {(progress: GlyphDownloadStats) => void} [opts.onprogress]
|
|
63
|
+
* @param {boolean} [opts.skipLocalGlyphs] Skip glyph ranges rendered client-side by MapLibre GL via localIdeographFontFamily (CJK, Hangul, Kana, Yi, etc.)
|
|
74
64
|
* @returns {AsyncGenerator<[ReadableStream<Uint8Array>, GlyphInfo]>}
|
|
75
65
|
*/
|
|
76
|
-
getGlyphs({ onprogress }?: {
|
|
66
|
+
getGlyphs({ onprogress, skipLocalGlyphs }?: {
|
|
77
67
|
onprogress?: ((progress: GlyphDownloadStats) => void) | undefined;
|
|
68
|
+
skipLocalGlyphs?: boolean | undefined;
|
|
78
69
|
}): AsyncGenerator<[ReadableStream<Uint8Array>, GlyphInfo]>;
|
|
79
70
|
/**
|
|
80
71
|
* Get all the tiles for this style within the given bounds and zoom range.
|
|
@@ -87,14 +78,14 @@ declare class StyleDownloader {
|
|
|
87
78
|
* bytes downloaded.
|
|
88
79
|
*
|
|
89
80
|
* @param {object} opts
|
|
90
|
-
* @param {import('./utils/geo.js').BBox} opts.bounds
|
|
81
|
+
* @param {Readonly<import('./utils/geo.js').BBox>} opts.bounds
|
|
91
82
|
* @param {number} opts.maxzoom
|
|
92
83
|
* @param {(progress: TileDownloadStats) => void} [opts.onprogress]
|
|
93
84
|
* @param {boolean} [opts.trackErrors=false] Include errors in the returned array of skipped tiles - this has memory overhead so should only be used for debugging.
|
|
94
85
|
* @returns {AsyncGenerator<[ReadableStream<Uint8Array>, TileInfo]> & { readonly skipped: Array<TileInfo & { error?: Error }>, readonly stats: TileDownloadStats }}
|
|
95
86
|
*/
|
|
96
87
|
getTiles({ bounds, maxzoom, onprogress, trackErrors }: {
|
|
97
|
-
bounds: BBox
|
|
88
|
+
bounds: Readonly<import("./utils/geo.js").BBox>;
|
|
98
89
|
maxzoom: number;
|
|
99
90
|
onprogress?: ((progress: TileDownloadStats) => void) | undefined;
|
|
100
91
|
trackErrors?: boolean | undefined;
|
|
@@ -106,13 +97,16 @@ declare class StyleDownloader {
|
|
|
106
97
|
};
|
|
107
98
|
#private;
|
|
108
99
|
}
|
|
109
|
-
type ResponsePromise = ky.ResponsePromise & {
|
|
100
|
+
export type ResponsePromise = import("ky").ResponsePromise & {
|
|
110
101
|
body: ReadableStream<Uint8Array>;
|
|
111
102
|
};
|
|
112
|
-
type GlyphDownloadStats = {
|
|
103
|
+
export type GlyphDownloadStats = {
|
|
113
104
|
total: number;
|
|
114
105
|
downloaded: number;
|
|
115
106
|
totalBytes: number;
|
|
116
107
|
};
|
|
117
|
-
|
|
118
|
-
|
|
108
|
+
import type { StyleInlinedSources } from './types.js';
|
|
109
|
+
import type { GlyphInfo } from './writer.js';
|
|
110
|
+
import type { TileDownloadStats } from './tile-downloader.js';
|
|
111
|
+
import type { TileInfo } from './writer.js';
|
|
112
|
+
import type { StyleSpecification } from '@maplibre/maplibre-gl-style-spec';
|
|
@@ -1,12 +1,3 @@
|
|
|
1
|
-
import { T as TileInfo$1 } from './types-qfyJk4ot.js';
|
|
2
|
-
import { BBox } from './utils/geo.js';
|
|
3
|
-
import { FetchQueue } from './utils/fetch.js';
|
|
4
|
-
import '@maplibre/maplibre-gl-style-spec';
|
|
5
|
-
import 'geojson';
|
|
6
|
-
import 'type-fest';
|
|
7
|
-
import './utils/streams.js';
|
|
8
|
-
import 'stream/web';
|
|
9
|
-
|
|
10
1
|
/** @typedef {Omit<import('./writer.js').TileInfo, 'sourceId'>} TileInfo */
|
|
11
2
|
/**
|
|
12
3
|
* @typedef {object} TileDownloadStats
|
|
@@ -21,11 +12,11 @@ import 'stream/web';
|
|
|
21
12
|
*
|
|
22
13
|
* @param {object} opts
|
|
23
14
|
* @param {string[]} opts.tileUrls Array of tile URL templates. Use `{x}`, `{y}`, `{z}` placeholders, and optional `{scheme}` placeholder which can be `xyz` or `tms`.
|
|
24
|
-
* @param {import('./utils/geo.js').BBox} opts.bounds Bounding box of the area to download
|
|
15
|
+
* @param {Readonly<import('./utils/geo.js').BBox>} opts.bounds Bounding box of the area to download
|
|
25
16
|
* @param {number} opts.maxzoom Maximum zoom level to download
|
|
26
17
|
* @param {(progress: TileDownloadStats) => void} [opts.onprogress] Callback to report download progress
|
|
27
18
|
* @param {boolean} [opts.trackErrors=false] Include errors in the returned array of skipped tiles - this has memory overhead so should only be used for debugging.
|
|
28
|
-
* @param {import('./utils/geo.js').BBox} [opts.sourceBounds=MAX_BOUNDS] Bounding box of source data.
|
|
19
|
+
* @param {Readonly<import('./utils/geo.js').BBox>} [opts.sourceBounds=MAX_BOUNDS] Bounding box of source data.
|
|
29
20
|
* @param {boolean} [opts.boundsBuffer=false] Buffer the bounds by one tile at each zoom level to ensure no tiles are missed at the edges. With this set to false, in most instances the map will appear incomplete when viewed because the downloaded tiles at lower zoom levels will not cover the map view area.
|
|
30
21
|
* @param {number} [opts.minzoom=0] Minimum zoom level to download (for most cases this should be left as `0` - the size overhead is minimal, because each zoom level has 4x as many tiles)
|
|
31
22
|
* @param {number} [opts.concurrency=8] Number of concurrent downloads (ignored if `fetchQueue` is provided)
|
|
@@ -33,13 +24,13 @@ import 'stream/web';
|
|
|
33
24
|
* @param {'xyz' | 'tms'} [opts.scheme='xyz'] Tile scheme to use for tile URLs
|
|
34
25
|
* @returns {AsyncGenerator<[ReadableStream<Uint8Array>, TileInfo]> & { readonly skipped: Array<TileInfo & { error?: Error }>, readonly stats: TileDownloadStats }}
|
|
35
26
|
*/
|
|
36
|
-
|
|
27
|
+
export function downloadTiles({ tileUrls, bounds, maxzoom, onprogress, trackErrors, sourceBounds, boundsBuffer, minzoom, concurrency, fetchQueue, scheme, }: {
|
|
37
28
|
tileUrls: string[];
|
|
38
|
-
bounds: BBox
|
|
29
|
+
bounds: Readonly<import("./utils/geo.js").BBox>;
|
|
39
30
|
maxzoom: number;
|
|
40
31
|
onprogress?: ((progress: TileDownloadStats) => void) | undefined;
|
|
41
32
|
trackErrors?: boolean | undefined;
|
|
42
|
-
sourceBounds?:
|
|
33
|
+
sourceBounds?: readonly [number, number, number, number] | undefined;
|
|
43
34
|
boundsBuffer?: boolean | undefined;
|
|
44
35
|
minzoom?: number | undefined;
|
|
45
36
|
concurrency?: number | undefined;
|
|
@@ -54,15 +45,15 @@ declare function downloadTiles({ tileUrls, bounds, maxzoom, onprogress, trackErr
|
|
|
54
45
|
/**
|
|
55
46
|
*
|
|
56
47
|
* @param {object} opts
|
|
57
|
-
* @param {import('./utils/geo.js').BBox} [opts.bounds]
|
|
58
|
-
* @param {import('./utils/geo.js').BBox} [opts.sourceBounds]
|
|
48
|
+
* @param {Readonly<import('./utils/geo.js').BBox>} [opts.bounds]
|
|
49
|
+
* @param {Readonly<import('./utils/geo.js').BBox>} [opts.sourceBounds]
|
|
59
50
|
* @param {boolean} [opts.boundsBuffer]
|
|
60
51
|
* @param {number} [opts.minzoom]
|
|
61
52
|
* @param {number} opts.maxzoom
|
|
62
53
|
*/
|
|
63
|
-
|
|
64
|
-
bounds?:
|
|
65
|
-
sourceBounds?:
|
|
54
|
+
export function tileIterator({ bounds, minzoom, maxzoom, sourceBounds, boundsBuffer, }: {
|
|
55
|
+
bounds?: readonly [number, number, number, number] | undefined;
|
|
56
|
+
sourceBounds?: readonly [number, number, number, number] | undefined;
|
|
66
57
|
boundsBuffer?: boolean | undefined;
|
|
67
58
|
minzoom?: number | undefined;
|
|
68
59
|
maxzoom: number;
|
|
@@ -71,12 +62,11 @@ declare function tileIterator({ bounds, minzoom, maxzoom, sourceBounds, boundsBu
|
|
|
71
62
|
y: number;
|
|
72
63
|
z: number;
|
|
73
64
|
}, void, unknown>;
|
|
74
|
-
type TileInfo = Omit<TileInfo
|
|
75
|
-
type TileDownloadStats = {
|
|
65
|
+
export type TileInfo = Omit<import("./writer.js").TileInfo, "sourceId">;
|
|
66
|
+
export type TileDownloadStats = {
|
|
76
67
|
total: number;
|
|
77
68
|
downloaded: number;
|
|
78
69
|
skipped: number;
|
|
79
70
|
totalBytes: number;
|
|
80
71
|
};
|
|
81
|
-
|
|
82
|
-
export { type TileDownloadStats, type TileInfo, downloadTiles, tileIterator };
|
|
72
|
+
import { FetchQueue } from './utils/fetch.js';
|
package/dist/types.d.ts
ADDED
|
@@ -0,0 +1,61 @@
|
|
|
1
|
+
import type { SourceSpecification, StyleSpecification, ValidationError, GeoJSONSourceSpecification, VectorSourceSpecification, RasterSourceSpecification, RasterDEMSourceSpecification } from '@maplibre/maplibre-gl-style-spec';
|
|
2
|
+
import type { GeoJSON, BBox } from 'geojson';
|
|
3
|
+
import type { SetRequired } from 'type-fest';
|
|
4
|
+
import { SUPPORTED_SOURCE_TYPES } from './writer.js';
|
|
5
|
+
export type InputSource = Extract<SourceSpecification, {
|
|
6
|
+
type: (typeof SUPPORTED_SOURCE_TYPES)[number];
|
|
7
|
+
}>;
|
|
8
|
+
type TransformInlinedSource<T extends SourceSpecification> = T extends GeoJSONSourceSpecification ? OmitUnion<T, 'data'> & {
|
|
9
|
+
data: GeoJSON;
|
|
10
|
+
} : T extends VectorSourceSpecification | RasterSourceSpecification | RasterDEMSourceSpecification ? SetRequired<OmitUnion<T, 'url'>, 'tiles'> : T;
|
|
11
|
+
/**
|
|
12
|
+
* This is a slightly stricter version of SourceSpecification that requires
|
|
13
|
+
* sources to be inlined (e.g. no urls to TileJSON or GeoJSON files).
|
|
14
|
+
*/
|
|
15
|
+
export type InlinedSource = TransformInlinedSource<SourceSpecification>;
|
|
16
|
+
type SupportedInlinedSource = Extract<InlinedSource, {
|
|
17
|
+
type: (typeof SUPPORTED_SOURCE_TYPES)[number];
|
|
18
|
+
}>;
|
|
19
|
+
/**
|
|
20
|
+
* This is a slightly stricter version of StyleSpecification that requires
|
|
21
|
+
* sources to be inlined (e.g. no urls to TileJSON or GeoJSON files).
|
|
22
|
+
*/
|
|
23
|
+
export type StyleInlinedSources = Omit<StyleSpecification, 'sources'> & {
|
|
24
|
+
sources: {
|
|
25
|
+
[_: string]: InlinedSource;
|
|
26
|
+
};
|
|
27
|
+
};
|
|
28
|
+
export type SMPSource = TransformSMPInputSource<SupportedInlinedSource>;
|
|
29
|
+
/**
|
|
30
|
+
* This is a slightly stricter version of StyleSpecification that is provided in
|
|
31
|
+
* a Styled Map Package. Tile sources must have tile URLs inlined (they cannot
|
|
32
|
+
* refer to a TileJSON url), and they must have bounds, minzoom, and maxzoom.
|
|
33
|
+
* GeoJSON sources must have inlined GeoJSON (not a URL to a GeoJSON file).
|
|
34
|
+
*/
|
|
35
|
+
export type SMPStyle = TransformSMPStyle<StyleSpecification>;
|
|
36
|
+
export type TransformSMPInputSource<T extends SupportedInlinedSource> = T extends GeoJSONSourceSpecification ? T & {
|
|
37
|
+
data: {
|
|
38
|
+
bbox: BBox;
|
|
39
|
+
};
|
|
40
|
+
} : T extends RasterSourceSpecification | VectorSourceSpecification ? SetRequired<T, 'bounds' | 'minzoom' | 'maxzoom'> : T;
|
|
41
|
+
type TransformSMPStyle<T extends StyleSpecification> = Omit<T, 'sources'> & {
|
|
42
|
+
metadata: {
|
|
43
|
+
'smp:bounds': [number, number, number, number];
|
|
44
|
+
'smp:maxzoom': 0;
|
|
45
|
+
'smp:sourceFolders': {
|
|
46
|
+
[_: string]: string;
|
|
47
|
+
};
|
|
48
|
+
[key: string]: unknown;
|
|
49
|
+
};
|
|
50
|
+
sources: {
|
|
51
|
+
[_: string]: SMPSource;
|
|
52
|
+
};
|
|
53
|
+
};
|
|
54
|
+
export interface ValidateStyle {
|
|
55
|
+
(style: unknown): style is StyleSpecification;
|
|
56
|
+
errors: Array<ValidationError>;
|
|
57
|
+
}
|
|
58
|
+
export type DownloadStream = ReadableStream<Uint8Array>;
|
|
59
|
+
export type RequiredUnion<T> = T extends any ? Required<T> : never;
|
|
60
|
+
export type OmitUnion<T, K extends keyof any> = T extends unknown ? Omit<T, K> : never;
|
|
61
|
+
export {};
|
package/dist/utils/errors.d.ts
CHANGED
|
@@ -5,14 +5,12 @@
|
|
|
5
5
|
* @param {unknown} error
|
|
6
6
|
* @returns {error is Error & { code: 'ENOENT' | 'EPERM' }}
|
|
7
7
|
*/
|
|
8
|
-
|
|
8
|
+
export function isFileNotThereError(error: unknown): error is Error & {
|
|
9
9
|
code: "ENOENT" | "EPERM";
|
|
10
10
|
};
|
|
11
|
-
|
|
11
|
+
export class ENOENT extends Error {
|
|
12
12
|
/** @param {string} path */
|
|
13
13
|
constructor(path: string);
|
|
14
14
|
code: string;
|
|
15
15
|
path: string;
|
|
16
16
|
}
|
|
17
|
-
|
|
18
|
-
export { ENOENT, isFileNotThereError };
|
package/dist/utils/fetch.d.ts
CHANGED
|
@@ -1,6 +1,3 @@
|
|
|
1
|
-
import { ProgressCallback } from './streams.js';
|
|
2
|
-
import 'stream/web';
|
|
3
|
-
|
|
4
1
|
/**
|
|
5
2
|
* @typedef {object} DownloadResponse
|
|
6
3
|
* @property {ReadableStream<Uint8Array>} body Web ReadableStream of the response body
|
|
@@ -10,7 +7,7 @@ import 'stream/web';
|
|
|
10
7
|
/**
|
|
11
8
|
* A wrapper for fetch that limits the number of concurrent downloads.
|
|
12
9
|
*/
|
|
13
|
-
|
|
10
|
+
export class FetchQueue {
|
|
14
11
|
/** @param {number} concurrency */
|
|
15
12
|
constructor(concurrency: number);
|
|
16
13
|
get activeCount(): number;
|
|
@@ -28,11 +25,11 @@ declare class FetchQueue {
|
|
|
28
25
|
* @returns {Promise<DownloadResponse>}
|
|
29
26
|
*/
|
|
30
27
|
fetch(url: string, { onprogress }?: {
|
|
31
|
-
onprogress?: ProgressCallback;
|
|
28
|
+
onprogress?: import("./streams.js").ProgressCallback;
|
|
32
29
|
}): Promise<DownloadResponse>;
|
|
33
30
|
#private;
|
|
34
31
|
}
|
|
35
|
-
type DownloadResponse = {
|
|
32
|
+
export type DownloadResponse = {
|
|
36
33
|
/**
|
|
37
34
|
* Web ReadableStream of the response body
|
|
38
35
|
*/
|
|
@@ -46,5 +43,3 @@ type DownloadResponse = {
|
|
|
46
43
|
*/
|
|
47
44
|
contentLength: number | null;
|
|
48
45
|
};
|
|
49
|
-
|
|
50
|
-
export { type DownloadResponse, FetchQueue };
|