<Self>(): SchemaTagBuilder<Self>
<Self, I>(): InterfaceTagBuilder<Self, I>
<const S extends Spec>(
wireKey: string,
spec: S & RejectBareLocal<S>,
options?: TagOptions & { readonly node?: NodeKey<unknown> }
): SharedTagFactory<S>Create a HyperService service tag.
Solo (schema) — Tag<Self>()(key, spec): value type inferred from the spec; wire key = .key.
class Counter extends Hyperlink.Tag<Counter>()("Counter", {
increment: Hyperlink.effectFn({ by: Schema.Number }),
current: Hyperlink.effect(Schema.Number),
}) {}Optional { defaults } on the options bag is sugar for .pipe(Hyperlink.defaults(…)) —
bag keys widen Service / yield* Tag the same way.
Solo (interface) — Tag<Self, I>()(key, contract): interface I is SSOT; bare
local takes its type from I.
Shared Spec — Tag(wireKey, spec) then Factory<Self>()(instanceKey): one RpcGroup
prefixed by wireKey, many Context identities routed by header key. Use only when every
instance has the same procedure names and schemas. Serve with ordinary serve /
serveRemote (merge layers); dial with ordinary client.
const Counters = Hyperlink.Tag("demo/SharedCounters", {
snapshot: Hyperlink.effect(Schema.Number),
});
class Nwsl extends Counters<Nwsl>()("@app/Nwsl/counters") {}
class Mls extends Counters<Mls>()("@app/Mls/counters") {}
Layer.mergeAll(
Hyperlink.serve(Nwsl, { snapshot: Effect.succeed(1) }),
Hyperlink.serve(Mls, { snapshot: Effect.succeed(2) }),
);Keys must be unique: a duplicate throws at declaration. Solo tags also claim their key as
the wire prefix; shared factories claim wireKey once for the whole family of instances.
const const makeTag: {
<Self>(): SchemaTagBuilder<Self>
<Self, I>(): InterfaceTagBuilder<Self, I>
<S extends Spec>(
wireKey: string,
spec: S & RejectBareLocal<S>,
options?: TagOptions & {
readonly node?: NodeKey<unknown>
}
): SharedTagFactory<S>
}
Create a HyperService service tag.
Solo (schema) — Tag<Self>()(key, spec): value type inferred from the spec; wire key = .key.
class Counter extends Hyperlink.Tag<Counter>()("Counter", {
increment: Hyperlink.effectFn({ by: Schema.Number }),
current: Hyperlink.effect(Schema.Number),
}) {}
Optional { defaults } on the options bag is sugar for .pipe(Hyperlink.defaults(…)) —
bag keys widen Service / yield* Tag the same way.
Solo (interface) — Tag<Self, I>()(key, contract): interface I is SSOT; bare
local
takes its type from I.
Shared Spec — Tag(wireKey, spec) then Factory<Self>()(instanceKey): one RpcGroup
prefixed by wireKey, many Context identities routed by header key. Use only when every
instance has the same procedure names and schemas. Serve with ordinary
serve
/
serveRemote
(merge layers); dial with ordinary
client
.
const Counters = Hyperlink.Tag("demo/SharedCounters", {
snapshot: Hyperlink.effect(Schema.Number),
});
class Nwsl extends Counters<Nwsl>()("@app/Nwsl/counters") {}
class Mls extends Counters<Mls>()("@app/Mls/counters") {}
Layer.mergeAll(
Hyperlink.serve(Nwsl, { snapshot: Effect.succeed(1) }),
Hyperlink.serve(Mls, { snapshot: Effect.succeed(2) }),
);
Keys must be unique: a duplicate throws at declaration. Solo tags also claim their key as
the wire prefix; shared factories claim wireKey once for the whole family of instances.
makeTag = const retype: <{
<Self>(): SchemaTagBuilder<Self>;
<Self, I>(): InterfaceTagBuilder<Self, I>;
<const S extends Spec>(wireKey: string, spec: S & RejectBareLocal<S>, options?: TagOptions & {
readonly node?: NodeKey<unknown>;
}): SharedTagFactory<S>;
}>(value: never) => {
<Self>(): SchemaTagBuilder<Self>;
<Self, I>(): InterfaceTagBuilder<Self, I>;
<const S extends Spec>(wireKey: string, spec: S & RejectBareLocal<S>, options?: TagOptions & {
readonly node?: NodeKey<unknown>;
}): SharedTagFactory<S>;
}
Retype through never (not any/unknown channels) at dynamic Effect/Rpc factories.
Same bridge as internal/nodeServerCommon.retype — kept local so this module does not
import server plumbing.
retype<{
/** Schema-driven solo: infer the service from `spec`; bare {@link local} is a compile error. */
<function (type parameter) Self in <Self>(): SchemaTagBuilder<Self>Self>(): type SchemaTagBuilder<Self> = {
<
const S extends Spec,
const D extends DefaultsBag,
HSelf
>(
key: string,
spec: S & RejectBareLocal<S>,
options: TagOptions & {
readonly node: AddressedNode<HSelf>
readonly defaults: DefaultsInput<D>
}
): TagWithDefaults<
NodeBoundTag<Self, S, HSelf> & {
readonly [nodeSym]: AddressedNode<HSelf>
},
D
>
<
const S extends Spec,
const D extends DefaultsBag,
HSelf
>(
key: string,
spec: S & RejectBareLocal<S>,
options: TagOptions & {
readonly node: NodeKey<HSelf>
readonly defaults: DefaultsInput<D>
}
): TagWithDefaults<
NodeBoundTag<Self, S, HSelf>,
D
>
<
const S extends Spec,
const D extends DefaultsBag
>(
key: string,
spec: S & RejectBareLocal<S>,
options: TagOptions & {
readonly defaults: DefaultsInput<D>
}
): TagWithDefaults<HyperlinkTag<Self, S>, D>
<const S extends Spec, HSelf>(
key: string,
spec: S & RejectBareLocal<S>,
options: TagOptions & {
readonly node: AddressedNode<HSelf>
}
): NodeBoundTag<Self, S, HSelf> & {
readonly [nodeSym]: AddressedNode<HSelf>
}
<const S extends Spec, HSelf>(
key: string,
spec: S & RejectBareLocal<S>,
options: TagOptions & {
readonly node: NodeKey<HSelf>
}
): NodeBoundTag<Self, S, HSelf>
<const S extends Spec>(
key: string,
spec: S & RejectBareLocal<S>,
options?: TagOptions
): HyperlinkTag<Self, S>
}
Schema-driven
Tag
<Self>() builder — bare
local
rejected (
RejectBareLocal
).
Node-bearing overloads first so options.node still infers HSelf when options are a variable.
{ defaults } overloads (required key) before optional-options so bag keys stay precise.
SchemaTagBuilder<function (type parameter) Self in <Self>(): SchemaTagBuilder<Self>Self>;
/** Interface-driven solo: `I` is SSOT; bare {@link local} takes its type from `I`. */
<function (type parameter) Self in <Self, I>(): InterfaceTagBuilder<Self, I>Self, function (type parameter) I in <Self, I>(): InterfaceTagBuilder<Self, I>I>(): type InterfaceTagBuilder<Self, I> = {
<
const S extends Spec,
const D extends DefaultsBag,
HSelf
>(
key: string,
spec: S & Validate<S, I>,
options: TagOptions & {
readonly node: AddressedNode<HSelf>
readonly defaults: DefaultsInput<D>
}
): TagWithDefaults<
NodeBoundTag<
Self,
ResolveLocals<S, I>,
HSelf
> & {
readonly [nodeSym]: AddressedNode<HSelf>
},
D
>
<
const S extends Spec,
const D extends DefaultsBag,
HSelf
>(
key: string,
spec: S & Validate<S, I>,
options: TagOptions & {
readonly node: NodeKey<HSelf>
readonly defaults: DefaultsInput<D>
}
): TagWithDefaults<
NodeBoundTag<
Self,
ResolveLocals<S, I>,
HSelf
>,
D
>
<
const S extends Spec,
const D extends DefaultsBag
>(
key: string,
spec: S & Validate<S, I>,
options: TagOptions & {
readonly defaults: DefaultsInput<D>
}
): TagWithDefaults<
HyperlinkTag<Self, ResolveLocals<S, I>>,
D
>
<const S extends Spec, HSelf>(
key: string,
spec: S & Validate<S, I>,
options: TagOptions & {
readonly node: AddressedNode<HSelf>
}
): NodeBoundTag<
Self,
ResolveLocals<S, I>,
HSelf
> & {
readonly [nodeSym]: AddressedNode<HSelf>
}
<const S extends Spec, HSelf>(
key: string,
spec: S & Validate<S, I>,
options: TagOptions & {
readonly node: NodeKey<HSelf>
}
): NodeBoundTag<
Self,
ResolveLocals<S, I>,
HSelf
>
<const S extends Spec>(
key: string,
spec: S & Validate<S, I>,
options?: TagOptions
): HyperlinkTag<Self, ResolveLocals<S, I>>
}
Interface-driven
Tag
<Self, I>() builder — bare
local
typed from I
(
Validate
/
ResolveLocals
).
InterfaceTagBuilder<function (type parameter) Self in <Self, I>(): InterfaceTagBuilder<Self, I>Self, function (type parameter) I in <Self, I>(): InterfaceTagBuilder<Self, I>I>;
/** Shared Spec: one wire key, many instance tags (`Factory<Self>()(instanceKey)`). */
<const function (type parameter) S in <const S extends Spec>(wireKey: string, spec: S & RejectBareLocal<S>, options?: TagOptions & {
readonly node?: NodeKey<unknown>;
}): SharedTagFactory<S>
S extends Spec>(
wireKey: stringwireKey: string,
spec: S & RejectBareLocal<S>spec: function (type parameter) S in <const S extends Spec>(wireKey: string, spec: S & RejectBareLocal<S>, options?: TagOptions & {
readonly node?: NodeKey<unknown>;
}): SharedTagFactory<S>
S & type RejectBareLocal<C> = {
readonly [K in keyof C]: C[K] extends BareLocal
? LocalNeedsType<K>
: C[K] extends Spec
? RejectBareLocal<C[K]>
: C[K]
}
Reject bare
local
members in a plain
Tag
<Self>() contract — bare locals need
Tag
<Self, I>() so the interface can supply their type.
RejectBareLocal<function (type parameter) S in <const S extends Spec>(wireKey: string, spec: S & RejectBareLocal<S>, options?: TagOptions & {
readonly node?: NodeKey<unknown>;
}): SharedTagFactory<S>
S>,
options: TagOptions & {
readonly node?: NodeKey<unknown>
}
options?: type TagOptions = {
readonly description?: string
readonly kind?: string
}
Optional description / kind bag shared by every
Tag
builder overload.
defaults is not on this type — only on overloads that use
DefaultsInput
so Promise-returning fns stay rejected (a loose DefaultsBag would accept them).
TagOptions & { readonly node?: NodeKey<unknown>node?: 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> },
): interface SharedTagFactory<S extends Spec>Shared-Spec factory from
Tag
(wireKey, spec). Mint instances with the Effect-shaped
double call: Factory<Self>()(instanceKey).
SharedTagFactory<function (type parameter) S in <const S extends Spec>(wireKey: string, spec: S & RejectBareLocal<S>, options?: TagOptions & {
readonly node?: NodeKey<unknown>;
}): SharedTagFactory<S>
S>;
}>(function function (local function) makeTag(wireKeyOrNever?: string, sharedSpec?: Spec, sharedOptions?: TagOptions & {
readonly node?: NodeKey<unknown>;
}): ((() => (key: string, instanceOptions?: {
readonly description?: string;
readonly node?: NodeKey<unknown>;
readonly defaults?: DefaultsBag;
}) => (Context.ServiceClass<unknown, string, {
readonly [x: string]: never;
}> & {
[sharedTagSym]?: true | undefined;
[interfaceLocalsSym]?: true | undefined;
[kindSym]: string;
... 9 more ...;
[nodeSym]: NodeKey<...> | undefined;
}) | TagWithDefaults<...>) & {
...;
}) | ((key: string, spec: Spec, options?: TagOptions & {
readonly node?: NodeKey<unknown>;
readonly defaults?: DefaultsBag;
}) => (Context.ServiceClass<...> & {
[sharedTagSym]?: true | undefined;
[interfaceLocalsSym]?: true | undefined;
[kindSym]: string;
... 9 more ...;
[nodeSym]: NodeKey<...> | undefined;
}) | TagWithDefaults<...>)
makeTag(
wireKeyOrNever: string | undefinedwireKeyOrNever?: string,
sharedSpec: SpecsharedSpec?: Spec,
sharedOptions: TagOptions & {
readonly node?: NodeKey<unknown>
}
sharedOptions?: type TagOptions = {
readonly description?: string
readonly kind?: string
}
Optional description / kind bag shared by every
Tag
builder overload.
defaults is not on this type — only on overloads that use
DefaultsInput
so Promise-returning fns stay rejected (a loose DefaultsBag would accept them).
TagOptions & { readonly node?: NodeKey<unknown>node?: 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> },
) {
// Shared-Spec factory: Tag(wireKey, spec) → Factory<Self>()(instanceKey).
if (typeof wireKeyOrNever: string | undefinedwireKeyOrNever === "string" && sharedSpec: SpecsharedSpec !== var undefinedundefined) {
const const wireKey: stringwireKey = wireKeyOrNever: stringwireKeyOrNever;
const claimWireKey: (
wireKey: string
) => void
Reserve a wire key (RpcGroup prefix); a duplicate throws — two HyperServices can't share a prefix.
claimWireKey(const wireKey: stringwireKey);
const const flat: FlatSpecflat = const flattenSpec: (
spec: Spec,
prefix?: string
) => FlatSpec
Flatten a nested spec to a flat path-keyed record (identity for a flat spec).
flattenSpec(sharedSpec: SpecsharedSpec);
const const group: RpcGroupOf<Spec>const group: {
requests: ReadonlyMap<string, R>;
annotations: Context.Context<never>;
add: (...rpcs: Rpcs2) => RpcGroup.RpcGroup<Rpcs2[number]>;
merge: (...groups: Groups) => RpcGroup.RpcGroup<RpcGroup.Rpcs<Groups[number]>>;
omit: (...tags: Tags) => RpcGroup.RpcGroup<never>;
middleware: (middleware: M) => RpcGroup.RpcGroup<never>;
prefix: (prefix: Prefix) => RpcGroup.RpcGroup<never>;
toHandlers: (build: Handlers | Effect.Effect<Handlers, EX, RX>) => Effect.Effect<Context.Context<never>, EX, RX | RpcGroup.HandlersServices<never, Handlers>>;
toLayer: (build: Handlers | Effect.Effect<Handlers, EX, RX>) => Layer.Layer<never, EX, Exclude<RX, Scope.Scope> | RpcGroup.HandlersServices<never, Handlers>>;
of: (handlers: Handlers) => Handlers;
toLayerHandler: (tag: Tag, build: Handler | Effect.Effect<Handler, EX, RX>) => Layer.Layer<Rpc.Handler<Tag>, EX, Exclude<RX, Scope.Scope> | (Handler extends (...args: any) => Effect.Effect<infer _A, infer _E, infer _R> | Rpc.Wrapper<Effect.Effect<infer _A…;
accessHandler: (tag: Tag) => Effect.Effect<(payload: never, options: { readonly client: Rpc.ServerClient; readonly requestId: RequestId; readonly headers: Headers.Headers }) => never, never, Rpc.Handler<Tag>>;
annotate: (service: Context.Key<I, S>, value: S) => RpcGroup.RpcGroup<never>;
annotateRpcs: (service: Context.Key<I, S>, value: S) => RpcGroup.RpcGroup<never>;
annotateMerge: (annotations: Context.Context<S>) => RpcGroup.RpcGroup<never>;
annotateRpcsMerge: (annotations: Context.Context<S>) => RpcGroup.RpcGroup<never>;
pipe: { <A>(this: A): A; <A, B = never>(this: A, ab: (_: A) => B): B; <A, B = never, C = never>(this: A, ab: (_: A) => B, bc: (_: B) => C): C; <A, B = never, C = never, D = never>(this: A, ab: (_: A) => B, bc: (_: B) => C, cd: (_: C) => D): D; <…;
}
group = const retype: <RpcGroupOf<Spec>>(value: never) => RpcGroupOf<Spec>Retype through never (not any/unknown channels) at dynamic Effect/Rpc factories.
Same bridge as internal/nodeServerCommon.retype — kept local so this module does not
import server plumbing.
retype<type RpcGroupOf<S extends Spec> =
RpcGroup.RpcGroup<RpcUnionOf<S, "">>
The precisely-typed RPC contract group for a
Spec
. Carrying this exact type
(rather than a loose Rpc<string, …>) is what keeps the remote client's requirement
channel honest: concrete schemas declare never encoding/decoding services, so
RpcClient.make infers a real R (just the transport Protocol) instead of any.
RpcGroupOf<Spec>>(
const buildRpcGroup: (
wireKey: string,
spec: FlatSpec
) => RpcGroup.RpcGroup<any>
Build the shared RPC contract group from a
Spec
, namespaced by wireKey. 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 wireKey.
buildRpcGroup(const wireKey: stringwireKey, const flat: FlatSpecflat) as never,
);
const const factoryKind: stringfactoryKind = sharedOptions: TagOptions & {
readonly node?: NodeKey<unknown>
}
sharedOptions?.kind?: string | undefinedkind ?? const wireKey: stringwireKey;
const const factoryNode:
| NodeKey<unknown>
| undefined
factoryNode = sharedOptions: TagOptions & {
readonly node?: NodeKey<unknown>
}
sharedOptions?.node?: NodeKey<unknown>node;
const const mint: () => (
key: string,
instanceOptions?: {
readonly description?: string
readonly node?: NodeKey<unknown>
readonly defaults?: DefaultsBag
}
) =>
| (Context.ServiceClass<
unknown,
string,
{ readonly [x: string]: never }
> & {
[sharedTagSym]?: true | undefined
[interfaceLocalsSym]?: true | undefined
[kindSym]: string
[readinessSym]: undefined
[peersSym]: Context.Key<
PeersId<unknown>,
Record<string, PeerServiceOf<Spec>>
>
[selfNodeSym]: Context.Key<
SelfNodeId<unknown>,
string
>
[nodesSym]?:
| ReadonlyArray<AnyNode>
| undefined
[wireKeySym]: string
description: string | undefined
[specSym]: FlatSpec
[groupSym]: RpcGroupOf<Spec>
[localCapSym]: Context.Key<
Local<unknown>,
{ readonly granted: true }
>
[nodeSym]: NodeKey<unknown> | undefined
})
| TagWithDefaults<
Context.ServiceClass<
unknown,
string,
{ readonly [x: string]: never }
> & {
[sharedTagSym]?: true | undefined
[interfaceLocalsSym]?: true | undefined
[kindSym]: string
[readinessSym]: undefined
[peersSym]: Context.Key<
PeersId<unknown>,
Record<string, PeerServiceOf<Spec>>
>
[selfNodeSym]: Context.Key<
SelfNodeId<unknown>,
string
>
[nodesSym]?:
| ReadonlyArray<AnyNode>
| undefined
[wireKeySym]: string
description: string | undefined
[specSym]: FlatSpec
[groupSym]: RpcGroupOf<Spec>
[localCapSym]: Context.Key<
Local<unknown>,
{ readonly granted: true }
>
[nodeSym]: NodeKey<unknown> | undefined
},
DefaultsBag
>
mint =
() =>
(
key: stringkey: string,
instanceOptions: {
readonly description?: string
readonly node?: NodeKey<unknown>
readonly defaults?: DefaultsBag
}
instanceOptions?: {
readonly description?: string | undefineddescription?: string;
readonly node?: NodeKey<unknown>node?: 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 defaults?: DefaultsBagdefaults?: type DefaultsBag = {
readonly [key: string]: unknown
}
A bag of Tag-baked defaults for
defaults
.
DefaultsBag;
},
) => {
const const tag: Context.ServiceClass<unknown, string, {
readonly [x: string]: never;
}> & {
[sharedTagSym]?: true | undefined;
[interfaceLocalsSym]?: true | undefined;
[kindSym]: string;
[readinessSym]: undefined;
[peersSym]: Context.Key<PeersId<unknown>, Record<string, PeerServiceOf<Spec>>>;
[selfNodeSym]: Context.Key<SelfNodeId<unknown>, string>;
[nodesSym]?: readonly AnyNode[] | undefined;
... 5 more ...;
[nodeSym]: NodeKey<...> | undefined;
}
tag = const buildInstanceTag: <unknown, Spec>(wireKey: string, key: string, spec: Spec, group: RpcGroupOf<Spec>, description: string | undefined, node: NodeKey<unknown> | undefined, kindOverride: string | undefined, interfaceLocalsMarker?: boolean, sharedMarker?: boolean) => Context.ServiceClass<unknown, string, {
readonly [x: string]: never;
}> & {
[sharedTagSym]?: true | undefined;
[interfaceLocalsSym]?: true | undefined;
[kindSym]: string;
[readinessSym]: undefined;
[peersSym]: Context.Key<...>;
... 7 more ...;
[nodeSym]: NodeKey<...> | undefined;
}
The single tag-creation primitive: dup-key guard + Context.Service + stow wireKey/spec/group.
Tag-creation primitive used by
makeTag
. key is Context identity; for solo tags
wireKey is the same string (RpcGroup prefix).
buildInstanceTag<unknown, Spec>(
const wireKey: stringwireKey,
key: stringkey,
sharedSpec: SpecsharedSpec,
const group: RpcGroupOf<Spec>const group: {
requests: ReadonlyMap<string, R>;
annotations: Context.Context<never>;
add: (...rpcs: Rpcs2) => RpcGroup.RpcGroup<Rpcs2[number]>;
merge: (...groups: Groups) => RpcGroup.RpcGroup<RpcGroup.Rpcs<Groups[number]>>;
omit: (...tags: Tags) => RpcGroup.RpcGroup<never>;
middleware: (middleware: M) => RpcGroup.RpcGroup<never>;
prefix: (prefix: Prefix) => RpcGroup.RpcGroup<never>;
toHandlers: (build: Handlers | Effect.Effect<Handlers, EX, RX>) => Effect.Effect<Context.Context<never>, EX, RX | RpcGroup.HandlersServices<never, Handlers>>;
toLayer: (build: Handlers | Effect.Effect<Handlers, EX, RX>) => Layer.Layer<never, EX, Exclude<RX, Scope.Scope> | RpcGroup.HandlersServices<never, Handlers>>;
of: (handlers: Handlers) => Handlers;
toLayerHandler: (tag: Tag, build: Handler | Effect.Effect<Handler, EX, RX>) => Layer.Layer<Rpc.Handler<Tag>, EX, Exclude<RX, Scope.Scope> | (Handler extends (...args: any) => Effect.Effect<infer _A, infer _E, infer _R> | Rpc.Wrapper<Effect.Effect<infer _A…;
accessHandler: (tag: Tag) => Effect.Effect<(payload: never, options: { readonly client: Rpc.ServerClient; readonly requestId: RequestId; readonly headers: Headers.Headers }) => never, never, Rpc.Handler<Tag>>;
annotate: (service: Context.Key<I, S>, value: S) => RpcGroup.RpcGroup<never>;
annotateRpcs: (service: Context.Key<I, S>, value: S) => RpcGroup.RpcGroup<never>;
annotateMerge: (annotations: Context.Context<S>) => RpcGroup.RpcGroup<never>;
annotateRpcsMerge: (annotations: Context.Context<S>) => RpcGroup.RpcGroup<never>;
pipe: { <A>(this: A): A; <A, B = never>(this: A, ab: (_: A) => B): B; <A, B = never, C = never>(this: A, ab: (_: A) => B, bc: (_: B) => C): C; <A, B = never, C = never, D = never>(this: A, ab: (_: A) => B, bc: (_: B) => C, cd: (_: C) => D): D; <…;
}
group,
instanceOptions: {
readonly description?: string
readonly node?: NodeKey<unknown>
readonly defaults?: DefaultsBag
}
instanceOptions?.description?: string | undefineddescription ?? sharedOptions: TagOptions & {
readonly node?: NodeKey<unknown>
}
sharedOptions?.description?: string | undefineddescription,
instanceOptions: {
readonly description?: string
readonly node?: NodeKey<unknown>
readonly defaults?: DefaultsBag
}
instanceOptions?.node?: NodeKey<unknown>node ?? const factoryNode:
| NodeKey<unknown>
| undefined
factoryNode,
const factoryKind: stringfactoryKind,
false,
true,
);
return const applyTagDefaults: <
T extends PipeableTag,
D extends DefaultsBag
>(
tag: T,
bag: D | undefined
) => T | TagWithDefaults<T, D>
Apply
defaults
when a bag is present — factory { defaults } sugar helper.
applyTagDefaults(const tag: Context.ServiceClass<unknown, string, {
readonly [x: string]: never;
}> & {
[sharedTagSym]?: true | undefined;
[interfaceLocalsSym]?: true | undefined;
[kindSym]: string;
[readinessSym]: undefined;
[peersSym]: Context.Key<PeersId<unknown>, Record<string, PeerServiceOf<Spec>>>;
[selfNodeSym]: Context.Key<SelfNodeId<unknown>, string>;
[nodesSym]?: readonly AnyNode[] | undefined;
... 5 more ...;
[nodeSym]: NodeKey<...> | undefined;
}
tag, instanceOptions: {
readonly description?: string
readonly node?: NodeKey<unknown>
readonly defaults?: DefaultsBag
}
instanceOptions?.defaults?: DefaultsBagdefaults);
};
return var Object: ObjectConstructorProvides functionality common to all JavaScript objects.
Object.ObjectConstructor.assign<() => (key: string, instanceOptions?: {
readonly description?: string;
readonly node?: NodeKey<unknown>;
readonly defaults?: DefaultsBag;
}) => (Context.ServiceClass<unknown, string, {
readonly [x: string]: never;
}> & {
[sharedTagSym]?: true | undefined;
[interfaceLocalsSym]?: true | undefined;
[kindSym]: string;
[readinessSym]: undefined;
[peersSym]: Context.Key<PeersId<unknown>, Record<string, PeerServiceOf<Spec>>>;
... 7 more ...;
[nodeSym]: NodeKey<...> | undefined;
}) | TagWithDefaults<...>, {
...;
}>(target: () => (key: string, instanceOptions?: {
readonly description?: string;
readonly node?: NodeKey<unknown>;
readonly defaults?: DefaultsBag;
}) => (Context.ServiceClass<unknown, string, {
readonly [x: string]: never;
}> & {
[sharedTagSym]?: true | undefined;
[interfaceLocalsSym]?: true | undefined;
[kindSym]: string;
[readinessSym]: undefined;
[peersSym]: Context.Key<PeersId<unknown>, Record<string, PeerServiceOf<Spec>>>;
... 7 more ...;
[nodeSym]: NodeKey<...> | undefined;
}) | TagWithDefaults<...>, source: {
...;
}): (() => (key: string, instanceOptions?: {
readonly description?: string;
readonly node?: NodeKey<unknown>;
readonly defaults?: DefaultsBag;
}) => (Context.ServiceClass<unknown, string, {
readonly [x: string]: never;
}> & {
[sharedTagSym]?: true | undefined;
[interfaceLocalsSym]?: true | undefined;
[kindSym]: string;
[readinessSym]: undefined;
[peersSym]: Context.Key<PeersId<unknown>, Record<string, PeerServiceOf<Spec>>>;
... 7 more ...;
[nodeSym]: NodeKey<...> | undefined;
}) | TagWithDefaults<...>) & {
...;
} (+3 overloads)
Copy the values of all of the enumerable own properties from one or more source objects to a
target object. Returns the target object.
assign(const mint: () => (
key: string,
instanceOptions?: {
readonly description?: string
readonly node?: NodeKey<unknown>
readonly defaults?: DefaultsBag
}
) =>
| (Context.ServiceClass<
unknown,
string,
{ readonly [x: string]: never }
> & {
[sharedTagSym]?: true | undefined
[interfaceLocalsSym]?: true | undefined
[kindSym]: string
[readinessSym]: undefined
[peersSym]: Context.Key<
PeersId<unknown>,
Record<string, PeerServiceOf<Spec>>
>
[selfNodeSym]: Context.Key<
SelfNodeId<unknown>,
string
>
[nodesSym]?:
| ReadonlyArray<AnyNode>
| undefined
[wireKeySym]: string
description: string | undefined
[specSym]: FlatSpec
[groupSym]: RpcGroupOf<Spec>
[localCapSym]: Context.Key<
Local<unknown>,
{ readonly granted: true }
>
[nodeSym]: NodeKey<unknown> | undefined
})
| TagWithDefaults<
Context.ServiceClass<
unknown,
string,
{ readonly [x: string]: never }
> & {
[sharedTagSym]?: true | undefined
[interfaceLocalsSym]?: true | undefined
[kindSym]: string
[readinessSym]: undefined
[peersSym]: Context.Key<
PeersId<unknown>,
Record<string, PeerServiceOf<Spec>>
>
[selfNodeSym]: Context.Key<
SelfNodeId<unknown>,
string
>
[nodesSym]?:
| ReadonlyArray<AnyNode>
| undefined
[wireKeySym]: string
description: string | undefined
[specSym]: FlatSpec
[groupSym]: RpcGroupOf<Spec>
[localCapSym]: Context.Key<
Local<unknown>,
{ readonly granted: true }
>
[nodeSym]: NodeKey<unknown> | undefined
},
DefaultsBag
>
mint, {
wireKey: stringwireKey,
kind: stringkind: const factoryKind: stringfactoryKind,
description: string | undefineddescription: sharedOptions: TagOptions & {
readonly node?: NodeKey<unknown>
}
sharedOptions?.description?: string | undefineddescription,
[const specSym: typeof specSymWhere the contract spec is stowed on a Tag (hidden from the value surface). Exported so
the public
HyperlinkTag
type is nameable across modules.
specSym]: const flat: FlatSpecflat,
[const groupSym: typeof groupSymWhere the built RPC group is stowed on a Tag.
groupSym]: const group: RpcGroupOf<Spec>const group: {
requests: ReadonlyMap<string, R>;
annotations: Context.Context<never>;
add: (...rpcs: Rpcs2) => RpcGroup.RpcGroup<Rpcs2[number]>;
merge: (...groups: Groups) => RpcGroup.RpcGroup<RpcGroup.Rpcs<Groups[number]>>;
omit: (...tags: Tags) => RpcGroup.RpcGroup<never>;
middleware: (middleware: M) => RpcGroup.RpcGroup<never>;
prefix: (prefix: Prefix) => RpcGroup.RpcGroup<never>;
toHandlers: (build: Handlers | Effect.Effect<Handlers, EX, RX>) => Effect.Effect<Context.Context<never>, EX, RX | RpcGroup.HandlersServices<never, Handlers>>;
toLayer: (build: Handlers | Effect.Effect<Handlers, EX, RX>) => Layer.Layer<never, EX, Exclude<RX, Scope.Scope> | RpcGroup.HandlersServices<never, Handlers>>;
of: (handlers: Handlers) => Handlers;
toLayerHandler: (tag: Tag, build: Handler | Effect.Effect<Handler, EX, RX>) => Layer.Layer<Rpc.Handler<Tag>, EX, Exclude<RX, Scope.Scope> | (Handler extends (...args: any) => Effect.Effect<infer _A, infer _E, infer _R> | Rpc.Wrapper<Effect.Effect<infer _A…;
accessHandler: (tag: Tag) => Effect.Effect<(payload: never, options: { readonly client: Rpc.ServerClient; readonly requestId: RequestId; readonly headers: Headers.Headers }) => never, never, Rpc.Handler<Tag>>;
annotate: (service: Context.Key<I, S>, value: S) => RpcGroup.RpcGroup<never>;
annotateRpcs: (service: Context.Key<I, S>, value: S) => RpcGroup.RpcGroup<never>;
annotateMerge: (annotations: Context.Context<S>) => RpcGroup.RpcGroup<never>;
annotateRpcsMerge: (annotations: Context.Context<S>) => RpcGroup.RpcGroup<never>;
pipe: { <A>(this: A): A; <A, B = never>(this: A, ab: (_: A) => B): B; <A, B = never, C = never>(this: A, ab: (_: A) => B, bc: (_: B) => C): C; <A, B = never, C = never, D = never>(this: A, ab: (_: A) => B, bc: (_: B) => C, cd: (_: C) => D): D; <…;
}
group,
});
}
// Solo builder — overload surface discriminates schema vs interface.
// `options.node` rides the call so its identity `HSelf` infers; node-bearing overloads narrow
// `[nodeSym]` for {@link Hyperlink.client}. An {@link AddressedNode} further enables auto-connect.
// Self/S are phantom here: the public overloads restate them; pin `unknown`/`Spec` so this body
// does not chase a free type parameter into RpcGroupOf / ServiceOf.
function function (local function) build(key: string, spec: Spec, options?: TagOptions & { readonly node?: NodeKey<unknown>; readonly defaults?: DefaultsBag }): (Context.ServiceClass<unknown, string, { readonly [x: string]: never }> & { [sharedTagSym]?: true | undefined; [interfaceLocalsSym]?: true | undefined; [kindSym]: string; [readinessSym]: undefined; [peersSym]: Context.Key<PeersId<unknown>, Record<string, PeerServiceOf<Spec>>>; [selfNodeSym]: Context.Key<SelfNodeId<unknown>, string>; [nodesSym]?: ReadonlyArray<AnyNode> | undefined; [wireKeySym]: string; description: string | undefined; [specSym]: FlatSpec; [groupSym]: RpcGroupOf<Spec>; [localCapSym]: Context.Key<Local<unknown>, { readonly granted: true }>; [nodeSym]: NodeKey<unknown> | undefined }) | TagWithDefaults<Context.ServiceClass<unknown, string, { readonly [x: string]: never }> & { [sharedTagSym]?: true | undefined; [interfaceLocalsSym]?: true | undefined; [kindSym]: string; [readinessSym]: undefined; [peersSym]: Context.Key<PeersId<unknown>, Record<string, PeerServiceOf<Spec>>>; [selfNodeSym]: Context.Key<SelfNodeId<unknown>, string>; [nodesSym]?: ReadonlyArray<AnyNode> | undefined; [wireKeySym]: string; description: string | undefined; [specSym]: FlatSpec; [groupSym]: RpcGroupOf<Spec>; [localCapSym]: Context.Key<Local<unknown>, { readonly granted: true }>; [nodeSym]: NodeKey<unknown> | undefined }, DefaultsBag>build(
key: stringkey: string,
spec: Specspec: Spec,
options: TagOptions & {
readonly node?: NodeKey<unknown>
readonly defaults?: DefaultsBag
}
options?: type TagOptions = {
readonly description?: string
readonly kind?: string
}
Optional description / kind bag shared by every
Tag
builder overload.
defaults is not on this type — only on overloads that use
DefaultsInput
so Promise-returning fns stay rejected (a loose DefaultsBag would accept them).
TagOptions & {
readonly node?: NodeKey<unknown>node?: 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 defaults?: DefaultsBagdefaults?: type DefaultsBag = {
readonly [key: string]: unknown
}
A bag of Tag-baked defaults for
defaults
.
DefaultsBag;
},
) {
const claimWireKey: (
wireKey: string
) => void
Reserve a wire key (RpcGroup prefix); a duplicate throws — two HyperServices can't share a prefix.
claimWireKey(key: stringkey);
const const flat: FlatSpecflat = const flattenSpec: (
spec: Spec,
prefix?: string
) => FlatSpec
Flatten a nested spec to a flat path-keyed record (identity for a flat spec).
flattenSpec(spec: Specspec);
const const interfaceLocals: booleaninterfaceLocals = var Object: ObjectConstructorProvides functionality common to all JavaScript objects.
Object.ObjectConstructor.values<AnyMethod | AnyLocalMethod | AnyDefaultMethod>(o: {
[s: string]: AnyMethod | AnyLocalMethod | AnyDefaultMethod;
} | ArrayLike<AnyMethod | AnyLocalMethod | AnyDefaultMethod>): (AnyMethod | AnyLocalMethod | AnyDefaultMethod)[] (+1 overload)
Returns an array of values of the enumerable own properties of an object
values(const flat: FlatSpecflat).Array<AnyMethod | AnyLocalMethod | AnyDefaultMethod>.some(predicate: (value: AnyMethod | AnyLocalMethod | AnyDefaultMethod, index: number, array: (AnyMethod | AnyLocalMethod | AnyDefaultMethod)[]) => unknown, thisArg?: any): booleanDetermines whether the specified callback function returns true for any element of an array.
some((m: | AnyMethod
| AnyLocalMethod
| AnyDefaultMethod
m) =>
import PredicatePredicate.const hasProperty: <typeof bareLocalSym>(self: unknown, property: typeof bareLocalSym) => self is { [K in typeof bareLocalSym]: unknown; } (+1 overload)Checks whether a value has a given property key.
When to use
Use when you need a Predicate guard for property access on unknown
values with a simple structural object check.
Details
Uses the in operator and isObjectKeyword. This does not check property
value types.
Example (Guarding object properties)
import { Predicate } from "effect"
const hasName = Predicate.hasProperty("name")
const data: unknown = { name: "Ada" }
if (hasName(data)) {
console.log(data.name)
}
hasProperty(m: | AnyMethod
| AnyLocalMethod
| AnyDefaultMethod
m, const bareLocalSym: typeof bareLocalSymBrand marking the bare
local
value (used without ()): a valid
LocalMethod
whose element type is supplied by the service interface position in a
Tag
<Self, I>()
contract. Distinct from a called local<T>() so the contract can reject a bare local that has no
interface type to resolve from.
bareLocalSym),
);
const const tag: Context.ServiceClass<unknown, string, {
readonly [x: string]: never;
}> & {
[sharedTagSym]?: true | undefined;
[interfaceLocalsSym]?: true | undefined;
[kindSym]: string;
[readinessSym]: undefined;
[peersSym]: Context.Key<PeersId<unknown>, Record<string, PeerServiceOf<Spec>>>;
[selfNodeSym]: Context.Key<SelfNodeId<unknown>, string>;
[nodesSym]?: readonly AnyNode[] | undefined;
... 5 more ...;
[nodeSym]: NodeKey<...> | undefined;
}
tag = const buildInstanceTag: <unknown, Spec>(wireKey: string, key: string, spec: Spec, group: RpcGroupOf<Spec>, description: string | undefined, node: NodeKey<unknown> | undefined, kindOverride: string | undefined, interfaceLocalsMarker?: boolean, sharedMarker?: boolean) => Context.ServiceClass<unknown, string, {
readonly [x: string]: never;
}> & {
[sharedTagSym]?: true | undefined;
[interfaceLocalsSym]?: true | undefined;
[kindSym]: string;
[readinessSym]: undefined;
[peersSym]: Context.Key<...>;
... 7 more ...;
[nodeSym]: NodeKey<...> | undefined;
}
The single tag-creation primitive: dup-key guard + Context.Service + stow wireKey/spec/group.
Tag-creation primitive used by
makeTag
. key is Context identity; for solo tags
wireKey is the same string (RpcGroup prefix).
buildInstanceTag<unknown, Spec>(
key: stringkey,
key: stringkey,
spec: Specspec,
const retype: <RpcGroupOf<Spec>>(value: never) => RpcGroupOf<Spec>Retype through never (not any/unknown channels) at dynamic Effect/Rpc factories.
Same bridge as internal/nodeServerCommon.retype — kept local so this module does not
import server plumbing.
retype<type RpcGroupOf<S extends Spec> =
RpcGroup.RpcGroup<RpcUnionOf<S, "">>
The precisely-typed RPC contract group for a
Spec
. Carrying this exact type
(rather than a loose Rpc<string, …>) is what keeps the remote client's requirement
channel honest: concrete schemas declare never encoding/decoding services, so
RpcClient.make infers a real R (just the transport Protocol) instead of any.
RpcGroupOf<Spec>>(const buildRpcGroup: (
wireKey: string,
spec: FlatSpec
) => RpcGroup.RpcGroup<any>
Build the shared RPC contract group from a
Spec
, namespaced by wireKey. 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 wireKey.
buildRpcGroup(key: stringkey, const flat: FlatSpecflat) as never),
options: TagOptions & {
readonly node?: NodeKey<unknown>
readonly defaults?: DefaultsBag
}
options?.description?: string | undefineddescription,
options: TagOptions & {
readonly node?: NodeKey<unknown>
readonly defaults?: DefaultsBag
}
options?.node?: NodeKey<unknown>node,
options: TagOptions & {
readonly node?: NodeKey<unknown>
readonly defaults?: DefaultsBag
}
options?.kind?: string | undefinedkind,
const interfaceLocals: booleaninterfaceLocals,
);
return const applyTagDefaults: <
T extends PipeableTag,
D extends DefaultsBag
>(
tag: T,
bag: D | undefined
) => T | TagWithDefaults<T, D>
Apply
defaults
when a bag is present — factory { defaults } sugar helper.
applyTagDefaults(const tag: Context.ServiceClass<unknown, string, {
readonly [x: string]: never;
}> & {
[sharedTagSym]?: true | undefined;
[interfaceLocalsSym]?: true | undefined;
[kindSym]: string;
[readinessSym]: undefined;
[peersSym]: Context.Key<PeersId<unknown>, Record<string, PeerServiceOf<Spec>>>;
[selfNodeSym]: Context.Key<SelfNodeId<unknown>, string>;
[nodesSym]?: readonly AnyNode[] | undefined;
... 5 more ...;
[nodeSym]: NodeKey<...> | undefined;
}
tag, options: TagOptions & {
readonly node?: NodeKey<unknown>
readonly defaults?: DefaultsBag
}
options?.defaults?: DefaultsBagdefaults);
}
return function (local function) build(key: string, spec: Spec, options?: TagOptions & { readonly node?: NodeKey<unknown>; readonly defaults?: DefaultsBag }): (Context.ServiceClass<unknown, string, { readonly [x: string]: never }> & { [sharedTagSym]?: true | undefined; [interfaceLocalsSym]?: true | undefined; [kindSym]: string; [readinessSym]: undefined; [peersSym]: Context.Key<PeersId<unknown>, Record<string, PeerServiceOf<Spec>>>; [selfNodeSym]: Context.Key<SelfNodeId<unknown>, string>; [nodesSym]?: ReadonlyArray<AnyNode> | undefined; [wireKeySym]: string; description: string | undefined; [specSym]: FlatSpec; [groupSym]: RpcGroupOf<Spec>; [localCapSym]: Context.Key<Local<unknown>, { readonly granted: true }>; [nodeSym]: NodeKey<unknown> | undefined }) | TagWithDefaults<Context.ServiceClass<unknown, string, { readonly [x: string]: never }> & { [sharedTagSym]?: true | undefined; [interfaceLocalsSym]?: true | undefined; [kindSym]: string; [readinessSym]: undefined; [peersSym]: Context.Key<PeersId<unknown>, Record<string, PeerServiceOf<Spec>>>; [selfNodeSym]: Context.Key<SelfNodeId<unknown>, string>; [nodesSym]?: ReadonlyArray<AnyNode> | undefined; [wireKeySym]: string; description: string | undefined; [specSym]: FlatSpec; [groupSym]: RpcGroupOf<Spec>; [localCapSym]: Context.Key<Local<unknown>, { readonly granted: true }>; [nodeSym]: NodeKey<unknown> | undefined }, DefaultsBag>build;
} as never);