Skip to main content

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โ€‹

  • format magic constant and numeric version.
  • 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.