@deepseek-ai/dsh-session 0.0.1-rc.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/LICENSE +28 -0
- package/README.i18n.yaml +6 -0
- package/README.md +143 -0
- package/README.zh.md +143 -0
- package/lib/index.js +1841 -0
- package/lib/invariant.js +168 -0
- package/lib/types/chunk-rows.d.ts +92 -0
- package/lib/types/chunk-rows.js +301 -0
- package/lib/types/index.d.ts +424 -0
- package/lib/types/index.js +1015 -0
- package/lib/types/invariant.d.ts +18 -0
- package/lib/types/invariant.js +199 -0
- package/lib/types/json.d.ts +36 -0
- package/lib/types/json.js +174 -0
- package/lib/types/preparation.d.ts +33 -0
- package/lib/types/preparation.js +37 -0
- package/lib/types/repair.d.ts +38 -0
- package/lib/types/repair.js +144 -0
- package/lib/types/request-header.d.ts +35 -0
- package/lib/types/request-header.js +65 -0
- package/lib/types/surface.d.ts +123 -0
- package/lib/types/surface.js +377 -0
- package/lib/types/types.d.ts +426 -0
- package/lib/types/types.js +18 -0
- package/package.json +60 -0
|
@@ -0,0 +1,424 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Event-sourced session service: append-only session log, in-memory store, and
|
|
3
|
+
* the derived LLM message history. Persistence is a plugin concern (subscribe
|
|
4
|
+
* to `session/event`, drain on `session/flush`).
|
|
5
|
+
*
|
|
6
|
+
* @module @deepseek-ai/dsh-session
|
|
7
|
+
*/
|
|
8
|
+
import { Context, Service } from '@deepseek-ai/cordis';
|
|
9
|
+
import type { Scoped } from '@deepseek-ai/dsh-scope';
|
|
10
|
+
import type { Message } from '@deepseek-ai/dsh-llm';
|
|
11
|
+
import { SessionId } from './types.ts';
|
|
12
|
+
import type { TypeRTLookup } from '@deepseek-ai/dsh-type-meta';
|
|
13
|
+
import type { CreateSessionOptions, EpochHeader, PrepareSessionOptions, RequestContext, SessionEvent, SessionEventMap, SessionEventType, SessionHeader, SurfaceIntent, SurfaceEventType } from './types.ts';
|
|
14
|
+
import type { SessionSurface } from './surface.ts';
|
|
15
|
+
export * from './types.ts';
|
|
16
|
+
export { SessionPreparation } from './preparation.ts';
|
|
17
|
+
export type { SessionPreparationOptions } from './preparation.ts';
|
|
18
|
+
export type { AssistantMessage, ToolResultMessage, UserMessage } from '@deepseek-ai/dsh-llm';
|
|
19
|
+
export { isJsonValue, snapshotJsonValue } from './json.ts';
|
|
20
|
+
export type { JsonValue } from './json.ts';
|
|
21
|
+
export { interruptedTurnClosers, lastActivityTime, TOOL_NOT_STARTED, TOOL_OUTCOME_UNKNOWN } from './repair.ts';
|
|
22
|
+
export { decodeStorageRecord, packChunkRuns } from './chunk-rows.ts';
|
|
23
|
+
export type { ChunkRow, StorageRecord } from './chunk-rows.ts';
|
|
24
|
+
export type { SessionSurface, SurfaceFoldReplacement, SurfaceFoldResult } from './surface.ts';
|
|
25
|
+
export { deriveEventMessage, foldSurface, isAppendSurfaceEvent, isReplacementSurfaceEvent, isSurfaceEvent, isSurfaceEligibleType } from './surface.ts';
|
|
26
|
+
export { canonicalHeader, foldRequestHeader, headerEquals } from './request-header.ts';
|
|
27
|
+
/**
|
|
28
|
+
* Find the latest closed turn that entered at least one model step, ignoring
|
|
29
|
+
* balanced no-step turns produced by rejection, empty input, or cancellation.
|
|
30
|
+
* @param events - session events, or an owned suffix, to inspect.
|
|
31
|
+
* @returns the latest matching turn end, or `undefined`.
|
|
32
|
+
*/
|
|
33
|
+
export declare function findLastMessageTurnEnd(events: readonly SessionEvent[]): SessionEvent<'turn/end'> | undefined;
|
|
34
|
+
declare module '@deepseek-ai/cordis' {
|
|
35
|
+
interface Context {
|
|
36
|
+
sessions: SessionStore;
|
|
37
|
+
}
|
|
38
|
+
interface Events {
|
|
39
|
+
/**
|
|
40
|
+
* Creation announcement during session publication. A synchronous throw vetoes and rolls
|
|
41
|
+
* back with a paired disposal; detach requested during dispatch is deferred.
|
|
42
|
+
* A returned-promise rejection is logged but cannot retroactively veto this
|
|
43
|
+
* synchronous boundary.
|
|
44
|
+
* Scope-filtered dispatch (`@deepseek-ai/dsh-scope`): agent-scoped listeners
|
|
45
|
+
* receive only sessions entered through that agent's context.
|
|
46
|
+
* @param session - the session just entered and announced.
|
|
47
|
+
* @dshScopeScan unsupported
|
|
48
|
+
* @mode emit
|
|
49
|
+
*/
|
|
50
|
+
'session/created'(this: Scoped<Session>, session: Session): void;
|
|
51
|
+
/**
|
|
52
|
+
* Emitted once when an announced session leaves the store, including
|
|
53
|
+
* publication rollback, but never for an entry whose creation announcement
|
|
54
|
+
* did not begin. Listener failures are logged and contained.
|
|
55
|
+
* Scope-filtered dispatch (`@deepseek-ai/dsh-scope`) reuses the owner scope.
|
|
56
|
+
* @param session - the session that is no longer live in the store.
|
|
57
|
+
* @dshScopeScan unsupported
|
|
58
|
+
* @mode emit
|
|
59
|
+
*/
|
|
60
|
+
'session/disposed'(this: Scoped<Session>, session: Session): void;
|
|
61
|
+
/**
|
|
62
|
+
* Post-commit, fire-and-forget append feed. The listener snapshot resolves
|
|
63
|
+
* before the log push, but callbacks run after it; observer failures are
|
|
64
|
+
* logged and contained without making the committed append fail.
|
|
65
|
+
* Scope-filtered dispatch (`@deepseek-ai/dsh-scope`): agent-scoped listeners
|
|
66
|
+
* receive only events from sessions entered through that agent's context.
|
|
67
|
+
* @param session - the session whose log grew.
|
|
68
|
+
* @param event - the appended event, exactly as recorded.
|
|
69
|
+
* @dshScopeScan unsupported
|
|
70
|
+
* @mode emit
|
|
71
|
+
*/
|
|
72
|
+
'session/event'(this: Scoped<Session>, session: Session, event: SessionEvent): void;
|
|
73
|
+
/**
|
|
74
|
+
* Awaited parallel durability checkpoint: every listener runs and the
|
|
75
|
+
* caller awaits all of them, with no waterfall veto. Scope-filtered dispatch
|
|
76
|
+
* (`@deepseek-ai/dsh-scope`) reuses the session's owner scope.
|
|
77
|
+
* @param session - the session whose buffered events must reach durable storage.
|
|
78
|
+
* @dshScopeScan unsupported
|
|
79
|
+
* @mode parallel
|
|
80
|
+
*/
|
|
81
|
+
'session/flush'(this: Scoped<Session>, session: Session): Promise<void> | void;
|
|
82
|
+
}
|
|
83
|
+
}
|
|
84
|
+
declare module '@deepseek-ai/dsh-type-meta' {
|
|
85
|
+
interface TypeRTLookupMap {
|
|
86
|
+
session: TypeRTLookup<Session, SessionId>;
|
|
87
|
+
}
|
|
88
|
+
}
|
|
89
|
+
/**
|
|
90
|
+
* Validate an exclusively owned event and deeply freeze its identified message
|
|
91
|
+
* without copying the event. The caller transfers an object graph that no
|
|
92
|
+
* producer retains and that shares no mutable children with another event.
|
|
93
|
+
* Use {@link snapshotSessionEvent} when exclusive ownership is not guaranteed.
|
|
94
|
+
* @param event - exclusively owned event imported across a trusted boundary.
|
|
95
|
+
* @returns the same event object with a validated, deeply frozen message.
|
|
96
|
+
*/
|
|
97
|
+
export declare function adoptSessionEvent<T extends SessionEvent>(event: T): T;
|
|
98
|
+
/**
|
|
99
|
+
* Detach one event while preserving deep immutability for its identified message.
|
|
100
|
+
* @param event - event imported across a query or persistence boundary.
|
|
101
|
+
* @returns a detached event snapshot with a validated, deeply frozen message.
|
|
102
|
+
*/
|
|
103
|
+
export declare function snapshotSessionEvent<T extends SessionEvent>(event: T): T;
|
|
104
|
+
/**
|
|
105
|
+
* An event-sourced session: an append-only log of {@link SessionEvent}s.
|
|
106
|
+
*
|
|
107
|
+
* Plain class (not a Service) — create live instances via
|
|
108
|
+
* `ctx.sessions.create()` and detached instances via {@link create}.
|
|
109
|
+
* Seeding with an existing event log replays/forks a session.
|
|
110
|
+
* @typert object
|
|
111
|
+
*/
|
|
112
|
+
export declare class Session {
|
|
113
|
+
private log;
|
|
114
|
+
/** Single incremental owner of surface acceptance and projection state. */
|
|
115
|
+
private readonly surfaceManager;
|
|
116
|
+
/** The ordered surface over this session's event log. */
|
|
117
|
+
get surface(): SessionSurface;
|
|
118
|
+
/**
|
|
119
|
+
* Detached, deep-frozen creation metadata (format version, cwd, lineage,
|
|
120
|
+
* seed boundary). Supplied by the store via `ctx.sessions.create()`. When a
|
|
121
|
+
* `Session` is created without a store-owned header, a minimal header is
|
|
122
|
+
* synthesized (stamped with the current {@link SESSION_FORMAT_VERSION}) so
|
|
123
|
+
* `session.header` is always present. Kept out of the event log — it is a
|
|
124
|
+
* storage concern, not replayable conversation state.
|
|
125
|
+
*/
|
|
126
|
+
readonly header: SessionHeader;
|
|
127
|
+
/** The session identity, derived from its durable header's single copy. */
|
|
128
|
+
get id(): SessionId;
|
|
129
|
+
/**
|
|
130
|
+
* The first seq appended IN THIS PROCESS: the length of the constructor
|
|
131
|
+
* seed (0 without one). Events with smaller seq values entered through
|
|
132
|
+
* construction — replay, fork, or resume — and were never published on the
|
|
133
|
+
* `session/event` firehose (constructor seeds do not emit), so consumers
|
|
134
|
+
* that replay the log as a publication substitute (telemetry adoption)
|
|
135
|
+
* start here. Distinct from `header.seedLength`, the DURABLE fork-lineage
|
|
136
|
+
* boundary: a resumed session's constructor seed is its full stored log,
|
|
137
|
+
* while its header keeps the original fork value — this field is the
|
|
138
|
+
* in-process construction fact.
|
|
139
|
+
*
|
|
140
|
+
* Not persisted itself: a seeded session projects it into the log as the
|
|
141
|
+
* `session/end-seed` event, which is what a consumer reading STORED history
|
|
142
|
+
* reads. Locate the LAST such event, not necessarily one at this seq — a
|
|
143
|
+
* seed already ending in one is not re-marked, so reopening an untouched
|
|
144
|
+
* session leaves that event at a smaller seq than `firstLiveSeq`. Prefer
|
|
145
|
+
* this field in-process: it is exact before the marker reaches storage.
|
|
146
|
+
*
|
|
147
|
+
* When this lifecycle appends the marker, it occupies this seq before the
|
|
148
|
+
* store attaches and therefore does not publish either. Otherwise this seq
|
|
149
|
+
* holds an ordinary published write.
|
|
150
|
+
*/
|
|
151
|
+
readonly firstLiveSeq: number;
|
|
152
|
+
/**
|
|
153
|
+
* Create a detached session by validating and snapshotting borrowed seed
|
|
154
|
+
* events and storage metadata.
|
|
155
|
+
* @param id - session identity.
|
|
156
|
+
* @param seed - optional borrowed replay or fork events.
|
|
157
|
+
* @param header - optional borrowed storage metadata.
|
|
158
|
+
* @returns a detached session.
|
|
159
|
+
*/
|
|
160
|
+
static create(id: SessionId, seed?: readonly SessionEvent[], header?: SessionHeader): Session;
|
|
161
|
+
/**
|
|
162
|
+
* Restore a detached session by taking ownership of fresh persistence values.
|
|
163
|
+
* The storage format, event envelopes, sequence continuity, surface transitions,
|
|
164
|
+
* and header fields are validated before the restored objects are frozen.
|
|
165
|
+
* @param id - restored session identity.
|
|
166
|
+
* @param seed - fresh detached events whose ownership is transferred.
|
|
167
|
+
* @param header - fresh detached metadata whose ownership is transferred.
|
|
168
|
+
* @returns a restored detached session.
|
|
169
|
+
*/
|
|
170
|
+
static fromRestore(id: SessionId, seed: readonly SessionEvent[], header: SessionHeader): Session;
|
|
171
|
+
private constructor();
|
|
172
|
+
/** Cached immutable public snapshot of the private append-only log. */
|
|
173
|
+
private eventsSnapshot;
|
|
174
|
+
/**
|
|
175
|
+
* An immutable snapshot of the append-only event log. The snapshot is reused
|
|
176
|
+
* until the next append; a previously returned array does not grow later.
|
|
177
|
+
* Events and their nested data are deep-frozen at acceptance, so neither a
|
|
178
|
+
* cast nor ordinary JavaScript can rewrite durable history.
|
|
179
|
+
*/
|
|
180
|
+
get events(): readonly SessionEvent[];
|
|
181
|
+
/** The next event's sequence number — always the log length (the `seq = log.length` contiguity contract). */
|
|
182
|
+
get seq(): number;
|
|
183
|
+
/**
|
|
184
|
+
* Append one typed event to the log and synchronously notify observers via
|
|
185
|
+
* the store-owned, module-private publication hooks. The hot path never blocks
|
|
186
|
+
* on I/O — persistence plugins buffer asynchronously. Once the event enters
|
|
187
|
+
* the log, the append is committed: observer failures are logged and
|
|
188
|
+
* contained per listener, so they do not change the return value or prevent
|
|
189
|
+
* later listeners from observing the same accepted event.
|
|
190
|
+
*
|
|
191
|
+
* @param type - The event type (key of {@link SessionEventMap}).
|
|
192
|
+
* @param data - The event payload; must be JSON-serializable.
|
|
193
|
+
* @param opts - Surface metadata: `surfaceOp` controls how the event enters
|
|
194
|
+
* the ordered surface; `sourceEventSeqs` lists the seq numbers of earlier
|
|
195
|
+
* events this one derives from. REQUIRED for
|
|
196
|
+
* {@link SurfaceEventType} events (every message-producing event must
|
|
197
|
+
* declare how it joins the surface, the sole source of derived model
|
|
198
|
+
* history) and
|
|
199
|
+
* rejected by the compiler for non-surface types like `turn/start` or
|
|
200
|
+
* `assistant/chunk`.
|
|
201
|
+
* @returns the logged event — its assigned `seq`/`time` plus the SNAPSHOT of
|
|
202
|
+
* `data` that entered the log, so reading `event.data` back sees the logged
|
|
203
|
+
* value, never the caller's still-mutable input.
|
|
204
|
+
* @throws if `data` or surface metadata is not losslessly JSON-serializable
|
|
205
|
+
* (BigInt, function, symbol, undefined, negative zero, non-finite number,
|
|
206
|
+
* circular reference, sparse array, or an exotic object such as
|
|
207
|
+
* Map/Set/Date/class instance), or when the candidate violates the
|
|
208
|
+
* canonical surface contract (marker shape and eligibility, unique
|
|
209
|
+
* earlier source-event references, positional replacement validity, and complete
|
|
210
|
+
* shadowed-node coverage). One recursive pass reads, validates, and
|
|
211
|
+
* copies each nested value once, so a stateful getter cannot supply one value
|
|
212
|
+
* to validation and another to storage. The event log is the durable source
|
|
213
|
+
* of truth, so a bad event fails at the append site rather than later during
|
|
214
|
+
* a backend flush. A synchronous internal dispatch validation failure or an
|
|
215
|
+
* append reentered while this acceptance/publication boundary is open also
|
|
216
|
+
* rejects before the log changes.
|
|
217
|
+
*/
|
|
218
|
+
append<T extends SessionEventType>(type: T, data: SessionEventMap[T], ...opts: T extends SurfaceEventType ? [opts: SurfaceIntent] : []): SessionEvent<T>;
|
|
219
|
+
/** Cached fold of the request-header events — see {@link requestHeader}. */
|
|
220
|
+
private headerFold;
|
|
221
|
+
/** Log position (events consumed) the header fold has reached. */
|
|
222
|
+
private headerFoldSeq;
|
|
223
|
+
/**
|
|
224
|
+
* The {@link EpochHeader} in force after the log's last header event — the
|
|
225
|
+
* header the NEXT request will be compared against — or undefined before
|
|
226
|
+
* the first `request/header` snapshot. The live, incrementally-maintained
|
|
227
|
+
* form of `foldRequestHeader(session.events)`: each header event is folded
|
|
228
|
+
* once, when first seen, so a per-step read costs O(new events).
|
|
229
|
+
* @returns the folded header, or undefined when no header event exists yet.
|
|
230
|
+
*/
|
|
231
|
+
requestHeader(): EpochHeader | undefined;
|
|
232
|
+
/** Cached fold of `request/context` events. */
|
|
233
|
+
private contextFold;
|
|
234
|
+
private contextFoldSeq;
|
|
235
|
+
/**
|
|
236
|
+
* Return the latest resolved route metadata, or `undefined` before the first
|
|
237
|
+
* `request/context` event. Each event is folded once.
|
|
238
|
+
* @returns the latest immutable route metadata.
|
|
239
|
+
*/
|
|
240
|
+
requestContext(): RequestContext | undefined;
|
|
241
|
+
/** The derived-message cache: frozen projections, extended per unseen node. */
|
|
242
|
+
private derived;
|
|
243
|
+
/** Surface position (nodes projected) the cache has reached. */
|
|
244
|
+
private derivedNodes;
|
|
245
|
+
/** {@link SurfaceManager.replaceGeneration} the cache was built under. */
|
|
246
|
+
private derivedGeneration;
|
|
247
|
+
/**
|
|
248
|
+
* Derive the LLM message history by walking the ordered sequences of
|
|
249
|
+
* message-producing events maintained by `surfaceOp` markers. The
|
|
250
|
+
* surface is the single source of derived history: every message-producing
|
|
251
|
+
* append records its `surfaceOp`, so a raw event with no marker (a chunk, a
|
|
252
|
+
* turn boundary) is correctly absent, and a compaction `replace` deletes the
|
|
253
|
+
* shadowed nodes from the derivation. The projection rules are
|
|
254
|
+
* {@link deriveEventMessage}, folded per node.
|
|
255
|
+
*
|
|
256
|
+
* CACHED: each surface node is projected exactly once, when first seen — a
|
|
257
|
+
* call costs O(new nodes), and a surface rewrite (a `replace`;
|
|
258
|
+
* {@link SessionSurface.replaceGeneration}) rebuilds. The returned array is
|
|
259
|
+
* a fresh snapshot per call (later appends never grow an array a caller
|
|
260
|
+
* already holds); the `Message` objects in it are SHARED and **deep-frozen**.
|
|
261
|
+
* Their content reuses the already frozen durable event data, so the cache
|
|
262
|
+
* needs no second deep clone and consumers still cannot mutate the log.
|
|
263
|
+
* @returns a fresh array of the shared, frozen derived history.
|
|
264
|
+
*/
|
|
265
|
+
deriveMessages(): Message[];
|
|
266
|
+
/**
|
|
267
|
+
* Instance face of the pure per-node `deriveEventMessage` export from
|
|
268
|
+
* `surface.ts`.
|
|
269
|
+
* @param event - the event to project.
|
|
270
|
+
* @returns the derived message, or null when the event produces none.
|
|
271
|
+
*/
|
|
272
|
+
deriveEventMessage(event: SessionEvent): Message | null;
|
|
273
|
+
}
|
|
274
|
+
/** A fork source: either the live session object or its live store id. */
|
|
275
|
+
export type SessionForkSource = Session | SessionId;
|
|
276
|
+
/**
|
|
277
|
+
* Rejection codes for session forking: the fork source id is unknown to the
|
|
278
|
+
* live store (`SESSION_NOT_FOUND`) or names a session object that is not the
|
|
279
|
+
* store's live instance (`SESSION_NOT_LIVE`); the requested child id is
|
|
280
|
+
* already taken (`SESSION_ALREADY_EXISTS`); the boundary is not a contiguous
|
|
281
|
+
* existing seq (`INVALID_BOUNDARY`); or the selected prefix ends inside an
|
|
282
|
+
* open turn (`OPEN_TURN`).
|
|
283
|
+
*/
|
|
284
|
+
export type SessionForkErrorCode = 'SESSION_NOT_FOUND' | 'SESSION_NOT_LIVE' | 'SESSION_ALREADY_EXISTS' | 'INVALID_BOUNDARY' | 'OPEN_TURN';
|
|
285
|
+
/** Typed error for session fork rejections. */
|
|
286
|
+
export declare class SessionForkError extends Error {
|
|
287
|
+
readonly code: SessionForkErrorCode;
|
|
288
|
+
constructor(message: string, code: SessionForkErrorCode);
|
|
289
|
+
}
|
|
290
|
+
/**
|
|
291
|
+
* In-memory session store (`ctx.sessions`).
|
|
292
|
+
*
|
|
293
|
+
* Persistence is intentionally not implemented here — persistence plugins
|
|
294
|
+
* subscribe to `session/event` and flush on `session/flush` / dispose.
|
|
295
|
+
*/
|
|
296
|
+
export declare class SessionStore extends Service {
|
|
297
|
+
private store;
|
|
298
|
+
private counter;
|
|
299
|
+
constructor(ctx: Context);
|
|
300
|
+
/**
|
|
301
|
+
* Create a session owned by the calling fiber: disposing that fiber stops
|
|
302
|
+
* event notification and removes the session from the store. `options.seed`
|
|
303
|
+
* populates the session with a copy of those events (replay/fork);
|
|
304
|
+
* `options.meta` attaches creation metadata (validated absolute `cwd`, seed
|
|
305
|
+
* and parent lineage, and delegation depth) as the immutable
|
|
306
|
+
* {@link SessionHeader} (the store fills `version`/`id`/`createdAt`).
|
|
307
|
+
*
|
|
308
|
+
* For an agent whose session must be torn down IN ORDER with its loop (so the
|
|
309
|
+
* loop's final events are published before the store attachment ends), do NOT use this
|
|
310
|
+
* — fold the session lifecycle into the agent's own effect via
|
|
311
|
+
* {@link prepare} + {@link enter} + {@link announce} (see
|
|
312
|
+
* `dsh-agent-loop`'s creation transaction).
|
|
313
|
+
*
|
|
314
|
+
* @param id - the session id; omitted, the store mints `session-<n>`.
|
|
315
|
+
* @param options - seed events and/or creation metadata for the header.
|
|
316
|
+
* @returns the live session, already entered and announced.
|
|
317
|
+
* @throws if a session with `id` already exists, metadata is not a plain
|
|
318
|
+
* lossless-JSON record with valid scalar fields, or `meta.cwd` is a
|
|
319
|
+
* non-absolute path (storage backends key directories off it).
|
|
320
|
+
*/
|
|
321
|
+
create(id?: SessionId, options?: CreateSessionOptions): Session;
|
|
322
|
+
/**
|
|
323
|
+
* Build a session WITHOUT entering it into the store — validate the id/cwd and
|
|
324
|
+
* construct the {@link Session} (with its immutable {@link SessionHeader}).
|
|
325
|
+
* Pairs with {@link enter} + {@link announce}: a caller that owns a composite
|
|
326
|
+
* `ctx.effect` (the agent factory) folds the session lifecycle into that ONE
|
|
327
|
+
* effect so a fiber unload tears the session + agent down as a single ORDERED
|
|
328
|
+
* chain rather than as racing sibling effects — which would remove the publication hooks
|
|
329
|
+
* before the driver's closing events commit, dropping them.
|
|
330
|
+
*
|
|
331
|
+
* @param id - the session id; omitted, the store mints `session-<n>`.
|
|
332
|
+
* @param options - seed events and/or creation metadata for the header. With
|
|
333
|
+
* `seedSource: 'persistence'`, metadata and events must be fresh detached
|
|
334
|
+
* graphs whose ownership transfers to this call: they are validated and
|
|
335
|
+
* frozen in place through {@link Session.fromRestore}, so the caller must
|
|
336
|
+
* retain no mutable aliases.
|
|
337
|
+
* @returns the constructed session, NOT yet in the store.
|
|
338
|
+
* @throws if a session with `id` already exists, metadata is not a plain
|
|
339
|
+
* lossless-JSON record with valid scalar fields, or `meta.cwd` is a
|
|
340
|
+
* non-absolute path.
|
|
341
|
+
*/
|
|
342
|
+
prepare(id?: SessionId, options?: PrepareSessionOptions): Session;
|
|
343
|
+
/**
|
|
344
|
+
* Enter a {@link prepare}d session into the store: install the module-private
|
|
345
|
+
* append publication hooks and add it to the store. Returns the DETACH
|
|
346
|
+
* disposer (hooks + store removal). Does NOT emit `session/created` —
|
|
347
|
+
* the caller yields this disposer inside its effect and THEN calls
|
|
348
|
+
* {@link announce}, so a throwing `session/created` listener rolls the attach
|
|
349
|
+
* back instead of leaking it.
|
|
350
|
+
*
|
|
351
|
+
* Re-checks the id for a duplicate: `prepare` and `enter` are public
|
|
352
|
+
* cross-package primitives and a caller may interleave arbitrary work (or
|
|
353
|
+
* another create) between them, so a stale prepared session must NOT overwrite
|
|
354
|
+
* a live store entry of the same id — its detach disposer would later delete
|
|
355
|
+
* the REAL session. The {@link create} convenience and the agent factory call
|
|
356
|
+
* the two back-to-back so they never trip this, but the public API cannot
|
|
357
|
+
* assume that.
|
|
358
|
+
*
|
|
359
|
+
* @param session - a {@link prepare}d session not yet in the store.
|
|
360
|
+
* @returns the detach disposer (publication hooks + store removal). When called from
|
|
361
|
+
* a synchronous `session/created` listener, removal and disposal wait until
|
|
362
|
+
* that creation dispatch unwinds.
|
|
363
|
+
* @throws if a session with this id is already in the store.
|
|
364
|
+
*/
|
|
365
|
+
enter(session: Session): () => void;
|
|
366
|
+
/** Remove one exact entered session and emit its paired disposal when announced. */
|
|
367
|
+
private detachEntered;
|
|
368
|
+
/** Emit `session/created` exactly once for an {@link enter}ed session (with
|
|
369
|
+
* the carrier {@link enter} captured). Separate from {@link enter} so the
|
|
370
|
+
* caller can yield the detach disposer first (rollback safety — see
|
|
371
|
+
* {@link enter}).
|
|
372
|
+
* @param session - the entered session to announce to listeners.
|
|
373
|
+
* @throws if the session is not live or its announcement already began,
|
|
374
|
+
* including a reentrant call from a creation listener. */
|
|
375
|
+
announce(session: Session): void;
|
|
376
|
+
/** Emit the paired teardown notification with per-listener containment. */
|
|
377
|
+
private emitDisposed;
|
|
378
|
+
/**
|
|
379
|
+
* Dispatch the awaited `session/flush` durability checkpoint for `session`,
|
|
380
|
+
* with the carrier captured at {@link enter}. THE flush entry point: the
|
|
381
|
+
* store owns the carrier, so callers (the checkpoint policy's per-request
|
|
382
|
+
* barrier, goal-session's idle checkpoint, teardown drains, and consumers
|
|
383
|
+
* that flush themselves before reading storage) must come through here
|
|
384
|
+
* rather than dispatch a raw `ctx.parallel('session/flush', …)` — one owner,
|
|
385
|
+
* one spelling, and the scoped-dispatch invariant can pin it.
|
|
386
|
+
* @param session - the session whose buffered events must reach durable storage.
|
|
387
|
+
* @returns whether at least one durability listener participated, after every
|
|
388
|
+
* listener has settled successfully.
|
|
389
|
+
* @throws the first registered listener failure after every listener settles.
|
|
390
|
+
*/
|
|
391
|
+
flush(session: Session): Promise<boolean>;
|
|
392
|
+
/** Return the exact live entry; detached/prepared objects reject. */
|
|
393
|
+
private liveEntryFor;
|
|
394
|
+
/**
|
|
395
|
+
* Look up a live session.
|
|
396
|
+
* @param id - the session id to look up.
|
|
397
|
+
* @returns the session, or undefined when no live session has that id.
|
|
398
|
+
*/
|
|
399
|
+
get(id: SessionId): Session | undefined;
|
|
400
|
+
/**
|
|
401
|
+
* All live sessions, in creation order.
|
|
402
|
+
* @returns a fresh array; mutating it does not affect the store.
|
|
403
|
+
*/
|
|
404
|
+
list(): Session[];
|
|
405
|
+
/**
|
|
406
|
+
* Create a live child session from a stable prefix of a live source.
|
|
407
|
+
* `boundary` is an inclusive source event seq; omitted means the source's
|
|
408
|
+
* current last event. The selected slice may end with a between-turn event
|
|
409
|
+
* but must not end inside an open turn.
|
|
410
|
+
*
|
|
411
|
+
* @param source - Live source session object or id.
|
|
412
|
+
* @param boundary - Inclusive source event seq to fork through; omitted means
|
|
413
|
+
* the source's current last event, and omitted on an empty source forks an
|
|
414
|
+
* empty child.
|
|
415
|
+
* @param childSessionId - Optional child session id; omitted delegates to
|
|
416
|
+
* `SessionStore`'s id policy.
|
|
417
|
+
* @returns The created live child session.
|
|
418
|
+
*/
|
|
419
|
+
fork(source: SessionForkSource, boundary?: number, childSessionId?: SessionId): Session;
|
|
420
|
+
private _forkSeed;
|
|
421
|
+
private _resolveForkSource;
|
|
422
|
+
}
|
|
423
|
+
export default SessionStore;
|
|
424
|
+
//# sourceMappingURL=index.d.ts.map
|