EventStoreStore — EventStoreDB (Kurrent)
Read this page in the documentation
EventStoreStore — EventStoreDB (Kurrent) Overview EventStoreDB (recently rebranded Kurrent) is a purpose-built database for event sourcing: an append-only log of immutable events organized into streams, with catch-up and persistent subscriptions for reading them back. It has no SQL-shaped access pattern. Because none of that fits the SQL-shaped Dialect interface, EventStoreStore implements the minimal NoSqlStore marker interface (src/nosql/store.ts) — connection lifecycle plus a getClient() escape hatch — and exposes EventStoreDB's own operations (append, catch-up subscribe, read) directly rather than forcing them into a query(sql) shape. Identity: Property | Value | --------- | ----------------------- | name | 'eventstore' | library | '@eventstore/db-client'| The store is built on @eventstore/db-client: an EventStoreDBClient appends (appendToStream), subscribes (subscribeToStream), and reads (readStream); the module's jsonEvent(...) helper builds event payloads. There is no command-object pattern — the driver exposes methods directly. Lazy loading — not a hard dependency @eventstore/db-client is not a hard dependency of this package. The driver is loaded lazily via require() inside connect(), rather than a top-level import. Importing this module therefore does not require the driver to be installed — it is only needed when an EventStore store is actually connected. Injected client EventStoreStoreOptions accepts a pre-built client (an EventStoreDBClient or any object exposing the methods below, typed as EventStoreClientLike). When provided, connect() uses it directly (and best-effort-loads the module only for its jsonEvent helper). This is how the test suite injects a mock client (no driver, no network). Message encoding publish() accepts a string or Buffer (parsed as JSON when possible, otherwise wrapped as { value }) or any other value (used as the event data directly). Each event is written as a JSON event with a caller-supplied type (default 'message'), built via the driver's jsonEvent(...) when the module is loaded, or a plain JSON-event-shaped object as a fallback. Connection Build a store from connection options and call connect(): All connection options are optional: Option | Type | Purpose | ------------------ | ---------------------- | -------------------------------------------------------------------------------------------------------------------------- | connectionString | string | EventStoreDB connection string. Used to build the client via EventStoreDBClient.connectionString(...). Defaults to 'esdb://localhost:2113?tls=false'. | client | EventStoreClientLike | A pre-built client to use directly (mock or custom config). When set, the driver is not required. | Injected-client form Methods Driver failures are wrapped in a DatabaseError (preserving the original error); using a method before connect() (or after disconnect()) throws a ConnectionError. Lifecycle Method | Signature | Behavior | ------------- | ---------------------------------- | ---------------------------------------------------------------------------------------------------------------------------------------------------------- | connect | connect(): Promise<void> | Idempotent (returns early if already connected). Uses an injected client if provided, otherwise lazy-requires @eventstore/db-client and builds a client from the connection string. Wraps failures in ConnectionError. | disconnect | disconnect(): Promise<void> | Stops all tracked subscriptions, calls the client's optional dispose(), and clears state. | isConnected | isConnected(): boolean | true only when connected and a client is present. | getClient | getClient(): EventStoreClientLike| Returns the underlying EventStoreDBClient for operations not wrapped here. Throws ConnectionError if not connected. | Producing Method | Signature | Driver call | Behavior | --------- | --------------------------------------------------------------------------------------- | ----------------------- | --------------------------------------------------------------------------------------------------------------- | publish | publish(stream: string, message: EventStoreMessage, options?: AppendOptions): Promise<any> | client.appendToStream() | Builds a JSON event from message (type defaults to 'message') and appends it to stream. Passes { expectedRevision } only when supplied. Returns the driver's append result (next expected revision, etc.). | Stream administration Method | Signature | Behavior | -------------- | -------------------------------------------- | ---------------------------------------------------------------------------------------------------------------- | createStream | createStream(name: string): Promise<void> | Documented no-op. EventStoreDB creates streams implicitly on the first append, so this only checks the connection and resolves without contacting the server. | createTopic | createTopic(name: string): Promise<void> | Alias for createStream(), matching the common store surface. | Reading Method | Signature | Driver call | Behavior | ------------ | ----------------------------------------------------------- | --------------------- | --------------------------------------------------------------------------------------------------- | readStream | readStream(stream: string, options?: unknown): Promise<any[]> | client.readStream() | Drains the driver's async iterable into an array. options (fromRevision, maxCount, direction, ...) pass straight through. | Consuming Method | Signature | Driver call | Behavior | ----------- | ------------------------------------------------------------------------------------------------------------- | ------------------------------ | ---------------------------------------------------------------------------------------------------------------------------------------------------------------------------- | subscribe | subscribe(stream: string, handler: (event: any) => void \| Promise<void>, options?: EventStoreSubscribeOptions): Promise<EventStoreSubscription> | client.subscribeToStream() | Opens a catch-up subscription (default fromRevision: 'end') and iterates it, invoking handler per resolved event. Resolves once the subscription is opened; the consuming loop runs detached. Returns a subscription whose stop() unsubscribes the iterable and untracks it. | Example Verification status Unit / mock-verified only. The tests in tests/nosql/eventstore.test.ts are fully mock-driven: a fake EventStoreDBClient (with jest-spy appendToStream, subscribeToStream, readStream, dispose) is injected via EventStoreStoreOptions.client. The real @eventstore/db-client package is not installed, and there is no live EventStoreDB access and no network in the test run. Since the module isn't loaded, the store falls back to a plain JSON-event-shaped object for appends. What this proves: publish builds a JSON event: a JSON string message is parsed into data (with the supplied type), and an object message passes straight through as data (type defaults to 'message'). createStream / createTopic are no-ops that resolve without appending. readStream drains the async iterable into an array and passes options through. subscribe opens a catch-up subscription (default fromRevision: 'end'), forwards each event to the handler, and stop() unsubscribes the underlying iterable. Lifecycle behavior: connecting via an injected client, disconnect() disposing the client, and ConnectionError before connect(). Error handling: append failures wrapped in DatabaseError. What this does not prove: live execution against a real EventStoreDB / Kurrent server, and the real jsonEvent(...) payload construction (the fallback shape is exercised instead). The method-call shape is verified against the driver's documented contract, but end-to-end execution over the wire has not been exercised here. Related reading All data stores — the full catalogue, grouped by purpose Database types — where this sits among the 22 categories