Skip to content

Event Log Reference

The event-log system is an append-only, offline-first store. You define events (durable, tagged facts), group them, register handlers that fold each event into your projections, and persist everything in an EventJournal. Local writes are command-like (encode payload, run the handler, commit only on success); remote replicas replay the same journal entries through the same handlers, with optional compaction, reactivity invalidation, and encryption.

This page is the exhaustive per-module reference. For the conceptual overview and end-to-end walkthroughs see /event-log/; for the server side of the sync protocol see /event-log/sync-server/.

Define events, group them, build a schema, register handlers, and obtain a typed client. The example uses an in-memory journal and a generated identity.

import { Effect, Layer, Schema } from "effect"
import * as EventGroup from "effect/unstable/eventlog/EventGroup"
import * as EventLog from "effect/unstable/eventlog/EventLog"
import { layerMemory } from "effect/unstable/eventlog/EventJournal"
import { layerSubtle } from "effect/unstable/eventlog/EventLogEncryption"
// 1. Define a group of events. Each event has a tag, a primaryKey derived from
// the decoded payload, and optional payload/success/error schemas.
const Todos = EventGroup.empty
.add({
tag: "TodoCreated",
primaryKey: (p) => p.id,
payload: Schema.Struct({ id: Schema.String, title: Schema.String }),
success: Schema.String
})
.add({
tag: "TodoCompleted",
primaryKey: (p) => p.id,
payload: Schema.Struct({ id: Schema.String })
})
// 2. Combine groups into an EventLogSchema.
const schema = EventLog.schema(Todos)
// 3. Register a handler for every event tag in the group.
const TodosHandlers = EventLog.group(Todos, (handlers) =>
handlers
.handle("TodoCreated", ({ payload }) =>
Effect.as(Effect.log(`created ${payload.title}`), payload.id)
)
.handle("TodoCompleted", ({ payload }) =>
Effect.log(`completed ${payload.id}`)
)
)
// 4. Build the runtime layer: schema + handlers + journal + identity.
const EventLogLive = EventLog.layer(schema, TodosHandlers).pipe(
Layer.provide(layerMemory),
Layer.provide(Layer.effect(EventLog.Identity, EventLog.makeIdentity)),
Layer.provide(layerSubtle)
)
// 5. Use a typed client to write events.
const program = Effect.gen(function* () {
const write = yield* EventLog.makeClient(schema)
const id = yield* write("TodoCreated", { id: "1", title: "Buy milk" })
// => "1" (the handler's success value)
yield* write("TodoCompleted", { id })
})
program.pipe(Effect.provide(EventLogLive), Effect.runFork)

import * as Event from "effect/unstable/eventlog/Event"

An Event is the durable contract for one kind of fact: a stable tag, a primaryKey derived from the decoded payload, and the payload/success/error schemas. The payload schema also derives the MessagePack schema used to persist entries and send them to remote replicas.

Creates a single event definition. Omitted payload/success default to Schema.Void; omitted error defaults to Schema.Never. The MessagePack payload schema (payloadMsgPack) is derived automatically.

import { Schema } from "effect"
import * as Event from "effect/unstable/eventlog/Event"
const UserRegistered = Event.make({
tag: "UserRegistered",
primaryKey: (p) => p.userId,
payload: Schema.Struct({ userId: Schema.String, email: Schema.String }),
success: Schema.Void,
error: Schema.Never
})
UserRegistered.tag // => "UserRegistered"
UserRegistered.primaryKey({ userId: "u1", email: "a@b.c" }) // => "u1"
UserRegistered.payloadMsgPack // Msgpack schema derived from the payload

Returns a new event definition whose error schema is a union of the existing error and the supplied one. Use it to attach a shared error to a single event.

import { Schema } from "effect"
import * as Event from "effect/unstable/eventlog/Event"
class Forbidden extends Schema.TaggedErrorClass<Forbidden>("Forbidden")(
"Forbidden",
{}
) {}
const Created = Event.make({ tag: "Created", primaryKey: () => "x" })
const CreatedWithError = Event.addError(Created, Forbidden)
// CreatedWithError.error is now `Schema.Union([Never, Forbidden])`

Guard that returns true when a value is an event definition.

Event.isEvent(UserRegistered) // => true
Event.isEvent({}) // => false

The runtime/type identifier "~effect/eventlog/Event" that marks event definitions; used internally by isEvent.

Event<Tag, Payload, Success, Error> is the interface produced by make. It exposes tag, primaryKey, payload, payloadMsgPack, success, and error. Payload/Success default to typeof Schema.Void and Error to typeof Schema.Never.

Event.Any is the type-erased event definition (runtime properties preserved, type parameters dropped); Event.AnyWithProps is the same with its structural properties available. Use these as constraints in generic event-handling code.

Marker service interface (EventHandler<Tag>) associated with the handler for an event tag. ToService derives it so handler layers can advertise which tags they implement.

These are type-level utilities — there is no runtime value to print. They derive information from a single Event or from a union of events selected by tag.

  • Tag<A> — extracts the tag string literal from an event definition.
  • Payload<A> — decoded payload value type (Schema.Type of the payload schema).
  • PayloadSchema<A> — the payload schema itself.
  • PayloadWithTag<Events, Tag> — decoded payload value type for the event with Tag in a union.
  • PayloadSchemaWithTag<Events, Tag> — payload schema for the event with Tag in a union.
  • Success<A> — decoded success value type.
  • SuccessSchema<A> — the success schema.
  • SuccessWithTag<Events, Tag> — decoded success value type for the event with Tag.
  • Error<A> — decoded error value type.
  • ErrorSchema<A> — the error schema.
  • ErrorWithTag<Events, Tag> — decoded error value type for the event with Tag.
  • TaggedPayload<A>{ _tag: Tag; payload: Payload } for an event (used by compaction).
  • ToService<A> — derives the EventHandler<Tag> service marker for an event.
  • AddError<A, Error> — event type with Error unioned into its error schema.
  • WithTag<Events, Tag> — extracts the event with Tag from a union.
  • ExcludeTag<Events, Tag> — removes the event with Tag from a union (tracks remaining handlers).
  • Services<A> — all schema encode/decode services for the payload, success, and error schemas.
  • ServicesClient<A> — client-side schema services (payload encode, success/error decode).
  • ServicesServer<A> — server-side schema services (payload decode, success/error encode).
  • ServicesClientWithTag<Events, Tag>ServicesClient for the event with Tag in a union.
// Usage in context: the handler signature uses these helpers internally.
type Created = typeof UserRegistered
type Tag = Event.Tag<Created> // => "UserRegistered"
type Payload = Event.Payload<Created> // => { userId: string; email: string }

import * as EventGroup from "effect/unstable/eventlog/EventGroup"

An immutable catalog of event definitions for one domain. Start from empty, chain .add(...), and pass the result to EventLog.schema (for clients) and EventLog.group (for handlers).

The starting point: an EventGroup<never> with no events.

import * as EventGroup from "effect/unstable/eventlog/EventGroup"
const group = EventGroup.empty

.add({ tag, primaryKey, payload?, success?, error? }) returns a new group with the event added; .addError(error) returns a new group with the error schema unioned into every event. Both are immutable and chainable.

import { Schema } from "effect"
import * as EventGroup from "effect/unstable/eventlog/EventGroup"
class StoreFull extends Schema.TaggedErrorClass<StoreFull>("StoreFull")(
"StoreFull",
{}
) {}
const Cart = EventGroup.empty
.add({
tag: "ItemAdded",
primaryKey: (p) => p.cartId,
payload: Schema.Struct({ cartId: Schema.String, sku: Schema.String })
})
.add({
tag: "CartCleared",
primaryKey: (p) => p.cartId,
payload: Schema.Struct({ cartId: Schema.String })
})
// shared error applied to both events:
.addError(StoreFull)

Guard that returns true when a value is an event group.

EventGroup.isEventGroup(Cart) // => true

The identifier "~effect/eventlog/EventGroup" marking groups; used by isEventGroup.

  • Events<Group> — the union of Event definitions contained in a group.
  • ToService<A> — the union of EventHandler service markers for all events (what a handler layer provides).
  • ServicesClient<Group> — client-side schema services required by all events.
  • ServicesServer<Group> — server-side schema services required by all events.
  • Any — type-erased group marker.
  • AnyWithPropsEventGroup<Event.Any>, with the events record available structurally.

import * as EventLog from "effect/unstable/eventlog/EventLog"

The high-level runtime that connects event definitions, handler layers, an EventJournal, and optional remote replicas.

Combines one or more event groups into an EventLogSchema. This is the value you pass to makeClient, layer, and EventLog.write.

const appSchema = EventLog.schema(Cart, Todos)

EventLogSchema / isEventLogSchema / SchemaTypeId

Section titled “EventLogSchema / isEventLogSchema / SchemaTypeId”

EventLogSchema<Groups> carries a groups array and the SchemaTypeId brand ("~effect/eventlog/EventLog/Schema"). isEventLogSchema guards values carrying that brand.

EventLog.isEventLogSchema(appSchema) // => true
appSchema.groups // => [Cart, Todos]

Returns a typed write function over a schema, preserving each event’s success and error types. Requires the EventLog service.

const program = Effect.gen(function* () {
const write = yield* EventLog.makeClient(appSchema)
yield* write("ItemAdded", { cartId: "c1", sku: "SKU-1" })
// success/error types are inferred per tag; failures include EventJournalError
})

The Context.Service exposing journal-backed writes.

  • write — encodes the payload, derives the primary key, runs the matching handler, and commits the entry only when the handler succeeds.
  • entries — reads all committed Entry values from the underlying journal.
  • destroy — removes all journal data.
const dump = Effect.gen(function* () {
const log = yield* EventLog.EventLog
const entries = yield* log.entries
return entries.length // => number of committed entries
})

Builds a Layer that registers handlers for every event in a group. The callback receives a Handlers builder; each .handle(tag, fn) records a handler, and the return type is validated so every tag is handled. Handler functions receive { storeId, payload, entry, conflicts }.

const CartHandlers = EventLog.group(Cart, (handlers) =>
handlers
.handle("ItemAdded", ({ payload, entry }) =>
Effect.log(`add ${payload.sku} (entry ${entry.idString})`)
)
.handle("CartCleared", ({ payload }) => Effect.log(`clear ${payload.cartId}`))
)
// Layer provides EventGroup.ToService<Cart>, requires Registry (+ any handler services)

Handlers<R, Events> tracks the events still needing handlers in its Events parameter. .handle(tag, handler) returns a builder with that tag removed and any handler service requirements accumulated into R. HandlersTypeId is the brand "~effect/eventlog/EventLog/Handlers".

The handler receives:

// (options) => Effect<Success, Error, R1>
{
storeId, // StoreId for this write/replay
payload, // decoded payload for the tag
entry, // the Entry being committed/replayed
conflicts // ReadonlyArray<{ entry; payload }> — concurrent entries (remote replay)
}

Type-level helpers used by group:

  • Handlers.Any — matches any Handlers value regardless of services or remaining events.
  • Handlers.Item<R> — runtime representation of one registered handler (event metadata, captured context, and the handler function).
  • Handlers.ValidateReturn<A> — checks the builder returned all handlers; an unhandled tag becomes Event not handled: <tag>, and a non-Handlers return becomes Must return the implemented handlers.
  • Handlers.Error<A> — extracts the error type from an effect producing Handlers.
  • Handlers.Services<A> — services required by a Handlers value (or effect producing one), including event schema services.

Registers a compaction handler. During remote replay, matching entries are decoded, grouped by primary key, and passed to your effect, which may rewrite the history by calling write(tag, payload). The effect receives { primaryKey, entries, events, write } where events is an array of { _tag, payload } (Event.TaggedPayload).

// Collapse a cart's history into a single "snapshot" event during replay.
const CartCompaction = EventLog.groupCompaction(Cart, ({ events, write }) => {
// events: ReadonlyArray<{ _tag; payload }> for this primaryKey, in order
const last = events[events.length - 1]
if (last._tag === "CartCleared") {
return write("CartCleared", last.payload)
}
return Effect.void
})
// Layer requires Registry + payload DecodingServices for the group's events

Registers reactivity keys to invalidate when a group’s events are written or replayed. Pass a single key array (applied to every tag) or a per-tag map.

// Same keys for all tags:
const CartReactivity1 = EventLog.groupReactivity(Cart, ["carts"])
// Per-tag keys:
const CartReactivity2 = EventLog.groupReactivity(Cart, {
ItemAdded: ["carts", "cart-items"],
CartCleared: ["carts"]
})
// On write/replay, keys are invalidated for the entry's primaryKey via Reactivity

Context.Service holding { publicKey: string; privateKey: Redacted<Uint8Array> }. Used for remote authentication and to derive encryption/signing keys.

import { Layer } from "effect"
const IdentityLive = Layer.effect(EventLog.Identity, EventLog.makeIdentity)
// requires EventLogEncryption to generate the identity

Schema for an identity: publicKey as a string and privateKey as a redacted, base64-encoded Uint8Array.

Effect that generates a fresh identity using the configured EventLogEncryption service.

const eff = EventLog.makeIdentity // Effect<Identity, never, EventLogEncryption>

encodeIdentityString / decodeIdentityString

Section titled “encodeIdentityString / decodeIdentityString”

Serialize an identity to/from a base64url string (handy for persisting an identity in local storage). decodeIdentityString throws a schema error on invalid input.

const program = Effect.gen(function* () {
const identity = yield* EventLog.makeIdentity
const str = EventLog.encodeIdentityString(identity)
// => base64url string containing publicKey + privateKey bytes
const back = EventLog.decodeIdentityString(str)
back.publicKey === identity.publicKey // => true
})

Context.Reference<StoreId> selecting the logical store for writes and remote replication. Defaults to StoreId.make("default"). Override it to scope a runtime to a specific store.

import { Layer } from "effect"
import { StoreId } from "effect/unstable/eventlog/EventLogMessage"
const StoreLayer = Layer.succeed(
EventLog.CurrentStoreId,
StoreId.make("tenant-42")
)

Registry is the lower-level collector for handlers, compactors, remote replicas, and reactivity keys. layerRegistry provides an in-memory implementation. You usually get it transitively from layerEventLog/layer, but you can provide it directly when assembling a custom runtime.

const program = Effect.gen(function* () {
const registry = yield* EventLog.Registry
registry.handlers // ReadonlyMap<string, Handlers.Item<any>>
registry.reactivityKeys // Record<string, ReadonlyArray<string>>
})

Provides EventLog | Registry from an EventJournal and Identity. Use this when you register handlers separately (e.g. via standalone group/groupCompaction layers) rather than through layer.

// Layer<EventLog | Registry, never, EventJournal | Identity>
const runtime = EventLog.layerEventLog

The convenience layer: combines a schema, a handler layer, and the runtime into one Layer<EventLog | Registry, E, ... | EventJournal | Identity>. The schema argument does not register handlers by itself — handler registration comes from the supplied layer.

const Live = EventLog.layer(appSchema, CartHandlers).pipe(
Layer.provide(layerMemory),
Layer.provide(IdentityLive),
Layer.provide(layerSubtle)
)

Advanced. Builds the effect used to replay entries received from a remote: it decodes the entry and its conflicts, runs the matching handler with the supplied identity and store id, logs failures, and invalidates configured reactivity keys. Used internally by the runtime; you rarely call it directly.


import * as EventJournal from "effect/unstable/eventlog/EventJournal"

The persistence boundary: stores committed entries, publishes local changes, and tracks remote replication metadata. Entry ids are UUID v7, so ordering is clock-derived.

The Context.Service with these members:

  • entriesEffect<ReadonlyArray<Entry>, EventJournalError>; read all entries for replay.
  • write — write one local entry, running a caller effect before committing; commits only if the effect succeeds.
  • writeFromRemote — import a batch of RemoteEntry; splits duplicates, optionally compacts, runs replay effects with conflicts, returns { duplicateEntries }.
  • withRemoteUncommited — run an effect with the entries a given remote has not yet acknowledged (used to push pending writes).
  • nextRemoteSequence — the next sequence number to request from a remote.
  • changesEffect<PubSub.Subscription<Entry>, never, Scope>; subscribe to local writes.
  • destroy — remove all data.
  • withLock(storeId) => (effect) => effect; serialize work for one store id.
const program = Effect.gen(function* () {
const journal = yield* EventJournal.EventJournal
const all = yield* journal.entries
return all.length // => number of entries
})

In-memory journal. makeMemory is the constructor effect; layerMemory is the ready-made layer. Data lives only in process memory and is lost when discarded.

import { layerMemory } from "effect/unstable/eventlog/EventJournal"
// Layer<EventJournal>
const journal = layerMemory

Browser journal backed by IndexedDB. Takes optional { database } (default "effect_event_journal"). makeIndexedDb requires Scope so the connection can be closed; layerIndexedDb manages the scope for you.

import { layerIndexedDb } from "effect/unstable/eventlog/EventJournal"
// Layer<EventJournal, EventJournalError>
const journal = layerIndexedDb({ database: "my_app_journal" })

Data.TaggedError("EventJournalError") recording the failing method and the underlying cause.

import { EventJournalError } from "effect/unstable/eventlog/EventJournal"
new EventJournalError({ method: "write", cause: "disk full" })._tag
// => "EventJournalError"

Schema.Class for a committed entry: id (EntryId), event (tag string), primaryKey, and payload (MessagePack bytes). Statics: arrayMsgpack, encodeArray, decodeArray, and Order (orders by entry id). Getters: idString, createdAtMillis, createdAt.

import { Entry, makeEntryIdUnsafe } from "effect/unstable/eventlog/EventJournal"
const entry = new Entry(
{
id: makeEntryIdUnsafe(),
event: "ItemAdded",
primaryKey: "c1",
payload: new Uint8Array([1, 2, 3])
},
{ disableChecks: true }
)
entry.event // => "ItemAdded"
entry.idString // => "0190..." (UUID v7 string)
entry.createdAtMillis // => epoch ms encoded in the UUID v7 id
entry.createdAt // => DateTime.Utc

Schema.Class pairing a remoteSequence number with an Entry. Produced by remote change streams and consumed by writeFromRemote.

import { RemoteEntry } from "effect/unstable/eventlog/EventJournal"
const remote = new RemoteEntry({ remoteSequence: 7, entry })
remote.remoteSequence // => 7

UUID v7 byte ids for entries; the embedded timestamp gives total ordering.

  • EntryId (type) — Uint8Array & Brand<...>.
  • EntryId (schema) — branded Uint8Array schema.
  • EntryIdTypeId — the brand identifier.
  • makeEntryIdUnsafe({ msecs? }) — generate a UUID v7 id, optionally at a given timestamp (unsafe: bytes are cast without validation).
  • entryIdMillis(id) — extract the epoch-ms timestamp from a v7 id.
  • EntryIdOrderOrder over the raw id bytes.
import {
makeEntryIdUnsafe,
entryIdMillis,
EntryIdOrder
} from "effect/unstable/eventlog/EventJournal"
const a = makeEntryIdUnsafe({ msecs: 1_000 })
const b = makeEntryIdUnsafe({ msecs: 2_000 })
entryIdMillis(a) // => 1000
EntryIdOrder(a, b) // => -1

UUID v4 byte ids identifying a remote journal source.

  • RemoteId (type) — Uint8Array & Brand<...>.
  • RemoteId (schema) — branded Uint8Array schema.
  • RemoteIdTypeId — the brand identifier.
  • makeRemoteIdUnsafe() — generate a random RemoteId (unsafe cast).
import { makeRemoteIdUnsafe } from "effect/unstable/eventlog/EventJournal"
const id = makeRemoteIdUnsafe() // => Uint8Array(16) branded RemoteId

import * as SqlEventJournal from "effect/unstable/eventlog/SqlEventJournal"

A durable EventJournal backed by a SqlClient. Construction runs only minimal CREATE TABLE IF NOT EXISTS statements — indexes, migrations, retention, and any table-name strategy are your responsibility.

Provides EventJournal from a SqlClient. Optional { entryTable, remotesTable } override the default table names (effect_event_journal, effect_event_remotes). May fail with SqlError during table creation.

import { Layer } from "effect"
import * as SqlEventJournal from "effect/unstable/eventlog/SqlEventJournal"
// e.g. a SQLite client layer:
// import { layer as SqliteLive } from "..."
const JournalLive = SqlEventJournal.layer({
entryTable: "todo_journal",
remotesTable: "todo_remotes"
}).pipe(Layer.provide(SqliteLive))
// Layer<EventJournal, SqlError, SqlClient>

Constructs the SQL-backed EventJournal service directly (same options as layer). Use when you assemble the service yourself.

import * as SqlEventJournal from "effect/unstable/eventlog/SqlEventJournal"
const eff = SqlEventJournal.make()
// Effect<EventJournal["Service"], SqlError, SqlClient>

import * as EventLogRemote from "effect/unstable/eventlog/EventLogRemote"

Client-side replica support: write local entries to a remote and stream remote changes over the event-log RPC protocol. Sessions begin with a hello/authenticate handshake, cache authentication per identity public key, and retry Forbidden responses by re-authenticating.

The Context.Service representing one remote replica.

  • id — the remote’s RemoteId.
  • changes({ identity, storeId, startSequence }) => Effect<Queue.Dequeue<RemoteEntry, EventLogRemoteError>, never, Scope>; subscribe to remote changes from a sequence number.
  • write({ identity, storeId, entries }) => Effect<void, EventLogRemoteError>; push local entries (chunked if large).
  • whenAuthenticated — run an effect only after the current Identity has completed the handshake.

Layers providing EventLogRemote from an RpcClient.Protocol and Registry. layerEncrypted additionally wires the Web Crypto encryption layer; it is the default for untrusted transports. layerUnencrypted sends plaintext entries — use only on trusted transports or in tests. Provide an RPC protocol layer (see the /event-log/sync-server/ and RPC docs).

import { Layer } from "effect"
import * as EventLogRemote from "effect/unstable/eventlog/EventLogRemote"
// import an RpcClient.Protocol layer, e.g. over WebSocket/HTTP:
// import { ProtocolLive } from "..."
// Layer<EventLogRemote, EventLogRemoteError, RpcClient.Protocol | Registry>
const RemoteLive = EventLogRemote.layerEncrypted.pipe(
Layer.provide(ProtocolLive)
)

makeEncrypted / makeUnencrypted / makeWith

Section titled “makeEncrypted / makeUnencrypted / makeWith”

Constructor effects behind the layers. makeEncrypted encrypts writes and decrypts changes via EventLogEncryption; makeUnencrypted uses plaintext payloads; makeWith({ encodeWrite, decodeChanges }) builds a remote from custom encode/decode functions. All register the remote with the Registry for the current scope.

import * as EventLogRemote from "effect/unstable/eventlog/EventLogRemote"
// Effect<EventLogRemote, EventLogRemoteError, Scope | EventLogRemoteClient | EventLogEncryption | Registry>
const eff = EventLogRemote.makeEncrypted

Context.Service providing the typed RPC client over EventLogRemoteRpcs. Its static .layer builds the client from an RpcClient.Protocol. layerEncrypted/ layerUnencrypted provide this for you.

import * as EventLogRemote from "effect/unstable/eventlog/EventLogRemote"
// Layer<EventLogRemoteClient, never, RpcClient.Protocol>
const ClientLive = EventLogRemote.EventLogRemoteClient.layer

Data.TaggedError("EventLogRemoteError") recording the failing method and cause.

import { EventLogRemoteError } from "effect/unstable/eventlog/EventLogRemote"
new EventLogRemoteError({ method: "write", cause: "socket closed" })._tag
// => "EventLogRemoteError"

import * as EventLogEncryption from "effect/unstable/eventlog/EventLogEncryption"

Cryptographic operations for encrypted remote replication. Keys are derived deterministically from the identity private key material, so the same stable identity is required to decrypt entries across sessions and devices.

The Context.Service with:

  • encrypt(identity, entries) — encode and AES-GCM-encrypt entries, returning { iv, encryptedEntries }.
  • decrypt(identity, entries) — decrypt EncryptedRemoteEntry[] back into RemoteEntry[].
  • sha256(data) — SHA-256 hash as Uint8Array.
  • sha256String(data) — SHA-256 hash as a lowercase hex string.
  • generateIdentity — create a fresh Identity (random public key + 32 random private-key bytes).
const program = Effect.gen(function* () {
const enc = yield* EventLogEncryption.EventLogEncryption
const hex = yield* enc.sha256String(new Uint8Array([1, 2, 3]))
// => 64-char lowercase hex string
})

makeEncryptionSubtle(crypto) builds the service from a Web Crypto Crypto implementation (AES-GCM, SHA-256). layerSubtle provides it using globalThis.crypto.

import { layerSubtle } from "effect/unstable/eventlog/EventLogEncryption"
// Layer<EventLogEncryption>
const EncryptionLive = layerSubtle

Schemas for encrypted payloads. EncryptedEntry pairs an entryId with the encrypted bytes; EncryptedRemoteEntry adds the remote sequence and the AES-GCM iv. Mostly used internally by the encrypted remote and the server protocol.


import { ... } from "effect/unstable/eventlog/EventLogMessage"

These define the shared remote protocol. They are mostly internal to the sync client/server; you typically only touch StoreId. See /event-log/sync-server/ for server-side usage.

  • StoreId — branded string (and schema) identifying a logical store; StoreId.make("default") is the default used by CurrentStoreId.
  • EventLogRemoteRpcs — the RpcGroup with the hello, authenticate, write, and changes endpoints.
  • EventLogAuthenticationRpcMiddleware that authenticates requests and provides the client Identity to handlers.
  • EventLogProtocolErrorSchema.TaggedErrorClass with a code of "Unauthorized" | "Forbidden" | "NotFound" | "InvalidRequest" | "InternalServerError", plus requestTag, optional publicKey/storeId, and a message.
import { StoreId } from "effect/unstable/eventlog/EventLogMessage"
const store = StoreId.make("default") // => branded "default"