@probemesh/sdk 0.1.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/LICENSE +22 -0
- package/README.md +160 -0
- package/dist/chunk-257Y7LN2.js +827 -0
- package/dist/chunk-257Y7LN2.js.map +1 -0
- package/dist/chunk-2ASMVLG4.js +56 -0
- package/dist/chunk-2ASMVLG4.js.map +1 -0
- package/dist/chunk-2KWGHJYP.js +285 -0
- package/dist/chunk-2KWGHJYP.js.map +1 -0
- package/dist/chunk-3H7UGVI6.js +1117 -0
- package/dist/chunk-3H7UGVI6.js.map +1 -0
- package/dist/chunk-5Q3PDYIA.js +657 -0
- package/dist/chunk-5Q3PDYIA.js.map +1 -0
- package/dist/chunk-CXZOO3U4.js +550 -0
- package/dist/chunk-CXZOO3U4.js.map +1 -0
- package/dist/chunk-FRFBK4SY.js +270 -0
- package/dist/chunk-FRFBK4SY.js.map +1 -0
- package/dist/chunk-HJK52QJF.js +994 -0
- package/dist/chunk-HJK52QJF.js.map +1 -0
- package/dist/chunk-HNBDX7IU.js +705 -0
- package/dist/chunk-HNBDX7IU.js.map +1 -0
- package/dist/chunk-NYTV263W.js +116 -0
- package/dist/chunk-NYTV263W.js.map +1 -0
- package/dist/chunk-PXG54XOG.js +595 -0
- package/dist/chunk-PXG54XOG.js.map +1 -0
- package/dist/chunk-TDOBAMYM.js +607 -0
- package/dist/chunk-TDOBAMYM.js.map +1 -0
- package/dist/chunk-TV42EZSI.js +2157 -0
- package/dist/chunk-TV42EZSI.js.map +1 -0
- package/dist/chunk-UU2ZG7P7.js +408 -0
- package/dist/chunk-UU2ZG7P7.js.map +1 -0
- package/dist/chunk-WKN7QOCA.js +977 -0
- package/dist/chunk-WKN7QOCA.js.map +1 -0
- package/dist/chunk-ZJOLPBJJ.js +1091 -0
- package/dist/chunk-ZJOLPBJJ.js.map +1 -0
- package/dist/cli/audit-trail-export.cjs +1193 -0
- package/dist/cli/audit-trail-export.cjs.map +1 -0
- package/dist/cli/audit-trail-export.d.cts +1 -0
- package/dist/cli/audit-trail-export.d.ts +1 -0
- package/dist/cli/audit-trail-export.js +24 -0
- package/dist/cli/audit-trail-export.js.map +1 -0
- package/dist/cli/catalog-check.cjs +2687 -0
- package/dist/cli/catalog-check.cjs.map +1 -0
- package/dist/cli/catalog-check.d.cts +1 -0
- package/dist/cli/catalog-check.d.ts +1 -0
- package/dist/cli/catalog-check.js +26 -0
- package/dist/cli/catalog-check.js.map +1 -0
- package/dist/cli/probemesh-init.cjs +1049 -0
- package/dist/cli/probemesh-init.cjs.map +1 -0
- package/dist/cli/probemesh-init.d.cts +1 -0
- package/dist/cli/probemesh-init.d.ts +1 -0
- package/dist/cli/probemesh-init.js +22 -0
- package/dist/cli/probemesh-init.js.map +1 -0
- package/dist/cli/provider-conformance.cjs +6180 -0
- package/dist/cli/provider-conformance.cjs.map +1 -0
- package/dist/cli/provider-conformance.d.cts +1 -0
- package/dist/cli/provider-conformance.d.ts +1 -0
- package/dist/cli/provider-conformance.js +29 -0
- package/dist/cli/provider-conformance.js.map +1 -0
- package/dist/cli/provider-dossier-check.cjs +2978 -0
- package/dist/cli/provider-dossier-check.cjs.map +1 -0
- package/dist/cli/provider-dossier-check.d.cts +1 -0
- package/dist/cli/provider-dossier-check.d.ts +1 -0
- package/dist/cli/provider-dossier-check.js +27 -0
- package/dist/cli/provider-dossier-check.js.map +1 -0
- package/dist/cli/provider-dossier.cjs +1753 -0
- package/dist/cli/provider-dossier.cjs.map +1 -0
- package/dist/cli/provider-dossier.d.cts +1 -0
- package/dist/cli/provider-dossier.d.ts +1 -0
- package/dist/cli/provider-dossier.js +26 -0
- package/dist/cli/provider-dossier.js.map +1 -0
- package/dist/cli/x402-accept.cjs +6009 -0
- package/dist/cli/x402-accept.cjs.map +1 -0
- package/dist/cli/x402-accept.d.cts +1 -0
- package/dist/cli/x402-accept.d.ts +1 -0
- package/dist/cli/x402-accept.js +28 -0
- package/dist/cli/x402-accept.js.map +1 -0
- package/dist/index.cjs +13671 -0
- package/dist/index.cjs.map +1 -0
- package/dist/index.d.cts +2026 -0
- package/dist/index.d.ts +2026 -0
- package/dist/index.js +2560 -0
- package/dist/index.js.map +1 -0
- package/package.json +111 -0
|
@@ -0,0 +1,827 @@
|
|
|
1
|
+
import {
|
|
2
|
+
createProbeMesh,
|
|
3
|
+
startHostedRouter
|
|
4
|
+
} from "./chunk-TV42EZSI.js";
|
|
5
|
+
import {
|
|
6
|
+
createProviderCatalogArtifact,
|
|
7
|
+
formatProviderCatalogArtifact
|
|
8
|
+
} from "./chunk-3H7UGVI6.js";
|
|
9
|
+
import {
|
|
10
|
+
loadCliConfigDefault,
|
|
11
|
+
redactX402Secrets
|
|
12
|
+
} from "./chunk-NYTV263W.js";
|
|
13
|
+
import {
|
|
14
|
+
ProbeMeshError,
|
|
15
|
+
isProbeMeshError
|
|
16
|
+
} from "./chunk-2ASMVLG4.js";
|
|
17
|
+
|
|
18
|
+
// src/protocols/x402Acceptance.ts
|
|
19
|
+
var DEFAULT_REQUIRED_RECEIPT_TYPES = [
|
|
20
|
+
"payment_proof",
|
|
21
|
+
"settlement_confirmation",
|
|
22
|
+
"provider_delivery"
|
|
23
|
+
];
|
|
24
|
+
async function runX402ProviderAcceptance(options) {
|
|
25
|
+
assertAcceptanceOptions(options);
|
|
26
|
+
const telemetryEvents = [];
|
|
27
|
+
const requiredReceiptTypes = options.requiredReceiptTypes ?? DEFAULT_REQUIRED_RECEIPT_TYPES;
|
|
28
|
+
const hostedRouter = await startHostedRouter({
|
|
29
|
+
port: 0,
|
|
30
|
+
adapters: options.adapters,
|
|
31
|
+
apiKeys: options.apiKey ? [options.apiKey] : void 0,
|
|
32
|
+
onTelemetryEvent(event) {
|
|
33
|
+
telemetryEvents.push(event);
|
|
34
|
+
}
|
|
35
|
+
});
|
|
36
|
+
let response;
|
|
37
|
+
let error;
|
|
38
|
+
try {
|
|
39
|
+
const probemesh = createProbeMesh({
|
|
40
|
+
hosted: {
|
|
41
|
+
baseUrl: hostedRouter.url,
|
|
42
|
+
apiKey: options.apiKey
|
|
43
|
+
}
|
|
44
|
+
});
|
|
45
|
+
try {
|
|
46
|
+
response = await probemesh.call(options.request);
|
|
47
|
+
} catch (caught) {
|
|
48
|
+
error = toAcceptanceError(caught);
|
|
49
|
+
}
|
|
50
|
+
} finally {
|
|
51
|
+
await hostedRouter.close();
|
|
52
|
+
}
|
|
53
|
+
const baseChecks = createAcceptanceChecks({
|
|
54
|
+
response,
|
|
55
|
+
error,
|
|
56
|
+
telemetryEvents,
|
|
57
|
+
expectedProviderId: options.expectedProviderId,
|
|
58
|
+
requiredReceiptTypes
|
|
59
|
+
});
|
|
60
|
+
const checks = [
|
|
61
|
+
...baseChecks,
|
|
62
|
+
createSecretSafeOutputCheck({
|
|
63
|
+
response,
|
|
64
|
+
error,
|
|
65
|
+
telemetryEvents,
|
|
66
|
+
checks: baseChecks,
|
|
67
|
+
requiredReceiptTypes,
|
|
68
|
+
forbiddenOutputValues: options.forbiddenOutputValues ?? []
|
|
69
|
+
})
|
|
70
|
+
];
|
|
71
|
+
const status = checks.every((check) => check.status === "passed") ? "passed" : "failed";
|
|
72
|
+
const forbiddenOutputValues = options.forbiddenOutputValues ?? [];
|
|
73
|
+
const sanitizedChecks = sanitizeAcceptanceOutput(checks, forbiddenOutputValues);
|
|
74
|
+
const sanitizedResponse = sanitizeAcceptanceOutput(response, forbiddenOutputValues);
|
|
75
|
+
const sanitizedError = sanitizeAcceptanceOutput(error, forbiddenOutputValues);
|
|
76
|
+
const sanitizedTelemetryEvents = sanitizeAcceptanceOutput(
|
|
77
|
+
telemetryEvents,
|
|
78
|
+
forbiddenOutputValues
|
|
79
|
+
);
|
|
80
|
+
return {
|
|
81
|
+
status,
|
|
82
|
+
checks: sanitizedChecks,
|
|
83
|
+
response: sanitizedResponse,
|
|
84
|
+
error: sanitizedError,
|
|
85
|
+
telemetryEvents: sanitizedTelemetryEvents,
|
|
86
|
+
summary: createSummary({
|
|
87
|
+
status,
|
|
88
|
+
checks: sanitizedChecks,
|
|
89
|
+
response: sanitizedResponse,
|
|
90
|
+
error: sanitizedError,
|
|
91
|
+
telemetryEvents: sanitizedTelemetryEvents,
|
|
92
|
+
requiredReceiptTypes
|
|
93
|
+
})
|
|
94
|
+
};
|
|
95
|
+
}
|
|
96
|
+
function summarizeX402AcceptanceResult(result) {
|
|
97
|
+
return createSummary({
|
|
98
|
+
status: result.status,
|
|
99
|
+
checks: result.checks,
|
|
100
|
+
response: result.response,
|
|
101
|
+
error: result.error,
|
|
102
|
+
telemetryEvents: result.telemetryEvents,
|
|
103
|
+
requiredReceiptTypes: result.summary.requiredReceiptTypes
|
|
104
|
+
});
|
|
105
|
+
}
|
|
106
|
+
function evaluateX402ProviderAcceptanceGate(result, options = {}) {
|
|
107
|
+
const requiredCheckNames = options.requiredCheckNames ?? result.checks.map((check) => check.name);
|
|
108
|
+
const failedRequiredCheckNames = requiredCheckNames.filter((checkName) => {
|
|
109
|
+
const check = result.checks.find((candidate) => candidate.name === checkName);
|
|
110
|
+
return check?.status !== "passed";
|
|
111
|
+
});
|
|
112
|
+
const reasons = createGateReasons({
|
|
113
|
+
result,
|
|
114
|
+
requiredCheckNames,
|
|
115
|
+
failedRequiredCheckNames
|
|
116
|
+
});
|
|
117
|
+
const accepted = result.status === "passed" && failedRequiredCheckNames.length === 0;
|
|
118
|
+
return {
|
|
119
|
+
accepted,
|
|
120
|
+
status: accepted ? "accepted" : "rejected",
|
|
121
|
+
requiredCheckNames: [...requiredCheckNames],
|
|
122
|
+
failedRequiredCheckNames,
|
|
123
|
+
reasons: accepted ? ["All required x402 provider acceptance checks passed."] : reasons
|
|
124
|
+
};
|
|
125
|
+
}
|
|
126
|
+
function createX402ProviderAcceptanceReport(result, options = {}) {
|
|
127
|
+
const summary = summarizeX402AcceptanceResult(result);
|
|
128
|
+
const receiptRefs = result.response?.receiptRefs ?? result.error?.receiptRefs;
|
|
129
|
+
const report = {
|
|
130
|
+
title: options.title ?? "x402 Provider Acceptance Report",
|
|
131
|
+
status: result.status,
|
|
132
|
+
gate: evaluateX402ProviderAcceptanceGate(result, options.gate),
|
|
133
|
+
summary,
|
|
134
|
+
checks: result.checks,
|
|
135
|
+
receipts: summarizeAcceptanceReceipts(receiptRefs),
|
|
136
|
+
route: summary.route,
|
|
137
|
+
timelineEventTypes: summary.timelineEventTypes,
|
|
138
|
+
telemetryEventTypes: summary.telemetryEventTypes,
|
|
139
|
+
safety: summary.safety,
|
|
140
|
+
retrySafety: summary.retrySafety,
|
|
141
|
+
error: result.error
|
|
142
|
+
};
|
|
143
|
+
return sanitizeAcceptanceOutput(report, options.forbiddenOutputValues ?? []);
|
|
144
|
+
}
|
|
145
|
+
function formatX402ProviderAcceptanceReport(report, options = {}) {
|
|
146
|
+
const sanitizedReport = sanitizeAcceptanceOutput(report, []);
|
|
147
|
+
if ((options.format ?? "markdown") === "json") {
|
|
148
|
+
return JSON.stringify(sanitizedReport, null, 2);
|
|
149
|
+
}
|
|
150
|
+
return formatAcceptanceReportMarkdown(sanitizedReport);
|
|
151
|
+
}
|
|
152
|
+
function createAcceptanceChecks(options) {
|
|
153
|
+
return [
|
|
154
|
+
completedResponseCheck(options.response, options.error),
|
|
155
|
+
selectedProviderCheck(
|
|
156
|
+
options.response,
|
|
157
|
+
options.error,
|
|
158
|
+
options.expectedProviderId
|
|
159
|
+
),
|
|
160
|
+
routeMetadataCheck(options.response, options.error),
|
|
161
|
+
timelineEventsCheck(options.response, options.error),
|
|
162
|
+
requiredReceiptsCheck(options.response, options.error, options.requiredReceiptTypes),
|
|
163
|
+
safetySettledDeliveredCheck(options.response, options.error),
|
|
164
|
+
retrySafetyAfterSuccessCheck(options.response, options.error),
|
|
165
|
+
telemetryMatchesTimelineCheck(options.response, options.telemetryEvents)
|
|
166
|
+
];
|
|
167
|
+
}
|
|
168
|
+
function createGateReasons(options) {
|
|
169
|
+
const reasons = [];
|
|
170
|
+
if (options.result.status !== "passed") {
|
|
171
|
+
reasons.push(`Acceptance result status is "${options.result.status}".`);
|
|
172
|
+
}
|
|
173
|
+
for (const checkName of options.failedRequiredCheckNames) {
|
|
174
|
+
const check = options.result.checks.find(
|
|
175
|
+
(candidate) => candidate.name === checkName
|
|
176
|
+
);
|
|
177
|
+
if (!check) {
|
|
178
|
+
reasons.push(`Required check "${checkName}" was not found.`);
|
|
179
|
+
continue;
|
|
180
|
+
}
|
|
181
|
+
reasons.push(`Required check "${checkName}" failed: ${check.message}`);
|
|
182
|
+
}
|
|
183
|
+
return reasons;
|
|
184
|
+
}
|
|
185
|
+
function summarizeAcceptanceReceipts(receiptRefs) {
|
|
186
|
+
const receipts = receiptRefs ?? [];
|
|
187
|
+
const byType = {};
|
|
188
|
+
for (const receiptRef of receipts) {
|
|
189
|
+
byType[receiptRef.type] = (byType[receiptRef.type] ?? 0) + 1;
|
|
190
|
+
}
|
|
191
|
+
return {
|
|
192
|
+
total: receipts.length,
|
|
193
|
+
types: getReceiptTypes(receipts),
|
|
194
|
+
providers: [
|
|
195
|
+
...new Set(receipts.map((receiptRef) => receiptRef.provider))
|
|
196
|
+
],
|
|
197
|
+
byType,
|
|
198
|
+
hasPaymentProof: receipts.some(
|
|
199
|
+
(receiptRef) => receiptRef.type === "payment_proof"
|
|
200
|
+
),
|
|
201
|
+
hasSettlementConfirmation: receipts.some(
|
|
202
|
+
(receiptRef) => receiptRef.type === "settlement_confirmation"
|
|
203
|
+
),
|
|
204
|
+
hasProviderDelivery: receipts.some(
|
|
205
|
+
(receiptRef) => receiptRef.type === "provider_delivery"
|
|
206
|
+
)
|
|
207
|
+
};
|
|
208
|
+
}
|
|
209
|
+
function formatAcceptanceReportMarkdown(report) {
|
|
210
|
+
const lines = [
|
|
211
|
+
`# ${report.title}`,
|
|
212
|
+
"",
|
|
213
|
+
`Gate: ${report.gate.status}`,
|
|
214
|
+
`Acceptance: ${report.status}`,
|
|
215
|
+
`Provider: ${report.summary.providerId ?? "unknown"}`,
|
|
216
|
+
`Call: ${report.summary.callId ?? "unknown"}`,
|
|
217
|
+
`Error: ${report.summary.errorCode ?? "none"}`,
|
|
218
|
+
"",
|
|
219
|
+
"## Gate Reasons",
|
|
220
|
+
...formatList(report.gate.reasons),
|
|
221
|
+
"",
|
|
222
|
+
"## Checks",
|
|
223
|
+
...report.checks.map(
|
|
224
|
+
(check) => `- [${check.status === "passed" ? "x" : " "}] ${check.name}: ${check.message}`
|
|
225
|
+
),
|
|
226
|
+
"",
|
|
227
|
+
"## Receipts",
|
|
228
|
+
`- Total: ${report.receipts.total}`,
|
|
229
|
+
`- Types: ${formatInlineList(report.receipts.types)}`,
|
|
230
|
+
`- Providers: ${formatInlineList(report.receipts.providers)}`,
|
|
231
|
+
`- Payment proof: ${String(report.receipts.hasPaymentProof)}`,
|
|
232
|
+
`- Settlement confirmation: ${String(
|
|
233
|
+
report.receipts.hasSettlementConfirmation
|
|
234
|
+
)}`,
|
|
235
|
+
`- Provider delivery: ${String(report.receipts.hasProviderDelivery)}`,
|
|
236
|
+
"",
|
|
237
|
+
"## Route",
|
|
238
|
+
`- Route ID: ${report.route?.routeId ?? "none"}`,
|
|
239
|
+
`- Selected provider: ${report.route?.selectedProviderId ?? "none"}`,
|
|
240
|
+
`- Fallback used: ${String(report.route?.fallbackUsed ?? false)}`,
|
|
241
|
+
`- Stop reason: ${report.route?.stopReason ?? "none"}`,
|
|
242
|
+
"",
|
|
243
|
+
"## Safety",
|
|
244
|
+
`- Payment: ${report.safety?.paymentStatus ?? "unknown"}`,
|
|
245
|
+
`- Settlement: ${report.safety?.settlementStatus ?? "unknown"}`,
|
|
246
|
+
`- Delivery: ${report.safety?.deliveryStatus ?? "unknown"}`,
|
|
247
|
+
`- Money may have moved: ${String(
|
|
248
|
+
report.safety?.moneyMayHaveMoved ?? false
|
|
249
|
+
)}`,
|
|
250
|
+
"",
|
|
251
|
+
"## Retry Safety",
|
|
252
|
+
`- Retryable: ${String(report.retrySafety?.retryable ?? false)}`,
|
|
253
|
+
`- Safe to auto retry: ${String(
|
|
254
|
+
report.retrySafety?.safeToAutoRetry ?? false
|
|
255
|
+
)}`,
|
|
256
|
+
`- Reason: ${report.retrySafety?.reason ?? "unknown"}`,
|
|
257
|
+
"",
|
|
258
|
+
"## Timeline",
|
|
259
|
+
`- Events: ${formatInlineList(report.timelineEventTypes)}`,
|
|
260
|
+
`- Telemetry: ${formatInlineList(report.telemetryEventTypes)}`
|
|
261
|
+
];
|
|
262
|
+
return `${lines.join("\n")}
|
|
263
|
+
`;
|
|
264
|
+
}
|
|
265
|
+
function formatList(values) {
|
|
266
|
+
if (values.length === 0) {
|
|
267
|
+
return ["- none"];
|
|
268
|
+
}
|
|
269
|
+
return values.map((value) => `- ${value}`);
|
|
270
|
+
}
|
|
271
|
+
function formatInlineList(values) {
|
|
272
|
+
return values.length > 0 ? values.join(", ") : "none";
|
|
273
|
+
}
|
|
274
|
+
function completedResponseCheck(response, error) {
|
|
275
|
+
if (response?.status === "completed") {
|
|
276
|
+
return pass("completed_response", "Hosted x402 call completed.");
|
|
277
|
+
}
|
|
278
|
+
return fail(
|
|
279
|
+
"completed_response",
|
|
280
|
+
error ? `Hosted x402 call failed with ${error.code}.` : "Hosted x402 call did not return a completed response.",
|
|
281
|
+
{
|
|
282
|
+
errorCode: error?.code,
|
|
283
|
+
errorMessage: error?.message
|
|
284
|
+
}
|
|
285
|
+
);
|
|
286
|
+
}
|
|
287
|
+
function selectedProviderCheck(response, error, expectedProviderId) {
|
|
288
|
+
const providerId = response?.provider.id;
|
|
289
|
+
if (providerId && (!expectedProviderId || providerId === expectedProviderId)) {
|
|
290
|
+
return pass("selected_provider", "Hosted route selected the expected provider.", {
|
|
291
|
+
providerId
|
|
292
|
+
});
|
|
293
|
+
}
|
|
294
|
+
return fail("selected_provider", "Hosted route did not select the expected provider.", {
|
|
295
|
+
expectedProviderId,
|
|
296
|
+
providerId,
|
|
297
|
+
errorProvider: error?.provider
|
|
298
|
+
});
|
|
299
|
+
}
|
|
300
|
+
function routeMetadataCheck(response, error) {
|
|
301
|
+
if (response?.route?.mode === "hosted" && typeof response.route.routeId === "string" && response.route.routeId.length > 0) {
|
|
302
|
+
return pass("route_metadata", "Hosted route metadata is present.", {
|
|
303
|
+
routeId: response.route.routeId,
|
|
304
|
+
selectedProviderId: response.route.selectedProviderId
|
|
305
|
+
});
|
|
306
|
+
}
|
|
307
|
+
return fail("route_metadata", "Hosted route metadata is missing.", {
|
|
308
|
+
errorRouteId: error?.route?.routeId
|
|
309
|
+
});
|
|
310
|
+
}
|
|
311
|
+
function timelineEventsCheck(response, error) {
|
|
312
|
+
const timelineEventTypes = response?.timeline?.events.map((event) => event.type) ?? [];
|
|
313
|
+
const requiredEvents = [
|
|
314
|
+
"call.requested",
|
|
315
|
+
"provider.attempted",
|
|
316
|
+
"provider.selected",
|
|
317
|
+
"payment.attempted",
|
|
318
|
+
"receipt.recorded",
|
|
319
|
+
"call.completed"
|
|
320
|
+
];
|
|
321
|
+
const missingEvents = requiredEvents.filter(
|
|
322
|
+
(eventType) => !timelineEventTypes.includes(eventType)
|
|
323
|
+
);
|
|
324
|
+
if (missingEvents.length === 0) {
|
|
325
|
+
return pass("timeline_events", "Hosted timeline contains the x402 acceptance events.", {
|
|
326
|
+
timelineEventTypes
|
|
327
|
+
});
|
|
328
|
+
}
|
|
329
|
+
return fail("timeline_events", "Hosted timeline is missing required x402 events.", {
|
|
330
|
+
missingEvents,
|
|
331
|
+
timelineEventTypes,
|
|
332
|
+
errorTimelineEventTypes: error?.timeline?.events.map((event) => event.type)
|
|
333
|
+
});
|
|
334
|
+
}
|
|
335
|
+
function requiredReceiptsCheck(response, error, requiredReceiptTypes) {
|
|
336
|
+
const receiptTypes = getReceiptTypes(response?.receiptRefs);
|
|
337
|
+
const missingReceiptTypes = requiredReceiptTypes.filter(
|
|
338
|
+
(receiptType) => !receiptTypes.includes(receiptType)
|
|
339
|
+
);
|
|
340
|
+
if (missingReceiptTypes.length === 0) {
|
|
341
|
+
return pass("required_receipts", "Required x402 receipts are present.", {
|
|
342
|
+
receiptTypes
|
|
343
|
+
});
|
|
344
|
+
}
|
|
345
|
+
return fail("required_receipts", "Required x402 receipts are missing.", {
|
|
346
|
+
missingReceiptTypes,
|
|
347
|
+
receiptTypes,
|
|
348
|
+
errorReceiptTypes: getReceiptTypes(error?.receiptRefs)
|
|
349
|
+
});
|
|
350
|
+
}
|
|
351
|
+
function safetySettledDeliveredCheck(response, error) {
|
|
352
|
+
const safety = response?.safety;
|
|
353
|
+
if (safety?.paymentStatus === "authorized" && safety.settlementStatus === "settled" && safety.deliveryStatus === "delivered" && safety.moneyMayHaveMoved === true) {
|
|
354
|
+
return pass("safety_settled_delivered", "Safety metadata proves authorized, settled delivery.", {
|
|
355
|
+
safety
|
|
356
|
+
});
|
|
357
|
+
}
|
|
358
|
+
return fail(
|
|
359
|
+
"safety_settled_delivered",
|
|
360
|
+
"Safety metadata does not prove settled delivery.",
|
|
361
|
+
{
|
|
362
|
+
safety,
|
|
363
|
+
errorSafety: error?.safety
|
|
364
|
+
}
|
|
365
|
+
);
|
|
366
|
+
}
|
|
367
|
+
function retrySafetyAfterSuccessCheck(response, error) {
|
|
368
|
+
const retrySafety = response?.retrySafety;
|
|
369
|
+
if (retrySafety?.retryable === false && retrySafety.safeToAutoRetry === false && retrySafety.reason === "completed") {
|
|
370
|
+
return pass("retry_safety_after_success", "Completed paid call is not retryable.", {
|
|
371
|
+
retrySafety
|
|
372
|
+
});
|
|
373
|
+
}
|
|
374
|
+
return fail(
|
|
375
|
+
"retry_safety_after_success",
|
|
376
|
+
"Completed paid call retry safety is missing or incorrect.",
|
|
377
|
+
{
|
|
378
|
+
retrySafety,
|
|
379
|
+
errorRetrySafety: error?.retrySafety
|
|
380
|
+
}
|
|
381
|
+
);
|
|
382
|
+
}
|
|
383
|
+
function telemetryMatchesTimelineCheck(response, telemetryEvents) {
|
|
384
|
+
const timelineEventTypes = response?.timeline?.events.map((event) => event.type) ?? [];
|
|
385
|
+
const telemetryEventTypes = telemetryEvents.map((event) => event.type);
|
|
386
|
+
const matches = timelineEventTypes.length > 0 && timelineEventTypes.length === telemetryEventTypes.length && timelineEventTypes.every(
|
|
387
|
+
(eventType, index) => eventType === telemetryEventTypes[index]
|
|
388
|
+
);
|
|
389
|
+
if (matches) {
|
|
390
|
+
return pass("telemetry_matches_timeline", "Telemetry mirrors the hosted timeline.", {
|
|
391
|
+
telemetryEventTypes
|
|
392
|
+
});
|
|
393
|
+
}
|
|
394
|
+
return fail("telemetry_matches_timeline", "Telemetry does not mirror the hosted timeline.", {
|
|
395
|
+
timelineEventTypes,
|
|
396
|
+
telemetryEventTypes
|
|
397
|
+
});
|
|
398
|
+
}
|
|
399
|
+
function createSecretSafeOutputCheck(options) {
|
|
400
|
+
const forbiddenOutputValues = options.forbiddenOutputValues.filter(
|
|
401
|
+
(value) => value.length > 0
|
|
402
|
+
);
|
|
403
|
+
const candidate = {
|
|
404
|
+
response: options.response,
|
|
405
|
+
error: options.error,
|
|
406
|
+
telemetryEvents: options.telemetryEvents,
|
|
407
|
+
checks: options.checks,
|
|
408
|
+
summary: createSummary({
|
|
409
|
+
status: options.checks.every((check) => check.status === "passed") ? "passed" : "failed",
|
|
410
|
+
checks: options.checks,
|
|
411
|
+
response: options.response,
|
|
412
|
+
error: options.error,
|
|
413
|
+
telemetryEvents: options.telemetryEvents,
|
|
414
|
+
requiredReceiptTypes: options.requiredReceiptTypes
|
|
415
|
+
})
|
|
416
|
+
};
|
|
417
|
+
const serialized = JSON.stringify(candidate);
|
|
418
|
+
const leakedValues = forbiddenOutputValues.filter(
|
|
419
|
+
(value) => serialized.includes(value)
|
|
420
|
+
);
|
|
421
|
+
if (leakedValues.length === 0) {
|
|
422
|
+
return pass("secret_safe_output", "Serialized acceptance output contains no forbidden values.", {
|
|
423
|
+
checkedForbiddenValueCount: forbiddenOutputValues.length
|
|
424
|
+
});
|
|
425
|
+
}
|
|
426
|
+
return fail("secret_safe_output", "Serialized acceptance output contains forbidden values.", {
|
|
427
|
+
leakedValueCount: leakedValues.length
|
|
428
|
+
});
|
|
429
|
+
}
|
|
430
|
+
function createSummary(options) {
|
|
431
|
+
const receiptRefs = options.response?.receiptRefs ?? options.error?.receiptRefs;
|
|
432
|
+
const timeline = options.response?.timeline ?? options.error?.timeline;
|
|
433
|
+
const route = options.response?.route ?? options.error?.route;
|
|
434
|
+
const failedCheckNames = options.checks.filter((check) => check.status === "failed").map((check) => check.name);
|
|
435
|
+
return {
|
|
436
|
+
status: options.status,
|
|
437
|
+
totalChecks: options.checks.length,
|
|
438
|
+
passedChecks: options.checks.length - failedCheckNames.length,
|
|
439
|
+
failedChecks: failedCheckNames.length,
|
|
440
|
+
failedCheckNames,
|
|
441
|
+
callId: options.response?.callId ?? options.error?.callId,
|
|
442
|
+
providerId: options.response?.provider.id ?? options.error?.provider,
|
|
443
|
+
errorCode: options.error?.code,
|
|
444
|
+
receiptTypes: getReceiptTypes(receiptRefs),
|
|
445
|
+
requiredReceiptTypes: [...options.requiredReceiptTypes],
|
|
446
|
+
timelineEventTypes: timeline?.events.map((event) => event.type) ?? [],
|
|
447
|
+
telemetryEventTypes: options.telemetryEvents.map((event) => event.type),
|
|
448
|
+
safety: options.response?.safety ?? options.error?.safety,
|
|
449
|
+
retrySafety: options.response?.retrySafety ?? options.error?.retrySafety,
|
|
450
|
+
route: route ? {
|
|
451
|
+
routeId: route.routeId,
|
|
452
|
+
selectedProviderId: route.selectedProviderId,
|
|
453
|
+
fallbackUsed: route.explanation?.fallbackUsed,
|
|
454
|
+
fallbackCount: route.explanation?.fallbackCount,
|
|
455
|
+
stopReason: route.explanation?.stopReason
|
|
456
|
+
} : void 0
|
|
457
|
+
};
|
|
458
|
+
}
|
|
459
|
+
function toAcceptanceError(error) {
|
|
460
|
+
if (isProbeMeshError(error)) {
|
|
461
|
+
return {
|
|
462
|
+
name: "ProbeMeshError",
|
|
463
|
+
code: error.code,
|
|
464
|
+
message: error.message,
|
|
465
|
+
status: "failed",
|
|
466
|
+
capability: error.capability,
|
|
467
|
+
provider: error.provider,
|
|
468
|
+
callId: error.callId,
|
|
469
|
+
receiptRefs: error.receiptRefs,
|
|
470
|
+
safety: error.safety,
|
|
471
|
+
timeline: error.timeline,
|
|
472
|
+
retrySafety: error.retrySafety,
|
|
473
|
+
route: error.route
|
|
474
|
+
};
|
|
475
|
+
}
|
|
476
|
+
return {
|
|
477
|
+
name: "ProbeMeshError",
|
|
478
|
+
code: "provider_unavailable",
|
|
479
|
+
message: error instanceof Error ? error.message : "x402 provider acceptance call failed.",
|
|
480
|
+
status: "failed"
|
|
481
|
+
};
|
|
482
|
+
}
|
|
483
|
+
function getReceiptTypes(receiptRefs) {
|
|
484
|
+
return [...new Set((receiptRefs ?? []).map((receiptRef) => receiptRef.type))];
|
|
485
|
+
}
|
|
486
|
+
function sanitizeAcceptanceOutput(value, forbiddenOutputValues) {
|
|
487
|
+
const forbiddenValues = forbiddenOutputValues.filter((entry) => entry.length > 0);
|
|
488
|
+
return redactX402Secrets(
|
|
489
|
+
replaceForbiddenValues(value, forbiddenValues, /* @__PURE__ */ new WeakSet())
|
|
490
|
+
);
|
|
491
|
+
}
|
|
492
|
+
function replaceForbiddenValues(value, forbiddenValues, seen) {
|
|
493
|
+
if (typeof value === "string") {
|
|
494
|
+
return forbiddenValues.reduce(
|
|
495
|
+
(current, forbidden) => current.split(forbidden).join("[REDACTED]"),
|
|
496
|
+
value
|
|
497
|
+
);
|
|
498
|
+
}
|
|
499
|
+
if (value === null || typeof value !== "object" || value instanceof Date) {
|
|
500
|
+
return value;
|
|
501
|
+
}
|
|
502
|
+
if (seen.has(value)) {
|
|
503
|
+
return "[Circular]";
|
|
504
|
+
}
|
|
505
|
+
seen.add(value);
|
|
506
|
+
if (Array.isArray(value)) {
|
|
507
|
+
const entries2 = value.map(
|
|
508
|
+
(entry) => replaceForbiddenValues(entry, forbiddenValues, seen)
|
|
509
|
+
);
|
|
510
|
+
seen.delete(value);
|
|
511
|
+
return entries2;
|
|
512
|
+
}
|
|
513
|
+
const entries = Object.fromEntries(
|
|
514
|
+
Object.entries(value).map(([key, entry]) => [
|
|
515
|
+
key,
|
|
516
|
+
replaceForbiddenValues(entry, forbiddenValues, seen)
|
|
517
|
+
])
|
|
518
|
+
);
|
|
519
|
+
seen.delete(value);
|
|
520
|
+
return entries;
|
|
521
|
+
}
|
|
522
|
+
function pass(name, message, details) {
|
|
523
|
+
return {
|
|
524
|
+
name,
|
|
525
|
+
status: "passed",
|
|
526
|
+
message,
|
|
527
|
+
details
|
|
528
|
+
};
|
|
529
|
+
}
|
|
530
|
+
function fail(name, message, details) {
|
|
531
|
+
return {
|
|
532
|
+
name,
|
|
533
|
+
status: "failed",
|
|
534
|
+
message,
|
|
535
|
+
details
|
|
536
|
+
};
|
|
537
|
+
}
|
|
538
|
+
function assertAcceptanceOptions(options) {
|
|
539
|
+
if (!options || typeof options !== "object" || Array.isArray(options)) {
|
|
540
|
+
throw invalidOptions("x402 acceptance options must be an object.");
|
|
541
|
+
}
|
|
542
|
+
if (!Array.isArray(options.adapters) || options.adapters.length === 0) {
|
|
543
|
+
throw invalidOptions("x402 acceptance options require at least one adapter.");
|
|
544
|
+
}
|
|
545
|
+
if (!options.request || typeof options.request !== "object" || Array.isArray(options.request)) {
|
|
546
|
+
throw invalidOptions("x402 acceptance options require a call request object.");
|
|
547
|
+
}
|
|
548
|
+
if (options.apiKey !== void 0 && (typeof options.apiKey !== "string" || options.apiKey.length === 0)) {
|
|
549
|
+
throw invalidOptions("x402 acceptance apiKey must be a non-empty string.");
|
|
550
|
+
}
|
|
551
|
+
if (options.expectedProviderId !== void 0 && (typeof options.expectedProviderId !== "string" || options.expectedProviderId.length === 0)) {
|
|
552
|
+
throw invalidOptions(
|
|
553
|
+
"x402 acceptance expectedProviderId must be a non-empty string."
|
|
554
|
+
);
|
|
555
|
+
}
|
|
556
|
+
if (options.requiredReceiptTypes !== void 0 && (!Array.isArray(options.requiredReceiptTypes) || options.requiredReceiptTypes.some(
|
|
557
|
+
(receiptType) => typeof receiptType !== "string" || receiptType.length === 0
|
|
558
|
+
))) {
|
|
559
|
+
throw invalidOptions(
|
|
560
|
+
"x402 acceptance requiredReceiptTypes must be an array of receipt type strings."
|
|
561
|
+
);
|
|
562
|
+
}
|
|
563
|
+
if (options.forbiddenOutputValues !== void 0 && (!Array.isArray(options.forbiddenOutputValues) || options.forbiddenOutputValues.some((value) => typeof value !== "string"))) {
|
|
564
|
+
throw invalidOptions(
|
|
565
|
+
"x402 acceptance forbiddenOutputValues must be an array of strings."
|
|
566
|
+
);
|
|
567
|
+
}
|
|
568
|
+
}
|
|
569
|
+
function invalidOptions(message) {
|
|
570
|
+
return new ProbeMeshError({
|
|
571
|
+
code: "invalid_request",
|
|
572
|
+
message
|
|
573
|
+
});
|
|
574
|
+
}
|
|
575
|
+
|
|
576
|
+
// src/cli/x402AcceptanceCli.ts
|
|
577
|
+
import { mkdir, writeFile } from "fs/promises";
|
|
578
|
+
import { dirname, resolve } from "path";
|
|
579
|
+
var USAGE = `Usage: probemesh-x402-accept --config <path> [--format markdown|json] [--out-json <path>] [--out-md <path>] [--out-catalog <path>] [--title <text>]`;
|
|
580
|
+
async function runX402ProviderAcceptanceCli(options = {}) {
|
|
581
|
+
const argv = options.argv ?? [];
|
|
582
|
+
const cwd = options.cwd ?? process.cwd();
|
|
583
|
+
try {
|
|
584
|
+
const parsedArgs = parseCliArgs(argv);
|
|
585
|
+
if (parsedArgs.help) {
|
|
586
|
+
return {
|
|
587
|
+
exitCode: 0,
|
|
588
|
+
skipped: true,
|
|
589
|
+
stdout: `${USAGE}
|
|
590
|
+
`
|
|
591
|
+
};
|
|
592
|
+
}
|
|
593
|
+
if (!parsedArgs.configPath) {
|
|
594
|
+
return cliFailure("--config <path> is required.");
|
|
595
|
+
}
|
|
596
|
+
const configExport = await loadCliConfig(parsedArgs.configPath, {
|
|
597
|
+
argv,
|
|
598
|
+
cwd
|
|
599
|
+
});
|
|
600
|
+
if (isCliSkip(configExport)) {
|
|
601
|
+
return {
|
|
602
|
+
exitCode: 0,
|
|
603
|
+
skipped: true,
|
|
604
|
+
skip: configExport,
|
|
605
|
+
stdout: `x402 acceptance skipped: ${configExport.reason}
|
|
606
|
+
`
|
|
607
|
+
};
|
|
608
|
+
}
|
|
609
|
+
assertCliConfig(configExport);
|
|
610
|
+
const result = await runX402ProviderAcceptance(configExport.acceptance);
|
|
611
|
+
const report = createX402ProviderAcceptanceReport(result, {
|
|
612
|
+
...configExport.report ?? {},
|
|
613
|
+
title: parsedArgs.title ?? configExport.report?.title,
|
|
614
|
+
forbiddenOutputValues: mergeForbiddenOutputValues(configExport)
|
|
615
|
+
});
|
|
616
|
+
const selectedFormat = parsedArgs.format ?? configExport.report?.format ?? "markdown";
|
|
617
|
+
const stdout = formatX402ProviderAcceptanceReport(report, {
|
|
618
|
+
format: selectedFormat
|
|
619
|
+
});
|
|
620
|
+
const catalogArtifact = createOptionalCatalogArtifact(
|
|
621
|
+
configExport,
|
|
622
|
+
report,
|
|
623
|
+
parsedArgs.outCatalog
|
|
624
|
+
);
|
|
625
|
+
const artifactPaths = await writeArtifacts({
|
|
626
|
+
cwd,
|
|
627
|
+
report,
|
|
628
|
+
catalogArtifact,
|
|
629
|
+
outputs: {
|
|
630
|
+
json: parsedArgs.outJson ?? configExport.outputs?.json,
|
|
631
|
+
markdown: parsedArgs.outMarkdown ?? configExport.outputs?.markdown,
|
|
632
|
+
catalog: parsedArgs.outCatalog ?? configExport.outputs?.catalog
|
|
633
|
+
}
|
|
634
|
+
});
|
|
635
|
+
return {
|
|
636
|
+
exitCode: report.gate.accepted ? 0 : 1,
|
|
637
|
+
skipped: false,
|
|
638
|
+
report,
|
|
639
|
+
catalogArtifact,
|
|
640
|
+
stdout,
|
|
641
|
+
artifactPaths
|
|
642
|
+
};
|
|
643
|
+
} catch (error) {
|
|
644
|
+
return cliFailure(error instanceof Error ? error.message : "Unknown CLI failure.");
|
|
645
|
+
}
|
|
646
|
+
}
|
|
647
|
+
function parseCliArgs(argv) {
|
|
648
|
+
const parsedArgs = {};
|
|
649
|
+
for (let index = 0; index < argv.length; index += 1) {
|
|
650
|
+
const arg = argv[index];
|
|
651
|
+
if (arg === "--") {
|
|
652
|
+
continue;
|
|
653
|
+
}
|
|
654
|
+
if (arg === "--help" || arg === "-h") {
|
|
655
|
+
parsedArgs.help = true;
|
|
656
|
+
continue;
|
|
657
|
+
}
|
|
658
|
+
if (arg === "--config") {
|
|
659
|
+
parsedArgs.configPath = requireValue(argv, index, arg);
|
|
660
|
+
index += 1;
|
|
661
|
+
continue;
|
|
662
|
+
}
|
|
663
|
+
if (arg === "--format") {
|
|
664
|
+
const format = requireValue(argv, index, arg);
|
|
665
|
+
if (format !== "markdown" && format !== "json") {
|
|
666
|
+
throw new Error("--format must be markdown or json.");
|
|
667
|
+
}
|
|
668
|
+
parsedArgs.format = format;
|
|
669
|
+
index += 1;
|
|
670
|
+
continue;
|
|
671
|
+
}
|
|
672
|
+
if (arg === "--out-json") {
|
|
673
|
+
parsedArgs.outJson = requireValue(argv, index, arg);
|
|
674
|
+
index += 1;
|
|
675
|
+
continue;
|
|
676
|
+
}
|
|
677
|
+
if (arg === "--out-md") {
|
|
678
|
+
parsedArgs.outMarkdown = requireValue(argv, index, arg);
|
|
679
|
+
index += 1;
|
|
680
|
+
continue;
|
|
681
|
+
}
|
|
682
|
+
if (arg === "--out-catalog") {
|
|
683
|
+
parsedArgs.outCatalog = requireValue(argv, index, arg);
|
|
684
|
+
index += 1;
|
|
685
|
+
continue;
|
|
686
|
+
}
|
|
687
|
+
if (arg === "--title") {
|
|
688
|
+
parsedArgs.title = requireValue(argv, index, arg);
|
|
689
|
+
index += 1;
|
|
690
|
+
continue;
|
|
691
|
+
}
|
|
692
|
+
throw new Error(`Unknown argument "${arg}".`);
|
|
693
|
+
}
|
|
694
|
+
return parsedArgs;
|
|
695
|
+
}
|
|
696
|
+
function requireValue(argv, index, flag) {
|
|
697
|
+
const value = argv[index + 1];
|
|
698
|
+
if (!value || value.startsWith("--")) {
|
|
699
|
+
throw new Error(`${flag} requires a value.`);
|
|
700
|
+
}
|
|
701
|
+
return value;
|
|
702
|
+
}
|
|
703
|
+
async function loadCliConfig(configPath, context) {
|
|
704
|
+
const configExport = await loadCliConfigDefault(configPath, context.cwd);
|
|
705
|
+
if (typeof configExport === "function") {
|
|
706
|
+
return configExport(context);
|
|
707
|
+
}
|
|
708
|
+
return configExport;
|
|
709
|
+
}
|
|
710
|
+
function isCliSkip(value) {
|
|
711
|
+
return !!value && typeof value === "object" && !Array.isArray(value) && value.skip === true && typeof value.reason === "string";
|
|
712
|
+
}
|
|
713
|
+
function assertCliConfig(value) {
|
|
714
|
+
if (!value || typeof value !== "object" || Array.isArray(value)) {
|
|
715
|
+
throw new Error("x402 acceptance CLI config must export an object.");
|
|
716
|
+
}
|
|
717
|
+
if (!("acceptance" in value) || !value.acceptance || typeof value.acceptance !== "object") {
|
|
718
|
+
throw new Error("x402 acceptance CLI config requires acceptance options.");
|
|
719
|
+
}
|
|
720
|
+
const outputs = value.outputs;
|
|
721
|
+
if (outputs !== void 0 && (!outputs || typeof outputs !== "object" || Array.isArray(outputs) || outputs.json !== void 0 && typeof outputs.json !== "string" || outputs.markdown !== void 0 && typeof outputs.markdown !== "string" || outputs.catalog !== void 0 && typeof outputs.catalog !== "string")) {
|
|
722
|
+
throw new Error("x402 acceptance CLI outputs must contain string paths.");
|
|
723
|
+
}
|
|
724
|
+
const catalog = value.catalog;
|
|
725
|
+
if (catalog !== void 0) {
|
|
726
|
+
if (!catalog || typeof catalog !== "object" || Array.isArray(catalog)) {
|
|
727
|
+
throw new Error("x402 acceptance CLI catalog config must be an object.");
|
|
728
|
+
}
|
|
729
|
+
if (!("manifest" in catalog) || !catalog.manifest || typeof catalog.manifest !== "object") {
|
|
730
|
+
throw new Error("x402 acceptance CLI catalog config requires manifest.");
|
|
731
|
+
}
|
|
732
|
+
if (catalog.artifactId !== void 0 && typeof catalog.artifactId !== "string") {
|
|
733
|
+
throw new Error("x402 acceptance CLI catalog artifactId must be a string.");
|
|
734
|
+
}
|
|
735
|
+
if (catalog.generatedAt !== void 0 && typeof catalog.generatedAt !== "string") {
|
|
736
|
+
throw new Error("x402 acceptance CLI catalog generatedAt must be a string.");
|
|
737
|
+
}
|
|
738
|
+
}
|
|
739
|
+
}
|
|
740
|
+
function mergeForbiddenOutputValues(config) {
|
|
741
|
+
return [
|
|
742
|
+
...config.acceptance.forbiddenOutputValues ?? [],
|
|
743
|
+
...config.report?.forbiddenOutputValues ?? []
|
|
744
|
+
];
|
|
745
|
+
}
|
|
746
|
+
function createOptionalCatalogArtifact(config, report, requestedCatalogOutput) {
|
|
747
|
+
if (!config.catalog) {
|
|
748
|
+
if (requestedCatalogOutput ?? config.outputs?.catalog) {
|
|
749
|
+
throw new Error(
|
|
750
|
+
"x402 acceptance CLI catalog output requires catalog manifest config."
|
|
751
|
+
);
|
|
752
|
+
}
|
|
753
|
+
return void 0;
|
|
754
|
+
}
|
|
755
|
+
return createProviderCatalogArtifact({
|
|
756
|
+
manifest: config.catalog.manifest,
|
|
757
|
+
acceptanceReport: report,
|
|
758
|
+
artifactId: config.catalog.artifactId,
|
|
759
|
+
generatedAt: config.catalog.generatedAt,
|
|
760
|
+
forbiddenOutputValues: mergeForbiddenOutputValues(config)
|
|
761
|
+
});
|
|
762
|
+
}
|
|
763
|
+
async function writeArtifacts(options) {
|
|
764
|
+
const artifactPaths = {};
|
|
765
|
+
if (options.outputs.json) {
|
|
766
|
+
const outputPath = resolve(options.cwd, options.outputs.json);
|
|
767
|
+
await writeArtifact(
|
|
768
|
+
outputPath,
|
|
769
|
+
formatX402ProviderAcceptanceReport(options.report, {
|
|
770
|
+
format: "json"
|
|
771
|
+
})
|
|
772
|
+
);
|
|
773
|
+
artifactPaths.json = outputPath;
|
|
774
|
+
}
|
|
775
|
+
if (options.outputs.markdown) {
|
|
776
|
+
const outputPath = resolve(options.cwd, options.outputs.markdown);
|
|
777
|
+
await writeArtifact(
|
|
778
|
+
outputPath,
|
|
779
|
+
formatX402ProviderAcceptanceReport(options.report, {
|
|
780
|
+
format: "markdown"
|
|
781
|
+
})
|
|
782
|
+
);
|
|
783
|
+
artifactPaths.markdown = outputPath;
|
|
784
|
+
}
|
|
785
|
+
if (options.outputs.catalog) {
|
|
786
|
+
if (!options.catalogArtifact) {
|
|
787
|
+
throw new Error(
|
|
788
|
+
"x402 acceptance CLI catalog output requires a catalog artifact."
|
|
789
|
+
);
|
|
790
|
+
}
|
|
791
|
+
const outputPath = resolve(options.cwd, options.outputs.catalog);
|
|
792
|
+
await writeArtifact(
|
|
793
|
+
outputPath,
|
|
794
|
+
formatProviderCatalogArtifact(options.catalogArtifact, {
|
|
795
|
+
format: "json"
|
|
796
|
+
})
|
|
797
|
+
);
|
|
798
|
+
artifactPaths.catalog = outputPath;
|
|
799
|
+
}
|
|
800
|
+
return artifactPaths;
|
|
801
|
+
}
|
|
802
|
+
async function writeArtifact(outputPath, body) {
|
|
803
|
+
await mkdir(dirname(outputPath), {
|
|
804
|
+
recursive: true
|
|
805
|
+
});
|
|
806
|
+
await writeFile(outputPath, body, "utf8");
|
|
807
|
+
}
|
|
808
|
+
function cliFailure(message) {
|
|
809
|
+
return {
|
|
810
|
+
exitCode: 2,
|
|
811
|
+
skipped: false,
|
|
812
|
+
stdout: "",
|
|
813
|
+
stderr: `${message}
|
|
814
|
+
${USAGE}
|
|
815
|
+
`
|
|
816
|
+
};
|
|
817
|
+
}
|
|
818
|
+
|
|
819
|
+
export {
|
|
820
|
+
runX402ProviderAcceptance,
|
|
821
|
+
summarizeX402AcceptanceResult,
|
|
822
|
+
evaluateX402ProviderAcceptanceGate,
|
|
823
|
+
createX402ProviderAcceptanceReport,
|
|
824
|
+
formatX402ProviderAcceptanceReport,
|
|
825
|
+
runX402ProviderAcceptanceCli
|
|
826
|
+
};
|
|
827
|
+
//# sourceMappingURL=chunk-257Y7LN2.js.map
|