Validation
Loading a scene is not a blind JSON.parse. @oh-just-another/serialization validates every document against a zod schema before it reaches the editor, so malformed or tampered input fails loudly instead of corrupting the scene.
Validation on loadโ
parseScene and deserializeScene run the document through SceneDocumentZ (a zod schema) after migrations and before hydration. A validation failure throws DeserializationError, whose reason carries the original ZodError.
import { parseScene, DeserializationError } from "@oh-just-another/serialization";
try {
const scene = parseScene(untrustedJson);
editor.loadScene(scene);
} catch (err) {
if (err instanceof DeserializationError) {
console.error("Invalid scene:", err.reason); // ZodError
} else {
throw err;
}
}
The schemaโ
SceneDocumentZ is the exported zod schema for a full scene document; SceneDocument is its inferred type. The element sub-schema is a z.union of strict per-shape schemas for the built-in type literals, plus a passthrough arm that accepts any non-builtin type with the standard base fields โ so plugin-registered custom shapes validate and persist without modifying the kernel schema.
import { SceneDocumentZ, type SceneDocument } from "@oh-just-another/serialization";
const result = SceneDocumentZ.safeParse(input);
if (result.success) {
const doc: SceneDocument = result.data;
}
What gets checkedโ
formatmagic constant and numericversion.- Each element against its discriminated shape schema (unknown types pass through the plugin arm).
- Links, layers, and the viewport (
pan,zoom,rotation,size,gridEnabled).
After validation, the hydrate step re-brands ElementId / LinkId / LayerId back to their branded kernel types and strips undefined-valued optional keys.