AnyNodeA Tag erased — its transport endpoints set, plus the primary address
(url and/or Unix path) and ProtocolKind kind (the first-declared endpoint, kept for
single-protocol readers), so a tag's distributed set is self-describing about where AND how to
reach each one.
export type type AnyNode = NodeKey<unknown> & {
readonly url: string | undefined
readonly path: string | undefined
readonly kind: ProtocolKind | undefined
readonly endpoints?: Endpoints
readonly onConflict?: OnConflict
readonly [portSym]?: number
}
A
Tag
erased — its transport endpoints set, plus the primary address
(url and/or Unix path) and
ProtocolKind
kind (the first-declared endpoint, kept for
single-protocol readers), so a tag's distributed set is self-describing about where AND how to
reach each one.
AnyNode = type NodeKey<HSelf> = Context.Key<
HSelf,
NodeProtocol
>
The Context key of a
Node
(HSelf = its identity): a service whose value is the
transport
NodeProtocol
. Stored on a node-bearing tag under
nodeSym
; read by
Hyperlink.client
to resolve where to connect (its requirement channel).
NodeKey<unknown> & {
readonly url: string | undefinedurl: string | undefined;
readonly path: string | undefinedpath: string | undefined;
readonly kind: ProtocolKind | undefinedkind: type ProtocolKind =
| "Http"
| "WebSocket"
| "IpcSocket"
The transport a
Node
speaks — tag-style names (apps rarely type this alias; they write
the literals or get inference from url / path):
"Http" — RpcClient.layerProtocolHttp (servers / CLIs)
"WebSocket" — browser WS (layerProtocolWebsocket / client layerProtocolSocket over WS)
"IpcSocket" — Unix-domain socket (same-machine; see
ipcServer
)
Stamped on the node so the topology is self-describing about how to reach it — connect/client
derive the transport from it. Inferred from a ws(s):// url, an http target, or { path } →
IpcSocket; otherwise declare it explicitly.
ProtocolKind | undefined;
readonly endpoints?: Endpoints | undefinedendpoints?: Endpoints;
/** Stamped advertise conflict policy (default `"inherit"` on ordinary nodes). */
readonly onConflict?: OnConflictStamped advertise conflict policy (default "inherit" on ordinary nodes).
onConflict?: type OnConflict =
| "livenessReplace"
| "askIncumbent"
| "reject"
| "inherit"
Directory advertise conflict policy when the same nodeKey already has a row.
livenessReplace — ping incumbent; alive → reject; dead → replace
askIncumbent — if alive, Lookup asks NodeStatus.yield; refuse/timeout → reject
reject — alive → reject; dead → still replace
inherit — continue up the resolve chain (call-site → node → Lookup → hard fallback)
OnConflict;
/** The bare port a node was declared with ({@link portSym}) — the dial resolves the host via Config. */
readonly [const portSym: typeof portSymA node declared with a bare port (Node.Tag()("x", 3009)) carries that port here. The eager
url is a localhost preview (pure, sync at class-definition — no runtime to read a Config);
the authoritative dial host is resolved at the dial boundary (an Effect context) via
Hyperlink.protocolHttp
(port) + the client Config. So the port is the SSOT and the effect
stays at the edge.
portSym]?: number;
};