<
const ClientOnly extends boolean = false,
const Storage extends "local" | "sql" | "byo" = never
>(options: {
readonly transport: "http" | "websocket"
readonly serialization?: "msgpack" | "ndjson" | undefined
readonly clientOnly?: ClientOnly | undefined
readonly storage?: Storage | undefined
readonly runnerHealth?: "ping" | "k8s" | undefined
readonly runnerHealthK8s?:
| {
readonly namespace?: string | undefined
readonly labelSelector?: string | undefined
}
| undefined
readonly shardingConfig?:
| Partial<ShardingConfig.ShardingConfig["Service"]>
| undefined
}): ClientOnly extends true
? Layer.Layer<
| Sharding
| Runners.Runners
| ("byo" extends Storage ? never : MessageStorage.MessageStorage),
Config.ConfigError,
"local" extends Storage
? never
: "byo" extends Storage
? MessageStorage.MessageStorage | RunnerStorage.RunnerStorage
: SqlClient
>
: Layer.Layer<
| Sharding
| Runners.Runners
| ("byo" extends Storage ? never : MessageStorage.MessageStorage),
ServeError | Config.ConfigError,
"local" extends Storage
? never
: "byo" extends Storage
? MessageStorage.MessageStorage | RunnerStorage.RunnerStorage
: SqlClient
>Builds the Node cluster HTTP/WebSocket sharding layer, configuring runner transport, RPC serialization, message storage, runner health checks, and optional client-only mode.
export const const layer: <
ClientOnly extends boolean = false,
Storage extends "local" | "sql" | "byo" = never
>(options: {
readonly transport: "http" | "websocket"
readonly serialization?:
| "msgpack"
| "ndjson"
| undefined
readonly clientOnly?: ClientOnly | undefined
readonly storage?: Storage | undefined
readonly runnerHealth?:
| "ping"
| "k8s"
| undefined
readonly runnerHealthK8s?:
| {
readonly namespace?: string | undefined
readonly labelSelector?:
| string
| undefined
}
| undefined
readonly shardingConfig?:
| Partial<
ShardingConfig.ShardingConfig["Service"]
>
| undefined
}) => ClientOnly extends true
? Layer.Layer<
| Sharding
| Runners.Runners
| ("byo" extends Storage
? never
: MessageStorage.MessageStorage),
Config.ConfigError,
"local" extends Storage
? never
: "byo" extends Storage
?
| MessageStorage.MessageStorage
| RunnerStorage.RunnerStorage
: SqlClient
>
: Layer.Layer<
| Sharding
| Runners.Runners
| ("byo" extends Storage
? never
: MessageStorage.MessageStorage),
ServeError | Config.ConfigError,
"local" extends Storage
? never
: "byo" extends Storage
?
| MessageStorage.MessageStorage
| RunnerStorage.RunnerStorage
: SqlClient
>
Builds the Node cluster HTTP/WebSocket sharding layer, configuring runner
transport, RPC serialization, message storage, runner health checks, and
optional client-only mode.
layer = <
const function (type parameter) ClientOnly in <const ClientOnly extends boolean = false, const Storage extends "local" | "sql" | "byo" = never>(options: {
readonly transport: "http" | "websocket";
readonly serialization?: "msgpack" | "ndjson" | undefined;
readonly clientOnly?: ClientOnly | undefined;
readonly storage?: Storage | undefined;
readonly runnerHealth?: "ping" | "k8s" | undefined;
readonly runnerHealthK8s?: {
readonly namespace?: string | undefined;
readonly labelSelector?: string | undefined;
} | undefined;
readonly shardingConfig?: Partial<ShardingConfig.ShardingConfig["Service"]> | undefined;
}): ClientOnly extends true ? Layer.Layer<Sharding | Runners.Runners | ("byo" extends Storage ? never : MessageStorage.MessageStorage), Config.ConfigError, "local" extends Storage ? never : "byo" extends Storage ? (MessageStorage.MessageStorage | RunnerStorage.RunnerStorage) : SqlClient> : Layer.Layer<Sharding | Runners.Runners | ("byo" extends Storage ? never : MessageStorage.MessageStorage), ServeError | Config.ConfigError, "local" extends Storage ? never : "byo" extends Storage ? (MessageStorage.MessageStorage | RunnerStorage.RunnerStorage) : SqlClient>
ClientOnly extends boolean = false,
const function (type parameter) Storage in <const ClientOnly extends boolean = false, const Storage extends "local" | "sql" | "byo" = never>(options: {
readonly transport: "http" | "websocket";
readonly serialization?: "msgpack" | "ndjson" | undefined;
readonly clientOnly?: ClientOnly | undefined;
readonly storage?: Storage | undefined;
readonly runnerHealth?: "ping" | "k8s" | undefined;
readonly runnerHealthK8s?: {
readonly namespace?: string | undefined;
readonly labelSelector?: string | undefined;
} | undefined;
readonly shardingConfig?: Partial<ShardingConfig.ShardingConfig["Service"]> | undefined;
}): ClientOnly extends true ? Layer.Layer<Sharding | Runners.Runners | ("byo" extends Storage ? never : MessageStorage.MessageStorage), Config.ConfigError, "local" extends Storage ? never : "byo" extends Storage ? (MessageStorage.MessageStorage | RunnerStorage.RunnerStorage) : SqlClient> : Layer.Layer<Sharding | Runners.Runners | ("byo" extends Storage ? never : MessageStorage.MessageStorage), ServeError | Config.ConfigError, "local" extends Storage ? never : "byo" extends Storage ? (MessageStorage.MessageStorage | RunnerStorage.RunnerStorage) : SqlClient>
Storage extends "local" | "sql" | "byo" = never
>(options: {
readonly transport: "http" | "websocket"
readonly serialization?:
| "msgpack"
| "ndjson"
| undefined
readonly clientOnly?: ClientOnly | undefined
readonly storage?: Storage | undefined
readonly runnerHealth?:
| "ping"
| "k8s"
| undefined
readonly runnerHealthK8s?:
| {
readonly namespace?: string | undefined
readonly labelSelector?:
| string
| undefined
}
| undefined
readonly shardingConfig?:
| Partial<
ShardingConfig.ShardingConfig["Service"]
>
| undefined
}
options: {
readonly transport: "http" | "websocket"transport: "http" | "websocket"
readonly serialization?: "msgpack" | "ndjson" | undefinedserialization?: "msgpack" | "ndjson" | undefined
readonly clientOnly?: ClientOnly | undefinedclientOnly?: function (type parameter) ClientOnly in <const ClientOnly extends boolean = false, const Storage extends "local" | "sql" | "byo" = never>(options: {
readonly transport: "http" | "websocket";
readonly serialization?: "msgpack" | "ndjson" | undefined;
readonly clientOnly?: ClientOnly | undefined;
readonly storage?: Storage | undefined;
readonly runnerHealth?: "ping" | "k8s" | undefined;
readonly runnerHealthK8s?: {
readonly namespace?: string | undefined;
readonly labelSelector?: string | undefined;
} | undefined;
readonly shardingConfig?: Partial<ShardingConfig.ShardingConfig["Service"]> | undefined;
}): ClientOnly extends true ? Layer.Layer<Sharding | Runners.Runners | ("byo" extends Storage ? never : MessageStorage.MessageStorage), Config.ConfigError, "local" extends Storage ? never : "byo" extends Storage ? (MessageStorage.MessageStorage | RunnerStorage.RunnerStorage) : SqlClient> : Layer.Layer<Sharding | Runners.Runners | ("byo" extends Storage ? never : MessageStorage.MessageStorage), ServeError | Config.ConfigError, "local" extends Storage ? never : "byo" extends Storage ? (MessageStorage.MessageStorage | RunnerStorage.RunnerStorage) : SqlClient>
ClientOnly | undefined
readonly storage?: Storage | undefinedstorage?: function (type parameter) Storage in <const ClientOnly extends boolean = false, const Storage extends "local" | "sql" | "byo" = never>(options: {
readonly transport: "http" | "websocket";
readonly serialization?: "msgpack" | "ndjson" | undefined;
readonly clientOnly?: ClientOnly | undefined;
readonly storage?: Storage | undefined;
readonly runnerHealth?: "ping" | "k8s" | undefined;
readonly runnerHealthK8s?: {
readonly namespace?: string | undefined;
readonly labelSelector?: string | undefined;
} | undefined;
readonly shardingConfig?: Partial<ShardingConfig.ShardingConfig["Service"]> | undefined;
}): ClientOnly extends true ? Layer.Layer<Sharding | Runners.Runners | ("byo" extends Storage ? never : MessageStorage.MessageStorage), Config.ConfigError, "local" extends Storage ? never : "byo" extends Storage ? (MessageStorage.MessageStorage | RunnerStorage.RunnerStorage) : SqlClient> : Layer.Layer<Sharding | Runners.Runners | ("byo" extends Storage ? never : MessageStorage.MessageStorage), ServeError | Config.ConfigError, "local" extends Storage ? never : "byo" extends Storage ? (MessageStorage.MessageStorage | RunnerStorage.RunnerStorage) : SqlClient>
Storage | undefined
readonly runnerHealth?: "ping" | "k8s" | undefinedrunnerHealth?: "ping" | "k8s" | undefined
readonly runnerHealthK8s?: | {
readonly namespace?: string | undefined
readonly labelSelector?: string | undefined
}
| undefined
runnerHealthK8s?: {
readonly namespace?: string | undefinednamespace?: string | undefined
readonly labelSelector?: string | undefinedlabelSelector?: string | undefined
} | undefined
readonly shardingConfig?: Partial<{
readonly runnerAddress: Option.Option<RunnerAddress>;
readonly runnerListenAddress: Option.Option<RunnerAddress>;
readonly runnerShardWeight: number;
readonly availableShardGroups: ReadonlyArray<string>;
readonly assignedShardGroups: ReadonlyArray<string>;
readonly shardsPerGroup: number;
readonly shardLockRefreshInterval: Input;
readonly shardLockExpiration: Input;
readonly shardLockDisableAdvisory: boolean;
readonly preemptiveShutdown: boolean;
... 9 more ...;
readonly simulateRemoteSerialization: boolean;
}> | undefined
shardingConfig?: type Partial<T> = {
[P in keyof T]?: T[P] | undefined
}
Make all properties in T optional
Partial<import ShardingConfigShardingConfig.class ShardingConfigclass ShardingConfig {
key: Identifier;
Service: {
runnerAddress: Option.Option<RunnerAddress>;
runnerListenAddress: Option.Option<RunnerAddress>;
runnerShardWeight: number;
availableShardGroups: ReadonlyArray<string>;
assignedShardGroups: ReadonlyArray<string>;
shardsPerGroup: number;
shardLockRefreshInterval: Duration.Input;
shardLockExpiration: Duration.Input;
shardLockDisableAdvisory: boolean;
preemptiveShutdown: boolean;
entityMailboxCapacity: number | "unbounded";
entityMaxIdleTime: Duration.Input;
entityRegistrationTimeout: Duration.Input;
entityTerminationTimeout: Duration.Input;
entityMessagePollInterval: Duration.Input;
entityReplyPollInterval: Duration.Input;
refreshAssignmentsInterval: Duration.Input;
sendRetryInterval: Duration.Input;
runnerHealthCheckInterval: Duration.Input;
simulateRemoteSerialization: boolean;
};
}
Represents the configuration for the Sharding service on a given runner.
ShardingConfig["Service"]> | undefined
}): function (type parameter) ClientOnly in <const ClientOnly extends boolean = false, const Storage extends "local" | "sql" | "byo" = never>(options: {
readonly transport: "http" | "websocket";
readonly serialization?: "msgpack" | "ndjson" | undefined;
readonly clientOnly?: ClientOnly | undefined;
readonly storage?: Storage | undefined;
readonly runnerHealth?: "ping" | "k8s" | undefined;
readonly runnerHealthK8s?: {
readonly namespace?: string | undefined;
readonly labelSelector?: string | undefined;
} | undefined;
readonly shardingConfig?: Partial<ShardingConfig.ShardingConfig["Service"]> | undefined;
}): ClientOnly extends true ? Layer.Layer<Sharding | Runners.Runners | ("byo" extends Storage ? never : MessageStorage.MessageStorage), Config.ConfigError, "local" extends Storage ? never : "byo" extends Storage ? (MessageStorage.MessageStorage | RunnerStorage.RunnerStorage) : SqlClient> : Layer.Layer<Sharding | Runners.Runners | ("byo" extends Storage ? never : MessageStorage.MessageStorage), ServeError | Config.ConfigError, "local" extends Storage ? never : "byo" extends Storage ? (MessageStorage.MessageStorage | RunnerStorage.RunnerStorage) : SqlClient>
ClientOnly extends true ? 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<
class Shardingclass Sharding {
key: Identifier;
Service: {
getRegistrationEvents: Stream.Stream<ShardingRegistrationEvent>;
getShardId: (entityId: EntityId, group: string) => ShardId;
hasShardId: (shardId: ShardId) => boolean;
getSnowflake: Effect.Effect<Snowflake.Snowflake>;
isShutdown: Effect.Effect<boolean>;
makeClient: <Type extends string, Rpcs extends Rpc.Any>(entity: Entity<Type, Rpcs>) => Effect.Effect<(entityId: string) => RpcClient.RpcClient.From<Rpcs, MailboxFull | AlreadyProcessingMessage | PersistenceError>>;
registerEntity: <Type extends string, Rpcs extends Rpc.Any, Handlers extends HandlersFrom<Rpcs>, RX>(entity: Entity<Type, Rpcs>, handlers: Effect.Effect<Handlers, never, RX>, options?: { readonly maxIdleTime?: Input | undefined; readonly concurrency?: num…;
registerSingleton: <E, R>(name: string, run: Effect.Effect<void, E, R>, options?: { readonly shardGroup?: string | undefined }) => Effect.Effect<void, never, R | Scope.Scope>;
send: (message: Message.Incoming<any>) => Effect.Effect<void, EntityNotAssignedToRunner | MailboxFull | AlreadyProcessingMessage>;
sendOutgoing: (message: Message.Outgoing<any>, discard: boolean) => Effect.Effect<void, MailboxFull | AlreadyProcessingMessage | PersistenceError>;
notify: (message: Message.Incoming<any>, options?: { readonly waitUntilRead?: boolean | undefined }) => Effect.Effect<void, EntityNotAssignedToRunner | AlreadyProcessingMessage>;
reset: (requestId: Snowflake.Snowflake) => Effect.Effect<boolean>;
pollStorage: Effect.Effect<void>;
activeEntityCount: Effect.Effect<number>;
};
}
Service that registers entities and singletons, routes messages to owned
shards, generates runner-local snowflake ids, and polls
storage for persisted work.
When to use
Use to access or provide cluster routing, shard ownership, entity
registration, singleton registration, and persisted-work polling.
Sharding | import RunnersRunners.class Runnersclass Runners {
key: Identifier;
Service: {
ping: (address: RunnerAddress) => Effect.Effect<void, RunnerUnavailable>;
sendLocal: <R extends Rpc.Any>(options: { readonly message: Message.Outgoing<R>; readonly send: <Rpc extends Rpc.Any>(message: Message.IncomingLocal<Rpc>) => Effect.Effect<void, EntityNotAssignedToRunner | MailboxFull | AlreadyProcessingMessage>; rea…;
send: <R extends Rpc.Any>(options: { readonly address: RunnerAddress; readonly message: Message.Outgoing<R> }) => Effect.Effect<void, EntityNotAssignedToRunner | RunnerUnavailable | MailboxFull | AlreadyProcessingMessage | PersistenceError>;
notify: <R extends Rpc.Any>(options: { readonly address: Option.Option<RunnerAddress>; readonly message: Message.Outgoing<R>; readonly discard: boolean }) => Effect.Effect<void, PersistenceError>;
notifyLocal: <R extends Rpc.Any>(options: { readonly message: Message.Outgoing<R>; readonly notify: (options: Message.IncomingLocal<any>) => Effect.Effect<void, EntityNotAssignedToRunner>; readonly discard: boolean; readonly storageOnly?: boolean | und…;
onRunnerUnavailable: (address: RunnerAddress) => Effect.Effect<void>;
};
}
Service for communicating with cluster runners, including pinging runners,
sending and notifying messages, coordinating persisted replies, and marking
runners unavailable.
Runners | ("byo" extends function (type parameter) Storage in <const ClientOnly extends boolean = false, const Storage extends "local" | "sql" | "byo" = never>(options: {
readonly transport: "http" | "websocket";
readonly serialization?: "msgpack" | "ndjson" | undefined;
readonly clientOnly?: ClientOnly | undefined;
readonly storage?: Storage | undefined;
readonly runnerHealth?: "ping" | "k8s" | undefined;
readonly runnerHealthK8s?: {
readonly namespace?: string | undefined;
readonly labelSelector?: string | undefined;
} | undefined;
readonly shardingConfig?: Partial<ShardingConfig.ShardingConfig["Service"]> | undefined;
}): ClientOnly extends true ? Layer.Layer<Sharding | Runners.Runners | ("byo" extends Storage ? never : MessageStorage.MessageStorage), Config.ConfigError, "local" extends Storage ? never : "byo" extends Storage ? (MessageStorage.MessageStorage | RunnerStorage.RunnerStorage) : SqlClient> : Layer.Layer<Sharding | Runners.Runners | ("byo" extends Storage ? never : MessageStorage.MessageStorage), ServeError | Config.ConfigError, "local" extends Storage ? never : "byo" extends Storage ? (MessageStorage.MessageStorage | RunnerStorage.RunnerStorage) : SqlClient>
Storage ? never : import MessageStorageMessageStorage.class MessageStorageclass MessageStorage {
key: Identifier;
Service: {
saveRequest: <R extends Rpc.Any>(envelope: Message.OutgoingRequest<R>) => Effect.Effect<SaveResult<R>, PersistenceError | MalformedMessage>;
saveEnvelope: (envelope: Message.OutgoingEnvelope) => Effect.Effect<void, PersistenceError | MalformedMessage>;
saveReply: <R extends Rpc.Any>(reply: Reply.ReplyWithContext<R>) => Effect.Effect<void, PersistenceError | MalformedMessage>;
clearReplies: (requestId: Snowflake.Snowflake) => Effect.Effect<void, PersistenceError>;
repliesFor: <R extends Rpc.Any>(requests: Iterable<Message.OutgoingRequest<R>>) => Effect.Effect<Array<Reply.Reply<R>>, PersistenceError | MalformedMessage>;
repliesForUnfiltered: (requestIds: Iterable<Snowflake.Snowflake>) => Effect.Effect<Array<Reply.Encoded>, PersistenceError | MalformedMessage>;
requestIdForPrimaryKey: (options: { readonly address: EntityAddress; readonly tag: string; readonly id: string }) => Effect.Effect<Option.Option<Snowflake.Snowflake>, PersistenceError>;
registerReplyHandler: <R extends Rpc.Any>(message: Message.OutgoingRequest<R> | Message.IncomingRequest<R>) => Effect.Effect<void, EntityNotAssignedToRunner>;
unregisterReplyHandler: (requestId: Snowflake.Snowflake) => Effect.Effect<void>;
unregisterShardReplyHandlers: (shardId: ShardId.ShardId) => Effect.Effect<void>;
unprocessedMessages: (shardIds: Iterable<ShardId.ShardId>) => Effect.Effect<Array<Message.Incoming<any>>, PersistenceError>;
unprocessedMessagesById: <R extends Rpc.Any>(messageIds: Iterable<Snowflake.Snowflake>) => Effect.Effect<Array<Message.Incoming<R>>, PersistenceError>;
resetShards: (shardIds: Iterable<ShardId.ShardId>) => Effect.Effect<void, PersistenceError>;
resetAddress: (address: EntityAddress) => Effect.Effect<void, PersistenceError>;
clearAddress: (address: EntityAddress) => Effect.Effect<void, PersistenceError>;
withTransaction: <A, E, R>(effect: Effect.Effect<A, E, R>) => Effect.Effect<A, E, R>;
};
}
Service for cluster mailbox persistence and reply delivery.
Details
It stores outgoing requests, control envelopes, and replies; reads unprocessed
messages; manages reply handlers; and provides transaction wrapping for storage
operations.
MessageStorage),
import ConfigConfig.class ConfigErrorclass ConfigError {
_tag: 'ConfigError';
name: string;
cause: SourceError | Schema.SchemaError;
message: string;
toString: () => string;
}
Represents the error type produced when config loading or validation fails.
When to use
Use when you need to inspect config loading or validation failures.
Details
Wraps either:
- A
SourceError — the provider could not read data (I/O failure).
- A
SchemaError — the data was found but did not match the schema
(wrong type, out of range, missing key, etc.).
ConfigError,
"local" extends function (type parameter) Storage in <const ClientOnly extends boolean = false, const Storage extends "local" | "sql" | "byo" = never>(options: {
readonly transport: "http" | "websocket";
readonly serialization?: "msgpack" | "ndjson" | undefined;
readonly clientOnly?: ClientOnly | undefined;
readonly storage?: Storage | undefined;
readonly runnerHealth?: "ping" | "k8s" | undefined;
readonly runnerHealthK8s?: {
readonly namespace?: string | undefined;
readonly labelSelector?: string | undefined;
} | undefined;
readonly shardingConfig?: Partial<ShardingConfig.ShardingConfig["Service"]> | undefined;
}): ClientOnly extends true ? Layer.Layer<Sharding | Runners.Runners | ("byo" extends Storage ? never : MessageStorage.MessageStorage), Config.ConfigError, "local" extends Storage ? never : "byo" extends Storage ? (MessageStorage.MessageStorage | RunnerStorage.RunnerStorage) : SqlClient> : Layer.Layer<Sharding | Runners.Runners | ("byo" extends Storage ? never : MessageStorage.MessageStorage), ServeError | Config.ConfigError, "local" extends Storage ? never : "byo" extends Storage ? (MessageStorage.MessageStorage | RunnerStorage.RunnerStorage) : SqlClient>
Storage ? never
: "byo" extends function (type parameter) Storage in <const ClientOnly extends boolean = false, const Storage extends "local" | "sql" | "byo" = never>(options: {
readonly transport: "http" | "websocket";
readonly serialization?: "msgpack" | "ndjson" | undefined;
readonly clientOnly?: ClientOnly | undefined;
readonly storage?: Storage | undefined;
readonly runnerHealth?: "ping" | "k8s" | undefined;
readonly runnerHealthK8s?: {
readonly namespace?: string | undefined;
readonly labelSelector?: string | undefined;
} | undefined;
readonly shardingConfig?: Partial<ShardingConfig.ShardingConfig["Service"]> | undefined;
}): ClientOnly extends true ? Layer.Layer<Sharding | Runners.Runners | ("byo" extends Storage ? never : MessageStorage.MessageStorage), Config.ConfigError, "local" extends Storage ? never : "byo" extends Storage ? (MessageStorage.MessageStorage | RunnerStorage.RunnerStorage) : SqlClient> : Layer.Layer<Sharding | Runners.Runners | ("byo" extends Storage ? never : MessageStorage.MessageStorage), ServeError | Config.ConfigError, "local" extends Storage ? never : "byo" extends Storage ? (MessageStorage.MessageStorage | RunnerStorage.RunnerStorage) : SqlClient>
Storage ? (import MessageStorageMessageStorage.class MessageStorageclass MessageStorage {
key: Identifier;
Service: {
saveRequest: <R extends Rpc.Any>(envelope: Message.OutgoingRequest<R>) => Effect.Effect<SaveResult<R>, PersistenceError | MalformedMessage>;
saveEnvelope: (envelope: Message.OutgoingEnvelope) => Effect.Effect<void, PersistenceError | MalformedMessage>;
saveReply: <R extends Rpc.Any>(reply: Reply.ReplyWithContext<R>) => Effect.Effect<void, PersistenceError | MalformedMessage>;
clearReplies: (requestId: Snowflake.Snowflake) => Effect.Effect<void, PersistenceError>;
repliesFor: <R extends Rpc.Any>(requests: Iterable<Message.OutgoingRequest<R>>) => Effect.Effect<Array<Reply.Reply<R>>, PersistenceError | MalformedMessage>;
repliesForUnfiltered: (requestIds: Iterable<Snowflake.Snowflake>) => Effect.Effect<Array<Reply.Encoded>, PersistenceError | MalformedMessage>;
requestIdForPrimaryKey: (options: { readonly address: EntityAddress; readonly tag: string; readonly id: string }) => Effect.Effect<Option.Option<Snowflake.Snowflake>, PersistenceError>;
registerReplyHandler: <R extends Rpc.Any>(message: Message.OutgoingRequest<R> | Message.IncomingRequest<R>) => Effect.Effect<void, EntityNotAssignedToRunner>;
unregisterReplyHandler: (requestId: Snowflake.Snowflake) => Effect.Effect<void>;
unregisterShardReplyHandlers: (shardId: ShardId.ShardId) => Effect.Effect<void>;
unprocessedMessages: (shardIds: Iterable<ShardId.ShardId>) => Effect.Effect<Array<Message.Incoming<any>>, PersistenceError>;
unprocessedMessagesById: <R extends Rpc.Any>(messageIds: Iterable<Snowflake.Snowflake>) => Effect.Effect<Array<Message.Incoming<R>>, PersistenceError>;
resetShards: (shardIds: Iterable<ShardId.ShardId>) => Effect.Effect<void, PersistenceError>;
resetAddress: (address: EntityAddress) => Effect.Effect<void, PersistenceError>;
clearAddress: (address: EntityAddress) => Effect.Effect<void, PersistenceError>;
withTransaction: <A, E, R>(effect: Effect.Effect<A, E, R>) => Effect.Effect<A, E, R>;
};
}
Service for cluster mailbox persistence and reply delivery.
Details
It stores outgoing requests, control envelopes, and replies; reads unprocessed
messages; manages reply handlers; and provides transaction wrapping for storage
operations.
MessageStorage | import RunnerStorageRunnerStorage.class RunnerStorageclass RunnerStorage {
key: Identifier;
Service: {
register: (runner: Runner, healthy: boolean) => Effect.Effect<MachineId.MachineId, PersistenceError>;
unregister: (address: RunnerAddress) => Effect.Effect<void, PersistenceError>;
getRunners: Effect.Effect<Array<readonly [runner: Runner, healthy: boolean]>, PersistenceError>;
setRunnerHealth: (address: RunnerAddress, healthy: boolean) => Effect.Effect<void, PersistenceError>;
acquire: (address: RunnerAddress, shardIds: Iterable<ShardId.ShardId>) => Effect.Effect<Array<ShardId.ShardId>, PersistenceError>;
refresh: (address: RunnerAddress, shardIds: Iterable<ShardId.ShardId>) => Effect.Effect<Array<ShardId.ShardId>, PersistenceError>;
release: (address: RunnerAddress, shardId: ShardId.ShardId) => Effect.Effect<void, PersistenceError>;
releaseAll: (address: RunnerAddress) => Effect.Effect<void, PersistenceError>;
};
}
Represents a generic interface to the persistent storage required by the
cluster.
RunnerStorage)
: SqlClient
> :
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<
class Shardingclass Sharding {
key: Identifier;
Service: {
getRegistrationEvents: Stream.Stream<ShardingRegistrationEvent>;
getShardId: (entityId: EntityId, group: string) => ShardId;
hasShardId: (shardId: ShardId) => boolean;
getSnowflake: Effect.Effect<Snowflake.Snowflake>;
isShutdown: Effect.Effect<boolean>;
makeClient: <Type extends string, Rpcs extends Rpc.Any>(entity: Entity<Type, Rpcs>) => Effect.Effect<(entityId: string) => RpcClient.RpcClient.From<Rpcs, MailboxFull | AlreadyProcessingMessage | PersistenceError>>;
registerEntity: <Type extends string, Rpcs extends Rpc.Any, Handlers extends HandlersFrom<Rpcs>, RX>(entity: Entity<Type, Rpcs>, handlers: Effect.Effect<Handlers, never, RX>, options?: { readonly maxIdleTime?: Input | undefined; readonly concurrency?: num…;
registerSingleton: <E, R>(name: string, run: Effect.Effect<void, E, R>, options?: { readonly shardGroup?: string | undefined }) => Effect.Effect<void, never, R | Scope.Scope>;
send: (message: Message.Incoming<any>) => Effect.Effect<void, EntityNotAssignedToRunner | MailboxFull | AlreadyProcessingMessage>;
sendOutgoing: (message: Message.Outgoing<any>, discard: boolean) => Effect.Effect<void, MailboxFull | AlreadyProcessingMessage | PersistenceError>;
notify: (message: Message.Incoming<any>, options?: { readonly waitUntilRead?: boolean | undefined }) => Effect.Effect<void, EntityNotAssignedToRunner | AlreadyProcessingMessage>;
reset: (requestId: Snowflake.Snowflake) => Effect.Effect<boolean>;
pollStorage: Effect.Effect<void>;
activeEntityCount: Effect.Effect<number>;
};
}
Service that registers entities and singletons, routes messages to owned
shards, generates runner-local snowflake ids, and polls
storage for persisted work.
When to use
Use to access or provide cluster routing, shard ownership, entity
registration, singleton registration, and persisted-work polling.
Sharding | import RunnersRunners.class Runnersclass Runners {
key: Identifier;
Service: {
ping: (address: RunnerAddress) => Effect.Effect<void, RunnerUnavailable>;
sendLocal: <R extends Rpc.Any>(options: { readonly message: Message.Outgoing<R>; readonly send: <Rpc extends Rpc.Any>(message: Message.IncomingLocal<Rpc>) => Effect.Effect<void, EntityNotAssignedToRunner | MailboxFull | AlreadyProcessingMessage>; rea…;
send: <R extends Rpc.Any>(options: { readonly address: RunnerAddress; readonly message: Message.Outgoing<R> }) => Effect.Effect<void, EntityNotAssignedToRunner | RunnerUnavailable | MailboxFull | AlreadyProcessingMessage | PersistenceError>;
notify: <R extends Rpc.Any>(options: { readonly address: Option.Option<RunnerAddress>; readonly message: Message.Outgoing<R>; readonly discard: boolean }) => Effect.Effect<void, PersistenceError>;
notifyLocal: <R extends Rpc.Any>(options: { readonly message: Message.Outgoing<R>; readonly notify: (options: Message.IncomingLocal<any>) => Effect.Effect<void, EntityNotAssignedToRunner>; readonly discard: boolean; readonly storageOnly?: boolean | und…;
onRunnerUnavailable: (address: RunnerAddress) => Effect.Effect<void>;
};
}
Service for communicating with cluster runners, including pinging runners,
sending and notifying messages, coordinating persisted replies, and marking
runners unavailable.
Runners | ("byo" extends function (type parameter) Storage in <const ClientOnly extends boolean = false, const Storage extends "local" | "sql" | "byo" = never>(options: {
readonly transport: "http" | "websocket";
readonly serialization?: "msgpack" | "ndjson" | undefined;
readonly clientOnly?: ClientOnly | undefined;
readonly storage?: Storage | undefined;
readonly runnerHealth?: "ping" | "k8s" | undefined;
readonly runnerHealthK8s?: {
readonly namespace?: string | undefined;
readonly labelSelector?: string | undefined;
} | undefined;
readonly shardingConfig?: Partial<ShardingConfig.ShardingConfig["Service"]> | undefined;
}): ClientOnly extends true ? Layer.Layer<Sharding | Runners.Runners | ("byo" extends Storage ? never : MessageStorage.MessageStorage), Config.ConfigError, "local" extends Storage ? never : "byo" extends Storage ? (MessageStorage.MessageStorage | RunnerStorage.RunnerStorage) : SqlClient> : Layer.Layer<Sharding | Runners.Runners | ("byo" extends Storage ? never : MessageStorage.MessageStorage), ServeError | Config.ConfigError, "local" extends Storage ? never : "byo" extends Storage ? (MessageStorage.MessageStorage | RunnerStorage.RunnerStorage) : SqlClient>
Storage ? never : import MessageStorageMessageStorage.class MessageStorageclass MessageStorage {
key: Identifier;
Service: {
saveRequest: <R extends Rpc.Any>(envelope: Message.OutgoingRequest<R>) => Effect.Effect<SaveResult<R>, PersistenceError | MalformedMessage>;
saveEnvelope: (envelope: Message.OutgoingEnvelope) => Effect.Effect<void, PersistenceError | MalformedMessage>;
saveReply: <R extends Rpc.Any>(reply: Reply.ReplyWithContext<R>) => Effect.Effect<void, PersistenceError | MalformedMessage>;
clearReplies: (requestId: Snowflake.Snowflake) => Effect.Effect<void, PersistenceError>;
repliesFor: <R extends Rpc.Any>(requests: Iterable<Message.OutgoingRequest<R>>) => Effect.Effect<Array<Reply.Reply<R>>, PersistenceError | MalformedMessage>;
repliesForUnfiltered: (requestIds: Iterable<Snowflake.Snowflake>) => Effect.Effect<Array<Reply.Encoded>, PersistenceError | MalformedMessage>;
requestIdForPrimaryKey: (options: { readonly address: EntityAddress; readonly tag: string; readonly id: string }) => Effect.Effect<Option.Option<Snowflake.Snowflake>, PersistenceError>;
registerReplyHandler: <R extends Rpc.Any>(message: Message.OutgoingRequest<R> | Message.IncomingRequest<R>) => Effect.Effect<void, EntityNotAssignedToRunner>;
unregisterReplyHandler: (requestId: Snowflake.Snowflake) => Effect.Effect<void>;
unregisterShardReplyHandlers: (shardId: ShardId.ShardId) => Effect.Effect<void>;
unprocessedMessages: (shardIds: Iterable<ShardId.ShardId>) => Effect.Effect<Array<Message.Incoming<any>>, PersistenceError>;
unprocessedMessagesById: <R extends Rpc.Any>(messageIds: Iterable<Snowflake.Snowflake>) => Effect.Effect<Array<Message.Incoming<R>>, PersistenceError>;
resetShards: (shardIds: Iterable<ShardId.ShardId>) => Effect.Effect<void, PersistenceError>;
resetAddress: (address: EntityAddress) => Effect.Effect<void, PersistenceError>;
clearAddress: (address: EntityAddress) => Effect.Effect<void, PersistenceError>;
withTransaction: <A, E, R>(effect: Effect.Effect<A, E, R>) => Effect.Effect<A, E, R>;
};
}
Service for cluster mailbox persistence and reply delivery.
Details
It stores outgoing requests, control envelopes, and replies; reads unprocessed
messages; manages reply handlers; and provides transaction wrapping for storage
operations.
MessageStorage),
class ServeErrorclass ServeError {
name: string;
message: string;
stack: string;
cause: unknown;
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: Tag;
}
Error wrapping a low-level failure from the HTTP server implementation.
ServeError | import ConfigConfig.class ConfigErrorclass ConfigError {
_tag: 'ConfigError';
name: string;
cause: SourceError | Schema.SchemaError;
message: string;
toString: () => string;
}
Represents the error type produced when config loading or validation fails.
When to use
Use when you need to inspect config loading or validation failures.
Details
Wraps either:
- A
SourceError — the provider could not read data (I/O failure).
- A
SchemaError — the data was found but did not match the schema
(wrong type, out of range, missing key, etc.).
ConfigError,
"local" extends function (type parameter) Storage in <const ClientOnly extends boolean = false, const Storage extends "local" | "sql" | "byo" = never>(options: {
readonly transport: "http" | "websocket";
readonly serialization?: "msgpack" | "ndjson" | undefined;
readonly clientOnly?: ClientOnly | undefined;
readonly storage?: Storage | undefined;
readonly runnerHealth?: "ping" | "k8s" | undefined;
readonly runnerHealthK8s?: {
readonly namespace?: string | undefined;
readonly labelSelector?: string | undefined;
} | undefined;
readonly shardingConfig?: Partial<ShardingConfig.ShardingConfig["Service"]> | undefined;
}): ClientOnly extends true ? Layer.Layer<Sharding | Runners.Runners | ("byo" extends Storage ? never : MessageStorage.MessageStorage), Config.ConfigError, "local" extends Storage ? never : "byo" extends Storage ? (MessageStorage.MessageStorage | RunnerStorage.RunnerStorage) : SqlClient> : Layer.Layer<Sharding | Runners.Runners | ("byo" extends Storage ? never : MessageStorage.MessageStorage), ServeError | Config.ConfigError, "local" extends Storage ? never : "byo" extends Storage ? (MessageStorage.MessageStorage | RunnerStorage.RunnerStorage) : SqlClient>
Storage ? never
: "byo" extends function (type parameter) Storage in <const ClientOnly extends boolean = false, const Storage extends "local" | "sql" | "byo" = never>(options: {
readonly transport: "http" | "websocket";
readonly serialization?: "msgpack" | "ndjson" | undefined;
readonly clientOnly?: ClientOnly | undefined;
readonly storage?: Storage | undefined;
readonly runnerHealth?: "ping" | "k8s" | undefined;
readonly runnerHealthK8s?: {
readonly namespace?: string | undefined;
readonly labelSelector?: string | undefined;
} | undefined;
readonly shardingConfig?: Partial<ShardingConfig.ShardingConfig["Service"]> | undefined;
}): ClientOnly extends true ? Layer.Layer<Sharding | Runners.Runners | ("byo" extends Storage ? never : MessageStorage.MessageStorage), Config.ConfigError, "local" extends Storage ? never : "byo" extends Storage ? (MessageStorage.MessageStorage | RunnerStorage.RunnerStorage) : SqlClient> : Layer.Layer<Sharding | Runners.Runners | ("byo" extends Storage ? never : MessageStorage.MessageStorage), ServeError | Config.ConfigError, "local" extends Storage ? never : "byo" extends Storage ? (MessageStorage.MessageStorage | RunnerStorage.RunnerStorage) : SqlClient>
Storage ? (import MessageStorageMessageStorage.class MessageStorageclass MessageStorage {
key: Identifier;
Service: {
saveRequest: <R extends Rpc.Any>(envelope: Message.OutgoingRequest<R>) => Effect.Effect<SaveResult<R>, PersistenceError | MalformedMessage>;
saveEnvelope: (envelope: Message.OutgoingEnvelope) => Effect.Effect<void, PersistenceError | MalformedMessage>;
saveReply: <R extends Rpc.Any>(reply: Reply.ReplyWithContext<R>) => Effect.Effect<void, PersistenceError | MalformedMessage>;
clearReplies: (requestId: Snowflake.Snowflake) => Effect.Effect<void, PersistenceError>;
repliesFor: <R extends Rpc.Any>(requests: Iterable<Message.OutgoingRequest<R>>) => Effect.Effect<Array<Reply.Reply<R>>, PersistenceError | MalformedMessage>;
repliesForUnfiltered: (requestIds: Iterable<Snowflake.Snowflake>) => Effect.Effect<Array<Reply.Encoded>, PersistenceError | MalformedMessage>;
requestIdForPrimaryKey: (options: { readonly address: EntityAddress; readonly tag: string; readonly id: string }) => Effect.Effect<Option.Option<Snowflake.Snowflake>, PersistenceError>;
registerReplyHandler: <R extends Rpc.Any>(message: Message.OutgoingRequest<R> | Message.IncomingRequest<R>) => Effect.Effect<void, EntityNotAssignedToRunner>;
unregisterReplyHandler: (requestId: Snowflake.Snowflake) => Effect.Effect<void>;
unregisterShardReplyHandlers: (shardId: ShardId.ShardId) => Effect.Effect<void>;
unprocessedMessages: (shardIds: Iterable<ShardId.ShardId>) => Effect.Effect<Array<Message.Incoming<any>>, PersistenceError>;
unprocessedMessagesById: <R extends Rpc.Any>(messageIds: Iterable<Snowflake.Snowflake>) => Effect.Effect<Array<Message.Incoming<R>>, PersistenceError>;
resetShards: (shardIds: Iterable<ShardId.ShardId>) => Effect.Effect<void, PersistenceError>;
resetAddress: (address: EntityAddress) => Effect.Effect<void, PersistenceError>;
clearAddress: (address: EntityAddress) => Effect.Effect<void, PersistenceError>;
withTransaction: <A, E, R>(effect: Effect.Effect<A, E, R>) => Effect.Effect<A, E, R>;
};
}
Service for cluster mailbox persistence and reply delivery.
Details
It stores outgoing requests, control envelopes, and replies; reads unprocessed
messages; manages reply handlers; and provides transaction wrapping for storage
operations.
MessageStorage | import RunnerStorageRunnerStorage.class RunnerStorageclass RunnerStorage {
key: Identifier;
Service: {
register: (runner: Runner, healthy: boolean) => Effect.Effect<MachineId.MachineId, PersistenceError>;
unregister: (address: RunnerAddress) => Effect.Effect<void, PersistenceError>;
getRunners: Effect.Effect<Array<readonly [runner: Runner, healthy: boolean]>, PersistenceError>;
setRunnerHealth: (address: RunnerAddress, healthy: boolean) => Effect.Effect<void, PersistenceError>;
acquire: (address: RunnerAddress, shardIds: Iterable<ShardId.ShardId>) => Effect.Effect<Array<ShardId.ShardId>, PersistenceError>;
refresh: (address: RunnerAddress, shardIds: Iterable<ShardId.ShardId>) => Effect.Effect<Array<ShardId.ShardId>, PersistenceError>;
release: (address: RunnerAddress, shardId: ShardId.ShardId) => Effect.Effect<void, PersistenceError>;
releaseAll: (address: RunnerAddress) => Effect.Effect<void, PersistenceError>;
};
}
Represents a generic interface to the persistent storage required by the
cluster.
RunnerStorage)
: SqlClient
> =>
{
const const layer: Layer.Layer<any, any, any>const layer: {
build: (memoMap: MemoMap, scope: Scope.Scope) => Effect<Context.Context<any>, any, any>;
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; <…;
}
layer: 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<any, any, any> = options: {
readonly transport: "http" | "websocket"
readonly serialization?:
| "msgpack"
| "ndjson"
| undefined
readonly clientOnly?: ClientOnly | undefined
readonly storage?: Storage | undefined
readonly runnerHealth?:
| "ping"
| "k8s"
| undefined
readonly runnerHealthK8s?:
| {
readonly namespace?: string | undefined
readonly labelSelector?:
| string
| undefined
}
| undefined
readonly shardingConfig?:
| Partial<
ShardingConfig.ShardingConfig["Service"]
>
| undefined
}
options.clientOnly?: ClientOnly | undefinedclientOnly
// client only
? options: {
readonly transport: "http" | "websocket"
readonly serialization?:
| "msgpack"
| "ndjson"
| undefined
readonly clientOnly?: ClientOnly | undefined
readonly storage?: Storage | undefined
readonly runnerHealth?:
| "ping"
| "k8s"
| undefined
readonly runnerHealthK8s?:
| {
readonly namespace?: string | undefined
readonly labelSelector?:
| string
| undefined
}
| undefined
readonly shardingConfig?:
| Partial<
ShardingConfig.ShardingConfig["Service"]
>
| undefined
}
options.transport: "http" | "websocket"transport === "http"
? import LayerLayer.const provide: {
<RIn, E, ROut>(that: Layer<ROut, E, RIn>): <
RIn2,
E2,
ROut2
>(
self: Layer<ROut2, E2, RIn2>
) => Layer<
ROut2,
E | E2,
RIn | Exclude<RIn2, ROut>
>
<Layers extends [Any, ...Array<Any>]>(
that: Layers
): <A, E, R>(
self: Layer<A, E, R>
) => Layer<
A,
E | Error<Layers[number]>,
| Services<Layers[number]>
| Exclude<R, Success<Layers[number]>>
>
<RIn2, E2, ROut2, RIn, E, ROut>(
self: Layer<ROut2, E2, RIn2>,
that: Layer<ROut, E, RIn>
): Layer<
ROut2,
E | E2,
RIn | Exclude<RIn2, ROut>
>
<A, E, R, Layers extends [Any, ...Array<Any>]>(
self: Layer<A, E, R>,
that: Layers
): Layer<
A,
E | Error<Layers[number]>,
| Services<Layers[number]>
| Exclude<R, Success<Layers[number]>>
>
}
Feeds the output services of the dependency layer into the requirements of
this layer, returning a layer that only provides the services from this layer.
When to use
Use when you need to hide an implementation dependency layer from callers.
Details
In serviceLayer.pipe(Layer.provide(dependencyLayer)), the dependency layer is
built first and is used to satisfy the requirements of serviceLayer.
Example (Providing layer dependencies)
import { Context, Effect, Layer } from "effect"
class Database extends Context.Service<Database, {
readonly query: (sql: string) => Effect.Effect<string>
}>()("Database") {}
class UserService extends Context.Service<UserService, {
readonly getUser: (id: string) => Effect.Effect<{
id: string
name: string
}>
}>()("UserService") {}
class Logger extends Context.Service<Logger, {
readonly log: (msg: string) => Effect.Effect<void>
}>()("Logger") {}
// Create dependency layers
const databaseLayer = Layer.succeed(Database, {
query: Effect.fn("Database.query")((sql: string) => Effect.succeed(`DB: ${sql}`))
})
const loggerLayer = Layer.succeed(Logger, {
log: Effect.fn("Logger.log")((msg: string) => Effect.sync(() => console.log(`[LOG] ${msg}`)))
})
// UserService depends on Database and Logger
const userServiceLayer = Layer.effect(UserService, Effect.gen(function*() {
const database = yield* Database
const logger = yield* Logger
return {
getUser: Effect.fn("UserService.getUser")(function*(id: string) {
yield* logger.log(`Looking up user ${id}`)
const result = yield* database.query(
`SELECT * FROM users WHERE id = ${id}`
)
return { id, name: result }
})
}
}))
// Provide dependencies to UserService layer
const userServiceWithDependencies = userServiceLayer.pipe(
Layer.provide(Layer.mergeAll(databaseLayer, loggerLayer))
)
// Now UserService layer has no dependencies
const program = Effect.gen(function*() {
const userService = yield* UserService
return yield* userService.getUser("123")
}).pipe(
Effect.provide(userServiceWithDependencies)
)
provide(import HttpRunnerHttpRunner.const layerHttpClientOnly: Layer.Layer<
Sharding.Sharding | Runners.Runners,
never,
| RpcSerialization.RpcSerialization
| ShardingConfig.ShardingConfig
| HttpClient.HttpClient
| MessageStorage
| RunnerStorage
>
const layerHttpClientOnly: {
build: (memoMap: MemoMap, scope: Scope.Scope) => Effect<Context.Context<Sharding | Runners>, never, RpcSerialization | HttpClient | MessageStorage | ShardingConfig | RunnerStorage>;
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; <…;
}
Provides a client-only HTTP runner layer.
When to use
Use to provide runner clients over HTTP from a process that should not serve
runner routes.
Details
It configures runner clients to communicate over HTTP without serving runner
HTTP routes.
layerHttpClientOnly, import NodeHttpClientNodeHttpClient.const layerUndici: Layer.Layer<Client.HttpClient>const layerUndici: {
build: (memoMap: MemoMap, scope: Scope.Scope) => Effect<Context.Context<HttpClient>, 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; <…;
}
Provides an Undici-backed HttpClient together with a scoped default
Undici Agent dispatcher.
layerUndici)
: import LayerLayer.const provide: {
<RIn, E, ROut>(that: Layer<ROut, E, RIn>): <
RIn2,
E2,
ROut2
>(
self: Layer<ROut2, E2, RIn2>
) => Layer<
ROut2,
E | E2,
RIn | Exclude<RIn2, ROut>
>
<Layers extends [Any, ...Array<Any>]>(
that: Layers
): <A, E, R>(
self: Layer<A, E, R>
) => Layer<
A,
E | Error<Layers[number]>,
| Services<Layers[number]>
| Exclude<R, Success<Layers[number]>>
>
<RIn2, E2, ROut2, RIn, E, ROut>(
self: Layer<ROut2, E2, RIn2>,
that: Layer<ROut, E, RIn>
): Layer<
ROut2,
E | E2,
RIn | Exclude<RIn2, ROut>
>
<A, E, R, Layers extends [Any, ...Array<Any>]>(
self: Layer<A, E, R>,
that: Layers
): Layer<
A,
E | Error<Layers[number]>,
| Services<Layers[number]>
| Exclude<R, Success<Layers[number]>>
>
}
Feeds the output services of the dependency layer into the requirements of
this layer, returning a layer that only provides the services from this layer.
When to use
Use when you need to hide an implementation dependency layer from callers.
Details
In serviceLayer.pipe(Layer.provide(dependencyLayer)), the dependency layer is
built first and is used to satisfy the requirements of serviceLayer.
Example (Providing layer dependencies)
import { Context, Effect, Layer } from "effect"
class Database extends Context.Service<Database, {
readonly query: (sql: string) => Effect.Effect<string>
}>()("Database") {}
class UserService extends Context.Service<UserService, {
readonly getUser: (id: string) => Effect.Effect<{
id: string
name: string
}>
}>()("UserService") {}
class Logger extends Context.Service<Logger, {
readonly log: (msg: string) => Effect.Effect<void>
}>()("Logger") {}
// Create dependency layers
const databaseLayer = Layer.succeed(Database, {
query: Effect.fn("Database.query")((sql: string) => Effect.succeed(`DB: ${sql}`))
})
const loggerLayer = Layer.succeed(Logger, {
log: Effect.fn("Logger.log")((msg: string) => Effect.sync(() => console.log(`[LOG] ${msg}`)))
})
// UserService depends on Database and Logger
const userServiceLayer = Layer.effect(UserService, Effect.gen(function*() {
const database = yield* Database
const logger = yield* Logger
return {
getUser: Effect.fn("UserService.getUser")(function*(id: string) {
yield* logger.log(`Looking up user ${id}`)
const result = yield* database.query(
`SELECT * FROM users WHERE id = ${id}`
)
return { id, name: result }
})
}
}))
// Provide dependencies to UserService layer
const userServiceWithDependencies = userServiceLayer.pipe(
Layer.provide(Layer.mergeAll(databaseLayer, loggerLayer))
)
// Now UserService layer has no dependencies
const program = Effect.gen(function*() {
const userService = yield* UserService
return yield* userService.getUser("123")
}).pipe(
Effect.provide(userServiceWithDependencies)
)
provide(import HttpRunnerHttpRunner.const layerWebsocketClientOnly: Layer.Layer<
Sharding.Sharding | Runners.Runners,
never,
| ShardingConfig.ShardingConfig
| MessageStorage
| RunnerStorage
| RpcSerialization.RpcSerialization
| Socket.WebSocketConstructor
>
const layerWebsocketClientOnly: {
build: (memoMap: MemoMap, scope: Scope.Scope) => Effect<Context.Context<Sharding | Runners>, never, RpcSerialization | WebSocketConstructor | MessageStorage | ShardingConfig | RunnerStorage>;
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; <…;
}
Provides a client-only WebSocket runner layer.
When to use
Use to provide runner clients over WebSocket from a process that should not
serve runner routes.
Details
It configures runner clients to communicate over WebSocket without serving
runner WebSocket routes.
layerWebsocketClientOnly, import NodeSocketNodeSocket.const layerWebSocketConstructor: Layer.Layer<Socket.WebSocketConstructor>const layerWebSocketConstructor: {
build: (memoMap: MemoMap, scope: Scope.Scope) => Effect<Context.Context<WebSocketConstructor>, 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; <…;
}
Provides a Socket.WebSocketConstructor, using globalThis.WebSocket when
available and falling back to the ws package otherwise.
layerWebSocketConstructor)
// with server
: options: {
readonly transport: "http" | "websocket"
readonly serialization?:
| "msgpack"
| "ndjson"
| undefined
readonly clientOnly?: ClientOnly | undefined
readonly storage?: Storage | undefined
readonly runnerHealth?:
| "ping"
| "k8s"
| undefined
readonly runnerHealthK8s?:
| {
readonly namespace?: string | undefined
readonly labelSelector?:
| string
| undefined
}
| undefined
readonly shardingConfig?:
| Partial<
ShardingConfig.ShardingConfig["Service"]
>
| undefined
}
options.transport: "http" | "websocket"transport === "http"
? import LayerLayer.const provide: {
<RIn, E, ROut>(that: Layer<ROut, E, RIn>): <
RIn2,
E2,
ROut2
>(
self: Layer<ROut2, E2, RIn2>
) => Layer<
ROut2,
E | E2,
RIn | Exclude<RIn2, ROut>
>
<Layers extends [Any, ...Array<Any>]>(
that: Layers
): <A, E, R>(
self: Layer<A, E, R>
) => Layer<
A,
E | Error<Layers[number]>,
| Services<Layers[number]>
| Exclude<R, Success<Layers[number]>>
>
<RIn2, E2, ROut2, RIn, E, ROut>(
self: Layer<ROut2, E2, RIn2>,
that: Layer<ROut, E, RIn>
): Layer<
ROut2,
E | E2,
RIn | Exclude<RIn2, ROut>
>
<A, E, R, Layers extends [Any, ...Array<Any>]>(
self: Layer<A, E, R>,
that: Layers
): Layer<
A,
E | Error<Layers[number]>,
| Services<Layers[number]>
| Exclude<R, Success<Layers[number]>>
>
}
Feeds the output services of the dependency layer into the requirements of
this layer, returning a layer that only provides the services from this layer.
When to use
Use when you need to hide an implementation dependency layer from callers.
Details
In serviceLayer.pipe(Layer.provide(dependencyLayer)), the dependency layer is
built first and is used to satisfy the requirements of serviceLayer.
Example (Providing layer dependencies)
import { Context, Effect, Layer } from "effect"
class Database extends Context.Service<Database, {
readonly query: (sql: string) => Effect.Effect<string>
}>()("Database") {}
class UserService extends Context.Service<UserService, {
readonly getUser: (id: string) => Effect.Effect<{
id: string
name: string
}>
}>()("UserService") {}
class Logger extends Context.Service<Logger, {
readonly log: (msg: string) => Effect.Effect<void>
}>()("Logger") {}
// Create dependency layers
const databaseLayer = Layer.succeed(Database, {
query: Effect.fn("Database.query")((sql: string) => Effect.succeed(`DB: ${sql}`))
})
const loggerLayer = Layer.succeed(Logger, {
log: Effect.fn("Logger.log")((msg: string) => Effect.sync(() => console.log(`[LOG] ${msg}`)))
})
// UserService depends on Database and Logger
const userServiceLayer = Layer.effect(UserService, Effect.gen(function*() {
const database = yield* Database
const logger = yield* Logger
return {
getUser: Effect.fn("UserService.getUser")(function*(id: string) {
yield* logger.log(`Looking up user ${id}`)
const result = yield* database.query(
`SELECT * FROM users WHERE id = ${id}`
)
return { id, name: result }
})
}
}))
// Provide dependencies to UserService layer
const userServiceWithDependencies = userServiceLayer.pipe(
Layer.provide(Layer.mergeAll(databaseLayer, loggerLayer))
)
// Now UserService layer has no dependencies
const program = Effect.gen(function*() {
const userService = yield* UserService
return yield* userService.getUser("123")
}).pipe(
Effect.provide(userServiceWithDependencies)
)
provide(import HttpRunnerHttpRunner.const layerHttp: Layer.Layer<
Sharding.Sharding | Runners.Runners,
never,
| RpcSerialization.RpcSerialization
| ShardingConfig.ShardingConfig
| HttpClient.HttpClient
| HttpServer.HttpServer
| MessageStorage
| RunnerStorage
| RunnerHealth
>
const layerHttp: {
build: (memoMap: MemoMap, scope: Scope.Scope) => Effect<Context.Context<Sharding | Runners>, never, RpcSerialization | HttpClient | MessageStorage | ShardingConfig | RunnerStorage | RunnerHealth | HttpServer>;
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; <…;
}
Layer that serves runner routes at / and configures HTTP runner clients.
Details
It serves runner routes at / and configures runner clients to communicate
over HTTP.
layerHttp, [const layerHttpServer: Layer.Layer<
| HttpPlatform
| Etag.Generator
| NodeServices
| HttpServer,
ServeError,
ShardingConfig.ShardingConfig
>
const layerHttpServer: {
build: (memoMap: MemoMap, scope: Scope.Scope) => Effect<Context.Context<HttpServer | Generator | HttpPlatform | NodeServices>, ServeError, ShardingConfig>;
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; <…;
}
Provides the HTTP server and Node HTTP services used by cluster runners,
listening on ShardingConfig.runnerListenAddress or runnerAddress.
layerHttpServer, import NodeHttpClientNodeHttpClient.const layerUndici: Layer.Layer<Client.HttpClient>const layerUndici: {
build: (memoMap: MemoMap, scope: Scope.Scope) => Effect<Context.Context<HttpClient>, 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; <…;
}
Provides an Undici-backed HttpClient together with a scoped default
Undici Agent dispatcher.
layerUndici])
: import LayerLayer.const provide: {
<RIn, E, ROut>(that: Layer<ROut, E, RIn>): <
RIn2,
E2,
ROut2
>(
self: Layer<ROut2, E2, RIn2>
) => Layer<
ROut2,
E | E2,
RIn | Exclude<RIn2, ROut>
>
<Layers extends [Any, ...Array<Any>]>(
that: Layers
): <A, E, R>(
self: Layer<A, E, R>
) => Layer<
A,
E | Error<Layers[number]>,
| Services<Layers[number]>
| Exclude<R, Success<Layers[number]>>
>
<RIn2, E2, ROut2, RIn, E, ROut>(
self: Layer<ROut2, E2, RIn2>,
that: Layer<ROut, E, RIn>
): Layer<
ROut2,
E | E2,
RIn | Exclude<RIn2, ROut>
>
<A, E, R, Layers extends [Any, ...Array<Any>]>(
self: Layer<A, E, R>,
that: Layers
): Layer<
A,
E | Error<Layers[number]>,
| Services<Layers[number]>
| Exclude<R, Success<Layers[number]>>
>
}
Feeds the output services of the dependency layer into the requirements of
this layer, returning a layer that only provides the services from this layer.
When to use
Use when you need to hide an implementation dependency layer from callers.
Details
In serviceLayer.pipe(Layer.provide(dependencyLayer)), the dependency layer is
built first and is used to satisfy the requirements of serviceLayer.
Example (Providing layer dependencies)
import { Context, Effect, Layer } from "effect"
class Database extends Context.Service<Database, {
readonly query: (sql: string) => Effect.Effect<string>
}>()("Database") {}
class UserService extends Context.Service<UserService, {
readonly getUser: (id: string) => Effect.Effect<{
id: string
name: string
}>
}>()("UserService") {}
class Logger extends Context.Service<Logger, {
readonly log: (msg: string) => Effect.Effect<void>
}>()("Logger") {}
// Create dependency layers
const databaseLayer = Layer.succeed(Database, {
query: Effect.fn("Database.query")((sql: string) => Effect.succeed(`DB: ${sql}`))
})
const loggerLayer = Layer.succeed(Logger, {
log: Effect.fn("Logger.log")((msg: string) => Effect.sync(() => console.log(`[LOG] ${msg}`)))
})
// UserService depends on Database and Logger
const userServiceLayer = Layer.effect(UserService, Effect.gen(function*() {
const database = yield* Database
const logger = yield* Logger
return {
getUser: Effect.fn("UserService.getUser")(function*(id: string) {
yield* logger.log(`Looking up user ${id}`)
const result = yield* database.query(
`SELECT * FROM users WHERE id = ${id}`
)
return { id, name: result }
})
}
}))
// Provide dependencies to UserService layer
const userServiceWithDependencies = userServiceLayer.pipe(
Layer.provide(Layer.mergeAll(databaseLayer, loggerLayer))
)
// Now UserService layer has no dependencies
const program = Effect.gen(function*() {
const userService = yield* UserService
return yield* userService.getUser("123")
}).pipe(
Effect.provide(userServiceWithDependencies)
)
provide(import HttpRunnerHttpRunner.const layerWebsocket: Layer.Layer<
Sharding.Sharding | Runners.Runners,
never,
| RpcSerialization.RpcSerialization
| ShardingConfig.ShardingConfig
| Socket.WebSocketConstructor
| HttpServer.HttpServer
| MessageStorage
| RunnerStorage
| RunnerHealth
>
const layerWebsocket: {
build: (memoMap: MemoMap, scope: Scope.Scope) => Effect<Context.Context<Sharding | Runners>, never, RpcSerialization | WebSocketConstructor | MessageStorage | ShardingConfig | RunnerStorage | RunnerHealth | HttpServer>;
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; <…;
}
Layer that serves runner routes at / and configures WebSocket runner clients.
Details
It serves runner routes at / and configures runner clients to communicate
over WebSocket.
layerWebsocket, [const layerHttpServer: Layer.Layer<
| HttpPlatform
| Etag.Generator
| NodeServices
| HttpServer,
ServeError,
ShardingConfig.ShardingConfig
>
const layerHttpServer: {
build: (memoMap: MemoMap, scope: Scope.Scope) => Effect<Context.Context<HttpServer | Generator | HttpPlatform | NodeServices>, ServeError, ShardingConfig>;
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; <…;
}
Provides the HTTP server and Node HTTP services used by cluster runners,
listening on ShardingConfig.runnerListenAddress or runnerAddress.
layerHttpServer, import NodeSocketNodeSocket.const layerWebSocketConstructor: Layer.Layer<Socket.WebSocketConstructor>const layerWebSocketConstructor: {
build: (memoMap: MemoMap, scope: Scope.Scope) => Effect<Context.Context<WebSocketConstructor>, 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; <…;
}
Provides a Socket.WebSocketConstructor, using globalThis.WebSocket when
available and falling back to the ws package otherwise.
layerWebSocketConstructor])
const const runnerHealth: Layer.Layer<
any,
any,
any
>
const runnerHealth: {
build: (memoMap: MemoMap, scope: Scope.Scope) => Effect<Context.Context<any>, any, any>;
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; <…;
}
runnerHealth: 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<any, any, any> = options: {
readonly transport: "http" | "websocket"
readonly serialization?:
| "msgpack"
| "ndjson"
| undefined
readonly clientOnly?: ClientOnly | undefined
readonly storage?: Storage | undefined
readonly runnerHealth?:
| "ping"
| "k8s"
| undefined
readonly runnerHealthK8s?:
| {
readonly namespace?: string | undefined
readonly labelSelector?:
| string
| undefined
}
| undefined
readonly shardingConfig?:
| Partial<
ShardingConfig.ShardingConfig["Service"]
>
| undefined
}
options?.clientOnly?: ClientOnly | undefinedclientOnly
? import LayerLayer.const empty: Layer<never>const empty: {
build: (memoMap: MemoMap, scope: Scope.Scope) => 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; <…;
}
An empty layer that provides no services, cannot fail, has no requirements,
and performs no construction or finalization work.
When to use
Use as the no-op branch when conditionally composing layers.
Example (Disabling optional lifecycle work)
import { Console, Layer } from "effect"
declare const flag: boolean
const StartupLogLive = flag
? Layer.effectDiscard(Console.log("application starting"))
: Layer.empty
empty as any
: options: {
readonly transport: "http" | "websocket"
readonly serialization?:
| "msgpack"
| "ndjson"
| undefined
readonly clientOnly?: ClientOnly | undefined
readonly storage?: Storage | undefined
readonly runnerHealth?:
| "ping"
| "k8s"
| undefined
readonly runnerHealthK8s?:
| {
readonly namespace?: string | undefined
readonly labelSelector?:
| string
| undefined
}
| undefined
readonly shardingConfig?:
| Partial<
ShardingConfig.ShardingConfig["Service"]
>
| undefined
}
options?.runnerHealth?: "ping" | "k8s" | undefinedrunnerHealth === "k8s"
? import RunnerHealthRunnerHealth.const layerK8s: (
options?:
| {
readonly namespace?: string | undefined
readonly labelSelector?:
| string
| undefined
}
| undefined
) => Layer.Layer<
RunnerHealth.RunnerHealth,
never,
K8sHttpClient
>
Layer that checks Kubernetes pod readiness to determine whether a runner is
healthy.
Details
The provided HttpClient must trust the pod CA certificate and the pod service
account must be allowed to list pods.
Gotchas
If the Kubernetes API check fails, the runner is treated as healthy.
layerK8s(options: {
readonly transport: "http" | "websocket"
readonly serialization?:
| "msgpack"
| "ndjson"
| undefined
readonly clientOnly?: ClientOnly | undefined
readonly storage?: Storage | undefined
readonly runnerHealth?:
| "ping"
| "k8s"
| undefined
readonly runnerHealthK8s?:
| {
readonly namespace?: string | undefined
readonly labelSelector?:
| string
| undefined
}
| undefined
readonly shardingConfig?:
| Partial<
ShardingConfig.ShardingConfig["Service"]
>
| undefined
}
options.runnerHealthK8s?: | {
readonly namespace?: string | undefined
readonly labelSelector?: string | undefined
}
| undefined
runnerHealthK8s).Pipeable.pipe<Layer.Layer<RunnerHealth.RunnerHealth, never, K8sHttpClient>, Layer.Layer<RunnerHealth.RunnerHealth, never, never>>(this: Layer.Layer<RunnerHealth.RunnerHealth, never, K8sHttpClient>, ab: (_: Layer.Layer<RunnerHealth.RunnerHealth, never, K8sHttpClient>) => Layer.Layer<RunnerHealth.RunnerHealth, never, never>): Layer.Layer<RunnerHealth.RunnerHealth, never, never> (+21 overloads)pipe(
import LayerLayer.const provide: {
<RIn, E, ROut>(that: Layer<ROut, E, RIn>): <
RIn2,
E2,
ROut2
>(
self: Layer<ROut2, E2, RIn2>
) => Layer<
ROut2,
E | E2,
RIn | Exclude<RIn2, ROut>
>
<Layers extends [Any, ...Array<Any>]>(
that: Layers
): <A, E, R>(
self: Layer<A, E, R>
) => Layer<
A,
E | Error<Layers[number]>,
| Services<Layers[number]>
| Exclude<R, Success<Layers[number]>>
>
<RIn2, E2, ROut2, RIn, E, ROut>(
self: Layer<ROut2, E2, RIn2>,
that: Layer<ROut, E, RIn>
): Layer<
ROut2,
E | E2,
RIn | Exclude<RIn2, ROut>
>
<A, E, R, Layers extends [Any, ...Array<Any>]>(
self: Layer<A, E, R>,
that: Layers
): Layer<
A,
E | Error<Layers[number]>,
| Services<Layers[number]>
| Exclude<R, Success<Layers[number]>>
>
}
Feeds the output services of the dependency layer into the requirements of
this layer, returning a layer that only provides the services from this layer.
When to use
Use when you need to hide an implementation dependency layer from callers.
Details
In serviceLayer.pipe(Layer.provide(dependencyLayer)), the dependency layer is
built first and is used to satisfy the requirements of serviceLayer.
Example (Providing layer dependencies)
import { Context, Effect, Layer } from "effect"
class Database extends Context.Service<Database, {
readonly query: (sql: string) => Effect.Effect<string>
}>()("Database") {}
class UserService extends Context.Service<UserService, {
readonly getUser: (id: string) => Effect.Effect<{
id: string
name: string
}>
}>()("UserService") {}
class Logger extends Context.Service<Logger, {
readonly log: (msg: string) => Effect.Effect<void>
}>()("Logger") {}
// Create dependency layers
const databaseLayer = Layer.succeed(Database, {
query: Effect.fn("Database.query")((sql: string) => Effect.succeed(`DB: ${sql}`))
})
const loggerLayer = Layer.succeed(Logger, {
log: Effect.fn("Logger.log")((msg: string) => Effect.sync(() => console.log(`[LOG] ${msg}`)))
})
// UserService depends on Database and Logger
const userServiceLayer = Layer.effect(UserService, Effect.gen(function*() {
const database = yield* Database
const logger = yield* Logger
return {
getUser: Effect.fn("UserService.getUser")(function*(id: string) {
yield* logger.log(`Looking up user ${id}`)
const result = yield* database.query(
`SELECT * FROM users WHERE id = ${id}`
)
return { id, name: result }
})
}
}))
// Provide dependencies to UserService layer
const userServiceWithDependencies = userServiceLayer.pipe(
Layer.provide(Layer.mergeAll(databaseLayer, loggerLayer))
)
// Now UserService layer has no dependencies
const program = Effect.gen(function*() {
const userService = yield* UserService
return yield* userService.getUser("123")
}).pipe(
Effect.provide(userServiceWithDependencies)
)
provide(const layerK8sHttpClient: Layer.Layer<
K8sHttpClient,
never,
never
>
(alias) const layerK8sHttpClient: {
build: (memoMap: MemoMap, scope: Scope.Scope) => Effect<Context.Context<K8sHttpClient>, 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; <…;
}
Provides a K8sHttpClient backed by the Undici HTTP client and the
Kubernetes-aware dispatcher.
layerK8sHttpClient)
)
: import RunnerHealthRunnerHealth.const layerPing: Layer.Layer<
RunnerHealth,
never,
Runners.Runners
>
const layerPing: {
build: (memoMap: MemoMap, scope: Scope.Scope) => Effect<Context.Context<RunnerHealth>, never, Runners>;
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; <…;
}
Layer that pings runners directly to check whether they are healthy.
layerPing.Pipeable.pipe<Layer.Layer<RunnerHealth.RunnerHealth, never, Runners.Runners>, Layer.Layer<RunnerHealth.RunnerHealth, never, ShardingConfig.ShardingConfig | MessageStorage.MessageStorage | Runners.RpcClientProtocol>, Layer.Layer<RunnerHealth.RunnerHealth, never, ShardingConfig.ShardingConfig | MessageStorage.MessageStorage | RpcSerialization.RpcSerialization>>(this: Layer.Layer<...>, ab: (_: Layer.Layer<...>) => Layer.Layer<...>, bc: (_: Layer.Layer<...>) => Layer.Layer<...>): Layer.Layer<...> (+21 overloads)pipe(
import LayerLayer.const provide: {
<RIn, E, ROut>(that: Layer<ROut, E, RIn>): <
RIn2,
E2,
ROut2
>(
self: Layer<ROut2, E2, RIn2>
) => Layer<
ROut2,
E | E2,
RIn | Exclude<RIn2, ROut>
>
<Layers extends [Any, ...Array<Any>]>(
that: Layers
): <A, E, R>(
self: Layer<A, E, R>
) => Layer<
A,
E | Error<Layers[number]>,
| Services<Layers[number]>
| Exclude<R, Success<Layers[number]>>
>
<RIn2, E2, ROut2, RIn, E, ROut>(
self: Layer<ROut2, E2, RIn2>,
that: Layer<ROut, E, RIn>
): Layer<
ROut2,
E | E2,
RIn | Exclude<RIn2, ROut>
>
<A, E, R, Layers extends [Any, ...Array<Any>]>(
self: Layer<A, E, R>,
that: Layers
): Layer<
A,
E | Error<Layers[number]>,
| Services<Layers[number]>
| Exclude<R, Success<Layers[number]>>
>
}
Feeds the output services of the dependency layer into the requirements of
this layer, returning a layer that only provides the services from this layer.
When to use
Use when you need to hide an implementation dependency layer from callers.
Details
In serviceLayer.pipe(Layer.provide(dependencyLayer)), the dependency layer is
built first and is used to satisfy the requirements of serviceLayer.
Example (Providing layer dependencies)
import { Context, Effect, Layer } from "effect"
class Database extends Context.Service<Database, {
readonly query: (sql: string) => Effect.Effect<string>
}>()("Database") {}
class UserService extends Context.Service<UserService, {
readonly getUser: (id: string) => Effect.Effect<{
id: string
name: string
}>
}>()("UserService") {}
class Logger extends Context.Service<Logger, {
readonly log: (msg: string) => Effect.Effect<void>
}>()("Logger") {}
// Create dependency layers
const databaseLayer = Layer.succeed(Database, {
query: Effect.fn("Database.query")((sql: string) => Effect.succeed(`DB: ${sql}`))
})
const loggerLayer = Layer.succeed(Logger, {
log: Effect.fn("Logger.log")((msg: string) => Effect.sync(() => console.log(`[LOG] ${msg}`)))
})
// UserService depends on Database and Logger
const userServiceLayer = Layer.effect(UserService, Effect.gen(function*() {
const database = yield* Database
const logger = yield* Logger
return {
getUser: Effect.fn("UserService.getUser")(function*(id: string) {
yield* logger.log(`Looking up user ${id}`)
const result = yield* database.query(
`SELECT * FROM users WHERE id = ${id}`
)
return { id, name: result }
})
}
}))
// Provide dependencies to UserService layer
const userServiceWithDependencies = userServiceLayer.pipe(
Layer.provide(Layer.mergeAll(databaseLayer, loggerLayer))
)
// Now UserService layer has no dependencies
const program = Effect.gen(function*() {
const userService = yield* UserService
return yield* userService.getUser("123")
}).pipe(
Effect.provide(userServiceWithDependencies)
)
provide(import RunnersRunners.const layerRpc: Layer.Layer<
Runners,
never,
| MessageStorage.MessageStorage
| RpcClientProtocol
| ShardingConfig
>
const layerRpc: {
build: (memoMap: MemoMap, scope: Scope.Scope) => Effect<Context.Context<Runners>, never, RpcClientProtocol | MessageStorage | ShardingConfig>;
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; <…;
}
Layer that provides an RPC-backed Runners service using RpcClientProtocol,
message storage, sharding configuration, and the default snowflake generator.
layerRpc),
import LayerLayer.const provide: {
<RIn, E, ROut>(that: Layer<ROut, E, RIn>): <
RIn2,
E2,
ROut2
>(
self: Layer<ROut2, E2, RIn2>
) => Layer<
ROut2,
E | E2,
RIn | Exclude<RIn2, ROut>
>
<Layers extends [Any, ...Array<Any>]>(
that: Layers
): <A, E, R>(
self: Layer<A, E, R>
) => Layer<
A,
E | Error<Layers[number]>,
| Services<Layers[number]>
| Exclude<R, Success<Layers[number]>>
>
<RIn2, E2, ROut2, RIn, E, ROut>(
self: Layer<ROut2, E2, RIn2>,
that: Layer<ROut, E, RIn>
): Layer<
ROut2,
E | E2,
RIn | Exclude<RIn2, ROut>
>
<A, E, R, Layers extends [Any, ...Array<Any>]>(
self: Layer<A, E, R>,
that: Layers
): Layer<
A,
E | Error<Layers[number]>,
| Services<Layers[number]>
| Exclude<R, Success<Layers[number]>>
>
}
Feeds the output services of the dependency layer into the requirements of
this layer, returning a layer that only provides the services from this layer.
When to use
Use when you need to hide an implementation dependency layer from callers.
Details
In serviceLayer.pipe(Layer.provide(dependencyLayer)), the dependency layer is
built first and is used to satisfy the requirements of serviceLayer.
Example (Providing layer dependencies)
import { Context, Effect, Layer } from "effect"
class Database extends Context.Service<Database, {
readonly query: (sql: string) => Effect.Effect<string>
}>()("Database") {}
class UserService extends Context.Service<UserService, {
readonly getUser: (id: string) => Effect.Effect<{
id: string
name: string
}>
}>()("UserService") {}
class Logger extends Context.Service<Logger, {
readonly log: (msg: string) => Effect.Effect<void>
}>()("Logger") {}
// Create dependency layers
const databaseLayer = Layer.succeed(Database, {
query: Effect.fn("Database.query")((sql: string) => Effect.succeed(`DB: ${sql}`))
})
const loggerLayer = Layer.succeed(Logger, {
log: Effect.fn("Logger.log")((msg: string) => Effect.sync(() => console.log(`[LOG] ${msg}`)))
})
// UserService depends on Database and Logger
const userServiceLayer = Layer.effect(UserService, Effect.gen(function*() {
const database = yield* Database
const logger = yield* Logger
return {
getUser: Effect.fn("UserService.getUser")(function*(id: string) {
yield* logger.log(`Looking up user ${id}`)
const result = yield* database.query(
`SELECT * FROM users WHERE id = ${id}`
)
return { id, name: result }
})
}
}))
// Provide dependencies to UserService layer
const userServiceWithDependencies = userServiceLayer.pipe(
Layer.provide(Layer.mergeAll(databaseLayer, loggerLayer))
)
// Now UserService layer has no dependencies
const program = Effect.gen(function*() {
const userService = yield* UserService
return yield* userService.getUser("123")
}).pipe(
Effect.provide(userServiceWithDependencies)
)
provide(
options: {
readonly transport: "http" | "websocket"
readonly serialization?:
| "msgpack"
| "ndjson"
| undefined
readonly clientOnly?: ClientOnly | undefined
readonly storage?: Storage | undefined
readonly runnerHealth?:
| "ping"
| "k8s"
| undefined
readonly runnerHealthK8s?:
| {
readonly namespace?: string | undefined
readonly labelSelector?:
| string
| undefined
}
| undefined
readonly shardingConfig?:
| Partial<
ShardingConfig.ShardingConfig["Service"]
>
| undefined
}
options.transport: "http" | "websocket"transport === "http"
? import HttpRunnerHttpRunner.const layerClientProtocolHttpDefault: Layer.Layer<
Runners.RpcClientProtocol,
never,
| RpcSerialization.RpcSerialization
| HttpClient.HttpClient
>
const layerClientProtocolHttpDefault: {
build: (memoMap: MemoMap, scope: Scope.Scope) => Effect<Context.Context<RpcClientProtocol>, never, RpcSerialization | HttpClient>;
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; <…;
}
Default HTTP runner client protocol layer using path /.
layerClientProtocolHttpDefault.Pipeable.pipe<Layer.Layer<Runners.RpcClientProtocol, never, RpcSerialization.RpcSerialization | HttpClient>, Layer.Layer<Runners.RpcClientProtocol, never, RpcSerialization.RpcSerialization>>(this: Layer.Layer<...>, ab: (_: Layer.Layer<Runners.RpcClientProtocol, never, RpcSerialization.RpcSerialization | HttpClient>) => Layer.Layer<Runners.RpcClientProtocol, never, RpcSerialization.RpcSerialization>): Layer.Layer<...> (+21 overloads)pipe(import LayerLayer.const provide: {
<RIn, E, ROut>(that: Layer<ROut, E, RIn>): <
RIn2,
E2,
ROut2
>(
self: Layer<ROut2, E2, RIn2>
) => Layer<
ROut2,
E | E2,
RIn | Exclude<RIn2, ROut>
>
<Layers extends [Any, ...Array<Any>]>(
that: Layers
): <A, E, R>(
self: Layer<A, E, R>
) => Layer<
A,
E | Error<Layers[number]>,
| Services<Layers[number]>
| Exclude<R, Success<Layers[number]>>
>
<RIn2, E2, ROut2, RIn, E, ROut>(
self: Layer<ROut2, E2, RIn2>,
that: Layer<ROut, E, RIn>
): Layer<
ROut2,
E | E2,
RIn | Exclude<RIn2, ROut>
>
<A, E, R, Layers extends [Any, ...Array<Any>]>(
self: Layer<A, E, R>,
that: Layers
): Layer<
A,
E | Error<Layers[number]>,
| Services<Layers[number]>
| Exclude<R, Success<Layers[number]>>
>
}
Feeds the output services of the dependency layer into the requirements of
this layer, returning a layer that only provides the services from this layer.
When to use
Use when you need to hide an implementation dependency layer from callers.
Details
In serviceLayer.pipe(Layer.provide(dependencyLayer)), the dependency layer is
built first and is used to satisfy the requirements of serviceLayer.
Example (Providing layer dependencies)
import { Context, Effect, Layer } from "effect"
class Database extends Context.Service<Database, {
readonly query: (sql: string) => Effect.Effect<string>
}>()("Database") {}
class UserService extends Context.Service<UserService, {
readonly getUser: (id: string) => Effect.Effect<{
id: string
name: string
}>
}>()("UserService") {}
class Logger extends Context.Service<Logger, {
readonly log: (msg: string) => Effect.Effect<void>
}>()("Logger") {}
// Create dependency layers
const databaseLayer = Layer.succeed(Database, {
query: Effect.fn("Database.query")((sql: string) => Effect.succeed(`DB: ${sql}`))
})
const loggerLayer = Layer.succeed(Logger, {
log: Effect.fn("Logger.log")((msg: string) => Effect.sync(() => console.log(`[LOG] ${msg}`)))
})
// UserService depends on Database and Logger
const userServiceLayer = Layer.effect(UserService, Effect.gen(function*() {
const database = yield* Database
const logger = yield* Logger
return {
getUser: Effect.fn("UserService.getUser")(function*(id: string) {
yield* logger.log(`Looking up user ${id}`)
const result = yield* database.query(
`SELECT * FROM users WHERE id = ${id}`
)
return { id, name: result }
})
}
}))
// Provide dependencies to UserService layer
const userServiceWithDependencies = userServiceLayer.pipe(
Layer.provide(Layer.mergeAll(databaseLayer, loggerLayer))
)
// Now UserService layer has no dependencies
const program = Effect.gen(function*() {
const userService = yield* UserService
return yield* userService.getUser("123")
}).pipe(
Effect.provide(userServiceWithDependencies)
)
provide(import NodeHttpClientNodeHttpClient.const layerUndici: Layer.Layer<Client.HttpClient>const layerUndici: {
build: (memoMap: MemoMap, scope: Scope.Scope) => Effect<Context.Context<HttpClient>, 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; <…;
}
Provides an Undici-backed HttpClient together with a scoped default
Undici Agent dispatcher.
layerUndici))
: import HttpRunnerHttpRunner.const layerClientProtocolWebsocketDefault: Layer.Layer<
Runners.RpcClientProtocol,
never,
| RpcSerialization.RpcSerialization
| Socket.WebSocketConstructor
>
const layerClientProtocolWebsocketDefault: {
build: (memoMap: MemoMap, scope: Scope.Scope) => Effect<Context.Context<RpcClientProtocol>, never, RpcSerialization | WebSocketConstructor>;
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; <…;
}
Default WebSocket runner client protocol layer using path /.
layerClientProtocolWebsocketDefault.Pipeable.pipe<Layer.Layer<Runners.RpcClientProtocol, never, RpcSerialization.RpcSerialization | WebSocketConstructor>, Layer.Layer<Runners.RpcClientProtocol, never, RpcSerialization.RpcSerialization>>(this: Layer.Layer<...>, ab: (_: Layer.Layer<Runners.RpcClientProtocol, never, RpcSerialization.RpcSerialization | WebSocketConstructor>) => Layer.Layer<Runners.RpcClientProtocol, never, RpcSerialization.RpcSerialization>): Layer.Layer<...> (+21 overloads)pipe(import LayerLayer.const provide: {
<RIn, E, ROut>(that: Layer<ROut, E, RIn>): <
RIn2,
E2,
ROut2
>(
self: Layer<ROut2, E2, RIn2>
) => Layer<
ROut2,
E | E2,
RIn | Exclude<RIn2, ROut>
>
<Layers extends [Any, ...Array<Any>]>(
that: Layers
): <A, E, R>(
self: Layer<A, E, R>
) => Layer<
A,
E | Error<Layers[number]>,
| Services<Layers[number]>
| Exclude<R, Success<Layers[number]>>
>
<RIn2, E2, ROut2, RIn, E, ROut>(
self: Layer<ROut2, E2, RIn2>,
that: Layer<ROut, E, RIn>
): Layer<
ROut2,
E | E2,
RIn | Exclude<RIn2, ROut>
>
<A, E, R, Layers extends [Any, ...Array<Any>]>(
self: Layer<A, E, R>,
that: Layers
): Layer<
A,
E | Error<Layers[number]>,
| Services<Layers[number]>
| Exclude<R, Success<Layers[number]>>
>
}
Feeds the output services of the dependency layer into the requirements of
this layer, returning a layer that only provides the services from this layer.
When to use
Use when you need to hide an implementation dependency layer from callers.
Details
In serviceLayer.pipe(Layer.provide(dependencyLayer)), the dependency layer is
built first and is used to satisfy the requirements of serviceLayer.
Example (Providing layer dependencies)
import { Context, Effect, Layer } from "effect"
class Database extends Context.Service<Database, {
readonly query: (sql: string) => Effect.Effect<string>
}>()("Database") {}
class UserService extends Context.Service<UserService, {
readonly getUser: (id: string) => Effect.Effect<{
id: string
name: string
}>
}>()("UserService") {}
class Logger extends Context.Service<Logger, {
readonly log: (msg: string) => Effect.Effect<void>
}>()("Logger") {}
// Create dependency layers
const databaseLayer = Layer.succeed(Database, {
query: Effect.fn("Database.query")((sql: string) => Effect.succeed(`DB: ${sql}`))
})
const loggerLayer = Layer.succeed(Logger, {
log: Effect.fn("Logger.log")((msg: string) => Effect.sync(() => console.log(`[LOG] ${msg}`)))
})
// UserService depends on Database and Logger
const userServiceLayer = Layer.effect(UserService, Effect.gen(function*() {
const database = yield* Database
const logger = yield* Logger
return {
getUser: Effect.fn("UserService.getUser")(function*(id: string) {
yield* logger.log(`Looking up user ${id}`)
const result = yield* database.query(
`SELECT * FROM users WHERE id = ${id}`
)
return { id, name: result }
})
}
}))
// Provide dependencies to UserService layer
const userServiceWithDependencies = userServiceLayer.pipe(
Layer.provide(Layer.mergeAll(databaseLayer, loggerLayer))
)
// Now UserService layer has no dependencies
const program = Effect.gen(function*() {
const userService = yield* UserService
return yield* userService.getUser("123")
}).pipe(
Effect.provide(userServiceWithDependencies)
)
provide(import NodeSocketNodeSocket.const layerWebSocketConstructor: Layer.Layer<Socket.WebSocketConstructor>const layerWebSocketConstructor: {
build: (memoMap: MemoMap, scope: Scope.Scope) => Effect<Context.Context<WebSocketConstructor>, 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; <…;
}
Provides a Socket.WebSocketConstructor, using globalThis.WebSocket when
available and falling back to the ws package otherwise.
layerWebSocketConstructor))
)
)
return const layer: Layer.Layer<any, any, any>const layer: {
build: (memoMap: MemoMap, scope: Scope.Scope) => Effect<Context.Context<any>, any, any>;
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; <…;
}
layer.Pipeable.pipe<Layer.Layer<any, any, any>, Layer.Layer<any, any, any>, Layer.Layer<any, any, any>, Layer.Layer<any, any, any>, Layer.Layer<any, any, any>, Layer.Layer<any, any, any>>(this: Layer.Layer<...>, ab: (_: Layer.Layer<any, any, any>) => Layer.Layer<any, any, any>, bc: (_: Layer.Layer<any, any, any>) => Layer.Layer<any, any, any>, cd: (_: Layer.Layer<any, any, any>) => Layer.Layer<any, any, any>, de: (_: Layer.Layer<any, any, any>) => Layer.Layer<any, any, any>, ef: (_: Layer.Layer<...>) => Layer.Layer<...>): Layer.Layer<...> (+21 overloads)pipe(
import LayerLayer.const provide: {
<RIn, E, ROut>(that: Layer<ROut, E, RIn>): <
RIn2,
E2,
ROut2
>(
self: Layer<ROut2, E2, RIn2>
) => Layer<
ROut2,
E | E2,
RIn | Exclude<RIn2, ROut>
>
<Layers extends [Any, ...Array<Any>]>(
that: Layers
): <A, E, R>(
self: Layer<A, E, R>
) => Layer<
A,
E | Error<Layers[number]>,
| Services<Layers[number]>
| Exclude<R, Success<Layers[number]>>
>
<RIn2, E2, ROut2, RIn, E, ROut>(
self: Layer<ROut2, E2, RIn2>,
that: Layer<ROut, E, RIn>
): Layer<
ROut2,
E | E2,
RIn | Exclude<RIn2, ROut>
>
<A, E, R, Layers extends [Any, ...Array<Any>]>(
self: Layer<A, E, R>,
that: Layers
): Layer<
A,
E | Error<Layers[number]>,
| Services<Layers[number]>
| Exclude<R, Success<Layers[number]>>
>
}
Feeds the output services of the dependency layer into the requirements of
this layer, returning a layer that only provides the services from this layer.
When to use
Use when you need to hide an implementation dependency layer from callers.
Details
In serviceLayer.pipe(Layer.provide(dependencyLayer)), the dependency layer is
built first and is used to satisfy the requirements of serviceLayer.
Example (Providing layer dependencies)
import { Context, Effect, Layer } from "effect"
class Database extends Context.Service<Database, {
readonly query: (sql: string) => Effect.Effect<string>
}>()("Database") {}
class UserService extends Context.Service<UserService, {
readonly getUser: (id: string) => Effect.Effect<{
id: string
name: string
}>
}>()("UserService") {}
class Logger extends Context.Service<Logger, {
readonly log: (msg: string) => Effect.Effect<void>
}>()("Logger") {}
// Create dependency layers
const databaseLayer = Layer.succeed(Database, {
query: Effect.fn("Database.query")((sql: string) => Effect.succeed(`DB: ${sql}`))
})
const loggerLayer = Layer.succeed(Logger, {
log: Effect.fn("Logger.log")((msg: string) => Effect.sync(() => console.log(`[LOG] ${msg}`)))
})
// UserService depends on Database and Logger
const userServiceLayer = Layer.effect(UserService, Effect.gen(function*() {
const database = yield* Database
const logger = yield* Logger
return {
getUser: Effect.fn("UserService.getUser")(function*(id: string) {
yield* logger.log(`Looking up user ${id}`)
const result = yield* database.query(
`SELECT * FROM users WHERE id = ${id}`
)
return { id, name: result }
})
}
}))
// Provide dependencies to UserService layer
const userServiceWithDependencies = userServiceLayer.pipe(
Layer.provide(Layer.mergeAll(databaseLayer, loggerLayer))
)
// Now UserService layer has no dependencies
const program = Effect.gen(function*() {
const userService = yield* UserService
return yield* userService.getUser("123")
}).pipe(
Effect.provide(userServiceWithDependencies)
)
provide(const runnerHealth: Layer.Layer<
any,
any,
any
>
const runnerHealth: {
build: (memoMap: MemoMap, scope: Scope.Scope) => Effect<Context.Context<any>, any, any>;
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; <…;
}
runnerHealth),
import LayerLayer.const provideMerge: {
<RIn, E, ROut>(that: Layer<ROut, E, RIn>): <
RIn2,
E2,
ROut2
>(
self: Layer<ROut2, E2, RIn2>
) => Layer<
ROut | ROut2,
E | E2,
RIn | Exclude<RIn2, ROut>
>
<Layers extends [Any, ...Array<Any>]>(
that: Layers
): <A, E, R>(
self: Layer<A, E, R>
) => Layer<
A | Success<Layers[number]>,
E | Error<Layers[number]>,
| Services<Layers[number]>
| Exclude<R, Success<Layers[number]>>
>
<RIn2, E2, ROut2, RIn, E, ROut>(
self: Layer<ROut2, E2, RIn2>,
that: Layer<ROut, E, RIn>
): Layer<
ROut | ROut2,
E | E2,
RIn | Exclude<RIn2, ROut>
>
<A, E, R, Layers extends [Any, ...Array<Any>]>(
self: Layer<A, E, R>,
that: Layers
): Layer<
A | Success<Layers[number]>,
E | Error<Layers[number]>,
| Services<Layers[number]>
| Exclude<R, Success<Layers[number]>>
>
}
Feeds the output services of the dependency layer into the requirements of
this layer, returning a layer that provides both sets of services.
When to use
Use when you need to compose Layers while keeping both the constructed
service and the dependency used to build it available.
Details
Prefer
provide
when the dependency should stay private.
Example (Providing dependencies while retaining services)
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") {}
class UserService extends Context.Service<UserService, {
readonly getUser: (id: string) => Effect.Effect<{
id: string
name: string
}>
}>()("UserService") {}
// Create dependency layers
const databaseLayer = Layer.succeed(Database, {
query: Effect.fn("Database.query")((sql: string) => Effect.succeed(`DB: ${sql}`))
})
const loggerLayer = Layer.succeed(Logger, {
log: Effect.fn("Logger.log")((msg: string) => Effect.sync(() => console.log(`[LOG] ${msg}`)))
})
// UserService depends on Database and Logger
const userServiceLayer = Layer.effect(UserService, Effect.gen(function*() {
const database = yield* Database
const logger = yield* Logger
return {
getUser: Effect.fn("UserService.getUser")(function*(id: string) {
yield* logger.log(`Looking up user ${id}`)
const result = yield* database.query(
`SELECT * FROM users WHERE id = ${id}`
)
return { id, name: result }
})
}
}))
// Provide dependencies and merge all services together
const allServicesLayer = userServiceLayer.pipe(
Layer.provideMerge(Layer.mergeAll(databaseLayer, loggerLayer))
)
// Now the resulting layer provides UserService, Database, AND Logger
const program = Effect.gen(function*() {
const userService = yield* UserService
const logger = yield* Logger // Still available!
const database = yield* Database // Still available!
const user = yield* userService.getUser("123")
yield* logger.log(`Found user: ${user.name}`)
return user
}).pipe(
Effect.provide(allServicesLayer)
)
provideMerge(
options: {
readonly transport: "http" | "websocket"
readonly serialization?:
| "msgpack"
| "ndjson"
| undefined
readonly clientOnly?: ClientOnly | undefined
readonly storage?: Storage | undefined
readonly runnerHealth?:
| "ping"
| "k8s"
| undefined
readonly runnerHealthK8s?:
| {
readonly namespace?: string | undefined
readonly labelSelector?:
| string
| undefined
}
| undefined
readonly shardingConfig?:
| Partial<
ShardingConfig.ShardingConfig["Service"]
>
| undefined
}
options?.storage?: Storage | undefinedstorage === "local"
? import MessageStorageMessageStorage.const layerNoop: Layer.Layer<MessageStorage>const layerNoop: {
build: (memoMap: MemoMap, scope: Scope.Scope) => Effect<Context.Context<MessageStorage>, 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; <…;
}
Layer that provides the no-op MessageStorage service.
layerNoop
: options: {
readonly transport: "http" | "websocket"
readonly serialization?:
| "msgpack"
| "ndjson"
| undefined
readonly clientOnly?: ClientOnly | undefined
readonly storage?: Storage | undefined
readonly runnerHealth?:
| "ping"
| "k8s"
| undefined
readonly runnerHealthK8s?:
| {
readonly namespace?: string | undefined
readonly labelSelector?:
| string
| undefined
}
| undefined
readonly shardingConfig?:
| Partial<
ShardingConfig.ShardingConfig["Service"]
>
| undefined
}
options?.storage?: Storage | undefinedstorage === "byo"
? import LayerLayer.const empty: Layer<never>const empty: {
build: (memoMap: MemoMap, scope: Scope.Scope) => 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; <…;
}
An empty layer that provides no services, cannot fail, has no requirements,
and performs no construction or finalization work.
When to use
Use as the no-op branch when conditionally composing layers.
Example (Disabling optional lifecycle work)
import { Console, Layer } from "effect"
declare const flag: boolean
const StartupLogLive = flag
? Layer.effectDiscard(Console.log("application starting"))
: Layer.empty
empty
: import LayerLayer.const orDie: <A, E, R>(
self: Layer<A, E, R>
) => Layer<A, never, R>
Converts layer construction failures into defects, removing them from the
layer's error type.
Details
Use this only when failures should be treated as unrecoverable defects rather
than typed errors that callers can handle.
Example (Converting layer failures to defects)
import { Context, Data, Effect, Layer } from "effect"
class DatabaseError extends Data.TaggedError("DatabaseError")<{
message: string
}> {}
class Database extends Context.Service<Database, {
readonly query: (sql: string) => Effect.Effect<string>
}>()("Database") {}
// Layer that can fail during construction
const flakyDatabaseLayer = Layer.effect(Database, Effect.gen(function*() {
console.log("connecting")
return yield* new DatabaseError({ message: "Connection failed" })
}))
// Convert failures to fiber death - removes error from type
const reliableDatabaseLayer = flakyDatabaseLayer.pipe(Layer.orDie)
// Now the layer type is Layer<Database, never, never> - no error in type
const program = Effect.gen(function*() {
const database = yield* Database
return yield* database.query("SELECT * FROM users")
}).pipe(
Effect.provide(reliableDatabaseLayer)
)
// Running the program prints "connecting", then the DatabaseError is
// converted into a fiber defect instead of remaining a typed error.
orDie(import SqlMessageStorageSqlMessageStorage.const layer: Layer.Layer<
MessageStorage.MessageStorage,
never,
SqlClient.SqlClient | ShardingConfig
>
const layer: {
build: (memoMap: MemoMap, scope: Scope.Scope) => Effect<Context.Context<MessageStorage>, never, ShardingConfig | SqlClient>;
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; <…;
}
Layer that provides SQL-backed MessageStorage using the default table prefix
and the default snowflake generator.
When to use
Use when a cluster should persist mailbox messages and replies in SQL using
the default cluster table prefix and the standard snowflake generator.
Details
The layer runs the SQL migrations through make, provides MessageStorage,
and supplies Snowflake.layerGenerator internally. Callers still provide
SqlClient and ShardingConfig.
Gotchas
This layer always uses the cluster table prefix. Use layerWith before
deployment if you need a different stable prefix, because changing prefixes
later points the runtime at a different set of tables.
layer)
),
import LayerLayer.const provide: {
<RIn, E, ROut>(that: Layer<ROut, E, RIn>): <
RIn2,
E2,
ROut2
>(
self: Layer<ROut2, E2, RIn2>
) => Layer<
ROut2,
E | E2,
RIn | Exclude<RIn2, ROut>
>
<Layers extends [Any, ...Array<Any>]>(
that: Layers
): <A, E, R>(
self: Layer<A, E, R>
) => Layer<
A,
E | Error<Layers[number]>,
| Services<Layers[number]>
| Exclude<R, Success<Layers[number]>>
>
<RIn2, E2, ROut2, RIn, E, ROut>(
self: Layer<ROut2, E2, RIn2>,
that: Layer<ROut, E, RIn>
): Layer<
ROut2,
E | E2,
RIn | Exclude<RIn2, ROut>
>
<A, E, R, Layers extends [Any, ...Array<Any>]>(
self: Layer<A, E, R>,
that: Layers
): Layer<
A,
E | Error<Layers[number]>,
| Services<Layers[number]>
| Exclude<R, Success<Layers[number]>>
>
}
Feeds the output services of the dependency layer into the requirements of
this layer, returning a layer that only provides the services from this layer.
When to use
Use when you need to hide an implementation dependency layer from callers.
Details
In serviceLayer.pipe(Layer.provide(dependencyLayer)), the dependency layer is
built first and is used to satisfy the requirements of serviceLayer.
Example (Providing layer dependencies)
import { Context, Effect, Layer } from "effect"
class Database extends Context.Service<Database, {
readonly query: (sql: string) => Effect.Effect<string>
}>()("Database") {}
class UserService extends Context.Service<UserService, {
readonly getUser: (id: string) => Effect.Effect<{
id: string
name: string
}>
}>()("UserService") {}
class Logger extends Context.Service<Logger, {
readonly log: (msg: string) => Effect.Effect<void>
}>()("Logger") {}
// Create dependency layers
const databaseLayer = Layer.succeed(Database, {
query: Effect.fn("Database.query")((sql: string) => Effect.succeed(`DB: ${sql}`))
})
const loggerLayer = Layer.succeed(Logger, {
log: Effect.fn("Logger.log")((msg: string) => Effect.sync(() => console.log(`[LOG] ${msg}`)))
})
// UserService depends on Database and Logger
const userServiceLayer = Layer.effect(UserService, Effect.gen(function*() {
const database = yield* Database
const logger = yield* Logger
return {
getUser: Effect.fn("UserService.getUser")(function*(id: string) {
yield* logger.log(`Looking up user ${id}`)
const result = yield* database.query(
`SELECT * FROM users WHERE id = ${id}`
)
return { id, name: result }
})
}
}))
// Provide dependencies to UserService layer
const userServiceWithDependencies = userServiceLayer.pipe(
Layer.provide(Layer.mergeAll(databaseLayer, loggerLayer))
)
// Now UserService layer has no dependencies
const program = Effect.gen(function*() {
const userService = yield* UserService
return yield* userService.getUser("123")
}).pipe(
Effect.provide(userServiceWithDependencies)
)
provide(
options: {
readonly transport: "http" | "websocket"
readonly serialization?:
| "msgpack"
| "ndjson"
| undefined
readonly clientOnly?: ClientOnly | undefined
readonly storage?: Storage | undefined
readonly runnerHealth?:
| "ping"
| "k8s"
| undefined
readonly runnerHealthK8s?:
| {
readonly namespace?: string | undefined
readonly labelSelector?:
| string
| undefined
}
| undefined
readonly shardingConfig?:
| Partial<
ShardingConfig.ShardingConfig["Service"]
>
| undefined
}
options?.storage?: Storage | undefinedstorage === "local"
? import RunnerStorageRunnerStorage.const layerMemory: Layer.Layer<RunnerStorage>const layerMemory: {
build: (memoMap: MemoMap, scope: Scope.Scope) => Effect<Context.Context<RunnerStorage>, 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; <…;
}
Layer that provides the in-memory RunnerStorage implementation.
layerMemory
: options: {
readonly transport: "http" | "websocket"
readonly serialization?:
| "msgpack"
| "ndjson"
| undefined
readonly clientOnly?: ClientOnly | undefined
readonly storage?: Storage | undefined
readonly runnerHealth?:
| "ping"
| "k8s"
| undefined
readonly runnerHealthK8s?:
| {
readonly namespace?: string | undefined
readonly labelSelector?:
| string
| undefined
}
| undefined
readonly shardingConfig?:
| Partial<
ShardingConfig.ShardingConfig["Service"]
>
| undefined
}
options?.storage?: Storage | undefinedstorage === "byo"
? import LayerLayer.const empty: Layer<never>const empty: {
build: (memoMap: MemoMap, scope: Scope.Scope) => 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; <…;
}
An empty layer that provides no services, cannot fail, has no requirements,
and performs no construction or finalization work.
When to use
Use as the no-op branch when conditionally composing layers.
Example (Disabling optional lifecycle work)
import { Console, Layer } from "effect"
declare const flag: boolean
const StartupLogLive = flag
? Layer.effectDiscard(Console.log("application starting"))
: Layer.empty
empty
: import LayerLayer.const orDie: <A, E, R>(
self: Layer<A, E, R>
) => Layer<A, never, R>
Converts layer construction failures into defects, removing them from the
layer's error type.
Details
Use this only when failures should be treated as unrecoverable defects rather
than typed errors that callers can handle.
Example (Converting layer failures to defects)
import { Context, Data, Effect, Layer } from "effect"
class DatabaseError extends Data.TaggedError("DatabaseError")<{
message: string
}> {}
class Database extends Context.Service<Database, {
readonly query: (sql: string) => Effect.Effect<string>
}>()("Database") {}
// Layer that can fail during construction
const flakyDatabaseLayer = Layer.effect(Database, Effect.gen(function*() {
console.log("connecting")
return yield* new DatabaseError({ message: "Connection failed" })
}))
// Convert failures to fiber death - removes error from type
const reliableDatabaseLayer = flakyDatabaseLayer.pipe(Layer.orDie)
// Now the layer type is Layer<Database, never, never> - no error in type
const program = Effect.gen(function*() {
const database = yield* Database
return yield* database.query("SELECT * FROM users")
}).pipe(
Effect.provide(reliableDatabaseLayer)
)
// Running the program prints "connecting", then the DatabaseError is
// converted into a fiber defect instead of remaining a typed error.
orDie(import SqlRunnerStorageSqlRunnerStorage.const layer: Layer.Layer<
RunnerStorage.RunnerStorage,
SqlError,
| SqlClient.SqlClient
| ShardingConfig.ShardingConfig
>
const layer: {
build: (memoMap: MemoMap, scope: Scope.Scope) => Effect<Context.Context<RunnerStorage>, SqlError, ShardingConfig | SqlClient>;
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; <…;
}
Layer that provides SQL-backed RunnerStorage using the default table prefix.
layer)
),
import LayerLayer.const provide: {
<RIn, E, ROut>(that: Layer<ROut, E, RIn>): <
RIn2,
E2,
ROut2
>(
self: Layer<ROut2, E2, RIn2>
) => Layer<
ROut2,
E | E2,
RIn | Exclude<RIn2, ROut>
>
<Layers extends [Any, ...Array<Any>]>(
that: Layers
): <A, E, R>(
self: Layer<A, E, R>
) => Layer<
A,
E | Error<Layers[number]>,
| Services<Layers[number]>
| Exclude<R, Success<Layers[number]>>
>
<RIn2, E2, ROut2, RIn, E, ROut>(
self: Layer<ROut2, E2, RIn2>,
that: Layer<ROut, E, RIn>
): Layer<
ROut2,
E | E2,
RIn | Exclude<RIn2, ROut>
>
<A, E, R, Layers extends [Any, ...Array<Any>]>(
self: Layer<A, E, R>,
that: Layers
): Layer<
A,
E | Error<Layers[number]>,
| Services<Layers[number]>
| Exclude<R, Success<Layers[number]>>
>
}
Feeds the output services of the dependency layer into the requirements of
this layer, returning a layer that only provides the services from this layer.
When to use
Use when you need to hide an implementation dependency layer from callers.
Details
In serviceLayer.pipe(Layer.provide(dependencyLayer)), the dependency layer is
built first and is used to satisfy the requirements of serviceLayer.
Example (Providing layer dependencies)
import { Context, Effect, Layer } from "effect"
class Database extends Context.Service<Database, {
readonly query: (sql: string) => Effect.Effect<string>
}>()("Database") {}
class UserService extends Context.Service<UserService, {
readonly getUser: (id: string) => Effect.Effect<{
id: string
name: string
}>
}>()("UserService") {}
class Logger extends Context.Service<Logger, {
readonly log: (msg: string) => Effect.Effect<void>
}>()("Logger") {}
// Create dependency layers
const databaseLayer = Layer.succeed(Database, {
query: Effect.fn("Database.query")((sql: string) => Effect.succeed(`DB: ${sql}`))
})
const loggerLayer = Layer.succeed(Logger, {
log: Effect.fn("Logger.log")((msg: string) => Effect.sync(() => console.log(`[LOG] ${msg}`)))
})
// UserService depends on Database and Logger
const userServiceLayer = Layer.effect(UserService, Effect.gen(function*() {
const database = yield* Database
const logger = yield* Logger
return {
getUser: Effect.fn("UserService.getUser")(function*(id: string) {
yield* logger.log(`Looking up user ${id}`)
const result = yield* database.query(
`SELECT * FROM users WHERE id = ${id}`
)
return { id, name: result }
})
}
}))
// Provide dependencies to UserService layer
const userServiceWithDependencies = userServiceLayer.pipe(
Layer.provide(Layer.mergeAll(databaseLayer, loggerLayer))
)
// Now UserService layer has no dependencies
const program = Effect.gen(function*() {
const userService = yield* UserService
return yield* userService.getUser("123")
}).pipe(
Effect.provide(userServiceWithDependencies)
)
provide(import ShardingConfigShardingConfig.const layerFromEnv: (
options?:
| Partial<
ShardingConfig.ShardingConfig["Service"]
>
| undefined
) => Layer.Layer<
ShardingConfig.ShardingConfig,
Config.ConfigError
>
Layer that loads ShardingConfig from environment variables and, when options
are provided, overlays those options on top of the loaded values.
layerFromEnv(options: {
readonly transport: "http" | "websocket"
readonly serialization?:
| "msgpack"
| "ndjson"
| undefined
readonly clientOnly?: ClientOnly | undefined
readonly storage?: Storage | undefined
readonly runnerHealth?:
| "ping"
| "k8s"
| undefined
readonly runnerHealthK8s?:
| {
readonly namespace?: string | undefined
readonly labelSelector?:
| string
| undefined
}
| undefined
readonly shardingConfig?:
| Partial<
ShardingConfig.ShardingConfig["Service"]
>
| undefined
}
options?.shardingConfig?: Partial<{
readonly runnerAddress: Option.Option<RunnerAddress>;
readonly runnerListenAddress: Option.Option<RunnerAddress>;
readonly runnerShardWeight: number;
readonly availableShardGroups: ReadonlyArray<string>;
readonly assignedShardGroups: ReadonlyArray<string>;
readonly shardsPerGroup: number;
readonly shardLockRefreshInterval: Input;
readonly shardLockExpiration: Input;
readonly shardLockDisableAdvisory: boolean;
readonly preemptiveShutdown: boolean;
... 9 more ...;
readonly simulateRemoteSerialization: boolean;
}> | undefined
shardingConfig)),
import LayerLayer.const provide: {
<RIn, E, ROut>(that: Layer<ROut, E, RIn>): <
RIn2,
E2,
ROut2
>(
self: Layer<ROut2, E2, RIn2>
) => Layer<
ROut2,
E | E2,
RIn | Exclude<RIn2, ROut>
>
<Layers extends [Any, ...Array<Any>]>(
that: Layers
): <A, E, R>(
self: Layer<A, E, R>
) => Layer<
A,
E | Error<Layers[number]>,
| Services<Layers[number]>
| Exclude<R, Success<Layers[number]>>
>
<RIn2, E2, ROut2, RIn, E, ROut>(
self: Layer<ROut2, E2, RIn2>,
that: Layer<ROut, E, RIn>
): Layer<
ROut2,
E | E2,
RIn | Exclude<RIn2, ROut>
>
<A, E, R, Layers extends [Any, ...Array<Any>]>(
self: Layer<A, E, R>,
that: Layers
): Layer<
A,
E | Error<Layers[number]>,
| Services<Layers[number]>
| Exclude<R, Success<Layers[number]>>
>
}
Feeds the output services of the dependency layer into the requirements of
this layer, returning a layer that only provides the services from this layer.
When to use
Use when you need to hide an implementation dependency layer from callers.
Details
In serviceLayer.pipe(Layer.provide(dependencyLayer)), the dependency layer is
built first and is used to satisfy the requirements of serviceLayer.
Example (Providing layer dependencies)
import { Context, Effect, Layer } from "effect"
class Database extends Context.Service<Database, {
readonly query: (sql: string) => Effect.Effect<string>
}>()("Database") {}
class UserService extends Context.Service<UserService, {
readonly getUser: (id: string) => Effect.Effect<{
id: string
name: string
}>
}>()("UserService") {}
class Logger extends Context.Service<Logger, {
readonly log: (msg: string) => Effect.Effect<void>
}>()("Logger") {}
// Create dependency layers
const databaseLayer = Layer.succeed(Database, {
query: Effect.fn("Database.query")((sql: string) => Effect.succeed(`DB: ${sql}`))
})
const loggerLayer = Layer.succeed(Logger, {
log: Effect.fn("Logger.log")((msg: string) => Effect.sync(() => console.log(`[LOG] ${msg}`)))
})
// UserService depends on Database and Logger
const userServiceLayer = Layer.effect(UserService, Effect.gen(function*() {
const database = yield* Database
const logger = yield* Logger
return {
getUser: Effect.fn("UserService.getUser")(function*(id: string) {
yield* logger.log(`Looking up user ${id}`)
const result = yield* database.query(
`SELECT * FROM users WHERE id = ${id}`
)
return { id, name: result }
})
}
}))
// Provide dependencies to UserService layer
const userServiceWithDependencies = userServiceLayer.pipe(
Layer.provide(Layer.mergeAll(databaseLayer, loggerLayer))
)
// Now UserService layer has no dependencies
const program = Effect.gen(function*() {
const userService = yield* UserService
return yield* userService.getUser("123")
}).pipe(
Effect.provide(userServiceWithDependencies)
)
provide(
options: {
readonly transport: "http" | "websocket"
readonly serialization?:
| "msgpack"
| "ndjson"
| undefined
readonly clientOnly?: ClientOnly | undefined
readonly storage?: Storage | undefined
readonly runnerHealth?:
| "ping"
| "k8s"
| undefined
readonly runnerHealthK8s?:
| {
readonly namespace?: string | undefined
readonly labelSelector?:
| string
| undefined
}
| undefined
readonly shardingConfig?:
| Partial<
ShardingConfig.ShardingConfig["Service"]
>
| undefined
}
options?.serialization?: "msgpack" | "ndjson" | undefinedserialization === "ndjson" ? import RpcSerializationRpcSerialization.const layerNdjson: Layer.Layer<RpcSerialization>const layerNdjson: {
build: (memoMap: MemoMap, scope: Scope.Scope) => Effect<Context.Context<RpcSerialization>, 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; <…;
}
RPC serialization layer that uses NDJSON for serialization.
When to use
Use when you have a transport protocol that does not provide message framing.
layerNdjson : import RpcSerializationRpcSerialization.const layerMsgPack: Layer.Layer<RpcSerialization>const layerMsgPack: {
build: (memoMap: MemoMap, scope: Scope.Scope) => Effect<Context.Context<RpcSerialization>, 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; <…;
}
RPC serialization layer that uses MessagePack for serialization.
Details
MessagePack has a more compact binary format compared to JSON and NDJSON. It
also has better support for binary data.
layerMsgPack
)
) as any
}