Skip to content

Commit 97394f2

Browse files
committed
feat: add rich payment pages guide and payment links docs
- Bump mppx to 0.5.1 (PR #266 payment links support) - Bump viem to ^2.47.5 (peer dep) - Add guide page: /guides/payment-links with interactive demo, prompt mode, and manual mode (Next.js, Hono, Express, Other) - Add payment links subsection to tempo/charge docs - Add payment links subsection to stripe/charge docs - Add /api/payment-link/photo API route with html: true - Add PaymentLinkDemo component and PaymentLinksCard - Add sidebar entry under Guides
1 parent 55dade1 commit 97394f2

10 files changed

Lines changed: 632 additions & 53 deletions

File tree

package.json

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -25,12 +25,12 @@
2525
"@stripe/stripe-js": "^8.9.0",
2626
"@vercel/blob": "^2.3.1",
2727
"mermaid": "^11.12.2",
28-
"mppx": "https://pkg.pr.new/mppx@231",
28+
"mppx": "https://pkg.pr.new/mppx@266",
2929
"react": "^19",
3030
"react-dom": "^19",
3131
"stripe": "^20.4.1",
3232
"tailwindcss": "^4.1.18",
33-
"viem": "^2.46.2",
33+
"viem": "^2.47.5",
3434
"vocs": "https://pkg.pr.new/wevm/vocs@319c55c",
3535
"wagmi": "^3.4.2",
3636
"waku": "^1.0.0-alpha.4"

pnpm-lock.yaml

Lines changed: 28 additions & 51 deletions
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

src/components/PaymentLinkDemo.tsx

Lines changed: 43 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,43 @@
1+
"use client";
2+
3+
const PAYMENT_LINK_URL = "/api/payment-link/photo";
4+
5+
export function PaymentLinkDemo() {
6+
return (
7+
<div className="not-prose">
8+
<div
9+
style={{
10+
border: "1px solid var(--vocs-color_border)",
11+
borderRadius: 12,
12+
overflow: "hidden",
13+
background: "var(--vocs-color_backgroundDark)",
14+
display: "flex",
15+
flexDirection: "column",
16+
alignItems: "center",
17+
justifyContent: "center",
18+
gap: 16,
19+
padding: "40px 24px",
20+
textAlign: "center",
21+
}}
22+
>
23+
<a
24+
href={PAYMENT_LINK_URL}
25+
target="_blank"
26+
rel="noopener noreferrer"
27+
className="no-underline! px-5 py-2.5 rounded-lg transition-opacity hover:opacity-80"
28+
style={{
29+
fontSize: "0.9375rem",
30+
fontWeight: 500,
31+
whiteSpace: "nowrap",
32+
color: "light-dark(#fff, #111)",
33+
backgroundColor:
34+
"light-dark(#111, rgba(255,255,255,0.92))",
35+
textDecoration: "none",
36+
}}
37+
>
38+
Open payment link ↗
39+
</a>
40+
</div>
41+
</div>
42+
);
43+
}

src/components/cards.tsx

Lines changed: 11 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -77,6 +77,17 @@ export function PayAsYouGoCard() {
7777
);
7878
}
7979

80+
export function PaymentLinksCard() {
81+
return (
82+
<Card
83+
description="Turn any API endpoint into a shareable payment page"
84+
icon="lucide:link"
85+
title="Payment links"
86+
to="/guides/payment-links"
87+
/>
88+
);
89+
}
90+
8091
export function ProxyExistingServiceCard() {
8192
return (
8293
<Card

src/mppx-payment-link.server.ts

Lines changed: 33 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,33 @@
1+
import { Mppx, tempo } from "mppx/server";
2+
import { createClient, http } from "viem";
3+
import { privateKeyToAccount } from "viem/accounts";
4+
import { tempoModerato } from "viem/chains";
5+
6+
const realm = process.env.REALM ?? "mpp.tempo.xyz";
7+
const account = privateKeyToAccount(
8+
(process.env.FEE_PAYER_PRIVATE_KEY ??
9+
"0x0000000000000000000000000000000000000000000000000000000000000001") as `0x${string}`,
10+
);
11+
12+
export const mppx = Mppx.create({
13+
methods: [
14+
tempo({
15+
account,
16+
currency: import.meta.env.VITE_DEFAULT_CURRENCY!,
17+
feePayer: true,
18+
getClient() {
19+
return createClient({
20+
chain: tempoModerato,
21+
transport: http(
22+
import.meta.env.RPC_URL ?? "https://rpc.moderato.tempo.xyz",
23+
),
24+
});
25+
},
26+
html: true,
27+
sse: true,
28+
testnet: true,
29+
}),
30+
],
31+
realm,
32+
secretKey: "demo",
33+
});
Lines changed: 61 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,61 @@
1+
import { mppx } from "../../../../mppx-payment-link.server";
2+
3+
export async function GET(request: Request) {
4+
const result = await mppx.charge({
5+
amount: "0.01",
6+
description: "Random stock photo",
7+
})(request);
8+
9+
if (result.status === 402) return result.challenge;
10+
11+
const res = await fetch("https://picsum.photos/1024/1024");
12+
const imageUrl = res.url;
13+
14+
const html = `<!doctype html>
15+
<html lang="en">
16+
<head>
17+
<meta charset="UTF-8" />
18+
<meta name="viewport" content="width=device-width, initial-scale=1.0" />
19+
<title>Photo — MPP Demo</title>
20+
<style>
21+
:root { color-scheme: dark light; }
22+
* { margin: 0; padding: 0; box-sizing: border-box; }
23+
body {
24+
min-height: 100vh;
25+
display: flex;
26+
flex-direction: column;
27+
align-items: center;
28+
justify-content: center;
29+
gap: 16px;
30+
padding: 32px;
31+
font-family: system-ui, -apple-system, sans-serif;
32+
background: light-dark(#fafafa, #0a0a0a);
33+
color: light-dark(#111, #eee);
34+
}
35+
img {
36+
max-width: 480px;
37+
width: 100%;
38+
border-radius: 12px;
39+
box-shadow: 0 4px 24px rgba(0,0,0,0.15);
40+
}
41+
p {
42+
font-size: 13px;
43+
color: light-dark(#666, #888);
44+
}
45+
</style>
46+
</head>
47+
<body>
48+
<img src="${imageUrl}" alt="Random photo from Picsum" />
49+
<p>Paid via MPP — $0.01</p>
50+
</body>
51+
</html>`;
52+
53+
return result.withReceipt(
54+
new Response(html, {
55+
headers: {
56+
"Cache-Control": "no-store",
57+
"Content-Type": "text/html; charset=utf-8",
58+
},
59+
}),
60+
);
61+
}

0 commit comments

Comments
 (0)