Baked-in default store layer: provides Storage from a process-local in-memory
EventJournal. Materializes any scope on demand so withDefault never fails when this
layer is in context. Toolkit layers soft-merge this via withDefaultStorage; apps
override by providing a Service (Layer.provide / provideMerge) so Soft unwrap sees
ambient Storage before the default.
export const const layerDefaultMemory: Layer.Layer<Storage>const layerDefaultMemory: {
build: (memoMap: Layer.MemoMap, scope: Scope.Scope) => Effect.Effect<Context.Context<Storage>, 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; <…;
}
Baked-in default store layer: provides
Storage
from a process-local in-memory
EventJournal. Materializes any scope on demand so
withDefault
never fails when this
layer is in context. Toolkit layers soft-merge this via
withDefaultStorage
; apps
override by providing a
Service
(Layer.provide / provideMerge) so Soft unwrap sees
ambient
Storage
before the default.
layerDefaultMemory: 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 Storageclass Storage {
Service: Service;
key: Identifier;
}
Scope bridge every store handle resolves through — provided by an app
Service
layer or
the soft-default
layerDefaultMemory
(via
withDefaultStorage
). Engines resolve
handles via
withDefault
/
withStorage
(preferred) or bridge.at.
Storage> = import LayerLayer.const unwrap: <Storage, never, never, never, EventJournal.EventJournal>(self: Effect.Effect<Layer.Layer<Storage, never, never>, never, EventJournal.EventJournal>) => Layer.Layer<Storage, never, EventJournal.EventJournal>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: <{
readonly entries: Effect.Effect<ReadonlyArray<EventJournal.Entry>, EventJournal.EventJournalError>;
readonly write: <A, E, R>(options: {
readonly event: string;
readonly primaryKey: string;
readonly payload: Uint8Array;
readonly effect: (entry: EventJournal.Entry) => Effect.Effect<A, E, R>;
}) => Effect.Effect<A, EventJournal.EventJournalError | E, R>;
readonly writeFromRemote: (options: {
readonly remoteId: EventJournal.RemoteId;
readonly entries: ReadonlyArray<EventJournal.RemoteEntry>;
readonly compact?: ((uncommitted: ReadonlyArray<EventJournal.RemoteEntry>) => Effect.Effect<ReadonlyArray<EventJournal.Entry>, EventJournal.EventJournalError>) | undefined;
readonly effect: (options: {
readonly entry: EventJournal.Entry;
readonly conflicts: ReadonlyArray<EventJournal.Entry>;
}) => Effect.Effect<void, EventJournal.EventJournalError>;
}) => Effect.Effect<{
readonly duplicateEntries: ReadonlyArray<EventJournal.Entry>;
}, EventJournal.EventJournalError>;
... 4 more ...;
readonly withLock: (storeId: StoreId) => <A, E, R>(effect: Effect.Effect<A, E, R>) => Effect.Effect<A, E, R>;
}, never, EventJournal.EventJournal, Layer.Layer<...>>(self: Effect.Effect<...>, f: (a: {
readonly entries: Effect.Effect<ReadonlyArray<EventJournal.Entry>, EventJournal.EventJournalError>;
readonly write: <A, E, R>(options: {
readonly event: string;
readonly primaryKey: string;
readonly payload: Uint8Array;
readonly effect: (entry: EventJournal.Entry) => Effect.Effect<A, E, R>;
}) => Effect.Effect<A, EventJournal.EventJournalError | E, R>;
readonly writeFromRemote: (options: {
readonly remoteId: EventJournal.RemoteId;
readonly entries: ReadonlyArray<EventJournal.RemoteEntry>;
readonly compact?: ((uncommitted: ReadonlyArray<EventJournal.RemoteEntry>) => Effect.Effect<ReadonlyArray<EventJournal.Entry>, EventJournal.EventJournalError>) | undefined;
readonly effect: (options: {
readonly entry: EventJournal.Entry;
readonly conflicts: ReadonlyArray<EventJournal.Entry>;
}) => Effect.Effect<void, EventJournal.EventJournalError>;
}) => Effect.Effect<{
readonly duplicateEntries: ReadonlyArray<EventJournal.Entry>;
}, EventJournal.EventJournalError>;
... 4 more ...;
readonly withLock: (storeId: StoreId) => <A, E, R>(effect: Effect.Effect<A, E, R>) => Effect.Effect<A, E, R>;
}) => Layer.Layer<...>) => Effect.Effect<...> (+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(import EventJournalEventJournal.class EventJournalclass EventJournal {
key: Identifier;
Service: {
entries: Effect.Effect<ReadonlyArray<Entry>, EventJournalError>;
write: <A, E, R>(options: { readonly event: string; readonly primaryKey: string; readonly payload: Uint8Array; readonly effect: (entry: Entry) => Effect.Effect<A, E, R> }) => Effect.Effect<A, EventJournalError | E, R>;
writeFromRemote: (options: { readonly remoteId: RemoteId; readonly entries: ReadonlyArray<RemoteEntry>; readonly compact?: ((uncommitted: ReadonlyArray<RemoteEntry>) => Effect.Effect<ReadonlyArray<Entry>, EventJournalError>) | undefined; readonly effect: (…;
withRemoteUncommited: <A, E, R>(remoteId: RemoteId, f: (entries: ReadonlyArray<Entry>) => Effect.Effect<A, E, R>) => Effect.Effect<A, EventJournalError | E, R>;
nextRemoteSequence: (remoteId: RemoteId) => Effect.Effect<number, EventJournalError>;
changes: Effect.Effect<PubSub.Subscription<Entry>, never, Scope>;
destroy: Effect.Effect<void, EventJournalError>;
withLock: (storeId: StoreId) => <A, E, R>(effect: Effect.Effect<A, E, R>) => Effect.Effect<A, E, R>;
};
of: (this: void, self: { readonly entries: Effect.Effect<ReadonlyArray<EventJournal.Entry>, EventJournal.EventJournalError>; readonly write: <A, E, R>(options: { readonly event: string; readonly primaryKey: string; readonly payload: Uint8Array…;
context: (self: { readonly entries: Effect.Effect<ReadonlyArray<EventJournal.Entry>, EventJournal.EventJournalError>; readonly write: <A, E, R>(options: { readonly event: string; readonly primaryKey: string; readonly payload: Uint8Array; readonly e…;
use: (f: (service: { readonly entries: Effect.Effect<ReadonlyArray<EventJournal.Entry>, EventJournal.EventJournalError>; readonly write: <A, E, R>(options: { readonly event: string; readonly primaryKey: string; readonly payload: Uint8Array; rea…;
useSync: (f: (service: { readonly entries: Effect.Effect<ReadonlyArray<EventJournal.Entry>, EventJournal.EventJournalError>; readonly write: <A, E, R>(options: { readonly event: string; readonly primaryKey: string; readonly payload: Uint8Array; rea…;
Identifier: Identifier;
stack: string | undefined;
pipe: { <A>(this: A): A; <A, B = never>(this: A, ab: (_: A) => B): B; <A, B = never, C = never>(this: A, ab: (_: A) => B, bc: (_: B) => C): C; <A, B = never, C = never, D = never>(this: A, ab: (_: A) => B, bc: (_: B) => C, cd: (_: C) => D): D; <…;
toString: () => string;
toJSON: () => unknown;
}
Context service for storing and replaying event journal entries.
Details
The service writes local entries, imports entries from remote journals, exposes
a stream of local changes, and provides per-store locking.
EventJournal, (journal: {
readonly entries: Effect.Effect<ReadonlyArray<EventJournal.Entry>, EventJournal.EventJournalError>;
readonly write: <A, E, R>(options: {
readonly event: string;
readonly primaryKey: string;
readonly payload: Uint8Array;
readonly effect: (entry: EventJournal.Entry) => Effect.Effect<A, E, R>;
}) => Effect.Effect<A, EventJournal.EventJournalError | E, R>;
readonly writeFromRemote: (options: {
readonly remoteId: EventJournal.RemoteId;
readonly entries: ReadonlyArray<EventJournal.RemoteEntry>;
readonly compact?: ((uncommitted: ReadonlyArray<EventJournal.RemoteEntry>) => Effect.Effect<ReadonlyArray<EventJournal.Entry>, EventJournal.EventJournalError>) | undefined;
readonly effect: (options: {
readonly entry: EventJournal.Entry;
readonly conflicts: ReadonlyArray<EventJournal.Entry>;
}) => Effect.Effect<void, EventJournal.EventJournalError>;
}) => Effect.Effect<{
readonly duplicateEntries: ReadonlyArray<EventJournal.Entry>;
}, EventJournal.EventJournalError>;
... 4 more ...;
readonly withLock: (storeId: StoreId) => <A, E, R>(effect: Effect.Effect<A, E, R>) => Effect.Effect<A, E, R>;
}
journal) =>
import LayerLayer.const succeed: <Storage, StorageApi>(service: Context.Key<Storage, StorageApi>, resource: StorageApi) => Layer.Layer<Storage, never, never> (+1 overload)Constructs a layer that provides a single service from an already available
value.
When to use
Use when you need a Layer that provides a service from an already
constructed implementation without effectful acquisition.
Example (Creating a layer from a service implementation)
import { Context, Effect, Layer } from "effect"
class Database extends Context.Service<Database, {
readonly query: (sql: string) => Effect.Effect<string>
}>()("Database") {}
const DatabaseLive = Layer.succeed(Database, {
query: Effect.fn("Database.query")((sql: string) => Effect.succeed(`Query result: ${sql}`))
})
succeed(class Storageclass Storage {
key: Identifier;
of: (this: void, self: StorageApi) => StorageApi;
context: (self: StorageApi) => Context.Context<Storage>;
use: (f: (service: StorageApi) => Effect.Effect<A, E, R>) => Effect.Effect<A, E, Storage | R>;
useSync: (f: (service: StorageApi) => A) => Effect.Effect<A, never, Storage>;
Identifier: Identifier;
Service: Shape;
stack: string | undefined;
pipe: { <A>(this: A): A; <A, B = never>(this: A, ab: (_: A) => B): B; <A, B = never, C = never>(this: A, ab: (_: A) => B, bc: (_: B) => C): C; <A, B = never, C = never, D = never>(this: A, ab: (_: A) => B, bc: (_: B) => C, cd: (_: C) => D): D; <…;
toString: () => string;
toJSON: () => unknown;
}
Scope bridge every store handle resolves through — provided by an app
Service
layer or
the soft-default
layerDefaultMemory
(via
withDefaultStorage
). Engines resolve
handles via
withDefault
/
withStorage
(preferred) or bridge.at.
Storage, import buildDefaultScopeBridgebuildDefaultScopeBridge(journal: {
readonly entries: Effect.Effect<ReadonlyArray<EventJournal.Entry>, EventJournal.EventJournalError>;
readonly write: <A, E, R>(options: {
readonly event: string;
readonly primaryKey: string;
readonly payload: Uint8Array;
readonly effect: (entry: EventJournal.Entry) => Effect.Effect<A, E, R>;
}) => Effect.Effect<A, EventJournal.EventJournalError | E, R>;
readonly writeFromRemote: (options: {
readonly remoteId: EventJournal.RemoteId;
readonly entries: ReadonlyArray<EventJournal.RemoteEntry>;
readonly compact?: ((uncommitted: ReadonlyArray<EventJournal.RemoteEntry>) => Effect.Effect<ReadonlyArray<EventJournal.Entry>, EventJournal.EventJournalError>) | undefined;
readonly effect: (options: {
readonly entry: EventJournal.Entry;
readonly conflicts: ReadonlyArray<EventJournal.Entry>;
}) => Effect.Effect<void, EventJournal.EventJournalError>;
}) => Effect.Effect<{
readonly duplicateEntries: ReadonlyArray<EventJournal.Entry>;
}, EventJournal.EventJournalError>;
... 4 more ...;
readonly withLock: (storeId: StoreId) => <A, E, R>(effect: Effect.Effect<A, E, R>) => Effect.Effect<A, E, R>;
}
journal)),
),
).Pipeable.pipe<Layer.Layer<Storage, never, EventJournal.EventJournal>, Layer.Layer<Storage, never, never>>(this: Layer.Layer<Storage, never, EventJournal.EventJournal>, ab: (_: Layer.Layer<Storage, never, EventJournal.EventJournal>) => Layer.Layer<Storage, never, never>): Layer.Layer<Storage, never, never> (+21 overloads)pipe(import LayerLayer.const provide: <never, never, EventJournal.EventJournal>(that: Layer.Layer<EventJournal.EventJournal, never, never>) => <RIn2, E2, ROut2>(self: Layer.Layer<ROut2, E2, RIn2>) => Layer.Layer<ROut2, E2, Exclude<RIn2, EventJournal.EventJournal>> (+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 EventJournalEventJournal.const layerMemory: Layer.Layer<
EventJournal.EventJournal,
never,
never
>
const layerMemory: {
build: (memoMap: Layer.MemoMap, scope: Scope.Scope) => Effect.Effect<Context.Context<EventJournal.EventJournal>, 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 an in-memory EventJournal.
Gotchas
All journal data is stored in process memory and is not persisted across layer
lifetimes.
layerMemory));