styled-map-package-api 5.0.0-pre.0 → 5.0.0-pre.2
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 +97 -0
- package/dist/download.d.cts +1 -2
- package/dist/download.d.ts +1 -2
- package/dist/from-mbtiles.cjs +67 -40
- package/dist/from-mbtiles.d.cts +7 -3
- package/dist/from-mbtiles.d.ts +7 -3
- package/dist/from-mbtiles.js +67 -40
- package/dist/index.d.cts +2 -3
- package/dist/index.d.ts +2 -3
- package/dist/reader.cjs +1 -1
- package/dist/reader.d.cts +1 -2
- package/dist/reader.d.ts +1 -2
- package/dist/reader.js +1 -1
- package/dist/server.d.cts +1 -2
- package/dist/server.d.ts +1 -2
- package/dist/style-downloader.d.cts +1 -2
- package/dist/style-downloader.d.ts +1 -2
- package/dist/tile-downloader.d.cts +1 -2
- package/dist/tile-downloader.d.ts +1 -2
- package/dist/{types-CJq90eOB.d.cts → types-qfyJk4ot.d.cts} +20 -4
- package/dist/{types-CJq90eOB.d.ts → types-qfyJk4ot.d.ts} +20 -4
- package/dist/utils/file-formats.d.cts +1 -2
- package/dist/utils/file-formats.d.ts +1 -2
- package/dist/utils/style.d.cts +1 -2
- package/dist/utils/style.d.ts +1 -2
- package/dist/utils/templates.d.cts +1 -2
- package/dist/utils/templates.d.ts +1 -2
- package/dist/writer.cjs +79 -5
- package/dist/writer.d.cts +1 -2
- package/dist/writer.d.ts +1 -2
- package/dist/writer.js +69 -5
- package/package.json +6 -3
package/README.md
ADDED
|
@@ -0,0 +1,97 @@
|
|
|
1
|
+
# styled-map-package-api
|
|
2
|
+
|
|
3
|
+
JavaScript API for reading, writing, and serving Styled Map Package (`.smp`) files. Works in both Node.js and browsers.
|
|
4
|
+
|
|
5
|
+
An `.smp` file is a ZIP archive containing all the resources needed to serve a MapLibre vector styled map offline: style JSON, vector and raster tiles, glyphs (fonts), sprites, and metadata.
|
|
6
|
+
|
|
7
|
+
## Installation
|
|
8
|
+
|
|
9
|
+
```sh
|
|
10
|
+
npm install styled-map-package-api
|
|
11
|
+
```
|
|
12
|
+
|
|
13
|
+
## Usage
|
|
14
|
+
|
|
15
|
+
### Reading an SMP file
|
|
16
|
+
|
|
17
|
+
```js
|
|
18
|
+
import { Reader } from 'styled-map-package-api/reader'
|
|
19
|
+
|
|
20
|
+
const reader = new Reader('path/to/map.smp')
|
|
21
|
+
const style = await reader.getStyle()
|
|
22
|
+
```
|
|
23
|
+
|
|
24
|
+
### Writing an SMP file
|
|
25
|
+
|
|
26
|
+
```js
|
|
27
|
+
import { Writer } from 'styled-map-package-api/writer'
|
|
28
|
+
|
|
29
|
+
const writer = new Writer(style, sources)
|
|
30
|
+
const stream = writer.outputStream
|
|
31
|
+
// Pipe stream to a file or other writable destination
|
|
32
|
+
await writer.finish()
|
|
33
|
+
```
|
|
34
|
+
|
|
35
|
+
### Serving over HTTP
|
|
36
|
+
|
|
37
|
+
```js
|
|
38
|
+
import { Reader } from 'styled-map-package-api/reader'
|
|
39
|
+
import { createServer } from 'styled-map-package-api/server'
|
|
40
|
+
|
|
41
|
+
const reader = new Reader('path/to/map.smp')
|
|
42
|
+
const server = createServer()
|
|
43
|
+
// server.fetch(request, reader) returns a WHATWG Response
|
|
44
|
+
```
|
|
45
|
+
|
|
46
|
+
### Downloading a map for offline use
|
|
47
|
+
|
|
48
|
+
```js
|
|
49
|
+
import { download } from 'styled-map-package-api/download'
|
|
50
|
+
|
|
51
|
+
const stream = download({
|
|
52
|
+
styleUrl: 'https://demotiles.maplibre.org/style.json',
|
|
53
|
+
bbox: [-180, -80, 180, 80],
|
|
54
|
+
maxzoom: 5,
|
|
55
|
+
})
|
|
56
|
+
// Pipe the ReadableStream to a file
|
|
57
|
+
```
|
|
58
|
+
|
|
59
|
+
### Converting from MBTiles
|
|
60
|
+
|
|
61
|
+
> **Note:** MBTiles conversion requires Node >= 20 (uses `better-sqlite3` which dropped Node 18 support).
|
|
62
|
+
|
|
63
|
+
```js
|
|
64
|
+
import { fromMBTiles } from 'styled-map-package-api/from-mbtiles'
|
|
65
|
+
|
|
66
|
+
// From a file path (Node.js)
|
|
67
|
+
const stream = fromMBTiles('path/to/tiles.mbtiles')
|
|
68
|
+
|
|
69
|
+
// From an ArrayBuffer or Uint8Array (Node.js and browsers)
|
|
70
|
+
const stream = fromMBTiles(buffer)
|
|
71
|
+
|
|
72
|
+
// Pipe the ReadableStream to an .smp file
|
|
73
|
+
```
|
|
74
|
+
|
|
75
|
+
## API
|
|
76
|
+
|
|
77
|
+
### Exports
|
|
78
|
+
|
|
79
|
+
| Export path | Description |
|
|
80
|
+
| ----------------------------------------- | ----------------------------------------------------------------- |
|
|
81
|
+
| `styled-map-package-api` | Main entry — `Reader`, `Writer`, `createServer`, `download`, etc. |
|
|
82
|
+
| `styled-map-package-api/reader` | `Reader` class for reading `.smp` files |
|
|
83
|
+
| `styled-map-package-api/writer` | `Writer` class for creating `.smp` files |
|
|
84
|
+
| `styled-map-package-api/server` | `createServer()` — HTTP handler using WHATWG Request/Response |
|
|
85
|
+
| `styled-map-package-api/download` | `download()` — download an online map style for offline use |
|
|
86
|
+
| `styled-map-package-api/style-downloader` | `StyleDownloader` — downloads styles, sprites, and glyphs |
|
|
87
|
+
| `styled-map-package-api/tile-downloader` | `downloadTiles()` — downloads tile data |
|
|
88
|
+
| `styled-map-package-api/from-mbtiles` | `fromMBTiles()` — convert MBTiles to SMP stream |
|
|
89
|
+
| `styled-map-package-api/utils/mapbox` | Mapbox URL detection and API utilities |
|
|
90
|
+
|
|
91
|
+
### Browser support
|
|
92
|
+
|
|
93
|
+
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).
|
|
94
|
+
|
|
95
|
+
## License
|
|
96
|
+
|
|
97
|
+
MIT
|
package/dist/download.d.cts
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
import { GlyphDownloadStats } from './style-downloader.cjs';
|
|
2
2
|
import { TileDownloadStats } from './tile-downloader.cjs';
|
|
3
|
-
import { D as DownloadStream } from './types-
|
|
3
|
+
import { D as DownloadStream } from './types-qfyJk4ot.cjs';
|
|
4
4
|
import { BBox } from './utils/geo.cjs';
|
|
5
5
|
import 'ky';
|
|
6
6
|
import '@maplibre/maplibre-gl-style-spec';
|
|
@@ -9,7 +9,6 @@ import './utils/streams.cjs';
|
|
|
9
9
|
import 'stream/web';
|
|
10
10
|
import 'geojson';
|
|
11
11
|
import 'type-fest';
|
|
12
|
-
import 'events';
|
|
13
12
|
|
|
14
13
|
/**
|
|
15
14
|
* @typedef {object} DownloadProgress
|
package/dist/download.d.ts
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
import { GlyphDownloadStats } from './style-downloader.js';
|
|
2
2
|
import { TileDownloadStats } from './tile-downloader.js';
|
|
3
|
-
import { D as DownloadStream } from './types-
|
|
3
|
+
import { D as DownloadStream } from './types-qfyJk4ot.js';
|
|
4
4
|
import { BBox } from './utils/geo.js';
|
|
5
5
|
import 'ky';
|
|
6
6
|
import '@maplibre/maplibre-gl-style-spec';
|
|
@@ -9,7 +9,6 @@ import './utils/streams.js';
|
|
|
9
9
|
import 'stream/web';
|
|
10
10
|
import 'geojson';
|
|
11
11
|
import 'type-fest';
|
|
12
|
-
import 'events';
|
|
13
12
|
|
|
14
13
|
/**
|
|
15
14
|
* @typedef {object} DownloadProgress
|
package/dist/from-mbtiles.cjs
CHANGED
|
@@ -25,50 +25,77 @@ var import_mbtiles_reader = require("mbtiles-reader");
|
|
|
25
25
|
var import_streams = require('./utils/streams.cjs');
|
|
26
26
|
var import_writer = require('./writer.cjs');
|
|
27
27
|
const SOURCE_ID = "mbtiles-source";
|
|
28
|
-
function fromMBTiles(
|
|
29
|
-
|
|
30
|
-
|
|
31
|
-
|
|
32
|
-
|
|
33
|
-
|
|
34
|
-
|
|
35
|
-
|
|
36
|
-
|
|
37
|
-
[SOURCE_ID]: {
|
|
38
|
-
...reader.metadata,
|
|
39
|
-
type: "raster"
|
|
28
|
+
function fromMBTiles(source) {
|
|
29
|
+
let outputReader;
|
|
30
|
+
let conversionDone;
|
|
31
|
+
const pipeAbort = new AbortController();
|
|
32
|
+
return new ReadableStream({
|
|
33
|
+
async start() {
|
|
34
|
+
const reader = await import_mbtiles_reader.MBTiles.open(source);
|
|
35
|
+
if (reader.metadata.format === "pbf") {
|
|
36
|
+
throw new Error("Vector MBTiles are not yet supported");
|
|
40
37
|
}
|
|
41
|
-
|
|
42
|
-
|
|
43
|
-
|
|
44
|
-
|
|
45
|
-
|
|
46
|
-
|
|
47
|
-
|
|
48
|
-
|
|
49
|
-
|
|
50
|
-
|
|
51
|
-
|
|
52
|
-
|
|
53
|
-
|
|
54
|
-
|
|
55
|
-
|
|
38
|
+
const style = {
|
|
39
|
+
version: 8,
|
|
40
|
+
name: reader.metadata.name,
|
|
41
|
+
sources: {
|
|
42
|
+
[SOURCE_ID]: {
|
|
43
|
+
...reader.metadata,
|
|
44
|
+
type: "raster"
|
|
45
|
+
}
|
|
46
|
+
},
|
|
47
|
+
layers: [
|
|
48
|
+
{
|
|
49
|
+
id: "background",
|
|
50
|
+
type: "background",
|
|
51
|
+
paint: {
|
|
52
|
+
"background-color": "white"
|
|
53
|
+
}
|
|
54
|
+
},
|
|
55
|
+
{
|
|
56
|
+
id: "raster",
|
|
57
|
+
type: "raster",
|
|
58
|
+
source: SOURCE_ID,
|
|
59
|
+
paint: {
|
|
60
|
+
"raster-opacity": 1
|
|
61
|
+
}
|
|
62
|
+
}
|
|
63
|
+
]
|
|
64
|
+
};
|
|
65
|
+
const writer = new import_writer.Writer(style);
|
|
66
|
+
outputReader = writer.outputStream.getReader();
|
|
67
|
+
conversionDone = (async () => {
|
|
68
|
+
try {
|
|
69
|
+
await (0, import_streams.readableFromAsync)(mbtilesToTileArgs(reader)).pipeTo(
|
|
70
|
+
writer.createTileWriteStream(),
|
|
71
|
+
{ signal: pipeAbort.signal }
|
|
72
|
+
);
|
|
73
|
+
writer.finish();
|
|
74
|
+
} catch (err) {
|
|
75
|
+
try {
|
|
76
|
+
writer.abort(err instanceof Error ? err : new Error(String(err)));
|
|
77
|
+
} catch {
|
|
78
|
+
}
|
|
56
79
|
}
|
|
80
|
+
})();
|
|
81
|
+
},
|
|
82
|
+
async pull(controller) {
|
|
83
|
+
const { done, value } = await /** @type {ReadableStreamDefaultReader<Uint8Array>} */
|
|
84
|
+
outputReader.read();
|
|
85
|
+
if (done) {
|
|
86
|
+
controller.close();
|
|
87
|
+
} else {
|
|
88
|
+
controller.enqueue(value);
|
|
57
89
|
}
|
|
58
|
-
|
|
59
|
-
|
|
60
|
-
|
|
61
|
-
|
|
62
|
-
|
|
63
|
-
|
|
64
|
-
|
|
65
|
-
);
|
|
66
|
-
writer.finish();
|
|
67
|
-
} catch (err) {
|
|
68
|
-
writer.abort(err instanceof Error ? err : new Error(String(err)));
|
|
90
|
+
},
|
|
91
|
+
async cancel(reason) {
|
|
92
|
+
pipeAbort.abort(reason);
|
|
93
|
+
await conversionDone;
|
|
94
|
+
await /** @type {ReadableStreamDefaultReader<Uint8Array>} */
|
|
95
|
+
outputReader.cancel(reason).catch(() => {
|
|
96
|
+
});
|
|
69
97
|
}
|
|
70
|
-
})
|
|
71
|
-
return writer.outputStream;
|
|
98
|
+
});
|
|
72
99
|
}
|
|
73
100
|
async function* mbtilesToTileArgs(mbtiles) {
|
|
74
101
|
for (const { z, x, y, data, format } of mbtiles) {
|
package/dist/from-mbtiles.d.cts
CHANGED
|
@@ -1,10 +1,14 @@
|
|
|
1
1
|
/**
|
|
2
2
|
* Convert a MBTiles file to a styled map package, returned as a web
|
|
3
|
-
* ReadableStream.
|
|
3
|
+
* ReadableStream. The async MBTiles.open() happens lazily inside the
|
|
4
|
+
* stream's start(), so this function is synchronous.
|
|
4
5
|
*
|
|
5
|
-
*
|
|
6
|
+
* Requires Node >= 20 (uses better-sqlite3 which dropped Node 18 support).
|
|
7
|
+
*
|
|
8
|
+
* @param {string | ArrayBuffer | Uint8Array} source MBTiles source — file path
|
|
9
|
+
* (Node), OPFS path (browser Worker), or in-memory buffer.
|
|
6
10
|
* @returns {ReadableStream<Uint8Array>}
|
|
7
11
|
*/
|
|
8
|
-
declare function fromMBTiles(
|
|
12
|
+
declare function fromMBTiles(source: string | ArrayBuffer | Uint8Array): ReadableStream<Uint8Array>;
|
|
9
13
|
|
|
10
14
|
export { fromMBTiles };
|
package/dist/from-mbtiles.d.ts
CHANGED
|
@@ -1,10 +1,14 @@
|
|
|
1
1
|
/**
|
|
2
2
|
* Convert a MBTiles file to a styled map package, returned as a web
|
|
3
|
-
* ReadableStream.
|
|
3
|
+
* ReadableStream. The async MBTiles.open() happens lazily inside the
|
|
4
|
+
* stream's start(), so this function is synchronous.
|
|
4
5
|
*
|
|
5
|
-
*
|
|
6
|
+
* Requires Node >= 20 (uses better-sqlite3 which dropped Node 18 support).
|
|
7
|
+
*
|
|
8
|
+
* @param {string | ArrayBuffer | Uint8Array} source MBTiles source — file path
|
|
9
|
+
* (Node), OPFS path (browser Worker), or in-memory buffer.
|
|
6
10
|
* @returns {ReadableStream<Uint8Array>}
|
|
7
11
|
*/
|
|
8
|
-
declare function fromMBTiles(
|
|
12
|
+
declare function fromMBTiles(source: string | ArrayBuffer | Uint8Array): ReadableStream<Uint8Array>;
|
|
9
13
|
|
|
10
14
|
export { fromMBTiles };
|
package/dist/from-mbtiles.js
CHANGED
|
@@ -2,50 +2,77 @@ import { MBTiles } from "mbtiles-reader";
|
|
|
2
2
|
import { readableFromAsync } from "./utils/streams.js";
|
|
3
3
|
import { Writer } from "./writer.js";
|
|
4
4
|
const SOURCE_ID = "mbtiles-source";
|
|
5
|
-
function fromMBTiles(
|
|
6
|
-
|
|
7
|
-
|
|
8
|
-
|
|
9
|
-
|
|
10
|
-
|
|
11
|
-
|
|
12
|
-
|
|
13
|
-
|
|
14
|
-
[SOURCE_ID]: {
|
|
15
|
-
...reader.metadata,
|
|
16
|
-
type: "raster"
|
|
5
|
+
function fromMBTiles(source) {
|
|
6
|
+
let outputReader;
|
|
7
|
+
let conversionDone;
|
|
8
|
+
const pipeAbort = new AbortController();
|
|
9
|
+
return new ReadableStream({
|
|
10
|
+
async start() {
|
|
11
|
+
const reader = await MBTiles.open(source);
|
|
12
|
+
if (reader.metadata.format === "pbf") {
|
|
13
|
+
throw new Error("Vector MBTiles are not yet supported");
|
|
17
14
|
}
|
|
18
|
-
|
|
19
|
-
|
|
20
|
-
|
|
21
|
-
|
|
22
|
-
|
|
23
|
-
|
|
24
|
-
|
|
25
|
-
|
|
26
|
-
|
|
27
|
-
|
|
28
|
-
|
|
29
|
-
|
|
30
|
-
|
|
31
|
-
|
|
32
|
-
|
|
15
|
+
const style = {
|
|
16
|
+
version: 8,
|
|
17
|
+
name: reader.metadata.name,
|
|
18
|
+
sources: {
|
|
19
|
+
[SOURCE_ID]: {
|
|
20
|
+
...reader.metadata,
|
|
21
|
+
type: "raster"
|
|
22
|
+
}
|
|
23
|
+
},
|
|
24
|
+
layers: [
|
|
25
|
+
{
|
|
26
|
+
id: "background",
|
|
27
|
+
type: "background",
|
|
28
|
+
paint: {
|
|
29
|
+
"background-color": "white"
|
|
30
|
+
}
|
|
31
|
+
},
|
|
32
|
+
{
|
|
33
|
+
id: "raster",
|
|
34
|
+
type: "raster",
|
|
35
|
+
source: SOURCE_ID,
|
|
36
|
+
paint: {
|
|
37
|
+
"raster-opacity": 1
|
|
38
|
+
}
|
|
39
|
+
}
|
|
40
|
+
]
|
|
41
|
+
};
|
|
42
|
+
const writer = new Writer(style);
|
|
43
|
+
outputReader = writer.outputStream.getReader();
|
|
44
|
+
conversionDone = (async () => {
|
|
45
|
+
try {
|
|
46
|
+
await readableFromAsync(mbtilesToTileArgs(reader)).pipeTo(
|
|
47
|
+
writer.createTileWriteStream(),
|
|
48
|
+
{ signal: pipeAbort.signal }
|
|
49
|
+
);
|
|
50
|
+
writer.finish();
|
|
51
|
+
} catch (err) {
|
|
52
|
+
try {
|
|
53
|
+
writer.abort(err instanceof Error ? err : new Error(String(err)));
|
|
54
|
+
} catch {
|
|
55
|
+
}
|
|
33
56
|
}
|
|
57
|
+
})();
|
|
58
|
+
},
|
|
59
|
+
async pull(controller) {
|
|
60
|
+
const { done, value } = await /** @type {ReadableStreamDefaultReader<Uint8Array>} */
|
|
61
|
+
outputReader.read();
|
|
62
|
+
if (done) {
|
|
63
|
+
controller.close();
|
|
64
|
+
} else {
|
|
65
|
+
controller.enqueue(value);
|
|
34
66
|
}
|
|
35
|
-
|
|
36
|
-
|
|
37
|
-
|
|
38
|
-
|
|
39
|
-
|
|
40
|
-
|
|
41
|
-
|
|
42
|
-
);
|
|
43
|
-
writer.finish();
|
|
44
|
-
} catch (err) {
|
|
45
|
-
writer.abort(err instanceof Error ? err : new Error(String(err)));
|
|
67
|
+
},
|
|
68
|
+
async cancel(reason) {
|
|
69
|
+
pipeAbort.abort(reason);
|
|
70
|
+
await conversionDone;
|
|
71
|
+
await /** @type {ReadableStreamDefaultReader<Uint8Array>} */
|
|
72
|
+
outputReader.cancel(reason).catch(() => {
|
|
73
|
+
});
|
|
46
74
|
}
|
|
47
|
-
})
|
|
48
|
-
return writer.outputStream;
|
|
75
|
+
});
|
|
49
76
|
}
|
|
50
77
|
async function* mbtilesToTileArgs(mbtiles) {
|
|
51
78
|
for (const { z, x, y, data, format } of mbtiles) {
|
package/dist/index.d.cts
CHANGED
|
@@ -1,5 +1,5 @@
|
|
|
1
|
-
import { S as SMPSource$1, a as SMPStyle$1 } from './types-
|
|
2
|
-
export { W as Writer } from './types-
|
|
1
|
+
import { S as SMPSource$1, a as SMPStyle$1 } from './types-qfyJk4ot.cjs';
|
|
2
|
+
export { W as Writer } from './types-qfyJk4ot.cjs';
|
|
3
3
|
export { Reader } from './reader.cjs';
|
|
4
4
|
export { createServer } from './server.cjs';
|
|
5
5
|
export { StyleDownloader } from './style-downloader.cjs';
|
|
@@ -9,7 +9,6 @@ export { fromMBTiles } from './from-mbtiles.cjs';
|
|
|
9
9
|
import '@maplibre/maplibre-gl-style-spec';
|
|
10
10
|
import 'geojson';
|
|
11
11
|
import 'type-fest';
|
|
12
|
-
import 'events';
|
|
13
12
|
import '@gmaclennan/zip-reader';
|
|
14
13
|
import 'itty-router';
|
|
15
14
|
import 'itty-router/IttyRouter';
|
package/dist/index.d.ts
CHANGED
|
@@ -1,5 +1,5 @@
|
|
|
1
|
-
import { S as SMPSource$1, a as SMPStyle$1 } from './types-
|
|
2
|
-
export { W as Writer } from './types-
|
|
1
|
+
import { S as SMPSource$1, a as SMPStyle$1 } from './types-qfyJk4ot.js';
|
|
2
|
+
export { W as Writer } from './types-qfyJk4ot.js';
|
|
3
3
|
export { Reader } from './reader.js';
|
|
4
4
|
export { createServer } from './server.js';
|
|
5
5
|
export { StyleDownloader } from './style-downloader.js';
|
|
@@ -9,7 +9,6 @@ export { fromMBTiles } from './from-mbtiles.js';
|
|
|
9
9
|
import '@maplibre/maplibre-gl-style-spec';
|
|
10
10
|
import 'geojson';
|
|
11
11
|
import 'type-fest';
|
|
12
|
-
import 'events';
|
|
13
12
|
import '@gmaclennan/zip-reader';
|
|
14
13
|
import 'itty-router';
|
|
15
14
|
import 'itty-router/IttyRouter';
|
package/dist/reader.cjs
CHANGED
|
@@ -155,7 +155,7 @@ class Reader {
|
|
|
155
155
|
sourcePromise.catch(import_misc.noop);
|
|
156
156
|
zipPromise = sourcePromise.then((source) => {
|
|
157
157
|
this.#fileSource = source;
|
|
158
|
-
return import_zip_reader.ZipReader.from(source);
|
|
158
|
+
return import_zip_reader.ZipReader.from(source, { skipUniqueEntryCheck: true });
|
|
159
159
|
});
|
|
160
160
|
} else {
|
|
161
161
|
zipPromise = Promise.resolve(filepathOrZip);
|
package/dist/reader.d.cts
CHANGED
|
@@ -1,9 +1,8 @@
|
|
|
1
|
-
import { a as SMPStyle } from './types-
|
|
1
|
+
import { a as SMPStyle } from './types-qfyJk4ot.cjs';
|
|
2
2
|
import * as _gmaclennan_zip_reader from '@gmaclennan/zip-reader';
|
|
3
3
|
import '@maplibre/maplibre-gl-style-spec';
|
|
4
4
|
import 'geojson';
|
|
5
5
|
import 'type-fest';
|
|
6
|
-
import 'events';
|
|
7
6
|
|
|
8
7
|
/**
|
|
9
8
|
* @typedef {object} Resource
|
package/dist/reader.d.ts
CHANGED
|
@@ -1,9 +1,8 @@
|
|
|
1
|
-
import { a as SMPStyle } from './types-
|
|
1
|
+
import { a as SMPStyle } from './types-qfyJk4ot.js';
|
|
2
2
|
import * as _gmaclennan_zip_reader from '@gmaclennan/zip-reader';
|
|
3
3
|
import '@maplibre/maplibre-gl-style-spec';
|
|
4
4
|
import 'geojson';
|
|
5
5
|
import 'type-fest';
|
|
6
|
-
import 'events';
|
|
7
6
|
|
|
8
7
|
/**
|
|
9
8
|
* @typedef {object} Resource
|
package/dist/reader.js
CHANGED
|
@@ -128,7 +128,7 @@ class Reader {
|
|
|
128
128
|
sourcePromise.catch(noop);
|
|
129
129
|
zipPromise = sourcePromise.then((source) => {
|
|
130
130
|
this.#fileSource = source;
|
|
131
|
-
return ZipReader.from(source);
|
|
131
|
+
return ZipReader.from(source, { skipUniqueEntryCheck: true });
|
|
132
132
|
});
|
|
133
133
|
} else {
|
|
134
134
|
zipPromise = Promise.resolve(filepathOrZip);
|
package/dist/server.d.cts
CHANGED
|
@@ -1,11 +1,10 @@
|
|
|
1
1
|
import { RequestLike } from 'itty-router';
|
|
2
2
|
import { Reader } from './reader.cjs';
|
|
3
3
|
import { IttyRouter } from 'itty-router/IttyRouter';
|
|
4
|
-
import './types-
|
|
4
|
+
import './types-qfyJk4ot.cjs';
|
|
5
5
|
import '@maplibre/maplibre-gl-style-spec';
|
|
6
6
|
import 'geojson';
|
|
7
7
|
import 'type-fest';
|
|
8
|
-
import 'events';
|
|
9
8
|
import '@gmaclennan/zip-reader';
|
|
10
9
|
|
|
11
10
|
/**
|
package/dist/server.d.ts
CHANGED
|
@@ -1,11 +1,10 @@
|
|
|
1
1
|
import { RequestLike } from 'itty-router';
|
|
2
2
|
import { Reader } from './reader.js';
|
|
3
3
|
import { IttyRouter } from 'itty-router/IttyRouter';
|
|
4
|
-
import './types-
|
|
4
|
+
import './types-qfyJk4ot.js';
|
|
5
5
|
import '@maplibre/maplibre-gl-style-spec';
|
|
6
6
|
import 'geojson';
|
|
7
7
|
import 'type-fest';
|
|
8
|
-
import 'events';
|
|
9
8
|
import '@gmaclennan/zip-reader';
|
|
10
9
|
|
|
11
10
|
/**
|
|
@@ -1,11 +1,10 @@
|
|
|
1
1
|
import * as ky from 'ky';
|
|
2
2
|
import { BBox } from './utils/geo.cjs';
|
|
3
|
-
import { b as StyleInlinedSources, G as GlyphInfo, T as TileInfo } from './types-
|
|
3
|
+
import { b as StyleInlinedSources, G as GlyphInfo, T as TileInfo } from './types-qfyJk4ot.cjs';
|
|
4
4
|
import { TileDownloadStats } from './tile-downloader.cjs';
|
|
5
5
|
import { StyleSpecification } from '@maplibre/maplibre-gl-style-spec';
|
|
6
6
|
import 'geojson';
|
|
7
7
|
import 'type-fest';
|
|
8
|
-
import 'events';
|
|
9
8
|
import './utils/fetch.cjs';
|
|
10
9
|
import './utils/streams.cjs';
|
|
11
10
|
import 'stream/web';
|
|
@@ -1,11 +1,10 @@
|
|
|
1
1
|
import * as ky from 'ky';
|
|
2
2
|
import { BBox } from './utils/geo.js';
|
|
3
|
-
import { b as StyleInlinedSources, G as GlyphInfo, T as TileInfo } from './types-
|
|
3
|
+
import { b as StyleInlinedSources, G as GlyphInfo, T as TileInfo } from './types-qfyJk4ot.js';
|
|
4
4
|
import { TileDownloadStats } from './tile-downloader.js';
|
|
5
5
|
import { StyleSpecification } from '@maplibre/maplibre-gl-style-spec';
|
|
6
6
|
import 'geojson';
|
|
7
7
|
import 'type-fest';
|
|
8
|
-
import 'events';
|
|
9
8
|
import './utils/fetch.js';
|
|
10
9
|
import './utils/streams.js';
|
|
11
10
|
import 'stream/web';
|
|
@@ -1,10 +1,9 @@
|
|
|
1
|
-
import { T as TileInfo$1 } from './types-
|
|
1
|
+
import { T as TileInfo$1 } from './types-qfyJk4ot.cjs';
|
|
2
2
|
import { BBox } from './utils/geo.cjs';
|
|
3
3
|
import { FetchQueue } from './utils/fetch.cjs';
|
|
4
4
|
import '@maplibre/maplibre-gl-style-spec';
|
|
5
5
|
import 'geojson';
|
|
6
6
|
import 'type-fest';
|
|
7
|
-
import 'events';
|
|
8
7
|
import './utils/streams.cjs';
|
|
9
8
|
import 'stream/web';
|
|
10
9
|
|
|
@@ -1,10 +1,9 @@
|
|
|
1
|
-
import { T as TileInfo$1 } from './types-
|
|
1
|
+
import { T as TileInfo$1 } from './types-qfyJk4ot.js';
|
|
2
2
|
import { BBox } from './utils/geo.js';
|
|
3
3
|
import { FetchQueue } from './utils/fetch.js';
|
|
4
4
|
import '@maplibre/maplibre-gl-style-spec';
|
|
5
5
|
import 'geojson';
|
|
6
6
|
import 'type-fest';
|
|
7
|
-
import 'events';
|
|
8
7
|
import './utils/streams.js';
|
|
9
8
|
import 'stream/web';
|
|
10
9
|
|
|
@@ -1,7 +1,6 @@
|
|
|
1
1
|
import { StyleSpecification, SourceSpecification, GeoJSONSourceSpecification, VectorSourceSpecification, RasterSourceSpecification, RasterDEMSourceSpecification } from '@maplibre/maplibre-gl-style-spec';
|
|
2
2
|
import { GeoJSON, BBox } from 'geojson';
|
|
3
3
|
import { SetRequired } from 'type-fest';
|
|
4
|
-
import { EventEmitter } from 'events';
|
|
5
4
|
|
|
6
5
|
/** @typedef {string | Uint8Array | ReadableStream } Source */
|
|
7
6
|
/** @typedef {`${number}-${number}`} GlyphRange */
|
|
@@ -28,20 +27,28 @@ import { EventEmitter } from 'events';
|
|
|
28
27
|
/** @import { StyleSpecification } from '@maplibre/maplibre-gl-style-spec' */
|
|
29
28
|
/** @import { InputSource, SMPSource } from './types.js' */
|
|
30
29
|
declare const SUPPORTED_SOURCE_TYPES: readonly ["raster", "vector", "geojson"];
|
|
30
|
+
/**
|
|
31
|
+
* @typedef {object} WriterOptions
|
|
32
|
+
* @property {boolean} [dedupe] When true, duplicate tiles (with identical
|
|
33
|
+
* content) are stored only once in the archive. Additional entries in the
|
|
34
|
+
* central directory point to the same data. This reduces file size for
|
|
35
|
+
* tilesets with many repeated tiles (e.g. ocean tiles).
|
|
36
|
+
*/
|
|
31
37
|
/**
|
|
32
38
|
* Write a styled map package to a stream. Stream `writer.outputStream` to a
|
|
33
39
|
* destination, e.g. `fs.createWriteStream('my-map.styledmap')`. You must call
|
|
34
40
|
* `witer.finish()` and then wait for your writable stream to `finish` before
|
|
35
41
|
* using the output.
|
|
36
42
|
*/
|
|
37
|
-
declare class Writer
|
|
43
|
+
declare class Writer {
|
|
38
44
|
static SUPPORTED_SOURCE_TYPES: readonly ["raster", "vector", "geojson"];
|
|
39
45
|
/**
|
|
40
46
|
* @param {any} style A v7 or v8 MapLibre style. v7 styles will be migrated to
|
|
41
47
|
* v8. (There are currently no typescript declarations for v7 styles, hence
|
|
42
48
|
* this is typed as `any` and validated internally)
|
|
49
|
+
* @param {WriterOptions} [options]
|
|
43
50
|
*/
|
|
44
|
-
constructor(style: any);
|
|
51
|
+
constructor(style: any, { dedupe }?: WriterOptions);
|
|
45
52
|
/**
|
|
46
53
|
* @returns {ReadableStream<Uint8Array>} Readable stream of the styled map package
|
|
47
54
|
*/
|
|
@@ -132,6 +139,15 @@ type GlyphInfo = {
|
|
|
132
139
|
font: string;
|
|
133
140
|
range: GlyphRange;
|
|
134
141
|
};
|
|
142
|
+
type WriterOptions = {
|
|
143
|
+
/**
|
|
144
|
+
* When true, duplicate tiles (with identical
|
|
145
|
+
* content) are stored only once in the archive. Additional entries in the
|
|
146
|
+
* central directory point to the same data. This reduces file size for
|
|
147
|
+
* tilesets with many repeated tiles (e.g. ocean tiles).
|
|
148
|
+
*/
|
|
149
|
+
dedupe?: boolean | undefined;
|
|
150
|
+
};
|
|
135
151
|
|
|
136
152
|
type TransformInlinedSource<T extends SourceSpecification> = T extends GeoJSONSourceSpecification ? OmitUnion<T, 'data'> & {
|
|
137
153
|
data: GeoJSON;
|
|
@@ -181,4 +197,4 @@ type TransformSMPStyle<T extends StyleSpecification> = Omit<T, 'sources'> & {
|
|
|
181
197
|
type DownloadStream = ReadableStream<Uint8Array>;
|
|
182
198
|
type OmitUnion<T, K extends keyof any> = T extends unknown ? Omit<T, K> : never;
|
|
183
199
|
|
|
184
|
-
export { type DownloadStream as D, type GlyphInfo as G, type InlinedSource as I, type SMPSource as S, type TileInfo as T, Writer as W, type SMPStyle as a, type StyleInlinedSources as b, type TileFormat as c, type GlyphRange as d, SUPPORTED_SOURCE_TYPES as e, type Source as f, type SourceInfo as g };
|
|
200
|
+
export { type DownloadStream as D, type GlyphInfo as G, type InlinedSource as I, type SMPSource as S, type TileInfo as T, Writer as W, type SMPStyle as a, type StyleInlinedSources as b, type TileFormat as c, type GlyphRange as d, SUPPORTED_SOURCE_TYPES as e, type Source as f, type SourceInfo as g, type WriterOptions as h };
|
|
@@ -1,7 +1,6 @@
|
|
|
1
1
|
import { StyleSpecification, SourceSpecification, GeoJSONSourceSpecification, VectorSourceSpecification, RasterSourceSpecification, RasterDEMSourceSpecification } from '@maplibre/maplibre-gl-style-spec';
|
|
2
2
|
import { GeoJSON, BBox } from 'geojson';
|
|
3
3
|
import { SetRequired } from 'type-fest';
|
|
4
|
-
import { EventEmitter } from 'events';
|
|
5
4
|
|
|
6
5
|
/** @typedef {string | Uint8Array | ReadableStream } Source */
|
|
7
6
|
/** @typedef {`${number}-${number}`} GlyphRange */
|
|
@@ -28,20 +27,28 @@ import { EventEmitter } from 'events';
|
|
|
28
27
|
/** @import { StyleSpecification } from '@maplibre/maplibre-gl-style-spec' */
|
|
29
28
|
/** @import { InputSource, SMPSource } from './types.js' */
|
|
30
29
|
declare const SUPPORTED_SOURCE_TYPES: readonly ["raster", "vector", "geojson"];
|
|
30
|
+
/**
|
|
31
|
+
* @typedef {object} WriterOptions
|
|
32
|
+
* @property {boolean} [dedupe] When true, duplicate tiles (with identical
|
|
33
|
+
* content) are stored only once in the archive. Additional entries in the
|
|
34
|
+
* central directory point to the same data. This reduces file size for
|
|
35
|
+
* tilesets with many repeated tiles (e.g. ocean tiles).
|
|
36
|
+
*/
|
|
31
37
|
/**
|
|
32
38
|
* Write a styled map package to a stream. Stream `writer.outputStream` to a
|
|
33
39
|
* destination, e.g. `fs.createWriteStream('my-map.styledmap')`. You must call
|
|
34
40
|
* `witer.finish()` and then wait for your writable stream to `finish` before
|
|
35
41
|
* using the output.
|
|
36
42
|
*/
|
|
37
|
-
declare class Writer
|
|
43
|
+
declare class Writer {
|
|
38
44
|
static SUPPORTED_SOURCE_TYPES: readonly ["raster", "vector", "geojson"];
|
|
39
45
|
/**
|
|
40
46
|
* @param {any} style A v7 or v8 MapLibre style. v7 styles will be migrated to
|
|
41
47
|
* v8. (There are currently no typescript declarations for v7 styles, hence
|
|
42
48
|
* this is typed as `any` and validated internally)
|
|
49
|
+
* @param {WriterOptions} [options]
|
|
43
50
|
*/
|
|
44
|
-
constructor(style: any);
|
|
51
|
+
constructor(style: any, { dedupe }?: WriterOptions);
|
|
45
52
|
/**
|
|
46
53
|
* @returns {ReadableStream<Uint8Array>} Readable stream of the styled map package
|
|
47
54
|
*/
|
|
@@ -132,6 +139,15 @@ type GlyphInfo = {
|
|
|
132
139
|
font: string;
|
|
133
140
|
range: GlyphRange;
|
|
134
141
|
};
|
|
142
|
+
type WriterOptions = {
|
|
143
|
+
/**
|
|
144
|
+
* When true, duplicate tiles (with identical
|
|
145
|
+
* content) are stored only once in the archive. Additional entries in the
|
|
146
|
+
* central directory point to the same data. This reduces file size for
|
|
147
|
+
* tilesets with many repeated tiles (e.g. ocean tiles).
|
|
148
|
+
*/
|
|
149
|
+
dedupe?: boolean | undefined;
|
|
150
|
+
};
|
|
135
151
|
|
|
136
152
|
type TransformInlinedSource<T extends SourceSpecification> = T extends GeoJSONSourceSpecification ? OmitUnion<T, 'data'> & {
|
|
137
153
|
data: GeoJSON;
|
|
@@ -181,4 +197,4 @@ type TransformSMPStyle<T extends StyleSpecification> = Omit<T, 'sources'> & {
|
|
|
181
197
|
type DownloadStream = ReadableStream<Uint8Array>;
|
|
182
198
|
type OmitUnion<T, K extends keyof any> = T extends unknown ? Omit<T, K> : never;
|
|
183
199
|
|
|
184
|
-
export { type DownloadStream as D, type GlyphInfo as G, type InlinedSource as I, type SMPSource as S, type TileInfo as T, Writer as W, type SMPStyle as a, type StyleInlinedSources as b, type TileFormat as c, type GlyphRange as d, SUPPORTED_SOURCE_TYPES as e, type Source as f, type SourceInfo as g };
|
|
200
|
+
export { type DownloadStream as D, type GlyphInfo as G, type InlinedSource as I, type SMPSource as S, type TileInfo as T, Writer as W, type SMPStyle as a, type StyleInlinedSources as b, type TileFormat as c, type GlyphRange as d, SUPPORTED_SOURCE_TYPES as e, type Source as f, type SourceInfo as g, type WriterOptions as h };
|
|
@@ -1,8 +1,7 @@
|
|
|
1
|
-
import { c as TileFormat } from '../types-
|
|
1
|
+
import { c as TileFormat } from '../types-qfyJk4ot.cjs';
|
|
2
2
|
import '@maplibre/maplibre-gl-style-spec';
|
|
3
3
|
import 'geojson';
|
|
4
4
|
import 'type-fest';
|
|
5
|
-
import 'events';
|
|
6
5
|
|
|
7
6
|
/**
|
|
8
7
|
* For a given buffer, determine the tile format based on the magic bytes.
|
|
@@ -1,8 +1,7 @@
|
|
|
1
|
-
import { c as TileFormat } from '../types-
|
|
1
|
+
import { c as TileFormat } from '../types-qfyJk4ot.js';
|
|
2
2
|
import '@maplibre/maplibre-gl-style-spec';
|
|
3
3
|
import 'geojson';
|
|
4
4
|
import 'type-fest';
|
|
5
|
-
import 'events';
|
|
6
5
|
|
|
7
6
|
/**
|
|
8
7
|
* For a given buffer, determine the tile format based on the magic bytes.
|
package/dist/utils/style.d.cts
CHANGED
|
@@ -1,10 +1,9 @@
|
|
|
1
1
|
import { BBox } from './geo.cjs';
|
|
2
|
-
import { I as InlinedSource } from '../types-
|
|
2
|
+
import { I as InlinedSource } from '../types-qfyJk4ot.cjs';
|
|
3
3
|
import * as _maplibre_maplibre_gl_style_spec from '@maplibre/maplibre-gl-style-spec';
|
|
4
4
|
import { StyleSpecification, ValidationError } from '@maplibre/maplibre-gl-style-spec';
|
|
5
5
|
import 'geojson';
|
|
6
6
|
import 'type-fest';
|
|
7
|
-
import 'events';
|
|
8
7
|
|
|
9
8
|
/** @import {StyleSpecification, ExpressionSpecification, ValidationError} from '@maplibre/maplibre-gl-style-spec' */
|
|
10
9
|
/**
|
package/dist/utils/style.d.ts
CHANGED
|
@@ -1,10 +1,9 @@
|
|
|
1
1
|
import { BBox } from './geo.js';
|
|
2
|
-
import { I as InlinedSource } from '../types-
|
|
2
|
+
import { I as InlinedSource } from '../types-qfyJk4ot.js';
|
|
3
3
|
import * as _maplibre_maplibre_gl_style_spec from '@maplibre/maplibre-gl-style-spec';
|
|
4
4
|
import { StyleSpecification, ValidationError } from '@maplibre/maplibre-gl-style-spec';
|
|
5
5
|
import 'geojson';
|
|
6
6
|
import 'type-fest';
|
|
7
|
-
import 'events';
|
|
8
7
|
|
|
9
8
|
/** @import {StyleSpecification, ExpressionSpecification, ValidationError} from '@maplibre/maplibre-gl-style-spec' */
|
|
10
9
|
/**
|
|
@@ -1,8 +1,7 @@
|
|
|
1
1
|
import * as type_fest from 'type-fest';
|
|
2
|
-
import { d as GlyphRange, T as TileInfo, c as TileFormat } from '../types-
|
|
2
|
+
import { d as GlyphRange, T as TileInfo, c as TileFormat } from '../types-qfyJk4ot.cjs';
|
|
3
3
|
import '@maplibre/maplibre-gl-style-spec';
|
|
4
4
|
import 'geojson';
|
|
5
|
-
import 'events';
|
|
6
5
|
|
|
7
6
|
/**
|
|
8
7
|
* @param {string} path
|
|
@@ -1,8 +1,7 @@
|
|
|
1
1
|
import * as type_fest from 'type-fest';
|
|
2
|
-
import { d as GlyphRange, T as TileInfo, c as TileFormat } from '../types-
|
|
2
|
+
import { d as GlyphRange, T as TileInfo, c as TileFormat } from '../types-qfyJk4ot.js';
|
|
3
3
|
import '@maplibre/maplibre-gl-style-spec';
|
|
4
4
|
import 'geojson';
|
|
5
|
-
import 'events';
|
|
6
5
|
|
|
7
6
|
/**
|
|
8
7
|
* @param {string} path
|
package/dist/writer.cjs
CHANGED
|
@@ -1,7 +1,9 @@
|
|
|
1
1
|
"use strict";
|
|
2
|
+
var __create = Object.create;
|
|
2
3
|
var __defProp = Object.defineProperty;
|
|
3
4
|
var __getOwnPropDesc = Object.getOwnPropertyDescriptor;
|
|
4
5
|
var __getOwnPropNames = Object.getOwnPropertyNames;
|
|
6
|
+
var __getProtoOf = Object.getPrototypeOf;
|
|
5
7
|
var __hasOwnProp = Object.prototype.hasOwnProperty;
|
|
6
8
|
var __export = (target, all) => {
|
|
7
9
|
for (var name in all)
|
|
@@ -15,6 +17,14 @@ var __copyProps = (to, from, except, desc) => {
|
|
|
15
17
|
}
|
|
16
18
|
return to;
|
|
17
19
|
};
|
|
20
|
+
var __toESM = (mod, isNodeMode, target) => (target = mod != null ? __create(__getProtoOf(mod)) : {}, __copyProps(
|
|
21
|
+
// If the importer is in node compatibility mode or this is not an ESM
|
|
22
|
+
// file that has been converted to a CommonJS file using a Babel-
|
|
23
|
+
// compatible transform (i.e. "__esModule" has not been set), then set
|
|
24
|
+
// "default" to the CommonJS "module.exports" for node compatibility.
|
|
25
|
+
isNodeMode || !mod || !mod.__esModule ? __defProp(target, "default", { value: mod, enumerable: true }) : target,
|
|
26
|
+
mod
|
|
27
|
+
));
|
|
18
28
|
var __toCommonJS = (mod) => __copyProps(__defProp({}, "__esModule", { value: true }), mod);
|
|
19
29
|
var writer_exports = {};
|
|
20
30
|
__export(writer_exports, {
|
|
@@ -24,7 +34,6 @@ __export(writer_exports, {
|
|
|
24
34
|
module.exports = __toCommonJS(writer_exports);
|
|
25
35
|
var import_maplibre_gl_style_spec = require("@maplibre/maplibre-gl-style-spec");
|
|
26
36
|
var import_bbox = require("@turf/bbox");
|
|
27
|
-
var import_events = require("events");
|
|
28
37
|
var import_filter_obj = require("filter-obj");
|
|
29
38
|
var import_zip_writer = require("zip-writer");
|
|
30
39
|
var import_file_formats = require('./utils/file-formats.cjs');
|
|
@@ -41,7 +50,7 @@ const SUPPORTED_SOURCE_TYPES = (
|
|
|
41
50
|
"geojson"
|
|
42
51
|
]
|
|
43
52
|
);
|
|
44
|
-
class Writer
|
|
53
|
+
class Writer {
|
|
45
54
|
#zipWriter = new import_zip_writer.ZipWriter();
|
|
46
55
|
/** @type {Set<string>} */
|
|
47
56
|
#addedFiles = /* @__PURE__ */ new Set();
|
|
@@ -57,14 +66,20 @@ class Writer extends import_events.EventEmitter {
|
|
|
57
66
|
#outputStream;
|
|
58
67
|
/** @type {ReadableStreamDefaultController<Uint8Array>} */
|
|
59
68
|
#outputController;
|
|
69
|
+
/** @type {boolean} */
|
|
70
|
+
#dedupe;
|
|
71
|
+
/** @type {Map<string, string>} hash → first entry name */
|
|
72
|
+
#tileHashes = /* @__PURE__ */ new Map();
|
|
73
|
+
/** @type {Array<{ name: string, originalName: string }>} */
|
|
74
|
+
#duplicateEntries = [];
|
|
60
75
|
static SUPPORTED_SOURCE_TYPES = SUPPORTED_SOURCE_TYPES;
|
|
61
76
|
/**
|
|
62
77
|
* @param {any} style A v7 or v8 MapLibre style. v7 styles will be migrated to
|
|
63
78
|
* v8. (There are currently no typescript declarations for v7 styles, hence
|
|
64
79
|
* this is typed as `any` and validated internally)
|
|
80
|
+
* @param {WriterOptions} [options]
|
|
65
81
|
*/
|
|
66
|
-
constructor(style) {
|
|
67
|
-
super();
|
|
82
|
+
constructor(style, { dedupe = false } = {}) {
|
|
68
83
|
if (!style || !("version" in style)) {
|
|
69
84
|
throw new Error("Invalid style");
|
|
70
85
|
}
|
|
@@ -81,6 +96,7 @@ class Writer extends import_events.EventEmitter {
|
|
|
81
96
|
throw new AggregateError(errors, "Invalid style");
|
|
82
97
|
}
|
|
83
98
|
this.#style = styleCopy;
|
|
99
|
+
this.#dedupe = dedupe;
|
|
84
100
|
for (const [sourceId, source] of Object.entries(this.#style.sources)) {
|
|
85
101
|
if (source.type !== "geojson") continue;
|
|
86
102
|
this.#addSource(sourceId, source);
|
|
@@ -254,6 +270,23 @@ class Writer extends import_events.EventEmitter {
|
|
|
254
270
|
source.bounds = (0, import_geo.unionBBox)([source.bounds, bbox2]);
|
|
255
271
|
}
|
|
256
272
|
const name = (0, import_templates.getTileFilename)({ sourceId: encodedSourceId, z, x, y, format });
|
|
273
|
+
if (this.#dedupe) {
|
|
274
|
+
const data = await toUint8Array(tileData);
|
|
275
|
+
const hash = await hashData(data);
|
|
276
|
+
if (this.#addedFiles.has(name)) {
|
|
277
|
+
throw new Error(`${name} already added`);
|
|
278
|
+
}
|
|
279
|
+
this.#addedFiles.add(name);
|
|
280
|
+
const existingName = this.#tileHashes.get(hash);
|
|
281
|
+
if (existingName) {
|
|
282
|
+
this.#duplicateEntries.push({ name, originalName: existingName });
|
|
283
|
+
return;
|
|
284
|
+
}
|
|
285
|
+
this.#tileHashes.set(hash, name);
|
|
286
|
+
const readable = toWebStream(data);
|
|
287
|
+
await this.#zipWriter.addEntry({ readable, name, store: true });
|
|
288
|
+
return;
|
|
289
|
+
}
|
|
257
290
|
return this.#append(tileData, { name, store: true });
|
|
258
291
|
}
|
|
259
292
|
/**
|
|
@@ -318,7 +351,17 @@ class Writer extends import_events.EventEmitter {
|
|
|
318
351
|
this.#prepareStyle();
|
|
319
352
|
const style = JSON.stringify(this.#style);
|
|
320
353
|
await this.#append(style, { name: import_templates.STYLE_FILE });
|
|
321
|
-
|
|
354
|
+
let entries = await this.#zipWriter.entries();
|
|
355
|
+
if (this.#duplicateEntries.length > 0) {
|
|
356
|
+
const entriesByName = new Map(entries.map((e) => [e.name, e]));
|
|
357
|
+
for (const { name, originalName } of this.#duplicateEntries) {
|
|
358
|
+
const original = entriesByName.get(originalName);
|
|
359
|
+
if (!original) {
|
|
360
|
+
throw new Error(`Original entry ${originalName} not found`);
|
|
361
|
+
}
|
|
362
|
+
entries.push({ ...original, name });
|
|
363
|
+
}
|
|
364
|
+
}
|
|
322
365
|
const sortedEntries = sortEntries(entries);
|
|
323
366
|
await this.#zipWriter.finalize({ entries: sortedEntries });
|
|
324
367
|
}
|
|
@@ -432,6 +475,37 @@ function get2DBBox(bbox2) {
|
|
|
432
475
|
if (bbox2.length === 4) return bbox2;
|
|
433
476
|
return [bbox2[0], bbox2[1], bbox2[3], bbox2[4]];
|
|
434
477
|
}
|
|
478
|
+
async function toUint8Array(source) {
|
|
479
|
+
if (source instanceof Uint8Array) return source;
|
|
480
|
+
if (typeof source === "string") return new TextEncoder().encode(source);
|
|
481
|
+
const reader = (
|
|
482
|
+
/** @type {ReadableStream<Uint8Array>} */
|
|
483
|
+
source.getReader()
|
|
484
|
+
);
|
|
485
|
+
const chunks = [];
|
|
486
|
+
let totalLength = 0;
|
|
487
|
+
while (true) {
|
|
488
|
+
const { done, value } = await reader.read();
|
|
489
|
+
if (done) break;
|
|
490
|
+
chunks.push(value);
|
|
491
|
+
totalLength += value.byteLength;
|
|
492
|
+
}
|
|
493
|
+
const result = new Uint8Array(totalLength);
|
|
494
|
+
let offset = 0;
|
|
495
|
+
for (const chunk of chunks) {
|
|
496
|
+
result.set(chunk, offset);
|
|
497
|
+
offset += chunk.byteLength;
|
|
498
|
+
}
|
|
499
|
+
return result;
|
|
500
|
+
}
|
|
501
|
+
async function hashData(data) {
|
|
502
|
+
let c = globalThis.crypto;
|
|
503
|
+
if (!c) {
|
|
504
|
+
c = (await import("node:crypto")).webcrypto;
|
|
505
|
+
}
|
|
506
|
+
const buf = await c.subtle.digest("SHA-256", data);
|
|
507
|
+
return Array.from(new Uint8Array(buf)).map((b) => b.toString(16).padStart(2, "0")).join("");
|
|
508
|
+
}
|
|
435
509
|
function sortEntries(entries) {
|
|
436
510
|
return [...entries].sort((a, b) => {
|
|
437
511
|
if (a.name === import_templates.VERSION_FILE) return -1;
|
package/dist/writer.d.cts
CHANGED
|
@@ -1,5 +1,4 @@
|
|
|
1
|
-
export { G as GlyphInfo, d as GlyphRange, e as SUPPORTED_SOURCE_TYPES, f as Source, g as SourceInfo, c as TileFormat, T as TileInfo, W as Writer } from './types-
|
|
2
|
-
import 'events';
|
|
1
|
+
export { G as GlyphInfo, d as GlyphRange, e as SUPPORTED_SOURCE_TYPES, f as Source, g as SourceInfo, c as TileFormat, T as TileInfo, W as Writer, h as WriterOptions } from './types-qfyJk4ot.cjs';
|
|
3
2
|
import '@maplibre/maplibre-gl-style-spec';
|
|
4
3
|
import 'geojson';
|
|
5
4
|
import 'type-fest';
|
package/dist/writer.d.ts
CHANGED
|
@@ -1,5 +1,4 @@
|
|
|
1
|
-
export { G as GlyphInfo, d as GlyphRange, e as SUPPORTED_SOURCE_TYPES, f as Source, g as SourceInfo, c as TileFormat, T as TileInfo, W as Writer } from './types-
|
|
2
|
-
import 'events';
|
|
1
|
+
export { G as GlyphInfo, d as GlyphRange, e as SUPPORTED_SOURCE_TYPES, f as Source, g as SourceInfo, c as TileFormat, T as TileInfo, W as Writer, h as WriterOptions } from './types-qfyJk4ot.js';
|
|
3
2
|
import '@maplibre/maplibre-gl-style-spec';
|
|
4
3
|
import 'geojson';
|
|
5
4
|
import 'type-fest';
|
package/dist/writer.js
CHANGED
|
@@ -1,6 +1,5 @@
|
|
|
1
1
|
import { validateStyleMin, migrate } from "@maplibre/maplibre-gl-style-spec";
|
|
2
2
|
import { bbox } from "@turf/bbox";
|
|
3
|
-
import { EventEmitter } from "events";
|
|
4
3
|
import { excludeKeys } from "filter-obj";
|
|
5
4
|
import { ZipWriter } from "zip-writer";
|
|
6
5
|
import { getTileFormatFromStream } from "./utils/file-formats.js";
|
|
@@ -29,7 +28,7 @@ const SUPPORTED_SOURCE_TYPES = (
|
|
|
29
28
|
"geojson"
|
|
30
29
|
]
|
|
31
30
|
);
|
|
32
|
-
class Writer
|
|
31
|
+
class Writer {
|
|
33
32
|
#zipWriter = new ZipWriter();
|
|
34
33
|
/** @type {Set<string>} */
|
|
35
34
|
#addedFiles = /* @__PURE__ */ new Set();
|
|
@@ -45,14 +44,20 @@ class Writer extends EventEmitter {
|
|
|
45
44
|
#outputStream;
|
|
46
45
|
/** @type {ReadableStreamDefaultController<Uint8Array>} */
|
|
47
46
|
#outputController;
|
|
47
|
+
/** @type {boolean} */
|
|
48
|
+
#dedupe;
|
|
49
|
+
/** @type {Map<string, string>} hash → first entry name */
|
|
50
|
+
#tileHashes = /* @__PURE__ */ new Map();
|
|
51
|
+
/** @type {Array<{ name: string, originalName: string }>} */
|
|
52
|
+
#duplicateEntries = [];
|
|
48
53
|
static SUPPORTED_SOURCE_TYPES = SUPPORTED_SOURCE_TYPES;
|
|
49
54
|
/**
|
|
50
55
|
* @param {any} style A v7 or v8 MapLibre style. v7 styles will be migrated to
|
|
51
56
|
* v8. (There are currently no typescript declarations for v7 styles, hence
|
|
52
57
|
* this is typed as `any` and validated internally)
|
|
58
|
+
* @param {WriterOptions} [options]
|
|
53
59
|
*/
|
|
54
|
-
constructor(style) {
|
|
55
|
-
super();
|
|
60
|
+
constructor(style, { dedupe = false } = {}) {
|
|
56
61
|
if (!style || !("version" in style)) {
|
|
57
62
|
throw new Error("Invalid style");
|
|
58
63
|
}
|
|
@@ -69,6 +74,7 @@ class Writer extends EventEmitter {
|
|
|
69
74
|
throw new AggregateError(errors, "Invalid style");
|
|
70
75
|
}
|
|
71
76
|
this.#style = styleCopy;
|
|
77
|
+
this.#dedupe = dedupe;
|
|
72
78
|
for (const [sourceId, source] of Object.entries(this.#style.sources)) {
|
|
73
79
|
if (source.type !== "geojson") continue;
|
|
74
80
|
this.#addSource(sourceId, source);
|
|
@@ -242,6 +248,23 @@ class Writer extends EventEmitter {
|
|
|
242
248
|
source.bounds = unionBBox([source.bounds, bbox2]);
|
|
243
249
|
}
|
|
244
250
|
const name = getTileFilename({ sourceId: encodedSourceId, z, x, y, format });
|
|
251
|
+
if (this.#dedupe) {
|
|
252
|
+
const data = await toUint8Array(tileData);
|
|
253
|
+
const hash = await hashData(data);
|
|
254
|
+
if (this.#addedFiles.has(name)) {
|
|
255
|
+
throw new Error(`${name} already added`);
|
|
256
|
+
}
|
|
257
|
+
this.#addedFiles.add(name);
|
|
258
|
+
const existingName = this.#tileHashes.get(hash);
|
|
259
|
+
if (existingName) {
|
|
260
|
+
this.#duplicateEntries.push({ name, originalName: existingName });
|
|
261
|
+
return;
|
|
262
|
+
}
|
|
263
|
+
this.#tileHashes.set(hash, name);
|
|
264
|
+
const readable = toWebStream(data);
|
|
265
|
+
await this.#zipWriter.addEntry({ readable, name, store: true });
|
|
266
|
+
return;
|
|
267
|
+
}
|
|
245
268
|
return this.#append(tileData, { name, store: true });
|
|
246
269
|
}
|
|
247
270
|
/**
|
|
@@ -306,7 +329,17 @@ class Writer extends EventEmitter {
|
|
|
306
329
|
this.#prepareStyle();
|
|
307
330
|
const style = JSON.stringify(this.#style);
|
|
308
331
|
await this.#append(style, { name: STYLE_FILE });
|
|
309
|
-
|
|
332
|
+
let entries = await this.#zipWriter.entries();
|
|
333
|
+
if (this.#duplicateEntries.length > 0) {
|
|
334
|
+
const entriesByName = new Map(entries.map((e) => [e.name, e]));
|
|
335
|
+
for (const { name, originalName } of this.#duplicateEntries) {
|
|
336
|
+
const original = entriesByName.get(originalName);
|
|
337
|
+
if (!original) {
|
|
338
|
+
throw new Error(`Original entry ${originalName} not found`);
|
|
339
|
+
}
|
|
340
|
+
entries.push({ ...original, name });
|
|
341
|
+
}
|
|
342
|
+
}
|
|
310
343
|
const sortedEntries = sortEntries(entries);
|
|
311
344
|
await this.#zipWriter.finalize({ entries: sortedEntries });
|
|
312
345
|
}
|
|
@@ -420,6 +453,37 @@ function get2DBBox(bbox2) {
|
|
|
420
453
|
if (bbox2.length === 4) return bbox2;
|
|
421
454
|
return [bbox2[0], bbox2[1], bbox2[3], bbox2[4]];
|
|
422
455
|
}
|
|
456
|
+
async function toUint8Array(source) {
|
|
457
|
+
if (source instanceof Uint8Array) return source;
|
|
458
|
+
if (typeof source === "string") return new TextEncoder().encode(source);
|
|
459
|
+
const reader = (
|
|
460
|
+
/** @type {ReadableStream<Uint8Array>} */
|
|
461
|
+
source.getReader()
|
|
462
|
+
);
|
|
463
|
+
const chunks = [];
|
|
464
|
+
let totalLength = 0;
|
|
465
|
+
while (true) {
|
|
466
|
+
const { done, value } = await reader.read();
|
|
467
|
+
if (done) break;
|
|
468
|
+
chunks.push(value);
|
|
469
|
+
totalLength += value.byteLength;
|
|
470
|
+
}
|
|
471
|
+
const result = new Uint8Array(totalLength);
|
|
472
|
+
let offset = 0;
|
|
473
|
+
for (const chunk of chunks) {
|
|
474
|
+
result.set(chunk, offset);
|
|
475
|
+
offset += chunk.byteLength;
|
|
476
|
+
}
|
|
477
|
+
return result;
|
|
478
|
+
}
|
|
479
|
+
async function hashData(data) {
|
|
480
|
+
let c = globalThis.crypto;
|
|
481
|
+
if (!c) {
|
|
482
|
+
c = (await import("node:crypto")).webcrypto;
|
|
483
|
+
}
|
|
484
|
+
const buf = await c.subtle.digest("SHA-256", data);
|
|
485
|
+
return Array.from(new Uint8Array(buf)).map((b) => b.toString(16).padStart(2, "0")).join("");
|
|
486
|
+
}
|
|
423
487
|
function sortEntries(entries) {
|
|
424
488
|
return [...entries].sort((a, b) => {
|
|
425
489
|
if (a.name === VERSION_FILE) return -1;
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "styled-map-package-api",
|
|
3
|
-
"version": "5.0.0-pre.
|
|
3
|
+
"version": "5.0.0-pre.2",
|
|
4
4
|
"description": "JavaScript API for reading, writing, and serving Styled Map Package (.smp) files",
|
|
5
5
|
"type": "module",
|
|
6
6
|
"main": "./dist/index.cjs",
|
|
@@ -114,7 +114,7 @@
|
|
|
114
114
|
"keywords": [],
|
|
115
115
|
"license": "MIT",
|
|
116
116
|
"dependencies": {
|
|
117
|
-
"@gmaclennan/zip-reader": "^1.0.0
|
|
117
|
+
"@gmaclennan/zip-reader": "^1.0.0",
|
|
118
118
|
"@mapbox/sphericalmercator": "^1.2.0",
|
|
119
119
|
"@maplibre/maplibre-gl-style-spec": "^20.3.1",
|
|
120
120
|
"@placemarkio/check-geojson": "^0.1.12",
|
|
@@ -124,12 +124,15 @@
|
|
|
124
124
|
"itty-router": "^5.0.22",
|
|
125
125
|
"ky": "^1.7.5",
|
|
126
126
|
"map-obj": "^5.0.2",
|
|
127
|
-
"mbtiles-reader": "^
|
|
127
|
+
"mbtiles-reader": "^2.0.1",
|
|
128
128
|
"p-limit": "^6.2.0",
|
|
129
129
|
"readable-stream": "^4.7.0",
|
|
130
130
|
"yocto-queue": "^1.1.1",
|
|
131
131
|
"zip-writer": "^2.2.0"
|
|
132
132
|
},
|
|
133
|
+
"optionalDependencies": {
|
|
134
|
+
"better-sqlite3": "^12.8.0"
|
|
135
|
+
},
|
|
133
136
|
"devDependencies": {
|
|
134
137
|
"@commander-js/extra-typings": "^12.1.0",
|
|
135
138
|
"@types/geojson": "^7946.0.16",
|