powertools-x402 0.1.0 → 0.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 CHANGED
@@ -16,9 +16,11 @@ Requires Node 18+. `@aws-lambda-powertools/event-handler` is a peer dependency,
16
16
 
17
17
  - No payment attached? The caller gets a 402 with signed payment requirements
18
18
  - Payment attached? It gets verified with a facilitator before your handler runs
19
- - Settlement happens after your handler succeeds. If it throws or returns an error status, the caller is never charged
19
+ - With the default exact payment flow, settlement happens after your handler succeeds. If the handler throws or returns an error status, settlement does not occur
20
20
  - Verified payment details (payer, amount, network) are available in the request store
21
21
 
22
+ One contract to understand before you ship: in the default exact flow, verify happens before your handler and settlement happens after. That's the right fit for work that can safely run before the money moves, like inference, generation, and data retrieval. It is not a transaction around your business logic. If your handler performs an irreversible side effect and settlement fails afterward, the work already happened. Keep that kind of work reversible or reconcilable, or handle it with your own orchestration.
23
+
22
24
  ## Usage
23
25
 
24
26
  ### Charge for a route
@@ -50,6 +52,8 @@ app.post(
50
52
  export const handler = (event: unknown, context: Context) => app.resolve(event, context);
51
53
  ```
52
54
 
55
+ Dollar prices settle in USDC on the route's network. `'$0.01'` on Base Sepolia charges 0.01 USDC.
56
+
53
57
  ### Read payment details in the handler
54
58
 
55
59
  ```ts
@@ -74,22 +78,50 @@ const x402 = createX402({
74
78
 
75
79
  This emits `PaymentRequired`, `PaymentRejected`, `PaymentVerified`, `PaymentSettled`, `PaymentCancelled`, and `SettlementFailed` counts under the `x402` namespace. Metrics publish immediately, so there's no `publishStoredMetrics()` call to remember. Pass your own `metrics` instance if you want a different namespace.
76
80
 
77
- ### Use an authenticated facilitator
81
+ ### Settle on mainnet with the Coinbase facilitator
82
+
83
+ The free `x402.org` facilitator is testnet only. Mainnet payments settle through the [Coinbase Developer Platform](https://portal.cdp.coinbase.com/) facilitator:
84
+
85
+ ```bash
86
+ npm install @coinbase/x402
87
+ ```
78
88
 
79
89
  ```ts
90
+ import { coinbaseFacilitator } from 'powertools-x402/coinbase';
91
+
80
92
  const x402 = createX402({
81
- facilitator: {
82
- url: 'https://facilitator.example.com',
83
- createAuthHeaders: async () => {
84
- const headers = { Authorization: `Bearer ${token}` };
85
- return { verify: headers, settle: headers, supported: headers };
86
- },
87
- },
93
+ facilitator: coinbaseFacilitator(), // reads CDP_API_KEY_ID and CDP_API_KEY_SECRET
88
94
  network: 'eip155:8453', // Base mainnet
89
95
  payTo: process.env.PAY_TO!,
90
96
  });
91
97
  ```
92
98
 
99
+ Using a different facilitator? Pass `{ url, createAuthHeaders }` straight through the `facilitator` option.
100
+
101
+ ### Settle into your Stripe balance
102
+
103
+ Stripe supports x402 through [machine payments](https://docs.stripe.com/payments/machine/x402). Payments settle through the Coinbase facilitator into a Stripe crypto deposit address, and each settled payment is recorded as a Stripe PaymentIntent. Funds land in your Stripe balance next to your card payments.
104
+
105
+ ```bash
106
+ npm install stripe @coinbase/x402
107
+ ```
108
+
109
+ ```ts
110
+ import { createStripeX402 } from 'powertools-x402/stripe';
111
+
112
+ // Reads STRIPE_SECRET_KEY, STRIPE_DEPOSIT_ADDRESS, CDP_API_KEY_ID, and CDP_API_KEY_SECRET
113
+ const x402 = createStripeX402();
114
+
115
+ app.post('/paid', [x402.paid({ price: '$0.01' })], async () => ({ foo: 'bar' }));
116
+ ```
117
+
118
+ Prefer explicit config? Pass `depositAddress`, `stripeSecretKey` (or your own `stripe` client), and `cdpApiKeyId`/`cdpApiKeySecret` directly. Every other `createX402` option works here too.
119
+
120
+ A couple things to know:
121
+
122
+ - Create your deposit address once with `POST /v1/crypto/deposit_addresses` and store it. Keep that call off your request path.
123
+ - This uses Stripe's `2026-05-27.preview` API version, and you'll need the Stablecoins and Crypto payment method approved on your Stripe account.
124
+
93
125
  ### Accept multiple payment options on one route
94
126
 
95
127
  ```ts
@@ -103,6 +135,22 @@ x402.paid({
103
135
 
104
136
  Want to take payments on non-EVM networks? Register additional schemes with the `schemes` option on `createX402`.
105
137
 
138
+ ### Price in a specific token
139
+
140
+ Dollar strings are shorthand for USDC. To pin the exact asset yourself, pass atomic units and the token address:
141
+
142
+ ```ts
143
+ x402.paid({
144
+ price: {
145
+ amount: '10000', // atomic units, USDC has 6 decimals
146
+ asset: '0x036CbD53842c5426634e7929541eC2318f3dCF7e', // USDC on Base Sepolia
147
+ extra: { name: 'USDC', version: '2' }, // EIP-712 domain the payer signs against
148
+ },
149
+ });
150
+ ```
151
+
152
+ The same shape works for any EIP-3009 token. Set `extra` to the token's EIP-712 domain.
153
+
106
154
  ### Let some callers through free
107
155
 
108
156
  ```ts
@@ -129,23 +177,25 @@ x402.paid({
129
177
 
130
178
  ### Test your routes without a network
131
179
 
132
- The `facilitator` option takes any object with `verify`, `settle`, and `getSupported`, so your tests never touch the network:
180
+ Import from `powertools-x402/testing` and your tests never touch the network. `stubFacilitator()` approves every payment, and `testPayer()` signs real payments with a throwaway account so you can test the paid path end to end:
133
181
 
134
182
  ```ts
135
- const facilitator = {
136
- getSupported: async () => ({
137
- kinds: [{ x402Version: 2, scheme: 'exact', network: 'eip155:84532' }],
138
- extensions: [],
139
- signers: {},
140
- }),
141
- verify: async () => ({ isValid: true, payer: '0xPayer' }),
142
- settle: async () => ({ success: true, transaction: '0xTx', network: 'eip155:84532' }),
143
- };
183
+ import { stubFacilitator, testPayer } from 'powertools-x402/testing';
184
+
185
+ const facilitator = stubFacilitator(); // defaults to Base Sepolia
186
+ const x402 = createX402({
187
+ facilitator,
188
+ network: 'eip155:84532',
189
+ payTo: '0x209693Bc6afc0C5328bA36FaF03C514EF312287C',
190
+ });
144
191
 
145
- const x402 = createX402({ facilitator, network: 'eip155:84532', payTo: '0xYou' });
192
+ // 402 challenge, then pay it and assert on your handler's behavior
193
+ const payer = testPayer();
194
+ const challenge = await app.resolve(event('POST', '/paid'), context);
195
+ const paid = await app.resolve(event('POST', '/paid', await payer.payFor(challenge)), context);
146
196
  ```
147
197
 
148
- Drive your router with API Gateway events through `app.resolve(event, context)`. Check out [test/middleware.test.ts](test/middleware.test.ts) for full round trips, including client-side payment signing.
198
+ Spy on `facilitator.verify` or `facilitator.settle` to assert calls or force failures. `payFor` also accepts fetch `Response` objects. And if you'd rather roll your own facilitator stub, it's any object with `verify`, `settle`, and `getSupported`.
149
199
 
150
200
  ### Pay for a request (client side)
151
201
 
@@ -178,6 +228,7 @@ Need testnet USDC? Grab some from the [Circle faucet](https://faucet.circle.com/
178
228
 
179
229
  - [example/handler.ts](example/handler.ts) - lambdalith with free and paid routes
180
230
  - [example/client.ts](example/client.ts) - paying client, step by step
231
+ - [example/stripe.ts](example/stripe.ts) - settle x402 payments into your Stripe balance
181
232
  - [example/template.yaml](example/template.yaml) - SAM deploy (esbuild, ESM, HTTP API)
182
233
 
183
234
  ## License
@@ -0,0 +1,211 @@
1
+ // src/index.ts
2
+ import { Metrics } from "@aws-lambda-powertools/metrics";
3
+ import {
4
+ HTTPFacilitatorClient,
5
+ x402HTTPResourceServer,
6
+ x402ResourceServer
7
+ } from "@x402/core/server";
8
+ import { registerExactEvmScheme } from "@x402/evm/exact/server";
9
+
10
+ // src/adapter.ts
11
+ var PowertoolsAdapter = class {
12
+ constructor(request) {
13
+ this.request = request;
14
+ }
15
+ request;
16
+ getHeader(name) {
17
+ return this.request.headers.get(name) ?? void 0;
18
+ }
19
+ getMethod() {
20
+ return this.request.method;
21
+ }
22
+ getPath() {
23
+ return new URL(this.request.url).pathname;
24
+ }
25
+ getUrl() {
26
+ return this.request.url;
27
+ }
28
+ getAcceptHeader() {
29
+ return this.request.headers.get("accept") ?? "";
30
+ }
31
+ getUserAgent() {
32
+ return this.request.headers.get("user-agent") ?? "";
33
+ }
34
+ getQueryParams() {
35
+ const params = new URL(this.request.url).searchParams;
36
+ const result = {};
37
+ for (const key of new Set(params.keys())) {
38
+ const values = params.getAll(key);
39
+ result[key] = values.length === 1 ? values[0] : values;
40
+ }
41
+ return result;
42
+ }
43
+ getQueryParam(name) {
44
+ const values = new URL(this.request.url).searchParams.getAll(name);
45
+ if (values.length === 0) return void 0;
46
+ return values.length === 1 ? values[0] : values;
47
+ }
48
+ async getBody() {
49
+ try {
50
+ return await this.request.clone().json();
51
+ } catch {
52
+ return void 0;
53
+ }
54
+ }
55
+ };
56
+
57
+ // src/facilitator.ts
58
+ var CachingFacilitatorClient = class {
59
+ constructor(client) {
60
+ this.client = client;
61
+ }
62
+ client;
63
+ #supported;
64
+ verify(payload, requirements) {
65
+ return this.client.verify(payload, requirements);
66
+ }
67
+ settle(payload, requirements) {
68
+ return this.client.settle(payload, requirements);
69
+ }
70
+ getSupported() {
71
+ this.#supported ??= this.client.getSupported().catch((error) => {
72
+ this.#supported = void 0;
73
+ throw error;
74
+ });
75
+ return this.#supported;
76
+ }
77
+ };
78
+
79
+ // src/index.ts
80
+ var toFacilitatorClient = (facilitator) => {
81
+ if (typeof facilitator === "string") return new HTTPFacilitatorClient({ url: facilitator });
82
+ if ("getSupported" in facilitator) return facilitator;
83
+ return new HTTPFacilitatorClient(facilitator);
84
+ };
85
+ var toResponse = ({ status, headers, body, isHtml }) => new Response(isHtml ? String(body ?? "") : JSON.stringify(body ?? {}), { status, headers });
86
+ function createX402(options) {
87
+ const facilitator = new CachingFacilitatorClient(toFacilitatorClient(options.facilitator));
88
+ const resourceServer = new x402ResourceServer(facilitator);
89
+ for (const register of options.schemes ?? [registerExactEvmScheme]) {
90
+ register(resourceServer);
91
+ }
92
+ const { logger } = options;
93
+ const metrics = options.enableMetrics ? options.metrics ?? new Metrics({ namespace: "x402" }) : void 0;
94
+ const count = (name) => metrics && (metrics.singleMetric?.() ?? metrics).addMetric(name, "Count", 1);
95
+ const payers = /* @__PURE__ */ new WeakMap();
96
+ resourceServer.onAfterVerify(async ({ paymentPayload, result }) => {
97
+ if (result.payer) payers.set(paymentPayload, result.payer);
98
+ });
99
+ function paid(route) {
100
+ const { price, accepts, onProtectedRequest, ...routeConfig } = route;
101
+ if (accepts === void 0 && price === void 0) {
102
+ throw new Error("paid() requires a price or an accepts configuration");
103
+ }
104
+ const httpServer = new x402HTTPResourceServer(resourceServer, {
105
+ ...routeConfig,
106
+ mimeType: routeConfig.mimeType ?? "application/json",
107
+ accepts: accepts ?? {
108
+ scheme: "exact",
109
+ network: options.network,
110
+ payTo: options.payTo,
111
+ price
112
+ }
113
+ });
114
+ if (onProtectedRequest) httpServer.onProtectedRequest(onProtectedRequest);
115
+ let ready;
116
+ const initialize = () => ready ??= httpServer.initialize().catch((error) => {
117
+ ready = void 0;
118
+ throw error;
119
+ });
120
+ return async ({ reqCtx, next }) => {
121
+ await initialize();
122
+ const adapter = new PowertoolsAdapter(reqCtx.req);
123
+ const context = {
124
+ adapter,
125
+ path: adapter.getPath(),
126
+ method: adapter.getMethod()
127
+ };
128
+ const result = await httpServer.processHTTPRequest(context, options.paywall);
129
+ if (result.type === "no-payment-required") {
130
+ await next();
131
+ return;
132
+ }
133
+ if (result.type === "payment-error") {
134
+ count(adapter.getHeader("payment-signature") ? "PaymentRejected" : "PaymentRequired");
135
+ logger?.debug("x402 payment not accepted", { status: result.response.status });
136
+ reqCtx.res = toResponse(result.response);
137
+ return;
138
+ }
139
+ const {
140
+ cancellationDispatcher,
141
+ beforeHandlerSettlement,
142
+ paymentPayload,
143
+ paymentRequirements,
144
+ declaredExtensions
145
+ } = result;
146
+ reqCtx.set("payment", {
147
+ network: paymentRequirements.network,
148
+ scheme: paymentRequirements.scheme,
149
+ asset: paymentRequirements.asset,
150
+ amount: paymentRequirements.amount,
151
+ payer: payers.get(paymentPayload)
152
+ });
153
+ count("PaymentVerified");
154
+ try {
155
+ await next();
156
+ } catch (error) {
157
+ await cancellationDispatcher.cancel({ reason: "handler_threw", error });
158
+ count("PaymentCancelled");
159
+ logger?.warn("x402 payment cancelled: handler threw", { path: context.path });
160
+ throw error;
161
+ }
162
+ if (reqCtx.res.status >= 400) {
163
+ await cancellationDispatcher.cancel({
164
+ reason: "handler_failed",
165
+ responseStatus: reqCtx.res.status
166
+ });
167
+ count("PaymentCancelled");
168
+ logger?.warn("x402 payment cancelled: handler failed", {
169
+ path: context.path,
170
+ status: reqCtx.res.status
171
+ });
172
+ return;
173
+ }
174
+ const settlement = await httpServer.processSettlement(
175
+ paymentPayload,
176
+ paymentRequirements,
177
+ declaredExtensions,
178
+ {
179
+ request: context,
180
+ responseBody: Buffer.from(await reqCtx.res.clone().arrayBuffer()),
181
+ responseHeaders: Object.fromEntries(reqCtx.res.headers.entries())
182
+ },
183
+ void 0,
184
+ beforeHandlerSettlement
185
+ );
186
+ if (!settlement.success) {
187
+ count("SettlementFailed");
188
+ logger?.error("x402 settlement failed", {
189
+ path: context.path,
190
+ errorReason: settlement.errorReason
191
+ });
192
+ reqCtx.res = toResponse(settlement.response);
193
+ return;
194
+ }
195
+ count("PaymentSettled");
196
+ logger?.debug("x402 payment settled", { path: context.path, transaction: settlement.transaction });
197
+ for (const [name, value] of Object.entries(settlement.headers)) {
198
+ reqCtx.res.headers.set(name, value);
199
+ }
200
+ const cacheControl = reqCtx.res.headers.get("cache-control");
201
+ reqCtx.res.headers.set("cache-control", cacheControl ? `${cacheControl}, private` : "private");
202
+ };
203
+ }
204
+ return { paid, resourceServer };
205
+ }
206
+
207
+ export {
208
+ PowertoolsAdapter,
209
+ CachingFacilitatorClient,
210
+ createX402
211
+ };
@@ -0,0 +1,7 @@
1
+ // src/coinbase.ts
2
+ import { createFacilitatorConfig } from "@coinbase/x402";
3
+ var coinbaseFacilitator = (apiKeyId, apiKeySecret) => createFacilitatorConfig(apiKeyId, apiKeySecret);
4
+
5
+ export {
6
+ coinbaseFacilitator
7
+ };
@@ -0,0 +1,31 @@
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/coinbase.ts
21
+ var coinbase_exports = {};
22
+ __export(coinbase_exports, {
23
+ coinbaseFacilitator: () => coinbaseFacilitator
24
+ });
25
+ module.exports = __toCommonJS(coinbase_exports);
26
+ var import_x402 = require("@coinbase/x402");
27
+ var coinbaseFacilitator = (apiKeyId, apiKeySecret) => (0, import_x402.createFacilitatorConfig)(apiKeyId, apiKeySecret);
28
+ // Annotate the CommonJS export names for ESM import in node:
29
+ 0 && (module.exports = {
30
+ coinbaseFacilitator
31
+ });
@@ -0,0 +1,9 @@
1
+ import { FacilitatorConfig } from '@x402/core/server';
2
+
3
+ /**
4
+ * Coinbase Developer Platform facilitator for mainnet settlement.
5
+ * Falls back to CDP_API_KEY_ID and CDP_API_KEY_SECRET when keys are omitted.
6
+ */
7
+ declare const coinbaseFacilitator: (apiKeyId?: string, apiKeySecret?: string) => FacilitatorConfig;
8
+
9
+ export { coinbaseFacilitator };
@@ -0,0 +1,9 @@
1
+ import { FacilitatorConfig } from '@x402/core/server';
2
+
3
+ /**
4
+ * Coinbase Developer Platform facilitator for mainnet settlement.
5
+ * Falls back to CDP_API_KEY_ID and CDP_API_KEY_SECRET when keys are omitted.
6
+ */
7
+ declare const coinbaseFacilitator: (apiKeyId?: string, apiKeySecret?: string) => FacilitatorConfig;
8
+
9
+ export { coinbaseFacilitator };
@@ -0,0 +1,6 @@
1
+ import {
2
+ coinbaseFacilitator
3
+ } from "./chunk-FLK2T35N.js";
4
+ export {
5
+ coinbaseFacilitator
6
+ };
package/dist/index.js CHANGED
@@ -1,208 +1,8 @@
1
- // src/index.ts
2
- import { Metrics } from "@aws-lambda-powertools/metrics";
3
1
  import {
4
- HTTPFacilitatorClient,
5
- x402HTTPResourceServer,
6
- x402ResourceServer
7
- } from "@x402/core/server";
8
- import { registerExactEvmScheme } from "@x402/evm/exact/server";
9
-
10
- // src/adapter.ts
11
- var PowertoolsAdapter = class {
12
- constructor(request) {
13
- this.request = request;
14
- }
15
- request;
16
- getHeader(name) {
17
- return this.request.headers.get(name) ?? void 0;
18
- }
19
- getMethod() {
20
- return this.request.method;
21
- }
22
- getPath() {
23
- return new URL(this.request.url).pathname;
24
- }
25
- getUrl() {
26
- return this.request.url;
27
- }
28
- getAcceptHeader() {
29
- return this.request.headers.get("accept") ?? "";
30
- }
31
- getUserAgent() {
32
- return this.request.headers.get("user-agent") ?? "";
33
- }
34
- getQueryParams() {
35
- const params = new URL(this.request.url).searchParams;
36
- const result = {};
37
- for (const key of new Set(params.keys())) {
38
- const values = params.getAll(key);
39
- result[key] = values.length === 1 ? values[0] : values;
40
- }
41
- return result;
42
- }
43
- getQueryParam(name) {
44
- const values = new URL(this.request.url).searchParams.getAll(name);
45
- if (values.length === 0) return void 0;
46
- return values.length === 1 ? values[0] : values;
47
- }
48
- async getBody() {
49
- try {
50
- return await this.request.clone().json();
51
- } catch {
52
- return void 0;
53
- }
54
- }
55
- };
56
-
57
- // src/facilitator.ts
58
- var CachingFacilitatorClient = class {
59
- constructor(client) {
60
- this.client = client;
61
- }
62
- client;
63
- #supported;
64
- verify(payload, requirements) {
65
- return this.client.verify(payload, requirements);
66
- }
67
- settle(payload, requirements) {
68
- return this.client.settle(payload, requirements);
69
- }
70
- getSupported() {
71
- this.#supported ??= this.client.getSupported().catch((error) => {
72
- this.#supported = void 0;
73
- throw error;
74
- });
75
- return this.#supported;
76
- }
77
- };
78
-
79
- // src/index.ts
80
- var toFacilitatorClient = (facilitator) => {
81
- if (typeof facilitator === "string") return new HTTPFacilitatorClient({ url: facilitator });
82
- if ("getSupported" in facilitator) return facilitator;
83
- return new HTTPFacilitatorClient(facilitator);
84
- };
85
- var toResponse = ({ status, headers, body, isHtml }) => new Response(isHtml ? String(body ?? "") : JSON.stringify(body ?? {}), { status, headers });
86
- function createX402(options) {
87
- const facilitator = new CachingFacilitatorClient(toFacilitatorClient(options.facilitator));
88
- const resourceServer = new x402ResourceServer(facilitator);
89
- for (const register of options.schemes ?? [registerExactEvmScheme]) {
90
- register(resourceServer);
91
- }
92
- const { logger } = options;
93
- const metrics = options.enableMetrics ? options.metrics ?? new Metrics({ namespace: "x402" }) : void 0;
94
- const count = (name) => metrics && (metrics.singleMetric?.() ?? metrics).addMetric(name, "Count", 1);
95
- const payers = /* @__PURE__ */ new WeakMap();
96
- resourceServer.onAfterVerify(async ({ paymentPayload, result }) => {
97
- if (result.payer) payers.set(paymentPayload, result.payer);
98
- });
99
- function paid(route) {
100
- const { price, accepts, onProtectedRequest, ...routeConfig } = route;
101
- if (accepts === void 0 && price === void 0) {
102
- throw new Error("paid() requires a price or an accepts configuration");
103
- }
104
- const httpServer = new x402HTTPResourceServer(resourceServer, {
105
- ...routeConfig,
106
- mimeType: routeConfig.mimeType ?? "application/json",
107
- accepts: accepts ?? {
108
- scheme: "exact",
109
- network: options.network,
110
- payTo: options.payTo,
111
- price
112
- }
113
- });
114
- if (onProtectedRequest) httpServer.onProtectedRequest(onProtectedRequest);
115
- let ready;
116
- const initialize = () => ready ??= httpServer.initialize().catch((error) => {
117
- ready = void 0;
118
- throw error;
119
- });
120
- return async ({ reqCtx, next }) => {
121
- await initialize();
122
- const adapter = new PowertoolsAdapter(reqCtx.req);
123
- const context = {
124
- adapter,
125
- path: adapter.getPath(),
126
- method: adapter.getMethod()
127
- };
128
- const result = await httpServer.processHTTPRequest(context, options.paywall);
129
- if (result.type === "no-payment-required") {
130
- await next();
131
- return;
132
- }
133
- if (result.type === "payment-error") {
134
- count(adapter.getHeader("payment-signature") ? "PaymentRejected" : "PaymentRequired");
135
- logger?.debug("x402 payment not accepted", { status: result.response.status });
136
- reqCtx.res = toResponse(result.response);
137
- return;
138
- }
139
- const {
140
- cancellationDispatcher,
141
- beforeHandlerSettlement,
142
- paymentPayload,
143
- paymentRequirements,
144
- declaredExtensions
145
- } = result;
146
- reqCtx.set("payment", {
147
- network: paymentRequirements.network,
148
- scheme: paymentRequirements.scheme,
149
- asset: paymentRequirements.asset,
150
- amount: paymentRequirements.amount,
151
- payer: payers.get(paymentPayload)
152
- });
153
- count("PaymentVerified");
154
- try {
155
- await next();
156
- } catch (error) {
157
- await cancellationDispatcher.cancel({ reason: "handler_threw", error });
158
- count("PaymentCancelled");
159
- logger?.warn("x402 payment cancelled: handler threw", { path: context.path });
160
- throw error;
161
- }
162
- if (reqCtx.res.status >= 400) {
163
- await cancellationDispatcher.cancel({
164
- reason: "handler_failed",
165
- responseStatus: reqCtx.res.status
166
- });
167
- count("PaymentCancelled");
168
- logger?.warn("x402 payment cancelled: handler failed", {
169
- path: context.path,
170
- status: reqCtx.res.status
171
- });
172
- return;
173
- }
174
- const settlement = await httpServer.processSettlement(
175
- paymentPayload,
176
- paymentRequirements,
177
- declaredExtensions,
178
- {
179
- request: context,
180
- responseBody: Buffer.from(await reqCtx.res.clone().arrayBuffer()),
181
- responseHeaders: Object.fromEntries(reqCtx.res.headers.entries())
182
- },
183
- void 0,
184
- beforeHandlerSettlement
185
- );
186
- if (!settlement.success) {
187
- count("SettlementFailed");
188
- logger?.error("x402 settlement failed", {
189
- path: context.path,
190
- errorReason: settlement.errorReason
191
- });
192
- reqCtx.res = toResponse(settlement.response);
193
- return;
194
- }
195
- count("PaymentSettled");
196
- logger?.debug("x402 payment settled", { path: context.path, transaction: settlement.transaction });
197
- for (const [name, value] of Object.entries(settlement.headers)) {
198
- reqCtx.res.headers.set(name, value);
199
- }
200
- const cacheControl = reqCtx.res.headers.get("cache-control");
201
- reqCtx.res.headers.set("cache-control", cacheControl ? `${cacheControl}, private` : "private");
202
- };
203
- }
204
- return { paid, resourceServer };
205
- }
2
+ CachingFacilitatorClient,
3
+ PowertoolsAdapter,
4
+ createX402
5
+ } from "./chunk-D46V2DLG.js";
206
6
  export {
207
7
  CachingFacilitatorClient,
208
8
  PowertoolsAdapter,