@devlab.group/agent-commerce 0.1.0-alpha.0 → 0.2.0-beta.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/README.md +41 -22
- package/dist/{chunk-CZ6ZDAYD.js → chunk-ASK67X56.js} +9 -7
- package/dist/chunk-ASK67X56.js.map +1 -0
- package/dist/chunk-MQMKQGAB.js +199 -0
- package/dist/chunk-MQMKQGAB.js.map +1 -0
- package/dist/cli/index.d.ts +1 -0
- package/dist/cli/index.js +253 -49
- package/dist/cli/index.js.map +1 -1
- package/dist/guardrails-Di_yI_DW.d.ts +25 -0
- package/dist/index.d.ts +36 -18
- package/dist/index.js +74 -33
- package/dist/index.js.map +1 -1
- package/dist/mcp.d.ts +2 -2
- package/dist/mcp.js +2 -2
- package/dist/mcp.js.map +1 -1
- package/dist/{protocol-adapter-C0goMgLK.d.ts → protocol-adapter-CtB0sOnV.d.ts} +2 -3
- package/dist/{runtime-LCk2TzGN.d.ts → runtime-Bie-9FAM.d.ts} +15 -3
- package/dist/x402.d.ts +69 -17
- package/dist/x402.js +265 -216
- package/dist/x402.js.map +1 -1
- package/package.json +13 -7
- package/dist/chunk-CZ6ZDAYD.js.map +0 -1
|
@@ -0,0 +1,25 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* How the gateway authenticates to a remote facilitator.
|
|
3
|
+
*
|
|
4
|
+
* Deliberately generic: x402 facilitators are not a Coinbase-only category,
|
|
5
|
+
* and a scheme that only fits one vendor's credentials would make the
|
|
6
|
+
* abstraction a fiction. `bearer` covers every facilitator that takes a static
|
|
7
|
+
* token; a facilitator needing per-request signed credentials (CDP's JWT among
|
|
8
|
+
* them) is not supported yet and is refused rather than silently sent nothing.
|
|
9
|
+
*/
|
|
10
|
+
type FacilitatorAuth = {
|
|
11
|
+
readonly type: 'none';
|
|
12
|
+
} | {
|
|
13
|
+
readonly type: 'bearer';
|
|
14
|
+
readonly token: string;
|
|
15
|
+
};
|
|
16
|
+
type X402FacilitatorConfig = {
|
|
17
|
+
readonly mode: 'local';
|
|
18
|
+
readonly signerPrivateKey: string;
|
|
19
|
+
} | {
|
|
20
|
+
readonly mode: 'remote';
|
|
21
|
+
readonly url: string;
|
|
22
|
+
readonly auth: FacilitatorAuth;
|
|
23
|
+
};
|
|
24
|
+
|
|
25
|
+
export type { FacilitatorAuth as F, X402FacilitatorConfig as X };
|
package/dist/index.d.ts
CHANGED
|
@@ -1,7 +1,8 @@
|
|
|
1
|
-
import { I as IsoTimestamp, D as DecimalAmount, P as PaymentMethodName, B as BackendHandler, A as AdapterDescriptor, a as AdapterHealth, C as CommerceResource, R as ResourceRegistry, b as PaymentProvider, L as Logger, c as Clock, d as IdGenerator } from './runtime-
|
|
2
|
-
export { e as BackendMethod, f as DEFAULT_BACKEND_TIMEOUT_MS, J as JsonSchema, N as NOOP_LOGGER, g as PaymentChallenge, h as PaymentContext, i as PaymentRequirement, j as PaymentResult, k as PaymentSettlementContext, l as PaymentSubmission, m as PaymentVerificationContext, n as Pricing, o as ProtocolName, s as systemClock } from './runtime-
|
|
3
|
-
import {
|
|
4
|
-
|
|
1
|
+
import { I as IsoTimestamp, D as DecimalAmount, P as PaymentMethodName, B as BackendHandler, A as AdapterDescriptor, a as AdapterHealth, C as CommerceResource, R as ResourceRegistry, b as PaymentProvider, L as Logger, c as Clock, d as IdGenerator } from './runtime-Bie-9FAM.js';
|
|
2
|
+
export { e as BackendMethod, f as DEFAULT_BACKEND_TIMEOUT_MS, J as JsonSchema, N as NOOP_LOGGER, g as PaymentChallenge, h as PaymentContext, i as PaymentRequirement, j as PaymentResult, k as PaymentSettlementContext, l as PaymentSubmission, m as PaymentVerificationContext, n as Pricing, o as ProtocolName, s as systemClock } from './runtime-Bie-9FAM.js';
|
|
3
|
+
import { X as X402FacilitatorConfig } from './guardrails-Di_yI_DW.js';
|
|
4
|
+
import { D as DeliveredOutcome, P as PaymentRequiredOutcome, C as CommerceEvent, a as PaymentAttempt, b as CommerceReceipt, E as ExecutionPipeline, c as ProtocolAdapter } from './protocol-adapter-CtB0sOnV.js';
|
|
5
|
+
export { d as COMMERCE_EVENT_TYPES, e as CanonicalRequest, f as CommerceEventType, g as EventSink, h as ExecutionOutcome, H as HttpProtocolAdapter, i as ProtocolAdapterContext, j as isHttpProtocolAdapter } from './protocol-adapter-CtB0sOnV.js';
|
|
5
6
|
import { FastifyInstance } from 'fastify';
|
|
6
7
|
import 'node:http';
|
|
7
8
|
|
|
@@ -93,13 +94,29 @@ declare function toCommerceError(value: unknown, fallbackCode?: CommerceErrorCod
|
|
|
93
94
|
|
|
94
95
|
/**
|
|
95
96
|
* Reserved input property carrying a payment proof on protocols that have no
|
|
96
|
-
* header channel (MCP tool calls). Over HTTP the `
|
|
97
|
+
* header channel (MCP tool calls). Over HTTP the `PAYMENT-SIGNATURE` header is
|
|
98
|
+
* used.
|
|
97
99
|
*/
|
|
98
100
|
declare const PAYMENT_INPUT_FIELD = "_payment";
|
|
99
|
-
/**
|
|
100
|
-
|
|
101
|
-
|
|
102
|
-
|
|
101
|
+
/**
|
|
102
|
+
* HTTP request header carrying the payment proof.
|
|
103
|
+
*
|
|
104
|
+
* x402 v2 header names, lowercased because that is how Node presents incoming
|
|
105
|
+
* headers. v1's `X-PAYMENT` / `X-PAYMENT-RESPONSE` pair is not accepted: this
|
|
106
|
+
* gateway speaks one protocol version, and quietly honouring both would mean
|
|
107
|
+
* two verification paths for the same money.
|
|
108
|
+
*/
|
|
109
|
+
declare const PAYMENT_HEADER = "payment-signature";
|
|
110
|
+
/** HTTP response header carrying the settlement result. */
|
|
111
|
+
declare const PAYMENT_RESPONSE_HEADER = "payment-response";
|
|
112
|
+
/**
|
|
113
|
+
* HTTP response header carrying the base64 payment challenge on a 402.
|
|
114
|
+
*
|
|
115
|
+
* The 402 body still carries {@link PaymentRequiredEnvelope} — richer, and the
|
|
116
|
+
* only channel MCP has — but an x402 v2 client reads the challenge from this
|
|
117
|
+
* header and ignores the body, so both are sent.
|
|
118
|
+
*/
|
|
119
|
+
declare const PAYMENT_REQUIRED_HEADER = "payment-required";
|
|
103
120
|
/**
|
|
104
121
|
* Key under which a protocol adapter attaches a {@link DeliverySummary} to its
|
|
105
122
|
* result metadata — MCP's `CallToolResult._meta`, and anywhere else a protocol
|
|
@@ -130,6 +147,12 @@ interface PaymentRequiredEnvelope {
|
|
|
130
147
|
readonly expiresAt?: IsoTimestamp;
|
|
131
148
|
/** Provider-native requirement objects, passed through verbatim. */
|
|
132
149
|
readonly accepts: readonly Readonly<Record<string, unknown>>[];
|
|
150
|
+
/**
|
|
151
|
+
* The provider's own challenge document, verbatim — see
|
|
152
|
+
* {@link PaymentChallenge.envelope}. Present for providers that have one;
|
|
153
|
+
* a buyer's protocol client can hand this straight to its SDK.
|
|
154
|
+
*/
|
|
155
|
+
readonly envelope?: Readonly<Record<string, unknown>>;
|
|
133
156
|
};
|
|
134
157
|
}
|
|
135
158
|
interface ErrorEnvelope {
|
|
@@ -150,7 +173,7 @@ interface ErrorEnvelope {
|
|
|
150
173
|
* `/api/receipts` is an operator route behind `server.adminToken`.
|
|
151
174
|
*
|
|
152
175
|
* Before this existed the two surfaces disagreed: HTTP callers received a
|
|
153
|
-
* settlement summary in
|
|
176
|
+
* settlement summary in the payment-response header while MCP callers received
|
|
154
177
|
* nothing, so an MCP buyer's only route to their own receipt was the merchant's
|
|
155
178
|
* ledger. Both surfaces now emit this same shape.
|
|
156
179
|
*/
|
|
@@ -353,13 +376,8 @@ interface GatewayConfig {
|
|
|
353
376
|
readonly assetDecimals: number;
|
|
354
377
|
readonly payTo: string;
|
|
355
378
|
readonly maxTimeoutSeconds: number;
|
|
356
|
-
readonly facilitator:
|
|
357
|
-
|
|
358
|
-
readonly signerPrivateKey: string;
|
|
359
|
-
} | {
|
|
360
|
-
readonly mode: 'remote';
|
|
361
|
-
readonly url: string;
|
|
362
|
-
};
|
|
379
|
+
readonly facilitator: X402FacilitatorConfig;
|
|
380
|
+
readonly allowMainnet?: boolean;
|
|
363
381
|
};
|
|
364
382
|
};
|
|
365
383
|
}
|
|
@@ -409,4 +427,4 @@ interface SqliteReceiptStoreOptions {
|
|
|
409
427
|
}
|
|
410
428
|
declare function createSqliteReceiptStore(options: SqliteReceiptStoreOptions): ReceiptStore;
|
|
411
429
|
|
|
412
|
-
export { AdapterDescriptor, AdapterHealth, type BackendExecutor, BackendHandler, type BackendRequest, type BackendResponse, COMMERCE_ERROR_CODES, COMMERCE_ERROR_HTTP_STATUS, Clock, CommerceError, type CommerceErrorCode, type CommerceErrorInfo, type CommerceErrorOptions, CommerceEvent, CommerceReceipt, CommerceResource, DELIVERY_SUMMARY_META_KEY, DecimalAmount, DeliveredOutcome, type DeliverySummary, type ErrorEnvelope, ExecutionPipeline, type GatewayConfig, type GatewayInstance, type GatewayOptions, IdGenerator, IsoTimestamp, type ListOptions, Logger, PAYMENT_HEADER, PAYMENT_INPUT_FIELD, PAYMENT_RESPONSE_HEADER, PaymentAttempt, type PaymentAttemptReservation, type PaymentAttemptUpdate, PaymentMethodName, PaymentProvider, type PaymentRequiredEnvelope, PaymentRequiredOutcome, ProtocolAdapter, RETRYABLE_ERROR_CODES, type ReceiptStore, ResourceRegistry, createGateway, createSqliteReceiptStore, isCommerceError, isPaymentRequiredEnvelope, loadConfig, parseConfig, createSqliteReceiptStore as receipts, toCommerceError, toDeliverySummary, toErrorEnvelope, toPaymentRequiredEnvelope };
|
|
430
|
+
export { AdapterDescriptor, AdapterHealth, type BackendExecutor, BackendHandler, type BackendRequest, type BackendResponse, COMMERCE_ERROR_CODES, COMMERCE_ERROR_HTTP_STATUS, Clock, CommerceError, type CommerceErrorCode, type CommerceErrorInfo, type CommerceErrorOptions, CommerceEvent, CommerceReceipt, CommerceResource, DELIVERY_SUMMARY_META_KEY, DecimalAmount, DeliveredOutcome, type DeliverySummary, type ErrorEnvelope, ExecutionPipeline, type GatewayConfig, type GatewayInstance, type GatewayOptions, IdGenerator, IsoTimestamp, type ListOptions, Logger, PAYMENT_HEADER, PAYMENT_INPUT_FIELD, PAYMENT_REQUIRED_HEADER, PAYMENT_RESPONSE_HEADER, PaymentAttempt, type PaymentAttemptReservation, type PaymentAttemptUpdate, PaymentMethodName, PaymentProvider, type PaymentRequiredEnvelope, PaymentRequiredOutcome, ProtocolAdapter, RETRYABLE_ERROR_CODES, type ReceiptStore, ResourceRegistry, createGateway, createSqliteReceiptStore, isCommerceError, isPaymentRequiredEnvelope, loadConfig, parseConfig, createSqliteReceiptStore as receipts, toCommerceError, toDeliverySummary, toErrorEnvelope, toPaymentRequiredEnvelope };
|
package/dist/index.js
CHANGED
|
@@ -1,5 +1,6 @@
|
|
|
1
|
-
import {
|
|
2
|
-
|
|
1
|
+
import { resolveX402Deployment, resolveDeploymentMode, requireNetworkProfile } from './chunk-MQMKQGAB.js';
|
|
2
|
+
import { CommerceError, PAYMENT_INPUT_FIELD, systemClock, NOOP_LOGGER, PACKAGE_VERSION, toCommerceError, DEFAULT_BACKEND_TIMEOUT_MS, toErrorEnvelope, isHttpProtocolAdapter, isCommerceError, PAYMENT_HEADER, toPaymentRequiredEnvelope, PAYMENT_REQUIRED_HEADER, PAYMENT_RESPONSE_HEADER } from './chunk-ASK67X56.js';
|
|
3
|
+
export { COMMERCE_ERROR_CODES, COMMERCE_ERROR_HTTP_STATUS, COMMERCE_EVENT_TYPES, CommerceError, DEFAULT_BACKEND_TIMEOUT_MS, DELIVERY_SUMMARY_META_KEY, NOOP_LOGGER, PAYMENT_HEADER, PAYMENT_INPUT_FIELD, PAYMENT_REQUIRED_HEADER, PAYMENT_RESPONSE_HEADER, RETRYABLE_ERROR_CODES, isCommerceError, isHttpProtocolAdapter, isPaymentRequiredEnvelope, systemClock, toCommerceError, toDeliverySummary, toErrorEnvelope, toPaymentRequiredEnvelope } from './chunk-ASK67X56.js';
|
|
3
4
|
import { promises, existsSync, mkdirSync, accessSync, constants, chmodSync } from 'fs';
|
|
4
5
|
import * as path from 'path';
|
|
5
6
|
import { dirname } from 'path';
|
|
@@ -952,6 +953,7 @@ function createExecutionPipeline(options) {
|
|
|
952
953
|
provider: paymentResult.provider,
|
|
953
954
|
amount: paymentResult.amount,
|
|
954
955
|
currency: paymentResult.currency,
|
|
956
|
+
...paymentResult.network !== void 0 ? { network: paymentResult.network } : {},
|
|
955
957
|
...paymentResult.externalReference !== void 0 ? { externalReference: paymentResult.externalReference } : {}
|
|
956
958
|
}
|
|
957
959
|
}
|
|
@@ -1148,6 +1150,10 @@ var ResourceEntrySchema = z.object({
|
|
|
1148
1150
|
payments: z.array(z.string().min(1)).optional()
|
|
1149
1151
|
}).strict();
|
|
1150
1152
|
var ResourcesMapSchema = z.record(z.string().min(1), ResourceEntrySchema);
|
|
1153
|
+
var FacilitatorAuthSchema = z.discriminatedUnion("type", [
|
|
1154
|
+
z.object({ type: z.literal("none") }).strict(),
|
|
1155
|
+
z.object({ type: z.literal("bearer"), token: z.string().min(1) }).strict()
|
|
1156
|
+
]);
|
|
1151
1157
|
var FacilitatorSchema = z.discriminatedUnion("mode", [
|
|
1152
1158
|
z.object({
|
|
1153
1159
|
mode: z.literal("local"),
|
|
@@ -1155,7 +1161,12 @@ var FacilitatorSchema = z.discriminatedUnion("mode", [
|
|
|
1155
1161
|
}).strict(),
|
|
1156
1162
|
z.object({
|
|
1157
1163
|
mode: z.literal("remote"),
|
|
1158
|
-
url: z.string().min(1)
|
|
1164
|
+
url: z.string().min(1),
|
|
1165
|
+
// Absent means "this facilitator takes no credential" — an explicit
|
|
1166
|
+
// statement, normalised to `{ type: 'none' }` below. On a mainnet that
|
|
1167
|
+
// combination is refused outright, so the default can never quietly
|
|
1168
|
+
// become an unauthenticated production facilitator.
|
|
1169
|
+
auth: FacilitatorAuthSchema.optional()
|
|
1159
1170
|
}).strict()
|
|
1160
1171
|
]);
|
|
1161
1172
|
var X402Schema = z.object({
|
|
@@ -1168,7 +1179,9 @@ var X402Schema = z.object({
|
|
|
1168
1179
|
assetDecimals: NumberOrString,
|
|
1169
1180
|
payTo: z.string().min(1),
|
|
1170
1181
|
maxTimeoutSeconds: NumberOrString,
|
|
1171
|
-
facilitator: FacilitatorSchema
|
|
1182
|
+
facilitator: FacilitatorSchema,
|
|
1183
|
+
/** Real funds. Never defaulted — see src/payments/x402/guardrails.ts. */
|
|
1184
|
+
allowMainnet: BooleanOrString.optional()
|
|
1172
1185
|
}).strict();
|
|
1173
1186
|
var PaymentsSchema = z.object({
|
|
1174
1187
|
x402: X402Schema.optional()
|
|
@@ -1290,14 +1303,12 @@ function normalise(raw) {
|
|
|
1290
1303
|
}
|
|
1291
1304
|
};
|
|
1292
1305
|
const x402Raw = raw.payments.x402;
|
|
1293
|
-
|
|
1294
|
-
|
|
1295
|
-
|
|
1296
|
-
|
|
1297
|
-
|
|
1298
|
-
|
|
1299
|
-
}
|
|
1300
|
-
const x402 = x402Raw ? {
|
|
1306
|
+
const facilitator = x402Raw === void 0 ? void 0 : x402Raw.facilitator.mode === "local" ? { mode: "local", signerPrivateKey: x402Raw.facilitator.signerPrivateKey } : {
|
|
1307
|
+
mode: "remote",
|
|
1308
|
+
url: x402Raw.facilitator.url,
|
|
1309
|
+
auth: x402Raw.facilitator.auth ?? { type: "none" }
|
|
1310
|
+
};
|
|
1311
|
+
const x402 = x402Raw && facilitator ? {
|
|
1301
1312
|
enabled: toBoolean(x402Raw.enabled, "payments.x402.enabled"),
|
|
1302
1313
|
network: x402Raw.network,
|
|
1303
1314
|
rpcUrl: x402Raw.rpcUrl,
|
|
@@ -1309,18 +1320,26 @@ function normalise(raw) {
|
|
|
1309
1320
|
max: 36
|
|
1310
1321
|
}),
|
|
1311
1322
|
payTo: x402Raw.payTo,
|
|
1312
|
-
maxTimeoutSeconds: toNumber(
|
|
1313
|
-
|
|
1314
|
-
|
|
1315
|
-
|
|
1316
|
-
|
|
1317
|
-
|
|
1318
|
-
|
|
1319
|
-
|
|
1323
|
+
maxTimeoutSeconds: toNumber(
|
|
1324
|
+
x402Raw.maxTimeoutSeconds,
|
|
1325
|
+
"payments.x402.maxTimeoutSeconds",
|
|
1326
|
+
{
|
|
1327
|
+
min: 1
|
|
1328
|
+
}
|
|
1329
|
+
),
|
|
1330
|
+
facilitator,
|
|
1331
|
+
...x402Raw.allowMainnet !== void 0 ? { allowMainnet: toBoolean(x402Raw.allowMainnet, "payments.x402.allowMainnet") } : {}
|
|
1320
1332
|
} : void 0;
|
|
1321
1333
|
if (x402) {
|
|
1322
1334
|
validateAddress("payments.x402.payTo", x402.payTo);
|
|
1323
1335
|
validateAddress("payments.x402.asset", x402.asset);
|
|
1336
|
+
resolveX402Deployment({
|
|
1337
|
+
network: x402.network,
|
|
1338
|
+
payTo: x402.payTo,
|
|
1339
|
+
asset: x402.asset,
|
|
1340
|
+
facilitator: x402.facilitator,
|
|
1341
|
+
...x402.allowMainnet !== void 0 ? { allowMainnet: x402.allowMainnet } : {}
|
|
1342
|
+
});
|
|
1324
1343
|
}
|
|
1325
1344
|
const resources = Object.entries(raw.resources).map(
|
|
1326
1345
|
([id, entry]) => normaliseResource(id, entry, protocols, x402)
|
|
@@ -1365,7 +1384,7 @@ function normaliseResource(id, entry, protocols, x402) {
|
|
|
1365
1384
|
}
|
|
1366
1385
|
for (const protocol of entry.expose) {
|
|
1367
1386
|
if (!SUPPORTED_PROTOCOLS.has(protocol)) {
|
|
1368
|
-
const hint = protocol === "ucp" ? " (UCP is planned, not supported in
|
|
1387
|
+
const hint = protocol === "ucp" ? " (UCP is planned, not supported in this release)" : "";
|
|
1369
1388
|
throw new CommerceError(
|
|
1370
1389
|
"CONFIG_INVALID",
|
|
1371
1390
|
`Resource "${id}" exposes unsupported protocol "${protocol}"${hint}. Supported: http, mcp.`,
|
|
@@ -1401,7 +1420,7 @@ function normaliseResource(id, entry, protocols, x402) {
|
|
|
1401
1420
|
if (entry.pricing.type === "dynamic") {
|
|
1402
1421
|
throw new CommerceError(
|
|
1403
1422
|
"CONFIG_INVALID",
|
|
1404
|
-
`Resource "${id}" uses pricing.type "dynamic", which is not supported in
|
|
1423
|
+
`Resource "${id}" uses pricing.type "dynamic", which is not supported in this release`,
|
|
1405
1424
|
{ details: { path: `resources.${id}.pricing.type`, resourceId: id } }
|
|
1406
1425
|
);
|
|
1407
1426
|
}
|
|
@@ -1755,7 +1774,7 @@ var SECRET_FIELD_NAMES = [
|
|
|
1755
1774
|
];
|
|
1756
1775
|
var REDACT_PATHS = [
|
|
1757
1776
|
"req.headers.authorization",
|
|
1758
|
-
'req.headers["
|
|
1777
|
+
'req.headers["payment-signature"]',
|
|
1759
1778
|
...SECRET_FIELD_NAMES,
|
|
1760
1779
|
...SECRET_FIELD_NAMES.map((name) => `*.${name}`)
|
|
1761
1780
|
];
|
|
@@ -1813,7 +1832,8 @@ function wrapPino(instance) {
|
|
|
1813
1832
|
return logger;
|
|
1814
1833
|
}
|
|
1815
1834
|
var CORS_METHODS = "GET,POST,DELETE,OPTIONS";
|
|
1816
|
-
var CORS_HEADERS = "content-type,
|
|
1835
|
+
var CORS_HEADERS = "content-type,payment-signature,x-request-id,authorization";
|
|
1836
|
+
var CORS_EXPOSED_HEADERS = "payment-required,payment-response,x-request-id";
|
|
1817
1837
|
function buildAccessControlHook(options) {
|
|
1818
1838
|
const allowedOrigins = new Set(options.allowedOrigins.map((origin) => origin.toLowerCase()));
|
|
1819
1839
|
const publicHostname = hostnameOf(options.publicBaseUrl);
|
|
@@ -1832,6 +1852,7 @@ function buildAccessControlHook(options) {
|
|
|
1832
1852
|
reply.header("access-control-allow-origin", origin);
|
|
1833
1853
|
reply.header("access-control-allow-methods", CORS_METHODS);
|
|
1834
1854
|
reply.header("access-control-allow-headers", CORS_HEADERS);
|
|
1855
|
+
reply.header("access-control-expose-headers", CORS_EXPOSED_HEADERS);
|
|
1835
1856
|
reply.header("vary", "Origin");
|
|
1836
1857
|
if (request.method === "OPTIONS") {
|
|
1837
1858
|
reply.status(204).send();
|
|
@@ -2142,7 +2163,7 @@ function createReadinessProbe(options, ttlMs = READINESS_TTL_MS) {
|
|
|
2142
2163
|
}
|
|
2143
2164
|
|
|
2144
2165
|
// src/gateway/well-known.ts
|
|
2145
|
-
var GATEWAY_SUPPORTED_SPEC = "agent-commerce/v0.
|
|
2166
|
+
var GATEWAY_SUPPORTED_SPEC = "agent-commerce/v0.2.0-beta";
|
|
2146
2167
|
async function buildWellKnownDocument(options) {
|
|
2147
2168
|
const adapters = await Promise.all(
|
|
2148
2169
|
options.adapterRuntimes.map(async (runtime) => ({
|
|
@@ -2172,9 +2193,18 @@ async function buildWellKnownDocument(options) {
|
|
|
2172
2193
|
assetDecimals: x402.assetDecimals,
|
|
2173
2194
|
payTo: x402.payTo,
|
|
2174
2195
|
maxTimeoutSeconds: x402.maxTimeoutSeconds,
|
|
2175
|
-
// Never the signerPrivateKey
|
|
2176
|
-
//
|
|
2177
|
-
|
|
2196
|
+
// Never the signerPrivateKey, and never the facilitator URL:
|
|
2197
|
+
// a facilitator endpoint is a per-deployment operational detail
|
|
2198
|
+
// that can carry a tenant path or an API key, exactly like
|
|
2199
|
+
// `rpcUrl` above. Only whether it is local or remote is public.
|
|
2200
|
+
facilitator: { mode: x402.facilitator.mode },
|
|
2201
|
+
// Chain id 84532 is shared between the local dev chain and
|
|
2202
|
+
// public Base Sepolia, so the network id alone cannot say which
|
|
2203
|
+
// one a client is talking to. This can.
|
|
2204
|
+
mode: resolveDeploymentMode(
|
|
2205
|
+
requireNetworkProfile(x402.network, "payments.x402.network"),
|
|
2206
|
+
x402.facilitator.mode
|
|
2207
|
+
)
|
|
2178
2208
|
}
|
|
2179
2209
|
} : {}
|
|
2180
2210
|
}
|
|
@@ -2309,7 +2339,12 @@ async function handleInvoke(request, reply, options) {
|
|
|
2309
2339
|
};
|
|
2310
2340
|
const outcome = await options.pipeline.execute(canonicalRequest);
|
|
2311
2341
|
if (outcome.kind === "payment-required") {
|
|
2312
|
-
|
|
2342
|
+
const envelope = toPaymentRequiredEnvelope(outcome);
|
|
2343
|
+
if (envelope.payment.envelope !== void 0) {
|
|
2344
|
+
reply.header(PAYMENT_REQUIRED_HEADER, encodeHeaderDocument(envelope.payment.envelope));
|
|
2345
|
+
}
|
|
2346
|
+
reply.header("cache-control", "no-store");
|
|
2347
|
+
reply.status(402).send(envelope);
|
|
2313
2348
|
return;
|
|
2314
2349
|
}
|
|
2315
2350
|
if (outcome.payment) {
|
|
@@ -2329,7 +2364,7 @@ function errorPaymentSummary(error) {
|
|
|
2329
2364
|
const payment = error.details?.["payment"];
|
|
2330
2365
|
if (typeof payment !== "object" || payment === null) return void 0;
|
|
2331
2366
|
const rec = payment;
|
|
2332
|
-
const { status, provider, amount, currency, externalReference } = rec;
|
|
2367
|
+
const { status, provider, amount, currency, network, externalReference } = rec;
|
|
2333
2368
|
if (typeof status !== "string" || typeof provider !== "string" || typeof amount !== "string" || typeof currency !== "string") {
|
|
2334
2369
|
return void 0;
|
|
2335
2370
|
}
|
|
@@ -2338,18 +2373,24 @@ function errorPaymentSummary(error) {
|
|
|
2338
2373
|
provider,
|
|
2339
2374
|
amount,
|
|
2340
2375
|
currency,
|
|
2376
|
+
...typeof network === "string" ? { network } : {},
|
|
2341
2377
|
...typeof externalReference === "string" ? { externalReference } : {}
|
|
2342
2378
|
};
|
|
2343
2379
|
}
|
|
2380
|
+
function encodeHeaderDocument(document) {
|
|
2381
|
+
return Buffer.from(JSON.stringify(document), "utf8").toString("base64");
|
|
2382
|
+
}
|
|
2344
2383
|
function encodePaymentSummary(payment) {
|
|
2345
|
-
|
|
2384
|
+
return encodeHeaderDocument({
|
|
2385
|
+
success: payment.status === "settled",
|
|
2386
|
+
transaction: payment.externalReference ?? "",
|
|
2387
|
+
network: payment.network ?? "",
|
|
2346
2388
|
status: payment.status,
|
|
2347
2389
|
provider: payment.provider,
|
|
2348
2390
|
amount: payment.amount,
|
|
2349
2391
|
currency: payment.currency,
|
|
2350
2392
|
...payment.externalReference !== void 0 ? { externalReference: payment.externalReference } : {}
|
|
2351
|
-
};
|
|
2352
|
-
return Buffer.from(JSON.stringify(summary), "utf8").toString("base64");
|
|
2393
|
+
});
|
|
2353
2394
|
}
|
|
2354
2395
|
function parseLimit(value) {
|
|
2355
2396
|
if (Array.isArray(value)) return parseLimit(value[0]);
|