mirror of
https://github.com/zap-proto/dev.git
synced 2026-10-30 15:05:18 +00:00
* docs: tools section (pb2zap, zap2pb), zip server page, ZAP-only production story - content/docs/tools/: new Tooling nav group — the complete pb<->ZAP interop boundary. pb2zap (go/ast codemod off protobuf), zap2pb (the one sanctioned protobuf import: Marshal/Unmarshal/Equal/ AppendMessage, v0.2.0), and the migration path over the existing schema/codegen pages. - content/docs/zip.mdx: the ZAP-native application server — one Listen verb (ZAP primary, HTTP secondary), typed handlers with REST/OpenAPI/MCP projections, Mount composition, and the hanzoai/cloud case: sub-1,000-line compose root hosting ~75K LOC of subsystems (76:1). - why-zap: scrub the unmeasured benchmark tables (per the benchmarks-page policy), replace with mechanism arguments and the ZAP-only-in-production account: zero gRPC, protobuf confined to the four-function zap2pb boundary at the OTLP edge. - ecosystem: add zip/pb2zap/zap2pb rows; quick-start + index: link the new pages, drop the unmeasured 5-20x claim. * fix(build): alias MDX collections to regenerated docs/, drop frozen .docs snapshot next.config.mjs and tsconfig.json pointed @hanzo/docs-mdx:collections/* at .docs/ — a snapshot frozen on Jun 1 — while the MDX plugin regenerates docs/ on every build. Result: no page added since the snapshot (schema, codegen, rpc, capabilities, and this PR%27s tools/zip) was ever emitted; the site silently served 37 routes instead of 45. Alias both resolvers at docs/ and remove .docs. --------- Co-authored-by: Hanzo Dev <[email protected]>
59 lines
3.3 KiB
Plaintext
59 lines
3.3 KiB
Plaintext
---
|
|
title: zap2pb
|
|
description: The sanctioned ZAP↔protobuf wire boundary — one file, four functions, the only place protobuf is imported.
|
|
---
|
|
|
|
# zap2pb
|
|
|
|
[`zap2pb`](https://github.com/zap-proto/zap2pb) is the other edge of [pb2zap](/docs/tools/pb2zap): where pb2zap moves your *code* off protobuf, zap2pb is the one place a ZAP-native stack still *touches* protobuf — because some external system on the other end of a socket demands it.
|
|
|
|
It is deliberately tiny: one file, four functions, wrapping `google.golang.org/protobuf`. That is the point. The package exists as **policy, not convenience** — it is the single sanctioned import of protobuf in the stack, so "who still links protobuf?" has a one-word answer.
|
|
|
|
```bash
|
|
go get github.com/zap-proto/[email protected]
|
|
```
|
|
|
|
## API
|
|
|
|
```go
|
|
// Marshal encodes m to protobuf wire bytes.
|
|
func Marshal(m proto.Message) ([]byte, error)
|
|
|
|
// Unmarshal decodes protobuf wire bytes into m.
|
|
func Unmarshal(b []byte, m proto.Message) error
|
|
|
|
// Equal reports whether a and b are semantically equal messages.
|
|
func Equal(a, b proto.Message) bool
|
|
|
|
// AppendMessage marshals m and appends it to dst as length-delimited
|
|
// field num; repeated calls with one num build a `repeated` field,
|
|
// byte-identical to marshaling the enclosing message.
|
|
func AppendMessage(dst []byte, num int, m proto.Message) ([]byte, error)
|
|
```
|
|
|
|
That is the entire surface. If your interop edge needs more than this, the edge is too wide.
|
|
|
|
## Why `AppendMessage` exists
|
|
|
|
The subtle function is `AppendMessage`, and it exists for a dependency-hygiene reason. Generated protobuf packages for RPC services ship their gRPC service stubs in the same package, with no build tag — importing the generated *request* type drags `google.golang.org/grpc` into your module graph. `AppendMessage` lets you hand-build the enclosing request envelope from its grpc-free field messages instead, byte-identical to marshaling the generated type, without ever importing it.
|
|
|
|
## The OTLP edge, concretely
|
|
|
|
Observability is the edge where this matters in practice. OpenTelemetry's OTLP (and OpAMP) wire is protobuf; that is the industry contract and not worth fighting. The ZAP-native answer:
|
|
|
|
- Spans are marshaled as standard OTLP protobuf **messages** — through this package.
|
|
- The bytes ship over the **ZAP wire** (zero-copy frames, X-Wing PQ-KEM handshake) to the collector's ZAP receiver — never OTLP-over-HTTP (`:4318`) or OTLP-over-gRPC (`:4317`).
|
|
- The `ExportTraceServiceRequest` envelope is built with `AppendMessage` from the grpc-free trace messages, so no gRPC enters the module graph.
|
|
|
|
The result: OTLP-compatible telemetry, zero gRPC, and protobuf confined to one four-function file. This is the boundary that lets the [ZAP-only production stack](/docs/why-zap#zap-only-in-production) claim *zero protobuf in application code* and mean it.
|
|
|
|
## The rule
|
|
|
|
Exactly one import of `google.golang.org/protobuf` per stack — this one. A second import site is a regression, not a style choice: it un-answers the question the package exists to answer.
|
|
|
|
## Related
|
|
|
|
- [Tools overview](/docs/tools) — the full pb↔ZAP migration path
|
|
- [pb2zap](/docs/tools/pb2zap) — the codemod that gets your code off protobuf in the first place
|
|
- [Why ZAP](/docs/why-zap) — what a stack looks like when this boundary is all that is left
|