One config, one client per request
A server serves many shoppers, so a client must be bound to this request’s cookies. Keep one long-lived config and bind a client per request withwithStorage():
src/kit.server.ts
createRequestCookieStorage(source, options) reads cookies straight off a Request, a Headers object or a raw Cookie header string. With collect, every write is appended as a serialized Set-Cookie string for you to attach to the response. withStorage() returns a copy of the client bound to that storage.
Reads versus writes
Cookies must not be
httpOnly if browser code also reads the cart (the elements, useCart, the shared cart store). The default leaves httpOnly off.
Hono and Cloudflare Workers
src/index.ts
c.env.QUICKBUTIK_PUBLISHABLE_KEY) instead of process.env.
Express
Express has noRequest object, so pass the raw Cookie header string as the source:
Deriving
origin from the Host header is convenient for successUrl. For canonical URLs in SEO tags, use a fixed configured origin instead, because a canonical built from an attacker-supplied Host is a known SEO-poisoning vector.Astro
Fetch in the frontmatter with a request-bound client, put thebuildSeo() output in the layout <head>, and use the web components in a client <script> for the interactive parts:
src/pages/products/[slug].astro
serializeJsonLd() escapes every <, so merchant content can’t close the script tag. For a cart that works without JavaScript, post forms to an API endpoint that uses the Hono-style pattern above.
Build time: static params and sitemaps
products.listAll() pages through the whole catalog (bounded at 200 pages). It’s for build time and sitemaps, not for a request path:
getBySlug() walking pages on a hot path. After that, look products up with products.get(id), which is a single request.
Bring your own storage adapter
Any object withkind, get, set and remove works as storage, and each method may return a promise. That covers a signed cookie, a Redis or KV session, or a test double:
"auto" storage resolves: Storage & SSR.