@osmix/pbf 0.0.1

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 (45) hide show
  1. package/CHANGELOG.md +7 -0
  2. package/README.md +144 -0
  3. package/dist/blobs-to-blocks.d.ts +5 -0
  4. package/dist/blobs-to-blocks.js +21 -0
  5. package/dist/blocks-to-pbf.d.ts +16 -0
  6. package/dist/blocks-to-pbf.js +73 -0
  7. package/dist/index.d.ts +8 -0
  8. package/dist/index.js +8 -0
  9. package/dist/pbf-to-blobs.d.ts +6 -0
  10. package/dist/pbf-to-blobs.js +48 -0
  11. package/dist/pbf-to-blocks.d.ts +20 -0
  12. package/dist/pbf-to-blocks.js +53 -0
  13. package/dist/proto/fileformat.d.ts +26 -0
  14. package/dist/proto/fileformat.js +56 -0
  15. package/dist/proto/osmformat.d.ts +91 -0
  16. package/dist/proto/osmformat.js +458 -0
  17. package/dist/spec.d.ts +5 -0
  18. package/dist/spec.js +9 -0
  19. package/dist/utils.d.ts +27 -0
  20. package/dist/utils.js +92 -0
  21. package/package.json +49 -0
  22. package/src/blobs-to-blocks.ts +28 -0
  23. package/src/blocks-to-pbf.ts +98 -0
  24. package/src/index.ts +8 -0
  25. package/src/pbf-to-blobs.ts +56 -0
  26. package/src/pbf-to-blocks.ts +77 -0
  27. package/src/proto/fileformat.proto +68 -0
  28. package/src/proto/fileformat.ts +70 -0
  29. package/src/proto/osmformat.proto +262 -0
  30. package/src/proto/osmformat.ts +488 -0
  31. package/src/spec.ts +10 -0
  32. package/src/utils.ts +90 -0
  33. package/test/blobs-to-blocks.test.ts +73 -0
  34. package/test/helpers.ts +66 -0
  35. package/test/pbf-to-blobs.test.ts +85 -0
  36. package/test/read.bench.ts +42 -0
  37. package/test/read.test.ts +45 -0
  38. package/test/streams.test.ts +92 -0
  39. package/test/utils.bun.test.ts +327 -0
  40. package/test/utils.test.ts +56 -0
  41. package/test/utils.ts +65 -0
  42. package/test/verify-pbf-reading.bun.test.ts +39 -0
  43. package/test/write.test.ts +86 -0
  44. package/tsconfig.json +9 -0
  45. package/vitest.config.ts +7 -0
@@ -0,0 +1,488 @@
1
+ // code generated by @mapbox/pbf v4.0.1 and types merged in by hand
2
+ import type Pbf from "pbf"
3
+
4
+ export type OsmPbfHeaderBBox = {
5
+ left: number
6
+ right: number
7
+ top: number
8
+ bottom: number
9
+ }
10
+
11
+ export type OsmPbfHeaderBlock = {
12
+ bbox?: OsmPbfHeaderBBox
13
+ required_features: string[]
14
+ optional_features: string[]
15
+ writingprogram?: string
16
+ source?: string
17
+ osmosis_replication_timestamp?: number
18
+ osmosis_replication_sequence_number?: number
19
+ osmosis_replication_base_url?: string
20
+ }
21
+
22
+ export interface OsmPbfBlockSettings {
23
+ granularity?: number
24
+ lat_offset?: number
25
+ lon_offset?: number
26
+ date_granularity?: number
27
+ }
28
+
29
+ export interface OsmPbfBlock extends OsmPbfBlockSettings {
30
+ stringtable: OsmPbfStringTable
31
+ primitivegroup: OsmPbfGroup[]
32
+ }
33
+
34
+ export type OsmPbfGroup = {
35
+ nodes: OsmPbfNode[]
36
+ dense?: OsmPbfDenseNodes
37
+ ways: OsmPbfWay[]
38
+ relations: OsmPbfRelation[]
39
+ }
40
+
41
+ export type OsmPbfStringTable = Uint8Array[]
42
+
43
+ export interface OsmPbfInfo {
44
+ version?: number
45
+ timestamp?: number
46
+ changeset?: number
47
+ uid?: number
48
+ user_sid?: number
49
+ visible?: boolean
50
+ }
51
+
52
+ export type OsmPbfDenseInfo = {
53
+ version: number[]
54
+ timestamp: number[]
55
+ changeset: number[]
56
+ uid: number[]
57
+ user_sid: number[]
58
+ visible: boolean[]
59
+ }
60
+
61
+ export interface OsmPbfPrimitive {
62
+ id: number
63
+ keys: number[]
64
+ vals: number[]
65
+ info?: OsmPbfInfo
66
+ }
67
+
68
+ export interface OsmPbfNode extends OsmPbfPrimitive {
69
+ lat: number
70
+ lon: number
71
+ }
72
+
73
+ export type OsmPbfDenseNodes = {
74
+ id: number[]
75
+ denseinfo?: OsmPbfDenseInfo
76
+ lat: number[]
77
+ lon: number[]
78
+ keys_vals: number[]
79
+ }
80
+
81
+ export interface OsmPbfWay extends OsmPbfPrimitive {
82
+ refs: number[]
83
+ }
84
+
85
+ export interface OsmPbfRelation extends OsmPbfPrimitive {
86
+ roles_sid: number[]
87
+ memids: number[]
88
+ types: number[]
89
+ }
90
+
91
+ /**
92
+ * Reads an `OsmPbfHeaderBlock` message from the provided Pbf reader.
93
+ */
94
+ export function readHeaderBlock(pbf: Pbf, end?: number): OsmPbfHeaderBlock {
95
+ return pbf.readFields(
96
+ readHeaderBlockField,
97
+ {
98
+ required_features: [],
99
+ optional_features: [],
100
+ },
101
+ end,
102
+ )
103
+ }
104
+ /**
105
+ * Populates header block fields based on the protobuf tag encountered.
106
+ */
107
+ function readHeaderBlockField(tag: number, obj: OsmPbfHeaderBlock, pbf: Pbf) {
108
+ if (tag === 1) obj.bbox = readHeaderBBox(pbf, pbf.readVarint() + pbf.pos)
109
+ else if (tag === 4) obj.required_features.push(pbf.readString())
110
+ else if (tag === 5) obj.optional_features.push(pbf.readString())
111
+ else if (tag === 16) obj.writingprogram = pbf.readString()
112
+ else if (tag === 17) obj.source = pbf.readString()
113
+ else if (tag === 32) obj.osmosis_replication_timestamp = pbf.readVarint(true)
114
+ else if (tag === 33) {
115
+ obj.osmosis_replication_sequence_number = pbf.readVarint(true)
116
+ } else if (tag === 34) obj.osmosis_replication_base_url = pbf.readString()
117
+ }
118
+ /**
119
+ * Serializes an `OsmPbfHeaderBlock` message into the Pbf writer.
120
+ */
121
+ export function writeHeaderBlock(obj: OsmPbfHeaderBlock, pbf: Pbf) {
122
+ if (obj.bbox) pbf.writeMessage(1, writeHeaderBBox, obj.bbox)
123
+ if (obj.required_features) {
124
+ for (const item of obj.required_features) pbf.writeStringField(4, item)
125
+ }
126
+ if (obj.optional_features) {
127
+ for (const item of obj.optional_features) pbf.writeStringField(5, item)
128
+ }
129
+ if (obj.writingprogram) pbf.writeStringField(16, obj.writingprogram)
130
+ if (obj.source) pbf.writeStringField(17, obj.source)
131
+ if (obj.osmosis_replication_timestamp) {
132
+ pbf.writeVarintField(32, obj.osmosis_replication_timestamp)
133
+ }
134
+ if (obj.osmosis_replication_sequence_number) {
135
+ pbf.writeVarintField(33, obj.osmosis_replication_sequence_number)
136
+ }
137
+ if (obj.osmosis_replication_base_url) {
138
+ pbf.writeStringField(34, obj.osmosis_replication_base_url)
139
+ }
140
+ }
141
+
142
+ /**
143
+ * Reads a header bounding box and converts nanodegrees to degrees.
144
+ */
145
+ function readHeaderBBox(pbf: Pbf, end?: number): OsmPbfHeaderBBox {
146
+ return pbf.readFields(
147
+ readHeaderBBoxField,
148
+ { left: 0, right: 0, top: 0, bottom: 0 },
149
+ end,
150
+ )
151
+ }
152
+ /**
153
+ * Populates bounding box properties while converting from nanodegrees.
154
+ */
155
+ function readHeaderBBoxField(tag: number, obj: OsmPbfHeaderBBox, pbf: Pbf) {
156
+ if (tag === 1) obj.left = pbf.readSVarint() / 1e9
157
+ else if (tag === 2) obj.right = pbf.readSVarint() / 1e9
158
+ else if (tag === 3) obj.top = pbf.readSVarint() / 1e9
159
+ else if (tag === 4) obj.bottom = pbf.readSVarint() / 1e9
160
+ }
161
+ /**
162
+ * Serializes a header bounding box, converting degrees back to nanodegrees.
163
+ */
164
+ function writeHeaderBBox(obj: OsmPbfHeaderBBox, pbf: Pbf) {
165
+ if (obj.left) pbf.writeSVarintField(1, obj.left * 1e9)
166
+ if (obj.right) pbf.writeSVarintField(2, obj.right * 1e9)
167
+ if (obj.top) pbf.writeSVarintField(3, obj.top * 1e9)
168
+ if (obj.bottom) pbf.writeSVarintField(4, obj.bottom * 1e9)
169
+ }
170
+
171
+ /**
172
+ * Reads a primitive block containing string tables and primitive groups.
173
+ */
174
+ export function readPrimitiveBlock(pbf: Pbf, end?: number): OsmPbfBlock {
175
+ return pbf.readFields(
176
+ readPrimitiveBlockField,
177
+ {
178
+ stringtable: [],
179
+ primitivegroup: [],
180
+ },
181
+ end,
182
+ )
183
+ }
184
+
185
+ /**
186
+ * Populates primitive block fields based on protobuf tags.
187
+ */
188
+ function readPrimitiveBlockField(tag: number, obj: OsmPbfBlock, pbf: Pbf) {
189
+ if (tag === 1) {
190
+ obj.stringtable = readStringTable(pbf, pbf.readVarint() + pbf.pos)
191
+ } else if (tag === 2) {
192
+ obj.primitivegroup.push(readPrimitiveGroup(pbf, pbf.readVarint() + pbf.pos))
193
+ } else if (tag === 17) {
194
+ obj.granularity = pbf.readVarint(true)
195
+ obj.granularity = !obj.granularity ? 1e7 : 1e9 / obj.granularity
196
+ } else if (tag === 19) obj.lat_offset = pbf.readVarint(true) * 1e-9
197
+ else if (tag === 20) obj.lon_offset = pbf.readVarint(true) * 1e-9
198
+ else if (tag === 18) obj.date_granularity = pbf.readVarint(true) ?? 1000
199
+ }
200
+
201
+ /**
202
+ * Serializes a primitive block including its string table and primitive groups.
203
+ */
204
+ export function writePrimitiveBlock(obj: OsmPbfBlock, pbf: Pbf) {
205
+ if (obj.stringtable) pbf.writeMessage(1, writeStringTable, obj.stringtable)
206
+ if (obj.primitivegroup) {
207
+ for (const item of obj.primitivegroup) {
208
+ pbf.writeMessage(2, writePrimitiveGroup, item)
209
+ }
210
+ }
211
+ if (obj.granularity != null && obj.granularity !== 1e7) {
212
+ console.error("writeGranularity", obj.granularity)
213
+ pbf.writeVarintField(17, 1e9 / obj.granularity)
214
+ }
215
+ if (obj.lat_offset) pbf.writeVarintField(19, obj.lat_offset / 1e-9)
216
+ if (obj.lon_offset) pbf.writeVarintField(20, obj.lon_offset / 1e-9)
217
+ if (obj.date_granularity != null && obj.date_granularity !== 1000) {
218
+ pbf.writeVarintField(18, obj.date_granularity)
219
+ }
220
+ }
221
+
222
+ /**
223
+ * Reads a primitive group with collections of primitives.
224
+ */
225
+ function readPrimitiveGroup(pbf: Pbf, end?: number): OsmPbfGroup {
226
+ return pbf.readFields(
227
+ readPrimitiveGroupField,
228
+ { nodes: [], ways: [], relations: [] },
229
+ end,
230
+ )
231
+ }
232
+ /**
233
+ * Populates primitive group collections from protobuf data.
234
+ */
235
+ function readPrimitiveGroupField(tag: number, obj: OsmPbfGroup, pbf: Pbf) {
236
+ if (tag === 1) obj.nodes.push(readNode(pbf, pbf.readVarint() + pbf.pos))
237
+ else if (tag === 2) {
238
+ obj.dense = readDenseNodes(pbf, pbf.readVarint() + pbf.pos)
239
+ } else if (tag === 3) obj.ways.push(readWay(pbf, pbf.readVarint() + pbf.pos))
240
+ else if (tag === 4) {
241
+ obj.relations.push(readRelation(pbf, pbf.readVarint() + pbf.pos))
242
+ }
243
+ }
244
+ /**
245
+ * Serializes a primitive group to protobuf.
246
+ */
247
+ function writePrimitiveGroup(obj: OsmPbfGroup, pbf: Pbf) {
248
+ if (obj.nodes) {
249
+ for (const item of obj.nodes) pbf.writeMessage(1, writeNode, item)
250
+ }
251
+ if (obj.dense) pbf.writeMessage(2, writeDenseNodes, obj.dense)
252
+ if (obj.ways) {
253
+ for (const item of obj.ways) pbf.writeMessage(3, writeWay, item)
254
+ }
255
+ if (obj.relations) {
256
+ for (const item of obj.relations) pbf.writeMessage(4, writeRelation, item)
257
+ }
258
+ }
259
+
260
+ /**
261
+ * Reads the shared string table for a primitive block.
262
+ */
263
+ function readStringTable(pbf: Pbf, end?: number): OsmPbfStringTable {
264
+ return pbf.readFields(readStringTableField, [], end)
265
+ }
266
+ /**
267
+ * Appends string table entries as they are encountered.
268
+ */
269
+ function readStringTableField(tag: number, obj: Uint8Array[], pbf: Pbf) {
270
+ if (tag === 1) obj.push(pbf.readBytes())
271
+ }
272
+ /**
273
+ * Serializes string table entries.
274
+ */
275
+ function writeStringTable(obj: OsmPbfStringTable, pbf: Pbf) {
276
+ if (obj) {
277
+ for (const item of obj) pbf.writeBytesField(1, item)
278
+ }
279
+ }
280
+
281
+ /**
282
+ * Reads metadata describing a single primitive.
283
+ */
284
+ function readInfo(pbf: Pbf, end?: number): OsmPbfInfo {
285
+ return pbf.readFields(readInfoField, {}, end)
286
+ }
287
+ /**
288
+ * Populates primitive metadata fields.
289
+ */
290
+ function readInfoField(tag: number, obj: OsmPbfInfo, pbf: Pbf) {
291
+ if (tag === 1) obj.version = pbf.readVarint(true)
292
+ else if (tag === 2) obj.timestamp = pbf.readVarint(true)
293
+ else if (tag === 3) obj.changeset = pbf.readVarint(true)
294
+ else if (tag === 4) obj.uid = pbf.readVarint(true)
295
+ else if (tag === 5) obj.user_sid = pbf.readVarint()
296
+ else if (tag === 6) obj.visible = pbf.readBoolean()
297
+ }
298
+ /**
299
+ * Serializes primitive metadata fields.
300
+ */
301
+ function writeInfo(obj: OsmPbfInfo, pbf: Pbf) {
302
+ if (obj.version != null && obj.version !== -1) {
303
+ pbf.writeVarintField(1, obj.version)
304
+ }
305
+ if (obj.timestamp) pbf.writeVarintField(2, obj.timestamp)
306
+ if (obj.changeset) pbf.writeVarintField(3, obj.changeset)
307
+ if (obj.uid) pbf.writeVarintField(4, obj.uid)
308
+ if (obj.user_sid) pbf.writeVarintField(5, obj.user_sid)
309
+ if (obj.visible) pbf.writeBooleanField(6, obj.visible)
310
+ }
311
+
312
+ /**
313
+ * Reads dense node metadata collections.
314
+ */
315
+ function readDenseInfo(pbf: Pbf, end?: number): OsmPbfDenseInfo {
316
+ return pbf.readFields(
317
+ readDenseInfoField,
318
+ {
319
+ version: [],
320
+ timestamp: [],
321
+ changeset: [],
322
+ uid: [],
323
+ user_sid: [],
324
+ visible: [],
325
+ },
326
+ end,
327
+ )
328
+ }
329
+ /**
330
+ * Populates dense node metadata arrays from packed fields.
331
+ */
332
+ function readDenseInfoField(tag: number, obj: OsmPbfDenseInfo, pbf: Pbf) {
333
+ if (tag === 1) pbf.readPackedVarint(obj.version, true)
334
+ else if (tag === 2) pbf.readPackedSVarint(obj.timestamp)
335
+ else if (tag === 3) pbf.readPackedSVarint(obj.changeset)
336
+ else if (tag === 4) pbf.readPackedSVarint(obj.uid)
337
+ else if (tag === 5) pbf.readPackedSVarint(obj.user_sid)
338
+ else if (tag === 6) pbf.readPackedBoolean(obj.visible)
339
+ }
340
+ /**
341
+ * Serializes dense node metadata arrays.
342
+ */
343
+ function writeDenseInfo(obj: OsmPbfDenseInfo, pbf: Pbf) {
344
+ if (obj.version) pbf.writePackedVarint(1, obj.version)
345
+ if (obj.timestamp) pbf.writePackedSVarint(2, obj.timestamp)
346
+ if (obj.changeset) pbf.writePackedSVarint(3, obj.changeset)
347
+ if (obj.uid) pbf.writePackedSVarint(4, obj.uid)
348
+ if (obj.user_sid) pbf.writePackedSVarint(5, obj.user_sid)
349
+ if (obj.visible) pbf.writePackedBoolean(6, obj.visible)
350
+ }
351
+
352
+ /**
353
+ * Reads a node primitive from the protobuf stream.
354
+ */
355
+ function readNode(pbf: Pbf, end?: number): OsmPbfNode {
356
+ return pbf.readFields(
357
+ readNodeField,
358
+ { id: 0, keys: [], vals: [], lat: 0, lon: 0 },
359
+ end,
360
+ )
361
+ }
362
+ /**
363
+ * Populates node fields based on protobuf tags.
364
+ */
365
+ function readNodeField(tag: number, obj: OsmPbfNode, pbf: Pbf) {
366
+ if (tag === 1) obj.id = pbf.readSVarint()
367
+ else if (tag === 2) pbf.readPackedVarint(obj.keys)
368
+ else if (tag === 3) pbf.readPackedVarint(obj.vals)
369
+ else if (tag === 4) obj.info = readInfo(pbf, pbf.readVarint() + pbf.pos)
370
+ else if (tag === 8) obj.lat = pbf.readSVarint()
371
+ else if (tag === 9) obj.lon = pbf.readSVarint()
372
+ }
373
+ /**
374
+ * Serializes a node primitive to protobuf.
375
+ */
376
+ function writeNode(obj: OsmPbfNode, pbf: Pbf) {
377
+ if (obj.id) pbf.writeSVarintField(1, obj.id)
378
+ if (obj.keys) pbf.writePackedVarint(2, obj.keys)
379
+ if (obj.vals) pbf.writePackedVarint(3, obj.vals)
380
+ if (obj.info) pbf.writeMessage(4, writeInfo, obj.info)
381
+ if (obj.lat) pbf.writeSVarintField(8, obj.lat)
382
+ if (obj.lon) pbf.writeSVarintField(9, obj.lon)
383
+ }
384
+
385
+ /**
386
+ * Reads dense node collections from the protobuf stream.
387
+ */
388
+ function readDenseNodes(pbf: Pbf, end?: number): OsmPbfDenseNodes {
389
+ return pbf.readFields(
390
+ readDenseNodesField,
391
+ { id: [], lat: [], lon: [], keys_vals: [] },
392
+ end,
393
+ )
394
+ }
395
+ /**
396
+ * Populates dense node arrays using packed encoding.
397
+ */
398
+ function readDenseNodesField(tag: number, obj: OsmPbfDenseNodes, pbf: Pbf) {
399
+ if (tag === 1) pbf.readPackedSVarint(obj.id)
400
+ else if (tag === 5) {
401
+ obj.denseinfo = readDenseInfo(pbf, pbf.readVarint() + pbf.pos)
402
+ } else if (tag === 8) pbf.readPackedSVarint(obj.lat)
403
+ else if (tag === 9) pbf.readPackedSVarint(obj.lon)
404
+ else if (tag === 10) pbf.readPackedVarint(obj.keys_vals, true)
405
+ }
406
+ /**
407
+ * Serializes dense node collections back to protobuf.
408
+ */
409
+ function writeDenseNodes(obj: OsmPbfDenseNodes, pbf: Pbf) {
410
+ if (obj.id) pbf.writePackedSVarint(1, obj.id)
411
+ if (obj.denseinfo) pbf.writeMessage(5, writeDenseInfo, obj.denseinfo)
412
+ if (obj.lat) pbf.writePackedSVarint(8, obj.lat)
413
+ if (obj.lon) pbf.writePackedSVarint(9, obj.lon)
414
+ if (obj.keys_vals) pbf.writePackedVarint(10, obj.keys_vals)
415
+ }
416
+
417
+ /**
418
+ * Reads a way primitive from the protobuf stream.
419
+ */
420
+ function readWay(pbf: Pbf, end?: number): OsmPbfWay {
421
+ return pbf.readFields(
422
+ readWayField,
423
+ { id: 0, keys: [], vals: [], refs: [], lat: [], lon: [] },
424
+ end,
425
+ )
426
+ }
427
+ /**
428
+ * Populates way fields based on protobuf tags.
429
+ */
430
+ function readWayField(tag: number, obj: OsmPbfWay, pbf: Pbf) {
431
+ if (tag === 1) obj.id = pbf.readVarint(true)
432
+ else if (tag === 2) pbf.readPackedVarint(obj.keys)
433
+ else if (tag === 3) pbf.readPackedVarint(obj.vals)
434
+ else if (tag === 4) obj.info = readInfo(pbf, pbf.readVarint() + pbf.pos)
435
+ else if (tag === 8) pbf.readPackedSVarint(obj.refs)
436
+ }
437
+ /**
438
+ * Serializes a way primitive to protobuf.
439
+ */
440
+ function writeWay(obj: OsmPbfWay, pbf: Pbf) {
441
+ if (obj.id) pbf.writeVarintField(1, obj.id)
442
+ if (obj.keys) pbf.writePackedVarint(2, obj.keys)
443
+ if (obj.vals) pbf.writePackedVarint(3, obj.vals)
444
+ if (obj.info) pbf.writeMessage(4, writeInfo, obj.info)
445
+ if (obj.refs) pbf.writePackedSVarint(8, obj.refs)
446
+ }
447
+
448
+ /**
449
+ * Reads a relation primitive from the protobuf stream.
450
+ */
451
+ function readRelation(pbf: Pbf, end?: number): OsmPbfRelation {
452
+ return pbf.readFields(
453
+ readRelationField,
454
+ {
455
+ id: 0,
456
+ keys: [],
457
+ vals: [],
458
+ roles_sid: [],
459
+ memids: [],
460
+ types: [],
461
+ },
462
+ end,
463
+ )
464
+ }
465
+ /**
466
+ * Populates relation fields based on protobuf tags.
467
+ */
468
+ function readRelationField(tag: number, obj: OsmPbfRelation, pbf: Pbf) {
469
+ if (tag === 1) obj.id = pbf.readVarint(true)
470
+ else if (tag === 2) pbf.readPackedVarint(obj.keys)
471
+ else if (tag === 3) pbf.readPackedVarint(obj.vals)
472
+ else if (tag === 4) obj.info = readInfo(pbf, pbf.readVarint() + pbf.pos)
473
+ else if (tag === 8) pbf.readPackedVarint(obj.roles_sid, true)
474
+ else if (tag === 9) pbf.readPackedSVarint(obj.memids)
475
+ else if (tag === 10) pbf.readPackedVarint(obj.types)
476
+ }
477
+ /**
478
+ * Serializes a relation primitive to protobuf.
479
+ */
480
+ function writeRelation(obj: OsmPbfRelation, pbf: Pbf) {
481
+ if (obj.id) pbf.writeVarintField(1, obj.id)
482
+ if (obj.keys) pbf.writePackedVarint(2, obj.keys)
483
+ if (obj.vals) pbf.writePackedVarint(3, obj.vals)
484
+ if (obj.info) pbf.writeMessage(4, writeInfo, obj.info)
485
+ if (obj.roles_sid) pbf.writePackedVarint(8, obj.roles_sid)
486
+ if (obj.memids) pbf.writePackedSVarint(9, obj.memids)
487
+ if (obj.types) pbf.writePackedVarint(10, obj.types)
488
+ }
package/src/spec.ts ADDED
@@ -0,0 +1,10 @@
1
+ // Recommended and maximum header and blob sizes as defined by the OSM PBF specification
2
+ // Header: 32 KiB and 64 KiB
3
+ export const RECOMMENDED_HEADER_SIZE_BYTES = 32 * 1024
4
+ export const MAX_HEADER_SIZE_BYTES = 64 * 1024
5
+ // Blob: 16 MiB and 32 MiB
6
+ export const RECOMMENDED_BLOB_SIZE_BYTES = 16 * 1024 * 1024
7
+ export const MAX_BLOB_SIZE_BYTES = 32 * 1024 * 1024
8
+
9
+ // Recommended maximum number of entities per block
10
+ export const MAX_ENTITIES_PER_BLOCK = 8_000
package/src/utils.ts ADDED
@@ -0,0 +1,90 @@
1
+ import { transformBytes } from "@osmix/shared/transform-bytes"
2
+
3
+ export type AsyncGeneratorValue<T> =
4
+ | T
5
+ | ReadableStream<T>
6
+ | AsyncGenerator<T>
7
+ | Promise<T>
8
+ | Promise<ReadableStream<T>>
9
+ | Promise<AsyncGenerator<T>>
10
+
11
+ /**
12
+ * Normalizes values, streams, and iterables into a unified async generator interface.
13
+ */
14
+ export async function* toAsyncGenerator<T>(
15
+ v: AsyncGeneratorValue<T>,
16
+ ): AsyncGenerator<T> {
17
+ if (v instanceof Promise) return toAsyncGenerator(await v)
18
+
19
+ if (v == null) throw Error("Value is null")
20
+ if (v instanceof ReadableStream) {
21
+ const reader = v.getReader()
22
+ while (true) {
23
+ const { done, value } = await reader.read()
24
+ if (done) break
25
+ yield value
26
+ }
27
+ reader.releaseLock()
28
+ } else if (ArrayBuffer.isView(v) || v instanceof ArrayBuffer) {
29
+ // Treat ArrayBuffer and TypedArrays (like Uint8Array, Buffer) as single values
30
+ yield v as T
31
+ } else if (
32
+ typeof v === "object" &&
33
+ (Symbol.asyncIterator in v || Symbol.iterator in v)
34
+ ) {
35
+ return v
36
+ } else {
37
+ yield v
38
+ }
39
+ }
40
+
41
+ /**
42
+ * Returns true when executing inside the Bun runtime.
43
+ */
44
+ export function isBun(): boolean {
45
+ return "Bun" in globalThis
46
+ }
47
+
48
+ /**
49
+ * Web decompression stream
50
+ */
51
+ export async function webDecompress(
52
+ data: Uint8Array<ArrayBuffer>,
53
+ ): Promise<Uint8Array<ArrayBuffer>> {
54
+ return transformBytes(data, new DecompressionStream("deflate"))
55
+ }
56
+
57
+ /**
58
+ * Web compression stream
59
+ */
60
+ export async function webCompress(
61
+ data: Uint8Array<ArrayBuffer>,
62
+ ): Promise<Uint8Array<ArrayBuffer>> {
63
+ return transformBytes(data, new CompressionStream("deflate"))
64
+ }
65
+
66
+ /**
67
+ * Concatenates multiple `Uint8Array` segments into a contiguous array.
68
+ */
69
+ export function concatUint8(...parts: Uint8Array[]): Uint8Array {
70
+ const total = parts.reduce((n, p) => n + p.length, 0)
71
+ const out = new Uint8Array(total)
72
+ let offset = 0
73
+ for (const p of parts) {
74
+ out.set(p, offset)
75
+ offset += p.length
76
+ }
77
+ return out
78
+ }
79
+
80
+ /**
81
+ * Encodes a 32-bit big-endian unsigned integer as a four-byte buffer.
82
+ */
83
+ export function uint32BE(n: number): Uint8Array {
84
+ const out = new Uint8Array(4)
85
+ out[0] = (n >>> 24) & 0xff
86
+ out[1] = (n >>> 16) & 0xff
87
+ out[2] = (n >>> 8) & 0xff
88
+ out[3] = n & 0xff
89
+ return out
90
+ }
@@ -0,0 +1,73 @@
1
+ import { assert, describe, it } from "vitest"
2
+ import { osmPbfBlobsToBlocksGenerator } from "../src/blobs-to-blocks"
3
+ import { createOsmPbfBlobGenerator } from "../src/pbf-to-blobs"
4
+ import {
5
+ createSamplePbfFileBytes,
6
+ isHeaderBlock,
7
+ isPrimitiveBlock,
8
+ } from "./helpers"
9
+
10
+ describe("osmPbfBlobsToBlocksGenerator", () => {
11
+ it("consumes asynchronous blob sources", async () => {
12
+ const { header, primitiveBlock, fileBytes } =
13
+ await createSamplePbfFileBytes()
14
+ const collectBlobs = createOsmPbfBlobGenerator()
15
+ const blobs: Uint8Array<ArrayBuffer>[] = []
16
+ for (const blob of collectBlobs(fileBytes)) blobs.push(blob)
17
+
18
+ const generator = osmPbfBlobsToBlocksGenerator(
19
+ (async function* () {
20
+ for (const blob of blobs) {
21
+ await Promise.resolve()
22
+ yield blob
23
+ }
24
+ })(),
25
+ )
26
+
27
+ const { value: headerBlock, done } = await generator.next()
28
+ assert.isFalse(done)
29
+ if (!isHeaderBlock(headerBlock)) {
30
+ assert.fail("Expected header block")
31
+ }
32
+ assert.deepEqual(headerBlock.bbox, header.bbox)
33
+ assert.deepEqual(headerBlock.required_features, header.required_features)
34
+ assert.deepEqual(headerBlock.optional_features, header.optional_features)
35
+
36
+ const { value: block, done: blockDone } = await generator.next()
37
+ assert.isFalse(blockDone)
38
+ if (!isPrimitiveBlock(block)) {
39
+ assert.fail("Expected primitive block")
40
+ }
41
+ assert.lengthOf(block.primitivegroup, primitiveBlock.primitivegroup.length)
42
+ const group = block.primitivegroup[0]
43
+ assert.exists(primitiveBlock.primitivegroup[0])
44
+ assert.exists(group?.dense)
45
+ assert.exists(group?.ways?.[0])
46
+ assert.lengthOf(group.ways, primitiveBlock.primitivegroup[0].ways.length)
47
+ assert.deepEqual(
48
+ group.ways[0].refs,
49
+ primitiveBlock.primitivegroup[0]?.ways?.[0]?.refs,
50
+ )
51
+
52
+ const final = await generator.next()
53
+ assert.isTrue(final.done)
54
+ })
55
+
56
+ it("accepts synchronous generators", async () => {
57
+ const { fileBytes } = await createSamplePbfFileBytes()
58
+ const collectBlobs = createOsmPbfBlobGenerator()
59
+ const blobs = [...collectBlobs(fileBytes)]
60
+ const generator = osmPbfBlobsToBlocksGenerator(
61
+ (function* () {
62
+ for (const blob of blobs) yield blob
63
+ })(),
64
+ )
65
+
66
+ const header = await generator.next()
67
+ assert.isFalse(header.done)
68
+ const block = await generator.next()
69
+ assert.isFalse(block.done)
70
+ const final = await generator.next()
71
+ assert.isTrue(final.done)
72
+ })
73
+ })