@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.
- package/dist/src/choosers.d.ts +74 -10
- package/dist/src/choosers.d.ts.map +1 -1
- package/dist/src/choosers.js +64 -0
- package/dist/src/harness/config.d.ts +19 -3
- package/dist/src/harness/config.d.ts.map +1 -1
- package/dist/src/harness/defaults.d.ts +10 -3
- package/dist/src/harness/defaults.d.ts.map +1 -1
- package/dist/src/harness/defaults.js +17 -1
- package/dist/src/harness/harness.d.ts +10 -4
- package/dist/src/harness/harness.d.ts.map +1 -1
- package/dist/src/harness/harness.js +124 -48
- package/dist/src/harness/harness.test.js +3 -2
- package/dist/src/harness/resource.d.ts +36 -2
- package/dist/src/harness/resource.d.ts.map +1 -1
- package/dist/src/harness/resource.js +33 -8
- package/dist/src/index.d.ts +12 -4
- package/dist/src/index.d.ts.map +1 -1
- package/dist/src/index.js +11 -3
- package/dist/src/interceptors/delay.d.ts +21 -0
- package/dist/src/interceptors/delay.d.ts.map +1 -1
- package/dist/src/interceptors/delay.js +21 -0
- package/dist/src/interceptors/failures.d.ts +42 -0
- package/dist/src/interceptors/failures.d.ts.map +1 -1
- package/dist/src/interceptors/failures.js +42 -0
- package/dist/src/interceptors/hooks.d.ts +27 -0
- package/dist/src/interceptors/hooks.d.ts.map +1 -1
- package/dist/src/interceptors/hooks.js +27 -0
- package/dist/src/interceptors/logging.d.ts +21 -0
- package/dist/src/interceptors/logging.d.ts.map +1 -1
- package/dist/src/interceptors/logging.js +18 -0
- package/dist/src/interceptors/matchers.d.ts +30 -0
- package/dist/src/interceptors/matchers.d.ts.map +1 -1
- package/dist/src/interceptors/matchers.js +30 -0
- package/dist/src/interceptors/responses.d.ts +75 -3
- package/dist/src/interceptors/responses.d.ts.map +1 -1
- package/dist/src/interceptors/responses.js +98 -8
- package/dist/src/interceptors/types.d.ts +11 -0
- package/dist/src/interceptors/types.d.ts.map +1 -1
- package/dist/src/interceptors/utils.d.ts +6 -0
- package/dist/src/interceptors/utils.d.ts.map +1 -1
- package/dist/src/interceptors/utils.js +6 -0
- package/dist/src/interceptors/v2.d.ts +15 -0
- package/dist/src/interceptors/v2.d.ts.map +1 -0
- package/dist/src/interceptors/v2.js +52 -0
- package/dist/src/scheme/client.d.ts +8 -2
- package/dist/src/scheme/client.d.ts.map +1 -1
- package/dist/src/scheme/client.js +1 -5
- package/dist/src/scheme/constants.d.ts +7 -0
- package/dist/src/scheme/constants.d.ts.map +1 -1
- package/dist/src/scheme/constants.js +7 -0
- package/dist/src/scheme/facilitator.d.ts +7 -1
- package/dist/src/scheme/facilitator.d.ts.map +1 -1
- package/dist/src/scheme/facilitator.js +35 -40
- package/dist/src/scheme/types.d.ts +8 -0
- package/dist/src/scheme/types.d.ts.map +1 -1
- package/dist/src/scheme/types.js +5 -0
- package/dist/src/test-handlers.d.ts +52 -0
- package/dist/src/test-handlers.d.ts.map +1 -0
- package/dist/src/test-handlers.js +110 -0
- package/dist/tsconfig.tsbuildinfo +1 -1
- 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
|
-
|
|
6
|
-
|
|
7
|
-
|
|
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,
|
|
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
|
-
|
|
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
|
-
|
|
22
|
-
|
|
23
|
-
|
|
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
|
-
|
|
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
|
-
|
|
30
|
-
|
|
78
|
+
transaction,
|
|
79
|
+
network,
|
|
80
|
+
payer: "test-payer",
|
|
31
81
|
});
|
|
32
82
|
}
|
|
33
|
-
|
|
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 {
|
|
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):
|
|
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":"
|
|
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 {
|
|
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;
|
|
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/
|
|
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":"
|
|
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 {
|
|
2
|
-
|
|
3
|
-
|
|
4
|
-
|
|
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
|
|
8
|
-
if (
|
|
9
|
-
return { valid: false, error:
|
|
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:
|
|
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
|
|
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.
|
|
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
|
-
|
|
83
|
-
|
|
84
|
-
|
|
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.
|
|
81
|
+
if (testPayload.amount !== requirements.amount) {
|
|
90
82
|
return {
|
|
91
83
|
success: false,
|
|
92
|
-
|
|
93
|
-
|
|
94
|
-
|
|
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
|
-
|
|
102
|
-
|
|
103
|
-
|
|
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
|
-
|
|
112
|
-
|
|
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"}
|
package/dist/src/scheme/types.js
CHANGED