<A, E, R>(
serve: Layer.Layer<A, E, R>,
options: IpcServerOptions
): Layer.Layer<A, E, R>
<const Serves extends ServerServeList>(
serves: Serves,
options: IpcServerOptions
): Layer.Layer<
Layer.Success<Serves[number]>,
Layer.Error<Serves[number]>,
Layer.Services<Serves[number]>
>A Unix-domain RPC server — same-machine sibling of httpServer / wsServer.
Speaks Effect's raw socket RPC protocol (RpcServer.layerProtocolSocketServer) over a
filesystem path — no HTTP, no WebSocket upgrade. Clients connect with connectIpc
or a node whose ProtocolKind is "IpcSocket" (Tag()("x", { path })).
class Worker extends Tag<Worker>()("worker", { path: "/tmp/worker.sock" }) {}
const live = Hyperlink.ipcServer(
[Hyperlink.serve(Jobs, jobsImpl)],
{ path: "/tmp/worker.sock" },
)
// or Node.unix(Worker, [Hyperlink.serve(Jobs, jobsImpl)])Auto-mounts node status/logs/ping like the http/ws servers. There is no /health HTTP route
(no HTTP listener) — probe readiness via the node-handle status RPC.
export function function ipcServer<A, E, R>(serve: Layer.Layer<A, E, R>, options: IpcServerOptions): Layer.Layer<A, E, R> (+1 overload)A Unix-domain RPC server — same-machine sibling of
httpServer
/
wsServer
.
Speaks Effect's raw socket RPC protocol (RpcServer.layerProtocolSocketServer) over a
filesystem path — no HTTP, no WebSocket upgrade. Clients connect with
connectIpc
or a node whose
ProtocolKind
is "IpcSocket" (Tag()("x", { path })).
class Worker extends Tag<Worker>()("worker", { path: "/tmp/worker.sock" }) {}
const live = Hyperlink.ipcServer(
[Hyperlink.serve(Jobs, jobsImpl)],
{ path: "/tmp/worker.sock" },
)
// or Node.unix(Worker, [Hyperlink.serve(Jobs, jobsImpl)])
Auto-mounts node status/logs/ping like the http/ws servers. There is no /health HTTP route
(no HTTP listener) — probe readiness via the node-handle status RPC.
ipcServer<function (type parameter) A in ipcServer<A, E, R>(serve: Layer.Layer<A, E, R>, options: IpcServerOptions): Layer.Layer<A, E, R>A, function (type parameter) E in ipcServer<A, E, R>(serve: Layer.Layer<A, E, R>, options: IpcServerOptions): Layer.Layer<A, E, R>E, function (type parameter) R in ipcServer<A, E, R>(serve: Layer.Layer<A, E, R>, options: IpcServerOptions): Layer.Layer<A, E, R>R>(
serve: Layer.Layer<A, E, R>(parameter) serve: {
build: (memoMap: MemoMap, scope: Scope.Scope) => Effect<Context.Context<A>, E, R>;
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; <…;
}
serve: 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<function (type parameter) A in ipcServer<A, E, R>(serve: Layer.Layer<A, E, R>, options: IpcServerOptions): Layer.Layer<A, E, R>A, function (type parameter) E in ipcServer<A, E, R>(serve: Layer.Layer<A, E, R>, options: IpcServerOptions): Layer.Layer<A, E, R>E, function (type parameter) R in ipcServer<A, E, R>(serve: Layer.Layer<A, E, R>, options: IpcServerOptions): Layer.Layer<A, E, R>R>,
options: IpcServerOptions(parameter) options: {
path: string;
serialization: Layer.Layer<RpcSerialization.RpcSerialization>;
node: string | { readonly key: string };
unlink: boolean;
advertiseNode: AnyNode & { readonly key: string };
onConflict: OnConflict;
assumeToken: string | Redacted.Redacted<string>;
onYield: Effect.Effect<boolean>;
}
options: IpcServerOptions,
): 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<function (type parameter) A in ipcServer<A, E, R>(serve: Layer.Layer<A, E, R>, options: IpcServerOptions): Layer.Layer<A, E, R>A, function (type parameter) E in ipcServer<A, E, R>(serve: Layer.Layer<A, E, R>, options: IpcServerOptions): Layer.Layer<A, E, R>E, function (type parameter) R in ipcServer<A, E, R>(serve: Layer.Layer<A, E, R>, options: IpcServerOptions): Layer.Layer<A, E, R>R>;
export function function ipcServer<const Serves extends ServerServeList>(serves: Serves, options: IpcServerOptions): Layer.Layer<Layer.Success<Serves[number]>, Layer.Error<Serves[number]>, Layer.Services<Serves[number]>> (+1 overload)A Unix-domain RPC server — same-machine sibling of
httpServer
/
wsServer
.
Speaks Effect's raw socket RPC protocol (RpcServer.layerProtocolSocketServer) over a
filesystem path — no HTTP, no WebSocket upgrade. Clients connect with
connectIpc
or a node whose
ProtocolKind
is "IpcSocket" (Tag()("x", { path })).
class Worker extends Tag<Worker>()("worker", { path: "/tmp/worker.sock" }) {}
const live = Hyperlink.ipcServer(
[Hyperlink.serve(Jobs, jobsImpl)],
{ path: "/tmp/worker.sock" },
)
// or Node.unix(Worker, [Hyperlink.serve(Jobs, jobsImpl)])
Auto-mounts node status/logs/ping like the http/ws servers. There is no /health HTTP route
(no HTTP listener) — probe readiness via the node-handle status RPC.
ipcServer<const function (type parameter) Serves in ipcServer<const Serves extends ServerServeList>(serves: Serves, options: IpcServerOptions): Layer.Layer<Layer.Success<Serves[number]>, Layer.Error<Serves[number]>, Layer.Services<Serves[number]>>Serves extends type ServerServeList = readonly [Layer.Any, ...Layer.Any[]]Non-empty serve list — open E/R so heterogeneous HyperService deps remain expressible.
ServerServeList>(
serves: const Serves extends ServerServeListserves: function (type parameter) Serves in ipcServer<const Serves extends ServerServeList>(serves: Serves, options: IpcServerOptions): Layer.Layer<Layer.Success<Serves[number]>, Layer.Error<Serves[number]>, Layer.Services<Serves[number]>>Serves,
options: IpcServerOptions(parameter) options: {
path: string;
serialization: Layer.Layer<RpcSerialization.RpcSerialization>;
node: string | { readonly key: string };
unlink: boolean;
advertiseNode: AnyNode & { readonly key: string };
onConflict: OnConflict;
assumeToken: string | Redacted.Redacted<string>;
onYield: Effect.Effect<boolean>;
}
options: IpcServerOptions,
): 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 LayerLayer.type Success<T extends Layer.Any> =
T extends Layer.Layer<
infer _ROut,
infer _E,
infer _RIn
>
? _ROut
: never
Extracts the service output type (ROut) from a Layer type.
When to use
Use to derive the services provided by an existing or generic Layer without
restating its ROut type parameter.
Success<function (type parameter) Serves in ipcServer<const Serves extends ServerServeList>(serves: Serves, options: IpcServerOptions): Layer.Layer<Layer.Success<Serves[number]>, Layer.Error<Serves[number]>, Layer.Services<Serves[number]>>Serves[number]>,
import LayerLayer.type Error<T extends Layer.Any> =
T extends Layer.Layer<
infer _ROut,
infer _E,
infer _RIn
>
? _E
: never
Extracts the error type (E) from a Layer type.
When to use
Use to derive a layer construction error type for helper types, wrappers, or
APIs that preserve a layer failure channel.
Error<function (type parameter) Serves in ipcServer<const Serves extends ServerServeList>(serves: Serves, options: IpcServerOptions): Layer.Layer<Layer.Success<Serves[number]>, Layer.Error<Serves[number]>, Layer.Services<Serves[number]>>Serves[number]>,
import LayerLayer.type Services<T extends Layer.Any> =
T extends infer L
? L extends Layer.Layer<
infer _ROut,
infer _E,
infer _RIn
>
? _RIn
: never
: never
Extracts the service requirements (RIn) from a Layer type.
When to use
Use to derive the dependency requirements of a generic or inferred Layer
without restating its RIn type parameter.
Services<function (type parameter) Serves in ipcServer<const Serves extends ServerServeList>(serves: Serves, options: IpcServerOptions): Layer.Layer<Layer.Success<Serves[number]>, Layer.Error<Serves[number]>, Layer.Services<Serves[number]>>Serves[number]>
>;
export function function ipcServer<A, E, R>(serve: Layer.Layer<A, E, R>, options: IpcServerOptions): Layer.Layer<A, E, R> (+1 overload)A Unix-domain RPC server — same-machine sibling of
httpServer
/
wsServer
.
Speaks Effect's raw socket RPC protocol (RpcServer.layerProtocolSocketServer) over a
filesystem path — no HTTP, no WebSocket upgrade. Clients connect with
connectIpc
or a node whose
ProtocolKind
is "IpcSocket" (Tag()("x", { path })).
class Worker extends Tag<Worker>()("worker", { path: "/tmp/worker.sock" }) {}
const live = Hyperlink.ipcServer(
[Hyperlink.serve(Jobs, jobsImpl)],
{ path: "/tmp/worker.sock" },
)
// or Node.unix(Worker, [Hyperlink.serve(Jobs, jobsImpl)])
Auto-mounts node status/logs/ping like the http/ws servers. There is no /health HTTP route
(no HTTP listener) — probe readiness via the node-handle status RPC.
ipcServer(
serves: | Layer.Any
| readonly [Layer.Any, ...Layer.Any[]]
serves: type ServerServeLayer = Layer.AnyOne serve layer accepted by
httpServer
/
wsServer
/
ipcServer
.
ServerServeLayer | type ServerServeList = readonly [Layer.Any, ...Layer.Any[]]Non-empty serve list — open E/R so heterogeneous HyperService deps remain expressible.
ServerServeList,
options: IpcServerOptions(parameter) options: {
path: string;
serialization: Layer.Layer<RpcSerialization.RpcSerialization>;
node: string | { readonly key: string };
unlink: boolean;
advertiseNode: AnyNode & { readonly key: string };
onConflict: OnConflict;
assumeToken: string | Redacted.Redacted<string>;
onYield: Effect.Effect<boolean>;
}
options: IpcServerOptions,
): import LayerLayer.Any {
const const list: readonly [
Layer.Any,
...Layer.Any[]
]
const list: {
0: Layer.Any;
length: number;
toString: () => string;
toLocaleString: { (): string; (locales: string | string[], options?: Intl.NumberFormatOptions & Intl.DateTimeFormatOptions): string };
concat: { (...items: Array<ConcatArray<Layer.Any>>): Array<Layer.Any>; (...items: Array<Layer.Any | ConcatArray<Layer.Any>>): Array<Layer.Any> };
join: (separator?: string) => string;
slice: (start?: number, end?: number) => Array<Layer.Any>;
indexOf: (searchElement: Layer.Any, fromIndex?: number) => number;
lastIndexOf: (searchElement: Layer.Any, fromIndex?: number) => number;
every: { (predicate: (value: Layer.Any, index: number, array: ReadonlyArray<Layer.Any>) => value is S, thisArg?: any): this is readonly S[]; (predicate: (value: Layer.Any, index: number, array: ReadonlyArray<Layer.Any>) => unknown, thisArg?: any)…;
some: (predicate: (value: Layer.Any, index: number, array: ReadonlyArray<Layer.Any>) => unknown, thisArg?: any) => boolean;
forEach: (callbackfn: (value: Layer.Any, index: number, array: ReadonlyArray<Layer.Any>) => void, thisArg?: any) => void;
map: (callbackfn: (value: Layer.Any, index: number, array: ReadonlyArray<Layer.Any>) => U, thisArg?: any) => Array<U>;
filter: { (predicate: (value: Layer.Any, index: number, array: ReadonlyArray<Layer.Any>) => value is S, thisArg?: any): Array<S>; (predicate: (value: Layer.Any, index: number, array: ReadonlyArray<Layer.Any>) => unknown, thisArg?: any): Array<Laye…;
reduce: { (callbackfn: (previousValue: Layer.Any, currentValue: Layer.Any, currentIndex: number, array: ReadonlyArray<Layer.Any>) => Layer.Any): Layer.Any; (callbackfn: (previousValue: Layer.Any, currentValue: Layer.Any, currentIndex: number, arra…;
reduceRight: { (callbackfn: (previousValue: Layer.Any, currentValue: Layer.Any, currentIndex: number, array: ReadonlyArray<Layer.Any>) => Layer.Any): Layer.Any; (callbackfn: (previousValue: Layer.Any, currentValue: Layer.Any, currentIndex: number, arra…;
find: { (predicate: (value: Layer.Any, index: number, obj: ReadonlyArray<Layer.Any>) => value is S, thisArg?: any): S | undefined; (predicate: (value: Layer.Any, index: number, obj: ReadonlyArray<Layer.Any>) => unknown, thisArg?: any): Layer.Any…;
findIndex: (predicate: (value: Layer.Any, index: number, obj: ReadonlyArray<Layer.Any>) => unknown, thisArg?: any) => number;
entries: () => ArrayIterator<[number, Layer.Any]>;
keys: () => ArrayIterator<number>;
values: () => ArrayIterator<Layer.Any>;
includes: (searchElement: Layer.Any, fromIndex?: number) => boolean;
flatMap: (callback: (this: This, value: Layer.Any, index: number, array: Array<Layer.Any>) => U | ReadonlyArray<U>, thisArg?: This | undefined) => Array<U>;
flat: (this: A, depth?: D | undefined) => Array<FlatArray<A, D>>;
at: (index: number) => Layer.Any | undefined;
findLast: { (predicate: (value: Layer.Any, index: number, array: ReadonlyArray<Layer.Any>) => value is S, thisArg?: any): S | undefined; (predicate: (value: Layer.Any, index: number, array: ReadonlyArray<Layer.Any>) => unknown, thisArg?: any): Layer…;
findLastIndex: (predicate: (value: Layer.Any, index: number, array: ReadonlyArray<Layer.Any>) => unknown, thisArg?: any) => number;
toReversed: () => Array<Layer.Any>;
toSorted: (compareFn?: ((a: Layer.Any, b: Layer.Any) => number) | undefined) => Array<Layer.Any>;
toSpliced: { (start: number, deleteCount: number, ...items: Array<Layer.Any>): Array<Layer.Any>; (start: number, deleteCount?: number): Array<Layer.Any> };
with: (index: number, value: Layer.Any) => Array<Layer.Any>;
}
list = function toServeList(serve: ServerServeLayer | ServerServeList): ServerServeListNormalize one serve layer or a list into
ServerServeList
.
toServeList(serves: | Layer.Any
| readonly [Layer.Any, ...Layer.Any[]]
serves);
return const ipcServerBase: (
options: IpcServerOptions
) => IpcServed
Registry → one RpcServer over a Unix-domain
SocketServer
.
ipcServerBase(options: IpcServerOptions(parameter) options: {
path: string;
serialization: Layer.Layer<RpcSerialization.RpcSerialization>;
node: string | { readonly key: string };
unlink: boolean;
advertiseNode: AnyNode & { readonly key: string };
onConflict: OnConflict;
assumeToken: string | Redacted.Redacted<string>;
onYield: Effect.Effect<boolean>;
}
options).Pipeable.pipe<IpcServed, Layer.Layer<never, never, Hyperlink.ServedHyperServices>, Layer.Layer<never, never, never>>(this: IpcServed, ab: (_: IpcServed) => Layer.Layer<never, never, Hyperlink.ServedHyperServices>, bc: (_: Layer.Layer<never, never, Hyperlink.ServedHyperServices>) => Layer.Layer<never, never, never>): Layer.Layer<never, never, never> (+21 overloads)pipe(
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(function closedLayer(layer: Layer.Any): Layer.Layer<never, never, never>Erase a
Layer.Any
to closed channels for internal composition (overload-impl pattern).
Prefer
retype
on factories when the source expression itself carries any/unknown
channels — those still fire if passed through here.
closedLayer(mergeServeList<Layers extends ServerServeList>(layers: Layers): Layer.Layer<Layer.Success<Layers[number]>, Layer.Error<Layers[number]>, Layer.Services<Layers[number]>>Merge a non-empty serve list — Effect
Layer.mergeAll
, preserving inferred channels at
call sites via the generic overload. Implementation retypes mergeAll to return
Layer.Any
so Effect's any-bounded signature never appears at this call site.
mergeServeList(const list: readonly [
Layer.Any,
...Layer.Any[]
]
const list: {
0: Layer.Any;
length: number;
toString: () => string;
toLocaleString: { (): string; (locales: string | string[], options?: Intl.NumberFormatOptions & Intl.DateTimeFormatOptions): string };
concat: { (...items: Array<ConcatArray<Layer.Any>>): Array<Layer.Any>; (...items: Array<Layer.Any | ConcatArray<Layer.Any>>): Array<Layer.Any> };
join: (separator?: string) => string;
slice: (start?: number, end?: number) => Array<Layer.Any>;
indexOf: (searchElement: Layer.Any, fromIndex?: number) => number;
lastIndexOf: (searchElement: Layer.Any, fromIndex?: number) => number;
every: { (predicate: (value: Layer.Any, index: number, array: ReadonlyArray<Layer.Any>) => value is S, thisArg?: any): this is readonly S[]; (predicate: (value: Layer.Any, index: number, array: ReadonlyArray<Layer.Any>) => unknown, thisArg?: any)…;
some: (predicate: (value: Layer.Any, index: number, array: ReadonlyArray<Layer.Any>) => unknown, thisArg?: any) => boolean;
forEach: (callbackfn: (value: Layer.Any, index: number, array: ReadonlyArray<Layer.Any>) => void, thisArg?: any) => void;
map: (callbackfn: (value: Layer.Any, index: number, array: ReadonlyArray<Layer.Any>) => U, thisArg?: any) => Array<U>;
filter: { (predicate: (value: Layer.Any, index: number, array: ReadonlyArray<Layer.Any>) => value is S, thisArg?: any): Array<S>; (predicate: (value: Layer.Any, index: number, array: ReadonlyArray<Layer.Any>) => unknown, thisArg?: any): Array<Laye…;
reduce: { (callbackfn: (previousValue: Layer.Any, currentValue: Layer.Any, currentIndex: number, array: ReadonlyArray<Layer.Any>) => Layer.Any): Layer.Any; (callbackfn: (previousValue: Layer.Any, currentValue: Layer.Any, currentIndex: number, arra…;
reduceRight: { (callbackfn: (previousValue: Layer.Any, currentValue: Layer.Any, currentIndex: number, array: ReadonlyArray<Layer.Any>) => Layer.Any): Layer.Any; (callbackfn: (previousValue: Layer.Any, currentValue: Layer.Any, currentIndex: number, arra…;
find: { (predicate: (value: Layer.Any, index: number, obj: ReadonlyArray<Layer.Any>) => value is S, thisArg?: any): S | undefined; (predicate: (value: Layer.Any, index: number, obj: ReadonlyArray<Layer.Any>) => unknown, thisArg?: any): Layer.Any…;
findIndex: (predicate: (value: Layer.Any, index: number, obj: ReadonlyArray<Layer.Any>) => unknown, thisArg?: any) => number;
entries: () => ArrayIterator<[number, Layer.Any]>;
keys: () => ArrayIterator<number>;
values: () => ArrayIterator<Layer.Any>;
includes: (searchElement: Layer.Any, fromIndex?: number) => boolean;
flatMap: (callback: (this: This, value: Layer.Any, index: number, array: Array<Layer.Any>) => U | ReadonlyArray<U>, thisArg?: This | undefined) => Array<U>;
flat: (this: A, depth?: D | undefined) => Array<FlatArray<A, D>>;
at: (index: number) => Layer.Any | undefined;
findLast: { (predicate: (value: Layer.Any, index: number, array: ReadonlyArray<Layer.Any>) => value is S, thisArg?: any): S | undefined; (predicate: (value: Layer.Any, index: number, array: ReadonlyArray<Layer.Any>) => unknown, thisArg?: any): Layer…;
findLastIndex: (predicate: (value: Layer.Any, index: number, array: ReadonlyArray<Layer.Any>) => unknown, thisArg?: any) => number;
toReversed: () => Array<Layer.Any>;
toSorted: (compareFn?: ((a: Layer.Any, b: Layer.Any) => number) | undefined) => Array<Layer.Any>;
toSpliced: { (start: number, deleteCount: number, ...items: Array<Layer.Any>): Array<Layer.Any>; (start: number, deleteCount?: number): Array<Layer.Any> };
with: (index: number, value: Layer.Any) => Array<Layer.Any>;
}
list))),
// Fresh registry per server — Lookup + Worker in one process must not share.
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 LayerLayer.const fresh: <A, E, R>(
self: Layer<A, E, R>
) => Layer<A, E, R>
Creates a fresh version of this layer that will not be shared.
When to use
Use when you need two parts of an application to receive separate instances
of a resource, such as two independent client sessions.
Gotchas
Do not use it just to work around confusing composition. By default, sharing
the same layer value is usually the desired behavior.
Example (Creating non-shared layer instances)
import { Context, Effect, Layer, Ref } from "effect"
class Counter extends Context.Service<Counter, {
readonly id: number
}>()("Counter") {}
class Left extends Context.Service<Left, {
readonly counterId: number
}>()("Left") {}
class Right extends Context.Service<Right, {
readonly counterId: number
}>()("Right") {}
const leftLayer = Layer.effect(Left, Effect.gen(function*() {
const counter = yield* Counter
return { counterId: counter.id }
}))
const rightLayer = Layer.effect(Right, Effect.gen(function*() {
const counter = yield* Counter
return { counterId: counter.id }
}))
const showIds = Effect.gen(function*() {
const left = yield* Left
const right = yield* Right
console.log(`same Counter: ${left.counterId === right.counterId}`)
})
const program = Effect.gen(function*() {
const nextId = yield* Ref.make(0)
const counterLayer = Layer.effect(Counter, Effect.gen(function*() {
const id = yield* Ref.updateAndGet(nextId, (n) => n + 1)
console.log("constructed Counter")
return { id }
}))
const shared = Layer.merge(
Layer.provide(leftLayer, counterLayer),
Layer.provide(rightLayer, counterLayer)
)
yield* Effect.provide(showIds, shared)
const freshCounterLayer = Layer.fresh(counterLayer)
const fresh = Layer.merge(
Layer.provide(leftLayer, freshCounterLayer),
Layer.provide(rightLayer, freshCounterLayer)
)
yield* Effect.provide(showIds, fresh)
})
Effect.runPromise(program)
// constructed Counter
// same Counter: true
// constructed Counter
// constructed Counter
// same Counter: false
fresh(import HyperlinkHyperlink.const servedHyperServicesLayer: Layer.Layer<ServedHyperServices>const servedHyperServicesLayer: {
build: (memoMap: MemoMap, scope: Scope.Scope) => Effect<Context.Context<ServedHyperServices>, 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; <…;
}
A fresh
ServedHyperServices
registry.
httpServer
/
ipcServer
/
wsServer
each provide
Layer.fresh
of this so two servers in one
process (e.g. Lookup + a Worker) do not share registrations via Layer memoization.
Provide this standalone only to collect serve registrations without a server.
servedHyperServicesLayer)),
);
}