API
@ogygia/federation
Fragment federation, with federate(), mount() and the signed wire.
On this page
- child_traceparent
- federate
- mount
- sign_headers
- user
- verify_signed_request
- FederateConfig
- FederateConfig.name
- FederateConfig.key
- FederateConfig.peers
- FederateConfig.visitor
- FederateConfig.expose
- FederateConfig.base
- FederateConfig.widgets
- FederateConfig.audience
- FederateConfig.skewMs
- FederateConfig.open
- FederateConfig.maxBodyBytes
- FederateConfig.deploy
- FragmentDocument
- FragmentDocument.status
- FragmentDocument.location
- FragmentDocument.title
- FragmentDocument.css
- FragmentDocument.head
- FragmentDocument.body
- FragmentDocument.runtime
- FragmentDocument.path
- FragmentDocument.sources
- FragmentDocument.build
- FragmentDocument.trace
- FragmentDocument.server_ms
- KitMountOptions
- KitMountOptions.user
- KitMountOptions.param
- MountOptions
- MountOptions.user
- MountOptions.stream
- Peer
- Peer.name
- Peer.origin
- Peer.label
- Peer.page
- Peer.widget
- Peer.doc
- Peer.postDoc
- Peer.widgetDoc
- Peer.drop
- PeerConfig
- PeerConfig.origin
- PeerConfig.key
- PeerConfig.timeout
- PeerConfig.cache
- PeerConfig.audience
- PeerConfig.label
- RemoteDials
- RemoteDials.render
- RemoteDials.claims
- VerifyConfig
- VerifyConfig.publicKeys
- VerifyConfig.skewMs
- VerifyConfig.audience
- WidgetDocument
- WidgetDocument.html
- WidgetDocument.origin
- WidgetDocument.sources
- WidgetDocument.build
- WidgetDocument.trace
- WidgetDocument.server_ms
- WidgetInfo
- WidgetInfo.user
- WidgetInfo.request
- WidgetInfo.url
- Claims
- VisitorResolver
- Widget
This page is generated from the package’s own .d.ts files on every build, so the signatures, descriptions and examples below always match the source.
import { … } from '@ogygia/federation';Exports child_traceparent · federate · mount · sign_headers · user · verify_signed_request · FederateConfig · FragmentDocument · KitMountOptions · MountOptions · Peer · PeerConfig · RemoteDials · VerifyConfig · WidgetDocument · WidgetInfo · Claims · VisitorResolver · Widget
child_traceparent
function
Continue the caller's trace (same trace-id, fresh span) or mint one.
function child_traceparent(incoming?: string | null): {
traceparent: string;
trace_id: string;
span_id: string;
};federate
function
federate({ name, key, peers, visitor, expose?, widgets? }). Returns the peer handles keyed by
their config names: const { cms, dash } = federate({ … }).
function federate<P extends Record<string, PeerConfig>>(config: FederateConfig<P>): { [K in keyof P]: Peer; };mount
function
mount(peer) in a table, or mount.kit(peer) from a Kit catchall.
const mount: typeof mount_fn & {
kit: typeof kit_mount;
}sign_headers
function
Caller side: headers proving "the holder of this private key sent EXACTLY this request, to
THIS audience, now". audience defaults to the target URL's host.
function sign_headers(privateKey: string, method: string, url: URL, body?: ArrayBuffer | Uint8Array | null, claims?: Claims, audience?: string): Record<string, string>;user
function
Read the VERIFIED visitor claims in any load / action / endpoint of an exposed router (and in
a widget's info.user). undefined on the standalone front door and for anonymous calls.
function user<T extends Claims = Claims>(c: {
request: Request;
}): T | undefined;verify_signed_request
function
Receiver side: fresh, valid, non-replayed signature from an authorized caller, bound to THIS
audience? Returns the (signature-bound) visitor claims on success, null on any failure.
function verify_signed_request(cfg: VerifyConfig, request: Request, url: URL, body?: ArrayBuffer | Uint8Array | null): {
user?: Claims;
} | null;FederateConfig
interface
interface FederateConfig<P extends Record<string, PeerConfig> = Record<string, PeerConfig>> {/*…*/}FederateConfig.name
This app's name — the tag prefix peers file its fragments under (r:<name>:…).
name: string;FederateConfig.key
This app's Ed25519 PRIVATE key (base64 PKCS8 DER; npx ogygia keys <name>). Signs every
outbound hop and thaw notice. Omit for an app that only ANSWERS (never calls).
key?: string;FederateConfig.peers
Everyone this app talks to, in either direction.
peers?: P;FederateConfig.visitor
THE visitor identity for outbound hops (on-behalf-of, signed, never via the browser).
visitor?: VisitorResolver;FederateConfig.expose
Serve this route table as fragments at /og/fragment/page (the MFE side).
expose?: Router;FederateConfig.base
The mount base the exposed table renders under (routes(table, { base })).
base?: string;FederateConfig.widgets
Named widget catalog served at /og/fragment/<name>; __catalog = the unsigned manifest.
widgets?: Record<string, WidgetDef>;FederateConfig.audience
The audience(s) THIS app verifies inbound calls against. Defaults to the request host; set when a reverse proxy rewrites Host between the hops.
audience?: string | string[];FederateConfig.skewMs
Clock skew / replay window for inbound signatures (ms, default 120 000).
skewMs?: number;FederateConfig.open
Acknowledge an intentionally OPEN endpoint (mTLS / mesh): serve expose/widgets with no
peer keys configured. Without it, exposing with nobody allowed to call is a config error.
open?: boolean;FederateConfig.maxBodyBytes
Cap on a forwarded fragment body (bytes, default 1 MiB).
maxBodyBytes?: number;FederateConfig.deploy
Deploy detection: 'auto' (default) broadcasts a thaw-all to peers on boot with a new
build id; 'manual' leaves it to the app (postrender.invalidateWhere({ prefix: '/' })).
deploy?: "auto" | "manual";FragmentDocument
interface
The wire document an exposed route table answers with.
interface FragmentDocument {/*…*/}FragmentDocument.status
status: number;FragmentDocument.location
3xx target (already in the answering app's OWN base space, e.g. /cms/posts/1).
location?: string;FragmentDocument.title
title: string;FragmentDocument.css
<link rel="stylesheet"> / <style> tags, asset hrefs absolute to the answering origin.
css: string[];FragmentDocument.head
HEAD CHANNEL: the page's SEO/social head bits (<meta> + canonical links; never
charset/viewport/http-equiv — those are the shell's).
head?: string;FragmentDocument.body
body: string;FragmentDocument.runtime
Absolute URL of the answering app's OWN ogygia runtime (a foreign host loads it to wake the fragment's islands).
runtime?: string;FragmentDocument.path
The answering app's OWN canonical pathname for this page (base + path) — the shell files
its stored page under p:<peer>:<path>, so postrender.invalidate('<path>') on the peer thaws
it (see internal/notes/federation.md §3–4).
path?: string;FragmentDocument.sources
PROVENANCE: the receipt tags this render consumed — its own s:<id>:<fp> (og.source) plus
any r:…/p:…/a:… it adopted from ITS peers (a chain). The consumer prefixes each with
this peer's name and files its stored page under them.
sources?: string[];FragmentDocument.build
The answering app's build id — changes per deploy.
build?: string;FragmentDocument.trace
OBSERVABILITY: the trace this render belonged to + how long it took.
trace?: {
trace_id: string;
span_id: string;
};FragmentDocument.server_ms
server_ms?: number;KitMountOptions
interface
interface KitMountOptions {/*…*/}KitMountOptions.user
Visitor claims for each hop — a plain Kit app has no c.visitor, so identity is read off
the EVENT (cookies / locals) explicitly.
user?: (e: KitMountEvent) => Claims | undefined;KitMountOptions.param
The catchall param name (src/routes/cms/[...rest] → 'rest'). Default 'rest'.
param?: string;MountOptions
interface
interface MountOptions {/*…*/}MountOptions.user
OVERRIDE the visitor claims for this mount. Default: the federation's visitor as it
reaches c.visitor, plus the table's experiment buckets, auto-carried.
user?: (c: Ctx) => Claims | undefined;MountOptions.stream
STREAM the mount: the shell's page flushes immediately with fallback in the slot, and the
fragment swaps in down the SAME response when the peer answers. GET only.
stream?: boolean | {
fallback?: string | unknown;
};Peer
interface
A peer handle — what federate() returns per peer.
interface Peer {/*…*/}Peer.name
readonly name: string;Peer.origin
readonly origin: string;Peer.label
readonly label: string;Peer.page
A remote ROUTE of this peer's exposed table as a region value. Static: awaits the hop and bakes; deferred: a signed hole.
page(path: string, dials?: RemoteDials & {
search?: string;
}): Promise<RegionValue>;Peer.widget
A named widget of this peer's catalog as a region value.
widget(name: string, props?: Record<string, string>, dials?: RemoteDials): Promise<RegionValue>;Peer.doc
Transport (used by mount()): the page DOCUMENT for a path (cache/SWR/coalescing).
doc(path: string, search: string, claims?: Claims, traceparent?: string): Promise<FragmentDocument>;Peer.postDoc
Transport: a mutation document — bypasses and invalidates the cache.
postDoc(path: string, search: string, body: ArrayBuffer, content_type: string, claims?: Claims, traceparent?: string): Promise<FragmentDocument>;Peer.widgetDoc
Transport: a raw widget document.
widgetDoc(name: string, props?: Record<string, string>, opts?: {
claims?: Claims;
traceparent?: string;
}): Promise<WidgetDocument>;Peer.drop
Thaw: drop cached documents carrying any of these tags ('all' = every entry).
drop(tags: ReadonlySet<string> | "all"): void;PeerConfig
interface
One peer — an app this app talks to, in either direction.
interface PeerConfig {/*…*/}PeerConfig.origin
Origin(s). Extra entries are same-build REPLICAS tried in order for READS (a retried mutation risks a double write — POSTs stay on the first).
origin: string | string[];PeerConfig.key
The peer's Ed25519 PUBLIC key(s), base64 SPKI DER — verifies calls and thaw notices FROM it. A list = rotation overlap. Omit for a peer this app only CALLS (never hears from).
key?: string | string[];PeerConfig.timeout
Max ms per UNCACHED hop; a miss becomes a boundary card, never a hung shell. Default 5000.
timeout?: number;PeerConfig.cache
Stale-while-revalidate cache for this peer's documents (ms). Entries carry the fragment's source tags, so a thaw notice drops exactly the stale ones. Off when omitted.
cache?: {
ttl: number;
max?: number;
};PeerConfig.audience
The audience signed into hops TO this peer (must equal what it verifies as its own). Defaults to the origin's host — set both ends only when a proxy rewrites Host.
audience?: string;PeerConfig.label
Server-Timing label (default: the peer's name).
label?: string;RemoteDials
interface
The dials a remote region takes — the region dials, with the same meanings.
interface RemoteDials {/*…*/}RemoteDials.render
'static' (default): one buffered signed hop during THIS render, HTML baked. 'deferred':
a hole — the browser fetches it from the SHELL's handle (signed capability), which forwards
to the peer with the visitor's claims derived at hole time.
render?: "static" | "deferred";RemoteDials.claims
Override the visitor claims for this hop (default: the federation's visitor, plus every
experiment bucket the request decided).
claims?: Claims;VerifyConfig
interface
interface VerifyConfig {/*…*/}VerifyConfig.publicKeys
base64 SPKI DER Ed25519 public keys of AUTHORIZED callers (a list = rotation overlap).
publicKeys: readonly string[];VerifyConfig.skewMs
Max clock skew / replay window in ms (default 120s).
skewMs?: number;VerifyConfig.audience
The audience(s) THIS app answers to. Defaults to the request URL's host.
audience?: string | string[];WidgetDocument
interface
What a named widget (/og/fragment/<name>) answers with.
interface WidgetDocument {/*…*/}WidgetDocument.html
html: string;WidgetDocument.origin
origin?: string;WidgetDocument.sources
sources?: string[];WidgetDocument.build
build?: string;WidgetDocument.trace
trace?: {
trace_id: string;
span_id: string;
};WidgetDocument.server_ms
server_ms?: number;WidgetInfo
interface
What a catalog widget receives alongside the caller-chosen props.
interface WidgetInfo {/*…*/}WidgetInfo.user
Signature-bound visitor claims (undefined when anonymous). AUTHORIZE against THESE — props are caller-chosen, claims are not.
user?: Claims;WidgetInfo.request
request: Request;WidgetInfo.url
url: URL;Claims
type
Visitor claims — who is BROWSING (the caller signature says who is CALLING). Bound into the signed payload: forging claims means forging the Ed25519 signature. They never transit the browser — the shell attaches them server-side from its own session.
type Claims = Record<string, unknown>;VisitorResolver
type
Visitor claims resolver — federate({ visitor }). Reads the LIVE event (cookies, locals);
runs on the shell for every hop, including hole-time fetches of deferred remote regions.
type VisitorResolver = (event: {
request: Request;
url: URL;
cookies?: {
get(name: string): string | undefined;
};
locals?: unknown;
}) => Claims | undefined;Widget
type
A widget: props in, an awaitable { html } out — region(Comp, props) IS that shape.
type Widget = (props: Record<string, string>, info: WidgetInfo) => PromiseLike<{
html: string | null;
}> | {
html: string | null;
};