@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
package/dist/index.js
ADDED
|
@@ -0,0 +1,2560 @@
|
|
|
1
|
+
import {
|
|
2
|
+
PROBEMESH_AUDIT_TRAIL_BUNDLE_SCHEMA_VERSION,
|
|
3
|
+
assertProbeMeshAuditTrailBundle,
|
|
4
|
+
createProbeMeshAuditTrailBundle,
|
|
5
|
+
createProbeMeshAuditTrailCollector,
|
|
6
|
+
formatProbeMeshAuditTrailBundle,
|
|
7
|
+
runProbeMeshAuditTrailExportCli,
|
|
8
|
+
summarizeProbeMeshAuditTrailBundle,
|
|
9
|
+
validateProbeMeshAuditTrailBundle
|
|
10
|
+
} from "./chunk-HNBDX7IU.js";
|
|
11
|
+
import {
|
|
12
|
+
runProviderCatalogPolicyCli
|
|
13
|
+
} from "./chunk-FRFBK4SY.js";
|
|
14
|
+
import {
|
|
15
|
+
getProbeMeshIntegrationTemplate,
|
|
16
|
+
listProbeMeshIntegrationTemplates,
|
|
17
|
+
renderProbeMeshIntegrationTemplate,
|
|
18
|
+
runProbeMeshInitCli
|
|
19
|
+
} from "./chunk-HJK52QJF.js";
|
|
20
|
+
import {
|
|
21
|
+
assertJsonSchemaLikeValue,
|
|
22
|
+
createProviderConformanceReport,
|
|
23
|
+
formatProviderConformanceReport,
|
|
24
|
+
runProviderConformance,
|
|
25
|
+
runProviderConformanceCli,
|
|
26
|
+
validateJsonSchemaLikeValue
|
|
27
|
+
} from "./chunk-WKN7QOCA.js";
|
|
28
|
+
import {
|
|
29
|
+
createHostedCatalogPolicyFromOnboardingDossiers,
|
|
30
|
+
createProviderCatalogFromOnboardingDossiers,
|
|
31
|
+
createProviderOnboardingDossierImportReport,
|
|
32
|
+
evaluateProviderOnboardingDossiers,
|
|
33
|
+
formatProviderOnboardingDossierImportReport,
|
|
34
|
+
parseProviderOnboardingDossierJson,
|
|
35
|
+
runProviderDossierCheckCli
|
|
36
|
+
} from "./chunk-PXG54XOG.js";
|
|
37
|
+
import {
|
|
38
|
+
runProviderOnboardingDossierCli
|
|
39
|
+
} from "./chunk-2KWGHJYP.js";
|
|
40
|
+
import {
|
|
41
|
+
PROVIDER_ONBOARDING_DOSSIER_SCHEMA_VERSION,
|
|
42
|
+
assertProviderOnboardingDossier,
|
|
43
|
+
createProviderOnboardingDossier,
|
|
44
|
+
formatProviderOnboardingDossier,
|
|
45
|
+
validateProviderOnboardingDossier
|
|
46
|
+
} from "./chunk-TDOBAMYM.js";
|
|
47
|
+
import {
|
|
48
|
+
PROVIDER_CONFORMANCE_ARTIFACT_SCHEMA_VERSION,
|
|
49
|
+
assertProviderConformanceArtifact,
|
|
50
|
+
createProviderConformanceArtifact,
|
|
51
|
+
formatProviderConformanceArtifact,
|
|
52
|
+
validateProviderConformanceArtifact
|
|
53
|
+
} from "./chunk-UU2ZG7P7.js";
|
|
54
|
+
import {
|
|
55
|
+
createX402ProviderAcceptanceReport,
|
|
56
|
+
evaluateX402ProviderAcceptanceGate,
|
|
57
|
+
formatX402ProviderAcceptanceReport,
|
|
58
|
+
runX402ProviderAcceptance,
|
|
59
|
+
runX402ProviderAcceptanceCli,
|
|
60
|
+
summarizeX402AcceptanceResult
|
|
61
|
+
} from "./chunk-257Y7LN2.js";
|
|
62
|
+
import {
|
|
63
|
+
createHostedRouter,
|
|
64
|
+
createProbeMesh,
|
|
65
|
+
startHostedRouter
|
|
66
|
+
} from "./chunk-TV42EZSI.js";
|
|
67
|
+
import {
|
|
68
|
+
PROBEMESH_CALL_AUDIT_ARTIFACT_SCHEMA_VERSION,
|
|
69
|
+
assertProbeMeshCallAuditArtifact,
|
|
70
|
+
createProbeMeshCallAuditArtifact,
|
|
71
|
+
formatProbeMeshCallAuditArtifact,
|
|
72
|
+
validateProbeMeshCallAuditArtifact
|
|
73
|
+
} from "./chunk-5Q3PDYIA.js";
|
|
74
|
+
import {
|
|
75
|
+
PROVIDER_CATALOG_POLICY_BUNDLE_SCHEMA_VERSION,
|
|
76
|
+
assertProviderCatalogPolicyBundle,
|
|
77
|
+
createProviderCatalogPolicyBundle,
|
|
78
|
+
formatProviderCatalogPolicyBundle,
|
|
79
|
+
validateProviderCatalogPolicyBundle,
|
|
80
|
+
verifyProviderCatalogPolicyBundleRuntime
|
|
81
|
+
} from "./chunk-CXZOO3U4.js";
|
|
82
|
+
import {
|
|
83
|
+
PROVIDER_CATALOG_SCHEMA_VERSION,
|
|
84
|
+
assertProviderCatalog,
|
|
85
|
+
createProviderCatalog,
|
|
86
|
+
createProviderCatalogPolicyReport,
|
|
87
|
+
evaluateProviderCatalogPolicy,
|
|
88
|
+
findProviderCatalogMatches,
|
|
89
|
+
formatProviderCatalogPolicyReport,
|
|
90
|
+
parseProviderCatalogArtifactJson,
|
|
91
|
+
summarizeProviderCatalog,
|
|
92
|
+
validateProviderCatalog
|
|
93
|
+
} from "./chunk-ZJOLPBJJ.js";
|
|
94
|
+
import {
|
|
95
|
+
PROVIDER_CATALOG_ARTIFACT_SCHEMA_VERSION,
|
|
96
|
+
assertProviderCatalogArtifact,
|
|
97
|
+
assertProviderManifest,
|
|
98
|
+
createProviderCatalogArtifact,
|
|
99
|
+
formatProviderCatalogArtifact,
|
|
100
|
+
getProviderPaymentOptions,
|
|
101
|
+
mergePaymentPreferences,
|
|
102
|
+
resolveProviderPaymentOption,
|
|
103
|
+
validatePaymentStrategy,
|
|
104
|
+
validateProviderCatalogArtifact,
|
|
105
|
+
validateProviderManifest
|
|
106
|
+
} from "./chunk-3H7UGVI6.js";
|
|
107
|
+
import {
|
|
108
|
+
redactX402Secrets
|
|
109
|
+
} from "./chunk-NYTV263W.js";
|
|
110
|
+
import {
|
|
111
|
+
ProbeMeshError,
|
|
112
|
+
isProbeMeshError
|
|
113
|
+
} from "./chunk-2ASMVLG4.js";
|
|
114
|
+
|
|
115
|
+
// src/adapters/priceLookup.ts
|
|
116
|
+
var DEFAULT_PRICES_USD = {
|
|
117
|
+
BTC: 64000.25,
|
|
118
|
+
ETH: 3200.12,
|
|
119
|
+
SOL: 145.33
|
|
120
|
+
};
|
|
121
|
+
function createPriceLookupAdapter(options = {}) {
|
|
122
|
+
const id = options.id ?? "demo-price-provider";
|
|
123
|
+
const displayName = options.displayName ?? "Demo Price Provider";
|
|
124
|
+
const prices = options.prices ?? DEFAULT_PRICES_USD;
|
|
125
|
+
return {
|
|
126
|
+
id,
|
|
127
|
+
displayName,
|
|
128
|
+
mode: "local",
|
|
129
|
+
capabilities: ["price-lookup"],
|
|
130
|
+
pricing: {
|
|
131
|
+
unit: "call",
|
|
132
|
+
amountUsd: 0.01,
|
|
133
|
+
currency: "USD"
|
|
134
|
+
},
|
|
135
|
+
call(request, context) {
|
|
136
|
+
const input = parsePriceLookupInput(request.input, request.capability, id);
|
|
137
|
+
const symbol = input.symbol.toUpperCase();
|
|
138
|
+
const currency = (input.currency ?? "USD").toUpperCase();
|
|
139
|
+
if (currency !== "USD") {
|
|
140
|
+
throw new ProbeMeshError({
|
|
141
|
+
code: "invalid_provider_response",
|
|
142
|
+
message: `Demo price adapter only supports USD prices, received "${currency}".`,
|
|
143
|
+
capability: request.capability,
|
|
144
|
+
provider: id,
|
|
145
|
+
callId: context.callId
|
|
146
|
+
});
|
|
147
|
+
}
|
|
148
|
+
const price = prices[symbol];
|
|
149
|
+
if (price === void 0) {
|
|
150
|
+
throw new ProbeMeshError({
|
|
151
|
+
code: "provider_unavailable",
|
|
152
|
+
message: `Demo price adapter has no mock price for "${symbol}".`,
|
|
153
|
+
capability: request.capability,
|
|
154
|
+
provider: id,
|
|
155
|
+
callId: context.callId
|
|
156
|
+
});
|
|
157
|
+
}
|
|
158
|
+
return {
|
|
159
|
+
data: {
|
|
160
|
+
symbol,
|
|
161
|
+
currency,
|
|
162
|
+
price,
|
|
163
|
+
asOf: context.startedAt.toISOString(),
|
|
164
|
+
source: id
|
|
165
|
+
},
|
|
166
|
+
cost: {
|
|
167
|
+
amountUsd: 0.01,
|
|
168
|
+
currency: "USD",
|
|
169
|
+
unit: "call"
|
|
170
|
+
},
|
|
171
|
+
receiptRefs: [
|
|
172
|
+
{
|
|
173
|
+
type: "provider_delivery",
|
|
174
|
+
provider: id,
|
|
175
|
+
status: "recorded",
|
|
176
|
+
ref: `${context.callId}:provider_delivery`,
|
|
177
|
+
timestamp: context.startedAt.toISOString()
|
|
178
|
+
}
|
|
179
|
+
]
|
|
180
|
+
};
|
|
181
|
+
}
|
|
182
|
+
};
|
|
183
|
+
}
|
|
184
|
+
function parsePriceLookupInput(input, capability, provider) {
|
|
185
|
+
if (!input || typeof input !== "object") {
|
|
186
|
+
throw new ProbeMeshError({
|
|
187
|
+
code: "invalid_provider_response",
|
|
188
|
+
message: "price-lookup input must be an object.",
|
|
189
|
+
capability,
|
|
190
|
+
provider
|
|
191
|
+
});
|
|
192
|
+
}
|
|
193
|
+
const candidate = input;
|
|
194
|
+
if (!candidate.symbol || typeof candidate.symbol !== "string") {
|
|
195
|
+
throw new ProbeMeshError({
|
|
196
|
+
code: "invalid_provider_response",
|
|
197
|
+
message: "price-lookup input requires a string symbol.",
|
|
198
|
+
capability,
|
|
199
|
+
provider
|
|
200
|
+
});
|
|
201
|
+
}
|
|
202
|
+
if (candidate.currency !== void 0 && typeof candidate.currency !== "string") {
|
|
203
|
+
throw new ProbeMeshError({
|
|
204
|
+
code: "invalid_provider_response",
|
|
205
|
+
message: "price-lookup currency must be a string when provided.",
|
|
206
|
+
capability,
|
|
207
|
+
provider
|
|
208
|
+
});
|
|
209
|
+
}
|
|
210
|
+
return {
|
|
211
|
+
symbol: candidate.symbol,
|
|
212
|
+
currency: candidate.currency
|
|
213
|
+
};
|
|
214
|
+
}
|
|
215
|
+
|
|
216
|
+
// src/demo/mockPaymentProtocol.ts
|
|
217
|
+
function createMockPaymentProtocol(options = {}) {
|
|
218
|
+
const mode = options.mode ?? "mock-payment";
|
|
219
|
+
let prepareAttempts = 0;
|
|
220
|
+
return {
|
|
221
|
+
mode,
|
|
222
|
+
prepare({ manifest, request, context }) {
|
|
223
|
+
prepareAttempts += 1;
|
|
224
|
+
if (options.failPrepare || options.failPrepareOnce && prepareAttempts === 1) {
|
|
225
|
+
throw new ProbeMeshError({
|
|
226
|
+
code: "payment_failed",
|
|
227
|
+
message: `Mock payment authorization failed for provider "${manifest.id}".`,
|
|
228
|
+
capability: request.capability,
|
|
229
|
+
provider: manifest.id,
|
|
230
|
+
callId: context.callId
|
|
231
|
+
});
|
|
232
|
+
}
|
|
233
|
+
const paymentAttemptId = options.paymentAttemptId ?? `${context.callId}:mock_payment_attempt`;
|
|
234
|
+
return {
|
|
235
|
+
mode: manifest.protocolMode,
|
|
236
|
+
headers: {
|
|
237
|
+
"x-mock-payment-intent": context.callId
|
|
238
|
+
},
|
|
239
|
+
metadata: {
|
|
240
|
+
authorized: true,
|
|
241
|
+
paymentAttemptId
|
|
242
|
+
},
|
|
243
|
+
receiptRefs: [
|
|
244
|
+
{
|
|
245
|
+
type: "payment_proof",
|
|
246
|
+
provider: manifest.id,
|
|
247
|
+
status: "recorded",
|
|
248
|
+
ref: `${context.callId}:mock_payment_authorized`,
|
|
249
|
+
timestamp: context.startedAt.toISOString()
|
|
250
|
+
}
|
|
251
|
+
],
|
|
252
|
+
safety: {
|
|
253
|
+
paymentAttemptId,
|
|
254
|
+
paymentStatus: "authorized",
|
|
255
|
+
moneyMayHaveMoved: true
|
|
256
|
+
}
|
|
257
|
+
};
|
|
258
|
+
},
|
|
259
|
+
settle({ manifest, request, context }) {
|
|
260
|
+
if (options.failSettle) {
|
|
261
|
+
throw new ProbeMeshError({
|
|
262
|
+
code: "payment_failed",
|
|
263
|
+
message: `Mock payment settlement failed for provider "${manifest.id}".`,
|
|
264
|
+
capability: request.capability,
|
|
265
|
+
provider: manifest.id,
|
|
266
|
+
callId: context.callId
|
|
267
|
+
});
|
|
268
|
+
}
|
|
269
|
+
return {
|
|
270
|
+
mode: manifest.protocolMode,
|
|
271
|
+
metadata: {
|
|
272
|
+
settled: true
|
|
273
|
+
},
|
|
274
|
+
receiptRefs: options.omitDeliveryReceipt ? [] : [
|
|
275
|
+
{
|
|
276
|
+
type: "provider_delivery",
|
|
277
|
+
provider: manifest.id,
|
|
278
|
+
status: "recorded",
|
|
279
|
+
ref: `${context.callId}:mock_delivery_recorded`,
|
|
280
|
+
timestamp: context.startedAt.toISOString()
|
|
281
|
+
}
|
|
282
|
+
],
|
|
283
|
+
safety: {
|
|
284
|
+
settlementStatus: "settled",
|
|
285
|
+
deliveryStatus: options.omitDeliveryReceipt ? "missing" : "delivered",
|
|
286
|
+
moneyMayHaveMoved: true
|
|
287
|
+
}
|
|
288
|
+
};
|
|
289
|
+
}
|
|
290
|
+
};
|
|
291
|
+
}
|
|
292
|
+
|
|
293
|
+
// src/providerKit/adapter.ts
|
|
294
|
+
function createAdapterFromManifest(manifest, handlers, options = {}) {
|
|
295
|
+
assertProviderManifest(manifest);
|
|
296
|
+
assertHandlers(manifest, handlers);
|
|
297
|
+
assertProtocolAdapters(options.protocolAdapters, manifest);
|
|
298
|
+
return {
|
|
299
|
+
id: manifest.id,
|
|
300
|
+
displayName: manifest.displayName,
|
|
301
|
+
mode: manifest.protocolMode,
|
|
302
|
+
capabilities: [...manifest.capabilities],
|
|
303
|
+
pricing: manifest.pricing,
|
|
304
|
+
...manifest.paymentOptions !== void 0 ? { paymentOptions: [...manifest.paymentOptions] } : {},
|
|
305
|
+
async call(request, context) {
|
|
306
|
+
const handler = handlers[request.capability];
|
|
307
|
+
if (!handler) {
|
|
308
|
+
throw new ProbeMeshError({
|
|
309
|
+
code: "provider_unavailable",
|
|
310
|
+
message: `Provider manifest "${manifest.id}" does not expose handler for capability "${request.capability}".`,
|
|
311
|
+
capability: request.capability,
|
|
312
|
+
provider: manifest.id,
|
|
313
|
+
callId: context.callId
|
|
314
|
+
});
|
|
315
|
+
}
|
|
316
|
+
const protocolMode = context.paymentSelection?.protocolMode ?? manifest.protocolMode;
|
|
317
|
+
const protocolAdapter = findProtocolAdapter(
|
|
318
|
+
manifest,
|
|
319
|
+
options.protocolAdapters,
|
|
320
|
+
protocolMode
|
|
321
|
+
);
|
|
322
|
+
const preparation = protocolAdapter?.prepare ? await prepareProtocol(protocolAdapter, manifest, request, context, protocolMode) : void 0;
|
|
323
|
+
const preparationReceiptRefs = preparation?.receiptRefs ?? [];
|
|
324
|
+
const preparationSafety = protocolAdapter ? mergeSafety(preparationReceiptRefs, preparation?.safety) : void 0;
|
|
325
|
+
const protocolExecution = protocolAdapter ? {
|
|
326
|
+
mode: protocolMode,
|
|
327
|
+
preparation,
|
|
328
|
+
receiptRefs: [...preparationReceiptRefs],
|
|
329
|
+
safety: preparationSafety
|
|
330
|
+
} : void 0;
|
|
331
|
+
const handlerContext = protocolExecution ? {
|
|
332
|
+
...context,
|
|
333
|
+
protocol: protocolExecution
|
|
334
|
+
} : context;
|
|
335
|
+
const result = await callHandler({
|
|
336
|
+
handler,
|
|
337
|
+
manifest,
|
|
338
|
+
request,
|
|
339
|
+
handlerContext,
|
|
340
|
+
preparation,
|
|
341
|
+
preparationSafety,
|
|
342
|
+
preparationReceiptRefs
|
|
343
|
+
});
|
|
344
|
+
const settlement = protocolAdapter?.settle ? await settleProtocol({
|
|
345
|
+
protocolAdapter,
|
|
346
|
+
manifest,
|
|
347
|
+
request,
|
|
348
|
+
handlerContext,
|
|
349
|
+
result,
|
|
350
|
+
preparation,
|
|
351
|
+
preparationSafety,
|
|
352
|
+
preparationReceiptRefs,
|
|
353
|
+
protocolMode
|
|
354
|
+
}) : void 0;
|
|
355
|
+
const protocolReceiptRefs = [
|
|
356
|
+
...preparationReceiptRefs,
|
|
357
|
+
...settlement?.receiptRefs ?? []
|
|
358
|
+
];
|
|
359
|
+
const mergedReceiptRefs = [
|
|
360
|
+
...result.receiptRefs ?? [],
|
|
361
|
+
...protocolReceiptRefs
|
|
362
|
+
];
|
|
363
|
+
const safety = protocolAdapter ? mergeSafety(
|
|
364
|
+
mergedReceiptRefs,
|
|
365
|
+
preparation?.safety,
|
|
366
|
+
result.safety,
|
|
367
|
+
settlement?.safety
|
|
368
|
+
) : result.safety;
|
|
369
|
+
if (protocolExecution) {
|
|
370
|
+
protocolExecution.settlement = settlement;
|
|
371
|
+
protocolExecution.receiptRefs = protocolReceiptRefs;
|
|
372
|
+
protocolExecution.safety = safety;
|
|
373
|
+
}
|
|
374
|
+
if (!result || typeof result !== "object" || Array.isArray(result) || result.receiptRefs !== void 0 && !Array.isArray(result.receiptRefs)) {
|
|
375
|
+
return result;
|
|
376
|
+
}
|
|
377
|
+
return {
|
|
378
|
+
...result,
|
|
379
|
+
receiptRefs: mergedReceiptRefs,
|
|
380
|
+
safety
|
|
381
|
+
};
|
|
382
|
+
}
|
|
383
|
+
};
|
|
384
|
+
}
|
|
385
|
+
async function prepareProtocol(protocolAdapter, manifest, request, context, protocolMode = manifest.protocolMode) {
|
|
386
|
+
try {
|
|
387
|
+
return await protocolAdapter.prepare?.({
|
|
388
|
+
manifest: manifestForProtocol(manifest, protocolMode),
|
|
389
|
+
request,
|
|
390
|
+
context
|
|
391
|
+
});
|
|
392
|
+
} catch (error) {
|
|
393
|
+
if (isProbeMeshError(error) && error.code !== "payment_failed") {
|
|
394
|
+
throw error;
|
|
395
|
+
}
|
|
396
|
+
throw new ProbeMeshError({
|
|
397
|
+
code: "payment_failed",
|
|
398
|
+
message: `Protocol "${protocolAdapter.mode}" failed while preparing payment for provider "${manifest.id}".`,
|
|
399
|
+
capability: request.capability,
|
|
400
|
+
provider: manifest.id,
|
|
401
|
+
callId: context.callId,
|
|
402
|
+
safety: mergeSafety([], {
|
|
403
|
+
paymentStatus: "failed",
|
|
404
|
+
settlementStatus: "not_attempted",
|
|
405
|
+
deliveryStatus: "not_attempted",
|
|
406
|
+
moneyMayHaveMoved: false
|
|
407
|
+
}),
|
|
408
|
+
cause: error
|
|
409
|
+
});
|
|
410
|
+
}
|
|
411
|
+
}
|
|
412
|
+
async function callHandler({
|
|
413
|
+
handler,
|
|
414
|
+
manifest,
|
|
415
|
+
request,
|
|
416
|
+
handlerContext,
|
|
417
|
+
preparation,
|
|
418
|
+
preparationSafety,
|
|
419
|
+
preparationReceiptRefs
|
|
420
|
+
}) {
|
|
421
|
+
try {
|
|
422
|
+
return await handler(request, handlerContext);
|
|
423
|
+
} catch (error) {
|
|
424
|
+
const errorReceiptRefs = isProbeMeshError(error) ? error.receiptRefs ?? [] : [];
|
|
425
|
+
const receiptRefs = [...preparationReceiptRefs, ...errorReceiptRefs];
|
|
426
|
+
const safety = mergeSafety(
|
|
427
|
+
receiptRefs,
|
|
428
|
+
preparation?.safety,
|
|
429
|
+
preparationSafety,
|
|
430
|
+
isProbeMeshError(error) ? error.safety : void 0,
|
|
431
|
+
{
|
|
432
|
+
deliveryStatus: "failed"
|
|
433
|
+
}
|
|
434
|
+
);
|
|
435
|
+
if (!paymentWasAttempted(safety, receiptRefs)) {
|
|
436
|
+
if (isProbeMeshError(error) && (receiptRefs.length > 0 || preparationSafety)) {
|
|
437
|
+
throw new ProbeMeshError({
|
|
438
|
+
code: error.code,
|
|
439
|
+
message: error.message,
|
|
440
|
+
capability: error.capability,
|
|
441
|
+
provider: error.provider,
|
|
442
|
+
callId: error.callId,
|
|
443
|
+
receiptRefs,
|
|
444
|
+
safety,
|
|
445
|
+
cause: error
|
|
446
|
+
});
|
|
447
|
+
}
|
|
448
|
+
throw error;
|
|
449
|
+
}
|
|
450
|
+
throw new ProbeMeshError({
|
|
451
|
+
code: isProbeMeshError(error) && error.code === "timeout_after_payment" ? "timeout_after_payment" : "charged_but_no_result",
|
|
452
|
+
message: error instanceof Error ? error.message : `Provider "${manifest.id}" failed after payment was prepared.`,
|
|
453
|
+
capability: request.capability,
|
|
454
|
+
provider: manifest.id,
|
|
455
|
+
callId: handlerContext.callId,
|
|
456
|
+
receiptRefs,
|
|
457
|
+
safety,
|
|
458
|
+
cause: error
|
|
459
|
+
});
|
|
460
|
+
}
|
|
461
|
+
}
|
|
462
|
+
async function settleProtocol({
|
|
463
|
+
protocolAdapter,
|
|
464
|
+
manifest,
|
|
465
|
+
request,
|
|
466
|
+
handlerContext,
|
|
467
|
+
result,
|
|
468
|
+
preparation,
|
|
469
|
+
preparationSafety,
|
|
470
|
+
preparationReceiptRefs,
|
|
471
|
+
protocolMode
|
|
472
|
+
}) {
|
|
473
|
+
try {
|
|
474
|
+
return await protocolAdapter.settle?.({
|
|
475
|
+
manifest: manifestForProtocol(manifest, protocolMode ?? manifest.protocolMode),
|
|
476
|
+
request,
|
|
477
|
+
context: handlerContext,
|
|
478
|
+
result,
|
|
479
|
+
preparation
|
|
480
|
+
});
|
|
481
|
+
} catch (error) {
|
|
482
|
+
const resultReceiptRefs = Array.isArray(result.receiptRefs) ? result.receiptRefs : [];
|
|
483
|
+
const receiptRefs = [...resultReceiptRefs, ...preparationReceiptRefs];
|
|
484
|
+
const hasDeliveryEvidence = receiptRefs.some(
|
|
485
|
+
(receiptRef) => receiptRef.type === "provider_delivery"
|
|
486
|
+
);
|
|
487
|
+
const safety = mergeSafety(
|
|
488
|
+
receiptRefs,
|
|
489
|
+
preparation?.safety,
|
|
490
|
+
preparationSafety,
|
|
491
|
+
result.safety,
|
|
492
|
+
{
|
|
493
|
+
settlementStatus: "failed",
|
|
494
|
+
deliveryStatus: hasDeliveryEvidence ? "delivered" : "missing"
|
|
495
|
+
}
|
|
496
|
+
);
|
|
497
|
+
throw new ProbeMeshError({
|
|
498
|
+
code: "payment_failed",
|
|
499
|
+
message: `Protocol "${protocolAdapter.mode}" failed while settling payment for provider "${manifest.id}".`,
|
|
500
|
+
capability: request.capability,
|
|
501
|
+
provider: manifest.id,
|
|
502
|
+
callId: handlerContext.callId,
|
|
503
|
+
receiptRefs,
|
|
504
|
+
safety,
|
|
505
|
+
cause: error
|
|
506
|
+
});
|
|
507
|
+
}
|
|
508
|
+
}
|
|
509
|
+
function mergeSafety(receiptRefs, ...partials) {
|
|
510
|
+
const safety = {
|
|
511
|
+
paymentStatus: "not_attempted",
|
|
512
|
+
settlementStatus: "not_attempted",
|
|
513
|
+
deliveryStatus: "not_attempted",
|
|
514
|
+
moneyMayHaveMoved: false
|
|
515
|
+
};
|
|
516
|
+
applyReceiptDerivedSafety(safety, receiptRefs);
|
|
517
|
+
for (const partial of partials) {
|
|
518
|
+
if (!partial) {
|
|
519
|
+
continue;
|
|
520
|
+
}
|
|
521
|
+
Object.assign(safety, partial);
|
|
522
|
+
}
|
|
523
|
+
if (safety.paymentStatus === "authorized" || safety.settlementStatus === "settled") {
|
|
524
|
+
safety.moneyMayHaveMoved = true;
|
|
525
|
+
}
|
|
526
|
+
return safety;
|
|
527
|
+
}
|
|
528
|
+
function applyReceiptDerivedSafety(safety, receiptRefs) {
|
|
529
|
+
if (receiptRefs.some((receiptRef) => receiptRef.type === "payment_proof")) {
|
|
530
|
+
safety.paymentStatus = "authorized";
|
|
531
|
+
safety.moneyMayHaveMoved = true;
|
|
532
|
+
}
|
|
533
|
+
if (receiptRefs.some(
|
|
534
|
+
(receiptRef) => receiptRef.type === "settlement_confirmation"
|
|
535
|
+
)) {
|
|
536
|
+
safety.settlementStatus = "settled";
|
|
537
|
+
}
|
|
538
|
+
if (receiptRefs.some((receiptRef) => receiptRef.type === "provider_delivery")) {
|
|
539
|
+
safety.deliveryStatus = "delivered";
|
|
540
|
+
}
|
|
541
|
+
}
|
|
542
|
+
function paymentWasAttempted(safety, receiptRefs) {
|
|
543
|
+
return safety.paymentStatus !== "not_attempted" || safety.moneyMayHaveMoved || receiptRefs.some((receiptRef) => receiptRef.type === "payment_proof");
|
|
544
|
+
}
|
|
545
|
+
function findProtocolAdapter(manifest, protocolAdapters, protocolMode = manifest.protocolMode) {
|
|
546
|
+
return protocolAdapters?.find(
|
|
547
|
+
(protocolAdapter) => protocolAdapter.mode === protocolMode
|
|
548
|
+
);
|
|
549
|
+
}
|
|
550
|
+
function manifestForProtocol(manifest, protocolMode) {
|
|
551
|
+
return protocolMode === manifest.protocolMode ? manifest : {
|
|
552
|
+
...manifest,
|
|
553
|
+
protocolMode
|
|
554
|
+
};
|
|
555
|
+
}
|
|
556
|
+
function assertProtocolAdapters(protocolAdapters, manifest) {
|
|
557
|
+
if (protocolAdapters === void 0) {
|
|
558
|
+
return;
|
|
559
|
+
}
|
|
560
|
+
if (!Array.isArray(protocolAdapters) || protocolAdapters.some(
|
|
561
|
+
(protocolAdapter) => !protocolAdapter || typeof protocolAdapter !== "object" || typeof protocolAdapter.mode !== "string" || protocolAdapter.mode.length === 0
|
|
562
|
+
)) {
|
|
563
|
+
throw new ProbeMeshError({
|
|
564
|
+
code: "invalid_request",
|
|
565
|
+
message: `Provider manifest "${manifest.id}" requires protocolAdapters to be an array of protocol adapter objects.`,
|
|
566
|
+
provider: manifest.id
|
|
567
|
+
});
|
|
568
|
+
}
|
|
569
|
+
}
|
|
570
|
+
function assertHandlers(manifest, handlers) {
|
|
571
|
+
if (!handlers || typeof handlers !== "object" || Array.isArray(handlers)) {
|
|
572
|
+
throw new ProbeMeshError({
|
|
573
|
+
code: "invalid_request",
|
|
574
|
+
message: `Provider manifest "${manifest.id}" requires a handlers object.`,
|
|
575
|
+
provider: manifest.id
|
|
576
|
+
});
|
|
577
|
+
}
|
|
578
|
+
const missingCapabilities = manifest.capabilities.filter(
|
|
579
|
+
(capability) => typeof handlers[capability] !== "function"
|
|
580
|
+
);
|
|
581
|
+
if (missingCapabilities.length > 0) {
|
|
582
|
+
throw new ProbeMeshError({
|
|
583
|
+
code: "invalid_request",
|
|
584
|
+
message: `Provider manifest "${manifest.id}" is missing handlers for capabilities: ${missingCapabilities.join(
|
|
585
|
+
", "
|
|
586
|
+
)}.`,
|
|
587
|
+
provider: manifest.id
|
|
588
|
+
});
|
|
589
|
+
}
|
|
590
|
+
}
|
|
591
|
+
|
|
592
|
+
// src/demo/paidPriceLookupProvider.ts
|
|
593
|
+
var DEFAULT_PAID_PRICES_USD = {
|
|
594
|
+
BTC: 64000.25,
|
|
595
|
+
ETH: 3200.12,
|
|
596
|
+
SOL: 145.33
|
|
597
|
+
};
|
|
598
|
+
function createPaidPriceLookupProvider(options = {}) {
|
|
599
|
+
const id = options.id ?? "paid-price-provider";
|
|
600
|
+
const displayName = options.displayName ?? "Paid Price Provider";
|
|
601
|
+
const amountUsd = options.amountUsd ?? 0.01;
|
|
602
|
+
const prices = options.prices ?? DEFAULT_PAID_PRICES_USD;
|
|
603
|
+
const failureMode = options.failureMode ?? "none";
|
|
604
|
+
const mockPaymentOptions = {
|
|
605
|
+
...options.mockPayment,
|
|
606
|
+
omitDeliveryReceipt: options.mockPayment?.omitDeliveryReceipt || failureMode === "missing_delivery_receipt"
|
|
607
|
+
};
|
|
608
|
+
const manifest = createPaidPriceLookupManifest({
|
|
609
|
+
id,
|
|
610
|
+
displayName,
|
|
611
|
+
amountUsd
|
|
612
|
+
});
|
|
613
|
+
return createAdapterFromManifest(
|
|
614
|
+
manifest,
|
|
615
|
+
{
|
|
616
|
+
"price-lookup": (request, context) => {
|
|
617
|
+
const input = parsePriceLookupInput2(request.input, id, context.callId);
|
|
618
|
+
const symbol = input.symbol.toUpperCase();
|
|
619
|
+
const currency = (input.currency ?? "USD").toUpperCase();
|
|
620
|
+
if (failureMode === "timeout_after_payment") {
|
|
621
|
+
throw new ProbeMeshError({
|
|
622
|
+
code: "timeout_after_payment",
|
|
623
|
+
message: `Paid price lookup demo timed out after payment authorization for provider "${id}".`,
|
|
624
|
+
capability: request.capability,
|
|
625
|
+
provider: id,
|
|
626
|
+
callId: context.callId
|
|
627
|
+
});
|
|
628
|
+
}
|
|
629
|
+
if (currency !== "USD") {
|
|
630
|
+
throw new ProbeMeshError({
|
|
631
|
+
code: "invalid_provider_response",
|
|
632
|
+
message: `Paid price lookup demo only supports USD prices, received "${currency}".`,
|
|
633
|
+
capability: request.capability,
|
|
634
|
+
provider: id,
|
|
635
|
+
callId: context.callId
|
|
636
|
+
});
|
|
637
|
+
}
|
|
638
|
+
const price = prices[symbol];
|
|
639
|
+
if (price === void 0) {
|
|
640
|
+
throw new ProbeMeshError({
|
|
641
|
+
code: "provider_unavailable",
|
|
642
|
+
message: `Paid price lookup demo has no mock price for "${symbol}".`,
|
|
643
|
+
capability: request.capability,
|
|
644
|
+
provider: id,
|
|
645
|
+
callId: context.callId
|
|
646
|
+
});
|
|
647
|
+
}
|
|
648
|
+
return {
|
|
649
|
+
data: {
|
|
650
|
+
symbol,
|
|
651
|
+
currency,
|
|
652
|
+
price,
|
|
653
|
+
asOf: context.startedAt.toISOString(),
|
|
654
|
+
source: id,
|
|
655
|
+
protocolMode: context.protocol?.mode,
|
|
656
|
+
paymentAuthorized: context.protocol?.preparation?.metadata?.authorized === true
|
|
657
|
+
}
|
|
658
|
+
};
|
|
659
|
+
}
|
|
660
|
+
},
|
|
661
|
+
{
|
|
662
|
+
protocolAdapters: [createMockPaymentProtocol(mockPaymentOptions)]
|
|
663
|
+
}
|
|
664
|
+
);
|
|
665
|
+
}
|
|
666
|
+
function createPaidPriceLookupManifest(options) {
|
|
667
|
+
return {
|
|
668
|
+
id: options.id,
|
|
669
|
+
displayName: options.displayName,
|
|
670
|
+
capabilities: ["price-lookup"],
|
|
671
|
+
protocolMode: "mock-payment",
|
|
672
|
+
pricing: {
|
|
673
|
+
unit: "call",
|
|
674
|
+
amountUsd: options.amountUsd,
|
|
675
|
+
currency: "USD"
|
|
676
|
+
},
|
|
677
|
+
inputSchema: {
|
|
678
|
+
type: "object",
|
|
679
|
+
properties: {
|
|
680
|
+
symbol: {
|
|
681
|
+
type: "string"
|
|
682
|
+
},
|
|
683
|
+
currency: {
|
|
684
|
+
type: "string"
|
|
685
|
+
}
|
|
686
|
+
},
|
|
687
|
+
required: ["symbol"]
|
|
688
|
+
},
|
|
689
|
+
outputSchema: {
|
|
690
|
+
type: "object",
|
|
691
|
+
properties: {
|
|
692
|
+
symbol: {
|
|
693
|
+
type: "string"
|
|
694
|
+
},
|
|
695
|
+
currency: {
|
|
696
|
+
type: "string"
|
|
697
|
+
},
|
|
698
|
+
price: {
|
|
699
|
+
type: "number"
|
|
700
|
+
},
|
|
701
|
+
paymentAuthorized: {
|
|
702
|
+
type: "boolean"
|
|
703
|
+
}
|
|
704
|
+
},
|
|
705
|
+
required: ["symbol", "currency", "price", "paymentAuthorized"]
|
|
706
|
+
},
|
|
707
|
+
receipts: {
|
|
708
|
+
payment: true,
|
|
709
|
+
delivery: true,
|
|
710
|
+
responseEvidence: false
|
|
711
|
+
},
|
|
712
|
+
limits: {
|
|
713
|
+
maxRequestsPerMinute: 60
|
|
714
|
+
}
|
|
715
|
+
};
|
|
716
|
+
}
|
|
717
|
+
function parsePriceLookupInput2(input, provider, callId) {
|
|
718
|
+
if (!input || typeof input !== "object") {
|
|
719
|
+
throw new ProbeMeshError({
|
|
720
|
+
code: "invalid_provider_response",
|
|
721
|
+
message: "price-lookup input must be an object.",
|
|
722
|
+
capability: "price-lookup",
|
|
723
|
+
provider,
|
|
724
|
+
callId
|
|
725
|
+
});
|
|
726
|
+
}
|
|
727
|
+
const candidate = input;
|
|
728
|
+
if (typeof candidate.symbol !== "string" || candidate.symbol.length === 0) {
|
|
729
|
+
throw new ProbeMeshError({
|
|
730
|
+
code: "invalid_provider_response",
|
|
731
|
+
message: "price-lookup input requires a string symbol.",
|
|
732
|
+
capability: "price-lookup",
|
|
733
|
+
provider,
|
|
734
|
+
callId
|
|
735
|
+
});
|
|
736
|
+
}
|
|
737
|
+
if (candidate.currency !== void 0 && typeof candidate.currency !== "string") {
|
|
738
|
+
throw new ProbeMeshError({
|
|
739
|
+
code: "invalid_provider_response",
|
|
740
|
+
message: "price-lookup currency must be a string when provided.",
|
|
741
|
+
capability: "price-lookup",
|
|
742
|
+
provider,
|
|
743
|
+
callId
|
|
744
|
+
});
|
|
745
|
+
}
|
|
746
|
+
return {
|
|
747
|
+
symbol: candidate.symbol,
|
|
748
|
+
currency: candidate.currency
|
|
749
|
+
};
|
|
750
|
+
}
|
|
751
|
+
|
|
752
|
+
// src/protocols/apiKeyProtocol.ts
|
|
753
|
+
var DEFAULT_MODE = "api-key";
|
|
754
|
+
var DEFAULT_HEADER_NAME = "x-api-key";
|
|
755
|
+
var DEFAULT_AUTHORIZATION_HEADER = "authorization";
|
|
756
|
+
var DEFAULT_AUTHORIZATION_SCHEME = "Bearer";
|
|
757
|
+
function createApiKeyProtocol(options = {}) {
|
|
758
|
+
assertApiKeyProtocolOptions(options);
|
|
759
|
+
const mode = options.mode ?? DEFAULT_MODE;
|
|
760
|
+
return {
|
|
761
|
+
mode,
|
|
762
|
+
async prepare({ manifest, request, context }) {
|
|
763
|
+
if (options.providerId && options.providerId !== manifest.id) {
|
|
764
|
+
throw new ProbeMeshError({
|
|
765
|
+
code: "invalid_request",
|
|
766
|
+
message: `API key protocol is configured for provider "${options.providerId}", but manifest "${manifest.id}" was used.`,
|
|
767
|
+
capability: request.capability,
|
|
768
|
+
provider: manifest.id,
|
|
769
|
+
callId: context.callId,
|
|
770
|
+
safety: noPaymentSafety()
|
|
771
|
+
});
|
|
772
|
+
}
|
|
773
|
+
const apiKey = await resolveApiKey(options);
|
|
774
|
+
if (!apiKey) {
|
|
775
|
+
throw new ProbeMeshError({
|
|
776
|
+
code: "unauthorized",
|
|
777
|
+
message: `API key is required for provider "${manifest.id}".`,
|
|
778
|
+
capability: request.capability,
|
|
779
|
+
provider: manifest.id,
|
|
780
|
+
callId: context.callId,
|
|
781
|
+
safety: noPaymentSafety()
|
|
782
|
+
});
|
|
783
|
+
}
|
|
784
|
+
const placement = options.placement ?? "header";
|
|
785
|
+
const headerName = headerNameForPlacement(options, placement);
|
|
786
|
+
const headers = {
|
|
787
|
+
[headerName]: headerValueForPlacement(options, placement, apiKey)
|
|
788
|
+
};
|
|
789
|
+
const preparation = {
|
|
790
|
+
mode: manifest.protocolMode,
|
|
791
|
+
metadata: {
|
|
792
|
+
authorized: true,
|
|
793
|
+
credentialPresent: true,
|
|
794
|
+
placement,
|
|
795
|
+
headerName,
|
|
796
|
+
providerId: manifest.id
|
|
797
|
+
},
|
|
798
|
+
receiptRefs: [
|
|
799
|
+
{
|
|
800
|
+
type: "authorization_decision",
|
|
801
|
+
provider: manifest.id,
|
|
802
|
+
status: "recorded",
|
|
803
|
+
ref: `${context.callId}:api_key_authorized`,
|
|
804
|
+
timestamp: context.startedAt.toISOString()
|
|
805
|
+
}
|
|
806
|
+
],
|
|
807
|
+
safety: noPaymentPreparationSafety()
|
|
808
|
+
};
|
|
809
|
+
Object.defineProperty(preparation, "headers", {
|
|
810
|
+
value: Object.freeze(headers),
|
|
811
|
+
enumerable: false,
|
|
812
|
+
configurable: false,
|
|
813
|
+
writable: false
|
|
814
|
+
});
|
|
815
|
+
return preparation;
|
|
816
|
+
}
|
|
817
|
+
};
|
|
818
|
+
}
|
|
819
|
+
function assertApiKeyProtocolOptions(options) {
|
|
820
|
+
if (options.providerId !== void 0 && (typeof options.providerId !== "string" || options.providerId.length === 0)) {
|
|
821
|
+
throw new ProbeMeshError({
|
|
822
|
+
code: "invalid_request",
|
|
823
|
+
message: "API key protocol providerId must be a non-empty string when provided."
|
|
824
|
+
});
|
|
825
|
+
}
|
|
826
|
+
if (options.apiKey !== void 0 && (typeof options.apiKey !== "string" || options.apiKey.length === 0)) {
|
|
827
|
+
throw new ProbeMeshError({
|
|
828
|
+
code: "invalid_request",
|
|
829
|
+
message: "API key protocol apiKey must be a non-empty string when provided."
|
|
830
|
+
});
|
|
831
|
+
}
|
|
832
|
+
if (options.resolveApiKey !== void 0 && typeof options.resolveApiKey !== "function") {
|
|
833
|
+
throw new ProbeMeshError({
|
|
834
|
+
code: "invalid_request",
|
|
835
|
+
message: "API key protocol resolveApiKey must be a function when provided."
|
|
836
|
+
});
|
|
837
|
+
}
|
|
838
|
+
if (options.placement !== void 0 && options.placement !== "header" && options.placement !== "authorization") {
|
|
839
|
+
throw new ProbeMeshError({
|
|
840
|
+
code: "invalid_request",
|
|
841
|
+
message: 'API key protocol placement must be "header" or "authorization".'
|
|
842
|
+
});
|
|
843
|
+
}
|
|
844
|
+
if (options.headerName !== void 0 && (typeof options.headerName !== "string" || options.headerName.length === 0)) {
|
|
845
|
+
throw new ProbeMeshError({
|
|
846
|
+
code: "invalid_request",
|
|
847
|
+
message: "API key protocol headerName must be a non-empty string when provided."
|
|
848
|
+
});
|
|
849
|
+
}
|
|
850
|
+
if (options.authorizationScheme !== void 0 && (typeof options.authorizationScheme !== "string" || options.authorizationScheme.length === 0)) {
|
|
851
|
+
throw new ProbeMeshError({
|
|
852
|
+
code: "invalid_request",
|
|
853
|
+
message: "API key protocol authorizationScheme must be a non-empty string when provided."
|
|
854
|
+
});
|
|
855
|
+
}
|
|
856
|
+
}
|
|
857
|
+
async function resolveApiKey(options) {
|
|
858
|
+
return options.apiKey ?? await options.resolveApiKey?.();
|
|
859
|
+
}
|
|
860
|
+
function headerNameForPlacement(options, placement) {
|
|
861
|
+
if (placement === "authorization") {
|
|
862
|
+
return options.headerName ?? DEFAULT_AUTHORIZATION_HEADER;
|
|
863
|
+
}
|
|
864
|
+
return options.headerName ?? DEFAULT_HEADER_NAME;
|
|
865
|
+
}
|
|
866
|
+
function headerValueForPlacement(options, placement, apiKey) {
|
|
867
|
+
if (placement === "authorization") {
|
|
868
|
+
return `${options.authorizationScheme ?? DEFAULT_AUTHORIZATION_SCHEME} ${apiKey}`;
|
|
869
|
+
}
|
|
870
|
+
return apiKey;
|
|
871
|
+
}
|
|
872
|
+
function noPaymentSafety() {
|
|
873
|
+
return {
|
|
874
|
+
paymentStatus: "not_attempted",
|
|
875
|
+
settlementStatus: "not_attempted",
|
|
876
|
+
deliveryStatus: "not_attempted",
|
|
877
|
+
moneyMayHaveMoved: false
|
|
878
|
+
};
|
|
879
|
+
}
|
|
880
|
+
function noPaymentPreparationSafety() {
|
|
881
|
+
return {
|
|
882
|
+
paymentStatus: "not_attempted",
|
|
883
|
+
settlementStatus: "not_attempted",
|
|
884
|
+
moneyMayHaveMoved: false
|
|
885
|
+
};
|
|
886
|
+
}
|
|
887
|
+
|
|
888
|
+
// src/protocols/x402Evm.ts
|
|
889
|
+
import { x402Client } from "@x402/core/client";
|
|
890
|
+
import {
|
|
891
|
+
registerExactEvmScheme
|
|
892
|
+
} from "@x402/evm/exact/client";
|
|
893
|
+
import {
|
|
894
|
+
getDefaultAsset,
|
|
895
|
+
toClientEvmSigner
|
|
896
|
+
} from "@x402/evm";
|
|
897
|
+
import { createPublicClient, http } from "viem";
|
|
898
|
+
import { privateKeyToAccount } from "viem/accounts";
|
|
899
|
+
var DEFAULT_NETWORK = "eip155:84532";
|
|
900
|
+
var DEFAULT_AMOUNT = "10000";
|
|
901
|
+
var DEFAULT_FACILITATOR_URL = "https://x402.org/facilitator";
|
|
902
|
+
var REQUIRED_TESTNET_ENV = [
|
|
903
|
+
"PROBEMESH_X402_EVM_PRIVATE_KEY",
|
|
904
|
+
"PROBEMESH_X402_PAY_TO",
|
|
905
|
+
"PROBEMESH_X402_ASSET"
|
|
906
|
+
];
|
|
907
|
+
var OPTIONAL_TESTNET_ENV = [
|
|
908
|
+
"PROBEMESH_X402_FACILITATOR_URL",
|
|
909
|
+
"PROBEMESH_X402_RPC_URL",
|
|
910
|
+
"PROBEMESH_X402_NETWORK",
|
|
911
|
+
"PROBEMESH_X402_AMOUNT",
|
|
912
|
+
"PROBEMESH_X402_ASSET_NAME",
|
|
913
|
+
"PROBEMESH_X402_ASSET_VERSION"
|
|
914
|
+
];
|
|
915
|
+
function resolveX402EvmTestnetConfig(options = {}) {
|
|
916
|
+
assertTestnetConfigOptions(options);
|
|
917
|
+
const env = options.env ?? process.env;
|
|
918
|
+
const defaultNetwork = options.defaultNetwork ?? DEFAULT_NETWORK;
|
|
919
|
+
const defaultAmount = options.defaultAmount ?? DEFAULT_AMOUNT;
|
|
920
|
+
const defaultFacilitatorUrl = options.defaultFacilitatorUrl ?? DEFAULT_FACILITATOR_URL;
|
|
921
|
+
const missingEnv = REQUIRED_TESTNET_ENV.filter((name) => !env[name]);
|
|
922
|
+
if (missingEnv.length > 0) {
|
|
923
|
+
return {
|
|
924
|
+
ok: false,
|
|
925
|
+
skip: {
|
|
926
|
+
reason: "Missing opt-in live x402 EVM environment variables.",
|
|
927
|
+
missingEnv,
|
|
928
|
+
requiredEnv: [...REQUIRED_TESTNET_ENV],
|
|
929
|
+
optionalEnv: [...OPTIONAL_TESTNET_ENV],
|
|
930
|
+
defaults: {
|
|
931
|
+
network: defaultNetwork,
|
|
932
|
+
amount: defaultAmount,
|
|
933
|
+
facilitatorUrl: defaultFacilitatorUrl
|
|
934
|
+
}
|
|
935
|
+
}
|
|
936
|
+
};
|
|
937
|
+
}
|
|
938
|
+
const network = requireEvmNetwork(
|
|
939
|
+
env.PROBEMESH_X402_NETWORK ?? defaultNetwork,
|
|
940
|
+
"PROBEMESH_X402_NETWORK"
|
|
941
|
+
);
|
|
942
|
+
const amount = requirePositiveIntegerString(
|
|
943
|
+
env.PROBEMESH_X402_AMOUNT ?? defaultAmount,
|
|
944
|
+
"PROBEMESH_X402_AMOUNT"
|
|
945
|
+
);
|
|
946
|
+
const facilitatorUrl = requireHttpUrl(
|
|
947
|
+
env.PROBEMESH_X402_FACILITATOR_URL ?? defaultFacilitatorUrl,
|
|
948
|
+
"PROBEMESH_X402_FACILITATOR_URL"
|
|
949
|
+
);
|
|
950
|
+
const rpcUrl = env.PROBEMESH_X402_RPC_URL ? requireHttpUrl(env.PROBEMESH_X402_RPC_URL, "PROBEMESH_X402_RPC_URL") : void 0;
|
|
951
|
+
const privateKey = requirePrivateKey(
|
|
952
|
+
env.PROBEMESH_X402_EVM_PRIVATE_KEY,
|
|
953
|
+
"PROBEMESH_X402_EVM_PRIVATE_KEY"
|
|
954
|
+
);
|
|
955
|
+
const asset = requireEvmAddress(
|
|
956
|
+
env.PROBEMESH_X402_ASSET,
|
|
957
|
+
"PROBEMESH_X402_ASSET"
|
|
958
|
+
);
|
|
959
|
+
const payTo = requireEvmAddress(
|
|
960
|
+
env.PROBEMESH_X402_PAY_TO,
|
|
961
|
+
"PROBEMESH_X402_PAY_TO"
|
|
962
|
+
);
|
|
963
|
+
const assetMetadata = resolveTestnetAssetMetadata({
|
|
964
|
+
network,
|
|
965
|
+
asset,
|
|
966
|
+
env
|
|
967
|
+
});
|
|
968
|
+
const config = {
|
|
969
|
+
privateKey,
|
|
970
|
+
network,
|
|
971
|
+
rpcUrl,
|
|
972
|
+
facilitatorUrl,
|
|
973
|
+
amount,
|
|
974
|
+
asset,
|
|
975
|
+
payTo,
|
|
976
|
+
assetMetadata
|
|
977
|
+
};
|
|
978
|
+
return {
|
|
979
|
+
ok: true,
|
|
980
|
+
config,
|
|
981
|
+
summary: {
|
|
982
|
+
network,
|
|
983
|
+
rpcConfigured: typeof rpcUrl === "string",
|
|
984
|
+
facilitatorUrl,
|
|
985
|
+
amount,
|
|
986
|
+
asset,
|
|
987
|
+
payTo,
|
|
988
|
+
assetMetadata,
|
|
989
|
+
privateKeyConfigured: true
|
|
990
|
+
}
|
|
991
|
+
};
|
|
992
|
+
}
|
|
993
|
+
function createX402EvmSigner(options = {}) {
|
|
994
|
+
assertX402EvmSignerOptions(options);
|
|
995
|
+
const signer = resolveClientEvmSigner(options);
|
|
996
|
+
const networks = resolveNetworks(options);
|
|
997
|
+
const client = new x402Client();
|
|
998
|
+
registerExactEvmScheme(client, {
|
|
999
|
+
signer,
|
|
1000
|
+
networks,
|
|
1001
|
+
schemeOptions: options.schemeOptions
|
|
1002
|
+
});
|
|
1003
|
+
return async (input) => {
|
|
1004
|
+
try {
|
|
1005
|
+
const paymentPayload = await client.createPaymentPayload(
|
|
1006
|
+
input.paymentRequired
|
|
1007
|
+
);
|
|
1008
|
+
return {
|
|
1009
|
+
paymentPayload,
|
|
1010
|
+
payer: signer.address,
|
|
1011
|
+
metadata: {
|
|
1012
|
+
signer: "evm",
|
|
1013
|
+
scheme: "exact",
|
|
1014
|
+
address: signer.address,
|
|
1015
|
+
networks,
|
|
1016
|
+
rpcConfigured: typeof options.rpcUrl === "string"
|
|
1017
|
+
}
|
|
1018
|
+
};
|
|
1019
|
+
} catch (error) {
|
|
1020
|
+
throw new ProbeMeshError({
|
|
1021
|
+
code: "payment_failed",
|
|
1022
|
+
message: `x402 EVM signer failed to create a payment payload for provider "${input.providerId}".`,
|
|
1023
|
+
capability: input.capability,
|
|
1024
|
+
provider: input.providerId,
|
|
1025
|
+
callId: input.callId,
|
|
1026
|
+
safety: {
|
|
1027
|
+
paymentStatus: "failed",
|
|
1028
|
+
settlementStatus: "not_attempted",
|
|
1029
|
+
deliveryStatus: "not_attempted",
|
|
1030
|
+
moneyMayHaveMoved: false
|
|
1031
|
+
},
|
|
1032
|
+
cause: error
|
|
1033
|
+
});
|
|
1034
|
+
}
|
|
1035
|
+
};
|
|
1036
|
+
}
|
|
1037
|
+
function createX402HttpFacilitator(options = {}) {
|
|
1038
|
+
assertX402HttpFacilitatorOptions(options);
|
|
1039
|
+
const baseUrl = (options.url ?? DEFAULT_FACILITATOR_URL).replace(/\/+$/, "");
|
|
1040
|
+
const timeoutMs = options.timeoutMs;
|
|
1041
|
+
return {
|
|
1042
|
+
async verify(input) {
|
|
1043
|
+
const response = await postFacilitatorJson({
|
|
1044
|
+
baseUrl,
|
|
1045
|
+
path: "verify",
|
|
1046
|
+
timeoutMs,
|
|
1047
|
+
createAuthHeaders: options.createAuthHeaders,
|
|
1048
|
+
body: {
|
|
1049
|
+
x402Version: input.paymentPayload.x402Version,
|
|
1050
|
+
paymentPayload: input.paymentPayload,
|
|
1051
|
+
paymentRequirements: input.paymentRequirements
|
|
1052
|
+
},
|
|
1053
|
+
providerId: input.providerId,
|
|
1054
|
+
capability: input.capability,
|
|
1055
|
+
callId: input.callId,
|
|
1056
|
+
unsafeAfterPayment: false
|
|
1057
|
+
});
|
|
1058
|
+
return response;
|
|
1059
|
+
},
|
|
1060
|
+
async settle(input) {
|
|
1061
|
+
const response = await postFacilitatorJson({
|
|
1062
|
+
baseUrl,
|
|
1063
|
+
path: "settle",
|
|
1064
|
+
timeoutMs,
|
|
1065
|
+
createAuthHeaders: options.createAuthHeaders,
|
|
1066
|
+
body: {
|
|
1067
|
+
x402Version: input.paymentPayload.x402Version,
|
|
1068
|
+
paymentPayload: input.paymentPayload,
|
|
1069
|
+
paymentRequirements: input.paymentRequirements
|
|
1070
|
+
},
|
|
1071
|
+
providerId: input.providerId,
|
|
1072
|
+
capability: input.capability,
|
|
1073
|
+
callId: input.callId,
|
|
1074
|
+
unsafeAfterPayment: true
|
|
1075
|
+
});
|
|
1076
|
+
return response;
|
|
1077
|
+
}
|
|
1078
|
+
};
|
|
1079
|
+
}
|
|
1080
|
+
function resolveClientEvmSigner(options) {
|
|
1081
|
+
const signer = options.signer ?? (options.privateKey ? privateKeyToAccount(options.privateKey) : void 0);
|
|
1082
|
+
if (!signer) {
|
|
1083
|
+
throw new ProbeMeshError({
|
|
1084
|
+
code: "invalid_request",
|
|
1085
|
+
message: "x402 EVM signer requires either privateKey or signer."
|
|
1086
|
+
});
|
|
1087
|
+
}
|
|
1088
|
+
if (options.rpcUrl) {
|
|
1089
|
+
const publicClient = createPublicClient({
|
|
1090
|
+
transport: http(options.rpcUrl)
|
|
1091
|
+
});
|
|
1092
|
+
return toClientEvmSigner(signer, publicClient);
|
|
1093
|
+
}
|
|
1094
|
+
return signer;
|
|
1095
|
+
}
|
|
1096
|
+
function resolveNetworks(options) {
|
|
1097
|
+
if (options.networks !== void 0) {
|
|
1098
|
+
return options.networks;
|
|
1099
|
+
}
|
|
1100
|
+
return [options.network ?? DEFAULT_NETWORK];
|
|
1101
|
+
}
|
|
1102
|
+
function assertX402EvmSignerOptions(options) {
|
|
1103
|
+
if (!options || typeof options !== "object" || Array.isArray(options)) {
|
|
1104
|
+
throw new ProbeMeshError({
|
|
1105
|
+
code: "invalid_request",
|
|
1106
|
+
message: "x402 EVM signer options must be an object."
|
|
1107
|
+
});
|
|
1108
|
+
}
|
|
1109
|
+
if (options.privateKey !== void 0 && (typeof options.privateKey !== "string" || !options.privateKey.startsWith("0x") || options.privateKey.length !== 66)) {
|
|
1110
|
+
throw new ProbeMeshError({
|
|
1111
|
+
code: "invalid_request",
|
|
1112
|
+
message: "x402 EVM signer privateKey must be a 32-byte 0x-prefixed hex string."
|
|
1113
|
+
});
|
|
1114
|
+
}
|
|
1115
|
+
if (options.signer !== void 0) {
|
|
1116
|
+
assertClientSigner(options.signer);
|
|
1117
|
+
}
|
|
1118
|
+
if (options.privateKey !== void 0 && options.signer !== void 0) {
|
|
1119
|
+
throw new ProbeMeshError({
|
|
1120
|
+
code: "invalid_request",
|
|
1121
|
+
message: "x402 EVM signer accepts either privateKey or signer, not both."
|
|
1122
|
+
});
|
|
1123
|
+
}
|
|
1124
|
+
if (options.network !== void 0 && !isValidEvmNetwork(options.network)) {
|
|
1125
|
+
throw new ProbeMeshError({
|
|
1126
|
+
code: "invalid_request",
|
|
1127
|
+
message: "x402 EVM signer network must use CAIP-2 eip155:<chainId> format."
|
|
1128
|
+
});
|
|
1129
|
+
}
|
|
1130
|
+
if (options.networks !== void 0 && (!Array.isArray(options.networks) || options.networks.length === 0 || options.networks.some((network) => !isValidEvmNetwork(network)))) {
|
|
1131
|
+
throw new ProbeMeshError({
|
|
1132
|
+
code: "invalid_request",
|
|
1133
|
+
message: "x402 EVM signer networks must be a non-empty array of CAIP-2 eip155:<chainId> values."
|
|
1134
|
+
});
|
|
1135
|
+
}
|
|
1136
|
+
if (options.network !== void 0 && options.networks !== void 0) {
|
|
1137
|
+
throw new ProbeMeshError({
|
|
1138
|
+
code: "invalid_request",
|
|
1139
|
+
message: "x402 EVM signer accepts either network or networks, not both."
|
|
1140
|
+
});
|
|
1141
|
+
}
|
|
1142
|
+
if (options.rpcUrl !== void 0 && (typeof options.rpcUrl !== "string" || options.rpcUrl.length === 0)) {
|
|
1143
|
+
throw new ProbeMeshError({
|
|
1144
|
+
code: "invalid_request",
|
|
1145
|
+
message: "x402 EVM signer rpcUrl must be a non-empty string when provided."
|
|
1146
|
+
});
|
|
1147
|
+
}
|
|
1148
|
+
}
|
|
1149
|
+
function assertX402HttpFacilitatorOptions(options) {
|
|
1150
|
+
if (!options || typeof options !== "object" || Array.isArray(options)) {
|
|
1151
|
+
throw new ProbeMeshError({
|
|
1152
|
+
code: "invalid_request",
|
|
1153
|
+
message: "x402 HTTP facilitator options must be an object."
|
|
1154
|
+
});
|
|
1155
|
+
}
|
|
1156
|
+
if (options.url !== void 0 && (typeof options.url !== "string" || options.url.length === 0)) {
|
|
1157
|
+
throw new ProbeMeshError({
|
|
1158
|
+
code: "invalid_request",
|
|
1159
|
+
message: "x402 HTTP facilitator url must be a non-empty string when provided."
|
|
1160
|
+
});
|
|
1161
|
+
}
|
|
1162
|
+
if (options.createAuthHeaders !== void 0 && typeof options.createAuthHeaders !== "function") {
|
|
1163
|
+
throw new ProbeMeshError({
|
|
1164
|
+
code: "invalid_request",
|
|
1165
|
+
message: "x402 HTTP facilitator createAuthHeaders must be a function when provided."
|
|
1166
|
+
});
|
|
1167
|
+
}
|
|
1168
|
+
if (options.timeoutMs !== void 0 && (!Number.isFinite(options.timeoutMs) || options.timeoutMs <= 0)) {
|
|
1169
|
+
throw new ProbeMeshError({
|
|
1170
|
+
code: "invalid_request",
|
|
1171
|
+
message: "x402 HTTP facilitator timeoutMs must be a positive number when provided."
|
|
1172
|
+
});
|
|
1173
|
+
}
|
|
1174
|
+
}
|
|
1175
|
+
async function postFacilitatorJson(options) {
|
|
1176
|
+
const controller = new AbortController();
|
|
1177
|
+
const timeout = options.timeoutMs !== void 0 ? setTimeout(() => controller.abort(), options.timeoutMs) : void 0;
|
|
1178
|
+
try {
|
|
1179
|
+
const authHeaders = await resolveFacilitatorAuthHeaders(
|
|
1180
|
+
options.createAuthHeaders,
|
|
1181
|
+
options.path
|
|
1182
|
+
);
|
|
1183
|
+
const response = await fetch(`${options.baseUrl}/${options.path}`, {
|
|
1184
|
+
method: "POST",
|
|
1185
|
+
headers: {
|
|
1186
|
+
"content-type": "application/json",
|
|
1187
|
+
...authHeaders
|
|
1188
|
+
},
|
|
1189
|
+
redirect: "follow",
|
|
1190
|
+
body: JSON.stringify(toJsonSafe(options.body)),
|
|
1191
|
+
signal: controller.signal
|
|
1192
|
+
});
|
|
1193
|
+
const responseText = await response.text();
|
|
1194
|
+
const responseBody = parseFacilitatorJson(
|
|
1195
|
+
responseText,
|
|
1196
|
+
options.path,
|
|
1197
|
+
options.providerId,
|
|
1198
|
+
options.capability,
|
|
1199
|
+
options.callId,
|
|
1200
|
+
options.unsafeAfterPayment
|
|
1201
|
+
);
|
|
1202
|
+
if (!response.ok && !isFacilitatorLifecycleResult(responseBody)) {
|
|
1203
|
+
throw facilitatorRequestError({
|
|
1204
|
+
path: options.path,
|
|
1205
|
+
providerId: options.providerId,
|
|
1206
|
+
capability: options.capability,
|
|
1207
|
+
callId: options.callId,
|
|
1208
|
+
unsafeAfterPayment: options.unsafeAfterPayment,
|
|
1209
|
+
message: `x402 HTTP facilitator ${options.path} request failed with HTTP ${response.status}.`
|
|
1210
|
+
});
|
|
1211
|
+
}
|
|
1212
|
+
return responseBody;
|
|
1213
|
+
} catch (error) {
|
|
1214
|
+
if (error instanceof ProbeMeshError) {
|
|
1215
|
+
throw error;
|
|
1216
|
+
}
|
|
1217
|
+
if (isAbortError(error)) {
|
|
1218
|
+
throw facilitatorRequestError({
|
|
1219
|
+
path: options.path,
|
|
1220
|
+
providerId: options.providerId,
|
|
1221
|
+
capability: options.capability,
|
|
1222
|
+
callId: options.callId,
|
|
1223
|
+
unsafeAfterPayment: options.unsafeAfterPayment,
|
|
1224
|
+
message: `x402 HTTP facilitator ${options.path} request timed out after ${options.timeoutMs}ms.`
|
|
1225
|
+
});
|
|
1226
|
+
}
|
|
1227
|
+
throw facilitatorRequestError({
|
|
1228
|
+
path: options.path,
|
|
1229
|
+
providerId: options.providerId,
|
|
1230
|
+
capability: options.capability,
|
|
1231
|
+
callId: options.callId,
|
|
1232
|
+
unsafeAfterPayment: options.unsafeAfterPayment,
|
|
1233
|
+
message: `x402 HTTP facilitator ${options.path} request failed.`
|
|
1234
|
+
});
|
|
1235
|
+
} finally {
|
|
1236
|
+
if (timeout) {
|
|
1237
|
+
clearTimeout(timeout);
|
|
1238
|
+
}
|
|
1239
|
+
}
|
|
1240
|
+
}
|
|
1241
|
+
async function resolveFacilitatorAuthHeaders(createAuthHeaders, path) {
|
|
1242
|
+
if (!createAuthHeaders) {
|
|
1243
|
+
return {};
|
|
1244
|
+
}
|
|
1245
|
+
const headers = await createAuthHeaders();
|
|
1246
|
+
const selected = headers[path] ?? {};
|
|
1247
|
+
if (!selected || typeof selected !== "object" || Array.isArray(selected) || Object.entries(selected).some(
|
|
1248
|
+
([key, value]) => typeof key !== "string" || key.length === 0 || typeof value !== "string"
|
|
1249
|
+
)) {
|
|
1250
|
+
throw new ProbeMeshError({
|
|
1251
|
+
code: "invalid_request",
|
|
1252
|
+
message: "x402 HTTP facilitator auth headers must be records of string values."
|
|
1253
|
+
});
|
|
1254
|
+
}
|
|
1255
|
+
return selected;
|
|
1256
|
+
}
|
|
1257
|
+
function parseFacilitatorJson(responseText, path, providerId, capability, callId, unsafeAfterPayment) {
|
|
1258
|
+
try {
|
|
1259
|
+
return responseText ? JSON.parse(responseText) : {};
|
|
1260
|
+
} catch {
|
|
1261
|
+
throw facilitatorRequestError({
|
|
1262
|
+
path,
|
|
1263
|
+
providerId,
|
|
1264
|
+
capability,
|
|
1265
|
+
callId,
|
|
1266
|
+
unsafeAfterPayment,
|
|
1267
|
+
message: `x402 HTTP facilitator ${path} response was not valid JSON.`
|
|
1268
|
+
});
|
|
1269
|
+
}
|
|
1270
|
+
}
|
|
1271
|
+
function isFacilitatorLifecycleResult(value) {
|
|
1272
|
+
return !!value && typeof value === "object" && !Array.isArray(value) && ("isValid" in value || "success" in value);
|
|
1273
|
+
}
|
|
1274
|
+
function facilitatorRequestError(options) {
|
|
1275
|
+
return new ProbeMeshError({
|
|
1276
|
+
code: "payment_failed",
|
|
1277
|
+
message: options.message,
|
|
1278
|
+
capability: options.capability,
|
|
1279
|
+
provider: options.providerId,
|
|
1280
|
+
callId: options.callId,
|
|
1281
|
+
safety: options.unsafeAfterPayment ? {
|
|
1282
|
+
paymentStatus: "authorized",
|
|
1283
|
+
settlementStatus: "failed",
|
|
1284
|
+
deliveryStatus: "missing",
|
|
1285
|
+
moneyMayHaveMoved: true
|
|
1286
|
+
} : {
|
|
1287
|
+
paymentStatus: "failed",
|
|
1288
|
+
settlementStatus: "not_attempted",
|
|
1289
|
+
deliveryStatus: "not_attempted",
|
|
1290
|
+
moneyMayHaveMoved: false
|
|
1291
|
+
}
|
|
1292
|
+
});
|
|
1293
|
+
}
|
|
1294
|
+
function toJsonSafe(value) {
|
|
1295
|
+
if (typeof value === "bigint") {
|
|
1296
|
+
return value.toString();
|
|
1297
|
+
}
|
|
1298
|
+
if (Array.isArray(value)) {
|
|
1299
|
+
return value.map((entry) => toJsonSafe(entry));
|
|
1300
|
+
}
|
|
1301
|
+
if (value && typeof value === "object") {
|
|
1302
|
+
return Object.fromEntries(
|
|
1303
|
+
Object.entries(value).map(([key, entry]) => [key, toJsonSafe(entry)])
|
|
1304
|
+
);
|
|
1305
|
+
}
|
|
1306
|
+
return value;
|
|
1307
|
+
}
|
|
1308
|
+
function isAbortError(error) {
|
|
1309
|
+
return !!error && typeof error === "object" && "name" in error && error.name === "AbortError";
|
|
1310
|
+
}
|
|
1311
|
+
function assertTestnetConfigOptions(options) {
|
|
1312
|
+
if (!options || typeof options !== "object" || Array.isArray(options)) {
|
|
1313
|
+
throw new ProbeMeshError({
|
|
1314
|
+
code: "invalid_request",
|
|
1315
|
+
message: "x402 EVM testnet config options must be an object."
|
|
1316
|
+
});
|
|
1317
|
+
}
|
|
1318
|
+
if (options.env !== void 0 && (!options.env || typeof options.env !== "object" || Array.isArray(options.env))) {
|
|
1319
|
+
throw new ProbeMeshError({
|
|
1320
|
+
code: "invalid_request",
|
|
1321
|
+
message: "x402 EVM testnet config env must be an object when provided."
|
|
1322
|
+
});
|
|
1323
|
+
}
|
|
1324
|
+
if (options.defaultNetwork !== void 0 && !isValidEvmNetwork(options.defaultNetwork)) {
|
|
1325
|
+
throw new ProbeMeshError({
|
|
1326
|
+
code: "invalid_request",
|
|
1327
|
+
message: "x402 EVM testnet defaultNetwork must use CAIP-2 eip155:<chainId> format."
|
|
1328
|
+
});
|
|
1329
|
+
}
|
|
1330
|
+
if (options.defaultAmount !== void 0) {
|
|
1331
|
+
requirePositiveIntegerString(
|
|
1332
|
+
options.defaultAmount,
|
|
1333
|
+
"x402 EVM testnet defaultAmount"
|
|
1334
|
+
);
|
|
1335
|
+
}
|
|
1336
|
+
if (options.defaultFacilitatorUrl !== void 0) {
|
|
1337
|
+
requireHttpUrl(
|
|
1338
|
+
options.defaultFacilitatorUrl,
|
|
1339
|
+
"x402 EVM testnet defaultFacilitatorUrl"
|
|
1340
|
+
);
|
|
1341
|
+
}
|
|
1342
|
+
}
|
|
1343
|
+
function assertClientSigner(signer) {
|
|
1344
|
+
if (!signer || typeof signer !== "object" || Array.isArray(signer) || typeof signer.address !== "string" || !signer.address.startsWith("0x") || typeof signer.signTypedData !== "function") {
|
|
1345
|
+
throw new ProbeMeshError({
|
|
1346
|
+
code: "invalid_request",
|
|
1347
|
+
message: "x402 EVM signer signer must expose address and signTypedData(...)."
|
|
1348
|
+
});
|
|
1349
|
+
}
|
|
1350
|
+
}
|
|
1351
|
+
function isValidEvmNetwork(network) {
|
|
1352
|
+
return typeof network === "string" && /^eip155:[1-9][0-9]*$/.test(network);
|
|
1353
|
+
}
|
|
1354
|
+
function requireEvmNetwork(value, field) {
|
|
1355
|
+
if (!isValidEvmNetwork(value)) {
|
|
1356
|
+
throw new ProbeMeshError({
|
|
1357
|
+
code: "invalid_request",
|
|
1358
|
+
message: `${field} must use CAIP-2 eip155:<chainId> format.`
|
|
1359
|
+
});
|
|
1360
|
+
}
|
|
1361
|
+
return value;
|
|
1362
|
+
}
|
|
1363
|
+
function requirePrivateKey(value, field) {
|
|
1364
|
+
if (typeof value !== "string" || !value.startsWith("0x") || value.length !== 66 || !/^0x[0-9a-fA-F]{64}$/.test(value)) {
|
|
1365
|
+
throw new ProbeMeshError({
|
|
1366
|
+
code: "invalid_request",
|
|
1367
|
+
message: `${field} must be a 32-byte 0x-prefixed hex string.`
|
|
1368
|
+
});
|
|
1369
|
+
}
|
|
1370
|
+
return value;
|
|
1371
|
+
}
|
|
1372
|
+
function requireEvmAddress(value, field) {
|
|
1373
|
+
if (typeof value !== "string" || !/^0x[0-9a-fA-F]{40}$/.test(value)) {
|
|
1374
|
+
throw new ProbeMeshError({
|
|
1375
|
+
code: "invalid_request",
|
|
1376
|
+
message: `${field} must be a 20-byte 0x-prefixed EVM address.`
|
|
1377
|
+
});
|
|
1378
|
+
}
|
|
1379
|
+
return value;
|
|
1380
|
+
}
|
|
1381
|
+
function requirePositiveIntegerString(value, field) {
|
|
1382
|
+
if (typeof value !== "string" || !/^[1-9][0-9]*$/.test(value)) {
|
|
1383
|
+
throw new ProbeMeshError({
|
|
1384
|
+
code: "invalid_request",
|
|
1385
|
+
message: `${field} must be a positive integer string.`
|
|
1386
|
+
});
|
|
1387
|
+
}
|
|
1388
|
+
return value;
|
|
1389
|
+
}
|
|
1390
|
+
function requireHttpUrl(value, field) {
|
|
1391
|
+
if (typeof value !== "string" || value.length === 0) {
|
|
1392
|
+
throw new ProbeMeshError({
|
|
1393
|
+
code: "invalid_request",
|
|
1394
|
+
message: `${field} must be a non-empty HTTP(S) URL.`
|
|
1395
|
+
});
|
|
1396
|
+
}
|
|
1397
|
+
try {
|
|
1398
|
+
const url = new URL(value);
|
|
1399
|
+
if (url.protocol !== "http:" && url.protocol !== "https:") {
|
|
1400
|
+
throw new Error("invalid protocol");
|
|
1401
|
+
}
|
|
1402
|
+
} catch {
|
|
1403
|
+
throw new ProbeMeshError({
|
|
1404
|
+
code: "invalid_request",
|
|
1405
|
+
message: `${field} must be a valid HTTP(S) URL.`
|
|
1406
|
+
});
|
|
1407
|
+
}
|
|
1408
|
+
return value;
|
|
1409
|
+
}
|
|
1410
|
+
function resolveTestnetAssetMetadata(options) {
|
|
1411
|
+
const configuredName = options.env.PROBEMESH_X402_ASSET_NAME;
|
|
1412
|
+
const configuredVersion = options.env.PROBEMESH_X402_ASSET_VERSION;
|
|
1413
|
+
if (configuredName !== void 0 && configuredName.length === 0) {
|
|
1414
|
+
throw new ProbeMeshError({
|
|
1415
|
+
code: "invalid_request",
|
|
1416
|
+
message: "PROBEMESH_X402_ASSET_NAME must be non-empty when provided."
|
|
1417
|
+
});
|
|
1418
|
+
}
|
|
1419
|
+
if (configuredVersion !== void 0 && configuredVersion.length === 0) {
|
|
1420
|
+
throw new ProbeMeshError({
|
|
1421
|
+
code: "invalid_request",
|
|
1422
|
+
message: "PROBEMESH_X402_ASSET_VERSION must be non-empty when provided."
|
|
1423
|
+
});
|
|
1424
|
+
}
|
|
1425
|
+
if (configuredName && configuredVersion) {
|
|
1426
|
+
return {
|
|
1427
|
+
name: configuredName,
|
|
1428
|
+
version: configuredVersion
|
|
1429
|
+
};
|
|
1430
|
+
}
|
|
1431
|
+
try {
|
|
1432
|
+
const defaultAsset = getDefaultAsset(options.network);
|
|
1433
|
+
if (defaultAsset.address.toLowerCase() === options.asset.toLowerCase()) {
|
|
1434
|
+
return {
|
|
1435
|
+
name: configuredName ?? defaultAsset.name,
|
|
1436
|
+
version: configuredVersion ?? defaultAsset.version
|
|
1437
|
+
};
|
|
1438
|
+
}
|
|
1439
|
+
} catch {
|
|
1440
|
+
}
|
|
1441
|
+
return {
|
|
1442
|
+
name: configuredName ?? "USDC",
|
|
1443
|
+
version: configuredVersion ?? "2"
|
|
1444
|
+
};
|
|
1445
|
+
}
|
|
1446
|
+
|
|
1447
|
+
// src/protocols/x402Protocol.ts
|
|
1448
|
+
import {
|
|
1449
|
+
decodePaymentRequiredHeader,
|
|
1450
|
+
decodePaymentSignatureHeader,
|
|
1451
|
+
encodePaymentRequiredHeader,
|
|
1452
|
+
encodePaymentResponseHeader,
|
|
1453
|
+
encodePaymentSignatureHeader
|
|
1454
|
+
} from "@x402/core/http";
|
|
1455
|
+
var DEFAULT_MODE2 = "x402";
|
|
1456
|
+
var DEFAULT_PAYER = "local-x402-agent";
|
|
1457
|
+
var DEFAULT_NETWORK2 = "eip155:84532";
|
|
1458
|
+
var DEFAULT_ASSET = "USDC";
|
|
1459
|
+
var DEFAULT_AMOUNT2 = "10000";
|
|
1460
|
+
var DEFAULT_PAY_TO = "probemesh-local-x402-provider";
|
|
1461
|
+
var DEFAULT_TIMEOUT_SECONDS = 60;
|
|
1462
|
+
var PAYMENT_REQUIRED_HEADER = "PAYMENT-REQUIRED";
|
|
1463
|
+
var PAYMENT_SIGNATURE_HEADER = "PAYMENT-SIGNATURE";
|
|
1464
|
+
var PAYMENT_RESPONSE_HEADER = "PAYMENT-RESPONSE";
|
|
1465
|
+
function createX402Protocol(options = {}) {
|
|
1466
|
+
assertX402ProtocolOptions(options);
|
|
1467
|
+
const mode = options.mode ?? X402_PROTOCOL_DEFAULT_MODE;
|
|
1468
|
+
const signer = options.signer ?? createX402LocalSigner({
|
|
1469
|
+
payer: options.payer,
|
|
1470
|
+
paymentId: options.paymentId
|
|
1471
|
+
});
|
|
1472
|
+
const facilitator = options.facilitator ?? createX402LocalFacilitator();
|
|
1473
|
+
return {
|
|
1474
|
+
mode,
|
|
1475
|
+
async prepare({ manifest, request, context }) {
|
|
1476
|
+
assertProviderMatches(
|
|
1477
|
+
options.providerId,
|
|
1478
|
+
manifest.id,
|
|
1479
|
+
request.capability,
|
|
1480
|
+
context.callId
|
|
1481
|
+
);
|
|
1482
|
+
const paymentRequired = await resolvePaymentRequired({
|
|
1483
|
+
options,
|
|
1484
|
+
manifest,
|
|
1485
|
+
request,
|
|
1486
|
+
context
|
|
1487
|
+
});
|
|
1488
|
+
const paymentRequirements = paymentRequired.accepts[0];
|
|
1489
|
+
const paymentId = options.paymentId ?? `${context.callId}:x402_payment`;
|
|
1490
|
+
const payer = options.payer ?? DEFAULT_PAYER;
|
|
1491
|
+
const signerResult = await signer({
|
|
1492
|
+
paymentRequired,
|
|
1493
|
+
paymentRequirements,
|
|
1494
|
+
manifest,
|
|
1495
|
+
request,
|
|
1496
|
+
context,
|
|
1497
|
+
providerId: manifest.id,
|
|
1498
|
+
capability: request.capability,
|
|
1499
|
+
callId: context.callId,
|
|
1500
|
+
paymentId,
|
|
1501
|
+
payer
|
|
1502
|
+
});
|
|
1503
|
+
assertSignerResult(signerResult, request.capability, manifest.id, context.callId);
|
|
1504
|
+
assertPaymentPayload(
|
|
1505
|
+
signerResult.paymentPayload,
|
|
1506
|
+
paymentRequirements,
|
|
1507
|
+
request.capability,
|
|
1508
|
+
manifest.id,
|
|
1509
|
+
context.callId
|
|
1510
|
+
);
|
|
1511
|
+
const verifyResult = await facilitator.verify({
|
|
1512
|
+
paymentPayload: signerResult.paymentPayload,
|
|
1513
|
+
paymentRequirements,
|
|
1514
|
+
paymentRequired,
|
|
1515
|
+
manifest,
|
|
1516
|
+
request,
|
|
1517
|
+
context,
|
|
1518
|
+
providerId: manifest.id,
|
|
1519
|
+
capability: request.capability,
|
|
1520
|
+
callId: context.callId
|
|
1521
|
+
});
|
|
1522
|
+
assertVerifyResult(
|
|
1523
|
+
verifyResult,
|
|
1524
|
+
request.capability,
|
|
1525
|
+
manifest.id,
|
|
1526
|
+
context.callId
|
|
1527
|
+
);
|
|
1528
|
+
if (!verifyResult.isValid) {
|
|
1529
|
+
throw new ProbeMeshError({
|
|
1530
|
+
code: "payment_failed",
|
|
1531
|
+
message: verifyResult.invalidMessage ?? `x402 facilitator rejected payment for provider "${manifest.id}".`,
|
|
1532
|
+
capability: request.capability,
|
|
1533
|
+
provider: manifest.id,
|
|
1534
|
+
callId: context.callId,
|
|
1535
|
+
safety: failedPaymentSafety()
|
|
1536
|
+
});
|
|
1537
|
+
}
|
|
1538
|
+
const headers = {
|
|
1539
|
+
[PAYMENT_REQUIRED_HEADER]: encodePaymentRequiredHeader(paymentRequired),
|
|
1540
|
+
[PAYMENT_SIGNATURE_HEADER]: encodePaymentSignatureHeader(
|
|
1541
|
+
signerResult.paymentPayload
|
|
1542
|
+
)
|
|
1543
|
+
};
|
|
1544
|
+
const resolvedPayer = verifyResult.payer ?? signerResult.payer ?? getPayloadString(signerResult.paymentPayload, "payer") ?? payer;
|
|
1545
|
+
const paymentAttemptId = `${paymentId}:attempt`;
|
|
1546
|
+
const preparation = {
|
|
1547
|
+
mode: manifest.protocolMode,
|
|
1548
|
+
metadata: {
|
|
1549
|
+
authorized: true,
|
|
1550
|
+
verified: true,
|
|
1551
|
+
x402Version: 2,
|
|
1552
|
+
paymentId,
|
|
1553
|
+
paymentAttemptId,
|
|
1554
|
+
payer: resolvedPayer,
|
|
1555
|
+
network: paymentRequirements.network,
|
|
1556
|
+
asset: paymentRequirements.asset,
|
|
1557
|
+
amount: paymentRequirements.amount,
|
|
1558
|
+
paymentRequired,
|
|
1559
|
+
selectedPaymentRequirements: paymentRequirements,
|
|
1560
|
+
verifyResponse: verifyResult,
|
|
1561
|
+
signerMetadata: signerResult.metadata,
|
|
1562
|
+
paymentRequiredHeader: PAYMENT_REQUIRED_HEADER,
|
|
1563
|
+
paymentSignatureHeader: PAYMENT_SIGNATURE_HEADER
|
|
1564
|
+
},
|
|
1565
|
+
receiptRefs: [
|
|
1566
|
+
{
|
|
1567
|
+
type: "payment_proof",
|
|
1568
|
+
provider: manifest.id,
|
|
1569
|
+
status: "recorded",
|
|
1570
|
+
ref: `${context.callId}:x402_payment_proof`,
|
|
1571
|
+
timestamp: context.startedAt.toISOString()
|
|
1572
|
+
}
|
|
1573
|
+
],
|
|
1574
|
+
safety: {
|
|
1575
|
+
paymentAttemptId,
|
|
1576
|
+
paymentStatus: "authorized",
|
|
1577
|
+
settlementStatus: "not_attempted",
|
|
1578
|
+
deliveryStatus: "not_attempted",
|
|
1579
|
+
moneyMayHaveMoved: true
|
|
1580
|
+
}
|
|
1581
|
+
};
|
|
1582
|
+
defineNonEnumerableHeaders(preparation, headers);
|
|
1583
|
+
return preparation;
|
|
1584
|
+
},
|
|
1585
|
+
async settle({ manifest, request, context, result, preparation }) {
|
|
1586
|
+
assertProviderMatches(
|
|
1587
|
+
options.providerId,
|
|
1588
|
+
manifest.id,
|
|
1589
|
+
request.capability,
|
|
1590
|
+
context.callId
|
|
1591
|
+
);
|
|
1592
|
+
const preparedPayment = decodePreparedPayment(
|
|
1593
|
+
preparation,
|
|
1594
|
+
request.capability,
|
|
1595
|
+
manifest.id,
|
|
1596
|
+
context.callId
|
|
1597
|
+
);
|
|
1598
|
+
const settleResult = await facilitator.settle({
|
|
1599
|
+
...preparedPayment,
|
|
1600
|
+
result,
|
|
1601
|
+
manifest,
|
|
1602
|
+
request,
|
|
1603
|
+
context,
|
|
1604
|
+
providerId: manifest.id,
|
|
1605
|
+
capability: request.capability,
|
|
1606
|
+
callId: context.callId
|
|
1607
|
+
});
|
|
1608
|
+
assertSettleResult(
|
|
1609
|
+
settleResult,
|
|
1610
|
+
request.capability,
|
|
1611
|
+
manifest.id,
|
|
1612
|
+
context.callId
|
|
1613
|
+
);
|
|
1614
|
+
const paymentId = getPayloadString(preparedPayment.paymentPayload, "paymentId") ?? `${context.callId}:x402_payment`;
|
|
1615
|
+
const paymentAttemptId = `${paymentId}:attempt`;
|
|
1616
|
+
const hasDeliveryReceipt = Array.isArray(result.receiptRefs) && result.receiptRefs.some(
|
|
1617
|
+
(receiptRef) => receiptRef.type === "provider_delivery"
|
|
1618
|
+
);
|
|
1619
|
+
if (!settleResult.success) {
|
|
1620
|
+
throw new ProbeMeshError({
|
|
1621
|
+
code: "payment_failed",
|
|
1622
|
+
message: settleResult.errorMessage ?? `x402 facilitator failed settlement for provider "${manifest.id}".`,
|
|
1623
|
+
capability: request.capability,
|
|
1624
|
+
provider: manifest.id,
|
|
1625
|
+
callId: context.callId,
|
|
1626
|
+
safety: {
|
|
1627
|
+
paymentAttemptId,
|
|
1628
|
+
paymentStatus: "authorized",
|
|
1629
|
+
settlementStatus: "failed",
|
|
1630
|
+
deliveryStatus: hasDeliveryReceipt ? "delivered" : "missing",
|
|
1631
|
+
moneyMayHaveMoved: true
|
|
1632
|
+
}
|
|
1633
|
+
});
|
|
1634
|
+
}
|
|
1635
|
+
const headers = {
|
|
1636
|
+
[PAYMENT_RESPONSE_HEADER]: encodePaymentResponseHeader(settleResult)
|
|
1637
|
+
};
|
|
1638
|
+
const settlement = {
|
|
1639
|
+
mode: manifest.protocolMode,
|
|
1640
|
+
metadata: {
|
|
1641
|
+
settled: true,
|
|
1642
|
+
x402Version: 2,
|
|
1643
|
+
paymentId,
|
|
1644
|
+
paymentAttemptId,
|
|
1645
|
+
settlementResponse: settleResult,
|
|
1646
|
+
paymentResponseHeader: PAYMENT_RESPONSE_HEADER
|
|
1647
|
+
},
|
|
1648
|
+
receiptRefs: [
|
|
1649
|
+
{
|
|
1650
|
+
type: "settlement_confirmation",
|
|
1651
|
+
provider: manifest.id,
|
|
1652
|
+
status: "recorded",
|
|
1653
|
+
ref: `${context.callId}:x402_settlement_confirmed`,
|
|
1654
|
+
timestamp: context.startedAt.toISOString()
|
|
1655
|
+
}
|
|
1656
|
+
],
|
|
1657
|
+
safety: {
|
|
1658
|
+
paymentAttemptId,
|
|
1659
|
+
paymentStatus: "authorized",
|
|
1660
|
+
settlementStatus: "settled",
|
|
1661
|
+
deliveryStatus: hasDeliveryReceipt ? "delivered" : "missing",
|
|
1662
|
+
moneyMayHaveMoved: true
|
|
1663
|
+
}
|
|
1664
|
+
};
|
|
1665
|
+
defineNonEnumerableHeaders(settlement, headers);
|
|
1666
|
+
return settlement;
|
|
1667
|
+
}
|
|
1668
|
+
};
|
|
1669
|
+
}
|
|
1670
|
+
function createX402LocalSigner(options = {}) {
|
|
1671
|
+
assertLocalSignerOptions(options);
|
|
1672
|
+
return (input) => {
|
|
1673
|
+
if (options.failSign) {
|
|
1674
|
+
throw new ProbeMeshError({
|
|
1675
|
+
code: "payment_failed",
|
|
1676
|
+
message: `x402 local signer failed for provider "${input.providerId}".`,
|
|
1677
|
+
capability: input.capability,
|
|
1678
|
+
provider: input.providerId,
|
|
1679
|
+
callId: input.callId,
|
|
1680
|
+
safety: noPaymentSafety2()
|
|
1681
|
+
});
|
|
1682
|
+
}
|
|
1683
|
+
const payer = options.payer ?? input.payer;
|
|
1684
|
+
const paymentId = options.paymentId ?? input.paymentId;
|
|
1685
|
+
const issuedAt = input.context.startedAt.toISOString();
|
|
1686
|
+
const paymentPayload = {
|
|
1687
|
+
x402Version: 2,
|
|
1688
|
+
resource: input.paymentRequired.resource,
|
|
1689
|
+
accepted: input.paymentRequirements,
|
|
1690
|
+
payload: {
|
|
1691
|
+
...options.payload ?? {},
|
|
1692
|
+
kind: "probemesh-local-x402-signature",
|
|
1693
|
+
payer,
|
|
1694
|
+
provider: input.providerId,
|
|
1695
|
+
callId: input.callId,
|
|
1696
|
+
paymentId,
|
|
1697
|
+
issuedAt,
|
|
1698
|
+
signature: `local-x402:${input.providerId}:${input.callId}:${paymentId}`
|
|
1699
|
+
},
|
|
1700
|
+
extensions: input.paymentRequired.extensions
|
|
1701
|
+
};
|
|
1702
|
+
return {
|
|
1703
|
+
payer,
|
|
1704
|
+
paymentPayload,
|
|
1705
|
+
metadata: {
|
|
1706
|
+
signer: "local",
|
|
1707
|
+
paymentId
|
|
1708
|
+
}
|
|
1709
|
+
};
|
|
1710
|
+
};
|
|
1711
|
+
}
|
|
1712
|
+
function createX402LocalFacilitator(options = {}) {
|
|
1713
|
+
assertLocalFacilitatorOptions(options);
|
|
1714
|
+
return {
|
|
1715
|
+
verify(input) {
|
|
1716
|
+
const payer = options.payer ?? getPayloadString(input.paymentPayload, "payer") ?? DEFAULT_PAYER;
|
|
1717
|
+
if (options.failVerify) {
|
|
1718
|
+
return {
|
|
1719
|
+
isValid: false,
|
|
1720
|
+
invalidReason: options.invalidReason ?? "local_verify_failed",
|
|
1721
|
+
invalidMessage: options.invalidMessage ?? `x402 local facilitator rejected payment for provider "${input.providerId}".`,
|
|
1722
|
+
payer,
|
|
1723
|
+
extra: {
|
|
1724
|
+
provider: input.providerId,
|
|
1725
|
+
callId: input.callId
|
|
1726
|
+
}
|
|
1727
|
+
};
|
|
1728
|
+
}
|
|
1729
|
+
if (input.paymentPayload.x402Version !== 2) {
|
|
1730
|
+
return {
|
|
1731
|
+
isValid: false,
|
|
1732
|
+
invalidReason: "unsupported_x402_version",
|
|
1733
|
+
invalidMessage: "x402 local facilitator only accepts V2 payloads.",
|
|
1734
|
+
payer
|
|
1735
|
+
};
|
|
1736
|
+
}
|
|
1737
|
+
if (!paymentRequirementsMatch(
|
|
1738
|
+
input.paymentPayload.accepted,
|
|
1739
|
+
input.paymentRequirements
|
|
1740
|
+
)) {
|
|
1741
|
+
return {
|
|
1742
|
+
isValid: false,
|
|
1743
|
+
invalidReason: "requirements_mismatch",
|
|
1744
|
+
invalidMessage: "x402 payment payload does not match the selected payment requirements.",
|
|
1745
|
+
payer
|
|
1746
|
+
};
|
|
1747
|
+
}
|
|
1748
|
+
return {
|
|
1749
|
+
isValid: true,
|
|
1750
|
+
payer,
|
|
1751
|
+
extra: {
|
|
1752
|
+
provider: input.providerId,
|
|
1753
|
+
callId: input.callId,
|
|
1754
|
+
paymentId: getPayloadString(input.paymentPayload, "paymentId")
|
|
1755
|
+
}
|
|
1756
|
+
};
|
|
1757
|
+
},
|
|
1758
|
+
settle(input) {
|
|
1759
|
+
const payer = options.payer ?? getPayloadString(input.paymentPayload, "payer") ?? DEFAULT_PAYER;
|
|
1760
|
+
const transaction = options.transaction ?? `${input.callId}:x402_local_settlement`;
|
|
1761
|
+
const baseResponse = {
|
|
1762
|
+
payer,
|
|
1763
|
+
transaction,
|
|
1764
|
+
network: input.paymentRequirements.network,
|
|
1765
|
+
amount: input.paymentRequirements.amount,
|
|
1766
|
+
extra: {
|
|
1767
|
+
provider: input.providerId,
|
|
1768
|
+
callId: input.callId,
|
|
1769
|
+
paymentId: getPayloadString(input.paymentPayload, "paymentId")
|
|
1770
|
+
}
|
|
1771
|
+
};
|
|
1772
|
+
if (options.failSettle) {
|
|
1773
|
+
return {
|
|
1774
|
+
...baseResponse,
|
|
1775
|
+
success: false,
|
|
1776
|
+
errorReason: options.errorReason ?? "local_settle_failed",
|
|
1777
|
+
errorMessage: options.errorMessage ?? `x402 local facilitator failed settlement for provider "${input.providerId}".`
|
|
1778
|
+
};
|
|
1779
|
+
}
|
|
1780
|
+
return {
|
|
1781
|
+
...baseResponse,
|
|
1782
|
+
success: true
|
|
1783
|
+
};
|
|
1784
|
+
}
|
|
1785
|
+
};
|
|
1786
|
+
}
|
|
1787
|
+
async function resolvePaymentRequired(options) {
|
|
1788
|
+
const defaultPaymentRequired = createDefaultPaymentRequired({
|
|
1789
|
+
providerId: options.manifest.id,
|
|
1790
|
+
capability: options.request.capability,
|
|
1791
|
+
config: options.options.paymentRequired
|
|
1792
|
+
});
|
|
1793
|
+
const paymentRequired = options.options.resolvePaymentRequired ? await options.options.resolvePaymentRequired({
|
|
1794
|
+
manifest: options.manifest,
|
|
1795
|
+
request: options.request,
|
|
1796
|
+
context: options.context
|
|
1797
|
+
}) : defaultPaymentRequired;
|
|
1798
|
+
assertPaymentRequired(paymentRequired);
|
|
1799
|
+
return paymentRequired;
|
|
1800
|
+
}
|
|
1801
|
+
function decodePreparedPayment(preparation, capability, provider, callId) {
|
|
1802
|
+
const paymentRequiredHeader = preparation?.headers?.[PAYMENT_REQUIRED_HEADER];
|
|
1803
|
+
const paymentSignatureHeader = preparation?.headers?.[PAYMENT_SIGNATURE_HEADER];
|
|
1804
|
+
if (!paymentRequiredHeader || !paymentSignatureHeader) {
|
|
1805
|
+
throw new ProbeMeshError({
|
|
1806
|
+
code: "payment_failed",
|
|
1807
|
+
message: `x402 prepared payment headers are missing for provider "${provider}".`,
|
|
1808
|
+
capability,
|
|
1809
|
+
provider,
|
|
1810
|
+
callId,
|
|
1811
|
+
safety: {
|
|
1812
|
+
paymentStatus: "authorized",
|
|
1813
|
+
settlementStatus: "failed",
|
|
1814
|
+
deliveryStatus: "missing",
|
|
1815
|
+
moneyMayHaveMoved: true
|
|
1816
|
+
}
|
|
1817
|
+
});
|
|
1818
|
+
}
|
|
1819
|
+
const paymentRequired = decodePaymentRequiredHeader(paymentRequiredHeader);
|
|
1820
|
+
const paymentPayload = decodePaymentSignatureHeader(paymentSignatureHeader);
|
|
1821
|
+
assertPaymentRequired(paymentRequired);
|
|
1822
|
+
assertPaymentPayload(
|
|
1823
|
+
paymentPayload,
|
|
1824
|
+
paymentPayload.accepted,
|
|
1825
|
+
capability,
|
|
1826
|
+
provider,
|
|
1827
|
+
callId
|
|
1828
|
+
);
|
|
1829
|
+
return {
|
|
1830
|
+
paymentRequired,
|
|
1831
|
+
paymentPayload,
|
|
1832
|
+
paymentRequirements: paymentPayload.accepted
|
|
1833
|
+
};
|
|
1834
|
+
}
|
|
1835
|
+
function assertSignerResult(signerResult, capability, provider, callId) {
|
|
1836
|
+
if (!signerResult || typeof signerResult !== "object" || Array.isArray(signerResult)) {
|
|
1837
|
+
throw new ProbeMeshError({
|
|
1838
|
+
code: "payment_failed",
|
|
1839
|
+
message: `x402 signer returned an invalid result for provider "${provider}".`,
|
|
1840
|
+
capability,
|
|
1841
|
+
provider,
|
|
1842
|
+
callId,
|
|
1843
|
+
safety: failedPaymentSafety()
|
|
1844
|
+
});
|
|
1845
|
+
}
|
|
1846
|
+
}
|
|
1847
|
+
function assertPaymentPayload(paymentPayload, paymentRequirements, capability, provider, callId) {
|
|
1848
|
+
if (!paymentPayload || typeof paymentPayload !== "object" || Array.isArray(paymentPayload)) {
|
|
1849
|
+
throw new ProbeMeshError({
|
|
1850
|
+
code: "payment_failed",
|
|
1851
|
+
message: `x402 signer returned an invalid payment payload for provider "${provider}".`,
|
|
1852
|
+
capability,
|
|
1853
|
+
provider,
|
|
1854
|
+
callId,
|
|
1855
|
+
safety: failedPaymentSafety()
|
|
1856
|
+
});
|
|
1857
|
+
}
|
|
1858
|
+
if (paymentPayload.x402Version !== 2) {
|
|
1859
|
+
throw new ProbeMeshError({
|
|
1860
|
+
code: "payment_failed",
|
|
1861
|
+
message: "x402 payment payload x402Version must be 2.",
|
|
1862
|
+
capability,
|
|
1863
|
+
provider,
|
|
1864
|
+
callId,
|
|
1865
|
+
safety: failedPaymentSafety()
|
|
1866
|
+
});
|
|
1867
|
+
}
|
|
1868
|
+
if (!paymentPayload.accepted || typeof paymentPayload.accepted !== "object" || Array.isArray(paymentPayload.accepted)) {
|
|
1869
|
+
throw new ProbeMeshError({
|
|
1870
|
+
code: "payment_failed",
|
|
1871
|
+
message: "x402 payment payload accepted requirements must be an object.",
|
|
1872
|
+
capability,
|
|
1873
|
+
provider,
|
|
1874
|
+
callId,
|
|
1875
|
+
safety: failedPaymentSafety()
|
|
1876
|
+
});
|
|
1877
|
+
}
|
|
1878
|
+
if (!paymentPayload.payload || typeof paymentPayload.payload !== "object" || Array.isArray(paymentPayload.payload)) {
|
|
1879
|
+
throw new ProbeMeshError({
|
|
1880
|
+
code: "payment_failed",
|
|
1881
|
+
message: "x402 payment payload payload must be an object.",
|
|
1882
|
+
capability,
|
|
1883
|
+
provider,
|
|
1884
|
+
callId,
|
|
1885
|
+
safety: failedPaymentSafety()
|
|
1886
|
+
});
|
|
1887
|
+
}
|
|
1888
|
+
if (!paymentRequirementsMatch(paymentPayload.accepted, paymentRequirements)) {
|
|
1889
|
+
throw new ProbeMeshError({
|
|
1890
|
+
code: "payment_failed",
|
|
1891
|
+
message: "x402 payment payload does not match the selected payment requirements.",
|
|
1892
|
+
capability,
|
|
1893
|
+
provider,
|
|
1894
|
+
callId,
|
|
1895
|
+
safety: failedPaymentSafety()
|
|
1896
|
+
});
|
|
1897
|
+
}
|
|
1898
|
+
}
|
|
1899
|
+
function assertVerifyResult(verifyResult, capability, provider, callId) {
|
|
1900
|
+
if (!verifyResult || typeof verifyResult !== "object" || Array.isArray(verifyResult) || typeof verifyResult.isValid !== "boolean") {
|
|
1901
|
+
throw new ProbeMeshError({
|
|
1902
|
+
code: "payment_failed",
|
|
1903
|
+
message: `x402 facilitator returned an invalid verify response for provider "${provider}".`,
|
|
1904
|
+
capability,
|
|
1905
|
+
provider,
|
|
1906
|
+
callId,
|
|
1907
|
+
safety: failedPaymentSafety()
|
|
1908
|
+
});
|
|
1909
|
+
}
|
|
1910
|
+
}
|
|
1911
|
+
function assertSettleResult(settleResult, capability, provider, callId) {
|
|
1912
|
+
if (!settleResult || typeof settleResult !== "object" || Array.isArray(settleResult) || typeof settleResult.success !== "boolean" || typeof settleResult.transaction !== "string" || settleResult.transaction.length === 0 || typeof settleResult.network !== "string" || settleResult.network.length === 0) {
|
|
1913
|
+
throw new ProbeMeshError({
|
|
1914
|
+
code: "payment_failed",
|
|
1915
|
+
message: `x402 facilitator returned an invalid settlement response for provider "${provider}".`,
|
|
1916
|
+
capability,
|
|
1917
|
+
provider,
|
|
1918
|
+
callId,
|
|
1919
|
+
safety: {
|
|
1920
|
+
paymentStatus: "authorized",
|
|
1921
|
+
settlementStatus: "failed",
|
|
1922
|
+
deliveryStatus: "missing",
|
|
1923
|
+
moneyMayHaveMoved: true
|
|
1924
|
+
}
|
|
1925
|
+
});
|
|
1926
|
+
}
|
|
1927
|
+
}
|
|
1928
|
+
function createDefaultPaymentRequired(options) {
|
|
1929
|
+
const config = options.config ?? {};
|
|
1930
|
+
const accepts = config.accepts ?? [
|
|
1931
|
+
{
|
|
1932
|
+
scheme: config.scheme ?? "exact",
|
|
1933
|
+
network: normalizeNetwork(config.network ?? DEFAULT_NETWORK2),
|
|
1934
|
+
asset: config.asset ?? DEFAULT_ASSET,
|
|
1935
|
+
amount: config.amount ?? DEFAULT_AMOUNT2,
|
|
1936
|
+
payTo: config.payTo ?? DEFAULT_PAY_TO,
|
|
1937
|
+
maxTimeoutSeconds: config.maxTimeoutSeconds ?? DEFAULT_TIMEOUT_SECONDS,
|
|
1938
|
+
extra: config.extra ?? {}
|
|
1939
|
+
}
|
|
1940
|
+
];
|
|
1941
|
+
return {
|
|
1942
|
+
x402Version: config.x402Version ?? 2,
|
|
1943
|
+
error: config.error,
|
|
1944
|
+
resource: normalizeResourceInfo(
|
|
1945
|
+
config.resource,
|
|
1946
|
+
options.providerId,
|
|
1947
|
+
options.capability
|
|
1948
|
+
),
|
|
1949
|
+
accepts,
|
|
1950
|
+
extensions: config.extensions
|
|
1951
|
+
};
|
|
1952
|
+
}
|
|
1953
|
+
function assertPaymentRequired(paymentRequired) {
|
|
1954
|
+
if (!paymentRequired || typeof paymentRequired !== "object" || Array.isArray(paymentRequired)) {
|
|
1955
|
+
throw new ProbeMeshError({
|
|
1956
|
+
code: "invalid_request",
|
|
1957
|
+
message: "x402 paymentRequired must be an object."
|
|
1958
|
+
});
|
|
1959
|
+
}
|
|
1960
|
+
if (paymentRequired.x402Version !== 2) {
|
|
1961
|
+
throw new ProbeMeshError({
|
|
1962
|
+
code: "invalid_request",
|
|
1963
|
+
message: "x402 paymentRequired.x402Version must be 2."
|
|
1964
|
+
});
|
|
1965
|
+
}
|
|
1966
|
+
if (!paymentRequired.resource || typeof paymentRequired.resource !== "object" || typeof paymentRequired.resource.url !== "string" || paymentRequired.resource.url.length === 0) {
|
|
1967
|
+
throw new ProbeMeshError({
|
|
1968
|
+
code: "invalid_request",
|
|
1969
|
+
message: "x402 paymentRequired.resource.url must be a non-empty string."
|
|
1970
|
+
});
|
|
1971
|
+
}
|
|
1972
|
+
if (!Array.isArray(paymentRequired.accepts) || paymentRequired.accepts.length === 0) {
|
|
1973
|
+
throw new ProbeMeshError({
|
|
1974
|
+
code: "invalid_request",
|
|
1975
|
+
message: "x402 paymentRequired.accepts must include at least one option."
|
|
1976
|
+
});
|
|
1977
|
+
}
|
|
1978
|
+
for (const requirements of paymentRequired.accepts) {
|
|
1979
|
+
assertPaymentRequirements(requirements);
|
|
1980
|
+
}
|
|
1981
|
+
}
|
|
1982
|
+
function assertPaymentRequirements(requirements) {
|
|
1983
|
+
if (!requirements || typeof requirements !== "object") {
|
|
1984
|
+
throw new ProbeMeshError({
|
|
1985
|
+
code: "invalid_request",
|
|
1986
|
+
message: "x402 payment requirements must be an object."
|
|
1987
|
+
});
|
|
1988
|
+
}
|
|
1989
|
+
for (const field of ["scheme", "network", "asset", "amount", "payTo"]) {
|
|
1990
|
+
const value = requirements[field];
|
|
1991
|
+
if (typeof value !== "string" || value.length === 0) {
|
|
1992
|
+
throw new ProbeMeshError({
|
|
1993
|
+
code: "invalid_request",
|
|
1994
|
+
message: `x402 payment requirements ${field} must be a non-empty string.`
|
|
1995
|
+
});
|
|
1996
|
+
}
|
|
1997
|
+
}
|
|
1998
|
+
if (typeof requirements.maxTimeoutSeconds !== "number" || !Number.isFinite(requirements.maxTimeoutSeconds) || requirements.maxTimeoutSeconds <= 0) {
|
|
1999
|
+
throw new ProbeMeshError({
|
|
2000
|
+
code: "invalid_request",
|
|
2001
|
+
message: "x402 payment requirements maxTimeoutSeconds must be a positive number."
|
|
2002
|
+
});
|
|
2003
|
+
}
|
|
2004
|
+
if (!requirements.extra || typeof requirements.extra !== "object" || Array.isArray(requirements.extra)) {
|
|
2005
|
+
throw new ProbeMeshError({
|
|
2006
|
+
code: "invalid_request",
|
|
2007
|
+
message: "x402 payment requirements extra must be an object."
|
|
2008
|
+
});
|
|
2009
|
+
}
|
|
2010
|
+
}
|
|
2011
|
+
function assertX402ProtocolOptions(options) {
|
|
2012
|
+
validateOptionalString(options.mode, "mode");
|
|
2013
|
+
validateOptionalString(options.providerId, "providerId");
|
|
2014
|
+
validateOptionalString(options.payer, "payer");
|
|
2015
|
+
validateOptionalString(options.paymentId, "paymentId");
|
|
2016
|
+
if (options.paymentRequired !== void 0 && (!options.paymentRequired || typeof options.paymentRequired !== "object" || Array.isArray(options.paymentRequired))) {
|
|
2017
|
+
throw new ProbeMeshError({
|
|
2018
|
+
code: "invalid_request",
|
|
2019
|
+
message: "x402 paymentRequired config must be an object when provided."
|
|
2020
|
+
});
|
|
2021
|
+
}
|
|
2022
|
+
if (options.resolvePaymentRequired !== void 0 && typeof options.resolvePaymentRequired !== "function") {
|
|
2023
|
+
throw new ProbeMeshError({
|
|
2024
|
+
code: "invalid_request",
|
|
2025
|
+
message: "x402 resolvePaymentRequired must be a function when provided."
|
|
2026
|
+
});
|
|
2027
|
+
}
|
|
2028
|
+
if (options.signer !== void 0 && typeof options.signer !== "function") {
|
|
2029
|
+
throw new ProbeMeshError({
|
|
2030
|
+
code: "invalid_request",
|
|
2031
|
+
message: "x402 signer must be a function when provided."
|
|
2032
|
+
});
|
|
2033
|
+
}
|
|
2034
|
+
if (options.facilitator !== void 0 && (!options.facilitator || typeof options.facilitator !== "object" || typeof options.facilitator.verify !== "function" || typeof options.facilitator.settle !== "function")) {
|
|
2035
|
+
throw new ProbeMeshError({
|
|
2036
|
+
code: "invalid_request",
|
|
2037
|
+
message: "x402 facilitator must expose verify(...) and settle(...) functions."
|
|
2038
|
+
});
|
|
2039
|
+
}
|
|
2040
|
+
}
|
|
2041
|
+
function assertLocalSignerOptions(options) {
|
|
2042
|
+
validateOptionalString(options.payer, "local signer payer");
|
|
2043
|
+
validateOptionalString(options.paymentId, "local signer paymentId");
|
|
2044
|
+
if (options.failSign !== void 0 && typeof options.failSign !== "boolean") {
|
|
2045
|
+
throw new ProbeMeshError({
|
|
2046
|
+
code: "invalid_request",
|
|
2047
|
+
message: "x402 local signer failSign must be a boolean when provided."
|
|
2048
|
+
});
|
|
2049
|
+
}
|
|
2050
|
+
if (options.payload !== void 0 && (!options.payload || typeof options.payload !== "object" || Array.isArray(options.payload))) {
|
|
2051
|
+
throw new ProbeMeshError({
|
|
2052
|
+
code: "invalid_request",
|
|
2053
|
+
message: "x402 local signer payload must be an object when provided."
|
|
2054
|
+
});
|
|
2055
|
+
}
|
|
2056
|
+
}
|
|
2057
|
+
function assertLocalFacilitatorOptions(options) {
|
|
2058
|
+
validateOptionalString(options.payer, "local facilitator payer");
|
|
2059
|
+
validateOptionalString(options.invalidReason, "local facilitator invalidReason");
|
|
2060
|
+
validateOptionalString(options.invalidMessage, "local facilitator invalidMessage");
|
|
2061
|
+
validateOptionalString(options.errorReason, "local facilitator errorReason");
|
|
2062
|
+
validateOptionalString(options.errorMessage, "local facilitator errorMessage");
|
|
2063
|
+
validateOptionalString(options.transaction, "local facilitator transaction");
|
|
2064
|
+
if (options.failVerify !== void 0 && typeof options.failVerify !== "boolean") {
|
|
2065
|
+
throw new ProbeMeshError({
|
|
2066
|
+
code: "invalid_request",
|
|
2067
|
+
message: "x402 local facilitator failVerify must be a boolean when provided."
|
|
2068
|
+
});
|
|
2069
|
+
}
|
|
2070
|
+
if (options.failSettle !== void 0 && typeof options.failSettle !== "boolean") {
|
|
2071
|
+
throw new ProbeMeshError({
|
|
2072
|
+
code: "invalid_request",
|
|
2073
|
+
message: "x402 local facilitator failSettle must be a boolean when provided."
|
|
2074
|
+
});
|
|
2075
|
+
}
|
|
2076
|
+
}
|
|
2077
|
+
function normalizeResourceInfo(resource, providerId, capability) {
|
|
2078
|
+
if (typeof resource === "string") {
|
|
2079
|
+
return {
|
|
2080
|
+
url: resource,
|
|
2081
|
+
description: `ProbeMesh x402 payment for ${capability}.`,
|
|
2082
|
+
mimeType: "application/json",
|
|
2083
|
+
serviceName: providerId
|
|
2084
|
+
};
|
|
2085
|
+
}
|
|
2086
|
+
return {
|
|
2087
|
+
url: resource?.url ?? `probemesh://${providerId}/${capability}`,
|
|
2088
|
+
description: resource?.description ?? `ProbeMesh x402 payment for ${capability}.`,
|
|
2089
|
+
mimeType: resource?.mimeType ?? "application/json",
|
|
2090
|
+
serviceName: resource?.serviceName ?? providerId,
|
|
2091
|
+
tags: resource?.tags,
|
|
2092
|
+
iconUrl: resource?.iconUrl
|
|
2093
|
+
};
|
|
2094
|
+
}
|
|
2095
|
+
function normalizeNetwork(network) {
|
|
2096
|
+
if (!network.includes(":")) {
|
|
2097
|
+
throw new ProbeMeshError({
|
|
2098
|
+
code: "invalid_request",
|
|
2099
|
+
message: "x402 payment requirements network must use CAIP-2 format."
|
|
2100
|
+
});
|
|
2101
|
+
}
|
|
2102
|
+
return network;
|
|
2103
|
+
}
|
|
2104
|
+
function defineNonEnumerableHeaders(target, headers) {
|
|
2105
|
+
Object.defineProperty(target, "headers", {
|
|
2106
|
+
value: Object.freeze(headers),
|
|
2107
|
+
enumerable: false,
|
|
2108
|
+
configurable: false,
|
|
2109
|
+
writable: false
|
|
2110
|
+
});
|
|
2111
|
+
}
|
|
2112
|
+
function assertProviderMatches(configuredProviderId, manifestProviderId, capability, callId) {
|
|
2113
|
+
if (!configuredProviderId || configuredProviderId === manifestProviderId) {
|
|
2114
|
+
return;
|
|
2115
|
+
}
|
|
2116
|
+
throw new ProbeMeshError({
|
|
2117
|
+
code: "invalid_request",
|
|
2118
|
+
message: `x402 protocol is configured for provider "${configuredProviderId}", but manifest "${manifestProviderId}" was used.`,
|
|
2119
|
+
capability,
|
|
2120
|
+
provider: manifestProviderId,
|
|
2121
|
+
callId
|
|
2122
|
+
});
|
|
2123
|
+
}
|
|
2124
|
+
function paymentRequirementsMatch(left, right) {
|
|
2125
|
+
return left.scheme === right.scheme && left.network === right.network && left.asset === right.asset && left.amount === right.amount && left.payTo === right.payTo;
|
|
2126
|
+
}
|
|
2127
|
+
function getPayloadString(paymentPayload, field) {
|
|
2128
|
+
const value = paymentPayload.payload[field];
|
|
2129
|
+
return typeof value === "string" && value.length > 0 ? value : void 0;
|
|
2130
|
+
}
|
|
2131
|
+
function validateOptionalString(value, field) {
|
|
2132
|
+
if (value !== void 0 && (typeof value !== "string" || value.length === 0)) {
|
|
2133
|
+
throw new ProbeMeshError({
|
|
2134
|
+
code: "invalid_request",
|
|
2135
|
+
message: `x402 ${field} must be a non-empty string when provided.`
|
|
2136
|
+
});
|
|
2137
|
+
}
|
|
2138
|
+
}
|
|
2139
|
+
function noPaymentSafety2() {
|
|
2140
|
+
return failedPaymentSafety();
|
|
2141
|
+
}
|
|
2142
|
+
function failedPaymentSafety() {
|
|
2143
|
+
return {
|
|
2144
|
+
paymentStatus: "failed",
|
|
2145
|
+
settlementStatus: "not_attempted",
|
|
2146
|
+
deliveryStatus: "not_attempted",
|
|
2147
|
+
moneyMayHaveMoved: false
|
|
2148
|
+
};
|
|
2149
|
+
}
|
|
2150
|
+
var X402_PROTOCOL_DEFAULT_MODE = DEFAULT_MODE2;
|
|
2151
|
+
|
|
2152
|
+
// src/protocols/x402SandboxProtocol.ts
|
|
2153
|
+
var DEFAULT_MODE3 = "x402";
|
|
2154
|
+
var DEFAULT_PAYER2 = "sandbox-agent";
|
|
2155
|
+
var DEFAULT_NETWORK3 = "eip155:84532";
|
|
2156
|
+
var DEFAULT_ASSET2 = "USDC";
|
|
2157
|
+
var DEFAULT_AMOUNT3 = "10000";
|
|
2158
|
+
var DEFAULT_PAY_TO2 = "sandbox-provider-wallet";
|
|
2159
|
+
var PAYMENT_REQUIRED_HEADER2 = "PAYMENT-REQUIRED";
|
|
2160
|
+
var PAYMENT_SIGNATURE_HEADER2 = "PAYMENT-SIGNATURE";
|
|
2161
|
+
var PAYMENT_RESPONSE_HEADER2 = "PAYMENT-RESPONSE";
|
|
2162
|
+
function createX402SandboxProtocol(options = {}) {
|
|
2163
|
+
assertX402SandboxProtocolOptions(options);
|
|
2164
|
+
const mode = options.mode ?? DEFAULT_MODE3;
|
|
2165
|
+
return {
|
|
2166
|
+
mode,
|
|
2167
|
+
prepare({ manifest, request, context }) {
|
|
2168
|
+
if (options.failPrepare) {
|
|
2169
|
+
throw new ProbeMeshError({
|
|
2170
|
+
code: "payment_failed",
|
|
2171
|
+
message: `x402 sandbox payment authorization failed for provider "${manifest.id}".`,
|
|
2172
|
+
capability: request.capability,
|
|
2173
|
+
provider: manifest.id,
|
|
2174
|
+
callId: context.callId,
|
|
2175
|
+
safety: failedPaymentSafety2()
|
|
2176
|
+
});
|
|
2177
|
+
}
|
|
2178
|
+
assertProviderMatches2(options.providerId, manifest.id, request.capability, context.callId);
|
|
2179
|
+
const paymentRequired = createPaymentRequirement({
|
|
2180
|
+
providerId: manifest.id,
|
|
2181
|
+
capability: request.capability,
|
|
2182
|
+
options
|
|
2183
|
+
});
|
|
2184
|
+
const paymentId = options.paymentId ?? `${context.callId}:x402_payment`;
|
|
2185
|
+
const payer = options.payer ?? DEFAULT_PAYER2;
|
|
2186
|
+
const paymentAttemptId = `${paymentId}:attempt`;
|
|
2187
|
+
const paymentPayload = createPaymentPayload({
|
|
2188
|
+
paymentRequired,
|
|
2189
|
+
providerId: manifest.id,
|
|
2190
|
+
callId: context.callId,
|
|
2191
|
+
paymentId,
|
|
2192
|
+
payer,
|
|
2193
|
+
issuedAt: context.startedAt.toISOString()
|
|
2194
|
+
});
|
|
2195
|
+
const headers = {
|
|
2196
|
+
[PAYMENT_REQUIRED_HEADER2]: encodeBase64Json(paymentRequired),
|
|
2197
|
+
[PAYMENT_SIGNATURE_HEADER2]: encodeBase64Json(paymentPayload)
|
|
2198
|
+
};
|
|
2199
|
+
const preparation = {
|
|
2200
|
+
mode: manifest.protocolMode,
|
|
2201
|
+
metadata: {
|
|
2202
|
+
authorized: true,
|
|
2203
|
+
x402Version: 2,
|
|
2204
|
+
paymentId,
|
|
2205
|
+
paymentAttemptId,
|
|
2206
|
+
payer,
|
|
2207
|
+
network: paymentRequired.network,
|
|
2208
|
+
asset: paymentRequired.asset,
|
|
2209
|
+
amount: paymentRequired.amount,
|
|
2210
|
+
paymentRequired,
|
|
2211
|
+
paymentPayload,
|
|
2212
|
+
paymentRequiredHeader: PAYMENT_REQUIRED_HEADER2,
|
|
2213
|
+
paymentSignatureHeader: PAYMENT_SIGNATURE_HEADER2
|
|
2214
|
+
},
|
|
2215
|
+
receiptRefs: [
|
|
2216
|
+
{
|
|
2217
|
+
type: "payment_proof",
|
|
2218
|
+
provider: manifest.id,
|
|
2219
|
+
status: "recorded",
|
|
2220
|
+
ref: `${context.callId}:x402_payment_proof`,
|
|
2221
|
+
timestamp: context.startedAt.toISOString()
|
|
2222
|
+
}
|
|
2223
|
+
],
|
|
2224
|
+
safety: {
|
|
2225
|
+
paymentAttemptId,
|
|
2226
|
+
paymentStatus: "authorized",
|
|
2227
|
+
settlementStatus: "not_attempted",
|
|
2228
|
+
deliveryStatus: "not_attempted",
|
|
2229
|
+
moneyMayHaveMoved: true
|
|
2230
|
+
}
|
|
2231
|
+
};
|
|
2232
|
+
defineNonEnumerableHeaders2(preparation, headers);
|
|
2233
|
+
return preparation;
|
|
2234
|
+
},
|
|
2235
|
+
settle({ manifest, request, context, result, preparation }) {
|
|
2236
|
+
assertProviderMatches2(options.providerId, manifest.id, request.capability, context.callId);
|
|
2237
|
+
const paymentAttemptId = getMetadataString(
|
|
2238
|
+
preparation?.metadata?.paymentAttemptId,
|
|
2239
|
+
`${context.callId}:x402_payment:attempt`
|
|
2240
|
+
);
|
|
2241
|
+
const paymentId = getMetadataString(
|
|
2242
|
+
preparation?.metadata?.paymentId,
|
|
2243
|
+
`${context.callId}:x402_payment`
|
|
2244
|
+
);
|
|
2245
|
+
const payer = getMetadataString(preparation?.metadata?.payer, DEFAULT_PAYER2);
|
|
2246
|
+
const network = getMetadataString(
|
|
2247
|
+
preparation?.metadata?.network,
|
|
2248
|
+
DEFAULT_NETWORK3
|
|
2249
|
+
);
|
|
2250
|
+
const asset = getMetadataString(preparation?.metadata?.asset, DEFAULT_ASSET2);
|
|
2251
|
+
const amount = getMetadataString(
|
|
2252
|
+
preparation?.metadata?.amount,
|
|
2253
|
+
DEFAULT_AMOUNT3
|
|
2254
|
+
);
|
|
2255
|
+
const hasDeliveryReceipt = Array.isArray(result.receiptRefs) && result.receiptRefs.some(
|
|
2256
|
+
(receiptRef) => receiptRef.type === "provider_delivery"
|
|
2257
|
+
);
|
|
2258
|
+
if (options.failSettle) {
|
|
2259
|
+
throw new ProbeMeshError({
|
|
2260
|
+
code: "payment_failed",
|
|
2261
|
+
message: `x402 sandbox settlement failed for provider "${manifest.id}".`,
|
|
2262
|
+
capability: request.capability,
|
|
2263
|
+
provider: manifest.id,
|
|
2264
|
+
callId: context.callId,
|
|
2265
|
+
safety: {
|
|
2266
|
+
paymentAttemptId,
|
|
2267
|
+
paymentStatus: "authorized",
|
|
2268
|
+
settlementStatus: "failed",
|
|
2269
|
+
deliveryStatus: "missing",
|
|
2270
|
+
moneyMayHaveMoved: true
|
|
2271
|
+
}
|
|
2272
|
+
});
|
|
2273
|
+
}
|
|
2274
|
+
const settlementResponse = {
|
|
2275
|
+
x402Version: 2,
|
|
2276
|
+
success: true,
|
|
2277
|
+
provider: manifest.id,
|
|
2278
|
+
payer,
|
|
2279
|
+
paymentId,
|
|
2280
|
+
paymentAttemptId,
|
|
2281
|
+
network,
|
|
2282
|
+
asset,
|
|
2283
|
+
amount,
|
|
2284
|
+
settledAt: context.startedAt.toISOString(),
|
|
2285
|
+
sandboxSettlementId: `${context.callId}:x402_settlement`
|
|
2286
|
+
};
|
|
2287
|
+
const headers = {
|
|
2288
|
+
[PAYMENT_RESPONSE_HEADER2]: encodeBase64Json(settlementResponse)
|
|
2289
|
+
};
|
|
2290
|
+
const settlement = {
|
|
2291
|
+
mode: manifest.protocolMode,
|
|
2292
|
+
metadata: {
|
|
2293
|
+
settled: true,
|
|
2294
|
+
x402Version: 2,
|
|
2295
|
+
paymentId,
|
|
2296
|
+
paymentAttemptId,
|
|
2297
|
+
settlementResponse,
|
|
2298
|
+
paymentResponseHeader: PAYMENT_RESPONSE_HEADER2
|
|
2299
|
+
},
|
|
2300
|
+
receiptRefs: [
|
|
2301
|
+
{
|
|
2302
|
+
type: "settlement_confirmation",
|
|
2303
|
+
provider: manifest.id,
|
|
2304
|
+
status: "recorded",
|
|
2305
|
+
ref: `${context.callId}:x402_settlement_confirmed`,
|
|
2306
|
+
timestamp: context.startedAt.toISOString()
|
|
2307
|
+
}
|
|
2308
|
+
],
|
|
2309
|
+
safety: {
|
|
2310
|
+
paymentAttemptId,
|
|
2311
|
+
paymentStatus: "authorized",
|
|
2312
|
+
settlementStatus: "settled",
|
|
2313
|
+
deliveryStatus: hasDeliveryReceipt ? "delivered" : "missing",
|
|
2314
|
+
moneyMayHaveMoved: true
|
|
2315
|
+
}
|
|
2316
|
+
};
|
|
2317
|
+
defineNonEnumerableHeaders2(settlement, headers);
|
|
2318
|
+
return settlement;
|
|
2319
|
+
}
|
|
2320
|
+
};
|
|
2321
|
+
}
|
|
2322
|
+
function assertX402SandboxProtocolOptions(options) {
|
|
2323
|
+
validateOptionalString2(options.mode, "mode");
|
|
2324
|
+
validateOptionalString2(options.providerId, "providerId");
|
|
2325
|
+
validateOptionalString2(options.paymentId, "paymentId");
|
|
2326
|
+
validateOptionalString2(options.payer, "payer");
|
|
2327
|
+
if (options.paymentRequired !== void 0 && (!options.paymentRequired || typeof options.paymentRequired !== "object" || Array.isArray(options.paymentRequired))) {
|
|
2328
|
+
throw new ProbeMeshError({
|
|
2329
|
+
code: "invalid_request",
|
|
2330
|
+
message: "x402 sandbox paymentRequired must be an object when provided."
|
|
2331
|
+
});
|
|
2332
|
+
}
|
|
2333
|
+
if (options.failPrepare !== void 0 && typeof options.failPrepare !== "boolean") {
|
|
2334
|
+
throw new ProbeMeshError({
|
|
2335
|
+
code: "invalid_request",
|
|
2336
|
+
message: "x402 sandbox failPrepare must be a boolean when provided."
|
|
2337
|
+
});
|
|
2338
|
+
}
|
|
2339
|
+
if (options.failSettle !== void 0 && typeof options.failSettle !== "boolean") {
|
|
2340
|
+
throw new ProbeMeshError({
|
|
2341
|
+
code: "invalid_request",
|
|
2342
|
+
message: "x402 sandbox failSettle must be a boolean when provided."
|
|
2343
|
+
});
|
|
2344
|
+
}
|
|
2345
|
+
}
|
|
2346
|
+
function validateOptionalString2(value, field) {
|
|
2347
|
+
if (value !== void 0 && (typeof value !== "string" || value.length === 0)) {
|
|
2348
|
+
throw new ProbeMeshError({
|
|
2349
|
+
code: "invalid_request",
|
|
2350
|
+
message: `x402 sandbox ${field} must be a non-empty string when provided.`
|
|
2351
|
+
});
|
|
2352
|
+
}
|
|
2353
|
+
}
|
|
2354
|
+
function assertProviderMatches2(configuredProviderId, manifestProviderId, capability, callId) {
|
|
2355
|
+
if (!configuredProviderId || configuredProviderId === manifestProviderId) {
|
|
2356
|
+
return;
|
|
2357
|
+
}
|
|
2358
|
+
throw new ProbeMeshError({
|
|
2359
|
+
code: "invalid_request",
|
|
2360
|
+
message: `x402 sandbox protocol is configured for provider "${configuredProviderId}", but manifest "${manifestProviderId}" was used.`,
|
|
2361
|
+
capability,
|
|
2362
|
+
provider: manifestProviderId,
|
|
2363
|
+
callId
|
|
2364
|
+
});
|
|
2365
|
+
}
|
|
2366
|
+
function createPaymentRequirement(options) {
|
|
2367
|
+
const overrides = options.options.paymentRequired ?? {};
|
|
2368
|
+
return {
|
|
2369
|
+
x402Version: 2,
|
|
2370
|
+
scheme: overrides.scheme ?? "exact",
|
|
2371
|
+
network: overrides.network ?? DEFAULT_NETWORK3,
|
|
2372
|
+
asset: overrides.asset ?? DEFAULT_ASSET2,
|
|
2373
|
+
amount: overrides.amount ?? DEFAULT_AMOUNT3,
|
|
2374
|
+
payTo: overrides.payTo ?? DEFAULT_PAY_TO2,
|
|
2375
|
+
resource: overrides.resource ?? `probemesh://${options.providerId}/${options.capability}`,
|
|
2376
|
+
description: overrides.description ?? `ProbeMesh x402 sandbox payment for ${options.capability}.`,
|
|
2377
|
+
maxTimeoutSeconds: overrides.maxTimeoutSeconds ?? 60,
|
|
2378
|
+
extra: overrides.extra
|
|
2379
|
+
};
|
|
2380
|
+
}
|
|
2381
|
+
function createPaymentPayload(options) {
|
|
2382
|
+
return {
|
|
2383
|
+
x402Version: 2,
|
|
2384
|
+
scheme: options.paymentRequired.scheme,
|
|
2385
|
+
network: options.paymentRequired.network,
|
|
2386
|
+
asset: options.paymentRequired.asset,
|
|
2387
|
+
amount: options.paymentRequired.amount,
|
|
2388
|
+
payTo: options.paymentRequired.payTo,
|
|
2389
|
+
resource: options.paymentRequired.resource,
|
|
2390
|
+
payer: options.payer,
|
|
2391
|
+
provider: options.providerId,
|
|
2392
|
+
callId: options.callId,
|
|
2393
|
+
paymentId: options.paymentId,
|
|
2394
|
+
issuedAt: options.issuedAt,
|
|
2395
|
+
sandboxSignature: `sandbox:${options.providerId}:${options.paymentId}`
|
|
2396
|
+
};
|
|
2397
|
+
}
|
|
2398
|
+
function defineNonEnumerableHeaders2(target, headers) {
|
|
2399
|
+
Object.defineProperty(target, "headers", {
|
|
2400
|
+
value: Object.freeze(headers),
|
|
2401
|
+
enumerable: false,
|
|
2402
|
+
configurable: false,
|
|
2403
|
+
writable: false
|
|
2404
|
+
});
|
|
2405
|
+
}
|
|
2406
|
+
function encodeBase64Json(value) {
|
|
2407
|
+
return Buffer.from(JSON.stringify(value), "utf8").toString("base64");
|
|
2408
|
+
}
|
|
2409
|
+
function getMetadataString(value, fallback) {
|
|
2410
|
+
return typeof value === "string" && value.length > 0 ? value : fallback;
|
|
2411
|
+
}
|
|
2412
|
+
function failedPaymentSafety2() {
|
|
2413
|
+
return {
|
|
2414
|
+
paymentStatus: "failed",
|
|
2415
|
+
settlementStatus: "not_attempted",
|
|
2416
|
+
deliveryStatus: "not_attempted",
|
|
2417
|
+
moneyMayHaveMoved: false
|
|
2418
|
+
};
|
|
2419
|
+
}
|
|
2420
|
+
|
|
2421
|
+
// src/receipts.ts
|
|
2422
|
+
function getReceiptRefs(source, type) {
|
|
2423
|
+
const receiptRefs = readReceiptRefs(source);
|
|
2424
|
+
if (type === void 0) {
|
|
2425
|
+
return [...receiptRefs];
|
|
2426
|
+
}
|
|
2427
|
+
return receiptRefs.filter((receiptRef) => receiptRef.type === type);
|
|
2428
|
+
}
|
|
2429
|
+
function findReceiptRef(source, type) {
|
|
2430
|
+
return getReceiptRefs(source, type)[0];
|
|
2431
|
+
}
|
|
2432
|
+
function hasReceipt(source, type) {
|
|
2433
|
+
return findReceiptRef(source, type) !== void 0;
|
|
2434
|
+
}
|
|
2435
|
+
function summarizeReceipts(source) {
|
|
2436
|
+
const receiptRefs = readReceiptRefs(source);
|
|
2437
|
+
const types = [];
|
|
2438
|
+
const providers = [];
|
|
2439
|
+
const byType = {};
|
|
2440
|
+
for (const receiptRef of receiptRefs) {
|
|
2441
|
+
if (!types.includes(receiptRef.type)) {
|
|
2442
|
+
types.push(receiptRef.type);
|
|
2443
|
+
}
|
|
2444
|
+
if (!providers.includes(receiptRef.provider)) {
|
|
2445
|
+
providers.push(receiptRef.provider);
|
|
2446
|
+
}
|
|
2447
|
+
byType[receiptRef.type] = (byType[receiptRef.type] ?? 0) + 1;
|
|
2448
|
+
}
|
|
2449
|
+
return {
|
|
2450
|
+
total: receiptRefs.length,
|
|
2451
|
+
types,
|
|
2452
|
+
providers,
|
|
2453
|
+
byType,
|
|
2454
|
+
hasPaymentProof: hasReceipt(receiptRefs, "payment_proof"),
|
|
2455
|
+
hasProviderDelivery: hasReceipt(receiptRefs, "provider_delivery")
|
|
2456
|
+
};
|
|
2457
|
+
}
|
|
2458
|
+
function readReceiptRefs(source) {
|
|
2459
|
+
return Array.isArray(source) ? source : source.receiptRefs;
|
|
2460
|
+
}
|
|
2461
|
+
export {
|
|
2462
|
+
PROBEMESH_AUDIT_TRAIL_BUNDLE_SCHEMA_VERSION,
|
|
2463
|
+
PROBEMESH_CALL_AUDIT_ARTIFACT_SCHEMA_VERSION,
|
|
2464
|
+
PROVIDER_CATALOG_ARTIFACT_SCHEMA_VERSION,
|
|
2465
|
+
PROVIDER_CATALOG_POLICY_BUNDLE_SCHEMA_VERSION,
|
|
2466
|
+
PROVIDER_CATALOG_SCHEMA_VERSION,
|
|
2467
|
+
PROVIDER_CONFORMANCE_ARTIFACT_SCHEMA_VERSION,
|
|
2468
|
+
PROVIDER_ONBOARDING_DOSSIER_SCHEMA_VERSION,
|
|
2469
|
+
ProbeMeshError,
|
|
2470
|
+
assertJsonSchemaLikeValue,
|
|
2471
|
+
assertProbeMeshAuditTrailBundle,
|
|
2472
|
+
assertProbeMeshCallAuditArtifact,
|
|
2473
|
+
assertProviderCatalog,
|
|
2474
|
+
assertProviderCatalogArtifact,
|
|
2475
|
+
assertProviderCatalogPolicyBundle,
|
|
2476
|
+
assertProviderConformanceArtifact,
|
|
2477
|
+
assertProviderManifest,
|
|
2478
|
+
assertProviderOnboardingDossier,
|
|
2479
|
+
createAdapterFromManifest,
|
|
2480
|
+
createApiKeyProtocol,
|
|
2481
|
+
createHostedCatalogPolicyFromOnboardingDossiers,
|
|
2482
|
+
createHostedRouter,
|
|
2483
|
+
createMockPaymentProtocol,
|
|
2484
|
+
createPaidPriceLookupProvider,
|
|
2485
|
+
createPriceLookupAdapter,
|
|
2486
|
+
createProbeMesh,
|
|
2487
|
+
createProbeMeshAuditTrailBundle,
|
|
2488
|
+
createProbeMeshAuditTrailCollector,
|
|
2489
|
+
createProbeMeshCallAuditArtifact,
|
|
2490
|
+
createProviderCatalog,
|
|
2491
|
+
createProviderCatalogArtifact,
|
|
2492
|
+
createProviderCatalogFromOnboardingDossiers,
|
|
2493
|
+
createProviderCatalogPolicyBundle,
|
|
2494
|
+
createProviderCatalogPolicyReport,
|
|
2495
|
+
createProviderConformanceArtifact,
|
|
2496
|
+
createProviderConformanceReport,
|
|
2497
|
+
createProviderOnboardingDossier,
|
|
2498
|
+
createProviderOnboardingDossierImportReport,
|
|
2499
|
+
createX402EvmSigner,
|
|
2500
|
+
createX402HttpFacilitator,
|
|
2501
|
+
createX402LocalFacilitator,
|
|
2502
|
+
createX402LocalSigner,
|
|
2503
|
+
createX402Protocol,
|
|
2504
|
+
createX402ProviderAcceptanceReport,
|
|
2505
|
+
createX402SandboxProtocol,
|
|
2506
|
+
evaluateProviderCatalogPolicy,
|
|
2507
|
+
evaluateProviderOnboardingDossiers,
|
|
2508
|
+
evaluateX402ProviderAcceptanceGate,
|
|
2509
|
+
findProviderCatalogMatches,
|
|
2510
|
+
findReceiptRef,
|
|
2511
|
+
formatProbeMeshAuditTrailBundle,
|
|
2512
|
+
formatProbeMeshCallAuditArtifact,
|
|
2513
|
+
formatProviderCatalogArtifact,
|
|
2514
|
+
formatProviderCatalogPolicyBundle,
|
|
2515
|
+
formatProviderCatalogPolicyReport,
|
|
2516
|
+
formatProviderConformanceArtifact,
|
|
2517
|
+
formatProviderConformanceReport,
|
|
2518
|
+
formatProviderOnboardingDossier,
|
|
2519
|
+
formatProviderOnboardingDossierImportReport,
|
|
2520
|
+
formatX402ProviderAcceptanceReport,
|
|
2521
|
+
getProbeMeshIntegrationTemplate,
|
|
2522
|
+
getProviderPaymentOptions,
|
|
2523
|
+
getReceiptRefs,
|
|
2524
|
+
hasReceipt,
|
|
2525
|
+
isProbeMeshError,
|
|
2526
|
+
listProbeMeshIntegrationTemplates,
|
|
2527
|
+
mergePaymentPreferences,
|
|
2528
|
+
parseProviderCatalogArtifactJson,
|
|
2529
|
+
parseProviderOnboardingDossierJson,
|
|
2530
|
+
redactX402Secrets,
|
|
2531
|
+
renderProbeMeshIntegrationTemplate,
|
|
2532
|
+
resolveProviderPaymentOption,
|
|
2533
|
+
resolveX402EvmTestnetConfig,
|
|
2534
|
+
runProbeMeshAuditTrailExportCli,
|
|
2535
|
+
runProbeMeshInitCli,
|
|
2536
|
+
runProviderCatalogPolicyCli,
|
|
2537
|
+
runProviderConformance,
|
|
2538
|
+
runProviderConformanceCli,
|
|
2539
|
+
runProviderDossierCheckCli,
|
|
2540
|
+
runProviderOnboardingDossierCli,
|
|
2541
|
+
runX402ProviderAcceptance,
|
|
2542
|
+
runX402ProviderAcceptanceCli,
|
|
2543
|
+
startHostedRouter,
|
|
2544
|
+
summarizeProbeMeshAuditTrailBundle,
|
|
2545
|
+
summarizeProviderCatalog,
|
|
2546
|
+
summarizeReceipts,
|
|
2547
|
+
summarizeX402AcceptanceResult,
|
|
2548
|
+
validateJsonSchemaLikeValue,
|
|
2549
|
+
validatePaymentStrategy,
|
|
2550
|
+
validateProbeMeshAuditTrailBundle,
|
|
2551
|
+
validateProbeMeshCallAuditArtifact,
|
|
2552
|
+
validateProviderCatalog,
|
|
2553
|
+
validateProviderCatalogArtifact,
|
|
2554
|
+
validateProviderCatalogPolicyBundle,
|
|
2555
|
+
validateProviderConformanceArtifact,
|
|
2556
|
+
validateProviderManifest,
|
|
2557
|
+
validateProviderOnboardingDossier,
|
|
2558
|
+
verifyProviderCatalogPolicyBundleRuntime
|
|
2559
|
+
};
|
|
2560
|
+
//# sourceMappingURL=index.js.map
|