Skip to content

alternet-dev/wavefront

Repository files navigation

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.

About

Infrastructure-agnostic edge proxy mapping a versioned external contract onto one evolving internal HTTP/JSON backend

Resources

License

Apache-2.0, MIT licenses found

Licenses found

Apache-2.0
LICENSE-APACHE
MIT
LICENSE-MIT

Stars

Watchers

Forks

Packages

 
 
 

Contributors

Languages