@osmix/pbf 0.0.2 → 0.0.3

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 (86) hide show
  1. package/CHANGELOG.md +6 -0
  2. package/README.md +75 -82
  3. package/dist/src/blobs-to-blocks.d.ts +51 -3
  4. package/dist/src/blobs-to-blocks.d.ts.map +1 -1
  5. package/dist/src/blobs-to-blocks.js +60 -7
  6. package/dist/src/blobs-to-blocks.js.map +1 -1
  7. package/dist/src/blocks-to-pbf.d.ts +41 -5
  8. package/dist/src/blocks-to-pbf.d.ts.map +1 -1
  9. package/dist/src/blocks-to-pbf.js +41 -5
  10. package/dist/src/blocks-to-pbf.js.map +1 -1
  11. package/dist/src/index.d.ts +28 -0
  12. package/dist/src/index.d.ts.map +1 -1
  13. package/dist/src/index.js +28 -0
  14. package/dist/src/index.js.map +1 -1
  15. package/dist/src/pbf-to-blobs.d.ts +22 -3
  16. package/dist/src/pbf-to-blobs.d.ts.map +1 -1
  17. package/dist/src/pbf-to-blobs.js +24 -3
  18. package/dist/src/pbf-to-blobs.js.map +1 -1
  19. package/dist/src/pbf-to-blocks.d.ts +46 -4
  20. package/dist/src/pbf-to-blocks.d.ts.map +1 -1
  21. package/dist/src/pbf-to-blocks.js +46 -4
  22. package/dist/src/pbf-to-blocks.js.map +1 -1
  23. package/dist/src/utils.d.ts +0 -4
  24. package/dist/src/utils.d.ts.map +1 -1
  25. package/dist/src/utils.js +0 -32
  26. package/dist/src/utils.js.map +1 -1
  27. package/dist/test/blobs-to-blocks.test.js +22 -18
  28. package/dist/test/blobs-to-blocks.test.js.map +1 -1
  29. package/dist/test/pbf-to-blobs.test.js +24 -16
  30. package/dist/test/pbf-to-blobs.test.js.map +1 -1
  31. package/dist/test/read.bench.js +6 -4
  32. package/dist/test/read.bench.js.map +1 -1
  33. package/dist/test/read.test.js +5 -5
  34. package/dist/test/read.test.js.map +1 -1
  35. package/dist/test/streams.test.js +21 -13
  36. package/dist/test/streams.test.js.map +1 -1
  37. package/dist/test/utils.d.ts.map +1 -1
  38. package/dist/test/utils.js +8 -8
  39. package/dist/test/utils.js.map +1 -1
  40. package/dist/test/utils.test.js +8 -8
  41. package/dist/test/utils.test.js.map +1 -1
  42. package/dist/test/write.test.js +13 -8
  43. package/dist/test/write.test.js.map +1 -1
  44. package/package.json +6 -7
  45. package/src/blobs-to-blocks.ts +78 -7
  46. package/src/blocks-to-pbf.ts +42 -5
  47. package/src/index.ts +29 -0
  48. package/src/pbf-to-blobs.ts +24 -3
  49. package/src/pbf-to-blocks.ts +46 -4
  50. package/src/utils.ts +0 -29
  51. package/test/blobs-to-blocks.test.ts +25 -19
  52. package/test/pbf-to-blobs.test.ts +23 -17
  53. package/test/read.bench.ts +8 -4
  54. package/test/read.test.ts +5 -5
  55. package/test/streams.test.ts +22 -13
  56. package/test/utils.test.ts +8 -8
  57. package/test/utils.ts +8 -8
  58. package/test/write.test.ts +13 -8
  59. package/dist/blobs-to-blocks.d.ts +0 -5
  60. package/dist/blobs-to-blocks.js +0 -21
  61. package/dist/blocks-to-pbf.d.ts +0 -16
  62. package/dist/blocks-to-pbf.js +0 -73
  63. package/dist/index.d.ts +0 -8
  64. package/dist/index.js +0 -8
  65. package/dist/pbf-to-blobs.d.ts +0 -6
  66. package/dist/pbf-to-blobs.js +0 -48
  67. package/dist/pbf-to-blocks.d.ts +0 -20
  68. package/dist/pbf-to-blocks.js +0 -53
  69. package/dist/proto/fileformat.d.ts +0 -26
  70. package/dist/proto/fileformat.js +0 -56
  71. package/dist/proto/osmformat.d.ts +0 -91
  72. package/dist/proto/osmformat.js +0 -458
  73. package/dist/spec.d.ts +0 -5
  74. package/dist/spec.js +0 -9
  75. package/dist/test/utils.bun.test.d.ts +0 -2
  76. package/dist/test/utils.bun.test.d.ts.map +0 -1
  77. package/dist/test/utils.bun.test.js +0 -221
  78. package/dist/test/utils.bun.test.js.map +0 -1
  79. package/dist/test/verify-pbf-reading.bun.test.d.ts +0 -2
  80. package/dist/test/verify-pbf-reading.bun.test.d.ts.map +0 -1
  81. package/dist/test/verify-pbf-reading.bun.test.js +0 -32
  82. package/dist/test/verify-pbf-reading.bun.test.js.map +0 -1
  83. package/dist/utils.d.ts +0 -27
  84. package/dist/utils.js +0 -92
  85. package/test/utils.bun.test.ts +0 -277
  86. package/test/verify-pbf-reading.bun.test.ts +0 -39
@@ -1,5 +1,5 @@
1
+ import { describe, expect, it } from "bun:test"
1
2
  import Pbf from "pbf"
2
- import { assert, describe, it } from "vitest"
3
3
  import { osmPbfBlobsToBlocksGenerator } from "../src/blobs-to-blocks"
4
4
  import { createOsmPbfBlobGenerator } from "../src/pbf-to-blobs"
5
5
  import { writeBlob, writeBlobHeader } from "../src/proto/fileformat"
@@ -30,7 +30,7 @@ describe("createOsmPbfBlobGenerator", () => {
30
30
  for (const blob of generate(fileBytes.slice(offset))) yielded.push(blob)
31
31
  }
32
32
 
33
- assert.equal(yielded.length, 2)
33
+ expect(yielded.length).toBe(2)
34
34
 
35
35
  const blocks = osmPbfBlobsToBlocksGenerator(
36
36
  (async function* () {
@@ -38,29 +38,35 @@ describe("createOsmPbfBlobGenerator", () => {
38
38
  })(),
39
39
  )
40
40
  const { value: headerBlock, done } = await blocks.next()
41
- assert.isFalse(done)
41
+ expect(done).toBe(false)
42
42
  if (!isHeaderBlock(headerBlock)) {
43
- assert.fail("Expected first block to be a header")
43
+ throw new Error("Expected first block to be a header")
44
44
  }
45
- assert.deepEqual(headerBlock.bbox, header.bbox)
46
- assert.deepEqual(headerBlock.required_features, header.required_features)
47
- assert.deepEqual(headerBlock.optional_features, header.optional_features)
45
+ expect(headerBlock.bbox).toEqual(header.bbox)
46
+ expect(headerBlock.required_features).toEqual(header.required_features)
47
+ expect(headerBlock.optional_features).toEqual(header.optional_features)
48
48
 
49
49
  const { value: primitive } = await blocks.next()
50
50
  if (!isPrimitiveBlock(primitive)) {
51
- assert.fail("Expected primitive block after header")
51
+ throw new Error("Expected primitive block after header")
52
52
  }
53
- assert.lengthOf(
54
- primitive.primitivegroup,
53
+ expect(primitive.primitivegroup).toHaveLength(
55
54
  primitiveBlock.primitivegroup.length,
56
55
  )
57
- assert.exists(primitive.primitivegroup[0])
58
- assert.exists(primitiveBlock.primitivegroup[0])
56
+ expect(primitive.primitivegroup[0]).toBeDefined()
57
+ expect(primitiveBlock.primitivegroup[0]).toBeDefined()
58
+ if (!primitive.primitivegroup[0])
59
+ throw new Error("primitive.primitivegroup[0] is undefined")
60
+ if (!primitiveBlock.primitivegroup[0])
61
+ throw new Error("primitiveBlock.primitivegroup[0] is undefined")
59
62
  const dense = primitive.primitivegroup[0].dense
60
- assert.exists(dense)
61
- assert.deepEqual(dense?.id, primitiveBlock.primitivegroup[0].dense?.id)
62
- assert.deepEqual(dense?.lat, primitiveBlock.primitivegroup[0].dense?.lat)
63
- assert.deepEqual(dense?.lon, primitiveBlock.primitivegroup[0].dense?.lon)
63
+ expect(dense).toBeDefined()
64
+ if (!dense) throw new Error("dense is undefined")
65
+ if (!primitiveBlock.primitivegroup[0]?.dense)
66
+ throw new Error("primitiveBlock.primitivegroup[0].dense is undefined")
67
+ expect(dense.id).toEqual(primitiveBlock.primitivegroup[0].dense.id)
68
+ expect(dense.lat).toEqual(primitiveBlock.primitivegroup[0].dense.lat)
69
+ expect(dense.lon).toEqual(primitiveBlock.primitivegroup[0].dense.lon)
64
70
  })
65
71
 
66
72
  it("throws when a blob omits zlib data", () => {
@@ -80,6 +86,6 @@ describe("createOsmPbfBlobGenerator", () => {
80
86
  const chunk = concatUint8(uint32BE(blobHeader.byteLength), blobHeader, blob)
81
87
  const generate = createOsmPbfBlobGenerator()
82
88
  const iterator = generate(chunk)
83
- assert.throws(() => iterator.next(), /Blob has no zlib data/)
89
+ expect(() => iterator.next()).toThrow(/Blob has no zlib data/)
84
90
  })
85
91
  })
@@ -1,9 +1,13 @@
1
+ import { beforeAll, describe, expect } from "bun:test"
1
2
  import {
2
3
  getFixtureFile,
3
4
  getFixtureFileReadStream,
4
5
  PBFs,
5
6
  } from "@osmix/shared/test/fixtures"
6
- import { assert, beforeAll, bench, describe } from "vitest"
7
+
8
+ // @ts-expect-error - bench is available at runtime but not in types
9
+ const { bench } = globalThis as { bench: typeof import("bun:test").test }
10
+
7
11
  import {
8
12
  OsmPbfBytesToBlocksTransformStream,
9
13
  readOsmPbf,
@@ -35,8 +39,8 @@ describe.each(Object.entries(PBFs))("%s", (_name, pbf) => {
35
39
  }),
36
40
  )
37
41
 
38
- assert.equal(count.nodes, pbf.nodes)
39
- assert.equal(count.ways, pbf.ways)
40
- assert.equal(count.relations, pbf.relations)
42
+ expect(count.nodes).toBe(pbf.nodes)
43
+ expect(count.ways).toBe(pbf.ways)
44
+ expect(count.relations).toBe(pbf.relations)
41
45
  })
42
46
  })
package/test/read.test.ts CHANGED
@@ -1,9 +1,9 @@
1
+ import { beforeAll, describe, expect, it } from "bun:test"
1
2
  import {
2
3
  getFixtureFile,
3
4
  getFixtureFileReadStream,
4
5
  PBFs,
5
6
  } from "@osmix/shared/test/fixtures"
6
- import { assert, beforeAll, describe, it } from "vitest"
7
7
  import {
8
8
  OsmPbfBytesToBlocksTransformStream,
9
9
  readOsmPbf,
@@ -25,15 +25,15 @@ describe("read", () => {
25
25
  if ("primitivegroup" in block) {
26
26
  for (const group of block.primitivegroup) onGroup(group)
27
27
  } else {
28
- assert.deepEqual(block.bbox, pbf.bbox)
28
+ expect(block.bbox).toEqual(pbf.bbox)
29
29
  }
30
30
  },
31
31
  }),
32
32
  )
33
33
 
34
- assert.equal(count.nodes, pbf.nodes)
35
- assert.equal(count.ways, pbf.ways)
36
- assert.equal(count.relations, pbf.relations)
34
+ expect(count.nodes).toBe(pbf.nodes)
35
+ expect(count.ways).toBe(pbf.ways)
36
+ expect(count.relations).toBe(pbf.relations)
37
37
  })
38
38
 
39
39
  it("from buffer", async () => {
@@ -1,4 +1,4 @@
1
- import { assert, describe, expect, it } from "vitest"
1
+ import { describe, expect, it } from "bun:test"
2
2
  import { OsmBlocksToPbfBytesTransformStream } from "../src/blocks-to-pbf"
3
3
  import { OsmPbfBytesToBlocksTransformStream } from "../src/pbf-to-blocks"
4
4
  import { concatUint8 } from "../src/utils"
@@ -46,13 +46,13 @@ describe("transform streams", () => {
46
46
  }),
47
47
  )
48
48
 
49
- assert.deepEqual(concatUint8(...chunks), fileBytes)
49
+ expect(concatUint8(...chunks)).toEqual(fileBytes)
50
50
  })
51
51
 
52
52
  it("parses streamed bytes back into header and primitive blocks", async () => {
53
53
  const { header, primitiveBlock, fileBytes } =
54
54
  await createSamplePbfFileBytes()
55
- assert.exists(primitiveBlock.primitivegroup[0])
55
+ expect(primitiveBlock.primitivegroup[0]).toBeDefined()
56
56
  const blocks: unknown[] = []
57
57
 
58
58
  const input = new ReadableStream({
@@ -71,22 +71,31 @@ describe("transform streams", () => {
71
71
  }),
72
72
  )
73
73
 
74
- assert.equal(blocks.length, 2)
74
+ expect(blocks.length).toBe(2)
75
75
  const headerBlock = blocks[0]
76
76
  if (!isHeaderBlock(headerBlock)) {
77
- assert.fail("Expected header block")
77
+ throw new Error("Expected header block")
78
78
  }
79
- assert.deepEqual(headerBlock.bbox, header.bbox)
80
- assert.deepEqual(headerBlock.required_features, header.required_features)
79
+ expect(headerBlock.bbox).toEqual(header.bbox)
80
+ expect(headerBlock.required_features).toEqual(header.required_features)
81
81
  const block = blocks[1]
82
82
  if (!isPrimitiveBlock(block)) {
83
- assert.fail("Expected primitive block")
83
+ throw new Error("Expected primitive block")
84
84
  }
85
- assert.lengthOf(block.primitivegroup, primitiveBlock.primitivegroup.length)
86
- assert.exists(block.primitivegroup)
87
- assert.exists(block.primitivegroup[0])
85
+ expect(block.primitivegroup).toHaveLength(
86
+ primitiveBlock.primitivegroup.length,
87
+ )
88
+ expect(block.primitivegroup).toBeDefined()
89
+ expect(block.primitivegroup[0]).toBeDefined()
90
+ if (!block.primitivegroup[0])
91
+ throw new Error("block.primitivegroup[0] is undefined")
92
+ if (!primitiveBlock.primitivegroup[0])
93
+ throw new Error("primitiveBlock.primitivegroup[0] is undefined")
88
94
  const dense = block.primitivegroup[0].dense
89
- assert.exists(dense)
90
- assert.deepEqual(dense.id, primitiveBlock.primitivegroup[0].dense?.id)
95
+ expect(dense).toBeDefined()
96
+ if (!dense) throw new Error("dense is undefined")
97
+ if (!primitiveBlock.primitivegroup[0]?.dense)
98
+ throw new Error("primitiveBlock.primitivegroup[0].dense is undefined")
99
+ expect(dense.id).toEqual(primitiveBlock.primitivegroup[0].dense.id)
91
100
  })
92
101
  })
@@ -1,4 +1,4 @@
1
- import { assert, describe, expect, it } from "vitest"
1
+ import { describe, expect, it } from "bun:test"
2
2
  import {
3
3
  concatUint8,
4
4
  toAsyncGenerator,
@@ -11,9 +11,9 @@ describe("utils", () => {
11
11
  it("wraps values into an async generator", async () => {
12
12
  const generator = toAsyncGenerator(3)
13
13
  const first = await generator.next()
14
- assert.deepEqual(first, { value: 3, done: false })
14
+ expect(first).toEqual({ value: 3, done: false })
15
15
  const done = await generator.next()
16
- assert.deepEqual(done, { value: undefined, done: true })
16
+ expect(done).toEqual({ value: undefined, done: true })
17
17
  })
18
18
 
19
19
  it("consumes readable streams", async () => {
@@ -26,7 +26,7 @@ describe("utils", () => {
26
26
  })
27
27
  const values: number[] = []
28
28
  for await (const value of toAsyncGenerator(stream)) values.push(value)
29
- assert.deepEqual(values, [1, 2])
29
+ expect(values).toEqual([1, 2])
30
30
  })
31
31
 
32
32
  it("throws on nullish inputs", async () => {
@@ -39,18 +39,18 @@ describe("utils", () => {
39
39
  it("concatenates Uint8Array segments", () => {
40
40
  const a = Uint8Array.of(1, 2)
41
41
  const b = Uint8Array.of(3)
42
- assert.deepEqual(concatUint8(a, b), Uint8Array.of(1, 2, 3))
42
+ expect(concatUint8(a, b)).toEqual(Uint8Array.of(1, 2, 3))
43
43
  })
44
44
 
45
45
  it("encodes big-endian 32-bit integers", () => {
46
- assert.deepEqual(uint32BE(0x01020304), Uint8Array.of(1, 2, 3, 4))
46
+ expect(uint32BE(0x01020304)).toEqual(Uint8Array.of(1, 2, 3, 4))
47
47
  })
48
48
 
49
49
  it("compresses and decompresses data", async () => {
50
50
  const input = new TextEncoder().encode("osmix") as Uint8Array<ArrayBuffer>
51
51
  const compressed = await webCompress(input)
52
- assert.notDeepEqual(compressed, input)
52
+ expect(compressed).not.toEqual(input)
53
53
  const decompressed = await webDecompress(compressed)
54
- assert.deepEqual(decompressed, input)
54
+ expect(decompressed).toEqual(input)
55
55
  })
56
56
  })
package/test/utils.ts CHANGED
@@ -1,5 +1,5 @@
1
+ import { expect } from "bun:test"
1
2
  import type { PbfFixture } from "@osmix/shared/test/fixtures"
2
- import { assert } from "vitest"
3
3
  import type {
4
4
  OsmPbfBlock,
5
5
  OsmPbfGroup,
@@ -13,18 +13,18 @@ export async function testOsmPbfReader(
13
13
  },
14
14
  pbf: PbfFixture,
15
15
  ) {
16
- assert.deepEqual(osm.header.bbox, pbf.bbox)
16
+ expect(osm.header.bbox).toEqual(pbf.bbox)
17
17
 
18
18
  const { onGroup, count } = createOsmEntityCounter()
19
19
  for await (const block of osm.blocks)
20
20
  for (const group of block.primitivegroup) onGroup(group)
21
21
 
22
- assert.equal(count.nodes, pbf.nodes)
23
- assert.equal(count.ways, pbf.ways)
24
- assert.equal(count.relations, pbf.relations)
25
- assert.equal(count.node0, pbf.node0.id)
26
- assert.equal(count.way0, pbf.way0)
27
- assert.equal(count.relation0, pbf.relation0)
22
+ expect(count.nodes).toBe(pbf.nodes)
23
+ expect(count.ways).toBe(pbf.ways)
24
+ expect(count.relations).toBe(pbf.relations)
25
+ expect(count.node0).toBe(pbf.node0.id)
26
+ expect(count.way0).toBe(pbf.way0)
27
+ expect(count.relation0).toBe(pbf.relation0)
28
28
 
29
29
  return count
30
30
  }
@@ -1,3 +1,4 @@
1
+ import { describe, expect, it } from "bun:test"
1
2
  import { unlink } from "node:fs/promises"
2
3
  import {
3
4
  getFixtureFile,
@@ -6,7 +7,6 @@ import {
6
7
  getFixturePath,
7
8
  PBFs,
8
9
  } from "@osmix/shared/test/fixtures"
9
- import { assert, describe, it } from "vitest"
10
10
  import {
11
11
  OsmBlocksToPbfBytesTransformStream,
12
12
  osmBlockToPbfBlobBytes,
@@ -53,15 +53,20 @@ describe("write", () => {
53
53
  }
54
54
 
55
55
  // Re-parse the new PBF and test
56
- assert.exists(data.buffer)
57
- // TODO: assert.equal(stream.buffer.byteLength, fileData.byteLength)
56
+ expect(data.buffer).toBeDefined()
57
+ // Note: We don't assert byte-level equality because the written PBF may have
58
+ // different compression, block ordering, or encoding than the original file.
59
+ // Semantic equivalence (verified by parsing and comparing entities) is more meaningful.
58
60
  const osm2 = await readOsmPbf(data)
59
61
 
60
- assert.deepEqual(osm.header, osm2.header)
62
+ expect(osm.header).toEqual(osm2.header)
61
63
  const entities = await testOsmPbfReader(osm2, pbf)
62
- assert.equal(entities.node0, node0)
63
- assert.equal(entities.way0, way0)
64
- assert.equal(entities.relation0, relation0)
64
+ if (node0 === null || way0 === null || relation0 === null) {
65
+ throw new Error("Expected node0, way0, and relation0 to be set")
66
+ }
67
+ expect(entities.node0).toBe(node0)
68
+ expect(entities.way0).toBe(way0)
69
+ expect(entities.relation0).toBe(relation0)
65
70
  })
66
71
 
67
72
  it("to file", async () => {
@@ -77,7 +82,7 @@ describe("write", () => {
77
82
  const testFileData = await getFixtureFile(pbf.url)
78
83
  const testOsm = await readOsmPbf(testFileData)
79
84
 
80
- assert.deepEqual(testOsm.header.bbox, pbf.bbox)
85
+ expect(testOsm.header.bbox).toEqual(pbf.bbox)
81
86
  await testOsmPbfReader(testOsm, pbf)
82
87
 
83
88
  await unlink(getFixturePath(testFileName))
@@ -1,5 +0,0 @@
1
- /**
2
- * Decompresses raw OSM PBF blobs and yields typed header and primitive blocks.
3
- * Expects the first blob to contain the file header and streams the rest as data blocks.
4
- */
5
- export declare function osmPbfBlobsToBlocksGenerator(blobs: AsyncGenerator<Uint8Array<ArrayBuffer>> | Generator<Uint8Array<ArrayBuffer>>): AsyncGenerator<import(".").OsmPbfHeaderBlock | import(".").OsmPbfBlock, void, unknown>;
@@ -1,21 +0,0 @@
1
- import Pbf from "pbf";
2
- import { readHeaderBlock, readPrimitiveBlock } from "./proto/osmformat";
3
- import { decompress } from "./utils";
4
- /**
5
- * Decompresses raw OSM PBF blobs and yields typed header and primitive blocks.
6
- * Expects the first blob to contain the file header and streams the rest as data blocks.
7
- */
8
- export async function* osmPbfBlobsToBlocksGenerator(blobs) {
9
- let headerRead = false;
10
- for await (const blob of blobs) {
11
- const decompressedBlob = await decompress(blob);
12
- const pbf = new Pbf(decompressedBlob);
13
- if (!headerRead) {
14
- headerRead = true;
15
- yield readHeaderBlock(pbf);
16
- }
17
- else {
18
- yield readPrimitiveBlock(pbf);
19
- }
20
- }
21
- }
@@ -1,16 +0,0 @@
1
- import type { OsmPbfBlock, OsmPbfHeaderBlock } from "./proto/osmformat";
2
- /**
3
- * Serializes a header or primitive block into a spec-compliant compressed blob.
4
- * Automatically sets the blob type, compresses the payload, and enforces size guardrails.
5
- * @param block - Parsed header or primitive block to encode.
6
- * @returns BlobHeader length prefix + Blob bytes as a single Uint8Array.
7
- */
8
- export declare function osmBlockToPbfBlobBytes(block: OsmPbfBlock | OsmPbfHeaderBlock): Promise<Uint8Array<ArrayBufferLike>>;
9
- /**
10
- * Web `TransformStream` that converts OSM header/data blocks into PBF byte chunks.
11
- * Throws if the header is not the first block and reuses `osmBlockToPbfBlobBytes` for encoding.
12
- */
13
- export declare class OsmBlocksToPbfBytesTransformStream extends TransformStream<OsmPbfHeaderBlock | OsmPbfBlock, Uint8Array> {
14
- headerEnqueued: boolean;
15
- constructor();
16
- }
@@ -1,73 +0,0 @@
1
- import Pbf from "pbf";
2
- import { writeBlob, writeBlobHeader } from "./proto/fileformat";
3
- import { writeHeaderBlock, writePrimitiveBlock } from "./proto/osmformat";
4
- import { MAX_BLOB_SIZE_BYTES, MAX_HEADER_SIZE_BYTES, RECOMMENDED_BLOB_SIZE_BYTES, RECOMMENDED_HEADER_SIZE_BYTES, } from "./spec";
5
- import { compress, concatUint8, uint32BE } from "./utils";
6
- /**
7
- * Serializes a header or primitive block into a spec-compliant compressed blob.
8
- * Automatically sets the blob type, compresses the payload, and enforces size guardrails.
9
- * @param block - Parsed header or primitive block to encode.
10
- * @returns BlobHeader length prefix + Blob bytes as a single Uint8Array.
11
- */
12
- export async function osmBlockToPbfBlobBytes(block) {
13
- const contentPbf = new Pbf();
14
- let type;
15
- if ("primitivegroup" in block) {
16
- type = "OSMData";
17
- writePrimitiveBlock(block, contentPbf);
18
- }
19
- else {
20
- type = "OSMHeader";
21
- writeHeaderBlock(block, contentPbf);
22
- }
23
- const contentData = contentPbf.finish();
24
- const raw_size = contentData.length;
25
- const compressedBuffer = await compress(contentData);
26
- const blobPbf = new Pbf();
27
- writeBlob({
28
- raw_size,
29
- zlib_data: compressedBuffer,
30
- }, blobPbf);
31
- const blob = blobPbf.finish();
32
- const blobHeaderPbf = new Pbf();
33
- writeBlobHeader({
34
- type,
35
- datasize: blob.length,
36
- }, blobHeaderPbf);
37
- const blobHeader = blobHeaderPbf.finish();
38
- const blobHeaderSize = uint32BE(blobHeader.byteLength);
39
- // Check the BlobHeader and Blob sizes, log error if over the recommended size, throw error if over the maximum size
40
- if (blobHeader.byteLength > RECOMMENDED_HEADER_SIZE_BYTES) {
41
- const sizeKiB = (blobHeader.byteLength / 1024).toFixed(2);
42
- if (blobHeader.byteLength > MAX_HEADER_SIZE_BYTES) {
43
- throw new Error(`BlobHeader is ${sizeKiB} KiB, the maximum size is 64KiB`);
44
- }
45
- console.warn(`BlobHeader is ${sizeKiB} KiB, the recommended size is 32KiB`);
46
- }
47
- if (blob.byteLength > RECOMMENDED_BLOB_SIZE_BYTES) {
48
- const sizeMiB = (blob.byteLength / 1024 / 1024).toFixed(2);
49
- if (blob.byteLength > MAX_BLOB_SIZE_BYTES) {
50
- throw new Error(`Blob is ${sizeMiB} MiB, the maximum size is 32MiB`);
51
- }
52
- console.warn(`Blob is ${sizeMiB} MiB, the recommended size is 16MiB`);
53
- }
54
- return concatUint8(blobHeaderSize, blobHeader, blob);
55
- }
56
- /**
57
- * Web `TransformStream` that converts OSM header/data blocks into PBF byte chunks.
58
- * Throws if the header is not the first block and reuses `osmBlockToPbfBlobBytes` for encoding.
59
- */
60
- export class OsmBlocksToPbfBytesTransformStream extends TransformStream {
61
- headerEnqueued = false;
62
- constructor() {
63
- super({
64
- transform: async (block, controller) => {
65
- if ("primitivegroup" in block && !this.headerEnqueued) {
66
- throw Error("Header first in ReadableStream of blocks.");
67
- }
68
- this.headerEnqueued = true;
69
- controller.enqueue(await osmBlockToPbfBlobBytes(block));
70
- },
71
- });
72
- }
73
- }
package/dist/index.d.ts DELETED
@@ -1,8 +0,0 @@
1
- export * from "./blobs-to-blocks";
2
- export * from "./blocks-to-pbf";
3
- export * from "./pbf-to-blobs";
4
- export * from "./pbf-to-blocks";
5
- export * from "./proto/fileformat";
6
- export * from "./proto/osmformat";
7
- export * from "./spec";
8
- export * from "./utils";
package/dist/index.js DELETED
@@ -1,8 +0,0 @@
1
- export * from "./blobs-to-blocks";
2
- export * from "./blocks-to-pbf";
3
- export * from "./pbf-to-blobs";
4
- export * from "./pbf-to-blocks";
5
- export * from "./proto/fileformat";
6
- export * from "./proto/osmformat";
7
- export * from "./spec";
8
- export * from "./utils";
@@ -1,6 +0,0 @@
1
- /**
2
- * Creates a stateful parser that slices incoming bytes into compressed OSM PBF blobs.
3
- * Works with buffers, iterables, or streams and yields `Uint8Array` payloads ready to decompress.
4
- * The first blob represents the file header; subsequent blobs hold primitive data.
5
- */
6
- export declare function createOsmPbfBlobGenerator(): (chunk: Uint8Array) => Generator<Uint8Array<ArrayBuffer>, void, unknown>;
@@ -1,48 +0,0 @@
1
- import Pbf from "pbf";
2
- import { HEADER_LENGTH_BYTES } from "./pbf-to-blocks";
3
- import { readBlob, readBlobHeader, } from "./proto/fileformat";
4
- /**
5
- * Creates a stateful parser that slices incoming bytes into compressed OSM PBF blobs.
6
- * Works with buffers, iterables, or streams and yields `Uint8Array` payloads ready to decompress.
7
- * The first blob represents the file header; subsequent blobs hold primitive data.
8
- */
9
- export function createOsmPbfBlobGenerator() {
10
- let pbf = new Pbf(new Uint8Array(0));
11
- let state = "header-length";
12
- let bytesNeeded = HEADER_LENGTH_BYTES;
13
- let blobHeader = null;
14
- /**
15
- * Feed the parser with the next chunk of bytes and yield any complete compressed blobs.
16
- */
17
- return function* nextChunk(chunk) {
18
- const currentBuffer = pbf.buf.slice(pbf.pos);
19
- const tmpBuffer = new Uint8Array(currentBuffer.buffer.byteLength + chunk.byteLength);
20
- tmpBuffer.set(currentBuffer.subarray(0));
21
- tmpBuffer.set(new Uint8Array(chunk), currentBuffer.byteLength);
22
- pbf = new Pbf(tmpBuffer);
23
- while (pbf.pos + bytesNeeded <= pbf.length) {
24
- if (state === "header-length") {
25
- const dataView = new DataView(pbf.buf.buffer);
26
- bytesNeeded = dataView.getInt32(pbf.pos, false); // network byte order
27
- pbf.pos += HEADER_LENGTH_BYTES;
28
- state = "header";
29
- }
30
- else if (state === "header") {
31
- blobHeader = readBlobHeader(pbf, pbf.pos + bytesNeeded);
32
- bytesNeeded = blobHeader.datasize;
33
- state = "blob";
34
- }
35
- else if (state === "blob") {
36
- if (blobHeader == null)
37
- throw Error("Blob header has not been read");
38
- const blob = readBlob(pbf, pbf.pos + bytesNeeded);
39
- if (blob.zlib_data === undefined || blob.zlib_data.length === 0)
40
- throw Error("Blob has no zlib data. Format is unsupported.");
41
- yield blob.zlib_data;
42
- state = "header-length";
43
- bytesNeeded = HEADER_LENGTH_BYTES;
44
- blobHeader = null;
45
- }
46
- }
47
- };
48
- }
@@ -1,20 +0,0 @@
1
- import { type OsmPbfBlock, type OsmPbfHeaderBlock } from "./proto/osmformat";
2
- import { type AsyncGeneratorValue } from "./utils";
3
- export declare const HEADER_LENGTH_BYTES = 4;
4
- /**
5
- * Parses OSM PBF bytes from buffers, streams, or generators into header + block iterators.
6
- * Returns the decoded header and a lazy async generator of primitive blocks.
7
- */
8
- export declare function readOsmPbf(data: AsyncGeneratorValue<ArrayBufferLike>): Promise<{
9
- header: OsmPbfHeaderBlock;
10
- blocks: AsyncGenerator<OsmPbfBlock>;
11
- }>;
12
- /**
13
- * Web `TransformStream` that turns raw PBF byte chunks into OSM header/data blocks.
14
- * Assumes the first decoded blob carries the header and emits it before any primitive blocks.
15
- */
16
- export declare class OsmPbfBytesToBlocksTransformStream extends TransformStream<ArrayBufferLike, OsmPbfHeaderBlock | OsmPbfBlock> {
17
- generateBlobsFromChunk: (chunk: Uint8Array) => Generator<Uint8Array<ArrayBuffer>, void, unknown>;
18
- header: OsmPbfHeaderBlock | null;
19
- constructor();
20
- }
@@ -1,53 +0,0 @@
1
- import Pbf from "pbf";
2
- import { osmPbfBlobsToBlocksGenerator } from "./blobs-to-blocks";
3
- import { createOsmPbfBlobGenerator } from "./pbf-to-blobs";
4
- import { readHeaderBlock, readPrimitiveBlock, } from "./proto/osmformat";
5
- import { decompress, toAsyncGenerator } from "./utils";
6
- export const HEADER_LENGTH_BYTES = 4;
7
- /**
8
- * Parses OSM PBF bytes from buffers, streams, or generators into header + block iterators.
9
- * Returns the decoded header and a lazy async generator of primitive blocks.
10
- */
11
- export async function readOsmPbf(data) {
12
- const generateBlobsFromChunk = createOsmPbfBlobGenerator();
13
- const blocks = osmPbfBlobsToBlocksGenerator((async function* () {
14
- for await (const chunk of toAsyncGenerator(data)) {
15
- for await (const blob of generateBlobsFromChunk(new Uint8Array(chunk))) {
16
- yield blob;
17
- }
18
- }
19
- })());
20
- const header = (await blocks.next()).value;
21
- if (header == null || !("required_features" in header)) {
22
- throw Error("OSM PBF header block not found");
23
- }
24
- return {
25
- header,
26
- blocks: blocks,
27
- };
28
- }
29
- /**
30
- * Web `TransformStream` that turns raw PBF byte chunks into OSM header/data blocks.
31
- * Assumes the first decoded blob carries the header and emits it before any primitive blocks.
32
- */
33
- export class OsmPbfBytesToBlocksTransformStream extends TransformStream {
34
- generateBlobsFromChunk = createOsmPbfBlobGenerator();
35
- header = null;
36
- constructor() {
37
- super({
38
- transform: async (bytesChunk, controller) => {
39
- for await (const rawBlobs of this.generateBlobsFromChunk(new Uint8Array(bytesChunk))) {
40
- const decompressed = await decompress(rawBlobs);
41
- const pbf = new Pbf(decompressed);
42
- if (this.header == null) {
43
- this.header = readHeaderBlock(pbf);
44
- controller.enqueue(this.header);
45
- }
46
- else {
47
- controller.enqueue(readPrimitiveBlock(pbf));
48
- }
49
- }
50
- },
51
- });
52
- }
53
- }
@@ -1,26 +0,0 @@
1
- import type Pbf from "pbf";
2
- export type OsmPbfBlob = {
3
- raw_size?: number;
4
- raw?: Uint8Array;
5
- zlib_data?: Uint8Array;
6
- };
7
- export type OsmPbfBlobHeader = {
8
- type: "OSMHeader" | "OSMData";
9
- datasize: number;
10
- };
11
- /**
12
- * Reads an `OsmPbfBlob` message from the current position in the Pbf reader.
13
- */
14
- export declare function readBlob(pbf: Pbf, end?: number): OsmPbfBlob;
15
- /**
16
- * Writes an `OsmPbfBlob` message to the provided Pbf writer.
17
- */
18
- export declare function writeBlob(obj: OsmPbfBlob, pbf: Pbf): void;
19
- /**
20
- * Reads an `OsmPbfBlobHeader` from the current position in the Pbf reader.
21
- */
22
- export declare function readBlobHeader(pbf: Pbf, end?: number): OsmPbfBlobHeader;
23
- /**
24
- * Writes an `OsmPbfBlobHeader` message to the provided Pbf writer.
25
- */
26
- export declare function writeBlobHeader(obj: OsmPbfBlobHeader, pbf: Pbf): void;