dsh-context 0.22.0 → 0.22.2

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/lib/index.d.ts ADDED
@@ -0,0 +1,584 @@
1
+ import { ZodType, z } from "zod";
2
+ import { Session, SessionEvent } from "@deepseek-ai/dsh-session";
3
+ import { Context, Service } from "@deepseek-ai/cordis";
4
+ //#region src/host/config.d.ts
5
+ /** dsh-context host config. All fields optional; defaults below. */
6
+ interface Config {
7
+ /** Cap on kept per-step request records (the hard step backstop). */
8
+ maxRequestSteps?: number;
9
+ /** Newest whole-turn window kept; trimming crosses whole turns, never mid-turn. */
10
+ maxKeptTurns?: number;
11
+ /** Newest context-event records kept. */
12
+ maxEvents?: number;
13
+ /**
14
+ * Surface nodes served to the browser (newest carry the signal; live
15
+ * inject nodes are always served — they are few and land first). The
16
+ * default is deliberately generous: auto-compaction keeps the live
17
+ * surface far below it in healthy sessions, so the browser effectively
18
+ * lists EVERY live node; the bound stays as a backstop for pathological
19
+ * sessions (every projection push ships the whole value, ~150B per node).
20
+ */
21
+ maxNodes?: number;
22
+ /** Removed (shadowed) surface nodes kept for per-step reconstruction. */
23
+ maxArchiveNodes?: number;
24
+ }
25
+ /**
26
+ * The cordis `Config` validator: strict on keys, defaults on the schema fields.
27
+ * Tolerates `undefined` (a patch row without a `config:` block — defaults win).
28
+ */
29
+ declare const Config: z.ZodPreprocess<z.ZodObject<{
30
+ maxRequestSteps: z.ZodDefault<z.ZodNumber>;
31
+ maxKeptTurns: z.ZodDefault<z.ZodNumber>;
32
+ maxEvents: z.ZodDefault<z.ZodNumber>;
33
+ maxNodes: z.ZodDefault<z.ZodNumber>;
34
+ maxArchiveNodes: z.ZodDefault<z.ZodNumber>;
35
+ }, z.core.$strict>>;
36
+ //#endregion
37
+ //#region src/shared/types.d.ts
38
+ /**
39
+ * Shared wire contract — the snapshot model exchanged between the Host and
40
+ * Client halves.
41
+ *
42
+ * The Host half no longer serves this over a custom RPC channel: it is the
43
+ * `view()` payload of the `contextTimeline` session projection, registered on
44
+ * the harness's `ctx.sessionProjections` registry. The registry drives
45
+ * `apply(state, event)` over every committed session event, persists the state
46
+ * through `ctx.sessionProjectionCache`, and pushes the finished value to the
47
+ * browser as a `session/projection` frame (with a tail-page baseline), where
48
+ * the Client reads it through the framework-standard `useProjection` seat.
49
+ *
50
+ * TYPE-ONLY host-side module: both halves import these as `import type`, so
51
+ * nothing from here ever reaches the runtime bundles.
52
+ */
53
+ declare module '@deepseek-ai/dsh-session-projection/types' {
54
+ interface SessionProjectionMap {
55
+ /**
56
+ * The plugin's whole-value context timeline: current composition,
57
+ * per-request history, context events, and the model-visible surface.
58
+ * The Host folds it from the session log; clients receive the finished
59
+ * value (key absence = the plugin's host half is not composed).
60
+ */
61
+ contextTimeline: ContextTimeline;
62
+ /**
63
+ * The request-header CONTENT epochs (full system prompt + tool schemas)
64
+ * behind the timeline's envelope figures. A separate unit so the hot
65
+ * `contextTimeline` value stays lean: headers change rarely, so this
66
+ * value (and its pushes) change only when a `request/header` lands.
67
+ * The Context browser card reads it to show the actual prompt/schema
68
+ * content of a picked step (key absence = older host: tokens only).
69
+ */
70
+ contextHeaders: ContextHeaders;
71
+ }
72
+ }
73
+ /** The five priced context categories (plus system/tools handled separately). */
74
+ type Category = 'user' | 'inject' | 'assistant' | 'tool';
75
+ interface Snapshot {
76
+ ok: boolean;
77
+ model?: string;
78
+ provider?: string;
79
+ contextWindow?: number;
80
+ current: {
81
+ system: number;
82
+ tools: number;
83
+ user: number;
84
+ inject: number;
85
+ assistant: number;
86
+ tool: number;
87
+ total: number;
88
+ };
89
+ /**
90
+ * Provider-anchored occupancy of the NEXT request. LEGACY since 0.11: the
91
+ * Host no longer folds this — the Client reads the official token-meter
92
+ * `contextPressure` projection key (`useProjection('contextPressure')`)
93
+ * instead. Kept optional for wire compatibility with older clients.
94
+ */
95
+ occupancy?: {
96
+ /** Provider-reported prompt size of the most recent request (input + cache). */
97
+ pressureTokens?: number;
98
+ /** Heuristic total over the current model-visible surface. */
99
+ surfaceTokens: number;
100
+ /** `surfaceTokens` at the newest usage sample. */
101
+ sampledSurfaceTokens?: number;
102
+ /** pressureTokens + surface movement since the sample (clamped ≥ 0). */
103
+ projectedTokens?: number;
104
+ /** Newest recorded route capacity (last-wins). */
105
+ contextWindow?: number;
106
+ };
107
+ toolList: {
108
+ name: string;
109
+ tokens: number;
110
+ }[];
111
+ requests: RequestRecord[];
112
+ events: ContextEventRecord[];
113
+ /**
114
+ * Cumulative session-cost raw material (per-family, per-period billed
115
+ * token totals — see SessionCostUsage). Absent until a DeepSeek V4
116
+ * request reports usage.
117
+ */
118
+ cost?: SessionCostUsage;
119
+ /**
120
+ * The served live surface: the newest `maxNodes` tail PLUS every live
121
+ * inject node older than the tail (injections land first and are few, so
122
+ * they are pinned — otherwise a long session would price them while the
123
+ * browser could list none). Seq-ordered, oldest first.
124
+ */
125
+ nodes: SurfaceNode[];
126
+ /** Live nodes not served (the overflow beyond `maxNodes`, minus pinned injects — see `nodes`). */
127
+ droppedNodes: number;
128
+ /**
129
+ * Recently REMOVED surface nodes (compaction/prune shadows), each stamped
130
+ * with `gone` (the replacing event's seq). Together with `nodes` this lets
131
+ * the Context browser reconstruct the assembled surface of any retained
132
+ * step: alive at request R = seq < R.seq && (gone undefined || gone > R.seq).
133
+ */
134
+ archive: SurfaceNode[];
135
+ /**
136
+ * Coverage floor of the served live `nodes`: the newest seq among the
137
+ * `droppedNodes` live nodes not served. Present only when droppedNodes > 0.
138
+ */
139
+ surfaceFloor?: number;
140
+ /**
141
+ * Coverage floor of `archive`: the newest `gone` among archive entries the
142
+ * retention bounds dropped. Steps with seq < archiveFloor may miss removed
143
+ * nodes (the browser shows the reconstruction as approximate).
144
+ */
145
+ archiveFloor?: number;
146
+ }
147
+ /**
148
+ * The `contextTimeline` projection's whole value — the same snapshot the
149
+ * Client has always rendered, now delivered through the session-projection
150
+ * pipeline. `ok` is always `true` here (a delivered projection is by
151
+ * definition available); it is kept for wire compatibility with the
152
+ * snapshot shape.
153
+ */
154
+ type ContextTimeline = Snapshot;
155
+ /**
156
+ * Cumulative billed-token totals for one pricing bucket of the session-cost
157
+ * estimate (host-folded, never trimmed — running totals over the COMPLETE
158
+ * session log, immune to the request/event retention bounds).
159
+ */
160
+ interface CostBucketTotals {
161
+ /** Billed prompt tokens that missed the provider cache. */
162
+ uncached: number;
163
+ /** Billed prompt tokens served from the provider cache. */
164
+ cacheRead: number;
165
+ /** Billed prompt tokens written into the provider cache. */
166
+ cacheWrite: number;
167
+ /** Billed output tokens (reasoning included). */
168
+ output: number;
169
+ }
170
+ /** One model family's totals split by DeepSeek's UTC pricing period. */
171
+ interface CostFamilyUsage {
172
+ /** Peak windows: 01:00-04:00 and 06:00-10:00 UTC. */
173
+ peak?: CostBucketTotals;
174
+ /** All other hours (half the peak rate). */
175
+ off?: CostBucketTotals;
176
+ }
177
+ /**
178
+ * The session-cost estimate's raw material: cumulative provider-reported
179
+ * token totals per DeepSeek V4 model family (matched on the model NAME,
180
+ * provider-agnostic) and pricing period. The Client prices these with its
181
+ * hardcoded list-price table in the locale's currency. Absent until a
182
+ * deepseek-v4-flash / deepseek-v4-pro request reports usage.
183
+ */
184
+ interface SessionCostUsage {
185
+ flash?: CostFamilyUsage;
186
+ pro?: CostFamilyUsage;
187
+ }
188
+ /** One model-visible message on the surface, with its heuristic token price. */
189
+ interface SurfaceNode {
190
+ seq: number;
191
+ /** Event timestamp (ms epoch); the Client shows it when present. */
192
+ time?: number;
193
+ cat: Category;
194
+ tokens: number;
195
+ /**
196
+ * Removal marker, present only on `archive` entries: the seq of the
197
+ * replacement surface event that shadowed this node (compaction/prune).
198
+ * The node is part of the assembled context of every request with
199
+ * seq > this node.seq and seq < gone.
200
+ */
201
+ gone?: number;
202
+ form?: string;
203
+ text?: string;
204
+ tool?: string;
205
+ err?: boolean;
206
+ skill?: string;
207
+ calls?: string[];
208
+ }
209
+ /** One answered model call (a step); consecutive records of one turn form it. */
210
+ interface RequestRecord {
211
+ turn?: number;
212
+ step?: number;
213
+ time: number;
214
+ seq: number;
215
+ system: number;
216
+ tools: number;
217
+ user: number;
218
+ inject: number;
219
+ assistant: number;
220
+ tool: number;
221
+ total: number;
222
+ prompt?: number;
223
+ output?: number;
224
+ /**
225
+ * Turn-mode aggregate marker, set by the Client's aggregateByTurn (one bar
226
+ * per turn shows its LAST step's record). The Host never sets it.
227
+ */
228
+ stepCount?: number;
229
+ }
230
+ /** A notable context event (compaction, prune, injection, model switch). */
231
+ interface ContextEventRecord {
232
+ seq: number;
233
+ time: number;
234
+ kind: 'compaction' | 'prune' | 'inject' | 'model';
235
+ form?: string;
236
+ tokens?: number;
237
+ count?: number;
238
+ sub?: string;
239
+ name?: string;
240
+ from?: string;
241
+ to?: string;
242
+ /** Turn/step of the request logged right BEFORE the event (host-stamped). */
243
+ fromTurn?: number;
244
+ fromStep?: number;
245
+ /** Turn/step of the request this event contributed to (host-stamped). */
246
+ turn?: number;
247
+ step?: number;
248
+ }
249
+ /** One tool schema as assembled into a request header, with its display price. */
250
+ interface HeaderTool {
251
+ name: string;
252
+ tokens: number;
253
+ /** Producer-declared description (may be long; the browser truncates). */
254
+ description?: string;
255
+ /** The raw JSON schema object the model received (plain JSON). */
256
+ schema?: unknown;
257
+ }
258
+ /**
259
+ * One request-header epoch: the full system prompt and tool schemas in force
260
+ * from this event's seq until the next epoch. Headers change rarely (the loop
261
+ * only logs `request/header` on change), so this unit's pushes are rare and
262
+ * carrying full content is cheap.
263
+ */
264
+ interface HeaderRecord {
265
+ seq: number;
266
+ time: number;
267
+ system?: string;
268
+ tools: HeaderTool[];
269
+ }
270
+ /** The `contextHeaders` projection value: the bounded epoch list (newest last). */
271
+ interface ContextHeaders {
272
+ headers: HeaderRecord[];
273
+ }
274
+ //#endregion
275
+ //#region src/host/fold.d.ts
276
+ /**
277
+ * History retention bounds (configurable since 0.11 — see config.ts; these
278
+ * are the defaults' values). The fold keeps per-STEP request records; once the
279
+ * newest run count exceeds `maxKeptTurns`, the timeline is trimmed to the
280
+ * most recent whole TURN runs (never cutting a turn in half), so turn
281
+ * granularity can always show the full recent turn range instead of a
282
+ * step-count fragment. The turn-run trim runs whenever the cap is crossed
283
+ * (not only when the raw step bound is), so the bounded state stays at the
284
+ * newest ~`maxKeptTurns` turns deterministically as a live log grows.
285
+ */
286
+ /** The projection unit's persisted state (plain JSON, bounded see above). */
287
+ interface TimelineState {
288
+ /** Model-visible surface, newest last. */
289
+ surface: SurfaceNode[];
290
+ /** Live per-category token sums over the surface. */
291
+ sums: Record<Category, number>;
292
+ systemTokens: number;
293
+ toolsTokens: number;
294
+ toolList: {
295
+ name: string;
296
+ tokens: number;
297
+ }[];
298
+ /**
299
+ * The projection-cache precondition is plain JSON: a property whose value
300
+ * is `undefined` makes the whole checkpoint unserializable
301
+ * (`snapshotJsonValue` rejects it), which fails EVERY cache write for the
302
+ * session — including the `title` projection row that powers the session
303
+ * list after a restart. Optional fields therefore use absent properties
304
+ * (`model`/`provider`/`lastModel`/`contextWindow` are simply not set until
305
+ * a value is known) instead of `undefined`-valued ones. Reads via
306
+ * `state.model` are identical for both shapes (`undefined` on miss).
307
+ */
308
+ model?: string;
309
+ provider?: string;
310
+ lastModel?: string;
311
+ contextWindow?: number;
312
+ requests: RequestRecord[];
313
+ events: ContextEventRecord[];
314
+ /**
315
+ * Recently removed surface nodes (stamped COPIES carrying `gone`), in
316
+ * removal order. Feeds the Context browser's per-step reconstruction.
317
+ * Bounded two ways in trimState: capped to `maxArchiveNodes`, and pruned
318
+ * to removals after the oldest retained request (older removals can only
319
+ * serve steps the requests trim already forgot).
320
+ */
321
+ archived: SurfaceNode[];
322
+ /**
323
+ * Session-cost raw material: cumulative billed-token totals per DeepSeek
324
+ * V4 model family and pricing period (see SessionCostUsage). Running
325
+ * totals — never trimmed, so the estimate always covers the COMPLETE
326
+ * session log even after the request/event retention bounds cut in.
327
+ * Absent until a v4-flash / v4-pro request reports usage.
328
+ */
329
+ cost?: SessionCostUsage;
330
+ /** Newest `gone` among archive entries dropped by the retention bounds. */
331
+ archiveFloor?: number;
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
+ //#endregion
346
+ //#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
347
+ /**
348
+ * Pure-type outlet of the session-projection Service Definition: the one projection type
349
+ * table, importable from client aggregates without dragging the host-side
350
+ * cordis Context merges of the package root (dsh-agent → dsh-session). Domain
351
+ * packages may declare-merge through either the package root or this outlet —
352
+ * re-export preserves symbol identity, so both land on the same table.
353
+ *
354
+ * @module @deepseek-ai/dsh-session-projection/types
355
+ */
356
+ /**
357
+ * The single projection type table for the whole chain (host provider, wire
358
+ * block, client cell, React hook). Domain packages merge their key here via
359
+ * declaration merging; values are wire-JSON whole values. How a value is
360
+ * rendered is the slot system's business, never this layer's.
361
+ */
362
+ interface SessionProjectionMap {}
363
+ //#endregion
364
+ //#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
365
+ declare module '@deepseek-ai/cordis' {
366
+ interface Context {
367
+ sessionProjections: SessionProjectionRegistry;
368
+ }
369
+ }
370
+ /**
371
+ * One domain's state-driven computation unit: three pure synchronous
372
+ * functions plus declarations — never an opaque getter. The framework drives
373
+ * `apply` on every committed session event; the domain holds no
374
+ * subscriptions and owns only the mathematics. All three functions MUST be
375
+ * synchronous (an async unit would tear the carriers' consistency cut) and
376
+ * `state` MUST be plain JSON (the persisted-cache precondition).
377
+ */
378
+ interface ProjectionDefinition<K extends keyof SessionProjectionMap, S> {
379
+ /** The projection key this unit owns (its `SessionProjectionMap` entry). */
380
+ key: K;
381
+ /** Validates the wire payload (`view` output) before it leaves the host. */
382
+ schema: ZodType<SessionProjectionMap[K]>;
383
+ /**
384
+ * State for the empty log.
385
+ * @returns the initial state.
386
+ */
387
+ init(): S;
388
+ /**
389
+ * Pure transition: previous state + one committed event → next state. A
390
+ * unit uninterested in an event MUST return the same state reference — an
391
+ * unchanged reference (`Object.is`) produces zero downstream work.
392
+ * @param state - the state covering all prior events.
393
+ * @param event - the next committed session event.
394
+ * @returns the next state (same reference when the event is not the unit's).
395
+ */
396
+ apply(state: S, event: SessionEvent): S;
397
+ /**
398
+ * State → wire payload (the read-side projection).
399
+ * @param state - the current state.
400
+ * @returns the whole current value for this unit's key.
401
+ */
402
+ view(state: S): SessionProjectionMap[K];
403
+ /**
404
+ * Persisted-cache invalidation version: bump whenever the serialized state fields or the
405
+ * fold semantics change, so persisted `(sessionId, key, ver, seq, val)`
406
+ * rows from an older unit are discarded instead of being forward-applied
407
+ * into garbage. Non-negative integer.
408
+ */
409
+ stateVersion: number;
410
+ }
411
+ /**
412
+ * Change-feed listener: one unit's value changed for one session. `value` is
413
+ * the schema-validated `view` output; `seq` is the unit's watermark at
414
+ * emission (the seq of the event that caused the change).
415
+ */
416
+ type ProjectionChangeListener = (session: Session, key: Extract<keyof SessionProjectionMap, string>, value: unknown, seq: number) => void;
417
+ /**
418
+ * One consistent read cut over every registered unit for one session.
419
+ * `asOfSeq` is the shared watermark — the seq of the last event every value
420
+ * reflects (`-1` for an empty log, mirroring `session/subscribed.lastSeq`).
421
+ */
422
+ interface ProjectionSnapshot {
423
+ /** Seq of the last event the values reflect; -1 for an empty log. */
424
+ asOfSeq: number;
425
+ /** Whole current value per registered key. */
426
+ values: Partial<SessionProjectionMap>;
427
+ }
428
+ /**
429
+ * One unit's checkpoint: its internal state (plain JSON by the unit
430
+ * contract), the seq of the last event folded into it, and the unit
431
+ * `stateVersion` that produced it — the persisted projection-cache row
432
+ * `(sessionId, key, ver, seq, val)` minus the two outer keys. A row is
433
+ * never authoritative, only a fold shortcut: `restore` discards it on a
434
+ * version mismatch or when it claims events past the stored log end.
435
+ */
436
+ interface ProjectionCheckpointRow {
437
+ /** The registering unit's `stateVersion` at fold time. */
438
+ ver: number;
439
+ /** Seq of the last event folded into `val`; -1 for the empty log. */
440
+ seq: number;
441
+ /** The unit's internal state — plain JSON per the unit contract. */
442
+ val: unknown;
443
+ }
444
+ /** Checkpoint rows keyed by projection key (one session's persisted cache value). */
445
+ type ProjectionCheckpoint = Record<string, ProjectionCheckpointRow>;
446
+ /**
447
+ * `ctx.sessionProjections`: the projection unit table and its drive. The
448
+ * service subscribes to `session/event` once; every committed event passes
449
+ * every registered unit's `apply` (eager drive), and a changed state
450
+ * reference notifies the change feed with the schema-validated view.
451
+ * Cells build lazily — a unit registered after events flowed, or a session
452
+ * older than the registry, folds `init` over the in-memory log on first
453
+ * touch (event or read). Registration is an effect (disposer rides the
454
+ * calling fiber): an unloaded domain plugin's key disappears from snapshots
455
+ * and clients read it as capability absence. Domain
456
+ * plugins register under `ctx.inject(['sessionProjections'], …)` so headless
457
+ * assemblies without the registry stay unaffected. Registrants sharing a key
458
+ * share one unit and are counted: the same tool package mounted in N agent
459
+ * presets registers N times, and the key survives until the last one
460
+ * unloads.
461
+ */
462
+ declare class SessionProjectionRegistry extends Service {
463
+ private readonly registrations;
464
+ private readonly listeners;
465
+ /**
466
+ * Create and install the registry as `ctx.sessionProjections`.
467
+ * @param ctx - Cordis context that owns the service.
468
+ */
469
+ constructor(ctx: Context);
470
+ /**
471
+ * Register one domain's unit. The registration is an effect on the calling
472
+ * context's fiber: disposing the fiber (or calling the returned disposer)
473
+ * removes the key — and the unit's cached cells — from subsequent drives
474
+ * and snapshots.
475
+ * @param definition - key, state schema, pure unit functions, and stateVersion.
476
+ * @returns the exact disposer that unregisters this unit.
477
+ */
478
+ register<K extends keyof SessionProjectionMap, S>(definition: ProjectionDefinition<K, S>): () => void;
479
+ /**
480
+ * Subscribe to the change feed. The registration is an effect on the
481
+ * calling context's fiber.
482
+ * @param listener - called once per unit whose state reference changed, per committed event.
483
+ * @returns the exact disposer that unsubscribes.
484
+ */
485
+ onChanged(listener: ProjectionChangeListener): () => void;
486
+ /**
487
+ * One consistent cut over every registered unit for one session, read from
488
+ * the watermark cache (missing cells fold lazily over the in-memory log).
489
+ * Fully synchronous — every value and `asOfSeq` reflect the same log
490
+ * position. Each value passes its unit's schema before leaving.
491
+ * @param session - the session whose projection values are read.
492
+ * @returns the snapshot; `values` is empty when no unit is registered.
493
+ */
494
+ snapshot(session: Session): ProjectionSnapshot;
495
+ /**
496
+ * State-level checkpoint of every registered unit for one session, read
497
+ * from the watermark cache (missing cells fold lazily over the in-memory
498
+ * log). This is the write side of the persisted projection cache: the
499
+ * returned rows are the `(key → {ver, seq, val})` part of the durable
500
+ * `(sessionId, key, ver, seq, val)`
501
+ * rows. Every `val` is a DETACHED structured clone — never the live
502
+ * cell reference: the watermark cache is this registry's authoritative
503
+ * mutable state, and a caller reaching the live reference could corrupt
504
+ * every subsequent snapshot and frame through it (plain JSON by the unit
505
+ * contract, so the clone is total).
506
+ * @param session - the session whose unit states are checkpointed.
507
+ * @returns one row per registered key; empty when no unit is registered.
508
+ */
509
+ checkpoint(session: Session): ProjectionCheckpoint;
510
+ /**
511
+ * The stored seq a {@link restore} tail read over `checkpoint` must start
512
+ * at: one event BELOW the lowest usable watermark (a row is usable when
513
+ * its `ver` matches the live unit's `stateVersion`; an absent or mismatched row
514
+ * pulls the floor to `0` — that key must refold the full log). The
515
+ * one-below anchor is load-bearing: the tail then proves how far the
516
+ * stored log still extends, so {@link restore} can detect a log that
517
+ * shrank below a row's watermark (crash-repair truncation) instead of
518
+ * serving the stale row as current — an empty tail read from the anchor
519
+ * yields an end below every watermark and the restore rejects for a full
520
+ * re-read.
521
+ * @param checkpoint - persisted rows for one session (possibly stale or empty).
522
+ * @returns the seq to hand the persistence `readFrom`, or `undefined`
523
+ * when no unit is registered (no read needed — {@link restore} would
524
+ * serve empty values regardless).
525
+ */
526
+ restoreFloor(checkpoint: ProjectionCheckpoint): number | undefined;
527
+ /**
528
+ * View a checkpoint's rows without any log read: for every registered
529
+ * unit whose row's `ver` matches, serve the schema-validated
530
+ * `view` of the stored state; mismatched or absent rows leave their key
531
+ * absent (a cold or listing consumer treats it as not-yet-available and a
532
+ * fuller read path refolds it). The zero-I/O rung of the read ladder —
533
+ * values are as stale as their rows, never wrong.
534
+ * @param checkpoint - persisted rows for one session (possibly stale or empty).
535
+ * @returns whole values per key with a usable row; empty when none.
536
+ */
537
+ viewCheckpoint(checkpoint: ProjectionCheckpoint): Partial<SessionProjectionMap>;
538
+ /**
539
+ * Cold read: fold every registered unit over a stored log suffix, seeding
540
+ * each from its checkpoint row when usable — the one read recipe (cached
541
+ * state + forward tail replay + `view`) applied without a live `Session`.
542
+ * Call with the events returned by a persistence
543
+ * `readFrom(id, restoreFloor(checkpoint))` and that same floor as
544
+ * `baseSeq`; the floor's one-below anchor makes the supplied end honest,
545
+ * so a shrunk log is detected here. A row is usable iff its
546
+ * `ver` matches the live unit's `stateVersion`, it does not predate `baseSeq`
547
+ * (`seq >= baseSeq - 1`), and it does not claim events past the
548
+ * supplied end (`seq <= endSeq`); an unusable row is discarded
549
+ * and its key refolds from `init` — which is only sound over the full
550
+ * log, so a discarded row with `baseSeq > 0` throws (the caller re-reads
551
+ * from seq 0, e.g. after a crash-repair truncation shrank the log below
552
+ * a row's watermark).
553
+ * @param checkpoint - persisted rows for one session (possibly stale or empty).
554
+ * @param events - the stored events with `seq >= baseSeq`, in seq order.
555
+ * @param baseSeq - the seq `events` starts at (its first event's seq when non-empty).
556
+ * @returns the snapshot cut at the supplied log end (`asOfSeq` is the last
557
+ * supplied event's seq, `baseSeq - 1` for an empty tail) plus the
558
+ * refreshed checkpoint rows at that cut, ready for a durable write-back.
559
+ */
560
+ restore(checkpoint: ProjectionCheckpoint, events: readonly SessionEvent[], baseSeq: number): {
561
+ snapshot: ProjectionSnapshot;
562
+ checkpoint: ProjectionCheckpoint;
563
+ };
564
+ /** Fold one unit from init over `events`, producing a cell watermarked at the last folded event. */
565
+ private buildCell;
566
+ /** Read (or lazily build, folding the full in-memory log) one unit's cell. */
567
+ private cellFor;
568
+ /** Eager drive: pass one committed event through every registered unit; notify on changed references. */
569
+ private drive;
570
+ }
571
+ //#endregion
572
+ //#region src/host/headers.d.ts
573
+ /** The unit's persisted state (plain JSON, bounded). */
574
+ interface HeadersState {
575
+ headers: HeaderRecord[];
576
+ }
577
+ //#endregion
578
+ //#region src/host/index.d.ts
579
+ declare const name = "dsh-context";
580
+ /** Required services: the session-projection registry that drives the unit. */
581
+ declare const inject: string[];
582
+ declare function apply(ctx: Context, config: Config): void;
583
+ //#endregion
584
+ export { type Category, Config, type ContextEventRecord, type ContextHeaders, type ContextTimeline, type HeaderRecord, type HeaderTool, type HeadersState, type RequestRecord, type Snapshot, type SurfaceNode, type TimelineState, apply, inject, name };