Skip to content

Astro Actions

Use @bnomei/emdash-mika/astro-actions from src/actions/.

Astro expects actions to be exported from a server object in src/actions/index.ts. Mika’s copyable src/actions/mika.ts keeps the package import isolated, then src/actions/index.ts decides how to expose and guard the tree:

src/actions/mika.ts
export {
createMikaActions,
type MikaActionName,
type MikaActions,
type MikaActionsOptions,
} from "@bnomei/emdash-mika/astro-actions";
src/actions/index.ts
import { createMikaActions } from "./mika";
import { api } from "../lib/mika-api";
export const server = {
mika: createMikaActions({ api }),
};

The action tree covers:

  • catalog sellables;
  • stock availability;
  • cart add/update/remove/merge/coupons;
  • wishlist add/remove/move/save/merge;
  • checkout start/status;
  • magic-link request/verify;
  • account export/delete/portal;
  • subscription cancel/change/renew.
  • download confirmation for the copied download interstitial.

Use the guard option for host policy such as rate limits, auth checks, bot checks, or feature locks.

guard runs before the selected Astro Action dispatches to Mika. Use it for browser-action concerns tied to Astro’s action context. operationPolicy runs at the Mika operation layer and is better when the same rule should also apply to plugin routes or trusted runner projections. Pass the host API with the same options, for example createMikaActions({ api, guard }).

The package exports the createMikaActions() factory and related types. It does not export a prebuilt mika action tree; hosts create the tree in src/actions/index.ts so they can pass api, guard, or operationPolicy explicitly.

Common first actions:

Task Action
Add a product to cart actions.mika.cart.add
Start checkout actions.mika.checkout.start
Add to wishlist actions.mika.wishlist.add
Request magic link actions.mika.magicLink.request
Confirm a download token actions.mika.download.confirm

Most browser mutations are form actions because copied templates are HTML-first:

The return column lists the inner success DTO, not the whole Action result. Ordinary actions.mika.* preserve MikaApiResult<DTO> inside Astro’s safe result; read the DTO at result.data.data only after result.data.ok === true.

Action path Accept Inner success DTO
actions.mika.catalog.sellables json readonly SellableDTO[]
actions.mika.stock.availability json AvailabilityDTO
actions.mika.cart.add form CartDTO
actions.mika.cart.update form CartDTO
actions.mika.cart.remove form CartDTO
actions.mika.cart.merge form CartDTO
actions.mika.cart.applyCoupon form CartDTO
actions.mika.cart.removeCoupon form CartDTO
actions.mika.wishlist.add form WishlistDTO
actions.mika.wishlist.remove form WishlistDTO
actions.mika.wishlist.moveToCart form CartDTO
actions.mika.wishlist.saveForLater form WishlistDTO
actions.mika.wishlist.merge form WishlistDTO
actions.mika.checkout.start form CheckoutSessionDTO
actions.mika.checkout.status json CheckoutSessionDTO
actions.mika.magicLink.request form { sent: boolean }
actions.mika.magicLink.verify form AccountDTO
actions.mika.account.export form AccountExportDTO
actions.mika.account.exportStatus json AccountExportDTO
actions.mika.account.delete form { requested: boolean }
actions.mika.account.portal form { redirectUrl: string }
actions.mika.subscription.cancel form AccountDTO
actions.mika.subscription.change form AccountDTO
actions.mika.subscription.renew form AccountDTO
actions.mika.download.confirm form DownloadResolutionDTO

JSON action clients exist for typed read/status calls such as catalog sellables, stock availability, checkout status, and account export status. Do not treat JSON action clients as permission to expose protected browser JSON mutation routes.

actions.mika.download.confirm is deliberately separate from download.resolve. The package template pages/download/[token].astro renders a GET interstitial and consumes the single-use token only after a user submits the POST form, so link scanners, previews, and browser prefetch cannot burn the token.

This is the breaking ordinary Action contract in the unpublished 0.2.0 target. Check both layers for Astro.getActionResult() and browser Action calls:

const result = Astro.getActionResult(actions.mika.checkout.start);
if (result?.error) {
// Astro validation/input-normalization or host guard failure.
// Inspect result.error.code and result.error.message.
} else if (result?.data?.ok === false) {
// Commerce failure: result.data.status and result.data.error.code/message.
} else if (result?.data?.ok && result.data.data.redirectUrl) {
return Astro.redirect(result.data.data.redirectUrl);
}

Commerce failures are no longer mapped from HTTP-like Mika statuses into Astro ActionError codes. A truthy result.data can be a failed Mika result. Branch on stable error codes, not message text. .orThrow() removes only Astro’s safe-result layer and still returns MikaApiResult<DTO>; it does not throw merely because Mika returned ok: false.

Direct createMika(Astro, { api }) server helpers remain unchanged: check result.ok, then read result.data or result.error without an extra Action layer.

The separate actions.mikaStorefront.describe/invoke/confirm surface returns tool descriptions or MikaStorefrontResponse inside Astro’s envelope, not this Mika ok/data envelope. See Browser Shopping Tools and Storefront Tools for its response and review/handoff contract.

  • ⓟ ../emdash-mika/src/astro-actions.ts
  • ⓟ ../emdash-mika/src/api/action-tree.ts
  • ⓟ ../emdash-mika/src/api/operation-policy.ts
  • ⓐ ../emdash-mika/src/templates/astro/actions/mika.ts
  • ⓐ ../emdash-mika/src/templates/astro/actions/index.ts
  • ⓐ ../emdash-mika/src/templates/astro/pages/download/[token].astro