Skip to content

Serve Studio design time from a session-free catalog route - #661

Merged
field123 merged 4 commits into
masterfrom
feat/537-design-time-catalog-route
Oct 5, 2026
Merged

field123 merged 4 commits into
masterfrom
feat/537-design-time-catalog-route

Conversation

@field123

@field123 field123 commented Oct 5, 2026

Copy link
Copy Markdown
Collaborator

Closes #537.

A designer editing in Studio has to see their own store's catalog — real names, real images, the store's own extension slugs and hierarchy node ids, none of which a fixture supplies. The shopper session cannot carry that: better-auth's SameSite=Lax cookie never reaches Studio's editing frame once a customer hosts their app host on their own registrable domain.

createEpDesignRoutes(epAuth) lives in its own file so "never reads the session" is a property of what it imports: no cookie parser, no getSession, no cart writer. It serves four declared names — getProduct, getProductList, getProductPage, getRelatedProducts — imported per module so the closed list is structural, and refuses everything else. It is not a forwarder: its implicit token is public and can write to /carts and /checkout. CORS is * with no credentials and no origin gate, and trustedOrigins takes no entry for it (ADR-0001).

The browser forks on realm once, before the request, so no proxy failure can retry against a route that cannot see the shopper. The artboard is detected through usePlasmicCanvasContext; the app-host document through window.__CanvasPkgs, read per call because Studio injects it asynchronously.

registerAll registers no server functions, asserted by a test. The half that cannot be asserted from inside the package — canvas-packages growing a ./server import — carries a comment instead.

Deletes window.__epProxyOrigin: unreachable where needed, unnecessary where reachable, set by nobody.

Two deviations from the issue

A transport failure throws in both realms rather than soft-failing to the caller's fallback. Soft-failing left the canvas showing "Product not found" when the route is unmounted — a caller's null is its own empty shape, not a mock floor — which fails the issue's own "sees clearly labelled sample data" criterion. Throwing routes the component to its error branch, which is where the "Sample" fixtures live. Off-allowlist names keep the issue's soft-fail-on-the-artboard, throw-in-the-panel split.

epAuth.config gains clientId, host and resolveConfig. The issue says no new config is needed because epAuth.config.clientId is already server-side; it was not on config, and a consumer reading its store from the Plasmic bundle bootstraps the factory with placeholders, so the static pair alone names a store that does not exist.

…free catalog route

A designer editing in Studio has to see their own store's catalog — real
names, real images, the store's own extension slugs and hierarchy node ids,
none of which a fixture supplies. The shopper session cannot carry that:
better-auth's SameSite=Lax cookie never reaches Studio's editing frame once a
customer hosts their app host on their own registrable domain.

createEpDesignRoutes is a separate file so "never reads the session" is a
property of what it imports: no cookie parser, no getSession, no cart writer.
It serves four declared names — getProduct, getProductList, getProductPage,
getRelatedProducts — imported per module so the closed list is structural, and
refuses everything else. It is not a forwarder: its implicit token is public
and can write to /carts and /checkout. CORS is * with no credentials and no
origin gate, and trustedOrigins takes no entry for it (ADR-0001).

The browser forks on realm once, before the request, so no proxy failure can
retry against a route that cannot see the shopper. The artboard is detected
through usePlasmicCanvasContext; the app-host document through
window.__CanvasPkgs, read per call because Studio injects it asynchronously.

An off-allowlist name soft-fails on the artboard, where the mock floor renders
in its place, and throws in the Configure panel, where nothing sits behind a
null to tell it apart from a wrong binding. A transport failure throws in both:
a caller's fallback is its own empty shape, so an unmounted route would read as
"Product not found" rather than as labelled sample data. That case also emits
one console warning naming the route and how to mount it.

registerAll registers no server functions, asserted by a test, and the
canvas-packages entry carries the comment for the half that cannot be.

Deletes window.__epProxyOrigin: unreachable where needed, unnecessary where
reachable, set by nobody.

Closes #537
@field123
field123 merged commit c097edd into master Oct 5, 2026
9 checks passed
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

Serve Studio design-time data from a session-free catalog route

1 participant