@faremeter/middleware 0.11.1 → 0.13.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.
@@ -49,6 +49,12 @@ export type HandleMiddlewareRequestArgs<MiddlewareResponse = unknown> = CommonMi
49
49
  getHeader: (key: string) => string | undefined;
50
50
  getPaymentRequiredResponse: typeof getPaymentRequiredResponse;
51
51
  sendJSONResponse: (status: PossibleStatusCodes, obj: PossibleJSONResponse) => MiddlewareResponse;
52
+ body: (context: {
53
+ paymentRequirements: x402PaymentRequirements;
54
+ paymentPayload: x402PaymentPayload;
55
+ settle: () => Promise<MiddlewareResponse | undefined>;
56
+ verify: () => Promise<MiddlewareResponse | undefined>;
57
+ }) => Promise<MiddlewareResponse | undefined>;
52
58
  };
53
59
  export declare function handleMiddlewareRequest<MiddlewareResponse>(args: HandleMiddlewareRequestArgs<MiddlewareResponse>): Promise<MiddlewareResponse | undefined>;
54
60
  export type createPaymentRequiredResponseCacheOpts = AgedLRUCacheOpts & {
@@ -1 +1 @@
1
- {"version":3,"file":"common.d.ts","sourceRoot":"","sources":["../../src/common.ts"],"names":[],"mappings":"AACA,OAAO,EACL,KAAK,uBAAuB,EAC5B,KAAK,kBAAkB,EAKxB,MAAM,uBAAuB,CAAC;AAC/B,OAAO,EAAE,KAAK,gBAAgB,EAAgB,MAAM,SAAS,CAAC;AAI9D,wBAAgB,+BAA+B,CAC7C,OAAO,EAAE,uBAAuB,EAAE,EAClC,OAAO,EAAE,kBAAkB;;;;;;;;;;;;cA6B5B;AAED,wBAAgB,8BAA8B,CAAC,GAAG,EAAE,QAAQ,QAS3D;AAED,MAAM,MAAM,mBAAmB,GAAG,OAAO,CAAC,uBAAuB,CAAC,CAAC;AAEnE,KAAK,8BAA8B,GAAG;IACpC,cAAc,EAAE,MAAM,CAAC;IACvB,OAAO,EAAE,mBAAmB,EAAE,CAAC;IAC/B,QAAQ,EAAE,MAAM,CAAC;CAClB,CAAC;AAEF,wBAAsB,0BAA0B,CAC9C,IAAI,EAAE,8BAA8B;;;;;;;;;;;;oBApC5B,CAAA;aAAuB,CAAC;;;GAkEjC;AAED,KAAK,mBAAmB,GAAG,GAAG,CAAC;AAC/B,KAAK,oBAAoB,GAAG,MAAM,CAAC;AAEnC,MAAM,MAAM,oBAAoB,GAAG;IACjC,cAAc,EAAE,MAAM,CAAC;IACvB,OAAO,EAAE,CAAC,mBAAmB,GAAG,mBAAmB,EAAE,CAAC,EAAE,CAAC;IACzD,WAAW,CAAC,EAAE,sCAAsC,CAAC;CACtD,CAAC;AAEF,MAAM,MAAM,2BAA2B,CAAC,kBAAkB,GAAG,OAAO,IAClE,oBAAoB,GAAG;IACrB,QAAQ,EAAE,MAAM,CAAC;IACjB,SAAS,EAAE,CAAC,GAAG,EAAE,MAAM,KAAK,MAAM,GAAG,SAAS,CAAC;IAC/C,0BAA0B,EAAE,OAAO,0BAA0B,CAAC;IAC9D,gBAAgB,EAAE,CAChB,MAAM,EAAE,mBAAmB,EAC3B,GAAG,EAAE,oBAAoB,KACtB,kBAAkB,CAAC;CACzB,CAAC;AAEJ,wBAAsB,uBAAuB,CAAC,kBAAkB,EAC9D,IAAI,EAAE,2BAA2B,CAAC,kBAAkB,CAAC,2CAiEtD;AAED,MAAM,MAAM,sCAAsC,GAAG,gBAAgB,GAAG;IACtE,OAAO,CAAC,EAAE,OAAO,CAAC;CACnB,CAAC;AACF,wBAAgB,kCAAkC,CAChD,IAAI,GAAE,sCAA2C;;EA8BlD"}
1
+ {"version":3,"file":"common.d.ts","sourceRoot":"","sources":["../../src/common.ts"],"names":[],"mappings":"AACA,OAAO,EACL,KAAK,uBAAuB,EAC5B,KAAK,kBAAkB,EAOxB,MAAM,uBAAuB,CAAC;AAC/B,OAAO,EAAE,KAAK,gBAAgB,EAAgB,MAAM,SAAS,CAAC;AAI9D,wBAAgB,+BAA+B,CAC7C,OAAO,EAAE,uBAAuB,EAAE,EAClC,OAAO,EAAE,kBAAkB;;;;;;;;;;;;cA6B5B;AAED,wBAAgB,8BAA8B,CAAC,GAAG,EAAE,QAAQ,QAS3D;AAED,MAAM,MAAM,mBAAmB,GAAG,OAAO,CAAC,uBAAuB,CAAC,CAAC;AAEnE,KAAK,8BAA8B,GAAG;IACpC,cAAc,EAAE,MAAM,CAAC;IACvB,OAAO,EAAE,mBAAmB,EAAE,CAAC;IAC/B,QAAQ,EAAE,MAAM,CAAC;CAClB,CAAC;AAEF,wBAAsB,0BAA0B,CAC9C,IAAI,EAAE,8BAA8B;;;;;;;;;;;;oBAtCoB,CAAC;aACtC,CAAC;;;GAmErB;AAED,KAAK,mBAAmB,GAAG,GAAG,CAAC;AAC/B,KAAK,oBAAoB,GAAG,MAAM,CAAC;AAEnC,MAAM,MAAM,oBAAoB,GAAG;IACjC,cAAc,EAAE,MAAM,CAAC;IACvB,OAAO,EAAE,CAAC,mBAAmB,GAAG,mBAAmB,EAAE,CAAC,EAAE,CAAC;IACzD,WAAW,CAAC,EAAE,sCAAsC,CAAC;CACtD,CAAC;AAEF,MAAM,MAAM,2BAA2B,CAAC,kBAAkB,GAAG,OAAO,IAClE,oBAAoB,GAAG;IACrB,QAAQ,EAAE,MAAM,CAAC;IACjB,SAAS,EAAE,CAAC,GAAG,EAAE,MAAM,KAAK,MAAM,GAAG,SAAS,CAAC;IAC/C,0BAA0B,EAAE,OAAO,0BAA0B,CAAC;IAC9D,gBAAgB,EAAE,CAChB,MAAM,EAAE,mBAAmB,EAC3B,GAAG,EAAE,oBAAoB,KACtB,kBAAkB,CAAC;IACxB,IAAI,EAAE,CAAC,OAAO,EAAE;QACd,mBAAmB,EAAE,uBAAuB,CAAC;QAC7C,cAAc,EAAE,kBAAkB,CAAC;QACnC,MAAM,EAAE,MAAM,OAAO,CAAC,kBAAkB,GAAG,SAAS,CAAC,CAAC;QACtD,MAAM,EAAE,MAAM,OAAO,CAAC,kBAAkB,GAAG,SAAS,CAAC,CAAC;KACvD,KAAK,OAAO,CAAC,kBAAkB,GAAG,SAAS,CAAC,CAAC;CAC/C,CAAC;AAEJ,wBAAsB,uBAAuB,CAAC,kBAAkB,EAC9D,IAAI,EAAE,2BAA2B,CAAC,kBAAkB,CAAC,2CA4GtD;AAED,MAAM,MAAM,sCAAsC,GAAG,gBAAgB,GAAG;IACtE,OAAO,CAAC,EAAE,OAAO,CAAC;CACnB,CAAC;AACF,wBAAgB,kCAAkC,CAChD,IAAI,GAAE,sCAA2C;;EA8BlD"}
@@ -1,5 +1,5 @@
1
1
  import { isValidationError } from "@faremeter/types";
2
- import { x402PaymentRequiredResponse, x402PaymentHeaderToPayload, x402SettleRequest, x402SettleResponse, } from "@faremeter/types/x402";
2
+ import { x402PaymentRequiredResponse, x402PaymentHeaderToPayload, x402VerifyRequest, x402VerifyResponse, x402SettleRequest, x402SettleResponse, } from "@faremeter/types/x402";
3
3
  import { AgedLRUCache } from "./cache.js";
4
4
  import { logger } from "./logger.js";
5
5
  export function findMatchingPaymentRequirements(accepts, payload) {
@@ -64,39 +64,74 @@ export async function handleMiddlewareRequest(args) {
64
64
  if (!paymentHeader) {
65
65
  return sendPaymentRequired();
66
66
  }
67
- const payload = x402PaymentHeaderToPayload(paymentHeader);
68
- if (isValidationError(payload)) {
69
- logger.debug(`couldn't validate client payload: ${payload.summary}`);
67
+ const paymentPayload = x402PaymentHeaderToPayload(paymentHeader);
68
+ if (isValidationError(paymentPayload)) {
69
+ logger.debug(`couldn't validate client payload: ${paymentPayload.summary}`);
70
70
  return sendPaymentRequired();
71
71
  }
72
- const paymentRequirements = findMatchingPaymentRequirements(paymentRequiredResponse.accepts, payload);
72
+ const paymentRequirements = findMatchingPaymentRequirements(paymentRequiredResponse.accepts, paymentPayload);
73
73
  if (!paymentRequirements) {
74
- logger.warning(`couldn't find matching payment requirements for payload`, payload);
74
+ logger.warning(`couldn't find matching payment requirements for payload`, paymentPayload);
75
75
  return sendPaymentRequired();
76
76
  }
77
- const settleRequest = {
78
- x402Version: 1,
79
- paymentHeader,
80
- paymentRequirements,
77
+ const settle = async () => {
78
+ const settleRequest = {
79
+ x402Version: 1,
80
+ paymentHeader,
81
+ paymentPayload,
82
+ paymentRequirements,
83
+ };
84
+ const t = await fetch(`${args.facilitatorURL}/settle`, {
85
+ method: "POST",
86
+ headers: {
87
+ Accept: "application/json",
88
+ "Content-Type": "application/json",
89
+ },
90
+ body: JSON.stringify(settleRequest),
91
+ });
92
+ const settlementResponse = x402SettleResponse(await t.json());
93
+ if (isValidationError(settlementResponse)) {
94
+ const msg = `error getting response from facilitator for settlement: ${settlementResponse.summary}`;
95
+ logger.error(msg);
96
+ throw new Error(msg);
97
+ }
98
+ if (!settlementResponse.success) {
99
+ logger.warning("failed to settle payment: {error}", settlementResponse);
100
+ return sendPaymentRequired();
101
+ }
81
102
  };
82
- const t = await fetch(`${args.facilitatorURL}/settle`, {
83
- method: "POST",
84
- headers: {
85
- Accept: "application/json",
86
- "Content-Type": "application/json",
87
- },
88
- body: JSON.stringify(settleRequest),
103
+ const verify = async () => {
104
+ const verifyRequest = {
105
+ x402Version: 1,
106
+ paymentHeader,
107
+ paymentPayload,
108
+ paymentRequirements,
109
+ };
110
+ const t = await fetch(`${args.facilitatorURL}/verify`, {
111
+ method: "POST",
112
+ headers: {
113
+ Accept: "application/json",
114
+ "Content-Type": "application/json",
115
+ },
116
+ body: JSON.stringify(verifyRequest),
117
+ });
118
+ const verifyResponse = x402VerifyResponse(await t.json());
119
+ if (isValidationError(verifyResponse)) {
120
+ const msg = `error getting response from facilitator for verification: ${verifyResponse.summary}`;
121
+ logger.error(msg);
122
+ throw new Error(msg);
123
+ }
124
+ if (!verifyResponse.isValid) {
125
+ logger.warning("failed to settle payment: {invalidReason}", verifyResponse);
126
+ return sendPaymentRequired();
127
+ }
128
+ };
129
+ return await args.body({
130
+ paymentRequirements,
131
+ paymentPayload,
132
+ settle,
133
+ verify,
89
134
  });
90
- const settlementResponse = x402SettleResponse(await t.json());
91
- if (isValidationError(settlementResponse)) {
92
- const msg = `error getting response from facilitator for settlement: ${settlementResponse.summary}`;
93
- logger.error(msg);
94
- throw new Error(msg);
95
- }
96
- if (!settlementResponse.success) {
97
- logger.warning("failed to settle payment: {error}", settlementResponse);
98
- return sendPaymentRequired();
99
- }
100
135
  }
101
136
  export function createPaymentRequiredResponseCache(opts = {}) {
102
137
  if (opts.disable) {
@@ -1,6 +1,6 @@
1
1
  import { type CommonMiddlewareArgs } from "./common.js";
2
2
  import type { NextFunction, Request, Response } from "express";
3
3
  type createMiddlewareArgs = CommonMiddlewareArgs;
4
- export declare function createMiddleware(args: createMiddlewareArgs): Promise<(req: Request, res: Response, next: NextFunction) => Promise<void>>;
4
+ export declare function createMiddleware(args: createMiddlewareArgs): Promise<(req: Request, res: Response, next: NextFunction) => Promise<Response<any, Record<string, any>> | undefined>>;
5
5
  export {};
6
6
  //# sourceMappingURL=express.d.ts.map
@@ -1 +1 @@
1
- {"version":3,"file":"express.d.ts","sourceRoot":"","sources":["../../src/express.ts"],"names":[],"mappings":"AAAA,OAAO,EAEL,KAAK,oBAAoB,EAE1B,MAAM,UAAU,CAAC;AAClB,OAAO,KAAK,EAAE,YAAY,EAAE,OAAO,EAAE,QAAQ,EAAE,MAAM,SAAS,CAAC;AAE/D,KAAK,oBAAoB,GAAG,oBAAoB,CAAC;AAEjD,wBAAsB,gBAAgB,CAAC,IAAI,EAAE,oBAAoB,iBAK5C,OAAO,OAAO,QAAQ,QAAQ,YAAY,oBAe9D"}
1
+ {"version":3,"file":"express.d.ts","sourceRoot":"","sources":["../../src/express.ts"],"names":[],"mappings":"AAAA,OAAO,EAEL,KAAK,oBAAoB,EAE1B,MAAM,UAAU,CAAC;AAClB,OAAO,KAAK,EAAE,YAAY,EAAE,OAAO,EAAE,QAAQ,EAAE,MAAM,SAAS,CAAC;AAE/D,KAAK,oBAAoB,GAAG,oBAAoB,CAAC;AAEjD,wBAAsB,gBAAgB,CAAC,IAAI,EAAE,oBAAoB,iBAK5C,OAAO,OAAO,QAAQ,QAAQ,YAAY,8DAiB9D"}
@@ -2,16 +2,19 @@ import { handleMiddlewareRequest, createPaymentRequiredResponseCache, } from "./
2
2
  export async function createMiddleware(args) {
3
3
  const { getPaymentRequiredResponse } = createPaymentRequiredResponseCache(args.cacheConfig);
4
4
  return async (req, res, next) => {
5
- const response = await handleMiddlewareRequest({
5
+ return await handleMiddlewareRequest({
6
6
  ...args,
7
7
  resource: `${req.protocol}://${req.headers.host}${req.path}`,
8
8
  getPaymentRequiredResponse,
9
9
  getHeader: (key) => req.header(key),
10
10
  sendJSONResponse: (status, body) => res.status(status).json(body),
11
+ body: async ({ settle }) => {
12
+ const response = await settle();
13
+ if (response !== undefined) {
14
+ return response;
15
+ }
16
+ next();
17
+ },
11
18
  });
12
- if (response) {
13
- return;
14
- }
15
- next();
16
19
  };
17
20
  }
@@ -1,6 +1,8 @@
1
1
  import { type CommonMiddlewareArgs } from "./common.js";
2
2
  import type { MiddlewareHandler } from "hono";
3
- type CreateMiddlewareArgs = CommonMiddlewareArgs;
3
+ type CreateMiddlewareArgs = {
4
+ verifyBeforeSettle?: boolean;
5
+ } & CommonMiddlewareArgs;
4
6
  export declare function createMiddleware(args: CreateMiddlewareArgs): Promise<MiddlewareHandler>;
5
7
  export {};
6
8
  //# sourceMappingURL=hono.d.ts.map
@@ -1 +1 @@
1
- {"version":3,"file":"hono.d.ts","sourceRoot":"","sources":["../../src/hono.ts"],"names":[],"mappings":"AAAA,OAAO,EAEL,KAAK,oBAAoB,EAE1B,MAAM,UAAU,CAAC;AAClB,OAAO,KAAK,EAAE,iBAAiB,EAAE,MAAM,MAAM,CAAC;AAE9C,KAAK,oBAAoB,GAAG,oBAAoB,CAAC;AAEjD,wBAAsB,gBAAgB,CACpC,IAAI,EAAE,oBAAoB,GACzB,OAAO,CAAC,iBAAiB,CAAC,CAuB5B"}
1
+ {"version":3,"file":"hono.d.ts","sourceRoot":"","sources":["../../src/hono.ts"],"names":[],"mappings":"AAAA,OAAO,EAEL,KAAK,oBAAoB,EAE1B,MAAM,UAAU,CAAC;AAClB,OAAO,KAAK,EAAE,iBAAiB,EAAE,MAAM,MAAM,CAAC;AAE9C,KAAK,oBAAoB,GAAG;IAC1B,kBAAkB,CAAC,EAAE,OAAO,CAAC;CAC9B,GAAG,oBAAoB,CAAC;AAEzB,wBAAsB,gBAAgB,CACpC,IAAI,EAAE,oBAAoB,GACzB,OAAO,CAAC,iBAAiB,CAAC,CAoD5B"}
package/dist/src/hono.js CHANGED
@@ -2,7 +2,7 @@ import { handleMiddlewareRequest, createPaymentRequiredResponseCache, } from "./
2
2
  export async function createMiddleware(args) {
3
3
  const { getPaymentRequiredResponse } = createPaymentRequiredResponseCache(args.cacheConfig);
4
4
  return async (c, next) => {
5
- const response = await handleMiddlewareRequest({
5
+ return await handleMiddlewareRequest({
6
6
  ...args,
7
7
  resource: c.req.url,
8
8
  getHeader: (key) => c.req.header(key),
@@ -11,10 +11,39 @@ export async function createMiddleware(args) {
11
11
  c.status(status);
12
12
  return c.json(body);
13
13
  },
14
+ body: async ({ verify, settle }) => {
15
+ if (args.verifyBeforeSettle) {
16
+ // If configured, try to verify the transaction before running
17
+ // the next operation.
18
+ const verifyResult = await verify();
19
+ if (verifyResult !== undefined) {
20
+ return verifyResult;
21
+ }
22
+ }
23
+ else {
24
+ // Otherwise just settle the payment beforehand, like we've
25
+ // done historically.
26
+ const settleResult = await settle();
27
+ if (settleResult !== undefined) {
28
+ return settleResult;
29
+ }
30
+ }
31
+ await next();
32
+ if (args.verifyBeforeSettle) {
33
+ // Close out the verification, by actually settling the
34
+ // payment.
35
+ const settleResult = await settle();
36
+ if (settleResult !== undefined) {
37
+ // If the settlement fails, we need to explicitly
38
+ // overwrite the downstream result. See:
39
+ //
40
+ // https://hono.dev/docs/guides/middleware#modify-the-response-after-next
41
+ //
42
+ c.res = undefined;
43
+ c.res = settleResult;
44
+ }
45
+ }
46
+ },
14
47
  });
15
- if (response) {
16
- return response;
17
- }
18
- await next();
19
48
  };
20
49
  }