@faremeter/test-harness 0.16.0 → 0.17.1

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.
Files changed (61) hide show
  1. package/dist/src/choosers.d.ts +74 -10
  2. package/dist/src/choosers.d.ts.map +1 -1
  3. package/dist/src/choosers.js +64 -0
  4. package/dist/src/harness/config.d.ts +19 -3
  5. package/dist/src/harness/config.d.ts.map +1 -1
  6. package/dist/src/harness/defaults.d.ts +10 -3
  7. package/dist/src/harness/defaults.d.ts.map +1 -1
  8. package/dist/src/harness/defaults.js +17 -1
  9. package/dist/src/harness/harness.d.ts +10 -4
  10. package/dist/src/harness/harness.d.ts.map +1 -1
  11. package/dist/src/harness/harness.js +124 -48
  12. package/dist/src/harness/harness.test.js +3 -2
  13. package/dist/src/harness/resource.d.ts +36 -2
  14. package/dist/src/harness/resource.d.ts.map +1 -1
  15. package/dist/src/harness/resource.js +33 -8
  16. package/dist/src/index.d.ts +12 -4
  17. package/dist/src/index.d.ts.map +1 -1
  18. package/dist/src/index.js +11 -3
  19. package/dist/src/interceptors/delay.d.ts +21 -0
  20. package/dist/src/interceptors/delay.d.ts.map +1 -1
  21. package/dist/src/interceptors/delay.js +21 -0
  22. package/dist/src/interceptors/failures.d.ts +42 -0
  23. package/dist/src/interceptors/failures.d.ts.map +1 -1
  24. package/dist/src/interceptors/failures.js +42 -0
  25. package/dist/src/interceptors/hooks.d.ts +27 -0
  26. package/dist/src/interceptors/hooks.d.ts.map +1 -1
  27. package/dist/src/interceptors/hooks.js +27 -0
  28. package/dist/src/interceptors/logging.d.ts +21 -0
  29. package/dist/src/interceptors/logging.d.ts.map +1 -1
  30. package/dist/src/interceptors/logging.js +18 -0
  31. package/dist/src/interceptors/matchers.d.ts +30 -0
  32. package/dist/src/interceptors/matchers.d.ts.map +1 -1
  33. package/dist/src/interceptors/matchers.js +30 -0
  34. package/dist/src/interceptors/responses.d.ts +75 -3
  35. package/dist/src/interceptors/responses.d.ts.map +1 -1
  36. package/dist/src/interceptors/responses.js +98 -8
  37. package/dist/src/interceptors/types.d.ts +11 -0
  38. package/dist/src/interceptors/types.d.ts.map +1 -1
  39. package/dist/src/interceptors/utils.d.ts +6 -0
  40. package/dist/src/interceptors/utils.d.ts.map +1 -1
  41. package/dist/src/interceptors/utils.js +6 -0
  42. package/dist/src/interceptors/v2.d.ts +15 -0
  43. package/dist/src/interceptors/v2.d.ts.map +1 -0
  44. package/dist/src/interceptors/v2.js +52 -0
  45. package/dist/src/scheme/client.d.ts +8 -2
  46. package/dist/src/scheme/client.d.ts.map +1 -1
  47. package/dist/src/scheme/client.js +1 -5
  48. package/dist/src/scheme/constants.d.ts +7 -0
  49. package/dist/src/scheme/constants.d.ts.map +1 -1
  50. package/dist/src/scheme/constants.js +7 -0
  51. package/dist/src/scheme/facilitator.d.ts +7 -1
  52. package/dist/src/scheme/facilitator.d.ts.map +1 -1
  53. package/dist/src/scheme/facilitator.js +35 -40
  54. package/dist/src/scheme/types.d.ts +8 -0
  55. package/dist/src/scheme/types.d.ts.map +1 -1
  56. package/dist/src/scheme/types.js +5 -0
  57. package/dist/src/test-handlers.d.ts +52 -0
  58. package/dist/src/test-handlers.d.ts.map +1 -0
  59. package/dist/src/test-handlers.js +110 -0
  60. package/dist/tsconfig.tsbuildinfo +1 -1
  61. package/package.json +7 -5
@@ -1,11 +1,83 @@
1
1
  import type { x402PaymentRequirements } from "@faremeter/types/x402";
2
+ /**
3
+ * Creates a JSON Response with the given status and body.
4
+ *
5
+ * @param status - HTTP status code.
6
+ * @param body - Object to serialize as JSON.
7
+ * @returns A Response with JSON content type.
8
+ */
2
9
  export declare function jsonResponse(status: number, body: object): Response;
10
+ /**
11
+ * Creates a failed verify response.
12
+ *
13
+ * @param reason - Reason for verification failure.
14
+ * @returns A 200 Response with isValid: false.
15
+ */
3
16
  export declare function verifyFailedResponse(reason: string): Response;
17
+ /**
18
+ * Creates a successful verify response.
19
+ *
20
+ * @returns A 200 Response with isValid: true.
21
+ */
4
22
  export declare function verifySuccessResponse(): Response;
5
- export declare function settleFailedResponse(error: string): Response;
6
- export declare function settleSuccessResponse(txHash: string, networkId: string): Response;
7
- export declare function paymentRequiredResponse(accepts: x402PaymentRequirements[]): Response;
23
+ /**
24
+ * Creates a failed settle response (v1 format).
25
+ *
26
+ * @param errorReason - Reason for settlement failure.
27
+ * @returns A 200 Response with success: false.
28
+ */
29
+ export declare function settleFailedResponse(errorReason: string): Response;
30
+ /**
31
+ * Creates a failed settle response (v2 format).
32
+ *
33
+ * @param errorReason - Reason for settlement failure.
34
+ * @param network - Network identifier for the response.
35
+ * @returns A 200 Response with success: false.
36
+ */
37
+ export declare function settleFailedResponseV2(errorReason: string, network: string): Response;
38
+ /**
39
+ * Creates a successful settle response (v1 format).
40
+ *
41
+ * @param transaction - Transaction identifier.
42
+ * @param network - Network identifier.
43
+ * @returns A 200 Response with success: true.
44
+ */
45
+ export declare function settleSuccessResponse(transaction: string, network: string): Response;
46
+ /**
47
+ * Creates a successful settle response (v2 format).
48
+ *
49
+ * @param transaction - Transaction identifier.
50
+ * @param network - Network identifier.
51
+ * @returns A 200 Response with success: true.
52
+ */
53
+ export declare function settleSuccessResponseV2(transaction: string, network: string): Response;
54
+ /**
55
+ * Creates a 402 Payment Required response.
56
+ *
57
+ * @param accepts - Payment requirements the server accepts.
58
+ * @param error - Optional error message.
59
+ * @returns A 402 Response with x402Version: 1.
60
+ */
61
+ export declare function paymentRequiredResponse(accepts: x402PaymentRequirements[], error?: string): Response;
62
+ /**
63
+ * Creates a network error for testing error handling.
64
+ *
65
+ * @param message - Error message.
66
+ * @returns An Error to be thrown by interceptors.
67
+ */
8
68
  export declare function networkError(message?: string): Error;
69
+ /**
70
+ * Creates a timeout error for testing timeout handling.
71
+ *
72
+ * @returns An Error with "Request timed out" message.
73
+ */
9
74
  export declare function timeoutError(): Error;
75
+ /**
76
+ * Creates an HTTP error response.
77
+ *
78
+ * @param status - HTTP status code.
79
+ * @param message - Error message.
80
+ * @returns A Response with the error JSON body.
81
+ */
10
82
  export declare function httpError(status: number, message: string): Response;
11
83
  //# sourceMappingURL=responses.d.ts.map
@@ -1 +1 @@
1
- {"version":3,"file":"responses.d.ts","sourceRoot":"","sources":["../../../src/interceptors/responses.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,uBAAuB,EAAE,MAAM,uBAAuB,CAAC;AAErE,wBAAgB,YAAY,CAAC,MAAM,EAAE,MAAM,EAAE,IAAI,EAAE,MAAM,GAAG,QAAQ,CAKnE;AAED,wBAAgB,oBAAoB,CAAC,MAAM,EAAE,MAAM,GAAG,QAAQ,CAK7D;AAED,wBAAgB,qBAAqB,IAAI,QAAQ,CAIhD;AAED,wBAAgB,oBAAoB,CAAC,KAAK,EAAE,MAAM,GAAG,QAAQ,CAO5D;AAED,wBAAgB,qBAAqB,CACnC,MAAM,EAAE,MAAM,EACd,SAAS,EAAE,MAAM,GAChB,QAAQ,CAMV;AAED,wBAAgB,uBAAuB,CACrC,OAAO,EAAE,uBAAuB,EAAE,GACjC,QAAQ,CAKV;AAED,wBAAgB,YAAY,CAAC,OAAO,SAAkB,GAAG,KAAK,CAE7D;AAED,wBAAgB,YAAY,IAAI,KAAK,CAEpC;AAED,wBAAgB,SAAS,CAAC,MAAM,EAAE,MAAM,EAAE,OAAO,EAAE,MAAM,GAAG,QAAQ,CAEnE"}
1
+ {"version":3,"file":"responses.d.ts","sourceRoot":"","sources":["../../../src/interceptors/responses.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,uBAAuB,EAAE,MAAM,uBAAuB,CAAC;AAErE;;;;;;GAMG;AACH,wBAAgB,YAAY,CAAC,MAAM,EAAE,MAAM,EAAE,IAAI,EAAE,MAAM,GAAG,QAAQ,CAKnE;AAED;;;;;GAKG;AACH,wBAAgB,oBAAoB,CAAC,MAAM,EAAE,MAAM,GAAG,QAAQ,CAM7D;AAED;;;;GAIG;AACH,wBAAgB,qBAAqB,IAAI,QAAQ,CAKhD;AAED;;;;;GAKG;AACH,wBAAgB,oBAAoB,CAAC,WAAW,EAAE,MAAM,GAAG,QAAQ,CAQlE;AAED;;;;;;GAMG;AACH,wBAAgB,sBAAsB,CACpC,WAAW,EAAE,MAAM,EACnB,OAAO,EAAE,MAAM,GACd,QAAQ,CAOV;AAED;;;;;;GAMG;AACH,wBAAgB,qBAAqB,CACnC,WAAW,EAAE,MAAM,EACnB,OAAO,EAAE,MAAM,GACd,QAAQ,CAOV;AAED;;;;;;GAMG;AACH,wBAAgB,uBAAuB,CACrC,WAAW,EAAE,MAAM,EACnB,OAAO,EAAE,MAAM,GACd,QAAQ,CAMV;AAED;;;;;;GAMG;AACH,wBAAgB,uBAAuB,CACrC,OAAO,EAAE,uBAAuB,EAAE,EAClC,KAAK,SAAK,GACT,QAAQ,CAMV;AAED;;;;;GAKG;AACH,wBAAgB,YAAY,CAAC,OAAO,SAAkB,GAAG,KAAK,CAE7D;AAED;;;;GAIG;AACH,wBAAgB,YAAY,IAAI,KAAK,CAEpC;AAED;;;;;;GAMG;AACH,wBAAgB,SAAS,CAAC,MAAM,EAAE,MAAM,EAAE,OAAO,EAAE,MAAM,GAAG,QAAQ,CAEnE"}
@@ -1,47 +1,137 @@
1
+ /**
2
+ * Creates a JSON Response with the given status and body.
3
+ *
4
+ * @param status - HTTP status code.
5
+ * @param body - Object to serialize as JSON.
6
+ * @returns A Response with JSON content type.
7
+ */
1
8
  export function jsonResponse(status, body) {
2
9
  return new Response(JSON.stringify(body), {
3
10
  status,
4
11
  headers: { "Content-Type": "application/json" },
5
12
  });
6
13
  }
14
+ /**
15
+ * Creates a failed verify response.
16
+ *
17
+ * @param reason - Reason for verification failure.
18
+ * @returns A 200 Response with isValid: false.
19
+ */
7
20
  export function verifyFailedResponse(reason) {
8
21
  return jsonResponse(200, {
9
22
  isValid: false,
10
23
  invalidReason: reason,
24
+ payer: "",
11
25
  });
12
26
  }
27
+ /**
28
+ * Creates a successful verify response.
29
+ *
30
+ * @returns A 200 Response with isValid: true.
31
+ */
13
32
  export function verifySuccessResponse() {
14
33
  return jsonResponse(200, {
15
34
  isValid: true,
35
+ payer: "test-payer",
16
36
  });
17
37
  }
18
- export function settleFailedResponse(error) {
38
+ /**
39
+ * Creates a failed settle response (v1 format).
40
+ *
41
+ * @param errorReason - Reason for settlement failure.
42
+ * @returns A 200 Response with success: false.
43
+ */
44
+ export function settleFailedResponse(errorReason) {
19
45
  return jsonResponse(200, {
20
46
  success: false,
21
- error,
22
- txHash: null,
23
- networkId: null,
47
+ errorReason,
48
+ transaction: "",
49
+ network: "",
50
+ payer: "",
51
+ });
52
+ }
53
+ /**
54
+ * Creates a failed settle response (v2 format).
55
+ *
56
+ * @param errorReason - Reason for settlement failure.
57
+ * @param network - Network identifier for the response.
58
+ * @returns A 200 Response with success: false.
59
+ */
60
+ export function settleFailedResponseV2(errorReason, network) {
61
+ return jsonResponse(200, {
62
+ success: false,
63
+ errorReason,
64
+ transaction: "",
65
+ network,
24
66
  });
25
67
  }
26
- export function settleSuccessResponse(txHash, networkId) {
68
+ /**
69
+ * Creates a successful settle response (v1 format).
70
+ *
71
+ * @param transaction - Transaction identifier.
72
+ * @param network - Network identifier.
73
+ * @returns A 200 Response with success: true.
74
+ */
75
+ export function settleSuccessResponse(transaction, network) {
27
76
  return jsonResponse(200, {
28
77
  success: true,
29
- txHash,
30
- networkId,
78
+ transaction,
79
+ network,
80
+ payer: "test-payer",
31
81
  });
32
82
  }
33
- export function paymentRequiredResponse(accepts) {
83
+ /**
84
+ * Creates a successful settle response (v2 format).
85
+ *
86
+ * @param transaction - Transaction identifier.
87
+ * @param network - Network identifier.
88
+ * @returns A 200 Response with success: true.
89
+ */
90
+ export function settleSuccessResponseV2(transaction, network) {
91
+ return jsonResponse(200, {
92
+ success: true,
93
+ transaction,
94
+ network,
95
+ });
96
+ }
97
+ /**
98
+ * Creates a 402 Payment Required response.
99
+ *
100
+ * @param accepts - Payment requirements the server accepts.
101
+ * @param error - Optional error message.
102
+ * @returns A 402 Response with x402Version: 1.
103
+ */
104
+ export function paymentRequiredResponse(accepts, error = "") {
34
105
  return jsonResponse(402, {
35
106
  x402Version: 1,
36
107
  accepts,
108
+ error,
37
109
  });
38
110
  }
111
+ /**
112
+ * Creates a network error for testing error handling.
113
+ *
114
+ * @param message - Error message.
115
+ * @returns An Error to be thrown by interceptors.
116
+ */
39
117
  export function networkError(message = "Network error") {
40
118
  return new Error(message);
41
119
  }
120
+ /**
121
+ * Creates a timeout error for testing timeout handling.
122
+ *
123
+ * @returns An Error with "Request timed out" message.
124
+ */
42
125
  export function timeoutError() {
43
126
  return new Error("Request timed out");
44
127
  }
128
+ /**
129
+ * Creates an HTTP error response.
130
+ *
131
+ * @param status - HTTP status code.
132
+ * @param message - Error message.
133
+ * @returns A Response with the error JSON body.
134
+ */
45
135
  export function httpError(status, message) {
46
136
  return jsonResponse(status, { error: message });
47
137
  }
@@ -1,3 +1,9 @@
1
+ /**
2
+ * A function that wraps fetch to intercept requests and responses.
3
+ *
4
+ * Interceptors can modify requests before they're sent, inspect or modify
5
+ * responses, inject failures, add delays, or log activity.
6
+ */
1
7
  export type Interceptor = (fetch: typeof globalThis.fetch) => typeof globalThis.fetch;
2
8
  /**
3
9
  * Compose multiple interceptors into a single interceptor.
@@ -16,5 +22,10 @@ export type Interceptor = (fetch: typeof globalThis.fetch) => typeof globalThis.
16
22
  * ```
17
23
  */
18
24
  export declare function composeInterceptors(...interceptors: Interceptor[]): Interceptor;
25
+ /**
26
+ * Predicate function that determines whether a request should be matched.
27
+ *
28
+ * Used by interceptors to selectively apply behavior to specific requests.
29
+ */
19
30
  export type RequestMatcher = (url: string, init?: RequestInit) => boolean;
20
31
  //# sourceMappingURL=types.d.ts.map
@@ -1 +1 @@
1
- {"version":3,"file":"types.d.ts","sourceRoot":"","sources":["../../../src/interceptors/types.ts"],"names":[],"mappings":"AAAA,MAAM,MAAM,WAAW,GAAG,CACxB,KAAK,EAAE,OAAO,UAAU,CAAC,KAAK,KAC3B,OAAO,UAAU,CAAC,KAAK,CAAC;AAE7B;;;;;;;;;;;;;;;GAeG;AACH,wBAAgB,mBAAmB,CACjC,GAAG,YAAY,EAAE,WAAW,EAAE,GAC7B,WAAW,CAMb;AAED,MAAM,MAAM,cAAc,GAAG,CAAC,GAAG,EAAE,MAAM,EAAE,IAAI,CAAC,EAAE,WAAW,KAAK,OAAO,CAAC"}
1
+ {"version":3,"file":"types.d.ts","sourceRoot":"","sources":["../../../src/interceptors/types.ts"],"names":[],"mappings":"AAAA;;;;;GAKG;AACH,MAAM,MAAM,WAAW,GAAG,CACxB,KAAK,EAAE,OAAO,UAAU,CAAC,KAAK,KAC3B,OAAO,UAAU,CAAC,KAAK,CAAC;AAE7B;;;;;;;;;;;;;;;GAeG;AACH,wBAAgB,mBAAmB,CACjC,GAAG,YAAY,EAAE,WAAW,EAAE,GAC7B,WAAW,CAMb;AAED;;;;GAIG;AACH,MAAM,MAAM,cAAc,GAAG,CAAC,GAAG,EAAE,MAAM,EAAE,IAAI,CAAC,EAAE,WAAW,KAAK,OAAO,CAAC"}
@@ -1,2 +1,8 @@
1
+ /**
2
+ * Extracts the URL string from various request input types.
3
+ *
4
+ * @param input - A URL string, URL object, or Request object.
5
+ * @returns The URL as a string.
6
+ */
1
7
  export declare function getURLFromRequestInfo(input: RequestInfo | URL | string): string;
2
8
  //# sourceMappingURL=utils.d.ts.map
@@ -1 +1 @@
1
- {"version":3,"file":"utils.d.ts","sourceRoot":"","sources":["../../../src/interceptors/utils.ts"],"names":[],"mappings":"AAAA,wBAAgB,qBAAqB,CACnC,KAAK,EAAE,WAAW,GAAG,GAAG,GAAG,MAAM,GAChC,MAAM,CAUR"}
1
+ {"version":3,"file":"utils.d.ts","sourceRoot":"","sources":["../../../src/interceptors/utils.ts"],"names":[],"mappings":"AAAA;;;;;GAKG;AACH,wBAAgB,qBAAqB,CACnC,KAAK,EAAE,WAAW,GAAG,GAAG,GAAG,MAAM,GAChC,MAAM,CAUR"}
@@ -1,3 +1,9 @@
1
+ /**
2
+ * Extracts the URL string from various request input types.
3
+ *
4
+ * @param input - A URL string, URL object, or Request object.
5
+ * @returns The URL as a string.
6
+ */
1
7
  export function getURLFromRequestInfo(input) {
2
8
  if (typeof input === "string") {
3
9
  return input;
@@ -0,0 +1,15 @@
1
+ import type { Interceptor } from "./types.js";
2
+ /**
3
+ * Creates an interceptor that transforms v1 402 responses to v2 format.
4
+ *
5
+ * This allows testing v2 client behavior by making the middleware appear
6
+ * to respond with v2 format even though it defaults to v1.
7
+ *
8
+ * The transformation:
9
+ * - Parses the JSON body as v1 PaymentRequiredResponse
10
+ * - Converts to v2 PaymentRequiredResponse format
11
+ * - Encodes as base64 in PAYMENT-REQUIRED header
12
+ * - Returns 402 with the new header
13
+ */
14
+ export declare function createV2ResponseInterceptor(): Interceptor;
15
+ //# sourceMappingURL=v2.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"v2.d.ts","sourceRoot":"","sources":["../../../src/interceptors/v2.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,WAAW,EAAE,MAAM,SAAS,CAAC;AAO3C;;;;;;;;;;;GAWG;AACH,wBAAgB,2BAA2B,IAAI,WAAW,CA8CzD"}
@@ -0,0 +1,52 @@
1
+ import { x402PaymentRequiredResponse } from "@faremeter/types/x402";
2
+ import { isValidationError } from "@faremeter/types";
3
+ import { adaptPaymentRequiredResponseV1ToV2 } from "@faremeter/types/x402-adapters";
4
+ import { V2_PAYMENT_REQUIRED_HEADER } from "@faremeter/types/x402v2";
5
+ import { normalizeNetworkId } from "@faremeter/info";
6
+ /**
7
+ * Creates an interceptor that transforms v1 402 responses to v2 format.
8
+ *
9
+ * This allows testing v2 client behavior by making the middleware appear
10
+ * to respond with v2 format even though it defaults to v1.
11
+ *
12
+ * The transformation:
13
+ * - Parses the JSON body as v1 PaymentRequiredResponse
14
+ * - Converts to v2 PaymentRequiredResponse format
15
+ * - Encodes as base64 in PAYMENT-REQUIRED header
16
+ * - Returns 402 with the new header
17
+ */
18
+ export function createV2ResponseInterceptor() {
19
+ return (baseFetch) => async (input, init) => {
20
+ const response = await baseFetch(input, init);
21
+ // Only transform 402 responses that don't already have v2 header
22
+ if (response.status !== 402 ||
23
+ response.headers.has(V2_PAYMENT_REQUIRED_HEADER)) {
24
+ return response;
25
+ }
26
+ const cloned = response.clone();
27
+ let body;
28
+ try {
29
+ body = await cloned.json();
30
+ }
31
+ catch {
32
+ return response;
33
+ }
34
+ const v1Response = x402PaymentRequiredResponse(body);
35
+ if (isValidationError(v1Response)) {
36
+ return response;
37
+ }
38
+ // Convert to v2 format using shared adapter
39
+ const resourceURL = v1Response.accepts[0]?.resource ?? "";
40
+ const v2Response = adaptPaymentRequiredResponseV1ToV2(v1Response, resourceURL, normalizeNetworkId);
41
+ // Encode as base64
42
+ const encoded = btoa(JSON.stringify(v2Response));
43
+ // Create new response with v2 header
44
+ const newHeaders = new Headers(response.headers);
45
+ newHeaders.set(V2_PAYMENT_REQUIRED_HEADER, encoded);
46
+ return new Response(null, {
47
+ status: 402,
48
+ statusText: "Payment Required",
49
+ headers: newHeaders,
50
+ });
51
+ };
52
+ }
@@ -1,9 +1,15 @@
1
- import type { PaymentHandler } from "@faremeter/types/client";
1
+ import type { PaymentHandlerV1 } from "@faremeter/types/client";
2
2
  import type { x402PaymentRequirements } from "@faremeter/types/x402";
3
3
  import { type TestPaymentPayload } from "./types.js";
4
+ /**
5
+ * Options for creating a test payment handler.
6
+ */
4
7
  export type CreateTestPaymentHandlerOpts = {
8
+ /** Optional callback when requirements are matched. */
5
9
  onMatch?: (requirements: x402PaymentRequirements) => void;
10
+ /** Optional callback when payment is executed. */
6
11
  onExec?: (requirements: x402PaymentRequirements, payload: TestPaymentPayload) => void;
12
+ /** Custom metadata to include in test payloads. */
7
13
  metadata?: Record<string, unknown>;
8
14
  };
9
15
  /**
@@ -12,5 +18,5 @@ export type CreateTestPaymentHandlerOpts = {
12
18
  * This handler creates simple test payment payloads without any cryptographic
13
19
  * operations, making it suitable for testing the x402 protocol flow.
14
20
  */
15
- export declare function createTestPaymentHandler(opts?: CreateTestPaymentHandlerOpts): PaymentHandler;
21
+ export declare function createTestPaymentHandler(opts?: CreateTestPaymentHandlerOpts): PaymentHandlerV1;
16
22
  //# sourceMappingURL=client.d.ts.map
@@ -1 +1 @@
1
- {"version":3,"file":"client.d.ts","sourceRoot":"","sources":["../../../src/scheme/client.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EACV,cAAc,EAGf,MAAM,yBAAyB,CAAC;AACjC,OAAO,KAAK,EAAE,uBAAuB,EAAE,MAAM,uBAAuB,CAAC;AAGrE,OAAO,EAAkB,KAAK,kBAAkB,EAAE,MAAM,SAAS,CAAC;AAElE,MAAM,MAAM,4BAA4B,GAAG;IACzC,OAAO,CAAC,EAAE,CAAC,YAAY,EAAE,uBAAuB,KAAK,IAAI,CAAC;IAC1D,MAAM,CAAC,EAAE,CACP,YAAY,EAAE,uBAAuB,EACrC,OAAO,EAAE,kBAAkB,KACxB,IAAI,CAAC;IACV,QAAQ,CAAC,EAAE,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,CAAC;CACpC,CAAC;AASF;;;;;GAKG;AACH,wBAAgB,wBAAwB,CACtC,IAAI,GAAE,4BAAiC,GACtC,cAAc,CAiChB"}
1
+ {"version":3,"file":"client.d.ts","sourceRoot":"","sources":["../../../src/scheme/client.ts"],"names":[],"mappings":"AACA,OAAO,KAAK,EACV,gBAAgB,EAGjB,MAAM,yBAAyB,CAAC;AACjC,OAAO,KAAK,EAAE,uBAAuB,EAAE,MAAM,uBAAuB,CAAC;AAGrE,OAAO,EAAkB,KAAK,kBAAkB,EAAE,MAAM,SAAS,CAAC;AAElE;;GAEG;AACH,MAAM,MAAM,4BAA4B,GAAG;IACzC,uDAAuD;IACvD,OAAO,CAAC,EAAE,CAAC,YAAY,EAAE,uBAAuB,KAAK,IAAI,CAAC;IAC1D,kDAAkD;IAClD,MAAM,CAAC,EAAE,CACP,YAAY,EAAE,uBAAuB,EACrC,OAAO,EAAE,kBAAkB,KACxB,IAAI,CAAC;IACV,mDAAmD;IACnD,QAAQ,CAAC,EAAE,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,CAAC;CACpC,CAAC;AAEF;;;;;GAKG;AACH,wBAAgB,wBAAwB,CACtC,IAAI,GAAE,4BAAiC,GACtC,gBAAgB,CAiClB"}
@@ -1,9 +1,5 @@
1
- import { TEST_SCHEME, TEST_NETWORK } from "./constants.js";
1
+ import { isMatchingRequirement } from "./constants.js";
2
2
  import { generateTestId } from "./types.js";
3
- function isMatchingRequirement(req) {
4
- return (req.scheme.toLowerCase() === TEST_SCHEME.toLowerCase() &&
5
- req.network.toLowerCase() === TEST_NETWORK.toLowerCase());
6
- }
7
3
  /**
8
4
  * Create a test payment handler.
9
5
  *
@@ -1,4 +1,11 @@
1
1
  export declare const TEST_SCHEME = "test";
2
2
  export declare const TEST_NETWORK = "test-local";
3
3
  export declare const TEST_ASSET = "TEST";
4
+ /**
5
+ * Checks if a payment requirement matches the test scheme and network.
6
+ */
7
+ export declare function isMatchingRequirement(req: {
8
+ scheme: string;
9
+ network: string;
10
+ }): boolean;
4
11
  //# sourceMappingURL=constants.d.ts.map
@@ -1 +1 @@
1
- {"version":3,"file":"constants.d.ts","sourceRoot":"","sources":["../../../src/scheme/constants.ts"],"names":[],"mappings":"AAAA,eAAO,MAAM,WAAW,SAAS,CAAC;AAElC,eAAO,MAAM,YAAY,eAAe,CAAC;AAEzC,eAAO,MAAM,UAAU,SAAS,CAAC"}
1
+ {"version":3,"file":"constants.d.ts","sourceRoot":"","sources":["../../../src/scheme/constants.ts"],"names":[],"mappings":"AAAA,eAAO,MAAM,WAAW,SAAS,CAAC;AAClC,eAAO,MAAM,YAAY,eAAe,CAAC;AACzC,eAAO,MAAM,UAAU,SAAS,CAAC;AAEjC;;GAEG;AACH,wBAAgB,qBAAqB,CAAC,GAAG,EAAE;IACzC,MAAM,EAAE,MAAM,CAAC;IACf,OAAO,EAAE,MAAM,CAAC;CACjB,GAAG,OAAO,CAKV"}
@@ -1,3 +1,10 @@
1
1
  export const TEST_SCHEME = "test";
2
2
  export const TEST_NETWORK = "test-local";
3
3
  export const TEST_ASSET = "TEST";
4
+ /**
5
+ * Checks if a payment requirement matches the test scheme and network.
6
+ */
7
+ export function isMatchingRequirement(req) {
8
+ return (req.scheme.toLowerCase() === TEST_SCHEME.toLowerCase() &&
9
+ req.network.toLowerCase() === TEST_NETWORK.toLowerCase());
10
+ }
@@ -1,9 +1,15 @@
1
- import type { x402PaymentRequirements, x402PaymentPayload } from "@faremeter/types/x402";
1
+ import type { x402PaymentRequirements, x402PaymentPayload } from "@faremeter/types/x402v2";
2
2
  import type { FacilitatorHandler } from "@faremeter/types/facilitator";
3
3
  import type { TestPaymentPayload } from "./types.js";
4
+ /**
5
+ * Options for creating a test facilitator handler.
6
+ */
4
7
  export type CreateTestFacilitatorHandlerOpts = {
8
+ /** Address that should receive payments. */
5
9
  payTo: string;
10
+ /** Optional callback invoked during verify. */
6
11
  onVerify?: (requirements: x402PaymentRequirements, payload: x402PaymentPayload, testPayload: TestPaymentPayload) => void;
12
+ /** Optional callback invoked during settle. */
7
13
  onSettle?: (requirements: x402PaymentRequirements, payload: x402PaymentPayload, testPayload: TestPaymentPayload) => void;
8
14
  };
9
15
  /**
@@ -1 +1 @@
1
- {"version":3,"file":"facilitator.d.ts","sourceRoot":"","sources":["../../../src/scheme/facilitator.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EACV,uBAAuB,EACvB,kBAAkB,EAInB,MAAM,uBAAuB,CAAC;AAC/B,OAAO,KAAK,EAAE,kBAAkB,EAAE,MAAM,8BAA8B,CAAC;AAGvE,OAAO,KAAK,EAAE,kBAAkB,EAAE,MAAM,SAAS,CAAC;AAElD,MAAM,MAAM,gCAAgC,GAAG;IAC7C,KAAK,EAAE,MAAM,CAAC;IACd,QAAQ,CAAC,EAAE,CACT,YAAY,EAAE,uBAAuB,EACrC,OAAO,EAAE,kBAAkB,EAC3B,WAAW,EAAE,kBAAkB,KAC5B,IAAI,CAAC;IACV,QAAQ,CAAC,EAAE,CACT,YAAY,EAAE,uBAAuB,EACrC,OAAO,EAAE,kBAAkB,EAC3B,WAAW,EAAE,kBAAkB,KAC5B,IAAI,CAAC;CACX,CAAC;AAuCF;;;;;GAKG;AACH,wBAAgB,4BAA4B,CAC1C,IAAI,EAAE,gCAAgC,GACrC,kBAAkB,CAiHpB"}
1
+ {"version":3,"file":"facilitator.d.ts","sourceRoot":"","sources":["../../../src/scheme/facilitator.ts"],"names":[],"mappings":"AAEA,OAAO,KAAK,EACV,uBAAuB,EACvB,kBAAkB,EAInB,MAAM,yBAAyB,CAAC;AACjC,OAAO,KAAK,EAAE,kBAAkB,EAAE,MAAM,8BAA8B,CAAC;AAQvE,OAAO,KAAK,EAAE,kBAAkB,EAAE,MAAM,SAAS,CAAC;AASlD;;GAEG;AACH,MAAM,MAAM,gCAAgC,GAAG;IAC7C,4CAA4C;IAC5C,KAAK,EAAE,MAAM,CAAC;IACd,+CAA+C;IAC/C,QAAQ,CAAC,EAAE,CACT,YAAY,EAAE,uBAAuB,EACrC,OAAO,EAAE,kBAAkB,EAC3B,WAAW,EAAE,kBAAkB,KAC5B,IAAI,CAAC;IACV,+CAA+C;IAC/C,QAAQ,CAAC,EAAE,CACT,YAAY,EAAE,uBAAuB,EACrC,OAAO,EAAE,kBAAkB,EAC3B,WAAW,EAAE,kBAAkB,KAC5B,IAAI,CAAC;CACX,CAAC;AAcF;;;;;GAKG;AACH,wBAAgB,4BAA4B,CAC1C,IAAI,EAAE,gCAAgC,GACrC,kBAAkB,CAwHpB"}
@@ -1,28 +1,18 @@
1
- import { TEST_SCHEME, TEST_NETWORK, TEST_ASSET } from "./constants.js";
2
- function isMatchingRequirement(req) {
3
- return (req.scheme.toLowerCase() === TEST_SCHEME.toLowerCase() &&
4
- req.network.toLowerCase() === TEST_NETWORK.toLowerCase());
5
- }
1
+ import { type } from "arktype";
2
+ import { isValidationError } from "@faremeter/types";
3
+ import { TEST_SCHEME, TEST_NETWORK, TEST_ASSET, isMatchingRequirement, } from "./constants.js";
4
+ const testPaymentPayload = type({
5
+ testId: "string > 0",
6
+ amount: "string > 0",
7
+ timestamp: "number > 0",
8
+ "metadata?": "Record<string, unknown>",
9
+ });
6
10
  function validateTestPayload(payload) {
7
- const p = payload;
8
- if (typeof p.testId !== "string" || p.testId.length === 0) {
9
- return { valid: false, error: "Missing or invalid testId" };
10
- }
11
- if (typeof p.amount !== "string" || p.amount.length === 0) {
12
- return { valid: false, error: "Missing or invalid amount" };
13
- }
14
- if (typeof p.timestamp !== "number" || p.timestamp <= 0) {
15
- return { valid: false, error: "Missing or invalid timestamp" };
11
+ const result = testPaymentPayload(payload);
12
+ if (isValidationError(result)) {
13
+ return { valid: false, error: result.summary };
16
14
  }
17
- return {
18
- valid: true,
19
- payload: {
20
- testId: p.testId,
21
- amount: p.amount,
22
- timestamp: p.timestamp,
23
- metadata: p.metadata,
24
- },
25
- };
15
+ return { valid: true, payload: result };
26
16
  }
27
17
  /**
28
18
  * Create a test facilitator handler.
@@ -35,18 +25,19 @@ export function createTestFacilitatorHandler(opts) {
35
25
  const getSupported = () => {
36
26
  return [
37
27
  Promise.resolve({
38
- x402Version: 1,
28
+ x402Version: 2,
39
29
  scheme: TEST_SCHEME,
40
30
  network: TEST_NETWORK,
41
31
  }),
42
32
  ];
43
33
  };
44
- const getRequirements = async (req) => {
34
+ const getRequirements = async ({ accepts: req, }) => {
35
+ // || is intentional: tests pass empty strings to signal "not provided".
45
36
  return req.filter(isMatchingRequirement).map((r) => ({
46
37
  ...r,
47
38
  asset: r.asset || TEST_ASSET,
48
39
  payTo: r.payTo || payTo,
49
- maxTimeoutSeconds: r.maxTimeoutSeconds || 300,
40
+ maxTimeoutSeconds: r.maxTimeoutSeconds ?? 300,
50
41
  }));
51
42
  };
52
43
  const handleVerify = async (requirements, payment) => {
@@ -59,7 +50,7 @@ export function createTestFacilitatorHandler(opts) {
59
50
  }
60
51
  const testPayload = result.payload;
61
52
  // Verify amount matches
62
- if (testPayload.amount !== requirements.maxAmountRequired) {
53
+ if (testPayload.amount !== requirements.amount) {
63
54
  return { isValid: false, invalidReason: "Amount mismatch" };
64
55
  }
65
56
  // Verify payment is to the correct address
@@ -69,7 +60,7 @@ export function createTestFacilitatorHandler(opts) {
69
60
  if (onVerify) {
70
61
  onVerify(requirements, payment, testPayload);
71
62
  }
72
- return { isValid: true };
63
+ return { isValid: true, payer: "test-payer" };
73
64
  };
74
65
  const handleSettle = async (requirements, payment) => {
75
66
  if (!isMatchingRequirement(requirements)) {
@@ -79,28 +70,31 @@ export function createTestFacilitatorHandler(opts) {
79
70
  if (!result.valid) {
80
71
  return {
81
72
  success: false,
82
- error: result.error,
83
- txHash: null,
84
- networkId: null,
73
+ errorReason: result.error,
74
+ transaction: "",
75
+ network: requirements.network,
76
+ payer: "",
85
77
  };
86
78
  }
87
79
  const testPayload = result.payload;
88
80
  // Verify amount matches
89
- if (testPayload.amount !== requirements.maxAmountRequired) {
81
+ if (testPayload.amount !== requirements.amount) {
90
82
  return {
91
83
  success: false,
92
- error: "Amount mismatch",
93
- txHash: null,
94
- networkId: null,
84
+ errorReason: "Amount mismatch",
85
+ transaction: "",
86
+ network: requirements.network,
87
+ payer: "",
95
88
  };
96
89
  }
97
90
  // Verify payment is to the correct address
98
91
  if (requirements.payTo.toLowerCase() !== payTo.toLowerCase()) {
99
92
  return {
100
93
  success: false,
101
- error: "Payment to wrong address",
102
- txHash: null,
103
- networkId: null,
94
+ errorReason: "Payment to wrong address",
95
+ transaction: "",
96
+ network: requirements.network,
97
+ payer: "",
104
98
  };
105
99
  }
106
100
  if (onSettle) {
@@ -108,8 +102,9 @@ export function createTestFacilitatorHandler(opts) {
108
102
  }
109
103
  return {
110
104
  success: true,
111
- txHash: `test-tx-${testPayload.testId}`,
112
- networkId: TEST_NETWORK,
105
+ transaction: `test-tx-${testPayload.testId}`,
106
+ network: TEST_NETWORK,
107
+ payer: "test-payer",
113
108
  };
114
109
  };
115
110
  return {
@@ -1,8 +1,16 @@
1
+ /**
2
+ * Payload structure for test payment scheme transactions.
3
+ */
1
4
  export type TestPaymentPayload = {
2
5
  testId: string;
3
6
  amount: string;
4
7
  timestamp: number;
5
8
  metadata?: Record<string, unknown> | undefined;
6
9
  };
10
+ /**
11
+ * Generates a unique test payment identifier.
12
+ *
13
+ * @returns A string like "test-1234567890-abc123".
14
+ */
7
15
  export declare function generateTestId(): string;
8
16
  //# sourceMappingURL=types.d.ts.map
@@ -1 +1 @@
1
- {"version":3,"file":"types.d.ts","sourceRoot":"","sources":["../../../src/scheme/types.ts"],"names":[],"mappings":"AAAA,MAAM,MAAM,kBAAkB,GAAG;IAC/B,MAAM,EAAE,MAAM,CAAC;IACf,MAAM,EAAE,MAAM,CAAC;IACf,SAAS,EAAE,MAAM,CAAC;IAClB,QAAQ,CAAC,EAAE,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,GAAG,SAAS,CAAC;CAChD,CAAC;AAEF,wBAAgB,cAAc,IAAI,MAAM,CAEvC"}
1
+ {"version":3,"file":"types.d.ts","sourceRoot":"","sources":["../../../src/scheme/types.ts"],"names":[],"mappings":"AAAA;;GAEG;AACH,MAAM,MAAM,kBAAkB,GAAG;IAC/B,MAAM,EAAE,MAAM,CAAC;IACf,MAAM,EAAE,MAAM,CAAC;IACf,SAAS,EAAE,MAAM,CAAC;IAClB,QAAQ,CAAC,EAAE,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,GAAG,SAAS,CAAC;CAChD,CAAC;AAEF;;;;GAIG;AACH,wBAAgB,cAAc,IAAI,MAAM,CAEvC"}
@@ -1,3 +1,8 @@
1
+ /**
2
+ * Generates a unique test payment identifier.
3
+ *
4
+ * @returns A string like "test-1234567890-abc123".
5
+ */
1
6
  export function generateTestId() {
2
7
  return `test-${Date.now()}-${Math.random().toString(36).substring(2, 9)}`;
3
8
  }