@parallel-protocol/x402 0.6.0 → 0.7.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/dist/next.cjs CHANGED
@@ -1,6 +1,7 @@
1
1
  'use strict';
2
2
 
3
- var chunkK6QETMQA_cjs = require('./chunk-K6QETMQA.cjs');
3
+ var chunkPOU7EH3E_cjs = require('./chunk-POU7EH3E.cjs');
4
+ require('./chunk-JPMK5YBU.cjs');
4
5
  var server = require('next/server');
5
6
 
6
7
  // src/next/adapter.ts
@@ -21,11 +22,22 @@ var NextAdapter = class {
21
22
  getUrl() {
22
23
  return this.req.url;
23
24
  }
25
+ // Read from a clone: a request body is a stream that can be consumed once,
26
+ // and the handler still needs the original.
27
+ async getBody() {
28
+ if (!chunkPOU7EH3E_cjs.isJsonContentType(this.req.headers.get("content-type") ?? void 0))
29
+ return void 0;
30
+ try {
31
+ return await this.req.clone().json();
32
+ } catch {
33
+ return void 0;
34
+ }
35
+ }
24
36
  };
25
37
 
26
38
  // src/next/index.ts
27
39
  function withPayment(config, handler) {
28
- const gate = chunkK6QETMQA_cjs.createPaymentGate(config);
40
+ const gate = chunkPOU7EH3E_cjs.createPaymentGate(config);
29
41
  return async (req) => {
30
42
  const gateResult = await gate(new NextAdapter(req));
31
43
  if (gateResult.type === "pass") {
@@ -42,11 +54,11 @@ function withPayment(config, handler) {
42
54
  }
43
55
  let response;
44
56
  try {
45
- const outcome = await chunkK6QETMQA_cjs.raceTimeout(
57
+ const outcome = await chunkPOU7EH3E_cjs.raceTimeout(
46
58
  handler(req),
47
59
  gateResult.handlerTimeoutMs
48
60
  );
49
- if (outcome === chunkK6QETMQA_cjs.HANDLER_TIMEOUT) {
61
+ if (outcome === chunkPOU7EH3E_cjs.HANDLER_TIMEOUT) {
50
62
  return new server.NextResponse(null, { status: 504 });
51
63
  }
52
64
  response = outcome;
@@ -55,10 +67,10 @@ function withPayment(config, handler) {
55
67
  }
56
68
  let raw;
57
69
  if (gateResult.scheme === "upto") {
58
- raw = response.headers.get(chunkK6QETMQA_cjs.SETTLE_AMOUNT_HEADER) ?? void 0;
70
+ raw = response.headers.get(chunkPOU7EH3E_cjs.SETTLE_AMOUNT_HEADER) ?? void 0;
59
71
  if (raw !== void 0) {
60
72
  const headers = new Headers(response.headers);
61
- headers.delete(chunkK6QETMQA_cjs.SETTLE_AMOUNT_HEADER);
73
+ headers.delete(chunkPOU7EH3E_cjs.SETTLE_AMOUNT_HEADER);
62
74
  response = new server.NextResponse(response.body, {
63
75
  status: response.status,
64
76
  headers
@@ -68,15 +80,22 @@ function withPayment(config, handler) {
68
80
  if (response.status >= 200 && response.status < 300) {
69
81
  let settleOptions;
70
82
  if (gateResult.scheme === "upto") {
71
- const resolved = chunkK6QETMQA_cjs.resolveSettleAmount(
72
- raw,
73
- gateResult.maxAmount,
74
- gateResult.decimals
75
- );
83
+ const handled = response;
84
+ const resolved = await chunkPOU7EH3E_cjs.resolveCharge(gateResult, raw, {
85
+ status: handled.status,
86
+ header: (name) => handled.headers.get(name) ?? void 0,
87
+ // Read from a clone: the body streams once, to the client.
88
+ body: () => chunkPOU7EH3E_cjs.jsonFromResponse(handled)
89
+ });
76
90
  if (resolved.kind === "invalid") {
77
- return server.NextResponse.json(chunkK6QETMQA_cjs.INVALID_SETTLE_AMOUNT_RESPONSE, {
78
- status: 402
91
+ handled.body?.cancel().catch(() => {
79
92
  });
93
+ return server.NextResponse.json(
94
+ chunkPOU7EH3E_cjs.invalidSettleAmountResponse(resolved.reason),
95
+ {
96
+ status: 402
97
+ }
98
+ );
80
99
  }
81
100
  if (resolved.kind === "skip") return response;
82
101
  settleOptions = { amount: resolved.amount };
@@ -85,7 +104,7 @@ function withPayment(config, handler) {
85
104
  const settleResponse = settleOptions ? await gateResult.settle(settleOptions) : await gateResult.settle();
86
105
  if (settleResponse.success) {
87
106
  const headers = new Headers(response.headers);
88
- headers.set("payment-response", chunkK6QETMQA_cjs.encodeBase64(settleResponse));
107
+ headers.set("payment-response", chunkPOU7EH3E_cjs.encodeBase64(settleResponse));
89
108
  headers.set("access-control-expose-headers", "payment-response");
90
109
  return new server.NextResponse(response.body, {
91
110
  status: response.status,
@@ -94,6 +113,8 @@ function withPayment(config, handler) {
94
113
  }
95
114
  } catch {
96
115
  }
116
+ response.body?.cancel().catch(() => {
117
+ });
97
118
  return server.NextResponse.json(
98
119
  {
99
120
  error: "PAYMENT_SETTLEMENT_FAILED",
package/dist/next.d.cts CHANGED
@@ -1,5 +1,5 @@
1
1
  import { NextRequest, NextResponse } from 'next/server';
2
- import { H as HTTPAdapter, P as PaymentMiddlewareConfig } from './types-CBzm5CtM.cjs';
2
+ import { H as HTTPAdapter, P as PaymentMiddlewareConfig } from './types-q_gu5wjz.cjs';
3
3
  import 'viem';
4
4
 
5
5
  declare class NextAdapter implements HTTPAdapter {
@@ -9,6 +9,7 @@ declare class NextAdapter implements HTTPAdapter {
9
9
  getMethod(): string;
10
10
  getPath(): string;
11
11
  getUrl(): string;
12
+ getBody(): Promise<unknown>;
12
13
  }
13
14
 
14
15
  type NextHandler = (req: NextRequest) => Promise<NextResponse>;
package/dist/next.d.ts CHANGED
@@ -1,5 +1,5 @@
1
1
  import { NextRequest, NextResponse } from 'next/server';
2
- import { H as HTTPAdapter, P as PaymentMiddlewareConfig } from './types-CBzm5CtM.js';
2
+ import { H as HTTPAdapter, P as PaymentMiddlewareConfig } from './types-q_gu5wjz.js';
3
3
  import 'viem';
4
4
 
5
5
  declare class NextAdapter implements HTTPAdapter {
@@ -9,6 +9,7 @@ declare class NextAdapter implements HTTPAdapter {
9
9
  getMethod(): string;
10
10
  getPath(): string;
11
11
  getUrl(): string;
12
+ getBody(): Promise<unknown>;
12
13
  }
13
14
 
14
15
  type NextHandler = (req: NextRequest) => Promise<NextResponse>;
package/dist/next.js CHANGED
@@ -1,4 +1,5 @@
1
- import { createPaymentGate, raceTimeout, HANDLER_TIMEOUT, SETTLE_AMOUNT_HEADER, resolveSettleAmount, INVALID_SETTLE_AMOUNT_RESPONSE, encodeBase64 } from './chunk-TLCEPWQI.js';
1
+ import { isJsonContentType, createPaymentGate, raceTimeout, HANDLER_TIMEOUT, SETTLE_AMOUNT_HEADER, resolveCharge, jsonFromResponse, invalidSettleAmountResponse, encodeBase64 } from './chunk-AENXD4OC.js';
2
+ import './chunk-AFRDHGDT.js';
2
3
  import { NextResponse } from 'next/server';
3
4
 
4
5
  // src/next/adapter.ts
@@ -19,6 +20,17 @@ var NextAdapter = class {
19
20
  getUrl() {
20
21
  return this.req.url;
21
22
  }
23
+ // Read from a clone: a request body is a stream that can be consumed once,
24
+ // and the handler still needs the original.
25
+ async getBody() {
26
+ if (!isJsonContentType(this.req.headers.get("content-type") ?? void 0))
27
+ return void 0;
28
+ try {
29
+ return await this.req.clone().json();
30
+ } catch {
31
+ return void 0;
32
+ }
33
+ }
22
34
  };
23
35
 
24
36
  // src/next/index.ts
@@ -66,15 +78,22 @@ function withPayment(config, handler) {
66
78
  if (response.status >= 200 && response.status < 300) {
67
79
  let settleOptions;
68
80
  if (gateResult.scheme === "upto") {
69
- const resolved = resolveSettleAmount(
70
- raw,
71
- gateResult.maxAmount,
72
- gateResult.decimals
73
- );
81
+ const handled = response;
82
+ const resolved = await resolveCharge(gateResult, raw, {
83
+ status: handled.status,
84
+ header: (name) => handled.headers.get(name) ?? void 0,
85
+ // Read from a clone: the body streams once, to the client.
86
+ body: () => jsonFromResponse(handled)
87
+ });
74
88
  if (resolved.kind === "invalid") {
75
- return NextResponse.json(INVALID_SETTLE_AMOUNT_RESPONSE, {
76
- status: 402
89
+ handled.body?.cancel().catch(() => {
77
90
  });
91
+ return NextResponse.json(
92
+ invalidSettleAmountResponse(resolved.reason),
93
+ {
94
+ status: 402
95
+ }
96
+ );
78
97
  }
79
98
  if (resolved.kind === "skip") return response;
80
99
  settleOptions = { amount: resolved.amount };
@@ -92,6 +111,8 @@ function withPayment(config, handler) {
92
111
  }
93
112
  } catch {
94
113
  }
114
+ response.body?.cancel().catch(() => {
115
+ });
95
116
  return NextResponse.json(
96
117
  {
97
118
  error: "PAYMENT_SETTLEMENT_FAILED",
@@ -4,8 +4,52 @@ interface FacilitatorConfig {
4
4
  url: string;
5
5
  apiKey?: string;
6
6
  }
7
+ /**
8
+ * What a per-request price function sees. `body` is the request body as the
9
+ * framework parsed it (JSON), or `undefined` when there is none.
10
+ */
11
+ interface PriceContext {
12
+ method: string;
13
+ path: string;
14
+ url: string;
15
+ header(name: string): string | undefined;
16
+ body: unknown;
17
+ }
18
+ /**
19
+ * Prices one request from its content. Called on the unpaid request to build
20
+ * the 402 and again on the paid retry, so it must be pure: same request, same
21
+ * price. Returns a price in the same format as a fixed `price`.
22
+ */
23
+ type PriceFunction = (ctx: PriceContext) => string | bigint | Promise<string | bigint>;
24
+ /**
25
+ * What a meter function sees once the handler has answered: the response
26
+ * (`body` is its JSON as parsed by the middleware, `undefined` when it is not
27
+ * JSON) and the request as the price function saw it.
28
+ */
29
+ interface MeterContext {
30
+ status: number;
31
+ header(name: string): string | undefined;
32
+ body: unknown;
33
+ request: PriceContext;
34
+ }
35
+ /**
36
+ * Names the amount a metered route charges, from the handler's response.
37
+ * Returns an amount in the same format as `price`, bounded by the cap;
38
+ * `"0"` serves the request for free; `undefined` leaves the decision to the
39
+ * `payment-settle-amount` header, then to the cap.
40
+ */
41
+ type MeterFunction = (ctx: MeterContext) => string | bigint | undefined | null | Promise<string | bigint | undefined | null>;
7
42
  interface RouteConfig {
8
- price: string | bigint;
43
+ /**
44
+ * A fixed amount (`"0.01"` or a bigint in the smallest unit), or a function
45
+ * of the request for resources priced per request.
46
+ */
47
+ price: string | bigint | PriceFunction;
48
+ /**
49
+ * Metered routes only: reads the amount to charge from the handler's
50
+ * response instead of the `payment-settle-amount` header.
51
+ */
52
+ meter?: MeterFunction;
9
53
  decimals?: number;
10
54
  network: string;
11
55
  payTo: Address;
@@ -39,6 +83,11 @@ interface RunHandlerResult {
39
83
  getResponseHeader?(name: string): string | undefined;
40
84
  /** Strips a header before the response leaves (metered routes). */
41
85
  removeResponseHeader?(name: string): void;
86
+ /**
87
+ * The handler's response body as JSON, for routes with a `meter` function;
88
+ * `undefined` when the response is not JSON.
89
+ */
90
+ getResponseBody?(): Promise<unknown>;
42
91
  sendResponse(): void;
43
92
  discardResponse(): void;
44
93
  }
@@ -47,6 +96,8 @@ interface HTTPAdapter {
47
96
  getMethod(): string;
48
97
  getPath(): string;
49
98
  getUrl(): string;
99
+ /** The parsed request body, for routes priced per request. */
100
+ getBody?(): Promise<unknown>;
50
101
  runHandler?(options?: RunHandlerOptions): Promise<RunHandlerResult>;
51
102
  }
52
103
  interface ResourceInfo {
@@ -120,6 +171,9 @@ type VerifiedPayment = {
120
171
  /** How long the handler may run before the middleware gives up on it. */
121
172
  handlerTimeoutMs: number;
122
173
  settle(options?: SettleOptions): Promise<FacilitatorResponse>;
174
+ /** The route's meter function, and the request it will be shown. */
175
+ meter?: MeterFunction;
176
+ request?: PriceContext;
123
177
  };
124
178
  type PaymentGateResult = {
125
179
  type: "pass";
@@ -128,4 +182,4 @@ type PaymentGateResult = {
128
182
  result: MiddlewareResult;
129
183
  } | VerifiedPayment;
130
184
 
131
- export type { FacilitatorConfig as F, HTTPAdapter as H, MiddlewareResult as M, PaymentMiddlewareConfig as P, RunHandlerOptions as R, SettleOptions as S, VerifiedPayment as V, RunHandlerResult as a, FacilitatorPaymentRequirements as b, FacilitatorResponse as c, PaymentGateResult as d, PassResult as e, PaymentConfirmation as f, PaymentFailure as g, PaymentRequired as h, PaymentRequirements as i, ResourceInfo as j, RouteConfig as k };
185
+ export type { FacilitatorConfig as F, HTTPAdapter as H, MiddlewareResult as M, PaymentMiddlewareConfig as P, RunHandlerOptions as R, SettleOptions as S, VerifiedPayment as V, RunHandlerResult as a, FacilitatorPaymentRequirements as b, FacilitatorResponse as c, PaymentGateResult as d, PassResult as e, MeterContext as f, MeterFunction as g, PaymentConfirmation as h, PaymentFailure as i, PaymentRequired as j, PaymentRequirements as k, PriceContext as l, PriceFunction as m, ResourceInfo as n, RouteConfig as o };
@@ -4,8 +4,52 @@ interface FacilitatorConfig {
4
4
  url: string;
5
5
  apiKey?: string;
6
6
  }
7
+ /**
8
+ * What a per-request price function sees. `body` is the request body as the
9
+ * framework parsed it (JSON), or `undefined` when there is none.
10
+ */
11
+ interface PriceContext {
12
+ method: string;
13
+ path: string;
14
+ url: string;
15
+ header(name: string): string | undefined;
16
+ body: unknown;
17
+ }
18
+ /**
19
+ * Prices one request from its content. Called on the unpaid request to build
20
+ * the 402 and again on the paid retry, so it must be pure: same request, same
21
+ * price. Returns a price in the same format as a fixed `price`.
22
+ */
23
+ type PriceFunction = (ctx: PriceContext) => string | bigint | Promise<string | bigint>;
24
+ /**
25
+ * What a meter function sees once the handler has answered: the response
26
+ * (`body` is its JSON as parsed by the middleware, `undefined` when it is not
27
+ * JSON) and the request as the price function saw it.
28
+ */
29
+ interface MeterContext {
30
+ status: number;
31
+ header(name: string): string | undefined;
32
+ body: unknown;
33
+ request: PriceContext;
34
+ }
35
+ /**
36
+ * Names the amount a metered route charges, from the handler's response.
37
+ * Returns an amount in the same format as `price`, bounded by the cap;
38
+ * `"0"` serves the request for free; `undefined` leaves the decision to the
39
+ * `payment-settle-amount` header, then to the cap.
40
+ */
41
+ type MeterFunction = (ctx: MeterContext) => string | bigint | undefined | null | Promise<string | bigint | undefined | null>;
7
42
  interface RouteConfig {
8
- price: string | bigint;
43
+ /**
44
+ * A fixed amount (`"0.01"` or a bigint in the smallest unit), or a function
45
+ * of the request for resources priced per request.
46
+ */
47
+ price: string | bigint | PriceFunction;
48
+ /**
49
+ * Metered routes only: reads the amount to charge from the handler's
50
+ * response instead of the `payment-settle-amount` header.
51
+ */
52
+ meter?: MeterFunction;
9
53
  decimals?: number;
10
54
  network: string;
11
55
  payTo: Address;
@@ -39,6 +83,11 @@ interface RunHandlerResult {
39
83
  getResponseHeader?(name: string): string | undefined;
40
84
  /** Strips a header before the response leaves (metered routes). */
41
85
  removeResponseHeader?(name: string): void;
86
+ /**
87
+ * The handler's response body as JSON, for routes with a `meter` function;
88
+ * `undefined` when the response is not JSON.
89
+ */
90
+ getResponseBody?(): Promise<unknown>;
42
91
  sendResponse(): void;
43
92
  discardResponse(): void;
44
93
  }
@@ -47,6 +96,8 @@ interface HTTPAdapter {
47
96
  getMethod(): string;
48
97
  getPath(): string;
49
98
  getUrl(): string;
99
+ /** The parsed request body, for routes priced per request. */
100
+ getBody?(): Promise<unknown>;
50
101
  runHandler?(options?: RunHandlerOptions): Promise<RunHandlerResult>;
51
102
  }
52
103
  interface ResourceInfo {
@@ -120,6 +171,9 @@ type VerifiedPayment = {
120
171
  /** How long the handler may run before the middleware gives up on it. */
121
172
  handlerTimeoutMs: number;
122
173
  settle(options?: SettleOptions): Promise<FacilitatorResponse>;
174
+ /** The route's meter function, and the request it will be shown. */
175
+ meter?: MeterFunction;
176
+ request?: PriceContext;
123
177
  };
124
178
  type PaymentGateResult = {
125
179
  type: "pass";
@@ -128,4 +182,4 @@ type PaymentGateResult = {
128
182
  result: MiddlewareResult;
129
183
  } | VerifiedPayment;
130
184
 
131
- export type { FacilitatorConfig as F, HTTPAdapter as H, MiddlewareResult as M, PaymentMiddlewareConfig as P, RunHandlerOptions as R, SettleOptions as S, VerifiedPayment as V, RunHandlerResult as a, FacilitatorPaymentRequirements as b, FacilitatorResponse as c, PaymentGateResult as d, PassResult as e, PaymentConfirmation as f, PaymentFailure as g, PaymentRequired as h, PaymentRequirements as i, ResourceInfo as j, RouteConfig as k };
185
+ export type { FacilitatorConfig as F, HTTPAdapter as H, MiddlewareResult as M, PaymentMiddlewareConfig as P, RunHandlerOptions as R, SettleOptions as S, VerifiedPayment as V, RunHandlerResult as a, FacilitatorPaymentRequirements as b, FacilitatorResponse as c, PaymentGateResult as d, PassResult as e, MeterContext as f, MeterFunction as g, PaymentConfirmation as h, PaymentFailure as i, PaymentRequired as j, PaymentRequirements as k, PriceContext as l, PriceFunction as m, ResourceInfo as n, RouteConfig as o };
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@parallel-protocol/x402",
3
- "version": "0.6.0",
3
+ "version": "0.7.0",
4
4
  "description": "Parallel Protocol x402 payment middleware — Express, Next.js, Fastify, Hono",
5
5
  "author": "Parallel Protocol <contact@parallel.best>",
6
6
  "repository": {
@@ -69,6 +69,16 @@
69
69
  "default": "./dist/hono.cjs"
70
70
  }
71
71
  },
72
+ "./llm": {
73
+ "import": {
74
+ "types": "./dist/llm.d.ts",
75
+ "default": "./dist/llm.js"
76
+ },
77
+ "require": {
78
+ "types": "./dist/llm.d.cts",
79
+ "default": "./dist/llm.cjs"
80
+ }
81
+ },
72
82
  "./package.json": "./package.json"
73
83
  },
74
84
  "files": [