← Files Biological Sequence & Alignment ViewerARCHIVED FILE
src/persistent/durable-viewer-state.test.ts
37.3 KB · Sep 30, 2026 · 23:01 UTC
import { runInNewContext } from "node:vm";
import { afterEach, describe, expect, it, vi } from "vitest";
import { parseMsa } from "../msa/parser";
import type { AlignmentWorkbenchView } from "../msa/use-alignment-workbench-commands";
import { addSequenceFeature, insertSequence } from "../sequence/editing";
import {
createSequenceInterfaceSettings,
validateSequenceInterfaceSettingsForSource,
} from "../sequence/interface-state";
import { parseSequenceDocument } from "../sequence/parser";
import { parseSequenceTrack } from "../sequence/tracks";
import type { SequenceWorkbenchView } from "../sequence/use-sequence-workbench-commands";
import {
alignmentWorkbenchReducer,
createAlignmentWorkbenchState,
createSequenceWorkbenchState,
sequenceWorkbenchReducer,
} from "../workbench-state";
import {
applySequenceDurableDocumentPatches,
createDurableAlignmentState,
createDurableSequenceState,
createSequenceDurableDocumentPatches,
decodeSequenceDurableViewerState,
encodeSequenceDurableViewerState,
MAX_SEQUENCE_DURABLE_CHECKPOINT_BYTES,
SEQUENCE_DURABLE_CHECKPOINT_DEBOUNCE_MS,
SequenceDurableViewerStateController,
type SequenceDurableViewerState,
type SequenceNativeCheckpointClient,
} from "./durable-viewer-state";
afterEach(() => vi.useRealTimers());
describe("application-owned durable Sequence and Alignment viewer state", () => {
it("persists bounded sequence interface controls without report payloads or source snapshots", () => {
const input = sequenceInterfaceCheckpointFixture();
const captured = createDurableSequenceState(input);
const restored = decodeSequenceDurableViewerState(
encodeSequenceDurableViewerState({
family: "sequence",
mode: "sequence",
sequence: captured,
sourceRevision: "revision-1",
sourceStateKey: input.sourceStateKey,
version: 1,
}),
);
expect(restored.sequence?.view.interface).toEqual(input.view.interface);
expect(restored.sequence?.session.view.sequence?.interface).toEqual(
input.view.interface,
);
expect(restored.sequence?.session.snapshot).toBeUndefined();
expect(restored.sequence?.documentPatches).toEqual([]);
expect(restored.sequence?.view.interface?.quality).not.toHaveProperty(
"report",
);
});
it("keeps legacy native checkpoints without interface settings backward compatible", () => {
const legacy = checkpointEnvelope("artifact:legacy-interface");
const restored = decodeSequenceDurableViewerState(
encodeSequenceDurableViewerState(legacy),
);
expect(restored.sequence?.view.interface).toBeUndefined();
expect(restored.sequence?.session.view.sequence?.interface).toBeUndefined();
});
it("rejects out-of-source trace settings when capturing a different selected record", () => {
const input = sequenceInterfaceCheckpointFixture();
input.view.selectedRecordId = input.state.document.records[1]!.id;
input.view.interface!.readPileup.selectedRead = null;
expect(() => createDurableSequenceState(input)).toThrow(
"outside its selected source record",
);
input.view.interface!.chromatogram.firstBase = 3;
const captured = createDurableSequenceState(input);
expect(captured.view.selectedRecordId).toBe(
input.state.document.records[1]!.id,
);
expect(captured.view.interface?.chromatogram.firstBase).toBe(3);
});
it("revalidates source-relative read selections against the reconstructed selected record", () => {
const input = sequenceInterfaceCheckpointFixture();
input.view.interface!.chromatogram.firstBase = 1;
const captured = createDurableSequenceState(input);
const restored = decodeSequenceDurableViewerState(
encodeSequenceDurableViewerState({
family: "sequence",
mode: "sequence",
sequence: captured,
sourceRevision: "revision-1",
sourceStateKey: input.sourceStateKey,
version: 1,
}),
).sequence!;
const document = applySequenceDurableDocumentPatches(
input.initialDocument,
restored.documentPatches,
);
expect(() =>
validateSequenceInterfaceSettingsForSource({
record: document.records[0],
records: document.records,
settings: restored.view.interface!,
tracks: restored.session.tracks,
}),
).not.toThrow();
expect(() =>
validateSequenceInterfaceSettingsForSource({
record: document.records[1],
records: document.records,
settings: restored.view.interface!,
tracks: restored.session.tracks,
}),
).toThrow(/different.*source record/u);
});
it("rejects malformed interface controls and unresolved native-view read identities", () => {
const checkpoint = checkpointEnvelope("artifact:invalid-interface");
const sequence = checkpoint.sequence!;
sequence.view.interface = createSequenceInterfaceSettings();
sequence.view.interface.chromatogram.basesPerWindow = 101;
expect(() => encodeSequenceDurableViewerState(checkpoint)).toThrow();
sequence.view.interface = createSequenceInterfaceSettings();
sequence.view.interface.readPileup.selectedRead = {
sourceReadIndex: 0,
trackId: "not-loaded",
};
expect(() => encodeSequenceDurableViewerState(checkpoint)).toThrow(
"saved read selection",
);
expect(() =>
decodeSequenceDurableViewerState(
new TextEncoder().encode(JSON.stringify(checkpoint)),
),
).toThrow("could not be restored");
});
it("creates a native checkpoint after a completed FASTQ quality-report job", () => {
const initial = parseSequenceDocument({
contents: "@QA-SYNTHETIC-QC\nACGTACGTACGT\n+\nIIIIIIIIIIII\n",
fileName: "synthetic-qc.fastq",
});
const state = createSequenceWorkbenchState(initial);
state.jobs.push({
completedAt: 2,
id: "00000000-0000-4000-8000-000000000001",
kind: "quality-report",
message: "Quality-report control completed.",
parameters: { analysis: "quality-report" },
progress: 1,
result: { analysis: "quality-report", scope: { analyzedReads: 1 } },
startedAt: 1,
status: "completed",
});
const captured = createDurableSequenceState({
activeSearchHitIndex: 0,
initialDocument: initial,
query: "",
sourceStateKey: "artifact:synthetic-qc",
state,
view: {
...sequenceView(initial.records[0]!.id),
interface: createSequenceInterfaceSettings(),
selectedFeatureId: null,
},
});
expect(captured.session.jobs[0]).toMatchObject({
kind: "quality-report",
status: "completed",
});
expect(() =>
encodeSequenceDurableViewerState({
family: "sequence",
mode: "sequence",
sequence: captured,
sourceRevision: "revision-1",
sourceStateKey: "artifact:synthetic-qc",
version: 1,
}),
).not.toThrow();
});
it("stores a multi-megabyte sequence edit as a bounded source-relative patch", () => {
const source = {
features: [{ end: 8, id: "preserved-feature", start: 2 }],
record: "A".repeat(4 * 1024 * 1024),
};
const edited = {
...source,
features: [...source.features, { end: 120, id: "restored-annotation", start: 100 }],
record:
source.record.slice(0, 2 * 1024 * 1024) + "CGT" + source.record.slice(2 * 1024 * 1024 + 3),
};
const patches = createSequenceDurableDocumentPatches(source, edited);
expect(new TextEncoder().encode(JSON.stringify(patches)).byteLength).toBeLessThan(2_048);
expect(patches).toContainEqual(
expect.objectContaining({
operation: "splice-string",
path: ["record"],
value: "CGT",
}),
);
expect(applySequenceDurableDocumentPatches(source, patches)).toEqual(edited);
});
it("preserves sequence locus, strand, annotation, unsaved edits and history", () => {
const initial = sequenceDocument("AACCGGTTAACC");
const record = initial.records[0];
if (record == null) throw new Error("Expected a source sequence.");
const edited = {
...initial,
records: [
{
...record,
features: [
...record.features,
{
end: 6,
id: "annotation-1",
label: "edited feature",
qualifiers: {},
start: 2,
strand: "+" as const,
type: "misc_feature",
},
],
sequence: "AATCGGTTAACC",
},
],
};
const state = sequenceWorkbenchReducer(createSequenceWorkbenchState(initial), {
description: "Replace residue and annotate the source copy",
document: edited,
type: "apply-sequence-document",
});
const captured = createDurableSequenceState({
activeSearchHitIndex: 7,
focusCoordinate: 6,
initialDocument: initial,
query: "CGG",
sourceStateKey: "artifact:sequence-source",
state,
view: sequenceView(record.id),
});
const restored = decodeSequenceDurableViewerState(
encodeSequenceDurableViewerState({
family: "sequence",
mode: "sequence",
sequence: captured,
sourceRevision: "revision-1",
sourceStateKey: "artifact:sequence-source",
version: 1,
}),
);
expect(restored.sequence).toMatchObject({
activeSearchHitIndex: 7,
focusCoordinate: 6,
query: "CGG",
view: {
orientation: "reverse-complement",
selectedFeatureId: "annotation-1",
selectedRecordId: record.id,
viewport: { end: 10, start: 2 },
},
});
if (restored.sequence == null) {
throw new Error("Expected recovered sequence state.");
}
expect(applySequenceDurableDocumentPatches(initial, restored.sequence.documentPatches)).toEqual(
state.document,
);
expect(restored.sequence.history).toHaveLength(1);
expect(
applySequenceDurableDocumentPatches(initial, restored.sequence.history[0]?.patches ?? []),
).toEqual(initial);
expect(restored.sequence.session.dirty).toBe(true);
});
it("recovers authentic BED12 exon and coding blocks despite legacy undefined metadata", async () => {
const initial = sequenceDocument("A".repeat(6_000));
const record = initial.records[0];
if (record == null) throw new Error("Expected a source sequence.");
const parsedTrack = parseSequenceTrack({
content: "chr22\t1000\t5000\tmRNA1\t0\t+\t1200\t4900\t0\t2\t567,488\t0,3512\n",
displayName: "ucsc-bed12-track.bed",
format: "bed",
id: "public-chr22-transcript",
requestedReference: "chr22",
});
const track = {
...parsedTrack,
features: parsedTrack.features?.map((feature) => ({
...feature,
phase: undefined,
source: undefined,
})),
source: {
...parsedTrack.source,
contentHash: undefined,
workspacePath: undefined,
},
};
const state = sequenceWorkbenchReducer(createSequenceWorkbenchState(initial), {
track,
type: "add-track",
});
const captured = createDurableSequenceState({
activeSearchHitIndex: 0,
initialDocument: initial,
query: "",
sourceStateKey: "artifact:public-chr22",
state,
view: sequenceView(record.id),
});
expect(captured.session.tracks[0]?.source).toEqual({
displayName: "ucsc-bed12-track.bed",
});
expect(captured.session.tracks[0]?.features?.[0]).toMatchObject({
codingSegments: [
{ end: 1567, start: 1201 },
{ end: 4900, start: 4513 },
],
segments: [
{ end: 1567, start: 1001 },
{ end: 5000, start: 4513 },
],
});
expect(captured.session.tracks[0]?.features?.[0]).not.toHaveProperty("phase");
const client = mockNativeClient({ hasCheckpoint: false });
const controller = new SequenceDurableViewerStateController(client);
controller.updateSequence({
sourceStateKey: "artifact:public-chr22",
state: captured,
});
await controller.flush();
const persisted = vi.mocked(client.checkpoint).mock.calls[0]?.[0]?.checkpoint;
if (persisted == null) throw new Error("Expected a native recovery checkpoint.");
const recovered = new SequenceDurableViewerStateController(
mockNativeClient({ checkpoint: persisted, hasCheckpoint: true }),
);
await expect(recovered.restore()).resolves.toMatchObject({
sequence: {
session: {
tracks: [
{
features: [
{
segments: [
{ end: 1567, start: 1001 },
{ end: 5000, start: 4513 },
],
},
],
},
],
},
},
});
});
it("recovers annotated sequence edits without inventing absent quality or feature fields", () => {
const initial = sequenceDocument("AACCGGTTAACC");
const record = initial.records[0];
if (record == null) throw new Error("Expected a source sequence.");
const annotated = addSequenceFeature(initial, record.id, {
end: 6,
id: "annotation-1",
label: undefined,
qualifiers: {},
segments: undefined,
start: 2,
strand: "+",
translationCoordinateMap: undefined,
type: "misc_feature",
});
const edited = insertSequence(annotated, record.id, 3, "T").document;
let state = sequenceWorkbenchReducer(createSequenceWorkbenchState(initial), {
description: "Add a real annotation without absent optional values",
document: annotated,
type: "apply-sequence-document",
});
state = sequenceWorkbenchReducer(state, {
description: "Edit the annotated sequence copy",
document: edited,
type: "apply-sequence-document",
});
const captured = createDurableSequenceState({
activeSearchHitIndex: 0,
initialDocument: initial,
query: "",
sourceStateKey: "artifact:annotated-public-sequence",
state,
view: sequenceView(record.id),
});
const restored = applySequenceDurableDocumentPatches(
initial,
captured.documentPatches,
);
expect(restored.records[0]?.sequence).toBe("AATCCGGTTAACC");
expect(restored.records[0]).not.toHaveProperty("quality");
expect(restored.records[0]?.features[0]).not.toHaveProperty("label");
expect(restored.records[0]?.features[0]).not.toHaveProperty("segments");
expect(restored.records[0]?.features[0]).not.toHaveProperty("translationCoordinateMap");
expect(captured.history).toHaveLength(2);
});
it("normalizes trusted optional properties without admitting unsafe recovery values", () => {
const initial = sequenceDocument("AACCGGTTAACC");
const record = initial.records[0];
if (record == null) throw new Error("Expected a source sequence.");
const track = parseSequenceTrack({
content: "chr22\t0\t4\n",
displayName: "public-regions.bed",
format: "bed",
id: "bounded-public-track",
requestedReference: "chr22",
});
const capture = (candidate: typeof track) =>
createDurableSequenceState({
activeSearchHitIndex: 0,
initialDocument: initial,
query: "",
sourceStateKey: "artifact:bounded-public-track",
state: sequenceWorkbenchReducer(createSequenceWorkbenchState(initial), {
track: candidate,
type: "add-track",
}),
view: sequenceView(record.id),
});
const withOptional = {
...track,
source: { ...track.source, contentHash: undefined },
};
expect(capture(withOptional).session.tracks[0]?.source).not.toHaveProperty(
"contentHash",
);
const unsafePrototype = Object.assign(
Object.create({ inherited: true }) as typeof track.source,
track.source,
);
expect(() => capture({ ...track, source: unsafePrototype })).toThrow(
/non-JSON/u,
);
const unsafeSource = { ...track.source };
Object.defineProperty(unsafeSource, "__proto__", {
enumerable: true,
value: "polluted",
});
expect(() => capture({ ...track, source: unsafeSource })).toThrow(/unsafe/u);
expect(() =>
capture({
...track,
features: track.features?.map((feature) => ({
...feature,
score: Number.POSITIVE_INFINITY,
})),
}),
).toThrow(/invalid number/u);
expect(() =>
createSequenceDurableDocumentPatches({}, { optional: undefined }),
).toThrow(/non-JSON/u);
});
it("keeps private VCF genotypes inside source-bound native recovery state", () => {
const initial = sequenceDocument("AACCGGTTAACC");
const record = initial.records[0];
if (record == null) throw new Error("Expected a source sequence.");
const track = parseSequenceTrack({
content: [
"##fileformat=VCFv4.3",
"##FORMAT=<ID=GT,Number=1,Type=String,Description=Genotype>",
"#CHROM\tPOS\tID\tREF\tALT\tQUAL\tFILTER\tINFO\tFORMAT\tPUBLIC_A\tPUBLIC_B",
"1\t5\t.\tA\tG\t.\t.\tAC=1\tGT\t0/1\t1/1",
].join("\n"),
displayName: "public-spec.vcf",
format: "vcf",
id: "source-bound-public-vcf",
requestedReference: "1",
});
const state = sequenceWorkbenchReducer(createSequenceWorkbenchState(initial), {
track,
type: "add-track",
});
const captured = createDurableSequenceState({
activeSearchHitIndex: 0,
initialDocument: initial,
query: "",
sourceStateKey: "artifact:source-bound-public-vcf",
state,
view: sequenceView(record.id),
});
const recovered = decodeSequenceDurableViewerState(
encodeSequenceDurableViewerState({
family: "sequence",
mode: "sequence",
sequence: captured,
sourceRevision: "revision-1",
sourceStateKey: "artifact:source-bound-public-vcf",
version: 1,
}),
);
expect(recovered.sequence?.session.tracks[0]?.vcfHeader).toMatchObject({
sampleNames: ["PUBLIC_A", "PUBLIC_B"],
});
expect(recovered.sequence?.session.tracks[0]?.variants?.[0]).toMatchObject({
rawFilter: ".",
samples: { PUBLIC_A: "0/1", PUBLIC_B: "1/1" },
});
expect(recovered.sequence?.session.tracks[0]?.variants?.[0]).not.toHaveProperty(
"sampleValues",
);
});
it("losslessly recovers 27 variants and 100 genotypes within the native checkpoint budget", () => {
const initial = sequenceDocument("AACCGGTTAACC");
const record = initial.records[0];
if (record == null) throw new Error("Expected a source sequence.");
const sampleNames = Array.from(
{ length: 100 },
(_, index) => `S${String(index).padStart(3, "0")}`,
);
const values = (variantIndex: number) =>
sampleNames.map(
(_, sampleIndex) =>
`0/1:${String(variantIndex).padStart(2, "0")}.${String(sampleIndex).padStart(6, "0")}:0.987654:-0.333333`,
);
const content = [
"##fileformat=VCFv4.3",
"##FORMAT=<ID=GT,Number=1,Type=String,Description=Genotype>",
[
"#CHROM",
"POS",
"ID",
"REF",
"ALT",
"QUAL",
"FILTER",
"INFO",
"FORMAT",
...sampleNames,
].join("\t"),
...Array.from({ length: 27 }, (_, index) =>
["1", String(10_583 + index), ".", "G", "A", ".", ".", "AC=1", "GT:DS:GL", ...values(index)].join("\t"),
),
].join("\n");
const track = parseSequenceTrack({
content,
displayName: "official-27-variant-100-sample-conformance.vcf",
format: "vcf",
id: "full-public-conformance-track",
requestedReference: "1",
});
expect(new TextEncoder().encode(JSON.stringify(track)).byteLength).toBeGreaterThan(
MAX_SEQUENCE_DURABLE_CHECKPOINT_BYTES,
);
const state = sequenceWorkbenchReducer(createSequenceWorkbenchState(initial), {
track,
type: "add-track",
});
const captured = createDurableSequenceState({
activeSearchHitIndex: 0,
initialDocument: initial,
query: "",
sourceStateKey: "artifact:full-public-conformance",
state,
view: sequenceView(record.id),
});
const checkpoint = encodeSequenceDurableViewerState({
family: "sequence",
mode: "sequence",
sequence: captured,
sourceRevision: "revision-1",
sourceStateKey: "artifact:full-public-conformance",
version: 1,
});
expect(checkpoint.byteLength).toBeLessThanOrEqual(
MAX_SEQUENCE_DURABLE_CHECKPOINT_BYTES,
);
const recovered = decodeSequenceDurableViewerState(checkpoint);
const recoveredTrack = recovered.sequence?.session.tracks[0];
expect(recoveredTrack?.vcfHeader?.sampleNames).toEqual(sampleNames);
expect(recoveredTrack?.variants).toHaveLength(27);
for (const [index, variant] of (recoveredTrack?.variants ?? []).entries()) {
expect(Object.values(variant.samples)).toEqual(values(index));
expect(variant).not.toHaveProperty("sampleValues");
}
});
it.each(["legacy", "modern"] as const)("preserves %s alignment edits, display controls, focus and virtual viewport", (variant) => {
const result = parseMsa(">row-a\nAACCGG\n>row-b\nAATCGG\n", "demo.aln-fasta");
if (result.status !== "success") throw new Error(result.message);
const initial = result.document;
const row = initial.rows[0];
if (row == null) throw new Error("Expected a source alignment row.");
const edited = {
...initial,
rows: initial.rows.map((candidate) =>
candidate.id === row.id ? { ...candidate, alignedSequence: "AATCGG" } : candidate,
),
};
let state = alignmentWorkbenchReducer(createAlignmentWorkbenchState(initial), {
description: "Restore an alignment-cell edit",
document: edited,
type: "apply-alignment-document",
});
state = alignmentWorkbenchReducer(state, {
rowIds: [row.id],
type: "select-alignment-rows",
});
const view = alignmentView(row.id);
if (variant === "modern") {
view.enabledMetricTracks = ["identity", "sequence-logo"];
view.rowSortDirection = "desc";
view.rowSortKey = "identity";
view.showSequenceLogoHelp = true;
}
const captured = createDurableAlignmentState({
alignmentColumnJump: "42",
anchorRowId: row.id,
fileName: "demo.aln-fasta",
focusedCell: { column: 2, rowId: row.id, symbol: "T" },
guideTreeNewick: "(row-a,row-b);",
initialDocument: initial,
motifQuery: "TCG",
pinnedCell: { column: 3, rowId: row.id, symbol: "C" },
referencePositionJump: "19",
selectedHitIndex: 3,
sourceStateKey: "artifact:alignment-source",
state,
view,
viewport: { column: 91, row: 14 },
});
const restored = decodeSequenceDurableViewerState(
encodeSequenceDurableViewerState({
alignment: captured,
family: "sequence",
mode: "alignment",
sourceRevision: "revision-1",
sourceStateKey: "artifact:alignment-source",
version: 1,
}),
);
expect(restored.alignment).toMatchObject({
anchorRowId: row.id,
focusedCell: { column: 2, rowId: row.id, symbol: "T" },
guideTreeNewick: "(row-a,row-b);",
motifQuery: "TCG",
pinnedCell: { column: 3, rowId: row.id, symbol: "C" },
selectedHitIndex: 3,
view: {
referenceMode: "anchor",
rowFilter: "row-a",
selectedRows: [row.id],
},
viewport: { column: 91, row: 14 },
});
if (restored.alignment == null) {
throw new Error("Expected recovered alignment state.");
}
expect(restored.alignment.view).toEqual(view);
expect(
applySequenceDurableDocumentPatches(initial, restored.alignment.documentPatches),
).toEqual(edited);
});
it("produces byte-identical deterministic checkpoints", () => {
const first = checkpointEnvelope("artifact:deterministic");
const second = checkpointEnvelope("artifact:deterministic");
expect(encodeSequenceDurableViewerState(first)).toEqual(
encodeSequenceDurableViewerState(second),
);
});
it("accepts authentic Uint8Array checkpoints across native process realms", () => {
const checkpoint = checkpointEnvelope("artifact:cross-realm");
const bytes = encodeSequenceDurableViewerState(checkpoint);
const transferred = runInNewContext("new Uint8Array(bytes)", {
bytes: Array.from(bytes),
}) as Uint8Array;
expect(transferred instanceof Uint8Array).toBe(false);
expect(decodeSequenceDurableViewerState(transferred)).toEqual(checkpoint);
});
it("automatically recovers exact native state after an application restart", async () => {
const checkpoint = checkpointEnvelope("artifact:cold-restart");
const client = mockNativeClient({
checkpoint: encodeSequenceDurableViewerState(checkpoint),
hasCheckpoint: true,
});
const controller = new SequenceDurableViewerStateController(client);
await expect(controller.restore()).resolves.toEqual(checkpoint);
expect(client.restoreCheckpoint).toHaveBeenCalledOnce();
expect(client.checkpoint).not.toHaveBeenCalled();
expect(controller.restoredState?.sequence?.query).toBe("CGG");
});
it("opens a first-use native viewer without checkpoint metadata or MCP", async () => {
const client = mockNativeClient({ hasCheckpoint: false });
const controller = new SequenceDurableViewerStateController(client);
await expect(controller.restore()).resolves.toBeNull();
expect(client.restoreCheckpoint).toHaveBeenCalledOnce();
expect(client.checkpoint).not.toHaveBeenCalled();
expect(controller.restoredState).toBeNull();
});
it("coalesces interactions into the latest automatic native checkpoint", async () => {
vi.useFakeTimers();
const client = mockNativeClient({ hasCheckpoint: false });
const controller = new SequenceDurableViewerStateController(client);
const first = checkpointEnvelope("artifact:latest-only");
if (first.sequence == null) throw new Error("Expected sequence state.");
controller.updateSequence({
sourceStateKey: first.sourceStateKey,
state: first.sequence,
});
controller.updateSequence({
sourceStateKey: first.sourceStateKey,
state: { ...first.sequence, query: "latest-only-search" },
});
expect(client.checkpoint).not.toHaveBeenCalled();
await vi.advanceTimersByTimeAsync(SEQUENCE_DURABLE_CHECKPOINT_DEBOUNCE_MS);
expect(client.checkpoint).toHaveBeenCalledOnce();
const checkpointCall = vi.mocked(client.checkpoint).mock.calls[0]?.[0];
if (checkpointCall == null) throw new Error("Expected a native checkpoint.");
expect(decodeSequenceDurableViewerState(checkpointCall.checkpoint)).toMatchObject({
sequence: { query: "latest-only-search" },
});
});
it("persists source-bound toolbar visibility without invalidating legacy checkpoints", async () => {
const client = mockNativeClient({ hasCheckpoint: false });
const controller = new SequenceDurableViewerStateController(client);
const state = checkpointEnvelope("artifact:toolbar");
if (state.sequence == null) throw new Error("Expected sequence state.");
controller.setToolbarVisibility({
sourceStateKey: state.sourceStateKey,
visible: false,
});
expect(controller.restoredState).toBeNull();
controller.updateSequence({
sourceStateKey: state.sourceStateKey,
state: state.sequence,
});
expect(controller.restoredState?.toolbarVisible).toBe(false);
controller.setToolbarVisibility({
sourceStateKey: "artifact:other-source",
visible: true,
});
expect(controller.restoredState?.toolbarVisible).toBe(false);
controller.updateSequence({
sourceStateKey: state.sourceStateKey,
state: { ...state.sequence, query: "preserve-toolbar" },
});
await controller.flush();
const checkpoint = vi.mocked(client.checkpoint).mock.calls[0]?.[0];
if (checkpoint == null) throw new Error("Expected a persisted checkpoint.");
expect(decodeSequenceDurableViewerState(checkpoint.checkpoint)).toMatchObject({
sequence: { query: "preserve-toolbar" },
toolbarVisible: false,
});
expect(decodeSequenceDurableViewerState(encodeSequenceDurableViewerState(state)))
.not.toHaveProperty("toolbarVisible");
});
it("never transfers a pending toolbar choice to a different source", () => {
const client = mockNativeClient({ hasCheckpoint: false });
const controller = new SequenceDurableViewerStateController(client);
const state = checkpointEnvelope("artifact:actual-source");
if (state.sequence == null) throw new Error("Expected sequence state.");
controller.setToolbarVisibility({
sourceStateKey: "artifact:stale-source",
visible: false,
});
controller.updateSequence({
sourceStateKey: state.sourceStateKey,
state: state.sequence,
});
expect(controller.restoredState?.toolbarVisible).toBeUndefined();
});
it("never applies a pending toolbar choice after its source revision changes", () => {
const client = mockNativeClient({ hasCheckpoint: false });
const controller = new SequenceDurableViewerStateController(client);
const state = checkpointEnvelope("artifact:same-name");
if (state.sequence == null) throw new Error("Expected sequence state.");
controller.setToolbarVisibility({
sourceStateKey: state.sourceStateKey,
visible: false,
});
Object.defineProperty(client.session, "sourceRevision", {
value: "revision-2",
});
controller.updateSequence({
sourceStateKey: state.sourceStateKey,
state: state.sequence,
});
expect(controller.restoredState?.sourceRevision).toBe("revision-2");
expect(controller.restoredState?.toolbarVisible).toBeUndefined();
});
it("keeps toolbar visibility when switching an authenticated source between viewer modes", () => {
const client = mockNativeClient({ hasCheckpoint: false });
const controller = new SequenceDurableViewerStateController(client);
const state = checkpointEnvelope("artifact:both-modes");
if (state.sequence == null) throw new Error("Expected sequence state.");
const parsed = parseMsa(">row-a\nAC-GT\n>row-b\nACTGT\n", "family.fasta");
if (parsed.status !== "success") throw new Error(parsed.message);
const anchor = parsed.document.rows[0];
if (anchor == null) throw new Error("Expected alignment rows.");
controller.updateSequence({
sourceStateKey: state.sourceStateKey,
state: state.sequence,
});
controller.setToolbarVisibility({
sourceStateKey: state.sourceStateKey,
visible: false,
});
controller.updateAlignment({
sourceStateKey: state.sourceStateKey,
state: createDurableAlignmentState({
alignmentColumnJump: "",
anchorRowId: anchor.id,
focusedCell: null,
guideTreeNewick: null,
initialDocument: parsed.document,
motifQuery: "",
pinnedCell: null,
referencePositionJump: "",
selectedHitIndex: 0,
sourceStateKey: state.sourceStateKey,
state: createAlignmentWorkbenchState(parsed.document),
view: alignmentView(anchor.id),
viewport: { column: 0, row: 0 },
}),
});
expect(controller.restoredState).toMatchObject({
mode: "alignment",
toolbarVisible: false,
});
});
it("refuses a checkpoint from a changed biological source", async () => {
const checkpoint = checkpointEnvelope("artifact:stale-source");
const client = mockNativeClient({
checkpoint: encodeSequenceDurableViewerState({
...checkpoint,
sourceRevision: "old-revision",
}),
hasCheckpoint: true,
});
await expect(new SequenceDurableViewerStateController(client).restore()).rejects.toThrow(
/revision|source/u,
);
});
it("refuses oversized, malformed, cross-mode and unsafe recovery state", () => {
expect(() =>
decodeSequenceDurableViewerState(new Uint8Array(MAX_SEQUENCE_DURABLE_CHECKPOINT_BYTES + 1)),
).toThrow(/invalid|large/u);
expect(() => decodeSequenceDurableViewerState(new TextEncoder().encode("{not-json"))).toThrow(
/checkpoint/u,
);
expect(() =>
applySequenceDurableDocumentPatches({ safe: true }, [
{
operation: "replace",
path: ["__proto__", "polluted"],
value: true,
},
]),
).toThrow(/unsafe/u);
expect(() =>
encodeSequenceDurableViewerState({
...checkpointEnvelope("artifact:wrong-mode"),
mode: "alignment",
}),
).toThrow(/mode|restorable/u);
});
it("never invents an MCP fallback after a refused native checkpoint", async () => {
const client = mockNativeClient({ hasCheckpoint: false });
vi.mocked(client.checkpoint).mockRejectedValueOnce(
new Error("The native source capability was revoked."),
);
const controller = new SequenceDurableViewerStateController(client);
const checkpoint = checkpointEnvelope("artifact:revoked");
if (checkpoint.sequence == null) throw new Error("Expected sequence state.");
controller.updateSequence({
sourceStateKey: checkpoint.sourceStateKey,
state: checkpoint.sequence,
});
await expect(controller.flush()).rejects.toThrow(/revoked/u);
expect(client.checkpoint).toHaveBeenCalledOnce();
expect(client.restoreCheckpoint).not.toHaveBeenCalled();
});
});
function sequenceInterfaceCheckpointFixture() {
const initialDocument = parseSequenceDocument({
contents: ">chr1\nACGTACGTACGT\n>chr2\nACGT\n",
fileName: "synthetic-interface.fasta",
});
const state = createSequenceWorkbenchState(initialDocument);
state.tracks.push(
parseSequenceTrack({
content:
"@SQ\tSN:1\tLN:12\nselected\t0\t1\t5\t60\t4M\t*\t0\t0\tACGT\tIIII\n",
displayName: "synthetic-read.sam",
format: "sam",
id: "synthetic-read-source",
requestedReference: "chr1",
}),
);
const settings = createSequenceInterfaceSettings();
settings.annotationIndex = { expanded: true, page: 1, query: "gene" };
settings.chromatogram = { basesPerWindow: 20, firstBase: 5 };
settings.originRangeExpanded = true;
settings.quality.adapterSequence = "ACGTACGT";
settings.quality.view.methodsExpanded = true;
settings.quality.view.distributionsExpanded = true;
settings.quality.view.expandedTables = ["cycle-quality", "read-gc"];
settings.readPileup.options.minimumMappingQuality = 40;
settings.readPileup.options.showAllBases = true;
settings.readPileup.selectedRead = {
sourceReadIndex: 0,
trackId: state.tracks[0]!.id,
};
settings.recordBrowser = {
expanded: true,
page: 2,
query: "chr",
sortBy: "label",
};
const view: SequenceWorkbenchView = {
...sequenceView(initialDocument.records[0]!.id),
interface: settings,
selectedFeatureId: null,
selection: null,
viewport: null,
};
return {
activeSearchHitIndex: 0,
initialDocument,
query: "",
sourceStateKey: "artifact:interface-settings",
state,
view,
};
}
function sequenceDocument(sequence: string) {
return parseSequenceDocument({
contents: ">demo\n" + sequence + "\n",
fileName: "demo.fasta",
});
}
function sequenceView(recordId: string): SequenceWorkbenchView {
return {
geneticCodeId: 1,
layout: "split",
orientation: "reverse-complement",
paletteId: "neutral",
selectedFeatureId: "annotation-1",
selectedRecordId: recordId,
selection: { end: 6, recordId, start: 2 },
showFeatures: true,
showQuality: false,
showTranslation: false,
synchronizedViews: true,
viewport: { end: 10, start: 2 },
wrapWidth: 60,
};
}
function alignmentView(rowId: string): AlignmentWorkbenchView {
return {
analysisScope: "all-unhidden-rows",
cellWidth: 25,
colorMode: "identity",
referenceMode: "anchor",
residuePalette: "neutral",
rowFilter: "row-a",
searchScope: "currently-displayed-rows",
selectedColumns: { end: 4, start: 2 },
selectedRows: [rowId],
showAnnotationTracks: true,
showIdenticalAsDots: true,
showRnaStructureOverlays: false,
};
}
function checkpointEnvelope(sourceStateKey: string): SequenceDurableViewerState {
const initial = sequenceDocument("AACCGGTTAACC");
const record = initial.records[0];
if (record == null) throw new Error("Expected a source sequence.");
return {
family: "sequence",
mode: "sequence",
sequence: createDurableSequenceState({
activeSearchHitIndex: 2,
focusCoordinate: 4,
initialDocument: initial,
query: "CGG",
sourceStateKey,
state: createSequenceWorkbenchState(initial),
view: sequenceView(record.id),
}),
sourceRevision: "revision-1",
sourceStateKey,
version: 1,
};
}
function mockNativeClient(
input: { checkpoint: Uint8Array; hasCheckpoint: true } | { hasCheckpoint: false },
): SequenceNativeCheckpointClient {
return {
checkpoint: vi.fn(async ({ lastAcknowledgedRevision }) => ({
checkpointVersion: 1 as const,
lastAcknowledgedRevision: lastAcknowledgedRevision + 1,
logicalSessionId: "native-logical-session",
recoveryReference: "native-durable-reference",
})),
restoreCheckpoint: vi.fn(async () =>
input.hasCheckpoint
? {
checkpoint: input.checkpoint,
hasCheckpoint: true as const,
lastAcknowledgedRevision: 4,
recoveryReference: "native-durable-reference",
sourceRevision: "revision-1",
}
: { hasCheckpoint: false as const },
),
session: {
backendGeneration: 2,
backendInstanceId: "native-sequence-worker",
family: "sequence",
logicalSessionId: "native-logical-session",
sourceRevision: "revision-1",
},
};
}
SHA-256: db8d8f424496f9e0a99a1c1c982ef5a05f1c553b99d1ebd313205310a8598925