<Self, S extends Spec, A, EPick, EOwn, ROwn>(
tag: HyperlinkTag<Self, S>,
pick: (peer: PeerServiceOf<S>) => Effect.Effect<A, EPick>,
own: Effect.Effect<A, EOwn, ROwn>
): Effect.Effect<
Record<string, A>,
EOwn,
ROwn | PeersId<Self> | SelfNodeId<Self>
>A fleet fold of successful peer leaf picks keyed by node (plus selfNode). Soft on
down peers — failures are skipped (partial table). Prefer this for optional metric-style
aggregates. For health, use hyperlink-ts/FleetHealth (Exit → Reachable /
Unreachable) or MultiNode.combineByNodeExit.
// metric-style: missing peers omitted
inFlightByNode: Hyperlink.fleetHealth(FleetMetrics, (peer) => peer.snapshot.pipe(...), own)Requires the peersLayer capability (which bundles selfNode). The only error /
requirement is own's.
export const const fleetHealth: <
Self,
S extends Spec,
A,
EPick,
EOwn,
ROwn
>(
tag: HyperlinkTag<Self, S>,
pick: (
peer: PeerServiceOf<S>
) => Effect.Effect<A, EPick>,
own: Effect.Effect<A, EOwn, ROwn>
) => Effect.Effect<
Record<string, A>,
EOwn,
ROwn | PeersId<Self> | SelfNodeId<Self>
>
A fleet fold of successful peer leaf picks keyed by node (plus
selfNode
). Soft on
down peers — failures are skipped (partial table). Prefer this for optional metric-style
aggregates. For health, use hyperlink-ts/FleetHealth (Exit → Reachable /
Unreachable) or MultiNode.combineByNodeExit.
// metric-style: missing peers omitted
inFlightByNode: Hyperlink.fleetHealth(FleetMetrics, (peer) => peer.snapshot.pipe(...), own)
Requires the
peersLayer
capability (which bundles
selfNode
). The only error /
requirement is own's.
fleetHealth = <function (type parameter) Self in <Self, S extends Spec, A, EPick, EOwn, ROwn>(tag: HyperlinkTag<Self, S>, pick: (peer: PeerServiceOf<S>) => Effect.Effect<A, EPick>, own: Effect.Effect<A, EOwn, ROwn>): Effect.Effect<Record<string, A>, EOwn, ROwn | PeersId<Self> | SelfNodeId<Self>>Self, function (type parameter) S in <Self, S extends Spec, A, EPick, EOwn, ROwn>(tag: HyperlinkTag<Self, S>, pick: (peer: PeerServiceOf<S>) => Effect.Effect<A, EPick>, own: Effect.Effect<A, EOwn, ROwn>): Effect.Effect<Record<string, A>, EOwn, ROwn | PeersId<Self> | SelfNodeId<Self>>S extends Spec, function (type parameter) A in <Self, S extends Spec, A, EPick, EOwn, ROwn>(tag: HyperlinkTag<Self, S>, pick: (peer: PeerServiceOf<S>) => Effect.Effect<A, EPick>, own: Effect.Effect<A, EOwn, ROwn>): Effect.Effect<Record<string, A>, EOwn, ROwn | PeersId<Self> | SelfNodeId<Self>>A, function (type parameter) EPick in <Self, S extends Spec, A, EPick, EOwn, ROwn>(tag: HyperlinkTag<Self, S>, pick: (peer: PeerServiceOf<S>) => Effect.Effect<A, EPick>, own: Effect.Effect<A, EOwn, ROwn>): Effect.Effect<Record<string, A>, EOwn, ROwn | PeersId<Self> | SelfNodeId<Self>>EPick, function (type parameter) EOwn in <Self, S extends Spec, A, EPick, EOwn, ROwn>(tag: HyperlinkTag<Self, S>, pick: (peer: PeerServiceOf<S>) => Effect.Effect<A, EPick>, own: Effect.Effect<A, EOwn, ROwn>): Effect.Effect<Record<string, A>, EOwn, ROwn | PeersId<Self> | SelfNodeId<Self>>EOwn, function (type parameter) ROwn in <Self, S extends Spec, A, EPick, EOwn, ROwn>(tag: HyperlinkTag<Self, S>, pick: (peer: PeerServiceOf<S>) => Effect.Effect<A, EPick>, own: Effect.Effect<A, EOwn, ROwn>): Effect.Effect<Record<string, A>, EOwn, ROwn | PeersId<Self> | SelfNodeId<Self>>ROwn>(
tag: HyperlinkTag<Self, S>(parameter) tag: {
groupId: string;
description: string | undefined;
key: Identifier;
of: (this: void, self: Simplify<{ readonly [K in keyof S]: S[K] extends FromLocalMethod<infer M> ? InjectLocal<M, Self> : S[K] extends LocalMethod<infer T> ? LocalEffect<T, never, Self> : S[K] extends { readonly _tag: 'constant'; } ? SuccessOf…;
context: (self: Simplify<{ readonly [K in keyof S]: S[K] extends FromLocalMethod<infer M> ? InjectLocal<M, Self> : S[K] extends LocalMethod<infer T> ? LocalEffect<T, never, Self> : S[K] extends { readonly _tag: 'constant'; } ? SuccessOf<AsMethod<S[…;
use: (f: (service: Simplify<{ readonly [K in keyof S]: S[K] extends FromLocalMethod<infer M> ? InjectLocal<M, Self> : S[K] extends LocalMethod<infer T> ? LocalEffect<T, never, Self> : S[K] extends { readonly _tag: 'constant'; } ? SuccessOf<AsMe…;
useSync: (f: (service: Simplify<{ readonly [K in keyof S]: S[K] extends FromLocalMethod<infer M> ? InjectLocal<M, Self> : S[K] extends LocalMethod<infer T> ? LocalEffect<T, never, Self> : S[K] extends { readonly _tag: 'constant'; } ? SuccessOf<AsMe…;
Identifier: Identifier;
Service: Shape;
stack: string | undefined;
pipe: { <A>(this: A): A; <A, B = never>(this: A, ab: (_: A) => B): B; <A, B = never, C = never>(this: A, ab: (_: A) => B, bc: (_: B) => C): C; <A, B = never, C = never, D = never>(this: A, ab: (_: A) => B, bc: (_: B) => C, cd: (_: C) => D): D; <…;
toString: () => string;
toJSON: () => unknown;
}
tag: interface HyperlinkTag<Self, S extends Spec, Svc = Simplify<{ readonly [K in keyof S]: S[K] extends FromLocalMethod<infer M> ? InjectLocal<M, Self> : S[K] extends LocalMethod<infer T> ? LocalEffect<...> : S[K] extends { ...; } ? SuccessOf<...> : S[K] extends { ...; } ? Subscribable<...> : S[K] extends { ...; } ? ClientMethod<...> : S[K] extends Spec ? Simplify<...> : never; }>>The type of a resource tag carrying spec S — what
Hyperlink.Tag
/ a
Hyperlink.tagFor
factory produce (and what you extend). Lets a consumer write
<S extends Spec>(tag: HyperlinkTag<Self, S>) and read the spec through named types
(
specOf
/
groupOf
) instead of a Parameters<typeof specOf> workaround.
HyperlinkTag<function (type parameter) Self in <Self, S extends Spec, A, EPick, EOwn, ROwn>(tag: HyperlinkTag<Self, S>, pick: (peer: PeerServiceOf<S>) => Effect.Effect<A, EPick>, own: Effect.Effect<A, EOwn, ROwn>): Effect.Effect<Record<string, A>, EOwn, ROwn | PeersId<Self> | SelfNodeId<Self>>Self, function (type parameter) S in <Self, S extends Spec, A, EPick, EOwn, ROwn>(tag: HyperlinkTag<Self, S>, pick: (peer: PeerServiceOf<S>) => Effect.Effect<A, EPick>, own: Effect.Effect<A, EOwn, ROwn>): Effect.Effect<Record<string, A>, EOwn, ROwn | PeersId<Self> | SelfNodeId<Self>>S>,
pick: (
peer: PeerServiceOf<S>
) => Effect.Effect<A, EPick>
pick: (peer: PeerServiceOf<S>peer: type PeerServiceOf<S extends Spec> = {
readonly [K in keyof S as S[K] extends {
readonly fleet: true
}
? never
: S[K] extends AnyLocalMethod
? 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, A, EPick, EOwn, ROwn>(tag: HyperlinkTag<Self, S>, pick: (peer: PeerServiceOf<S>) => Effect.Effect<A, EPick>, own: Effect.Effect<A, EOwn, ROwn>): Effect.Effect<Record<string, A>, EOwn, ROwn | PeersId<Self> | SelfNodeId<Self>>S>) => 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<function (type parameter) A in <Self, S extends Spec, A, EPick, EOwn, ROwn>(tag: HyperlinkTag<Self, S>, pick: (peer: PeerServiceOf<S>) => Effect.Effect<A, EPick>, own: Effect.Effect<A, EOwn, ROwn>): Effect.Effect<Record<string, A>, EOwn, ROwn | PeersId<Self> | SelfNodeId<Self>>A, function (type parameter) EPick in <Self, S extends Spec, A, EPick, EOwn, ROwn>(tag: HyperlinkTag<Self, S>, pick: (peer: PeerServiceOf<S>) => Effect.Effect<A, EPick>, own: Effect.Effect<A, EOwn, ROwn>): Effect.Effect<Record<string, A>, EOwn, ROwn | PeersId<Self> | SelfNodeId<Self>>EPick>,
own: Effect.Effect<A, EOwn, ROwn>(parameter) own: {
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;
}
own: 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<function (type parameter) A in <Self, S extends Spec, A, EPick, EOwn, ROwn>(tag: HyperlinkTag<Self, S>, pick: (peer: PeerServiceOf<S>) => Effect.Effect<A, EPick>, own: Effect.Effect<A, EOwn, ROwn>): Effect.Effect<Record<string, A>, EOwn, ROwn | PeersId<Self> | SelfNodeId<Self>>A, function (type parameter) EOwn in <Self, S extends Spec, A, EPick, EOwn, ROwn>(tag: HyperlinkTag<Self, S>, pick: (peer: PeerServiceOf<S>) => Effect.Effect<A, EPick>, own: Effect.Effect<A, EOwn, ROwn>): Effect.Effect<Record<string, A>, EOwn, ROwn | PeersId<Self> | SelfNodeId<Self>>EOwn, function (type parameter) ROwn in <Self, S extends Spec, A, EPick, EOwn, ROwn>(tag: HyperlinkTag<Self, S>, pick: (peer: PeerServiceOf<S>) => Effect.Effect<A, EPick>, own: Effect.Effect<A, EOwn, ROwn>): Effect.Effect<Record<string, A>, EOwn, ROwn | PeersId<Self> | SelfNodeId<Self>>ROwn>,
): 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<
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, function (type parameter) A in <Self, S extends Spec, A, EPick, EOwn, ROwn>(tag: HyperlinkTag<Self, S>, pick: (peer: PeerServiceOf<S>) => Effect.Effect<A, EPick>, own: Effect.Effect<A, EOwn, ROwn>): Effect.Effect<Record<string, A>, EOwn, ROwn | PeersId<Self> | SelfNodeId<Self>>A>,
function (type parameter) EOwn in <Self, S extends Spec, A, EPick, EOwn, ROwn>(tag: HyperlinkTag<Self, S>, pick: (peer: PeerServiceOf<S>) => Effect.Effect<A, EPick>, own: Effect.Effect<A, EOwn, ROwn>): Effect.Effect<Record<string, A>, EOwn, ROwn | PeersId<Self> | SelfNodeId<Self>>EOwn,
function (type parameter) ROwn in <Self, S extends Spec, A, EPick, EOwn, ROwn>(tag: HyperlinkTag<Self, S>, pick: (peer: PeerServiceOf<S>) => Effect.Effect<A, EPick>, own: Effect.Effect<A, EOwn, ROwn>): Effect.Effect<Record<string, A>, EOwn, ROwn | PeersId<Self> | SelfNodeId<Self>>ROwn | interface PeersId<Self>Phantom brand for the per-resource
peers
capability, so distinct resources' peer sets
don't collide in one context.
PeersId<function (type parameter) Self in <Self, S extends Spec, A, EPick, EOwn, ROwn>(tag: HyperlinkTag<Self, S>, pick: (peer: PeerServiceOf<S>) => Effect.Effect<A, EPick>, own: Effect.Effect<A, EOwn, ROwn>): Effect.Effect<Record<string, A>, EOwn, ROwn | PeersId<Self> | SelfNodeId<Self>>Self> | interface SelfNodeId<Self>Phantom brand for the per-resource
selfNode
capability (which node this instance runs as),
so distinct resources' self-node identities don't collide in one context.
SelfNodeId<function (type parameter) Self in <Self, S extends Spec, A, EPick, EOwn, ROwn>(tag: HyperlinkTag<Self, S>, pick: (peer: PeerServiceOf<S>) => Effect.Effect<A, EPick>, own: Effect.Effect<A, EOwn, ROwn>): Effect.Effect<Record<string, A>, EOwn, ROwn | PeersId<Self> | SelfNodeId<Self>>Self>
> =>
import EffectEffect.const gen: <any, any>(f: () => Generator<any, any, never>) => Effect.Effect<any, unknown, unknown> (+1 overload)Provides a way to write effectful code using generator functions, simplifying
control flow and error handling.
When to use
Use when you want to write effectful code that looks and behaves like
synchronous code, while still handling asynchronous tasks, errors, and complex
control flow such as loops and conditions.
Generator functions work similarly to async/await but keep errors,
requirements, and interruption in the Effect type. You can yield* values
from effects and return the final result at the end.
Example (Sequencing effects with generators)
import { Data, Effect } from "effect"
class DiscountRateError extends Data.TaggedError("DiscountRateError")<{}> {}
const addServiceCharge = (amount: number) => amount + 1
const applyDiscount = (
total: number,
discountRate: number
): Effect.Effect<number, DiscountRateError> =>
discountRate === 0
? Effect.fail(new DiscountRateError())
: Effect.succeed(total - (total * discountRate) / 100)
const fetchTransactionAmount = Effect.promise(() => Promise.resolve(100))
const fetchDiscountRate = Effect.promise(() => Promise.resolve(5))
export const program = Effect.gen(function*() {
const transactionAmount = yield* fetchTransactionAmount
const discountRate = yield* fetchDiscountRate
const discountedAmount = yield* applyDiscount(
transactionAmount,
discountRate
)
const finalAmount = addServiceCharge(discountedAmount)
return `Final amount to charge: ${finalAmount}`
})
gen(function* () {
const const self: stringself = yield* const selfNode: <Self, S extends Spec>(
tag: HyperlinkTag<Self, S>
) => Effect.Effect<
string,
never,
SelfNodeId<Self>
>
The node key this instance runs as — the same key its
peers
are keyed by. For folds that
key per node (combineByNode), so a resource's own logic can name its own row without
hand-threading the node key. Requires the
selfNodeLayer
/
peersLayer
capability:
fleetStatus: Effect.gen(function* () {
const self = yield* Hyperlink.selfNode(FleetDatabase); // the node key I am
const peers = yield* Hyperlink.peers(FleetDatabase);
const byNode = yield* combineQuery(peers, (p) => p.status, combineByNode);
return { ...byNode, [self]: yield* ownStatus }; // key my own row, consistently
})
selfNode(tag: HyperlinkTag<Self, S>(parameter) tag: {
groupId: string;
description: string | undefined;
key: Identifier;
of: (this: void, self: Simplify<{ readonly [K in keyof S]: S[K] extends FromLocalMethod<infer M> ? InjectLocal<M, Self> : S[K] extends LocalMethod<infer T> ? LocalEffect<T, never, Self> : S[K] extends { readonly _tag: 'constant'; } ? SuccessOf…;
context: (self: Simplify<{ readonly [K in keyof S]: S[K] extends FromLocalMethod<infer M> ? InjectLocal<M, Self> : S[K] extends LocalMethod<infer T> ? LocalEffect<T, never, Self> : S[K] extends { readonly _tag: 'constant'; } ? SuccessOf<AsMethod<S[…;
use: (f: (service: Simplify<{ readonly [K in keyof S]: S[K] extends FromLocalMethod<infer M> ? InjectLocal<M, Self> : S[K] extends LocalMethod<infer T> ? LocalEffect<T, never, Self> : S[K] extends { readonly _tag: 'constant'; } ? SuccessOf<AsMe…;
useSync: (f: (service: Simplify<{ readonly [K in keyof S]: S[K] extends FromLocalMethod<infer M> ? InjectLocal<M, Self> : S[K] extends LocalMethod<infer T> ? LocalEffect<T, never, Self> : S[K] extends { readonly _tag: 'constant'; } ? SuccessOf<AsMe…;
Identifier: Identifier;
Service: Shape;
stack: string | undefined;
pipe: { <A>(this: A): A; <A, B = never>(this: A, ab: (_: A) => B): B; <A, B = never, C = never>(this: A, ab: (_: A) => B, bc: (_: B) => C): C; <A, B = never, C = never, D = never>(this: A, ab: (_: A) => B, bc: (_: B) => C, cd: (_: C) => D): D; <…;
toString: () => string;
toJSON: () => unknown;
}
tag);
const const peerClients: Record<
string,
PeerServiceOf<S>
>
peerClients = yield* const peers: <Self, S extends Spec>(
tag: HyperlinkTag<Self, S>
) => Effect.Effect<
Record<string, PeerServiceOf<S>>,
never,
PeersId<Self>
>
The resource's peer clients — the OTHER nodes' full services, keyed by node — for a resource's
own cross-node logic. Requires the
peersLayer
capability. Fold them with /MultiNode's
combineQuery/combineStream (or iterate) and add your own value:
totalConnections: combineQuery(peers, (p) => p.connections, combineSum).pipe(
Effect.map((others) => pool.activeCount() + others), // self + peers — you write self in
)
Fold over per-instance ("leaf") fields (p.connections), not a peer's own fleet field
(p.totalConnections) — a peer client is the full service, so a fleet field is callable but would
make it re-gather its peers (a cross-node fan-out, not what you want in a fold). The plain-query
model has no type-level leaf/fleet distinction, so this is a convention, not a compile error.
peers(tag: HyperlinkTag<Self, S>(parameter) tag: {
groupId: string;
description: string | undefined;
key: Identifier;
of: (this: void, self: Simplify<{ readonly [K in keyof S]: S[K] extends FromLocalMethod<infer M> ? InjectLocal<M, Self> : S[K] extends LocalMethod<infer T> ? LocalEffect<T, never, Self> : S[K] extends { readonly _tag: 'constant'; } ? SuccessOf…;
context: (self: Simplify<{ readonly [K in keyof S]: S[K] extends FromLocalMethod<infer M> ? InjectLocal<M, Self> : S[K] extends LocalMethod<infer T> ? LocalEffect<T, never, Self> : S[K] extends { readonly _tag: 'constant'; } ? SuccessOf<AsMethod<S[…;
use: (f: (service: Simplify<{ readonly [K in keyof S]: S[K] extends FromLocalMethod<infer M> ? InjectLocal<M, Self> : S[K] extends LocalMethod<infer T> ? LocalEffect<T, never, Self> : S[K] extends { readonly _tag: 'constant'; } ? SuccessOf<AsMe…;
useSync: (f: (service: Simplify<{ readonly [K in keyof S]: S[K] extends FromLocalMethod<infer M> ? InjectLocal<M, Self> : S[K] extends LocalMethod<infer T> ? LocalEffect<T, never, Self> : S[K] extends { readonly _tag: 'constant'; } ? SuccessOf<AsMe…;
Identifier: Identifier;
Service: Shape;
stack: string | undefined;
pipe: { <A>(this: A): A; <A, B = never>(this: A, ab: (_: A) => B): B; <A, B = never, C = never>(this: A, ab: (_: A) => B, bc: (_: B) => C): C; <A, B = never, C = never, D = never>(this: A, ab: (_: A) => B, bc: (_: B) => C, cd: (_: C) => D): D; <…;
toString: () => string;
toJSON: () => unknown;
}
tag);
const const byNode: anybyNode = yield* import combineQuerycombineQuery(const peerClients: Record<
string,
PeerServiceOf<S>
>
peerClients, pick: (
peer: PeerServiceOf<S>
) => Effect.Effect<A, EPick>
pick, import combineByNodecombineByNode);
const const ownValue: AownValue = yield* own: Effect.Effect<A, EOwn, ROwn>(parameter) own: {
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;
}
own;
return { ...const byNode: anybyNode, [const self: stringself]: const ownValue: AownValue };
});