powertools-x402 0.1.1 → 0.2.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 +76 -54
- package/dist/chunk-4ZP7AJJC.js +231 -0
- package/dist/chunk-FLK2T35N.js +7 -0
- package/dist/coinbase.cjs +31 -0
- package/dist/coinbase.d.cts +9 -0
- package/dist/coinbase.d.ts +9 -0
- package/dist/coinbase.js +6 -0
- package/dist/index.cjs +21 -1
- package/dist/index.d.cts +11 -2
- package/dist/index.d.ts +11 -2
- package/dist/index.js +4 -204
- package/dist/stripe.cjs +336 -0
- package/dist/stripe.d.cts +38 -0
- package/dist/stripe.d.ts +38 -0
- package/dist/stripe.js +80 -0
- package/dist/testing.cjs +84 -0
- package/dist/testing.d.cts +29 -0
- package/dist/testing.d.ts +29 -0
- package/dist/testing.js +56 -0
- package/package.json +46 -2
package/dist/stripe.js
ADDED
|
@@ -0,0 +1,80 @@
|
|
|
1
|
+
import {
|
|
2
|
+
coinbaseFacilitator
|
|
3
|
+
} from "./chunk-FLK2T35N.js";
|
|
4
|
+
import {
|
|
5
|
+
createX402
|
|
6
|
+
} from "./chunk-4ZP7AJJC.js";
|
|
7
|
+
|
|
8
|
+
// src/stripe.ts
|
|
9
|
+
import Stripe from "stripe";
|
|
10
|
+
var BASE_MAINNET = "eip155:8453";
|
|
11
|
+
var BASE_USDC = "0x833589fCD6eDb6E08f4c7C32D4f71b54bdA02913";
|
|
12
|
+
var STRIPE_PREVIEW_API_VERSION = "2026-05-27.preview";
|
|
13
|
+
function createStripeX402(options = {}) {
|
|
14
|
+
const {
|
|
15
|
+
depositAddress = process.env.STRIPE_DEPOSIT_ADDRESS,
|
|
16
|
+
stripeSecretKey = process.env.STRIPE_SECRET_KEY,
|
|
17
|
+
stripe,
|
|
18
|
+
cdpApiKeyId,
|
|
19
|
+
cdpApiKeySecret,
|
|
20
|
+
facilitator,
|
|
21
|
+
...rest
|
|
22
|
+
} = options;
|
|
23
|
+
if (!depositAddress) {
|
|
24
|
+
throw new Error(
|
|
25
|
+
"createStripeX402 requires a depositAddress (or STRIPE_DEPOSIT_ADDRESS). Create one with POST /v1/crypto/deposit_addresses."
|
|
26
|
+
);
|
|
27
|
+
}
|
|
28
|
+
if (!stripe && !stripeSecretKey) {
|
|
29
|
+
throw new Error("createStripeX402 requires a stripe client or stripeSecretKey (or STRIPE_SECRET_KEY).");
|
|
30
|
+
}
|
|
31
|
+
const stripeClient = stripe ?? new Stripe(stripeSecretKey, {
|
|
32
|
+
apiVersion: STRIPE_PREVIEW_API_VERSION
|
|
33
|
+
});
|
|
34
|
+
const x402 = createX402({
|
|
35
|
+
...rest,
|
|
36
|
+
network: BASE_MAINNET,
|
|
37
|
+
facilitator: facilitator ?? coinbaseFacilitator(cdpApiKeyId, cdpApiKeySecret),
|
|
38
|
+
payTo: depositAddress
|
|
39
|
+
});
|
|
40
|
+
x402.resourceServer.onAfterSettle(async ({ result, requirements }) => {
|
|
41
|
+
if (!result.success || !result.transaction) return;
|
|
42
|
+
if (requirements.network !== BASE_MAINNET) return;
|
|
43
|
+
if (requirements.asset.toLowerCase() !== BASE_USDC.toLowerCase()) return;
|
|
44
|
+
const amountInCents = Math.round(Number(requirements.amount) / 1e4);
|
|
45
|
+
if (amountInCents < 1) return;
|
|
46
|
+
try {
|
|
47
|
+
await stripeClient.paymentIntents.create(
|
|
48
|
+
{
|
|
49
|
+
amount: amountInCents,
|
|
50
|
+
currency: "usd",
|
|
51
|
+
confirm: true,
|
|
52
|
+
payment_method_data: { type: "crypto" },
|
|
53
|
+
payment_method_types: ["crypto"],
|
|
54
|
+
payment_method_options: {
|
|
55
|
+
// transaction_verification ships in the 2026-05-27.preview API
|
|
56
|
+
// version and is not yet in stripe-node's stable types
|
|
57
|
+
crypto: {
|
|
58
|
+
mode: "transaction_verification",
|
|
59
|
+
transaction_verification_options: {
|
|
60
|
+
network: "base",
|
|
61
|
+
transaction_hash: result.transaction
|
|
62
|
+
}
|
|
63
|
+
}
|
|
64
|
+
}
|
|
65
|
+
},
|
|
66
|
+
{ idempotencyKey: result.transaction }
|
|
67
|
+
);
|
|
68
|
+
} catch (error) {
|
|
69
|
+
(rest.logger ?? console).error("stripe payment intent recording failed", {
|
|
70
|
+
transaction: result.transaction,
|
|
71
|
+
amountInCents,
|
|
72
|
+
error: error instanceof Error ? error.message : String(error)
|
|
73
|
+
});
|
|
74
|
+
}
|
|
75
|
+
});
|
|
76
|
+
return x402;
|
|
77
|
+
}
|
|
78
|
+
export {
|
|
79
|
+
createStripeX402
|
|
80
|
+
};
|
package/dist/testing.cjs
ADDED
|
@@ -0,0 +1,84 @@
|
|
|
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/testing.ts
|
|
21
|
+
var testing_exports = {};
|
|
22
|
+
__export(testing_exports, {
|
|
23
|
+
TEST_PAYER_ADDRESS: () => TEST_PAYER_ADDRESS,
|
|
24
|
+
TEST_TRANSACTION_HASH: () => TEST_TRANSACTION_HASH,
|
|
25
|
+
stubFacilitator: () => stubFacilitator,
|
|
26
|
+
testPayer: () => testPayer
|
|
27
|
+
});
|
|
28
|
+
module.exports = __toCommonJS(testing_exports);
|
|
29
|
+
var import_client = require("@x402/core/client");
|
|
30
|
+
var import_client2 = require("@x402/evm/exact/client");
|
|
31
|
+
var import_accounts = require("viem/accounts");
|
|
32
|
+
var TEST_PAYER_ADDRESS = "0x0000000000000000000000000000000000C0FFEE";
|
|
33
|
+
var TEST_TRANSACTION_HASH = `0x${"ab".repeat(32)}`;
|
|
34
|
+
function stubFacilitator(options = {}) {
|
|
35
|
+
const networks = [options.network ?? "eip155:84532"].flat();
|
|
36
|
+
const payer = options.payer ?? TEST_PAYER_ADDRESS;
|
|
37
|
+
return {
|
|
38
|
+
async getSupported() {
|
|
39
|
+
return {
|
|
40
|
+
kinds: networks.map((network) => ({ x402Version: 2, scheme: "exact", network })),
|
|
41
|
+
extensions: [],
|
|
42
|
+
signers: {}
|
|
43
|
+
};
|
|
44
|
+
},
|
|
45
|
+
async verify() {
|
|
46
|
+
return { isValid: true, payer, ...options.verify };
|
|
47
|
+
},
|
|
48
|
+
async settle() {
|
|
49
|
+
return {
|
|
50
|
+
success: true,
|
|
51
|
+
transaction: TEST_TRANSACTION_HASH,
|
|
52
|
+
network: networks[0],
|
|
53
|
+
payer,
|
|
54
|
+
...options.settle
|
|
55
|
+
};
|
|
56
|
+
}
|
|
57
|
+
};
|
|
58
|
+
}
|
|
59
|
+
var getHeaderFrom = (challenge) => (name) => {
|
|
60
|
+
if (challenge.headers instanceof Headers) return challenge.headers.get(name) ?? void 0;
|
|
61
|
+
const value = challenge.headers?.[name.toLowerCase()];
|
|
62
|
+
return value === void 0 ? void 0 : String(value);
|
|
63
|
+
};
|
|
64
|
+
function testPayer(privateKey) {
|
|
65
|
+
const account = (0, import_accounts.privateKeyToAccount)(privateKey ?? (0, import_accounts.generatePrivateKey)());
|
|
66
|
+
const client = new import_client.x402HTTPClient(
|
|
67
|
+
(0, import_client2.registerExactEvmScheme)(new import_client.x402Client(), { signer: account })
|
|
68
|
+
);
|
|
69
|
+
return {
|
|
70
|
+
address: account.address,
|
|
71
|
+
async payFor(challenge) {
|
|
72
|
+
const paymentRequired = client.getPaymentRequiredResponse(getHeaderFrom(challenge));
|
|
73
|
+
const payload = await client.createPaymentPayload(paymentRequired);
|
|
74
|
+
return client.encodePaymentSignatureHeader(payload);
|
|
75
|
+
}
|
|
76
|
+
};
|
|
77
|
+
}
|
|
78
|
+
// Annotate the CommonJS export names for ESM import in node:
|
|
79
|
+
0 && (module.exports = {
|
|
80
|
+
TEST_PAYER_ADDRESS,
|
|
81
|
+
TEST_TRANSACTION_HASH,
|
|
82
|
+
stubFacilitator,
|
|
83
|
+
testPayer
|
|
84
|
+
});
|
|
@@ -0,0 +1,29 @@
|
|
|
1
|
+
import { FacilitatorClient } from '@x402/core/server';
|
|
2
|
+
import { Network, VerifyResponse, SettleResponse } from '@x402/core/types';
|
|
3
|
+
|
|
4
|
+
declare const TEST_PAYER_ADDRESS = "0x0000000000000000000000000000000000C0FFEE";
|
|
5
|
+
declare const TEST_TRANSACTION_HASH: string;
|
|
6
|
+
interface StubFacilitatorOptions {
|
|
7
|
+
network?: Network | Network[];
|
|
8
|
+
payer?: string;
|
|
9
|
+
verify?: Partial<VerifyResponse>;
|
|
10
|
+
settle?: Partial<SettleResponse>;
|
|
11
|
+
}
|
|
12
|
+
/**
|
|
13
|
+
* In-memory facilitator that approves every payment. Spy on its methods or
|
|
14
|
+
* override verify/settle responses to exercise failure paths.
|
|
15
|
+
*/
|
|
16
|
+
declare function stubFacilitator(options?: StubFacilitatorOptions): FacilitatorClient;
|
|
17
|
+
type ChallengeLike = Response | {
|
|
18
|
+
headers?: Record<string, unknown>;
|
|
19
|
+
};
|
|
20
|
+
/**
|
|
21
|
+
* A payment client backed by a throwaway account. Feed it a 402 response and
|
|
22
|
+
* it returns the headers that make the retried request a valid paid request.
|
|
23
|
+
*/
|
|
24
|
+
declare function testPayer(privateKey?: `0x${string}`): {
|
|
25
|
+
address: `0x${string}`;
|
|
26
|
+
payFor(challenge: ChallengeLike): Promise<Record<string, string>>;
|
|
27
|
+
};
|
|
28
|
+
|
|
29
|
+
export { type StubFacilitatorOptions, TEST_PAYER_ADDRESS, TEST_TRANSACTION_HASH, stubFacilitator, testPayer };
|
|
@@ -0,0 +1,29 @@
|
|
|
1
|
+
import { FacilitatorClient } from '@x402/core/server';
|
|
2
|
+
import { Network, VerifyResponse, SettleResponse } from '@x402/core/types';
|
|
3
|
+
|
|
4
|
+
declare const TEST_PAYER_ADDRESS = "0x0000000000000000000000000000000000C0FFEE";
|
|
5
|
+
declare const TEST_TRANSACTION_HASH: string;
|
|
6
|
+
interface StubFacilitatorOptions {
|
|
7
|
+
network?: Network | Network[];
|
|
8
|
+
payer?: string;
|
|
9
|
+
verify?: Partial<VerifyResponse>;
|
|
10
|
+
settle?: Partial<SettleResponse>;
|
|
11
|
+
}
|
|
12
|
+
/**
|
|
13
|
+
* In-memory facilitator that approves every payment. Spy on its methods or
|
|
14
|
+
* override verify/settle responses to exercise failure paths.
|
|
15
|
+
*/
|
|
16
|
+
declare function stubFacilitator(options?: StubFacilitatorOptions): FacilitatorClient;
|
|
17
|
+
type ChallengeLike = Response | {
|
|
18
|
+
headers?: Record<string, unknown>;
|
|
19
|
+
};
|
|
20
|
+
/**
|
|
21
|
+
* A payment client backed by a throwaway account. Feed it a 402 response and
|
|
22
|
+
* it returns the headers that make the retried request a valid paid request.
|
|
23
|
+
*/
|
|
24
|
+
declare function testPayer(privateKey?: `0x${string}`): {
|
|
25
|
+
address: `0x${string}`;
|
|
26
|
+
payFor(challenge: ChallengeLike): Promise<Record<string, string>>;
|
|
27
|
+
};
|
|
28
|
+
|
|
29
|
+
export { type StubFacilitatorOptions, TEST_PAYER_ADDRESS, TEST_TRANSACTION_HASH, stubFacilitator, testPayer };
|
package/dist/testing.js
ADDED
|
@@ -0,0 +1,56 @@
|
|
|
1
|
+
// src/testing.ts
|
|
2
|
+
import { x402Client, x402HTTPClient } from "@x402/core/client";
|
|
3
|
+
import { registerExactEvmScheme } from "@x402/evm/exact/client";
|
|
4
|
+
import { generatePrivateKey, privateKeyToAccount } from "viem/accounts";
|
|
5
|
+
var TEST_PAYER_ADDRESS = "0x0000000000000000000000000000000000C0FFEE";
|
|
6
|
+
var TEST_TRANSACTION_HASH = `0x${"ab".repeat(32)}`;
|
|
7
|
+
function stubFacilitator(options = {}) {
|
|
8
|
+
const networks = [options.network ?? "eip155:84532"].flat();
|
|
9
|
+
const payer = options.payer ?? TEST_PAYER_ADDRESS;
|
|
10
|
+
return {
|
|
11
|
+
async getSupported() {
|
|
12
|
+
return {
|
|
13
|
+
kinds: networks.map((network) => ({ x402Version: 2, scheme: "exact", network })),
|
|
14
|
+
extensions: [],
|
|
15
|
+
signers: {}
|
|
16
|
+
};
|
|
17
|
+
},
|
|
18
|
+
async verify() {
|
|
19
|
+
return { isValid: true, payer, ...options.verify };
|
|
20
|
+
},
|
|
21
|
+
async settle() {
|
|
22
|
+
return {
|
|
23
|
+
success: true,
|
|
24
|
+
transaction: TEST_TRANSACTION_HASH,
|
|
25
|
+
network: networks[0],
|
|
26
|
+
payer,
|
|
27
|
+
...options.settle
|
|
28
|
+
};
|
|
29
|
+
}
|
|
30
|
+
};
|
|
31
|
+
}
|
|
32
|
+
var getHeaderFrom = (challenge) => (name) => {
|
|
33
|
+
if (challenge.headers instanceof Headers) return challenge.headers.get(name) ?? void 0;
|
|
34
|
+
const value = challenge.headers?.[name.toLowerCase()];
|
|
35
|
+
return value === void 0 ? void 0 : String(value);
|
|
36
|
+
};
|
|
37
|
+
function testPayer(privateKey) {
|
|
38
|
+
const account = privateKeyToAccount(privateKey ?? generatePrivateKey());
|
|
39
|
+
const client = new x402HTTPClient(
|
|
40
|
+
registerExactEvmScheme(new x402Client(), { signer: account })
|
|
41
|
+
);
|
|
42
|
+
return {
|
|
43
|
+
address: account.address,
|
|
44
|
+
async payFor(challenge) {
|
|
45
|
+
const paymentRequired = client.getPaymentRequiredResponse(getHeaderFrom(challenge));
|
|
46
|
+
const payload = await client.createPaymentPayload(paymentRequired);
|
|
47
|
+
return client.encodePaymentSignatureHeader(payload);
|
|
48
|
+
}
|
|
49
|
+
};
|
|
50
|
+
}
|
|
51
|
+
export {
|
|
52
|
+
TEST_PAYER_ADDRESS,
|
|
53
|
+
TEST_TRANSACTION_HASH,
|
|
54
|
+
stubFacilitator,
|
|
55
|
+
testPayer
|
|
56
|
+
};
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "powertools-x402",
|
|
3
|
-
"version": "0.
|
|
3
|
+
"version": "0.2.0",
|
|
4
4
|
"description": "x402 payment middleware for AWS Lambda Powertools Event Handler",
|
|
5
5
|
"license": "MIT",
|
|
6
6
|
"author": "Allen Helton <allenheltondev@gmail.com>",
|
|
@@ -30,6 +30,36 @@
|
|
|
30
30
|
"types": "./dist/index.d.cts",
|
|
31
31
|
"default": "./dist/index.cjs"
|
|
32
32
|
}
|
|
33
|
+
},
|
|
34
|
+
"./stripe": {
|
|
35
|
+
"import": {
|
|
36
|
+
"types": "./dist/stripe.d.ts",
|
|
37
|
+
"default": "./dist/stripe.js"
|
|
38
|
+
},
|
|
39
|
+
"require": {
|
|
40
|
+
"types": "./dist/stripe.d.cts",
|
|
41
|
+
"default": "./dist/stripe.cjs"
|
|
42
|
+
}
|
|
43
|
+
},
|
|
44
|
+
"./coinbase": {
|
|
45
|
+
"import": {
|
|
46
|
+
"types": "./dist/coinbase.d.ts",
|
|
47
|
+
"default": "./dist/coinbase.js"
|
|
48
|
+
},
|
|
49
|
+
"require": {
|
|
50
|
+
"types": "./dist/coinbase.d.cts",
|
|
51
|
+
"default": "./dist/coinbase.cjs"
|
|
52
|
+
}
|
|
53
|
+
},
|
|
54
|
+
"./testing": {
|
|
55
|
+
"import": {
|
|
56
|
+
"types": "./dist/testing.d.ts",
|
|
57
|
+
"default": "./dist/testing.js"
|
|
58
|
+
},
|
|
59
|
+
"require": {
|
|
60
|
+
"types": "./dist/testing.d.cts",
|
|
61
|
+
"default": "./dist/testing.cjs"
|
|
62
|
+
}
|
|
33
63
|
}
|
|
34
64
|
},
|
|
35
65
|
"files": [
|
|
@@ -52,7 +82,21 @@
|
|
|
52
82
|
"@x402/evm": "^2.23.0"
|
|
53
83
|
},
|
|
54
84
|
"peerDependencies": {
|
|
55
|
-
"@aws-lambda-powertools/event-handler": "^2.35.0"
|
|
85
|
+
"@aws-lambda-powertools/event-handler": "^2.35.0",
|
|
86
|
+
"@coinbase/x402": "^2.1.0",
|
|
87
|
+
"stripe": "^22.0.0",
|
|
88
|
+
"viem": "^2.0.0"
|
|
89
|
+
},
|
|
90
|
+
"peerDependenciesMeta": {
|
|
91
|
+
"@coinbase/x402": {
|
|
92
|
+
"optional": true
|
|
93
|
+
},
|
|
94
|
+
"stripe": {
|
|
95
|
+
"optional": true
|
|
96
|
+
},
|
|
97
|
+
"viem": {
|
|
98
|
+
"optional": true
|
|
99
|
+
}
|
|
56
100
|
},
|
|
57
101
|
"devDependencies": {
|
|
58
102
|
"@aws-lambda-powertools/event-handler": "^2.35.0",
|