wavefront

module
v0.7.4 Latest Latest
Warning

This package is not in the latest version of its module.

Go to latest
Published: Jun 15, 2026 License: Apache-2.0, MIT

README

wavefront

A small, infrastructure-agnostic edge proxy that maps a versioned external contract onto a single evolving internal HTTP/JSON backend. Clients frozen at different points in contract-time keep working while the backend migrates freely.

pinned clients --versioned protobuf--> wavefront --current JSON/REST--> backend
                                           |
                                           +- descriptor bundle (one layer per contract version)
                                           +- per-version resolution: route, or a transform shim
                                           +- auth-transparent (forwards the bearer)

Why

A pinned client is nearsighted in time: it sees an API only as it was the day it shipped — app-store update lag, partners on last year's contract, a surface on an old build. Without mediation, every internal change is hostage to the oldest client in the wild, and teams accrete /v1 /v2 /v3 sprawl inside every service.

By Fermat's principle, a signal crossing differing media takes the path of least time and its wavefront reshapes to still arrive coherent. wavefront is the version-mediation scheme, extracted: one declarative edge where external contract variance is absorbed so the internal API stays singular.

Core concepts (1-minute version)

  • Bundle — the descriptor input: a directory of immutable per-version layers (each a proto FileDescriptorSet, the frozen OpenAPI, and the route binding) plus an operator-owned resolution.yaml. Generated by the consumer, committed, loaded read-only.
  • Contract version — the external contract a client speaks; the selector that picks a transform profile.
  • Transform — declarative request/response mapping for a version (field add / rename / optionalize / default / coerce; route remap).
  • Adapter — a codec pair. protobuf ↔ OpenAPI/JSON is the reference adapter, not the identity.
  • Selector — the key a request is resolved by. The contract version today; the engine is designed to extend to other selectors (codec, profile, tenant, cohort).

For depth, see docs/concepts.md.

What it is — and isn't

It IS:

  • A descriptor-driven edge contract-mapping engine.
  • A version anti-corruption layer over a single internal backend.
  • Auth-transparent: it forwards the bearer; the backend validates.
  • Codec-agnostic via adapters (protobuf↔JSON shipped first).

It IS NOT:

  • An auth server. Bring your own token issuer/validator (the backend's).
  • A policy/authz engine. No PII redaction, no business logic.
  • A message broker or database. No persistence, no replay.
  • A reverse proxy / TLS terminator / router. The ingress owns that.
  • A WebSocket/streaming tier. wavefront is request/response only.

Install

The wavefront-bundle CLI is published to the alternet-dev Homebrew tap as a prebuilt binary (no Go toolchain required):

brew install alternet-dev/tap/wavefront-bundle

The Homebrew formula installs only the CLI. The proxy server is distributed exclusively as the multi-arch container image at ghcr.io/alternet-dev/wavefront; see the container invocation in Quick start below.

Quick start

Generate the bundle from your OpenAPI — a file, or the live service's /openapi.json (no manual export step) — then run the proxy against it:

# installed via Homebrew, or built from source:
#   go build -o wavefront-bundle ./cmd/wavefront-bundle

# from a file…
wavefront-bundle add --openapi ./openapi.json --bundle ./bundle
# …or straight from a running service:
wavefront-bundle add --openapi https://api.internal/openapi.json --bundle ./bundle

The bundle is committed in your repo (it is the contract source of truth) and mounted or baked in for wavefront.

From source:

go build -o wavefront ./cmd/wavefront

WAVEFRONT_BUNDLE_PATH=./bundle \
WAVEFRONT_UPSTREAM_BASE_URL=http://localhost:9000 \
./wavefront

Or via the prebuilt multi-arch container:

docker run --rm -p 8080:8080 \
  -e WAVEFRONT_BUNDLE_PATH=/etc/wavefront/bundle \
  -e WAVEFRONT_UPSTREAM_BASE_URL=http://core-api:9000 \
  -v $(pwd)/bundle:/etc/wavefront/bundle:ro \
  ghcr.io/alternet-dev/wavefront:latest

A bundle is a directory of immutable per-version layers plus an operator-owned resolution.yaml. Each layer is one contract version, holding that version's frozen descriptors:

bundle/
  resolution.yaml            # operator-owned: per-version resolution overrides
  2024-11/                   # one immutable layer per contract version
    descriptors.binpb        #   proto FileDescriptorSet
    openapi.json             #   the frozen internal OpenAPI surface
    versions.yaml            #   the route binding for this version

add emits a new layer and never rewrites an existing one; remove and retire take a version out of service, and verify gates the bundle's consistency in your CI.

Configuration

All configuration is environment variables, read once at startup.

Var Default Meaning
WAVEFRONT_BUNDLE_PATH — (required) path to the descriptor bundle dir
WAVEFRONT_UPSTREAM_BASE_URL — (required) the default internal backend base URL
WAVEFRONT_TARGETS (none) named backend targets, comma-separated name=url pairs
WAVEFRONT_LISTEN_ADDR 0.0.0.0:8080 bind address for HTTP
WAVEFRONT_METRICS_ADDR 0.0.0.0:9090 bind address for /metrics
WAVEFRONT_CONTRACT_VERSION_HEADER X-Api-Contract-Version header carrying the client's contract version
WAVEFRONT_REQUEST_TIMEOUT_MS 15000 upstream request timeout
WAVEFRONT_READ_HEADER_TIMEOUT_MS 10000 data-plane ReadHeaderTimeout (slow-headers cap)
WAVEFRONT_READ_TIMEOUT_MS 30000 data-plane ReadTimeout (headers + body)
WAVEFRONT_MAX_BODY_BYTES 1048576 inbound body cap
WAVEFRONT_LOG_LEVEL info structured log level

Operational notes:

  • Fail-fast. The bundle is loaded once at boot; a missing or invalid bundle → refuse to start. Roll a new bundle by deploying a new process.
  • GET /metrics exposes Prometheus counters — wavefront_requests_total and wavefront_errors_total, both labelled by negotiated contract_version; errors carry code plus a transform_outcome dimension that splits transform_failed by chain side. /health and /ready are the probes.
  • Codec. protobuf ↔ JSON is the only adapter today; the adapter boundary is built so another codec could be added. All non-hop-by-hop client headers are forwarded untouched.

The bundle schema and transform vocabulary are detailed in docs/protocol.md; integrating a consumer is covered in docs/embedding.md.

Reading order

  1. docs/concepts.md — first principles + vocabulary
  2. docs/protocol.md — bundle schema + wire contract
  3. docs/embedding.md — how a consumer integrates
  4. docs/client.md — multi-language client integration
  5. docs/architecture.md — implementation shape
  6. docs/operations.md — running it

LLM agents: start with AGENTS.md.

License

Dual MIT / Apache-2.0.

Directories

Path Synopsis
cmd
wavefront command
Command wavefront is the edge contract-mediation proxy: it maps a versioned external contract onto a single evolving internal HTTP/JSON backend.
Command wavefront is the edge contract-mediation proxy: it maps a versioned external contract onto a single evolving internal HTTP/JSON backend.
wavefront-bundle command
Command wavefront-bundle builds and maintains the read-only wavefront bundle — a directory of immutable per-version layers.
Command wavefront-bundle builds and maintains the read-only wavefront bundle — a directory of immutable per-version layers.
internal
adapter
Package adapter is the codec boundary.
Package adapter is the codec boundary.
bundle
Package bundle loads and validates the read-only descriptor bundle (descriptors.binpb + openapi.json + versions.yaml) at boot, fail-fast.
Package bundle loads and validates the read-only descriptor bundle (descriptors.binpb + openapi.json + versions.yaml) at boot, fail-fast.
bundlegen
Package bundlegen is the OpenAPI → bundle generator.
Package bundlegen is the OpenAPI → bundle generator.
bundletest
Package bundletest is shared test scaffolding: it builds a self-contained FileDescriptorSet and writes a valid on-disk bundle so negotiate/server/e2e can exercise the real bundle.Load path without protoc.
Package bundletest is shared test scaffolding: it builds a self-contained FileDescriptorSet and writes a valid on-disk bundle so negotiate/server/e2e can exercise the real bundle.Load path without protoc.
config
Package config parses the WAVEFRONT_* environment once at startup into an immutable Config.
Package config parses the WAVEFRONT_* environment once at startup into an immutable Config.
negotiate
Package negotiate resolves the contract the client declared.
Package negotiate resolves the contract the client declared.
probe
Package probe implements the container self-probe behind `wavefront probe --ready`.
Package probe implements the container self-probe behind `wavefront probe --ready`.
server
Package server is the proxy core: a data-plane listener that runs the negotiate → decode → one upstream call → encode pipeline, and an ops listener for /metrics, /health, /ready.
Package server is the proxy core: a data-plane listener that runs the negotiate → decode → one upstream call → encode pipeline, and an ops listener for /metrics, /health, /ready.
tracing
Package tracing emits a single wavefront-attributed span per proxied request to an OTLP/HTTP collector, without pulling in the OpenTelemetry SDK.
Package tracing emits a single wavefront-attributed span per proxied request to an OTLP/HTTP collector, without pulling in the OpenTelemetry SDK.
transform
Package transform is the mechanical transform runtime.
Package transform is the mechanical transform runtime.
wireerror
Package wireerror is the error contract: the typed, wavefront-originated failures returned to a client as a proper HTTP status + standard headers + the `X-Wavefront-Error` code + a fixed `wavefront.v0.Error` protobuf body.
Package wireerror is the error contract: the typed, wavefront-originated failures returned to a client as a proper HTTP status + standard headers + the `X-Wavefront-Error` code + a fixed `wavefront.v0.Error` protobuf body.

Jump to

Keyboard shortcuts

? : This menu
/ : Search site
f or F : Jump to
y or Y : Canonical URL