<S extends Spec, Impl extends ServeImplOf<S, any>>(
tag: {
readonly [wireKeySym]: string
readonly [specSym]: FlatSpec
readonly [specTypeSym]?: S
readonly [groupSym]: RpcGroupOf<S>
},
impl: Impl
): Layer.Layer<HandlerContextOf<S>, never, ServeRequirements<Impl>>A HyperService'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-HyperService Layer.provide discharges this HyperService's dependency in isolation:
Hyperlink.serveRemote(SeasonMatches, seasonMatchesImpl).pipe(Layer.provide(importHandlersLayer))The point of serveRemote is the run-time-requirement case: N HyperServices needing different
implementations of the same tag, each isolated — merge the layers onto one RpcServer (groups are
prefix-keyed).
Plain impls infer R via ServeRequirements. For a Driver, use
serveRemoteDriver so the driver's R is the Layer requirement (no toolkit retype).
export const const serveRemote: <
S extends Spec,
Impl extends ServeImplOf<S, any>
>(
tag: {
readonly [wireKeySym]: string
readonly [specSym]: FlatSpec
readonly [specTypeSym]?: S
readonly [groupSym]: RpcGroupOf<S>
},
impl: Impl
) => Layer.Layer<
HandlerContextOf<S>,
never,
ServeRequirements<Impl>
>
A HyperService'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-HyperService Layer.provide discharges this HyperService's dependency in isolation:
Hyperlink.serveRemote(SeasonMatches, seasonMatchesImpl).pipe(Layer.provide(importHandlersLayer))
The point of serveRemote is the run-time-requirement case: N HyperServices needing different
implementations of the same tag, each isolated — merge the layers onto one RpcServer (groups are
prefix-keyed).
Plain impls infer R via
ServeRequirements
. For a
Driver
, use
serveRemoteDriver
so the driver's R is the Layer requirement (no toolkit retype).
serveRemote = <function (type parameter) S in <S extends Spec, Impl extends ServeImplOf<S, any>>(tag: {
readonly [wireKeySym]: string;
readonly [specSym]: FlatSpec;
readonly [specTypeSym]?: S;
readonly [groupSym]: RpcGroupOf<S>;
}, impl: Impl): 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 [wireKeySym]: string;
readonly [specSym]: FlatSpec;
readonly [specTypeSym]?: S;
readonly [groupSym]: RpcGroupOf<S>;
}, impl: Impl): 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
| AnyDefaultMethod
? 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 [wireKeySym]: string;
readonly [specSym]: FlatSpec;
readonly [specTypeSym]?: S;
readonly [groupSym]: RpcGroupOf<S>;
}, impl: Impl): Layer.Layer<HandlerContextOf<S>, never, ServeRequirements<Impl>>
S, any>>(
tag: {
readonly [wireKeySym]: string
readonly [specSym]: FlatSpec
readonly [specTypeSym]?: S
readonly [groupSym]: RpcGroupOf<S>
}
tag: {
readonly [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]: 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
| AnyDefaultMethod
}
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 [wireKeySym]: string;
readonly [specSym]: FlatSpec;
readonly [specTypeSym]?: S;
readonly [groupSym]: RpcGroupOf<S>;
}, impl: Impl): 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 [wireKeySym]: string;
readonly [specSym]: FlatSpec;
readonly [specTypeSym]?: S;
readonly [groupSym]: RpcGroupOf<S>;
}, impl: Impl): Layer.Layer<HandlerContextOf<S>, never, ServeRequirements<Impl>>
S>;
},
impl: Impl extends ServeImplOf<S, any>impl: function (type parameter) Impl in <S extends Spec, Impl extends ServeImplOf<S, any>>(tag: {
readonly [wireKeySym]: string;
readonly [specSym]: FlatSpec;
readonly [specTypeSym]?: S;
readonly [groupSym]: RpcGroupOf<S>;
}, impl: Impl): Layer.Layer<HandlerContextOf<S>, never, ServeRequirements<Impl>>
Impl,
): 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 [wireKeySym]: string;
readonly [specSym]: FlatSpec;
readonly [specTypeSym]?: S;
readonly [groupSym]: RpcGroupOf<S>;
}, impl: Impl): 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 [wireKeySym]: string;
readonly [specSym]: FlatSpec;
readonly [specTypeSym]?: S;
readonly [groupSym]: RpcGroupOf<S>;
}, impl: Impl): Layer.Layer<HandlerContextOf<S>, never, ServeRequirements<Impl>>
Impl>> =>
const retype: <Layer.Layer<Rpc.ToHandler<RpcUnionOf<S, "">>, never, ServeRequirements<Impl>>>(value: never) => Layer.Layer<Rpc.ToHandler<RpcUnionOf<S, "">>, never, ServeRequirements<Impl>>Retype through never (not any/unknown channels) at dynamic Effect/Rpc factories.
Same bridge as internal/nodeServerCommon.retype — kept local so this module does not
import server plumbing.
retype<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 [wireKeySym]: string;
readonly [specSym]: FlatSpec;
readonly [specTypeSym]?: S;
readonly [groupSym]: RpcGroupOf<S>;
}, impl: Impl): 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 [wireKeySym]: string;
readonly [specSym]: FlatSpec;
readonly [specTypeSym]?: S;
readonly [groupSym]: RpcGroupOf<S>;
}, impl: Impl): Layer.Layer<HandlerContextOf<S>, never, ServeRequirements<Impl>>
Impl>>>(
const serveRemoteHandlers: (
tag: ServeRemoteTag,
wireImpl: unknown,
workerContext:
| Context.Context<unknown>
| undefined
) => Layer.Any
Shared handler mount + registry registration for
serveRemote
/
serveRemoteDriver
.
Returns
Layer.Any
; public wrappers reify R /
HandlerContextOf
.
Shared-Spec tags (
Tag
(wireKey, spec) instances) merge under one RpcGroup: the first
serve mounts handlers; later serves of the same wire key only append instances.
serveRemoteHandlers(tag: {
readonly [wireKeySym]: string
readonly [specSym]: FlatSpec
readonly [specTypeSym]?: S
readonly [groupSym]: RpcGroupOf<S>
}
tag, impl: Impl extends ServeImplOf<S, any>impl, var undefinedundefined) as never,
);