@cplieger/web-terminal-engine 5.0.1 → 5.0.3

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/jsr.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@cplieger/web-terminal-engine",
3
- "version": "5.0.1",
3
+ "version": "5.0.3",
4
4
  "license": "MPL-2.0",
5
5
  "exports": {
6
6
  ".": "./src/index.ts"
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@cplieger/web-terminal-engine",
3
- "version": "5.0.1",
3
+ "version": "5.0.3",
4
4
  "type": "module",
5
5
  "scripts": {
6
6
  "typecheck": "tsc -p tsconfig.json",
package/src/connection.ts CHANGED
@@ -42,6 +42,7 @@ import * as modes from "./modes.js";
42
42
  // anchor — the shape that leaves the rows under the reader blank while the far
43
43
  // end of the gap fills.
44
44
  import { PAGE_SIZE } from "./store.js";
45
+ import * as render from "./render.js";
45
46
  import type { ControlMessage, ScrollMessage, ServerMessage } from "./types.js";
46
47
  import { INITIAL_DELAY_MS, nextBackoffDelay } from "./reconnect.js";
47
48
 
@@ -528,8 +529,47 @@ export interface Callbacks {
528
529
 
529
530
  let cb: Callbacks | null = null;
530
531
 
532
+ /**
533
+ * The members this module answers for ITSELF, from the renderer.
534
+ *
535
+ * Every one of them is a fact about local state, not a decision: what this client
536
+ * already holds, how much replay it wants, where to route a resume ack or a history
537
+ * reply. The renderer is the layer that knows, because several carry a viewport
538
+ * reading only it can take, and both modules belong to this library. A consumer
539
+ * that supplied them was choosing between engine accessors on the engine's behalf,
540
+ * which is how `getHaveThrough` came to be wired to the highest index HELD rather
541
+ * than the highest the server had confirmed: the resume then claimed rows the
542
+ * application had merely drawn, and a frozen copy of its input box appeared in
543
+ * scrollback on almost every reattach.
544
+ *
545
+ * A consumer may still override any of them, and `getReplayMax` is the one where
546
+ * that is expected: how much history a client wants resident is its policy, not the
547
+ * engine's fact. The rest exist as overrides only because removing them from
548
+ * `Callbacks` would break a published surface; treat them as deprecated and prefer
549
+ * supplying nothing.
550
+ *
551
+ * Read lazily, per resume, rather than captured at init: the renderer's answers are
552
+ * functions of whichever store is currently bound, which a tab switch changes.
553
+ */
554
+ function engineDefaults(): Partial<Callbacks> {
555
+ return {
556
+ getHaveThrough: render.getReplayBoundary,
557
+ getReplayMax: render.replayMaxForResume,
558
+ onResumeTransition: render.applyResumeTransition,
559
+ onResumeBounds: render.noteResumeBounds,
560
+ onHistoryReply: render.handleHistoryReply,
561
+ noteSolicited: render.noteSolicited,
562
+ clearSolicited: render.clearSolicited,
563
+ onHistoryRetry: render.maybeFetchHistory,
564
+ };
565
+ }
566
+
531
567
  export function init(callbacks: Callbacks): void {
532
- cb = callbacks;
568
+ // Consumer last: an explicit member wins, an absent one gets the engine's own.
569
+ // The alternative, leaving them absent, is not neutral — the resume send reads
570
+ // `cb?.getHaveThrough?.() ?? -1`, so silence asks for a full bounded replay on
571
+ // every attach, which is the worst answer available rather than the safe one.
572
+ cb = { ...engineDefaults(), ...callbacks };
533
573
  if (callbacks.wsPath !== undefined) {
534
574
  wsPath = callbacks.wsPath;
535
575
  }