@deepseek-ai/dsh-session-persistence 0.1.2-rc.1 → 0.1.5-alpha.1
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.i18n.yaml +2 -2
- package/README.md +45 -28
- package/README.zh.md +46 -29
- package/lib/index.js +167 -1494
- package/lib/types/errors.d.ts +98 -2
- package/lib/types/handle.d.ts +107 -0
- package/lib/types/index.d.ts +114 -191
- package/lib/types/storage-contract.d.ts +62 -0
- package/package.json +9 -9
- package/lib/types/coordinator.d.ts +0 -361
- package/lib/types/preparations.d.ts +0 -129
- package/lib/types/write-behind.d.ts +0 -62
package/package.json
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@deepseek-ai/dsh-session-persistence",
|
|
3
3
|
"description": "Abstract durable session persistence seam (ctx.sessionPersistence) for the DeepSeek Harness",
|
|
4
|
-
"version": "0.1.
|
|
4
|
+
"version": "0.1.5-alpha.1",
|
|
5
5
|
"publishConfig": {
|
|
6
6
|
"access": "public"
|
|
7
7
|
},
|
|
@@ -27,19 +27,19 @@
|
|
|
27
27
|
],
|
|
28
28
|
"license": "MIT",
|
|
29
29
|
"peerDependencies": {
|
|
30
|
-
"@deepseek-ai/dsh-brand": "^0.1.2-rc.1",
|
|
31
30
|
"@deepseek-ai/cordis": "^4.0.2",
|
|
32
|
-
"@deepseek-ai/dsh-
|
|
33
|
-
"@deepseek-ai/dsh-
|
|
31
|
+
"@deepseek-ai/dsh-brand": "^0.1.5-alpha.1",
|
|
32
|
+
"@deepseek-ai/dsh-session": "^0.1.5-alpha.1",
|
|
33
|
+
"@deepseek-ai/dsh-timeout": "^0.1.5-alpha.1"
|
|
34
34
|
},
|
|
35
35
|
"devDependencies": {
|
|
36
36
|
"@deepseek-ai/cordis": "^4.0.2",
|
|
37
|
-
"@deepseek-ai/dsh-
|
|
38
|
-
"@deepseek-ai/dsh-
|
|
39
|
-
"@deepseek-ai/dsh-
|
|
40
|
-
"@deepseek-ai/dsh-
|
|
37
|
+
"@deepseek-ai/dsh-scope": "^0.1.5-alpha.1",
|
|
38
|
+
"@deepseek-ai/dsh-session": "^0.1.5-alpha.1",
|
|
39
|
+
"@deepseek-ai/dsh-timeout": "^0.1.5-alpha.1",
|
|
40
|
+
"@deepseek-ai/dsh-brand": "^0.1.5-alpha.1"
|
|
41
41
|
},
|
|
42
42
|
"dependencies": {
|
|
43
|
-
"@deepseek-ai/dsh-util-values": "^0.1.
|
|
43
|
+
"@deepseek-ai/dsh-util-values": "^0.1.5-alpha.1"
|
|
44
44
|
}
|
|
45
45
|
}
|
|
@@ -1,361 +0,0 @@
|
|
|
1
|
-
/**
|
|
2
|
-
* Shared buffering, serialization, adoption, repair, and disposal orchestration
|
|
3
|
-
* for first-party backends. Third-party backends may implement the public
|
|
4
|
-
* persistence seam directly.
|
|
5
|
-
* @module @deepseek-ai/dsh-session-persistence/coordinator
|
|
6
|
-
*/
|
|
7
|
-
import { Context } from '@deepseek-ai/cordis';
|
|
8
|
-
import { SessionPreparation } from '@deepseek-ai/dsh-session';
|
|
9
|
-
import type { Session, SessionEvent, SessionId, SessionHeader, SessionLogOffset as SessionLogOffsetType } from '@deepseek-ai/dsh-session';
|
|
10
|
-
import type { BorrowedSessionSource, SessionEventSuffix, SessionInspection, SessionLocation, SessionStorageMetadata } from './index.ts';
|
|
11
|
-
import type { SessionPersistenceRevision } from './revision.ts';
|
|
12
|
-
/** Default number of detached session preparations retained by a coordinator. */
|
|
13
|
-
export declare const DEFAULT_PREPARED_SESSION_CACHE_SIZE = 5;
|
|
14
|
-
/** Default maximum intentional wait before a live session batch starts writing. */
|
|
15
|
-
export declare const DEFAULT_WRITE_BATCH_MAX_DELAY_MS = 200;
|
|
16
|
-
/** Largest write batching delay accepted by Node's timer implementation. */
|
|
17
|
-
export declare const MAX_WRITE_BATCH_DELAY_MS = 2147483647;
|
|
18
|
-
/** Durable session contents failed validation after a successful backend read. */
|
|
19
|
-
export declare class SessionPersistenceCorruptionError extends Error {
|
|
20
|
-
/**
|
|
21
|
-
* @param message - stable corruption context.
|
|
22
|
-
* @param options - original validation failure.
|
|
23
|
-
*/
|
|
24
|
-
constructor(message: string, options: ErrorOptions);
|
|
25
|
-
}
|
|
26
|
-
/**
|
|
27
|
-
* The stored log is intact but this runtime cannot faithfully interpret it:
|
|
28
|
-
* the header carries an unsupported format version, or an event's type is
|
|
29
|
-
* unknown to this build and the event is not marked ignorable. Distinct from
|
|
30
|
-
* {@link SessionPersistenceCorruptionError} — nothing is damaged; the raw log
|
|
31
|
-
* remains readable at {@link location} when the backend keeps one artifact
|
|
32
|
-
* per session.
|
|
33
|
-
*/
|
|
34
|
-
export declare class SessionFormatUnsupportedError extends Error {
|
|
35
|
-
readonly location?: SessionLocation | undefined;
|
|
36
|
-
/**
|
|
37
|
-
* @param message - stable reason the log cannot be interpreted, already
|
|
38
|
-
* including the raw-log path when one exists.
|
|
39
|
-
* @param location - the backend's artifact location, when one exists.
|
|
40
|
-
*/
|
|
41
|
-
constructor(message: string, location?: SessionLocation | undefined);
|
|
42
|
-
}
|
|
43
|
-
/**
|
|
44
|
-
* Direction-aware refusal text for a stored session whose format version this
|
|
45
|
-
* build does not read. Shared by the coordinator's load-time check and by
|
|
46
|
-
* backends that must refuse BEFORE decoding version-dependent structure (a
|
|
47
|
-
* future format may not satisfy this build's structural checks at all, and the
|
|
48
|
-
* user must see "upgrade the harness", never "corrupt").
|
|
49
|
-
* @param id - the stored session id, for message context.
|
|
50
|
-
* @param version - the stored format version.
|
|
51
|
-
* @returns the stable refusal text, without a raw-log path suffix.
|
|
52
|
-
*/
|
|
53
|
-
export declare function sessionFormatVersionRefusal(id: string, version: number): string;
|
|
54
|
-
/** Coordinator policy supplied by a concrete persistence backend. */
|
|
55
|
-
export interface PersistenceCoordinatorOptions {
|
|
56
|
-
/** Maximum completed unpublished preparations retained for reuse. */
|
|
57
|
-
readonly preparedSessionCacheSize: number;
|
|
58
|
-
/** Maximum intentional batching wait after an idle live queue receives work. */
|
|
59
|
-
readonly writeBatchMaxDelayMs: number;
|
|
60
|
-
}
|
|
61
|
-
/**
|
|
62
|
-
* A stored session's header, valid contiguous event prefix, source-qualified
|
|
63
|
-
* revision, and optional opaque torn-tail marker. The revision identifies the
|
|
64
|
-
* exact detached prefix. The coordinator only checks marker presence and
|
|
65
|
-
* returns its value to {@link PersistenceBackend.commitRepair}; each backend
|
|
66
|
-
* owns the marker type.
|
|
67
|
-
*/
|
|
68
|
-
export interface StoredPrefix<TornMarker = unknown> extends SessionStorageMetadata {
|
|
69
|
-
events: SessionEvent[];
|
|
70
|
-
/** Revision observed for exactly this detached prefix. */
|
|
71
|
-
revision: SessionPersistenceRevision;
|
|
72
|
-
tornMarker?: TornMarker;
|
|
73
|
-
}
|
|
74
|
-
/**
|
|
75
|
-
* A stored session's header plus the events at or past a requested seq — the
|
|
76
|
-
* return shape of the optional seek-capable
|
|
77
|
-
* {@link PersistenceBackend.loadStoredFrom} hook. Non-mutating reads carry no
|
|
78
|
-
* torn marker: there is nothing to repair.
|
|
79
|
-
*/
|
|
80
|
-
export interface StoredSuffix extends SessionStorageMetadata {
|
|
81
|
-
events: SessionEvent[];
|
|
82
|
-
}
|
|
83
|
-
/**
|
|
84
|
-
* The storage contract between {@link PersistenceCoordinator} and a concrete
|
|
85
|
-
* backend: the minimal set of durable primitives the orchestration calls. A
|
|
86
|
-
* backend implements these (over files, rows, an object store, …); the
|
|
87
|
-
* coordinator supplies everything else (buffering, serialization, cursors,
|
|
88
|
-
* adoption, crash repair sequencing, dispose quiescence).
|
|
89
|
-
*
|
|
90
|
-
* @typeParam TornMarker - the backend's opaque torn-tail repair token (see
|
|
91
|
-
* {@link StoredPrefix}). The coordinator treats it as fully opaque.
|
|
92
|
-
*/
|
|
93
|
-
export interface PersistenceBackend<TornMarker = unknown> {
|
|
94
|
-
/** Human-readable backend name, used in the dispose-failure AggregateError. */
|
|
95
|
-
readonly name: string;
|
|
96
|
-
/**
|
|
97
|
-
* Read a stored prefix by id, scanning every backend storage scope. Returns
|
|
98
|
-
* `undefined` if no stored artifact exists. Returned metadata must identify
|
|
99
|
-
* `id` before repair or state publication. Used by resume/load, live adoption,
|
|
100
|
-
* and — via `!== undefined` — the create-collision probe. The returned
|
|
101
|
-
* `tornMarker` is present iff there is a torn tail to truncate. Every header
|
|
102
|
-
* and event graph must be fresh, mutually unaliased, and unretained by the
|
|
103
|
-
* backend because preparation freezes and publishes them in place. The
|
|
104
|
-
* returned revision must identify exactly those values and use the same
|
|
105
|
-
* representation as {@link readStoredRevision}.
|
|
106
|
-
* @param id - persisted session id to resolve.
|
|
107
|
-
* @param signal - optional cancellation for backend read work.
|
|
108
|
-
*/
|
|
109
|
-
loadStored(id: SessionId, signal?: AbortSignal): Promise<StoredPrefix<TornMarker> | undefined>;
|
|
110
|
-
/**
|
|
111
|
-
* Read the current source-qualified revision for one stored session without
|
|
112
|
-
* loading its event log. Returns `undefined` when the identity is absent.
|
|
113
|
-
* @param id - persisted session id to observe.
|
|
114
|
-
* @param signal - optional cancellation for backend read work.
|
|
115
|
-
*/
|
|
116
|
-
readStoredRevision(id: SessionId, signal?: AbortSignal): Promise<SessionPersistenceRevision | undefined>;
|
|
117
|
-
/**
|
|
118
|
-
* Optional seek-capable suffix read behind the service's `readFrom`: return
|
|
119
|
-
* the header plus the stored events with `seq >= fromSeq` without reading
|
|
120
|
-
* the whole log. A backend whose medium can address events by seq implements
|
|
121
|
-
* this so `readFrom` scales with the suffix; sequential backends
|
|
122
|
-
* omit it and the coordinator falls back to {@link loadStored} plus a
|
|
123
|
-
* forward skip. Non-mutating (no truncation, no closers). Validation of the
|
|
124
|
-
* region strictly below `fromSeq` is limited to seq contiguity — the
|
|
125
|
-
* service contract scopes this read to the suffix — unless that suffix
|
|
126
|
-
* contains a supported legacy shape whose normalization needs earlier
|
|
127
|
-
* message-identity facts, in which case the coordinator falls back
|
|
128
|
-
* to the complete stored prefix.
|
|
129
|
-
* Unknown-type refusal follows the same suffix scope: a seek-capable
|
|
130
|
-
* backend's `readFrom` checks only the returned suffix, while the
|
|
131
|
-
* sequential fallback parses the whole artifact and refuses on an unknown
|
|
132
|
-
* required event anywhere in it — over-refusal on the sequential side is
|
|
133
|
-
* accepted rather than widening the seek read.
|
|
134
|
-
* @param id - persisted session id to resolve.
|
|
135
|
-
* @param fromSeq - first event seq to include (non-negative safe integer,
|
|
136
|
-
* validated by the coordinator before this hook runs).
|
|
137
|
-
* @param signal - optional cancellation for backend read work.
|
|
138
|
-
*/
|
|
139
|
-
loadStoredFrom?(id: SessionId, fromSeq: SessionLogOffsetType, signal?: AbortSignal): Promise<StoredSuffix | undefined>;
|
|
140
|
-
/** Durably create an empty header-only session artifact. */
|
|
141
|
-
materializeHeader?(storage: SessionStorageMetadata): Promise<void>;
|
|
142
|
-
/**
|
|
143
|
-
* Durably append a CONTIGUOUS batch, lazily materializing the session first
|
|
144
|
-
* when `!isMaterialized`. The materialize-write and the first event batch MUST
|
|
145
|
-
* commit ATOMICALLY (a crash between them must not leave a materialized-but-
|
|
146
|
-
* empty session). Returns once the batch is durable.
|
|
147
|
-
* The coordinator calls this only after a first batch reaches the declared
|
|
148
|
-
* inherited prefix length.
|
|
149
|
-
*/
|
|
150
|
-
appendBatch(storage: SessionStorageMetadata, events: readonly SessionEvent[], isMaterialized: boolean): Promise<void>;
|
|
151
|
-
/**
|
|
152
|
-
* Make a crash repair durable: truncate the torn tail (iff
|
|
153
|
-
* `tornMarker !== undefined`) and append `closers` (iff any). NOT required to
|
|
154
|
-
* be atomic — a file backend may truncate-then-append in two fsync'd steps.
|
|
155
|
-
* Used by load (truncate + synthetic closers) and by live-adoption (truncate
|
|
156
|
-
* only, `closers = []`).
|
|
157
|
-
*/
|
|
158
|
-
commitRepair(storage: SessionStorageMetadata, tornMarker: TornMarker | undefined, closers: readonly SessionEvent[]): Promise<void>;
|
|
159
|
-
/**
|
|
160
|
-
* List all stored (materialized) sessions' metadata.
|
|
161
|
-
* @param signal - optional cancellation for backend listing work.
|
|
162
|
-
*/
|
|
163
|
-
list(signal?: AbortSignal): Promise<SessionHeader[]>;
|
|
164
|
-
/**
|
|
165
|
-
* Optional side-effect-free artifact locator, used to point refusal
|
|
166
|
-
* diagnostics ({@link SessionFormatUnsupportedError}) at the raw log.
|
|
167
|
-
* Backends without one artifact per session omit it or return `undefined`.
|
|
168
|
-
* @param meta - the header whose artifact is requested.
|
|
169
|
-
*/
|
|
170
|
-
locate?(meta: SessionHeader): SessionLocation | undefined;
|
|
171
|
-
/**
|
|
172
|
-
* Optional lifecycle teardown (e.g. close a database handle). Awaited by the
|
|
173
|
-
* coordinator's dispose effect AFTER the quiescence drain. A stateless file
|
|
174
|
-
* backend omits it.
|
|
175
|
-
*/
|
|
176
|
-
close?(): Promise<void>;
|
|
177
|
-
}
|
|
178
|
-
/**
|
|
179
|
-
* Owns the backend-agnostic session write-path orchestration. A backend
|
|
180
|
-
* constructs one (`new PersistenceCoordinator(ctx, this)`), implements
|
|
181
|
-
* {@link PersistenceBackend}, and delegates its write/read service methods to
|
|
182
|
-
* the matching coordinator methods.
|
|
183
|
-
*
|
|
184
|
-
* All per-id operations are serialized (a per-id promise chain) so concurrent
|
|
185
|
-
* flushes / a flush racing a load never interleave storage writes. The
|
|
186
|
-
* constructor installs the write-path listeners, per-session retirement, and
|
|
187
|
-
* the backend dispose effect.
|
|
188
|
-
*
|
|
189
|
-
* @typeParam TornMarker - the backend's opaque torn-tail repair token.
|
|
190
|
-
*/
|
|
191
|
-
export declare class PersistenceCoordinator<TornMarker = unknown> {
|
|
192
|
-
private ctx;
|
|
193
|
-
private backend;
|
|
194
|
-
/** Backend bookkeeping keyed by session id (NOT the live Session object). */
|
|
195
|
-
private states;
|
|
196
|
-
/** Lifecycle and write-behind state keyed by the exact live Session. */
|
|
197
|
-
private live;
|
|
198
|
-
/** Exact disposed lifecycles whose buffered tail is still draining. */
|
|
199
|
-
private retirements;
|
|
200
|
-
/** Shared cold reads, unpublished reservations, and completed LRU entries. */
|
|
201
|
-
private readonly preparations;
|
|
202
|
-
/**
|
|
203
|
-
* Per-session serialization: every operation chains onto the prior one for the
|
|
204
|
-
* same id, so writes for one session never interleave. Keyed by session id.
|
|
205
|
-
*/
|
|
206
|
-
private chains;
|
|
207
|
-
/** Resolved fixed write-batching window shared by per-session controllers. */
|
|
208
|
-
private readonly writeBatchMaxDelayMs;
|
|
209
|
-
constructor(ctx: Context, backend: PersistenceBackend<TornMarker>, options?: PersistenceCoordinatorOptions);
|
|
210
|
-
/**
|
|
211
|
-
* Register detached session metadata for lazy creation on the first append.
|
|
212
|
-
* @param meta - header to snapshot; duplicate tracked or persisted ids reject.
|
|
213
|
-
* @param inheritedEventCount - exact inherited prefix length; required for
|
|
214
|
-
* a seeded header and omitted only for an unseeded header.
|
|
215
|
-
*/
|
|
216
|
-
create(meta: SessionHeader, inheritedEventCount?: SessionLogOffsetType): Promise<void>;
|
|
217
|
-
/**
|
|
218
|
-
* Materialize one exact live session without inventing a session event.
|
|
219
|
-
* @param session - live session already registered through the write path.
|
|
220
|
-
*/
|
|
221
|
-
ensureMaterialized(session: Session): Promise<void>;
|
|
222
|
-
private createCore;
|
|
223
|
-
/**
|
|
224
|
-
* Durably persist a batch of events. Honors the append-only and contiguous-seq
|
|
225
|
-
* contracts; rejects non-JSON-serializable `event.data`.
|
|
226
|
-
* @param id - the session the batch belongs to.
|
|
227
|
-
* @param events - the contiguous batch to persist, in seq order; materialized
|
|
228
|
-
* as a detached lossless-JSON snapshot at call time.
|
|
229
|
-
*/
|
|
230
|
-
append(id: SessionId, events: readonly SessionEvent[]): Promise<void>;
|
|
231
|
-
private appendCore;
|
|
232
|
-
/**
|
|
233
|
-
* Prepare and reserve the exact unpublished Session used by resume.
|
|
234
|
-
* Revision retries converge once the durable log remains unchanged for one
|
|
235
|
-
* read/check round trip; continuous external writers may delay completion.
|
|
236
|
-
* @param id - persisted session to prepare.
|
|
237
|
-
* @param signal - optional cancellation for reading and repair.
|
|
238
|
-
* @returns an owned preparation released after publication or rollback.
|
|
239
|
-
*/
|
|
240
|
-
prepare(id: SessionId, signal?: AbortSignal): Promise<SessionPreparation>;
|
|
241
|
-
/**
|
|
242
|
-
* Commit recovery and return its immutable logical view without publication.
|
|
243
|
-
* Revision retries converge once the durable log remains unchanged for one
|
|
244
|
-
* read/check round trip; continuous external writers may delay completion.
|
|
245
|
-
* @param id - persisted session to load.
|
|
246
|
-
* @returns prepared header and balanced events.
|
|
247
|
-
*/
|
|
248
|
-
load(id: SessionId): Promise<SessionInspection>;
|
|
249
|
-
/**
|
|
250
|
-
* Inspect a logical session without publishing it or committing recovery.
|
|
251
|
-
* A stale ready source is reloaded. A source already committing or reserved
|
|
252
|
-
* for resume remains exclusive, and inspection may borrow its immutable view.
|
|
253
|
-
* Revision retries converge once the log is stable for one read/check round
|
|
254
|
-
* trip; continuous external writers may delay completion.
|
|
255
|
-
* @param id - persisted session to inspect.
|
|
256
|
-
* @param signal - optional cancellation for preparation work.
|
|
257
|
-
* @returns immutable prepared metadata and events; a live view may have an open turn.
|
|
258
|
-
*/
|
|
259
|
-
inspect(id: SessionId, signal?: AbortSignal): Promise<SessionInspection>;
|
|
260
|
-
/**
|
|
261
|
-
* Borrow one exact logical view while pinning its reusable prepared Session.
|
|
262
|
-
* @param id - persisted session to observe.
|
|
263
|
-
* @param signal - optional cancellation for preparation work.
|
|
264
|
-
* @returns a disposable observation retaining the prepared source.
|
|
265
|
-
*/
|
|
266
|
-
borrowSession(id: SessionId, signal?: AbortSignal): Promise<BorrowedSessionSource>;
|
|
267
|
-
/**
|
|
268
|
-
* Read the stored events from `fromSeq` onward, detached and non-mutating
|
|
269
|
-
* (the read-from-seq primitive behind the service's `readFrom`). Runs on
|
|
270
|
-
* the same per-id chain as writes; a backend with the seek-capable
|
|
271
|
-
* {@link PersistenceBackend.loadStoredFrom} hook reads only the suffix,
|
|
272
|
-
* every other backend reads its stored prefix and skips forward here.
|
|
273
|
-
* @param id - persisted session to read.
|
|
274
|
-
* @param fromSeq - first event seq to include; a non-negative safe integer.
|
|
275
|
-
* @param signal - optional cancellation for queued and backend read work.
|
|
276
|
-
* @returns stored metadata, the requested offset, and valid events with `seq >= fromSeq`.
|
|
277
|
-
*/
|
|
278
|
-
readFrom(id: SessionId, fromSeq: SessionLogOffsetType, signal?: AbortSignal): Promise<SessionEventSuffix>;
|
|
279
|
-
private readFromCore;
|
|
280
|
-
/** Read one detached physical prefix without logical recovery or caching. */
|
|
281
|
-
private readStoredPrefix;
|
|
282
|
-
/** Read, repair in memory, validate, and freeze one cold source once. */
|
|
283
|
-
private prepareCore;
|
|
284
|
-
/** Commit one prepared repair and establish its ownerless durable cursor. */
|
|
285
|
-
private commitPrepared;
|
|
286
|
-
/** Whether one cached source still names the current durable log revision. */
|
|
287
|
-
private isPreparedSourceCurrent;
|
|
288
|
-
/** Return one durable immutable view of an already-live Session. */
|
|
289
|
-
private loadLiveSnapshot;
|
|
290
|
-
/** Borrow one immutable view from an already-live Session. */
|
|
291
|
-
private inspectLive;
|
|
292
|
-
/** Await one retiring lifecycle with caller cancellation. */
|
|
293
|
-
private waitForRetirement;
|
|
294
|
-
/**
|
|
295
|
-
* Run `op` after any in-flight operation for the same session id, so writes for
|
|
296
|
-
* one session never interleave. Errors do not poison the chain. NOTE: serialized
|
|
297
|
-
* public methods must NOT call each other (deadlock); they call the unserialized
|
|
298
|
-
* `*Core` helpers instead.
|
|
299
|
-
*/
|
|
300
|
-
private serialize;
|
|
301
|
-
/** Build a state for a session discovered in storage but not yet in memory. */
|
|
302
|
-
private adopt;
|
|
303
|
-
private assertVersion;
|
|
304
|
-
/**
|
|
305
|
-
* Refuse a log containing an event type this build does not know, unless the
|
|
306
|
-
* writer marked the event ignorable: an unrecognized required event may
|
|
307
|
-
* change how the rest of the log must be interpreted, so silently skipping
|
|
308
|
-
* it would reconstruct a wrong session (the envelope contract on
|
|
309
|
-
* `SessionEvent.ignorable`). Runs on NORMALIZED events — after
|
|
310
|
-
* `snapshotStoredEvents`/`adoptStoredEvents` has upgraded the legacy shapes
|
|
311
|
-
* this build still reads and rejected the ones it does not, so those keep
|
|
312
|
-
* their specific diagnostics.
|
|
313
|
-
*/
|
|
314
|
-
private assertEventsSupported;
|
|
315
|
-
/** Build a format refusal that points at the raw artifact when the backend has one. */
|
|
316
|
-
private unsupported;
|
|
317
|
-
/** Reject backend metadata that is not bound to the requested session id. */
|
|
318
|
-
private assertStoredId;
|
|
319
|
-
private installWritePath;
|
|
320
|
-
/** Start and observe one disposed session's final drain. */
|
|
321
|
-
private retire;
|
|
322
|
-
/** Drain and release state owned by one exact disposed Session lifecycle. */
|
|
323
|
-
private retireCore;
|
|
324
|
-
/** Return the one lifecycle controller for a live session, creating it if needed. */
|
|
325
|
-
private initFor;
|
|
326
|
-
/** Bind one exact prepared Session and persist only its unpublished suffix. */
|
|
327
|
-
private attachPrepared;
|
|
328
|
-
/**
|
|
329
|
-
* Whether a live session's `seed` reproduces the first `cursor` persisted
|
|
330
|
-
* events. A `cursor` of 0 (nothing persisted yet) trivially matches. Used when
|
|
331
|
-
* a live session claims ownerless state left by a prior `load()`/`create()`.
|
|
332
|
-
*/
|
|
333
|
-
private seedMatchesPersisted;
|
|
334
|
-
/**
|
|
335
|
-
* On session/created: sync the backend's in-memory state to a live Session.
|
|
336
|
-
*
|
|
337
|
-
* Cases, by whether this backend tracks the id and whether an artifact exists:
|
|
338
|
-
* 1. Already tracked → no-op (or claim ownerless state if the seed matches,
|
|
339
|
-
* or reclaim a truly-abandoned id, else reject as a collision).
|
|
340
|
-
* 2. Not tracked, an artifact EXISTS at the same cwd and is a seq-aligned
|
|
341
|
-
* PREFIX of the live events → ADOPT it, persisting any live suffix.
|
|
342
|
-
* 3. Not tracked, an artifact EXISTS at another cwd or is NOT a prefix →
|
|
343
|
-
* REJECT (collision).
|
|
344
|
-
* 4. Not tracked and NO artifact → a genuinely new session: register meta
|
|
345
|
-
* (lazy) and persist its seed once.
|
|
346
|
-
*/
|
|
347
|
-
private onCreated;
|
|
348
|
-
/**
|
|
349
|
-
* Adopt a stored prefix as a live session's history (HMR/reload): verify the
|
|
350
|
-
* seed covers the stored prefix, truncate any torn tail (NOT the open turn —
|
|
351
|
-
* the live Session is still the authority), bind ownership, and persist the
|
|
352
|
-
* live suffix that was ahead of the stored prefix.
|
|
353
|
-
*/
|
|
354
|
-
private adoptLivePrefix;
|
|
355
|
-
private flush;
|
|
356
|
-
/** Build one package-private write controller around initialization and id serialization. */
|
|
357
|
-
private createWriteBehind;
|
|
358
|
-
/** Append one controller-owned prefix after filtering events initialization already stored. */
|
|
359
|
-
private appendLiveBatch;
|
|
360
|
-
}
|
|
361
|
-
//# sourceMappingURL=coordinator.d.ts.map
|
|
@@ -1,129 +0,0 @@
|
|
|
1
|
-
/**
|
|
2
|
-
* Bounded sharing and exclusive reservation of unpublished Sessions.
|
|
3
|
-
* @module @deepseek-ai/dsh-session-persistence/preparations
|
|
4
|
-
*/
|
|
5
|
-
import type { Session, SessionId } from '@deepseek-ai/dsh-session';
|
|
6
|
-
interface PreparedSource {
|
|
7
|
-
readonly session: Session;
|
|
8
|
-
}
|
|
9
|
-
type PreparationPhase = 'loading' | 'ready' | 'committing' | 'reserved';
|
|
10
|
-
interface PreparationEntry<Source, CommitState> {
|
|
11
|
-
readonly id: SessionId;
|
|
12
|
-
readonly result: Promise<Source>;
|
|
13
|
-
phase: PreparationPhase;
|
|
14
|
-
source?: Source;
|
|
15
|
-
reservation?: SessionPreparationReservation<Source, CommitState>;
|
|
16
|
-
reservationSettled?: Promise<void>;
|
|
17
|
-
settleReservation?: () => void;
|
|
18
|
-
pins: number;
|
|
19
|
-
}
|
|
20
|
-
/** A borrowed prepared source that remains outside ready-entry eviction until released. */
|
|
21
|
-
export interface PreparationLease<Source> extends Disposable {
|
|
22
|
-
/** Shared immutable prepared source. */
|
|
23
|
-
readonly source: Source;
|
|
24
|
-
}
|
|
25
|
-
/** One exclusively held prepared source and its committed persistence state. */
|
|
26
|
-
export interface SessionPreparationReservation<Source, CommitState> {
|
|
27
|
-
readonly entry: PreparationEntry<Source, CommitState>;
|
|
28
|
-
readonly source: Source;
|
|
29
|
-
readonly state: CommitState;
|
|
30
|
-
}
|
|
31
|
-
/** Per-coordinator cold-read sharing, exclusive reservation, and ready-entry LRU. */
|
|
32
|
-
export declare class SessionPreparations<Source extends PreparedSource, CommitState> {
|
|
33
|
-
private readonly capacity;
|
|
34
|
-
private readonly entries;
|
|
35
|
-
constructor(capacity: number);
|
|
36
|
-
/**
|
|
37
|
-
* Whether this pool currently knows about an unpublished identity.
|
|
38
|
-
* @param id - session identity.
|
|
39
|
-
* @returns whether an entry exists for the identity.
|
|
40
|
-
*/
|
|
41
|
-
has(id: SessionId): boolean;
|
|
42
|
-
/**
|
|
43
|
-
* Observe one prepared source, sharing an in-flight read for the same id.
|
|
44
|
-
* @param id - session identity.
|
|
45
|
-
* @param load - cold loader used when no entry exists.
|
|
46
|
-
* @param signal - optional cancellation signal while waiting.
|
|
47
|
-
* @returns the shared prepared source.
|
|
48
|
-
*/
|
|
49
|
-
inspect(id: SessionId, load: () => Promise<Source>, signal?: AbortSignal): Promise<Source>;
|
|
50
|
-
/**
|
|
51
|
-
* Borrow one prepared source and pin its ready entry against LRU eviction.
|
|
52
|
-
* @param id - session identity.
|
|
53
|
-
* @param load - cold loader used when no entry exists.
|
|
54
|
-
* @param signal - optional cancellation signal while waiting.
|
|
55
|
-
* @returns a caller-owned observation lease.
|
|
56
|
-
*/
|
|
57
|
-
borrow(id: SessionId, load: () => Promise<Source>, signal?: AbortSignal): Promise<PreparationLease<Source>>;
|
|
58
|
-
/**
|
|
59
|
-
* Reserve one ready source after committing its pending durable repair.
|
|
60
|
-
* @param id - session identity.
|
|
61
|
-
* @param load - cold loader used when no entry exists.
|
|
62
|
-
* @param commit - durable repair and cursor-state commit.
|
|
63
|
-
* @param signal - optional cancellation signal while waiting.
|
|
64
|
-
* @returns the exclusive reservation, or undefined if its entry was invalidated.
|
|
65
|
-
*/
|
|
66
|
-
reserve(id: SessionId, load: () => Promise<Source>, commit: (source: Source) => Promise<{
|
|
67
|
-
source: Source;
|
|
68
|
-
state: CommitState;
|
|
69
|
-
} | undefined>, signal?: AbortSignal): Promise<SessionPreparationReservation<Source, CommitState> | undefined>;
|
|
70
|
-
/**
|
|
71
|
-
* Return the exact reservation for Session publication, rejecting aliases.
|
|
72
|
-
* @param session - exact Session candidate for publication.
|
|
73
|
-
* @returns its reservation, or undefined when no preparation exists.
|
|
74
|
-
*/
|
|
75
|
-
reservationFor(session: Session): SessionPreparationReservation<Source, CommitState> | undefined;
|
|
76
|
-
/**
|
|
77
|
-
* Consume a reservation after its exact Session has attached.
|
|
78
|
-
* @param reservation - reservation to consume.
|
|
79
|
-
*/
|
|
80
|
-
attach(reservation: SessionPreparationReservation<Source, CommitState>): void;
|
|
81
|
-
/**
|
|
82
|
-
* Consume a reservation whose caller only needs the committed inspection.
|
|
83
|
-
* @param reservation - reservation to consume.
|
|
84
|
-
*/
|
|
85
|
-
discard(reservation: SessionPreparationReservation<Source, CommitState>): void;
|
|
86
|
-
/**
|
|
87
|
-
* Return a reusable unpublished reservation to the ready LRU.
|
|
88
|
-
* @param reservation - reservation to release.
|
|
89
|
-
* @param reusable - whether the source remains valid for reuse.
|
|
90
|
-
*/
|
|
91
|
-
release(reservation: SessionPreparationReservation<Source, CommitState>, reusable: boolean): void;
|
|
92
|
-
/**
|
|
93
|
-
* Discard a prepared view after the durable log changes.
|
|
94
|
-
* @param id - changed session identity.
|
|
95
|
-
*/
|
|
96
|
-
invalidate(id: SessionId): void;
|
|
97
|
-
/**
|
|
98
|
-
* Discard an exact stale ready source without disturbing an exclusive owner.
|
|
99
|
-
* @param id - changed session identity.
|
|
100
|
-
* @param expected - exact source observed before its revision check.
|
|
101
|
-
* @returns whether the source was discarded, retained by a reservation, or is absent.
|
|
102
|
-
*/
|
|
103
|
-
discardReady(id: SessionId, expected: Source): 'discarded' | 'retained' | 'missing';
|
|
104
|
-
/**
|
|
105
|
-
* Reject writes while an unpublished Session exclusively reserves the id.
|
|
106
|
-
* @param id - session identity to check.
|
|
107
|
-
*/
|
|
108
|
-
assertWritable(id: SessionId): void;
|
|
109
|
-
/**
|
|
110
|
-
* Remove a completed entry for an already-serialized append adoption.
|
|
111
|
-
* @param id - adopted session identity.
|
|
112
|
-
* @returns the prepared source, or undefined when no ready entry exists.
|
|
113
|
-
*/
|
|
114
|
-
takeReady(id: SessionId): Source | undefined;
|
|
115
|
-
private entryFor;
|
|
116
|
-
private makeReady;
|
|
117
|
-
private remove;
|
|
118
|
-
private touch;
|
|
119
|
-
}
|
|
120
|
-
/**
|
|
121
|
-
* Give a queued observer a prompt cancellation view without cancelling shared work.
|
|
122
|
-
* @param operation - shared operation whose settlement remains authoritative.
|
|
123
|
-
* @param signal - observer-local cancellation signal.
|
|
124
|
-
* @param started - whether the operation has crossed its cancellation cutoff.
|
|
125
|
-
* @returns the operation result or the observer's prompt cancellation.
|
|
126
|
-
*/
|
|
127
|
-
export declare function observeQueuedAbort<T>(operation: Promise<T>, signal: AbortSignal, started?: () => boolean): Promise<T>;
|
|
128
|
-
export {};
|
|
129
|
-
//# sourceMappingURL=preparations.d.ts.map
|
|
@@ -1,62 +0,0 @@
|
|
|
1
|
-
/**
|
|
2
|
-
* Bounded per-session write batching for the shared persistence coordinator.
|
|
3
|
-
* @module @deepseek-ai/dsh-session-persistence/write-behind
|
|
4
|
-
*/
|
|
5
|
-
import type { SessionEvent } from '@deepseek-ai/dsh-session';
|
|
6
|
-
/** Dependencies and scheduling policy for one live session's write controller. */
|
|
7
|
-
export interface SessionWriteBehindOptions {
|
|
8
|
-
/** Maximum intentional batching wait after an idle queue receives work. */
|
|
9
|
-
readonly maxDelayMs: number;
|
|
10
|
-
/** Persist one stable ordered prefix; resolves only after backend durability. */
|
|
11
|
-
readonly write: (events: readonly SessionEvent[]) => Promise<void>;
|
|
12
|
-
/** Observe a detached background write failure without rejecting the producer. */
|
|
13
|
-
readonly reportBackgroundFailure: (error: unknown) => void;
|
|
14
|
-
}
|
|
15
|
-
/**
|
|
16
|
-
* Owns one live session's pending events, fixed batching deadline, active write,
|
|
17
|
-
* failure retention, and explicit quiescence barrier.
|
|
18
|
-
*/
|
|
19
|
-
export declare class SessionWriteBehind {
|
|
20
|
-
private readonly options;
|
|
21
|
-
private pending;
|
|
22
|
-
private timer;
|
|
23
|
-
private active;
|
|
24
|
-
private barrier;
|
|
25
|
-
private deadlineExpired;
|
|
26
|
-
private automaticPaused;
|
|
27
|
-
/**
|
|
28
|
-
* @param options - fixed scheduling policy and durable batch sink.
|
|
29
|
-
*/
|
|
30
|
-
constructor(options: SessionWriteBehindOptions);
|
|
31
|
-
/** Whether this controller owns queued events or an active durable write. */
|
|
32
|
-
get hasWork(): boolean;
|
|
33
|
-
/**
|
|
34
|
-
* Copy one event into the persistence-owned queue and start a fixed deadline
|
|
35
|
-
* when the automatic path is idle.
|
|
36
|
-
* @param event - frozen live event to retain independently of its producer.
|
|
37
|
-
*/
|
|
38
|
-
enqueue(event: SessionEvent): void;
|
|
39
|
-
/**
|
|
40
|
-
* Cancel the batching wait and durably drain through a quiescent point.
|
|
41
|
-
* Concurrent callers join the same barrier.
|
|
42
|
-
* @returns a promise that rejects if the barrier's durable retry fails.
|
|
43
|
-
*/
|
|
44
|
-
flush(): Promise<void>;
|
|
45
|
-
/** Cancel the current automatic deadline without draining retained work. */
|
|
46
|
-
cancelAutomaticWait(): void;
|
|
47
|
-
/** Start the one fixed window for the current pending prefix. */
|
|
48
|
-
private armTimer;
|
|
49
|
-
/** Cancel any pending automatic deadline. */
|
|
50
|
-
private cancelTimer;
|
|
51
|
-
/** Start a background write now, or remember that an active write used the budget. */
|
|
52
|
-
private onDeadline;
|
|
53
|
-
/** Start one detached write whose failure is reported and retained. */
|
|
54
|
-
private startBackground;
|
|
55
|
-
/** Continue immediately after an over-budget active write, otherwise keep its timer. */
|
|
56
|
-
private continueAutomatic;
|
|
57
|
-
/** Await overlapping work, drain to quiescence, and settle the shared barrier. */
|
|
58
|
-
private drainBarrier;
|
|
59
|
-
/** Start one stable pending prefix, retaining it in order if durability fails. */
|
|
60
|
-
private startWrite;
|
|
61
|
-
}
|
|
62
|
-
//# sourceMappingURL=write-behind.d.ts.map
|