styled-map-package 2.2.1 → 3.0.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/bin/smp-download.js +3 -3
- package/bin/smp-mbtiles.js +1 -1
- package/bin/smp-view.js +2 -2
- package/dist/download.cjs +101 -0
- package/dist/download.d.cts +65 -0
- package/dist/{lib/download.d.ts → download.d.ts} +22 -6
- package/dist/download.js +77 -0
- package/dist/from-mbtiles.cjs +91 -0
- package/dist/from-mbtiles.d.cts +17 -0
- package/dist/from-mbtiles.d.ts +17 -0
- package/dist/from-mbtiles.js +57 -0
- package/dist/index.cjs +49 -0
- package/dist/index.d.cts +27 -0
- package/dist/index.d.ts +27 -0
- package/dist/index.js +18 -0
- package/dist/reader-watch.cjs +135 -0
- package/dist/reader-watch.d.cts +24 -0
- package/dist/reader-watch.d.ts +24 -0
- package/dist/reader-watch.js +101 -0
- package/dist/reader.cjs +167 -0
- package/dist/reader.d.cts +62 -0
- package/dist/{lib/reader.d.ts → reader.d.ts} +16 -5
- package/dist/reader.js +138 -0
- package/dist/reporters.cjs +122 -0
- package/dist/reporters.d.cts +10 -0
- package/dist/{lib/reporters.d.ts → reporters.d.ts} +5 -2
- package/dist/reporters.js +88 -0
- package/dist/server.cjs +79 -0
- package/dist/server.d.cts +37 -0
- package/dist/server.d.ts +37 -0
- package/dist/server.js +45 -0
- package/dist/style-downloader.cjs +312 -0
- package/dist/style-downloader.d.cts +120 -0
- package/dist/{lib/style-downloader.d.ts → style-downloader.d.ts} +23 -13
- package/dist/style-downloader.js +288 -0
- package/dist/tile-downloader.cjs +158 -0
- package/dist/tile-downloader.d.cts +84 -0
- package/dist/{lib/tile-downloader.d.ts → tile-downloader.d.ts} +22 -10
- package/dist/tile-downloader.js +126 -0
- package/dist/{lib/writer.d.ts → types-B4Xn1F9K.d.cts} +74 -14
- package/dist/types-B4Xn1F9K.d.ts +189 -0
- package/dist/utils/errors.cjs +41 -0
- package/dist/utils/errors.d.cts +18 -0
- package/dist/{lib/utils → utils}/errors.d.ts +4 -2
- package/dist/utils/errors.js +16 -0
- package/dist/utils/fetch.cjs +96 -0
- package/dist/utils/fetch.d.cts +51 -0
- package/dist/{lib/utils → utils}/fetch.d.ts +10 -4
- package/dist/utils/fetch.js +62 -0
- package/dist/utils/file-formats.cjs +98 -0
- package/dist/utils/file-formats.d.cts +35 -0
- package/dist/{lib/utils → utils}/file-formats.d.ts +13 -3
- package/dist/utils/file-formats.js +62 -0
- package/dist/utils/geo.cjs +84 -0
- package/dist/utils/geo.d.cts +46 -0
- package/dist/{lib/utils → utils}/geo.d.ts +8 -6
- package/dist/utils/geo.js +56 -0
- package/dist/utils/mapbox.cjs +121 -0
- package/dist/utils/mapbox.d.cts +43 -0
- package/dist/utils/mapbox.d.ts +43 -0
- package/dist/utils/mapbox.js +91 -0
- package/dist/utils/misc.cjs +39 -0
- package/{lib/utils/misc.js → dist/utils/misc.d.cts} +5 -9
- package/dist/{lib/utils → utils}/misc.d.ts +5 -3
- package/dist/utils/misc.js +13 -0
- package/dist/utils/streams.cjs +130 -0
- package/dist/utils/streams.d.cts +73 -0
- package/dist/{lib/utils → utils}/streams.d.ts +14 -10
- package/dist/utils/streams.js +103 -0
- package/dist/utils/style.cjs +126 -0
- package/dist/utils/style.d.cts +69 -0
- package/dist/{lib/utils → utils}/style.d.ts +19 -9
- package/dist/utils/style.js +98 -0
- package/dist/utils/templates.cjs +114 -0
- package/dist/utils/templates.d.cts +78 -0
- package/dist/{lib/utils → utils}/templates.d.ts +24 -14
- package/dist/utils/templates.js +79 -0
- package/dist/writer.cjs +401 -0
- package/dist/writer.d.cts +7 -0
- package/dist/writer.d.ts +7 -0
- package/dist/writer.js +374 -0
- package/package.json +87 -33
- package/dist/lib/from-mbtiles.d.ts +0 -13
- package/dist/lib/index.d.ts +0 -10
- package/dist/lib/reader-watch.d.ts +0 -13
- package/dist/lib/server.d.ts +0 -15
- package/dist/lib/types.d.ts +0 -64
- package/dist/lib/utils/mapbox.d.ts +0 -41
- package/lib/download.js +0 -114
- package/lib/from-mbtiles.js +0 -83
- package/lib/index.js +0 -11
- package/lib/reader-watch.js +0 -133
- package/lib/reader.js +0 -165
- package/lib/reporters.js +0 -92
- package/lib/server.js +0 -81
- package/lib/style-downloader.js +0 -363
- package/lib/tile-downloader.js +0 -188
- package/lib/types.ts +0 -104
- package/lib/utils/errors.js +0 -24
- package/lib/utils/fetch.js +0 -100
- package/lib/utils/file-formats.js +0 -85
- package/lib/utils/geo.js +0 -87
- package/lib/utils/mapbox.js +0 -155
- package/lib/utils/streams.js +0 -165
- package/lib/utils/style.js +0 -174
- package/lib/utils/templates.js +0 -136
- package/lib/writer.js +0 -478
package/dist/writer.js
ADDED
|
@@ -0,0 +1,374 @@
|
|
|
1
|
+
import { validateStyleMin, migrate } from "@maplibre/maplibre-gl-style-spec";
|
|
2
|
+
import { bbox } from "@turf/bbox";
|
|
3
|
+
import archiver from "archiver";
|
|
4
|
+
import { EventEmitter } from "events";
|
|
5
|
+
import { excludeKeys } from "filter-obj";
|
|
6
|
+
import fs from "fs";
|
|
7
|
+
import { pEvent } from "p-event";
|
|
8
|
+
import { PassThrough, pipeline } from "readable-stream";
|
|
9
|
+
import { Readable } from "stream";
|
|
10
|
+
import { getTileFormatFromStream } from "./utils/file-formats.js";
|
|
11
|
+
import { MAX_BOUNDS, tileToBBox, unionBBox } from "./utils/geo.js";
|
|
12
|
+
import { clone } from "./utils/misc.js";
|
|
13
|
+
import { writeStreamFromAsync } from "./utils/streams.js";
|
|
14
|
+
import { replaceFontStacks } from "./utils/style.js";
|
|
15
|
+
import {
|
|
16
|
+
getGlyphFilename,
|
|
17
|
+
getSpriteFilename,
|
|
18
|
+
getSpriteUri,
|
|
19
|
+
getTileFilename,
|
|
20
|
+
getTileUri,
|
|
21
|
+
GLYPH_URI,
|
|
22
|
+
STYLE_FILE
|
|
23
|
+
} from "./utils/templates.js";
|
|
24
|
+
const SUPPORTED_SOURCE_TYPES = (
|
|
25
|
+
/** @type {const} */
|
|
26
|
+
[
|
|
27
|
+
"raster",
|
|
28
|
+
"vector",
|
|
29
|
+
"geojson"
|
|
30
|
+
]
|
|
31
|
+
);
|
|
32
|
+
class Writer extends EventEmitter {
|
|
33
|
+
#archive = archiver("zip", { zlib: { level: 9 } }).setMaxListeners(Infinity).on("error", console.error);
|
|
34
|
+
/** @type {Set<string>} */
|
|
35
|
+
#addedFiles = /* @__PURE__ */ new Set();
|
|
36
|
+
/** @type {Set<string>} */
|
|
37
|
+
#fonts = /* @__PURE__ */ new Set();
|
|
38
|
+
/** @type {Set<string>} */
|
|
39
|
+
#addedSpriteIds = /* @__PURE__ */ new Set();
|
|
40
|
+
/** @type {Map<string, SourceInfo>} */
|
|
41
|
+
#sources = /* @__PURE__ */ new Map();
|
|
42
|
+
/** @type {StyleSpecification} */
|
|
43
|
+
#style;
|
|
44
|
+
#outputStream;
|
|
45
|
+
static SUPPORTED_SOURCE_TYPES = SUPPORTED_SOURCE_TYPES;
|
|
46
|
+
/**
|
|
47
|
+
* @param {any} style A v7 or v8 MapLibre style. v7 styles will be migrated to
|
|
48
|
+
* v8. (There are currently no typescript declarations for v7 styles, hence
|
|
49
|
+
* this is typed as `any` and validated internally)
|
|
50
|
+
* @param {object} opts
|
|
51
|
+
* @param {number} [opts.highWaterMark=1048576] The maximum number of bytes to buffer during write
|
|
52
|
+
*/
|
|
53
|
+
constructor(style, { highWaterMark = 1024 * 1024 } = {}) {
|
|
54
|
+
super();
|
|
55
|
+
if (!style || !("version" in style)) {
|
|
56
|
+
throw new Error("Invalid style");
|
|
57
|
+
}
|
|
58
|
+
if (style.version !== 7 && style.version !== 8) {
|
|
59
|
+
throw new Error(`Invalid style: Unsupported version v${style.version}`);
|
|
60
|
+
}
|
|
61
|
+
if (!Array.isArray(style.layers)) {
|
|
62
|
+
throw new Error("Invalid style: missing layers property");
|
|
63
|
+
}
|
|
64
|
+
const styleCopy = clone(style);
|
|
65
|
+
migrate(styleCopy);
|
|
66
|
+
const errors = validateStyleMin(styleCopy);
|
|
67
|
+
if (errors.length) {
|
|
68
|
+
throw new AggregateError(errors, "Invalid style");
|
|
69
|
+
}
|
|
70
|
+
this.#style = styleCopy;
|
|
71
|
+
for (const [sourceId, source] of Object.entries(this.#style.sources)) {
|
|
72
|
+
if (source.type !== "geojson") continue;
|
|
73
|
+
this.#addSource(sourceId, source);
|
|
74
|
+
}
|
|
75
|
+
this.#outputStream = new PassThrough({ highWaterMark });
|
|
76
|
+
pipeline(this.#archive, this.#outputStream, (err) => {
|
|
77
|
+
if (err) this.emit("error", err);
|
|
78
|
+
});
|
|
79
|
+
}
|
|
80
|
+
/**
|
|
81
|
+
* @returns {import('stream').Readable} Readable stream of the styled map package
|
|
82
|
+
*/
|
|
83
|
+
get outputStream() {
|
|
84
|
+
return this.#outputStream;
|
|
85
|
+
}
|
|
86
|
+
#getBounds() {
|
|
87
|
+
let bounds;
|
|
88
|
+
let maxzoom = 0;
|
|
89
|
+
for (const { source } of this.#sources.values()) {
|
|
90
|
+
if (source.type === "geojson") {
|
|
91
|
+
if (isEmptyFeatureCollection(source.data)) continue;
|
|
92
|
+
const bbox2 = get2DBBox(source.data.bbox);
|
|
93
|
+
bounds = bounds ? unionBBox([bounds, bbox2]) : [...bbox2];
|
|
94
|
+
} else {
|
|
95
|
+
if (source.maxzoom < maxzoom) continue;
|
|
96
|
+
if (source.maxzoom === maxzoom) {
|
|
97
|
+
bounds = bounds ? unionBBox([bounds, source.bounds]) : source.bounds;
|
|
98
|
+
} else {
|
|
99
|
+
bounds = source.bounds;
|
|
100
|
+
maxzoom = source.maxzoom;
|
|
101
|
+
}
|
|
102
|
+
}
|
|
103
|
+
}
|
|
104
|
+
return bounds;
|
|
105
|
+
}
|
|
106
|
+
#getMaxZoom() {
|
|
107
|
+
let maxzoom = 0;
|
|
108
|
+
for (const { source } of this.#sources.values()) {
|
|
109
|
+
const sourceMaxzoom = (
|
|
110
|
+
// For GeoJSON sources, the maxzoom is 16 unless otherwise set
|
|
111
|
+
source.type === "geojson" ? source.maxzoom || 16 : source.maxzoom
|
|
112
|
+
);
|
|
113
|
+
maxzoom = Math.max(maxzoom, sourceMaxzoom);
|
|
114
|
+
}
|
|
115
|
+
return maxzoom;
|
|
116
|
+
}
|
|
117
|
+
/**
|
|
118
|
+
* Add a source definition to the styled map package
|
|
119
|
+
*
|
|
120
|
+
* @param {string} sourceId
|
|
121
|
+
* @param {InputSource} source
|
|
122
|
+
* @returns {SourceInfo}
|
|
123
|
+
*/
|
|
124
|
+
#addSource(sourceId, source) {
|
|
125
|
+
const encodedSourceId = encodeSourceId(this.#sources.size);
|
|
126
|
+
const tileSourceOverrides = {
|
|
127
|
+
minzoom: 0,
|
|
128
|
+
maxzoom: 0,
|
|
129
|
+
bounds: (
|
|
130
|
+
/** @type {import('./utils/geo.js').BBox} */
|
|
131
|
+
[...MAX_BOUNDS]
|
|
132
|
+
),
|
|
133
|
+
tiles: (
|
|
134
|
+
/** @type {string[]} */
|
|
135
|
+
[]
|
|
136
|
+
)
|
|
137
|
+
};
|
|
138
|
+
let smpSource;
|
|
139
|
+
switch (source.type) {
|
|
140
|
+
case "raster":
|
|
141
|
+
case "vector":
|
|
142
|
+
smpSource = {
|
|
143
|
+
...excludeKeys(source, ["tiles", "url"]),
|
|
144
|
+
...tileSourceOverrides
|
|
145
|
+
};
|
|
146
|
+
break;
|
|
147
|
+
case "geojson":
|
|
148
|
+
smpSource = {
|
|
149
|
+
...source,
|
|
150
|
+
maxzoom: 0,
|
|
151
|
+
data: typeof source.data !== "string" ? (
|
|
152
|
+
// Add a bbox property to the GeoJSON data if it doesn't already have one
|
|
153
|
+
{ ...source.data, bbox: source.data.bbox || bbox(source.data) }
|
|
154
|
+
) : (
|
|
155
|
+
// If GeoJSON data is referenced by a URL, start with an empty FeatureCollection
|
|
156
|
+
{
|
|
157
|
+
type: "FeatureCollection",
|
|
158
|
+
features: [],
|
|
159
|
+
bbox: [0, 0, 0, 0]
|
|
160
|
+
}
|
|
161
|
+
)
|
|
162
|
+
};
|
|
163
|
+
break;
|
|
164
|
+
}
|
|
165
|
+
const sourceInfo = {
|
|
166
|
+
source: smpSource,
|
|
167
|
+
encodedSourceId
|
|
168
|
+
};
|
|
169
|
+
this.#sources.set(sourceId, sourceInfo);
|
|
170
|
+
return sourceInfo;
|
|
171
|
+
}
|
|
172
|
+
/**
|
|
173
|
+
* Add a tile to the styled map package
|
|
174
|
+
*
|
|
175
|
+
* @param {Source} tileData
|
|
176
|
+
* @param {TileInfo} opts
|
|
177
|
+
*/
|
|
178
|
+
async addTile(tileData, { z, x, y, sourceId, format }) {
|
|
179
|
+
let sourceInfo = this.#sources.get(sourceId);
|
|
180
|
+
if (!sourceInfo) {
|
|
181
|
+
const source2 = this.#style.sources[sourceId];
|
|
182
|
+
if (!source2) {
|
|
183
|
+
throw new Error(`Source not referenced in style.json: ${sourceId}`);
|
|
184
|
+
}
|
|
185
|
+
if (source2.type !== "raster" && source2.type !== "vector") {
|
|
186
|
+
throw new Error(`Unsupported source type: ${source2.type}`);
|
|
187
|
+
}
|
|
188
|
+
sourceInfo = this.#addSource(sourceId, source2);
|
|
189
|
+
}
|
|
190
|
+
const { source, encodedSourceId } = sourceInfo;
|
|
191
|
+
if (source.type !== "raster" && source.type !== "vector") {
|
|
192
|
+
throw new Error(`Unsupported source type: ${source.type}`);
|
|
193
|
+
}
|
|
194
|
+
if (!format) {
|
|
195
|
+
const tileDataStream = typeof tileData === "string" ? fs.createReadStream(tileData) : tileData instanceof Uint8Array ? Readable.from(tileData) : tileData;
|
|
196
|
+
[format, tileData] = await getTileFormatFromStream(tileDataStream);
|
|
197
|
+
}
|
|
198
|
+
if (!sourceInfo.format) {
|
|
199
|
+
sourceInfo.format = format;
|
|
200
|
+
} else if (sourceInfo.format !== format) {
|
|
201
|
+
throw new Error(
|
|
202
|
+
`Tile format mismatch for source ${sourceId}: expected ${sourceInfo.format}, got ${format}`
|
|
203
|
+
);
|
|
204
|
+
}
|
|
205
|
+
const bbox2 = tileToBBox({ z, x, y });
|
|
206
|
+
if (z > source.maxzoom) {
|
|
207
|
+
source.maxzoom = z;
|
|
208
|
+
source.bounds = bbox2;
|
|
209
|
+
} else if (z === source.maxzoom) {
|
|
210
|
+
source.bounds = unionBBox([source.bounds, bbox2]);
|
|
211
|
+
}
|
|
212
|
+
const name = getTileFilename({ sourceId: encodedSourceId, z, x, y, format });
|
|
213
|
+
return this.#append(tileData, { name, store: true });
|
|
214
|
+
}
|
|
215
|
+
/**
|
|
216
|
+
* Create a write stream for adding tiles to the styled map package
|
|
217
|
+
*
|
|
218
|
+
* @param {object} opts
|
|
219
|
+
* @param {number} [opts.concurrency=16] The number of concurrent writes
|
|
220
|
+
*
|
|
221
|
+
* @returns
|
|
222
|
+
*/
|
|
223
|
+
createTileWriteStream({ concurrency = 16 } = {}) {
|
|
224
|
+
return writeStreamFromAsync(this.addTile.bind(this), { concurrency });
|
|
225
|
+
}
|
|
226
|
+
/**
|
|
227
|
+
* Add a sprite to the styled map package
|
|
228
|
+
*
|
|
229
|
+
* @param {object} options
|
|
230
|
+
* @param {Source} options.json
|
|
231
|
+
* @param {Source} options.png
|
|
232
|
+
* @param {number} [options.pixelRatio]
|
|
233
|
+
* @param {string} [options.id='default']
|
|
234
|
+
* @returns {Promise<void>}
|
|
235
|
+
*/
|
|
236
|
+
async addSprite({ json, png, pixelRatio = 1, id = "default" }) {
|
|
237
|
+
this.#addedSpriteIds.add(id);
|
|
238
|
+
const jsonName = getSpriteFilename({ id, pixelRatio, ext: ".json" });
|
|
239
|
+
const pngName = getSpriteFilename({ id, pixelRatio, ext: ".png" });
|
|
240
|
+
await Promise.all([
|
|
241
|
+
this.#append(json, { name: jsonName }),
|
|
242
|
+
this.#append(png, { name: pngName })
|
|
243
|
+
]);
|
|
244
|
+
}
|
|
245
|
+
/**
|
|
246
|
+
* Add glyphs to the styled map package
|
|
247
|
+
*
|
|
248
|
+
* @param {Source} glyphData
|
|
249
|
+
* @param {GlyphInfo} glyphInfo
|
|
250
|
+
* @returns {Promise<void>}
|
|
251
|
+
*/
|
|
252
|
+
addGlyphs(glyphData, { font: fontName, range }) {
|
|
253
|
+
this.#fonts.add(fontName);
|
|
254
|
+
const name = getGlyphFilename({ fontstack: fontName, range });
|
|
255
|
+
return this.#append(glyphData, { name });
|
|
256
|
+
}
|
|
257
|
+
/**
|
|
258
|
+
* Create a write stream for adding glyphs to the styled map package
|
|
259
|
+
*
|
|
260
|
+
* @param {object} opts
|
|
261
|
+
* @param {number} [opts.concurrency=16] The number of concurrent writes
|
|
262
|
+
* @returns
|
|
263
|
+
*/
|
|
264
|
+
createGlyphWriteStream({ concurrency = 16 } = {}) {
|
|
265
|
+
return writeStreamFromAsync(this.addGlyphs.bind(this), { concurrency });
|
|
266
|
+
}
|
|
267
|
+
/**
|
|
268
|
+
* Finalize the styled map package and write the style to the archive.
|
|
269
|
+
* This method must be called to complete the archive.
|
|
270
|
+
* You must wait for your destination write stream to 'finish' before using the output.
|
|
271
|
+
*/
|
|
272
|
+
finish() {
|
|
273
|
+
this.#prepareStyle();
|
|
274
|
+
const style = JSON.stringify(this.#style);
|
|
275
|
+
this.#append(style, { name: STYLE_FILE });
|
|
276
|
+
this.#archive.finalize();
|
|
277
|
+
}
|
|
278
|
+
/**
|
|
279
|
+
* Mutates the style object to prepare it for writing to the archive.
|
|
280
|
+
* Deterministic: can be run more than once with the same result.
|
|
281
|
+
*/
|
|
282
|
+
#prepareStyle() {
|
|
283
|
+
if (this.#sources.size === 0) {
|
|
284
|
+
throw new Error("Missing sources: add at least one source");
|
|
285
|
+
}
|
|
286
|
+
if (this.#style.glyphs && this.#fonts.size === 0) {
|
|
287
|
+
throw new Error(
|
|
288
|
+
"Missing fonts: style references glyphs but no fonts added"
|
|
289
|
+
);
|
|
290
|
+
}
|
|
291
|
+
replaceFontStacks(this.#style, [...this.#fonts]);
|
|
292
|
+
if (this.#style.glyphs) {
|
|
293
|
+
this.#style.glyphs = GLYPH_URI;
|
|
294
|
+
}
|
|
295
|
+
if (typeof this.#style.sprite === "string") {
|
|
296
|
+
if (!this.#addedSpriteIds.has("default")) {
|
|
297
|
+
throw new Error(
|
|
298
|
+
"Missing sprite: style references sprite but none added"
|
|
299
|
+
);
|
|
300
|
+
}
|
|
301
|
+
this.#style.sprite = getSpriteUri();
|
|
302
|
+
} else if (Array.isArray(this.#style.sprite)) {
|
|
303
|
+
this.#style.sprite = this.#style.sprite.map(({ id }) => {
|
|
304
|
+
if (!this.#addedSpriteIds.has(id)) {
|
|
305
|
+
throw new Error(
|
|
306
|
+
`Missing sprite: style references sprite ${id} but none added`
|
|
307
|
+
);
|
|
308
|
+
}
|
|
309
|
+
return { id, url: getSpriteUri(id) };
|
|
310
|
+
});
|
|
311
|
+
}
|
|
312
|
+
this.#style.sources = {};
|
|
313
|
+
for (const [sourceId, { source, encodedSourceId, format = "mvt" }] of this.#sources) {
|
|
314
|
+
if (source.type === "geojson" && isEmptyFeatureCollection(source.data)) {
|
|
315
|
+
continue;
|
|
316
|
+
}
|
|
317
|
+
this.#style.sources[sourceId] = source;
|
|
318
|
+
if (!("tiles" in source)) continue;
|
|
319
|
+
source.tiles = [getTileUri({ sourceId: encodedSourceId, format })];
|
|
320
|
+
}
|
|
321
|
+
this.#style.layers = this.#style.layers.filter(
|
|
322
|
+
(layer) => !("source" in layer) || !!this.#style.sources[layer.source]
|
|
323
|
+
);
|
|
324
|
+
const metadata = this.#style.metadata || (this.#style.metadata = {});
|
|
325
|
+
const bounds = this.#getBounds();
|
|
326
|
+
if (bounds) {
|
|
327
|
+
metadata["smp:bounds"] = bounds;
|
|
328
|
+
const [w, s, e, n] = bounds;
|
|
329
|
+
this.#style.center = [w + (e - w) / 2, s + (n - s) / 2];
|
|
330
|
+
}
|
|
331
|
+
metadata["smp:maxzoom"] = this.#getMaxZoom();
|
|
332
|
+
metadata["smp:sourceFolders"] = {};
|
|
333
|
+
for (const [sourceId, { encodedSourceId }] of this.#sources) {
|
|
334
|
+
metadata["smp:sourceFolders"][sourceId] = encodedSourceId;
|
|
335
|
+
}
|
|
336
|
+
this.#style.zoom = Math.max(0, this.#getMaxZoom() - 2);
|
|
337
|
+
}
|
|
338
|
+
/**
|
|
339
|
+
*
|
|
340
|
+
* @param {Source} source
|
|
341
|
+
* @param {{ name: string, store?: boolean }} options
|
|
342
|
+
* @returns {Promise<void>}
|
|
343
|
+
*/
|
|
344
|
+
async #append(source, { name, store = false }) {
|
|
345
|
+
if (this.#addedFiles.has(name)) {
|
|
346
|
+
throw new Error(`${name} already added`);
|
|
347
|
+
}
|
|
348
|
+
this.#addedFiles.add(name);
|
|
349
|
+
const onAdded = pEvent(
|
|
350
|
+
this.#archive,
|
|
351
|
+
"entry",
|
|
352
|
+
(entry) => entry.name === name
|
|
353
|
+
);
|
|
354
|
+
this.#archive.append(convertSource(source), { name, store });
|
|
355
|
+
await onAdded;
|
|
356
|
+
}
|
|
357
|
+
}
|
|
358
|
+
function encodeSourceId(sourceIndex) {
|
|
359
|
+
return sourceIndex.toString(36);
|
|
360
|
+
}
|
|
361
|
+
function convertSource(source) {
|
|
362
|
+
return !Buffer.isBuffer(source) && source instanceof Uint8Array ? Buffer.from(source.buffer, source.byteOffset, source.length) : source;
|
|
363
|
+
}
|
|
364
|
+
function isEmptyFeatureCollection(data) {
|
|
365
|
+
return data.type === "FeatureCollection" && data.features.length === 0;
|
|
366
|
+
}
|
|
367
|
+
function get2DBBox(bbox2) {
|
|
368
|
+
if (bbox2.length === 4) return bbox2;
|
|
369
|
+
return [bbox2[0], bbox2[1], bbox2[3], bbox2[4]];
|
|
370
|
+
}
|
|
371
|
+
export {
|
|
372
|
+
SUPPORTED_SOURCE_TYPES,
|
|
373
|
+
Writer
|
|
374
|
+
};
|
package/package.json
CHANGED
|
@@ -1,65 +1,120 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "styled-map-package",
|
|
3
|
-
"version": "
|
|
3
|
+
"version": "3.0.0",
|
|
4
4
|
"description": "",
|
|
5
|
+
"type": "module",
|
|
6
|
+
"main": "./dist/index.cjs",
|
|
7
|
+
"module": "./dist/index.js",
|
|
8
|
+
"types": "./dist/index.d.ts",
|
|
5
9
|
"exports": {
|
|
6
10
|
".": {
|
|
7
|
-
"
|
|
8
|
-
|
|
11
|
+
"import": {
|
|
12
|
+
"types": "./dist/index.d.ts",
|
|
13
|
+
"default": "./dist/index.js"
|
|
14
|
+
},
|
|
15
|
+
"require": {
|
|
16
|
+
"types": "./dist/index.d.cts",
|
|
17
|
+
"default": "./dist/index.cjs"
|
|
18
|
+
}
|
|
9
19
|
},
|
|
10
20
|
"./reader": {
|
|
11
|
-
"
|
|
12
|
-
|
|
21
|
+
"import": {
|
|
22
|
+
"types": "./dist/reader.d.ts",
|
|
23
|
+
"default": "./dist/reader.js"
|
|
24
|
+
},
|
|
25
|
+
"require": {
|
|
26
|
+
"types": "./dist/reader.d.cts",
|
|
27
|
+
"default": "./dist/reader.cjs"
|
|
28
|
+
}
|
|
13
29
|
},
|
|
14
30
|
"./reader-watch": {
|
|
15
|
-
"
|
|
16
|
-
|
|
31
|
+
"import": {
|
|
32
|
+
"types": "./dist/reader-watch.d.ts",
|
|
33
|
+
"default": "./dist/reader-watch.js"
|
|
34
|
+
},
|
|
35
|
+
"require": {
|
|
36
|
+
"types": "./dist/reader-watch.d.cts",
|
|
37
|
+
"default": "./dist/reader-watch.cjs"
|
|
38
|
+
}
|
|
17
39
|
},
|
|
18
40
|
"./writer": {
|
|
19
|
-
"
|
|
20
|
-
|
|
41
|
+
"import": {
|
|
42
|
+
"types": "./dist/writer.d.ts",
|
|
43
|
+
"default": "./dist/writer.js"
|
|
44
|
+
},
|
|
45
|
+
"require": {
|
|
46
|
+
"types": "./dist/writer.d.cts",
|
|
47
|
+
"default": "./dist/writer.cjs"
|
|
48
|
+
}
|
|
21
49
|
},
|
|
22
50
|
"./server": {
|
|
23
|
-
"
|
|
24
|
-
|
|
51
|
+
"import": {
|
|
52
|
+
"types": "./dist/server.d.ts",
|
|
53
|
+
"default": "./dist/server.js"
|
|
54
|
+
},
|
|
55
|
+
"require": {
|
|
56
|
+
"types": "./dist/server.d.cts",
|
|
57
|
+
"default": "./dist/server.cjs"
|
|
58
|
+
}
|
|
25
59
|
},
|
|
26
60
|
"./style-downloader": {
|
|
27
|
-
"
|
|
28
|
-
|
|
61
|
+
"import": {
|
|
62
|
+
"types": "./dist/style-downloader.d.ts",
|
|
63
|
+
"default": "./dist/style-downloader.js"
|
|
64
|
+
},
|
|
65
|
+
"require": {
|
|
66
|
+
"types": "./dist/style-downloader.d.cts",
|
|
67
|
+
"default": "./dist/style-downloader.cjs"
|
|
68
|
+
}
|
|
29
69
|
},
|
|
30
70
|
"./tile-downloader": {
|
|
31
|
-
"
|
|
32
|
-
|
|
71
|
+
"import": {
|
|
72
|
+
"types": "./dist/tile-downloader.d.ts",
|
|
73
|
+
"default": "./dist/tile-downloader.js"
|
|
74
|
+
},
|
|
75
|
+
"require": {
|
|
76
|
+
"types": "./dist/tile-downloader.d.cts",
|
|
77
|
+
"default": "./dist/tile-downloader.cjs"
|
|
78
|
+
}
|
|
33
79
|
},
|
|
34
80
|
"./download": {
|
|
35
|
-
"
|
|
36
|
-
|
|
81
|
+
"import": {
|
|
82
|
+
"types": "./dist/download.d.ts",
|
|
83
|
+
"default": "./dist/download.js"
|
|
84
|
+
},
|
|
85
|
+
"require": {
|
|
86
|
+
"types": "./dist/download.d.cts",
|
|
87
|
+
"default": "./dist/download.cjs"
|
|
88
|
+
}
|
|
37
89
|
},
|
|
38
90
|
"./from-mbtiles": {
|
|
39
|
-
"
|
|
40
|
-
|
|
41
|
-
|
|
91
|
+
"import": {
|
|
92
|
+
"types": "./dist/from-mbtiles.d.ts",
|
|
93
|
+
"default": "./dist/from-mbtiles.js"
|
|
94
|
+
},
|
|
95
|
+
"require": {
|
|
96
|
+
"types": "./dist/from-mbtiles.d.cts",
|
|
97
|
+
"default": "./dist/from-mbtiles.cjs"
|
|
98
|
+
}
|
|
99
|
+
},
|
|
100
|
+
"./package.json": "./package.json"
|
|
42
101
|
},
|
|
43
|
-
"main": "./lib/index.js",
|
|
44
|
-
"types": "./dist/lib/index.d.ts",
|
|
45
102
|
"bin": {
|
|
46
103
|
"styled-map-package": "./bin/smp.js",
|
|
47
104
|
"smp": "./bin/smp.js"
|
|
48
105
|
},
|
|
49
|
-
"type": "module",
|
|
50
106
|
"files": [
|
|
51
107
|
"bin",
|
|
52
108
|
"dist",
|
|
53
|
-
"lib",
|
|
54
109
|
"map-viewer"
|
|
55
110
|
],
|
|
56
111
|
"scripts": {
|
|
57
|
-
"test": "npm run lint && npm run types && node --test",
|
|
112
|
+
"test": "npm run lint && npm run build && npm run types && node --test",
|
|
58
113
|
"prepare": "husky",
|
|
59
114
|
"lint": "eslint .",
|
|
60
115
|
"types": "tsc",
|
|
61
|
-
"build
|
|
62
|
-
"prepack": "npm run build
|
|
116
|
+
"build": "tsup",
|
|
117
|
+
"prepack": "npm run build"
|
|
63
118
|
},
|
|
64
119
|
"keywords": [],
|
|
65
120
|
"author": "",
|
|
@@ -99,14 +154,12 @@
|
|
|
99
154
|
"yocto-queue": "^1.1.1"
|
|
100
155
|
},
|
|
101
156
|
"devDependencies": {
|
|
102
|
-
"@eslint/js": "^9.
|
|
157
|
+
"@eslint/js": "^9.25.1",
|
|
103
158
|
"@jsquash/jpeg": "^1.4.0",
|
|
104
159
|
"@jsquash/png": "^3.0.1",
|
|
105
160
|
"@stealthybox/jpg-stream": "^1.1.2",
|
|
106
161
|
"@trivago/prettier-plugin-sort-imports": "^4.3.0",
|
|
107
162
|
"@types/archiver": "^6.0.3",
|
|
108
|
-
"@types/eslint": "^9.6.1",
|
|
109
|
-
"@types/eslint__js": "^8.42.3",
|
|
110
163
|
"@types/geojson": "^7946.0.16",
|
|
111
164
|
"@types/http-errors": "^2.0.4",
|
|
112
165
|
"@types/mapbox__sphericalmercator": "^1.2.3",
|
|
@@ -115,9 +168,10 @@
|
|
|
115
168
|
"@types/yauzl-promise": "^4.0.1",
|
|
116
169
|
"ava": "^6.2.0",
|
|
117
170
|
"block-stream2": "^2.1.0",
|
|
118
|
-
"
|
|
171
|
+
"esbuild-fix-imports-plugin": "^1.0.20",
|
|
172
|
+
"eslint": "^9.25.1",
|
|
119
173
|
"execa": "^9.4.0",
|
|
120
|
-
"globals": "^
|
|
174
|
+
"globals": "^16.0.0",
|
|
121
175
|
"husky": "^9.1.7",
|
|
122
176
|
"jpg-stream": "^1.1.2",
|
|
123
177
|
"lint-staged": "^15.4.3",
|
|
@@ -126,8 +180,8 @@
|
|
|
126
180
|
"png-stream": "^1.0.5",
|
|
127
181
|
"prettier": "^3.5.2",
|
|
128
182
|
"random-bytes-readable-stream": "^3.0.0",
|
|
129
|
-
"rimraf": "^4.4.1",
|
|
130
183
|
"tempy": "^3.1.0",
|
|
184
|
+
"tsup": "^8.4.0",
|
|
131
185
|
"type-fest": "^4.35.0",
|
|
132
186
|
"typescript": "^5.7.3"
|
|
133
187
|
},
|
|
@@ -1,13 +0,0 @@
|
|
|
1
|
-
/**
|
|
2
|
-
* @overload
|
|
3
|
-
* @param {string} mbtilesPath
|
|
4
|
-
* @returns {import('stream').Readable}
|
|
5
|
-
*/
|
|
6
|
-
export default function fromMBTiles(mbtilesPath: string): import("stream").Readable;
|
|
7
|
-
/**
|
|
8
|
-
* @overload
|
|
9
|
-
* @param {string} mbtilesPath
|
|
10
|
-
* @param {string} outputPath
|
|
11
|
-
* @returns {Promise<void>}
|
|
12
|
-
*/
|
|
13
|
-
export default function fromMBTiles(mbtilesPath: string, outputPath: string): Promise<void>;
|
package/dist/lib/index.d.ts
DELETED
|
@@ -1,10 +0,0 @@
|
|
|
1
|
-
export { default as Reader } from "./reader.js";
|
|
2
|
-
export { default as ReaderWatch } from "./reader-watch.js";
|
|
3
|
-
export { default as Writer } from "./writer.js";
|
|
4
|
-
export { default as Server } from "./server.js";
|
|
5
|
-
export { default as StyleDownloader } from "./style-downloader.js";
|
|
6
|
-
export { downloadTiles } from "./tile-downloader.js";
|
|
7
|
-
export { default as download } from "./download.js";
|
|
8
|
-
export { default as fromMBTiles } from "./from-mbtiles.js";
|
|
9
|
-
export type SMPSource = import("./types.js").SMPSource;
|
|
10
|
-
export type SMPStyle = import("./types.js").SMPStyle;
|
|
@@ -1,13 +0,0 @@
|
|
|
1
|
-
/** @implements {Pick<Reader, keyof Reader>} */
|
|
2
|
-
export default class ReaderWatch implements Pick<Reader, keyof Reader> {
|
|
3
|
-
/**
|
|
4
|
-
* @param {string} filepath
|
|
5
|
-
*/
|
|
6
|
-
constructor(filepath: string);
|
|
7
|
-
opened(): Promise<void>;
|
|
8
|
-
getStyle(baseUrl?: string | null): Promise<import("./types.js").SMPStyle>;
|
|
9
|
-
getResource(path: string): Promise<Resource>;
|
|
10
|
-
close(): Promise<void>;
|
|
11
|
-
#private;
|
|
12
|
-
}
|
|
13
|
-
import Reader from './reader.js';
|
package/dist/lib/server.d.ts
DELETED
|
@@ -1,15 +0,0 @@
|
|
|
1
|
-
export default function _default(instance: import("fastify").FastifyInstance<import("fastify").RawServerDefault, import("http").IncomingMessage, import("http").ServerResponse<import("http").IncomingMessage>, import("fastify").FastifyBaseLogger, import("fastify").FastifyTypeProviderDefault>, opts: PluginOptions, done: (err?: Error) => void): void;
|
|
2
|
-
export type PluginOptionsFilepath = {
|
|
3
|
-
/**
|
|
4
|
-
* Path to styled map package (`.smp`) file
|
|
5
|
-
*/
|
|
6
|
-
filepath: string;
|
|
7
|
-
};
|
|
8
|
-
export type PluginOptionsReader = {
|
|
9
|
-
/**
|
|
10
|
-
* SMP Reader interface (also supports ReaderWatch)
|
|
11
|
-
*/
|
|
12
|
-
reader: Pick<Reader, keyof Reader>;
|
|
13
|
-
};
|
|
14
|
-
export type PluginOptions = PluginOptionsFilepath | PluginOptionsReader;
|
|
15
|
-
import Reader from './reader.js';
|
package/dist/lib/types.d.ts
DELETED
|
@@ -1,64 +0,0 @@
|
|
|
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 { Readable } from 'stream';
|
|
4
|
-
import type { SetRequired } from 'type-fest';
|
|
5
|
-
import { SUPPORTED_SOURCE_TYPES } from './writer.js';
|
|
6
|
-
export type InputSource = Extract<SourceSpecification, {
|
|
7
|
-
type: (typeof SUPPORTED_SOURCE_TYPES)[number];
|
|
8
|
-
}>;
|
|
9
|
-
type TransformInlinedSource<T extends SourceSpecification> = T extends GeoJSONSourceSpecification ? OmitUnion<T, 'data'> & {
|
|
10
|
-
data: GeoJSON;
|
|
11
|
-
} : T extends VectorSourceSpecification | RasterSourceSpecification | RasterDEMSourceSpecification ? SetRequired<OmitUnion<T, 'url'>, 'tiles'> : T;
|
|
12
|
-
/**
|
|
13
|
-
* This is a slightly stricter version of SourceSpecification that requires
|
|
14
|
-
* sources to be inlined (e.g. no urls to TileJSON or GeoJSON files).
|
|
15
|
-
*/
|
|
16
|
-
export type InlinedSource = TransformInlinedSource<SourceSpecification>;
|
|
17
|
-
type SupportedInlinedSource = Extract<InlinedSource, {
|
|
18
|
-
type: (typeof SUPPORTED_SOURCE_TYPES)[number];
|
|
19
|
-
}>;
|
|
20
|
-
/**
|
|
21
|
-
* This is a slightly stricter version of StyleSpecification that requires
|
|
22
|
-
* sources to be inlined (e.g. no urls to TileJSON or GeoJSON files).
|
|
23
|
-
*/
|
|
24
|
-
export type StyleInlinedSources = Omit<StyleSpecification, 'sources'> & {
|
|
25
|
-
sources: {
|
|
26
|
-
[_: string]: InlinedSource;
|
|
27
|
-
};
|
|
28
|
-
};
|
|
29
|
-
export type SMPSource = TransformSMPInputSource<SupportedInlinedSource>;
|
|
30
|
-
/**
|
|
31
|
-
* This is a slightly stricter version of StyleSpecification that is provided in
|
|
32
|
-
* a Styled Map Package. Tile sources must have tile URLs inlined (they cannot
|
|
33
|
-
* refer to a TileJSON url), and they must have bounds, minzoom, and maxzoom.
|
|
34
|
-
* GeoJSON sources must have inlined GeoJSON (not a URL to a GeoJSON file).
|
|
35
|
-
*/
|
|
36
|
-
export type SMPStyle = TransformSMPStyle<StyleSpecification>;
|
|
37
|
-
export type TransformSMPInputSource<T extends SupportedInlinedSource> = T extends GeoJSONSourceSpecification ? T & {
|
|
38
|
-
data: {
|
|
39
|
-
bbox: BBox;
|
|
40
|
-
};
|
|
41
|
-
} : T extends RasterSourceSpecification | VectorSourceSpecification ? SetRequired<T, 'bounds' | 'minzoom' | 'maxzoom'> : T;
|
|
42
|
-
type TransformSMPStyle<T extends StyleSpecification> = Omit<T, 'sources'> & {
|
|
43
|
-
metadata: {
|
|
44
|
-
'smp:bounds': [number, number, number, number];
|
|
45
|
-
'smp:maxzoom': 0;
|
|
46
|
-
'smp:sourceFolders': {
|
|
47
|
-
[_: string]: string;
|
|
48
|
-
};
|
|
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 interface DownloadStream extends Readable {
|
|
59
|
-
iterator(...args: Parameters<Readable['iterator']>): AsyncIterableIterator<Buffer>;
|
|
60
|
-
[Symbol.asyncIterator](): AsyncIterableIterator<Buffer>;
|
|
61
|
-
}
|
|
62
|
-
export type RequiredUnion<T> = T extends any ? Required<T> : never;
|
|
63
|
-
export type OmitUnion<T, K extends keyof any> = T extends unknown ? Omit<T, K> : never;
|
|
64
|
-
export {};
|