@sealrelay/client
v0.1.0
Published
Client for the SealRelay matching API — the frozen ClientRequest/ClientResponse wire.
Readme
@sealrelay/client
Client for the SealRelay matching API — the frozen ClientRequest / ClientResponse
wire described in docs/sdk/SURFACE.md.
SealRelay is a pairwise, domain-scoped matching service: two offices check they mean the same person without sending the file through us.
What this package is
A transport client for the API face. It builds ClientRequest JSON, posts it to
the matching endpoint, and parses the ClientResponse.
What this package is not
- It does not implement OPRF blinding.
Publish,Lookup,EvalBatchandEvalDomaincarry blinded bytes produced client-side by the Rust SDK (sealrelay-sdk, voprf 0.5.0). This package passes those bytes through; it does not derive them. A pure-JavaScript reimplementation of the ciphersuite is not shipped here and should not be assumed. - It does not reimplement
sealrelay-core. Adapters and outsiders use only API / SDK / MCP.
Install
Not published. Build the tarball from the repository:
npm packUse
import { Client, Requests, Id } from "@sealrelay/client";
const client = new Client("https://sealrelay.quicktoolry.com");
// Liveness only — not a lookup, not billed.
await client.health(); // { service: "sealrelay-matching", status: "live" }
// Unauthenticated tree head.
const head = await client.serveHead();
head.variant; // "ServedHead"
head.payload.size; // log size
head.payload.root; // [u8; 32] as an array of integers
// Coverage of a domain: active-only count plus continuity-break signal.
const cov = await client.coverage(Id.marker("example-domain", 1));
cov.payload.active;
cov.payload.continuity_break;
cov.payload.coverage; // { published, roster } — freshness, not completenessWire facts
Verified against a running sealrelayd, not assumed:
ClientRequestandClientResponseare externally tagged. A unit variant is the bare JSON string"ServeHead". A struct variant is{"Coverage":{"domain":[…]}}.- Every identifier (
SubjectId,ParticipantId,DomainId,EpochId) and every[u8; 32]/Vec<u8>is a JSON array of integers — never hex, never base64. - A body that is not a
ClientRequestreturns HTTP 400 with{"error":"not_a_client_request",…}. That is a transport error and never a matching answer. This client raisesSealRelayErrorfor it and never returns it as a NO.
The four NOs
The four subject-side NOs (not-found / no-consent / quota / bad-token) are
bit-identical by design. Response.lookupOutcome reports the LookupOutcome
variant (Hit / Hits / UniformNo / Distinct); do not attempt to tell the four
NOs apart, because on the wire there is nothing to tell apart.
Identifiers
Id.marker(tag, n) mirrors sealrelay_ids::marker. It is not high-entropy: at
most the first 16 bytes of tag contribute, bytes 16..24 stay zero, and n is
big-endian in bytes 24..32. Two tags sharing a 16-byte prefix are one identity.
Keep tags at most 16 bytes and distinct within that, or hash the tag first.
Downtime cache
Clients do not implement a second cache. Call lookup and accept UniformNo when the
window has expired. Only a last signed YES may be cached, never a NO, only while
matching is actually down, and 24 h then fail-closed.
License
LicenseRef-Proprietary. No license file is distributed with this package.
