opentool 0.7.2 → 0.7.4
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/README.md +42 -15
- package/dist/cli/index.d.ts +4 -3
- package/dist/cli/index.js +263 -669
- package/dist/cli/index.js.map +1 -1
- package/dist/index.d.ts +3 -3
- package/dist/index.js +596 -867
- package/dist/index.js.map +1 -1
- package/dist/validate-BrOwtVYW.d.ts +382 -0
- package/dist/x402/index.d.ts +154 -0
- package/dist/x402/index.js +707 -0
- package/dist/x402/index.js.map +1 -0
- package/package.json +4 -4
- package/dist/index-D_bCF2Bf.d.ts +0 -487
- package/dist/payment/index.d.ts +0 -2
- package/dist/payment/index.js +0 -969
- package/dist/payment/index.js.map +0 -1
- package/dist/validate-CqB2Juma.d.ts +0 -216
package/dist/index.js
CHANGED
|
@@ -6,9 +6,9 @@ import * as path5 from 'path';
|
|
|
6
6
|
import { fileURLToPath, pathToFileURL } from 'url';
|
|
7
7
|
import { zodToJsonSchema } from '@alcyone-labs/zod-to-json-schema';
|
|
8
8
|
import { z } from 'zod';
|
|
9
|
-
import { zeroAddress,
|
|
10
|
-
import { baseSepolia, mainnet, base } from 'viem/chains';
|
|
9
|
+
import { zeroAddress, createWalletClient, http, createPublicClient } from 'viem';
|
|
11
10
|
import { privateKeyToAccount } from 'viem/accounts';
|
|
11
|
+
import { baseSepolia, mainnet, base } from 'viem/chains';
|
|
12
12
|
import { Turnkey } from '@turnkey/sdk-server';
|
|
13
13
|
import { createAccount } from '@turnkey/viem';
|
|
14
14
|
import { tmpdir } from 'os';
|
|
@@ -21,136 +21,8 @@ var __require = /* @__PURE__ */ ((x) => typeof require !== "undefined" ? require
|
|
|
21
21
|
if (typeof require !== "undefined") return require.apply(this, arguments);
|
|
22
22
|
throw Error('Dynamic require of "' + x + '" is not supported');
|
|
23
23
|
});
|
|
24
|
-
var
|
|
25
|
-
var paymentSchemaVersionSchema = z.literal(PAYMENT_SCHEMA_VERSION);
|
|
26
|
-
var decimalStringSchema = z.string().regex(/^(?:0|[1-9]\d*)(?:\.\d+)?$/, "Value must be a positive decimal string");
|
|
27
|
-
var currencySchema = z.object({
|
|
28
|
-
code: z.string().min(2).max(12).transform((value) => value.toUpperCase()),
|
|
29
|
-
symbol: z.string().min(1).max(6).optional(),
|
|
30
|
-
decimals: z.number().int().min(0).max(36).optional(),
|
|
31
|
-
kind: z.enum(["fiat", "crypto"]).default("crypto").optional(),
|
|
32
|
-
description: z.string().optional()
|
|
33
|
-
});
|
|
34
|
-
var paymentAmountSchema = z.object({
|
|
35
|
-
value: decimalStringSchema,
|
|
36
|
-
currency: currencySchema,
|
|
37
|
-
display: z.string().optional()
|
|
38
|
-
});
|
|
39
|
-
var cryptoAssetSchema = z.object({
|
|
40
|
-
symbol: z.string().min(2).max(12),
|
|
41
|
-
network: z.string().min(1).optional(),
|
|
42
|
-
chainId: z.number().int().min(0).optional(),
|
|
43
|
-
address: z.string().min(1).optional(),
|
|
44
|
-
decimals: z.number().int().min(0).max(36).optional(),
|
|
45
|
-
standard: z.enum(["erc20", "spl", "custom"]).default("erc20").optional(),
|
|
46
|
-
description: z.string().optional()
|
|
47
|
-
});
|
|
48
|
-
var facilitatorConfigSchema = z.object({
|
|
49
|
-
url: z.string().url(),
|
|
50
|
-
vendor: z.string().optional(),
|
|
51
|
-
verifyPath: z.string().default("/verify").optional(),
|
|
52
|
-
settlePath: z.string().default("/settle").optional(),
|
|
53
|
-
apiKey: z.string().optional(),
|
|
54
|
-
apiKeyEnv: z.string().optional(),
|
|
55
|
-
apiKeyHeader: z.string().default("Authorization").optional(),
|
|
56
|
-
headers: z.record(z.string(), z.string()).optional(),
|
|
57
|
-
timeoutMs: z.number().int().positive().optional()
|
|
58
|
-
});
|
|
59
|
-
var settlementTermsSchema = z.object({
|
|
60
|
-
windowSeconds: z.number().int().positive().optional(),
|
|
61
|
-
targetConfirmations: z.number().int().positive().optional(),
|
|
62
|
-
finalityDescription: z.string().optional(),
|
|
63
|
-
slaDescription: z.string().optional()
|
|
64
|
-
});
|
|
65
|
-
var paymentFieldSchema = z.object({
|
|
66
|
-
key: z.string().min(1),
|
|
67
|
-
label: z.string().min(1),
|
|
68
|
-
required: z.boolean().default(true).optional(),
|
|
69
|
-
description: z.string().optional(),
|
|
70
|
-
example: z.string().optional()
|
|
71
|
-
});
|
|
72
|
-
var x402ProofSchema = z.object({
|
|
73
|
-
mode: z.literal("x402"),
|
|
74
|
-
scheme: z.string().min(1),
|
|
75
|
-
network: z.string().min(1),
|
|
76
|
-
version: z.number().int().min(1).optional(),
|
|
77
|
-
facilitator: facilitatorConfigSchema.optional(),
|
|
78
|
-
verifier: z.string().optional()
|
|
79
|
-
});
|
|
80
|
-
var directProofSchema = z.object({
|
|
81
|
-
mode: z.literal("direct"),
|
|
82
|
-
proofTypes: z.array(z.string().min(1)).nonempty(),
|
|
83
|
-
verifier: z.string().optional(),
|
|
84
|
-
instructions: z.string().optional(),
|
|
85
|
-
fields: z.array(paymentFieldSchema).optional(),
|
|
86
|
-
allowsManualReview: z.boolean().optional()
|
|
87
|
-
});
|
|
88
|
-
var paymentProofSchema = z.discriminatedUnion("mode", [
|
|
89
|
-
x402ProofSchema,
|
|
90
|
-
directProofSchema
|
|
91
|
-
]);
|
|
92
|
-
var paymentOptionSchema = z.object({
|
|
93
|
-
id: z.string().min(1),
|
|
94
|
-
title: z.string().min(1),
|
|
95
|
-
description: z.string().optional(),
|
|
96
|
-
amount: paymentAmountSchema,
|
|
97
|
-
asset: cryptoAssetSchema,
|
|
98
|
-
payTo: z.string().min(1),
|
|
99
|
-
resource: z.string().url().optional(),
|
|
100
|
-
proof: paymentProofSchema,
|
|
101
|
-
settlement: settlementTermsSchema.optional(),
|
|
102
|
-
metadata: z.record(z.string(), z.unknown()).optional()
|
|
103
|
-
});
|
|
104
|
-
var paymentRequirementsSchema = z.object({
|
|
105
|
-
schemaVersion: paymentSchemaVersionSchema,
|
|
106
|
-
message: z.string().optional(),
|
|
107
|
-
title: z.string().optional(),
|
|
108
|
-
resource: z.string().url().optional(),
|
|
109
|
-
accepts: z.array(paymentOptionSchema).nonempty(),
|
|
110
|
-
metadata: z.record(z.string(), z.unknown()).optional(),
|
|
111
|
-
fallbackText: z.string().optional()
|
|
112
|
-
});
|
|
113
|
-
var x402PaymentHeaderSchema = z.object({
|
|
114
|
-
x402Version: z.number().int().min(1),
|
|
115
|
-
scheme: z.string().min(1),
|
|
116
|
-
network: z.string().min(1),
|
|
117
|
-
payload: z.unknown(),
|
|
118
|
-
correlationId: z.string().optional()
|
|
119
|
-
});
|
|
120
|
-
var directPaymentPayloadSchema = z.object({
|
|
121
|
-
schemaVersion: z.literal(1),
|
|
122
|
-
optionId: z.string().min(1),
|
|
123
|
-
proofType: z.string().min(1),
|
|
124
|
-
payload: z.unknown(),
|
|
125
|
-
metadata: z.record(z.string(), z.unknown()).optional()
|
|
126
|
-
});
|
|
127
|
-
var paymentSuccessMetadataSchema = z.object({
|
|
128
|
-
optionId: z.string().min(1),
|
|
129
|
-
verifier: z.string().optional(),
|
|
130
|
-
txHash: z.string().optional(),
|
|
131
|
-
networkId: z.string().optional(),
|
|
132
|
-
amount: paymentAmountSchema.optional(),
|
|
133
|
-
settledAt: z.string().datetime().optional(),
|
|
134
|
-
payload: z.unknown().optional()
|
|
135
|
-
});
|
|
136
|
-
var paymentFailureSchema = z.object({
|
|
137
|
-
reason: z.string().min(1),
|
|
138
|
-
code: z.enum([
|
|
139
|
-
"verifier_not_found",
|
|
140
|
-
"verification_failed",
|
|
141
|
-
"invalid_payload",
|
|
142
|
-
"unsupported_option",
|
|
143
|
-
"missing_header",
|
|
144
|
-
"unknown"
|
|
145
|
-
]).default("unknown").optional(),
|
|
146
|
-
retryable: z.boolean().optional(),
|
|
147
|
-
detail: z.unknown().optional()
|
|
148
|
-
});
|
|
149
|
-
|
|
150
|
-
// src/helpers/payment.ts
|
|
151
|
-
var X402_VERSION_DEFAULT = 1;
|
|
24
|
+
var X402_VERSION = 1;
|
|
152
25
|
var HEADER_X402 = "X-PAYMENT";
|
|
153
|
-
var HEADER_DIRECT = "X-PAYMENT-PROOF";
|
|
154
26
|
var HEADER_PAYMENT_RESPONSE = "X-PAYMENT-RESPONSE";
|
|
155
27
|
var x402RequirementSchema = z.object({
|
|
156
28
|
scheme: z.string().min(1),
|
|
@@ -165,272 +37,209 @@ var x402RequirementSchema = z.object({
|
|
|
165
37
|
maxTimeoutSeconds: z.number().int().positive().optional(),
|
|
166
38
|
extra: z.record(z.string(), z.unknown()).nullable().optional()
|
|
167
39
|
});
|
|
168
|
-
|
|
169
|
-
|
|
170
|
-
|
|
171
|
-
|
|
172
|
-
|
|
173
|
-
|
|
174
|
-
|
|
175
|
-
|
|
176
|
-
|
|
177
|
-
|
|
178
|
-
|
|
179
|
-
|
|
180
|
-
|
|
181
|
-
x402: x402Body
|
|
182
|
-
};
|
|
183
|
-
}
|
|
184
|
-
return parsed;
|
|
185
|
-
}
|
|
186
|
-
function paymentRequiredResponse(definition, init) {
|
|
187
|
-
const body = createPaymentRequiredBody(definition);
|
|
188
|
-
const headers = new Headers(init?.headers);
|
|
189
|
-
if (!headers.has("content-type")) {
|
|
190
|
-
headers.set("content-type", "application/json; charset=utf-8");
|
|
40
|
+
var x402PaymentHeaderSchema = z.object({
|
|
41
|
+
x402Version: z.number().int().positive(),
|
|
42
|
+
scheme: z.string().min(1),
|
|
43
|
+
network: z.string().min(1),
|
|
44
|
+
correlationId: z.string().optional(),
|
|
45
|
+
payload: z.unknown()
|
|
46
|
+
});
|
|
47
|
+
var SUPPORTED_CURRENCIES = {
|
|
48
|
+
USDC: {
|
|
49
|
+
decimals: 6,
|
|
50
|
+
symbol: "USDC",
|
|
51
|
+
network: "base",
|
|
52
|
+
assetAddress: "0x833589fCD6eDb6E08f4c7C37b7b4c6e997E08A43"
|
|
191
53
|
}
|
|
54
|
+
};
|
|
55
|
+
var DEFAULT_FACILITATOR = {
|
|
56
|
+
url: "https://facilitator.x402.rs",
|
|
57
|
+
verifyPath: "/verify",
|
|
58
|
+
settlePath: "/settle",
|
|
59
|
+
apiKeyHeader: "Authorization"
|
|
60
|
+
};
|
|
61
|
+
|
|
62
|
+
// src/x402/helpers.ts
|
|
63
|
+
function createX402PaymentRequired(definition) {
|
|
64
|
+
const requirement = toX402Requirement(definition);
|
|
65
|
+
const body = {
|
|
66
|
+
schemaVersion: 1,
|
|
67
|
+
message: definition.description ?? "Payment required",
|
|
68
|
+
resource: definition.resource,
|
|
69
|
+
accepts: [
|
|
70
|
+
{
|
|
71
|
+
id: "x402",
|
|
72
|
+
title: `Pay ${definition.amount} ${definition.currency.code}`,
|
|
73
|
+
description: definition.description,
|
|
74
|
+
amount: {
|
|
75
|
+
value: definition.amount,
|
|
76
|
+
currency: {
|
|
77
|
+
code: definition.currency.code,
|
|
78
|
+
symbol: definition.currency.symbol,
|
|
79
|
+
decimals: definition.currency.decimals,
|
|
80
|
+
kind: "crypto"
|
|
81
|
+
}
|
|
82
|
+
},
|
|
83
|
+
asset: {
|
|
84
|
+
symbol: definition.asset.symbol,
|
|
85
|
+
network: definition.asset.network,
|
|
86
|
+
address: definition.asset.address,
|
|
87
|
+
decimals: definition.asset.decimals,
|
|
88
|
+
standard: "erc20"
|
|
89
|
+
},
|
|
90
|
+
payTo: definition.payTo,
|
|
91
|
+
resource: definition.resource,
|
|
92
|
+
proof: {
|
|
93
|
+
mode: "x402",
|
|
94
|
+
scheme: definition.scheme,
|
|
95
|
+
network: definition.network,
|
|
96
|
+
version: X402_VERSION,
|
|
97
|
+
facilitator: definition.facilitator,
|
|
98
|
+
verifier: "x402:facilitator"
|
|
99
|
+
}
|
|
100
|
+
}
|
|
101
|
+
],
|
|
102
|
+
metadata: definition.metadata ?? {},
|
|
103
|
+
x402: {
|
|
104
|
+
x402Version: X402_VERSION,
|
|
105
|
+
error: definition.description ?? "Payment required",
|
|
106
|
+
accepts: [requirement]
|
|
107
|
+
}
|
|
108
|
+
};
|
|
192
109
|
return new Response(JSON.stringify(body), {
|
|
193
|
-
|
|
194
|
-
|
|
195
|
-
|
|
110
|
+
status: 402,
|
|
111
|
+
headers: {
|
|
112
|
+
"Content-Type": "application/json"
|
|
113
|
+
}
|
|
196
114
|
});
|
|
197
115
|
}
|
|
198
|
-
function
|
|
199
|
-
const
|
|
200
|
-
|
|
201
|
-
|
|
202
|
-
if (x402Header) {
|
|
203
|
-
const { attempt, failure } = parseX402Header(x402Header);
|
|
204
|
-
if (attempt) {
|
|
205
|
-
attempts.push(attempt);
|
|
206
|
-
} else if (failure) {
|
|
207
|
-
failures.push(failure);
|
|
208
|
-
}
|
|
209
|
-
}
|
|
210
|
-
const directHeader = source.headers.get(HEADER_DIRECT);
|
|
211
|
-
if (directHeader) {
|
|
212
|
-
const { attempt, failure } = parseDirectHeader(directHeader);
|
|
213
|
-
if (attempt) {
|
|
214
|
-
attempts.push(attempt);
|
|
215
|
-
} else if (failure) {
|
|
216
|
-
failures.push(failure);
|
|
217
|
-
}
|
|
218
|
-
}
|
|
219
|
-
if (attempts.length === 0 && failures.length === 0) {
|
|
220
|
-
failures.push(
|
|
221
|
-
paymentFailureSchema.parse({
|
|
222
|
-
reason: "No payment headers present",
|
|
223
|
-
code: "missing_header",
|
|
224
|
-
retryable: false
|
|
225
|
-
})
|
|
226
|
-
);
|
|
116
|
+
function extractX402Attempt(request) {
|
|
117
|
+
const raw = request.headers.get(HEADER_X402);
|
|
118
|
+
if (!raw) {
|
|
119
|
+
return null;
|
|
227
120
|
}
|
|
228
|
-
|
|
229
|
-
|
|
230
|
-
async function verifyPayment(options) {
|
|
231
|
-
const definition = paymentRequirementsSchema.parse(options.definition);
|
|
232
|
-
const attempts = options.attempts ? options.attempts : options.request ? extractPaymentAttempts(options.request).attempts : [];
|
|
233
|
-
if (attempts.length === 0) {
|
|
121
|
+
try {
|
|
122
|
+
const payload = decodeJson(raw, x402PaymentHeaderSchema);
|
|
234
123
|
return {
|
|
235
|
-
|
|
236
|
-
|
|
237
|
-
|
|
238
|
-
|
|
239
|
-
reason: "No payment attempt found",
|
|
240
|
-
code: "missing_header",
|
|
241
|
-
retryable: false
|
|
242
|
-
})
|
|
124
|
+
type: "x402",
|
|
125
|
+
headerName: HEADER_X402,
|
|
126
|
+
raw,
|
|
127
|
+
payload
|
|
243
128
|
};
|
|
129
|
+
} catch {
|
|
130
|
+
return null;
|
|
244
131
|
}
|
|
245
|
-
|
|
246
|
-
|
|
247
|
-
|
|
248
|
-
|
|
132
|
+
}
|
|
133
|
+
async function verifyX402Payment(attempt, definition, options = {}) {
|
|
134
|
+
const fetchImpl = options.fetchImpl ?? fetch;
|
|
135
|
+
const facilitator = definition.facilitator;
|
|
136
|
+
const verifierUrl = new URL(
|
|
137
|
+
facilitator.verifyPath ?? "/verify",
|
|
138
|
+
ensureTrailingSlash(facilitator.url)
|
|
139
|
+
).toString();
|
|
140
|
+
const requirement = toX402Requirement(definition);
|
|
141
|
+
const headers = buildFacilitatorHeaders(facilitator);
|
|
142
|
+
try {
|
|
143
|
+
const verifyResponse = await fetchImpl(verifierUrl, {
|
|
144
|
+
method: "POST",
|
|
145
|
+
headers,
|
|
146
|
+
body: JSON.stringify({
|
|
147
|
+
x402Version: attempt.payload.x402Version,
|
|
148
|
+
paymentPayload: attempt.payload,
|
|
149
|
+
paymentRequirements: requirement
|
|
150
|
+
})
|
|
151
|
+
});
|
|
152
|
+
if (!verifyResponse.ok) {
|
|
153
|
+
return {
|
|
154
|
+
success: false,
|
|
155
|
+
failure: {
|
|
156
|
+
reason: `Facilitator verify request failed: ${verifyResponse.status}`,
|
|
157
|
+
code: "verification_failed"
|
|
158
|
+
}
|
|
159
|
+
};
|
|
249
160
|
}
|
|
250
|
-
|
|
251
|
-
|
|
252
|
-
|
|
253
|
-
|
|
254
|
-
|
|
255
|
-
|
|
256
|
-
|
|
257
|
-
definition
|
|
258
|
-
};
|
|
259
|
-
if (options.settle !== void 0) {
|
|
260
|
-
context2.settle = options.settle;
|
|
161
|
+
const verifyPayload = await verifyResponse.json();
|
|
162
|
+
if (!verifyPayload.isValid) {
|
|
163
|
+
return {
|
|
164
|
+
success: false,
|
|
165
|
+
failure: {
|
|
166
|
+
reason: verifyPayload.invalidReason ?? "Facilitator verification failed",
|
|
167
|
+
code: "verification_failed"
|
|
261
168
|
}
|
|
262
|
-
return runFacilitatorVerifier({
|
|
263
|
-
...context2,
|
|
264
|
-
fetchImpl: options.fetchImpl ?? fetch
|
|
265
|
-
});
|
|
266
|
-
}
|
|
267
|
-
const verifier = verifierId ? options.verifiers?.[verifierId] : void 0;
|
|
268
|
-
if (!verifier) {
|
|
269
|
-
return {
|
|
270
|
-
success: false,
|
|
271
|
-
optionId: option.id,
|
|
272
|
-
attemptType: attempt.type,
|
|
273
|
-
failure: paymentFailureSchema.parse({
|
|
274
|
-
reason: `No verifier registered for id: ${verifierId ?? "(missing)"}`,
|
|
275
|
-
code: "verifier_not_found",
|
|
276
|
-
retryable: false
|
|
277
|
-
})
|
|
278
|
-
};
|
|
279
|
-
}
|
|
280
|
-
const context = {
|
|
281
|
-
attempt,
|
|
282
|
-
option,
|
|
283
|
-
definition
|
|
284
169
|
};
|
|
285
|
-
if (options.settle !== void 0) {
|
|
286
|
-
context.settle = options.settle;
|
|
287
|
-
}
|
|
288
|
-
return verifier(context);
|
|
289
170
|
}
|
|
290
|
-
|
|
291
|
-
|
|
292
|
-
const
|
|
293
|
-
|
|
294
|
-
|
|
295
|
-
|
|
296
|
-
|
|
297
|
-
|
|
298
|
-
|
|
299
|
-
|
|
300
|
-
|
|
301
|
-
|
|
302
|
-
|
|
171
|
+
const responseHeaders = {};
|
|
172
|
+
if (options.settle) {
|
|
173
|
+
const settleUrl = new URL(
|
|
174
|
+
facilitator.settlePath ?? "/settle",
|
|
175
|
+
ensureTrailingSlash(facilitator.url)
|
|
176
|
+
).toString();
|
|
177
|
+
try {
|
|
178
|
+
const settleResponse = await fetchImpl(settleUrl, {
|
|
179
|
+
method: "POST",
|
|
180
|
+
headers,
|
|
181
|
+
body: JSON.stringify({
|
|
182
|
+
x402Version: attempt.payload.x402Version,
|
|
183
|
+
paymentPayload: attempt.payload,
|
|
184
|
+
paymentRequirements: requirement
|
|
303
185
|
})
|
|
304
|
-
};
|
|
305
|
-
|
|
306
|
-
|
|
307
|
-
|
|
308
|
-
|
|
309
|
-
|
|
310
|
-
|
|
311
|
-
|
|
312
|
-
|
|
186
|
+
});
|
|
187
|
+
if (settleResponse.ok) {
|
|
188
|
+
const settlePayload = await settleResponse.json();
|
|
189
|
+
if (settlePayload.txHash) {
|
|
190
|
+
responseHeaders[HEADER_PAYMENT_RESPONSE] = JSON.stringify({
|
|
191
|
+
settled: true,
|
|
192
|
+
txHash: settlePayload.txHash
|
|
193
|
+
});
|
|
194
|
+
}
|
|
195
|
+
}
|
|
196
|
+
} catch {
|
|
313
197
|
}
|
|
314
|
-
return verifier(context);
|
|
315
198
|
}
|
|
316
|
-
|
|
317
|
-
|
|
318
|
-
|
|
319
|
-
|
|
320
|
-
|
|
321
|
-
|
|
322
|
-
|
|
323
|
-
|
|
324
|
-
retryable: false
|
|
325
|
-
})
|
|
326
|
-
};
|
|
327
|
-
}
|
|
328
|
-
function createPaymentResponseHeader(metadata) {
|
|
329
|
-
const parsed = paymentSuccessMetadataSchema.parse(metadata);
|
|
330
|
-
return encodeJson(parsed);
|
|
331
|
-
}
|
|
332
|
-
function parseX402Header(value) {
|
|
333
|
-
try {
|
|
334
|
-
const payload = decodeJson(value, x402PaymentHeaderSchema);
|
|
335
|
-
return {
|
|
336
|
-
attempt: {
|
|
337
|
-
type: "x402",
|
|
338
|
-
headerName: HEADER_X402,
|
|
339
|
-
raw: value,
|
|
340
|
-
payload
|
|
199
|
+
const result = {
|
|
200
|
+
success: true,
|
|
201
|
+
metadata: {
|
|
202
|
+
optionId: "x402",
|
|
203
|
+
verifier: "x402:facilitator",
|
|
204
|
+
amount: definition.amount,
|
|
205
|
+
currency: definition.currency.code,
|
|
206
|
+
network: definition.network
|
|
341
207
|
}
|
|
342
208
|
};
|
|
209
|
+
if (Object.keys(responseHeaders).length > 0) {
|
|
210
|
+
result.responseHeaders = responseHeaders;
|
|
211
|
+
}
|
|
212
|
+
return result;
|
|
343
213
|
} catch (error) {
|
|
344
214
|
return {
|
|
345
|
-
|
|
346
|
-
|
|
347
|
-
|
|
348
|
-
|
|
349
|
-
})
|
|
350
|
-
};
|
|
351
|
-
}
|
|
352
|
-
}
|
|
353
|
-
function parseDirectHeader(value) {
|
|
354
|
-
try {
|
|
355
|
-
const payload = decodeJson(value, directPaymentPayloadSchema);
|
|
356
|
-
return {
|
|
357
|
-
attempt: {
|
|
358
|
-
type: "direct",
|
|
359
|
-
headerName: HEADER_DIRECT,
|
|
360
|
-
raw: value,
|
|
361
|
-
payload
|
|
215
|
+
success: false,
|
|
216
|
+
failure: {
|
|
217
|
+
reason: error instanceof Error ? error.message : "Unknown error",
|
|
218
|
+
code: "verification_failed"
|
|
362
219
|
}
|
|
363
220
|
};
|
|
364
|
-
} catch (error) {
|
|
365
|
-
return {
|
|
366
|
-
failure: paymentFailureSchema.parse({
|
|
367
|
-
reason: `Invalid X-PAYMENT-PROOF header: ${error.message}`,
|
|
368
|
-
code: "invalid_payload",
|
|
369
|
-
retryable: false
|
|
370
|
-
})
|
|
371
|
-
};
|
|
372
221
|
}
|
|
373
222
|
}
|
|
374
|
-
function
|
|
375
|
-
|
|
376
|
-
|
|
377
|
-
if (attempt.type === "x402" && option.proof.mode === "x402") {
|
|
378
|
-
return option.proof.scheme === attempt.payload.scheme && option.proof.network === attempt.payload.network;
|
|
379
|
-
}
|
|
380
|
-
if (attempt.type === "direct" && option.proof.mode === "direct") {
|
|
381
|
-
return option.id === attempt.payload.optionId;
|
|
382
|
-
}
|
|
383
|
-
return false;
|
|
384
|
-
});
|
|
385
|
-
}
|
|
386
|
-
function resolveX402Version(options) {
|
|
387
|
-
const versions = [];
|
|
388
|
-
for (const option of options) {
|
|
389
|
-
if (option.proof.mode === "x402" && option.proof.version) {
|
|
390
|
-
versions.push(option.proof.version);
|
|
391
|
-
}
|
|
392
|
-
}
|
|
393
|
-
return versions.length > 0 ? Math.max(...versions) : X402_VERSION_DEFAULT;
|
|
394
|
-
}
|
|
395
|
-
function toX402Requirement(option, fallbackResource, settlement) {
|
|
396
|
-
if (option.proof.mode !== "x402") {
|
|
397
|
-
return void 0;
|
|
398
|
-
}
|
|
399
|
-
const decimals = resolveDecimals(option);
|
|
400
|
-
const assetAddress = option.asset.address;
|
|
401
|
-
if (!assetAddress) {
|
|
402
|
-
throw new Error(
|
|
403
|
-
`x402 payment option '${option.id}' is missing asset.address`
|
|
404
|
-
);
|
|
405
|
-
}
|
|
406
|
-
const units = decimalToBaseUnits(option.amount.value, decimals);
|
|
223
|
+
function toX402Requirement(definition) {
|
|
224
|
+
const decimals = definition.asset.decimals;
|
|
225
|
+
const units = decimalToBaseUnits(definition.amount, decimals);
|
|
407
226
|
return x402RequirementSchema.parse({
|
|
408
|
-
scheme:
|
|
409
|
-
network:
|
|
227
|
+
scheme: definition.scheme,
|
|
228
|
+
network: definition.network,
|
|
410
229
|
maxAmountRequired: units,
|
|
411
|
-
asset:
|
|
412
|
-
payTo:
|
|
413
|
-
resource:
|
|
414
|
-
description:
|
|
415
|
-
|
|
230
|
+
asset: definition.asset.address,
|
|
231
|
+
payTo: definition.payTo,
|
|
232
|
+
resource: definition.resource,
|
|
233
|
+
description: definition.description,
|
|
234
|
+
mimeType: "application/json",
|
|
235
|
+
maxTimeoutSeconds: 900,
|
|
416
236
|
extra: {
|
|
417
|
-
symbol:
|
|
418
|
-
currencyCode:
|
|
237
|
+
symbol: definition.asset.symbol,
|
|
238
|
+
currencyCode: definition.currency.code,
|
|
419
239
|
decimals
|
|
420
240
|
}
|
|
421
241
|
});
|
|
422
242
|
}
|
|
423
|
-
function resolveDecimals(option) {
|
|
424
|
-
if (typeof option.asset.decimals === "number") {
|
|
425
|
-
return option.asset.decimals;
|
|
426
|
-
}
|
|
427
|
-
if (typeof option.amount.currency.decimals === "number") {
|
|
428
|
-
return option.amount.currency.decimals;
|
|
429
|
-
}
|
|
430
|
-
throw new Error(
|
|
431
|
-
`Payment option '${option.id}' must specify asset.decimals or currency.decimals`
|
|
432
|
-
);
|
|
433
|
-
}
|
|
434
243
|
function decimalToBaseUnits(value, decimals) {
|
|
435
244
|
const [whole, fraction = ""] = value.split(".");
|
|
436
245
|
const sanitizedFraction = fraction.slice(0, decimals);
|
|
@@ -444,10 +253,6 @@ function decodeJson(value, schema) {
|
|
|
444
253
|
const parsed = JSON.parse(json);
|
|
445
254
|
return schema.parse(parsed);
|
|
446
255
|
}
|
|
447
|
-
function encodeJson(value) {
|
|
448
|
-
const json = JSON.stringify(value);
|
|
449
|
-
return Buffer.from(json, "utf-8").toString("base64");
|
|
450
|
-
}
|
|
451
256
|
function normalizeBase64(input) {
|
|
452
257
|
if (/^[A-Za-z0-9+/=]+$/.test(input)) {
|
|
453
258
|
return input;
|
|
@@ -456,221 +261,313 @@ function normalizeBase64(input) {
|
|
|
456
261
|
const paddingNeeded = (4 - restored.length % 4) % 4;
|
|
457
262
|
return restored + "=".repeat(paddingNeeded);
|
|
458
263
|
}
|
|
459
|
-
|
|
460
|
-
|
|
461
|
-
|
|
462
|
-
|
|
463
|
-
|
|
464
|
-
|
|
465
|
-
}) {
|
|
466
|
-
if (option.proof.mode !== "x402" || attempt.type !== "x402" || !option.proof.facilitator) {
|
|
467
|
-
return {
|
|
468
|
-
success: false,
|
|
469
|
-
optionId: option.id,
|
|
470
|
-
attemptType: attempt.type,
|
|
471
|
-
failure: paymentFailureSchema.parse({
|
|
472
|
-
reason: "Facilitator verifier invoked for non-x402 option",
|
|
473
|
-
code: "verification_failed",
|
|
474
|
-
retryable: false
|
|
475
|
-
})
|
|
476
|
-
};
|
|
477
|
-
}
|
|
478
|
-
const facilitator = option.proof.facilitator;
|
|
479
|
-
const verifierUrl = new URL(
|
|
480
|
-
facilitator.verifyPath ?? "/verify",
|
|
481
|
-
ensureTrailingSlash(facilitator.url)
|
|
482
|
-
).toString();
|
|
483
|
-
const requirement = toX402Requirement(option, definition.resource, option.settlement);
|
|
484
|
-
if (!requirement) {
|
|
485
|
-
return {
|
|
486
|
-
success: false,
|
|
487
|
-
optionId: option.id,
|
|
488
|
-
attemptType: attempt.type,
|
|
489
|
-
failure: paymentFailureSchema.parse({
|
|
490
|
-
reason: "Unable to derive x402 requirement for facilitator",
|
|
491
|
-
code: "verification_failed",
|
|
492
|
-
retryable: false
|
|
493
|
-
})
|
|
494
|
-
};
|
|
264
|
+
function buildFacilitatorHeaders(facilitator) {
|
|
265
|
+
const headers = {
|
|
266
|
+
"Content-Type": "application/json"
|
|
267
|
+
};
|
|
268
|
+
if (facilitator.apiKeyHeader && process.env.X402_FACILITATOR_API_KEY) {
|
|
269
|
+
headers[facilitator.apiKeyHeader] = process.env.X402_FACILITATOR_API_KEY;
|
|
495
270
|
}
|
|
496
|
-
|
|
497
|
-
|
|
498
|
-
|
|
499
|
-
|
|
500
|
-
|
|
501
|
-
|
|
502
|
-
|
|
503
|
-
|
|
504
|
-
|
|
505
|
-
|
|
506
|
-
|
|
507
|
-
|
|
508
|
-
|
|
271
|
+
return headers;
|
|
272
|
+
}
|
|
273
|
+
function ensureTrailingSlash(url) {
|
|
274
|
+
return url.endsWith("/") ? url : `${url}/`;
|
|
275
|
+
}
|
|
276
|
+
var PAYMENT_HEADERS = [HEADER_X402, HEADER_PAYMENT_RESPONSE];
|
|
277
|
+
var X402Client = class {
|
|
278
|
+
constructor(config) {
|
|
279
|
+
this.account = privateKeyToAccount(config.privateKey);
|
|
280
|
+
const chain = baseSepolia;
|
|
281
|
+
this.walletClient = createWalletClient({
|
|
282
|
+
account: this.account,
|
|
283
|
+
chain,
|
|
284
|
+
transport: http(config.rpcUrl)
|
|
509
285
|
});
|
|
510
|
-
|
|
511
|
-
|
|
512
|
-
|
|
513
|
-
|
|
514
|
-
|
|
515
|
-
|
|
516
|
-
|
|
517
|
-
|
|
518
|
-
|
|
519
|
-
}
|
|
520
|
-
};
|
|
521
|
-
|
|
522
|
-
|
|
523
|
-
|
|
524
|
-
|
|
525
|
-
|
|
526
|
-
|
|
527
|
-
|
|
528
|
-
|
|
529
|
-
|
|
530
|
-
|
|
531
|
-
|
|
532
|
-
|
|
286
|
+
}
|
|
287
|
+
async pay(request) {
|
|
288
|
+
try {
|
|
289
|
+
const initialResponse = await fetch(request.url, {
|
|
290
|
+
method: request.method ?? "POST",
|
|
291
|
+
headers: {
|
|
292
|
+
"Content-Type": "application/json",
|
|
293
|
+
...request.headers
|
|
294
|
+
},
|
|
295
|
+
...request.body ? { body: JSON.stringify(request.body) } : {}
|
|
296
|
+
});
|
|
297
|
+
if (initialResponse.status !== 402) {
|
|
298
|
+
return {
|
|
299
|
+
success: initialResponse.ok,
|
|
300
|
+
response: initialResponse
|
|
301
|
+
};
|
|
302
|
+
}
|
|
303
|
+
const paymentRequirements = await initialResponse.json();
|
|
304
|
+
const x402Requirements = paymentRequirements.x402?.accepts?.[0];
|
|
305
|
+
if (!x402Requirements) {
|
|
306
|
+
return {
|
|
307
|
+
success: false,
|
|
308
|
+
error: "No x402 payment requirements found in 402 response"
|
|
309
|
+
};
|
|
310
|
+
}
|
|
311
|
+
const authorization = await this.signTransferAuthorization({
|
|
312
|
+
from: this.account.address,
|
|
313
|
+
to: x402Requirements.payTo,
|
|
314
|
+
value: BigInt(x402Requirements.maxAmountRequired),
|
|
315
|
+
validAfter: BigInt(Math.floor(Date.now() / 1e3)),
|
|
316
|
+
validBefore: BigInt(Math.floor(Date.now() / 1e3) + 900),
|
|
317
|
+
// 15 min
|
|
318
|
+
nonce: `0x${Array.from(
|
|
319
|
+
{ length: 32 },
|
|
320
|
+
() => Math.floor(Math.random() * 256).toString(16).padStart(2, "0")
|
|
321
|
+
).join("")}`,
|
|
322
|
+
tokenAddress: x402Requirements.asset
|
|
323
|
+
});
|
|
324
|
+
const paymentProof = {
|
|
325
|
+
x402Version: 1,
|
|
326
|
+
scheme: x402Requirements.scheme,
|
|
327
|
+
network: x402Requirements.network,
|
|
328
|
+
correlationId: "",
|
|
329
|
+
payload: {
|
|
330
|
+
signature: authorization.signature,
|
|
331
|
+
authorization: {
|
|
332
|
+
from: authorization.from,
|
|
333
|
+
to: authorization.to,
|
|
334
|
+
value: authorization.value.toString(),
|
|
335
|
+
validAfter: authorization.validAfter.toString(),
|
|
336
|
+
validBefore: authorization.validBefore.toString(),
|
|
337
|
+
nonce: authorization.nonce
|
|
338
|
+
}
|
|
339
|
+
}
|
|
533
340
|
};
|
|
534
|
-
|
|
535
|
-
|
|
341
|
+
const paymentHeader = Buffer.from(JSON.stringify(paymentProof)).toString("base64");
|
|
342
|
+
const paidResponse = await fetch(request.url, {
|
|
343
|
+
method: request.method ?? "POST",
|
|
344
|
+
headers: {
|
|
345
|
+
"Content-Type": "application/json",
|
|
346
|
+
"X-PAYMENT": paymentHeader,
|
|
347
|
+
...request.headers
|
|
348
|
+
},
|
|
349
|
+
...request.body ? { body: JSON.stringify(request.body) } : {}
|
|
350
|
+
});
|
|
536
351
|
return {
|
|
537
|
-
success:
|
|
538
|
-
|
|
539
|
-
|
|
540
|
-
|
|
541
|
-
|
|
542
|
-
|
|
543
|
-
|
|
352
|
+
success: paidResponse.ok,
|
|
353
|
+
response: paidResponse,
|
|
354
|
+
paymentDetails: {
|
|
355
|
+
amount: x402Requirements.maxAmountRequired,
|
|
356
|
+
currency: x402Requirements.extra?.currencyCode ?? "USDC",
|
|
357
|
+
network: x402Requirements.network,
|
|
358
|
+
signature: authorization.signature
|
|
359
|
+
}
|
|
544
360
|
};
|
|
545
|
-
}
|
|
546
|
-
const settleUrl = new URL(
|
|
547
|
-
facilitator.settlePath ?? "/settle",
|
|
548
|
-
ensureTrailingSlash(facilitator.url)
|
|
549
|
-
).toString();
|
|
550
|
-
const settleResponse = await fetchImpl(settleUrl, {
|
|
551
|
-
method: "POST",
|
|
552
|
-
headers,
|
|
553
|
-
body: JSON.stringify({
|
|
554
|
-
x402Version: attempt.payload.x402Version,
|
|
555
|
-
paymentHeader: attempt.raw,
|
|
556
|
-
paymentRequirements: requirement
|
|
557
|
-
}),
|
|
558
|
-
signal: controller?.signal ?? null
|
|
559
|
-
});
|
|
560
|
-
if (!settleResponse.ok) {
|
|
361
|
+
} catch (error) {
|
|
561
362
|
return {
|
|
562
363
|
success: false,
|
|
563
|
-
|
|
564
|
-
attemptType: attempt.type,
|
|
565
|
-
failure: paymentFailureSchema.parse({
|
|
566
|
-
reason: `Facilitator settle request failed: ${settleResponse.status}`,
|
|
567
|
-
code: "verification_failed",
|
|
568
|
-
retryable: settleResponse.status >= 500
|
|
569
|
-
})
|
|
364
|
+
error: error instanceof Error ? error.message : String(error)
|
|
570
365
|
};
|
|
571
366
|
}
|
|
572
|
-
|
|
573
|
-
|
|
574
|
-
|
|
575
|
-
|
|
576
|
-
optionId: option.id,
|
|
577
|
-
attemptType: attempt.type,
|
|
578
|
-
failure: paymentFailureSchema.parse({
|
|
579
|
-
reason: settlePayload.error ?? "Facilitator settlement failed",
|
|
580
|
-
code: "verification_failed",
|
|
581
|
-
retryable: false
|
|
582
|
-
})
|
|
583
|
-
};
|
|
367
|
+
}
|
|
368
|
+
async signTransferAuthorization(params) {
|
|
369
|
+
if (!this.walletClient.chain) {
|
|
370
|
+
throw new Error("Wallet client chain not configured");
|
|
584
371
|
}
|
|
585
|
-
const
|
|
586
|
-
|
|
587
|
-
|
|
588
|
-
|
|
589
|
-
|
|
590
|
-
});
|
|
591
|
-
return {
|
|
592
|
-
success: true,
|
|
593
|
-
optionId: option.id,
|
|
594
|
-
attemptType: attempt.type,
|
|
595
|
-
metadata,
|
|
596
|
-
responseHeaders: {
|
|
597
|
-
[HEADER_PAYMENT_RESPONSE]: createPaymentResponseHeader(metadata)
|
|
598
|
-
}
|
|
372
|
+
const domain = {
|
|
373
|
+
name: "USD Coin",
|
|
374
|
+
version: "2",
|
|
375
|
+
chainId: this.walletClient.chain.id,
|
|
376
|
+
verifyingContract: params.tokenAddress
|
|
599
377
|
};
|
|
600
|
-
|
|
378
|
+
const types = {
|
|
379
|
+
TransferWithAuthorization: [
|
|
380
|
+
{ name: "from", type: "address" },
|
|
381
|
+
{ name: "to", type: "address" },
|
|
382
|
+
{ name: "value", type: "uint256" },
|
|
383
|
+
{ name: "validAfter", type: "uint256" },
|
|
384
|
+
{ name: "validBefore", type: "uint256" },
|
|
385
|
+
{ name: "nonce", type: "bytes32" }
|
|
386
|
+
]
|
|
387
|
+
};
|
|
388
|
+
const message = {
|
|
389
|
+
from: params.from,
|
|
390
|
+
to: params.to,
|
|
391
|
+
value: params.value,
|
|
392
|
+
validAfter: params.validAfter,
|
|
393
|
+
validBefore: params.validBefore,
|
|
394
|
+
nonce: params.nonce
|
|
395
|
+
};
|
|
396
|
+
const signature = await this.walletClient.signTypedData({
|
|
397
|
+
account: this.account,
|
|
398
|
+
domain,
|
|
399
|
+
types,
|
|
400
|
+
primaryType: "TransferWithAuthorization",
|
|
401
|
+
message
|
|
402
|
+
});
|
|
601
403
|
return {
|
|
602
|
-
|
|
603
|
-
|
|
604
|
-
|
|
605
|
-
|
|
606
|
-
|
|
607
|
-
|
|
608
|
-
|
|
609
|
-
})
|
|
404
|
+
signature,
|
|
405
|
+
from: params.from,
|
|
406
|
+
to: params.to,
|
|
407
|
+
value: params.value,
|
|
408
|
+
validAfter: params.validAfter,
|
|
409
|
+
validBefore: params.validBefore,
|
|
410
|
+
nonce: params.nonce
|
|
610
411
|
};
|
|
611
|
-
} finally {
|
|
612
|
-
if (timeout) {
|
|
613
|
-
clearTimeout(timeout);
|
|
614
|
-
}
|
|
615
412
|
}
|
|
616
|
-
|
|
617
|
-
|
|
618
|
-
const headers = {
|
|
619
|
-
"content-type": "application/json"
|
|
620
|
-
};
|
|
621
|
-
if (config?.headers) {
|
|
622
|
-
Object.assign(headers, config.headers);
|
|
623
|
-
}
|
|
624
|
-
const apiKey = resolveFacilitatorApiKey(config);
|
|
625
|
-
if (apiKey) {
|
|
626
|
-
const headerName = config?.apiKeyHeader ?? "Authorization";
|
|
627
|
-
headers[headerName] = apiKey;
|
|
413
|
+
getAddress() {
|
|
414
|
+
return this.account.address;
|
|
628
415
|
}
|
|
629
|
-
|
|
416
|
+
};
|
|
417
|
+
async function payX402(config) {
|
|
418
|
+
const client = new X402Client({
|
|
419
|
+
privateKey: config.privateKey,
|
|
420
|
+
...config.rpcUrl ? { rpcUrl: config.rpcUrl } : {}
|
|
421
|
+
});
|
|
422
|
+
return client.pay({
|
|
423
|
+
url: config.url,
|
|
424
|
+
body: config.body
|
|
425
|
+
});
|
|
630
426
|
}
|
|
631
|
-
|
|
632
|
-
|
|
633
|
-
|
|
427
|
+
var X402BrowserClient = class {
|
|
428
|
+
constructor(config) {
|
|
429
|
+
this.walletClient = config.walletClient;
|
|
430
|
+
this.chainId = config.chainId;
|
|
634
431
|
}
|
|
635
|
-
|
|
636
|
-
|
|
637
|
-
|
|
638
|
-
|
|
639
|
-
|
|
432
|
+
async pay(request) {
|
|
433
|
+
try {
|
|
434
|
+
const initialResponse = await fetch(request.url, {
|
|
435
|
+
method: request.method ?? "POST",
|
|
436
|
+
headers: {
|
|
437
|
+
"Content-Type": "application/json",
|
|
438
|
+
...request.headers
|
|
439
|
+
},
|
|
440
|
+
...request.body ? { body: JSON.stringify(request.body) } : {}
|
|
441
|
+
});
|
|
442
|
+
if (initialResponse.status !== 402) {
|
|
443
|
+
return {
|
|
444
|
+
success: initialResponse.ok,
|
|
445
|
+
response: initialResponse
|
|
446
|
+
};
|
|
447
|
+
}
|
|
448
|
+
const paymentRequirements = await initialResponse.json();
|
|
449
|
+
const x402Requirements = paymentRequirements.x402?.accepts?.[0];
|
|
450
|
+
if (!x402Requirements) {
|
|
451
|
+
return {
|
|
452
|
+
success: false,
|
|
453
|
+
error: "No x402 payment requirements found in 402 response"
|
|
454
|
+
};
|
|
455
|
+
}
|
|
456
|
+
const account = this.walletClient.account;
|
|
457
|
+
if (!account) {
|
|
458
|
+
return {
|
|
459
|
+
success: false,
|
|
460
|
+
error: "No account connected to wallet"
|
|
461
|
+
};
|
|
462
|
+
}
|
|
463
|
+
const authorization = {
|
|
464
|
+
from: account.address,
|
|
465
|
+
to: x402Requirements.payTo,
|
|
466
|
+
value: BigInt(x402Requirements.maxAmountRequired),
|
|
467
|
+
validAfter: BigInt(Math.floor(Date.now() / 1e3)),
|
|
468
|
+
validBefore: BigInt(Math.floor(Date.now() / 1e3) + 900),
|
|
469
|
+
nonce: `0x${Array.from(
|
|
470
|
+
{ length: 32 },
|
|
471
|
+
() => Math.floor(Math.random() * 256).toString(16).padStart(2, "0")
|
|
472
|
+
).join("")}`
|
|
473
|
+
};
|
|
474
|
+
const signature = await this.signTransferAuthorization(
|
|
475
|
+
authorization,
|
|
476
|
+
x402Requirements.asset
|
|
477
|
+
);
|
|
478
|
+
const paymentProof = {
|
|
479
|
+
x402Version: 1,
|
|
480
|
+
scheme: x402Requirements.scheme,
|
|
481
|
+
network: x402Requirements.network,
|
|
482
|
+
correlationId: "",
|
|
483
|
+
payload: {
|
|
484
|
+
signature,
|
|
485
|
+
authorization: {
|
|
486
|
+
from: authorization.from,
|
|
487
|
+
to: authorization.to,
|
|
488
|
+
value: authorization.value.toString(),
|
|
489
|
+
validAfter: authorization.validAfter.toString(),
|
|
490
|
+
validBefore: authorization.validBefore.toString(),
|
|
491
|
+
nonce: authorization.nonce
|
|
492
|
+
}
|
|
493
|
+
}
|
|
494
|
+
};
|
|
495
|
+
const paymentHeader = btoa(JSON.stringify(paymentProof));
|
|
496
|
+
const paidResponse = await fetch(request.url, {
|
|
497
|
+
method: request.method ?? "POST",
|
|
498
|
+
headers: {
|
|
499
|
+
"Content-Type": "application/json",
|
|
500
|
+
"X-PAYMENT": paymentHeader,
|
|
501
|
+
...request.headers
|
|
502
|
+
},
|
|
503
|
+
...request.body ? { body: JSON.stringify(request.body) } : {}
|
|
504
|
+
});
|
|
505
|
+
return {
|
|
506
|
+
success: paidResponse.ok,
|
|
507
|
+
response: paidResponse,
|
|
508
|
+
paymentDetails: {
|
|
509
|
+
amount: x402Requirements.maxAmountRequired,
|
|
510
|
+
currency: x402Requirements.extra?.currencyCode ?? "USDC",
|
|
511
|
+
network: x402Requirements.network,
|
|
512
|
+
signature
|
|
513
|
+
}
|
|
514
|
+
};
|
|
515
|
+
} catch (error) {
|
|
516
|
+
return {
|
|
517
|
+
success: false,
|
|
518
|
+
error: error instanceof Error ? error.message : String(error)
|
|
519
|
+
};
|
|
520
|
+
}
|
|
640
521
|
}
|
|
641
|
-
|
|
642
|
-
|
|
643
|
-
|
|
644
|
-
|
|
645
|
-
}
|
|
646
|
-
var PAYMENT_HEADERS = {
|
|
647
|
-
x402: HEADER_X402,
|
|
648
|
-
direct: HEADER_DIRECT,
|
|
649
|
-
response: HEADER_PAYMENT_RESPONSE
|
|
650
|
-
};
|
|
651
|
-
|
|
652
|
-
// src/payment/index.ts
|
|
653
|
-
var DEFAULT_ID_X402 = "x402";
|
|
654
|
-
var DEFAULT_ID_402 = "402";
|
|
655
|
-
var SUPPORTED_CURRENCIES = {
|
|
656
|
-
USDC: {
|
|
657
|
-
decimals: 6,
|
|
658
|
-
symbol: "USDC",
|
|
659
|
-
x402: {
|
|
660
|
-
network: "base",
|
|
661
|
-
assetAddress: "0x833589fCD6eDb6E08f4c7C37b7b4c6e997E08A43"
|
|
522
|
+
async signTransferAuthorization(authorization, tokenAddress) {
|
|
523
|
+
const account = this.walletClient.account;
|
|
524
|
+
if (!account) {
|
|
525
|
+
throw new Error("No account connected to wallet");
|
|
662
526
|
}
|
|
527
|
+
const domain = {
|
|
528
|
+
name: "USD Coin",
|
|
529
|
+
version: "2",
|
|
530
|
+
chainId: this.chainId,
|
|
531
|
+
verifyingContract: tokenAddress
|
|
532
|
+
};
|
|
533
|
+
const types = {
|
|
534
|
+
TransferWithAuthorization: [
|
|
535
|
+
{ name: "from", type: "address" },
|
|
536
|
+
{ name: "to", type: "address" },
|
|
537
|
+
{ name: "value", type: "uint256" },
|
|
538
|
+
{ name: "validAfter", type: "uint256" },
|
|
539
|
+
{ name: "validBefore", type: "uint256" },
|
|
540
|
+
{ name: "nonce", type: "bytes32" }
|
|
541
|
+
]
|
|
542
|
+
};
|
|
543
|
+
const message = {
|
|
544
|
+
from: authorization.from,
|
|
545
|
+
to: authorization.to,
|
|
546
|
+
value: authorization.value,
|
|
547
|
+
validAfter: authorization.validAfter,
|
|
548
|
+
validBefore: authorization.validBefore,
|
|
549
|
+
nonce: authorization.nonce
|
|
550
|
+
};
|
|
551
|
+
return await this.walletClient.signTypedData({
|
|
552
|
+
account,
|
|
553
|
+
domain,
|
|
554
|
+
types,
|
|
555
|
+
primaryType: "TransferWithAuthorization",
|
|
556
|
+
message
|
|
557
|
+
});
|
|
663
558
|
}
|
|
664
559
|
};
|
|
665
|
-
|
|
666
|
-
|
|
667
|
-
|
|
668
|
-
}
|
|
669
|
-
|
|
670
|
-
|
|
560
|
+
async function payX402WithWallet(walletClient, chainId, request) {
|
|
561
|
+
const client = new X402BrowserClient({ walletClient, chainId });
|
|
562
|
+
return client.pay(request);
|
|
563
|
+
}
|
|
564
|
+
|
|
565
|
+
// src/x402/index.ts
|
|
566
|
+
var PAYMENT_CONTEXT_SYMBOL = Symbol.for("opentool.x402.context");
|
|
567
|
+
var X402PaymentRequiredError = class extends Error {
|
|
671
568
|
constructor(response, verification) {
|
|
672
|
-
super("Payment required");
|
|
673
|
-
this.name = "
|
|
569
|
+
super("X402 Payment required");
|
|
570
|
+
this.name = "X402PaymentRequiredError";
|
|
674
571
|
this.response = response;
|
|
675
572
|
this.verification = verification;
|
|
676
573
|
}
|
|
@@ -687,246 +584,133 @@ function setPaymentContext(request, context) {
|
|
|
687
584
|
request[PAYMENT_CONTEXT_SYMBOL] = context;
|
|
688
585
|
}
|
|
689
586
|
}
|
|
690
|
-
function
|
|
587
|
+
function getX402PaymentContext(request) {
|
|
691
588
|
return request[PAYMENT_CONTEXT_SYMBOL];
|
|
692
589
|
}
|
|
693
|
-
function
|
|
694
|
-
const entries = Object.entries(headers ?? {});
|
|
695
|
-
if (entries.length === 0) {
|
|
696
|
-
return response;
|
|
697
|
-
}
|
|
698
|
-
let mutated = false;
|
|
699
|
-
const merged = new Headers(response.headers);
|
|
700
|
-
for (const [key, value] of entries) {
|
|
701
|
-
if (!merged.has(key)) {
|
|
702
|
-
merged.set(key, value);
|
|
703
|
-
mutated = true;
|
|
704
|
-
}
|
|
705
|
-
}
|
|
706
|
-
if (!mutated) {
|
|
707
|
-
return response;
|
|
708
|
-
}
|
|
709
|
-
return new Response(response.body, {
|
|
710
|
-
status: response.status,
|
|
711
|
-
statusText: response.statusText,
|
|
712
|
-
headers: merged
|
|
713
|
-
});
|
|
714
|
-
}
|
|
715
|
-
function withPaymentRequirement(handler, payment, options = {}) {
|
|
716
|
-
return async (request) => {
|
|
717
|
-
const verification = await requirePayment(request, payment, options);
|
|
718
|
-
if (verification instanceof Response) {
|
|
719
|
-
return verification;
|
|
720
|
-
}
|
|
721
|
-
setPaymentContext(request, verification);
|
|
722
|
-
const response = await Promise.resolve(handler(request));
|
|
723
|
-
return applyPaymentHeaders(response, verification.headers);
|
|
724
|
-
};
|
|
725
|
-
}
|
|
726
|
-
function definePayment(config) {
|
|
727
|
-
const verifiers = {
|
|
728
|
-
...config.verifiers ?? {}
|
|
729
|
-
};
|
|
730
|
-
const methods = config.acceptedMethods ?? ["402"];
|
|
731
|
-
const includeX402 = methods.includes("x402");
|
|
732
|
-
const includePlain402 = methods.includes("402");
|
|
733
|
-
if (!includeX402 && !includePlain402) {
|
|
734
|
-
throw new Error(
|
|
735
|
-
"definePayment requires at least one payment transport (x402 or 402)"
|
|
736
|
-
);
|
|
737
|
-
}
|
|
590
|
+
function defineX402Payment(config) {
|
|
738
591
|
const currencyCode = normalizeCurrency(config.currency);
|
|
739
592
|
const currencySpec = SUPPORTED_CURRENCIES[currencyCode];
|
|
740
593
|
if (!currencySpec) {
|
|
741
|
-
throw new Error(`Unsupported currency for payments: ${currencyCode}`);
|
|
594
|
+
throw new Error(`Unsupported currency for x402 payments: ${currencyCode}`);
|
|
742
595
|
}
|
|
743
|
-
const
|
|
744
|
-
const
|
|
745
|
-
|
|
746
|
-
|
|
747
|
-
|
|
748
|
-
const overrides = config.x402 ?? {};
|
|
749
|
-
const defaults = currencySpec.x402;
|
|
750
|
-
if (!defaults && (!overrides.network || !overrides.assetAddress)) {
|
|
751
|
-
throw new Error(
|
|
752
|
-
"x402 payments require a network and assetAddress; supply them or choose a supported currency."
|
|
753
|
-
);
|
|
754
|
-
}
|
|
755
|
-
const facilitator = resolveFacilitator(
|
|
756
|
-
config.facilitator ?? overrides.facilitator ?? "opentool"
|
|
757
|
-
);
|
|
758
|
-
accepts.push(
|
|
759
|
-
paymentOptionSchema.parse({
|
|
760
|
-
id: overrides.id ?? DEFAULT_ID_X402,
|
|
761
|
-
title: `Pay ${value} ${currencyCode}`,
|
|
762
|
-
amount: {
|
|
763
|
-
value,
|
|
764
|
-
currency: { code: currencyCode, symbol, decimals }
|
|
765
|
-
},
|
|
766
|
-
asset: {
|
|
767
|
-
symbol,
|
|
768
|
-
network: overrides.network ?? defaults?.network ?? "",
|
|
769
|
-
address: overrides.assetAddress ?? defaults?.assetAddress ?? "",
|
|
770
|
-
decimals,
|
|
771
|
-
standard: "erc20"
|
|
772
|
-
},
|
|
773
|
-
payTo: config.payTo,
|
|
774
|
-
proof: {
|
|
775
|
-
mode: "x402",
|
|
776
|
-
network: overrides.network ?? defaults?.network ?? "",
|
|
777
|
-
scheme: overrides.scheme ?? "exact",
|
|
778
|
-
version: overrides.version ?? 1,
|
|
779
|
-
facilitator,
|
|
780
|
-
verifier: facilitator ? "x402:facilitator" : void 0
|
|
781
|
-
},
|
|
782
|
-
settlement: overrides.settlement
|
|
783
|
-
})
|
|
784
|
-
);
|
|
785
|
-
}
|
|
786
|
-
if (includePlain402) {
|
|
787
|
-
const overrides = config.direct ?? {};
|
|
788
|
-
const id = overrides.id ?? DEFAULT_ID_402;
|
|
789
|
-
const verifierId = overrides.verifierId ?? `direct:${id}`;
|
|
790
|
-
const proofType = overrides.proofType ?? id;
|
|
791
|
-
const verifier = overrides.verify ?? buildDefaultDirectVerifier(overrides.token, verifierId, id);
|
|
792
|
-
verifiers[verifierId] = verifier;
|
|
793
|
-
accepts.push(
|
|
794
|
-
paymentOptionSchema.parse({
|
|
795
|
-
id,
|
|
796
|
-
title: `Pay ${value} ${currencyCode}`,
|
|
797
|
-
amount: {
|
|
798
|
-
value,
|
|
799
|
-
currency: { code: currencyCode, symbol, decimals }
|
|
800
|
-
},
|
|
801
|
-
asset: {
|
|
802
|
-
symbol,
|
|
803
|
-
decimals,
|
|
804
|
-
standard: "erc20"
|
|
805
|
-
},
|
|
806
|
-
payTo: config.payTo,
|
|
807
|
-
proof: {
|
|
808
|
-
mode: "direct",
|
|
809
|
-
proofTypes: [proofType],
|
|
810
|
-
verifier: verifierId,
|
|
811
|
-
instructions: overrides.instructions,
|
|
812
|
-
fields: overrides.fields,
|
|
813
|
-
allowsManualReview: overrides.allowsManualReview
|
|
814
|
-
},
|
|
815
|
-
settlement: overrides.settlement
|
|
816
|
-
})
|
|
596
|
+
const network = config.network ?? currencySpec.network;
|
|
597
|
+
const assetAddress = config.assetAddress ?? currencySpec.assetAddress;
|
|
598
|
+
if (!network || !assetAddress) {
|
|
599
|
+
throw new Error(
|
|
600
|
+
"x402 payments require a network and assetAddress; supply them or choose a supported currency."
|
|
817
601
|
);
|
|
818
602
|
}
|
|
819
|
-
const
|
|
820
|
-
const
|
|
821
|
-
if (currencyCode === "USDC") {
|
|
822
|
-
baseMetadata.amountUSDC = Number(value);
|
|
823
|
-
}
|
|
824
|
-
baseMetadata.x402 = includeX402;
|
|
825
|
-
baseMetadata.plain402 = includePlain402;
|
|
826
|
-
baseMetadata.acceptedMethods = methods;
|
|
827
|
-
baseMetadata.acceptedCurrencies = config.acceptedCurrencies ?? [currencyCode];
|
|
828
|
-
if (config.chains) {
|
|
829
|
-
baseMetadata.chains = config.chains;
|
|
830
|
-
}
|
|
831
|
-
if (facilitatorLabel) {
|
|
832
|
-
baseMetadata.facilitator = facilitatorLabel;
|
|
833
|
-
}
|
|
834
|
-
const metadata = config.metadata ? { ...baseMetadata, ...config.metadata } : baseMetadata;
|
|
603
|
+
const facilitator = resolveFacilitator(config.facilitator);
|
|
604
|
+
const value = toDecimalString(config.amount);
|
|
835
605
|
const definition = {
|
|
836
|
-
|
|
837
|
-
|
|
838
|
-
|
|
606
|
+
amount: value,
|
|
607
|
+
currency: {
|
|
608
|
+
code: currencyCode,
|
|
609
|
+
symbol: currencySpec.symbol,
|
|
610
|
+
decimals: currencySpec.decimals
|
|
611
|
+
},
|
|
612
|
+
asset: {
|
|
613
|
+
symbol: currencySpec.symbol,
|
|
614
|
+
network,
|
|
615
|
+
address: assetAddress,
|
|
616
|
+
decimals: currencySpec.decimals
|
|
617
|
+
},
|
|
618
|
+
payTo: config.payTo,
|
|
619
|
+
scheme: config.scheme ?? "exact",
|
|
620
|
+
network,
|
|
621
|
+
facilitator
|
|
839
622
|
};
|
|
840
|
-
if (config.
|
|
841
|
-
definition.message = config.message;
|
|
842
|
-
}
|
|
843
|
-
if (config.resource !== void 0) {
|
|
623
|
+
if (config.resource) {
|
|
844
624
|
definition.resource = config.resource;
|
|
845
625
|
}
|
|
846
|
-
|
|
626
|
+
if (config.message) {
|
|
627
|
+
definition.description = config.message;
|
|
628
|
+
}
|
|
629
|
+
if (config.metadata) {
|
|
630
|
+
definition.metadata = config.metadata;
|
|
631
|
+
}
|
|
632
|
+
const baseMetadata = {
|
|
633
|
+
amountUSDC: currencyCode === "USDC" ? Number(value) : void 0,
|
|
634
|
+
facilitator: "x402rs",
|
|
635
|
+
network
|
|
636
|
+
};
|
|
637
|
+
const metadata = config.metadata ? { ...baseMetadata, ...config.metadata } : baseMetadata;
|
|
638
|
+
return {
|
|
847
639
|
definition,
|
|
848
|
-
verifiers,
|
|
849
640
|
metadata
|
|
850
641
|
};
|
|
851
|
-
if (config.message !== void 0) {
|
|
852
|
-
defined.message = config.message;
|
|
853
|
-
}
|
|
854
|
-
return defined;
|
|
855
642
|
}
|
|
856
|
-
async function
|
|
857
|
-
const
|
|
858
|
-
const
|
|
859
|
-
|
|
860
|
-
|
|
861
|
-
|
|
643
|
+
async function requireX402Payment(request, payment, options = {}) {
|
|
644
|
+
const definition = isX402Payment(payment) ? payment.definition : payment;
|
|
645
|
+
const attempt = extractX402Attempt(request);
|
|
646
|
+
if (!attempt) {
|
|
647
|
+
const response = createX402PaymentRequired(definition);
|
|
648
|
+
throw new X402PaymentRequiredError(response);
|
|
649
|
+
}
|
|
862
650
|
const verifyOptions = {
|
|
863
|
-
|
|
864
|
-
request
|
|
651
|
+
settle: options.settle !== void 0 ? options.settle : true
|
|
865
652
|
};
|
|
866
|
-
if (
|
|
867
|
-
verifyOptions.verifiers = mergedVerifiers;
|
|
868
|
-
}
|
|
869
|
-
if (options.settle !== void 0) {
|
|
870
|
-
verifyOptions.settle = options.settle;
|
|
871
|
-
}
|
|
872
|
-
if (options.fetchImpl) {
|
|
653
|
+
if (options.fetchImpl !== void 0) {
|
|
873
654
|
verifyOptions.fetchImpl = options.fetchImpl;
|
|
874
655
|
}
|
|
875
|
-
const verification = await
|
|
656
|
+
const verification = await verifyX402Payment(attempt, definition, verifyOptions);
|
|
876
657
|
if (!verification.success || !verification.metadata) {
|
|
877
658
|
if (options.onFailure) {
|
|
878
659
|
return options.onFailure(verification);
|
|
879
660
|
}
|
|
880
|
-
const response =
|
|
881
|
-
throw new
|
|
661
|
+
const response = createX402PaymentRequired(definition);
|
|
662
|
+
throw new X402PaymentRequiredError(response, verification);
|
|
882
663
|
}
|
|
883
664
|
return {
|
|
884
665
|
payment: verification.metadata,
|
|
885
666
|
headers: verification.responseHeaders ?? {},
|
|
886
|
-
optionId: verification.optionId,
|
|
887
667
|
result: verification
|
|
888
668
|
};
|
|
889
669
|
}
|
|
890
|
-
function
|
|
891
|
-
|
|
892
|
-
|
|
893
|
-
|
|
894
|
-
|
|
895
|
-
}
|
|
896
|
-
|
|
897
|
-
|
|
898
|
-
|
|
899
|
-
verifiers: {}
|
|
670
|
+
function withX402Payment(handler, payment, options = {}) {
|
|
671
|
+
return async (request) => {
|
|
672
|
+
const verification = await requireX402Payment(request, payment, options);
|
|
673
|
+
if (verification instanceof Response) {
|
|
674
|
+
return verification;
|
|
675
|
+
}
|
|
676
|
+
setPaymentContext(request, verification);
|
|
677
|
+
const response = await Promise.resolve(handler(request));
|
|
678
|
+
return applyPaymentHeaders(response, verification.headers);
|
|
900
679
|
};
|
|
901
680
|
}
|
|
902
|
-
function
|
|
903
|
-
|
|
904
|
-
|
|
905
|
-
|
|
906
|
-
if (!value) {
|
|
907
|
-
return void 0;
|
|
681
|
+
function applyPaymentHeaders(response, headers) {
|
|
682
|
+
const entries = Object.entries(headers ?? {});
|
|
683
|
+
if (entries.length === 0) {
|
|
684
|
+
return response;
|
|
908
685
|
}
|
|
909
|
-
|
|
910
|
-
|
|
911
|
-
|
|
912
|
-
|
|
913
|
-
|
|
686
|
+
let mutated = false;
|
|
687
|
+
const merged = new Headers(response.headers);
|
|
688
|
+
for (const [key, value] of entries) {
|
|
689
|
+
if (!merged.has(key)) {
|
|
690
|
+
merged.set(key, value);
|
|
691
|
+
mutated = true;
|
|
914
692
|
}
|
|
915
|
-
return { url: value };
|
|
916
693
|
}
|
|
917
|
-
|
|
694
|
+
if (!mutated) {
|
|
695
|
+
return response;
|
|
696
|
+
}
|
|
697
|
+
return new Response(response.body, {
|
|
698
|
+
status: response.status,
|
|
699
|
+
statusText: response.statusText,
|
|
700
|
+
headers: merged
|
|
701
|
+
});
|
|
918
702
|
}
|
|
919
|
-
function
|
|
703
|
+
function isX402Payment(value) {
|
|
704
|
+
return !!value && typeof value === "object" && "definition" in value && value.definition !== void 0;
|
|
705
|
+
}
|
|
706
|
+
function resolveFacilitator(value) {
|
|
920
707
|
if (!value) {
|
|
921
|
-
return
|
|
708
|
+
return DEFAULT_FACILITATOR;
|
|
922
709
|
}
|
|
923
710
|
if (typeof value === "string") {
|
|
924
|
-
|
|
925
|
-
return value;
|
|
926
|
-
}
|
|
927
|
-
return "custom";
|
|
711
|
+
return { ...DEFAULT_FACILITATOR, url: value };
|
|
928
712
|
}
|
|
929
|
-
return
|
|
713
|
+
return value;
|
|
930
714
|
}
|
|
931
715
|
function normalizeCurrency(currency) {
|
|
932
716
|
return (currency ?? "USDC").toUpperCase();
|
|
@@ -934,55 +718,6 @@ function normalizeCurrency(currency) {
|
|
|
934
718
|
function toDecimalString(value) {
|
|
935
719
|
return typeof value === "number" ? value.toString() : value;
|
|
936
720
|
}
|
|
937
|
-
function buildDefaultDirectVerifier(expectedToken, verifierId, optionId) {
|
|
938
|
-
return async ({ attempt, option }) => {
|
|
939
|
-
if (attempt.type !== "direct") {
|
|
940
|
-
return {
|
|
941
|
-
success: false,
|
|
942
|
-
optionId: option.id,
|
|
943
|
-
attemptType: attempt.type,
|
|
944
|
-
failure: {
|
|
945
|
-
reason: "Expected direct payment payload",
|
|
946
|
-
code: "invalid_payload"
|
|
947
|
-
}
|
|
948
|
-
};
|
|
949
|
-
}
|
|
950
|
-
const payload = attempt.payload.payload;
|
|
951
|
-
if (expectedToken) {
|
|
952
|
-
if (payload?.token !== expectedToken) {
|
|
953
|
-
return {
|
|
954
|
-
success: false,
|
|
955
|
-
optionId: option.id,
|
|
956
|
-
attemptType: attempt.type,
|
|
957
|
-
failure: {
|
|
958
|
-
reason: "Invalid or missing payment proof",
|
|
959
|
-
code: "verification_failed"
|
|
960
|
-
}
|
|
961
|
-
};
|
|
962
|
-
}
|
|
963
|
-
} else if (!payload) {
|
|
964
|
-
return {
|
|
965
|
-
success: false,
|
|
966
|
-
optionId: option.id,
|
|
967
|
-
attemptType: attempt.type,
|
|
968
|
-
failure: {
|
|
969
|
-
reason: "Payment proof is required",
|
|
970
|
-
code: "verification_failed"
|
|
971
|
-
}
|
|
972
|
-
};
|
|
973
|
-
}
|
|
974
|
-
return {
|
|
975
|
-
success: true,
|
|
976
|
-
optionId,
|
|
977
|
-
attemptType: attempt.type,
|
|
978
|
-
metadata: {
|
|
979
|
-
optionId,
|
|
980
|
-
verifier: verifierId,
|
|
981
|
-
payload
|
|
982
|
-
}
|
|
983
|
-
};
|
|
984
|
-
};
|
|
985
|
-
}
|
|
986
721
|
|
|
987
722
|
// src/adapters/mcp.ts
|
|
988
723
|
var HTTP_METHODS = [
|
|
@@ -1010,7 +745,7 @@ function createMcpAdapter(options) {
|
|
|
1010
745
|
const response = await Promise.resolve(httpHandler(request));
|
|
1011
746
|
return await responseToToolResponse(response);
|
|
1012
747
|
} catch (error) {
|
|
1013
|
-
if (error instanceof
|
|
748
|
+
if (error instanceof X402PaymentRequiredError) {
|
|
1014
749
|
return await responseToToolResponse(error.response);
|
|
1015
750
|
}
|
|
1016
751
|
throw error;
|
|
@@ -1249,7 +984,7 @@ async function loadToolsFromDirectory(metadataMap) {
|
|
|
1249
984
|
const entry = httpHandlers[index];
|
|
1250
985
|
httpHandlers[index] = {
|
|
1251
986
|
...entry,
|
|
1252
|
-
handler:
|
|
987
|
+
handler: withX402Payment(entry.handler, payment)
|
|
1253
988
|
};
|
|
1254
989
|
}
|
|
1255
990
|
}
|
|
@@ -2505,23 +2240,45 @@ var McpAnnotationsSchema = z.object({
|
|
|
2505
2240
|
openWorldHint: z.boolean().optional(),
|
|
2506
2241
|
requiresPayment: z.boolean().optional()
|
|
2507
2242
|
}).strict();
|
|
2508
|
-
var
|
|
2509
|
-
|
|
2510
|
-
|
|
2511
|
-
|
|
2512
|
-
|
|
2513
|
-
|
|
2514
|
-
|
|
2515
|
-
|
|
2516
|
-
|
|
2517
|
-
|
|
2243
|
+
var X402PaymentSchema = z.object({
|
|
2244
|
+
definition: z.object({
|
|
2245
|
+
amount: z.string(),
|
|
2246
|
+
currency: z.object({
|
|
2247
|
+
code: z.string(),
|
|
2248
|
+
symbol: z.string(),
|
|
2249
|
+
decimals: z.number()
|
|
2250
|
+
}),
|
|
2251
|
+
asset: z.object({
|
|
2252
|
+
symbol: z.string(),
|
|
2253
|
+
network: z.string(),
|
|
2254
|
+
address: z.string(),
|
|
2255
|
+
decimals: z.number()
|
|
2256
|
+
}),
|
|
2257
|
+
payTo: z.string(),
|
|
2258
|
+
resource: z.string().optional(),
|
|
2259
|
+
description: z.string().optional(),
|
|
2260
|
+
scheme: z.string(),
|
|
2261
|
+
network: z.string(),
|
|
2262
|
+
facilitator: z.object({
|
|
2263
|
+
url: z.string(),
|
|
2264
|
+
verifyPath: z.string().optional(),
|
|
2265
|
+
settlePath: z.string().optional(),
|
|
2266
|
+
apiKeyHeader: z.string().optional()
|
|
2267
|
+
}),
|
|
2268
|
+
metadata: z.record(z.string(), z.unknown()).optional()
|
|
2269
|
+
}),
|
|
2270
|
+
metadata: z.record(z.string(), z.unknown()).optional()
|
|
2271
|
+
}).passthrough();
|
|
2272
|
+
var PaymentConfigSchema = z.union([
|
|
2273
|
+
X402PaymentSchema,
|
|
2274
|
+
z.record(z.string(), z.unknown())
|
|
2275
|
+
]);
|
|
2518
2276
|
var DiscoveryMetadataSchema = z.object({
|
|
2519
2277
|
keywords: z.array(z.string()).optional(),
|
|
2520
2278
|
category: z.string().optional(),
|
|
2521
2279
|
useCases: z.array(z.string()).optional(),
|
|
2522
2280
|
capabilities: z.array(z.string()).optional(),
|
|
2523
2281
|
requirements: z.record(z.string(), z.any()).optional(),
|
|
2524
|
-
pricing: z.record(z.string(), z.any()).optional(),
|
|
2525
2282
|
compatibility: z.record(z.string(), z.any()).optional(),
|
|
2526
2283
|
documentation: z.union([z.string(), z.array(z.string())]).optional()
|
|
2527
2284
|
}).catchall(z.any());
|
|
@@ -2542,7 +2299,7 @@ var ToolSchema = z.object({
|
|
|
2542
2299
|
discovery: DiscoveryMetadataSchema.optional(),
|
|
2543
2300
|
chains: z.array(z.union([z.string(), z.number()])).optional()
|
|
2544
2301
|
}).strict();
|
|
2545
|
-
var
|
|
2302
|
+
var MetadataSchema = z.object({
|
|
2546
2303
|
metadataSpecVersion: z.string().optional(),
|
|
2547
2304
|
name: z.string().optional(),
|
|
2548
2305
|
displayName: z.string().optional(),
|
|
@@ -2566,11 +2323,10 @@ var AuthoredMetadataSchema = z.object({
|
|
|
2566
2323
|
useCases: z.array(z.string()).optional(),
|
|
2567
2324
|
capabilities: z.array(z.string()).optional(),
|
|
2568
2325
|
requirements: z.record(z.string(), z.any()).optional(),
|
|
2569
|
-
pricing: z.record(z.string(), z.any()).optional(),
|
|
2570
2326
|
compatibility: z.record(z.string(), z.any()).optional(),
|
|
2571
2327
|
chains: z.array(z.union([z.string(), z.number()])).optional()
|
|
2572
2328
|
}).catchall(z.any());
|
|
2573
|
-
var
|
|
2329
|
+
var BuildMetadataSchema = z.object({
|
|
2574
2330
|
metadataSpecVersion: z.string().default(METADATA_SPEC_VERSION),
|
|
2575
2331
|
name: z.string(),
|
|
2576
2332
|
displayName: z.string(),
|
|
@@ -2672,7 +2428,7 @@ async function importFresh(modulePath) {
|
|
|
2672
2428
|
|
|
2673
2429
|
// src/cli/shared/metadata.ts
|
|
2674
2430
|
var METADATA_ENTRY = "metadata.ts";
|
|
2675
|
-
async function
|
|
2431
|
+
async function loadMetadata2(projectRoot) {
|
|
2676
2432
|
const absPath = path5.join(projectRoot, METADATA_ENTRY);
|
|
2677
2433
|
if (!fs2.existsSync(absPath)) {
|
|
2678
2434
|
throw new Error(
|
|
@@ -2693,7 +2449,7 @@ async function loadAuthoredMetadata(projectRoot) {
|
|
|
2693
2449
|
const compiledPath = resolveCompiledPath(outDir, METADATA_ENTRY);
|
|
2694
2450
|
const moduleExports = await importFresh(compiledPath);
|
|
2695
2451
|
const metadataExport = extractMetadataExport(moduleExports);
|
|
2696
|
-
const parsed =
|
|
2452
|
+
const parsed = MetadataSchema.parse(metadataExport);
|
|
2697
2453
|
return { metadata: parsed, sourcePath: absPath };
|
|
2698
2454
|
} finally {
|
|
2699
2455
|
cleanup();
|
|
@@ -2734,7 +2490,7 @@ function readPackageJson(projectRoot) {
|
|
|
2734
2490
|
async function buildMetadataArtifact(options) {
|
|
2735
2491
|
const projectRoot = options.projectRoot;
|
|
2736
2492
|
const packageInfo = readPackageJson(projectRoot);
|
|
2737
|
-
const { metadata: authored, sourcePath } = await
|
|
2493
|
+
const { metadata: authored, sourcePath } = await loadMetadata2(projectRoot);
|
|
2738
2494
|
const defaultsApplied = [];
|
|
2739
2495
|
const folderName = path5.basename(projectRoot);
|
|
2740
2496
|
const name = resolveField(
|
|
@@ -2779,7 +2535,7 @@ async function buildMetadataArtifact(options) {
|
|
|
2779
2535
|
if (!authored.website && packageInfo.homepage) {
|
|
2780
2536
|
defaultsApplied.push("website \u2192 package.json homepage");
|
|
2781
2537
|
}
|
|
2782
|
-
const payment = resolvePayment(authored
|
|
2538
|
+
const payment = resolvePayment(authored);
|
|
2783
2539
|
const baseImage = authored.image ?? authored.iconPath;
|
|
2784
2540
|
const animation = authored.animation_url ?? authored.videoPath;
|
|
2785
2541
|
const discovery = buildDiscovery(authored);
|
|
@@ -2812,7 +2568,7 @@ async function buildMetadataArtifact(options) {
|
|
|
2812
2568
|
}
|
|
2813
2569
|
return toolDefinition;
|
|
2814
2570
|
});
|
|
2815
|
-
const metadata =
|
|
2571
|
+
const metadata = BuildMetadataSchema.parse({
|
|
2816
2572
|
metadataSpecVersion: authored.metadataSpecVersion ?? METADATA_SPEC_VERSION,
|
|
2817
2573
|
name,
|
|
2818
2574
|
displayName,
|
|
@@ -2868,32 +2624,8 @@ function extractRepository(repository) {
|
|
|
2868
2624
|
}
|
|
2869
2625
|
return repository.url;
|
|
2870
2626
|
}
|
|
2871
|
-
function resolvePayment(authored,
|
|
2872
|
-
|
|
2873
|
-
return authored.payment;
|
|
2874
|
-
}
|
|
2875
|
-
const discoveryPricing = authored.discovery?.pricing;
|
|
2876
|
-
const legacyPricing = authored.pricing;
|
|
2877
|
-
const pricing = discoveryPricing ?? legacyPricing;
|
|
2878
|
-
if (!pricing) {
|
|
2879
|
-
return void 0;
|
|
2880
|
-
}
|
|
2881
|
-
const amount = typeof pricing.defaultAmount === "number" ? pricing.defaultAmount : 0;
|
|
2882
|
-
const sourceLabel = discoveryPricing ? "discovery.pricing.defaultAmount" : "pricing.defaultAmount";
|
|
2883
|
-
defaults.push(`payment \u2192 synthesized from ${sourceLabel}`);
|
|
2884
|
-
const acceptedMethodsRaw = Array.isArray(pricing.acceptedMethods) ? pricing.acceptedMethods : ["402"];
|
|
2885
|
-
const acceptedMethods = acceptedMethodsRaw.map(
|
|
2886
|
-
(method) => method === "x402" ? "x402" : "402"
|
|
2887
|
-
);
|
|
2888
|
-
return {
|
|
2889
|
-
amountUSDC: amount,
|
|
2890
|
-
description: typeof pricing.description === "string" ? pricing.description : void 0,
|
|
2891
|
-
x402: acceptedMethods.includes("x402"),
|
|
2892
|
-
plain402: acceptedMethods.includes("402"),
|
|
2893
|
-
acceptedMethods,
|
|
2894
|
-
acceptedCurrencies: Array.isArray(pricing.acceptedCurrencies) ? pricing.acceptedCurrencies : ["USDC"],
|
|
2895
|
-
chains: Array.isArray(pricing.chains) ? pricing.chains : [8453]
|
|
2896
|
-
};
|
|
2627
|
+
function resolvePayment(authored, _defaults) {
|
|
2628
|
+
return authored.payment ?? void 0;
|
|
2897
2629
|
}
|
|
2898
2630
|
function buildDiscovery(authored) {
|
|
2899
2631
|
const legacyDiscovery = {};
|
|
@@ -2915,9 +2647,6 @@ function buildDiscovery(authored) {
|
|
|
2915
2647
|
if (Array.isArray(authored.categories) && authored.categories.length > 0) {
|
|
2916
2648
|
legacyDiscovery.category = authored.categories[0];
|
|
2917
2649
|
}
|
|
2918
|
-
if (authored.pricing) {
|
|
2919
|
-
legacyDiscovery.pricing = authored.pricing;
|
|
2920
|
-
}
|
|
2921
2650
|
const merged = {
|
|
2922
2651
|
...legacyDiscovery,
|
|
2923
2652
|
...authored.discovery ?? {}
|
|
@@ -3000,7 +2729,7 @@ async function loadAndValidateTools(toolsDir, options = {}) {
|
|
|
3000
2729
|
const entry = httpHandlers[index];
|
|
3001
2730
|
httpHandlers[index] = {
|
|
3002
2731
|
...entry,
|
|
3003
|
-
handler:
|
|
2732
|
+
handler: withX402Payment(entry.handler, paymentExport)
|
|
3004
2733
|
};
|
|
3005
2734
|
}
|
|
3006
2735
|
}
|
|
@@ -3013,11 +2742,11 @@ async function loadAndValidateTools(toolsDir, options = {}) {
|
|
|
3013
2742
|
...schema ? { schema } : {}
|
|
3014
2743
|
});
|
|
3015
2744
|
let metadataOverrides = toolModule.metadata ?? null;
|
|
3016
|
-
if (paymentExport
|
|
2745
|
+
if (paymentExport) {
|
|
3017
2746
|
if (metadataOverrides) {
|
|
3018
2747
|
metadataOverrides = {
|
|
3019
2748
|
...metadataOverrides,
|
|
3020
|
-
payment: metadataOverrides.payment ?? paymentExport
|
|
2749
|
+
payment: metadataOverrides.payment ?? paymentExport,
|
|
3021
2750
|
annotations: {
|
|
3022
2751
|
...metadataOverrides.annotations ?? {},
|
|
3023
2752
|
requiresPayment: metadataOverrides.annotations?.requiresPayment ?? true
|
|
@@ -3025,7 +2754,7 @@ async function loadAndValidateTools(toolsDir, options = {}) {
|
|
|
3025
2754
|
};
|
|
3026
2755
|
} else {
|
|
3027
2756
|
metadataOverrides = {
|
|
3028
|
-
payment: paymentExport
|
|
2757
|
+
payment: paymentExport,
|
|
3029
2758
|
annotations: { requiresPayment: true }
|
|
3030
2759
|
};
|
|
3031
2760
|
}
|
|
@@ -3271,6 +3000,6 @@ function timestamp() {
|
|
|
3271
3000
|
return (/* @__PURE__ */ new Date()).toISOString().replace("T", " ").slice(0, 19);
|
|
3272
3001
|
}
|
|
3273
3002
|
|
|
3274
|
-
export { AIAbortError, AIError, AIFetchError, AIResponseError, DEFAULT_BASE_URL, DEFAULT_CHAIN, DEFAULT_MODEL, DEFAULT_TIMEOUT_MS, DEFAULT_TOKENS,
|
|
3003
|
+
export { AIAbortError, AIError, AIFetchError, AIResponseError, DEFAULT_BASE_URL, DEFAULT_CHAIN, DEFAULT_FACILITATOR, DEFAULT_MODEL, DEFAULT_TIMEOUT_MS, DEFAULT_TOKENS, HTTP_METHODS2 as HTTP_METHODS, PAYMENT_HEADERS, SUPPORTED_CURRENCIES, WEBSEARCH_TOOL_DEFINITION, WEBSEARCH_TOOL_NAME, X402BrowserClient, X402Client, X402PaymentRequiredError, chains, createAIClient, createDevServer, createMcpAdapter, createStdioServer, defineX402Payment, ensureTextContent, flattenMessageContent, generateMetadata, generateMetadataCommand, generateText, getModelConfig, getRpcUrl, getX402PaymentContext, isStreamingSupported, isToolCallingSupported, listModels, loadAndValidateTools, normalizeModelName, payX402, payX402WithWallet, registry, requireX402Payment, resolveConfig, resolveRuntimePath, resolveToolset, responseToToolResponse, streamText, tokens, validateCommand, wallet, walletToolkit, withX402Payment };
|
|
3275
3004
|
//# sourceMappingURL=index.js.map
|
|
3276
3005
|
//# sourceMappingURL=index.js.map
|