First Product Page
Use this page after Mika is registered and actions.mika.* exists. It shows the smallest host-owned product page shape: resolve host content, ask Mika for sellables, render product metadata, then render purchase forms.
Product pages stay host-owned. Mika supplies the request-bound helper, form contracts, sellable data, and copyable purchase components.
Prerequisites
Section titled “Prerequisites”- Mika is registered in the host EmDash config.
createMikaActions()is exported asserver.mika.- The host can look up a product by route slug.
- The product purchase component dependency set from First Integration Checklist is copied, including
src/lib/routes.ts;ProductStructuredData.astrois copied too. - If rendering copied Kumo-backed components,
@cloudflare/kumo, React,@astrojs/react, andsrc/styles/kumo.cssare installed and imported. - The product route can render on demand with
export const prerender = falseor server output.
The usual first page does this:
- Fetch the host product entry.
- Create a request-bound Mika helper with
createMika(Astro). - Load sellables with
Mika.catalog.sellables(collection, id). - Render visible host product content.
- Render
ProductStructuredDatawith matching product and offer metadata. - Render
ProductPurchasefor variants, stock state, add-to-cart, buy-now, and wishlist actions.
Map Host Product Routes To Mika Content Refs
Section titled “Map Host Product Routes To Mika Content Refs”The URL slug is host-owned. Mika sellable lookup uses a content ref, usually a collection name plus the host entry ID.
Resolve the slug to a host product first, then pass the stable content ref to Mika:
const product = productBySlug(Astro.params.slug);const sellablesResult = await Mika.catalog.sellables("products", product.id);Do not assume the route slug and Mika content ID are the same value. The seeded template route /products/[slug].astro resolves the slug with templateProductBySlug(slug), then calls Mika.catalog.sellables("products", product.id).
The sample below is host-app pseudocode for src/pages/products/[slug].astro.
---import { createMika } from "@bnomei/emdash-mika/astro";import ProductPurchase from "../../components/ProductPurchase.astro";import ProductStructuredData from "../../components/ProductStructuredData.astro";import { productBySlug } from "../../lib/products";
export const prerender = false;
const Mika = createMika(Astro);const slug = Astro.params["slug"];if (!slug) return Astro.redirect("/404");
const product = productBySlug(slug);if (!product) return Astro.redirect("/404");
const sellablesResult = await Mika.catalog.sellables("products", product.id);const sellables = sellablesResult.ok ? sellablesResult.data : [];---
<ProductStructuredData sellables={sellables} product={{ name: product.title, description: product.description, url: Astro.url }}/><ProductPurchase sellables={sellables} />The seeded template uses the same boundary, but its lookup is templateProductBySlug(slug) from src/lib/mika-api.ts and its route passes fixture overrides with createMika(Astro, { api: mikaApiOverrides }) so the page reads the resettable template store instead of production repositories.
Handle Posted Form Results
Section titled “Handle Posted Form Results”The same page also receives the POST results from the purchase forms. Read them with Astro.getActionResult(), and redirect to the provider when a checkout starts:
---import { actions } from "astro:actions";
const checkout = Astro.getActionResult(actions.mika.checkout.start);if (checkout?.data?.redirectUrl) return Astro.redirect(checkout.data.redirectUrl);
const added = Astro.getActionResult(actions.mika.cart.add); // CartDTO on success---ProductPurchase owns the add-to-cart, buy-now, and wishlist forms. It derives its view model with createMikaPurchaseModel(sellables) (selected sellable/price, maxQuantity, unavailable, grouped-variant controls), so you do not hand-assemble those controls.
Verify
Section titled “Verify”- The page renders host product copy and Mika purchase controls from the same content ref.
ProductStructuredDatareceives the same sellables shown to buyers.- Add-to-cart submits to
actions.mika.cart.addandAstro.getActionResult()can render the result. - Checkout start either redirects to a provider session or returns a clear provider/configuration error.
Next: use Astro Storefront to copy the full action and component set, or use Cart, Wishlist, And Checkout once the product form posts successfully.
Source Anchors
Section titled “Source Anchors”- ⓐ
../emdash-mika/src/templates/astro/examples/astro-storefront.md - ⓐ
../emdash-mika/src/templates/astro/components/ProductPurchase.astro - ⓐ
../emdash-mika/src/templates/astro/components/ProductStructuredData.astro - ⓟ
../emdash-mika/src/astro.ts - ⓣ
../emdash-mika-template/src/pages/products/[slug].astro - ⓣ
../emdash-mika-template/src/lib/mika-api.ts - ⓣ
../emdash-mika-template/src/lib/mika-fixture-storefront.ts