Storage
PostgreSQL
Connect PostgreSQL storage to your agent using your application’s native Effect SQL client:
import { import PostgresStorage
PostgresStorage } from "@yielded/agent-storage-postgres";import { import NodeCrypto
NodeCrypto } from "@effect/platform-node";import { import PgClient
PgClient } from "@effect/sql-pg";import { import Config
Config, import Effect
Effect, import Layer
Layer } from "effect";import { import AgentRuntime
AgentRuntime, import PersistentHistory
PersistentHistory } from "@yielded/agent";
const const Database: Layer.Layer<PgClient.PgClient | SqlClient, Config.ConfigError | SqlError, never>
Database = import PgClient
PgClient.const layerConfig: (config: Config.Wrap<PgClient.PgPoolConfig>) => Layer.Layer<PgClient.PgClient | SqlClient, Config.ConfigError | SqlError>
Creates a client layer from wrapped pool configuration.
layerConfig({ url?: { readonly label: Config.Config<string | undefined>; readonly "~effect/Redacted": { readonly _A: Config.Config<Covariant<string>>; } | Config.Config<{ readonly _A: Covariant<string>; }>; readonly "~effect/Equal": Config.Config<(that: Equal) => boolean>; readonly "~effect/Hash": Config.Config<() => number>; readonly pipe: Config.Config<{ <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, B = never, C = never, D = never, E = never>(this: A, ab: (_: A) => B, bc: (_: B) => C, cd: (_: C) => D, de: (_: D) => E): E; <A, B = never, C = never, D = never, E = never, F = never>(this: A, ab: (_: A) => B, bc: (_: B) => C, cd: (_: C) => D, de: (_: D) => E, ef: (_: E) => F): F; <A, B = never, C = never, D = never, E = never, F = never, G = never>(this: A, ab: (_: A) => B, bc: (_: B) => C, cd: (_: C) => D, de: (_: D) => E, ef: (_: E) => F, fg: (_: F) => G): G; <A, B = never, C = never, D = never, E = never, F = never, G = never, H = never>(this: A, ab: (_: A) => B, bc: (_: B) => C, cd: (_: C) => D, de: (_: D) => E, ef: (_: E) => F, fg: (_: F) => G, gh: (_: G) => H): H; <A, B = never, C = never, D = never, E = never, F = never, G = never, H = never, I = never>(this: A, ab: (_: A) => B, bc: (_: B) => C, cd: (_: C) => D, de: (_: D) => E, ef: (_: E) => F, fg: (_: F) => G, gh: (_: G) => H, hi: (_: H) => I): I; <A, B = never, C = never, D = never, E = never, F = never, G = never, H = never, I = never, J = never>(this: A, ab: (_: A) => B, bc: (_: B) => C, cd: (_: C) => D, de: (_: D) => E, ef: (_: E) => F, fg: (_: F) => G, gh: (_: G) => H, hi: (_: H) => I, ij: (_: I) => J): J; <A, B = never, C = never, D = never, E = never, F = never, G = never, H = never, I = never, J = never, K = never>(this: A, ab: (_: A) => B, bc: (_: B) => C, cd: (_: C) => D, de: (_: D) => E, ef: (_: E) => F, fg: (_: F) => G, gh: (_: G) => H, hi: (_: H) => I, ij: (_: I) => J, jk: (_: J) => K): K; <A, B = never, C = never, D = never, E = never, F = never, G = never, H = never, I = never, J = never, K = never, L = never>(this: A, ab: (_: A) => B, bc: (_: B) => C, cd: (_: C) => D, de: (_: D) => E, ef: (_: E) => F, fg: (_: F) => G, gh: (_: G) => H, hi: (_: H) => I, ij: (_: I) => J, jk: (_: J) => K, kl: (_: K) => L): L; <A, B = never, C = never, D = never, E = never, F = never, G = never, H = never, I = never, J = never, K = never, L = never, M = never>(this: A, ab: (_: A) => B, bc: (_: B) => C, cd: (_: C) => D, de: (_: D) => E, ef: (_: E) => F, fg: (_: F) => G, gh: (_: G) => H, hi: (_: H) => I, ij: (_: I) => J, jk: (_: J) => K, kl: (_: K) => L, lm: (_: L) => M): M; <A, B = never, C = never, D = never, E = never, F = never, G = never, H = never, I = never, J = never, K = never, L = never, M = never, N = never>(this: A, ab: (_: A) => B, bc: (_: B) => C, cd: (_: C) => D, de: (_: D) => E, ef: (_: E) => F, fg: (_: F) => G, gh: (_: G) => H, hi: (_: H) => I, ij: (_: I) => J, jk: (_: J) => K, kl: (_: K) => L, lm: (_: L) => M, mn: (_: M) => N): N; <A, B = never, C = never, D = never, E = never, F = never, G = never, H = never, I = never, J = never, K = never, L = never, M = never, N = never, O = never>(this: A, ab: (_: A) => B, bc: (_: B) => C, cd: (_: C) => D, de: (_: D) => E, ef: (_: E) => F, fg: (_: F) => G, gh: (_: G) => H, hi: (_: H) => I, ij: (_: I) => J, jk: (_: J) => K, kl: (_: K) => L, lm: (_: L) => M, mn: (_: M) => N, no: (_: N) => O): O; <A, B = never, C = never, D = never, E = never, F = never, G = never, H = never, I = never, J = never, K = never, L = never, M = never, N = never, O = never, P = never>(this: A, ab: (_: A) => B, bc: (_: B) => C, cd: (_: C) => D, de: (_: D) => E, ef: (_: E) => F, fg: (_: F) => G, gh: (_: G) => H, hi: (_: H) => I, ij: (_: I) => J, jk: (_: J) => K, kl: (_: K) => L, lm: (_: L) => M, mn: (_: M) => N, no: (_: N) => O, op: (_: O) => P): P; <A, B = never, C = never, D = never, E = never, F = never, G = never, H = never, I = never, J = never, K = never, L = never, M = never, N = never, O = never, P = never, Q = never>(this: A, ab: (_: A) => B, bc: (_: B) => C, cd: (_: C) => D, de: (_: D) => E, ef: (_: E) => F, fg: (_: F) => G, gh: (_: G) => H, hi: (_: H) => I, ij: (_: I) => J, jk: (_: J) => K, kl: (_: K) => L, lm: (_: L) => M, mn: (_: M) => N, no: (_: N) => O, op: (_: O) => P, pq: (_: P) => Q): Q; <A, B = never, C = never, D = never, E = never, F = never, G = never, H = never, I = never, J = never, K = never, L = never, M = never, N = never, O = never, P = never, Q = never, R = never>(this: A, ab: (_: A) => B, bc: (_: B) => C, cd: (_: C) => D, de: (_: D) => E, ef: (_: E) => F, fg: (_: F) => G, gh: (_: G) => H, hi: (_: H) => I, ij: (_: I) => J, jk: (_: J) => K, kl: (_: ...
url: import Config
Config.function Redacted(name?: string): Config.Config<import("effect/Redacted").Redacted<string>>
Creates a config for a redacted string value. The parsed result is wrapped
in a Redacted container that hides the value from logs and toString.
When to use
Use to read secret string settings that should not be exposed in logs or
string output.
Details
Shortcut for Config.schema(Schema.Redacted(Schema.String), name).
Example (Reading a secret)
import { Config, ConfigProvider, Effect } from "effect"
const program = Config.Redacted("API_KEY").pipe(Effect.map(String))
const provider = ConfigProvider.fromEnv({ env: { API_KEY: "sk-1234567890abcdef" }})
Effect.runSync( program.pipe(Effect.provideService(ConfigProvider.ConfigProvider, provider))) // => "<redacted>"
Redacted("DATABASE_URL"),});
const const Persistence: Layer.Layer<PgClient.PgClient | SqlClient | ThreadReader | ThreadStore | ThreadImport | SubmissionLedger | SettlementPublisher, Config.ConfigError | SqlError | PostgresStorageError | PostgresStorageCompatibilityError | PostgresStorageCorruptionError | PostgresWriteContention, never>
Persistence = import PostgresStorage
PostgresStorage.const layer: Layer.Layer<ThreadReader | ThreadStore | ThreadImport | SubmissionLedger | SettlementPublisher, PostgresStorageError | PostgresStorageCompatibilityError | PostgresStorageCorruptionError | PostgresWriteContention, SqlClient | Crypto>
Thread history and submissions with default settings. Requires SqlClient and Crypto.
layer.Pipeable.pipe<Layer.Layer<ThreadReader | ThreadStore | ThreadImport | SubmissionLedger | SettlementPublisher, PostgresStorageError | PostgresStorageCompatibilityError | PostgresStorageCorruptionError | PostgresWriteContention, SqlClient | Crypto>, Layer.Layer<PgClient.PgClient | SqlClient | ... 4 more ... | SettlementPublisher, Config.ConfigError | ... 4 more ... | PostgresWriteContention, Crypto>, Layer.Layer<...>>(this: Layer.Layer<...>, ab: (_: Layer.Layer<...>) => Layer.Layer<...>, bc: (_: Layer.Layer<...>) => Layer.Layer<...>): Layer.Layer<...> (+21 overloads)
pipe( import Layer
Layer.const provideMerge: <never, Config.ConfigError | SqlError, PgClient.PgClient | SqlClient>(that: Layer.Layer<PgClient.PgClient | SqlClient, Config.ConfigError | SqlError, never>) => <RIn2, E2, ROut2>(self: Layer.Layer<ROut2, E2, RIn2>) => Layer.Layer<PgClient.PgClient | SqlClient | ROut2, Config.ConfigError | SqlError | E2, Exclude<RIn2, PgClient.PgClient | SqlClient>> (+3 overloads)
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 layersconst databaseLayer = Layer.succeed(Database, { query: Effect.fn("Database.query")((sql: string) => Effect.succeed(`DB: ${sql}`))})
const logs: Array<string> = []const loggerLayer = Layer.succeed(Logger, { log: Effect.fn("Logger.log")((msg: string) => Effect.sync(() => logs.push(`[LOG] ${msg}`)))})
// UserService depends on Database and Loggerconst 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 togetherconst allServicesLayer = userServiceLayer.pipe( Layer.provideMerge(Layer.mergeAll(databaseLayer, loggerLayer)))
// Now the resulting layer provides UserService, Database, AND Loggerconst 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))Effect.runSync(program) // => { id: "123", name: "DB: SELECT * FROM users WHERE id = 123" }logs // => ["[LOG] Looking up user 123", "[LOG] Found user: DB: SELECT * FROM users WHERE id = 123"]
provideMerge(const Database: Layer.Layer<PgClient.PgClient | SqlClient, Config.ConfigError | SqlError, never>
Database), import Layer
Layer.const provide: <never, never, Crypto>(that: Layer.Layer<Crypto, never, never>) => <RIn2, E2, ROut2>(self: Layer.Layer<ROut2, E2, RIn2>) => Layer.Layer<ROut2, E2, Exclude<RIn2, Crypto>> (+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 layersconst databaseLayer = Layer.succeed(Database, { query: Effect.fn("Database.query")((sql: string) => Effect.succeed(`DB: ${sql}`))})
const logs: Array<string> = []const loggerLayer = Layer.succeed(Logger, { log: Effect.fn("Logger.log")((msg: string) => Effect.sync(() => logs.push(`[LOG] ${msg}`)))})
// UserService depends on Database and Loggerconst 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 layerconst userServiceWithDependencies = userServiceLayer.pipe( Layer.provide(Layer.mergeAll(databaseLayer, loggerLayer)))
// Now UserService layer has no dependenciesconst program = Effect.gen(function*() { const userService = yield* UserService return yield* userService.getUser("123")}).pipe( Effect.provide(userServiceWithDependencies))Effect.runSync(program) // => { id: "123", name: "DB: SELECT * FROM users WHERE id = 123" }logs // => ["[LOG] Looking up user 123"]
provide(import NodeCrypto
NodeCrypto.const layer: Layer.Layer<Crypto, never, never>
Layer that provides the Node.js Crypto service implementation.
layer),);
const const History: Layer.Layer<PgClient.PgClient | SqlClient | ThreadReader | ThreadStore | ThreadImport | SubmissionLedger | SettlementPublisher | ThreadHistory, Config.ConfigError | SqlError | PostgresStorageError | PostgresStorageCompatibilityError | PostgresStorageCorruptionError | PostgresWriteContention, never>
History = import PersistentHistory
PersistentHistory.const layer: Layer.Layer<ThreadHistory, never, ThreadStore>
Provide retained history to the normal AgentRuntime entry points. Each successful Run appends
one three-record batch. Staging is private to that Run; interruption discards it. Epoch zero
and the loaded tail fence stale writers without replaying external execution. A storage failure
after append may leave the whole Run recorded. Adapter failpoints cover both durable mutations.
layer.Pipeable.pipe<Layer.Layer<ThreadHistory, never, ThreadStore>, Layer.Layer<PgClient.PgClient | SqlClient | ThreadReader | ThreadStore | ThreadImport | SubmissionLedger | SettlementPublisher | ThreadHistory, Config.ConfigError | SqlError | PostgresStorageError | PostgresStorageCompatibilityError | PostgresStorageCorruptionError | PostgresWriteContention, never>>(this: Layer.Layer<...>, ab: (_: Layer.Layer<...>) => Layer.Layer<...>): Layer.Layer<...> (+21 overloads)
pipe(import Layer
Layer.const provideMerge: <never, Config.ConfigError | SqlError | PostgresStorageError | PostgresStorageCompatibilityError | PostgresStorageCorruptionError | PostgresWriteContention, PgClient.PgClient | SqlClient | ThreadReader | ThreadStore | ThreadImport | SubmissionLedger | SettlementPublisher>(that: Layer.Layer<PgClient.PgClient | ... 5 more ... | SettlementPublisher, Config.ConfigError | ... 4 more ... | PostgresWriteContention, never>) => <RIn2, E2, ROut2>(self: Layer.Layer<...>) => Layer.Layer<...> (+3 overloads)
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 layersconst databaseLayer = Layer.succeed(Database, { query: Effect.fn("Database.query")((sql: string) => Effect.succeed(`DB: ${sql}`))})
const logs: Array<string> = []const loggerLayer = Layer.succeed(Logger, { log: Effect.fn("Logger.log")((msg: string) => Effect.sync(() => logs.push(`[LOG] ${msg}`)))})
// UserService depends on Database and Loggerconst 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 togetherconst allServicesLayer = userServiceLayer.pipe( Layer.provideMerge(Layer.mergeAll(databaseLayer, loggerLayer)))
// Now the resulting layer provides UserService, Database, AND Loggerconst 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))Effect.runSync(program) // => { id: "123", name: "DB: SELECT * FROM users WHERE id = 123" }logs // => ["[LOG] Looking up user 123", "[LOG] Found user: DB: SELECT * FROM users WHERE id = 123"]
provideMerge(const Persistence: Layer.Layer<PgClient.PgClient | SqlClient | ThreadReader | ThreadStore | ThreadImport | SubmissionLedger | SettlementPublisher, Config.ConfigError | SqlError | PostgresStorageError | PostgresStorageCompatibilityError | PostgresStorageCorruptionError | PostgresWriteContention, never>
Persistence));
const const program: Effect.Effect<{ readonly runId: string & Brand<"@effect-agent/core/RunId">; readonly threadId: string & Brand<"@effect-agent/core/ThreadId">; readonly output: { readonly itinerary: readonly string[]; }; readonly finishReason: "completed" | "budget-exhausted" | "model-stop"; readonly turns: number; readonly usage?: RunTotals | undefined; readonly runDisposition?: Json | undefined; readonly exhausted?: "tokens" | "tool-calls" | "turns" | undefined; readonly delegatedUsage?: RunTotals | undefined;}, Config.ConfigError | ... 5 more ... | AgentRuntime.AgentRuntimeFailure<...>, ModelServices>
program = import AgentRuntime
AgentRuntime.run<Definition<String, Struct<{ readonly itinerary: $Array<String>;}>, "Plan a trip with one itinerary entry per day.", Toolkit<{}>, undefined, undefined, undefined> & { readonly id: Brand<"@effect-agent/core/AgentId"> & "trip-planner";}, never, never>(agent: Definition<String, Struct<{ readonly itinerary: $Array<String>;}>, "Plan a trip with one itinerary entry per day.", Toolkit<{}>, undefined, undefined, undefined> & { readonly id: Brand<"@effect-agent/core/AgentId"> & "trip-planner";}, input: string, options?: RunOptions<...> | undefined): Effect.Effect<...>export run
Accept schema-encoded input, retaining runtime validation. Use runUnknown for external data.
run(const agent: Definition<String, Struct<{ readonly itinerary: $Array<String>;}>, "Plan a trip with one itinerary entry per day.", Toolkit<{}>, undefined, undefined, undefined> & { readonly id: Brand<"@effect-agent/core/AgentId"> & "trip-planner";}
agent, const input: string
input, { RunOptions<HookError = never, HookRequirements = never>.threadId?: (string & Brand<"@effect-agent/core/ThreadId">) | undefined
Reuse a Thread identity, including retained history, instead of allocating one.
threadId }).Pipeable.pipe<Effect.Effect<{ readonly runId: string & Brand<"@effect-agent/core/RunId">; readonly threadId: string & Brand<"@effect-agent/core/ThreadId">; readonly output: { readonly itinerary: readonly string[]; }; readonly finishReason: "completed" | "budget-exhausted" | "model-stop"; readonly turns: number; readonly usage?: RunTotals | undefined; readonly runDisposition?: Json | undefined; readonly exhausted?: "tokens" | "tool-calls" | "turns" | undefined; readonly delegatedUsage?: RunTotals | undefined;}, AgentRuntime.AgentRuntimeFailure<Definition<String, ... 5 more ..., undefined> & { ...;}, never, never>, AgentRuntime.AgentRuntimeRequirements<...>>, Effect.Effect<...>>(this: Effect.Effect<...>, ab: (_: Effect.Effect<...>) => Effect.Effect<...>): Effect.Effect<...> (+21 overloads)
pipe(import Effect
Effect.const provide: <PgClient.PgClient | SqlClient | ThreadReader | ThreadStore | ThreadImport | SubmissionLedger | SettlementPublisher | ThreadHistory, Config.ConfigError | SqlError | PostgresStorageError | PostgresStorageCompatibilityError | PostgresStorageCorruptionError | PostgresWriteContention, never>(layer: Layer.Layer<...>, options?: { readonly local?: boolean | undefined;} | undefined) => <A, E, R>(self: Effect.Effect<...>) => Effect.Effect<...> (+5 overloads)
Provides dependencies to an effect using layers or a context. Use options.local
to build the layer every time; by default, layers are shared between provide
calls.
Example (Providing dependencies with a layer)
import { Context, Effect, Layer } from "effect"
interface Database { readonly query: (sql: string) => Effect.Effect<string>}
const Database = Context.Service<Database>("Database")
const DatabaseLayer = Layer.succeed(Database)({ query: Effect.fn("Database.query")((sql: string) => Effect.succeed(`Result for: ${sql}`))})
const program = Effect.gen(function*() { const db = yield* Database return yield* db.query("SELECT * FROM users")})
const provided = Effect.provide(program, DatabaseLayer)
await Effect.runPromise(provided) // => "Result for: SELECT * FROM users"
provide(const History: Layer.Layer<PgClient.PgClient | SqlClient | ThreadReader | ThreadStore | ThreadImport | SubmissionLedger | SettlementPublisher | ThreadHistory, Config.ConfigError | SqlError | PostgresStorageError | PostgresStorageCompatibilityError | PostgresStorageCorruptionError | PostgresWriteContention, never>
History));Install and connect
Section titled “Install and connect”bun add @yielded/agent-storage-postgres@beta effectRequires PostgreSQL 16 or newer. Create the database and set DATABASE_URL to its connection URL.
Keep framework packages at one release and use compatible
Effect and model provider packages.
Here, agent, input, and threadId come from your application.
PostgresStorage.layer provides ThreadStore and SubmissionLedger;
PersistentHistory.layer connects the thread store to ordinary AgentRuntime calls.
History also exposes the same native SQL client for application queries.
Supply the agent’s model and tool Layers at your application boundary. For a server, provide
History once around the application or build one ManagedRuntime so requests share the pool.
Reuse the same thread ID to continue a conversation, including after a process restart.
What is retained
Section titled “What is retained”This setup commits each successful Run as one atomic batch. It does not recover interrupted execution. See retained history for commit and concurrency behavior, and persistence and durability for recovery.
Database ownership
Section titled “Database ownership”The adapter initializes its tables when the Layer opens. Credentials need permission to use
and initialize the selected schema. Tables default to public; use
PostgresStorage.layerWith({ schema: "agent" }) for another namespace. An existing schema avoids
the need for database-wide CREATE permission. Storage qualifies its tables without changing
the client’s search path, codecs, or application query transformations.
Call storage writes and snapshot reads outside sql.withTransaction: the adapter owns
its transactions and rejects nesting. It also rejects incompatible stored versions.
For individual stores, configuration, and error details, see the PostgreSQL package reference. For durable execution with PostgreSQL, supply these stores to a custom durable runtime and provide its recovery driver. The existing Node.js host owns SQLite storage.