(
target?: number | string,
serialization?: Layer.Layer<RpcSerialization.RpcSerialization>
): Layer.Layer<RpcClient.Protocol>Build a WebSocket client Protocol (one multiplexed connection + ndjson) for one endpoint
url (default "/rpc"). The url may be a same-origin path ("/rpc" — resolved against the
page location, http→ws / https→wss), an http(s):// url (scheme swapped), or an absolute
ws(s):// url; resolution is lazy, so this is safe at module scope in a file a Node server also
imports. The browser transport — every stream rides one connection, past the ~6-connection cap that
starves streams over protocolHttp.
export const const protocolWebsocket: (
target?: number | string,
serialization?: Layer.Layer<RpcSerialization.RpcSerialization>
) => Layer.Layer<RpcClient.Protocol>
Build a WebSocket client Protocol (one multiplexed connection + ndjson) for one endpoint
url (default "/rpc"). The url may be a same-origin path ("/rpc" — resolved against the
page location, http→ws / https→wss), an http(s):// url (scheme swapped), or an absolute
ws(s):// url; resolution is lazy, so this is safe at module scope in a file a Node server also
imports. The browser transport — every stream rides one connection, past the ~6-connection cap that
starves streams over
protocolHttp
.
protocolWebsocket = (
target: string | numbertarget: number | string = "/rpc",
serialization: Layer.Layer<
RpcSerialization.RpcSerialization,
never,
never
>
(parameter) serialization: {
build: (memoMap: Layer.MemoMap, scope: Scope.Scope) => Effect.Effect<Context.Context<RpcSerialization.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; <…;
}
serialization: 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<import RpcSerializationRpcSerialization.class RpcSerializationclass RpcSerialization {
key: Identifier;
Service: {
makeUnsafe: () => RpcSerialization.Parser;
contentType: string;
includesFraming: boolean;
};
}
Service that describes how RPC protocol messages are encoded and decoded,
including the content type and whether the serialization format provides
message framing.
When to use
Use to provide the serialization boundary shared by RPC clients and servers
for a chosen wire format.
RpcSerialization> = const defaultSerialization: Layer.Layer<
RpcSerialization.RpcSerialization,
never,
never
>
const defaultSerialization: {
build: (memoMap: Layer.MemoMap, scope: Scope.Scope) => Effect.Effect<Context.Context<RpcSerialization.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; <…;
}
defaultSerialization,
): 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<import RpcClientRpcClient.class Protocolclass Protocol {
key: Identifier;
Service: {
run: (clientId: number, f: (data: FromServerEncoded) => Effect.Effect<void>) => Effect.Effect<never>;
send: (clientId: number, request: FromClientEncoded, transferables?: ReadonlyArray<globalThis.Transferable>) => Effect.Effect<void, RpcClientError>;
supportsAck: boolean;
supportsTransferables: boolean;
};
}
Defines the service interface for an RPC client transport, responsible for running the
receive loop and sending encoded client messages.
When to use
Use to provide the transport boundary for RPC clients over HTTP, WebSocket,
workers, sockets, or custom protocols.
Protocol> => {
const const build: (
url: string
) => Layer.Layer<RpcClient.Protocol>
build = (url: stringurl: string): 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<import RpcClientRpcClient.class Protocolclass Protocol {
key: Identifier;
Service: {
run: (clientId: number, f: (data: FromServerEncoded) => Effect.Effect<void>) => Effect.Effect<never>;
send: (clientId: number, request: FromClientEncoded, transferables?: ReadonlyArray<globalThis.Transferable>) => Effect.Effect<void, RpcClientError>;
supportsAck: boolean;
supportsTransferables: boolean;
};
}
Defines the service interface for an RPC client transport, responsible for running the
receive loop and sending encoded client messages.
When to use
Use to provide the transport boundary for RPC clients over HTTP, WebSocket,
workers, sockets, or custom protocols.
Protocol> =>
import RpcClientRpcClient.const layerProtocolSocket: (options?: {
readonly retryTransientErrors?:
| boolean
| undefined
}) => Layer.Layer<
RpcClient.Protocol,
never,
| Socket.Socket
| RpcSerialization.RpcSerialization
>
Provides a client Protocol backed by the current Socket and
RpcSerialization services.
layerProtocolSocket().Pipeable.pipe<Layer.Layer<RpcClient.Protocol, never, RpcSerialization.RpcSerialization | Socket.Socket>, Layer.Layer<RpcClient.Protocol, never, Socket.Socket>, Layer.Layer<RpcClient.Protocol, never, Socket.WebSocketConstructor>, Layer.Layer<RpcClient.Protocol, never, never>>(this: Layer.Layer<...>, ab: (_: Layer.Layer<RpcClient.Protocol, never, RpcSerialization.RpcSerialization | Socket.Socket>) => Layer.Layer<...>, bc: (_: Layer.Layer<...>) => Layer.Layer<...>, cd: (_: Layer.Layer<...>) => Layer.Layer<...>): Layer.Layer<...> (+21 overloads)pipe(
import LayerLayer.const provide: <never, never, RpcSerialization.RpcSerialization>(that: Layer.Layer<RpcSerialization.RpcSerialization, never, never>) => <RIn2, E2, ROut2>(self: Layer.Layer<ROut2, E2, RIn2>) => Layer.Layer<ROut2, E2, Exclude<RIn2, RpcSerialization.RpcSerialization>> (+3 overloads)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(serialization: Layer.Layer<
RpcSerialization.RpcSerialization,
never,
never
>
(parameter) serialization: {
build: (memoMap: Layer.MemoMap, scope: Scope.Scope) => Effect.Effect<Context.Context<RpcSerialization.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; <…;
}
serialization),
import LayerLayer.const provide: <Socket.WebSocketConstructor, never, Socket.Socket>(that: Layer.Layer<Socket.Socket, never, Socket.WebSocketConstructor>) => <RIn2, E2, ROut2>(self: Layer.Layer<ROut2, E2, RIn2>) => Layer.Layer<ROut2, E2, Socket.WebSocketConstructor | Exclude<RIn2, Socket.Socket>> (+3 overloads)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 SocketSocket.const layerWebSocket: (
url: string | Effect.Effect<string>,
options?:
| {
readonly closeCodeIsError?:
| ((code: number) => boolean)
| undefined
readonly openTimeout?:
| Duration.Input
| undefined
readonly protocols?:
| string
| Array<string>
| undefined
}
| undefined
) => Layer.Layer<
Socket.Socket,
never,
Socket.WebSocketConstructor
>
Layer that provides a Socket service backed by a WebSocket URL or URL
effect.
layerWebSocket(import EffectEffect.const sync: <string>(
thunk: Fn.LazyArg<string>
) => Effect.Effect<string, never, never>
Creates an Effect that represents a synchronous side-effectful computation.
When to use
Use when you need to wrap a synchronous side-effectful operation that is not
expected to throw.
Details
The provided function is evaluated lazily when the effect runs.
Gotchas
The function must not throw. If it throws, the thrown value is treated as a
defect, not as a typed failure. Use try when throwing is expected.
Example (Capturing synchronous logging in an Effect)
import { Effect } from "effect"
const log = (message: string) =>
Effect.sync(() => {
console.log(message) // side effect
})
// ┌─── Effect<void, never, never>
// ▼
const program = log("Hello, World!")
sync(() => const toWebSocketUrl: (
raw: string
) => string
toWebSocketUrl(url: stringurl)))),
import LayerLayer.const provide: <never, never, Socket.WebSocketConstructor>(that: Layer.Layer<Socket.WebSocketConstructor, never, never>) => <RIn2, E2, ROut2>(self: Layer.Layer<ROut2, E2, RIn2>) => Layer.Layer<ROut2, E2, Exclude<RIn2, Socket.WebSocketConstructor>> (+3 overloads)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 SocketSocket.const layerWebSocketConstructorGlobal: Layer.Layer<
Socket.WebSocketConstructor,
never,
never
>
const layerWebSocketConstructorGlobal: {
build: (memoMap: Layer.MemoMap, scope: Scope.Scope) => Effect.Effect<Context.Context<Socket.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; <…;
}
Layer that provides WebSocketConstructor using globalThis.WebSocket.
layerWebSocketConstructorGlobal),
);
// A bare port defers to the `clientHost` Config (→ `ws://${host}:port/rpc`); a path / url stays sync.
return typeof target: string | numbertarget === "number" || /^:\d+$/.RegExp.test(string: string): booleanReturns a Boolean value that indicates whether or not a pattern exists in a searched string.
test(target: stringtarget)
? import LayerLayer.const unwrap: <RpcClient.Protocol, never, never, never, never>(self: Effect.Effect<Layer.Layer<RpcClient.Protocol, never, never>, never, never>) => Layer.Layer<RpcClient.Protocol, never, never>Unwraps a Layer from an Effect, flattening the nested structure.
When to use
Use when you have an Effect that produces a Layer and you want to
use that layer directly.
Details
The resulting Layer will have the combined error and dependency types from
both the outer Effect and the inner Layer.
Example (Unwrapping an effectful layer)
import { Context, Effect, Layer } from "effect"
class Database extends Context.Service<Database, {
readonly query: (sql: string) => Effect.Effect<string>
}>()("Database") {}
const layerEffect = Effect.succeed(
Layer.succeed(Database, { query: Effect.fn("Database.query")((sql: string) => Effect.succeed("result")) })
)
const unwrappedLayer = Layer.unwrap(layerEffect)
unwrap(import EffectEffect.const map: <string, never, never, Layer.Layer<RpcClient.Protocol, never, never>>(self: Effect.Effect<string, never, never>, f: (a: string) => Layer.Layer<RpcClient.Protocol, never, never>) => Effect.Effect<Layer.Layer<RpcClient.Protocol, never, never>, never, never> (+1 overload)Transforms the value inside an effect by applying a function to it.
When to use
Use to transform an effect's success value with a function that returns a
plain value, producing a new effect without changing the original effect's
typed error or context requirements.
Details
map takes a function and applies it to the value contained within an
effect, creating a new effect with the transformed value.
It's important to note that effects are immutable, meaning that the original
effect is not modified. Instead, a new effect is returned with the updated
value.
Example (Choosing map syntax variants)
import { Effect, pipe } from "effect"
const myEffect = Effect.succeed(1)
const transformation = (n: number) => n + 1
const mappedWithPipe = pipe(myEffect, Effect.map(transformation))
const mappedWithDataFirst = Effect.map(myEffect, transformation)
const mappedWithMethod = myEffect.pipe(Effect.map(transformation))
Example (Adding a service charge)
import { Effect, pipe } from "effect"
const addServiceCharge = (amount: number) => amount + 1
const fetchTransactionAmount = Effect.promise(() => Promise.resolve(100))
const finalAmount = pipe(
fetchTransactionAmount,
Effect.map(addServiceCharge)
)
Effect.runPromise(finalAmount).then(console.log)
// Output: 101
map(const clientTargetUrl: (
scheme: "http" | "ws",
target: number | string
) => Effect.Effect<string>
A bare port (3009) / ":3009" resolves to ${scheme}://${clientHost}:port/rpc (Config host,
read at layer build); a path / full url passes through unchanged.
clientTargetUrl("ws", target: string | numbertarget), const build: (
url: string
) => Layer.Layer<RpcClient.Protocol>
build))
: const build: (
url: string
) => Layer.Layer<RpcClient.Protocol>
build(target: stringtarget);
};