<Self, S extends Spec, HSelf>(
tag: NodeBoundTag<Self, S, HSelf> & {
readonly [nodeSym]: AddressedNode<HSelf>
}
): Layer.Layer<Self, ClientVerifyError>
<Self, S extends Spec, HSelf>(
tag: NodeBoundTag<Self, S, HSelf>
): Layer.Layer<Self, never, HSelf>
<Self, S extends Spec, HSelf>(
tag: HyperlinkTag<Self, S>,
node: AddressedNode<HSelf>
): Layer.Layer<Self, ClientVerifyError>
<Self, S extends Spec, HSelf>(
tag: HyperlinkTag<Self, S>,
node: NodeKey<HSelf>
): Layer.Layer<Self, never, HSelf>
<Self, S extends Spec>(tag: HyperlinkTag<Self, S>): Layer.Layer<
Self,
never,
RpcClient.Protocol
>The client layer for a resource: drive it over RPC as if it were local — the exact
same yield* Tag code as the local layer, only the provided layer differs, so it doesn't
matter where the resource actually runs.
Paths, by whether — and where — the tag names a Node:
- node-bearing + AddressedNode —
client(Hosted)when the tag's{ node }is dialable: auto-wires connect (R = never). Bare bound nodes still require the node service. - nodeless tag + AddressedNode —
client(tag, Worker)same auto-connect gate. - bare node —
client(tag, Bare)/ bare-boundclient(Hosted)still require the node; provide Node.connect(Bare, protocol)(or lookup / discoverClient) yourself. - nodeless tag, ambient transport — ambient
RpcClient.Protocol.
function function clientLayer<Self, S extends Spec, HSelf>(tag: NodeBoundTag<Self, S, HSelf> & {
readonly [nodeSym]: AddressedNode<HSelf>;
}): Layer.Layer<Self, ClientVerifyError> (+4 overloads)
The client layer for a resource: drive it over RPC as if it were local — the exact
same yield* Tag code as the local layer, only the provided layer differs, so it doesn't
matter where the resource actually runs.
Paths, by whether — and where — the tag names a
Node
:
- **node-bearing +
AddressedNode
** —
client(Hosted) when the tag's { node } is
dialable: auto-wires connect (R = never). Bare bound nodes still require the node service.
- **nodeless tag +
AddressedNode
** —
client(tag, Worker) same auto-connect gate.
- bare node —
client(tag, Bare) / bare-bound client(Hosted) still require the node;
provide
Node.connect
(Bare, protocol) (or lookup / discoverClient) yourself.
- nodeless tag, ambient transport — ambient
RpcClient.Protocol.
clientLayer<function (type parameter) Self in clientLayer<Self, S extends Spec, HSelf>(tag: NodeBoundTag<Self, S, HSelf> & {
readonly [nodeSym]: AddressedNode<HSelf>;
}): Layer.Layer<Self, ClientVerifyError>
Self, function (type parameter) S in clientLayer<Self, S extends Spec, HSelf>(tag: NodeBoundTag<Self, S, HSelf> & {
readonly [nodeSym]: AddressedNode<HSelf>;
}): Layer.Layer<Self, ClientVerifyError>
S extends Spec, function (type parameter) HSelf in clientLayer<Self, S extends Spec, HSelf>(tag: NodeBoundTag<Self, S, HSelf> & {
readonly [nodeSym]: AddressedNode<HSelf>;
}): Layer.Layer<Self, ClientVerifyError>
HSelf>(
tag: NodeBoundTag<Self, S, HSelf> & {
readonly [nodeSym]: AddressedNode<HSelf>
}
tag: 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 clientLayer<Self, S extends Spec, HSelf>(tag: NodeBoundTag<Self, S, HSelf> & {
readonly [nodeSym]: AddressedNode<HSelf>;
}): Layer.Layer<Self, ClientVerifyError>
Self, function (type parameter) S in clientLayer<Self, S extends Spec, HSelf>(tag: NodeBoundTag<Self, S, HSelf> & {
readonly [nodeSym]: AddressedNode<HSelf>;
}): Layer.Layer<Self, ClientVerifyError>
S, function (type parameter) HSelf in clientLayer<Self, S extends Spec, HSelf>(tag: NodeBoundTag<Self, S, HSelf> & {
readonly [nodeSym]: AddressedNode<HSelf>;
}): Layer.Layer<Self, ClientVerifyError>
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 clientLayer<Self, S extends Spec, HSelf>(tag: NodeBoundTag<Self, S, HSelf> & {
readonly [nodeSym]: AddressedNode<HSelf>;
}): Layer.Layer<Self, ClientVerifyError>
HSelf>;
},
): import LayerLayer.interface Layer<in ROut, out E = never, out RIn = never>A Layer describes how to build one or more services for dependency injection.
When to use
Use to model construction of application services for dependency injection,
especially when services have dependencies, can fail during construction, or
need scoped setup and release.
Details
A Layer<ROut, E, RIn> represents ROut as the services this layer
provides, E as the possible errors during layer construction, and RIn as
the services this layer requires as dependencies.
Layer<function (type parameter) Self in clientLayer<Self, S extends Spec, HSelf>(tag: NodeBoundTag<Self, S, HSelf> & {
readonly [nodeSym]: AddressedNode<HSelf>;
}): Layer.Layer<Self, ClientVerifyError>
Self, type ClientVerifyError = anyErrors default-on / deep client verify may surface on addressed client Layers.
ClientVerifyError>;
function function clientLayer<Self, S extends Spec, HSelf>(tag: NodeBoundTag<Self, S, HSelf>): Layer.Layer<Self, never, HSelf> (+4 overloads)The client layer for a resource: drive it over RPC as if it were local — the exact
same yield* Tag code as the local layer, only the provided layer differs, so it doesn't
matter where the resource actually runs.
Paths, by whether — and where — the tag names a
Node
:
- **node-bearing +
AddressedNode
** —
client(Hosted) when the tag's { node } is
dialable: auto-wires connect (R = never). Bare bound nodes still require the node service.
- **nodeless tag +
AddressedNode
** —
client(tag, Worker) same auto-connect gate.
- bare node —
client(tag, Bare) / bare-bound client(Hosted) still require the node;
provide
Node.connect
(Bare, protocol) (or lookup / discoverClient) yourself.
- nodeless tag, ambient transport — ambient
RpcClient.Protocol.
clientLayer<function (type parameter) Self in clientLayer<Self, S extends Spec, HSelf>(tag: NodeBoundTag<Self, S, HSelf>): Layer.Layer<Self, never, HSelf>Self, function (type parameter) S in clientLayer<Self, S extends Spec, HSelf>(tag: NodeBoundTag<Self, S, HSelf>): Layer.Layer<Self, never, HSelf>S extends Spec, function (type parameter) HSelf in clientLayer<Self, S extends Spec, HSelf>(tag: NodeBoundTag<Self, S, HSelf>): Layer.Layer<Self, never, HSelf>HSelf>(
tag: NodeBoundTag<Self, S, HSelf>(parameter) tag: {
groupId: string;
description: string | undefined;
key: Identifier;
of: (this: void, self: 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…;
context: (self: 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<AsMethod<S[…;
use: (f: (service: 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<AsMe…;
useSync: (f: (service: 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<AsMe…;
Identifier: Identifier;
Service: Shape;
stack: string | undefined;
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; <…;
toString: () => string;
toJSON: () => unknown;
}
tag: 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 clientLayer<Self, S extends Spec, HSelf>(tag: NodeBoundTag<Self, S, HSelf>): Layer.Layer<Self, never, HSelf>Self, function (type parameter) S in clientLayer<Self, S extends Spec, HSelf>(tag: NodeBoundTag<Self, S, HSelf>): Layer.Layer<Self, never, HSelf>S, function (type parameter) HSelf in clientLayer<Self, S extends Spec, HSelf>(tag: NodeBoundTag<Self, S, HSelf>): Layer.Layer<Self, never, HSelf>HSelf>,
): import LayerLayer.interface Layer<in ROut, out E = never, out RIn = never>A Layer describes how to build one or more services for dependency injection.
When to use
Use to model construction of application services for dependency injection,
especially when services have dependencies, can fail during construction, or
need scoped setup and release.
Details
A Layer<ROut, E, RIn> represents ROut as the services this layer
provides, E as the possible errors during layer construction, and RIn as
the services this layer requires as dependencies.
Layer<function (type parameter) Self in clientLayer<Self, S extends Spec, HSelf>(tag: NodeBoundTag<Self, S, HSelf>): Layer.Layer<Self, never, HSelf>Self, never, function (type parameter) HSelf in clientLayer<Self, S extends Spec, HSelf>(tag: NodeBoundTag<Self, S, HSelf>): Layer.Layer<Self, never, HSelf>HSelf>;
function function clientLayer<Self, S extends Spec, HSelf>(tag: HyperlinkTag<Self, S>, node: AddressedNode<HSelf>): Layer.Layer<Self, ClientVerifyError> (+4 overloads)The client layer for a resource: drive it over RPC as if it were local — the exact
same yield* Tag code as the local layer, only the provided layer differs, so it doesn't
matter where the resource actually runs.
Paths, by whether — and where — the tag names a
Node
:
- **node-bearing +
AddressedNode
** —
client(Hosted) when the tag's { node } is
dialable: auto-wires connect (R = never). Bare bound nodes still require the node service.
- **nodeless tag +
AddressedNode
** —
client(tag, Worker) same auto-connect gate.
- bare node —
client(tag, Bare) / bare-bound client(Hosted) still require the node;
provide
Node.connect
(Bare, protocol) (or lookup / discoverClient) yourself.
- nodeless tag, ambient transport — ambient
RpcClient.Protocol.
clientLayer<function (type parameter) Self in clientLayer<Self, S extends Spec, HSelf>(tag: HyperlinkTag<Self, S>, node: AddressedNode<HSelf>): Layer.Layer<Self, ClientVerifyError>Self, function (type parameter) S in clientLayer<Self, S extends Spec, HSelf>(tag: HyperlinkTag<Self, S>, node: AddressedNode<HSelf>): Layer.Layer<Self, ClientVerifyError>S extends Spec, function (type parameter) HSelf in clientLayer<Self, S extends Spec, HSelf>(tag: HyperlinkTag<Self, S>, node: AddressedNode<HSelf>): Layer.Layer<Self, ClientVerifyError>HSelf>(
tag: HyperlinkTag<Self, S>(parameter) tag: {
groupId: string;
description: string | undefined;
key: Identifier;
of: (this: void, self: 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…;
context: (self: 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<AsMethod<S[…;
use: (f: (service: 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<AsMe…;
useSync: (f: (service: 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<AsMe…;
Identifier: Identifier;
Service: Shape;
stack: string | undefined;
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; <…;
toString: () => string;
toJSON: () => unknown;
}
tag: 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 clientLayer<Self, S extends Spec, HSelf>(tag: HyperlinkTag<Self, S>, node: AddressedNode<HSelf>): Layer.Layer<Self, ClientVerifyError>Self, function (type parameter) S in clientLayer<Self, S extends Spec, HSelf>(tag: HyperlinkTag<Self, S>, node: AddressedNode<HSelf>): Layer.Layer<Self, ClientVerifyError>S>,
node: AddressedNode<HSelf>node: import AddressedNodeAddressedNode<function (type parameter) HSelf in clientLayer<Self, S extends Spec, HSelf>(tag: HyperlinkTag<Self, S>, node: AddressedNode<HSelf>): Layer.Layer<Self, ClientVerifyError>HSelf>,
): import LayerLayer.interface Layer<in ROut, out E = never, out RIn = never>A Layer describes how to build one or more services for dependency injection.
When to use
Use to model construction of application services for dependency injection,
especially when services have dependencies, can fail during construction, or
need scoped setup and release.
Details
A Layer<ROut, E, RIn> represents ROut as the services this layer
provides, E as the possible errors during layer construction, and RIn as
the services this layer requires as dependencies.
Layer<function (type parameter) Self in clientLayer<Self, S extends Spec, HSelf>(tag: HyperlinkTag<Self, S>, node: AddressedNode<HSelf>): Layer.Layer<Self, ClientVerifyError>Self, type ClientVerifyError = anyErrors default-on / deep client verify may surface on addressed client Layers.
ClientVerifyError>;
function function clientLayer<Self, S extends Spec, HSelf>(tag: HyperlinkTag<Self, S>, node: NodeKey<HSelf>): Layer.Layer<Self, never, HSelf> (+4 overloads)The client layer for a resource: drive it over RPC as if it were local — the exact
same yield* Tag code as the local layer, only the provided layer differs, so it doesn't
matter where the resource actually runs.
Paths, by whether — and where — the tag names a
Node
:
- **node-bearing +
AddressedNode
** —
client(Hosted) when the tag's { node } is
dialable: auto-wires connect (R = never). Bare bound nodes still require the node service.
- **nodeless tag +
AddressedNode
** —
client(tag, Worker) same auto-connect gate.
- bare node —
client(tag, Bare) / bare-bound client(Hosted) still require the node;
provide
Node.connect
(Bare, protocol) (or lookup / discoverClient) yourself.
- nodeless tag, ambient transport — ambient
RpcClient.Protocol.
clientLayer<function (type parameter) Self in clientLayer<Self, S extends Spec, HSelf>(tag: HyperlinkTag<Self, S>, node: NodeKey<HSelf>): Layer.Layer<Self, never, HSelf>Self, function (type parameter) S in clientLayer<Self, S extends Spec, HSelf>(tag: HyperlinkTag<Self, S>, node: NodeKey<HSelf>): Layer.Layer<Self, never, HSelf>S extends Spec, function (type parameter) HSelf in clientLayer<Self, S extends Spec, HSelf>(tag: HyperlinkTag<Self, S>, node: NodeKey<HSelf>): Layer.Layer<Self, never, HSelf>HSelf>(
tag: HyperlinkTag<Self, S>(parameter) tag: {
groupId: string;
description: string | undefined;
key: Identifier;
of: (this: void, self: 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…;
context: (self: 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<AsMethod<S[…;
use: (f: (service: 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<AsMe…;
useSync: (f: (service: 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<AsMe…;
Identifier: Identifier;
Service: Shape;
stack: string | undefined;
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; <…;
toString: () => string;
toJSON: () => unknown;
}
tag: 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 clientLayer<Self, S extends Spec, HSelf>(tag: HyperlinkTag<Self, S>, node: NodeKey<HSelf>): Layer.Layer<Self, never, HSelf>Self, function (type parameter) S in clientLayer<Self, S extends Spec, HSelf>(tag: HyperlinkTag<Self, S>, node: NodeKey<HSelf>): Layer.Layer<Self, never, HSelf>S>,
node: NodeKey<HSelf>node: import NodeKeyNodeKey<function (type parameter) HSelf in clientLayer<Self, S extends Spec, HSelf>(tag: HyperlinkTag<Self, S>, node: NodeKey<HSelf>): Layer.Layer<Self, never, HSelf>HSelf>,
): import LayerLayer.interface Layer<in ROut, out E = never, out RIn = never>A Layer describes how to build one or more services for dependency injection.
When to use
Use to model construction of application services for dependency injection,
especially when services have dependencies, can fail during construction, or
need scoped setup and release.
Details
A Layer<ROut, E, RIn> represents ROut as the services this layer
provides, E as the possible errors during layer construction, and RIn as
the services this layer requires as dependencies.
Layer<function (type parameter) Self in clientLayer<Self, S extends Spec, HSelf>(tag: HyperlinkTag<Self, S>, node: NodeKey<HSelf>): Layer.Layer<Self, never, HSelf>Self, never, function (type parameter) HSelf in clientLayer<Self, S extends Spec, HSelf>(tag: HyperlinkTag<Self, S>, node: NodeKey<HSelf>): Layer.Layer<Self, never, HSelf>HSelf>;
function function clientLayer<Self, S extends Spec>(tag: HyperlinkTag<Self, S>): Layer.Layer<Self, never, RpcClient.Protocol> (+4 overloads)The client layer for a resource: drive it over RPC as if it were local — the exact
same yield* Tag code as the local layer, only the provided layer differs, so it doesn't
matter where the resource actually runs.
Paths, by whether — and where — the tag names a
Node
:
- **node-bearing +
AddressedNode
** —
client(Hosted) when the tag's { node } is
dialable: auto-wires connect (R = never). Bare bound nodes still require the node service.
- **nodeless tag +
AddressedNode
** —
client(tag, Worker) same auto-connect gate.
- bare node —
client(tag, Bare) / bare-bound client(Hosted) still require the node;
provide
Node.connect
(Bare, protocol) (or lookup / discoverClient) yourself.
- nodeless tag, ambient transport — ambient
RpcClient.Protocol.
clientLayer<function (type parameter) Self in clientLayer<Self, S extends Spec>(tag: HyperlinkTag<Self, S>): Layer.Layer<Self, never, RpcClient.Protocol>Self, function (type parameter) S in clientLayer<Self, S extends Spec>(tag: HyperlinkTag<Self, S>): Layer.Layer<Self, never, RpcClient.Protocol>S extends Spec>(
tag: HyperlinkTag<Self, S>(parameter) tag: {
groupId: string;
description: string | undefined;
key: Identifier;
of: (this: void, self: 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…;
context: (self: 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<AsMethod<S[…;
use: (f: (service: 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<AsMe…;
useSync: (f: (service: 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<AsMe…;
Identifier: Identifier;
Service: Shape;
stack: string | undefined;
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; <…;
toString: () => string;
toJSON: () => unknown;
}
tag: 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 clientLayer<Self, S extends Spec>(tag: HyperlinkTag<Self, S>): Layer.Layer<Self, never, RpcClient.Protocol>Self, function (type parameter) S in clientLayer<Self, S extends Spec>(tag: HyperlinkTag<Self, S>): Layer.Layer<Self, never, RpcClient.Protocol>S>,
): import LayerLayer.interface Layer<in ROut, out E = never, out RIn = never>A Layer describes how to build one or more services for dependency injection.
When to use
Use to model construction of application services for dependency injection,
especially when services have dependencies, can fail during construction, or
need scoped setup and release.
Details
A Layer<ROut, E, RIn> represents ROut as the services this layer
provides, E as the possible errors during layer construction, and RIn as
the services this layer requires as dependencies.
Layer<function (type parameter) Self in clientLayer<Self, S extends Spec>(tag: HyperlinkTag<Self, S>): Layer.Layer<Self, never, RpcClient.Protocol>Self, never, import RpcClientRpcClient.class Protocolclass Protocol {
key: Identifier;
Service: {
run: (clientId: number, f: (data: FromServerEncoded) => Effect.Effect<void>) => Effect.Effect<never>;
send: (clientId: number, request: FromClientEncoded, transferables?: ReadonlyArray<globalThis.Transferable>) => Effect.Effect<void, RpcClientError>;
supportsAck: boolean;
supportsTransferables: boolean;
};
}
Defines the service interface for an RPC client transport, responsible for running the
receive loop and sending encoded client messages.
When to use
Use to provide the transport boundary for RPC clients over HTTP, WebSocket,
workers, sockets, or custom protocols.
Protocol>;
function function clientLayer<Self, S extends Spec, HSelf>(tag: NodeBoundTag<Self, S, HSelf> & {
readonly [nodeSym]: AddressedNode<HSelf>;
}): Layer.Layer<Self, ClientVerifyError> (+4 overloads)
The client layer for a resource: drive it over RPC as if it were local — the exact
same yield* Tag code as the local layer, only the provided layer differs, so it doesn't
matter where the resource actually runs.
Paths, by whether — and where — the tag names a
Node
:
- **node-bearing +
AddressedNode
** —
client(Hosted) when the tag's { node } is
dialable: auto-wires connect (R = never). Bare bound nodes still require the node service.
- **nodeless tag +
AddressedNode
** —
client(tag, Worker) same auto-connect gate.
- bare node —
client(tag, Bare) / bare-bound client(Hosted) still require the node;
provide
Node.connect
(Bare, protocol) (or lookup / discoverClient) yourself.
- nodeless tag, ambient transport — ambient
RpcClient.Protocol.
clientLayer<function (type parameter) Self in clientLayer<Self, S extends Spec>(tag: HyperlinkTag<Self, S>, node?: NodeKey<unknown>): Layer.Layer<Self, ClientVerifyError, RpcClient.Protocol>Self, function (type parameter) S in clientLayer<Self, S extends Spec>(tag: HyperlinkTag<Self, S>, node?: NodeKey<unknown>): Layer.Layer<Self, ClientVerifyError, RpcClient.Protocol>S extends Spec>(
tag: HyperlinkTag<Self, S>(parameter) tag: {
groupId: string;
description: string | undefined;
key: Identifier;
of: (this: void, self: 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…;
context: (self: 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<AsMethod<S[…;
use: (f: (service: 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<AsMe…;
useSync: (f: (service: 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<AsMe…;
Identifier: Identifier;
Service: Shape;
stack: string | undefined;
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; <…;
toString: () => string;
toJSON: () => unknown;
}
tag: 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 clientLayer<Self, S extends Spec>(tag: HyperlinkTag<Self, S>, node?: NodeKey<unknown>): Layer.Layer<Self, ClientVerifyError, RpcClient.Protocol>Self, function (type parameter) S in clientLayer<Self, S extends Spec>(tag: HyperlinkTag<Self, S>, node?: NodeKey<unknown>): Layer.Layer<Self, ClientVerifyError, RpcClient.Protocol>S>,
node: anynode?: import NodeKeyNodeKey<unknown>,
): import LayerLayer.interface Layer<in ROut, out E = never, out RIn = never>A Layer describes how to build one or more services for dependency injection.
When to use
Use to model construction of application services for dependency injection,
especially when services have dependencies, can fail during construction, or
need scoped setup and release.
Details
A Layer<ROut, E, RIn> represents ROut as the services this layer
provides, E as the possible errors during layer construction, and RIn as
the services this layer requires as dependencies.
Layer<function (type parameter) Self in clientLayer<Self, S extends Spec>(tag: HyperlinkTag<Self, S>, node?: NodeKey<unknown>): Layer.Layer<Self, ClientVerifyError, RpcClient.Protocol>Self, type ClientVerifyError = anyErrors default-on / deep client verify may surface on addressed client Layers.
ClientVerifyError, import RpcClientRpcClient.class Protocolclass Protocol {
key: Identifier;
Service: {
run: (clientId: number, f: (data: FromServerEncoded) => Effect.Effect<void>) => Effect.Effect<never>;
send: (clientId: number, request: FromClientEncoded, transferables?: ReadonlyArray<globalThis.Transferable>) => Effect.Effect<void, RpcClientError>;
supportsAck: boolean;
supportsTransferables: boolean;
};
}
Defines the service interface for an RPC client transport, responsible for running the
receive loop and sending encoded client messages.
When to use
Use to provide the transport boundary for RPC clients over HTTP, WebSocket,
workers, sockets, or custom protocols.
Protocol> {
const const group: RpcGroupOf<S>const group: {
requests: ReadonlyMap<string, R>;
annotations: Context.Context<never>;
add: (...rpcs: Rpcs2) => RpcGroup.RpcGroup<RpcUnionOf<S, ''> | Rpcs2[number]>;
merge: (...groups: Groups) => RpcGroup.RpcGroup<RpcUnionOf<S, ''> | RpcGroup.Rpcs<Groups[number]>>;
omit: (...tags: Tags) => RpcGroup.RpcGroup<Exclude<RpcUnionOf<S, ''>, { readonly _tag: Tags[number] }>>;
middleware: (middleware: M) => RpcGroup.RpcGroup<Rpc.AddMiddleware<RpcUnionOf<S, ''>, M>>;
prefix: (prefix: Prefix) => RpcGroup.RpcGroup<Rpc.Prefixed<RpcUnionOf<S, ''>, Prefix>>;
toHandlers: (build: Handlers | Effect.Effect<Handlers, EX, RX>) => Effect.Effect<Context.Context<Rpc.ToHandler<RpcUnionOf<S, ''>>>, EX, RX | RpcGroup.HandlersServices<RpcUnionOf<S, ''>, Handlers>>;
toLayer: (build: Handlers | Effect.Effect<Handlers, EX, RX>) => Layer.Layer<Rpc.ToHandler<RpcUnionOf<S, ''>>, EX, Exclude<RX, Scope.Scope> | RpcGroup.HandlersServices<RpcUnionOf<S, ''>, 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> | RpcGroup.HandlerServices<RpcUnionOf<S, ''>, Tag, Handler>>;
accessHandler: (tag: Tag) => Effect.Effect<(payload: Rpc.Payload<Extract<RpcUnionOf<S, ''>, { readonly _tag: Tag }>>, options: { readonly client: Rpc.ServerClient; readonly requestId: RequestId; readonly headers: Headers.Headers }) => Rpc.ResultFrom<Extr…;
annotate: (service: Context.Key<I, S>, value: S) => RpcGroup.RpcGroup<RpcUnionOf<S, ''>>;
annotateRpcs: (service: Context.Key<I, S>, value: S) => RpcGroup.RpcGroup<RpcUnionOf<S, ''>>;
annotateMerge: (annotations: Context.Context<S>) => RpcGroup.RpcGroup<RpcUnionOf<S, ''>>;
annotateRpcsMerge: (annotations: Context.Context<S>) => RpcGroup.RpcGroup<RpcUnionOf<S, ''>>;
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 = tag: HyperlinkTag<Self, S>(parameter) tag: {
groupId: string;
description: string | undefined;
key: Identifier;
of: (this: void, self: 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…;
context: (self: 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<AsMethod<S[…;
use: (f: (service: 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<AsMe…;
useSync: (f: (service: 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<AsMe…;
Identifier: Identifier;
Service: Shape;
stack: string | undefined;
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; <…;
toString: () => string;
toJSON: () => unknown;
}
tag[const groupSym: typeof groupSymWhere the built RPC group is stowed on a Tag.
groupSym];
// an explicit `node` (for a nodeless tag) wins; otherwise the tag's own node, if any.
const const nodeKey: anynodeKey = node: anynode ?? tag: HyperlinkTag<Self, S>(parameter) tag: {
groupId: string;
description: string | undefined;
key: Identifier;
of: (this: void, self: 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…;
context: (self: 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<AsMethod<S[…;
use: (f: (service: 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<AsMe…;
useSync: (f: (service: 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<AsMe…;
Identifier: Identifier;
Service: Shape;
stack: string | undefined;
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; <…;
toString: () => string;
toJSON: () => unknown;
}
tag[const nodeSym: typeof nodeSymWhere the resource's
Node
(if any) is stowed on a Tag.
nodeSym];
// no node anywhere: take the transport from the ambient `RpcClient.Protocol`.
// `serviceOption` so a missing protocol surfaces as {@link MissingClientProtocol} (not Effect's
// opaque "Service not found" die). Typed as `E = never` like before — this replaces a defect,
// not a channel that callers already handled; Protocol stays required in `R`.
if (const nodeKey: anynodeKey === var undefinedundefined) {
return import LayerLayer.const effect: <Self, 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<AsMethod<S[K]>> : S[K] extends {
readonly _tag: "ref";
} ? Subscribable<SuccessOf<AsMethod<S[K]>>> : S[K] extends {
readonly kind: MethodKind;
} ? ClientMethod<...> : S[K] extends Spec ? Simplify<...> : never; }>, MissingClientProtocol, Scope.Scope>(service: Context.Key<...>, effect: Effect.Effect<...>) => Layer.Layer<...> (+1 overload)
Constructs a layer from an effect that produces a single service.
When to use
Use when you need to construct a Layer-provided service with an Effect,
dependencies, or scoped resource acquisition.
Details
This allows you to create a Layer from an Effect that produces a service.
The Effect is executed in the scope of the layer, allowing for proper
resource management.
Example (Creating a layer from an effect)
import { Context, Effect, Layer } from "effect"
class Database extends Context.Service<Database, {
readonly query: (sql: string) => Effect.Effect<string>
}>()("Database") {}
const layer = Layer.effect(Database,
Effect.sync(() => ({
query: (sql: string) => Effect.succeed(`Query: ${sql}`)
}))
)
effect(
tag: HyperlinkTag<Self, S>(parameter) tag: {
groupId: string;
description: string | undefined;
key: Identifier;
of: (this: void, self: 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…;
context: (self: 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<AsMethod<S[…;
use: (f: (service: 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<AsMe…;
useSync: (f: (service: 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<AsMe…;
Identifier: Identifier;
Service: Shape;
stack: string | undefined;
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; <…;
toString: () => string;
toJSON: () => unknown;
}
tag,
import EffectEffect.const gen: <Effect.Effect<never, MissingClientProtocol, never> | Effect.Effect<Option.Option<{
readonly run: (clientId: number, f: (data: FromServerEncoded) => Effect.Effect<void>) => Effect.Effect<never>;
readonly send: (clientId: number, request: FromClientEncoded, transferables?: ReadonlyArray<globalThis.Transferable>) => Effect.Effect<void, RpcClientError>;
readonly supportsAck: boolean;
readonly supportsTransferables: boolean;
}>, never, never> | Effect.Effect<...> | Effect.Effect<...>, Simplify<...>>(f: () => Generator<...>) => Effect.Effect<...> (+1 overload)
Provides a way to write effectful code using generator functions, simplifying
control flow and error handling.
When to use
Use when you want to write effectful code that looks and behaves like
synchronous code, while still handling asynchronous tasks, errors, and complex
control flow such as loops and conditions.
Generator functions work similarly to async/await but keep errors,
requirements, and interruption in the Effect type. You can yield* values
from effects and return the final result at the end.
Example (Sequencing effects with generators)
import { Data, Effect } from "effect"
class DiscountRateError extends Data.TaggedError("DiscountRateError")<{}> {}
const addServiceCharge = (amount: number) => amount + 1
const applyDiscount = (
total: number,
discountRate: number
): Effect.Effect<number, DiscountRateError> =>
discountRate === 0
? Effect.fail(new DiscountRateError())
: Effect.succeed(total - (total * discountRate) / 100)
const fetchTransactionAmount = Effect.promise(() => Promise.resolve(100))
const fetchDiscountRate = Effect.promise(() => Promise.resolve(5))
export const program = Effect.gen(function*() {
const transactionAmount = yield* fetchTransactionAmount
const discountRate = yield* fetchDiscountRate
const discountedAmount = yield* applyDiscount(
transactionAmount,
discountRate
)
const finalAmount = addServiceCharge(discountedAmount)
return `Final amount to charge: ${finalAmount}`
})
gen(function* () {
const const protocol: Option.Option<{
readonly run: (
clientId: number,
f: (
data: FromServerEncoded
) => Effect.Effect<void>
) => Effect.Effect<never>
readonly send: (
clientId: number,
request: FromClientEncoded,
transferables?: ReadonlyArray<globalThis.Transferable>
) => Effect.Effect<void, RpcClientError>
readonly supportsAck: boolean
readonly supportsTransferables: boolean
}>
protocol = yield* import EffectEffect.const serviceOption: <RpcClient.Protocol, {
readonly run: (clientId: number, f: (data: FromServerEncoded) => Effect.Effect<void>) => Effect.Effect<never>;
readonly send: (clientId: number, request: FromClientEncoded, transferables?: ReadonlyArray<globalThis.Transferable>) => Effect.Effect<void, RpcClientError>;
readonly supportsAck: boolean;
readonly supportsTransferables: boolean;
}>(key: Context.Key<RpcClient.Protocol, {
readonly run: (clientId: number, f: (data: FromServerEncoded) => Effect.Effect<void>) => Effect.Effect<never>;
readonly send: (clientId: number, request: FromClientEncoded, transferables?: ReadonlyArray<globalThis.Transferable>) => Effect.Effect<void, RpcClientError>;
readonly supportsAck: boolean;
readonly supportsTransferables: boolean;
}>) => Effect.Effect<...>
Optionally accesses a service from the environment.
When to use
Use to read an optional dependency from the current context without making
that dependency part of the effect's required environment.
Details
This function attempts to access a service from the environment. If the
service is available, it returns Some(service). If the service is not
available, it returns None. Unlike service, this function does not
require the service to be present in the environment.
Example (Accessing an optional service)
import { Context, Effect, Option } from "effect"
// Define a service key
const Logger = Context.Service<{
log: (msg: string) => void
}>("Logger")
// Use serviceOption to optionally access the logger
const program = Effect.gen(function*() {
const maybeLogger = yield* Effect.serviceOption(Logger)
if (Option.isSome(maybeLogger)) {
maybeLogger.value.log("Service is available")
} else {
console.log("Service not available")
}
})
serviceOption(import RpcClientRpcClient.class Protocolclass Protocol {
key: Identifier;
Service: {
run: (clientId: number, f: (data: FromServerEncoded) => Effect.Effect<void>) => Effect.Effect<never>;
send: (clientId: number, request: FromClientEncoded, transferables?: ReadonlyArray<globalThis.Transferable>) => Effect.Effect<void, RpcClientError>;
supportsAck: boolean;
supportsTransferables: boolean;
};
make: <EX, RX>(f: (write: (clientId: number, response: FromServerEncoded) => Effect.Effect<void>, clientIds: ReadonlySet<number>) => Effect.Effect<Omit<RpcClient.Protocol['Service'], 'run'>, EX, RX>) => Effect.Effect<RpcClient.Protocol['Service'…;
of: (this: void, self: { readonly run: (clientId: number, f: (data: FromServerEncoded) => Effect.Effect<void>) => Effect.Effect<never>; readonly send: (clientId: number, request: FromClientEncoded, transferables?: ReadonlyArray<globalThis.Tran…;
context: (self: { readonly run: (clientId: number, f: (data: FromServerEncoded) => Effect.Effect<void>) => Effect.Effect<never>; readonly send: (clientId: number, request: FromClientEncoded, transferables?: ReadonlyArray<globalThis.Transferable>) =…;
use: (f: (service: { readonly run: (clientId: number, f: (data: FromServerEncoded) => Effect.Effect<void>) => Effect.Effect<never>; readonly send: (clientId: number, request: FromClientEncoded, transferables?: ReadonlyArray<globalThis.Transfera…;
useSync: (f: (service: { readonly run: (clientId: number, f: (data: FromServerEncoded) => Effect.Effect<void>) => Effect.Effect<never>; readonly send: (clientId: number, request: FromClientEncoded, transferables?: ReadonlyArray<globalThis.Transfera…;
Identifier: Identifier;
stack: string | undefined;
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; <…;
toString: () => string;
toJSON: () => unknown;
}
Defines the service interface for an RPC client transport, responsible for running the
receive loop and sending encoded client messages.
When to use
Use to provide the transport boundary for RPC clients over HTTP, WebSocket,
workers, sockets, or custom protocols.
Protocol);
if (import OptionOption.const isNone: <{
readonly run: (clientId: number, f: (data: FromServerEncoded) => Effect.Effect<void>) => Effect.Effect<never>;
readonly send: (clientId: number, request: FromClientEncoded, transferables?: ReadonlyArray<globalThis.Transferable>) => Effect.Effect<void, RpcClientError>;
readonly supportsAck: boolean;
readonly supportsTransferables: boolean;
}>(self: Option.Option<{
readonly run: (clientId: number, f: (data: FromServerEncoded) => Effect.Effect<void>) => Effect.Effect<never>;
readonly send: (clientId: number, request: FromClientEncoded, transferables?: ReadonlyArray<globalThis.Transferable>) => Effect.Effect<void, RpcClientError>;
readonly supportsAck: boolean;
readonly supportsTransferables: boolean;
}>) => self is Option.None<...>
Checks whether an Option is None (absent).
When to use
Use when you need to branch on an absent Option before accessing .value.
Details
- Acts as a type guard, narrowing to
None<A>
Example (Checking for None)
import { Option } from "effect"
console.log(Option.isNone(Option.some(1)))
// Output: false
console.log(Option.isNone(Option.none()))
// Output: true
isNone(const protocol: Option.Option<{
readonly run: (
clientId: number,
f: (
data: FromServerEncoded
) => Effect.Effect<void>
) => Effect.Effect<never>
readonly send: (
clientId: number,
request: FromClientEncoded,
transferables?: ReadonlyArray<globalThis.Transferable>
) => Effect.Effect<void, RpcClientError>
readonly supportsAck: boolean
readonly supportsTransferables: boolean
}>
protocol)) {
return yield* new constructor MissingClientProtocol<{
readonly resource: string;
}>(args: {
readonly resource: string;
}): MissingClientProtocol
A nodeless
Hyperlink.client
(tag) was built with no ambient
RpcClient.Protocol
.
Replaces Effect's opaque "Service not found: …/Protocol" die with a remediation message naming
the three ways to connect. The Layer still requires RpcClient.Protocol in R (compile-time)
and keeps E = never (this replaces a defect, not a typed channel callers already matched);
catch via Exit / _tag when probing an unsatisfied build.
MissingClientProtocol({ resource: stringresource: tag: HyperlinkTag<Self, S>(parameter) tag: {
groupId: string;
description: string | undefined;
key: Identifier;
of: (this: void, self: 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…;
context: (self: 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<AsMethod<S[…;
use: (f: (service: 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<AsMe…;
useSync: (f: (service: 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<AsMe…;
Identifier: Identifier;
Service: Shape;
stack: string | undefined;
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; <…;
toString: () => string;
toJSON: () => unknown;
}
tag.ServiceClass<Self, string, Simplify<{ readonly [K in keyof S]: S[K] extends FromLocalMethod<infer M> ? InjectLocal<M, Self> : S[K] extends LocalMethod<...> ? LocalEffect<...> : S[K] extends { ...; } ? SuccessOf<...> : S[K] extends { ...; } ? Subscribable<...> : S[K] extends { ...; } ? ClientMethod<...> : S[K] extends Spec ? Simplify<...> : never; }>>.key: stringkey });
}
const const client: {
[K in keyof RpcClient.RpcClient.From<
RpcUnionOf<S, "">,
RpcClientError
>]: RpcClient.RpcClient.From<
RpcUnionOf<S, "">,
RpcClientError
>[K]
}
client = yield* import EffectEffect.const provideService: <{ [K in keyof RpcClient.RpcClient<Rpcs extends Rpc.Any, E = never>.From<RpcUnionOf<S, "">, RpcClientError>]: RpcClient.RpcClient.From<RpcUnionOf<S, "">, RpcClientError>[K]; }, never, RpcClient.Protocol | Scope.Scope | Rpc.MiddlewareClient<RpcUnionOf<S, "">>, RpcClient.Protocol, {
readonly run: (clientId: number, f: (data: FromServerEncoded) => Effect.Effect<void>) => Effect.Effect<never>;
readonly send: (clientId: number, request: FromClientEncoded, transferables?: ReadonlyArray<globalThis.Transferable>) => Effect.Effect<void, RpcClientError>;
readonly supportsAck: boolean;
readonly supportsTransferables: boolean;
}>(self: Effect.Effect<...>, service: Context.Key<...>, implementation: {
readonly run: (clientId: number, f: (data: FromServerEncoded) => Effect.Effect<void>) => Effect.Effect<never>;
readonly send: (clientId: number, request: FromClientEncoded, transferables?: ReadonlyArray<globalThis.Transferable>) => Effect.Effect<void, RpcClientError>;
readonly supportsAck: boolean;
readonly supportsTransferables: boolean;
}) => Effect.Effect<...> (+2 overloads)
Provides one concrete service implementation to an effect.
When to use
Use to satisfy one service requirement with an already-built implementation.
Details
The service requirement identified by the Context.Key is removed from the
effect requirements after the implementation is provided.
Example (Providing a service value)
import { Console, Context, Effect } from "effect"
// Define a service for configuration
const Config = Context.Service<{
apiUrl: string
timeout: number
}>("Config")
const fetchData = Effect.gen(function*() {
const config = yield* Effect.service(Config)
yield* Console.log(`Fetching from: ${config.apiUrl}`)
yield* Console.log(`Timeout: ${config.timeout}ms`)
return "data"
})
// Provide the service implementation
const program = Effect.provideService(fetchData, Config, {
apiUrl: "https://api.example.com",
timeout: 5000
})
Effect.runPromise(program).then(console.log)
// Output:
// Fetching from: https://api.example.com
// Timeout: 5000ms
// data
provideService(
import RpcClientRpcClient.const make: <RpcUnionOf<S, "">, false>(group: RpcGroup.RpcGroup<RpcUnionOf<S, "">>, options?: {
readonly spanPrefix?: string | undefined;
readonly spanAttributes?: Record<string, unknown> | undefined;
readonly generateRequestId?: (() => RequestId) | undefined;
readonly disableTracing?: boolean | undefined;
readonly flatten?: false | undefined;
} | undefined) => Effect.Effect<{ [K in keyof RpcClient.RpcClient<Rpcs extends Rpc.Any, E = never>.From<RpcUnionOf<S, "">, RpcClientError>]: RpcClient.RpcClient.From<...>[K]; }, never, RpcClient.Protocol | ... 1 more ... | Rpc.MiddlewareClient<...>>
Creates a schema-aware RPC client for a group using the current client
Protocol, encoding requests and decoding server responses.
make(const group: RpcGroupOf<S>const group: {
requests: ReadonlyMap<string, R>;
annotations: Context.Context<never>;
add: (...rpcs: Rpcs2) => RpcGroup.RpcGroup<RpcUnionOf<S, ''> | Rpcs2[number]>;
merge: (...groups: Groups) => RpcGroup.RpcGroup<RpcUnionOf<S, ''> | RpcGroup.Rpcs<Groups[number]>>;
omit: (...tags: Tags) => RpcGroup.RpcGroup<Exclude<RpcUnionOf<S, ''>, { readonly _tag: Tags[number] }>>;
middleware: (middleware: M) => RpcGroup.RpcGroup<Rpc.AddMiddleware<RpcUnionOf<S, ''>, M>>;
prefix: (prefix: Prefix) => RpcGroup.RpcGroup<Rpc.Prefixed<RpcUnionOf<S, ''>, Prefix>>;
toHandlers: (build: Handlers | Effect.Effect<Handlers, EX, RX>) => Effect.Effect<Context.Context<Rpc.ToHandler<RpcUnionOf<S, ''>>>, EX, RX | RpcGroup.HandlersServices<RpcUnionOf<S, ''>, Handlers>>;
toLayer: (build: Handlers | Effect.Effect<Handlers, EX, RX>) => Layer.Layer<Rpc.ToHandler<RpcUnionOf<S, ''>>, EX, Exclude<RX, Scope.Scope> | RpcGroup.HandlersServices<RpcUnionOf<S, ''>, 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> | RpcGroup.HandlerServices<RpcUnionOf<S, ''>, Tag, Handler>>;
accessHandler: (tag: Tag) => Effect.Effect<(payload: Rpc.Payload<Extract<RpcUnionOf<S, ''>, { readonly _tag: Tag }>>, options: { readonly client: Rpc.ServerClient; readonly requestId: RequestId; readonly headers: Headers.Headers }) => Rpc.ResultFrom<Extr…;
annotate: (service: Context.Key<I, S>, value: S) => RpcGroup.RpcGroup<RpcUnionOf<S, ''>>;
annotateRpcs: (service: Context.Key<I, S>, value: S) => RpcGroup.RpcGroup<RpcUnionOf<S, ''>>;
annotateMerge: (annotations: Context.Context<S>) => RpcGroup.RpcGroup<RpcUnionOf<S, ''>>;
annotateRpcsMerge: (annotations: Context.Context<S>) => RpcGroup.RpcGroup<RpcUnionOf<S, ''>>;
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),
import RpcClientRpcClient.class Protocolclass Protocol {
key: Identifier;
Service: {
run: (clientId: number, f: (data: FromServerEncoded) => Effect.Effect<void>) => Effect.Effect<never>;
send: (clientId: number, request: FromClientEncoded, transferables?: ReadonlyArray<globalThis.Transferable>) => Effect.Effect<void, RpcClientError>;
supportsAck: boolean;
supportsTransferables: boolean;
};
make: <EX, RX>(f: (write: (clientId: number, response: FromServerEncoded) => Effect.Effect<void>, clientIds: ReadonlySet<number>) => Effect.Effect<Omit<RpcClient.Protocol['Service'], 'run'>, EX, RX>) => Effect.Effect<RpcClient.Protocol['Service'…;
of: (this: void, self: { readonly run: (clientId: number, f: (data: FromServerEncoded) => Effect.Effect<void>) => Effect.Effect<never>; readonly send: (clientId: number, request: FromClientEncoded, transferables?: ReadonlyArray<globalThis.Tran…;
context: (self: { readonly run: (clientId: number, f: (data: FromServerEncoded) => Effect.Effect<void>) => Effect.Effect<never>; readonly send: (clientId: number, request: FromClientEncoded, transferables?: ReadonlyArray<globalThis.Transferable>) =…;
use: (f: (service: { readonly run: (clientId: number, f: (data: FromServerEncoded) => Effect.Effect<void>) => Effect.Effect<never>; readonly send: (clientId: number, request: FromClientEncoded, transferables?: ReadonlyArray<globalThis.Transfera…;
useSync: (f: (service: { readonly run: (clientId: number, f: (data: FromServerEncoded) => Effect.Effect<void>) => Effect.Effect<never>; readonly send: (clientId: number, request: FromClientEncoded, transferables?: ReadonlyArray<globalThis.Transfera…;
Identifier: Identifier;
stack: string | undefined;
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; <…;
toString: () => string;
toJSON: () => unknown;
}
Defines the service interface for an RPC client transport, responsible for running the
receive loop and sending encoded client messages.
When to use
Use to provide the transport boundary for RPC clients over HTTP, WebSocket,
workers, sockets, or custom protocols.
Protocol,
const protocol: Option.Some<{
readonly run: (
clientId: number,
f: (
data: FromServerEncoded
) => Effect.Effect<void>
) => Effect.Effect<never>
readonly send: (
clientId: number,
request: FromClientEncoded,
transferables?: ReadonlyArray<globalThis.Transferable>
) => Effect.Effect<void, RpcClientError>
readonly supportsAck: boolean
readonly supportsTransferables: boolean
}>
const protocol: {
_tag: "Some";
_op: "Some";
value: A;
valueOrUndefined: A;
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; <…;
toString: () => string;
toJSON: () => unknown;
}
protocol.Some<{ readonly run: (clientId: number, f: (data: FromServerEncoded) => Effect.Effect<void>) => Effect.Effect<never>; readonly send: (clientId: number, request: FromClientEncoded, transferables?: ReadonlyArray<globalThis.Transferable>) => Effect.Effect<void, RpcClientError>; readonly supportsAck: boolean; readonly supportsTransferables: boolean; }>.value: {
readonly run: (clientId: number, f: (data: FromServerEncoded) => Effect.Effect<void>) => Effect.Effect<never>;
readonly send: (clientId: number, request: FromClientEncoded, transferables?: ReadonlyArray<globalThis.Transferable>) => Effect.Effect<void, RpcClientError>;
readonly supportsAck: boolean;
readonly supportsTransferables: boolean;
}
value,
);
return yield* const buildClientService: <
Self,
S extends Spec
>(
tag: HyperlinkTag<Self, S>,
rpc: unknown
) => Effect.Effect<
ServiceOf<S, Self>,
never,
Scope.Scope
>
Build the client-side service for a tag from a wired RPC client: forward every wire method
(group-prefixed, id-pinned), and stub each
Hyperlink.local
member with a value that
requires the never-granted
Local
(so calling one through a client is a
compile error, and unreachable at runtime). Shared by both
clientLayer
paths.
buildClientService(tag: HyperlinkTag<Self, S>(parameter) tag: {
groupId: string;
description: string | undefined;
key: Identifier;
of: (this: void, self: 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…;
context: (self: 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<AsMethod<S[…;
use: (f: (service: 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<AsMe…;
useSync: (f: (service: 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<AsMe…;
Identifier: Identifier;
Service: Shape;
stack: string | undefined;
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; <…;
toString: () => string;
toJSON: () => unknown;
}
tag, const client: {
[K in keyof RpcClient.RpcClient.From<
RpcUnionOf<S, "">,
RpcClientError
>]: RpcClient.RpcClient.From<
RpcUnionOf<S, "">,
RpcClientError
>[K]
}
client);
}),
) as any;
}
// node chosen (from the tag or the argument): resolve the transport from that node service and
// provide it locally to the client, so the layer requires the node rather than the ambient
// Protocol. Reading a provided node service can't fail and `RpcClient.make` has no error channel,
// so client construction never fails or dies — only the resulting method calls carry typed errors.
// The node identity is erased to `unknown` on the base tag; the two node-typed overloads pin the
// precise `HSelf` for callers, so this one contained boundary assertion restates the impl's return.
const const layer: anylayer: any = (import LayerLayer.const effect: {
<I, S>(service: Context.Key<I, S>): <E, R>(
effect: Effect.Effect<S, E, R>
) => Layer.Layer<I, E, Exclude<R, Scope.Scope>>
<I, S, E, R>(
service: Context.Key<I, S>,
effect: Effect.Effect<NoInfer<S>, E, R>
): Layer.Layer<I, E, Exclude<R, Scope.Scope>>
}
Constructs a layer from an effect that produces a single service.
When to use
Use when you need to construct a Layer-provided service with an Effect,
dependencies, or scoped resource acquisition.
Details
This allows you to create a Layer from an Effect that produces a service.
The Effect is executed in the scope of the layer, allowing for proper
resource management.
Example (Creating a layer from an effect)
import { Context, Effect, Layer } from "effect"
class Database extends Context.Service<Database, {
readonly query: (sql: string) => Effect.Effect<string>
}>()("Database") {}
const layer = Layer.effect(Database,
Effect.sync(() => ({
query: (sql: string) => Effect.succeed(`Query: ${sql}`)
}))
)
effect as any)(
tag: HyperlinkTag<Self, S>(parameter) tag: {
groupId: string;
description: string | undefined;
key: Identifier;
of: (this: void, self: 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…;
context: (self: 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<AsMethod<S[…;
use: (f: (service: 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<AsMe…;
useSync: (f: (service: 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<AsMe…;
Identifier: Identifier;
Service: Shape;
stack: string | undefined;
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; <…;
toString: () => string;
toJSON: () => unknown;
}
tag,
import EffectEffect.const gen: <any, 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<AsMethod<S[K]>> : S[K] extends {
readonly _tag: "ref";
} ? Subscribable<SuccessOf<AsMethod<S[K]>>> : S[K] extends {
readonly kind: MethodKind;
} ? ClientMethod<...> : S[K] extends Spec ? Simplify<...> : never; }>>(f: () => Generator<...>) => Effect.Effect<...> (+1 overload)
Provides a way to write effectful code using generator functions, simplifying
control flow and error handling.
When to use
Use when you want to write effectful code that looks and behaves like
synchronous code, while still handling asynchronous tasks, errors, and complex
control flow such as loops and conditions.
Generator functions work similarly to async/await but keep errors,
requirements, and interruption in the Effect type. You can yield* values
from effects and return the final result at the end.
Example (Sequencing effects with generators)
import { Data, Effect } from "effect"
class DiscountRateError extends Data.TaggedError("DiscountRateError")<{}> {}
const addServiceCharge = (amount: number) => amount + 1
const applyDiscount = (
total: number,
discountRate: number
): Effect.Effect<number, DiscountRateError> =>
discountRate === 0
? Effect.fail(new DiscountRateError())
: Effect.succeed(total - (total * discountRate) / 100)
const fetchTransactionAmount = Effect.promise(() => Promise.resolve(100))
const fetchDiscountRate = Effect.promise(() => Promise.resolve(5))
export const program = Effect.gen(function*() {
const transactionAmount = yield* fetchTransactionAmount
const discountRate = yield* fetchDiscountRate
const discountedAmount = yield* applyDiscount(
transactionAmount,
discountRate
)
const finalAmount = addServiceCharge(discountedAmount)
return `Final amount to charge: ${finalAmount}`
})
gen(function* () {
const { const protocol: anyprotocol } = yield* const nodeKey: anynodeKey as any;
const const client: anyclient = yield* (import EffectEffect.const provideService: {
<I, S>(service: Context.Key<I, S>): {
(implementation: S): <A, E, R>(
self: Effect.Effect<A, E, R>
) => Effect.Effect<A, E, Exclude<R, I>>
<A, E, R>(
self: Effect.Effect<A, E, R>,
implementation: S
): Effect.Effect<A, E, Exclude<R, I>>
}
<I, S>(
service: Context.Key<I, S>,
implementation: S
): <A, E, R>(
self: Effect.Effect<A, E, R>
) => Effect.Effect<A, E, Exclude<R, I>>
<A, E, R, I, S>(
self: Effect.Effect<A, E, R>,
service: Context.Key<I, S>,
implementation: S
): Effect.Effect<A, E, Exclude<R, I>>
}
Provides one concrete service implementation to an effect.
When to use
Use to satisfy one service requirement with an already-built implementation.
Details
The service requirement identified by the Context.Key is removed from the
effect requirements after the implementation is provided.
Example (Providing a service value)
import { Console, Context, Effect } from "effect"
// Define a service for configuration
const Config = Context.Service<{
apiUrl: string
timeout: number
}>("Config")
const fetchData = Effect.gen(function*() {
const config = yield* Effect.service(Config)
yield* Console.log(`Fetching from: ${config.apiUrl}`)
yield* Console.log(`Timeout: ${config.timeout}ms`)
return "data"
})
// Provide the service implementation
const program = Effect.provideService(fetchData, Config, {
apiUrl: "https://api.example.com",
timeout: 5000
})
Effect.runPromise(program).then(console.log)
// Output:
// Fetching from: https://api.example.com
// Timeout: 5000ms
// data
provideService as any)(
(import RpcClientRpcClient.const make: <
Rpcs extends Rpc.Any,
const Flatten extends boolean = false
>(
group: RpcGroup.RpcGroup<Rpcs>,
options?:
| {
readonly spanPrefix?: string | undefined
readonly spanAttributes?:
| Record<string, unknown>
| undefined
readonly generateRequestId?:
| (() => RequestId)
| undefined
readonly disableTracing?:
| boolean
| undefined
readonly flatten?: Flatten | undefined
}
| undefined
) => Effect.Effect<
Flatten extends true
? RpcClient.RpcClient.Flat<
Rpcs,
RpcClientError
>
: RpcClient.RpcClient<Rpcs, RpcClientError>,
never,
| RpcClient.Protocol
| Rpc.MiddlewareClient<Rpcs>
| Scope.Scope
>
Creates a schema-aware RPC client for a group using the current client
Protocol, encoding requests and decoding server responses.
make as any)(const group: RpcGroupOf<S>const group: {
requests: ReadonlyMap<string, R>;
annotations: Context.Context<never>;
add: (...rpcs: Rpcs2) => RpcGroup.RpcGroup<RpcUnionOf<S, ''> | Rpcs2[number]>;
merge: (...groups: Groups) => RpcGroup.RpcGroup<RpcUnionOf<S, ''> | RpcGroup.Rpcs<Groups[number]>>;
omit: (...tags: Tags) => RpcGroup.RpcGroup<Exclude<RpcUnionOf<S, ''>, { readonly _tag: Tags[number] }>>;
middleware: (middleware: M) => RpcGroup.RpcGroup<Rpc.AddMiddleware<RpcUnionOf<S, ''>, M>>;
prefix: (prefix: Prefix) => RpcGroup.RpcGroup<Rpc.Prefixed<RpcUnionOf<S, ''>, Prefix>>;
toHandlers: (build: Handlers | Effect.Effect<Handlers, EX, RX>) => Effect.Effect<Context.Context<Rpc.ToHandler<RpcUnionOf<S, ''>>>, EX, RX | RpcGroup.HandlersServices<RpcUnionOf<S, ''>, Handlers>>;
toLayer: (build: Handlers | Effect.Effect<Handlers, EX, RX>) => Layer.Layer<Rpc.ToHandler<RpcUnionOf<S, ''>>, EX, Exclude<RX, Scope.Scope> | RpcGroup.HandlersServices<RpcUnionOf<S, ''>, 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> | RpcGroup.HandlerServices<RpcUnionOf<S, ''>, Tag, Handler>>;
accessHandler: (tag: Tag) => Effect.Effect<(payload: Rpc.Payload<Extract<RpcUnionOf<S, ''>, { readonly _tag: Tag }>>, options: { readonly client: Rpc.ServerClient; readonly requestId: RequestId; readonly headers: Headers.Headers }) => Rpc.ResultFrom<Extr…;
annotate: (service: Context.Key<I, S>, value: S) => RpcGroup.RpcGroup<RpcUnionOf<S, ''>>;
annotateRpcs: (service: Context.Key<I, S>, value: S) => RpcGroup.RpcGroup<RpcUnionOf<S, ''>>;
annotateMerge: (annotations: Context.Context<S>) => RpcGroup.RpcGroup<RpcUnionOf<S, ''>>;
annotateRpcsMerge: (annotations: Context.Context<S>) => RpcGroup.RpcGroup<RpcUnionOf<S, ''>>;
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),
import RpcClientRpcClient.class Protocolclass Protocol {
key: Identifier;
Service: {
run: (clientId: number, f: (data: FromServerEncoded) => Effect.Effect<void>) => Effect.Effect<never>;
send: (clientId: number, request: FromClientEncoded, transferables?: ReadonlyArray<globalThis.Transferable>) => Effect.Effect<void, RpcClientError>;
supportsAck: boolean;
supportsTransferables: boolean;
};
make: <EX, RX>(f: (write: (clientId: number, response: FromServerEncoded) => Effect.Effect<void>, clientIds: ReadonlySet<number>) => Effect.Effect<Omit<RpcClient.Protocol['Service'], 'run'>, EX, RX>) => Effect.Effect<RpcClient.Protocol['Service'…;
of: (this: void, self: { readonly run: (clientId: number, f: (data: FromServerEncoded) => Effect.Effect<void>) => Effect.Effect<never>; readonly send: (clientId: number, request: FromClientEncoded, transferables?: ReadonlyArray<globalThis.Tran…;
context: (self: { readonly run: (clientId: number, f: (data: FromServerEncoded) => Effect.Effect<void>) => Effect.Effect<never>; readonly send: (clientId: number, request: FromClientEncoded, transferables?: ReadonlyArray<globalThis.Transferable>) =…;
use: (f: (service: { readonly run: (clientId: number, f: (data: FromServerEncoded) => Effect.Effect<void>) => Effect.Effect<never>; readonly send: (clientId: number, request: FromClientEncoded, transferables?: ReadonlyArray<globalThis.Transfera…;
useSync: (f: (service: { readonly run: (clientId: number, f: (data: FromServerEncoded) => Effect.Effect<void>) => Effect.Effect<never>; readonly send: (clientId: number, request: FromClientEncoded, transferables?: ReadonlyArray<globalThis.Transfera…;
Identifier: Identifier;
stack: string | undefined;
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; <…;
toString: () => string;
toJSON: () => unknown;
}
Defines the service interface for an RPC client transport, responsible for running the
receive loop and sending encoded client messages.
When to use
Use to provide the transport boundary for RPC clients over HTTP, WebSocket,
workers, sockets, or custom protocols.
Protocol,
const protocol: anyprotocol,
);
return yield* const buildClientService: <
Self,
S extends Spec
>(
tag: HyperlinkTag<Self, S>,
rpc: unknown
) => Effect.Effect<
ServiceOf<S, Self>,
never,
Scope.Scope
>
Build the client-side service for a tag from a wired RPC client: forward every wire method
(group-prefixed, id-pinned), and stub each
Hyperlink.local
member with a value that
requires the never-granted
Local
(so calling one through a client is a
compile error, and unreachable at runtime). Shared by both
clientLayer
paths.
buildClientService(tag: HyperlinkTag<Self, S>(parameter) tag: {
groupId: string;
description: string | undefined;
key: Identifier;
of: (this: void, self: 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…;
context: (self: 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<AsMethod<S[…;
use: (f: (service: 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<AsMe…;
useSync: (f: (service: 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<AsMe…;
Identifier: Identifier;
Service: Shape;
stack: string | undefined;
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; <…;
toString: () => string;
toJSON: () => unknown;
}
tag, const client: anyclient);
}) as any,
);
// Dialable node (explicit 2nd arg *or* tag-bound): bake the canonical connect Layer
// (WeakMap-memoized per Node class) so multiple clients share one MemoMap transport.
// Default-on verify (reject): peer down / wrong-or-stale contract fails Layer build —
// opt out via {@link clientVerify}. Reserved NodeStatus is auto-served and absent from
// `status.resources`, so it stays tier-1 (reachability only).
if (import isAddressedNodeisAddressedNode(const nodeKey: anynodeKey as import AnyNodeAnyNode)) {
const const addressed: AddressedNode<unknown>addressed = const nodeKey: anynodeKey as import AddressedNodeAddressedNode<unknown>;
const const connected: anyconnected: any = const layer: anylayer.pipe(import LayerLayer.const provide: <any>(that: any) => <A, E, R>(self: Layer.Layer<A, E, R>) => Layer.Layer<A, any, any> (+3 overloads)Feeds the output services of the dependency layer into the requirements of
this layer, returning a layer that only provides the services from this layer.
When to use
Use when you need to hide an implementation dependency layer from callers.
Details
In serviceLayer.pipe(Layer.provide(dependencyLayer)), the dependency layer is
built first and is used to satisfy the requirements of serviceLayer.
Example (Providing layer dependencies)
import { Context, Effect, Layer } from "effect"
class Database extends Context.Service<Database, {
readonly query: (sql: string) => Effect.Effect<string>
}>()("Database") {}
class UserService extends Context.Service<UserService, {
readonly getUser: (id: string) => Effect.Effect<{
id: string
name: string
}>
}>()("UserService") {}
class Logger extends Context.Service<Logger, {
readonly log: (msg: string) => Effect.Effect<void>
}>()("Logger") {}
// Create dependency layers
const databaseLayer = Layer.succeed(Database, {
query: Effect.fn("Database.query")((sql: string) => Effect.succeed(`DB: ${sql}`))
})
const loggerLayer = Layer.succeed(Logger, {
log: Effect.fn("Logger.log")((msg: string) => Effect.sync(() => console.log(`[LOG] ${msg}`)))
})
// UserService depends on Database and Logger
const userServiceLayer = Layer.effect(UserService, Effect.gen(function*() {
const database = yield* Database
const logger = yield* Logger
return {
getUser: Effect.fn("UserService.getUser")(function*(id: string) {
yield* logger.log(`Looking up user ${id}`)
const result = yield* database.query(
`SELECT * FROM users WHERE id = ${id}`
)
return { id, name: result }
})
}
}))
// Provide dependencies to UserService layer
const userServiceWithDependencies = userServiceLayer.pipe(
Layer.provide(Layer.mergeAll(databaseLayer, loggerLayer))
)
// Now UserService layer has no dependencies
const program = Effect.gen(function*() {
const userService = yield* UserService
return yield* userService.getUser("123")
}).pipe(
Effect.provide(userServiceWithDependencies)
)
provide(import connectAddressedconnectAddressed(const addressed: AddressedNode<unknown>addressed)));
const const deepResource:
| {
resource: string
contractHash: string
}
| undefined
deepResource =
tag: HyperlinkTag<Self, S>(parameter) tag: {
groupId: string;
description: string | undefined;
key: Identifier;
of: (this: void, self: 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…;
context: (self: 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<AsMethod<S[…;
use: (f: (service: 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<AsMe…;
useSync: (f: (service: 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<AsMe…;
Identifier: Identifier;
Service: Shape;
stack: string | undefined;
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; <…;
toString: () => string;
toJSON: () => unknown;
}
tag.HyperlinkTag<Self, S, Simplify<{ readonly [K in keyof S]: S[K] extends FromLocalMethod<infer M> ? InjectLocal<M, Self> : S[K] extends LocalMethod<...> ? LocalEffect<...> : S[K] extends { ...; } ? SuccessOf<...> : S[K] extends { ...; } ? Subscribable<...> : S[K] extends { ...; } ? ClientMethod<...> : S[K] extends Spec ? Simplify<...> : never; }>>.groupId: stringWire prefix — namespaces this resource's procedures on a shared RpcServer.
groupId === "@pm/node-status"
? var undefinedundefined
: {
resource: stringresource: tag: HyperlinkTag<Self, S>(parameter) tag: {
groupId: string;
description: string | undefined;
key: Identifier;
of: (this: void, self: 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…;
context: (self: 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<AsMethod<S[…;
use: (f: (service: 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<AsMe…;
useSync: (f: (service: 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<AsMe…;
Identifier: Identifier;
Service: Shape;
stack: string | undefined;
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; <…;
toString: () => string;
toJSON: () => unknown;
}
tag.HyperlinkTag<Self, S, Simplify<{ readonly [K in keyof S]: S[K] extends FromLocalMethod<infer M> ? InjectLocal<M, Self> : S[K] extends LocalMethod<...> ? LocalEffect<...> : S[K] extends { ...; } ? SuccessOf<...> : S[K] extends { ...; } ? Subscribable<...> : S[K] extends { ...; } ? ClientMethod<...> : S[K] extends Spec ? Simplify<...> : never; }>>.groupId: stringWire prefix — namespaces this resource's procedures on a shared RpcServer.
groupId,
contractHash: stringcontractHash: const contractHash: <
Self,
S extends Spec
>(
tag: HyperlinkTag<Self, S>
) => string
F4 wire-contract fingerprint for a resource tag — same value the server stamps on
NodeStatus.resources[].contractHash at serve. Compare via
verifyConnection
({ deep: true, resource, contractHash }).
contractHash(tag: HyperlinkTag<Self, S>(parameter) tag: {
groupId: string;
description: string | undefined;
key: Identifier;
of: (this: void, self: 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…;
context: (self: 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<AsMethod<S[…;
use: (f: (service: 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<AsMe…;
useSync: (f: (service: 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<AsMe…;
Identifier: Identifier;
Service: Shape;
stack: string | undefined;
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; <…;
toString: () => string;
toJSON: () => unknown;
}
tag),
};
return import LayerLayer.const unwrap: <
unknown,
unknown,
unknown,
any,
never
>(
self: Effect.Effect<
Layer.Layer<unknown, unknown, unknown>,
any,
never
>
) => Layer.Layer<unknown, any, unknown>
Unwraps a Layer from an Effect, flattening the nested structure.
When to use
Use when you have an Effect that produces a Layer and you want to
use that layer directly.
Details
The resulting Layer will have the combined error and dependency types from
both the outer Effect and the inner Layer.
Example (Unwrapping an effectful layer)
import { Context, Effect, Layer } from "effect"
class Database extends Context.Service<Database, {
readonly query: (sql: string) => Effect.Effect<string>
}>()("Database") {}
const layerEffect = Effect.succeed(
Layer.succeed(Database, { query: Effect.fn("Database.query")((sql: string) => Effect.succeed("result")) })
)
const unwrappedLayer = Layer.unwrap(layerEffect)
unwrap(
import EffectEffect.const gen: <Effect.Effect<void, any, never>, any>(f: () => Generator<Effect.Effect<void, any, never>, any, never>) => Effect.Effect<any, any, never> (+1 overload)Provides a way to write effectful code using generator functions, simplifying
control flow and error handling.
When to use
Use when you want to write effectful code that looks and behaves like
synchronous code, while still handling asynchronous tasks, errors, and complex
control flow such as loops and conditions.
Generator functions work similarly to async/await but keep errors,
requirements, and interruption in the Effect type. You can yield* values
from effects and return the final result at the end.
Example (Sequencing effects with generators)
import { Data, Effect } from "effect"
class DiscountRateError extends Data.TaggedError("DiscountRateError")<{}> {}
const addServiceCharge = (amount: number) => amount + 1
const applyDiscount = (
total: number,
discountRate: number
): Effect.Effect<number, DiscountRateError> =>
discountRate === 0
? Effect.fail(new DiscountRateError())
: Effect.succeed(total - (total * discountRate) / 100)
const fetchTransactionAmount = Effect.promise(() => Promise.resolve(100))
const fetchDiscountRate = Effect.promise(() => Promise.resolve(5))
export const program = Effect.gen(function*() {
const transactionAmount = yield* fetchTransactionAmount
const discountRate = yield* fetchDiscountRate
const discountedAmount = yield* applyDiscount(
transactionAmount,
discountRate
)
const finalAmount = addServiceCharge(discountedAmount)
return `Final amount to charge: ${finalAmount}`
})
gen(function* () {
yield* const applyClientVerify: (
node: AnyNode,
options?: ClientVerifyProbeOptions
) => Effect.Effect<void, ClientVerifyError>
Default-on client verify (§8.6) — "reject" unless
ClientVerify
overrides.
When resource + contractHash are set (tag-aware clients), escalates to deep F3/F4.
applyClientVerify(const addressed: AddressedNode<unknown>addressed, const deepResource:
| {
resource: string
contractHash: string
}
| undefined
deepResource);
return const connected: anyconnected;
}),
) as any;
}
return const layer: anylayer as any;
}