@kotao/storefront-contracts
v0.2.4
Published
Integration-spine contracts (ADR-0003/ADR-0047): Liquid settings-as-data and source-authoritative React/Hydrogen editor manifests, signed shop context, external content and app-extension contracts — types + Zod validators + Web Crypto, no runtime IO.
Readme
@kotao/storefront-contracts
Runtime-free TypeScript and Zod contracts for Kotao themes, editor values, storefront routing, and signed shop context. The package is the public compatibility boundary between theme tooling, Workspaces, the storefront API, and storefront runtimes.
Hydrogen editor manifests
HydrogenEditorManifestSchema validates the version 1, code-authoritative visual-editing contract.
It separates component definitions from stable source instances, represents ordered document roots
and slot parentage, and carries only declarative prop, content-binding, variant, style, layout, and
responsive metadata. It never contains executable theme code.
Source anchors and instance IDs are derived from semantic identity with
createHydrogenSourceAnchorId and createHydrogenInstanceId. Diagnostic line and column ranges do
not participate in those IDs, so formatter-only commits do not invalidate editor selection or
review anchors.
The schema is bounded and fail-closed. It rejects unknown versions and controls, excessive payloads or tree depth, invalid component/slot/prop/style references, cycles, and contradictory complete or partial capability findings. External content is represented as an explicit binding reference; it does not grant access to a provider.
The existing ThemeManifestSchema remains the backwards-compatible Liquid/settings-as-data
contract.
External visual-editor content
ExternalContentBindingSchema is the version 1 provider-neutral contract used to connect an
editable Hydrogen prop to an installed content source. It records only a browser-safe public
provider key, document and field identity, the field value type, locale policy, explicit preview
and published modes, a bounded transform chain, nullability, and an explicit fallback. Provider
URLs, credentials, request headers, and internal installation IDs are not part of the contract.
Bindings are assigned with ExternalContentBindingAssignmentSchema, which verifies that the
transformed output is compatible with the target prop. The value vocabulary covers scalar text,
portable rich text, number, boolean, HTTPS URL, normalized media, and bounded scalar lists.
ExternalContentProviderBrowserMetadataSchema is the strict redacted provider shape, while
assertExternalContentProviderSupport rejects unknown providers or unsupported modes and
transforms against an authorized registry.
Preview resolution can be persisted as an ExternalContentPreviewSnapshotSchema. Its deterministic
token includes the public source identity, locale, preview/published mode, provider revision,
freshness, and normalized value—never wall-clock time or secrets. Published mode is always
explicitly either live or pinned to a provider revision.
Theme app extensions
AppExtensionManifestSchema validates version 1 manifests for app embeds, app sections, and app
blocks. A manifest carries stable app, extension, and semantic-version identity; schema-driven
settings; eligible templates, section groups, or section types; explicit instance limits; and an
immutable artifact entrypoint.
Capabilities are deny-by-default. An omitted capability list becomes empty. Network access requires
both network:fetch and at least one reviewed bare origin with a justification. Declaring origins
without the matching capability is invalid. The runtime must expose only the declared capabilities
and origins; the manifest never grants platform bindings directly.
Persisted editor state uses AppEmbedEnablementSchema for singleton-style embeds and
AppExtensionPlacementSchema for app section/block instances. Both reference the exact reviewed app
and extension version, so upgrades do not silently change existing instances.
Version 1 evolves additively. Consumers should validate with AppExtensionManifestSchema; unknown
manifest versions fail with a supported-version error instead of being interpreted as version 1.
import { AppExtensionManifestSchema } from '@kotao/storefront-contracts/theme'
const manifest = AppExtensionManifestSchema.parse(input)