Function: compile()
compile(
version,catalog,registry,route):CompileResult
Defined in: packages/core/src/compile.ts:118
Validates one document version and serializes it into an immutable, content-addressed Artifact. It reads nothing and writes nothing — fetching the document and storing the artifact belong to an adapter.
Two passes, each collecting rather than stopping at the first fault. Structure comes first:
every node names a registered block, every child id resolves, the graph flattens from roots
without cycles, and every filled slot is declared and inside its allow, min and max.
Props come second, each node's values run through its catalog entry's own schema. The second
pass runs only when the first found nothing.
Compiling the same document against the same catalog and registry yields the same
artifact.hash every time — key order is normalized before hashing, so an insertion order
cannot change the address.
Parameters
version
The document to compile. roots names the entry elements in order and
elements indexes every node by id. Both are read, neither is mutated.
catalog
The serializable half of registration, keyed by block name: the schema each
node's props are judged by, and the ui.fields hints deciding which fields freeze into the
artifact and which become holes filled at render. A block a node names and the catalog omits
is a fault.
registry
The registered blocks, keyed by name. It supplies the slot constraints the
structural pass judges against, and the version number each used block is stamped with in
artifact.blockVersions.
route
string
Where the artifact is published. It is baked into the artifact and into the
content address, and it is judged before the document is looked at: absolute, no trailing
slash unless it is / itself, [slug] for a param segment, and * only as the final
segment.
Returns
The artifact, and the issues that did not stop one existing. A key an author wrote
and the schema did not keep comes back as unknown-prop, naming the node and the dotted
path — the artifact is publishable either way, so logging it, shipping it or ignoring it is
the caller's call.
Throws
A NubbinError coded invalid-route when route addresses no page,
raised before anything in the document is read.
Throws
One NubbinError carrying every structural fault at once, in issues:
no-roots, unknown-block, dangling-child, cycle, unreachable, slot-not-allowed,
slot-min, slot-max.
Throws
One NubbinError carrying every prop fault at once: invalid-props for
a value a schema rejects or one that parses to something other than an object, and
unknown-block for a node whose block has no catalog entry.
Throws
A NubbinError coded not-standard-schema when a catalog entry's schema
exposes no ~standard.validate, or answers with a promise — compiling is synchronous.
Examples
Compile a document and store what comes back
import { compile, createRegistry, defineBlock, defineCatalog } from "@nubbin/core";
import type { DocumentVersion } from "@nubbin/core";
import { z } from "zod";
const heroSchema = z.object({ title: z.string(), price: z.number() });
const hero = defineBlock({
name: "Hero",
schema: heroSchema,
component: null,
version: 1,
slots: {},
});
const registry = createRegistry([hero]);
const catalog = defineCatalog({
Hero: { schema: heroSchema, ui: { fields: { price: { data: { revalidate: 60 } } } } },
});
const version: DocumentVersion = {
documentId: "d1",
version: 1,
roots: ["n1"],
elements: { n1: { id: "n1", block: "Hero", props: { title: "T", price: 10 } } },
meta: { title: "Summer promotion" },
createdAt: "2026-01-01T00:00:00Z",
createdBy: "studio",
};
const { artifact, issues } = compile(version, catalog, registry, "/promotions/summer");
artifact.tree[0]?.props; // { title: "T" } — frozen into the artifact
artifact.tree[0]?.holes; // { price: { revalidate: 60 } } — resolved at render instead
artifact.blockVersions; // { Hero: 1 }
issues; // [] — nothing the schema dropped
Branch on a refusal rather than reading its prose
import { NubbinError, NubbinIssueCode } from "@nubbin/core";
try {
const { artifact } = compile(version, catalog, registry, route);
await store.write(artifact);
} catch (error) {
if (!(error instanceof NubbinError)) throw error;
if (error.code === NubbinIssueCode.InvalidRoute) return rejectRoute(error.message);
for (const issue of error.issues) editor.mark(issue.at, issue.path, issue.message);
}