styled-map-package 1.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.
Files changed (60) hide show
  1. package/.github/workflows/node.yml +30 -0
  2. package/.github/workflows/release.yml +47 -0
  3. package/.husky/pre-commit +1 -0
  4. package/.nvmrc +1 -0
  5. package/LICENSE.md +7 -0
  6. package/README.md +28 -0
  7. package/bin/smp-download.js +83 -0
  8. package/bin/smp-view.js +52 -0
  9. package/bin/smp.js +11 -0
  10. package/eslint.config.js +17 -0
  11. package/lib/download.js +114 -0
  12. package/lib/index.js +6 -0
  13. package/lib/reader.js +150 -0
  14. package/lib/reporters.js +92 -0
  15. package/lib/server.js +64 -0
  16. package/lib/style-downloader.js +363 -0
  17. package/lib/tile-downloader.js +188 -0
  18. package/lib/types.ts +104 -0
  19. package/lib/utils/fetch.js +100 -0
  20. package/lib/utils/file-formats.js +85 -0
  21. package/lib/utils/geo.js +87 -0
  22. package/lib/utils/mapbox.js +155 -0
  23. package/lib/utils/misc.js +26 -0
  24. package/lib/utils/streams.js +162 -0
  25. package/lib/utils/style.js +174 -0
  26. package/lib/utils/templates.js +136 -0
  27. package/lib/writer.js +478 -0
  28. package/map-viewer/index.html +89 -0
  29. package/package.json +103 -0
  30. package/test/download-write-read.js +43 -0
  31. package/test/fixtures/invalid-styles/empty.json +1 -0
  32. package/test/fixtures/invalid-styles/missing-source.json +10 -0
  33. package/test/fixtures/invalid-styles/no-layers.json +4 -0
  34. package/test/fixtures/invalid-styles/no-sources.json +4 -0
  35. package/test/fixtures/invalid-styles/null.json +1 -0
  36. package/test/fixtures/invalid-styles/unsupported-version.json +5 -0
  37. package/test/fixtures/valid-styles/external-geojson.input.json +66 -0
  38. package/test/fixtures/valid-styles/external-geojson.output.json +93 -0
  39. package/test/fixtures/valid-styles/inline-geojson.input.json +421 -0
  40. package/test/fixtures/valid-styles/inline-geojson.output.json +1573 -0
  41. package/test/fixtures/valid-styles/maplibre-demotiles.input.json +831 -0
  42. package/test/fixtures/valid-styles/maplibre-unlabelled.input.json +496 -0
  43. package/test/fixtures/valid-styles/maplibre-unlabelled.output.json +1573 -0
  44. package/test/fixtures/valid-styles/minimal-labelled.input.json +37 -0
  45. package/test/fixtures/valid-styles/minimal-labelled.output.json +72 -0
  46. package/test/fixtures/valid-styles/minimal-sprites.input.json +37 -0
  47. package/test/fixtures/valid-styles/minimal-sprites.output.json +58 -0
  48. package/test/fixtures/valid-styles/minimal.input.json +54 -0
  49. package/test/fixtures/valid-styles/minimal.output.json +92 -0
  50. package/test/fixtures/valid-styles/multiple-sprites.input.json +46 -0
  51. package/test/fixtures/valid-styles/multiple-sprites.output.json +128 -0
  52. package/test/fixtures/valid-styles/raster-sources.input.json +33 -0
  53. package/test/fixtures/valid-styles/raster-sources.output.json +69 -0
  54. package/test/utils/assert-bbox-equal.js +19 -0
  55. package/test/utils/digest-stream.js +36 -0
  56. package/test/utils/image-streams.js +30 -0
  57. package/test/utils/reader-helper.js +72 -0
  58. package/test/write-read.js +620 -0
  59. package/tsconfig.json +18 -0
  60. package/types/buffer-peek-stream.d.ts +12 -0
@@ -0,0 +1,30 @@
1
+ // @ts-ignore
2
+ import JPEGEncoder from '@stealthybox/jpg-stream/encoder.js'
3
+ // @ts-ignore
4
+ import BlockStream from 'block-stream2'
5
+ // @ts-ignore
6
+ import PNGEncoder from 'png-stream/encoder.js'
7
+ import randomBytesReadableStream from 'random-bytes-readable-stream'
8
+
9
+ /**
10
+ * Create a random-noise image stream with the given dimensions, either PNG or
11
+ * JPEG.
12
+ *
13
+ * @param {object} options
14
+ * @param {number} options.width
15
+ * @param {number} options.height
16
+ * @param {'png' | 'jpg'} options.format
17
+ * @returns
18
+ */
19
+ export function randomImageStream({ width, height, format }) {
20
+ const encoder =
21
+ format === 'jpg'
22
+ ? new JPEGEncoder(width, height, { colorSpace: 'rgb', quality: 30 })
23
+ : new PNGEncoder(width, height, { colorSpace: 'rgb' })
24
+ return (
25
+ randomBytesReadableStream({ size: width * height * 3 })
26
+ // JPEG Encoder requires one line at a time
27
+ .pipe(new BlockStream({ size: width * 3 }))
28
+ .pipe(encoder)
29
+ )
30
+ }
@@ -0,0 +1,72 @@
1
+ import { once } from 'node:events'
2
+
3
+ import { replaceVariables } from '../../lib/utils/templates.js'
4
+ import { DigestStream } from './digest-stream.js'
5
+
6
+ /** @import { Reader } from '../../lib/index.js' */
7
+ /**
8
+ * A helper class for reading resources from a styled map package.
9
+ */
10
+ export class ReaderHelper {
11
+ #reader
12
+ /** @type {Awaited<ReturnType<Reader['getStyle']>> | undefined} */
13
+ #style
14
+ /** @param {Reader} reader */
15
+ constructor(reader) {
16
+ this.#reader = reader
17
+ }
18
+
19
+ /** @param {string} path */
20
+ async #digest(path) {
21
+ const resource = await this.#reader.getResource(path)
22
+ const digestStream = new DigestStream('md5')
23
+ resource.stream.pipe(digestStream).resume()
24
+ await once(digestStream, 'finish')
25
+ return digestStream.digest('hex')
26
+ }
27
+
28
+ /**
29
+ * @param {{ z: number, x: number, y: number, sourceId: string }} opts
30
+ */
31
+ async getTileHash({ z, x, y, sourceId }) {
32
+ const style = this.#style || (this.#style = await this.#reader.getStyle(''))
33
+ const source = style.sources[sourceId]
34
+ if (!source || !('tiles' in source) || !source.tiles) {
35
+ throw new Error(`Source not found: ${sourceId}`)
36
+ }
37
+ const tilePath = replaceVariables(source.tiles[0], { z, x, y })
38
+ return this.#digest(tilePath)
39
+ }
40
+
41
+ /**
42
+ * @param {import('../../lib/writer.js').GlyphInfo} glyphInfo
43
+ */
44
+ async getGlyphHash({ font, range }) {
45
+ const style = this.#style || (this.#style = await this.#reader.getStyle(''))
46
+ if (typeof style.glyphs !== 'string') {
47
+ throw new Error('No glyphs defined in style')
48
+ }
49
+ const glyphPath = replaceVariables(style.glyphs, { fontstack: font, range })
50
+ return this.#digest(glyphPath)
51
+ }
52
+
53
+ /** @param {{ id?: string, pixelRatio?: 1 | 2 | 3, ext: 'json' | 'png'}} opts */
54
+ async getSpriteHash({ id, pixelRatio = 1, ext }) {
55
+ const style = this.#style || (this.#style = await this.#reader.getStyle(''))
56
+ if (!style.sprite) {
57
+ throw new Error('No sprites defined in style')
58
+ }
59
+ const pixelRatioString = pixelRatio === 1 ? '' : `@${pixelRatio}x`
60
+ let spritePath
61
+ if (typeof style.sprite === 'string') {
62
+ spritePath = style.sprite + pixelRatioString + '.' + ext
63
+ } else {
64
+ const sprite = style.sprite.find((s) => s.id === (id || 'default'))
65
+ if (!sprite) {
66
+ throw new Error(`Sprite not found: ${id}`)
67
+ }
68
+ spritePath = sprite.url + pixelRatioString + '.' + ext
69
+ }
70
+ return this.#digest(spritePath)
71
+ }
72
+ }