@puga-labs/x402-mantle-sdk 0.2.0 → 0.3.1
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/dist/chunk-CTI5CRDY.js +274 -0
- package/dist/chunk-DA6ZBXNO.js +275 -0
- package/dist/chunk-FD4HG7KR.js +135 -0
- package/dist/chunk-GWVWPS3R.js +277 -0
- package/dist/chunk-HTZ3QFY4.js +135 -0
- package/dist/chunk-MQALBRGV.js +135 -0
- package/dist/chunk-PYIYE3HI.js +135 -0
- package/dist/chunk-Q6SPMEIW.js +235 -0
- package/dist/chunk-RNKXSBT7.js +135 -0
- package/dist/chunk-SPCXFN7C.js +284 -0
- package/dist/chunk-T5DRYLNB.js +135 -0
- package/dist/chunk-TSEE5NSJ.js +297 -0
- package/dist/chunk-WELDWRDX.js +307 -0
- package/dist/chunk-XAQGMFSR.js +56 -0
- package/dist/client.cjs +328 -0
- package/dist/client.d.cts +17 -0
- package/dist/client.d.ts +17 -0
- package/dist/client.js +12 -0
- package/dist/constants-C7aY8u5b.d.cts +77 -0
- package/dist/constants-C7aY8u5b.d.ts +77 -0
- package/dist/constants-CVFF0ray.d.ts +17 -0
- package/dist/constants-DzCGK0Q3.d.cts +17 -0
- package/dist/createMantleClient-DS1Ghqrz.d.cts +51 -0
- package/dist/createMantleClient-DS1Ghqrz.d.ts +51 -0
- package/dist/createMantleClient-DVFkbBfS.d.ts +87 -0
- package/dist/createMantleClient-NN0Nitp9.d.cts +87 -0
- package/dist/index.cjs +244 -43
- package/dist/index.d.cts +8 -164
- package/dist/index.d.ts +8 -164
- package/dist/index.js +21 -485
- package/dist/react.cjs +453 -0
- package/dist/react.d.cts +90 -0
- package/dist/react.d.ts +90 -0
- package/dist/react.js +10 -0
- package/dist/server.cjs +292 -0
- package/dist/server.d.cts +116 -0
- package/dist/server.d.ts +116 -0
- package/dist/server.js +12 -0
- package/dist/types-2zqbJvcz.d.cts +63 -0
- package/dist/types-2zqbJvcz.d.ts +63 -0
- package/package.json +37 -3
package/dist/server.cjs
ADDED
|
@@ -0,0 +1,292 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
var __defProp = Object.defineProperty;
|
|
3
|
+
var __getOwnPropDesc = Object.getOwnPropertyDescriptor;
|
|
4
|
+
var __getOwnPropNames = Object.getOwnPropertyNames;
|
|
5
|
+
var __hasOwnProp = Object.prototype.hasOwnProperty;
|
|
6
|
+
var __export = (target, all) => {
|
|
7
|
+
for (var name in all)
|
|
8
|
+
__defProp(target, name, { get: all[name], enumerable: true });
|
|
9
|
+
};
|
|
10
|
+
var __copyProps = (to, from, except, desc) => {
|
|
11
|
+
if (from && typeof from === "object" || typeof from === "function") {
|
|
12
|
+
for (let key of __getOwnPropNames(from))
|
|
13
|
+
if (!__hasOwnProp.call(to, key) && key !== except)
|
|
14
|
+
__defProp(to, key, { get: () => from[key], enumerable: !(desc = __getOwnPropDesc(from, key)) || desc.enumerable });
|
|
15
|
+
}
|
|
16
|
+
return to;
|
|
17
|
+
};
|
|
18
|
+
var __toCommonJS = (mod) => __copyProps(__defProp({}, "__esModule", { value: true }), mod);
|
|
19
|
+
|
|
20
|
+
// src/server.ts
|
|
21
|
+
var server_exports = {};
|
|
22
|
+
__export(server_exports, {
|
|
23
|
+
MANTLE_DEFAULTS: () => MANTLE_DEFAULTS,
|
|
24
|
+
createPaymentMiddleware: () => createPaymentMiddleware,
|
|
25
|
+
mantlePaywall: () => mantlePaywall
|
|
26
|
+
});
|
|
27
|
+
module.exports = __toCommonJS(server_exports);
|
|
28
|
+
|
|
29
|
+
// src/shared/constants.ts
|
|
30
|
+
var MANTLE_MAINNET_NETWORK_ID = "mantle-mainnet";
|
|
31
|
+
var MANTLE_MAINNET_USDC = {
|
|
32
|
+
symbol: "USDC",
|
|
33
|
+
address: "0x09Bc4E0D864854c6aFB6eB9A9cdF58aC190D0dF9",
|
|
34
|
+
decimals: 6
|
|
35
|
+
};
|
|
36
|
+
var MANTLE_DEFAULTS = {
|
|
37
|
+
NETWORK: "mantle-mainnet",
|
|
38
|
+
CHAIN_ID: 5e3,
|
|
39
|
+
USDC_ADDRESS: "0x09Bc4E0D864854c6aFB6eB9A9cdF58aC190D0dF9",
|
|
40
|
+
USDC_DECIMALS: 6,
|
|
41
|
+
CURRENCY: "USD",
|
|
42
|
+
SCHEME: "exact",
|
|
43
|
+
FACILITATOR_URL: (typeof process !== "undefined" ? process.env?.NEXT_PUBLIC_FACILITATOR_URL : void 0) || "http://localhost:8080"
|
|
44
|
+
};
|
|
45
|
+
function getDefaultAssetForNetwork(network) {
|
|
46
|
+
switch (network) {
|
|
47
|
+
case MANTLE_MAINNET_NETWORK_ID:
|
|
48
|
+
default:
|
|
49
|
+
return MANTLE_MAINNET_USDC;
|
|
50
|
+
}
|
|
51
|
+
}
|
|
52
|
+
function usdCentsToAtomic(cents, decimals) {
|
|
53
|
+
if (cents < 0) {
|
|
54
|
+
throw new Error("priceUsdCents must be non-negative");
|
|
55
|
+
}
|
|
56
|
+
if (decimals < 2) {
|
|
57
|
+
throw new Error("token decimals must be >= 2 for USD cent conversion");
|
|
58
|
+
}
|
|
59
|
+
const base = BigInt(10) ** BigInt(decimals - 2);
|
|
60
|
+
return BigInt(cents) * base;
|
|
61
|
+
}
|
|
62
|
+
|
|
63
|
+
// src/server/constants.ts
|
|
64
|
+
var DEFAULT_TELEMETRY_ENDPOINT = void 0;
|
|
65
|
+
|
|
66
|
+
// src/server/telemetry.ts
|
|
67
|
+
function createTelemetryEvent(entry, config) {
|
|
68
|
+
const assetConfig = getDefaultAssetForNetwork(entry.network);
|
|
69
|
+
return {
|
|
70
|
+
event: "payment_verified",
|
|
71
|
+
ts: entry.timestamp,
|
|
72
|
+
projectKey: config.projectKey,
|
|
73
|
+
network: entry.network,
|
|
74
|
+
buyer: entry.from,
|
|
75
|
+
payTo: entry.to,
|
|
76
|
+
amountAtomic: entry.valueAtomic,
|
|
77
|
+
asset: entry.asset,
|
|
78
|
+
decimals: assetConfig.decimals,
|
|
79
|
+
nonce: entry.id,
|
|
80
|
+
route: entry.route ?? "unknown",
|
|
81
|
+
// Facilitator metadata
|
|
82
|
+
facilitatorType: "hosted",
|
|
83
|
+
// SDK always uses hosted mode
|
|
84
|
+
facilitatorUrl: entry.facilitatorUrl,
|
|
85
|
+
// From PaymentLogEntry
|
|
86
|
+
// facilitatorAddress is undefined for SDK (not available)
|
|
87
|
+
// Optional metadata
|
|
88
|
+
txHash: entry.txHash,
|
|
89
|
+
priceUsd: entry.paymentRequirements?.price
|
|
90
|
+
};
|
|
91
|
+
}
|
|
92
|
+
async function sendTelemetry(event, endpoint) {
|
|
93
|
+
const targetEndpoint = endpoint ?? DEFAULT_TELEMETRY_ENDPOINT;
|
|
94
|
+
if (!targetEndpoint) {
|
|
95
|
+
return;
|
|
96
|
+
}
|
|
97
|
+
try {
|
|
98
|
+
const response = await fetch(targetEndpoint, {
|
|
99
|
+
method: "POST",
|
|
100
|
+
headers: {
|
|
101
|
+
"Content-Type": "application/json",
|
|
102
|
+
"Authorization": `Bearer ${event.projectKey}`
|
|
103
|
+
},
|
|
104
|
+
body: JSON.stringify(event)
|
|
105
|
+
});
|
|
106
|
+
if (!response.ok) {
|
|
107
|
+
console.warn(
|
|
108
|
+
`[x402-telemetry] Failed to send event: HTTP ${response.status}`
|
|
109
|
+
);
|
|
110
|
+
}
|
|
111
|
+
} catch (err) {
|
|
112
|
+
console.error("[x402-telemetry] Error sending telemetry:", err);
|
|
113
|
+
}
|
|
114
|
+
}
|
|
115
|
+
|
|
116
|
+
// src/server/paymentMiddleware.ts
|
|
117
|
+
function getRouteKey(req) {
|
|
118
|
+
const method = (req.method || "GET").toUpperCase();
|
|
119
|
+
const path = req.path || "/";
|
|
120
|
+
return `${method} ${path}`;
|
|
121
|
+
}
|
|
122
|
+
function decodePaymentHeader(paymentHeaderBase64) {
|
|
123
|
+
try {
|
|
124
|
+
if (typeof Buffer !== "undefined") {
|
|
125
|
+
const json = Buffer.from(paymentHeaderBase64, "base64").toString("utf8");
|
|
126
|
+
return JSON.parse(json);
|
|
127
|
+
}
|
|
128
|
+
if (typeof atob === "function") {
|
|
129
|
+
const json = atob(paymentHeaderBase64);
|
|
130
|
+
return JSON.parse(json);
|
|
131
|
+
}
|
|
132
|
+
throw new Error("No base64 decoding available in this environment");
|
|
133
|
+
} catch (err) {
|
|
134
|
+
const msg = err instanceof Error ? err.message : "Unknown error";
|
|
135
|
+
throw new Error(`Failed to decode paymentHeader: ${msg}`);
|
|
136
|
+
}
|
|
137
|
+
}
|
|
138
|
+
function createPaymentMiddleware(config) {
|
|
139
|
+
const { facilitatorUrl, receiverAddress, routes, onPaymentSettled, telemetry } = config;
|
|
140
|
+
if (!facilitatorUrl) {
|
|
141
|
+
throw new Error("facilitatorUrl is required");
|
|
142
|
+
}
|
|
143
|
+
if (!receiverAddress) {
|
|
144
|
+
throw new Error("receiverAddress is required");
|
|
145
|
+
}
|
|
146
|
+
if (!routes || Object.keys(routes).length === 0) {
|
|
147
|
+
throw new Error("routes config must not be empty");
|
|
148
|
+
}
|
|
149
|
+
return async function paymentMiddleware(req, res, next) {
|
|
150
|
+
const routeKey = getRouteKey(req);
|
|
151
|
+
const routeConfig = routes[routeKey];
|
|
152
|
+
if (!routeConfig) {
|
|
153
|
+
next();
|
|
154
|
+
return;
|
|
155
|
+
}
|
|
156
|
+
const { priceUsdCents, network } = routeConfig;
|
|
157
|
+
const assetConfig = getDefaultAssetForNetwork(network);
|
|
158
|
+
const maxAmountRequiredBigInt = usdCentsToAtomic(
|
|
159
|
+
priceUsdCents,
|
|
160
|
+
assetConfig.decimals
|
|
161
|
+
);
|
|
162
|
+
const paymentRequirements = {
|
|
163
|
+
scheme: "exact",
|
|
164
|
+
network,
|
|
165
|
+
asset: assetConfig.address,
|
|
166
|
+
maxAmountRequired: maxAmountRequiredBigInt.toString(),
|
|
167
|
+
payTo: receiverAddress,
|
|
168
|
+
price: `$${(priceUsdCents / 100).toFixed(2)}`,
|
|
169
|
+
currency: "USD"
|
|
170
|
+
};
|
|
171
|
+
const paymentHeader = req.header("X-PAYMENT") ?? req.header("x-payment");
|
|
172
|
+
if (!paymentHeader) {
|
|
173
|
+
res.status(402).json({
|
|
174
|
+
error: "Payment Required",
|
|
175
|
+
paymentRequirements,
|
|
176
|
+
paymentHeader: null
|
|
177
|
+
});
|
|
178
|
+
return;
|
|
179
|
+
}
|
|
180
|
+
try {
|
|
181
|
+
const verifyUrl = `${facilitatorUrl.replace(/\/+$/, "")}/verify`;
|
|
182
|
+
const verifyRes = await fetch(verifyUrl, {
|
|
183
|
+
method: "POST",
|
|
184
|
+
headers: {
|
|
185
|
+
"Content-Type": "application/json"
|
|
186
|
+
},
|
|
187
|
+
body: JSON.stringify({
|
|
188
|
+
x402Version: 1,
|
|
189
|
+
paymentHeader,
|
|
190
|
+
paymentRequirements
|
|
191
|
+
})
|
|
192
|
+
});
|
|
193
|
+
if (!verifyRes.ok) {
|
|
194
|
+
const text = await verifyRes.text().catch(() => "");
|
|
195
|
+
console.error(
|
|
196
|
+
"[x402-mantle-sdk] Facilitator /verify returned non-OK:",
|
|
197
|
+
verifyRes.status,
|
|
198
|
+
text
|
|
199
|
+
);
|
|
200
|
+
res.status(500).json({
|
|
201
|
+
error: "Payment verification error",
|
|
202
|
+
details: `Facilitator responded with HTTP ${verifyRes.status}`
|
|
203
|
+
});
|
|
204
|
+
return;
|
|
205
|
+
}
|
|
206
|
+
const verifyJson = await verifyRes.json();
|
|
207
|
+
if (!verifyJson.isValid) {
|
|
208
|
+
res.status(402).json({
|
|
209
|
+
error: "Payment verification failed",
|
|
210
|
+
invalidReason: verifyJson.invalidReason ?? null,
|
|
211
|
+
paymentRequirements,
|
|
212
|
+
paymentHeader: null
|
|
213
|
+
});
|
|
214
|
+
return;
|
|
215
|
+
}
|
|
216
|
+
if (onPaymentSettled) {
|
|
217
|
+
try {
|
|
218
|
+
const headerObj = decodePaymentHeader(paymentHeader);
|
|
219
|
+
const { authorization } = headerObj.payload;
|
|
220
|
+
const logEntry = {
|
|
221
|
+
id: authorization.nonce,
|
|
222
|
+
from: authorization.from,
|
|
223
|
+
to: authorization.to,
|
|
224
|
+
valueAtomic: authorization.value,
|
|
225
|
+
network,
|
|
226
|
+
asset: assetConfig.address,
|
|
227
|
+
route: routeKey,
|
|
228
|
+
timestamp: Date.now(),
|
|
229
|
+
facilitatorUrl,
|
|
230
|
+
// Pass from config closure
|
|
231
|
+
paymentRequirements
|
|
232
|
+
};
|
|
233
|
+
onPaymentSettled(logEntry);
|
|
234
|
+
if (telemetry) {
|
|
235
|
+
const event = createTelemetryEvent(logEntry, telemetry);
|
|
236
|
+
sendTelemetry(event, telemetry.endpoint).catch(
|
|
237
|
+
(err) => console.error("[x402-telemetry] Async send failed:", err)
|
|
238
|
+
);
|
|
239
|
+
}
|
|
240
|
+
} catch (err) {
|
|
241
|
+
console.error(
|
|
242
|
+
"[x402-mantle-sdk] Error calling onPaymentSettled hook:",
|
|
243
|
+
err
|
|
244
|
+
);
|
|
245
|
+
}
|
|
246
|
+
}
|
|
247
|
+
next();
|
|
248
|
+
return;
|
|
249
|
+
} catch (err) {
|
|
250
|
+
console.error(
|
|
251
|
+
"[x402-mantle-sdk] Error while calling facilitator /verify:",
|
|
252
|
+
err
|
|
253
|
+
);
|
|
254
|
+
const message = err instanceof Error ? err.message : "Unknown verification error";
|
|
255
|
+
res.status(500).json({
|
|
256
|
+
error: "Payment verification error",
|
|
257
|
+
details: message
|
|
258
|
+
});
|
|
259
|
+
return;
|
|
260
|
+
}
|
|
261
|
+
};
|
|
262
|
+
}
|
|
263
|
+
|
|
264
|
+
// src/server/mantlePaywall.ts
|
|
265
|
+
function mantlePaywall(opts) {
|
|
266
|
+
const { priceUsd, payTo, facilitatorUrl, telemetry, onPaymentSettled } = opts;
|
|
267
|
+
const priceUsdCents = Math.round(priceUsd * 100);
|
|
268
|
+
return async (req, res, next) => {
|
|
269
|
+
const method = (req.method || "GET").toUpperCase();
|
|
270
|
+
const path = req.path || "/";
|
|
271
|
+
const routeKey = `${method} ${path}`;
|
|
272
|
+
const middleware = createPaymentMiddleware({
|
|
273
|
+
facilitatorUrl: facilitatorUrl || MANTLE_DEFAULTS.FACILITATOR_URL,
|
|
274
|
+
receiverAddress: payTo,
|
|
275
|
+
routes: {
|
|
276
|
+
[routeKey]: {
|
|
277
|
+
priceUsdCents,
|
|
278
|
+
network: MANTLE_DEFAULTS.NETWORK
|
|
279
|
+
}
|
|
280
|
+
},
|
|
281
|
+
telemetry,
|
|
282
|
+
onPaymentSettled
|
|
283
|
+
});
|
|
284
|
+
return middleware(req, res, next);
|
|
285
|
+
};
|
|
286
|
+
}
|
|
287
|
+
// Annotate the CommonJS export names for ESM import in node:
|
|
288
|
+
0 && (module.exports = {
|
|
289
|
+
MANTLE_DEFAULTS,
|
|
290
|
+
createPaymentMiddleware,
|
|
291
|
+
mantlePaywall
|
|
292
|
+
});
|
|
@@ -0,0 +1,116 @@
|
|
|
1
|
+
import { Request, Response, NextFunction } from 'express';
|
|
2
|
+
import { N as NetworkId, P as PaymentRequirements } from './types-2zqbJvcz.cjs';
|
|
3
|
+
export { A as AssetConfig, a as Authorization, E as EIP1193Provider, d as PaymentHeaderBase64, c as PaymentHeaderObject, b as PaymentHeaderPayload } from './types-2zqbJvcz.cjs';
|
|
4
|
+
export { M as MANTLE_DEFAULTS } from './constants-DzCGK0Q3.cjs';
|
|
5
|
+
|
|
6
|
+
/** Unique key for a protected route, e.g. "GET /api/protected". */
|
|
7
|
+
type RouteKey = string;
|
|
8
|
+
/** Pricing config for a single route. */
|
|
9
|
+
interface RoutePricingConfig {
|
|
10
|
+
/** Price in USD cents, e.g. 1 => $0.01. */
|
|
11
|
+
priceUsdCents: number;
|
|
12
|
+
/** Network identifier (e.g. "mantle-mainnet"). */
|
|
13
|
+
network: NetworkId;
|
|
14
|
+
}
|
|
15
|
+
/** Map of route keys to pricing config. */
|
|
16
|
+
type RoutesConfig = Record<RouteKey, RoutePricingConfig>;
|
|
17
|
+
/** Log entry for a successfully settled payment. */
|
|
18
|
+
interface PaymentLogEntry {
|
|
19
|
+
id: string;
|
|
20
|
+
from: string;
|
|
21
|
+
to: string;
|
|
22
|
+
valueAtomic: string;
|
|
23
|
+
network: NetworkId;
|
|
24
|
+
asset: string;
|
|
25
|
+
route?: RouteKey;
|
|
26
|
+
txHash?: string;
|
|
27
|
+
timestamp: number;
|
|
28
|
+
facilitatorUrl?: string;
|
|
29
|
+
paymentRequirements?: PaymentRequirements;
|
|
30
|
+
}
|
|
31
|
+
/** Config for optional telemetry (billing/analytics). */
|
|
32
|
+
interface TelemetryConfig {
|
|
33
|
+
/** Project key from nosubs.ai dashboard. */
|
|
34
|
+
projectKey: string;
|
|
35
|
+
/**
|
|
36
|
+
* Telemetry endpoint URL.
|
|
37
|
+
* If not specified, uses DEFAULT_TELEMETRY_ENDPOINT (see server/constants.ts).
|
|
38
|
+
* If both are undefined, telemetry is not sent.
|
|
39
|
+
*/
|
|
40
|
+
endpoint?: string;
|
|
41
|
+
}
|
|
42
|
+
/** Telemetry event payload for payment_verified. */
|
|
43
|
+
interface TelemetryEvent {
|
|
44
|
+
event: "payment_verified";
|
|
45
|
+
ts: number;
|
|
46
|
+
projectKey: string;
|
|
47
|
+
network: string;
|
|
48
|
+
buyer: string;
|
|
49
|
+
payTo: string;
|
|
50
|
+
amountAtomic: string;
|
|
51
|
+
asset: string;
|
|
52
|
+
decimals: number;
|
|
53
|
+
nonce: string;
|
|
54
|
+
route: string;
|
|
55
|
+
facilitatorType: "hosted" | "self-hosted";
|
|
56
|
+
facilitatorUrl?: string;
|
|
57
|
+
facilitatorAddress?: string;
|
|
58
|
+
txHash?: string;
|
|
59
|
+
priceUsd?: string;
|
|
60
|
+
}
|
|
61
|
+
/** Config for createPaymentMiddleware. */
|
|
62
|
+
interface PaymentMiddlewareConfig {
|
|
63
|
+
/** Base URL of facilitator, e.g. https://facilitator.nosubs.ai */
|
|
64
|
+
facilitatorUrl: string;
|
|
65
|
+
/** Recipient address (developer). */
|
|
66
|
+
receiverAddress: `0x${string}`;
|
|
67
|
+
/** Map of protected routes and their pricing. */
|
|
68
|
+
routes: RoutesConfig;
|
|
69
|
+
/**
|
|
70
|
+
* Optional hook called whenever a payment is successfully settled.
|
|
71
|
+
* You can use this to push logs into your DB / analytics pipeline.
|
|
72
|
+
*/
|
|
73
|
+
onPaymentSettled?: (entry: PaymentLogEntry) => void;
|
|
74
|
+
/** Optional: Send usage telemetry for billing/analytics. */
|
|
75
|
+
telemetry?: TelemetryConfig;
|
|
76
|
+
}
|
|
77
|
+
/**
|
|
78
|
+
* Minimal config for mantlePaywall() - simplified API for single-route protection.
|
|
79
|
+
* This is the "sweet path" for Mantle mainnet + USDC with sensible defaults.
|
|
80
|
+
*/
|
|
81
|
+
interface MinimalPaywallOptions {
|
|
82
|
+
/** Price in USD (e.g. 0.01 for 1 cent). */
|
|
83
|
+
priceUsd: number;
|
|
84
|
+
/** Recipient address (developer wallet). */
|
|
85
|
+
payTo: `0x${string}`;
|
|
86
|
+
/** Optional facilitator URL (defaults to localhost:8080 or NEXT_PUBLIC_FACILITATOR_URL). */
|
|
87
|
+
facilitatorUrl?: string;
|
|
88
|
+
/** Optional telemetry config. */
|
|
89
|
+
telemetry?: TelemetryConfig;
|
|
90
|
+
/** Optional payment settled hook. */
|
|
91
|
+
onPaymentSettled?: (entry: PaymentLogEntry) => void;
|
|
92
|
+
}
|
|
93
|
+
/**
|
|
94
|
+
* Express middleware function type for Mantle paywall.
|
|
95
|
+
* Async function that returns Promise<void>.
|
|
96
|
+
*/
|
|
97
|
+
type MantleMiddleware = (req: Request, res: Response, next: NextFunction) => Promise<void>;
|
|
98
|
+
|
|
99
|
+
declare function createPaymentMiddleware(config: PaymentMiddlewareConfig): (req: Request, res: Response, next: NextFunction) => Promise<void>;
|
|
100
|
+
|
|
101
|
+
/**
|
|
102
|
+
* Simplified wrapper for protecting a single route with x402 payments.
|
|
103
|
+
* Uses Mantle mainnet defaults (USDC, exact scheme, etc.).
|
|
104
|
+
*
|
|
105
|
+
* Usage:
|
|
106
|
+
* ```typescript
|
|
107
|
+
* const pay = mantlePaywall({ priceUsd: 0.01, payTo: "0x..." });
|
|
108
|
+
* export const POST = pay(async (req) => { ... });
|
|
109
|
+
* ```
|
|
110
|
+
*
|
|
111
|
+
* @param opts - Minimal configuration (price, payTo, optional facilitator/telemetry).
|
|
112
|
+
* @returns Express middleware function for single-route protection.
|
|
113
|
+
*/
|
|
114
|
+
declare function mantlePaywall(opts: MinimalPaywallOptions): MantleMiddleware;
|
|
115
|
+
|
|
116
|
+
export { type MantleMiddleware, type MinimalPaywallOptions, NetworkId, type PaymentLogEntry, type PaymentMiddlewareConfig, PaymentRequirements, type RouteKey, type RoutePricingConfig, type RoutesConfig, type TelemetryConfig, type TelemetryEvent, createPaymentMiddleware, mantlePaywall };
|
package/dist/server.d.ts
ADDED
|
@@ -0,0 +1,116 @@
|
|
|
1
|
+
import { Request, Response, NextFunction } from 'express';
|
|
2
|
+
import { N as NetworkId, P as PaymentRequirements } from './types-2zqbJvcz.js';
|
|
3
|
+
export { A as AssetConfig, a as Authorization, E as EIP1193Provider, d as PaymentHeaderBase64, c as PaymentHeaderObject, b as PaymentHeaderPayload } from './types-2zqbJvcz.js';
|
|
4
|
+
export { M as MANTLE_DEFAULTS } from './constants-CVFF0ray.js';
|
|
5
|
+
|
|
6
|
+
/** Unique key for a protected route, e.g. "GET /api/protected". */
|
|
7
|
+
type RouteKey = string;
|
|
8
|
+
/** Pricing config for a single route. */
|
|
9
|
+
interface RoutePricingConfig {
|
|
10
|
+
/** Price in USD cents, e.g. 1 => $0.01. */
|
|
11
|
+
priceUsdCents: number;
|
|
12
|
+
/** Network identifier (e.g. "mantle-mainnet"). */
|
|
13
|
+
network: NetworkId;
|
|
14
|
+
}
|
|
15
|
+
/** Map of route keys to pricing config. */
|
|
16
|
+
type RoutesConfig = Record<RouteKey, RoutePricingConfig>;
|
|
17
|
+
/** Log entry for a successfully settled payment. */
|
|
18
|
+
interface PaymentLogEntry {
|
|
19
|
+
id: string;
|
|
20
|
+
from: string;
|
|
21
|
+
to: string;
|
|
22
|
+
valueAtomic: string;
|
|
23
|
+
network: NetworkId;
|
|
24
|
+
asset: string;
|
|
25
|
+
route?: RouteKey;
|
|
26
|
+
txHash?: string;
|
|
27
|
+
timestamp: number;
|
|
28
|
+
facilitatorUrl?: string;
|
|
29
|
+
paymentRequirements?: PaymentRequirements;
|
|
30
|
+
}
|
|
31
|
+
/** Config for optional telemetry (billing/analytics). */
|
|
32
|
+
interface TelemetryConfig {
|
|
33
|
+
/** Project key from nosubs.ai dashboard. */
|
|
34
|
+
projectKey: string;
|
|
35
|
+
/**
|
|
36
|
+
* Telemetry endpoint URL.
|
|
37
|
+
* If not specified, uses DEFAULT_TELEMETRY_ENDPOINT (see server/constants.ts).
|
|
38
|
+
* If both are undefined, telemetry is not sent.
|
|
39
|
+
*/
|
|
40
|
+
endpoint?: string;
|
|
41
|
+
}
|
|
42
|
+
/** Telemetry event payload for payment_verified. */
|
|
43
|
+
interface TelemetryEvent {
|
|
44
|
+
event: "payment_verified";
|
|
45
|
+
ts: number;
|
|
46
|
+
projectKey: string;
|
|
47
|
+
network: string;
|
|
48
|
+
buyer: string;
|
|
49
|
+
payTo: string;
|
|
50
|
+
amountAtomic: string;
|
|
51
|
+
asset: string;
|
|
52
|
+
decimals: number;
|
|
53
|
+
nonce: string;
|
|
54
|
+
route: string;
|
|
55
|
+
facilitatorType: "hosted" | "self-hosted";
|
|
56
|
+
facilitatorUrl?: string;
|
|
57
|
+
facilitatorAddress?: string;
|
|
58
|
+
txHash?: string;
|
|
59
|
+
priceUsd?: string;
|
|
60
|
+
}
|
|
61
|
+
/** Config for createPaymentMiddleware. */
|
|
62
|
+
interface PaymentMiddlewareConfig {
|
|
63
|
+
/** Base URL of facilitator, e.g. https://facilitator.nosubs.ai */
|
|
64
|
+
facilitatorUrl: string;
|
|
65
|
+
/** Recipient address (developer). */
|
|
66
|
+
receiverAddress: `0x${string}`;
|
|
67
|
+
/** Map of protected routes and their pricing. */
|
|
68
|
+
routes: RoutesConfig;
|
|
69
|
+
/**
|
|
70
|
+
* Optional hook called whenever a payment is successfully settled.
|
|
71
|
+
* You can use this to push logs into your DB / analytics pipeline.
|
|
72
|
+
*/
|
|
73
|
+
onPaymentSettled?: (entry: PaymentLogEntry) => void;
|
|
74
|
+
/** Optional: Send usage telemetry for billing/analytics. */
|
|
75
|
+
telemetry?: TelemetryConfig;
|
|
76
|
+
}
|
|
77
|
+
/**
|
|
78
|
+
* Minimal config for mantlePaywall() - simplified API for single-route protection.
|
|
79
|
+
* This is the "sweet path" for Mantle mainnet + USDC with sensible defaults.
|
|
80
|
+
*/
|
|
81
|
+
interface MinimalPaywallOptions {
|
|
82
|
+
/** Price in USD (e.g. 0.01 for 1 cent). */
|
|
83
|
+
priceUsd: number;
|
|
84
|
+
/** Recipient address (developer wallet). */
|
|
85
|
+
payTo: `0x${string}`;
|
|
86
|
+
/** Optional facilitator URL (defaults to localhost:8080 or NEXT_PUBLIC_FACILITATOR_URL). */
|
|
87
|
+
facilitatorUrl?: string;
|
|
88
|
+
/** Optional telemetry config. */
|
|
89
|
+
telemetry?: TelemetryConfig;
|
|
90
|
+
/** Optional payment settled hook. */
|
|
91
|
+
onPaymentSettled?: (entry: PaymentLogEntry) => void;
|
|
92
|
+
}
|
|
93
|
+
/**
|
|
94
|
+
* Express middleware function type for Mantle paywall.
|
|
95
|
+
* Async function that returns Promise<void>.
|
|
96
|
+
*/
|
|
97
|
+
type MantleMiddleware = (req: Request, res: Response, next: NextFunction) => Promise<void>;
|
|
98
|
+
|
|
99
|
+
declare function createPaymentMiddleware(config: PaymentMiddlewareConfig): (req: Request, res: Response, next: NextFunction) => Promise<void>;
|
|
100
|
+
|
|
101
|
+
/**
|
|
102
|
+
* Simplified wrapper for protecting a single route with x402 payments.
|
|
103
|
+
* Uses Mantle mainnet defaults (USDC, exact scheme, etc.).
|
|
104
|
+
*
|
|
105
|
+
* Usage:
|
|
106
|
+
* ```typescript
|
|
107
|
+
* const pay = mantlePaywall({ priceUsd: 0.01, payTo: "0x..." });
|
|
108
|
+
* export const POST = pay(async (req) => { ... });
|
|
109
|
+
* ```
|
|
110
|
+
*
|
|
111
|
+
* @param opts - Minimal configuration (price, payTo, optional facilitator/telemetry).
|
|
112
|
+
* @returns Express middleware function for single-route protection.
|
|
113
|
+
*/
|
|
114
|
+
declare function mantlePaywall(opts: MinimalPaywallOptions): MantleMiddleware;
|
|
115
|
+
|
|
116
|
+
export { type MantleMiddleware, type MinimalPaywallOptions, NetworkId, type PaymentLogEntry, type PaymentMiddlewareConfig, PaymentRequirements, type RouteKey, type RoutePricingConfig, type RoutesConfig, type TelemetryConfig, type TelemetryEvent, createPaymentMiddleware, mantlePaywall };
|
package/dist/server.js
ADDED
|
@@ -0,0 +1,63 @@
|
|
|
1
|
+
/** Network identifier used in x402 paymentRequirements / paymentHeader. */
|
|
2
|
+
type NetworkId = "mantle-mainnet" | (string & {});
|
|
3
|
+
/** Basic ERC-20 asset config (e.g. USDC on Mantle). */
|
|
4
|
+
interface AssetConfig {
|
|
5
|
+
symbol: string;
|
|
6
|
+
address: string;
|
|
7
|
+
decimals: number;
|
|
8
|
+
}
|
|
9
|
+
/** x402-style payment requirements (returned in 402 response). */
|
|
10
|
+
interface PaymentRequirements {
|
|
11
|
+
scheme: "exact";
|
|
12
|
+
network: NetworkId;
|
|
13
|
+
asset: string;
|
|
14
|
+
maxAmountRequired: string;
|
|
15
|
+
payTo: `0x${string}`;
|
|
16
|
+
price?: string;
|
|
17
|
+
currency?: string;
|
|
18
|
+
}
|
|
19
|
+
/** EIP-3009 TransferWithAuthorization payload. */
|
|
20
|
+
interface Authorization {
|
|
21
|
+
from: string;
|
|
22
|
+
to: string;
|
|
23
|
+
value: string;
|
|
24
|
+
validAfter: string;
|
|
25
|
+
validBefore: string;
|
|
26
|
+
nonce: string;
|
|
27
|
+
}
|
|
28
|
+
/** Inner payload of x402-style payment header. */
|
|
29
|
+
interface PaymentHeaderPayload {
|
|
30
|
+
signature: string;
|
|
31
|
+
authorization: Authorization;
|
|
32
|
+
}
|
|
33
|
+
/** Structured x402-style payment header (before base64 encoding). */
|
|
34
|
+
interface PaymentHeaderObject {
|
|
35
|
+
x402Version: number;
|
|
36
|
+
scheme: "exact";
|
|
37
|
+
network: NetworkId;
|
|
38
|
+
payload: PaymentHeaderPayload;
|
|
39
|
+
}
|
|
40
|
+
/** Base64-encoded payment header, sent in X-PAYMENT. */
|
|
41
|
+
type PaymentHeaderBase64 = string;
|
|
42
|
+
/**
|
|
43
|
+
* EIP-1193 provider interface (window.ethereum, MetaMask, etc.)
|
|
44
|
+
* Standard interface for Ethereum wallet providers.
|
|
45
|
+
*/
|
|
46
|
+
interface EIP1193Provider {
|
|
47
|
+
request(args: {
|
|
48
|
+
method: string;
|
|
49
|
+
params?: unknown[];
|
|
50
|
+
}): Promise<unknown>;
|
|
51
|
+
on?(event: string, listener: (...args: unknown[]) => void): void;
|
|
52
|
+
removeListener?(event: string, listener: (...args: unknown[]) => void): void;
|
|
53
|
+
}
|
|
54
|
+
/**
|
|
55
|
+
* Window ethereum extension for TypeScript
|
|
56
|
+
*/
|
|
57
|
+
declare global {
|
|
58
|
+
interface Window {
|
|
59
|
+
ethereum?: EIP1193Provider;
|
|
60
|
+
}
|
|
61
|
+
}
|
|
62
|
+
|
|
63
|
+
export type { AssetConfig as A, EIP1193Provider as E, NetworkId as N, PaymentRequirements as P, Authorization as a, PaymentHeaderPayload as b, PaymentHeaderObject as c, PaymentHeaderBase64 as d };
|
|
@@ -0,0 +1,63 @@
|
|
|
1
|
+
/** Network identifier used in x402 paymentRequirements / paymentHeader. */
|
|
2
|
+
type NetworkId = "mantle-mainnet" | (string & {});
|
|
3
|
+
/** Basic ERC-20 asset config (e.g. USDC on Mantle). */
|
|
4
|
+
interface AssetConfig {
|
|
5
|
+
symbol: string;
|
|
6
|
+
address: string;
|
|
7
|
+
decimals: number;
|
|
8
|
+
}
|
|
9
|
+
/** x402-style payment requirements (returned in 402 response). */
|
|
10
|
+
interface PaymentRequirements {
|
|
11
|
+
scheme: "exact";
|
|
12
|
+
network: NetworkId;
|
|
13
|
+
asset: string;
|
|
14
|
+
maxAmountRequired: string;
|
|
15
|
+
payTo: `0x${string}`;
|
|
16
|
+
price?: string;
|
|
17
|
+
currency?: string;
|
|
18
|
+
}
|
|
19
|
+
/** EIP-3009 TransferWithAuthorization payload. */
|
|
20
|
+
interface Authorization {
|
|
21
|
+
from: string;
|
|
22
|
+
to: string;
|
|
23
|
+
value: string;
|
|
24
|
+
validAfter: string;
|
|
25
|
+
validBefore: string;
|
|
26
|
+
nonce: string;
|
|
27
|
+
}
|
|
28
|
+
/** Inner payload of x402-style payment header. */
|
|
29
|
+
interface PaymentHeaderPayload {
|
|
30
|
+
signature: string;
|
|
31
|
+
authorization: Authorization;
|
|
32
|
+
}
|
|
33
|
+
/** Structured x402-style payment header (before base64 encoding). */
|
|
34
|
+
interface PaymentHeaderObject {
|
|
35
|
+
x402Version: number;
|
|
36
|
+
scheme: "exact";
|
|
37
|
+
network: NetworkId;
|
|
38
|
+
payload: PaymentHeaderPayload;
|
|
39
|
+
}
|
|
40
|
+
/** Base64-encoded payment header, sent in X-PAYMENT. */
|
|
41
|
+
type PaymentHeaderBase64 = string;
|
|
42
|
+
/**
|
|
43
|
+
* EIP-1193 provider interface (window.ethereum, MetaMask, etc.)
|
|
44
|
+
* Standard interface for Ethereum wallet providers.
|
|
45
|
+
*/
|
|
46
|
+
interface EIP1193Provider {
|
|
47
|
+
request(args: {
|
|
48
|
+
method: string;
|
|
49
|
+
params?: unknown[];
|
|
50
|
+
}): Promise<unknown>;
|
|
51
|
+
on?(event: string, listener: (...args: unknown[]) => void): void;
|
|
52
|
+
removeListener?(event: string, listener: (...args: unknown[]) => void): void;
|
|
53
|
+
}
|
|
54
|
+
/**
|
|
55
|
+
* Window ethereum extension for TypeScript
|
|
56
|
+
*/
|
|
57
|
+
declare global {
|
|
58
|
+
interface Window {
|
|
59
|
+
ethereum?: EIP1193Provider;
|
|
60
|
+
}
|
|
61
|
+
}
|
|
62
|
+
|
|
63
|
+
export type { AssetConfig as A, EIP1193Provider as E, NetworkId as N, PaymentRequirements as P, Authorization as a, PaymentHeaderPayload as b, PaymentHeaderObject as c, PaymentHeaderBase64 as d };
|