mpp-test-sdk 1.1.1 → 1.1.2
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 +102 -53
- package/dist/index.d.mts +11 -11
- package/dist/index.d.ts +11 -11
- package/package.json +2 -2
package/README.md
CHANGED
|
@@ -4,9 +4,9 @@
|
|
|
4
4
|
[](https://nodejs.org)
|
|
5
5
|
[](LICENSE)
|
|
6
6
|
|
|
7
|
-
Test pay-per-request APIs on **Solana devnet
|
|
7
|
+
Test pay-per-request APIs on **Solana** - devnet, testnet, or mainnet. Auto-creates wallets, airdrops SOL, handles HTTP 402 MPP payments. Zero setup required.
|
|
8
8
|
|
|
9
|
-
**[mpptestkit.com](https://mpptestkit.com)** · [GitHub](https://github.com/mpptestkit/mpp-test-sdk) · [X](https://x.com/mpptestkit)
|
|
9
|
+
**[mpptestkit.com](https://mpptestkit.com)** · [Playground](https://mpptestkit.com/playground) · [Docs](https://mpptestkit.com/docs) · [GitHub](https://github.com/mpptestkit/mpp-test-sdk) · [X](https://x.com/mpptestkit)
|
|
10
10
|
|
|
11
11
|
---
|
|
12
12
|
|
|
@@ -16,7 +16,7 @@ Test pay-per-request APIs on **Solana devnet**. Auto-creates wallets, airdrops S
|
|
|
16
16
|
npm i mpp-test-sdk
|
|
17
17
|
```
|
|
18
18
|
|
|
19
|
-
Requires Node.js
|
|
19
|
+
Requires Node.js 18+.
|
|
20
20
|
|
|
21
21
|
---
|
|
22
22
|
|
|
@@ -25,9 +25,16 @@ Requires Node.js 22+.
|
|
|
25
25
|
```ts
|
|
26
26
|
import { mppFetch } from "mpp-test-sdk";
|
|
27
27
|
|
|
28
|
-
//
|
|
28
|
+
// One line. No wallet setup. No config.
|
|
29
29
|
const res = await mppFetch("https://your-api.com/api/data");
|
|
30
30
|
const data = await res.json();
|
|
31
|
+
|
|
32
|
+
// What happened automatically:
|
|
33
|
+
// 1. SDK generated a Solana keypair
|
|
34
|
+
// 2. Airdropped 2 SOL from the devnet faucet
|
|
35
|
+
// 3. Server returned 402 Payment Required
|
|
36
|
+
// 4. SDK sent 0.001 SOL on Solana (~800ms finality)
|
|
37
|
+
// 5. Retried with Payment-Receipt header → 200 OK
|
|
31
38
|
```
|
|
32
39
|
|
|
33
40
|
Or with a dedicated client instance:
|
|
@@ -36,13 +43,14 @@ Or with a dedicated client instance:
|
|
|
36
43
|
import { createTestClient } from "mpp-test-sdk";
|
|
37
44
|
|
|
38
45
|
const client = await createTestClient({
|
|
46
|
+
network: "devnet",
|
|
39
47
|
onStep: (step) => console.log(step.type, step.message),
|
|
40
48
|
});
|
|
41
49
|
|
|
42
50
|
const res = await client.fetch("https://your-api.com/api/data");
|
|
43
51
|
```
|
|
44
52
|
|
|
45
|
-
|
|
53
|
+
Call `mppFetch.reset()` to discard the shared client and generate a fresh wallet on the next request.
|
|
46
54
|
|
|
47
55
|
---
|
|
48
56
|
|
|
@@ -53,19 +61,19 @@ import express from "express";
|
|
|
53
61
|
import { createTestServer } from "mpp-test-sdk";
|
|
54
62
|
|
|
55
63
|
const app = express();
|
|
64
|
+
const mpp = createTestServer(); // auto-generates server wallet
|
|
56
65
|
|
|
57
|
-
//
|
|
58
|
-
const mpp = createTestServer();
|
|
59
|
-
|
|
60
|
-
// Free — no middleware
|
|
66
|
+
// Free - no middleware
|
|
61
67
|
app.get("/api/ping", (req, res) => res.json({ ok: true }));
|
|
62
68
|
|
|
63
|
-
// Paid
|
|
64
|
-
app.get("/api/data",
|
|
65
|
-
|
|
66
|
-
})
|
|
69
|
+
// Paid - one line (0.001 SOL)
|
|
70
|
+
app.get("/api/data",
|
|
71
|
+
mpp.charge({ amount: "0.001" }),
|
|
72
|
+
(req, res) => res.json({ data: "premium content" })
|
|
73
|
+
);
|
|
67
74
|
|
|
68
75
|
app.listen(3001);
|
|
76
|
+
console.log("Payments go to:", mpp.recipientAddress);
|
|
69
77
|
```
|
|
70
78
|
|
|
71
79
|
---
|
|
@@ -74,9 +82,7 @@ app.listen(3001);
|
|
|
74
82
|
|
|
75
83
|
### `mppFetch(url, init?)`
|
|
76
84
|
|
|
77
|
-
Drop-in replacement for `fetch`.
|
|
78
|
-
|
|
79
|
-
Call `mppFetch.reset()` to discard the shared client and generate a new wallet on the next request.
|
|
85
|
+
Drop-in replacement for `fetch`. Lazily creates a shared client on first call and reuses it across requests.
|
|
80
86
|
|
|
81
87
|
### `createTestClient(config?)`
|
|
82
88
|
|
|
@@ -84,36 +90,58 @@ Creates a client with its own isolated Solana wallet.
|
|
|
84
90
|
|
|
85
91
|
| Option | Type | Default | Description |
|
|
86
92
|
|---|---|---|---|
|
|
87
|
-
| `
|
|
88
|
-
| `
|
|
93
|
+
| `network` | `"devnet" \| "testnet" \| "mainnet"` | `"devnet"` | Solana network to use |
|
|
94
|
+
| `secretKey` | `Uint8Array \| number[]` | auto-generated | Reuse a pre-funded keypair (required on mainnet) |
|
|
95
|
+
| `onStep` | `(step: PaymentStep) => void` | - | Lifecycle event callback |
|
|
89
96
|
| `timeout` | `number` | `30000` | Full flow timeout in ms |
|
|
90
|
-
| `rpcUrl` | `string` | devnet RPC | Solana RPC endpoint |
|
|
91
97
|
|
|
92
|
-
Returns `Promise<TestClient
|
|
98
|
+
Returns `Promise<TestClient>`:
|
|
99
|
+
|
|
100
|
+
```ts
|
|
101
|
+
interface TestClient {
|
|
102
|
+
address: string; // Solana public key (base58)
|
|
103
|
+
network: SolanaNetwork;
|
|
104
|
+
fetch: (url: string, init?: RequestInit) => Promise<Response>;
|
|
105
|
+
}
|
|
106
|
+
```
|
|
93
107
|
|
|
94
|
-
**Throws:**
|
|
108
|
+
**Throws:**
|
|
109
|
+
- `MppFaucetError` - devnet/testnet airdrop failed
|
|
110
|
+
- `MppNetworkError` - mainnet used without a `secretKey`
|
|
95
111
|
|
|
96
112
|
### `createTestServer(config?)`
|
|
97
113
|
|
|
98
|
-
Creates Express middleware that enforces
|
|
114
|
+
Creates Express middleware that enforces payment on any route.
|
|
99
115
|
|
|
100
116
|
| Option | Type | Default | Description |
|
|
101
117
|
|---|---|---|---|
|
|
102
|
-
| `
|
|
103
|
-
| `
|
|
104
|
-
|
|
105
|
-
|
|
118
|
+
| `network` | `"devnet" \| "testnet" \| "mainnet"` | `"devnet"` | Solana network to verify payments on |
|
|
119
|
+
| `secretKey` | `Uint8Array \| number[]` | auto-generated | Server wallet keypair |
|
|
120
|
+
|
|
121
|
+
**Properties:**
|
|
122
|
+
|
|
123
|
+
| Property | Description |
|
|
124
|
+
|---|---|
|
|
125
|
+
| `mpp.recipientAddress` | Server wallet public key - payments land here |
|
|
126
|
+
| `mpp.network` | Active network |
|
|
127
|
+
|
|
128
|
+
### `mpp.charge(opts)`
|
|
106
129
|
|
|
107
|
-
|
|
130
|
+
Express `RequestHandler`. Place before your route handler.
|
|
131
|
+
|
|
132
|
+
| Option | Type | Description |
|
|
133
|
+
|---|---|---|
|
|
134
|
+
| `amount` | `string` | Amount in SOL, e.g. `"0.001"` |
|
|
108
135
|
|
|
109
136
|
### `PaymentStep` events
|
|
110
137
|
|
|
111
138
|
| `step.type` | When |
|
|
112
139
|
|---|---|
|
|
113
140
|
| `"wallet-created"` | Solana keypair generated |
|
|
114
|
-
| `"funded"` |
|
|
115
|
-
| `"request"` | Outgoing HTTP request |
|
|
116
|
-
| `"payment"` | SOL
|
|
141
|
+
| `"funded"` | Faucet airdrop confirmed (devnet/testnet) |
|
|
142
|
+
| `"request"` | Outgoing HTTP request fired |
|
|
143
|
+
| `"payment"` | SOL transaction submitted and confirmed |
|
|
144
|
+
| `"retry"` | Request retried with Payment-Receipt header |
|
|
117
145
|
| `"success"` | Final 200 response received |
|
|
118
146
|
| `"error"` | Flow failed |
|
|
119
147
|
|
|
@@ -122,58 +150,79 @@ Returns `MppServer` with `.charge({ amount })` middleware.
|
|
|
122
150
|
## Error Handling
|
|
123
151
|
|
|
124
152
|
```ts
|
|
125
|
-
import {
|
|
153
|
+
import {
|
|
154
|
+
MppError,
|
|
155
|
+
MppFaucetError,
|
|
156
|
+
MppPaymentError,
|
|
157
|
+
MppTimeoutError,
|
|
158
|
+
MppNetworkError,
|
|
159
|
+
} from "mpp-test-sdk";
|
|
126
160
|
|
|
127
161
|
try {
|
|
128
|
-
const res = await
|
|
162
|
+
const res = await mppFetch("https://api.example.com/data");
|
|
129
163
|
} catch (err) {
|
|
130
|
-
if (err instanceof
|
|
131
|
-
//
|
|
164
|
+
if (err instanceof MppNetworkError) {
|
|
165
|
+
// Mainnet used without secretKey
|
|
166
|
+
} else if (err instanceof MppFaucetError) {
|
|
167
|
+
// Devnet/testnet airdrop failed - err.address
|
|
132
168
|
} else if (err instanceof MppPaymentError) {
|
|
133
|
-
// Server rejected payment
|
|
169
|
+
// Server rejected payment - err.status, err.url
|
|
134
170
|
} else if (err instanceof MppTimeoutError) {
|
|
135
|
-
// Flow timed out
|
|
171
|
+
// Flow timed out - err.url, err.timeoutMs
|
|
136
172
|
}
|
|
137
173
|
}
|
|
138
174
|
```
|
|
139
175
|
|
|
140
|
-
**Tip:** Pass a pre-funded `secretKey` to
|
|
176
|
+
**Tip:** Pass a pre-funded `secretKey` to skip faucet calls entirely - useful in CI or when devnet is rate-limiting.
|
|
141
177
|
|
|
142
178
|
---
|
|
143
179
|
|
|
144
180
|
## Protocol
|
|
145
181
|
|
|
146
|
-
The SDK implements **MPP (Machine Payments Protocol)** on Solana.
|
|
182
|
+
The SDK implements **MPP (Machine Payments Protocol)** on Solana. Plain HTTP headers, no custom transport:
|
|
147
183
|
|
|
148
184
|
```
|
|
149
|
-
# Server → Client (402)
|
|
150
|
-
Payment-Request: solana; amount="0.001"; recipient="
|
|
185
|
+
# Server → Client (402 Payment Required)
|
|
186
|
+
Payment-Request: solana; amount="0.001"; recipient="9WzDX..."; network="devnet"
|
|
151
187
|
|
|
152
|
-
# Client → Server (retry)
|
|
153
|
-
Payment-Receipt: solana; signature="
|
|
188
|
+
# Client → Server (retry with proof)
|
|
189
|
+
Payment-Receipt: solana; signature="3xKm7..."; network="devnet"
|
|
154
190
|
```
|
|
155
191
|
|
|
192
|
+
On-chain verification confirms: transaction exists, recipient matches, SOL delta ≥ required amount.
|
|
193
|
+
|
|
156
194
|
---
|
|
157
195
|
|
|
158
|
-
##
|
|
196
|
+
## Networks
|
|
159
197
|
|
|
160
|
-
| |
|
|
161
|
-
|
|
162
|
-
|
|
|
163
|
-
|
|
|
164
|
-
|
|
|
165
|
-
|
|
166
|
-
|
|
198
|
+
| | devnet | testnet | mainnet |
|
|
199
|
+
|---|---|---|---|
|
|
200
|
+
| Faucet | Auto (2 SOL) | Auto (2 SOL) | Bring your own |
|
|
201
|
+
| Cost | Free | Free | Real SOL |
|
|
202
|
+
| Use for | Local dev, CI | Pre-production | Production |
|
|
203
|
+
|
|
204
|
+
```ts
|
|
205
|
+
// Devnet (default)
|
|
206
|
+
const client = await createTestClient({ network: "devnet" });
|
|
207
|
+
|
|
208
|
+
// Mainnet - bring your own funded keypair
|
|
209
|
+
const client = await createTestClient({
|
|
210
|
+
network: "mainnet",
|
|
211
|
+
secretKey: Uint8Array.from(JSON.parse(process.env.SOLANA_SECRET_KEY!)),
|
|
212
|
+
});
|
|
213
|
+
```
|
|
167
214
|
|
|
168
215
|
---
|
|
169
216
|
|
|
170
217
|
## Troubleshooting
|
|
171
218
|
|
|
172
|
-
**`MppFaucetError`**
|
|
219
|
+
**`MppFaucetError`** - Devnet airdrop is rate-limited. Wait 30–60 seconds and retry, or pass a pre-funded `secretKey` to skip the faucet.
|
|
220
|
+
|
|
221
|
+
**`MppNetworkError`** - You passed `network: "mainnet"` without a `secretKey`. Mainnet has no faucet - provide a funded keypair.
|
|
173
222
|
|
|
174
|
-
**`MppTimeoutError`**
|
|
223
|
+
**`MppTimeoutError`** - Increase `timeout` in `createTestClient`. Solana devnet confirmations typically take 1–3 seconds.
|
|
175
224
|
|
|
176
|
-
**402 not handled**
|
|
225
|
+
**402 not handled** - Ensure `mpp.charge()` middleware is placed before the route handler on the server.
|
|
177
226
|
|
|
178
227
|
---
|
|
179
228
|
|
package/dist/index.d.mts
CHANGED
|
@@ -10,15 +10,15 @@ interface PaymentStep {
|
|
|
10
10
|
interface TestClientConfig {
|
|
11
11
|
/**
|
|
12
12
|
* Solana network to connect to.
|
|
13
|
-
* - `"devnet"` (default)
|
|
14
|
-
* - `"testnet"`
|
|
15
|
-
* - `"mainnet"`
|
|
13
|
+
* - `"devnet"` (default) - Free SOL airdrop, fast confirmation.
|
|
14
|
+
* - `"testnet"` - Solana's testnet. Also has free airdrop.
|
|
15
|
+
* - `"mainnet"` - Real SOL. Requires a pre-funded `secretKey`.
|
|
16
16
|
*/
|
|
17
17
|
network?: SolanaNetwork;
|
|
18
18
|
/**
|
|
19
19
|
* Pre-funded Solana keypair secret key (32 or 64 bytes).
|
|
20
|
-
* - On `devnet`/`testnet`: optional
|
|
21
|
-
* - On `mainnet`: **required**
|
|
20
|
+
* - On `devnet`/`testnet`: optional - wallet is auto-funded via airdrop.
|
|
21
|
+
* - On `mainnet`: **required** - no airdrop available.
|
|
22
22
|
*/
|
|
23
23
|
secretKey?: Uint8Array;
|
|
24
24
|
/** Lifecycle event callback for observing the payment flow. */
|
|
@@ -46,13 +46,13 @@ interface TestClient {
|
|
|
46
46
|
*
|
|
47
47
|
* @example
|
|
48
48
|
* ```ts
|
|
49
|
-
* // devnet (default)
|
|
49
|
+
* // devnet (default) - zero config
|
|
50
50
|
* const client = await createTestClient();
|
|
51
51
|
*
|
|
52
52
|
* // testnet
|
|
53
53
|
* const client = await createTestClient({ network: "testnet" });
|
|
54
54
|
*
|
|
55
|
-
* // mainnet
|
|
55
|
+
* // mainnet - must provide pre-funded wallet
|
|
56
56
|
* const client = await createTestClient({
|
|
57
57
|
* network: "mainnet",
|
|
58
58
|
* secretKey: loadKeypairFromFile("./wallet.json").secretKey,
|
|
@@ -108,9 +108,9 @@ interface MppServer {
|
|
|
108
108
|
interface TestServerConfig {
|
|
109
109
|
/**
|
|
110
110
|
* Solana network to connect to.
|
|
111
|
-
* - `"devnet"` (default)
|
|
112
|
-
* - `"testnet"`
|
|
113
|
-
* - `"mainnet"`
|
|
111
|
+
* - `"devnet"` (default) - Solana devnet.
|
|
112
|
+
* - `"testnet"` - Solana testnet.
|
|
113
|
+
* - `"mainnet"` - Solana mainnet (real SOL).
|
|
114
114
|
*/
|
|
115
115
|
network?: SolanaNetwork;
|
|
116
116
|
/** Server wallet keypair secret key. Auto-generated if omitted. */
|
|
@@ -127,7 +127,7 @@ interface TestServerConfig {
|
|
|
127
127
|
* Create a Solana MPP-enabled Express server.
|
|
128
128
|
*
|
|
129
129
|
* Handles the HTTP 402 payment flow and verifies SOL transfers on-chain.
|
|
130
|
-
* No config needed
|
|
130
|
+
* No config needed - auto-generates a server wallet.
|
|
131
131
|
*
|
|
132
132
|
* @example
|
|
133
133
|
* ```ts
|
package/dist/index.d.ts
CHANGED
|
@@ -10,15 +10,15 @@ interface PaymentStep {
|
|
|
10
10
|
interface TestClientConfig {
|
|
11
11
|
/**
|
|
12
12
|
* Solana network to connect to.
|
|
13
|
-
* - `"devnet"` (default)
|
|
14
|
-
* - `"testnet"`
|
|
15
|
-
* - `"mainnet"`
|
|
13
|
+
* - `"devnet"` (default) - Free SOL airdrop, fast confirmation.
|
|
14
|
+
* - `"testnet"` - Solana's testnet. Also has free airdrop.
|
|
15
|
+
* - `"mainnet"` - Real SOL. Requires a pre-funded `secretKey`.
|
|
16
16
|
*/
|
|
17
17
|
network?: SolanaNetwork;
|
|
18
18
|
/**
|
|
19
19
|
* Pre-funded Solana keypair secret key (32 or 64 bytes).
|
|
20
|
-
* - On `devnet`/`testnet`: optional
|
|
21
|
-
* - On `mainnet`: **required**
|
|
20
|
+
* - On `devnet`/`testnet`: optional - wallet is auto-funded via airdrop.
|
|
21
|
+
* - On `mainnet`: **required** - no airdrop available.
|
|
22
22
|
*/
|
|
23
23
|
secretKey?: Uint8Array;
|
|
24
24
|
/** Lifecycle event callback for observing the payment flow. */
|
|
@@ -46,13 +46,13 @@ interface TestClient {
|
|
|
46
46
|
*
|
|
47
47
|
* @example
|
|
48
48
|
* ```ts
|
|
49
|
-
* // devnet (default)
|
|
49
|
+
* // devnet (default) - zero config
|
|
50
50
|
* const client = await createTestClient();
|
|
51
51
|
*
|
|
52
52
|
* // testnet
|
|
53
53
|
* const client = await createTestClient({ network: "testnet" });
|
|
54
54
|
*
|
|
55
|
-
* // mainnet
|
|
55
|
+
* // mainnet - must provide pre-funded wallet
|
|
56
56
|
* const client = await createTestClient({
|
|
57
57
|
* network: "mainnet",
|
|
58
58
|
* secretKey: loadKeypairFromFile("./wallet.json").secretKey,
|
|
@@ -108,9 +108,9 @@ interface MppServer {
|
|
|
108
108
|
interface TestServerConfig {
|
|
109
109
|
/**
|
|
110
110
|
* Solana network to connect to.
|
|
111
|
-
* - `"devnet"` (default)
|
|
112
|
-
* - `"testnet"`
|
|
113
|
-
* - `"mainnet"`
|
|
111
|
+
* - `"devnet"` (default) - Solana devnet.
|
|
112
|
+
* - `"testnet"` - Solana testnet.
|
|
113
|
+
* - `"mainnet"` - Solana mainnet (real SOL).
|
|
114
114
|
*/
|
|
115
115
|
network?: SolanaNetwork;
|
|
116
116
|
/** Server wallet keypair secret key. Auto-generated if omitted. */
|
|
@@ -127,7 +127,7 @@ interface TestServerConfig {
|
|
|
127
127
|
* Create a Solana MPP-enabled Express server.
|
|
128
128
|
*
|
|
129
129
|
* Handles the HTTP 402 payment flow and verifies SOL transfers on-chain.
|
|
130
|
-
* No config needed
|
|
130
|
+
* No config needed - auto-generates a server wallet.
|
|
131
131
|
*
|
|
132
132
|
* @example
|
|
133
133
|
* ```ts
|
package/package.json
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "mpp-test-sdk",
|
|
3
|
-
"version": "1.1.
|
|
4
|
-
"description": "Test pay-per-request APIs on Solana devnet. Auto-creates wallets, airdrops SOL, handles 402 MPP payments
|
|
3
|
+
"version": "1.1.2",
|
|
4
|
+
"description": "Test pay-per-request APIs on Solana devnet. Auto-creates wallets, airdrops SOL, handles 402 MPP payments - zero setup required.",
|
|
5
5
|
"main": "dist/index.js",
|
|
6
6
|
"module": "dist/index.mjs",
|
|
7
7
|
"types": "dist/index.d.ts",
|