Skip to content
Draft
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
39 commits
Select commit Hold shift + click to select a range
a4144b5
feat: add html payment pages for browser 402 responses
tmm Mar 23, 2026
5c6eaf9
Merge branch 'main' of https://github.com/wevm/mppx into tmm/html-pay…
tmm Mar 23, 2026
7f390e6
chore: wip
tmm Mar 25, 2026
6884389
refactor: setup
tmm Mar 25, 2026
d22a758
chore: up
tmm Mar 25, 2026
a1ad0b6
chore: tweaks
tmm Mar 25, 2026
3ea13c3
chore: up
tmm Mar 25, 2026
feed1c4
chore: up
tmm Mar 25, 2026
f572e5f
chore: renames
tmm Mar 25, 2026
4c4bd41
wip: up
tmm Mar 26, 2026
ac05e22
chore: merge main, resolve conflicts
tmm Mar 26, 2026
a56dbed
chore: merge main, resolve middleware import conflicts
tmm Mar 26, 2026
bf6d8b2
chore: up
tmm Mar 26, 2026
8572f0b
wip: public api
tmm Mar 26, 2026
651ce54
chore: merge
tmm Mar 26, 2026
9396c6b
refactor: default off
tmm Mar 26, 2026
e999bae
chore: up
tmm Mar 26, 2026
af2f30d
chore: up
tmm Mar 26, 2026
efa6daf
chore: up
tmm Mar 26, 2026
24e783f
chore: format
tmm Mar 26, 2026
d0b758e
chore: up
tmm Mar 26, 2026
ef30de2
chore: up
tmm Mar 27, 2026
be99bf2
chore: up
tmm Mar 27, 2026
97ec923
chore: up
tmm Mar 27, 2026
6796dc6
refactor: internals
tmm Mar 27, 2026
cc43d3a
revert: remove unnecessary middleware changes
tmm Mar 27, 2026
c49e551
chore: up
tmm Mar 27, 2026
0856dd9
chore: tweaks
tmm Mar 27, 2026
7deec00
chore: tweaks
tmm Mar 27, 2026
520e076
ci: fix
tmm Mar 27, 2026
fe6ccf2
chore: up
tmm Mar 27, 2026
a52d9eb
chore: up
tmm Mar 27, 2026
3b6c8e7
chore: up
tmm Mar 27, 2026
5c31648
refactor: api design
tmm Mar 27, 2026
54ab328
chore: tweaks
tmm Mar 27, 2026
93a37e5
Merge remote-tracking branch 'origin/main' into tmm/html-payment-pages
tmm Mar 27, 2026
afe8ae9
chore: audit
tmm Mar 27, 2026
1b78777
fix: hide tempo disconnect button after submit
tmm Mar 27, 2026
30da017
Merge remote-tracking branch 'origin/main' into tmm/html-payment-pages
tmm Mar 27, 2026
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
12 changes: 11 additions & 1 deletion .github/workflows/verify.yml
Original file line number Diff line number Diff line change
Expand Up @@ -36,8 +36,11 @@ jobs:
- name: Lint & format
run: pnpm check:ci

- name: Generate HTML
run: pnpm gen:html

- name: Check types
run: pnpm dev && pnpm check:types && pnpm check:types:examples
run: pnpm check:types && pnpm check:types:html && pnpm check:types:examples

test:
name: Test Runtime
Expand Down Expand Up @@ -102,3 +105,10 @@ jobs:
pnpm run test --bail=1
env:
CI: true

- name: Run HTML e2e tests
run: pnpm test:html
env:
VITE_STRIPE_PUBLIC_KEY: ${{ secrets.VITE_STRIPE_PUBLIC_KEY }}
VITE_STRIPE_SECRET_KEY: ${{ secrets.VITE_STRIPE_SECRET_KEY }}
VITE_TEMPO_TAG: sha-20aecec
2 changes: 2 additions & 0 deletions .gitignore
Original file line number Diff line number Diff line change
Expand Up @@ -3,7 +3,9 @@ dist
node_modules
coverage
*.tsbuildinfo
*.gen.ts
.DS_Store
.env
.env.*
!.env.example
test-results/
38 changes: 34 additions & 4 deletions AGENTS.md
Original file line number Diff line number Diff line change
Expand Up @@ -145,12 +145,42 @@ id = base64url(HMAC-SHA256(server_secret, input))
## Commands

```bash
pnpm build # Build with zile
pnpm check # Lint with oxlint + format with oxfmt
pnpm check:types # TypeScript type checking
pnpm test # Run tests with vitest
pnpm build # Build with zile
pnpm check # Lint with oxlint + format with oxfmt
pnpm check:types # TypeScript type checking
pnpm check:types:html # TypeScript type checking for HTML payment pages (browser tsconfig)
pnpm test # Run tests with vitest
pnpm test:html # Run HTML e2e tests (Stripe + Tempo) with Playwright
pnpm check:types:examples # TypeScript type checking for examples/
```

## HTML Payment Pages

Browser-rendered payment pages live in `src/html/`. Each method (Tempo, Stripe) has its own directory with:

- `src/charge.ts` — Entry point, creates DOM and handles payment flow
- `src/env.d.ts` — Module augmentation for `MppxConfig` and `MppxChallengeRequest`
- `vite.config.ts` — Dev server and build config

### Build pipeline

`pnpm build` bundles each method's `charge.ts` into `{method}/server/internal/html.gen.ts` (generated, do not edit). The page shell is bundled into `server/internal/html.gen.ts`.

### Global types

- `src/html/env.d.ts` — Base global types (`mppx` var, `MppxConfig`, `MppxChallengeRequest`, `MppxEventMap`)
- Each method augments `MppxConfig` and `MppxChallengeRequest` via its own `src/env.d.ts`
- Browser tsconfig: `src/html/tsconfig.browser.json`

### Infrastructure routes (`mppx.html()`)

`Mppx.create()` returns an `html(request)` method that handles infrastructure routes:

- Service worker (`/__mppx_serviceWorker.js`)
- Method-registered routes (e.g., Stripe's `/__mppx_stripe_create_token`)

Methods register routes via `htmlRoutes` on `Method.toServer()`.

## Skills Reference

Load these skills for specialized guidance:
Expand Down
5 changes: 3 additions & 2 deletions examples/charge/src/server.ts
Original file line number Diff line number Diff line change
Expand Up @@ -5,13 +5,14 @@ import { tempoModerato } from 'viem/chains'
import { Actions } from 'viem/tempo'

const account = privateKeyToAccount(generatePrivateKey())
const currency = '0x20c0000000000000000000000000000000000000' as const // pathUSD

const mppx = Mppx.create({
methods: [
tempo({
currency,
account,
currency: '0x20c0000000000000000000000000000000000000',
feePayer: true,
html: {},
recipient: account.address,
testnet: true,
}),
Expand Down
4 changes: 4 additions & 0 deletions examples/stripe/src/server.ts
Original file line number Diff line number Diff line change
Expand Up @@ -9,6 +9,10 @@ const mppx = Mppx.create({
methods: [
stripe.charge({
client: stripeClient,
html: {
// Publishable key for browser HTML payment form.
publishableKey: process.env.VITE_STRIPE_PUBLIC_KEY!,
},
// Stripe Business Network profile ID.
networkId: 'internal',
// Ensure only card is supported.
Expand Down
40 changes: 34 additions & 6 deletions package.json
Original file line number Diff line number Diff line change
@@ -1,18 +1,29 @@
{
"scripts": {
"build": "zile",
"changeset:publish": "zile publish:prepare && changeset publish && zile publish:post",
"build": "pnpm gen:html && zile",
"build:html": "vp build src/html/page && vp build src/html/tempo && vp build src/html/stripe",
"changeset:publish": "pnpm gen:html && zile publish:prepare && changeset publish && zile publish:post",
"changeset:version": "changeset version",
"check": "vp lint --fix && vp fmt --write .",
"check:ci": "vp lint && vp fmt --check .",
"check:types": "tsgo -b",
"check:types:examples": "pnpm -r --filter './examples/**' run check:types",
"check:types:html": "tsgo -p src/html/tsconfig.browser.json",
"check:types:examples": "pnpm zile build && pnpm -r --filter './examples/**' run check:types",
"deps": "pnpx taze -r --no-ignore-other-workspaces --ignore-paths node_modules",
"deps:ci": "pnpx actions-up",
"dev": "zile dev",
"dev:example": "node scripts/dev:example.ts",
"dev": "pnpm gen:html && zile dev",
"dev:example": "pnpm gen:html && node scripts/dev:example.ts",
"dev:html:compose": "pnpm --filter @mppx/html-page dev:compose",
"dev:html:stripe": "pnpm --filter @mppx/html-stripe dev",
"dev:html:tempo": "pnpm --filter @mppx/html-tempo dev",
"gen:html": "pnpm build:html",
"mppx": "node --import tsx src/bin.ts",
"test": "vp test"
"test": "pnpm gen:html && vp test",
"test:html": "pnpm gen:html && pnpm test:html:form && pnpm test:html:compose && pnpm test:html:stripe && pnpm test:html:tempo",
"test:html:compose": "pnpm --filter @mppx/html-page test:compose",
"test:html:form": "pnpm --filter @mppx/html-page test:form",
"test:html:stripe": "pnpm --filter @mppx/html-stripe test",
"test:html:tempo": "pnpm --filter @mppx/html-tempo test"
},
"browserslist": [
"defaults",
Expand All @@ -39,13 +50,16 @@
"fast-check": "^4.6.0",
"file-type": "^21.3.2",
"hono": "^4.11.9",
"@playwright/test": "^1.58.2",
"playwright": "^1.58.2",
"prool": "^0.2.4",
"vite": "^8.0.0",
"tempo.ts": "^0.14.2",
"testcontainers": "^11.11.0",
"tsx": "^4.21.0",
"typescript": "~5.9.3",
"viem": "^2.47.6",
"vite-plus": "~0.1.14",
"vp": "npm:vite-plus@~0.1.14",
"zile": "^0.0.19"
},
Expand Down Expand Up @@ -146,6 +160,20 @@
"types": "./dist/middlewares/elysia.d.ts",
"src": "./src/middlewares/elysia.ts",
"default": "./dist/middlewares/elysia.js"
},
"./html": {
"types": "./dist/html/index.d.ts",
"src": "./src/html/index.ts",
"default": "./dist/html/index.js"
},
"./html/vite": {
"types": "./dist/html/vite.d.ts",
"src": "./src/html/vite.ts",
"default": "./dist/html/vite.js"
},
"./html/env": {
"types": "./dist/html/env.d.ts",
"src": "./src/html/env.d.ts"
}
},
"peerDependencies": {
Expand Down
89 changes: 89 additions & 0 deletions pnpm-lock.yaml

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

8 changes: 6 additions & 2 deletions pnpm-workspace.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -2,12 +2,15 @@ packages:
- .
- examples/*
- examples/session/*
- src/html/page
- src/html/tempo
- src/html/stripe

overrides:
mppx: 'workspace:*'
vite: 'npm:@voidzero-dev/vite-plus-core@~0.1.14'
mppx>vite: 'npm:@voidzero-dev/vite-plus-core@~0.1.14'
vitest: 'npm:@voidzero-dev/vite-plus-test@~0.1.14'
ox: '^0.14.1'
ox: '0.14.1'
viem: '^2.47.5'
tar@<=7.5.10: '7.5.11'
'@modelcontextprotocol/sdk@>=1.10.0 <=1.25.3': '1.26.0'
Expand All @@ -20,6 +23,7 @@ overrides:
'@hono/node-server@<1.19.10': '1.19.10'
elysia@<1.4.26: '1.4.26'
file-type: '21.3.2'
path-to-regexp: '^8.4.0'
flatted@<=3.4.1: '>=3.4.2'
undici@>=7.0.0 <7.24.0: '7.24.0'
socket.io-parser@>=4.0.0 <4.2.6: '>=4.2.6'
Expand Down
2 changes: 2 additions & 0 deletions src/Challenge.test.ts
Original file line number Diff line number Diff line change
Expand Up @@ -269,6 +269,7 @@ describe('fromMethod', () => {
"request": {
"amount": "1000000",
"currency": "0x20c0000000000000000000000000000000000001",
"decimals": 6,
"recipient": "0x742d35Cc6634C0532925a3b844Bc9e7595f8fE00",
},
}
Expand Down Expand Up @@ -300,6 +301,7 @@ describe('fromMethod', () => {
"request": {
"amount": "1000000",
"currency": "0x20c0000000000000000000000000000000000001",
"decimals": 6,
"methodDetails": {
"chainId": 42431,
"feePayer": true,
Expand Down
Loading
Loading