# @osmix/json

Convert OpenStreetMap PBF bytes to ergonomic JSON entities (and back again) for streaming editors, change workflows, and browser-based tooling. Builds on [`@osmix/pbf`](../pbf/README.md) primitives while staying friendly to modern runtimes.

## Highlights

- **Decode** `.osm.pbf` streams into header metadata and strongly typed node/way/relation JSON.
- **Encode** JSON entities back into spec-compliant PBF blobs with automatic string tables and delta encoding.
- **Stream** using Web Stream transforms to keep large datasets out of memory.
- **Compose** with other Osmix packages for complete read-modify-write workflows.

## Installation

```sh
pnpm add @osmix/json
```

## Usage

### Decode a PBF stream

```ts
import { osmPbfToJson } from "@osmix/json";
import { toAsyncGenerator } from "@osmix/pbf";

const stream = osmPbfToJson(Bun.file("./monaco.pbf").stream());

for await (const item of toAsyncGenerator(stream)) {
  if ("id" in item) {
    // item is OsmNode | OsmWay | OsmRelation
    console.log(item.id, item.tags?.name);
  } else {
    // item is OsmPbfHeaderBlock
    console.log("Features:", item.required_features);
  }
}
```

### Encode JSON to PBF

```ts
import { osmJsonToPbf } from "@osmix/json";

// Create header
const header = {
  required_features: ["OsmSchema-V0.6", "DenseNodes"],
  optional_features: [],
};

// Create entity generator
async function* generateEntities() {
  yield { id: 1, lon: -122.4, lat: 47.6, tags: { name: "Seattle" } };
  yield { id: 2, lon: -122.3, lat: 47.5 };
  yield { id: 10, refs: [1, 2], tags: { highway: "primary" } };
}

// Convert to PBF stream
const pbfStream = osmJsonToPbf(header, generateEntities());
await Bun.write("./output.pbf", pbfStream);
```

### Using TransformStreams

```ts
import { OsmBlocksToJsonTransformStream, OsmJsonToBlocksTransformStream } from "@osmix/json";
import { OsmPbfBytesToBlocksTransformStream, OsmBlocksToPbfBytesTransformStream } from "@osmix/pbf";

// Decode: bytes → blocks → JSON entities
const jsonStream = pbfBytes
  .pipeThrough(new OsmPbfBytesToBlocksTransformStream())
  .pipeThrough(new OsmBlocksToJsonTransformStream());

// Encode: JSON entities → blocks → bytes
const pbfStream = entityStream
  .pipeThrough(new OsmJsonToBlocksTransformStream())
  .pipeThrough(new OsmBlocksToPbfBytesTransformStream());
```

## API

### Decoding (PBF → JSON)

| Export                           | Description                                           |
| -------------------------------- | ----------------------------------------------------- |
| `osmPbfToJson(stream)`           | Convert PBF bytes to stream of header + JSON entities |
| `OsmBlocksToJsonTransformStream` | TransformStream: primitive blocks → JSON entities     |
| `blocksToJsonEntities(block)`    | Generator: extract entities from a single block       |
| `OsmPbfBlockParser`              | Class for parsing blocks with configurable options    |

### Encoding (JSON → PBF)

| Export                           | Description                                       |
| -------------------------------- | ------------------------------------------------- |
| `osmJsonToPbf(header, entities)` | Convert header + entities to PBF byte stream      |
| `OsmJsonToBlocksTransformStream` | TransformStream: JSON entities → primitive blocks |
| `jsonEntitiesToBlocks(entities)` | Async generator: entities → blocks                |
| `OsmPbfBlockBuilder`             | Class for building blocks from entities           |

### Types

| Export             | Description                                              |
| ------------------ | -------------------------------------------------------- |
| `ParseOptions`     | Options for `OsmPbfBlockParser` (parseTags, includeInfo) |
| `OSM_ENTITY_TYPES` | Array: `["node", "way", "relation"]`                     |

## Related Packages

- [`@osmix/pbf`](../pbf/README.md) – Low-level block readers and writers used here.
- [`@osmix/load`](../load/README.md) – Loads PBF into `Osm` indexes using these transforms.
- [`@osmix/core`](../core/README.md) – In-memory index that consumes these JSON entities.
- [`@osmix/change`](../change/README.md) – Dedupe and merge workflows.
- [`@osmix/geojson`](../geojson/README.md) – Convert JSON entities to GeoJSON.

## Environment and Limitations

- Requires Web Streams, `TextEncoder`/`TextDecoder` (Bun, Node 20+, modern browsers).
- Expects zlib-compressed blobs; other compression formats are not supported.
- JSON → PBF pipelines assume sorted entities (nodes, then ways, then relations).

## Development

```sh
pnpm run test packages/json
pnpm run lint packages/json
pnpm run typecheck packages/json
```

Run `pnpm run check` at the repo root before publishing.
