wolverine-ai 5.4.1 → 5.4.3
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/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "wolverine-ai",
|
|
3
|
-
"version": "5.4.
|
|
3
|
+
"version": "5.4.3",
|
|
4
4
|
"description": "Self-healing Node.js server framework powered by AI. Catches crashes, diagnoses errors, generates fixes, verifies, and restarts — automatically.",
|
|
5
5
|
"main": "src/index.js",
|
|
6
6
|
"bin": {
|
|
@@ -174,50 +174,29 @@ async function x402Plugin(fastify, opts) {
|
|
|
174
174
|
return;
|
|
175
175
|
}
|
|
176
176
|
|
|
177
|
-
//
|
|
177
|
+
// Settle via facilitator BEFORE handler runs — USDC must move before granting access
|
|
178
178
|
const payer = decodedPayment.payload.authorization.from;
|
|
179
|
-
request.x402 = { paid: true, amount: price, from: payer, value: userValue, verified: true };
|
|
180
|
-
|
|
181
|
-
// Log payment
|
|
182
|
-
_logPayment({ route: request.url, method: request.method, amount: price, from: payer, verified: true, timestamp: Date.now() });
|
|
183
|
-
});
|
|
184
|
-
|
|
185
|
-
// Settlement hook — settle AFTER successful handler response
|
|
186
|
-
fastify.addHook("onSend", async (request, reply, payload) => {
|
|
187
|
-
if (!request.x402?.paid || !_facilitatorClient) return payload;
|
|
188
|
-
if (reply.statusCode >= 400) return payload;
|
|
189
|
-
|
|
190
179
|
try {
|
|
191
|
-
const
|
|
192
|
-
|
|
193
|
-
const decodedPayment = { x402Version: raw.x402Version || 1, scheme: raw.scheme || "exact", network: raw.network || _network, payload: raw.payload };
|
|
194
|
-
|
|
195
|
-
const userValue = decodedPayment.payload.authorization.value;
|
|
196
|
-
const { getAddress } = await import("viem");
|
|
197
|
-
const proto = request.headers["x-forwarded-proto"] || "https";
|
|
198
|
-
const host = request.headers["x-forwarded-host"] || request.headers.host || "localhost";
|
|
199
|
-
const requirements = {
|
|
200
|
-
scheme: "exact", network: _network, maxAmountRequired: userValue,
|
|
201
|
-
resource: `${proto}://${host}${request.url}`, description: "", mimeType: "application/json",
|
|
202
|
-
payTo: getAddress(_payTo), maxTimeoutSeconds: 60, asset: getAddress(USDC_ADDRESS), extra: USDC_EIP712,
|
|
203
|
-
};
|
|
204
|
-
|
|
205
|
-
const settleResult = await _facilitatorClient.settle(decodedPayment, requirements);
|
|
206
|
-
if (settleResult.success) {
|
|
207
|
-
request.x402.txHash = settleResult.transaction;
|
|
208
|
-
request.x402.settled = true;
|
|
209
|
-
console.log(` 💰 x402 settled: ${settleResult.transaction || "confirmed"} (${request.x402.amount} from ${request.x402.from?.slice(0, 10)})`);
|
|
210
|
-
// Update payment log
|
|
211
|
-
_logPayment({ route: request.url, method: request.method, amount: request.x402.amount, from: request.x402.from, txHash: settleResult.transaction, verified: true, settled: true, timestamp: Date.now() });
|
|
212
|
-
} else {
|
|
180
|
+
const settleResult = await _facilitatorClient.settle(decodedPayment, actualRequirements);
|
|
181
|
+
if (!settleResult.success) {
|
|
213
182
|
console.log(` ⚠️ x402 settle failed: ${settleResult.errorReason || "unknown"}`);
|
|
183
|
+
reply.code(402).send({ error: "Payment settlement failed", reason: settleResult.errorReason });
|
|
184
|
+
return;
|
|
214
185
|
}
|
|
186
|
+
const txHash = settleResult.transaction || null;
|
|
187
|
+
console.log(` 💰 x402 settled: ${txHash || "confirmed"} (${price} from ${payer?.slice(0, 10)})`);
|
|
188
|
+
|
|
189
|
+
request.x402 = { paid: true, amount: price, from: payer, value: userValue, verified: true, settled: true, txHash };
|
|
190
|
+
_logPayment({ route: request.url, method: request.method, amount: price, from: payer, txHash, verified: true, settled: true, timestamp: Date.now() });
|
|
215
191
|
} catch (err) {
|
|
216
192
|
console.log(` ⚠️ x402 settle error: ${err.message}`);
|
|
193
|
+
reply.code(402).send({ error: "Payment settlement failed: " + err.message });
|
|
194
|
+
return;
|
|
217
195
|
}
|
|
218
|
-
return payload;
|
|
219
196
|
});
|
|
220
197
|
|
|
198
|
+
// No onSend settle needed — settlement happens in preHandler before handler runs
|
|
199
|
+
|
|
221
200
|
// Public info endpoint
|
|
222
201
|
fastify.get("/x402/info", async () => ({
|
|
223
202
|
payTo: _payTo, network: _network, protocol: "x402", x402Version: 1,
|
|
@@ -22,6 +22,9 @@ if (clusterEnabled && cluster.isPrimary && workerCount > 1) {
|
|
|
22
22
|
// Single worker or cluster worker — run the server
|
|
23
23
|
const fastify = require("fastify")({ logger: false });
|
|
24
24
|
|
|
25
|
+
// x402 payment middleware (auto-detects vault, no-op if no vault)
|
|
26
|
+
try { fastify.register(require("wolverine-ai/src/middleware/x402-fastify")); } catch {}
|
|
27
|
+
|
|
25
28
|
// Routes
|
|
26
29
|
fastify.register(require("./routes/health"), { prefix: "/health" });
|
|
27
30
|
fastify.register(require("./routes/api"), { prefix: "/api" });
|
|
@@ -1,26 +1,25 @@
|
|
|
1
1
|
/**
|
|
2
|
-
* Demo API routes —
|
|
2
|
+
* Demo API routes — free endpoints and x402 paid APIs.
|
|
3
3
|
*
|
|
4
|
-
*
|
|
5
|
-
*
|
|
6
|
-
*
|
|
4
|
+
* x402 Setup (one-time):
|
|
5
|
+
* 1. wolverine --init-vault Create encrypted wallet
|
|
6
|
+
* 2. Set CDP_API_KEY_ID + CDP_API_KEY_SECRET in .env.local
|
|
7
|
+
* (free at https://cdp.coinbase.com)
|
|
8
|
+
* 3. Add { config: { x402: { price: "$0.01" } } } to any route
|
|
7
9
|
*
|
|
8
|
-
*
|
|
9
|
-
*
|
|
10
|
-
*
|
|
10
|
+
* That's it — the route now requires USDC payment on Base.
|
|
11
|
+
* The middleware handles 402 responses, wallet signing, facilitator
|
|
12
|
+
* verification, and on-chain settlement automatically.
|
|
11
13
|
*
|
|
12
|
-
*
|
|
13
|
-
*
|
|
14
|
-
* -
|
|
15
|
-
*
|
|
16
|
-
* - Rollback-protected (never overwritten by restore)
|
|
17
|
-
*
|
|
18
|
-
* Dashboard: localhost:3001 — view wallet balances, x402 revenue,
|
|
19
|
-
* payment history, and all server health metrics in real time.
|
|
14
|
+
* Protocol: https://docs.cdp.coinbase.com/x402/welcome
|
|
15
|
+
* Network: Base mainnet — USDC payments
|
|
16
|
+
* Wallet: Auto-detected from vault
|
|
17
|
+
* Node: 22+ required
|
|
20
18
|
*/
|
|
21
19
|
|
|
22
20
|
async function routes(fastify) {
|
|
23
|
-
// ── Free endpoints ──
|
|
21
|
+
// ── Free endpoints (no x402 config = no payment required) ──
|
|
22
|
+
|
|
24
23
|
fastify.get("/", async () => ({ message: "Hello from Wolverine API" }));
|
|
25
24
|
|
|
26
25
|
fastify.get("/users", async () => ({
|
|
@@ -30,29 +29,19 @@ async function routes(fastify) {
|
|
|
30
29
|
],
|
|
31
30
|
}));
|
|
32
31
|
|
|
33
|
-
// ──
|
|
34
|
-
//
|
|
35
|
-
// Callers without a valid USDC payment get a 402 with payment instructions.
|
|
36
|
-
// Callers with a valid Payment-Signature header get the response.
|
|
37
|
-
//
|
|
38
|
-
// Protocol: https://docs.cdp.coinbase.com/x402/welcome
|
|
39
|
-
// Network: Base (eip155:8453) — USDC payments
|
|
40
|
-
// Wallet: Auto-detected from vault (wolverine --init-vault)
|
|
41
|
-
//
|
|
42
|
-
// To change pricing live without restart:
|
|
43
|
-
// Update the price in config and the next request picks it up.
|
|
44
|
-
// Or use the dashboard command: "change /api/premium price to $0.05"
|
|
45
|
-
|
|
46
|
-
// Fixed price — charge $0.01 per call:
|
|
32
|
+
// ── Paid endpoint — fixed price ──
|
|
33
|
+
// Just add x402 config. Handler only runs after USDC settles on-chain.
|
|
47
34
|
fastify.get("/premium", {
|
|
48
35
|
config: { x402: { price: "$0.01", description: "Premium data endpoint" } },
|
|
49
36
|
}, async (req) => ({
|
|
50
37
|
data: "This response cost $0.01 in USDC on Base",
|
|
51
|
-
paid: req.x402
|
|
52
|
-
from: req.x402
|
|
38
|
+
paid: req.x402.amount,
|
|
39
|
+
from: req.x402.from,
|
|
40
|
+
txHash: req.x402.txHash,
|
|
53
41
|
}));
|
|
54
42
|
|
|
55
|
-
//
|
|
43
|
+
// ── Paid endpoint — variable price ──
|
|
44
|
+
// Caller specifies amount in request body. Good for credit purchases.
|
|
56
45
|
// POST /api/purchase { "dollars": "5.00" }
|
|
57
46
|
fastify.post("/purchase", {
|
|
58
47
|
config: {
|
|
@@ -65,9 +54,10 @@ async function routes(fastify) {
|
|
|
65
54
|
},
|
|
66
55
|
},
|
|
67
56
|
}, async (req) => ({
|
|
68
|
-
message: `Received ${req.x402
|
|
69
|
-
from: req.x402
|
|
70
|
-
|
|
57
|
+
message: `Received ${req.x402.amount} USDC payment`,
|
|
58
|
+
from: req.x402.from,
|
|
59
|
+
txHash: req.x402.txHash,
|
|
60
|
+
settled: req.x402.settled,
|
|
71
61
|
}));
|
|
72
62
|
}
|
|
73
63
|
|