← Files Biological Sequence & Alignment ViewerARCHIVED FILE
src/persistent/recovery-adapter.ts
1.75 KB · Sep 30, 2026 · 23:01 UTC
import { z } from "zod";
export const SEQUENCE_SCIENTIFIC_RECOVERY_META_KEY = "openai/scientific-viewer/recovery";
export const SEQUENCE_PERSISTENT_RESOURCE_URI = "ui://sequence-viewer/viewer";
const opaqueRecoveryIdentifierSchema = z
.string()
.min(1)
.max(256)
.refine(
(value) => value === value.trim() && !/[\u0000-\u001f\u007f/\\]/u.test(value),
"Viewer recovery identifiers must be opaque and path-free.",
);
export const sequenceScientificRecoveryMetadataSchema = z
.object({
family: z.literal("sequence"),
logicalSessionId: opaqueRecoveryIdentifierSchema,
recoveryReference: opaqueRecoveryIdentifierSchema,
resourceUri: z.literal(SEQUENCE_PERSISTENT_RESOURCE_URI),
threadId: opaqueRecoveryIdentifierSchema.optional(),
})
.strict();
export type SequenceScientificRecoveryMetadata = z.infer<
typeof sequenceScientificRecoveryMetadataSchema
>;
export function createSequenceScientificRecoveryMetadata({
logicalSessionId,
recoveryReference,
threadId,
}: {
logicalSessionId: string;
recoveryReference: string;
threadId?: string;
}): SequenceScientificRecoveryMetadata {
return sequenceScientificRecoveryMetadataSchema.parse({
family: "sequence",
logicalSessionId,
recoveryReference,
resourceUri: SEQUENCE_PERSISTENT_RESOURCE_URI,
threadId,
});
}
export function parseSequenceScientificRecoveryMetadata(
metadata: unknown,
): SequenceScientificRecoveryMetadata | null {
if (
typeof metadata !== "object" ||
metadata == null ||
!(SEQUENCE_SCIENTIFIC_RECOVERY_META_KEY in metadata)
) {
return null;
}
const parsed = sequenceScientificRecoveryMetadataSchema.safeParse(
metadata[SEQUENCE_SCIENTIFIC_RECOVERY_META_KEY],
);
return parsed.success ? parsed.data : null;
}
SHA-256: 4d6f42128fcc078667992f84bf2ead1d9bb48aebce09c345aa3f224e9a4e6d68