Skip to content
Browse guides

Guide ·Markdown source ·View on GitHub

Lock, archive and serve documents

Work on the authoring/build side, retaining the original input until the conversion is reviewed:

import { createRegistry, prepare, assertPrepared } from "@publisle/core";
import { coreBlockDefinitions } from "@publisle/blocks-core";
import { lockDocument, resolveContracts } from "@publisle/contracts";
import { exportExchange, importExchange } from "@publisle/contracts/exchange";
import { toArchivalMarkdown, fromArchivalMarkdown } from "@publisle/markdown";
import {
  compilePublication,
  publicationReaderManifest,
} from "@publisle/adapter-core";

const registry = createRegistry(coreBlockDefinitions);
const locked = await lockDocument(article, registry);
// Store/review locked.original separately; approval saves document AND bundle.
const verified = await resolveContracts(locked.document.dependencies ?? [], {
  bundle: locked.bundle,
  offline: true,
});
const prepared = assertPrepared(
  prepare(locked.document, {
    registry,
    contractPins: locked.document.dependencies ?? [],
  }),
);
const decode = (text: string) => fromArchivalMarkdown(text).document;
await exportExchange("./new-article-package", {
  source: locked.document,
  bundle: verified,
  archival: { markdown: toArchivalMarkdown(locked.document), decode },
  resources: prepared.resources.resources.map((resource) => ({ resource })),
}); // Missing bytes stay explicitly missing; no network access occurs.
const imported = await importExchange("./new-article-package", {
  decodeArchival: decode,
});
const artifact = compilePublication(prepared, {
  build: {
    configuration: { renderers: "host-approved-configuration-1" },
    reproducible: true,
  },
});
const readerData = publicationReaderManifest(artifact);

Pass only readerData, separately instantiated HTML and approved host loaders to your reader. Import attachPublication/instantiatePublication from @publisle/adapter-core/publication-runtime. Artifact mode reports unsupported static framework components; supply renderers[type].static.lower or authored fallback rather than claiming arbitrary framework components compile to HTML. See delivery.

For authoring previews, pnpm cli lock article.json prints a pinned copy without writing. --output new-locked.json refuses overwrite; --in-place is prohibited for lock. Trusted CLI contractBundle config approves pins for later validation. Save the returned bundle through the library workflow above; source pins alone are not a distributable closure. Existing noncanonical inputs require an explicit upgrade preview first. Both playgrounds now offer Export archival Markdown; ordinary Markdown remains a separate readable projection. Import auto-detects the archival document directive.

Enable remote resolution only in preparation tooling with explicit policy and locations:

const closure = await resolveContracts(pins, {
  cache: verifiedCache,
  remote: {
    policy: {
      origins: ["https://contracts.example"],
      maxBytes: 500_000,
      timeoutMs: 2000,
    },
    locations: approvedImmutableIdToMirrorUrls,
  },
});

Neither a schema $ref nor a document module name enables fetching or execution. Keep full contracts/Ajv out of readers. Relative resources need a host resolver with the source base, explicit behavior version, resolved location and exact byte digest if verified. Directory exchange includes only bytes you explicitly supply and permit. See the exchange contract for grammar, integrity domains, budgets and filesystem limitations.