<S extends Spec, const Tags extends ReadonlyArray<WireInstanceTag<S>>>(
factory: {
readonly groupId: string
readonly [specSym]: FlatSpec
readonly [specTypeSym]?: S
readonly [groupSym]: RpcGroupOf<S>
},
...tags: Tags
): Layer.Layer<InstanceIdentifiers<Tags, S>, never, RpcClient.Protocol>The client layer for many instances of one factory, sharing a single RPC client —
the client mirror of Hyperlink.serveInstances. Builds one RpcClient for the
family's group and provides every instance's handle from it, each pinned to its own instance-key
header. So 100 instances of one control shape cost one client (and one shared
connection), not one client each — the contract/group/schemas are already shared.
Wire-only: instances declaring Hyperlink.local members aren't accepted (their service type is wider than the wire) — use Hyperlink.client per instance for those.
const const clientInstances: <
S extends Spec,
Tags extends ReadonlyArray<WireInstanceTag<S>>
>(
factory: {
readonly groupId: string
readonly [specSym]: FlatSpec
readonly [specTypeSym]?: S
readonly [groupSym]: RpcGroupOf<S>
},
...tags: Tags
) => Layer.Layer<
InstanceIdentifiers<Tags, S>,
never,
RpcClient.Protocol
>
The client layer for many instances of one factory, sharing a single RPC client —
the client mirror of
Hyperlink.serveInstances
. Builds one RpcClient for the
family's group and provides every instance's handle from it, each pinned to its own instance-key
header. So 100 instances of one control shape cost one client (and one shared
connection), not one client each — the contract/group/schemas are already shared.
Wire-only: instances declaring
Hyperlink.local
members aren't accepted (their service
type is wider than the wire) — use
Hyperlink.client
per instance for those.
clientInstances = <
function (type parameter) S in <S extends Spec, const Tags extends ReadonlyArray<WireInstanceTag<S>>>(factory: {
readonly groupId: string;
readonly [specSym]: FlatSpec;
readonly [specTypeSym]?: S;
readonly [groupSym]: RpcGroupOf<S>;
}, ...tags: Tags): Layer.Layer<InstanceIdentifiers<Tags, S>, never, RpcClient.Protocol>
S extends Spec,
const function (type parameter) Tags in <S extends Spec, const Tags extends ReadonlyArray<WireInstanceTag<S>>>(factory: {
readonly groupId: string;
readonly [specSym]: FlatSpec;
readonly [specTypeSym]?: S;
readonly [groupSym]: RpcGroupOf<S>;
}, ...tags: Tags): Layer.Layer<InstanceIdentifiers<Tags, S>, never, RpcClient.Protocol>
Tags extends interface ReadonlyArray<T>ReadonlyArray<type WireInstanceTag<S extends Spec> =
Context.Key<unknown, WireServiceOf<S>> & {
readonly key: string
}
A wire-only instance tag for
clientInstances
— keyed via the covariant
Context.Key
base so distinct Selfs are accepted without any.
WireInstanceTag<function (type parameter) S in <S extends Spec, const Tags extends ReadonlyArray<WireInstanceTag<S>>>(factory: {
readonly groupId: string;
readonly [specSym]: FlatSpec;
readonly [specTypeSym]?: S;
readonly [groupSym]: RpcGroupOf<S>;
}, ...tags: Tags): Layer.Layer<InstanceIdentifiers<Tags, S>, never, RpcClient.Protocol>
S>>,
>(
factory: {
readonly groupId: string
readonly [specSym]: FlatSpec
readonly [specTypeSym]?: S
readonly [groupSym]: RpcGroupOf<S>
}
factory: {
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, const Tags extends ReadonlyArray<WireInstanceTag<S>>>(factory: {
readonly groupId: string;
readonly [specSym]: FlatSpec;
readonly [specTypeSym]?: S;
readonly [groupSym]: RpcGroupOf<S>;
}, ...tags: Tags): Layer.Layer<InstanceIdentifiers<Tags, S>, never, RpcClient.Protocol>
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, const Tags extends ReadonlyArray<WireInstanceTag<S>>>(factory: {
readonly groupId: string;
readonly [specSym]: FlatSpec;
readonly [specTypeSym]?: S;
readonly [groupSym]: RpcGroupOf<S>;
}, ...tags: Tags): Layer.Layer<InstanceIdentifiers<Tags, S>, never, RpcClient.Protocol>
S>;
},
...tags: const Tags extends ReadonlyArray<WireInstanceTag<S>>tags: function (type parameter) Tags in <S extends Spec, const Tags extends ReadonlyArray<WireInstanceTag<S>>>(factory: {
readonly groupId: string;
readonly [specSym]: FlatSpec;
readonly [specTypeSym]?: S;
readonly [groupSym]: RpcGroupOf<S>;
}, ...tags: Tags): Layer.Layer<InstanceIdentifiers<Tags, S>, never, RpcClient.Protocol>
Tags
): 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 InstanceIdentifiers<
Tags extends ReadonlyArray<unknown>,
S extends Spec
> = Tags[number] extends Context.Key<
infer Self,
WireServiceOf<S>
>
? Self
: never
The instance identifiers a
clientInstances
layer provides (the union of tag Selfs).
InstanceIdentifiers<function (type parameter) Tags in <S extends Spec, const Tags extends ReadonlyArray<WireInstanceTag<S>>>(factory: {
readonly groupId: string;
readonly [specSym]: FlatSpec;
readonly [specTypeSym]?: S;
readonly [groupSym]: RpcGroupOf<S>;
}, ...tags: Tags): Layer.Layer<InstanceIdentifiers<Tags, S>, never, RpcClient.Protocol>
Tags, function (type parameter) S in <S extends Spec, const Tags extends ReadonlyArray<WireInstanceTag<S>>>(factory: {
readonly groupId: string;
readonly [specSym]: FlatSpec;
readonly [specTypeSym]?: S;
readonly [groupSym]: RpcGroupOf<S>;
}, ...tags: Tags): Layer.Layer<InstanceIdentifiers<Tags, S>, never, RpcClient.Protocol>
S>, never, import RpcClientRpcClient.class Protocolclass Protocol {
key: Identifier;
Service: {
run: (clientId: number, f: (data: FromServerEncoded) => Effect.Effect<void>) => Effect.Effect<never>;
send: (clientId: number, request: FromClientEncoded, transferables?: ReadonlyArray<globalThis.Transferable>) => Effect.Effect<void, RpcClientError>;
supportsAck: boolean;
supportsTransferables: boolean;
};
}
Defines the service interface for an RPC client transport, responsible for running the
receive loop and sending encoded client messages.
When to use
Use to provide the transport boundary for RPC clients over HTTP, WebSocket,
workers, sockets, or custom protocols.
Protocol> =>
import LayerLayer.const effectContext: <InstanceIdentifiers<Tags, S>, MissingClientProtocol, Scope.Scope>(effect: Effect.Effect<Context.Context<InstanceIdentifiers<Tags, S>>, MissingClientProtocol, Scope.Scope>) => Layer.Layer<InstanceIdentifiers<Tags, S>, MissingClientProtocol, never>Constructs a layer from an effect that produces all services in a Context.
When to use
Use when you need a Layer that effectfully constructs a Context with
multiple services.
Details
This allows you to create a Layer from an effectful computation that
returns multiple services. The Effect is executed in the scope of the
layer.
Example (Creating a layer from an effectful context)
import { Context, Effect, Layer } from "effect"
class Database extends Context.Service<
Database,
{ readonly query: (sql: string) => Effect.Effect<string> }
>()("Database") {}
const layer = Layer.effectContext(
Effect.succeed(Context.make(Database, {
query: (sql: string) => Effect.succeed(`Query: ${sql}`)
}))
)
effectContext(
import EffectEffect.const gen: <Effect.Effect<never, MissingClientProtocol, never> | Effect.Effect<Option.Option<{
readonly run: (clientId: number, f: (data: FromServerEncoded) => Effect.Effect<void>) => Effect.Effect<never>;
readonly send: (clientId: number, request: FromClientEncoded, transferables?: ReadonlyArray<globalThis.Transferable>) => Effect.Effect<void, RpcClientError>;
readonly supportsAck: boolean;
readonly supportsTransferables: boolean;
}>, never, never> | Effect.Effect<...>, Context.Context<...>>(f: () => Generator<...>) => Effect.Effect<...> (+1 overload)
Provides a way to write effectful code using generator functions, simplifying
control flow and error handling.
When to use
Use when you want to write effectful code that looks and behaves like
synchronous code, while still handling asynchronous tasks, errors, and complex
control flow such as loops and conditions.
Generator functions work similarly to async/await but keep errors,
requirements, and interruption in the Effect type. You can yield* values
from effects and return the final result at the end.
Example (Sequencing effects with generators)
import { Data, Effect } from "effect"
class DiscountRateError extends Data.TaggedError("DiscountRateError")<{}> {}
const addServiceCharge = (amount: number) => amount + 1
const applyDiscount = (
total: number,
discountRate: number
): Effect.Effect<number, DiscountRateError> =>
discountRate === 0
? Effect.fail(new DiscountRateError())
: Effect.succeed(total - (total * discountRate) / 100)
const fetchTransactionAmount = Effect.promise(() => Promise.resolve(100))
const fetchDiscountRate = Effect.promise(() => Promise.resolve(5))
export const program = Effect.gen(function*() {
const transactionAmount = yield* fetchTransactionAmount
const discountRate = yield* fetchDiscountRate
const discountedAmount = yield* applyDiscount(
transactionAmount,
discountRate
)
const finalAmount = addServiceCharge(discountedAmount)
return `Final amount to charge: ${finalAmount}`
})
gen(function* () {
const const protocol: Option.Option<{
readonly run: (
clientId: number,
f: (
data: FromServerEncoded
) => Effect.Effect<void>
) => Effect.Effect<never>
readonly send: (
clientId: number,
request: FromClientEncoded,
transferables?: ReadonlyArray<globalThis.Transferable>
) => Effect.Effect<void, RpcClientError>
readonly supportsAck: boolean
readonly supportsTransferables: boolean
}>
protocol = yield* import EffectEffect.const serviceOption: <RpcClient.Protocol, {
readonly run: (clientId: number, f: (data: FromServerEncoded) => Effect.Effect<void>) => Effect.Effect<never>;
readonly send: (clientId: number, request: FromClientEncoded, transferables?: ReadonlyArray<globalThis.Transferable>) => Effect.Effect<void, RpcClientError>;
readonly supportsAck: boolean;
readonly supportsTransferables: boolean;
}>(key: Context.Key<RpcClient.Protocol, {
readonly run: (clientId: number, f: (data: FromServerEncoded) => Effect.Effect<void>) => Effect.Effect<never>;
readonly send: (clientId: number, request: FromClientEncoded, transferables?: ReadonlyArray<globalThis.Transferable>) => Effect.Effect<void, RpcClientError>;
readonly supportsAck: boolean;
readonly supportsTransferables: boolean;
}>) => Effect.Effect<...>
Optionally accesses a service from the environment.
When to use
Use to read an optional dependency from the current context without making
that dependency part of the effect's required environment.
Details
This function attempts to access a service from the environment. If the
service is available, it returns Some(service). If the service is not
available, it returns None. Unlike service, this function does not
require the service to be present in the environment.
Example (Accessing an optional service)
import { Context, Effect, Option } from "effect"
// Define a service key
const Logger = Context.Service<{
log: (msg: string) => void
}>("Logger")
// Use serviceOption to optionally access the logger
const program = Effect.gen(function*() {
const maybeLogger = yield* Effect.serviceOption(Logger)
if (Option.isSome(maybeLogger)) {
maybeLogger.value.log("Service is available")
} else {
console.log("Service not available")
}
})
serviceOption(import RpcClientRpcClient.class Protocolclass Protocol {
key: Identifier;
Service: {
run: (clientId: number, f: (data: FromServerEncoded) => Effect.Effect<void>) => Effect.Effect<never>;
send: (clientId: number, request: FromClientEncoded, transferables?: ReadonlyArray<globalThis.Transferable>) => Effect.Effect<void, RpcClientError>;
supportsAck: boolean;
supportsTransferables: boolean;
};
make: <EX, RX>(f: (write: (clientId: number, response: FromServerEncoded) => Effect.Effect<void>, clientIds: ReadonlySet<number>) => Effect.Effect<Omit<RpcClient.Protocol['Service'], 'run'>, EX, RX>) => Effect.Effect<RpcClient.Protocol['Service'…;
of: (this: void, self: { readonly run: (clientId: number, f: (data: FromServerEncoded) => Effect.Effect<void>) => Effect.Effect<never>; readonly send: (clientId: number, request: FromClientEncoded, transferables?: ReadonlyArray<globalThis.Tran…;
context: (self: { readonly run: (clientId: number, f: (data: FromServerEncoded) => Effect.Effect<void>) => Effect.Effect<never>; readonly send: (clientId: number, request: FromClientEncoded, transferables?: ReadonlyArray<globalThis.Transferable>) =…;
use: (f: (service: { readonly run: (clientId: number, f: (data: FromServerEncoded) => Effect.Effect<void>) => Effect.Effect<never>; readonly send: (clientId: number, request: FromClientEncoded, transferables?: ReadonlyArray<globalThis.Transfera…;
useSync: (f: (service: { readonly run: (clientId: number, f: (data: FromServerEncoded) => Effect.Effect<void>) => Effect.Effect<never>; readonly send: (clientId: number, request: FromClientEncoded, transferables?: ReadonlyArray<globalThis.Transfera…;
Identifier: Identifier;
stack: string | undefined;
pipe: { <A>(this: A): A; <A, B = never>(this: A, ab: (_: A) => B): B; <A, B = never, C = never>(this: A, ab: (_: A) => B, bc: (_: B) => C): C; <A, B = never, C = never, D = never>(this: A, ab: (_: A) => B, bc: (_: B) => C, cd: (_: C) => D): D; <…;
toString: () => string;
toJSON: () => unknown;
}
Defines the service interface for an RPC client transport, responsible for running the
receive loop and sending encoded client messages.
When to use
Use to provide the transport boundary for RPC clients over HTTP, WebSocket,
workers, sockets, or custom protocols.
Protocol);
if (import OptionOption.const isNone: <{
readonly run: (clientId: number, f: (data: FromServerEncoded) => Effect.Effect<void>) => Effect.Effect<never>;
readonly send: (clientId: number, request: FromClientEncoded, transferables?: ReadonlyArray<globalThis.Transferable>) => Effect.Effect<void, RpcClientError>;
readonly supportsAck: boolean;
readonly supportsTransferables: boolean;
}>(self: Option.Option<{
readonly run: (clientId: number, f: (data: FromServerEncoded) => Effect.Effect<void>) => Effect.Effect<never>;
readonly send: (clientId: number, request: FromClientEncoded, transferables?: ReadonlyArray<globalThis.Transferable>) => Effect.Effect<void, RpcClientError>;
readonly supportsAck: boolean;
readonly supportsTransferables: boolean;
}>) => self is Option.None<...>
Checks whether an Option is None (absent).
When to use
Use when you need to branch on an absent Option before accessing .value.
Details
- Acts as a type guard, narrowing to
None<A>
Example (Checking for None)
import { Option } from "effect"
console.log(Option.isNone(Option.some(1)))
// Output: false
console.log(Option.isNone(Option.none()))
// Output: true
isNone(const protocol: Option.Option<{
readonly run: (
clientId: number,
f: (
data: FromServerEncoded
) => Effect.Effect<void>
) => Effect.Effect<never>
readonly send: (
clientId: number,
request: FromClientEncoded,
transferables?: ReadonlyArray<globalThis.Transferable>
) => Effect.Effect<void, RpcClientError>
readonly supportsAck: boolean
readonly supportsTransferables: boolean
}>
protocol)) {
return yield* new constructor MissingClientProtocol<{
readonly resource: string;
}>(args: {
readonly resource: string;
}): MissingClientProtocol
A nodeless
Hyperlink.client
(tag) was built with no ambient
RpcClient.Protocol
.
Replaces Effect's opaque "Service not found: …/Protocol" die with a remediation message naming
the three ways to connect. The Layer still requires RpcClient.Protocol in R (compile-time)
and keeps E = never (this replaces a defect, not a typed channel callers already matched);
catch via Exit / _tag when probing an unsatisfied build.
MissingClientProtocol({
resource: stringresource: factory: {
readonly groupId: string
readonly [specSym]: FlatSpec
readonly [specTypeSym]?: S
readonly [groupSym]: RpcGroupOf<S>
}
factory.groupId: stringgroupId,
});
}
const const rpc: {
[K in keyof RpcClient.RpcClient.From<
RpcUnionOf<S, "">,
RpcClientError
>]: RpcClient.RpcClient.From<
RpcUnionOf<S, "">,
RpcClientError
>[K]
}
rpc = yield* import EffectEffect.const provideService: <{ [K in keyof RpcClient.RpcClient<Rpcs extends Rpc.Any, E = never>.From<RpcUnionOf<S, "">, RpcClientError>]: RpcClient.RpcClient.From<RpcUnionOf<S, "">, RpcClientError>[K]; }, never, RpcClient.Protocol | Scope.Scope | Rpc.MiddlewareClient<RpcUnionOf<S, "">>, RpcClient.Protocol, {
readonly run: (clientId: number, f: (data: FromServerEncoded) => Effect.Effect<void>) => Effect.Effect<never>;
readonly send: (clientId: number, request: FromClientEncoded, transferables?: ReadonlyArray<globalThis.Transferable>) => Effect.Effect<void, RpcClientError>;
readonly supportsAck: boolean;
readonly supportsTransferables: boolean;
}>(self: Effect.Effect<...>, service: Context.Key<...>, implementation: {
readonly run: (clientId: number, f: (data: FromServerEncoded) => Effect.Effect<void>) => Effect.Effect<never>;
readonly send: (clientId: number, request: FromClientEncoded, transferables?: ReadonlyArray<globalThis.Transferable>) => Effect.Effect<void, RpcClientError>;
readonly supportsAck: boolean;
readonly supportsTransferables: boolean;
}) => Effect.Effect<...> (+2 overloads)
Provides one concrete service implementation to an effect.
When to use
Use to satisfy one service requirement with an already-built implementation.
Details
The service requirement identified by the Context.Key is removed from the
effect requirements after the implementation is provided.
Example (Providing a service value)
import { Console, Context, Effect } from "effect"
// Define a service for configuration
const Config = Context.Service<{
apiUrl: string
timeout: number
}>("Config")
const fetchData = Effect.gen(function*() {
const config = yield* Effect.service(Config)
yield* Console.log(`Fetching from: ${config.apiUrl}`)
yield* Console.log(`Timeout: ${config.timeout}ms`)
return "data"
})
// Provide the service implementation
const program = Effect.provideService(fetchData, Config, {
apiUrl: "https://api.example.com",
timeout: 5000
})
Effect.runPromise(program).then(console.log)
// Output:
// Fetching from: https://api.example.com
// Timeout: 5000ms
// data
provideService(
import RpcClientRpcClient.const make: <RpcUnionOf<S, "">, false>(group: RpcGroup.RpcGroup<RpcUnionOf<S, "">>, options?: {
readonly spanPrefix?: string | undefined;
readonly spanAttributes?: Record<string, unknown> | undefined;
readonly generateRequestId?: (() => RequestId) | undefined;
readonly disableTracing?: boolean | undefined;
readonly flatten?: false | undefined;
} | undefined) => Effect.Effect<{ [K in keyof RpcClient.RpcClient<Rpcs extends Rpc.Any, E = never>.From<RpcUnionOf<S, "">, RpcClientError>]: RpcClient.RpcClient.From<...>[K]; }, never, RpcClient.Protocol | ... 1 more ... | Rpc.MiddlewareClient<...>>
Creates a schema-aware RPC client for a group using the current client
Protocol, encoding requests and decoding server responses.
make(factory: {
readonly groupId: string
readonly [specSym]: FlatSpec
readonly [specTypeSym]?: S
readonly [groupSym]: RpcGroupOf<S>
}
factory[const groupSym: typeof groupSymWhere the built RPC group is stowed on a Tag.
groupSym]),
import RpcClientRpcClient.class Protocolclass Protocol {
key: Identifier;
Service: {
run: (clientId: number, f: (data: FromServerEncoded) => Effect.Effect<void>) => Effect.Effect<never>;
send: (clientId: number, request: FromClientEncoded, transferables?: ReadonlyArray<globalThis.Transferable>) => Effect.Effect<void, RpcClientError>;
supportsAck: boolean;
supportsTransferables: boolean;
};
make: <EX, RX>(f: (write: (clientId: number, response: FromServerEncoded) => Effect.Effect<void>, clientIds: ReadonlySet<number>) => Effect.Effect<Omit<RpcClient.Protocol['Service'], 'run'>, EX, RX>) => Effect.Effect<RpcClient.Protocol['Service'…;
of: (this: void, self: { readonly run: (clientId: number, f: (data: FromServerEncoded) => Effect.Effect<void>) => Effect.Effect<never>; readonly send: (clientId: number, request: FromClientEncoded, transferables?: ReadonlyArray<globalThis.Tran…;
context: (self: { readonly run: (clientId: number, f: (data: FromServerEncoded) => Effect.Effect<void>) => Effect.Effect<never>; readonly send: (clientId: number, request: FromClientEncoded, transferables?: ReadonlyArray<globalThis.Transferable>) =…;
use: (f: (service: { readonly run: (clientId: number, f: (data: FromServerEncoded) => Effect.Effect<void>) => Effect.Effect<never>; readonly send: (clientId: number, request: FromClientEncoded, transferables?: ReadonlyArray<globalThis.Transfera…;
useSync: (f: (service: { readonly run: (clientId: number, f: (data: FromServerEncoded) => Effect.Effect<void>) => Effect.Effect<never>; readonly send: (clientId: number, request: FromClientEncoded, transferables?: ReadonlyArray<globalThis.Transfera…;
Identifier: Identifier;
stack: string | undefined;
pipe: { <A>(this: A): A; <A, B = never>(this: A, ab: (_: A) => B): B; <A, B = never, C = never>(this: A, ab: (_: A) => B, bc: (_: B) => C): C; <A, B = never, C = never, D = never>(this: A, ab: (_: A) => B, bc: (_: B) => C, cd: (_: C) => D): D; <…;
toString: () => string;
toJSON: () => unknown;
}
Defines the service interface for an RPC client transport, responsible for running the
receive loop and sending encoded client messages.
When to use
Use to provide the transport boundary for RPC clients over HTTP, WebSocket,
workers, sockets, or custom protocols.
Protocol,
const protocol: Option.Some<{
readonly run: (
clientId: number,
f: (
data: FromServerEncoded
) => Effect.Effect<void>
) => Effect.Effect<never>
readonly send: (
clientId: number,
request: FromClientEncoded,
transferables?: ReadonlyArray<globalThis.Transferable>
) => Effect.Effect<void, RpcClientError>
readonly supportsAck: boolean
readonly supportsTransferables: boolean
}>
const protocol: {
_tag: "Some";
_op: "Some";
value: A;
valueOrUndefined: A;
pipe: { <A>(this: A): A; <A, B = never>(this: A, ab: (_: A) => B): B; <A, B = never, C = never>(this: A, ab: (_: A) => B, bc: (_: B) => C): C; <A, B = never, C = never, D = never>(this: A, ab: (_: A) => B, bc: (_: B) => C, cd: (_: C) => D): D; <…;
toString: () => string;
toJSON: () => unknown;
}
protocol.Some<{ readonly run: (clientId: number, f: (data: FromServerEncoded) => Effect.Effect<void>) => Effect.Effect<never>; readonly send: (clientId: number, request: FromClientEncoded, transferables?: ReadonlyArray<globalThis.Transferable>) => Effect.Effect<void, RpcClientError>; readonly supportsAck: boolean; readonly supportsTransferables: boolean; }>.value: {
readonly run: (clientId: number, f: (data: FromServerEncoded) => Effect.Effect<void>) => Effect.Effect<never>;
readonly send: (clientId: number, request: FromClientEncoded, transferables?: ReadonlyArray<globalThis.Transferable>) => Effect.Effect<void, RpcClientError>;
readonly supportsAck: boolean;
readonly supportsTransferables: boolean;
}
value,
);
let let context: Context.Context<never>let context: {
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;
}
context = import ContextContext.const empty: () => Context.Context<never>Returns an empty Context.
Example (Creating an empty context)
import { Context } from "effect"
import * as assert from "node:assert"
assert.strictEqual(Context.isContext(Context.empty()), true)
empty();
for (const const tag: WireInstanceTag<S>tag of tags: const Tags extends ReadonlyArray<WireInstanceTag<S>>tags) {
const const service: WireServiceOf<S>service = const nestService: (
flat: Record<string, unknown>
) => Record<string, unknown>
Nest a flat path-keyed service back into the tree. Identity (same reference) when there's no nesting
— so value fields' in-place setters keep updating the returned object.
nestService(
const forwardClient: <S extends Spec>(
rpc: unknown,
spec: S,
groupId: string,
instanceKey: string
) => WireServiceOf<S>
Map an RPC client + a spec into the typed service, forwarding each method to its
group-prefixed wire tag and pinning the instance key as a header. Shared by
Hyperlink.client
(production, over a real Protocol) and the in-memory
round-trip test (client from RpcTest).
forwardClient(const rpc: {
[K in keyof RpcClient.RpcClient.From<
RpcUnionOf<S, "">,
RpcClientError
>]: RpcClient.RpcClient.From<
RpcUnionOf<S, "">,
RpcClientError
>[K]
}
rpc, factory: {
readonly groupId: string
readonly [specSym]: FlatSpec
readonly [specTypeSym]?: S
readonly [groupSym]: RpcGroupOf<S>
}
factory[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], factory: {
readonly groupId: string
readonly [specSym]: FlatSpec
readonly [specTypeSym]?: S
readonly [groupSym]: RpcGroupOf<S>
}
factory.groupId: stringgroupId, const tag: WireInstanceTag<S>tag.key: stringkey),
) as type WireServiceOf<S extends Spec> = {
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
}
? ServiceMethod<AsMethod<S[K]>>
: S[K] extends Spec
? WireServiceOf<S[K]>
: never
}
The wire-only service: just the
Method
s (used by the server impl + forwarder).
WireServiceOf<function (type parameter) S in <S extends Spec, const Tags extends ReadonlyArray<WireInstanceTag<S>>>(factory: {
readonly groupId: string;
readonly [specSym]: FlatSpec;
readonly [specTypeSym]?: S;
readonly [groupSym]: RpcGroupOf<S>;
}, ...tags: Tags): Layer.Layer<InstanceIdentifiers<Tags, S>, never, RpcClient.Protocol>
S>;
let context: Context.Context<never>let context: {
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;
}
context = import ContextContext.const add: <never, unknown, WireServiceOf<S>>(self: Context.Context<never>, key: Context.Key<unknown, WireServiceOf<S>>, service: NoInfer<WireServiceOf<S>>) => Context.Context<unknown> (+1 overload)Adds a service to a given Context.
When to use
Use when you need to store a known service value in a Context.
Details
If the context already contains the same service key, the new service
replaces the previous one.
Example (Adding a service to a context)
import { Context, pipe } from "effect"
import * as assert from "node:assert"
const Port = Context.Service<{ PORT: number }>("Port")
const Timeout = Context.Service<{ TIMEOUT: number }>("Timeout")
const someContext = Context.make(Port, { PORT: 8080 })
const context = pipe(
someContext,
Context.add(Timeout, { TIMEOUT: 5000 })
)
assert.deepStrictEqual(Context.get(context, Port), { PORT: 8080 })
assert.deepStrictEqual(Context.get(context, Timeout), { TIMEOUT: 5000 })
add(let context: Context.Context<never>let context: {
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;
}
context, const tag: WireInstanceTag<S>tag, const service: WireServiceOf<S>service);
}
// The only cast here: TS can't track the identifier union accumulated by the
// per-instance `Context.add` loop. Runtime-safe — built key-for-key from `tags`.
return let context: Context.Context<never>let context: {
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;
}
context as import ContextContext.interface Context<in Services>Immutable collection of service implementations used for dependency
injection in Effect programs.
Details
The type parameter tracks the service identifiers available in the context.
At runtime, services are stored by each key's string key.
Example (Creating a context with multiple services)
import { Context } from "effect"
// Create a context with multiple services
const Logger = Context.Service<{ log: (msg: string) => void }>("Logger")
const Database = Context.Service<{ query: (sql: string) => string }>(
"Database"
)
const context = Context.make(Logger, {
log: (msg: string) => console.log(msg)
})
.pipe(Context.add(Database, { query: (sql) => `Result: ${sql}` }))
Context<type InstanceIdentifiers<
Tags extends ReadonlyArray<unknown>,
S extends Spec
> = Tags[number] extends Context.Key<
infer Self,
WireServiceOf<S>
>
? Self
: never
The instance identifiers a
clientInstances
layer provides (the union of tag Selfs).
InstanceIdentifiers<function (type parameter) Tags in <S extends Spec, const Tags extends ReadonlyArray<WireInstanceTag<S>>>(factory: {
readonly groupId: string;
readonly [specSym]: FlatSpec;
readonly [specTypeSym]?: S;
readonly [groupSym]: RpcGroupOf<S>;
}, ...tags: Tags): Layer.Layer<InstanceIdentifiers<Tags, S>, never, RpcClient.Protocol>
Tags, function (type parameter) S in <S extends Spec, const Tags extends ReadonlyArray<WireInstanceTag<S>>>(factory: {
readonly groupId: string;
readonly [specSym]: FlatSpec;
readonly [specTypeSym]?: S;
readonly [groupSym]: RpcGroupOf<S>;
}, ...tags: Tags): Layer.Layer<InstanceIdentifiers<Tags, S>, never, RpcClient.Protocol>
S>>;
}),
) as unknown as 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 InstanceIdentifiers<
Tags extends ReadonlyArray<unknown>,
S extends Spec
> = Tags[number] extends Context.Key<
infer Self,
WireServiceOf<S>
>
? Self
: never
The instance identifiers a
clientInstances
layer provides (the union of tag Selfs).
InstanceIdentifiers<function (type parameter) Tags in <S extends Spec, const Tags extends ReadonlyArray<WireInstanceTag<S>>>(factory: {
readonly groupId: string;
readonly [specSym]: FlatSpec;
readonly [specTypeSym]?: S;
readonly [groupSym]: RpcGroupOf<S>;
}, ...tags: Tags): Layer.Layer<InstanceIdentifiers<Tags, S>, never, RpcClient.Protocol>
Tags, function (type parameter) S in <S extends Spec, const Tags extends ReadonlyArray<WireInstanceTag<S>>>(factory: {
readonly groupId: string;
readonly [specSym]: FlatSpec;
readonly [specTypeSym]?: S;
readonly [groupSym]: RpcGroupOf<S>;
}, ...tags: Tags): Layer.Layer<InstanceIdentifiers<Tags, S>, never, RpcClient.Protocol>
S>,
never,
import RpcClientRpcClient.class Protocolclass Protocol {
key: Identifier;
Service: {
run: (clientId: number, f: (data: FromServerEncoded) => Effect.Effect<void>) => Effect.Effect<never>;
send: (clientId: number, request: FromClientEncoded, transferables?: ReadonlyArray<globalThis.Transferable>) => Effect.Effect<void, RpcClientError>;
supportsAck: boolean;
supportsTransferables: boolean;
};
}
Defines the service interface for an RPC client transport, responsible for running the
receive loop and sending encoded client messages.
When to use
Use to provide the transport boundary for RPC clients over HTTP, WebSocket,
workers, sockets, or custom protocols.
Protocol
>;