<Self>(): {
<const S extends Spec>(
key: string,
spec: S,
options?: { readonly description?: string; readonly kind?: string }
): HyperlinkTag<Self, S>
<const S extends Spec, HSelf>(
key: string,
spec: S,
options: {
readonly description?: string
readonly kind?: string
readonly node: AddressedNode<HSelf>
}
): NodeBoundTag<Self, S, HSelf> & {
readonly [nodeSym]: AddressedNode<HSelf>
}
<const S extends Spec, HSelf>(
key: string,
spec: S,
options: {
readonly description?: string
readonly kind?: string
readonly node: NodeKey<HSelf>
}
): NodeBoundTag<Self, S, HSelf>
}Create a resource service tag from a Spec. Extend the result, like
Context.Tag, but the value type is inferred from the spec:
class Counter extends Hyperlink.Tag<Counter>()("Counter", {
increment: Hyperlink.effectFn({ by: Schema.Number }),
current: Hyperlink.effect(Schema.Number),
}) {}
const c = yield* Counter; // { increment: (p) => Effect<void>; current: Effect<number> }Keys must be unique: a duplicate throws at declaration — Effect's Context is
keyed by the key string and silently last-write-wins on collisions, so we guard it.
For a single resource the key is also its group id (the wire prefix for its
procedures), so a shared RpcServer can node it alongside other resource types.
const const makeTag: <Self>() => {
<S extends Spec>(
key: string,
spec: S,
options?: {
readonly description?: string
readonly kind?: string
}
): HyperlinkTag<Self, S>
<S extends Spec, HSelf>(
key: string,
spec: S,
options: {
readonly description?: string
readonly kind?: string
readonly node: AddressedNode<HSelf>
}
): NodeBoundTag<Self, S, HSelf> & {
readonly [nodeSym]: AddressedNode<HSelf>
}
<S extends Spec, HSelf>(
key: string,
spec: S,
options: {
readonly description?: string
readonly kind?: string
readonly node: NodeKey<HSelf>
}
): NodeBoundTag<Self, S, HSelf>
}
Create a resource service tag from a
Spec
. Extend the result, like
Context.Tag, but the value type is inferred from the spec:
class Counter extends Hyperlink.Tag<Counter>()("Counter", {
increment: Hyperlink.effectFn({ by: Schema.Number }),
current: Hyperlink.effect(Schema.Number),
}) {}
const c = yield* Counter; // { increment: (p) => Effect<void>; current: Effect<number> }
Keys must be unique: a duplicate throws at declaration — Effect's Context is
keyed by the key string and silently last-write-wins on collisions, so we guard it.
For a single resource the key is also its group id (the wire prefix for its
procedures), so a shared RpcServer can node it alongside other resource types.
makeTag = <function (type parameter) Self in <Self>(): {
<const S extends Spec>(key: string, spec: S, options?: {
readonly description?: string;
readonly kind?: string;
}): HyperlinkTag<Self, S>;
<const S extends Spec, HSelf>(key: string, spec: S, options: {
readonly description?: string;
readonly kind?: string;
readonly node: AddressedNode<HSelf>;
}): NodeBoundTag<Self, S, HSelf> & {
readonly [nodeSym]: AddressedNode<HSelf>;
};
<const S extends Spec, HSelf>(key: string, spec: S, options: {
readonly description?: string;
readonly kind?: string;
readonly node: NodeKey<HSelf>;
}): NodeBoundTag<Self, S, HSelf>;
}
Self>() => {
// `Context.Service`-shaped: `Tag<Self>()(key, spec, options?)`. The spec (2nd arg) is the
// inferring call; `options.node` rides the inferring call so its identity `HSelf` infers from the
// argument, and the node-bearing overload narrows `[nodeSym]` to a concrete `NodeKey` — which is
// how `Hyperlink.client` discriminates the node-aware path. An {@link AddressedNode} narrows
// further so `client(Tag)` can auto-wire connect.
function function (local function) build<const S extends Spec>(key: string, spec: S, options?: {
readonly description?: string;
readonly kind?: string;
}): HyperlinkTag<Self, S> (+2 overloads)
build<const function (type parameter) S in build<const S extends Spec>(key: string, spec: S, options?: {
readonly description?: string;
readonly kind?: string;
}): HyperlinkTag<Self, S>
S extends Spec>(
key: stringkey: string,
spec: const S extends Specspec: function (type parameter) S in build<const S extends Spec>(key: string, spec: S, options?: {
readonly description?: string;
readonly kind?: string;
}): HyperlinkTag<Self, S>
S,
options: | {
readonly description?: string
readonly kind?: string
}
| undefined
options?: { readonly description?: string | undefineddescription?: string; readonly kind?: string | undefinedkind?: string },
): interface HyperlinkTag<Self, S extends Spec, Svc = Simplify<{ readonly [K in keyof S]: S[K] extends FromLocalMethod<infer M> ? InjectLocal<M, Self> : S[K] extends LocalMethod<infer T> ? LocalEffect<...> : S[K] extends { ...; } ? SuccessOf<...> : S[K] extends { ...; } ? Subscribable<...> : S[K] extends { ...; } ? ClientMethod<...> : S[K] extends Spec ? Simplify<...> : never; }>>The type of a resource tag carrying spec S — what
Hyperlink.Tag
/ a
Hyperlink.tagFor
factory produce (and what you extend). Lets a consumer write
<S extends Spec>(tag: HyperlinkTag<Self, S>) and read the spec through named types
(
specOf
/
groupOf
) instead of a Parameters<typeof specOf> workaround.
HyperlinkTag<function (type parameter) Self in <Self>(): {
<const S extends Spec>(key: string, spec: S, options?: {
readonly description?: string;
readonly kind?: string;
}): HyperlinkTag<Self, S>;
<const S extends Spec, HSelf>(key: string, spec: S, options: {
readonly description?: string;
readonly kind?: string;
readonly node: AddressedNode<HSelf>;
}): NodeBoundTag<Self, S, HSelf> & {
readonly [nodeSym]: AddressedNode<HSelf>;
};
<const S extends Spec, HSelf>(key: string, spec: S, options: {
readonly description?: string;
readonly kind?: string;
readonly node: NodeKey<HSelf>;
}): NodeBoundTag<Self, S, HSelf>;
}
Self, function (type parameter) S in build<const S extends Spec>(key: string, spec: S, options?: {
readonly description?: string;
readonly kind?: string;
}): HyperlinkTag<Self, S>
S>;
function function (local function) build<const S extends Spec, HSelf>(key: string, spec: S, options: {
readonly description?: string;
readonly kind?: string;
readonly node: AddressedNode<HSelf>;
}): NodeBoundTag<Self, S, HSelf> & {
readonly [nodeSym]: AddressedNode<HSelf>;
} (+2 overloads)
build<const function (type parameter) S in build<const S extends Spec, HSelf>(key: string, spec: S, options: {
readonly description?: string;
readonly kind?: string;
readonly node: AddressedNode<HSelf>;
}): NodeBoundTag<Self, S, HSelf> & {
readonly [nodeSym]: AddressedNode<HSelf>;
}
S extends Spec, function (type parameter) HSelf in build<const S extends Spec, HSelf>(key: string, spec: S, options: {
readonly description?: string;
readonly kind?: string;
readonly node: AddressedNode<HSelf>;
}): NodeBoundTag<Self, S, HSelf> & {
readonly [nodeSym]: AddressedNode<HSelf>;
}
HSelf>(
key: stringkey: string,
spec: const S extends Specspec: function (type parameter) S in build<const S extends Spec, HSelf>(key: string, spec: S, options: {
readonly description?: string;
readonly kind?: string;
readonly node: AddressedNode<HSelf>;
}): NodeBoundTag<Self, S, HSelf> & {
readonly [nodeSym]: AddressedNode<HSelf>;
}
S,
options: {
readonly description?: string
readonly kind?: string
readonly node: AddressedNode<HSelf>
}
options: {
readonly description?: string | undefineddescription?: string;
readonly kind?: string | undefinedkind?: string;
readonly node: AddressedNode<HSelf>node: import AddressedNodeAddressedNode<function (type parameter) HSelf in build<const S extends Spec, HSelf>(key: string, spec: S, options: {
readonly description?: string;
readonly kind?: string;
readonly node: AddressedNode<HSelf>;
}): NodeBoundTag<Self, S, HSelf> & {
readonly [nodeSym]: AddressedNode<HSelf>;
}
HSelf>;
},
): interface NodeBoundTag<Self, S extends Spec, HSelf, Svc = Simplify<{ readonly [K in keyof S]: S[K] extends FromLocalMethod<infer M> ? InjectLocal<M, Self> : S[K] extends LocalMethod<infer T> ? LocalEffect<...> : S[K] extends { ...; } ? SuccessOf<...> : S[K] extends { ...; } ? Subscribable<...> : S[K] extends { ...; } ? ClientMethod<...> : S[K] extends Spec ? Simplify<...> : never; }>>A
HyperlinkTag
bound to a concrete
Node
— its [nodeSym] narrowed to that node's
NodeKey<HSelf>, which is how
Hyperlink.client
discriminates the node-aware path. Returned
by the node-bearing tag constructors. It's a named type (not an inline & { [nodeSym] }) so a
consumer can export a node-bearing tag without leaking the internal symbol (TS4020).
NodeBoundTag<function (type parameter) Self in <Self>(): {
<const S extends Spec>(key: string, spec: S, options?: {
readonly description?: string;
readonly kind?: string;
}): HyperlinkTag<Self, S>;
<const S extends Spec, HSelf>(key: string, spec: S, options: {
readonly description?: string;
readonly kind?: string;
readonly node: AddressedNode<HSelf>;
}): NodeBoundTag<Self, S, HSelf> & {
readonly [nodeSym]: AddressedNode<HSelf>;
};
<const S extends Spec, HSelf>(key: string, spec: S, options: {
readonly description?: string;
readonly kind?: string;
readonly node: NodeKey<HSelf>;
}): NodeBoundTag<Self, S, HSelf>;
}
Self, function (type parameter) S in build<const S extends Spec, HSelf>(key: string, spec: S, options: {
readonly description?: string;
readonly kind?: string;
readonly node: AddressedNode<HSelf>;
}): NodeBoundTag<Self, S, HSelf> & {
readonly [nodeSym]: AddressedNode<HSelf>;
}
S, function (type parameter) HSelf in build<const S extends Spec, HSelf>(key: string, spec: S, options: {
readonly description?: string;
readonly kind?: string;
readonly node: AddressedNode<HSelf>;
}): NodeBoundTag<Self, S, HSelf> & {
readonly [nodeSym]: AddressedNode<HSelf>;
}
HSelf> & {
readonly [const nodeSym: typeof nodeSymWhere the resource's
Node
(if any) is stowed on a Tag.
nodeSym]: import AddressedNodeAddressedNode<function (type parameter) HSelf in build<const S extends Spec, HSelf>(key: string, spec: S, options: {
readonly description?: string;
readonly kind?: string;
readonly node: AddressedNode<HSelf>;
}): NodeBoundTag<Self, S, HSelf> & {
readonly [nodeSym]: AddressedNode<HSelf>;
}
HSelf>;
};
function function (local function) build<const S extends Spec, HSelf>(key: string, spec: S, options: {
readonly description?: string;
readonly kind?: string;
readonly node: NodeKey<HSelf>;
}): NodeBoundTag<Self, S, HSelf> (+2 overloads)
build<const function (type parameter) S in build<const S extends Spec, HSelf>(key: string, spec: S, options: {
readonly description?: string;
readonly kind?: string;
readonly node: NodeKey<HSelf>;
}): NodeBoundTag<Self, S, HSelf>
S extends Spec, function (type parameter) HSelf in build<const S extends Spec, HSelf>(key: string, spec: S, options: {
readonly description?: string;
readonly kind?: string;
readonly node: NodeKey<HSelf>;
}): NodeBoundTag<Self, S, HSelf>
HSelf>(
key: stringkey: string,
spec: const S extends Specspec: function (type parameter) S in build<const S extends Spec, HSelf>(key: string, spec: S, options: {
readonly description?: string;
readonly kind?: string;
readonly node: NodeKey<HSelf>;
}): NodeBoundTag<Self, S, HSelf>
S,
options: {
readonly description?: string
readonly kind?: string
readonly node: NodeKey<HSelf>
}
options: {
readonly description?: string | undefineddescription?: string;
readonly kind?: string | undefinedkind?: string;
readonly node: NodeKey<HSelf>node: import NodeKeyNodeKey<function (type parameter) HSelf in build<const S extends Spec, HSelf>(key: string, spec: S, options: {
readonly description?: string;
readonly kind?: string;
readonly node: NodeKey<HSelf>;
}): NodeBoundTag<Self, S, HSelf>
HSelf>;
},
): interface NodeBoundTag<Self, S extends Spec, HSelf, Svc = Simplify<{ readonly [K in keyof S]: S[K] extends FromLocalMethod<infer M> ? InjectLocal<M, Self> : S[K] extends LocalMethod<infer T> ? LocalEffect<...> : S[K] extends { ...; } ? SuccessOf<...> : S[K] extends { ...; } ? Subscribable<...> : S[K] extends { ...; } ? ClientMethod<...> : S[K] extends Spec ? Simplify<...> : never; }>>A
HyperlinkTag
bound to a concrete
Node
— its [nodeSym] narrowed to that node's
NodeKey<HSelf>, which is how
Hyperlink.client
discriminates the node-aware path. Returned
by the node-bearing tag constructors. It's a named type (not an inline & { [nodeSym] }) so a
consumer can export a node-bearing tag without leaking the internal symbol (TS4020).
NodeBoundTag<function (type parameter) Self in <Self>(): {
<const S extends Spec>(key: string, spec: S, options?: {
readonly description?: string;
readonly kind?: string;
}): HyperlinkTag<Self, S>;
<const S extends Spec, HSelf>(key: string, spec: S, options: {
readonly description?: string;
readonly kind?: string;
readonly node: AddressedNode<HSelf>;
}): NodeBoundTag<Self, S, HSelf> & {
readonly [nodeSym]: AddressedNode<HSelf>;
};
<const S extends Spec, HSelf>(key: string, spec: S, options: {
readonly description?: string;
readonly kind?: string;
readonly node: NodeKey<HSelf>;
}): NodeBoundTag<Self, S, HSelf>;
}
Self, function (type parameter) S in build<const S extends Spec, HSelf>(key: string, spec: S, options: {
readonly description?: string;
readonly kind?: string;
readonly node: NodeKey<HSelf>;
}): NodeBoundTag<Self, S, HSelf>
S, function (type parameter) HSelf in build<const S extends Spec, HSelf>(key: string, spec: S, options: {
readonly description?: string;
readonly kind?: string;
readonly node: NodeKey<HSelf>;
}): NodeBoundTag<Self, S, HSelf>
HSelf>;
function function (local function) build<const S extends Spec>(key: string, spec: S, options?: {
readonly description?: string;
readonly kind?: string;
}): HyperlinkTag<Self, S> (+2 overloads)
build<const function (type parameter) S in build<const S extends Spec>(key: string, spec: S, options?: {
readonly description?: string;
readonly kind?: string;
readonly node?: NodeKey<unknown>;
}): HyperlinkTag<Self, S>
S extends Spec>(
key: stringkey: string,
spec: const S extends Specspec: function (type parameter) S in build<const S extends Spec>(key: string, spec: S, options?: {
readonly description?: string;
readonly kind?: string;
readonly node?: NodeKey<unknown>;
}): HyperlinkTag<Self, S>
S,
options: | {
readonly description?: string
readonly kind?: string
readonly node?: NodeKey<unknown>
}
| undefined
options?: {
readonly description?: string | undefineddescription?: string;
readonly kind?: string | undefinedkind?: string;
readonly node?: anynode?: import NodeKeyNodeKey<unknown>;
},
): interface HyperlinkTag<Self, S extends Spec, Svc = Simplify<{ readonly [K in keyof S]: S[K] extends FromLocalMethod<infer M> ? InjectLocal<M, Self> : S[K] extends LocalMethod<infer T> ? LocalEffect<...> : S[K] extends { ...; } ? SuccessOf<...> : S[K] extends { ...; } ? Subscribable<...> : S[K] extends { ...; } ? ClientMethod<...> : S[K] extends Spec ? Simplify<...> : never; }>>The type of a resource tag carrying spec S — what
Hyperlink.Tag
/ a
Hyperlink.tagFor
factory produce (and what you extend). Lets a consumer write
<S extends Spec>(tag: HyperlinkTag<Self, S>) and read the spec through named types
(
specOf
/
groupOf
) instead of a Parameters<typeof specOf> workaround.
HyperlinkTag<function (type parameter) Self in <Self>(): {
<const S extends Spec>(key: string, spec: S, options?: {
readonly description?: string;
readonly kind?: string;
}): HyperlinkTag<Self, S>;
<const S extends Spec, HSelf>(key: string, spec: S, options: {
readonly description?: string;
readonly kind?: string;
readonly node: AddressedNode<HSelf>;
}): NodeBoundTag<Self, S, HSelf> & {
readonly [nodeSym]: AddressedNode<HSelf>;
};
<const S extends Spec, HSelf>(key: string, spec: S, options: {
readonly description?: string;
readonly kind?: string;
readonly node: NodeKey<HSelf>;
}): NodeBoundTag<Self, S, HSelf>;
}
Self, function (type parameter) S in build<const S extends Spec>(key: string, spec: S, options?: {
readonly description?: string;
readonly kind?: string;
readonly node?: NodeKey<unknown>;
}): HyperlinkTag<Self, S>
S> {
// single resource: key doubles as the group id (its wire prefix)
const claimGroupId: (
groupId: string
) => void
Reserve a group id (wire prefix); a duplicate throws — two resources can't share a prefix.
claimGroupId(key: stringkey);
return const buildInstanceTag: <Self, S>(groupId: string, key: string, spec: Spec, group: RpcGroupOf<S>, description: string | undefined, node: NodeKey<unknown> | undefined, kindOverride: string | undefined, fromServiceMarker?: boolean) => Context.ServiceClass<Self, string, Simplify<{ readonly [K in keyof S]: S[K] extends FromLocalMethod<infer M> ? InjectLocal<M, Self> : S[K] extends LocalMethod<infer T> ? LocalEffect<T, never, Self> : S[K] extends {
readonly _tag: "constant";
} ? SuccessOf<...> : S[K] extends {
...;
} ? Subscribable<...> : S[K] extends {
...;
} ? ClientMethod<...> : S[K] extends Spec ? Simplify<...> : never; }>> & {
...;
}
The single tag-creation primitive: dup-key guard + Context.Service + stow groupId/spec/group.
Both
makeTag
(per-tag spec) and
tagFor
(shared spec) go through it. key is the
instance identity (Context key + routing header); groupId is the wire prefix.
buildInstanceTag<function (type parameter) Self in <Self>(): {
<const S extends Spec>(key: string, spec: S, options?: {
readonly description?: string;
readonly kind?: string;
}): HyperlinkTag<Self, S>;
<const S extends Spec, HSelf>(key: string, spec: S, options: {
readonly description?: string;
readonly kind?: string;
readonly node: AddressedNode<HSelf>;
}): NodeBoundTag<Self, S, HSelf> & {
readonly [nodeSym]: AddressedNode<HSelf>;
};
<const S extends Spec, HSelf>(key: string, spec: S, options: {
readonly description?: string;
readonly kind?: string;
readonly node: NodeKey<HSelf>;
}): NodeBoundTag<Self, S, HSelf>;
}
Self, function (type parameter) S in build<const S extends Spec>(key: string, spec: S, options?: {
readonly description?: string;
readonly kind?: string;
readonly node?: NodeKey<unknown>;
}): HyperlinkTag<Self, S>
S>(
key: stringkey,
key: stringkey,
spec: const S extends Specspec,
const buildRpcGroup: (
groupId: string,
spec: FlatSpec
) => RpcGroup.RpcGroup<any>
Build the shared RPC contract group from a
Spec
, namespaced by groupId. A bare
Schema becomes a payload-free rpc returning that schema; a descriptor maps straight to
its parts. Every procedure's wire tag is
wireTag
-prefixed by groupId.
buildRpcGroup(key: stringkey, const flattenSpec: (
spec: Spec,
prefix?: string
) => FlatSpec
Flatten a nested spec to a flat path-keyed record (identity for a flat spec).
flattenSpec(spec: const S extends Specspec)),
options: | {
readonly description?: string
readonly kind?: string
readonly node?: NodeKey<unknown>
}
| undefined
options?.description?: string | undefineddescription,
options: | {
readonly description?: string
readonly kind?: string
readonly node?: NodeKey<unknown>
}
| undefined
options?.node?: anynode,
options: | {
readonly description?: string
readonly kind?: string
readonly node?: NodeKey<unknown>
}
| undefined
options?.kind?: string | undefinedkind,
);
}
return function (local function) build<const S extends Spec>(key: string, spec: S, options?: {
readonly description?: string;
readonly kind?: string;
}): HyperlinkTag<Self, S> (+2 overloads)
build;
};