cimplify mock
Boots an in-process Hono server that mirrors the production Cimplify API (~99% parity) with seeded data. The mock is the oracle for testing and local development; every scaffolded storefront wires `bun dev` to start it alongside Next.js.
Usage
The mock storefront API lives in @cimplify/sdk (not @cimplify/cli) because it's tightly coupled to the SDK's domain types and seed data. Boot it three ways — the cimplify mock CLI wrapper (recommended; finds the SDK bin for you and auto-loads a local seed file), the cimplify-mock bin directly, or bunx with no install.
# Via the CLI wrapper (auto-loads ./cimplify.seed.{ts,json} if present)
cimplify mock # default seed, 127.0.0.1:8787
cimplify mock --seed retail
# Zero-install via bunx
bunx @cimplify/sdk mock --seed restaurant
# Or install once and call the bin directly
bun add -g @cimplify/sdk
cimplify-mock --seed retailSeeds
| Seed | Use case |
|---|---|
default | A representative bakery; the default if you omit --seed. |
restaurant | Menu-driven, with reservations + add-ons. |
retail | Variant-aware retail with full PDPs. |
services | Bookable services with calendar availability. |
grocery | High-SKU grocery with quick-add. |
fashion | Multi-drop fashion with a lookbook. |
reesa-storefront | Reesa-specific seed for AI / agent demos. |
empty | A bare business with no products. Useful for onboarding flows. |
Custom seeds
The built-in seeds are a starting point, not a ceiling. To spin up your own demo
site — a specific bakery, a client's spa, a stress-test catalogue — supply your
own seed. No SDK fork, no patching node_modules. There are three ways, from
zero-code to full control; pick the one that fits.
Quickest: scaffold from a built-in
cimplify mock init writes an editable seed into the current directory, starting
from the closest built-in. Then cimplify mock picks it up automatically.
cimplify mock init --from retail # writes cimplify.seed.ts
cimplify mock init --from retail --format json # writes cimplify.seed.json instead
cimplify mock # auto-loads ./cimplify.seed.{ts,json}cimplify mock (and cimplify-mock) auto-load a cimplify.seed.json,
cimplify.seed.mjs, cimplify.seed.js, or cimplify.seed.ts in the working
directory when no --seed* flag is given. Drop the file in, restart, done. An
explicit --seed/--seed-file/--seed-module flag overrides the convention.
Tier 1 — JSON snapshot (no code)
The mock can dump its entire seeded state to a JSON file. Edit that file — rename the business, change prices, swap images, delete products — and boot from it. Pure data, no build step, hot-swappable.
cimplify mock --seed default --dump akua.json # 1. dump a starting point
$EDITOR akua.json # 2. edit the data
cimplify mock --seed-file akua.json # 3. boot from your dataThe default business is the snapshot's sole business. If a snapshot has several
businesses, set which one is the default with a top-level __meta block:
{
"__meta": { "defaultBusinessId": "bus_akua" },
"businesses": { "bus_akua": { "id": "bus_akua", "name": "Akua's Bakery", "...": "..." } },
"products": { "prod_sourdough": { "id": "prod_sourdough", "name": "Sourdough", "...": "..." } }
}Keys that aren't stores (like __meta) are ignored by the loader, so the sidecar
is safe to keep.
Tier 2 — Seed module (full power)
For logic — loops, generated variants, computed pricing — write a module that
default-exports a seed function. defineSeed types it; the ctx builder mints
ids, applies sensible defaults, and wires category/collection back-references for
you.
import { defineSeed } from "@cimplify/sdk/mock";
export default defineSeed((ctx) => {
const biz = ctx.business({ name: "Akua's Bakery", handle: "akua", default_currency: "GHS" });
const breads = ctx.category({ name: "Breads" });
for (const [name, price] of [["Sourdough", "25.00"], ["Baguette", "15.00"]] as const) {
ctx.product({ name, price, category: breads, image: ctx.image("bakery", "sourdough-loaf") });
}
return { businessId: biz.id };
});cimplify mock --seed-module ./cimplify.seed.ts # or just `cimplify mock` (convention).mjs and .js modules load under any runtime; .ts modules need bun (run via
bunx @cimplify/sdk mock or cimplify mock from a bun project) or another TS
loader. If you're on plain node, use a .mjs or .json seed.
Tier 3 — Extend a built-in
Start from a built-in seed inside a module, then mutate it — the fastest way to a distinct demo without authoring a whole catalogue.
import { defineSeed } from "@cimplify/sdk/mock";
export default defineSeed((ctx) => {
const { businessId } = ctx.extend("restaurant"); // full restaurant catalogue
ctx.product({ name: "Chef's Tasting Menu", price: "180.00" }); // then add your own
return { businessId };
});The ctx builder API
defineSeed((ctx) => …) receives a SeedContext. Every method mints an id,
fills defaults, and stores the record; products auto-link to the category /
collection you pass.
| Method | Creates |
|---|---|
ctx.business({ name, … }) | The storefront's business (also becomes the default business). |
ctx.category({ name, slug?, … }) | A catalogue category. |
ctx.collection({ name, slug?, … }) | A merchandising collection. |
ctx.product({ name, price, category?, collection?, image?, … }) | A product, back-linked to its category/collection. |
ctx.service({ name, price, durationMinutes }) | A bookable service. |
ctx.image(industry, slug) | A seed image URL on the Cimplify CDN. |
ctx.extend(name) | Applies a built-in seed first; returns { businessId }. |
ctx.registry | The raw state registry — escape hatch for anything not modeled above. |
The seed function returns { businessId }, naming the business the mock treats
as the signed-in tenant.
Programmatic (in-process)
createMockApp (from @cimplify/sdk/mock) takes the same sources directly —
useful in tests or custom harnesses:
import { createMockApp, defineSeed } from "@cimplify/sdk/mock";
const app = createMockApp({ seed: "retail" }); // built-in name
const app2 = createMockApp({ seed: { kind: "json", data: snapshot } }); // JSON snapshot
const app3 = createMockApp({ seed: { kind: "fn", seed: defineSeed((ctx) => { /* … */ }) } });Flags
| Flag | Default | Description |
|---|---|---|
--port <num> | 8787 | Listen port. |
--host <host> | 127.0.0.1 | Bind host. Use 0.0.0.0 to expose on a LAN. |
--seed <name> | default | One of the built-in seeds in the table above. |
--seed-file <file.json> | none | Boot from a JSON snapshot instead of a built-in. See Custom seeds. |
--seed-module <file> | none | Boot from a module that default-exports a seed function (.mjs/.js anywhere; .ts needs bun). |
--dump <file.json> | none | Seed, write the full state snapshot to <file>, and exit (no server). The way to create a --seed-file. |
--auth-mode <mode> | permissive | permissive accepts any token; strict enforces real OTP / session checks. |
--otp <code> | 123456 | Default OTP code accepted by auth.verifyOtp. |
--persist <file> | none | Persist mock state to a JSON file across restarts. |
--cors <origins> | none | Comma-separated allow-list, or * for any origin. |
--webhook-url <url> | none | POST mock events to this URL. |
--webhook-secret <key> | none | HMAC secret for webhook signatures. |
--frozen-at <iso> | now | Freeze the mock's clock at a given ISO timestamp. |
--quiet | off | Suppress per-request logs. |
Examples
# All time-sensitive flows (slot availability, deal expiry, fx quote ttl) anchor to this point.
cimplify mock \
--seed retail \
--frozen-at "2026-06-01T10:00:00Z"cimplify mock \
--host 0.0.0.0 \
--port 8787 \
--seed grocery \
--persist ./.mock-state.jsoncimplify mock \
--seed restaurant \
--webhook-url http://localhost:3000/api/webhooks \
--webhook-secret whsec_local_devcimplify mock \
--auth-mode strict \
--otp 042042In Next.js dev
Every storefront template wires bun dev to spawn the mock + next dev in parallel. next.config.ts proxies /v1/* to the mock to avoid CORS in the browser.
{
"scripts": {
"dev": "concurrently \"bun run dev:mock\" \"next dev\"",
"dev:mock": "cimplify mock --seed retail --quiet"
}
}Programmatic mock
For unit / integration tests you don't need a separate process; the mock runs in-process via the SDK's first-class fetch injection, parallel-safe and globalThis-free.
import { createTestClient, fixtures, assertCart } from "@cimplify/sdk/testing";
const h = await createTestClient({ seed: "retail" });
await fixtures.addFirstProduct(h.client);
const cart = await h.client.cart.get();
assertCart(cart);Where next
-
Testing harness
createTestClient, fixtures, suites. -
init Scaffold a storefront wired to the mock.
-
CLI overview Full subcommand index.
Domains
Domains live at the **business** scope: add and verify them once, then attach them to one or more projects per env (`preview` or `production`). One verified domain can serve any project in your business.
Component registry
67 ejectable components ship in the registry. `cimplify list` shows every component; `cimplify add <name>` copies one's source into your project. After ejection it's yours; you stop receiving SDK updates for that component, in exchange for full control over JSX, state, and behavior.