@seedhape/x402-merchant-sdk 0.1.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 +115 -0
- package/dist/index.d.ts +2 -0
- package/dist/index.d.ts.map +1 -0
- package/dist/index.js +2 -0
- package/dist/index.js.map +1 -0
- package/dist/middleware.d.ts +154 -0
- package/dist/middleware.d.ts.map +1 -0
- package/dist/middleware.js +286 -0
- package/dist/middleware.js.map +1 -0
- package/package.json +16 -0
package/README.md
ADDED
|
@@ -0,0 +1,115 @@
|
|
|
1
|
+
# @seedhape/x402-merchant-sdk
|
|
2
|
+
|
|
3
|
+
Add an x402 payment gate to an existing Express, Hono, or `node:http` service. The SDK returns a standard `402 Payment Required` challenge, verifies the buyer's payment through an x402 facilitator, settles USDC directly to the merchant wallet, and exposes a receipt for your application ledger.
|
|
4
|
+
|
|
5
|
+
## Install
|
|
6
|
+
|
|
7
|
+
```bash
|
|
8
|
+
npm install @seedhape/x402-merchant-sdk
|
|
9
|
+
```
|
|
10
|
+
|
|
11
|
+
## Express
|
|
12
|
+
|
|
13
|
+
```ts
|
|
14
|
+
import express from "express";
|
|
15
|
+
import { BASE_MAINNET, expressPaywall } from "@seedhape/x402-merchant-sdk";
|
|
16
|
+
|
|
17
|
+
const app = express();
|
|
18
|
+
|
|
19
|
+
app.use(expressPaywall({
|
|
20
|
+
...BASE_MAINNET,
|
|
21
|
+
payTo: "0xYourBaseMerchantWallet",
|
|
22
|
+
paymentMethods: ["eip3009", "erc7710"],
|
|
23
|
+
price: ({ path }) => path === "/weather"
|
|
24
|
+
? { amount: 50_000n, ...BASE_MAINNET }
|
|
25
|
+
: null,
|
|
26
|
+
free: ["/health", "/docs/*"],
|
|
27
|
+
facilitator: { url: process.env.FACILITATOR_URL! },
|
|
28
|
+
description: "Current weather data",
|
|
29
|
+
receipts: { record: async (receipt) => db.receipts.insert(receipt) },
|
|
30
|
+
}));
|
|
31
|
+
|
|
32
|
+
app.get("/weather", (req, res) => {
|
|
33
|
+
res.json({ temperature: 24, conditions: "clear", receipt: req.x402Receipt?.id });
|
|
34
|
+
});
|
|
35
|
+
```
|
|
36
|
+
|
|
37
|
+
`price` may be a fixed `Money` object or a resolver based on the request path, method, and query. Return `null` for a free route. USDC amounts are integer base units: `50_000n` is `0.05 USDC`.
|
|
38
|
+
|
|
39
|
+
## Network presets and payment methods
|
|
40
|
+
|
|
41
|
+
Use `BASE_MAINNET` or `BASE_SEPOLIA` to preconfigure the CAIP-2 network, USDC contract, decimals, and default facilitator:
|
|
42
|
+
|
|
43
|
+
```ts
|
|
44
|
+
import { BASE_SEPOLIA, expressPaywall } from "@seedhape/x402-merchant-sdk";
|
|
45
|
+
|
|
46
|
+
app.use(expressPaywall({
|
|
47
|
+
...BASE_SEPOLIA,
|
|
48
|
+
payTo: "0xYourStagingWallet",
|
|
49
|
+
paymentMethods: ["eip3009"],
|
|
50
|
+
price: ({ path }) => path === "/weather"
|
|
51
|
+
? { amount: 10_000n, ...BASE_SEPOLIA }
|
|
52
|
+
: null,
|
|
53
|
+
}));
|
|
54
|
+
```
|
|
55
|
+
|
|
56
|
+
`paymentMethods` is optional and defaults to `['eip3009']` for backward compatibility. Set `['erc7710']` to advertise only delegated payments, or `['eip3009', 'erc7710']` to let the buyer/client choose. Override `facilitator` when using a compatible provider of your choice.
|
|
57
|
+
|
|
58
|
+
## Hono and node:http
|
|
59
|
+
|
|
60
|
+
Use `honoPaywall(config)` with Hono or `nodePaywall(config)` for a raw Node server. All adapters use the same `PaywallConfig` and facilitator contract.
|
|
61
|
+
|
|
62
|
+
## Payment flow
|
|
63
|
+
|
|
64
|
+
1. An unpaid request receives a `402` challenge containing the merchant wallet, USDC asset, Base network, amount, and resource URL.
|
|
65
|
+
2. The buyer creates an x402 payment using EIP-3009 or another supported payment method.
|
|
66
|
+
3. The facilitator verifies and settles the payment.
|
|
67
|
+
4. USDC settles directly to `payTo`; Seedhape never holds merchant funds.
|
|
68
|
+
5. The request continues and `req.x402Receipt` contains the settlement record.
|
|
69
|
+
|
|
70
|
+
The SDK currently emits the exact x402 challenge shape. ERC-7710 selection is handled by a compatible client/facilitator path; the merchant's responsibility is to declare an accurate recipient, asset, network, amount, and resource.
|
|
71
|
+
|
|
72
|
+
## Bazaar discovery
|
|
73
|
+
|
|
74
|
+
Bazaar is an optional discovery layer. Add Bazaar discovery metadata to your x402 route when using an x402 resource server/facilitator that supports the Bazaar extension. Describe the input schema, route, method, and response so agents can find the service without a hardcoded URL. Bazaar does not change settlement or custody.
|
|
75
|
+
|
|
76
|
+
## Sonar discovery
|
|
77
|
+
|
|
78
|
+
[Sonar](https://sonar.seedhape.com/) is Seedhape's service discovery surface for merchants and agents. After deploying your x402 endpoint, list it in Sonar with its public URL, HTTP method, service description, input schema, price, token, network, receiving wallet, and supported payment methods. Sonar helps agents discover and evaluate the service; it does not custody funds or settle payments. The x402 paywall and facilitator still perform verification and settlement.
|
|
79
|
+
|
|
80
|
+
Sonar listing does not replace Bazaar metadata. A merchant can publish Bazaar discovery metadata for the open x402 ecosystem and list the same endpoint in Sonar for Seedhape discovery.
|
|
81
|
+
|
|
82
|
+
## Production checklist
|
|
83
|
+
|
|
84
|
+
- Use a self-custodial merchant receiving address.
|
|
85
|
+
- Use `eip155:8453` and Base USDC in production; use Base Sepolia only for testing.
|
|
86
|
+
- Configure a production facilitator URL and keep it server-side.
|
|
87
|
+
- Keep health, documentation, and discovery metadata routes free.
|
|
88
|
+
- Record the receipt ID, resource, payer, amount, network, and transaction hash.
|
|
89
|
+
- Treat `payTo`, asset, network, and resource as server-controlled values; never accept them from the buyer.
|
|
90
|
+
|
|
91
|
+
## Publishing and full integration guide
|
|
92
|
+
|
|
93
|
+
Authenticate and verify the package:
|
|
94
|
+
|
|
95
|
+
```bash
|
|
96
|
+
npm login
|
|
97
|
+
npm whoami
|
|
98
|
+
npm run typecheck
|
|
99
|
+
npm run build:packages
|
|
100
|
+
npm pack --dry-run --workspace=@seedhape/x402-merchant-sdk
|
|
101
|
+
```
|
|
102
|
+
|
|
103
|
+
Publish the public scoped package:
|
|
104
|
+
|
|
105
|
+
```bash
|
|
106
|
+
npm publish --workspace=@seedhape/x402-merchant-sdk --access public
|
|
107
|
+
```
|
|
108
|
+
|
|
109
|
+
For local tarball testing, versioning, Bazaar metadata, and the complete release checklist, see the repository guide:
|
|
110
|
+
|
|
111
|
+
[`docs/SDK-PUBLISHING-GUIDE.md`](https://github.com/seedhape/seedhape/blob/main/docs/SDK-PUBLISHING-GUIDE.md)
|
|
112
|
+
|
|
113
|
+
## License
|
|
114
|
+
|
|
115
|
+
MIT
|
package/dist/index.d.ts
ADDED
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"AAAA,cAAc,iBAAiB,CAAC"}
|
package/dist/index.js
ADDED
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"index.js","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"AAAA,cAAc,iBAAiB,CAAC"}
|
|
@@ -0,0 +1,154 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Merchant SDK — the paywall.
|
|
3
|
+
*
|
|
4
|
+
* Be clear-eyed about what this part is worth: wrapping an endpoint in a 402 is
|
|
5
|
+
* commoditised. CloudFront does it as a config change, Stripe and Cloudflare
|
|
6
|
+
* both ship it. If all you need is "charge agents per call", use one of those.
|
|
7
|
+
*
|
|
8
|
+
* What this SDK adds is the merchant-side boundary after a payment lands:
|
|
9
|
+
* settlement receipts keyed to your own order IDs and a transport-neutral API
|
|
10
|
+
* for Express, Hono, and node:http services.
|
|
11
|
+
*/
|
|
12
|
+
import type { IncomingMessage, ServerResponse } from "node:http";
|
|
13
|
+
export interface Money {
|
|
14
|
+
/** Base units of the asset. USDC has 6 decimals. */
|
|
15
|
+
amount: bigint;
|
|
16
|
+
asset: string;
|
|
17
|
+
network: string;
|
|
18
|
+
decimals: number;
|
|
19
|
+
}
|
|
20
|
+
export interface PriceResolver {
|
|
21
|
+
(req: {
|
|
22
|
+
path: string;
|
|
23
|
+
method: string;
|
|
24
|
+
query: URLSearchParams;
|
|
25
|
+
}): Money | null;
|
|
26
|
+
}
|
|
27
|
+
export interface Receipt {
|
|
28
|
+
id: string;
|
|
29
|
+
resource: string;
|
|
30
|
+
payer?: string;
|
|
31
|
+
payTo: string;
|
|
32
|
+
amount: bigint;
|
|
33
|
+
asset: string;
|
|
34
|
+
network: string;
|
|
35
|
+
txHash?: string;
|
|
36
|
+
/** INR paise at settlement time. */
|
|
37
|
+
inrPaise?: bigint;
|
|
38
|
+
fxRateScaled?: bigint;
|
|
39
|
+
settledAt: number;
|
|
40
|
+
/** Your own order/customer reference, if the caller supplied one. */
|
|
41
|
+
merchantRef?: string;
|
|
42
|
+
}
|
|
43
|
+
export interface ReceiptSink {
|
|
44
|
+
record(r: Receipt): Promise<void>;
|
|
45
|
+
}
|
|
46
|
+
export interface FacilitatorConfig {
|
|
47
|
+
/** e.g. https://x402.org/facilitator or your own. */
|
|
48
|
+
url: string;
|
|
49
|
+
apiKey?: string;
|
|
50
|
+
}
|
|
51
|
+
export type PaymentMethod = "eip3009" | "erc7710";
|
|
52
|
+
export interface MerchantNetworkConfig {
|
|
53
|
+
network: string;
|
|
54
|
+
asset: string;
|
|
55
|
+
decimals: number;
|
|
56
|
+
facilitator: FacilitatorConfig;
|
|
57
|
+
}
|
|
58
|
+
/** Base mainnet + USDC defaults. Override any field for a custom facilitator. */
|
|
59
|
+
export declare const BASE_MAINNET: MerchantNetworkConfig;
|
|
60
|
+
/** Base Sepolia + USDC defaults for development and staging. */
|
|
61
|
+
export declare const BASE_SEPOLIA: MerchantNetworkConfig;
|
|
62
|
+
export interface PaywallConfig {
|
|
63
|
+
payTo: string;
|
|
64
|
+
network: string;
|
|
65
|
+
asset: string;
|
|
66
|
+
decimals?: number;
|
|
67
|
+
/** Payment authorization methods advertised in the 402 response. */
|
|
68
|
+
paymentMethods?: PaymentMethod[];
|
|
69
|
+
/** Fixed price, or a function of the request. Return null to leave a route free. */
|
|
70
|
+
price: Money | PriceResolver;
|
|
71
|
+
facilitator: FacilitatorConfig;
|
|
72
|
+
receipts?: ReceiptSink;
|
|
73
|
+
/** INR per USDC scaled 1e8, for receipt valuation. */
|
|
74
|
+
fxRateScaled?: () => Promise<bigint>;
|
|
75
|
+
description?: string;
|
|
76
|
+
maxTimeoutSeconds?: number;
|
|
77
|
+
/** Routes that never require payment, e.g. ["/health", "/.well-known/*"]. */
|
|
78
|
+
free?: string[];
|
|
79
|
+
/**
|
|
80
|
+
* Settle before serving (safer, slower) or after (faster, risks serving an
|
|
81
|
+
* unsettled request). Default "before". Only choose "after" for idempotent
|
|
82
|
+
* reads where a rare free response is cheaper than the added latency.
|
|
83
|
+
*/
|
|
84
|
+
settlement?: "before" | "after";
|
|
85
|
+
}
|
|
86
|
+
export interface VerifyResult {
|
|
87
|
+
isValid: boolean;
|
|
88
|
+
invalidReason?: string;
|
|
89
|
+
payer?: string;
|
|
90
|
+
}
|
|
91
|
+
export interface SettleResult {
|
|
92
|
+
success: boolean;
|
|
93
|
+
transaction?: string;
|
|
94
|
+
network?: string;
|
|
95
|
+
payer?: string;
|
|
96
|
+
errorReason?: string;
|
|
97
|
+
}
|
|
98
|
+
export declare class Facilitator {
|
|
99
|
+
private readonly cfg;
|
|
100
|
+
private readonly fetchImpl;
|
|
101
|
+
constructor(cfg: FacilitatorConfig, fetchImpl?: typeof fetch);
|
|
102
|
+
verify(payload: unknown, requirements: unknown): Promise<VerifyResult>;
|
|
103
|
+
settle(payload: unknown, requirements: unknown): Promise<SettleResult>;
|
|
104
|
+
private call;
|
|
105
|
+
}
|
|
106
|
+
export interface PaywallOutcome {
|
|
107
|
+
/** "free" | "challenge" | "paid" | "rejected" */
|
|
108
|
+
kind: "free" | "challenge" | "paid" | "rejected";
|
|
109
|
+
status?: number;
|
|
110
|
+
challenge?: unknown;
|
|
111
|
+
settlementHeader?: string;
|
|
112
|
+
receipt?: Receipt;
|
|
113
|
+
reason?: string;
|
|
114
|
+
}
|
|
115
|
+
export declare class Paywall {
|
|
116
|
+
private readonly cfg;
|
|
117
|
+
private readonly facilitator;
|
|
118
|
+
private readonly decimals;
|
|
119
|
+
constructor(cfg: PaywallConfig);
|
|
120
|
+
priceFor(path: string, method: string, query: URLSearchParams): Money | null;
|
|
121
|
+
buildChallenge(price: Money, resource: string): {
|
|
122
|
+
x402Version: number;
|
|
123
|
+
accepts: {
|
|
124
|
+
scheme: string;
|
|
125
|
+
network: string;
|
|
126
|
+
maxAmountRequired: string;
|
|
127
|
+
resource: string;
|
|
128
|
+
description: string;
|
|
129
|
+
mimeType: string;
|
|
130
|
+
payTo: string;
|
|
131
|
+
maxTimeoutSeconds: number;
|
|
132
|
+
asset: string;
|
|
133
|
+
extra: {
|
|
134
|
+
name: string;
|
|
135
|
+
version: string;
|
|
136
|
+
decimals: number;
|
|
137
|
+
assetTransferMethod: PaymentMethod;
|
|
138
|
+
};
|
|
139
|
+
}[];
|
|
140
|
+
};
|
|
141
|
+
handle(args: {
|
|
142
|
+
path: string;
|
|
143
|
+
method: string;
|
|
144
|
+
query: URLSearchParams;
|
|
145
|
+
resource: string;
|
|
146
|
+
paymentHeader: string | null;
|
|
147
|
+
merchantRef?: string;
|
|
148
|
+
}): Promise<PaywallOutcome>;
|
|
149
|
+
private writeReceipt;
|
|
150
|
+
}
|
|
151
|
+
export declare function expressPaywall(cfg: PaywallConfig): (req: any, res: any, next: any) => Promise<any>;
|
|
152
|
+
export declare function honoPaywall(cfg: PaywallConfig): (c: any, next: any) => Promise<any>;
|
|
153
|
+
export declare function nodePaywall(cfg: PaywallConfig): (req: IncomingMessage, res: ServerResponse) => Promise<Receipt | "free" | null>;
|
|
154
|
+
//# sourceMappingURL=middleware.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"middleware.d.ts","sourceRoot":"","sources":["../src/middleware.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1,286 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Merchant SDK — the paywall.
|
|
3
|
+
*
|
|
4
|
+
* Be clear-eyed about what this part is worth: wrapping an endpoint in a 402 is
|
|
5
|
+
* commoditised. CloudFront does it as a config change, Stripe and Cloudflare
|
|
6
|
+
* both ship it. If all you need is "charge agents per call", use one of those.
|
|
7
|
+
*
|
|
8
|
+
* What this SDK adds is the merchant-side boundary after a payment lands:
|
|
9
|
+
* settlement receipts keyed to your own order IDs and a transport-neutral API
|
|
10
|
+
* for Express, Hono, and node:http services.
|
|
11
|
+
*/
|
|
12
|
+
import { randomUUID } from "node:crypto";
|
|
13
|
+
/** Base mainnet + USDC defaults. Override any field for a custom facilitator. */
|
|
14
|
+
export const BASE_MAINNET = {
|
|
15
|
+
network: "eip155:8453",
|
|
16
|
+
asset: "0x833589fCD6eDb6E08f4c7C32D4f71b54bdA02913",
|
|
17
|
+
decimals: 6,
|
|
18
|
+
facilitator: { url: "https://api.cdp.coinbase.com/platform/v2/x402" },
|
|
19
|
+
};
|
|
20
|
+
/** Base Sepolia + USDC defaults for development and staging. */
|
|
21
|
+
export const BASE_SEPOLIA = {
|
|
22
|
+
network: "eip155:84532",
|
|
23
|
+
asset: "0x036CbD53842c5426634e7929541eC2318f3dCF7e",
|
|
24
|
+
decimals: 6,
|
|
25
|
+
facilitator: { url: "https://api.cdp.coinbase.com/platform/v2/x402" },
|
|
26
|
+
};
|
|
27
|
+
// ---------------------------------------------------------------------------
|
|
28
|
+
// Facilitator
|
|
29
|
+
// ---------------------------------------------------------------------------
|
|
30
|
+
export class Facilitator {
|
|
31
|
+
cfg;
|
|
32
|
+
fetchImpl;
|
|
33
|
+
constructor(cfg, fetchImpl = fetch) {
|
|
34
|
+
this.cfg = cfg;
|
|
35
|
+
this.fetchImpl = fetchImpl;
|
|
36
|
+
}
|
|
37
|
+
async verify(payload, requirements) {
|
|
38
|
+
return this.call("/verify", { paymentPayload: payload, paymentRequirements: requirements });
|
|
39
|
+
}
|
|
40
|
+
async settle(payload, requirements) {
|
|
41
|
+
return this.call("/settle", { paymentPayload: payload, paymentRequirements: requirements });
|
|
42
|
+
}
|
|
43
|
+
async call(path, body) {
|
|
44
|
+
const res = await this.fetchImpl(`${this.cfg.url}${path}`, {
|
|
45
|
+
method: "POST",
|
|
46
|
+
headers: {
|
|
47
|
+
"content-type": "application/json",
|
|
48
|
+
...(this.cfg.apiKey ? { authorization: `Bearer ${this.cfg.apiKey}` } : {}),
|
|
49
|
+
},
|
|
50
|
+
body: JSON.stringify(body),
|
|
51
|
+
});
|
|
52
|
+
if (!res.ok) {
|
|
53
|
+
const t = await res.text();
|
|
54
|
+
throw new Error(`Facilitator ${path} returned ${res.status}: ${t}`);
|
|
55
|
+
}
|
|
56
|
+
return (await res.json());
|
|
57
|
+
}
|
|
58
|
+
}
|
|
59
|
+
export class Paywall {
|
|
60
|
+
cfg;
|
|
61
|
+
facilitator;
|
|
62
|
+
decimals;
|
|
63
|
+
constructor(cfg) {
|
|
64
|
+
this.cfg = cfg;
|
|
65
|
+
this.facilitator = new Facilitator(cfg.facilitator);
|
|
66
|
+
this.decimals = cfg.decimals ?? 6;
|
|
67
|
+
}
|
|
68
|
+
priceFor(path, method, query) {
|
|
69
|
+
if (this.cfg.free?.some((p) => matchRoute(path, p)))
|
|
70
|
+
return null;
|
|
71
|
+
const p = this.cfg.price;
|
|
72
|
+
return typeof p === "function" ? p({ path, method, query }) : p;
|
|
73
|
+
}
|
|
74
|
+
buildChallenge(price, resource) {
|
|
75
|
+
const paymentMethods = this.cfg.paymentMethods?.length
|
|
76
|
+
? this.cfg.paymentMethods
|
|
77
|
+
: ["eip3009"];
|
|
78
|
+
return {
|
|
79
|
+
x402Version: 1,
|
|
80
|
+
accepts: paymentMethods.map((paymentMethod) => ({
|
|
81
|
+
scheme: "exact",
|
|
82
|
+
network: this.cfg.network,
|
|
83
|
+
maxAmountRequired: price.amount.toString(),
|
|
84
|
+
resource,
|
|
85
|
+
description: this.cfg.description ?? "",
|
|
86
|
+
mimeType: "application/json",
|
|
87
|
+
payTo: this.cfg.payTo,
|
|
88
|
+
maxTimeoutSeconds: this.cfg.maxTimeoutSeconds ?? 300,
|
|
89
|
+
asset: this.cfg.asset,
|
|
90
|
+
extra: { name: "USDC", version: "2", decimals: this.decimals, assetTransferMethod: paymentMethod },
|
|
91
|
+
})),
|
|
92
|
+
};
|
|
93
|
+
}
|
|
94
|
+
async handle(args) {
|
|
95
|
+
const price = this.priceFor(args.path, args.method, args.query);
|
|
96
|
+
if (!price || price.amount === 0n)
|
|
97
|
+
return { kind: "free" };
|
|
98
|
+
if (!args.paymentHeader) {
|
|
99
|
+
return {
|
|
100
|
+
kind: "challenge",
|
|
101
|
+
status: 402,
|
|
102
|
+
challenge: this.buildChallenge(price, args.resource),
|
|
103
|
+
};
|
|
104
|
+
}
|
|
105
|
+
let payload;
|
|
106
|
+
try {
|
|
107
|
+
payload = JSON.parse(Buffer.from(args.paymentHeader, "base64").toString("utf8"));
|
|
108
|
+
}
|
|
109
|
+
catch {
|
|
110
|
+
return { kind: "rejected", status: 400, reason: "X-PAYMENT header is not valid base64 JSON." };
|
|
111
|
+
}
|
|
112
|
+
const requirements = this.buildChallenge(price, args.resource).accepts[0];
|
|
113
|
+
const verified = await this.facilitator.verify(payload, requirements);
|
|
114
|
+
if (!verified.isValid) {
|
|
115
|
+
return {
|
|
116
|
+
kind: "rejected",
|
|
117
|
+
status: 402,
|
|
118
|
+
reason: verified.invalidReason ?? "Payment verification failed.",
|
|
119
|
+
challenge: this.buildChallenge(price, args.resource),
|
|
120
|
+
};
|
|
121
|
+
}
|
|
122
|
+
if (this.cfg.settlement === "after") {
|
|
123
|
+
// Caller serves first, then invokes settleLater(). Kept explicit rather
|
|
124
|
+
// than fire-and-forget so a failed settlement is not silently swallowed.
|
|
125
|
+
return { kind: "paid", receipt: undefined };
|
|
126
|
+
}
|
|
127
|
+
const settled = await this.facilitator.settle(payload, requirements);
|
|
128
|
+
if (!settled.success) {
|
|
129
|
+
return {
|
|
130
|
+
kind: "rejected",
|
|
131
|
+
status: 402,
|
|
132
|
+
reason: settled.errorReason ?? "Settlement failed.",
|
|
133
|
+
};
|
|
134
|
+
}
|
|
135
|
+
const receipt = await this.writeReceipt({
|
|
136
|
+
resource: args.resource,
|
|
137
|
+
price,
|
|
138
|
+
settled,
|
|
139
|
+
payer: verified.payer ?? settled.payer,
|
|
140
|
+
merchantRef: args.merchantRef,
|
|
141
|
+
});
|
|
142
|
+
return {
|
|
143
|
+
kind: "paid",
|
|
144
|
+
receipt,
|
|
145
|
+
settlementHeader: Buffer.from(JSON.stringify(settled), "utf8").toString("base64"),
|
|
146
|
+
};
|
|
147
|
+
}
|
|
148
|
+
async writeReceipt(args) {
|
|
149
|
+
let inrPaise;
|
|
150
|
+
let fxRateScaled;
|
|
151
|
+
if (this.cfg.fxRateScaled) {
|
|
152
|
+
try {
|
|
153
|
+
fxRateScaled = await this.cfg.fxRateScaled();
|
|
154
|
+
inrPaise =
|
|
155
|
+
(args.price.amount * fxRateScaled * 100n) /
|
|
156
|
+
(10n ** BigInt(this.decimals) * 100000000n);
|
|
157
|
+
}
|
|
158
|
+
catch {
|
|
159
|
+
// A missing FX rate must not fail a settled payment. Backfill later.
|
|
160
|
+
}
|
|
161
|
+
}
|
|
162
|
+
const receipt = {
|
|
163
|
+
id: randomUUID(),
|
|
164
|
+
resource: args.resource,
|
|
165
|
+
payer: args.payer,
|
|
166
|
+
payTo: this.cfg.payTo,
|
|
167
|
+
amount: args.price.amount,
|
|
168
|
+
asset: this.cfg.asset,
|
|
169
|
+
network: this.cfg.network,
|
|
170
|
+
txHash: args.settled.transaction,
|
|
171
|
+
inrPaise,
|
|
172
|
+
fxRateScaled,
|
|
173
|
+
settledAt: Math.floor(Date.now() / 1000),
|
|
174
|
+
merchantRef: args.merchantRef,
|
|
175
|
+
};
|
|
176
|
+
await this.cfg.receipts?.record(receipt);
|
|
177
|
+
return receipt;
|
|
178
|
+
}
|
|
179
|
+
}
|
|
180
|
+
// ---------------------------------------------------------------------------
|
|
181
|
+
// Express adapter
|
|
182
|
+
// ---------------------------------------------------------------------------
|
|
183
|
+
/* eslint-disable @typescript-eslint/no-explicit-any */
|
|
184
|
+
export function expressPaywall(cfg) {
|
|
185
|
+
const paywall = new Paywall(cfg);
|
|
186
|
+
return async function middleware(req, res, next) {
|
|
187
|
+
try {
|
|
188
|
+
const url = new URL(req.originalUrl ?? req.url, `http://${req.headers.host ?? "localhost"}`);
|
|
189
|
+
const outcome = await paywall.handle({
|
|
190
|
+
path: url.pathname,
|
|
191
|
+
method: req.method,
|
|
192
|
+
query: url.searchParams,
|
|
193
|
+
resource: url.toString(),
|
|
194
|
+
paymentHeader: req.headers["x-payment"] ?? null,
|
|
195
|
+
merchantRef: req.headers["x-merchant-ref"],
|
|
196
|
+
});
|
|
197
|
+
switch (outcome.kind) {
|
|
198
|
+
case "free":
|
|
199
|
+
return next();
|
|
200
|
+
case "challenge":
|
|
201
|
+
res.status(402).json(outcome.challenge);
|
|
202
|
+
return;
|
|
203
|
+
case "rejected":
|
|
204
|
+
res.status(outcome.status ?? 402).json({
|
|
205
|
+
error: outcome.reason,
|
|
206
|
+
...(outcome.challenge ?? {}),
|
|
207
|
+
});
|
|
208
|
+
return;
|
|
209
|
+
case "paid":
|
|
210
|
+
if (outcome.settlementHeader) {
|
|
211
|
+
res.setHeader("X-PAYMENT-RESPONSE", outcome.settlementHeader);
|
|
212
|
+
res.setHeader("Access-Control-Expose-Headers", "X-PAYMENT-RESPONSE");
|
|
213
|
+
}
|
|
214
|
+
req.x402Receipt = outcome.receipt;
|
|
215
|
+
return next();
|
|
216
|
+
}
|
|
217
|
+
}
|
|
218
|
+
catch (e) {
|
|
219
|
+
next(e);
|
|
220
|
+
}
|
|
221
|
+
};
|
|
222
|
+
}
|
|
223
|
+
// ---------------------------------------------------------------------------
|
|
224
|
+
// Hono / Fetch-API adapter
|
|
225
|
+
// ---------------------------------------------------------------------------
|
|
226
|
+
export function honoPaywall(cfg) {
|
|
227
|
+
const paywall = new Paywall(cfg);
|
|
228
|
+
return async function middleware(c, next) {
|
|
229
|
+
const url = new URL(c.req.url);
|
|
230
|
+
const outcome = await paywall.handle({
|
|
231
|
+
path: url.pathname,
|
|
232
|
+
method: c.req.method,
|
|
233
|
+
query: url.searchParams,
|
|
234
|
+
resource: url.toString(),
|
|
235
|
+
paymentHeader: c.req.header("x-payment") ?? null,
|
|
236
|
+
merchantRef: c.req.header("x-merchant-ref"),
|
|
237
|
+
});
|
|
238
|
+
if (outcome.kind === "free")
|
|
239
|
+
return next();
|
|
240
|
+
if (outcome.kind === "challenge")
|
|
241
|
+
return c.json(outcome.challenge, 402);
|
|
242
|
+
if (outcome.kind === "rejected") {
|
|
243
|
+
return c.json({ error: outcome.reason, ...(outcome.challenge ?? {}) }, (outcome.status ?? 402));
|
|
244
|
+
}
|
|
245
|
+
c.set("x402Receipt", outcome.receipt);
|
|
246
|
+
await next();
|
|
247
|
+
if (outcome.settlementHeader) {
|
|
248
|
+
c.res.headers.set("X-PAYMENT-RESPONSE", outcome.settlementHeader);
|
|
249
|
+
c.res.headers.set("Access-Control-Expose-Headers", "X-PAYMENT-RESPONSE");
|
|
250
|
+
}
|
|
251
|
+
};
|
|
252
|
+
}
|
|
253
|
+
// ---------------------------------------------------------------------------
|
|
254
|
+
// Raw node:http adapter, for anything else
|
|
255
|
+
// ---------------------------------------------------------------------------
|
|
256
|
+
export function nodePaywall(cfg) {
|
|
257
|
+
const paywall = new Paywall(cfg);
|
|
258
|
+
return async function guard(req, res) {
|
|
259
|
+
const url = new URL(req.url ?? "/", `http://${req.headers.host ?? "localhost"}`);
|
|
260
|
+
const outcome = await paywall.handle({
|
|
261
|
+
path: url.pathname,
|
|
262
|
+
method: req.method ?? "GET",
|
|
263
|
+
query: url.searchParams,
|
|
264
|
+
resource: url.toString(),
|
|
265
|
+
paymentHeader: req.headers["x-payment"] ?? null,
|
|
266
|
+
});
|
|
267
|
+
if (outcome.kind === "free")
|
|
268
|
+
return "free";
|
|
269
|
+
if (outcome.kind === "paid") {
|
|
270
|
+
if (outcome.settlementHeader) {
|
|
271
|
+
res.setHeader("X-PAYMENT-RESPONSE", outcome.settlementHeader);
|
|
272
|
+
}
|
|
273
|
+
return outcome.receipt ?? null;
|
|
274
|
+
}
|
|
275
|
+
res.statusCode = outcome.status ?? 402;
|
|
276
|
+
res.setHeader("content-type", "application/json");
|
|
277
|
+
res.end(JSON.stringify(outcome.challenge ?? { error: outcome.reason }));
|
|
278
|
+
return null;
|
|
279
|
+
};
|
|
280
|
+
}
|
|
281
|
+
function matchRoute(path, pattern) {
|
|
282
|
+
if (pattern.endsWith("/*"))
|
|
283
|
+
return path.startsWith(pattern.slice(0, -1));
|
|
284
|
+
return path === pattern;
|
|
285
|
+
}
|
|
286
|
+
//# sourceMappingURL=middleware.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"middleware.js","sourceRoot":"","sources":["../src/middleware.ts"],"names":[],"mappings":"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"}
|
package/package.json
ADDED
|
@@ -0,0 +1,16 @@
|
|
|
1
|
+
{
|
|
2
|
+
"name": "@seedhape/x402-merchant-sdk",
|
|
3
|
+
"version": "0.1.0",
|
|
4
|
+
"description": "Add x402 payment-gated routes, settlement receipts, and merchant accounting to Node.js services.",
|
|
5
|
+
"type": "module",
|
|
6
|
+
"main": "./dist/index.js",
|
|
7
|
+
"types": "./dist/index.d.ts",
|
|
8
|
+
"exports": { ".": { "types": "./dist/index.d.ts", "import": "./dist/index.js" } },
|
|
9
|
+
"files": ["dist", "README.md"],
|
|
10
|
+
"keywords": ["x402", "payments", "usdc", "base", "merchant", "paywall", "api", "agents"],
|
|
11
|
+
"license": "MIT",
|
|
12
|
+
"repository": { "type": "git", "url": "https://github.com/seedhape/seedhape.git", "directory": "packages/merchant-sdk" },
|
|
13
|
+
"bugs": { "url": "https://github.com/seedhape/seedhape/issues" },
|
|
14
|
+
"publishConfig": { "access": "public" },
|
|
15
|
+
"dependencies": {}
|
|
16
|
+
}
|