Skip to content

Commit 7a5803b

Browse files
committed
docs: update PRD v1.2 + CLAUDE.md for Phases 2-5 completion
PRD.md: - Version bump v1.1 → v1.2, status reflects Phases 1-5 complete - Added Phase 2/3/4/5 completion tables with deliverables - Updated roadmap table (Phases 2-5 COMPLETE, Phase 6 NEXT) - Updated architecture tree with bindings modules and CLI crate - Updated test count metric (574 tests) - OQ-008 marked RESOLVED (napi-rs v3 migration complete) - DR-001 updated: CLI is standalone binary crate, not feature flag CLAUDE.md: - Updated artifact description (3 artifacts: Rust crate, npm addon, CLI) - Added CLI build commands - Updated workspace tree with transfer/, pool.rs, bindings modules, CLI - Updated crate responsibilities table (zone diff, DNSSEC, RndcPool, napi v3, CLI) - Updated napi-rs references from v2 to v3 throughout - Added CLI config resolution gotcha
1 parent 0ec9698 commit 7a5803b

2 files changed

Lines changed: 107 additions & 32 deletions

File tree

CLAUDE.md

Lines changed: 24 additions & 14 deletions
Original file line numberDiff line numberDiff line change
@@ -8,7 +8,7 @@ SPDX-License-Identifier: PolyForm-Noncommercial-1.0.0
88

99
Rust SDK for programmatic BIND9 DNS server management. Implements the rndc wire protocol, RFC 1035 zone file parsing, RFC 2136 dynamic updates (nsupdate), IXFR/AXFR zone transfer, and the BIND9 statistics-channel JSON API — all with zero shell subprocess dependencies.
1010

11-
Distributes as two coordinated artifacts from one codebase: a Rust crate (`bind9-sdk` on crates.io) and a Node.js/Bun native addon (napi-rs from `bind9-sdk-bindings`; v3 migration with automatic WASM fallback planned for Phase 4).
11+
Distributes as three coordinated artifacts from one codebase: a Rust crate (`bind9-sdk` on crates.io), a Node.js/Bun native addon (napi-rs v3 from `bind9-sdk-bindings`; native `.node` + WASM fallback), and a CLI tool (`bind9` binary from `bind9-sdk-cli`).
1212

1313
## Prerequisites
1414

@@ -37,7 +37,11 @@ cargo test --workspace
3737
# Integration tests (requires BIND9 on localhost:953 with test rndc key — see tests/README.md)
3838
cargo test --workspace -- --ignored
3939

40-
# Node.js/Bun native addon build (full surface via napi-rs)
40+
# CLI binary
41+
cargo build -p bind9-sdk-cli
42+
cargo run -p bind9-sdk-cli -- --help
43+
44+
# Node.js/Bun native addon build (full surface via napi-rs v3)
4145
cargo build --release --manifest-path crates/bind9-sdk-bindings/Cargo.toml --features nodejs
4246

4347
# Audit
@@ -56,13 +60,17 @@ bind9-sdk/ ← git repo root (this directory)
5660
│ │ └── src/
5761
│ │ ├── tsig/ ← TSIG: key, record, wire, tests
5862
│ │ ├── update/ ← RFC 2136: builder, message, tests
59-
│ │ └── zone/ ← zone parser/serializer; parser/ is itself a submodule
63+
│ │ └── zone/ ← zone parser/serializer, diff; parser/ is itself a submodule
6064
│ ├── bind9-sdk-net/ ← tokio; rndc TCP, nsupdate sender, IXFR/AXFR, stats HTTP
61-
│ │ └── src/rndc/ ← rndc wire protocol submodule
62-
│ └── bind9-sdk-bindings/ ← napi-rs v2 (Node.js/Bun native addon; v3 migration Phase 4)
65+
│ │ └── src/
66+
│ │ ├── rndc/ ← rndc wire protocol + DNSSEC commands
67+
│ │ ├── transfer/ ← IXFR/AXFR zone transfer client
68+
│ │ └── pool.rs ← connection pooling (RndcPool)
69+
│ ├── bind9-sdk-bindings/ ← napi-rs v3 (Node.js/Bun native addon + WASM fallback)
70+
│ └── bind9-sdk-cli/ ← clap CLI binary (`bind9`); zone/record/dnssec/stats subcommands
6371
├── docs/
64-
│ ├── plans/ ← implementation plans (13 files)
65-
│ └── specs/ ← design specs (3 files)
72+
│ ├── plans/ ← implementation plans
73+
│ └── specs/ ← design specs
6674
├── Cargo.toml ← workspace root
6775
├── rust-toolchain.toml
6876
└── REUSE.toml
@@ -72,9 +80,10 @@ bind9-sdk/ ← git repo root (this directory)
7280

7381
| Crate | `no_std` | Feature gate | What it provides |
7482
| --- | --- | --- | --- |
75-
| `bind9-sdk-core` | Yes || `DomainName`, `ResourceRecord`, `RecordData` (20+ variants), `Rcode`, `RecordType`, zone file parser/emitter (`ZoneFile`, `Zone`), RFC 2136 `UpdateBuilder` (typestate `Unsigned`/`Signed`, `UpdateMessage` with `request_mac()`), TSIG (`TsigKey`, `TsigRecord` with wire parsing + response verification, HMAC-SHA256/SHA512/SHA1), management traits (`NamedControl`, `DynamicUpdater`, `ZoneManager`, `StatsClient`) |
76-
| `bind9-sdk-net` | No | `net` (default) | `Bind9Client`, `ClientConfig`, `NetError`, `TlsConfig`; rndc TCP wire protocol (`RndcConnection` typestate, ISC binary encoding, 25+ `RndcCommand` variants, `NamedControl` impl), `NsUpdateSender` (UDP+TCP, TSIG response verification), `StatsHttpClient` (JSON deserialization, `StatsClient` impl), IXFR/AXFR client (planned) |
77-
| `bind9-sdk-bindings` || `nodejs` | napi-rs v2 exports (v3 migration in Phase 4): native `.node` + WASM fallback |
83+
| `bind9-sdk-core` | Yes || `DomainName`, `ResourceRecord`, `RecordData` (20+ variants), `Rcode`, `RecordType`, zone file parser/emitter (`ZoneFile`, `Zone`), zone diffing (`ZoneDiff`, `DiffEntry`, `Zone::diff()`/`apply_diff()`), RFC 2136 `UpdateBuilder` (typestate `Unsigned`/`Signed`, `UpdateMessage` with `request_mac()`), TSIG (`TsigKey`, `TsigRecord` with wire parsing + response verification, HMAC-SHA256/SHA512/SHA1), management traits (`NamedControl`, `DynamicUpdater`, `ZoneManager`, `StatsClient`) |
84+
| `bind9-sdk-net` | No | `net` (default) | `Bind9Client`, `ClientConfig`, `NetError`, `TlsConfig`; rndc TCP wire protocol (`RndcConnection` typestate, ISC binary encoding, 25+ `RndcCommand` variants, DNSSEC commands, `NamedControl` impl), `NsUpdateSender` (UDP+TCP, TSIG response verification), `StatsHttpClient` (JSON deserialization, `StatsClient` impl), IXFR/AXFR zone transfer client (random query IDs, compression pointer rejection, per-message timeouts, record count limits), `RndcPool` connection pooling |
85+
| `bind9-sdk-bindings` || `nodejs` | napi-rs v3: native `.node` + WASM fallback. Modules: domain, zone, record, tsig, update, rndc, nsupdate, stats, transfer, pool. Net modules gated behind `#[cfg(not(target_arch = "wasm32"))]` |
86+
| `bind9-sdk-cli` ||| `bind9` binary (clap). Subcommands: zone, record, dnssec, stats, completions. TOML config from XDG/macOS paths. Depends on `bind9-sdk` (re-export crate) |
7887
| `bind9-sdk` ||| Re-exports `core` and optionally `net`; the single crates.io entry point |
7988

8089
## Feature Flags
@@ -85,7 +94,7 @@ bind9-sdk/ ← git repo root (this directory)
8594
| `serde` | `bind9-sdk-core` | Enables `Serialize`/`Deserialize` on DNS types |
8695
| `net` *(default)* | `bind9-sdk` | Includes `bind9-sdk-net` (rndc, nsupdate, IXFR/AXFR, stats) |
8796
| `parallel` | `bind9-sdk-core` | Enables Rayon-based parallel zone parsing (implies `std`, incompatible with WASM) |
88-
| `nodejs` | `bind9-sdk-bindings` | Enables napi-rs exports (v2; v3 with WASM fallback in Phase 4) |
97+
| `nodejs` | `bind9-sdk-bindings` | Enables napi-rs v3 exports: native `.node` + WASM fallback |
8998

9099
## Key Design Decisions
91100

@@ -97,7 +106,7 @@ bind9-sdk/ ← git repo root (this directory)
97106

98107
4. **rndc wire protocol is NOT DNS** — BIND9's rndc uses a custom TCP framing format: 4-byte big-endian length prefix + ISC internal message encoding. Do not confuse with DNS-over-TCP (2-byte prefix). The protocol is documented in the BIND source (`lib/isc/netmgr/`, ISC KB). It is stable across BIND9 minor versions.
99108

100-
5. **napi-rs unified bindings**Currently pinned at napi-rs v2; migration to v3 is planned for Phase 4. v3 will compile to both native `.node` files and `wasm32-wasip1-threads` WASM from the same binding code. `wasm32-unknown-unknown` is retained in `rust-toolchain.toml` solely for the `no_std` validation hook on `bind9-sdk-core`.
109+
5. **napi-rs v3 unified bindings** — napi-rs v3 (napi-build = "2") compiles to both native `.node` files and `wasm32-wasip1-threads` WASM from the same binding code. Net-dependent modules are gated behind `#[cfg(not(target_arch = "wasm32"))]` so core-only bindings (domain, zone, record, tsig, update) work in WASM. `wasm32-unknown-unknown` is retained in `rust-toolchain.toml` solely for the `no_std` validation hook on `bind9-sdk-core`.
101110

102111
6. **`bind9-sdk` is the only published user-facing crate** — Users add `bind9-sdk` to their `Cargo.toml`, never internal crates directly. Internal crates are published to satisfy crates.io dependency resolution but carry no stability guarantees of their own.
103112

@@ -119,8 +128,9 @@ Key patterns enforced across all implementation:
119128
## Gotchas
120129

121130
- **`no_std` means `core::error::Error`**`std::error::Error` is not available in `bind9-sdk-core`. Use `core::error::Error` (stable since Rust 1.81, which is below our rust-version of 1.94). The `std` feature flag on `bind9-sdk-core` opts back in to `std::error::Error`.
122-
- **`wasm32-unknown-unknown` is for `no_std` validation only** — retained in `rust-toolchain.toml` for the WASM check hook on `bind9-sdk-core`. The planned napi-rs v3 WASM output will use `wasm32-wasip1-threads` (handled by the napi CLI, not the toolchain file).
123-
- **napi-rs requires a native build step**`cargo build --features nodejs` alone is not enough; napi-rs needs `napi build --release` to generate the `.node` file and JS bindings. Currently on napi-rs v2; v3 migration (with auto WASM fallback) is planned for Phase 4.
131+
- **`wasm32-unknown-unknown` is for `no_std` validation only** — retained in `rust-toolchain.toml` for the WASM check hook on `bind9-sdk-core`. The napi-rs v3 WASM output uses `wasm32-wasip1-threads` (handled by the napi CLI, not the toolchain file).
132+
- **napi-rs requires a native build step**`cargo build --features nodejs` alone is not enough; napi-rs needs `napi build --release` to generate the `.node` file and JS bindings. Uses napi-rs v3 with napi-build = "2".
133+
- **CLI config resolution**`bind9-sdk-cli` reads TOML config from XDG (`$XDG_CONFIG_HOME/bind9/config.toml`) or macOS (`~/Library/Application Support/bind9/config.toml`) via the `dirs` crate. Missing config is not an error.
124134
- **TSIG key format in `rndc.conf`** — base64-encoded raw HMAC-SHA256 key material, not PEM. The `algorithm hmac-sha256;` line is not a hint about encoding — it specifies the MAC algorithm directly.
125135
- **BIND9 rndc framing** — message length is encoded as a big-endian u32 (4 bytes), not the 2-byte DNS TCP length. Misreading this is the most common rndc client implementation bug.
126136
- **`cargo check --workspace` does not check WASM target** — always also run `cargo check -p bind9-sdk-core --target wasm32-unknown-unknown` before PR to catch `no_std` violations in core. The `--workspace` variant fails because non-core crates depend on `getrandom` which doesn't compile on `wasm32-unknown-unknown`.

0 commit comments

Comments
 (0)