<Self, S extends Spec, EIn = never, RIn = never>(
tag: HyperlinkTag<Self, S>,
self: AnyNode,
options?: {
readonly nodes?: ReadonlyArray<AnyNode>
readonly url?: (
node: AnyNode
) => Effect.Effect<string | undefined, EIn, RIn>
}
): Layer.Layer<PeersId<Self> | SelfNodeId<Self>, EIn, RIn>Provide the peers capability on this node: connect every OTHER node in the tag's
distributed / nodes set and expose them as the peer clients. Also provides the
selfNode capability (this node's key) for byNode-style folds. The opt-in mesh — add
it to a node's serve only where the HyperService's own logic reaches across nodes. self is the node
you are, so you're excluded from your own peer set.
Membership (D3):
- Fixed — non-empty
options.nodesor stampednodes([…])/distributed([…]). - Directory — stamped empty set (bare
.pipe(Hyperlink.distributed)/nodes([])): read LookupDirectory.nodesServing(tag.key)at layer build, then hot-rebind onDirectory.changeswhen a peer's dial moves (dialChanged) or membership changes. Soft empty map when Directory is absent. - Undeclared — no
nodesSymand nooptions.nodes→ empty static peers (not directory).
Peer addresses: each Node's own url / path is the default. Pass options.url to
override the url per node — an env-specific port, a tunnel, or a value from Effect Config —
falling back to Node.url when the resolver returns undefined. A node with no dialable address
is skipped (never a throw), so a partial mesh degrades cleanly. IpcSocket peers dial via
protocolIpc when only path is set. The resolver's error and requirements flow to the
layer (typed).
export const const peersLayer: <
Self,
S extends Spec,
EIn = never,
RIn = never
>(
tag: HyperlinkTag<Self, S>,
self: AnyNode,
options?: {
readonly nodes?: ReadonlyArray<AnyNode>
readonly url?: (
node: AnyNode
) => Effect.Effect<
string | undefined,
EIn,
RIn
>
}
) => Layer.Layer<
PeersId<Self> | SelfNodeId<Self>,
EIn,
RIn
>
Provide the
peers
capability on this node: connect every OTHER node in the tag's
distributed
/
nodes
set and expose them as the peer clients. Also provides the
selfNode
capability (this node's key) for byNode-style folds. The opt-in mesh — add
it to a node's serve only where the HyperService's own logic reaches across nodes. self is the node
you are, so you're excluded from your own peer set.
Membership (D3):
- Fixed — non-empty
options.nodes or stamped nodes([…]) / distributed([…]).
- Directory — stamped empty set (bare
.pipe(Hyperlink.distributed) / nodes([])): read
Lookup Directory.nodesServing(tag.key) at layer build, then hot-rebind on
Directory.changes when a peer's dial moves (dialChanged) or membership changes.
Soft empty map when Directory is absent.
- Undeclared — no
nodesSym and no options.nodes → empty static peers (not directory).
Peer addresses: each
Node
's own url / path is the default. Pass options.url to
override the url per node — an env-specific port, a tunnel, or a value from Effect Config —
falling back to Node.url when the resolver returns undefined. A node with no dialable address
is skipped (never a throw), so a partial mesh degrades cleanly. IpcSocket peers dial via
protocolIpc
when only path is set. The resolver's error and requirements flow to the
layer (typed).
peersLayer = <function (type parameter) Self in <Self, S extends Spec, EIn = never, RIn = never>(tag: HyperlinkTag<Self, S>, self: AnyNode, options?: {
readonly nodes?: ReadonlyArray<AnyNode>;
readonly url?: (node: AnyNode) => Effect.Effect<string | undefined, EIn, RIn>;
}): Layer.Layer<PeersId<Self> | SelfNodeId<Self>, EIn, RIn>
Self, function (type parameter) S in <Self, S extends Spec, EIn = never, RIn = never>(tag: HyperlinkTag<Self, S>, self: AnyNode, options?: {
readonly nodes?: ReadonlyArray<AnyNode>;
readonly url?: (node: AnyNode) => Effect.Effect<string | undefined, EIn, RIn>;
}): Layer.Layer<PeersId<Self> | SelfNodeId<Self>, EIn, RIn>
S extends Spec, function (type parameter) EIn in <Self, S extends Spec, EIn = never, RIn = never>(tag: HyperlinkTag<Self, S>, self: AnyNode, options?: {
readonly nodes?: ReadonlyArray<AnyNode>;
readonly url?: (node: AnyNode) => Effect.Effect<string | undefined, EIn, RIn>;
}): Layer.Layer<PeersId<Self> | SelfNodeId<Self>, EIn, RIn>
EIn = never, function (type parameter) RIn in <Self, S extends Spec, EIn = never, RIn = never>(tag: HyperlinkTag<Self, S>, self: AnyNode, options?: {
readonly nodes?: ReadonlyArray<AnyNode>;
readonly url?: (node: AnyNode) => Effect.Effect<string | undefined, EIn, RIn>;
}): Layer.Layer<PeersId<Self> | SelfNodeId<Self>, EIn, RIn>
RIn = never>(
tag: HyperlinkTag<Self, S>(parameter) tag: {
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 DefaultMethod<infer F> ? F : S[K] extends …;
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 DefaultMethod<infer F> ? F : S[K] extends { readonly _…;
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 DefaultMethod<infer F> ? F : S[K] extends { rea…;
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 DefaultMethod<infer F> ? F : S[K] extends { rea…;
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 DefaultMethod<...> ? F : S[K] extends { ...; } ? SuccessOf<...> : S[K] extends { ...; } ? Subscribable<...> : S[K] extends { ...; } ? ClientMethod<...> : S[K] extends Spec ? Simplify<...> : never; }>>The type of a HyperService tag carrying spec S — what
Hyperlink.Tag
produces
(and what you extend). Lets a consumer write
<S extends Spec>(tag: HyperlinkTag<Self, S>) and read the spec through named types
(
specOf
/
groupOf
) instead of a Parameters<typeof specOf> workaround.
HyperlinkTag<function (type parameter) Self in <Self, S extends Spec, EIn = never, RIn = never>(tag: HyperlinkTag<Self, S>, self: AnyNode, options?: {
readonly nodes?: ReadonlyArray<AnyNode>;
readonly url?: (node: AnyNode) => Effect.Effect<string | undefined, EIn, RIn>;
}): Layer.Layer<PeersId<Self> | SelfNodeId<Self>, EIn, RIn>
Self, function (type parameter) S in <Self, S extends Spec, EIn = never, RIn = never>(tag: HyperlinkTag<Self, S>, self: AnyNode, options?: {
readonly nodes?: ReadonlyArray<AnyNode>;
readonly url?: (node: AnyNode) => Effect.Effect<string | undefined, EIn, RIn>;
}): Layer.Layer<PeersId<Self> | SelfNodeId<Self>, EIn, RIn>
S>,
self: AnyNodeself: type AnyNode = NodeKey<unknown> & {
readonly url: string | undefined;
readonly path: string | undefined;
readonly kind: ProtocolKind | undefined;
readonly endpoints?: Endpoints;
readonly onConflict?: OnConflict;
readonly [portSym]?: number;
}
A
Tag
erased — its transport endpoints set, plus the primary address
(url and/or Unix path) and
ProtocolKind
kind (the first-declared endpoint, kept for
single-protocol readers), so a tag's distributed set is self-describing about where AND how to
reach each one.
AnyNode,
options: {
readonly nodes?: ReadonlyArray<AnyNode>
readonly url?: (
node: AnyNode
) => Effect.Effect<string | undefined, EIn, RIn>
}
options?: {
/** The fleet (including `self`) — supply it **at the use site** so a shared resource can be defined
* node-free and exported; falls back to the tag's baked-in {@link distributed} set when omitted.
* An explicit empty array is directory-backed (same as bare {@link distributed}). */
readonly nodes?: ReadonlyArray<AnyNode>The fleet (including self) — supply it at the use site so a shared resource can be defined
node-free and exported; falls back to the tag's baked-in
distributed
set when omitted.
An explicit empty array is directory-backed (same as bare
distributed
).
nodes?: interface ReadonlyArray<T>ReadonlyArray<type AnyNode = NodeKey<unknown> & {
readonly url: string | undefined;
readonly path: string | undefined;
readonly kind: ProtocolKind | undefined;
readonly endpoints?: Endpoints;
readonly onConflict?: OnConflict;
readonly [portSym]?: number;
}
A
Tag
erased — its transport endpoints set, plus the primary address
(url and/or Unix path) and
ProtocolKind
kind (the first-declared endpoint, kept for
single-protocol readers), so a tag's distributed set is self-describing about where AND how to
reach each one.
AnyNode>;
readonly url?: (
node: AnyNode
) => Effect.Effect<string | undefined, EIn, RIn>
url?: (node: AnyNodenode: type AnyNode = NodeKey<unknown> & {
readonly url: string | undefined;
readonly path: string | undefined;
readonly kind: ProtocolKind | undefined;
readonly endpoints?: Endpoints;
readonly onConflict?: OnConflict;
readonly [portSym]?: number;
}
A
Tag
erased — its transport endpoints set, plus the primary address
(url and/or Unix path) and
ProtocolKind
kind (the first-declared endpoint, kept for
single-protocol readers), so a tag's distributed set is self-describing about where AND how to
reach each one.
AnyNode) => import EffectEffect.interface Effect<out A, out E = never, out R = never>The Effect interface defines a value that lazily describes a workflow or
job. The workflow requires some context R, and may fail with an error of
type E, or succeed with a value of type A.
When to use
Use when you need to represent a lazy, composable workflow that can require
services, fail with a typed error, or succeed with a typed value.
Details
Effect values model resourceful interaction with the outside world,
including synchronous, asynchronous, concurrent, and parallel interaction.
They use a fiber-based concurrency model, with built-in support for
scheduling, fine-grained interruption, structured concurrency, and high
scalability.
To run an Effect value, you need a Runtime, which is a type that is
capable of executing Effect values.
Effect<string | undefined, function (type parameter) EIn in <Self, S extends Spec, EIn = never, RIn = never>(tag: HyperlinkTag<Self, S>, self: AnyNode, options?: {
readonly nodes?: ReadonlyArray<AnyNode>;
readonly url?: (node: AnyNode) => Effect.Effect<string | undefined, EIn, RIn>;
}): Layer.Layer<PeersId<Self> | SelfNodeId<Self>, EIn, RIn>
EIn, function (type parameter) RIn in <Self, S extends Spec, EIn = never, RIn = never>(tag: HyperlinkTag<Self, S>, self: AnyNode, options?: {
readonly nodes?: ReadonlyArray<AnyNode>;
readonly url?: (node: AnyNode) => Effect.Effect<string | undefined, EIn, RIn>;
}): Layer.Layer<PeersId<Self> | SelfNodeId<Self>, EIn, RIn>
RIn>;
},
): 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<interface PeersId<Self>Phantom brand for the per-HyperService
peers
capability, so distinct HyperServices' peer sets
don't collide in one context.
PeersId<function (type parameter) Self in <Self, S extends Spec, EIn = never, RIn = never>(tag: HyperlinkTag<Self, S>, self: AnyNode, options?: {
readonly nodes?: ReadonlyArray<AnyNode>;
readonly url?: (node: AnyNode) => Effect.Effect<string | undefined, EIn, RIn>;
}): Layer.Layer<PeersId<Self> | SelfNodeId<Self>, EIn, RIn>
Self> | interface SelfNodeId<Self>Phantom brand for the per-HyperService
selfNode
capability (which node this instance runs as),
so distinct HyperServices' self-node identities don't collide in one context.
SelfNodeId<function (type parameter) Self in <Self, S extends Spec, EIn = never, RIn = never>(tag: HyperlinkTag<Self, S>, self: AnyNode, options?: {
readonly nodes?: ReadonlyArray<AnyNode>;
readonly url?: (node: AnyNode) => Effect.Effect<string | undefined, EIn, RIn>;
}): Layer.Layer<PeersId<Self> | SelfNodeId<Self>, EIn, RIn>
Self>, function (type parameter) EIn in <Self, S extends Spec, EIn = never, RIn = never>(tag: HyperlinkTag<Self, S>, self: AnyNode, options?: {
readonly nodes?: ReadonlyArray<AnyNode>;
readonly url?: (node: AnyNode) => Effect.Effect<string | undefined, EIn, RIn>;
}): Layer.Layer<PeersId<Self> | SelfNodeId<Self>, EIn, RIn>
EIn, function (type parameter) RIn in <Self, S extends Spec, EIn = never, RIn = never>(tag: HyperlinkTag<Self, S>, self: AnyNode, options?: {
readonly nodes?: ReadonlyArray<AnyNode>;
readonly url?: (node: AnyNode) => Effect.Effect<string | undefined, EIn, RIn>;
}): Layer.Layer<PeersId<Self> | SelfNodeId<Self>, EIn, RIn>
RIn> =>
import LayerLayer.const merge: {
<RIn, E, ROut>(that: Layer<ROut, E, RIn>): <
RIn2,
E2,
ROut2
>(
self: Layer<ROut2, E2, RIn2>
) => Layer<ROut | ROut2, E | E2, RIn | RIn2>
<Layers extends [Any, ...Array<Any>]>(
that: Layers
): <A, E, R>(
self: Layer<A, E, R>
) => Layer<
A | Success<Layers[number]>,
E | Error<Layers[number]>,
Services<Layers[number]> | R
>
<RIn2, E2, ROut2, RIn, E, ROut>(
self: Layer<ROut2, E2, RIn2>,
that: Layer<ROut, E, RIn>
): Layer<ROut | ROut2, E | E2, RIn | RIn2>
<A, E, R, Layers extends [Any, ...Array<Any>]>(
self: Layer<A, E, R>,
that: Layers
): Layer<
A | Success<Layers[number]>,
E | Error<Layers[number]>,
Services<Layers[number]> | R
>
}
Merges this layer with another layer concurrently, producing a new layer with
combined input, error, and output types.
When to use
Use to combine an existing Layer with another Layer or an array of
layers while preserving pipeline style.
Details
This is a binary version of mergeAll that merges exactly two layers or one
layer with an array of layers. The layers are built concurrently and their
outputs are combined.
Example (Merging two layers)
import { Context, Effect, Layer } from "effect"
class Database extends Context.Service<Database, {
readonly query: (sql: string) => Effect.Effect<string>
}>()("Database") {}
class Logger extends Context.Service<Logger, {
readonly log: (msg: string) => Effect.Effect<void>
}>()("Logger") {}
const dbLayer = Layer.succeed(Database, {
query: Effect.fn("Database.query")((sql: string) => Effect.succeed("result"))
})
const loggerLayer = Layer.succeed(Logger, {
log: Effect.fn("Logger.log")((msg: string) => Effect.sync(() => console.log(msg)))
})
const mergedLayer = Layer.merge(dbLayer, loggerLayer)
merge(
import LayerLayer.const effect: {
<I, S>(service: Context.Key<I, S>): <E, R>(
effect: Effect<S, E, R>
) => Layer<I, E, Exclude<R, Scope.Scope>>
<I, S, E, R>(
service: Context.Key<I, S>,
effect: Effect<Types.NoInfer<S>, E, R>
): 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(
tag: HyperlinkTag<Self, S>(parameter) tag: {
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 DefaultMethod<infer F> ? F : S[K] extends …;
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 DefaultMethod<infer F> ? F : S[K] extends { readonly _…;
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 DefaultMethod<infer F> ? F : S[K] extends { rea…;
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 DefaultMethod<infer F> ? F : S[K] extends { rea…;
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 peersSym: typeof peersSymHolds a tag's per-HyperService
peers
capability key.
peersSym],
import EffectEffect.const gen: {
<Eff extends Effect<any, any, any>, AEff>(
f: () => Generator<Eff, AEff, never>
): Effect<
AEff,
[Eff] extends [never]
? never
: [Eff] extends [
Effect<infer _A, infer E, infer _R>
]
? E
: never,
[Eff] extends [never]
? never
: [Eff] extends [
Effect<infer _A, infer _E, infer R>
]
? R
: never
>
<Self, Eff extends Effect<any, any, any>, AEff>(
options: { readonly self: Self },
f: (this: Self) => Generator<Eff, AEff, never>
): Effect<
AEff,
[Eff] extends [never]
? never
: [Eff] extends [
Effect<infer _A, infer E, infer _R>
]
? E
: never,
[Eff] extends [never]
? never
: [Eff] extends [
Effect<infer _A, infer _E, infer R>
]
? R
: never
>
}
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 stamped:
| readonly AnyNode[]
| undefined
stamped =
options: {
readonly nodes?: ReadonlyArray<AnyNode>
readonly url?: (
node: AnyNode
) => Effect.Effect<string | undefined, EIn, RIn>
}
options?.nodes?: ReadonlyArray<AnyNode>The fleet (including self) — supply it at the use site so a shared resource can be defined
node-free and exported; falls back to the tag's baked-in
distributed
set when omitted.
An explicit empty array is directory-backed (same as bare
distributed
).
nodes !== var undefinedundefined ? options: {
readonly nodes?: ReadonlyArray<AnyNode>
readonly url?: (
node: AnyNode
) => Effect.Effect<string | undefined, EIn, RIn>
}
options.nodes?: ReadonlyArray<AnyNode>The fleet (including self) — supply it at the use site so a shared resource can be defined
node-free and exported; falls back to the tag's baked-in
distributed
set when omitted.
An explicit empty array is directory-backed (same as bare
distributed
).
nodes : tag: HyperlinkTag<Self, S>(parameter) tag: {
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 DefaultMethod<infer F> ? F : S[K] extends …;
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 DefaultMethod<infer F> ? F : S[K] extends { readonly _…;
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 DefaultMethod<infer F> ? F : S[K] extends { rea…;
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 DefaultMethod<infer F> ? F : S[K] extends { rea…;
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 nodesSym: typeof nodesSymHolds a tag's distributed set (the fleet).
nodesSym];
// D3: stamped empty set → Lookup directory membership (soft if Directory absent).
// Live rebind on Directory.changes when dial moves / peers appear or leave.
if (const stamped:
| readonly AnyNode[]
| undefined
stamped !== var undefinedundefined && const stamped: ReadonlyArray<AnyNode>stamped.ReadonlyArray<AnyNode>.length: numberGets the length of the array. This is a number one higher than the highest element defined in an array.
length === 0) {
const const Lookup: typeof import("/Users/nikolasstow/Coding/Hyperlink/worktrees/epsilon/src/Lookup")const Lookup: {
resolveOnConflict: (...prefs: ReadonlyArray<OnConflict | undefined>) => OnConflictResolved;
Endpoint: typeof Endpoint;
ClaimRequest: typeof ClaimRequest;
ResolveRequest: typeof ResolveRequest;
DuplicateIdentity: typeof DuplicateIdentity;
DirectoryEntry: typeof LookupDirectoryEntry;
DirectoryUpserted: typeof DirectoryUpserted;
DirectoryRemoved: typeof DirectoryRemoved;
DirectoryChange: Schema.Union<readonly [typeof DirectoryUpserted, typeof DirectoryRemoved]>;
AdvertiseRequest: typeof AdvertiseRequest;
UnregisterRequest: typeof UnregisterRequest;
NodesServingRequest: typeof NodesServingRequest;
IncumbentAlive: typeof IncumbentAlive;
AdviseRequest: typeof AdviseRequest;
ClearAdviceRequest: typeof ClearAdviceRequest;
PreferredRequest: typeof PreferredRequest;
LookupUnaddressed: typeof LookupUnaddressed;
kind: 'hyperlink-ts/Lookup';
Identity: typeof LookupIdentity;
Directory: typeof LookupDirectory;
Advice: typeof LookupAdvice;
nodesServing: (service: string | { readonly key: string }) => Effect.Effect<ReadonlyArray<DirectoryEntry>, never, Directory>;
advise: (input: { readonly serviceKey: string; readonly prefer: string }) => Effect.Effect<string, never, Advice>;
prefer: (service: string | { readonly key: string }, nodeKey: string) => Effect.Effect<string, never, Advice>;
preferEntry: (service: string | { readonly key: string }, entry: { readonly nodeKey: string }) => Effect.Effect<string, never, Advice>;
clearAdvice: (service: string | { readonly key: string }) => Effect.Effect<boolean, never, Advice>;
preferred: (service: string | { readonly key: string }) => Effect.Effect<Option.Option<string>, never, Advice>;
changes: Stream.Stream<DirectoryChange, never, Directory>;
directoryTable: () => Effect.Effect<{ readonly get: Effect.Effect<ReadonlyMap<string, DirectoryEntry>>; readonly getNode: (nodeKey: string) => Effect.Effect<Option.Option<DirectoryEntry>> }, never, Directory | Scope.Scope>;
defaultIpcPath: '/tmp/hyperlink-ts-lookup.sock';
layerIpc: (path: string, options?: { readonly unlink?: boolean; readonly onConflict?: OnConflictResolved }) => Layer.Layer<Directory | Identity | Advice | Hyperlink.Local<Identity> | Handler<'claim'> | Handler<'resolve'> | Hyperlink.Local<Directory>…;
layerNode: (node: AnyNode & { readonly key: string }, options?: { readonly unlink?: boolean }) => Layer.Layer<never, LookupUnaddressed>;
directoryAdvertiseLayer: (node: AnyNode & { readonly key: string }, serves: ReadonlyArray<string>, options?: { readonly onConflict?: OnConflict }) => Layer.Layer<never, IncumbentAlive>;
client: (node: AnyNode & { readonly path?: string }) => Layer.Layer<Services, LookupUnaddressed>;
clientOptions: (options?: { readonly path?: string }) => Layer.Layer<Services, LookupUnaddressed>;
layerOptions: (options?: { readonly path?: string; readonly unlink?: boolean }) => Layer.Layer<Services>;
layer: Layer.Layer<Services>;
}
Lookup = yield* import EffectEffect.const promise: <A>(
evaluate: (
signal: AbortSignal
) => PromiseLike<A>
) => Effect<A>
Creates an Effect that represents an asynchronous computation guaranteed to
succeed.
When to use
Use to convert a Promise into an Effect when the async operation is
guaranteed to succeed and will not reject.
Details
An optional AbortSignal can be provided to allow for interruption of the
wrapped Promise API.
Gotchas
The Promise must not reject. If it rejects, the rejection is treated as a
defect, not as a typed failure. Use tryPromise when rejection is expected.
Interruption aborts the provided AbortSignal, but the underlying
asynchronous operation only stops if it observes that signal.
Example (Wrapping a non-rejecting Promise)
import { Effect } from "effect"
const delay = (message: string) =>
Effect.promise<string>(
() =>
new Promise((resolve) => {
setTimeout(() => {
resolve(message)
}, 2000)
})
)
// ┌─── Effect<string, never, never>
// ▼
const program = delay("Async operation completed successfully!")
promise(() => import("./Lookup"));
const const dirOpt: Option.Option<{
readonly advertise: (payload: {
kind: "Http" | "WebSocket" | "IpcSocket"
serves: ReadonlyArray<string>
nodeKey: string
url?: string | undefined
path?: string | undefined
onConflict?:
| "livenessReplace"
| "askIncumbent"
| "reject"
| "inherit"
| undefined
}) => Effect.Effect<
LookupDirectoryEntry,
IncumbentAlive,
never
>
readonly unregister: (payload: {
nodeKey: string
kind?:
| "Http"
| "WebSocket"
| "IpcSocket"
| undefined
url?: string | undefined
path?: string | undefined
}) => Effect.Effect<boolean, never, never>
readonly nodesServing: (payload: {
serviceKey: string
}) => Effect.Effect<
ReadonlyArray<LookupDirectoryEntry>,
never,
never
>
readonly changes: Stream.Stream<
DirectoryUpserted | DirectoryRemoved,
never,
never
>
}>
dirOpt = yield* import EffectEffect.const serviceOption: <I, S>(
key: Context.Key<I, S>
) => Effect<Option<S>>
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(const Lookup: typeof import("/Users/nikolasstow/Coding/Hyperlink/worktrees/epsilon/src/Lookup")const Lookup: {
resolveOnConflict: (...prefs: ReadonlyArray<OnConflict | undefined>) => OnConflictResolved;
Endpoint: typeof Endpoint;
ClaimRequest: typeof ClaimRequest;
ResolveRequest: typeof ResolveRequest;
DuplicateIdentity: typeof DuplicateIdentity;
DirectoryEntry: typeof LookupDirectoryEntry;
DirectoryUpserted: typeof DirectoryUpserted;
DirectoryRemoved: typeof DirectoryRemoved;
DirectoryChange: Schema.Union<readonly [typeof DirectoryUpserted, typeof DirectoryRemoved]>;
AdvertiseRequest: typeof AdvertiseRequest;
UnregisterRequest: typeof UnregisterRequest;
NodesServingRequest: typeof NodesServingRequest;
IncumbentAlive: typeof IncumbentAlive;
AdviseRequest: typeof AdviseRequest;
ClearAdviceRequest: typeof ClearAdviceRequest;
PreferredRequest: typeof PreferredRequest;
LookupUnaddressed: typeof LookupUnaddressed;
kind: 'hyperlink-ts/Lookup';
Identity: typeof LookupIdentity;
Directory: typeof LookupDirectory;
Advice: typeof LookupAdvice;
nodesServing: (service: string | { readonly key: string }) => Effect.Effect<ReadonlyArray<DirectoryEntry>, never, Directory>;
advise: (input: { readonly serviceKey: string; readonly prefer: string }) => Effect.Effect<string, never, Advice>;
prefer: (service: string | { readonly key: string }, nodeKey: string) => Effect.Effect<string, never, Advice>;
preferEntry: (service: string | { readonly key: string }, entry: { readonly nodeKey: string }) => Effect.Effect<string, never, Advice>;
clearAdvice: (service: string | { readonly key: string }) => Effect.Effect<boolean, never, Advice>;
preferred: (service: string | { readonly key: string }) => Effect.Effect<Option.Option<string>, never, Advice>;
changes: Stream.Stream<DirectoryChange, never, Directory>;
directoryTable: () => Effect.Effect<{ readonly get: Effect.Effect<ReadonlyMap<string, DirectoryEntry>>; readonly getNode: (nodeKey: string) => Effect.Effect<Option.Option<DirectoryEntry>> }, never, Directory | Scope.Scope>;
defaultIpcPath: '/tmp/hyperlink-ts-lookup.sock';
layerIpc: (path: string, options?: { readonly unlink?: boolean; readonly onConflict?: OnConflictResolved }) => Layer.Layer<Directory | Identity | Advice | Hyperlink.Local<Identity> | Handler<'claim'> | Handler<'resolve'> | Hyperlink.Local<Directory>…;
layerNode: (node: AnyNode & { readonly key: string }, options?: { readonly unlink?: boolean }) => Layer.Layer<never, LookupUnaddressed>;
directoryAdvertiseLayer: (node: AnyNode & { readonly key: string }, serves: ReadonlyArray<string>, options?: { readonly onConflict?: OnConflict }) => Layer.Layer<never, IncumbentAlive>;
client: (node: AnyNode & { readonly path?: string }) => Layer.Layer<Services, LookupUnaddressed>;
clientOptions: (options?: { readonly path?: string }) => Layer.Layer<Services, LookupUnaddressed>;
layerOptions: (options?: { readonly path?: string; readonly unlink?: boolean }) => Layer.Layer<Services>;
layer: Layer.Layer<Services>;
}
Lookup.class Directoryclass Directory {
key: Identifier;
Service: {
advertise: (payload: { kind: 'Http' | 'WebSocket' | 'IpcSocket'; serves: ReadonlyArray<string>; nodeKey: string; url?: string | undefined; path?: string | undefined; onConflict?: 'livenessReplace' | 'askIncumbent' | 'reject' | 'inherit' | undefined }…;
unregister: (payload: { nodeKey: string; kind?: 'Http' | 'WebSocket' | 'IpcSocket' | undefined; url?: string | undefined; path?: string | undefined }) => Effect.Effect<boolean, never, never>;
nodesServing: (payload: { serviceKey: string }) => Effect.Effect<ReadonlyArray<LookupDirectoryEntry>, never, never>;
changes: Stream.Stream<DirectoryUpserted | DirectoryRemoved, never, never>;
};
description: string | undefined;
of: (this: void, self: { readonly advertise: (payload: { kind: 'Http' | 'WebSocket' | 'IpcSocket'; serves: ReadonlyArray<string>; nodeKey: string; url?: string | undefined; path?: string | undefined; onConflict?: 'livenessReplace' | 'askIncumb…;
context: (self: { readonly advertise: (payload: { kind: 'Http' | 'WebSocket' | 'IpcSocket'; serves: ReadonlyArray<string>; nodeKey: string; url?: string | undefined; path?: string | undefined; onConflict?: 'livenessReplace' | 'askIncumbent' | 'reje…;
use: (f: (service: { readonly advertise: (payload: { kind: 'Http' | 'WebSocket' | 'IpcSocket'; serves: ReadonlyArray<string>; nodeKey: string; url?: string | undefined; path?: string | undefined; onConflict?: 'livenessReplace' | 'askIncumbent' …;
useSync: (f: (service: { readonly advertise: (payload: { kind: 'Http' | 'WebSocket' | 'IpcSocket'; serves: ReadonlyArray<string>; nodeKey: string; url?: string | undefined; path?: string | undefined; onConflict?: 'livenessReplace' | 'askIncumbent' …;
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;
}
Lookup node directory — advertise / unregister / list by served HyperService key /
directorySpec.changes
membership push.
Directory);
if (import OptionOption.const isNone: <A>(
self: Option<A>
) => self is None<A>
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 dirOpt: Option.Option<{
readonly advertise: (payload: {
kind: "Http" | "WebSocket" | "IpcSocket"
serves: ReadonlyArray<string>
nodeKey: string
url?: string | undefined
path?: string | undefined
onConflict?:
| "livenessReplace"
| "askIncumbent"
| "reject"
| "inherit"
| undefined
}) => Effect.Effect<
LookupDirectoryEntry,
IncumbentAlive,
never
>
readonly unregister: (payload: {
nodeKey: string
kind?:
| "Http"
| "WebSocket"
| "IpcSocket"
| undefined
url?: string | undefined
path?: string | undefined
}) => Effect.Effect<boolean, never, never>
readonly nodesServing: (payload: {
serviceKey: string
}) => Effect.Effect<
ReadonlyArray<LookupDirectoryEntry>,
never,
never
>
readonly changes: Stream.Stream<
DirectoryUpserted | DirectoryRemoved,
never,
never
>
}>
dirOpt)) {
return {} as type Record<K extends keyof any, T> = {
[P in K]: T
}
Construct a type with a set of properties K of type T
Record<string, type PeerServiceOf<S extends Spec> = {
readonly [K in keyof S as S[K] extends {
readonly fleet: true
}
? never
: S[K] extends
| AnyLocalMethod
| AnyDefaultMethod
? never
: K]: S[K] extends {
readonly _tag: "ref"
}
? Effect.Effect<
SuccessOf<AsMethod<S[K]>>,
never,
never
>
: S[K] extends {
readonly kind: MethodKind
}
? ServiceMethod<AsMethod<S[K]>>
: S[K] extends Spec
? PeerServiceOf<S[K]>
: never
}
A peer's service as seen by
peers
— the per-instance ("leaf") wire methods only:
FleetField
s and
LocalMethod
s are excluded, so a fold can't recurse into a peer's
own fleet field. A full
ServiceOf
is assignable to it (width), so real clients fit.
PeerServiceOf<function (type parameter) S in <Self, S extends Spec, EIn = never, RIn = never>(tag: HyperlinkTag<Self, S>, self: AnyNode, options?: {
readonly nodes?: ReadonlyArray<AnyNode>;
readonly url?: (node: AnyNode) => Effect.Effect<string | undefined, EIn, RIn>;
}): Layer.Layer<PeersId<Self> | SelfNodeId<Self>, EIn, RIn>
S>>;
}
const const directory: {
readonly advertise: (payload: {
kind: "Http" | "WebSocket" | "IpcSocket";
serves: readonly string[];
nodeKey: string;
url?: string | undefined;
path?: string | undefined;
onConflict?: "livenessReplace" | "askIncumbent" | "reject" | "inherit" | undefined;
}) => Effect.Effect<LookupDirectoryEntry, IncumbentAlive, never>;
readonly unregister: (payload: {
nodeKey: string;
kind?: "Http" | "WebSocket" | "IpcSocket" | undefined;
url?: string | undefined;
path?: string | undefined;
}) => Effect.Effect<boolean, never, never>;
readonly nodesServing: (payload: {
...;
}) => Effect.Effect<...>;
readonly changes: Stream.Stream<...>;
}
directory = const dirOpt: Option.Some<{
readonly advertise: (payload: {
kind: "Http" | "WebSocket" | "IpcSocket"
serves: ReadonlyArray<string>
nodeKey: string
url?: string | undefined
path?: string | undefined
onConflict?:
| "livenessReplace"
| "askIncumbent"
| "reject"
| "inherit"
| undefined
}) => Effect.Effect<
LookupDirectoryEntry,
IncumbentAlive,
never
>
readonly unregister: (payload: {
nodeKey: string
kind?:
| "Http"
| "WebSocket"
| "IpcSocket"
| undefined
url?: string | undefined
path?: string | undefined
}) => Effect.Effect<boolean, never, never>
readonly nodesServing: (payload: {
serviceKey: string
}) => Effect.Effect<
ReadonlyArray<LookupDirectoryEntry>,
never,
never
>
readonly changes: Stream.Stream<
DirectoryUpserted | DirectoryRemoved,
never,
never
>
}>
const dirOpt: {
_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;
}
dirOpt.Some<{ readonly advertise: (payload: { kind: "Http" | "WebSocket" | "IpcSocket"; serves: readonly string[]; nodeKey: string; url?: string | undefined; path?: string | undefined; onConflict?: "livenessReplace" | "askIncumbent" | "reject" | "inherit" | undefined; }) => Effect<...>; readonly unregister: (payload: { ...; }) => Effect<...>; readonly nodesServing: (payload: { ...; }) => Effect<...>; readonly changes: Stream<...>; }>.value: {
readonly advertise: (payload: {
kind: "Http" | "WebSocket" | "IpcSocket";
serves: readonly string[];
nodeKey: string;
url?: string | undefined;
path?: string | undefined;
onConflict?: "livenessReplace" | "askIncumbent" | "reject" | "inherit" | undefined;
}) => Effect.Effect<LookupDirectoryEntry, IncumbentAlive, never>;
readonly unregister: (payload: {
nodeKey: string;
kind?: "Http" | "WebSocket" | "IpcSocket" | undefined;
url?: string | undefined;
path?: string | undefined;
}) => Effect.Effect<boolean, never, never>;
readonly nodesServing: (payload: {
...;
}) => Effect.Effect<...>;
readonly changes: Stream.Stream<...>;
}
value;
const const serviceKey: stringserviceKey = tag: HyperlinkTag<Self, S>(parameter) tag: {
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 DefaultMethod<infer F> ? F : S[K] extends …;
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 DefaultMethod<infer F> ? F : S[K] extends { readonly _…;
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 DefaultMethod<infer F> ? F : S[K] extends { rea…;
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 DefaultMethod<infer F> ? F : S[K] extends { rea…;
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 wireKeySym: typeof wireKeySymWhere the wire key (RpcGroup prefix) is stowed on a Tag. Solo
Tag
s use the
same string as
Context.Key.key
; shared-Spec instances use the factory wire key.
Read with
wireKeyOf
.
wireKeySym];
type type DialTarget = {
readonly key: string
readonly kind: ProtocolKind
readonly url?: string
readonly path?: string
}
DialTarget = {
readonly key: stringkey: string;
readonly kind: ProtocolKindkind: type ProtocolKind = "Http" | "WebSocket" | "IpcSocket"The transport a
Node
speaks — tag-style names (apps rarely type this alias; they write
the literals or get inference from url / path):
"Http" — RpcClient.layerProtocolHttp (servers / CLIs)
"WebSocket" — browser WS (layerProtocolWebsocket / client layerProtocolSocket over WS)
"IpcSocket" — Unix-domain socket (same-machine; see
ipcServer
)
Stamped on the node so the topology is self-describing about how to reach it — connect/client
derive the transport from it. Inferred from a ws(s):// url, an http target, or { path } →
IpcSocket; otherwise declare it explicitly.
ProtocolKind;
readonly url?: string | undefinedurl?: string;
readonly path?: string | undefinedpath?: string;
};
const const peersRecord: Record<
string,
PeerServiceOf<S>
>
peersRecord = var Object: ObjectConstructorProvides functionality common to all JavaScript objects.
Object.ObjectConstructor.create(o: object | null): any (+1 overload)Creates an object that has the specified prototype or that has null prototype.
create(null) as type Record<K extends keyof any, T> = {
[P in K]: T
}
Construct a type with a set of properties K of type T
Record<
string,
type PeerServiceOf<S extends Spec> = {
readonly [K in keyof S as S[K] extends {
readonly fleet: true
}
? never
: S[K] extends
| AnyLocalMethod
| AnyDefaultMethod
? never
: K]: S[K] extends {
readonly _tag: "ref"
}
? Effect.Effect<
SuccessOf<AsMethod<S[K]>>,
never,
never
>
: S[K] extends {
readonly kind: MethodKind
}
? ServiceMethod<AsMethod<S[K]>>
: S[K] extends Spec
? PeerServiceOf<S[K]>
: never
}
A peer's service as seen by
peers
— the per-instance ("leaf") wire methods only:
FleetField
s and
LocalMethod
s are excluded, so a fold can't recurse into a peer's
own fleet field. A full
ServiceOf
is assignable to it (width), so real clients fit.
PeerServiceOf<function (type parameter) S in <Self, S extends Spec, EIn = never, RIn = never>(tag: HyperlinkTag<Self, S>, self: AnyNode, options?: {
readonly nodes?: ReadonlyArray<AnyNode>;
readonly url?: (node: AnyNode) => Effect.Effect<string | undefined, EIn, RIn>;
}): Layer.Layer<PeersId<Self> | SelfNodeId<Self>, EIn, RIn>
S>
>;
const const peerScopes: Map<
string,
Scope.Closeable
>
peerScopes = new var Map: MapConstructor
new <string, Scope.Closeable>(iterable?: Iterable<readonly [string, Scope.Closeable]> | null | undefined) => Map<string, Scope.Closeable> (+3 overloads)
Map<string, import ScopeScope.Closeable>();
const const dialTargetOf: (row: {
readonly nodeKey: string
readonly kind: ProtocolKind
readonly url?: string
readonly path?: string
}) => DialTarget | undefined
dialTargetOf = (row: {
readonly nodeKey: string
readonly kind: ProtocolKind
readonly url?: string
readonly path?: string
}
row: {
readonly nodeKey: stringnodeKey: string;
readonly kind: ProtocolKindkind: type ProtocolKind = "Http" | "WebSocket" | "IpcSocket"The transport a
Node
speaks — tag-style names (apps rarely type this alias; they write
the literals or get inference from url / path):
"Http" — RpcClient.layerProtocolHttp (servers / CLIs)
"WebSocket" — browser WS (layerProtocolWebsocket / client layerProtocolSocket over WS)
"IpcSocket" — Unix-domain socket (same-machine; see
ipcServer
)
Stamped on the node so the topology is self-describing about how to reach it — connect/client
derive the transport from it. Inferred from a ws(s):// url, an http target, or { path } →
IpcSocket; otherwise declare it explicitly.
ProtocolKind;
readonly url?: string | undefinedurl?: string;
readonly path?: string | undefinedpath?: string;
}): type DialTarget = {
readonly key: string
readonly kind: ProtocolKind
readonly url?: string
readonly path?: string
}
DialTarget | undefined => {
if (row: {
readonly nodeKey: string
readonly kind: ProtocolKind
readonly url?: string
readonly path?: string
}
row.nodeKey: stringnodeKey === self: AnyNodeself.Key<unknown, NodeProtocol>.key: stringkey) return var undefinedundefined;
if (row: {
readonly nodeKey: string
readonly kind: ProtocolKind
readonly url?: string
readonly path?: string
}
row.kind: ProtocolKindkind === "IpcSocket" && row: {
readonly nodeKey: string
readonly kind: ProtocolKind
readonly url?: string
readonly path?: string
}
row.path?: string | undefinedpath !== var undefinedundefined) {
return { key: stringkey: row: {
readonly nodeKey: string
readonly kind: ProtocolKind
readonly url?: string
readonly path?: string
}
row.nodeKey: stringnodeKey, kind: ProtocolKindkind: row: {
readonly nodeKey: string
readonly kind: ProtocolKind
readonly url?: string
readonly path?: string
}
row.kind: ProtocolKindkind, path?: string | undefinedpath: row: {
readonly nodeKey: string
readonly kind: ProtocolKind
readonly url?: string
readonly path?: string
}
row.path?: stringpath };
}
if (row: {
readonly nodeKey: string
readonly kind: ProtocolKind
readonly url?: string
readonly path?: string
}
row.url?: string | undefinedurl !== var undefinedundefined) {
return { key: stringkey: row: {
readonly nodeKey: string
readonly kind: ProtocolKind
readonly url?: string
readonly path?: string
}
row.nodeKey: stringnodeKey, kind: ProtocolKindkind: row: {
readonly nodeKey: string
readonly kind: ProtocolKind
readonly url?: string
readonly path?: string
}
row.kind: ProtocolKindkind, url?: string | undefinedurl: row: {
readonly nodeKey: string
readonly kind: ProtocolKind
readonly url?: string
readonly path?: string
}
row.url?: stringurl };
}
return var undefinedundefined;
};
const const removePeer: (
nodeKey: string
) => Effect.Effect<void>
removePeer = (nodeKey: stringnodeKey: string): import EffectEffect.interface Effect<out A, out E = never, out R = never>The Effect interface defines a value that lazily describes a workflow or
job. The workflow requires some context R, and may fail with an error of
type E, or succeed with a value of type A.
When to use
Use when you need to represent a lazy, composable workflow that can require
services, fail with a typed error, or succeed with a typed value.
Details
Effect values model resourceful interaction with the outside world,
including synchronous, asynchronous, concurrent, and parallel interaction.
They use a fiber-based concurrency model, with built-in support for
scheduling, fine-grained interruption, structured concurrency, and high
scalability.
To run an Effect value, you need a Runtime, which is a type that is
capable of executing Effect values.
Effect<void> =>
import EffectEffect.const gen: {
<Eff extends Effect<any, any, any>, AEff>(
f: () => Generator<Eff, AEff, never>
): Effect<
AEff,
[Eff] extends [never]
? never
: [Eff] extends [
Effect<infer _A, infer E, infer _R>
]
? E
: never,
[Eff] extends [never]
? never
: [Eff] extends [
Effect<infer _A, infer _E, infer R>
]
? R
: never
>
<Self, Eff extends Effect<any, any, any>, AEff>(
options: { readonly self: Self },
f: (this: Self) => Generator<Eff, AEff, never>
): Effect<
AEff,
[Eff] extends [never]
? never
: [Eff] extends [
Effect<infer _A, infer E, infer _R>
]
? E
: never,
[Eff] extends [never]
? never
: [Eff] extends [
Effect<infer _A, infer _E, infer R>
]
? R
: never
>
}
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 scope: Scope.Closeable | undefinedscope = const peerScopes: Map<
string,
Scope.Closeable
>
peerScopes.Map<string, Closeable>.get(key: string): Scope.Closeable | undefinedReturns a specified element from the Map object. If the value that is associated to the provided key is an object, then you will get a reference to that object and any change made to that object will effectively modify it inside the Map.
get(nodeKey: stringnodeKey);
if (const scope: Scope.Closeable | undefinedscope === var undefinedundefined) return;
const peerScopes: Map<
string,
Scope.Closeable
>
peerScopes.Map<string, Closeable>.delete(key: string): booleandelete(nodeKey: stringnodeKey);
delete const peersRecord: Record<
string,
PeerServiceOf<S>
>
peersRecord[nodeKey: stringnodeKey];
yield* import ScopeScope.const close: <A, E>(
self: Scope,
exit: Exit<A, E>
) => Effect<void>
Closes a scope and runs its registered finalizers.
When to use
Use to close a scope manually with a specific exit value.
Details
Finalizers run in the scope's configured order and receive the supplied
Exit.
Example (Running scope finalizers)
import { Console, Effect, Exit, Scope } from "effect"
const resourceManagement = Effect.gen(function*() {
const scope = yield* Scope.make("sequential")
// Add multiple finalizers
yield* Scope.addFinalizer(scope, Console.log("Close database connection"))
yield* Scope.addFinalizer(scope, Console.log("Close file handle"))
yield* Scope.addFinalizer(scope, Console.log("Release memory"))
// Do some work...
yield* Console.log("Performing operations...")
// Close scope - finalizers run in reverse order of registration
yield* Scope.close(scope, Exit.succeed("Success!"))
// Output: "Release memory", "Close file handle", "Close database connection"
})
close(const scope: Scope.Closeableconst scope: {
strategy: "sequential" | "parallel";
state: State.Open | State.Closed | State.Empty;
}
scope, import ExitExit.const void: Exit.Exit<void, never>Provides a pre-allocated successful Exit with a void value.
When to use
Use when you need a shared successful Exit with no meaningful value.
Details
Equivalent to Exit.succeed(undefined) but shared as a single instance,
avoiding allocation for a common case.
Example (Referencing the void Exit)
import { Exit } from "effect"
const exit = Exit.void
console.log(Exit.isSuccess(exit)) // true
void);
});
const const upsertPeer: (row: {
readonly nodeKey: string
readonly kind: ProtocolKind
readonly url?: string
readonly path?: string
readonly serves: ReadonlyArray<string>
}) => Effect.Effect<void>
upsertPeer = (row: {
readonly nodeKey: string
readonly kind: ProtocolKind
readonly url?: string
readonly path?: string
readonly serves: ReadonlyArray<string>
}
row: {
readonly nodeKey: stringnodeKey: string;
readonly kind: ProtocolKindkind: type ProtocolKind = "Http" | "WebSocket" | "IpcSocket"The transport a
Node
speaks — tag-style names (apps rarely type this alias; they write
the literals or get inference from url / path):
"Http" — RpcClient.layerProtocolHttp (servers / CLIs)
"WebSocket" — browser WS (layerProtocolWebsocket / client layerProtocolSocket over WS)
"IpcSocket" — Unix-domain socket (same-machine; see
ipcServer
)
Stamped on the node so the topology is self-describing about how to reach it — connect/client
derive the transport from it. Inferred from a ws(s):// url, an http target, or { path } →
IpcSocket; otherwise declare it explicitly.
ProtocolKind;
readonly url?: string | undefinedurl?: string;
readonly path?: string | undefinedpath?: string;
readonly serves: readonly string[]serves: interface ReadonlyArray<T>ReadonlyArray<string>;
}): import EffectEffect.interface Effect<out A, out E = never, out R = never>The Effect interface defines a value that lazily describes a workflow or
job. The workflow requires some context R, and may fail with an error of
type E, or succeed with a value of type A.
When to use
Use when you need to represent a lazy, composable workflow that can require
services, fail with a typed error, or succeed with a typed value.
Details
Effect values model resourceful interaction with the outside world,
including synchronous, asynchronous, concurrent, and parallel interaction.
They use a fiber-based concurrency model, with built-in support for
scheduling, fine-grained interruption, structured concurrency, and high
scalability.
To run an Effect value, you need a Runtime, which is a type that is
capable of executing Effect values.
Effect<void> =>
import EffectEffect.const gen: {
<Eff extends Effect<any, any, any>, AEff>(
f: () => Generator<Eff, AEff, never>
): Effect<
AEff,
[Eff] extends [never]
? never
: [Eff] extends [
Effect<infer _A, infer E, infer _R>
]
? E
: never,
[Eff] extends [never]
? never
: [Eff] extends [
Effect<infer _A, infer _E, infer R>
]
? R
: never
>
<Self, Eff extends Effect<any, any, any>, AEff>(
options: { readonly self: Self },
f: (this: Self) => Generator<Eff, AEff, never>
): Effect<
AEff,
[Eff] extends [never]
? never
: [Eff] extends [
Effect<infer _A, infer E, infer _R>
]
? E
: never,
[Eff] extends [never]
? never
: [Eff] extends [
Effect<infer _A, infer _E, infer R>
]
? R
: never
>
}
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* () {
if (!row: {
readonly nodeKey: string
readonly kind: ProtocolKind
readonly url?: string
readonly path?: string
readonly serves: ReadonlyArray<string>
}
row.serves: readonly string[]serves.ReadonlyArray<string>.includes(searchElement: string, fromIndex?: number): booleanDetermines whether an array includes a certain element, returning true or false as appropriate.
includes(const serviceKey: stringserviceKey)) {
yield* const removePeer: (
nodeKey: string
) => Effect.Effect<void>
removePeer(row: {
readonly nodeKey: string
readonly kind: ProtocolKind
readonly url?: string
readonly path?: string
readonly serves: ReadonlyArray<string>
}
row.nodeKey: stringnodeKey);
return;
}
const const target: DialTarget | undefinedtarget = const dialTargetOf: (row: {
readonly nodeKey: string
readonly kind: ProtocolKind
readonly url?: string
readonly path?: string
}) => DialTarget | undefined
dialTargetOf(row: {
readonly nodeKey: string
readonly kind: ProtocolKind
readonly url?: string
readonly path?: string
readonly serves: ReadonlyArray<string>
}
row);
if (const target: DialTarget | undefinedtarget === var undefinedundefined) {
yield* const removePeer: (
nodeKey: string
) => Effect.Effect<void>
removePeer(row: {
readonly nodeKey: string
readonly kind: ProtocolKind
readonly url?: string
readonly path?: string
readonly serves: ReadonlyArray<string>
}
row.nodeKey: stringnodeKey);
return;
}
yield* const removePeer: (
nodeKey: string
) => Effect.Effect<void>
removePeer(row: {
readonly nodeKey: string
readonly kind: ProtocolKind
readonly url?: string
readonly path?: string
readonly serves: ReadonlyArray<string>
}
row.nodeKey: stringnodeKey);
const const scope: Scope.Closeableconst scope: {
strategy: "sequential" | "parallel";
state: State.Open | State.Closed | State.Empty;
}
scope = yield* import ScopeScope.const make: (
finalizerStrategy?: "sequential" | "parallel"
) => Effect<Closeable>
Creates a new Scope with the specified finalizer strategy.
Example (Creating a scope)
import { Console, Effect, Exit, Scope } from "effect"
const program = Effect.gen(function*() {
// Create a scope with sequential cleanup
const scope = yield* Scope.make("sequential")
// Add finalizers
yield* Scope.addFinalizer(scope, Console.log("Cleanup 1"))
yield* Scope.addFinalizer(scope, Console.log("Cleanup 2"))
// Close the scope (finalizers run in reverse order)
yield* Scope.close(scope, Exit.void)
// Output: "Cleanup 2", then "Cleanup 1"
})
make();
const const client: PeerServiceOf<S>client = yield* const buildPeerClientAt: <
Self,
S extends Spec
>(
tag: HyperlinkTag<Self, S>,
target: {
readonly key: string
readonly kind?: ProtocolKind
readonly url?: string
readonly path?: string
}
) => Effect.Effect<
PeerServiceOf<S>,
never,
Scope.Scope
>
Dial a peer from a directory row or static Node address — kind-aware (D3).
Prefer url when set (honors options.url overrides +
peerProtocolRef
);
WebSocket kind uses
protocolWebsocket
. Else IpcSocket/path →
protocolIpc
.
buildPeerClientAt(tag: HyperlinkTag<Self, S>(parameter) tag: {
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 DefaultMethod<infer F> ? F : S[K] extends …;
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 DefaultMethod<infer F> ? F : S[K] extends { readonly _…;
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 DefaultMethod<infer F> ? F : S[K] extends { rea…;
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 DefaultMethod<infer F> ? F : S[K] extends { rea…;
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 target: DialTargetconst target: {
key: string;
kind: ProtocolKind;
url: string;
path: string;
}
target).Pipeable.pipe<Effect.Effect<PeerServiceOf<S>, never, Scope.Scope>, Effect.Effect<PeerServiceOf<S>, never, never>>(this: Effect.Effect<PeerServiceOf<S>, never, Scope.Scope>, ab: (_: Effect.Effect<PeerServiceOf<S>, never, Scope.Scope>) => Effect.Effect<PeerServiceOf<S>, never, never>): Effect.Effect<PeerServiceOf<S>, never, never> (+21 overloads)pipe(
import ScopeScope.const provide: {
(value: Scope): <A, E, R>(
self: Effect<A, E, R>
) => Effect<A, E, Exclude<R, Scope>>
<A, E, R>(
self: Effect<A, E, R>,
value: Scope
): Effect<A, E, Exclude<R, Scope>>
}
Provides a concrete Scope to an effect.
When to use
Use to run an effect that requires Scope with a scope managed by the
caller.
Details
Providing the scope removes the Scope requirement from the effect context.
Example (Providing a scope)
import { Console, Effect, Scope } from "effect"
// An effect that requires a Scope
const program = Effect.gen(function*() {
const scope = yield* Scope.Scope
yield* Scope.addFinalizer(scope, Console.log("Cleanup"))
yield* Console.log("Working...")
})
// Provide a scope to the program
const withScope = Effect.gen(function*() {
const scope = yield* Scope.make()
yield* Scope.provide(scope)(program)
})
provide(const scope: Scope.Closeableconst scope: {
strategy: "sequential" | "parallel";
state: State.Open | State.Closed | State.Empty;
}
scope),
);
const peerScopes: Map<
string,
Scope.Closeable
>
peerScopes.Map<string, Closeable>.set(key: string, value: Scope.Closeable): Map<string, Scope.Closeable>Adds a new element with a specified key and value to the Map. If an element with the same key already exists, the element will be updated.
set(row: {
readonly nodeKey: string
readonly kind: ProtocolKind
readonly url?: string
readonly path?: string
readonly serves: ReadonlyArray<string>
}
row.nodeKey: stringnodeKey, const scope: Scope.Closeableconst scope: {
strategy: "sequential" | "parallel";
state: State.Open | State.Closed | State.Empty;
}
scope);
const peersRecord: Record<
string,
PeerServiceOf<S>
>
peersRecord[row: {
readonly nodeKey: string
readonly kind: ProtocolKind
readonly url?: string
readonly path?: string
readonly serves: ReadonlyArray<string>
}
row.nodeKey: stringnodeKey] = const client: PeerServiceOf<S>client;
});
const const rows: ReadonlyArray<LookupDirectoryEntry>rows = yield* const Lookup: typeof import("/Users/nikolasstow/Coding/Hyperlink/worktrees/epsilon/src/Lookup")const Lookup: {
resolveOnConflict: (...prefs: ReadonlyArray<OnConflict | undefined>) => OnConflictResolved;
Endpoint: typeof Endpoint;
ClaimRequest: typeof ClaimRequest;
ResolveRequest: typeof ResolveRequest;
DuplicateIdentity: typeof DuplicateIdentity;
DirectoryEntry: typeof LookupDirectoryEntry;
DirectoryUpserted: typeof DirectoryUpserted;
DirectoryRemoved: typeof DirectoryRemoved;
DirectoryChange: Schema.Union<readonly [typeof DirectoryUpserted, typeof DirectoryRemoved]>;
AdvertiseRequest: typeof AdvertiseRequest;
UnregisterRequest: typeof UnregisterRequest;
NodesServingRequest: typeof NodesServingRequest;
IncumbentAlive: typeof IncumbentAlive;
AdviseRequest: typeof AdviseRequest;
ClearAdviceRequest: typeof ClearAdviceRequest;
PreferredRequest: typeof PreferredRequest;
LookupUnaddressed: typeof LookupUnaddressed;
kind: 'hyperlink-ts/Lookup';
Identity: typeof LookupIdentity;
Directory: typeof LookupDirectory;
Advice: typeof LookupAdvice;
nodesServing: (service: string | { readonly key: string }) => Effect.Effect<ReadonlyArray<DirectoryEntry>, never, Directory>;
advise: (input: { readonly serviceKey: string; readonly prefer: string }) => Effect.Effect<string, never, Advice>;
prefer: (service: string | { readonly key: string }, nodeKey: string) => Effect.Effect<string, never, Advice>;
preferEntry: (service: string | { readonly key: string }, entry: { readonly nodeKey: string }) => Effect.Effect<string, never, Advice>;
clearAdvice: (service: string | { readonly key: string }) => Effect.Effect<boolean, never, Advice>;
preferred: (service: string | { readonly key: string }) => Effect.Effect<Option.Option<string>, never, Advice>;
changes: Stream.Stream<DirectoryChange, never, Directory>;
directoryTable: () => Effect.Effect<{ readonly get: Effect.Effect<ReadonlyMap<string, DirectoryEntry>>; readonly getNode: (nodeKey: string) => Effect.Effect<Option.Option<DirectoryEntry>> }, never, Directory | Scope.Scope>;
defaultIpcPath: '/tmp/hyperlink-ts-lookup.sock';
layerIpc: (path: string, options?: { readonly unlink?: boolean; readonly onConflict?: OnConflictResolved }) => Layer.Layer<Directory | Identity | Advice | Hyperlink.Local<Identity> | Handler<'claim'> | Handler<'resolve'> | Hyperlink.Local<Directory>…;
layerNode: (node: AnyNode & { readonly key: string }, options?: { readonly unlink?: boolean }) => Layer.Layer<never, LookupUnaddressed>;
directoryAdvertiseLayer: (node: AnyNode & { readonly key: string }, serves: ReadonlyArray<string>, options?: { readonly onConflict?: OnConflict }) => Layer.Layer<never, IncumbentAlive>;
client: (node: AnyNode & { readonly path?: string }) => Layer.Layer<Services, LookupUnaddressed>;
clientOptions: (options?: { readonly path?: string }) => Layer.Layer<Services, LookupUnaddressed>;
layerOptions: (options?: { readonly path?: string; readonly unlink?: boolean }) => Layer.Layer<Services>;
layer: Layer.Layer<Services>;
}
Lookup.const nodesServing: (
service: string | { readonly key: string }
) => Effect.Effect<
ReadonlyArray<DirectoryEntry>,
never,
Directory
>
List directory rows that advertise a HyperService (Tag or wire key).
Sugar over
Directory
.nodesServing — wire stays
NodesServingRequest
.
const rows = yield* Lookup.nodesServing(Jobs)
// or Lookup.nodesServing("fleet/Jobs")
nodesServing(tag: HyperlinkTag<Self, S>(parameter) tag: {
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 DefaultMethod<infer F> ? F : S[K] extends …;
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 DefaultMethod<infer F> ? F : S[K] extends { readonly _…;
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 DefaultMethod<infer F> ? F : S[K] extends { rea…;
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 DefaultMethod<infer F> ? F : S[K] extends { rea…;
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).Pipeable.pipe<Effect.Effect<readonly LookupDirectoryEntry[], never, LookupDirectory>, Effect.Effect<readonly LookupDirectoryEntry[], never, never>>(this: Effect.Effect<readonly LookupDirectoryEntry[], never, LookupDirectory>, ab: (_: Effect.Effect<readonly LookupDirectoryEntry[], never, LookupDirectory>) => Effect.Effect<readonly LookupDirectoryEntry[], never, never>): Effect.Effect<readonly LookupDirectoryEntry[], never, never> (+21 overloads)pipe(
import EffectEffect.const provideService: {
<I, S>(service: Context.Key<I, S>): {
(implementation: S): <A, E, R>(
self: Effect<A, E, R>
) => Effect<A, E, Exclude<R, I>>
<A, E, R>(
self: Effect<A, E, R>,
implementation: S
): Effect<A, E, Exclude<R, I>>
}
<I, S>(
service: Context.Key<I, S>,
implementation: S
): <A, E, R>(
self: Effect<A, E, R>
) => Effect<A, E, Exclude<R, I>>
<A, E, R, I, S>(
self: Effect<A, E, R>,
service: Context.Key<I, S>,
implementation: S
): 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(const Lookup: typeof import("/Users/nikolasstow/Coding/Hyperlink/worktrees/epsilon/src/Lookup")const Lookup: {
resolveOnConflict: (...prefs: ReadonlyArray<OnConflict | undefined>) => OnConflictResolved;
Endpoint: typeof Endpoint;
ClaimRequest: typeof ClaimRequest;
ResolveRequest: typeof ResolveRequest;
DuplicateIdentity: typeof DuplicateIdentity;
DirectoryEntry: typeof LookupDirectoryEntry;
DirectoryUpserted: typeof DirectoryUpserted;
DirectoryRemoved: typeof DirectoryRemoved;
DirectoryChange: Schema.Union<readonly [typeof DirectoryUpserted, typeof DirectoryRemoved]>;
AdvertiseRequest: typeof AdvertiseRequest;
UnregisterRequest: typeof UnregisterRequest;
NodesServingRequest: typeof NodesServingRequest;
IncumbentAlive: typeof IncumbentAlive;
AdviseRequest: typeof AdviseRequest;
ClearAdviceRequest: typeof ClearAdviceRequest;
PreferredRequest: typeof PreferredRequest;
LookupUnaddressed: typeof LookupUnaddressed;
kind: 'hyperlink-ts/Lookup';
Identity: typeof LookupIdentity;
Directory: typeof LookupDirectory;
Advice: typeof LookupAdvice;
nodesServing: (service: string | { readonly key: string }) => Effect.Effect<ReadonlyArray<DirectoryEntry>, never, Directory>;
advise: (input: { readonly serviceKey: string; readonly prefer: string }) => Effect.Effect<string, never, Advice>;
prefer: (service: string | { readonly key: string }, nodeKey: string) => Effect.Effect<string, never, Advice>;
preferEntry: (service: string | { readonly key: string }, entry: { readonly nodeKey: string }) => Effect.Effect<string, never, Advice>;
clearAdvice: (service: string | { readonly key: string }) => Effect.Effect<boolean, never, Advice>;
preferred: (service: string | { readonly key: string }) => Effect.Effect<Option.Option<string>, never, Advice>;
changes: Stream.Stream<DirectoryChange, never, Directory>;
directoryTable: () => Effect.Effect<{ readonly get: Effect.Effect<ReadonlyMap<string, DirectoryEntry>>; readonly getNode: (nodeKey: string) => Effect.Effect<Option.Option<DirectoryEntry>> }, never, Directory | Scope.Scope>;
defaultIpcPath: '/tmp/hyperlink-ts-lookup.sock';
layerIpc: (path: string, options?: { readonly unlink?: boolean; readonly onConflict?: OnConflictResolved }) => Layer.Layer<Directory | Identity | Advice | Hyperlink.Local<Identity> | Handler<'claim'> | Handler<'resolve'> | Hyperlink.Local<Directory>…;
layerNode: (node: AnyNode & { readonly key: string }, options?: { readonly unlink?: boolean }) => Layer.Layer<never, LookupUnaddressed>;
directoryAdvertiseLayer: (node: AnyNode & { readonly key: string }, serves: ReadonlyArray<string>, options?: { readonly onConflict?: OnConflict }) => Layer.Layer<never, IncumbentAlive>;
client: (node: AnyNode & { readonly path?: string }) => Layer.Layer<Services, LookupUnaddressed>;
clientOptions: (options?: { readonly path?: string }) => Layer.Layer<Services, LookupUnaddressed>;
layerOptions: (options?: { readonly path?: string; readonly unlink?: boolean }) => Layer.Layer<Services>;
layer: Layer.Layer<Services>;
}
Lookup.class Directoryclass Directory {
key: Identifier;
Service: {
advertise: (payload: { kind: 'Http' | 'WebSocket' | 'IpcSocket'; serves: ReadonlyArray<string>; nodeKey: string; url?: string | undefined; path?: string | undefined; onConflict?: 'livenessReplace' | 'askIncumbent' | 'reject' | 'inherit' | undefined }…;
unregister: (payload: { nodeKey: string; kind?: 'Http' | 'WebSocket' | 'IpcSocket' | undefined; url?: string | undefined; path?: string | undefined }) => Effect.Effect<boolean, never, never>;
nodesServing: (payload: { serviceKey: string }) => Effect.Effect<ReadonlyArray<LookupDirectoryEntry>, never, never>;
changes: Stream.Stream<DirectoryUpserted | DirectoryRemoved, never, never>;
};
description: string | undefined;
of: (this: void, self: { readonly advertise: (payload: { kind: 'Http' | 'WebSocket' | 'IpcSocket'; serves: ReadonlyArray<string>; nodeKey: string; url?: string | undefined; path?: string | undefined; onConflict?: 'livenessReplace' | 'askIncumb…;
context: (self: { readonly advertise: (payload: { kind: 'Http' | 'WebSocket' | 'IpcSocket'; serves: ReadonlyArray<string>; nodeKey: string; url?: string | undefined; path?: string | undefined; onConflict?: 'livenessReplace' | 'askIncumbent' | 'reje…;
use: (f: (service: { readonly advertise: (payload: { kind: 'Http' | 'WebSocket' | 'IpcSocket'; serves: ReadonlyArray<string>; nodeKey: string; url?: string | undefined; path?: string | undefined; onConflict?: 'livenessReplace' | 'askIncumbent' …;
useSync: (f: (service: { readonly advertise: (payload: { kind: 'Http' | 'WebSocket' | 'IpcSocket'; serves: ReadonlyArray<string>; nodeKey: string; url?: string | undefined; path?: string | undefined; onConflict?: 'livenessReplace' | 'askIncumbent' …;
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;
}
Lookup node directory — advertise / unregister / list by served HyperService key /
directorySpec.changes
membership push.
Directory, const directory: {
readonly advertise: (payload: {
kind: "Http" | "WebSocket" | "IpcSocket";
serves: readonly string[];
nodeKey: string;
url?: string | undefined;
path?: string | undefined;
onConflict?: "livenessReplace" | "askIncumbent" | "reject" | "inherit" | undefined;
}) => Effect.Effect<LookupDirectoryEntry, IncumbentAlive, never>;
readonly unregister: (payload: {
nodeKey: string;
kind?: "Http" | "WebSocket" | "IpcSocket" | undefined;
url?: string | undefined;
path?: string | undefined;
}) => Effect.Effect<boolean, never, never>;
readonly nodesServing: (payload: {
...;
}) => Effect.Effect<...>;
readonly changes: Stream.Stream<...>;
}
directory),
);
yield* import EffectEffect.const forEach: {
<
B,
E,
R,
S extends Iterable<any>,
Discard extends boolean = false
>(
f: (
a: Arr.ReadonlyArray.Infer<S>,
i: number
) => Effect<B, E, R>,
options?:
| {
readonly concurrency?:
| Concurrency
| undefined
readonly discard?: Discard | undefined
}
| undefined
): (
self: S
) => Effect<
Discard extends false
? Arr.ReadonlyArray.With<S, B>
: void,
E,
R
>
<
B,
E,
R,
S extends Iterable<any>,
Discard extends boolean = false
>(
self: S,
f: (
a: Arr.ReadonlyArray.Infer<S>,
i: number
) => Effect<B, E, R>,
options?:
| {
readonly concurrency?:
| Concurrency
| undefined
readonly discard?: Discard | undefined
}
| undefined
): Effect<
Discard extends false
? Arr.ReadonlyArray.With<S, B>
: void,
E,
R
>
}
Executes an effectful operation for each element in an Iterable.
When to use
Use to traverse an iterable with an effectful function while preserving
element order in the collected results.
Details
The forEach function applies a provided operation to each element in the
iterable, producing a new effect that returns an array of results.
If any effect fails, the iteration stops immediately (short-circuiting), and
the error is propagated.
Concurrency:
The concurrency option controls how many operations are performed
concurrently. By default, the operations are performed sequentially.
Discarding Results:
If the discard option is set to true, the intermediate results are not
collected, and the final result of the operation is void.
Example (Mapping over an iterable with effects)
import { Console, Effect } from "effect"
const result = Effect.forEach(
[1, 2, 3, 4, 5],
(n, index) =>
Console.log(`Currently at index ${index}`).pipe(Effect.as(n * 2))
)
Effect.runPromise(result).then(console.log)
// Output:
// Currently at index 0
// Currently at index 1
// Currently at index 2
// Currently at index 3
// Currently at index 4
// [ 2, 4, 6, 8, 10 ]
Example (Running effects without collecting results)
import { Console, Effect } from "effect"
// Apply effects but discard the results
const result = Effect.forEach(
[1, 2, 3, 4, 5],
(n, index) =>
Console.log(`Currently at index ${index}`).pipe(Effect.as(n * 2)),
{ discard: true }
)
Effect.runPromise(result).then(console.log)
// Output:
// Currently at index 0
// Currently at index 1
// Currently at index 2
// Currently at index 3
// Currently at index 4
// undefined
forEach(const rows: ReadonlyArray<LookupDirectoryEntry>rows, const upsertPeer: (row: {
readonly nodeKey: string
readonly kind: ProtocolKind
readonly url?: string
readonly path?: string
readonly serves: ReadonlyArray<string>
}) => Effect.Effect<void>
upsertPeer, { discard?: true | undefineddiscard: true });
yield* const directory: {
readonly advertise: (payload: {
kind: "Http" | "WebSocket" | "IpcSocket";
serves: readonly string[];
nodeKey: string;
url?: string | undefined;
path?: string | undefined;
onConflict?: "livenessReplace" | "askIncumbent" | "reject" | "inherit" | undefined;
}) => Effect.Effect<LookupDirectoryEntry, IncumbentAlive, never>;
readonly unregister: (payload: {
nodeKey: string;
kind?: "Http" | "WebSocket" | "IpcSocket" | undefined;
url?: string | undefined;
path?: string | undefined;
}) => Effect.Effect<boolean, never, never>;
readonly nodesServing: (payload: {
...;
}) => Effect.Effect<...>;
readonly changes: Stream.Stream<...>;
}
directory.changes: Stream.Stream<
DirectoryUpserted | DirectoryRemoved,
never,
never
>
(property) changes: {
channel: Channel.Channel<Arr.NonEmptyReadonlyArray<A>, E, void, unknown, unknown, unknown, R>;
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; <…;
}
changes.Pipeable.pipe<Stream.Stream<DirectoryUpserted | DirectoryRemoved, never, never>, Effect.Effect<void, never, never>, Effect.Effect<Fiber.Fiber<void, never>, never, Scope.Scope>>(this: Stream.Stream<DirectoryUpserted | DirectoryRemoved, never, never>, ab: (_: Stream.Stream<DirectoryUpserted | DirectoryRemoved, never, never>) => Effect.Effect<void, never, never>, bc: (_: Effect.Effect<void, never, never>) => Effect.Effect<Fiber.Fiber<void, never>, never, Scope.Scope>): Effect.Effect<...> (+21 overloads)pipe(
import StreamStream.const runForEach: {
<A, X, E2, R2>(
f: (a: A) => Effect.Effect<X, E2, R2>
): <E, R>(
self: Stream<A, E, R>
) => Effect.Effect<void, E2 | E, R2 | R>
<A, E, R, X, E2, R2>(
self: Stream<A, E, R>,
f: (a: A) => Effect.Effect<X, E2, R2>
): Effect.Effect<void, E | E2, R | R2>
}
Runs the provided effectful callback for each element of the stream.
Example (Running an effect for each value)
import { Console, Effect, Stream } from "effect"
const stream = Stream.make(1, 2, 3)
const program = Effect.gen(function*() {
yield* Stream.runForEach(stream, (n) => Console.log(`Processing: ${n}`))
})
Effect.runPromise(program)
// Processing: 1
// Processing: 2
// Processing: 3
runForEach((event: DirectoryUpserted | DirectoryRemovedevent) => {
if (event: DirectoryUpserted | DirectoryRemovedevent._tag: "DirectoryUpserted" | "DirectoryRemoved"_tag === "DirectoryRemoved") {
return const removePeer: (
nodeKey: string
) => Effect.Effect<void>
removePeer(event: DirectoryRemoved(parameter) event: {
_tag: 'DirectoryRemoved';
nodeKey: string;
previous: LookupDirectoryEntry;
}
event.nodeKey: stringnodeKey);
}
// New peer, dial moved, or serves list may add/remove this service key.
if (
event: DirectoryUpserted(parameter) event: {
_tag: 'DirectoryUpserted';
entry: LookupDirectoryEntry;
dialChanged: boolean;
previous: LookupDirectoryEntry | undefined;
}
event.previous?: LookupDirectoryEntry | undefinedprevious === var undefinedundefined ||
event: DirectoryUpserted(parameter) event: {
_tag: 'DirectoryUpserted';
entry: LookupDirectoryEntry;
dialChanged: boolean;
previous: LookupDirectoryEntry | undefined;
}
event.dialChanged: booleandialChanged ||
const peersRecord: Record<
string,
PeerServiceOf<S>
>
peersRecord[event: DirectoryUpserted(parameter) event: {
_tag: 'DirectoryUpserted';
entry: LookupDirectoryEntry;
dialChanged: boolean;
previous: LookupDirectoryEntry | undefined;
}
event.entry: LookupDirectoryEntry(property) entry: {
kind: 'Http' | 'WebSocket' | 'IpcSocket';
serves: ReadonlyArray<string>;
nodeKey: string;
url: string | undefined;
path: string | undefined;
}
entry.nodeKey: stringnodeKey] === var undefinedundefined ||
!event: DirectoryUpserted(parameter) event: {
_tag: 'DirectoryUpserted';
entry: LookupDirectoryEntry;
dialChanged: boolean;
previous: LookupDirectoryEntry | undefined;
}
event.entry: LookupDirectoryEntry(property) entry: {
kind: 'Http' | 'WebSocket' | 'IpcSocket';
serves: ReadonlyArray<string>;
nodeKey: string;
url: string | undefined;
path: string | undefined;
}
entry.serves: readonly string[]serves.ReadonlyArray<string>.includes(searchElement: string, fromIndex?: number): booleanDetermines whether an array includes a certain element, returning true or false as appropriate.
includes(const serviceKey: stringserviceKey)
) {
return const upsertPeer: (row: {
readonly nodeKey: string
readonly kind: ProtocolKind
readonly url?: string
readonly path?: string
readonly serves: ReadonlyArray<string>
}) => Effect.Effect<void>
upsertPeer(event: DirectoryUpserted(parameter) event: {
_tag: 'DirectoryUpserted';
entry: LookupDirectoryEntry;
dialChanged: boolean;
previous: LookupDirectoryEntry | undefined;
}
event.entry: LookupDirectoryEntry(property) entry: {
kind: 'Http' | 'WebSocket' | 'IpcSocket';
serves: ReadonlyArray<string>;
nodeKey: string;
url: string | undefined;
path: string | undefined;
}
entry);
}
return import EffectEffect.const void: Effect.Effect<void, never, never>(alias) const void: {
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;
}
Returns an effect that succeeds with void.
void;
}),
import EffectEffect.const forkScoped: <
Arg extends
| Effect<any, any, any>
| {
readonly startImmediately?:
| boolean
| undefined
readonly uninterruptible?:
| boolean
| "inherit"
| undefined
}
| undefined = {
readonly startImmediately?:
| boolean
| undefined
readonly uninterruptible?:
| boolean
| "inherit"
| undefined
}
>(
effectOrOptions?: Arg,
options?:
| {
readonly startImmediately?:
| boolean
| undefined
readonly uninterruptible?:
| boolean
| "inherit"
| undefined
}
| undefined
) => [Arg] extends [
Effect<infer _A, infer _E, infer _R>
]
? Effect<Fiber<_A, _E>, never, _R | Scope>
: <A, E, R>(
self: Effect<A, E, R>
) => Effect<Fiber<A, E>, never, R | Scope>
Forks the fiber in a Scope, interrupting it when the scope is closed.
Example (Forking into the current scope)
import { Effect } from "effect"
const backgroundTask = Effect.gen(function*() {
yield* Effect.sleep("5 seconds")
yield* Effect.log("Background task completed")
return "result"
})
const program = Effect.scoped(
Effect.gen(function*() {
const fiber = yield* backgroundTask.pipe(Effect.forkScoped)
// or fork a fiber that starts immediately:
yield* backgroundTask.pipe(Effect.forkScoped({ startImmediately: true }))
yield* Effect.log("Task forked in scope")
yield* Effect.sleep("1 second")
// Fiber will be interrupted when scope closes
return "scope completed"
})
)
forkScoped,
);
yield* import EffectEffect.const addFinalizer: <R>(
finalizer: (
exit: Exit.Exit<unknown, unknown>
) => Effect<void, never, R>
) => Effect<void, never, R | Scope>
Adds a finalizer to the current scope.
When to use
Use to register low-level cleanup in the current scope.
Details
The finalizer runs when the surrounding scope is closed and receives the
Exit value used to close the scope.
Example (Registering scope finalizers)
import { Console, Effect, Exit } from "effect"
const program = Effect.scoped(
Effect.gen(function*() {
// Add a finalizer that runs when the scope closes
yield* Effect.addFinalizer((exit) =>
Console.log(
Exit.isSuccess(exit)
? "Cleanup: Operation completed successfully"
: "Cleanup: Operation failed, cleaning up resources"
)
)
yield* Console.log("Performing main operation...")
// This could succeed or fail
return "operation result"
})
)
Effect.runPromise(program).then(console.log)
// Output:
// Performing main operation...
// Cleanup: Operation completed successfully
// operation result
addFinalizer(() =>
import EffectEffect.const forEach: {
<
B,
E,
R,
S extends Iterable<any>,
Discard extends boolean = false
>(
f: (
a: Arr.ReadonlyArray.Infer<S>,
i: number
) => Effect<B, E, R>,
options?:
| {
readonly concurrency?:
| Concurrency
| undefined
readonly discard?: Discard | undefined
}
| undefined
): (
self: S
) => Effect<
Discard extends false
? Arr.ReadonlyArray.With<S, B>
: void,
E,
R
>
<
B,
E,
R,
S extends Iterable<any>,
Discard extends boolean = false
>(
self: S,
f: (
a: Arr.ReadonlyArray.Infer<S>,
i: number
) => Effect<B, E, R>,
options?:
| {
readonly concurrency?:
| Concurrency
| undefined
readonly discard?: Discard | undefined
}
| undefined
): Effect<
Discard extends false
? Arr.ReadonlyArray.With<S, B>
: void,
E,
R
>
}
Executes an effectful operation for each element in an Iterable.
When to use
Use to traverse an iterable with an effectful function while preserving
element order in the collected results.
Details
The forEach function applies a provided operation to each element in the
iterable, producing a new effect that returns an array of results.
If any effect fails, the iteration stops immediately (short-circuiting), and
the error is propagated.
Concurrency:
The concurrency option controls how many operations are performed
concurrently. By default, the operations are performed sequentially.
Discarding Results:
If the discard option is set to true, the intermediate results are not
collected, and the final result of the operation is void.
Example (Mapping over an iterable with effects)
import { Console, Effect } from "effect"
const result = Effect.forEach(
[1, 2, 3, 4, 5],
(n, index) =>
Console.log(`Currently at index ${index}`).pipe(Effect.as(n * 2))
)
Effect.runPromise(result).then(console.log)
// Output:
// Currently at index 0
// Currently at index 1
// Currently at index 2
// Currently at index 3
// Currently at index 4
// [ 2, 4, 6, 8, 10 ]
Example (Running effects without collecting results)
import { Console, Effect } from "effect"
// Apply effects but discard the results
const result = Effect.forEach(
[1, 2, 3, 4, 5],
(n, index) =>
Console.log(`Currently at index ${index}`).pipe(Effect.as(n * 2)),
{ discard: true }
)
Effect.runPromise(result).then(console.log)
// Output:
// Currently at index 0
// Currently at index 1
// Currently at index 2
// Currently at index 3
// Currently at index 4
// undefined
forEach([...const peerScopes: Map<
string,
Scope.Closeable
>
peerScopes.Map<string, Closeable>.keys(): MapIterator<string>Returns an iterable of keys in the map
keys()], const removePeer: (
nodeKey: string
) => Effect.Effect<void>
removePeer, {
discard?: true | undefineddiscard: true,
}),
);
return const peersRecord: Record<
string,
PeerServiceOf<S>
>
peersRecord;
}
// Fixed fleet (or undeclared → []); drop self to get the peers.
const const fleet: ReadonlyArray<AnyNode>fleet = const stamped:
| readonly AnyNode[]
| undefined
stamped ?? [];
const const others: Array<AnyNode>others = const fleet: ReadonlyArray<AnyNode>fleet.ReadonlyArray<AnyNode>.filter(predicate: (value: AnyNode, index: number, array: readonly AnyNode[]) => unknown, thisArg?: any): AnyNode[] (+1 overload)Returns the elements of an array that meet the condition specified in a callback function.
filter((node: AnyNodenode) => node: AnyNodenode.Key<unknown, NodeProtocol>.key: stringkey !== self: AnyNodeself.Key<unknown, NodeProtocol>.key: stringkey);
const const resolveUrl: (
node: AnyNode
) => Effect.Effect<string | undefined, EIn, RIn>
resolveUrl = (
node: AnyNodenode: type AnyNode = NodeKey<unknown> & {
readonly url: string | undefined;
readonly path: string | undefined;
readonly kind: ProtocolKind | undefined;
readonly endpoints?: Endpoints;
readonly onConflict?: OnConflict;
readonly [portSym]?: number;
}
A
Tag
erased — its transport endpoints set, plus the primary address
(url and/or Unix path) and
ProtocolKind
kind (the first-declared endpoint, kept for
single-protocol readers), so a tag's distributed set is self-describing about where AND how to
reach each one.
AnyNode,
): import EffectEffect.interface Effect<out A, out E = never, out R = never>The Effect interface defines a value that lazily describes a workflow or
job. The workflow requires some context R, and may fail with an error of
type E, or succeed with a value of type A.
When to use
Use when you need to represent a lazy, composable workflow that can require
services, fail with a typed error, or succeed with a typed value.
Details
Effect values model resourceful interaction with the outside world,
including synchronous, asynchronous, concurrent, and parallel interaction.
They use a fiber-based concurrency model, with built-in support for
scheduling, fine-grained interruption, structured concurrency, and high
scalability.
To run an Effect value, you need a Runtime, which is a type that is
capable of executing Effect values.
Effect<string | undefined, function (type parameter) EIn in <Self, S extends Spec, EIn = never, RIn = never>(tag: HyperlinkTag<Self, S>, self: AnyNode, options?: {
readonly nodes?: ReadonlyArray<AnyNode>;
readonly url?: (node: AnyNode) => Effect.Effect<string | undefined, EIn, RIn>;
}): Layer.Layer<PeersId<Self> | SelfNodeId<Self>, EIn, RIn>
EIn, function (type parameter) RIn in <Self, S extends Spec, EIn = never, RIn = never>(tag: HyperlinkTag<Self, S>, self: AnyNode, options?: {
readonly nodes?: ReadonlyArray<AnyNode>;
readonly url?: (node: AnyNode) => Effect.Effect<string | undefined, EIn, RIn>;
}): Layer.Layer<PeersId<Self> | SelfNodeId<Self>, EIn, RIn>
RIn> =>
options: {
readonly nodes?: ReadonlyArray<AnyNode>
readonly url?: (
node: AnyNode
) => Effect.Effect<string | undefined, EIn, RIn>
}
options?.url?: (
node: AnyNode
) => Effect.Effect<string | undefined, EIn, RIn>
url === var undefinedundefined
? import EffectEffect.const succeed: <A>(value: A) => Effect<A>Creates an Effect that always succeeds with a given value.
When to use
Use when an effect should complete successfully with a specific value without any errors
or external dependencies.
Example (Creating a successful effect)
import { Effect } from "effect"
// Creating an effect that represents a successful scenario
//
// ┌─── Effect<number, never, never>
// ▼
const success = Effect.succeed(42)
succeed(node: AnyNodenode.url: string | undefinedurl)
: import EffectEffect.const map: {
<A, B>(f: (a: A) => B): <E, R>(
self: Effect<A, E, R>
) => Effect<B, E, R>
<A, E, R, B>(
self: Effect<A, E, R>,
f: (a: A) => B
): Effect<B, E, R>
}
Transforms the value inside an effect by applying a function to it.
When to use
Use to transform an effect's success value with a function that returns a
plain value, producing a new effect without changing the original effect's
typed error or context requirements.
Details
map takes a function and applies it to the value contained within an
effect, creating a new effect with the transformed value.
It's important to note that effects are immutable, meaning that the original
effect is not modified. Instead, a new effect is returned with the updated
value.
Example (Choosing map syntax variants)
import { Effect, pipe } from "effect"
const myEffect = Effect.succeed(1)
const transformation = (n: number) => n + 1
const mappedWithPipe = pipe(myEffect, Effect.map(transformation))
const mappedWithDataFirst = Effect.map(myEffect, transformation)
const mappedWithMethod = myEffect.pipe(Effect.map(transformation))
Example (Adding a service charge)
import { Effect, pipe } from "effect"
const addServiceCharge = (amount: number) => amount + 1
const fetchTransactionAmount = Effect.promise(() => Promise.resolve(100))
const finalAmount = pipe(
fetchTransactionAmount,
Effect.map(addServiceCharge)
)
Effect.runPromise(finalAmount).then(console.log)
// Output: 101
map(options: {
readonly nodes?: ReadonlyArray<AnyNode>
readonly url?: (
node: AnyNode
) => Effect.Effect<string | undefined, EIn, RIn>
}
options.url?: (
node: AnyNode
) => Effect.Effect<string | undefined, EIn, RIn>
url(node: AnyNodenode), (override: string | undefinedoverride) => override: string | undefinedoverride ?? node: AnyNodenode.url: string | undefinedurl);
const const resolved: {
key: string
kind: ProtocolKind | undefined
url: string | undefined
path: string | undefined
}[]
resolved = yield* import EffectEffect.const forEach: {
<
B,
E,
R,
S extends Iterable<any>,
Discard extends boolean = false
>(
f: (
a: Arr.ReadonlyArray.Infer<S>,
i: number
) => Effect<B, E, R>,
options?:
| {
readonly concurrency?:
| Concurrency
| undefined
readonly discard?: Discard | undefined
}
| undefined
): (
self: S
) => Effect<
Discard extends false
? Arr.ReadonlyArray.With<S, B>
: void,
E,
R
>
<
B,
E,
R,
S extends Iterable<any>,
Discard extends boolean = false
>(
self: S,
f: (
a: Arr.ReadonlyArray.Infer<S>,
i: number
) => Effect<B, E, R>,
options?:
| {
readonly concurrency?:
| Concurrency
| undefined
readonly discard?: Discard | undefined
}
| undefined
): Effect<
Discard extends false
? Arr.ReadonlyArray.With<S, B>
: void,
E,
R
>
}
Executes an effectful operation for each element in an Iterable.
When to use
Use to traverse an iterable with an effectful function while preserving
element order in the collected results.
Details
The forEach function applies a provided operation to each element in the
iterable, producing a new effect that returns an array of results.
If any effect fails, the iteration stops immediately (short-circuiting), and
the error is propagated.
Concurrency:
The concurrency option controls how many operations are performed
concurrently. By default, the operations are performed sequentially.
Discarding Results:
If the discard option is set to true, the intermediate results are not
collected, and the final result of the operation is void.
Example (Mapping over an iterable with effects)
import { Console, Effect } from "effect"
const result = Effect.forEach(
[1, 2, 3, 4, 5],
(n, index) =>
Console.log(`Currently at index ${index}`).pipe(Effect.as(n * 2))
)
Effect.runPromise(result).then(console.log)
// Output:
// Currently at index 0
// Currently at index 1
// Currently at index 2
// Currently at index 3
// Currently at index 4
// [ 2, 4, 6, 8, 10 ]
Example (Running effects without collecting results)
import { Console, Effect } from "effect"
// Apply effects but discard the results
const result = Effect.forEach(
[1, 2, 3, 4, 5],
(n, index) =>
Console.log(`Currently at index ${index}`).pipe(Effect.as(n * 2)),
{ discard: true }
)
Effect.runPromise(result).then(console.log)
// Output:
// Currently at index 0
// Currently at index 1
// Currently at index 2
// Currently at index 3
// Currently at index 4
// undefined
forEach(const others: Array<AnyNode>others, (node: AnyNodenode) =>
import EffectEffect.const map: {
<A, B>(f: (a: A) => B): <E, R>(
self: Effect<A, E, R>
) => Effect<B, E, R>
<A, E, R, B>(
self: Effect<A, E, R>,
f: (a: A) => B
): Effect<B, E, R>
}
Transforms the value inside an effect by applying a function to it.
When to use
Use to transform an effect's success value with a function that returns a
plain value, producing a new effect without changing the original effect's
typed error or context requirements.
Details
map takes a function and applies it to the value contained within an
effect, creating a new effect with the transformed value.
It's important to note that effects are immutable, meaning that the original
effect is not modified. Instead, a new effect is returned with the updated
value.
Example (Choosing map syntax variants)
import { Effect, pipe } from "effect"
const myEffect = Effect.succeed(1)
const transformation = (n: number) => n + 1
const mappedWithPipe = pipe(myEffect, Effect.map(transformation))
const mappedWithDataFirst = Effect.map(myEffect, transformation)
const mappedWithMethod = myEffect.pipe(Effect.map(transformation))
Example (Adding a service charge)
import { Effect, pipe } from "effect"
const addServiceCharge = (amount: number) => amount + 1
const fetchTransactionAmount = Effect.promise(() => Promise.resolve(100))
const finalAmount = pipe(
fetchTransactionAmount,
Effect.map(addServiceCharge)
)
Effect.runPromise(finalAmount).then(console.log)
// Output: 101
map(const resolveUrl: (
node: AnyNode
) => Effect.Effect<string | undefined, EIn, RIn>
resolveUrl(node: AnyNodenode), (url: string | undefinedurl) => ({
key: stringkey: node: AnyNodenode.Key<unknown, NodeProtocol>.key: stringkey,
kind: ProtocolKind | undefinedkind: node: AnyNodenode.kind: ProtocolKind | undefinedkind,
url: string | undefinedurl,
path: string | undefinedpath: node: AnyNodenode.path: string | undefinedpath,
})),
);
const const entries: (readonly [
string,
PeerServiceOf<S>
])[]
entries = yield* import EffectEffect.const forEach: {
<
B,
E,
R,
S extends Iterable<any>,
Discard extends boolean = false
>(
f: (
a: Arr.ReadonlyArray.Infer<S>,
i: number
) => Effect<B, E, R>,
options?:
| {
readonly concurrency?:
| Concurrency
| undefined
readonly discard?: Discard | undefined
}
| undefined
): (
self: S
) => Effect<
Discard extends false
? Arr.ReadonlyArray.With<S, B>
: void,
E,
R
>
<
B,
E,
R,
S extends Iterable<any>,
Discard extends boolean = false
>(
self: S,
f: (
a: Arr.ReadonlyArray.Infer<S>,
i: number
) => Effect<B, E, R>,
options?:
| {
readonly concurrency?:
| Concurrency
| undefined
readonly discard?: Discard | undefined
}
| undefined
): Effect<
Discard extends false
? Arr.ReadonlyArray.With<S, B>
: void,
E,
R
>
}
Executes an effectful operation for each element in an Iterable.
When to use
Use to traverse an iterable with an effectful function while preserving
element order in the collected results.
Details
The forEach function applies a provided operation to each element in the
iterable, producing a new effect that returns an array of results.
If any effect fails, the iteration stops immediately (short-circuiting), and
the error is propagated.
Concurrency:
The concurrency option controls how many operations are performed
concurrently. By default, the operations are performed sequentially.
Discarding Results:
If the discard option is set to true, the intermediate results are not
collected, and the final result of the operation is void.
Example (Mapping over an iterable with effects)
import { Console, Effect } from "effect"
const result = Effect.forEach(
[1, 2, 3, 4, 5],
(n, index) =>
Console.log(`Currently at index ${index}`).pipe(Effect.as(n * 2))
)
Effect.runPromise(result).then(console.log)
// Output:
// Currently at index 0
// Currently at index 1
// Currently at index 2
// Currently at index 3
// Currently at index 4
// [ 2, 4, 6, 8, 10 ]
Example (Running effects without collecting results)
import { Console, Effect } from "effect"
// Apply effects but discard the results
const result = Effect.forEach(
[1, 2, 3, 4, 5],
(n, index) =>
Console.log(`Currently at index ${index}`).pipe(Effect.as(n * 2)),
{ discard: true }
)
Effect.runPromise(result).then(console.log)
// Output:
// Currently at index 0
// Currently at index 1
// Currently at index 2
// Currently at index 3
// Currently at index 4
// undefined
forEach(
// no dialable address → skip (partial mesh); ipc path counts when url absent
const resolved: {
key: string
kind: ProtocolKind | undefined
url: string | undefined
path: string | undefined
}[]
resolved.Array<{ key: string; kind: ProtocolKind | undefined; url: string | undefined; path: string | undefined; }>.filter(predicate: (value: {
key: string;
kind: ProtocolKind | undefined;
url: string | undefined;
path: string | undefined;
}, index: number, array: {
key: string;
kind: ProtocolKind | undefined;
url: string | undefined;
path: string | undefined;
}[]) => unknown, thisArg?: any): {
key: string;
kind: ProtocolKind | undefined;
url: string | undefined;
path: string | undefined;
}[] (+1 overload)
Returns the elements of an array that meet the condition specified in a callback function.
filter(
(entry: {
key: string
kind: ProtocolKind | undefined
url: string | undefined
path: string | undefined
}
entry) =>
entry: {
key: string
kind: ProtocolKind | undefined
url: string | undefined
path: string | undefined
}
entry.url: string | undefinedurl !== var undefinedundefined ||
(entry: {
key: string
kind: ProtocolKind | undefined
url: string | undefined
path: string | undefined
}
entry.kind: ProtocolKind | undefinedkind === "IpcSocket" && entry: {
key: string
kind: ProtocolKind | undefined
url: string | undefined
path: string | undefined
}
entry.path: string | undefinedpath !== var undefinedundefined),
),
(target: {
key: string
kind: ProtocolKind | undefined
url: string | undefined
path: string | undefined
}
target) =>
import EffectEffect.const map: {
<A, B>(f: (a: A) => B): <E, R>(
self: Effect<A, E, R>
) => Effect<B, E, R>
<A, E, R, B>(
self: Effect<A, E, R>,
f: (a: A) => B
): Effect<B, E, R>
}
Transforms the value inside an effect by applying a function to it.
When to use
Use to transform an effect's success value with a function that returns a
plain value, producing a new effect without changing the original effect's
typed error or context requirements.
Details
map takes a function and applies it to the value contained within an
effect, creating a new effect with the transformed value.
It's important to note that effects are immutable, meaning that the original
effect is not modified. Instead, a new effect is returned with the updated
value.
Example (Choosing map syntax variants)
import { Effect, pipe } from "effect"
const myEffect = Effect.succeed(1)
const transformation = (n: number) => n + 1
const mappedWithPipe = pipe(myEffect, Effect.map(transformation))
const mappedWithDataFirst = Effect.map(myEffect, transformation)
const mappedWithMethod = myEffect.pipe(Effect.map(transformation))
Example (Adding a service charge)
import { Effect, pipe } from "effect"
const addServiceCharge = (amount: number) => amount + 1
const fetchTransactionAmount = Effect.promise(() => Promise.resolve(100))
const finalAmount = pipe(
fetchTransactionAmount,
Effect.map(addServiceCharge)
)
Effect.runPromise(finalAmount).then(console.log)
// Output: 101
map(
const buildPeerClientAt: <
Self,
S extends Spec
>(
tag: HyperlinkTag<Self, S>,
target: {
readonly key: string
readonly kind?: ProtocolKind
readonly url?: string
readonly path?: string
}
) => Effect.Effect<
PeerServiceOf<S>,
never,
Scope.Scope
>
Dial a peer from a directory row or static Node address — kind-aware (D3).
Prefer url when set (honors options.url overrides +
peerProtocolRef
);
WebSocket kind uses
protocolWebsocket
. Else IpcSocket/path →
protocolIpc
.
buildPeerClientAt(tag: HyperlinkTag<Self, S>(parameter) tag: {
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 DefaultMethod<infer F> ? F : S[K] extends …;
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 DefaultMethod<infer F> ? F : S[K] extends { readonly _…;
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 DefaultMethod<infer F> ? F : S[K] extends { rea…;
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 DefaultMethod<infer F> ? F : S[K] extends { rea…;
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, {
key: stringkey: target: {
key: string
kind: ProtocolKind | undefined
url: string | undefined
path: string | undefined
}
target.key: stringkey,
kind?: ProtocolKind | undefinedkind: target: {
key: string
kind: ProtocolKind | undefined
url: string | undefined
path: string | undefined
}
target.kind: ProtocolKind | undefinedkind,
...(target: {
key: string
kind: ProtocolKind | undefined
url: string | undefined
path: string | undefined
}
target.url: string | undefinedurl !== var undefinedundefined ? { url?: string | undefinedurl: target: {
key: string
kind: ProtocolKind | undefined
url: string | undefined
path: string | undefined
}
target.url: stringurl } : {}),
...(target: {
key: string
kind: ProtocolKind | undefined
url: string | undefined
path: string | undefined
}
target.path: string | undefinedpath !== var undefinedundefined ? { path?: string | undefinedpath: target: {
key: string
kind: ProtocolKind | undefined
url: string | undefined
path: string | undefined
}
target.path: stringpath } : {}),
}),
(client: PeerServiceOf<S>client) => [target: {
key: string
kind: ProtocolKind | undefined
url: string | undefined
path: string | undefined
}
target.key: stringkey, client: PeerServiceOf<S>client] as type const = readonly [string, PeerServiceOf<S>]const,
),
);
// Boundary: each peer client is a full `ServiceOf<S>` — a width-supertype of the leaf
// `PeerServiceOf<S>` the capability exposes — but the mapped types don't reduce under a generic
// `S`, so TS can't see the overlap; the erasure through `unknown` is the honest boundary.
return var Object: ObjectConstructorProvides functionality common to all JavaScript objects.
Object.ObjectConstructor.fromEntries<PeerServiceOf<S>>(entries: Iterable<readonly [PropertyKey, PeerServiceOf<S>]>): {
[k: string]: PeerServiceOf<S>;
} (+1 overload)
Returns an object created by key-value entries for properties and methods
fromEntries(const entries: (readonly [
string,
PeerServiceOf<S>
])[]
entries) as unknown as type Record<K extends keyof any, T> = {
[P in K]: T
}
Construct a type with a set of properties K of type T
Record<string, type PeerServiceOf<S extends Spec> = {
readonly [K in keyof S as S[K] extends {
readonly fleet: true
}
? never
: S[K] extends
| AnyLocalMethod
| AnyDefaultMethod
? never
: K]: S[K] extends {
readonly _tag: "ref"
}
? Effect.Effect<
SuccessOf<AsMethod<S[K]>>,
never,
never
>
: S[K] extends {
readonly kind: MethodKind
}
? ServiceMethod<AsMethod<S[K]>>
: S[K] extends Spec
? PeerServiceOf<S[K]>
: never
}
A peer's service as seen by
peers
— the per-instance ("leaf") wire methods only:
FleetField
s and
LocalMethod
s are excluded, so a fold can't recurse into a peer's
own fleet field. A full
ServiceOf
is assignable to it (width), so real clients fit.
PeerServiceOf<function (type parameter) S in <Self, S extends Spec, EIn = never, RIn = never>(tag: HyperlinkTag<Self, S>, self: AnyNode, options?: {
readonly nodes?: ReadonlyArray<AnyNode>;
readonly url?: (node: AnyNode) => Effect.Effect<string | undefined, EIn, RIn>;
}): Layer.Layer<PeersId<Self> | SelfNodeId<Self>, EIn, RIn>
S>>;
}),
),
const selfNodeLayer: <
Self,
S extends Spec
>(
tag: HyperlinkTag<Self, S>,
self: AnyNode
) => Layer.Layer<SelfNodeId<Self>>
Provide the
selfNode
capability on this node — the node key this instance runs as. Bundled
into
peersLayer
(so a mesh resource gets it for free); use this standalone when a HyperService
keys per node but doesn't gather peers, or alongside
peersFrom
in a test. No transport, no
failure path — just the identity.
selfNodeLayer(tag: HyperlinkTag<Self, S>(parameter) tag: {
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 DefaultMethod<infer F> ? F : S[K] extends …;
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 DefaultMethod<infer F> ? F : S[K] extends { readonly _…;
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 DefaultMethod<infer F> ? F : S[K] extends { rea…;
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 DefaultMethod<infer F> ? F : S[K] extends { rea…;
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, self: AnyNodeself),
);