<
const ClientOnly extends boolean = false,
const Storage extends "local" | "sql" | "byo" = never
>(options?: {
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),
ConfigError,
"local" extends Storage
? never
: "byo" extends Storage
? MessageStorage.MessageStorage | RunnerStorage.RunnerStorage
: SqlClient
>
: Layer.Layer<
| Sharding
| Runners.Runners
| ("byo" extends Storage ? never : MessageStorage.MessageStorage),
SocketServer.SocketServerError | ConfigError,
"local" extends Storage
? never
: "byo" extends Storage
? MessageStorage.MessageStorage | RunnerStorage.RunnerStorage
: SqlClient
>Builds the Node cluster socket sharding layer, configuring 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 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),
ConfigError,
"local" extends Storage
? never
: "byo" extends Storage
?
| MessageStorage.MessageStorage
| RunnerStorage.RunnerStorage
: SqlClient
>
: Layer.Layer<
| Sharding
| Runners.Runners
| ("byo" extends Storage
? never
: MessageStorage.MessageStorage),
| SocketServer.SocketServerError
| ConfigError,
"local" extends Storage
? never
: "byo" extends Storage
?
| MessageStorage.MessageStorage
| RunnerStorage.RunnerStorage
: SqlClient
>
Builds the Node cluster socket sharding layer, configuring 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 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), ConfigError, "local" extends Storage ? never : "byo" extends Storage ? (MessageStorage.MessageStorage | RunnerStorage.RunnerStorage) : SqlClient> : Layer.Layer<Sharding | Runners.Runners | ("byo" extends Storage ? never : MessageStorage.MessageStorage), SocketServer.SocketServerError | 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 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), ConfigError, "local" extends Storage ? never : "byo" extends Storage ? (MessageStorage.MessageStorage | RunnerStorage.RunnerStorage) : SqlClient> : Layer.Layer<Sharding | Runners.Runners | ("byo" extends Storage ? never : MessageStorage.MessageStorage), SocketServer.SocketServerError | ConfigError, "local" extends Storage ? never : "byo" extends Storage ? (MessageStorage.MessageStorage | RunnerStorage.RunnerStorage) : SqlClient>
Storage extends "local" | "sql" | "byo" = never
>(
options: | {
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
}
| undefined
options?: {
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 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), ConfigError, "local" extends Storage ? never : "byo" extends Storage ? (MessageStorage.MessageStorage | RunnerStorage.RunnerStorage) : SqlClient> : Layer.Layer<Sharding | Runners.Runners | ("byo" extends Storage ? never : MessageStorage.MessageStorage), SocketServer.SocketServerError | 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 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), ConfigError, "local" extends Storage ? never : "byo" extends Storage ? (MessageStorage.MessageStorage | RunnerStorage.RunnerStorage) : SqlClient> : Layer.Layer<Sharding | Runners.Runners | ("byo" extends Storage ? never : MessageStorage.MessageStorage), SocketServer.SocketServerError | 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<RunnerAddress>;
readonly runnerListenAddress: 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;
... 10 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 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), ConfigError, "local" extends Storage ? never : "byo" extends Storage ? (MessageStorage.MessageStorage | RunnerStorage.RunnerStorage) : SqlClient> : Layer.Layer<Sharding | Runners.Runners | ("byo" extends Storage ? never : MessageStorage.MessageStorage), SocketServer.SocketServerError | 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 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), ConfigError, "local" extends Storage ? never : "byo" extends Storage ? (MessageStorage.MessageStorage | RunnerStorage.RunnerStorage) : SqlClient> : Layer.Layer<Sharding | Runners.Runners | ("byo" extends Storage ? never : MessageStorage.MessageStorage), SocketServer.SocketServerError | 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 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 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), ConfigError, "local" extends Storage ? never : "byo" extends Storage ? (MessageStorage.MessageStorage | RunnerStorage.RunnerStorage) : SqlClient> : Layer.Layer<Sharding | Runners.Runners | ("byo" extends Storage ? never : MessageStorage.MessageStorage), SocketServer.SocketServerError | 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 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), ConfigError, "local" extends Storage ? never : "byo" extends Storage ? (MessageStorage.MessageStorage | RunnerStorage.RunnerStorage) : SqlClient> : Layer.Layer<Sharding | Runners.Runners | ("byo" extends Storage ? never : MessageStorage.MessageStorage), SocketServer.SocketServerError | 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 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), ConfigError, "local" extends Storage ? never : "byo" extends Storage ? (MessageStorage.MessageStorage | RunnerStorage.RunnerStorage) : SqlClient> : Layer.Layer<Sharding | Runners.Runners | ("byo" extends Storage ? never : MessageStorage.MessageStorage), SocketServer.SocketServerError | 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 SocketServerSocketServer.class SocketServerErrorclass SocketServerError {
message: string;
@effect/platform/SocketServer/SocketServerError: ErrorTypeId;
name: 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;
reason: SocketServer.SocketServerErrorReason;
}
Tagged socket server error that wraps a server error reason and exposes its
cause.
SocketServerError | 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 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), ConfigError, "local" extends Storage ? never : "byo" extends Storage ? (MessageStorage.MessageStorage | RunnerStorage.RunnerStorage) : SqlClient> : Layer.Layer<Sharding | Runners.Runners | ("byo" extends Storage ? never : MessageStorage.MessageStorage), SocketServer.SocketServerError | 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 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), ConfigError, "local" extends Storage ? never : "byo" extends Storage ? (MessageStorage.MessageStorage | RunnerStorage.RunnerStorage) : SqlClient> : Layer.Layer<Sharding | Runners.Runners | ("byo" extends Storage ? never : MessageStorage.MessageStorage), SocketServer.SocketServerError | 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 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
}
| undefined
options?.clientOnly?: ClientOnly | undefinedclientOnly
// client only
? 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 SocketRunnerSocketRunner.const layerClientOnly: Layer.Layer<
Sharding.Sharding | Runners.Runners,
never,
| Runners.RpcClientProtocol
| ShardingConfig
| MessageStorage
| RunnerStorage.RunnerStorage
>
const layerClientOnly: {
build: (memoMap: MemoMap, scope: Scope.Scope) => Effect<Context.Context<Runners | Sharding>, never, RpcClientProtocol | ShardingConfig | MessageStorage | 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 socket runner layer that provides Sharding and Runners clients
without starting a runner server or receiving shard assignments.
When to use
Use to join a socket-based cluster as a client-only participant that can send
messages without hosting shards.
layerClientOnly, import layerClientProtocollayerClientProtocol)
// with server
: 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 SocketRunnerSocketRunner.const layer: Layer.Layer<
Sharding.Sharding | Runners.Runners,
never,
| Runners.RpcClientProtocol
| ShardingConfig
| RpcSerialization.RpcSerialization
| SocketServer
| MessageStorage
| RunnerStorage.RunnerStorage
| RunnerHealth
>
const layer: {
build: (memoMap: MemoMap, scope: Scope.Scope) => Effect<Context.Context<Runners | Sharding>, never, RpcClientProtocol | RpcSerialization | SocketServer | ShardingConfig | MessageStorage | RunnerHealth | 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; <…;
}
Layer that runs a cluster runner over the socket RPC protocol, providing
Sharding and Runners clients and logging the socket listen address.
When to use
Use when a cluster runner process should accept runner RPCs through a
provided SocketServer and receive shard assignments while exposing
Sharding and Runners services.
Details
It logs the bound SocketServer.address when the layer starts, formatting TCP
addresses as hostname:port and Unix socket addresses as their filesystem
path.
Gotchas
Although this layer serves runner RPCs with the provided SocketServer,
outgoing calls to other runners still require a Runners.RpcClientProtocol
service.
layer, [import layerSocketServerlayerSocketServer, import layerClientProtocollayerClientProtocol])
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 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
}
| 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 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
}
| 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.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 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.K8sHttpClient>, Layer.Layer<RunnerHealth.RunnerHealth, never, never>>(this: Layer.Layer<RunnerHealth.RunnerHealth, never, K8sHttpClient.K8sHttpClient>, ab: (_: Layer.Layer<RunnerHealth.RunnerHealth, never, K8sHttpClient.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.K8sHttpClient>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, any, any>>(this: Layer.Layer<...>, ab: (_: Layer.Layer<RunnerHealth.RunnerHealth, never, Runners.Runners>) => Layer.Layer<RunnerHealth.RunnerHealth, never, ShardingConfig.ShardingConfig | ... 1 more ... | Runners.RpcClientProtocol>, 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 | ShardingConfig | MessageStorage>;
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(import layerClientProtocollayerClientProtocol)
)
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 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
}
| 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 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
}
| 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 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
}
| 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 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
}
| 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["Service"]>
| undefined
) => Layer.Layer<
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 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
}
| undefined
options?.shardingConfig?: Partial<{
readonly runnerAddress: Option<RunnerAddress>;
readonly runnerListenAddress: 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;
... 10 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 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
}
| 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
}