This file provides guidance to Claude Code (claude.ai/code) when working with code in this repository.
This is a Val Town project — a Klarna payment integration prototype demonstrating iframe-based payment flows for the JPM (J.P. Morgan) partnership. It runs on the Val Town platform (Deno serverless runtime, not Node.js).
This project is deployed and run via Val Town. Locally, use the vt CLI:
vt dev # Start local dev server vt push # Deploy to Val Town vt pull # Pull latest from Val Town
The project has a .vt/state.json that tracks the Val Town project ID and branch.
The app uses a single-iframe architecture for Klarna payment integration:
-
main.ts— HTTP request handler (Val Town entry point). Serves static files fromfrontend/andshared/using Val Town'sserveFile/readFileutilities. -
frontend/index.html— First-party merchant page. Embeds a single<iframe>pointing toklarna-iframe.html. Listens forpostMessageevents to resize the iframe between button-size and fullscreen, and to display payment results. -
frontend/klarna-iframe.html— Third-party iframe containing both the Klarna SDK payment button and the payment flow. Has a transparent background so the merchant page shows through the SDK's overlay. On button click, tells the parent to expand to fullscreen, then initiatesPayment.initiate()withON_PAGEmode. On completion/abort, tells the parent to shrink back to button size. -
shared/types.ts— TypeScript type definitions for allpostMessagepayloads (ButtonReadyMessage,ExpandIframeMessage,ShrinkIframeMessage,PaymentCompleteMessage,PaymentAbortMessage) plus type guard functions.
klarna-iframe → button-ready → index.html (parent sizes iframe)
klarna-iframe → expand-iframe → index.html (parent goes fullscreen)
klarna-iframe → shrink-iframe → index.html (parent restores button size)
klarna-iframe → payment-complete → index.html (parent shows result)
klarna-iframe → payment-abort → index.html (parent shows result)
- Runtime is Deno, not Node.js — use
Deno.env.get()for env vars, notprocess.env - Use
https://esm.shfor npm imports (works in both server and browser) - Code in
shared/must work in both frontend and backend — cannot useDenonamespace there - Entry point exports a default async function:
export default async function(req: Request) - Use
Response.redirectworkaround:new Response(null, { status: 302, headers: { Location: url } }) - Do NOT use Deno KV,
alert(),prompt(), orconfirm() - Imports use URL-based specifiers (e.g.,
https://esm.town/v/std/utils@85-main/index.ts)
The iframe initializes the Klarna Web SDK v2 from https://js.playground.klarna.com/web-sdk/v2/klarna.mjs using test credentials. The SDK is configured with products: ["PAYMENT"]. Payment is initiated with initiationMode: "ON_PAGE" so the SDK renders its overlay inside the fullscreen iframe rather than trying to open a popup (which would be blocked from within an iframe).
Uses TailwindCSS via twind CDN (https://cdn.twind.style). When using React, pin all dependencies to react@18.2.0.