@moneydevkit/nextjs 0.11.0 → 0.12.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +24 -23
- package/package.json +3 -3
package/README.md
CHANGED
|
@@ -236,9 +236,9 @@ export default function SuccessPage() {
|
|
|
236
236
|
}
|
|
237
237
|
```
|
|
238
238
|
|
|
239
|
-
##
|
|
239
|
+
## L402: Pay-per-call API Endpoints
|
|
240
240
|
|
|
241
|
-
Gate any API route behind a Lightning payment using the HTTP 402
|
|
241
|
+
Gate any API route behind a Lightning payment using the [L402 protocol](https://github.com/lightning/blips/pull/26) (HTTP 402). No accounts, no subscriptions — clients pay a Lightning invoice and get immediate access.
|
|
242
242
|
|
|
243
243
|
### How it works
|
|
244
244
|
|
|
@@ -249,25 +249,25 @@ Client Your Server Lightning
|
|
|
249
249
|
│──────────────────────────────► │ │
|
|
250
250
|
│ │ │
|
|
251
251
|
│ 402 Payment Required │ │
|
|
252
|
-
│ { invoice,
|
|
252
|
+
│ { invoice, macaroon, amount } │ │
|
|
253
253
|
│ ◄──────────────────────────── │ │
|
|
254
254
|
│ │ │
|
|
255
255
|
│ pay invoice ──────────────────┼────────────────────────────► │
|
|
256
256
|
│ ◄── preimage ─────────────────┼──────────────────────────────│
|
|
257
257
|
│ │ │
|
|
258
258
|
│ GET /api/premium │ │
|
|
259
|
-
│ Authorization:
|
|
259
|
+
│ Authorization: L402 <macaroon>:<preimage> │
|
|
260
260
|
│──────────────────────────────► │ │
|
|
261
|
-
│ │ verify
|
|
261
|
+
│ │ verify credential + preimage│
|
|
262
262
|
│ 200 OK { data } │ │
|
|
263
263
|
│ ◄──────────────────────────── │ │
|
|
264
264
|
```
|
|
265
265
|
|
|
266
266
|
1. Client requests a protected endpoint without credentials
|
|
267
|
-
2. Server returns **402** with a Lightning invoice and a signed
|
|
267
|
+
2. Server returns **402** with a Lightning invoice and a signed credential
|
|
268
268
|
3. Client pays the invoice and receives a preimage (proof of payment)
|
|
269
|
-
4. Client retries with `Authorization:
|
|
270
|
-
5. Server verifies the
|
|
269
|
+
4. Client retries with `Authorization: L402 <macaroon>:<preimage>`
|
|
270
|
+
5. Server verifies the credential, expiry, and preimage — then forwards to the handler
|
|
271
271
|
|
|
272
272
|
### Setup
|
|
273
273
|
|
|
@@ -324,7 +324,7 @@ export const POST = withPayment(
|
|
|
324
324
|
)
|
|
325
325
|
```
|
|
326
326
|
|
|
327
|
-
The pricing function is evaluated both when creating the invoice and when verifying the
|
|
327
|
+
The pricing function is evaluated both when creating the invoice and when verifying the credential. If the price changes between issuance and verification (e.g., the client replays a cheap credential on an expensive tier), the request is rejected with `amount_mismatch`.
|
|
328
328
|
|
|
329
329
|
### Fiat pricing
|
|
330
330
|
|
|
@@ -337,9 +337,9 @@ export const GET = withPayment(
|
|
|
337
337
|
)
|
|
338
338
|
```
|
|
339
339
|
|
|
340
|
-
###
|
|
340
|
+
### Credential expiry
|
|
341
341
|
|
|
342
|
-
|
|
342
|
+
Credentials (and their invoices) expire after 15 minutes by default. Override with `expirySeconds`:
|
|
343
343
|
|
|
344
344
|
```ts
|
|
345
345
|
export const GET = withPayment(
|
|
@@ -350,7 +350,7 @@ export const GET = withPayment(
|
|
|
350
350
|
|
|
351
351
|
### Client integration
|
|
352
352
|
|
|
353
|
-
Any HTTP client can consume an
|
|
353
|
+
Any HTTP client can consume an L402 endpoint:
|
|
354
354
|
|
|
355
355
|
```bash
|
|
356
356
|
# 1. Request the protected resource
|
|
@@ -358,7 +358,7 @@ curl -s https://example.com/api/premium
|
|
|
358
358
|
|
|
359
359
|
# Response: 402
|
|
360
360
|
# {
|
|
361
|
-
# "
|
|
361
|
+
# "macaroon": "eyJ...",
|
|
362
362
|
# "invoice": "lnbc...",
|
|
363
363
|
# "paymentHash": "abc123...",
|
|
364
364
|
# "amountSats": 100,
|
|
@@ -367,17 +367,17 @@ curl -s https://example.com/api/premium
|
|
|
367
367
|
|
|
368
368
|
# 2. Pay the invoice with any Lightning wallet and get the preimage
|
|
369
369
|
|
|
370
|
-
# 3. Retry with the
|
|
370
|
+
# 3. Retry with the credential and preimage
|
|
371
371
|
curl -s https://example.com/api/premium \
|
|
372
|
-
-H "Authorization:
|
|
372
|
+
-H "Authorization: L402 eyJ...:ff00aa..."
|
|
373
373
|
|
|
374
374
|
# Response: 200 { "content": "Premium data" }
|
|
375
375
|
```
|
|
376
376
|
|
|
377
|
-
The `WWW-Authenticate` header
|
|
377
|
+
The `WWW-Authenticate` header follows the bLIP-26 format:
|
|
378
378
|
|
|
379
379
|
```
|
|
380
|
-
WWW-Authenticate:
|
|
380
|
+
WWW-Authenticate: L402 macaroon="eyJ...", invoice="lnbc..."
|
|
381
381
|
```
|
|
382
382
|
|
|
383
383
|
### Programmatic client (Node.js / agent)
|
|
@@ -388,14 +388,15 @@ async function callPaidEndpoint(url: string, payFn: (invoice: string) => Promise
|
|
|
388
388
|
const challenge = await fetch(url)
|
|
389
389
|
if (challenge.status !== 402) return challenge
|
|
390
390
|
|
|
391
|
-
|
|
391
|
+
// The credential is in the `macaroon` field (L402 naming convention)
|
|
392
|
+
const { macaroon: credential, invoice } = await challenge.json()
|
|
392
393
|
|
|
393
394
|
// Step 2: pay the invoice (returns preimage)
|
|
394
395
|
const preimage = await payFn(invoice)
|
|
395
396
|
|
|
396
|
-
// Step 3: retry with proof of payment
|
|
397
|
+
// Step 3: retry with credential + proof of payment
|
|
397
398
|
return fetch(url, {
|
|
398
|
-
headers: { Authorization: `
|
|
399
|
+
headers: { Authorization: `L402 ${credential}:${preimage}` },
|
|
399
400
|
})
|
|
400
401
|
}
|
|
401
402
|
```
|
|
@@ -405,10 +406,10 @@ async function callPaidEndpoint(url: string, payFn: (invoice: string) => Promise
|
|
|
405
406
|
| Status | Code | Meaning |
|
|
406
407
|
|--------|------|---------|
|
|
407
408
|
| 402 | `payment_required` | No valid credentials — pay the returned invoice |
|
|
408
|
-
| 401 | `
|
|
409
|
+
| 401 | `invalid_credential` | Credential is malformed or has a bad signature |
|
|
409
410
|
| 401 | `invalid_payment_proof` | Preimage does not match the payment hash |
|
|
410
|
-
| 403 | `resource_mismatch` |
|
|
411
|
-
| 403 | `amount_mismatch` |
|
|
411
|
+
| 403 | `resource_mismatch` | Credential was issued for a different endpoint |
|
|
412
|
+
| 403 | `amount_mismatch` | Credential was issued for a different price |
|
|
412
413
|
| 500 | `configuration_error` | `MDK_ACCESS_TOKEN` is not set |
|
|
413
414
|
| 500 | `pricing_error` | Dynamic pricing function threw an error |
|
|
414
415
|
| 502 | `checkout_creation_failed` | Failed to create the checkout or invoice |
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@moneydevkit/nextjs",
|
|
3
|
-
"version": "0.
|
|
3
|
+
"version": "0.12.0",
|
|
4
4
|
"title": "@moneydevkit/nextjs",
|
|
5
5
|
"description": "moneydevkit checkout components for Next.js.",
|
|
6
6
|
"repository": {
|
|
@@ -46,7 +46,7 @@
|
|
|
46
46
|
},
|
|
47
47
|
"dependencies": {
|
|
48
48
|
"@hookform/resolvers": "^5.0.1",
|
|
49
|
-
"@moneydevkit/lightning-js": "0.1.
|
|
49
|
+
"@moneydevkit/lightning-js": "0.1.77",
|
|
50
50
|
"@orpc/client": "1.3.0",
|
|
51
51
|
"@orpc/contract": "1.3.0",
|
|
52
52
|
"@radix-ui/react-collapsible": "^1.1.11",
|
|
@@ -64,7 +64,7 @@
|
|
|
64
64
|
"vaul": "^1.1.2",
|
|
65
65
|
"zod": "^3.25.42",
|
|
66
66
|
"@moneydevkit/api-contract": "0.1.21",
|
|
67
|
-
"@moneydevkit/core": "0.
|
|
67
|
+
"@moneydevkit/core": "0.12.0"
|
|
68
68
|
},
|
|
69
69
|
"devDependencies": {
|
|
70
70
|
"@types/node": "^20.10.5",
|