1
/**2
* The per-session storage handle: one open channel onto a stored session's3
* append-only event log, returned by `SessionPersistence.create`/`open`.4
* @module @deepseek-ai/dsh-session-persistence/handle5
*/7
import type { SessionEvent, SessionHeader, SessionId, SessionLogOffset, SessionSeedEventState } from '@deepseek-ai/dsh-session'9
/**10
* Log access granted by an open. `write` is read-write: the session's single11
* mutator, which also reads its own log. `read` only observes — it never12
* takes ownership and works while another handle or process holds `write`.13
*/14
export type SessionAccess = 'read' | 'write'16
/** Options for {@link SessionHandle.read}. */17
export interface SessionHandleReadOptions {18
/** Optional cancellation for backend read work. */19
readonly signal?: AbortSignal20
}22
/** One persistence event slice returned by {@link SessionHandle.read}. */23
export interface SessionHandleReadResult {24
/**25
* Whether event values are exclusively owned or shared only after deep26
* freezing. Slicing preserves the producer's state even when no events remain.27
*/28
readonly eventState: SessionSeedEventState29
/** Event values in a caller-owned outer array. */30
readonly events: readonly SessionEvent[]31
}33
/** Options for {@link SessionHandle.append}. */34
export interface SessionHandleAppendOptions {35
/** Optional cancellation observed before the write starts. */36
readonly signal?: AbortSignal37
}39
/** Options for {@link SessionHandle.flush}. */40
export interface SessionHandleFlushOptions {41
/** Optional cancellation observed before the barrier starts. */42
readonly signal?: AbortSignal43
}45
/**46
* One open channel onto a stored session. A handle is single-owner state, not47
* a shared service: `read` never backtracks below what this handle already48
* observed, a `write` handle reads its own successful appends, and `close()`49
* is the one teardown (idempotent, uncancellable; `Symbol.asyncDispose`50
* delegates to it). Every operation on a closed handle rejects with51
* `SessionHandleClosedError`.52
*53
* Freshness across handles: once an `append` or `flush` resolves on a write54
* handle, every read STARTED afterwards on the same backend instance — on any55
* handle, or through `stat`/`list` — observes at least that prefix.56
* Reads concurrent with a mutation carry no ordering promise beyond the valid57
* contiguous prefix.58
*/59
export interface SessionHandle extends AsyncDisposable {60
/** The stored session this handle addresses. */61
readonly id: SessionId62
/** The immutable stored header, fixed at `create`/`open`. */63
readonly header: SessionHeader64
/**65
* Exact fork-inherited prefix length stored with the log; `0` when66
* `header.isSeeded` is false. Storage metadata paired with the header for67
* every body read, never part of the replayable event log.68
*/69
readonly inheritedEventCount: SessionLogOffset70
/** Whether this handle may mutate the log. */71
readonly access: SessionAccess73
/**74
* Read a slice of the valid contiguous logical log. The slice is a legal log75
* prefix segment: a torn physical tail is never returned, and repeated reads76
* on this handle never observe an older state than a prior read.77
* @param offset - first logical event seq to include; defaults to `0`.78
* @param length - maximum number of events to return; defaults to the rest79
* of the log. An offset at or past the end returns an empty list.80
* @param options - optional cancellation.81
* @returns the caller-owned outer slice plus the ownership state of its event values.82
*/83
read(offset?: number, length?: number, options?: SessionHandleReadOptions): Promise<SessionHandleReadResult>85
/**86
* Append a contiguous batch continuing the current logical end. The first87
* event's `seq` MUST equal the stored next-seq; committed events are never88
* rewritten. Persistence is best-effort: on resolution the batch is89
* accepted, ordered, and visible to reads on this backend instance, but90
* only a resolved {@link flush} promises it survives a crash — a backend91
* may buffer or batch physical writes behind append. Rejects with92
* `SessionReadOnlyError` on a read handle and `SessionOwnershipLostError`93
* when write ownership is gone.94
* @param events - the contiguous batch, in seq order.95
* @param options - optional cancellation observed before the write starts.96
*/97
append(events: readonly SessionEvent[], options?: SessionHandleAppendOptions): Promise<void>99
/**100
* The durability barrier — the one operation that promises storage: on101
* resolution every acknowledged append is durable and the session is102
* materialized for other processes; an empty created session becomes103
* durably listable here. Callers that must survive a crash flush; a backend104
* whose `append` already persists on resolution treats this as105
* materialize-if-needed. Rejects with `SessionReadOnlyError` on a read106
* handle.107
* @param options - optional cancellation observed before the barrier starts.108
*/109
flush(options?: SessionHandleFlushOptions): Promise<void>111
/**112
* Release the handle: a read handle frees local resources; a write handle113
* completes pending durability and releases write ownership. Idempotent,114
* asynchronous, and deliberately not cancellable.115
*/116
close(): Promise<void>117
}