@tapcart/app-studio-runtime
v0.2.0
Published
Shared block runtime for Tapcart App Studio — renderer, hooks, and host contracts.
Readme
@tapcart/app-studio-runtime
Host-agnostic block renderer for Tapcart App Studio.
This package compiles and evaluates user-authored block code under a host-supplied context, returning a React component ready to mount. Use it when you need to render App Studio blocks from any environment that can run React — SSR, in-browser preview, local dev clients, etc.
Installation
yarn add @tapcart/app-studio-runtime
# or
npm install @tapcart/app-studio-runtimePeer dependencies: react@^18 || ^19, react-dom@^18 || ^19.
Usage
import React from "react"
import * as jsxRuntime from "react/jsx-runtime"
import {
renderBlock,
BlockHost,
type HostContext,
} from "@tapcart/app-studio-runtime"
const host: HostContext = {
dependencies: {
react: React,
"react/jsx-runtime": jsxRuntime,
// ...any other modules your blocks import
},
appStudioComponents: {},
adapters: {},
scope: { blockId: "hero", blockConfig: {} },
}
// renderBlock throws BlockRenderError if compilation, evaluation, or the
// default-export check fails. Catch at the call site and decide how your
// host wants to surface failures (fallback UI, telemetry, etc.).
let Block
try {
Block = renderBlock({
code: pretranspiledBlockCode,
host,
blockId: "hero",
})
} catch (err) {
// err instanceof BlockRenderError
Block = () => null
}
// Mount inside a <BlockHost> so child code can call useHostContext()
const App = () => (
<BlockHost host={host}>
<Block />
</BlockHost>
)API
renderBlock({ code, host, blockId? })— compile + evaluate block code, return its default-exported React component. ThrowsBlockRenderErrorif compilation fails, evaluation throws, or the block has no default export.<BlockHost host={...}>— React provider exposing the host context to descendant components.useHostContext()— hook to access the current host inside a<BlockHost>subtree.buildBlockProps({ host, tapcartData, ... })— canonical constructor for theBlockPropsobject every host passes to mounted blocks.transpileCode(code)— standalone JSX/TS → CJS transpiler. Use when pre-transpiling block code before storage.evalCode({ code, dependencies, appStudioComponents, scope })— low-level eval. Most consumers should preferrenderBlock.UnsupportedInHostError— throw from adapter methods that a given host can't implement. Surfaces as the hook'serrorstate in consuming blocks.BlockRenderError— thrown byrenderBlockwhen a block fails to compile or run.withTapcartDataDefaults({ partial, integrationsApiUrl? })— fills canonical defaults (feature flags = true,hasApplePayCerts = false,themeOptions = {}, integrationtapcartApiUrldecoration) so non-SSR hosts produce aTapcartDatashape matching SSR's hosted response.
Scope
This package owns the bridge layer between host environments and block code:
the renderer, the HostContext, the canonical TapcartData shape, and the hook
surface that exposes host-provided capabilities to blocks. Adapter/hook pairs
shipped here:
useTapcart/TapcartAdapter— bridge to the native shell's actions + variablesuseCart/CartAdapter— cart state + mutations + checkout completionuseAuth/AuthAdapter— customer auth mutationsuseRouter/usePathname/useSearchParams/RouterAdapter— navigationuseWishlist/WishlistAdapter— wishlist stateuseQuickAdd/QuickAddAdapter— quick-add drawer controluseIntegrations/IntegrationsAdapter— initialized-integration registryuseLocalization/LocalizationAdapter— locale + translation lookupuseVariables/useActions— deprecated; delegate toTapcartAdapter
Out of scope: product / collection data fetching
Block authors fetch product and collection data via @tapcart/mobile-components,
not via the runtime. Mobile-components is host-agnostic by design — its
useProducts({ baseURL, ... }) and useCollection({ apiUrl, appId, ... }) hooks
take the API URL + tenant as args and hit Tapcart's product/collection HTTP API
directly. All three hosts (SSR, CLI dev, dashboard preview) bundle
@tapcart/mobile-components and register it in the block require shim.
The runtime intentionally does NOT ship useProducts / useCollection /
ProductsAdapter / CollectionAdapter — earlier iterations did, but the data
hooks have always lived in mobile-components and the runtime versions were
unused dead code. Don't re-add them here; if you need a different fetching
strategy, that's a @tapcart/mobile-components change.
Versioning
This package follows semver. Major versions may change the HostContext shape;
minor versions add capabilities (e.g., new adapter interfaces); patches are bug
fixes.
Contributing
See CONTRIBUTING.md for local development setup, build/test instructions, and notes for working on this package alongside its consumers.
