dsh-context 0.36.0 → 0.38.0
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.md +5 -1
- package/lib/client.js +718 -83
- package/lib/index.d.ts +149 -317
- package/lib/index.js +125 -10
- package/package.json +9 -10
package/lib/index.d.ts
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
|
-
import {
|
|
2
|
-
import
|
|
3
|
-
import { Context
|
|
1
|
+
import { z } from "zod";
|
|
2
|
+
import "@deepseek-ai/dsh-session";
|
|
3
|
+
import { Context } from "@deepseek-ai/cordis";
|
|
4
4
|
//#region src/host/config.d.ts
|
|
5
5
|
interface Config {
|
|
6
6
|
/** Cap on kept per-step request records (the hard step backstop). */
|
|
@@ -29,13 +29,113 @@ declare const Config: z.ZodPreprocess<z.ZodObject<{
|
|
|
29
29
|
maxArchiveNodes: z.ZodDefault<z.ZodNumber>;
|
|
30
30
|
}, z.core.$strict>>;
|
|
31
31
|
//#endregion
|
|
32
|
-
//#region src/
|
|
32
|
+
//#region src/host/headers.d.ts
|
|
33
|
+
interface HeadersState {
|
|
34
|
+
headers: HeaderRecord[];
|
|
35
|
+
}
|
|
36
|
+
//#endregion
|
|
37
|
+
//#region src/host/fold.d.ts
|
|
33
38
|
/**
|
|
34
|
-
*
|
|
35
|
-
*
|
|
36
|
-
*
|
|
37
|
-
*
|
|
39
|
+
* History retention bounds (configurable since 0.11 — see config.ts; these
|
|
40
|
+
* are the defaults' values). The fold keeps per-STEP request records; once the
|
|
41
|
+
* newest run count exceeds `maxKeptTurns`, the timeline is trimmed to the
|
|
42
|
+
* most recent whole TURN runs (never cutting a turn in half), so turn
|
|
43
|
+
* granularity can always show the full recent turn range instead of a
|
|
44
|
+
* step-count fragment. The turn-run trim runs whenever the cap is crossed
|
|
45
|
+
* (not only when the raw step bound is), so the bounded state stays at the
|
|
46
|
+
* newest ~`maxKeptTurns` turns deterministically as a live log grows.
|
|
38
47
|
*/
|
|
48
|
+
interface TimelineState {
|
|
49
|
+
/** Model-visible surface, newest last. */
|
|
50
|
+
surface: SurfaceNode[];
|
|
51
|
+
sums: Record<Category, number>;
|
|
52
|
+
systemTokens: number;
|
|
53
|
+
toolsTokens: number;
|
|
54
|
+
/**
|
|
55
|
+
* The projection-cache precondition is plain JSON: a property whose value
|
|
56
|
+
* is `undefined` makes the whole checkpoint unserializable
|
|
57
|
+
* (`snapshotJsonValue` rejects it), which fails EVERY cache write for the
|
|
58
|
+
* session — including the `title` projection row that powers the session
|
|
59
|
+
* list after a restart. Optional fields therefore use absent properties
|
|
60
|
+
* (`model`/`provider`/`lastModel`/`contextWindow` are simply not set until
|
|
61
|
+
* a value is known) instead of `undefined`-valued ones. Reads via
|
|
62
|
+
* `state.model` are identical for both shapes (`undefined` on miss).
|
|
63
|
+
*/
|
|
64
|
+
model?: string;
|
|
65
|
+
provider?: string;
|
|
66
|
+
lastModel?: string;
|
|
67
|
+
contextWindow?: number;
|
|
68
|
+
requests: RequestRecord[];
|
|
69
|
+
events: ContextEventRecord[];
|
|
70
|
+
/**
|
|
71
|
+
* Recently removed surface nodes (stamped COPIES carrying `gone`), in
|
|
72
|
+
* removal order. Feeds the Context browser's per-step reconstruction.
|
|
73
|
+
* Bounded two ways in trimState: capped to `maxArchiveNodes`, and pruned
|
|
74
|
+
* to removals after the oldest retained request (older removals can only
|
|
75
|
+
* serve steps the requests trim already forgot).
|
|
76
|
+
*/
|
|
77
|
+
archived: SurfaceNode[];
|
|
78
|
+
/**
|
|
79
|
+
* Session-cost raw material: cumulative billed-token totals per DeepSeek
|
|
80
|
+
* V4 model family and pricing period (see SessionCostUsage). Running
|
|
81
|
+
* totals — never trimmed, so the estimate always covers the COMPLETE
|
|
82
|
+
* session log even after the request/event retention bounds cut in.
|
|
83
|
+
* Absent until a v4-flash / v4-pro request reports usage.
|
|
84
|
+
*/
|
|
85
|
+
cost?: SessionCostUsage;
|
|
86
|
+
archiveFloor?: number;
|
|
87
|
+
/**
|
|
88
|
+
* Whole-session timing totals (see TimingTotals) — running sums over the
|
|
89
|
+
* COMPLETE session log, like `cost`. Absent until the first step or tool
|
|
90
|
+
* lifecycle folds in; created once and cloned-on-touch afterwards (the
|
|
91
|
+
* object is shared with the persisted previous state — see `ensure`).
|
|
92
|
+
*/
|
|
93
|
+
timing?: TimingTotals;
|
|
94
|
+
/**
|
|
95
|
+
* The open step's start instant, armed by `step/start` and consumed by the
|
|
96
|
+
* `assistant/message` (LM-call time) and `step/end` (wall time) that follow
|
|
97
|
+
* it. One slot, not a map: steps are sequential in the log, so the newest
|
|
98
|
+
* `step/start` is the one those events close — a hostile interleaved log
|
|
99
|
+
* degrades to skipped durations, never to unbounded state. Same
|
|
100
|
+
* arm/remove lifecycle as `pendingShadowedSeqs`.
|
|
101
|
+
*/
|
|
102
|
+
stepStart?: {
|
|
103
|
+
time: number;
|
|
104
|
+
};
|
|
105
|
+
/**
|
|
106
|
+
* Tool callId → the call's name and start instant, armed by `tool/call` and
|
|
107
|
+
* DELETED when its `tool/result` folds in (one result per call, in log
|
|
108
|
+
* order) — the map stays at pending-call size instead of growing for the
|
|
109
|
+
* session's whole lifetime (it is persisted state, shallow-copied by every
|
|
110
|
+
* fold step). The start instant prices the call's duration into
|
|
111
|
+
* `timing.toolsMs` when the result arrives.
|
|
112
|
+
*/
|
|
113
|
+
callNames: Record<string, {
|
|
114
|
+
name: string;
|
|
115
|
+
start: number;
|
|
116
|
+
}>;
|
|
117
|
+
/**
|
|
118
|
+
* Seq list of the surface nodes the next replacement will shadow, armed by
|
|
119
|
+
* the metering event (`compaction/summary` | `compaction/prune`) and
|
|
120
|
+
* consumed by the replacement that must follow it synchronously. The
|
|
121
|
+
* producer's shadow price covers exactly these seqs — which can differ
|
|
122
|
+
* from the replacement's declared range (pruned replacement nodes keep
|
|
123
|
+
* their own seqs, beyond the range end) — so removal must follow the seqs.
|
|
124
|
+
* Absent until armed, and REMOVED (not set to `undefined`) when consumed,
|
|
125
|
+
* to keep the state plain JSON for the projection cache.
|
|
126
|
+
*/
|
|
127
|
+
pendingShadowedSeqs?: number[];
|
|
128
|
+
/**
|
|
129
|
+
* The seq of the compaction/prune event that armed `pendingShadowedSeqs` —
|
|
130
|
+
* the shadowed path rewrites that event's `tokens` from the gross shadow
|
|
131
|
+
* price to the NET freed amount (removed nodes minus the synchronous
|
|
132
|
+
* replacement), so the row matches the drop the trend chart shows. Same
|
|
133
|
+
* arm/remove lifecycle as `pendingShadowedSeqs`.
|
|
134
|
+
*/
|
|
135
|
+
pendingShadowEventSeq?: number;
|
|
136
|
+
}
|
|
137
|
+
//#endregion
|
|
138
|
+
//#region src/shared/types.d.ts
|
|
39
139
|
declare module '@deepseek-ai/dsh-session-projection/types' {
|
|
40
140
|
interface SessionProjectionMap {
|
|
41
141
|
/**
|
|
@@ -55,6 +155,10 @@ declare module '@deepseek-ai/dsh-session-projection/types' {
|
|
|
55
155
|
*/
|
|
56
156
|
contextHeaders: ContextHeaders;
|
|
57
157
|
}
|
|
158
|
+
interface SessionProjectionStateMap {
|
|
159
|
+
contextTimeline: TimelineState;
|
|
160
|
+
contextHeaders: HeadersState;
|
|
161
|
+
}
|
|
58
162
|
}
|
|
59
163
|
type Category = 'user' | 'inject' | 'assistant' | 'tool';
|
|
60
164
|
interface Snapshot {
|
|
@@ -106,6 +210,12 @@ interface Snapshot {
|
|
|
106
210
|
* request reports usage.
|
|
107
211
|
*/
|
|
108
212
|
cost?: SessionCostUsage;
|
|
213
|
+
/**
|
|
214
|
+
* Whole-session timing totals (see TimingTotals). Absent until the first
|
|
215
|
+
* step lifecycle completes in the log (older plugin builds never folded
|
|
216
|
+
* one — clients treat absence as an empty timing card).
|
|
217
|
+
*/
|
|
218
|
+
timing?: TimingTotals;
|
|
109
219
|
/**
|
|
110
220
|
* The served live surface: the newest `maxNodes` tail PLUS every live inject node older than the tail (injections land first and are
|
|
111
221
|
* few,
|
|
@@ -149,6 +259,37 @@ interface CostBucketTotals {
|
|
|
149
259
|
cacheWrite: number;
|
|
150
260
|
output: number;
|
|
151
261
|
}
|
|
262
|
+
/**
|
|
263
|
+
* One completed tool name's whole-session call tally behind the timing
|
|
264
|
+
* card's top-tools ranking (running totals, never trimmed).
|
|
265
|
+
*/
|
|
266
|
+
interface ToolTimingTotals {
|
|
267
|
+
calls: number;
|
|
268
|
+
ms: number;
|
|
269
|
+
}
|
|
270
|
+
/**
|
|
271
|
+
* Whole-session timing totals, host-folded from the durable `step/start` /
|
|
272
|
+
`step/end` / `tool/call` / `tool/result` lifecycle (running totals over the
|
|
273
|
+
* COMPLETE session log — the same never-trimmed framing as `cost`). Durations
|
|
274
|
+
* are wall-clock milliseconds: `wallMs` sums whole steps, `lmMs` the
|
|
275
|
+
* step-start → assistant-message slice (the model call), `toolsMs` the sum of
|
|
276
|
+
* per-call tool durations (parallel calls each count, so it can overlap).
|
|
277
|
+
* Absent until the first step lifecycle completes in the log.
|
|
278
|
+
*/
|
|
279
|
+
interface TimingTotals {
|
|
280
|
+
/** Summed wall time of completed steps (the session's active time). */
|
|
281
|
+
wallMs: number;
|
|
282
|
+
/** Summed step-start → assistant-message time (model-call time). */
|
|
283
|
+
lmMs: number;
|
|
284
|
+
/** Completed model calls (assistant messages folded). */
|
|
285
|
+
calls: number;
|
|
286
|
+
/** Summed per-call durations of completed tool calls. */
|
|
287
|
+
toolsMs: number;
|
|
288
|
+
/** Completed tool calls (call/result pairs folded). */
|
|
289
|
+
toolCalls: number;
|
|
290
|
+
/** Per-tool-name tallies behind the timing card's ranking (bounded). */
|
|
291
|
+
tools: Record<string, ToolTimingTotals>;
|
|
292
|
+
}
|
|
152
293
|
/** One model family's totals split by DeepSeek's pricing period (Beijing Time). */
|
|
153
294
|
interface CostFamilyUsage {
|
|
154
295
|
peak?: CostBucketTotals;
|
|
@@ -273,315 +414,6 @@ interface ContextHeaders {
|
|
|
273
414
|
headers: HeaderRecord[];
|
|
274
415
|
}
|
|
275
416
|
//#endregion
|
|
276
|
-
//#region src/host/fold.d.ts
|
|
277
|
-
/**
|
|
278
|
-
* History retention bounds (configurable since 0.11 — see config.ts; these
|
|
279
|
-
* are the defaults' values). The fold keeps per-STEP request records; once the
|
|
280
|
-
* newest run count exceeds `maxKeptTurns`, the timeline is trimmed to the
|
|
281
|
-
* most recent whole TURN runs (never cutting a turn in half), so turn
|
|
282
|
-
* granularity can always show the full recent turn range instead of a
|
|
283
|
-
* step-count fragment. The turn-run trim runs whenever the cap is crossed
|
|
284
|
-
* (not only when the raw step bound is), so the bounded state stays at the
|
|
285
|
-
* newest ~`maxKeptTurns` turns deterministically as a live log grows.
|
|
286
|
-
*/
|
|
287
|
-
interface TimelineState {
|
|
288
|
-
/** Model-visible surface, newest last. */
|
|
289
|
-
surface: SurfaceNode[];
|
|
290
|
-
sums: Record<Category, number>;
|
|
291
|
-
systemTokens: number;
|
|
292
|
-
toolsTokens: number;
|
|
293
|
-
/**
|
|
294
|
-
* The projection-cache precondition is plain JSON: a property whose value
|
|
295
|
-
* is `undefined` makes the whole checkpoint unserializable
|
|
296
|
-
* (`snapshotJsonValue` rejects it), which fails EVERY cache write for the
|
|
297
|
-
* session — including the `title` projection row that powers the session
|
|
298
|
-
* list after a restart. Optional fields therefore use absent properties
|
|
299
|
-
* (`model`/`provider`/`lastModel`/`contextWindow` are simply not set until
|
|
300
|
-
* a value is known) instead of `undefined`-valued ones. Reads via
|
|
301
|
-
* `state.model` are identical for both shapes (`undefined` on miss).
|
|
302
|
-
*/
|
|
303
|
-
model?: string;
|
|
304
|
-
provider?: string;
|
|
305
|
-
lastModel?: string;
|
|
306
|
-
contextWindow?: number;
|
|
307
|
-
requests: RequestRecord[];
|
|
308
|
-
events: ContextEventRecord[];
|
|
309
|
-
/**
|
|
310
|
-
* Recently removed surface nodes (stamped COPIES carrying `gone`), in
|
|
311
|
-
* removal order. Feeds the Context browser's per-step reconstruction.
|
|
312
|
-
* Bounded two ways in trimState: capped to `maxArchiveNodes`, and pruned
|
|
313
|
-
* to removals after the oldest retained request (older removals can only
|
|
314
|
-
* serve steps the requests trim already forgot).
|
|
315
|
-
*/
|
|
316
|
-
archived: SurfaceNode[];
|
|
317
|
-
/**
|
|
318
|
-
* Session-cost raw material: cumulative billed-token totals per DeepSeek
|
|
319
|
-
* V4 model family and pricing period (see SessionCostUsage). Running
|
|
320
|
-
* totals — never trimmed, so the estimate always covers the COMPLETE
|
|
321
|
-
* session log even after the request/event retention bounds cut in.
|
|
322
|
-
* Absent until a v4-flash / v4-pro request reports usage.
|
|
323
|
-
*/
|
|
324
|
-
cost?: SessionCostUsage;
|
|
325
|
-
archiveFloor?: number;
|
|
326
|
-
/**
|
|
327
|
-
* Tool callId → name, armed by `tool/call` and DELETED when its
|
|
328
|
-
* `tool/result` folds in (one result per call, in log order) — the map
|
|
329
|
-
* stays at pending-call size instead of growing for the session's whole
|
|
330
|
-
* lifetime (it is persisted state, shallow-copied by every fold step).
|
|
331
|
-
*/
|
|
332
|
-
callNames: Record<string, string>;
|
|
333
|
-
/**
|
|
334
|
-
* Seq list of the surface nodes the next replacement will shadow, armed by
|
|
335
|
-
* the metering event (`compaction/summary` | `compaction/prune`) and
|
|
336
|
-
* consumed by the replacement that must follow it synchronously. The
|
|
337
|
-
* producer's shadow price covers exactly these seqs — which can differ
|
|
338
|
-
* from the replacement's declared range (pruned replacement nodes keep
|
|
339
|
-
* their own seqs, beyond the range end) — so removal must follow the seqs.
|
|
340
|
-
* Absent until armed, and REMOVED (not set to `undefined`) when consumed,
|
|
341
|
-
* to keep the state plain JSON for the projection cache.
|
|
342
|
-
*/
|
|
343
|
-
pendingShadowedSeqs?: number[];
|
|
344
|
-
/**
|
|
345
|
-
* The seq of the compaction/prune event that armed `pendingShadowedSeqs` —
|
|
346
|
-
* the shadowed path rewrites that event's `tokens` from the gross shadow
|
|
347
|
-
* price to the NET freed amount (removed nodes minus the synchronous
|
|
348
|
-
* replacement), so the row matches the drop the trend chart shows. Same
|
|
349
|
-
* arm/remove lifecycle as `pendingShadowedSeqs`.
|
|
350
|
-
*/
|
|
351
|
-
pendingShadowEventSeq?: number;
|
|
352
|
-
}
|
|
353
|
-
//#endregion
|
|
354
|
-
//#region node_modules/.pnpm/@deepseek-ai+dsh-session-projection@0.1.0-rc.8_@deepseek-ai+cordis@4.0.1_@deepseek-ai+d_c0ffab70d18276fadfe75ed916313ea3/node_modules/@deepseek-ai/dsh-session-projection/lib/types/types.d.ts
|
|
355
|
-
/**
|
|
356
|
-
* Pure-type outlet of the session-projection Service Definition: the one projection type
|
|
357
|
-
* table, importable from client aggregates without dragging the host-side
|
|
358
|
-
* cordis Context merges of the package root (dsh-agent → dsh-session). Domain
|
|
359
|
-
* packages may declare-merge through either the package root or this outlet —
|
|
360
|
-
* re-export preserves symbol identity, so both land on the same table.
|
|
361
|
-
*
|
|
362
|
-
* @module @deepseek-ai/dsh-session-projection/types
|
|
363
|
-
*/
|
|
364
|
-
/**
|
|
365
|
-
* The single projection type table for the whole chain (host provider, wire
|
|
366
|
-
* block, client cell, React hook). Domain packages merge their key here via
|
|
367
|
-
* declaration merging; values are wire-JSON whole values. How a value is
|
|
368
|
-
* rendered is the slot system's business, never this layer's.
|
|
369
|
-
*/
|
|
370
|
-
interface SessionProjectionMap {}
|
|
371
|
-
//#endregion
|
|
372
|
-
//#region node_modules/.pnpm/@deepseek-ai+dsh-session-projection@0.1.0-rc.8_@deepseek-ai+cordis@4.0.1_@deepseek-ai+d_c0ffab70d18276fadfe75ed916313ea3/node_modules/@deepseek-ai/dsh-session-projection/lib/types/index.d.ts
|
|
373
|
-
declare module '@deepseek-ai/cordis' {
|
|
374
|
-
interface Context {
|
|
375
|
-
sessionProjections: SessionProjectionRegistry;
|
|
376
|
-
}
|
|
377
|
-
}
|
|
378
|
-
/**
|
|
379
|
-
* One domain's state-driven computation unit: three pure synchronous
|
|
380
|
-
* functions plus declarations — never an opaque getter. The framework drives
|
|
381
|
-
* `apply` on every committed session event; the domain holds no
|
|
382
|
-
* subscriptions and owns only the mathematics. All three functions MUST be
|
|
383
|
-
* synchronous (an async unit would tear the carriers' consistency cut) and
|
|
384
|
-
* `state` MUST be plain JSON (the persisted-cache precondition).
|
|
385
|
-
*/
|
|
386
|
-
interface ProjectionDefinition<K extends keyof SessionProjectionMap, S> {
|
|
387
|
-
/** The projection key this unit owns (its `SessionProjectionMap` entry). */
|
|
388
|
-
key: K;
|
|
389
|
-
/** Validates the wire payload (`view` output) before it leaves the host. */
|
|
390
|
-
schema: ZodType<SessionProjectionMap[K]>;
|
|
391
|
-
/**
|
|
392
|
-
* State for the empty log.
|
|
393
|
-
* @returns the initial state.
|
|
394
|
-
*/
|
|
395
|
-
init(): S;
|
|
396
|
-
/**
|
|
397
|
-
* Pure transition: previous state + one committed event → next state. A
|
|
398
|
-
* unit uninterested in an event MUST return the same state reference — an
|
|
399
|
-
* unchanged reference (`Object.is`) produces zero downstream work.
|
|
400
|
-
* @param state - the state covering all prior events.
|
|
401
|
-
* @param event - the next committed session event.
|
|
402
|
-
* @returns the next state (same reference when the event is not the unit's).
|
|
403
|
-
*/
|
|
404
|
-
apply(state: S, event: SessionEvent): S;
|
|
405
|
-
/**
|
|
406
|
-
* State → wire payload (the read-side projection).
|
|
407
|
-
* @param state - the current state.
|
|
408
|
-
* @returns the whole current value for this unit's key.
|
|
409
|
-
*/
|
|
410
|
-
view(state: S): SessionProjectionMap[K];
|
|
411
|
-
/**
|
|
412
|
-
* Persisted-cache invalidation version: bump whenever the serialized state fields or the
|
|
413
|
-
* fold semantics change, so persisted `(sessionId, key, ver, seq, val)`
|
|
414
|
-
* rows from an older unit are discarded instead of being forward-applied
|
|
415
|
-
* into garbage. Non-negative integer.
|
|
416
|
-
*/
|
|
417
|
-
stateVersion: number;
|
|
418
|
-
}
|
|
419
|
-
/**
|
|
420
|
-
* Change-feed listener: one unit's value changed for one session. `value` is
|
|
421
|
-
* the schema-validated `view` output; `seq` is the unit's watermark at
|
|
422
|
-
* emission (the seq of the event that caused the change).
|
|
423
|
-
*/
|
|
424
|
-
type ProjectionChangeListener = (session: Session, key: Extract<keyof SessionProjectionMap, string>, value: unknown, seq: number) => void;
|
|
425
|
-
/**
|
|
426
|
-
* One consistent read cut over every registered unit for one session.
|
|
427
|
-
* `asOfSeq` is the shared watermark — the seq of the last event every value
|
|
428
|
-
* reflects (`-1` for an empty log, mirroring `session/subscribed.lastSeq`).
|
|
429
|
-
*/
|
|
430
|
-
interface ProjectionSnapshot {
|
|
431
|
-
/** Seq of the last event the values reflect; -1 for an empty log. */
|
|
432
|
-
asOfSeq: number;
|
|
433
|
-
/** Whole current value per registered key. */
|
|
434
|
-
values: Partial<SessionProjectionMap>;
|
|
435
|
-
}
|
|
436
|
-
/**
|
|
437
|
-
* One unit's checkpoint: its internal state (plain JSON by the unit
|
|
438
|
-
* contract), the seq of the last event folded into it, and the unit
|
|
439
|
-
* `stateVersion` that produced it — the persisted projection-cache row
|
|
440
|
-
* `(sessionId, key, ver, seq, val)` minus the two outer keys. A row is
|
|
441
|
-
* never authoritative, only a fold shortcut: `restore` discards it on a
|
|
442
|
-
* version mismatch or when it claims events past the stored log end.
|
|
443
|
-
*/
|
|
444
|
-
interface ProjectionCheckpointRow {
|
|
445
|
-
/** The registering unit's `stateVersion` at fold time. */
|
|
446
|
-
ver: number;
|
|
447
|
-
/** Seq of the last event folded into `val`; -1 for the empty log. */
|
|
448
|
-
seq: number;
|
|
449
|
-
/** The unit's internal state — plain JSON per the unit contract. */
|
|
450
|
-
val: unknown;
|
|
451
|
-
}
|
|
452
|
-
/** Checkpoint rows keyed by projection key (one session's persisted cache value). */
|
|
453
|
-
type ProjectionCheckpoint = Record<string, ProjectionCheckpointRow>;
|
|
454
|
-
/**
|
|
455
|
-
* `ctx.sessionProjections`: the projection unit table and its drive. The
|
|
456
|
-
* service subscribes to `session/event` once; every committed event passes
|
|
457
|
-
* every registered unit's `apply` (eager drive), and a changed state
|
|
458
|
-
* reference notifies the change feed with the schema-validated view.
|
|
459
|
-
* Cells build lazily — a unit registered after events flowed, or a session
|
|
460
|
-
* older than the registry, folds `init` over the in-memory log on first
|
|
461
|
-
* touch (event or read). Registration is an effect (disposer rides the
|
|
462
|
-
* calling fiber): an unloaded domain plugin's key disappears from snapshots
|
|
463
|
-
* and clients read it as capability absence. Domain
|
|
464
|
-
* plugins register under `ctx.inject(['sessionProjections'], …)` so headless
|
|
465
|
-
* assemblies without the registry stay unaffected. Registrants sharing a key
|
|
466
|
-
* share one unit and are counted: the same tool package mounted in N agent
|
|
467
|
-
* presets registers N times, and the key survives until the last one
|
|
468
|
-
* unloads.
|
|
469
|
-
*/
|
|
470
|
-
declare class SessionProjectionRegistry extends Service {
|
|
471
|
-
private readonly registrations;
|
|
472
|
-
private readonly listeners;
|
|
473
|
-
/**
|
|
474
|
-
* Create and install the registry as `ctx.sessionProjections`.
|
|
475
|
-
* @param ctx - Cordis context that owns the service.
|
|
476
|
-
*/
|
|
477
|
-
constructor(ctx: Context);
|
|
478
|
-
/**
|
|
479
|
-
* Register one domain's unit. The registration is an effect on the calling
|
|
480
|
-
* context's fiber: disposing the fiber (or calling the returned disposer)
|
|
481
|
-
* removes the key — and the unit's cached cells — from subsequent drives
|
|
482
|
-
* and snapshots.
|
|
483
|
-
* @param definition - key, state schema, pure unit functions, and stateVersion.
|
|
484
|
-
* @returns the exact disposer that unregisters this unit.
|
|
485
|
-
*/
|
|
486
|
-
register<K extends keyof SessionProjectionMap, S>(definition: ProjectionDefinition<K, S>): () => void;
|
|
487
|
-
/**
|
|
488
|
-
* Subscribe to the change feed. The registration is an effect on the
|
|
489
|
-
* calling context's fiber.
|
|
490
|
-
* @param listener - called once per unit whose state reference changed, per committed event.
|
|
491
|
-
* @returns the exact disposer that unsubscribes.
|
|
492
|
-
*/
|
|
493
|
-
onChanged(listener: ProjectionChangeListener): () => void;
|
|
494
|
-
/**
|
|
495
|
-
* One consistent cut over every registered unit for one session, read from
|
|
496
|
-
* the watermark cache (missing cells fold lazily over the in-memory log).
|
|
497
|
-
* Fully synchronous — every value and `asOfSeq` reflect the same log
|
|
498
|
-
* position. Each value passes its unit's schema before leaving.
|
|
499
|
-
* @param session - the session whose projection values are read.
|
|
500
|
-
* @returns the snapshot; `values` is empty when no unit is registered.
|
|
501
|
-
*/
|
|
502
|
-
snapshot(session: Session): ProjectionSnapshot;
|
|
503
|
-
/**
|
|
504
|
-
* State-level checkpoint of every registered unit for one session, read
|
|
505
|
-
* from the watermark cache (missing cells fold lazily over the in-memory
|
|
506
|
-
* log). This is the write side of the persisted projection cache: the
|
|
507
|
-
* returned rows are the `(key → {ver, seq, val})` part of the durable
|
|
508
|
-
* `(sessionId, key, ver, seq, val)`
|
|
509
|
-
* rows. Every `val` is a DETACHED structured clone — never the live
|
|
510
|
-
* cell reference: the watermark cache is this registry's authoritative
|
|
511
|
-
* mutable state, and a caller reaching the live reference could corrupt
|
|
512
|
-
* every subsequent snapshot and frame through it (plain JSON by the unit
|
|
513
|
-
* contract, so the clone is total).
|
|
514
|
-
* @param session - the session whose unit states are checkpointed.
|
|
515
|
-
* @returns one row per registered key; empty when no unit is registered.
|
|
516
|
-
*/
|
|
517
|
-
checkpoint(session: Session): ProjectionCheckpoint;
|
|
518
|
-
/**
|
|
519
|
-
* The stored seq a {@link restore} tail read over `checkpoint` must start
|
|
520
|
-
* at: one event BELOW the lowest usable watermark (a row is usable when
|
|
521
|
-
* its `ver` matches the live unit's `stateVersion`; an absent or mismatched row
|
|
522
|
-
* pulls the floor to `0` — that key must refold the full log). The
|
|
523
|
-
* one-below anchor is load-bearing: the tail then proves how far the
|
|
524
|
-
* stored log still extends, so {@link restore} can detect a log that
|
|
525
|
-
* shrank below a row's watermark (crash-repair truncation) instead of
|
|
526
|
-
* serving the stale row as current — an empty tail read from the anchor
|
|
527
|
-
* yields an end below every watermark and the restore rejects for a full
|
|
528
|
-
* re-read.
|
|
529
|
-
* @param checkpoint - persisted rows for one session (possibly stale or empty).
|
|
530
|
-
* @returns the seq to hand the persistence `readFrom`, or `undefined`
|
|
531
|
-
* when no unit is registered (no read needed — {@link restore} would
|
|
532
|
-
* serve empty values regardless).
|
|
533
|
-
*/
|
|
534
|
-
restoreFloor(checkpoint: ProjectionCheckpoint): number | undefined;
|
|
535
|
-
/**
|
|
536
|
-
* View a checkpoint's rows without any log read: for every registered
|
|
537
|
-
* unit whose row's `ver` matches, serve the schema-validated
|
|
538
|
-
* `view` of the stored state; mismatched or absent rows leave their key
|
|
539
|
-
* absent (a cold or listing consumer treats it as not-yet-available and a
|
|
540
|
-
* fuller read path refolds it). The zero-I/O rung of the read ladder —
|
|
541
|
-
* values are as stale as their rows, never wrong.
|
|
542
|
-
* @param checkpoint - persisted rows for one session (possibly stale or empty).
|
|
543
|
-
* @returns whole values per key with a usable row; empty when none.
|
|
544
|
-
*/
|
|
545
|
-
viewCheckpoint(checkpoint: ProjectionCheckpoint): Partial<SessionProjectionMap>;
|
|
546
|
-
/**
|
|
547
|
-
* Cold read: fold every registered unit over a stored log suffix, seeding
|
|
548
|
-
* each from its checkpoint row when usable — the one read recipe (cached
|
|
549
|
-
* state + forward tail replay + `view`) applied without a live `Session`.
|
|
550
|
-
* Call with the events returned by a persistence
|
|
551
|
-
* `readFrom(id, restoreFloor(checkpoint))` and that same floor as
|
|
552
|
-
* `baseSeq`; the floor's one-below anchor makes the supplied end honest,
|
|
553
|
-
* so a shrunk log is detected here. A row is usable iff its
|
|
554
|
-
* `ver` matches the live unit's `stateVersion`, it does not predate `baseSeq`
|
|
555
|
-
* (`seq >= baseSeq - 1`), and it does not claim events past the
|
|
556
|
-
* supplied end (`seq <= endSeq`); an unusable row is discarded
|
|
557
|
-
* and its key refolds from `init` — which is only sound over the full
|
|
558
|
-
* log, so a discarded row with `baseSeq > 0` throws (the caller re-reads
|
|
559
|
-
* from seq 0, e.g. after a crash-repair truncation shrank the log below
|
|
560
|
-
* a row's watermark).
|
|
561
|
-
* @param checkpoint - persisted rows for one session (possibly stale or empty).
|
|
562
|
-
* @param events - the stored events with `seq >= baseSeq`, in seq order.
|
|
563
|
-
* @param baseSeq - the seq `events` starts at (its first event's seq when non-empty).
|
|
564
|
-
* @returns the snapshot cut at the supplied log end (`asOfSeq` is the last
|
|
565
|
-
* supplied event's seq, `baseSeq - 1` for an empty tail) plus the
|
|
566
|
-
* refreshed checkpoint rows at that cut, ready for a durable write-back.
|
|
567
|
-
*/
|
|
568
|
-
restore(checkpoint: ProjectionCheckpoint, events: readonly SessionEvent[], baseSeq: number): {
|
|
569
|
-
snapshot: ProjectionSnapshot;
|
|
570
|
-
checkpoint: ProjectionCheckpoint;
|
|
571
|
-
};
|
|
572
|
-
/** Fold one unit from init over `events`, producing a cell watermarked at the last folded event. */
|
|
573
|
-
private buildCell;
|
|
574
|
-
/** Read (or lazily build, folding the full in-memory log) one unit's cell. */
|
|
575
|
-
private cellFor;
|
|
576
|
-
/** Eager drive: pass one committed event through every registered unit; notify on changed references. */
|
|
577
|
-
private drive;
|
|
578
|
-
}
|
|
579
|
-
//#endregion
|
|
580
|
-
//#region src/host/headers.d.ts
|
|
581
|
-
interface HeadersState {
|
|
582
|
-
headers: HeaderRecord[];
|
|
583
|
-
}
|
|
584
|
-
//#endregion
|
|
585
417
|
//#region src/host/index.d.ts
|
|
586
418
|
declare const name = "dsh-context";
|
|
587
419
|
declare const inject: string[];
|