numu-theme build ā contract validation) before you even try to install.your-theme/
āāā theme.json ā (1) manifest
āāā src/main.tsx ā (2) entry exporting `mount`
āāā settings_schema.json ā (3) global settings declarations
āāā schemas/sections/<type>.json ā (4) one per section type referenced
āāā locales/en.default.json ā (5) at least the default localetheme.json ā top-level manifest{
"id": "my-fashion-theme",
"name": { "en": "My Fashion Theme", "ar": "Ų«ŁŁ
Ų§ŁŁ
ŁŲ¶Ų©" },
"version": "1.0.0",
"author": "Your Name <you@example.com>",
"min_sdk_version": "0.6.0",
"presets": {
"templates": {
"home": { "name": "Home", "sections": {...}, "order": [...] },
"product": { ... },
"collection": { ... },
"cart": { ... }
}
},
"error_template_url": "dist/error.html",
"loading_template_url": "dist/loading.html"
}numu-theme lint's manifest-required-fields rule. The minimum:id ā kebab-case slug, unique on the marketplacename ā bilingual object {en, ar?}version ā semverauthor ā stringpresets.templates ā starter section layouts the customizer shows on first installerror_template_url / loading_template_url ā static HTML used by storefront error.tsx / loading.tsx (which load before the SDK federation runtime)src/main.tsx ā entrymount function with this signature:import type { MountContext } from "@numueg/theme-sdk";
export function mount(ctx: MountContext): () => void {
// create root, render
// return cleanup function
}numu-theme-plugin/src/lib/contract-validate.ts) checks:mount named export existsreact-dom + @numueg/theme-sdk are all listed as peerDependencies (i.e. externalized)main.tsx:import { createRoot } from "react-dom/client";
import { NuMuProvider } from "@numueg/theme-sdk";
import type { MountContext } from "@numueg/theme-sdk";
import Home from "./pages/Home";
import Product from "./pages/Product";
import Cart from "./pages/Cart";
import NotFound from "./pages/NotFound";
function dispatch(page: MountContext["page"]) {
switch (page.type) {
case "home": return <Home />;
case "product": return <Product product={page.data?.product} />;
case "cart": return <Cart />;
case "404": return <NotFound />;
default: return null;
}
}
export function mount(ctx: MountContext) {
const el = document.getElementById("numu-root")!;
const root = createRoot(el);
root.render(
<NuMuProvider
store={ctx.store}
themeSettings={ctx.themeSettings}
page={ctx.page}
locale={ctx.locale}
direction={ctx.direction}
currency={ctx.currency}
>
{dispatch(ctx.page)}
</NuMuProvider>
);
return () => root.unmount();
}settings_schema.json ā global theme settings{
"settings": [
{
"type": "color",
"id": "color_primary",
"label": "Primary color",
"default": "#0F172A"
},
{
"type": "font_picker",
"id": "font_heading",
"label": "Heading font",
"default": "Inter"
},
{
"type": "select",
"id": "header_layout",
"label": "Header layout",
"default": "logo-right",
"options": [
{ "value": "logo-right", "label": "Logo right" },
{ "value": "logo-center", "label": "Logo center" },
{ "value": "logo-left", "label": "Logo left" },
{ "value": "stacked", "label": "Stacked" }
]
}
]
}ctx.themeSettings at mount.schemas/sections/<type>.json ā per-section schematheme.json presets OR added via the customizer's Add-Section dialog needs a schema file. The schema declares settings (per-section), blocks (children), and presets (Add-Section variants).{
"type": "hero",
"name": "Hero",
"locales": { "ar": { "name": "Ų§ŁŲØŲ§ŁŲ± Ų§ŁŲ±Ų¦ŁŲ³Ł" } },
"settings": [
{ "type": "text", "id": "headline", "label": "Headline", "default": "Welcome" },
{ "type": "image_picker", "id": "background_image", "label": "Background" },
{ "type": "select", "id": "alignment", "label": "Alignment",
"default": "center",
"options": [
{ "value": "left", "label": "Left" },
{ "value": "center", "label": "Center" },
{ "value": "right", "label": "Right" }
]
}
],
"blocks": [
{ "type": "cta_button", "name": "CTA Button", "limit": 2, "settings": [...] }
],
"presets": [
{ "name": "Hero with button", "settings": {...}, "blocks": [...] },
{ "name": "Hero text-only", "settings": {...} }
]
}schema-codegen to generate TypeScript types into src/__generated__/sections.d.ts ā your section components get typed settings automatically:// auto-generated
export interface HeroSettings {
headline?: string;
background_image?: string;
alignment?: "left" | "center" | "right";
}// your section
import type { HeroSettings } from "../__generated__/sections";
export default function Hero({ settings }: { settings: HeroSettings }) {
return <section>{settings.headline}</section>;
}schema-registry-sync flags every section referenced in presets that's missing a schema (and vice versa).locales/en.default.json ā translations{
"cart": {
"title": "Your cart",
"empty": "Your cart is empty",
"checkout": "Checkout"
},
"product": {
"addToCart": "Add to cart",
"soldOut": "Sold out"
}
}useTranslation() in the SDK:import { useTranslation } from "@numueg/theme-sdk";
const t = useTranslation();
return <button>{t("product.addToCart")}</button>;locales/ar.json (and others) override per key. Lint rule locale-parity flags missing keys in non-default locales.| File | Purpose |
|---|---|
schemas/blocks/<type>.json | Reusable blocks across sections |
assets/* | Static assets; copied to dist/assets/ with content hashes |
templates/*.json | Customizer-installable templates beyond the presets in theme.json |
dist/error.html | Rendered by storefront error.tsx when the SDK fails before mount |
dist/loading.html | Rendered by storefront loading.tsx during route transitions |
home, product, collection, cart,
checkout_contact, checkout_shipping, checkout_payment,
checkout_review, checkout_processing, checkout_thank_you,
account, account_login, account_register, account_recover, account_reset,
account_profile, account_orders, account_order, account_addresses,
account_gift_cards, account_wishlist,
search, page, policies, blogs, blog, article,
password, 404null for any type you don't want to own ā the built-in fallback takes over for that route only.| Stage | Validator | Catches |
|---|---|---|
numu-theme lint (any time) | All 10 rules | Missing schemas, locale gaps, hex literals, useApp without availability guard, etc. |
numu-theme dev (HMR) | Schema codegen + contract validator | Type drift, missing mount export |
numu-theme build | Contract validator (strict) | Missing exports, React not externalized |
numu-theme submit (server-side) | AST scan + sandboxed re-build | Forbidden globals (document.write, raw eval), exfiltration patterns |
| Admin review | Manual + diff against last version | Visual regression, malicious code |