meridian_schemas
The framework- and brand-neutral root of the meridian design language: proto contracts (PanelDescriptor + Theme), @meridian/proto-ts, and the WebRenderer seam.
| Latest | 0.24.0 |
|---|---|
| Versions | 18 |
| Category | Modules & tooling |
| Compat level | 1 |
| Maintainers | Matt Marshall |
| Registry | https://registry.tbzl.dev/modules/meridian_schemas/ |
| Source | github.com/meridian-ux/meridian-schemas |
bazel_dep(name = "meridian_schemas", version = "0.24.0")
View source & releases on GitHub ↗
The framework- and brand-neutral root of the meridian design language. Every renderer and every emitter depends on this module; it depends on none of them.
It ships three things:
- The proto contracts —
meridian.ui.v1.PanelDescriptor(semantics: which RPC to call, how to map the response into rows/columns/actions, what bespoke panels to host) andmeridian.theme.v1.Theme(style). Semantics and style are orthogonal proto layers, so a renderer or a skin can depend on one without the other. Seeproto/. @savvifi/meridian-proto-ts— the canonical TypeScript surface, generated from the protos via protobuf-es (//bazel:proto_es.bzl). The single source the web renderers and the aion emitter consume.@savvifi/meridian-schemas(the WebRenderer seam) — the framework-neutralmount(container, descriptor, theme, invoker) → { update, unmount }interface plus the host transport/runtime contracts (RpcInvoker,RenderContext). Every web renderer implements it:meridian-web(web-components, reference),meridian-web-react(kit-driven React), and any future web renderer. Because the seam lives here, those renderers depend onmeridian-schemasrather than on each other. Seesrc/uiview/.
Language bindings for the non-web renderers (Java/JavaFX, Rust/TUI, Swift/SwiftUI) and the wasm web-components core live in their own renderer repos, each depending back on these protos.
Layering
aion graph ──emits──▶ PanelDescriptor + Theme (meridian-schemas)
│
WebRenderer seam (neutral TS)
├── meridian-web (web-components, reference)
├── meridian-web-react (React · swappable ComponentKit)
├── meridian-tui · meridian-javafx · meridian-swiftui
└── …
Dependency direction is strictly one-way: renderers and emitters → meridian-schemas.
The module stays brand- and framework-neutral; brand (a Theme) and framework
(the kit/renderer) are supplied by consumers.
Build
bazel build //... # proto contracts, @savvifi/meridian-proto-ts, the seam
Codegen uses a prebuilt protoc (//bazel:protoc_prebuilt.bzl) so it never
compiles protoc from source.
Gates
Two checks run on every PR (.github/workflows/ci.yml). Both exist because the
failure they catch has already shipped.
python3 tools/check_versions.py # published versions move in lockstep
node --test "tools/*.test.mjs" # the mirror gate still catches divergence
Mirroring meridian.ui.v1
Some repos carry a small hand-maintained copy of a few meridian.ui.v1 messages
instead of depending on this module — nav_tree.proto imports nothing but
field_behavior precisely so a ~40-line mirror is possible. That is supported.
A mirror that silently disagrees with the contract is not: a shipped mirror
transposed GetPanelRequest’s field numbers, and because both fields are wire
type 2 a canonical client and that mirror parse each other’s tag-1 field with no
error and get garbage.
If you maintain a mirror, run the gate in your own CI:
# your mirror -> a descriptor set (any toolchain: protoc, Bazel's proto_library,
# tonic_build's committed FDS — a FileDescriptorSet is the interchange format)
protoc -I proto --descriptor_set_out=mirror.binpb --include_imports \
meridian/ui/v1/layout_service.proto
node tools/mirror_conformance.mjs \
--canonical canonical.binpb \
--mirror mirror.binpb \
--allowlist mirror-deviations.json # optional
Only messages present in both are compared. Exit code is non-zero on divergence.
There are two kinds of mirror, and they want different strictness:
| kind | flag | a missing field means |
|---|---|---|
a deliberate hand-written subset (e.g. a ~40-line nav_tree copy) | (default) | fine — you don’t use it |
| a vendored copy of the full tree | --require-complete | drift, and a silent one |
In the second case a missing field is a real defect: proto decoders ignore unknown
fields, so a producer that sets Slot.sub_view against a consumer vendored before
that field existed gets a slot with no panel and no error. REQUIRED does not
save you — field_behavior is documentation only in proto3, and no runtime enforces
it. Measured across the vendored trees in this fleet: 11–16 fields behind canonical
each, with zero disagreements — stale, never wrong. The hand-written subset mirror
had the opposite profile: current, but with two transposed field numbers.
A deliberate divergence is legal but must be written down, which turns a silent landmine into a reviewable line:
{ "deviations": [
{ "message": "meridian.ui.v1.GetPanelRequest",
"field": "panel_id",
"reason": "legacy plugin surface returns an opaque bundle envelope" }
] }
"field": "*" waives a whole message.
Conformance#
No gate findings. 17 contested atoms. See how gating works or the full report.
Contested atoms
Third-party modules where this module resolves a different version than others do. Not a violation of anything this module did — it is the actionable form of a registry-level convergence finding, and the sentence a maintainer can act on.
| Atom | Resolved here | Elsewhere |
|---|---|---|
apple_support | 1.24.2 | 2.2.0 ×1 |
aspect_bazel_lib | 2.22.5 | 2.8.1 ×1 |
aspect_rules_js | 3.1.2 | 2.1.3 ×1 |
bazel_lib | 3.2.2 | 3.0.0 ×12 |
bazel_skylib | 1.8.2 | 1.9.0 ×2 |
gawk | 5.3.2.bcr.3 | 5.3.2.bcr.1 ×12 |
jq.bzl | 0.4.0 | 0.1.0 ×12 |
nlohmann_json | 3.6.1 | 3.12.0.bcr.1 ×1 |
package_metadata | 0.0.2 | 0.0.5 ×3 |
protobuf | 33.4 | 34.0.bcr.1 ×2 |
rules_jvm_external | 6.7 | 6.8 ×4 |
rules_nodejs | 6.7.4 | 6.3.0 ×16.7.3 ×1 |
rules_python | 1.7.0 | 2.0.1 ×1 |
rules_swift | 3.1.2 | 3.6.1 ×1 |
tar.bzl | 0.10.4 | 0.5.1 ×110.6.0 ×1 |
upb | 0.0.0-20220923-a547704 | 0.0.0-20230516-61a97ef ×1 |
yq.bzl | 0.3.4 | 0.1.1 ×12 |
Dependencies#
Depends on
Used by (3 in the registry)
Versions#
18 published versions, newest first. Each resolves to an immutable, integrity-checked archive.
| Version | Integrity (sha256) | Source archive |
|---|---|---|
0.24.0 latest | 6IC+Miutvgkr464L… | tag archive ↗ |
0.23.0 | ieqo3IpEpD5tN7J/… | tag archive ↗ |
0.22.0 | 9k0sL+0YO/1KyBK4… | tag archive ↗ |
0.21.0 | 6/OuMMQmvueA+66K… | tag archive ↗ |
0.20.0 | 8Jf3Tf26g2RyRVRe… | tag archive ↗ |
0.19.0 | r47GttPi87u5R+KF… | tag archive ↗ |
0.18.0 | uKmU1DPJDCbXfDC5… | tag archive ↗ |
0.17.0 | b9zIiJ80v9cvrPQQ… | tag archive ↗ |
0.16.0 | ewKAqDUPQ824ngJn… | tag archive ↗ |
0.15.0 | EpOQVvcrwTIIwa/p… | tag archive ↗ |
0.14.0 | GfiXTd3oJRqnNtzY… | tag archive ↗ |
0.12.0 | LnBUGiJs9xKoOZZs… | tag archive ↗ |
0.6.0 | /SMqc92fLtqCVyST… | tag archive ↗ |
0.5.0 | ZK4r3SxJ0e4TyM1h… | tag archive ↗ |
0.4.0 | /2dSjaH5t/szLsOy… | tag archive ↗ |
0.3.0 | UJIGBnjmSH5svRZw… | tag archive ↗ |
0.2.0 | s5jOejAH3WUnLI23… | tag archive ↗ |
0.1.0 | 4J9VMHR4Ha4glsFi… | tag archive ↗ |