<S extends Spec, Impl extends ServeImplOf<S, any>>(
tag: {
readonly groupId: string
readonly [specSym]: FlatSpec
readonly [specTypeSym]?: S
readonly [groupSym]: RpcGroupOf<S>
},
impl: Impl | BuiltHyperlink<S, any>
): Layer.Layer<HandlerContextOf<S>, never, ServeRequirements<Impl>>A resource's served-only handler layer — mounts the tag's group handlers (wire members only,
no local grant), with the handlers' requirement R preserved (not erased). This is the
served-only counterpart to serve, which additionally grants Local so
members stay callable in-process. serveRemote's R rides the layer's requirement channel, so a
per-resource Layer.provide discharges this resource's dependency in isolation:
Hyperlink.serveRemote(SeasonMatches, seasonMatchesImpl).pipe(Layer.provide(importHandlersLayer))The point of serveRemote is the run-time-requirement case: N resources needing different
implementations of the same tag, each isolated — merge the layers onto one RpcServer (groups are
prefix-keyed).
export const const serveRemote: <
S extends Spec,
Impl extends ServeImplOf<S, any>
>(
tag: {
readonly groupId: string
readonly [specSym]: FlatSpec
readonly [specTypeSym]?: S
readonly [groupSym]: RpcGroupOf<S>
},
impl: Impl | BuiltHyperlink<S, any>
) => Layer.Layer<
HandlerContextOf<S>,
never,
ServeRequirements<Impl>
>
A resource's served-only handler layer — mounts the tag's group handlers (wire members only,
no local grant), with the handlers' requirement R preserved (not erased). This is the
served-only counterpart to
serve
, which additionally grants
Local
so
members stay callable in-process. serveRemote's R rides the layer's requirement channel, so a
per-resource Layer.provide discharges this resource's dependency in isolation:
Hyperlink.serveRemote(SeasonMatches, seasonMatchesImpl).pipe(Layer.provide(importHandlersLayer))
The point of serveRemote is the run-time-requirement case: N resources needing different
implementations of the same tag, each isolated — merge the layers onto one RpcServer (groups are
prefix-keyed).
serveRemote = <function (type parameter) S in <S extends Spec, Impl extends ServeImplOf<S, any>>(tag: {
readonly groupId: string;
readonly [specSym]: FlatSpec;
readonly [specTypeSym]?: S;
readonly [groupSym]: RpcGroupOf<S>;
}, impl: Impl | BuiltHyperlink<S, any>): Layer.Layer<HandlerContextOf<S>, never, ServeRequirements<Impl>>
S extends Spec, function (type parameter) Impl in <S extends Spec, Impl extends ServeImplOf<S, any>>(tag: {
readonly groupId: string;
readonly [specSym]: FlatSpec;
readonly [specTypeSym]?: S;
readonly [groupSym]: RpcGroupOf<S>;
}, impl: Impl | BuiltHyperlink<S, any>): Layer.Layer<HandlerContextOf<S>, never, ServeRequirements<Impl>>
Impl extends type ServeImplOf<S extends Spec, R> = {
readonly [K in keyof S as S[K] extends AnyLocalMethod
? never
: K]: S[K] extends {
readonly _tag: "ref"
}
? Subscribable<SuccessOf<AsMethod<S[K]>>>
: S[K] extends {
readonly kind: MethodKind
}
? ServeMethod<AsMethod<S[K]>, R>
: S[K] extends Spec
? ServeImplOf<S[K], R>
: never
}
The implementation
serve
expects — the tag's wire members, whose handlers may share a run-time
requirement R. R is inferred from the impl (via
ServeRequirements
, the union of every
handler's requirement) and preserved on the returned layer, so it's discharged per resource by
Layer.provide, not shared ambiently.
ServeImplOf<function (type parameter) S in <S extends Spec, Impl extends ServeImplOf<S, any>>(tag: {
readonly groupId: string;
readonly [specSym]: FlatSpec;
readonly [specTypeSym]?: S;
readonly [groupSym]: RpcGroupOf<S>;
}, impl: Impl | BuiltHyperlink<S, any>): Layer.Layer<HandlerContextOf<S>, never, ServeRequirements<Impl>>
S, any>>(
tag: {
readonly groupId: string
readonly [specSym]: FlatSpec
readonly [specTypeSym]?: S
readonly [groupSym]: RpcGroupOf<S>
}
tag: {
readonly groupId: stringgroupId: string;
readonly [const specSym: typeof specSymWhere the contract spec is stowed on a Tag (hidden from the value surface). Exported so
the public
HyperlinkTag
type is nameable across modules.
specSym]: type FlatSpec = {
[x: string]: AnyMethod | AnyLocalMethod
}
A flat spec — a path-keyed record of leaves (no nested groups). The wire machinery runs on this;
a (possibly nested)
Spec
flattens to it via
flattenSpec
.
FlatSpec;
readonly [const specTypeSym: typeof specTypeSymPhantom carrier of a tag's (possibly nested) spec type S, so functions can infer S from a tag —
specSym
holds the flat spec at runtime and can't carry the nested S. Type-only, never set at
runtime.
specTypeSym]?: function (type parameter) S in <S extends Spec, Impl extends ServeImplOf<S, any>>(tag: {
readonly groupId: string;
readonly [specSym]: FlatSpec;
readonly [specTypeSym]?: S;
readonly [groupSym]: RpcGroupOf<S>;
}, impl: Impl | BuiltHyperlink<S, any>): Layer.Layer<HandlerContextOf<S>, never, ServeRequirements<Impl>>
S;
readonly [const groupSym: typeof groupSymWhere the built RPC group is stowed on a Tag.
groupSym]: type RpcGroupOf<S extends Spec> =
RpcGroup.RpcGroup<RpcUnionOf<S, "">>
The precisely-typed RPC contract group for a
Spec
. Carrying this exact type
(rather than a loose Rpc<string, …>) is what keeps the remote client's requirement
channel honest: concrete schemas declare never encoding/decoding services, so
RpcClient.make infers a real R (just the transport Protocol) instead of any.
RpcGroupOf<function (type parameter) S in <S extends Spec, Impl extends ServeImplOf<S, any>>(tag: {
readonly groupId: string;
readonly [specSym]: FlatSpec;
readonly [specTypeSym]?: S;
readonly [groupSym]: RpcGroupOf<S>;
}, impl: Impl | BuiltHyperlink<S, any>): Layer.Layer<HandlerContextOf<S>, never, ServeRequirements<Impl>>
S>;
},
impl: Impl | BuiltHyperlink<S, any>impl: function (type parameter) Impl in <S extends Spec, Impl extends ServeImplOf<S, any>>(tag: {
readonly groupId: string;
readonly [specSym]: FlatSpec;
readonly [specTypeSym]?: S;
readonly [groupSym]: RpcGroupOf<S>;
}, impl: Impl | BuiltHyperlink<S, any>): Layer.Layer<HandlerContextOf<S>, never, ServeRequirements<Impl>>
Impl | interface BuiltHyperlink<S extends Spec, R>A resource impl before worker-context discharge — the impl still carries requirement R on its
Effect methods, paired with the
Context.Context
captured at build time. Used by
QueueHyperlink
,
RunHyperlink
, and
Process
(any toolkit resource that builds
its driver under ambient R).
layer
/
serve
grant locally via
grantLocal
;
serveRemote
defers discharge to each wire call via
invokeWireMethodWithContext
so
one materialization backs both paths.
BuiltHyperlink<function (type parameter) S in <S extends Spec, Impl extends ServeImplOf<S, any>>(tag: {
readonly groupId: string;
readonly [specSym]: FlatSpec;
readonly [specTypeSym]?: S;
readonly [groupSym]: RpcGroupOf<S>;
}, impl: Impl | BuiltHyperlink<S, any>): Layer.Layer<HandlerContextOf<S>, never, ServeRequirements<Impl>>
S, any>,
): 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<type HandlerContextOf<S extends Spec> =
RpcUnionOf<S, ""> extends Rpc.Rpc<
infer _Tag extends string,
infer _Payload extends Schema.Top,
infer _Success extends Schema.Top,
infer _Error extends Schema.Top,
infer _Middleware extends AnyService,
infer _Requires
>
? Rpc.Handler<_Tag>
: never
The context a server layer for a
Spec
provides: the handler for every method.
Used to pin the server layers' output type so their requirement channel stays
never — RpcGroup's own ToHandlerFn defaults that channel to any, so without
this the inferred server layer would re-leak any into anything that consumes it.
HandlerContextOf<function (type parameter) S in <S extends Spec, Impl extends ServeImplOf<S, any>>(tag: {
readonly groupId: string;
readonly [specSym]: FlatSpec;
readonly [specTypeSym]?: S;
readonly [groupSym]: RpcGroupOf<S>;
}, impl: Impl | BuiltHyperlink<S, any>): Layer.Layer<HandlerContextOf<S>, never, ServeRequirements<Impl>>
S>, never, type ServeRequirements<Impl> = {
[K in keyof Impl]: Impl[K] extends (
payload: never
) => Effect.Effect<unknown, unknown, infer R>
? R
: Impl[K] extends (
payload: never
) => Stream.Stream<
unknown,
unknown,
infer R
>
? R
: Impl[K] extends Effect.Effect<
unknown,
unknown,
infer R
>
? R
: Impl[K] extends Stream.Stream<
unknown,
unknown,
infer R
>
? R
: never
}[keyof Impl]
The union of every handler's run-time requirement R in a
serve
impl — extracted from the
impl value (not a mapped-type parameter), so serve can infer it. Each member is one of the four
ServeMethod
forms; a member that requires nothing contributes never.
ServeRequirements<function (type parameter) Impl in <S extends Spec, Impl extends ServeImplOf<S, any>>(tag: {
readonly groupId: string;
readonly [specSym]: FlatSpec;
readonly [specTypeSym]?: S;
readonly [groupSym]: RpcGroupOf<S>;
}, impl: Impl | BuiltHyperlink<S, any>): Layer.Layer<HandlerContextOf<S>, never, ServeRequirements<Impl>>
Impl>> => {
const const group: RpcGroupOf<S>const group: {
requests: ReadonlyMap<string, R>;
annotations: Context.Context<never>;
add: (...rpcs: Rpcs2) => RpcGroup.RpcGroup<RpcUnionOf<S, ''> | Rpcs2[number]>;
merge: (...groups: Groups) => RpcGroup.RpcGroup<RpcUnionOf<S, ''> | RpcGroup.Rpcs<Groups[number]>>;
omit: (...tags: Tags) => RpcGroup.RpcGroup<Exclude<RpcUnionOf<S, ''>, { readonly _tag: Tags[number] }>>;
middleware: (middleware: M) => RpcGroup.RpcGroup<Rpc.AddMiddleware<RpcUnionOf<S, ''>, M>>;
prefix: (prefix: Prefix) => RpcGroup.RpcGroup<Rpc.Prefixed<RpcUnionOf<S, ''>, Prefix>>;
toHandlers: (build: Handlers | Effect.Effect<Handlers, EX, RX>) => Effect.Effect<Context.Context<Rpc.ToHandler<RpcUnionOf<S, ''>>>, EX, RX | RpcGroup.HandlersServices<RpcUnionOf<S, ''>, Handlers>>;
toLayer: (build: Handlers | Effect.Effect<Handlers, EX, RX>) => Layer.Layer<Rpc.ToHandler<RpcUnionOf<S, ''>>, EX, Exclude<RX, Scope.Scope> | RpcGroup.HandlersServices<RpcUnionOf<S, ''>, Handlers>>;
of: (handlers: Handlers) => Handlers;
toLayerHandler: (tag: Tag, build: Handler | Effect.Effect<Handler, EX, RX>) => Layer.Layer<Rpc.Handler<Tag>, EX, Exclude<RX, Scope.Scope> | RpcGroup.HandlerServices<RpcUnionOf<S, ''>, Tag, Handler>>;
accessHandler: (tag: Tag) => Effect.Effect<(payload: Rpc.Payload<Extract<RpcUnionOf<S, ''>, { readonly _tag: Tag }>>, options: { readonly client: Rpc.ServerClient; readonly requestId: RequestId; readonly headers: Headers.Headers }) => Rpc.ResultFrom<Extr…;
annotate: (service: Context.Key<I, S>, value: S) => RpcGroup.RpcGroup<RpcUnionOf<S, ''>>;
annotateRpcs: (service: Context.Key<I, S>, value: S) => RpcGroup.RpcGroup<RpcUnionOf<S, ''>>;
annotateMerge: (annotations: Context.Context<S>) => RpcGroup.RpcGroup<RpcUnionOf<S, ''>>;
annotateRpcsMerge: (annotations: Context.Context<S>) => RpcGroup.RpcGroup<RpcUnionOf<S, ''>>;
pipe: { <A>(this: A): A; <A, B = never>(this: A, ab: (_: A) => B): B; <A, B = never, C = never>(this: A, ab: (_: A) => B, bc: (_: B) => C): C; <A, B = never, C = never, D = never>(this: A, ab: (_: A) => B, bc: (_: B) => C, cd: (_: C) => D): D; <…;
}
group = tag: {
readonly groupId: string
readonly [specSym]: FlatSpec
readonly [specTypeSym]?: S
readonly [groupSym]: RpcGroupOf<S>
}
tag[const groupSym: typeof groupSymWhere the built RPC group is stowed on a Tag.
groupSym];
const const handlers: Record<
string,
(payload: unknown) => unknown
>
handlers: 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, (payload: unknownpayload: unknown) => unknown> = {};
const const wireImpl:
| Impl
| WithRequirement<ImplOf<S>, any>
wireImpl = const isBuiltHyperlink: (
u: unknown
) => u is BuiltHyperlink<Spec, unknown>
True when u is a
BuiltHyperlink
bundle.
isBuiltHyperlink(impl: Impl | BuiltHyperlink<S, any>impl) ? impl: Impl | BuiltHyperlink<S, any>(parameter) impl: {
impl: WithRequirement<ImplOf<S>, R>;
workerContext: Context.Context<R>;
}
impl.BuiltHyperlink<S, any>.impl: WithRequirement<ImplOf<S>, R>impl : impl: Impl | BuiltHyperlink<S, any>impl;
const const workerContext:
| Context.Context<any>
| undefined
workerContext = const isBuiltHyperlink: (
u: unknown
) => u is BuiltHyperlink<Spec, unknown>
True when u is a
BuiltHyperlink
bundle.
isBuiltHyperlink(impl: Impl | BuiltHyperlink<S, any>impl) ? impl: Impl | BuiltHyperlink<S, any>(parameter) impl: {
impl: WithRequirement<ImplOf<S>, R>;
workerContext: Context.Context<R>;
}
impl.BuiltHyperlink<S, any>.workerContext: Context.Context<any>(property) BuiltHyperlink<S, any>.workerContext: {
mapUnsafe: ReadonlyMap<string, any>;
mutable: boolean;
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;
}
workerContext : var undefinedundefined;
// flatten a (possibly nested) impl to path keys matching the flat spec + path-keyed group procedures.
const const flatImpl: Record<string, unknown>flatImpl = const flattenImpl: (
impl: Record<string, unknown>,
flatSpec: FlatSpec
) => Record<string, unknown>
flattenImpl(const wireImpl:
| ServeImplOf<S, any>
| Stream.Stream<unknown, unknown, unknown>
| Subscribable<unknown>
| ImplOf<S>
| ((
...args: unknown[]
) => Effect.Effect<unknown, unknown, any>)
| Effect.Effect<unknown, unknown, any>
| (((
...args: ReadonlyArray<never>
) => unknown) &
ImplOf<S>)
| {
readonly [K in keyof ImplOf<S>]: WithRequirement<
ImplOf<S>[K],
any
>
}
wireImpl 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, unknown>, tag: {
readonly groupId: string
readonly [specSym]: FlatSpec
readonly [specTypeSym]?: S
readonly [groupSym]: RpcGroupOf<S>
}
tag[const specSym: typeof specSymWhere the contract spec is stowed on a Tag (hidden from the value surface). Exported so
the public
HyperlinkTag
type is nameable across modules.
specSym]);
for (const [const key: stringkey, const member: unknownmember] of var Object: ObjectConstructorProvides functionality common to all JavaScript objects.
Object.ObjectConstructor.entries<unknown>(o: {
[s: string]: unknown;
} | ArrayLike<unknown>): [string, unknown][] (+1 overload)
Returns an array of key/values of the enumerable own properties of an object
entries(const flatImpl: Record<string, unknown>flatImpl)) {
const handlers: Record<
string,
(payload: unknown) => unknown
>
handlers[const wireTag: (
groupId: string,
method: string
) => string
wireTag(tag: {
readonly groupId: string
readonly [specSym]: FlatSpec
readonly [specTypeSym]?: S
readonly [groupSym]: RpcGroupOf<S>
}
tag.groupId: stringgroupId, const key: stringkey)] = (payload: unknownpayload) =>
const workerContext:
| Context.Context<any>
| undefined
workerContext === var undefinedundefined
? const invokeWireMethod: (
member: unknown,
method: AnyMethod,
payload: unknown
) => unknown
Invoke a wire impl member — spreads 2-tuple payloads when callStyle is "pair".
invokeWireMethod(const member: unknownmember, tag: {
readonly groupId: string
readonly [specSym]: FlatSpec
readonly [specTypeSym]?: S
readonly [groupSym]: RpcGroupOf<S>
}
tag[const specSym: typeof specSymWhere the contract spec is stowed on a Tag (hidden from the value surface). Exported so
the public
HyperlinkTag
type is nameable across modules.
specSym][const key: stringkey] as type AnyMethod = Method<
Schema.Top | Schema.Struct.Fields | undefined,
Schema.Top,
Schema.Top,
boolean,
MethodAnnotations,
never
>
Any
Method
, erased — the element type of a
Spec
.
AnyMethod, payload: unknownpayload)
: const invokeWireMethodWithContext: (
member: unknown,
method: AnyMethod,
payload: unknown,
context: Context.Context<unknown>
) => unknown
Like
invokeWireMethod
, but discharges context into each returned
Effect
/
Stream
.
invokeWireMethodWithContext(
const member: unknownmember,
tag: {
readonly groupId: string
readonly [specSym]: FlatSpec
readonly [specTypeSym]?: S
readonly [groupSym]: RpcGroupOf<S>
}
tag[const specSym: typeof specSymWhere the contract spec is stowed on a Tag (hidden from the value surface). Exported so
the public
HyperlinkTag
type is nameable across modules.
specSym][const key: stringkey] as type AnyMethod = Method<
Schema.Top | Schema.Struct.Fields | undefined,
Schema.Top,
Schema.Top,
boolean,
MethodAnnotations,
never
>
Any
Method
, erased — the element type of a
Spec
.
AnyMethod,
payload: unknownpayload,
const workerContext: Context.Context<any>const workerContext: {
mapUnsafe: ReadonlyMap<string, any>;
mutable: boolean;
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;
}
workerContext,
);
}
// dynamic handler construction (the group's `toLayer` boundary); the outer assertion **preserves**
// the handlers' requirement `R` — extracted from `impl` by {@link ServeRequirements} — instead of
// erasing it, so a per-resource `Layer.provide` can discharge it. `HandlerContextOf<S>` is the rpc
// handler slots; the requirement is the union of the handlers' run-time needs.
const const handlerLayer: anyhandlerLayer: any = const group: RpcGroupOf<S>const group: {
requests: ReadonlyMap<string, R>;
annotations: Context.Context<never>;
add: (...rpcs: Rpcs2) => RpcGroup.RpcGroup<RpcUnionOf<S, ''> | Rpcs2[number]>;
merge: (...groups: Groups) => RpcGroup.RpcGroup<RpcUnionOf<S, ''> | RpcGroup.Rpcs<Groups[number]>>;
omit: (...tags: Tags) => RpcGroup.RpcGroup<Exclude<RpcUnionOf<S, ''>, { readonly _tag: Tags[number] }>>;
middleware: (middleware: M) => RpcGroup.RpcGroup<Rpc.AddMiddleware<RpcUnionOf<S, ''>, M>>;
prefix: (prefix: Prefix) => RpcGroup.RpcGroup<Rpc.Prefixed<RpcUnionOf<S, ''>, Prefix>>;
toHandlers: (build: Handlers | Effect.Effect<Handlers, EX, RX>) => Effect.Effect<Context.Context<Rpc.ToHandler<RpcUnionOf<S, ''>>>, EX, RX | RpcGroup.HandlersServices<RpcUnionOf<S, ''>, Handlers>>;
toLayer: (build: Handlers | Effect.Effect<Handlers, EX, RX>) => Layer.Layer<Rpc.ToHandler<RpcUnionOf<S, ''>>, EX, Exclude<RX, Scope.Scope> | RpcGroup.HandlersServices<RpcUnionOf<S, ''>, Handlers>>;
of: (handlers: Handlers) => Handlers;
toLayerHandler: (tag: Tag, build: Handler | Effect.Effect<Handler, EX, RX>) => Layer.Layer<Rpc.Handler<Tag>, EX, Exclude<RX, Scope.Scope> | RpcGroup.HandlerServices<RpcUnionOf<S, ''>, Tag, Handler>>;
accessHandler: (tag: Tag) => Effect.Effect<(payload: Rpc.Payload<Extract<RpcUnionOf<S, ''>, { readonly _tag: Tag }>>, options: { readonly client: Rpc.ServerClient; readonly requestId: RequestId; readonly headers: Headers.Headers }) => Rpc.ResultFrom<Extr…;
annotate: (service: Context.Key<I, S>, value: S) => RpcGroup.RpcGroup<RpcUnionOf<S, ''>>;
annotateRpcs: (service: Context.Key<I, S>, value: S) => RpcGroup.RpcGroup<RpcUnionOf<S, ''>>;
annotateMerge: (annotations: Context.Context<S>) => RpcGroup.RpcGroup<RpcUnionOf<S, ''>>;
annotateRpcsMerge: (annotations: Context.Context<S>) => RpcGroup.RpcGroup<RpcUnionOf<S, ''>>;
pipe: { <A>(this: A): A; <A, B = never>(this: A, ab: (_: A) => B): B; <A, B = never, C = never>(this: A, ab: (_: A) => B, bc: (_: B) => C): C; <A, B = never, C = never, D = never>(this: A, ab: (_: A) => B, bc: (_: B) => C, cd: (_: C) => D): D; <…;
}
group.RpcGroup<RpcUnionOf<S, "">>.toLayer<any, never, never>(build: any): Layer.Layer<Rpc.ToHandler<RpcUnionOf<S, "">>, never, RpcGroup.HandlerServices<RpcUnionOf<S, "">, string, any>>Implement the handlers for the procedures in this group.
toLayer(const handlers: Record<
string,
(payload: unknown) => unknown
>
handlers as any);
// register into the served-resources registry when one is present (`httpServer` provides it), so the
// shared server + `/health` discover this resource without the caller listing it twice. Merged (not
// provided) so it isn't pruned as unused; a no-op when no registry is in context (standalone `serve`).
const const registration: Layer.Layer<
never,
never,
never
>
const registration: {
build: (memoMap: Layer.MemoMap, scope: Scope.Scope) => Effect.Effect<Context.Context<never>, never, never>;
pipe: { <A>(this: A): A; <A, B = never>(this: A, ab: (_: A) => B): B; <A, B = never, C = never>(this: A, ab: (_: A) => B, bc: (_: B) => C): C; <A, B = never, C = never, D = never>(this: A, ab: (_: A) => B, bc: (_: B) => C, cd: (_: C) => D): D; <…;
}
registration = import LayerLayer.const effectDiscard: <void, never, never>(effect: Effect.Effect<void, never, never>) => Layer.Layer<never, never, never>Constructs a layer from an effect, discarding its value and providing no
services.
When to use
Use when layer construction should run an Effect for its side effects while providing no
services.
Example (Running an effect during layer construction)
import { Effect, Layer } from "effect"
const initLayer = Layer.effectDiscard(
Effect.sync(() => {
console.log("Initializing application...")
})
)
effectDiscard(
import EffectEffect.const serviceOption: <ServedHyperlinks, {
readonly register: (entry: ServedHyperlink) => Effect.Effect<void>;
readonly all: Effect.Effect<ReadonlyArray<ServedHyperlink>>;
}>(key: Context.Key<ServedHyperlinks, {
readonly register: (entry: ServedHyperlink) => Effect.Effect<void>;
readonly all: Effect.Effect<ReadonlyArray<ServedHyperlink>>;
}>) => Effect.Effect<Option.Option<{
readonly register: (entry: ServedHyperlink) => Effect.Effect<void>;
readonly all: Effect.Effect<ReadonlyArray<ServedHyperlink>>;
}>, never, never>
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(class ServedHyperlinksclass ServedHyperlinks {
key: Identifier;
Service: {
register: (entry: ServedHyperlink) => Effect.Effect<void>;
all: Effect.Effect<ReadonlyArray<ServedHyperlink>>;
};
of: (this: void, self: { readonly register: (entry: ServedHyperlink) => Effect.Effect<void>; readonly all: Effect.Effect<ReadonlyArray<ServedHyperlink>> }) => { readonly register: (entry: ServedHyperlink) => Effect.Effect<void>; readonly all: …;
context: (self: { readonly register: (entry: ServedHyperlink) => Effect.Effect<void>; readonly all: Effect.Effect<ReadonlyArray<ServedHyperlink>> }) => Context.Context<ServedHyperlinks>;
use: (f: (service: { readonly register: (entry: ServedHyperlink) => Effect.Effect<void>; readonly all: Effect.Effect<ReadonlyArray<ServedHyperlink>> }) => Effect.Effect<A, E, R>) => Effect.Effect<A, E, ServedHyperlinks | R>;
useSync: (f: (service: { readonly register: (entry: ServedHyperlink) => Effect.Effect<void>; readonly all: Effect.Effect<ReadonlyArray<ServedHyperlink>> }) => A) => Effect.Effect<A, never, ServedHyperlinks>;
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;
}
The served-resources registry — an accumulator
serve
appends to and
httpServer
reads.
A plain Ref-backed list (not type-level state), so many serve layers compose under Layer.mergeAll
and the server sees every one. Provided by
httpServer
(or
servedHyperlinksLayer
); serve
registers only if it's present (so serve also works standalone).
ServedHyperlinks).Pipeable.pipe<Effect.Effect<Option.Option<{
readonly register: (entry: ServedHyperlink) => Effect.Effect<void>;
readonly all: Effect.Effect<ReadonlyArray<ServedHyperlink>>;
}>, never, never>, Effect.Effect<void, never, never>>(this: Effect.Effect<Option.Option<{
readonly register: (entry: ServedHyperlink) => Effect.Effect<void>;
readonly all: Effect.Effect<ReadonlyArray<ServedHyperlink>>;
}>, never, never>, ab: (_: Effect.Effect<Option.Option<{
readonly register: (entry: ServedHyperlink) => Effect.Effect<void>;
readonly all: Effect.Effect<ReadonlyArray<ServedHyperlink>>;
}>, never, never>) => Effect.Effect<void, never, never>): Effect.Effect<...> (+21 overloads)
pipe(
import EffectEffect.const flatMap: <Option.Option<{
readonly register: (entry: ServedHyperlink) => Effect.Effect<void>;
readonly all: Effect.Effect<ReadonlyArray<ServedHyperlink>>;
}>, void, never, never>(f: (a: Option.Option<{
readonly register: (entry: ServedHyperlink) => Effect.Effect<void>;
readonly all: Effect.Effect<ReadonlyArray<ServedHyperlink>>;
}>) => Effect.Effect<void, never, never>) => <E, R>(self: Effect.Effect<Option.Option<{
readonly register: (entry: ServedHyperlink) => Effect.Effect<void>;
readonly all: Effect.Effect<ReadonlyArray<ServedHyperlink>>;
}>, E, R>) => Effect.Effect<...> (+1 overload)
Chains effects to produce new Effect instances, useful for combining
operations that depend on previous results.
When to use
Use when you need to chain multiple effects, ensuring that each
step produces a new Effect while flattening any nested effects that may
occur.
Details
flatMap lets you sequence effects so that the result of one effect can be
used in the next step. It is similar to flatMap used with arrays but works
specifically with Effect instances, allowing you to avoid deeply nested
effect structures.
Since effects are immutable, flatMap always returns a new effect instead of
changing the original one.
Example (Choosing flatMap syntax variants)
import { Effect, pipe } from "effect"
const myEffect = Effect.succeed(1)
const transformation = (n: number) => Effect.succeed(n + 1)
const flatMappedWithPipe = pipe(myEffect, Effect.flatMap(transformation))
const flatMappedWithDataFirst = Effect.flatMap(myEffect, transformation)
const flatMappedWithMethod = myEffect.pipe(Effect.flatMap(transformation))
Example (Sequencing dependent effects)
import { Data, Effect, pipe } from "effect"
class DiscountRateError extends Data.TaggedError("DiscountRateError")<{}> {}
// Function to apply a discount safely to a transaction amount
const applyDiscount = (
total: number,
discountRate: number
): Effect.Effect<number, DiscountRateError> =>
discountRate === 0
? Effect.fail(new DiscountRateError())
: Effect.succeed(total - (total * discountRate) / 100)
// Simulated asynchronous task to fetch a transaction amount from database
const fetchTransactionAmount = Effect.promise(() => Promise.resolve(100))
// Chaining the fetch and discount application using `flatMap`
const finalAmount = pipe(
fetchTransactionAmount,
Effect.flatMap((amount) => applyDiscount(amount, 5))
)
Effect.runPromise(finalAmount).then(console.log)
// Output: 95
flatMap(
import OptionOption.const match: <Effect.Effect<void, never, never>, {
readonly register: (entry: ServedHyperlink) => Effect.Effect<void>;
readonly all: Effect.Effect<ReadonlyArray<ServedHyperlink>>;
}, Effect.Effect<void, never, never>>(options: {
readonly onNone: Fn.LazyArg<Effect.Effect<void, never, never>>;
readonly onSome: (a: {
readonly register: (entry: ServedHyperlink) => Effect.Effect<void>;
readonly all: Effect.Effect<ReadonlyArray<ServedHyperlink>>;
}) => Effect.Effect<void, never, never>;
}) => (self: Option.Option<{
readonly register: (entry: ServedHyperlink) => Effect.Effect<void>;
readonly all: Effect.Effect<ReadonlyArray<ServedHyperlink>>;
}>) => Effect.Effect<...> (+1 overload)
Pattern-matches on an Option, handling both None and Some cases.
When to use
Use when you need to handle both Some and None in one expression and
transform an Option into a plain value.
Details
- If
None, calls onNone and returns its result
- If
Some, calls onSome with the value and returns its result
- Supports the
dual API (data-last and data-first)
Example (Matching on an Option)
import { Option } from "effect"
const message = Option.match(Option.some(1), {
onNone: () => "Option is empty",
onSome: (value) => `Option has a value: ${value}`
})
console.log(message)
// Output: "Option has a value: 1"
match({
onNone: Fn.LazyArg<
Effect.Effect<void, never, never>
>
onNone: () => import EffectEffect.const void: Effect.Effect<void, never, never>
export void
(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,
onSome: (registry: {
readonly register: (
entry: ServedHyperlink
) => Effect.Effect<void>
readonly all: Effect.Effect<
ReadonlyArray<ServedHyperlink>
>
}) => Effect.Effect<void, never, never>
onSome: (registry: {
readonly register: (
entry: ServedHyperlink
) => Effect.Effect<void>
readonly all: Effect.Effect<
ReadonlyArray<ServedHyperlink>
>
}
registry) => {
const const bound: anybound = const nodeOf: (
tag: unknown
) => NodeKey<unknown> | undefined
The
Node
a tag is bound to (its transport key), or undefined for a nodeless/bare tag
or any non-tag. Accepts unknown so a Group member passes straight in — walk a group tree and
collect the distinct nodes to know which nodes back its resources.
nodeOf(tag: {
readonly groupId: string
readonly [specSym]: FlatSpec
readonly [specTypeSym]?: S
readonly [groupSym]: RpcGroupOf<S>
}
tag);
const const boundKinds: readonly ProtocolKind[]boundKinds = const nodeKindsOf: (
tag: unknown
) => ReadonlyArray<ProtocolKind>
The full set of
ProtocolKind
s a tag's
Node
speaks — every transport in its
endpoints set (a multi-protocol node has several), or its single primary kind, or [] for a
nodeless/bare tag. A structural read; the server asserts its own transport is a member of this
set (
ProtocolKindMismatch
) so a node served over any of its declared transports passes.
nodeKindsOf(tag: {
readonly groupId: string
readonly [specSym]: FlatSpec
readonly [specTypeSym]?: S
readonly [groupSym]: RpcGroupOf<S>
}
tag);
const const kind: stringkind = const kindOf: (
tag: unknown
) => string | undefined
The contract kind a tag was built for (e.g. hyperlink-ts/QueueHyperlink, or
kind
for a bare
Hyperlink.Tag
); undefined only for a non-tag. The robust replacement for
sniffing a tag's spec; accepts unknown so a Group member can be passed straight in.
kindOf(tag: {
readonly groupId: string
readonly [specSym]: FlatSpec
readonly [specTypeSym]?: S
readonly [groupSym]: RpcGroupOf<S>
}
tag) ?? "hyperlink";
return registry: {
readonly register: (
entry: ServedHyperlink
) => Effect.Effect<void>
readonly all: Effect.Effect<
ReadonlyArray<ServedHyperlink>
>
}
registry.register: (
entry: ServedHyperlink
) => Effect.Effect<void>
register({
ServedHyperlink.groupId: stringgroupId: tag: {
readonly groupId: string
readonly [specSym]: FlatSpec
readonly [specTypeSym]?: S
readonly [groupSym]: RpcGroupOf<S>
}
tag.groupId: stringgroupId,
ServedHyperlink.group: RpcGroup.RpcGroup<any>(property) ServedHyperlink.group: {
requests: ReadonlyMap<string, R>;
annotations: Context.Context<never>;
add: (...rpcs: Rpcs2) => RpcGroup.RpcGroup<RpcUnionOf<S, ''> | Rpcs2[number]>;
merge: (...groups: Groups) => RpcGroup.RpcGroup<RpcUnionOf<S, ''> | RpcGroup.Rpcs<Groups[number]>>;
omit: (...tags: Tags) => RpcGroup.RpcGroup<Exclude<RpcUnionOf<S, ''>, { readonly _tag: Tags[number] }>>;
middleware: (middleware: M) => RpcGroup.RpcGroup<Rpc.AddMiddleware<RpcUnionOf<S, ''>, M>>;
prefix: (prefix: Prefix) => RpcGroup.RpcGroup<Rpc.Prefixed<RpcUnionOf<S, ''>, Prefix>>;
toHandlers: (build: Handlers | Effect.Effect<Handlers, EX, RX>) => Effect.Effect<Context.Context<Rpc.ToHandler<RpcUnionOf<S, ''>>>, EX, RX | RpcGroup.HandlersServices<RpcUnionOf<S, ''>, Handlers>>;
toLayer: (build: Handlers | Effect.Effect<Handlers, EX, RX>) => Layer.Layer<Rpc.ToHandler<RpcUnionOf<S, ''>>, EX, Exclude<RX, Scope.Scope> | RpcGroup.HandlersServices<RpcUnionOf<S, ''>, Handlers>>;
of: (handlers: Handlers) => Handlers;
toLayerHandler: (tag: Tag, build: Handler | Effect.Effect<Handler, EX, RX>) => Layer.Layer<Rpc.Handler<Tag>, EX, Exclude<RX, Scope.Scope> | RpcGroup.HandlerServices<RpcUnionOf<S, ''>, Tag, Handler>>;
accessHandler: (tag: Tag) => Effect.Effect<(payload: Rpc.Payload<Extract<RpcUnionOf<S, ''>, { readonly _tag: Tag }>>, options: { readonly client: Rpc.ServerClient; readonly requestId: RequestId; readonly headers: Headers.Headers }) => Rpc.ResultFrom<Extr…;
annotate: (service: Context.Key<I, S>, value: S) => RpcGroup.RpcGroup<RpcUnionOf<S, ''>>;
annotateRpcs: (service: Context.Key<I, S>, value: S) => RpcGroup.RpcGroup<RpcUnionOf<S, ''>>;
annotateMerge: (annotations: Context.Context<S>) => RpcGroup.RpcGroup<RpcUnionOf<S, ''>>;
annotateRpcsMerge: (annotations: Context.Context<S>) => RpcGroup.RpcGroup<RpcUnionOf<S, ''>>;
pipe: { <A>(this: A): A; <A, B = never>(this: A, ab: (_: A) => B): B; <A, B = never, C = never>(this: A, ab: (_: A) => B, bc: (_: B) => C): C; <A, B = never, C = never, D = never>(this: A, ab: (_: A) => B, bc: (_: B) => C, cd: (_: C) => D): D; <…;
}
group,
ServedHyperlink.kind: stringkind,
ServedHyperlink.contractHash: stringF4 wire-contract fingerprint — stamped at serve from the tag Spec.
contractHash: import hashContracthashContract(tag: {
readonly groupId: string
readonly [specSym]: FlatSpec
readonly [specTypeSym]?: S
readonly [groupSym]: RpcGroupOf<S>
}
tag.groupId: stringgroupId, const kind: stringkind, tag: {
readonly groupId: string
readonly [specSym]: FlatSpec
readonly [specTypeSym]?: S
readonly [groupSym]: RpcGroupOf<S>
}
tag[const specSym: typeof specSymWhere the contract spec is stowed on a Tag (hidden from the value surface). Exported so
the public
HyperlinkTag
type is nameable across modules.
specSym]),
ServedHyperlink.readiness: Effect.Effect<Readiness, never, never>(property) ServedHyperlink.readiness: {
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;
}
readiness: const readinessCheckServed: (
tag: { readonly [specSym]: FlatSpec },
impl: unknown
) => Effect.Effect<Readiness>
Readiness for a served resource, where all we have is the wire impl (a value field is a Stream
there, a constant an Effect). Resolve those to plain values first — so the derivation sees the same
service shape
readinessOf
gives it (the materialized service), not the raw wire impl. The value
head is read in a short-lived scope so no Scope leaks into the result.
readinessCheckServed(tag: {
readonly groupId: string
readonly [specSym]: FlatSpec
readonly [specTypeSym]?: S
readonly [groupSym]: RpcGroupOf<S>
}
tag, const wireImpl:
| ServeImplOf<S, any>
| Stream.Stream<unknown, unknown, unknown>
| Subscribable<unknown>
| ImplOf<S>
| ((
...args: unknown[]
) => Effect.Effect<unknown, unknown, any>)
| Effect.Effect<unknown, unknown, any>
| (((
...args: ReadonlyArray<never>
) => unknown) &
ImplOf<S>)
| {
readonly [K in keyof ImplOf<S>]: WithRequirement<
ImplOf<S>[K],
any
>
}
wireImpl),
...(const bound: anybound !== var undefinedundefined ? { ServedHyperlink.nodeLogKey?: string | undefinedNode log key when the served tag is bound to a
Node
(options.node).
nodeLogKey: const bound: anybound.key } : {}),
...(const boundKinds: readonly ProtocolKind[]boundKinds.ReadonlyArray<T>.length: numberGets the length of the array. This is a number one higher than the highest element defined in an array.
length > 0 ? { ServedHyperlink.nodeKinds?: readonly ProtocolKind[] | undefinedDeclared transport set of the tag's
Node
, when node-bound — the server asserts its own
transport is a member, else
ProtocolKindMismatch
. A multi-protocol node lists all its
transports, so serving it over any one passes.
nodeKinds: const boundKinds: readonly ProtocolKind[]boundKinds } : {}),
});
},
}),
),
),
);
return import LayerLayer.const merge: <unknown, unknown, unknown, never, never, never>(self: Layer.Layer<unknown, unknown, unknown>, that: Layer.Layer<never, never, never>) => Layer.Layer<unknown, unknown, unknown> (+3 overloads)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(const handlerLayer: anyhandlerLayer, const registration: Layer.Layer<
never,
never,
never
>
const registration: {
build: (memoMap: Layer.MemoMap, scope: Scope.Scope) => Effect.Effect<Context.Context<never>, never, never>;
pipe: { <A>(this: A): A; <A, B = never>(this: A, ab: (_: A) => B): B; <A, B = never, C = never>(this: A, ab: (_: A) => B, bc: (_: B) => C): C; <A, B = never, C = never, D = never>(this: A, ab: (_: A) => B, bc: (_: B) => C, cd: (_: C) => D): D; <…;
}
registration) as any;
};