mppx 0.8.6 → 0.8.8
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/CHANGELOG.md +19 -0
- package/dist/cli/internal.js +2 -2
- package/dist/cli/internal.js.map +1 -1
- package/dist/cli/plugins/evm.d.ts +2 -0
- package/dist/cli/plugins/evm.d.ts.map +1 -0
- package/dist/cli/plugins/evm.js +51 -0
- package/dist/cli/plugins/evm.js.map +1 -0
- package/dist/cli/plugins/index.d.ts +1 -0
- package/dist/cli/plugins/index.d.ts.map +1 -1
- package/dist/cli/plugins/index.js +1 -0
- package/dist/cli/plugins/index.js.map +1 -1
- package/dist/cli/plugins/stripe.d.ts.map +1 -1
- package/dist/cli/plugins/stripe.js +3 -2
- package/dist/cli/plugins/stripe.js.map +1 -1
- package/dist/cli/validate/challenge.d.ts +2 -0
- package/dist/cli/validate/challenge.d.ts.map +1 -1
- package/dist/cli/validate/challenge.js +191 -84
- package/dist/cli/validate/challenge.js.map +1 -1
- package/dist/cli/validate/discovery.d.ts +1 -0
- package/dist/cli/validate/discovery.d.ts.map +1 -1
- package/dist/cli/validate/discovery.js +99 -35
- package/dist/cli/validate/discovery.js.map +1 -1
- package/dist/cli/validate/helpers.d.ts +14 -1
- package/dist/cli/validate/helpers.d.ts.map +1 -1
- package/dist/cli/validate/helpers.js +0 -13
- package/dist/cli/validate/helpers.js.map +1 -1
- package/dist/cli/validate/index.d.ts +1 -0
- package/dist/cli/validate/index.d.ts.map +1 -1
- package/dist/cli/validate/index.js +102 -153
- package/dist/cli/validate/index.js.map +1 -1
- package/dist/cli/validate/payment.d.ts +4 -1
- package/dist/cli/validate/payment.d.ts.map +1 -1
- package/dist/cli/validate/payment.js +312 -106
- package/dist/cli/validate/payment.js.map +1 -1
- package/dist/evm/Chains.d.ts +4 -0
- package/dist/evm/Chains.d.ts.map +1 -1
- package/dist/evm/Chains.js +4 -0
- package/dist/evm/Chains.js.map +1 -1
- package/dist/internal/AcceptPayment.d.ts.map +1 -1
- package/dist/internal/AcceptPayment.js +7 -1
- package/dist/internal/AcceptPayment.js.map +1 -1
- package/dist/stripe/server/internal/html.gen.d.ts +1 -1
- package/dist/stripe/server/internal/html.gen.d.ts.map +1 -1
- package/dist/stripe/server/internal/html.gen.js +1 -1
- package/dist/stripe/server/internal/html.gen.js.map +1 -1
- package/dist/tempo/server/internal/html.gen.d.ts +1 -1
- package/dist/tempo/server/internal/html.gen.d.ts.map +1 -1
- package/dist/tempo/server/internal/html.gen.js +1 -1
- package/dist/tempo/server/internal/html.gen.js.map +1 -1
- package/dist/tempo/server/internal/request-body.d.ts.map +1 -1
- package/dist/tempo/server/internal/request-body.js +2 -0
- package/dist/tempo/server/internal/request-body.js.map +1 -1
- package/dist/tempo/session/server/ChannelStore.js +4 -4
- package/dist/tempo/session/server/ChannelStore.js.map +1 -1
- package/dist/tempo/session/server/CredentialVerification.d.ts +8 -0
- package/dist/tempo/session/server/CredentialVerification.d.ts.map +1 -1
- package/dist/tempo/session/server/CredentialVerification.js +21 -1
- package/dist/tempo/session/server/CredentialVerification.js.map +1 -1
- package/dist/tempo/session/server/Session.d.ts.map +1 -1
- package/dist/tempo/session/server/Session.js +1 -0
- package/dist/tempo/session/server/Session.js.map +1 -1
- package/dist/validation/core.d.ts +75 -0
- package/dist/validation/core.d.ts.map +1 -0
- package/dist/validation/core.js +269 -0
- package/dist/validation/core.js.map +1 -0
- package/dist/validation/index.d.ts +3 -0
- package/dist/validation/index.d.ts.map +1 -0
- package/dist/validation/index.js +2 -0
- package/dist/validation/index.js.map +1 -0
- package/dist/x402/Assets.d.ts +9 -0
- package/dist/x402/Assets.d.ts.map +1 -1
- package/dist/x402/Assets.js +38 -0
- package/dist/x402/Assets.js.map +1 -1
- package/package.json +9 -4
- package/src/cli/internal.ts +2 -2
- package/src/cli/plugins/evm.ts +55 -0
- package/src/cli/plugins/index.ts +1 -0
- package/src/cli/plugins/stripe.ts +3 -2
- package/src/cli/validate/challenge.ts +345 -127
- package/src/cli/validate/discovery.test.ts +307 -0
- package/src/cli/validate/discovery.ts +104 -38
- package/src/cli/validate/helpers.ts +15 -13
- package/src/cli/validate/index.ts +121 -242
- package/src/cli/validate/payment.ts +413 -144
- package/src/cli/validate.test.ts +237 -3
- package/src/client/internal/Fetch.test.ts +142 -2
- package/src/evm/Chains.ts +6 -0
- package/src/evm/PublicInterface.test-d.ts +7 -0
- package/src/internal/AcceptPayment.test.ts +45 -0
- package/src/internal/AcceptPayment.ts +11 -1
- package/src/stripe/server/internal/html/package.json +1 -1
- package/src/stripe/server/internal/html.gen.ts +1 -1
- package/src/tempo/server/internal/html/package.json +1 -1
- package/src/tempo/server/internal/html.gen.ts +1 -1
- package/src/tempo/server/internal/request-body.test.ts +9 -0
- package/src/tempo/server/internal/request-body.ts +2 -0
- package/src/tempo/session/server/ChannelStore.test.ts +17 -0
- package/src/tempo/session/server/ChannelStore.ts +4 -4
- package/src/tempo/session/server/CredentialVerification.test.ts +118 -1
- package/src/tempo/session/server/CredentialVerification.ts +30 -0
- package/src/tempo/session/server/Session.integration.test.ts +5 -0
- package/src/tempo/session/server/Session.test.ts +119 -53
- package/src/tempo/session/server/Session.ts +1 -0
- package/src/validation/core.ts +374 -0
- package/src/validation/index.ts +11 -0
- package/src/x402/Assets.test.ts +42 -0
- package/src/x402/Assets.ts +40 -0
- package/src/x402/Exact.localnet.test.ts +475 -0
|
@@ -1,6 +1,7 @@
|
|
|
1
1
|
import { fetchWithTimeout, HTTP_METHODS } from './helpers.js';
|
|
2
2
|
export async function fetchDiscoveryDoc(baseUrl) {
|
|
3
|
-
|
|
3
|
+
// Trailing slash makes URL treat baseUrl as a directory, so relative resolution appends rather than replaces the last segment.
|
|
4
|
+
const url = new URL('openapi.json', baseUrl.replace(/\/?$/, '/')).href;
|
|
4
5
|
try {
|
|
5
6
|
const response = await fetchWithTimeout(url, {});
|
|
6
7
|
if (!response.ok)
|
|
@@ -27,32 +28,124 @@ export function extractEndpointsFromDiscovery(doc) {
|
|
|
27
28
|
if (!paths)
|
|
28
29
|
return [];
|
|
29
30
|
for (const [pathKey, pathItem] of Object.entries(paths)) {
|
|
31
|
+
const pathLevelParams = extractPathParameters(pathItem.parameters);
|
|
30
32
|
for (const [method, operation] of Object.entries(pathItem)) {
|
|
31
33
|
if (!HTTP_METHODS.has(method))
|
|
32
34
|
continue;
|
|
33
35
|
if (!operation || typeof operation !== 'object' || Array.isArray(operation))
|
|
34
36
|
continue;
|
|
35
37
|
const op = operation;
|
|
38
|
+
const opParams = extractPathParameters(op.parameters);
|
|
39
|
+
const merged = mergeParameters(pathLevelParams, opParams);
|
|
40
|
+
const params = merged.length > 0 ? merged : undefined;
|
|
36
41
|
if (op['x-payment-info']) {
|
|
37
42
|
const payInfo = op['x-payment-info'];
|
|
38
43
|
withPaymentInfo.push({
|
|
39
44
|
method: method.toUpperCase(),
|
|
40
45
|
path: pathKey,
|
|
41
46
|
amount: payInfo.amount,
|
|
47
|
+
parameters: params,
|
|
42
48
|
});
|
|
43
49
|
}
|
|
44
50
|
else {
|
|
45
51
|
const responses = op.responses;
|
|
46
52
|
if (responses && '402' in responses) {
|
|
47
|
-
with402Response.push({ method: method.toUpperCase(), path: pathKey });
|
|
53
|
+
with402Response.push({ method: method.toUpperCase(), path: pathKey, parameters: params });
|
|
48
54
|
}
|
|
49
55
|
}
|
|
50
56
|
}
|
|
51
57
|
}
|
|
52
58
|
return withPaymentInfo.length > 0 ? withPaymentInfo : with402Response;
|
|
53
59
|
}
|
|
54
|
-
|
|
55
|
-
|
|
60
|
+
export function extractRequestBodyFromDiscovery(doc, endpoint) {
|
|
61
|
+
const paths = doc.paths;
|
|
62
|
+
if (!paths)
|
|
63
|
+
return undefined;
|
|
64
|
+
const pathItem = paths[endpoint.path];
|
|
65
|
+
if (!pathItem)
|
|
66
|
+
return undefined;
|
|
67
|
+
const op = pathItem[endpoint.method.toLowerCase()];
|
|
68
|
+
if (!op?.requestBody)
|
|
69
|
+
return undefined;
|
|
70
|
+
const rb = op.requestBody;
|
|
71
|
+
const content = rb.content;
|
|
72
|
+
const jsonContent = content?.['application/json'];
|
|
73
|
+
if (!jsonContent)
|
|
74
|
+
return undefined;
|
|
75
|
+
if (jsonContent.example)
|
|
76
|
+
return JSON.stringify(jsonContent.example);
|
|
77
|
+
const schema = jsonContent.schema;
|
|
78
|
+
if (!schema || schema.type !== 'object')
|
|
79
|
+
return undefined;
|
|
80
|
+
const result = generateValueFromSchema(schema);
|
|
81
|
+
if (result && typeof result === 'object' && Object.keys(result).length > 0) {
|
|
82
|
+
return JSON.stringify(result);
|
|
83
|
+
}
|
|
84
|
+
return undefined;
|
|
85
|
+
}
|
|
86
|
+
export function buildUrl(baseUrl, endpoint, query) {
|
|
87
|
+
let path = endpoint.path;
|
|
88
|
+
if (endpoint.parameters) {
|
|
89
|
+
path = substitutePathParams(path, endpoint.parameters);
|
|
90
|
+
}
|
|
91
|
+
// Strip leading slash so URL resolves relative to baseUrl's path, not root.
|
|
92
|
+
const relativePath = path.startsWith('/') ? path.slice(1) : path;
|
|
93
|
+
let url = new URL(relativePath, baseUrl.replace(/\/?$/, '/')).href;
|
|
94
|
+
if (query) {
|
|
95
|
+
const u = new URL(url);
|
|
96
|
+
for (const q of query) {
|
|
97
|
+
const [key, ...rest] = q.split('=');
|
|
98
|
+
if (key)
|
|
99
|
+
u.searchParams.set(key, rest.join('='));
|
|
100
|
+
}
|
|
101
|
+
url = u.href;
|
|
102
|
+
}
|
|
103
|
+
return url;
|
|
104
|
+
}
|
|
105
|
+
// ── Internal helpers ─────────────────────────────────────────────────────────
|
|
106
|
+
function extractPathParameters(raw) {
|
|
107
|
+
if (!Array.isArray(raw))
|
|
108
|
+
return [];
|
|
109
|
+
const results = [];
|
|
110
|
+
for (const p of raw) {
|
|
111
|
+
if (!p || typeof p !== 'object')
|
|
112
|
+
continue;
|
|
113
|
+
const param = p;
|
|
114
|
+
if (param.in !== 'path' || typeof param.name !== 'string')
|
|
115
|
+
continue;
|
|
116
|
+
results.push(param.schema && typeof param.schema === 'object'
|
|
117
|
+
? {
|
|
118
|
+
name: param.name,
|
|
119
|
+
in: 'path',
|
|
120
|
+
schema: param.schema,
|
|
121
|
+
example: param.example,
|
|
122
|
+
}
|
|
123
|
+
: { name: param.name, in: 'path', example: param.example });
|
|
124
|
+
}
|
|
125
|
+
return results;
|
|
126
|
+
}
|
|
127
|
+
function mergeParameters(base, override) {
|
|
128
|
+
const merged = [...base];
|
|
129
|
+
for (const p of override) {
|
|
130
|
+
const idx = merged.findIndex((m) => m.name === p.name);
|
|
131
|
+
if (idx >= 0)
|
|
132
|
+
merged[idx] = p;
|
|
133
|
+
else
|
|
134
|
+
merged.push(p);
|
|
135
|
+
}
|
|
136
|
+
return merged;
|
|
137
|
+
}
|
|
138
|
+
function substitutePathParams(path, params) {
|
|
139
|
+
return path.replace(/\{([^}]+)\}/g, (match, name) => {
|
|
140
|
+
const param = params.find((p) => p.name === name && p.in === 'path');
|
|
141
|
+
if (!param)
|
|
142
|
+
return match;
|
|
143
|
+
const value = param.example ?? param.schema?.example ?? param.schema?.default;
|
|
144
|
+
if (value === undefined)
|
|
145
|
+
return match;
|
|
146
|
+
return encodeURIComponent(String(value));
|
|
147
|
+
});
|
|
148
|
+
}
|
|
56
149
|
function generateValueFromSchema(schema) {
|
|
57
150
|
if (schema.const !== undefined)
|
|
58
151
|
return schema.const;
|
|
@@ -62,14 +155,14 @@ function generateValueFromSchema(schema) {
|
|
|
62
155
|
return schema.default;
|
|
63
156
|
switch (schema.type) {
|
|
64
157
|
case 'string': {
|
|
158
|
+
if (schema.enum && Array.isArray(schema.enum))
|
|
159
|
+
return schema.enum[0];
|
|
65
160
|
if (schema.format === 'email')
|
|
66
161
|
return 'test@example.com';
|
|
67
162
|
if (schema.format === 'uuid')
|
|
68
163
|
return '00000000-0000-0000-0000-000000000000';
|
|
69
164
|
if (schema.format === 'uri' || schema.format === 'url')
|
|
70
165
|
return 'https://example.com';
|
|
71
|
-
if (schema.enum && Array.isArray(schema.enum))
|
|
72
|
-
return schema.enum[0];
|
|
73
166
|
return 'test';
|
|
74
167
|
}
|
|
75
168
|
case 'number':
|
|
@@ -96,33 +189,4 @@ function generateValueFromSchema(schema) {
|
|
|
96
189
|
return null;
|
|
97
190
|
}
|
|
98
191
|
}
|
|
99
|
-
// Looks up the requestBody schema for an endpoint in the OpenAPI doc and
|
|
100
|
-
// returns a JSON string suitable for the request. Uses the doc's example
|
|
101
|
-
// if one exists, otherwise generates a minimal body from the schema.
|
|
102
|
-
export function extractRequestBodyFromDiscovery(doc, endpoint) {
|
|
103
|
-
const paths = doc.paths;
|
|
104
|
-
if (!paths)
|
|
105
|
-
return undefined;
|
|
106
|
-
const pathItem = paths[endpoint.path];
|
|
107
|
-
if (!pathItem)
|
|
108
|
-
return undefined;
|
|
109
|
-
const op = pathItem[endpoint.method.toLowerCase()];
|
|
110
|
-
if (!op?.requestBody)
|
|
111
|
-
return undefined;
|
|
112
|
-
const rb = op.requestBody;
|
|
113
|
-
const content = rb.content;
|
|
114
|
-
const jsonContent = content?.['application/json'];
|
|
115
|
-
if (!jsonContent)
|
|
116
|
-
return undefined;
|
|
117
|
-
if (jsonContent.example)
|
|
118
|
-
return JSON.stringify(jsonContent.example);
|
|
119
|
-
const schema = jsonContent.schema;
|
|
120
|
-
if (!schema || schema.type !== 'object')
|
|
121
|
-
return undefined;
|
|
122
|
-
const result = generateValueFromSchema(schema);
|
|
123
|
-
if (result && typeof result === 'object' && Object.keys(result).length > 0) {
|
|
124
|
-
return JSON.stringify(result);
|
|
125
|
-
}
|
|
126
|
-
return undefined;
|
|
127
|
-
}
|
|
128
192
|
//# sourceMappingURL=discovery.js.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"discovery.js","sourceRoot":"","sources":["../../../src/cli/validate/discovery.ts"],"names":[],"mappings":"AACA,OAAO,EAAE,gBAAgB,EAAE,YAAY,EAAE,MAAM,cAAc,CAAA;AAE7D,MAAM,CAAC,KAAK,UAAU,iBAAiB,CACrC,OAAe;IAEf,MAAM,GAAG,GAAG,IAAI,GAAG,CAAC,
|
|
1
|
+
{"version":3,"file":"discovery.js","sourceRoot":"","sources":["../../../src/cli/validate/discovery.ts"],"names":[],"mappings":"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"}
|
|
@@ -8,6 +8,20 @@ export type EndpointSpec = {
|
|
|
8
8
|
method: string;
|
|
9
9
|
path: string;
|
|
10
10
|
amount?: string | undefined;
|
|
11
|
+
parameters?: PathParameter[] | undefined;
|
|
12
|
+
};
|
|
13
|
+
export type PathParameter = {
|
|
14
|
+
name: string;
|
|
15
|
+
in: 'path' | 'query' | 'header' | 'cookie';
|
|
16
|
+
schema?: {
|
|
17
|
+
type?: string;
|
|
18
|
+
format?: string;
|
|
19
|
+
pattern?: string;
|
|
20
|
+
enum?: unknown[];
|
|
21
|
+
example?: unknown;
|
|
22
|
+
default?: unknown;
|
|
23
|
+
};
|
|
24
|
+
example?: unknown;
|
|
11
25
|
};
|
|
12
26
|
export declare function check(label: string, detail?: string): CheckResult;
|
|
13
27
|
export declare function fail(label: string, detail?: string, hint?: string): CheckResult;
|
|
@@ -23,7 +37,6 @@ export type Counts = {
|
|
|
23
37
|
};
|
|
24
38
|
export declare function printResults(results: CheckResult[], counts: Counts): void;
|
|
25
39
|
export declare function fetchWithTimeout(url: string, init: RequestInit, timeoutMs?: number): Promise<Response>;
|
|
26
|
-
export declare function buildUrl(baseUrl: string, endpoint: EndpointSpec, query?: string[]): string;
|
|
27
40
|
export declare function formatBytes(bytes: number): string;
|
|
28
41
|
export declare const HTTP_METHODS: Set<string>;
|
|
29
42
|
export declare function isValidAddress(addr: unknown): boolean;
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"helpers.d.ts","sourceRoot":"","sources":["../../../src/cli/validate/helpers.ts"],"names":[],"mappings":"AAEA,MAAM,MAAM,WAAW,GAAG;IACxB,KAAK,EAAE,MAAM,CAAA;IACb,MAAM,CAAC,EAAE,MAAM,GAAG,SAAS,CAAA;IAC3B,IAAI,CAAC,EAAE,MAAM,GAAG,SAAS,CAAA;IACzB,QAAQ,EAAE,MAAM,GAAG,MAAM,GAAG,MAAM,GAAG,MAAM,CAAA;CAC5C,CAAA;AAED,MAAM,MAAM,YAAY,GAAG;IACzB,MAAM,EAAE,MAAM,CAAA;IACd,IAAI,EAAE,MAAM,CAAA;IACZ,MAAM,CAAC,EAAE,MAAM,GAAG,SAAS,CAAA;
|
|
1
|
+
{"version":3,"file":"helpers.d.ts","sourceRoot":"","sources":["../../../src/cli/validate/helpers.ts"],"names":[],"mappings":"AAEA,MAAM,MAAM,WAAW,GAAG;IACxB,KAAK,EAAE,MAAM,CAAA;IACb,MAAM,CAAC,EAAE,MAAM,GAAG,SAAS,CAAA;IAC3B,IAAI,CAAC,EAAE,MAAM,GAAG,SAAS,CAAA;IACzB,QAAQ,EAAE,MAAM,GAAG,MAAM,GAAG,MAAM,GAAG,MAAM,CAAA;CAC5C,CAAA;AAED,MAAM,MAAM,YAAY,GAAG;IACzB,MAAM,EAAE,MAAM,CAAA;IACd,IAAI,EAAE,MAAM,CAAA;IACZ,MAAM,CAAC,EAAE,MAAM,GAAG,SAAS,CAAA;IAC3B,UAAU,CAAC,EAAE,aAAa,EAAE,GAAG,SAAS,CAAA;CACzC,CAAA;AAED,MAAM,MAAM,aAAa,GAAG;IAC1B,IAAI,EAAE,MAAM,CAAA;IACZ,EAAE,EAAE,MAAM,GAAG,OAAO,GAAG,QAAQ,GAAG,QAAQ,CAAA;IAC1C,MAAM,CAAC,EAAE;QACP,IAAI,CAAC,EAAE,MAAM,CAAA;QACb,MAAM,CAAC,EAAE,MAAM,CAAA;QACf,OAAO,CAAC,EAAE,MAAM,CAAA;QAChB,IAAI,CAAC,EAAE,OAAO,EAAE,CAAA;QAChB,OAAO,CAAC,EAAE,OAAO,CAAA;QACjB,OAAO,CAAC,EAAE,OAAO,CAAA;KAClB,CAAA;IACD,OAAO,CAAC,EAAE,OAAO,CAAA;CAClB,CAAA;AAED,wBAAgB,KAAK,CAAC,KAAK,EAAE,MAAM,EAAE,MAAM,CAAC,EAAE,MAAM,GAAG,WAAW,CAEjE;AAED,wBAAgB,IAAI,CAAC,KAAK,EAAE,MAAM,EAAE,MAAM,CAAC,EAAE,MAAM,EAAE,IAAI,CAAC,EAAE,MAAM,GAAG,WAAW,CAK/E;AAED,wBAAgB,IAAI,CAAC,KAAK,EAAE,MAAM,EAAE,MAAM,CAAC,EAAE,MAAM,EAAE,IAAI,CAAC,EAAE,MAAM,GAAG,WAAW,CAK/E;AAED,wBAAgB,IAAI,CAAC,KAAK,EAAE,MAAM,EAAE,MAAM,CAAC,EAAE,MAAM,EAAE,IAAI,CAAC,EAAE,MAAM,GAAG,WAAW,CAI/E;AASD,wBAAgB,UAAU,CAAC,MAAM,EAAE,WAAW,QAO7C;AAED,wBAAgB,YAAY,CAAC,KAAK,EAAE,MAAM,QAEzC;AAED,MAAM,MAAM,MAAM,GAAG;IAAE,MAAM,EAAE,MAAM,CAAC;IAAC,MAAM,EAAE,MAAM,CAAC;IAAC,QAAQ,EAAE,MAAM,CAAC;IAAC,OAAO,EAAE,MAAM,CAAA;CAAE,CAAA;AAE1F,wBAAgB,YAAY,CAAC,OAAO,EAAE,WAAW,EAAE,EAAE,MAAM,EAAE,MAAM,QAQlE;AAED,wBAAsB,gBAAgB,CACpC,GAAG,EAAE,MAAM,EACX,IAAI,EAAE,WAAW,EACjB,SAAS,SAAS,GACjB,OAAO,CAAC,QAAQ,CAAC,CAQnB;AAED,wBAAgB,WAAW,CAAC,KAAK,EAAE,MAAM,GAAG,MAAM,CAIjD;AAED,eAAO,MAAM,YAAY,aASvB,CAAA;AAEF,wBAAgB,cAAc,CAAC,IAAI,EAAE,OAAO,GAAG,OAAO,CAErD;AAED,wBAAgB,oBAAoB,CAAC,MAAM,EAAE,OAAO,GAAG,OAAO,CAE7D;AAED,wBAAgB,gBAAgB,CAAC,KAAK,EAAE,MAAM,GAAG,YAAY,GAAG,IAAI,CASnE;AAID,wBAAgB,sBAAsB,CACpC,OAAO,EAAE,MAAM,GAAG,SAAS,EAC3B,YAAY,EAAE,MAAM,GACnB,MAAM,GAAG,SAAS,CAcpB"}
|
|
@@ -64,19 +64,6 @@ export async function fetchWithTimeout(url, init, timeoutMs = 15_000) {
|
|
|
64
64
|
clearTimeout(timeout);
|
|
65
65
|
}
|
|
66
66
|
}
|
|
67
|
-
export function buildUrl(baseUrl, endpoint, query) {
|
|
68
|
-
let url = new URL(endpoint.path, baseUrl).href;
|
|
69
|
-
if (query) {
|
|
70
|
-
const u = new URL(url);
|
|
71
|
-
for (const q of query) {
|
|
72
|
-
const [key, ...rest] = q.split('=');
|
|
73
|
-
if (key)
|
|
74
|
-
u.searchParams.set(key, rest.join('='));
|
|
75
|
-
}
|
|
76
|
-
url = u.href;
|
|
77
|
-
}
|
|
78
|
-
return url;
|
|
79
|
-
}
|
|
80
67
|
export function formatBytes(bytes) {
|
|
81
68
|
if (bytes < 1024)
|
|
82
69
|
return `${bytes}B`;
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"helpers.js","sourceRoot":"","sources":["../../../src/cli/validate/helpers.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,EAAE,EAAE,MAAM,aAAa,CAAA;
|
|
1
|
+
{"version":3,"file":"helpers.js","sourceRoot":"","sources":["../../../src/cli/validate/helpers.ts"],"names":[],"mappings":"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"}
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../../src/cli/validate/index.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,GAAG,EAAK,MAAM,OAAO,CAAA;
|
|
1
|
+
{"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../../src/cli/validate/index.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,GAAG,EAAK,MAAM,OAAO,CAAA;AAO9B,QAAA,MAAM,QAAQ;;;;;;;;;;;;;;mCAoIZ,CAAA;AAEF,eAAe,QAAQ,CAAA"}
|
|
@@ -1,10 +1,7 @@
|
|
|
1
1
|
import { Cli, z } from 'incur';
|
|
2
|
-
import { validate as
|
|
2
|
+
import { validate as validateCore, validateStream } from '../../validation/core.js';
|
|
3
3
|
import { pc } from '../utils.js';
|
|
4
|
-
import {
|
|
5
|
-
import { extractEndpointsFromDiscovery, extractRequestBodyFromDiscovery, fetchDiscoveryDoc, } from './discovery.js';
|
|
6
|
-
import { check, fail, parseEndpointArg, printCheck, printResults, printSection, resolveBodyForEndpoint, warn, } from './helpers.js';
|
|
7
|
-
import { validatePaymentFlow } from './payment.js';
|
|
4
|
+
import { printResults, printSection } from './helpers.js';
|
|
8
5
|
const validate = Cli.create('validate', {
|
|
9
6
|
description: 'Validate an MPP server implementation end-to-end',
|
|
10
7
|
args: z.object({
|
|
@@ -19,169 +16,123 @@ const validate = Cli.create('validate', {
|
|
|
19
16
|
query: z.array(z.string()).optional().describe('Query parameter (key=value, repeatable)'),
|
|
20
17
|
verbose: z.number().default(0).meta({ count: true }).describe('Verbosity level'),
|
|
21
18
|
yes: z.boolean().default(false).describe('Auto-approve mainnet payments'),
|
|
19
|
+
outputJson: z.boolean().default(false).describe('Output results as JSON'),
|
|
22
20
|
}),
|
|
23
21
|
alias: {
|
|
24
22
|
endpoint: 'e',
|
|
25
23
|
verbose: 'v',
|
|
26
24
|
yes: 'y',
|
|
25
|
+
outputJson: 'j',
|
|
27
26
|
},
|
|
28
27
|
async run(c) {
|
|
28
|
+
// JSON mode: batch everything
|
|
29
|
+
if (c.options.outputJson) {
|
|
30
|
+
const result = await validateCore({
|
|
31
|
+
url: c.args.url,
|
|
32
|
+
endpoint: c.options.endpoint,
|
|
33
|
+
body: c.options.body,
|
|
34
|
+
query: c.options.query,
|
|
35
|
+
verbose: c.options.verbose > 0,
|
|
36
|
+
yes: c.options.yes,
|
|
37
|
+
interactive: false,
|
|
38
|
+
});
|
|
39
|
+
console.log(JSON.stringify(result, null, 2));
|
|
40
|
+
const noEndpoints = result.endpoints.length === 0 && !c.options.endpoint;
|
|
41
|
+
if (result.summary.failed > 0 || !result.discovery.found || noEndpoints)
|
|
42
|
+
process.exit(1);
|
|
43
|
+
return;
|
|
44
|
+
}
|
|
45
|
+
// Streaming human-readable output
|
|
29
46
|
const baseUrl = c.args.url.replace(/\/$/, '').replace(/\/openapi\.json$/i, '');
|
|
30
|
-
const verbose = c.options.verbose > 0;
|
|
31
|
-
const counts = { passed: 0, failed: 0, warnings: 0, skipped: 0 };
|
|
32
47
|
console.log(`\n${pc.bold('mppx validate')} ${pc.dim(baseUrl)}\n`);
|
|
33
|
-
const {
|
|
34
|
-
|
|
35
|
-
|
|
36
|
-
|
|
37
|
-
|
|
48
|
+
const counts = { passed: 0, failed: 0, warnings: 0, skipped: 0 };
|
|
49
|
+
let sawMppEndpoint = false;
|
|
50
|
+
let sawNonMppPaymentEndpoint = false;
|
|
51
|
+
let sawMalformedChallenge = false;
|
|
52
|
+
let sawTestnet = false;
|
|
53
|
+
let sawMainnet = false;
|
|
54
|
+
let paymentSucceeded = false;
|
|
55
|
+
let discoveryFound = false;
|
|
56
|
+
let endpointCount = 0;
|
|
57
|
+
for await (const event of validateStream({
|
|
58
|
+
url: c.args.url,
|
|
38
59
|
endpoint: c.options.endpoint,
|
|
39
60
|
body: c.options.body,
|
|
40
61
|
query: c.options.query,
|
|
62
|
+
verbose: c.options.verbose > 0,
|
|
41
63
|
yes: c.options.yes,
|
|
42
|
-
|
|
43
|
-
|
|
64
|
+
interactive: !!process.stdin.isTTY,
|
|
65
|
+
onPaymentResults: (results) => printResults(results, counts),
|
|
66
|
+
})) {
|
|
67
|
+
switch (event.phase) {
|
|
68
|
+
case 'discovery':
|
|
69
|
+
printSection('Discovery (/openapi.json)');
|
|
70
|
+
printResults(event.results, counts);
|
|
71
|
+
discoveryFound = event.discovery.found;
|
|
72
|
+
if (!discoveryFound && !c.options.endpoint) {
|
|
73
|
+
console.log('');
|
|
74
|
+
console.log(pc.yellow(' No discovery document found.'));
|
|
75
|
+
console.log(pc.dim(' MPP servers must serve an OpenAPI document at /openapi.json with x-payment-info extensions.'));
|
|
76
|
+
console.log(pc.dim(' To test a specific endpoint: mppx validate <url> --endpoint POST:/your/path'));
|
|
77
|
+
console.log('');
|
|
78
|
+
process.exit(1);
|
|
79
|
+
}
|
|
80
|
+
if (event.discovery.endpoints.length === 0 && !c.options.endpoint && discoveryFound) {
|
|
81
|
+
console.log(pc.dim(' Use --endpoint to specify endpoints manually.'));
|
|
82
|
+
console.log('');
|
|
83
|
+
process.exit(1);
|
|
84
|
+
}
|
|
85
|
+
break;
|
|
86
|
+
case 'endpoint':
|
|
87
|
+
endpointCount++;
|
|
88
|
+
printSection(`${event.endpoint.method} ${event.endpoint.path}`);
|
|
89
|
+
break;
|
|
90
|
+
case 'challenge':
|
|
91
|
+
console.log(pc.dim(' Challenge'));
|
|
92
|
+
printResults(event.results, counts);
|
|
93
|
+
if (event.isMpp) {
|
|
94
|
+
sawMppEndpoint = true;
|
|
95
|
+
if (event.isTestnet)
|
|
96
|
+
sawTestnet = true;
|
|
97
|
+
if (event.isMainnet)
|
|
98
|
+
sawMainnet = true;
|
|
99
|
+
}
|
|
100
|
+
if (event.isNonMppPayment)
|
|
101
|
+
sawNonMppPaymentEndpoint = true;
|
|
102
|
+
if (event.isMalformedChallenge)
|
|
103
|
+
sawMalformedChallenge = true;
|
|
104
|
+
break;
|
|
105
|
+
case 'errorHandling':
|
|
106
|
+
console.log(pc.dim(' Error Handling'));
|
|
107
|
+
printResults(event.results, counts);
|
|
108
|
+
break;
|
|
109
|
+
case 'payment':
|
|
110
|
+
if (event.succeeded)
|
|
111
|
+
paymentSucceeded = true;
|
|
112
|
+
break;
|
|
113
|
+
}
|
|
114
|
+
}
|
|
115
|
+
// Summary
|
|
116
|
+
printSummary(counts, {
|
|
117
|
+
sawMppEndpoint,
|
|
118
|
+
sawNonMppPaymentEndpoint,
|
|
119
|
+
sawMalformedChallenge,
|
|
120
|
+
sawTestnet,
|
|
121
|
+
sawMainnet,
|
|
122
|
+
paymentSucceeded,
|
|
123
|
+
}, endpointCount);
|
|
44
124
|
},
|
|
45
125
|
});
|
|
46
126
|
export default validate;
|
|
47
|
-
// Each stage of validation is defined in its own function below.
|
|
48
|
-
async function discoverEndpoints(baseUrl, options, counts) {
|
|
49
|
-
let endpoints = [];
|
|
50
|
-
let discoveryDoc = null;
|
|
51
|
-
printSection('Discovery (/openapi.json)');
|
|
52
|
-
const discoveryResult = await fetchDiscoveryDoc(baseUrl);
|
|
53
|
-
if ('error' in discoveryResult) {
|
|
54
|
-
printCheck(fail('Document found', discoveryResult.error, 'MPP servers must serve an OpenAPI document at /openapi.json with x-payment-info extensions.'));
|
|
55
|
-
counts.failed++;
|
|
56
|
-
if (!options.endpoint) {
|
|
57
|
-
console.log('');
|
|
58
|
-
console.log(pc.yellow(' No discovery document found.'));
|
|
59
|
-
console.log(pc.dim(' MPP servers must serve an OpenAPI document at /openapi.json with x-payment-info extensions.'));
|
|
60
|
-
console.log(pc.dim(' To test a specific endpoint: mppx validate <url> --endpoint POST:/your/path'));
|
|
61
|
-
console.log('');
|
|
62
|
-
return { endpoints, discoveryDoc, shouldExit: true };
|
|
63
|
-
}
|
|
64
|
-
}
|
|
65
|
-
else {
|
|
66
|
-
printCheck(check('Document found and parseable'));
|
|
67
|
-
counts.passed++;
|
|
68
|
-
const issues = validateDiscovery(discoveryResult.doc);
|
|
69
|
-
const errors = issues.filter((i) => i.severity === 'error');
|
|
70
|
-
const warnings = issues.filter((i) => i.severity === 'warning');
|
|
71
|
-
if (errors.length > 0) {
|
|
72
|
-
printCheck(fail('Valid OpenAPI structure', `${errors.length} error(s)`));
|
|
73
|
-
counts.failed++;
|
|
74
|
-
for (const issue of errors) {
|
|
75
|
-
console.log(pc.dim(` ${issue.path}: ${issue.message}`));
|
|
76
|
-
}
|
|
77
|
-
}
|
|
78
|
-
else {
|
|
79
|
-
printCheck(check('Valid OpenAPI structure'));
|
|
80
|
-
counts.passed++;
|
|
81
|
-
}
|
|
82
|
-
for (const w of warnings) {
|
|
83
|
-
printCheck(warn(w.message, w.path));
|
|
84
|
-
counts.warnings++;
|
|
85
|
-
}
|
|
86
|
-
discoveryDoc = discoveryResult.doc;
|
|
87
|
-
}
|
|
88
|
-
// Resolve endpoints: --endpoint overrides discovery
|
|
89
|
-
if (options.endpoint) {
|
|
90
|
-
const parsed = parseEndpointArg(options.endpoint);
|
|
91
|
-
if (!parsed) {
|
|
92
|
-
console.log(pc.red(`Invalid endpoint format: "${options.endpoint}". Use METHOD:path (e.g. GET:/api/data)`));
|
|
93
|
-
return { endpoints, discoveryDoc, shouldExit: true };
|
|
94
|
-
}
|
|
95
|
-
endpoints.push(parsed);
|
|
96
|
-
}
|
|
97
|
-
else if (discoveryDoc) {
|
|
98
|
-
endpoints = extractEndpointsFromDiscovery(discoveryDoc);
|
|
99
|
-
const NO_AMOUNT = BigInt('999999999999999999');
|
|
100
|
-
endpoints.sort((a, b) => {
|
|
101
|
-
const aAmt = a.amount ? BigInt(a.amount) : NO_AMOUNT;
|
|
102
|
-
const bAmt = b.amount ? BigInt(b.amount) : NO_AMOUNT;
|
|
103
|
-
return aAmt < bAmt ? -1 : aAmt > bAmt ? 1 : 0;
|
|
104
|
-
});
|
|
105
|
-
if (endpoints.length === 0) {
|
|
106
|
-
printCheck(warn('Paid endpoints found', 'No endpoints with x-payment-info'));
|
|
107
|
-
counts.warnings++;
|
|
108
|
-
console.log(pc.dim(' Use --endpoint to specify endpoints manually.'));
|
|
109
|
-
return { endpoints, discoveryDoc, shouldExit: true };
|
|
110
|
-
}
|
|
111
|
-
printCheck(check('Paid endpoints found', `${endpoints.length} endpoint(s)`));
|
|
112
|
-
counts.passed++;
|
|
113
|
-
}
|
|
114
|
-
return { endpoints, discoveryDoc };
|
|
115
|
-
}
|
|
116
|
-
async function validateEndpoints(baseUrl, endpoints, discoveryDoc, counts, options) {
|
|
117
|
-
let sawTestnet = false;
|
|
118
|
-
let sawMainnet = false;
|
|
119
|
-
let paymentSucceeded = false;
|
|
120
|
-
let sawMppEndpoint = false;
|
|
121
|
-
let sawNonMppPaymentEndpoint = false;
|
|
122
|
-
for (const endpoint of endpoints) {
|
|
123
|
-
printSection(`${endpoint.method} ${endpoint.path}`);
|
|
124
|
-
// With --endpoint, --body is used directly. In discovery mode, resolve per-path or auto-generate.
|
|
125
|
-
let body;
|
|
126
|
-
if (options.endpoint) {
|
|
127
|
-
body = options.body;
|
|
128
|
-
}
|
|
129
|
-
else {
|
|
130
|
-
body = resolveBodyForEndpoint(options.body, endpoint.path);
|
|
131
|
-
if (!body && discoveryDoc) {
|
|
132
|
-
body = extractRequestBodyFromDiscovery(discoveryDoc, endpoint);
|
|
133
|
-
if (body && options.verbose) {
|
|
134
|
-
console.log(pc.dim(` Auto-generated body: ${body}`));
|
|
135
|
-
}
|
|
136
|
-
}
|
|
137
|
-
}
|
|
138
|
-
// Challenge
|
|
139
|
-
console.log(pc.dim(' Challenge'));
|
|
140
|
-
const { results: challengeResults, resolvedBody } = await validateChallenge(baseUrl, endpoint, options.verbose, {
|
|
141
|
-
body,
|
|
142
|
-
query: options.query,
|
|
143
|
-
discoveryDoc: discoveryDoc ?? undefined,
|
|
144
|
-
});
|
|
145
|
-
const effectiveBody = resolvedBody ?? body;
|
|
146
|
-
printResults(challengeResults, counts);
|
|
147
|
-
const isMppEndpoint = challengeResults.some((r) => r.severity === 'pass' && r.label === 'Challenge parseable');
|
|
148
|
-
if (!isMppEndpoint) {
|
|
149
|
-
if (challengeResults.some((r) => r.label === 'Not an MPP endpoint'))
|
|
150
|
-
sawNonMppPaymentEndpoint = true;
|
|
151
|
-
continue;
|
|
152
|
-
}
|
|
153
|
-
sawMppEndpoint = true;
|
|
154
|
-
const isTestnetEndpoint = challengeResults.some((r) => r.severity === 'pass' && r.label === 'Valid currency address' && r.detail === 'testnet');
|
|
155
|
-
if (isTestnetEndpoint)
|
|
156
|
-
sawTestnet = true;
|
|
157
|
-
else
|
|
158
|
-
sawMainnet = true;
|
|
159
|
-
// Error Handling
|
|
160
|
-
console.log(pc.dim(' Error Handling'));
|
|
161
|
-
const errorResults = await validateErrorHandling(baseUrl, endpoint, {
|
|
162
|
-
body: effectiveBody,
|
|
163
|
-
query: options.query,
|
|
164
|
-
});
|
|
165
|
-
printResults(errorResults, counts);
|
|
166
|
-
// Payment
|
|
167
|
-
console.log(pc.dim(' Payment'));
|
|
168
|
-
const paymentResults = await validatePaymentFlow(baseUrl, endpoint, options.verbose, {
|
|
169
|
-
body: effectiveBody,
|
|
170
|
-
query: options.query,
|
|
171
|
-
yes: options.yes,
|
|
172
|
-
});
|
|
173
|
-
printResults(paymentResults, counts);
|
|
174
|
-
if (paymentResults.some((r) => r.severity === 'pass' && r.label === 'Payment: successful')) {
|
|
175
|
-
paymentSucceeded = true;
|
|
176
|
-
}
|
|
177
|
-
}
|
|
178
|
-
return { sawMppEndpoint, sawNonMppPaymentEndpoint, sawTestnet, sawMainnet, paymentSucceeded };
|
|
179
|
-
}
|
|
180
127
|
function printSummary(counts, flags, endpointsLength) {
|
|
181
|
-
// No MPP endpoints found
|
|
182
128
|
if (!flags.sawMppEndpoint && endpointsLength > 0) {
|
|
183
129
|
console.log('');
|
|
184
|
-
if (flags.
|
|
130
|
+
if (flags.sawMalformedChallenge) {
|
|
131
|
+
console.log(pc.yellow(` Payment scheme detected but challenge format is invalid on ${endpointsLength} endpoint(s).`));
|
|
132
|
+
console.log(pc.dim(' The server uses WWW-Authenticate: Payment but the challenge parameters do not conform to MPP.'));
|
|
133
|
+
console.log(pc.dim(' Fix: encode payment details as base64url JSON in a request="..." parameter. See errors above.'));
|
|
134
|
+
}
|
|
135
|
+
else if (flags.sawNonMppPaymentEndpoint) {
|
|
185
136
|
console.log(pc.yellow(` No MPP endpoints found. Tested ${endpointsLength} endpoint(s) but none use WWW-Authenticate: Payment.`));
|
|
186
137
|
console.log(pc.dim(' This server may use x402 or another payment protocol.'));
|
|
187
138
|
}
|
|
@@ -196,7 +147,6 @@ function printSummary(counts, flags, endpointsLength) {
|
|
|
196
147
|
console.log('');
|
|
197
148
|
process.exit(1);
|
|
198
149
|
}
|
|
199
|
-
// Summary
|
|
200
150
|
console.log('');
|
|
201
151
|
const parts = [];
|
|
202
152
|
if (counts.passed > 0)
|
|
@@ -208,14 +158,13 @@ function printSummary(counts, flags, endpointsLength) {
|
|
|
208
158
|
if (counts.skipped > 0)
|
|
209
159
|
parts.push(pc.yellow(`${counts.skipped} skipped`));
|
|
210
160
|
console.log(`${pc.bold('Summary:')} ${parts.join(', ')}`);
|
|
211
|
-
// Cross-promotion
|
|
212
161
|
if (flags.paymentSucceeded && flags.sawTestnet && !flags.sawMainnet) {
|
|
213
162
|
console.log('');
|
|
214
|
-
console.log(pc.dim(' Tip: validate your mainnet server
|
|
163
|
+
console.log(pc.dim(' Tip: also validate your mainnet server to confirm real payments work end-to-end.'));
|
|
215
164
|
}
|
|
216
165
|
else if (flags.sawMainnet && !flags.sawTestnet) {
|
|
217
166
|
console.log('');
|
|
218
|
-
console.log(pc.dim(' Tip: validate
|
|
167
|
+
console.log(pc.dim(' Tip: also validate your testnet server for free. This CLI automatically provisions and funds a testnet wallet for testing.'));
|
|
219
168
|
}
|
|
220
169
|
console.log('');
|
|
221
170
|
if (counts.failed > 0)
|