@devlab.group/agent-commerce 1.4.1 → 1.5.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 +111 -128
- package/dist/ap2.d.ts +5 -5
- package/dist/ap2.js +19 -11
- package/dist/ap2.js.map +1 -1
- package/dist/{authorization-CPDcpJVa.d.ts → authorization-DA7mjy_O.d.ts} +4 -4
- package/dist/{chunk-ZEGFLRGV.js → chunk-5GEWKNIH.js} +5 -4
- package/dist/chunk-5GEWKNIH.js.map +1 -0
- package/dist/chunk-6D2EZ5ME.js +27 -0
- package/dist/chunk-6D2EZ5ME.js.map +1 -0
- package/dist/chunk-NKNXVDHN.js +701 -0
- package/dist/chunk-NKNXVDHN.js.map +1 -0
- package/dist/{chunk-NWIQLJNU.js → chunk-PBYN7EK2.js} +33 -31
- package/dist/chunk-PBYN7EK2.js.map +1 -0
- package/dist/{chunk-GF6KHHKL.js → chunk-US622BKF.js} +3 -3
- package/dist/{chunk-GF6KHHKL.js.map → chunk-US622BKF.js.map} +1 -1
- package/dist/cli/index.js +339 -107
- package/dist/cli/index.js.map +1 -1
- package/dist/constants-6mypC60h.d.ts +50 -0
- package/dist/index.d.ts +26 -11
- package/dist/index.js +189 -36
- package/dist/index.js.map +1 -1
- package/dist/mcp.d.ts +3 -3
- package/dist/mcp.js +4 -1
- package/dist/mcp.js.map +1 -1
- package/dist/mpp.d.ts +50 -0
- package/dist/mpp.js +351 -0
- package/dist/mpp.js.map +1 -0
- package/dist/{protocol-adapter-Bebmggf_.d.ts → protocol-adapter-APRjs1E2.d.ts} +2 -2
- package/dist/{runtime-CKq3d_3K.d.ts → runtime-DC5XQ9Cc.d.ts} +24 -13
- package/dist/x402.d.ts +1 -1
- package/dist/x402.js +7 -688
- package/dist/x402.js.map +1 -1
- package/package.json +13 -2
- package/dist/chunk-NWIQLJNU.js.map +0 -1
- package/dist/chunk-ZEGFLRGV.js.map +0 -1
package/README.md
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
<h1 align="center">Agent Commerce Gateway</h1>
|
|
2
2
|
|
|
3
3
|
<p align="center">
|
|
4
|
-
<strong>One backend.
|
|
4
|
+
<strong>One backend. Multiple agent-commerce protocols. Self-hosted and non-custodial.</strong>
|
|
5
5
|
</p>
|
|
6
6
|
|
|
7
7
|
<p align="center">
|
|
@@ -10,6 +10,7 @@
|
|
|
10
10
|
<img alt="TypeScript" src="https://img.shields.io/badge/TypeScript-strict-3178c6">
|
|
11
11
|
<img alt="MCP" src="https://img.shields.io/badge/MCP-supported-6b4fbb">
|
|
12
12
|
<img alt="x402" src="https://img.shields.io/badge/x402-supported-0052ff">
|
|
13
|
+
<img alt="MPP" src="https://img.shields.io/badge/MPP-experimental-f0a30a">
|
|
13
14
|
<img alt="A2A" src="https://img.shields.io/badge/A2A-experimental-f0a30a">
|
|
14
15
|
<img alt="ACP" src="https://img.shields.io/badge/ACP-experimental-f0a30a">
|
|
15
16
|
<img alt="AP2" src="https://img.shields.io/badge/AP2-experimental-f0a30a">
|
|
@@ -17,21 +18,19 @@
|
|
|
17
18
|
|
|
18
19
|
## What it is, in ten seconds
|
|
19
20
|
|
|
20
|
-
You already have an HTTP API. AI agents
|
|
21
|
-
|
|
21
|
+
You already have an HTTP API. Agent Commerce Gateway lets AI agents discover,
|
|
22
|
+
call and pay for it without adding those protocols to your backend.
|
|
22
23
|
|
|
23
|
-
|
|
24
|
-
|
|
25
|
-
|
|
26
|
-
|
|
27
|
-
|
|
28
|
-
|
|
29
|
-
behind the agent approved that exact purchase. The money goes straight to your
|
|
30
|
-
wallet - the gateway never holds it, and never holds your keys.
|
|
24
|
+
Run the gateway in your infrastructure and describe each endpoint in YAML, or
|
|
25
|
+
generate draft resource definitions from OpenAPI. Resources can be exposed over
|
|
26
|
+
HTTP, MCP or experimental A2A; dedicated resources can implement experimental
|
|
27
|
+
ACP checkout operations. Paid resources use x402 or experimental MPP and can
|
|
28
|
+
also require an AP2 mandate proving that the buyer approved the purchase. Funds
|
|
29
|
+
go directly to the merchant wallet; the gateway never holds them or your keys.
|
|
31
30
|
|
|
32
31
|
```text
|
|
33
32
|
Your existing API → Agent Commerce Gateway → AI Agent
|
|
34
|
-
|
|
33
|
+
MCP · A2A · ACP · x402 · MPP · AP2 · receipts · doctor
|
|
35
34
|
```
|
|
36
35
|
|
|
37
36
|
## Demo
|
|
@@ -68,21 +67,18 @@ npm install -g @devlab.group/agent-commerce # or install the `agent-commerce` bi
|
|
|
68
67
|
agent-commerce doctor
|
|
69
68
|
```
|
|
70
69
|
|
|
71
|
-
Requires **Node >= 22**.
|
|
72
|
-
|
|
73
|
-
|
|
74
|
-
|
|
75
|
-
|
|
76
|
-
onboarding an existing API is the CLI's main job.
|
|
70
|
+
Requires **Node >= 22**. The package includes the `agent-commerce` CLI
|
|
71
|
+
(`init`, `validate`, `doctor`, `demo`) and a library for embedding the gateway.
|
|
72
|
+
The default install excludes optional protocol, payment and authorization
|
|
73
|
+
peers. The OpenAPI parser is a regular dependency because import is part of the
|
|
74
|
+
CLI.
|
|
77
75
|
|
|
78
76
|
```ts
|
|
79
77
|
import { createGateway, loadConfig, receipts } from '@devlab.group/agent-commerce';
|
|
80
78
|
|
|
81
79
|
const config = await loadConfig({ path: 'config.yaml' });
|
|
82
80
|
const store = receipts({ path: './receipts.sqlite' });
|
|
83
|
-
//
|
|
84
|
-
// for the SQLite one this is where a schema written by a newer version is
|
|
85
|
-
// caught, at boot rather than at the first query
|
|
81
|
+
// Initialize before use so an incompatible SQLite schema fails at startup
|
|
86
82
|
await store.init();
|
|
87
83
|
|
|
88
84
|
const gateway = await createGateway({
|
|
@@ -94,21 +90,23 @@ const gateway = await createGateway({
|
|
|
94
90
|
const { url } = await gateway.listen();
|
|
95
91
|
```
|
|
96
92
|
|
|
97
|
-
### Optional peers
|
|
93
|
+
### Optional peers
|
|
98
94
|
|
|
99
|
-
|
|
100
|
-
|
|
101
|
-
the x402 rail brings the whole EVM signing and RPC stack, which a gateway
|
|
102
|
-
serving a free HTTP resource has no business installing.
|
|
95
|
+
Components with extra dependencies use separate subpaths, so a gateway serving
|
|
96
|
+
free HTTP resources does not install MCP, EVM, JOSE or SD-JWT packages.
|
|
103
97
|
|
|
104
98
|
| You want | Install | Import |
|
|
105
99
|
| --------------------------------------- | ---------------------------------- | ------------------------------------------ |
|
|
106
100
|
| gateway, config, receipts, CLI | `@devlab.group/agent-commerce` | `from '@devlab.group/agent-commerce'` |
|
|
107
101
|
| expose resources as MCP tools | `+ @modelcontextprotocol/sdk` | `from '@devlab.group/agent-commerce/mcp'` |
|
|
108
102
|
| accept x402 payments | `+ @x402/core @x402/evm viem` | `from '@devlab.group/agent-commerce/x402'` |
|
|
103
|
+
| accept MPP payments | `+ mppx viem @x402/core @x402/evm` | `from '@devlab.group/agent-commerce/mpp'` |
|
|
109
104
|
| verify AP2 mandates, sign checkout JWTs | `+ jose @sd-jwt/core canonicalize` | `from '@devlab.group/agent-commerce/ap2'` |
|
|
110
105
|
| authenticate to a CDP facilitator | `+ @coinbase/x402` | (no import - loaded on demand) |
|
|
111
106
|
|
|
107
|
+
MPP settles through an x402 facilitator, so its entry also needs the x402
|
|
108
|
+
peers.
|
|
109
|
+
|
|
112
110
|
```bash
|
|
113
111
|
npm install @devlab.group/agent-commerce @modelcontextprotocol/sdk @x402/core @x402/evm viem
|
|
114
112
|
```
|
|
@@ -119,23 +117,17 @@ import { x402 } from '@devlab.group/agent-commerce/x402';
|
|
|
119
117
|
import { ap2 } from '@devlab.group/agent-commerce/ap2';
|
|
120
118
|
```
|
|
121
119
|
|
|
122
|
-
|
|
123
|
-
|
|
124
|
-
deployment that gates nothing on a mandate should not carry a JOSE stack and an
|
|
125
|
-
SD-JWT parser to serve a resource.
|
|
120
|
+
AP2 peers remain optional because a deployment without mandate-gated resources
|
|
121
|
+
does not need JOSE or SD-JWT support.
|
|
126
122
|
|
|
127
123
|
Peers are pinned exactly: x402's schemas and EIP-712 domains cross this
|
|
128
124
|
boundary, so a version skew is a correctness problem rather than a convenience
|
|
129
|
-
one.
|
|
130
|
-
|
|
131
|
-
rather than starting a gateway that silently serves nothing.
|
|
125
|
+
one. Importing a subpath without its peer fails at load time and names the
|
|
126
|
+
missing package.
|
|
132
127
|
|
|
133
|
-
`@coinbase/x402`
|
|
134
|
-
|
|
135
|
-
|
|
136
|
-
high-severity advisories, while the package itself and the other three peers
|
|
137
|
-
audit clean. `auth.type: bearer` covers any facilitator with a static token and
|
|
138
|
-
installs nothing.
|
|
128
|
+
`@coinbase/x402` has no subpath import. It is loaded dynamically only for
|
|
129
|
+
`facilitator.auth.type: cdp` and brings the larger CDP dependency tree. A
|
|
130
|
+
facilitator with a static token can use `auth.type: bearer` without it.
|
|
139
131
|
|
|
140
132
|
## Quickstart
|
|
141
133
|
|
|
@@ -155,15 +147,13 @@ npm run agent-commerce -- doctor --config config-demo.yaml # verify the whole st
|
|
|
155
147
|
npm run demo:agent # watch an agent buy something
|
|
156
148
|
```
|
|
157
149
|
|
|
158
|
-
<sub><b>Linux
|
|
159
|
-
<code>
|
|
160
|
-
|
|
161
|
-
|
|
162
|
-
Desktop on macOS and Windows translates permissions through its VM and does not
|
|
163
|
-
need this.</sub>
|
|
150
|
+
<sub><b>Linux:</b> if your UID/GID is not 1000, export
|
|
151
|
+
<code>DOCKER_UID=$(id -u) DOCKER_GID=$(id -g)</code> before
|
|
152
|
+
<code>docker compose up</code>. This keeps the generated deployment manifest
|
|
153
|
+
host-writable. Docker Desktop does not need this.</sub>
|
|
164
154
|
|
|
165
|
-
|
|
166
|
-
|
|
155
|
+
The disposable local stack includes Anvil, MockUSDC, a demo merchant API, the
|
|
156
|
+
gateway and a dashboard.
|
|
167
157
|
|
|
168
158
|
To stop and wipe state: `docker compose down -v`.
|
|
169
159
|
|
|
@@ -174,7 +164,7 @@ To stop and wipe state: `docker compose down -v`.
|
|
|
174
164
|
│ AI Agent │
|
|
175
165
|
└───────────────────────────────────────┬──────────────────────────────────────┘
|
|
176
166
|
│ MCP · A2A · ACP · HTTP
|
|
177
|
-
│
|
|
167
|
+
│ payment proof
|
|
178
168
|
│ Agent-Authorization
|
|
179
169
|
┌───────────────────────────────────────▼──────────────────────────────────────┐
|
|
180
170
|
│ Agent Commerce Gateway (yours) │
|
|
@@ -184,7 +174,7 @@ To stop and wipe state: `docker compose down -v`.
|
|
|
184
174
|
│ ┌────────────────────┬──────────────┴──┬────────────────┐ │
|
|
185
175
|
│ ▼ ▼ ▼ ▼ │
|
|
186
176
|
│ AuthorizationProvider PaymentProvider BackendExecutor ReceiptStore │
|
|
187
|
-
│ (ap2)
|
|
177
|
+
│ (ap2) (x402, mpp) (bounded HTTP) (SQLite) │
|
|
188
178
|
└───────────────────────────────────────┬──────────────────────────────────────┘
|
|
189
179
|
│
|
|
190
180
|
┌──────────▼─────────┐
|
|
@@ -192,11 +182,10 @@ To stop and wipe state: `docker compose down -v`.
|
|
|
192
182
|
└────────────────────┘
|
|
193
183
|
```
|
|
194
184
|
|
|
195
|
-
Every protocol adapter
|
|
196
|
-
|
|
197
|
-
|
|
198
|
-
|
|
199
|
-
Full detail in [docs/architecture.md](docs/architecture.md).
|
|
185
|
+
Every protocol adapter uses one execution pipeline, so payment enforcement does
|
|
186
|
+
not depend on the adapter. The buyer pays the merchant directly on-chain; the
|
|
187
|
+
gateway holds neither the funds nor a buyer or merchant key. See
|
|
188
|
+
[Architecture](docs/architecture.md).
|
|
200
189
|
|
|
201
190
|
## Configure a resource
|
|
202
191
|
|
|
@@ -231,57 +220,56 @@ Already have an OpenAPI description? Generate the resources from it
|
|
|
231
220
|
agent-commerce import openapi ./openapi.yaml
|
|
232
221
|
```
|
|
233
222
|
|
|
234
|
-
It writes a reviewable `resources:` fragment
|
|
235
|
-
|
|
236
|
-
|
|
237
|
-
|
|
238
|
-
imported. See [OpenAPI import](docs/openapi-import.md) for the exact supported subset.
|
|
223
|
+
It writes a reviewable `resources:` fragment with path, query and JSON body
|
|
224
|
+
bindings and supported schemas. It omits `pricing`, `expose` and credentials;
|
|
225
|
+
the source document cannot decide price or exposure. See
|
|
226
|
+
[OpenAPI import](docs/openapi-import.md) for the supported subset.
|
|
239
227
|
|
|
240
228
|
See [docs/configuration.md](docs/configuration.md).
|
|
241
229
|
|
|
242
230
|
## Protocol support
|
|
243
231
|
|
|
244
|
-
| Protocol
|
|
245
|
-
|
|
|
246
|
-
| **
|
|
247
|
-
| **
|
|
248
|
-
| **
|
|
249
|
-
| **
|
|
250
|
-
| **
|
|
251
|
-
| **
|
|
252
|
-
|
|
|
253
|
-
|
|
254
|
-
|
|
255
|
-
method
|
|
256
|
-
|
|
257
|
-
|
|
258
|
-
|
|
259
|
-
|
|
260
|
-
|
|
261
|
-
|
|
262
|
-
|
|
263
|
-
|
|
264
|
-
|
|
265
|
-
|
|
266
|
-
|
|
267
|
-
|
|
268
|
-
|
|
269
|
-
list at runtime through `GET /.well-known/agent-commerce` and
|
|
270
|
-
`agent-commerce doctor`, so the claim is checkable rather than marketing.
|
|
232
|
+
| Protocol | Status | Pinned revision |
|
|
233
|
+
| -------- | ------------ | ------------------------------------------------------------------------- |
|
|
234
|
+
| **HTTP** | Supported | native routes |
|
|
235
|
+
| **MCP** | Supported | `@modelcontextprotocol/sdk@1.30.0` |
|
|
236
|
+
| **x402** | Supported | x402 v2 (`@x402/core`, `@x402/evm`), scheme `exact`, EVM |
|
|
237
|
+
| **MPP** | Experimental | `mppx@0.10.1`, `charge` + `evm` + EIP-3009, USDC on Base Sepolia and Base |
|
|
238
|
+
| **A2A** | Experimental | A2A v1.0.0, binding `JSONRPC`, method `SendMessage` |
|
|
239
|
+
| **ACP** | Experimental | ACP `2026-04-17`, REST checkout + discovery |
|
|
240
|
+
| **AP2** | Experimental | AP2 `v0.2.0`, Direct Checkout Mandate verification |
|
|
241
|
+
| UCP | Planned | no implementation |
|
|
242
|
+
|
|
243
|
+
[AP2](docs/ap2.md) is an authorization method, not a transport. It verifies a
|
|
244
|
+
mandate before a paid resource settles; the gateway does not issue the mandate
|
|
245
|
+
or its Checkout Receipt.
|
|
246
|
+
|
|
247
|
+
The experimental entries above ship off by default with documented subsets:
|
|
248
|
+
[A2A](docs/protocols.md#a2a), [ACP](docs/protocols.md#acp),
|
|
249
|
+
[AP2](docs/ap2.md#not-implemented) and [MPP](docs/protocols.md#mpp). Supported
|
|
250
|
+
[MCP](docs/protocols.md#mcp) and [x402](docs/protocols.md#x402) are also scoped.
|
|
251
|
+
ACP exposes only its five checkout operations; merchant `payment_data` is never
|
|
252
|
+
converted into a gateway payment proof.
|
|
253
|
+
|
|
254
|
+
`GET /.well-known/agent-commerce` reports `supportedSpec`, `capabilities` and
|
|
255
|
+
`unsupported` for registered adapters and providers. `agent-commerce doctor`
|
|
256
|
+
prints the `unsupported` lists for A2A, ACP and AP2.
|
|
271
257
|
|
|
272
258
|
## Payment model
|
|
273
259
|
|
|
274
260
|
- **Non-custodial.** The gateway never holds funds, and never asks for a
|
|
275
261
|
merchant or buyer private key. `payTo` is your address.
|
|
276
262
|
- **Fail closed.** Missing, malformed, expired, replayed, wrong-amount,
|
|
277
|
-
wrong-recipient, wrong-network and wrong-asset payments
|
|
278
|
-
test.
|
|
263
|
+
wrong-recipient, wrong-network and wrong-asset payments are rejected.
|
|
279
264
|
- **Replay-safe twice over.** EIP-3009 stops a double spend on-chain; the
|
|
280
265
|
gateway additionally reserves a `replayKey` derived from the authorisation
|
|
281
266
|
before it settles anything.
|
|
282
|
-
- **
|
|
267
|
+
- **On-chain settlement in CI.** The end-to-end test asserts the buyer's balance
|
|
283
268
|
falls and the merchant's rises by exactly the price, with a real transaction
|
|
284
269
|
hash in the receipt. A log line saying "payment successful" would not count.
|
|
270
|
+
- **One selected rail per resource.** A resource can name several rails, such as
|
|
271
|
+
`payments: [x402, mpp]`; the first enabled one serves it, and nothing selects
|
|
272
|
+
or falls back between rails per request.
|
|
285
273
|
- **Authorization is separate from payment.** A resource can also require an
|
|
286
274
|
AP2 mandate, verified before settlement and spendable exactly once. It never
|
|
287
275
|
moves money and never unlocks a resource on its own - the payment still has
|
|
@@ -294,19 +282,20 @@ not this process. No code changes, and no "live mode" to switch on.
|
|
|
294
282
|
|
|
295
283
|
### It has actually settled
|
|
296
284
|
|
|
297
|
-
|
|
298
|
-
|
|
285
|
+
These transactions each moved 0.01 USDC from a buyer to a merchant through a
|
|
286
|
+
remote facilitator:
|
|
299
287
|
|
|
300
|
-
| Network | Transaction |
|
|
301
|
-
| ------------ | --------------------------------------------------------------------------------------------------------------------- |
|
|
302
|
-
| Base Sepolia | [`0xea41b234c4…`](https://sepolia.basescan.org/tx/0xea41b234c4645a4d335589ec9753646aa7cccd1b97e9e15823b88bff7b54a247) |
|
|
303
|
-
| Base | [`0x57ec81c2a3…`](https://basescan.org/tx/0x57ec81c2a360d14d59a43cf4e24be09a6bd75cbe6185016372895bda73e42763) |
|
|
288
|
+
| Rail | Network | Transaction |
|
|
289
|
+
| ---- | ------------ | --------------------------------------------------------------------------------------------------------------------- |
|
|
290
|
+
| x402 | Base Sepolia | [`0xea41b234c4…`](https://sepolia.basescan.org/tx/0xea41b234c4645a4d335589ec9753646aa7cccd1b97e9e15823b88bff7b54a247) |
|
|
291
|
+
| x402 | Base | [`0x57ec81c2a3…`](https://basescan.org/tx/0x57ec81c2a360d14d59a43cf4e24be09a6bd75cbe6185016372895bda73e42763) |
|
|
292
|
+
| MPP | Base Sepolia | [`0x5d9fcd111b…`](https://sepolia.basescan.org/tx/0x5d9fcd111b615bb8fc9e56d55096f119fc81c3c72c334f813cfaecee402d0ac3) |
|
|
293
|
+
| MPP | Base | [`0xf4255bd7ec…`](https://basescan.org/tx/0xf4255bd7ec46ed06505dedfb5f9537924bd2633816e7952ec6f2b468395b1087) |
|
|
304
294
|
|
|
305
|
-
|
|
306
|
-
|
|
307
|
-
|
|
308
|
-
|
|
309
|
-
success is not the proof.
|
|
295
|
+
The buyer signed each EIP-3009 authorisation without ETH; the remote facilitator
|
|
296
|
+
paid gas and broadcast it. The gateway path received no buyer or merchant key.
|
|
297
|
+
The public-network smoke suites verify balance changes and fetch the transaction
|
|
298
|
+
receipt from the chain instead of trusting the gateway's response.
|
|
310
299
|
|
|
311
300
|
Reproduce with `npm run test:testnet` / `npm run test:mainnet` - both spend
|
|
312
301
|
real funds, skip themselves without credentials, and never run in CI.
|
|
@@ -322,17 +311,14 @@ gateway on a public network.
|
|
|
322
311
|
| `local` | this process, with an Anvil dev key | the local dev chain only |
|
|
323
312
|
| `remote` | an HTTP facilitator you point at | anywhere |
|
|
324
313
|
|
|
325
|
-
With `remote`, the gateway holds
|
|
326
|
-
EIP-3009 authorisation
|
|
327
|
-
|
|
328
|
-
|
|
329
|
-
nothing. What it can do is see every authorisation you handle, and stop
|
|
330
|
-
answering.
|
|
314
|
+
With `remote`, the gateway holds no facilitator signing key. The buyer signs an
|
|
315
|
+
EIP-3009 authorisation without ETH, and the facilitator pays gas. Because the
|
|
316
|
+
authorisation fixes the recipient, amount and chain, the facilitator cannot
|
|
317
|
+
redirect the transfer. It can see authorisations and refuse service.
|
|
331
318
|
|
|
332
|
-
|
|
333
|
-
|
|
334
|
-
|
|
335
|
-
own - `remote` does not care who operates the endpoint.
|
|
319
|
+
Remote facilitator auth supports `none`, `bearer` and `cdp`. CDP signs a fresh
|
|
320
|
+
JWT per request and conditionally loads `@coinbase/x402`; bearer auth needs no
|
|
321
|
+
extra peer. Other types are rejected at config load.
|
|
336
322
|
|
|
337
323
|
### Base Sepolia
|
|
338
324
|
|
|
@@ -366,8 +352,7 @@ together, and reported by `doctor`, `health()` and `/.well-known`.
|
|
|
366
352
|
|
|
367
353
|
### Base mainnet
|
|
368
354
|
|
|
369
|
-
|
|
370
|
-
load, and the gateway will not start without them:
|
|
355
|
+
Mainnet moves real funds. Config validation requires:
|
|
371
356
|
|
|
372
357
|
| Required | |
|
|
373
358
|
| ----------------------------------------------- | -------------------------------------------------------------------------------------------------------------- |
|
|
@@ -375,13 +360,13 @@ load, and the gateway will not start without them:
|
|
|
375
360
|
| `facilitator.mode: remote` | `local` needs a funded gas key inside this process |
|
|
376
361
|
| an HTTPS `facilitator.url` | |
|
|
377
362
|
| `allowUnauthenticatedFacilitator: true` | only if that facilitator takes no credential |
|
|
378
|
-
| a non-development `payTo`
|
|
379
|
-
|
|
|
363
|
+
| a non-development destination (`payTo` or `recipient`) | |
|
|
364
|
+
| Base USDC with `assetName: "USD Coin"` and `assetVersion: "2"` | the buyer signs this EIP-712 domain; `"USDC"` is wrong on Base |
|
|
380
365
|
|
|
381
366
|
Full config in [`examples/base-mainnet/`](examples/base-mainnet/), and
|
|
382
367
|
[`examples/base-mainnet-payai/`](examples/base-mainnet-payai/) for an
|
|
383
|
-
unauthenticated facilitator.
|
|
384
|
-
|
|
368
|
+
unauthenticated facilitator. The mainnet smoke suites cover x402 and MPP and
|
|
369
|
+
spend real USDC when their opt-ins and credentials are present.
|
|
385
370
|
|
|
386
371
|
`agent-commerce validate` reports any of the above before anything starts, and
|
|
387
372
|
`doctor` prints `LIVE MAINNET MODE - REAL FUNDS`.
|
|
@@ -404,17 +389,15 @@ INFO A2A disabled
|
|
|
404
389
|
INFO ACP disabled
|
|
405
390
|
INFO AP2 disabled
|
|
406
391
|
PASS Payments x402 v2 (scheme=exact) enabled - LOCAL dev chain (eip155:84532, chain id shared with Base Sepolia), destination=0x7099…79C8, facilitator=local
|
|
407
|
-
INFO Payments (MPP)
|
|
392
|
+
INFO Payments (MPP) MPP not configured
|
|
408
393
|
PASS Storage sqlite schema v1 writable; receipts=2
|
|
409
394
|
PASS Protocol versions reported by gateway /.well-known/agent-commerce
|
|
410
395
|
|
|
411
396
|
Score: 7/7 checks passed
|
|
412
397
|
```
|
|
413
398
|
|
|
414
|
-
|
|
415
|
-
|
|
416
|
-
resolves to, and fails if they disagree - a diagnostic that passes while the
|
|
417
|
-
system is misconfigured is worse than none.
|
|
399
|
+
`doctor` cross-checks the gateway's live settlement configuration against the
|
|
400
|
+
resolved local config and fails if they differ.
|
|
418
401
|
|
|
419
402
|
Exits non-zero if anything fails. `--json` for machines.
|
|
420
403
|
|
|
@@ -452,12 +435,12 @@ See [CONTRIBUTING.md](CONTRIBUTING.md).
|
|
|
452
435
|
**Now** - MCP, x402 v2, settlement on the local chain, Base Sepolia and Base
|
|
453
436
|
mainnet, receipts, doctor, deterministic demo, experimental A2A v1.0.0 and ACP
|
|
454
437
|
`2026-04-17` checkout adapters, experimental AP2 v0.2.0 mandate verification,
|
|
455
|
-
and experimental OpenAPI import.
|
|
438
|
+
experimental MPP `charge` payments, and experimental OpenAPI import.
|
|
456
439
|
|
|
457
|
-
**Next** - a `doctor` GitHub Action · UCP ·
|
|
458
|
-
mandates, agent key binding, constraint evaluation) ·
|
|
459
|
-
delegated payment) · Shopify and WooCommerce examples ·
|
|
460
|
-
observability · multi-file and remote OpenAPI sources.
|
|
440
|
+
**Next** - a `doctor` GitHub Action · UCP ·
|
|
441
|
+
autonomous-mode AP2 (open mandates, agent key binding, constraint evaluation) ·
|
|
442
|
+
more of ACP (carts, feed, delegated payment) · Shopify and WooCommerce examples ·
|
|
443
|
+
PostgreSQL · richer observability · multi-file and remote OpenAPI sources.
|
|
461
444
|
|
|
462
445
|
New protocols land only after the adapter model survives real use. Scope
|
|
463
446
|
discipline is a release requirement, not a mood.
|
|
@@ -467,8 +450,8 @@ discipline is a release requirement, not a mood.
|
|
|
467
450
|
| | |
|
|
468
451
|
| ---------------------------------------------- | ------------------------------------------- |
|
|
469
452
|
| [Architecture](docs/architecture.md) | how the pieces fit |
|
|
470
|
-
| [Payment flow](docs/payment-flow.md) | the paid round trip
|
|
471
|
-
| [Protocols](docs/protocols.md) |
|
|
453
|
+
| [Payment flow](docs/payment-flow.md) | the paid round trip and failure paths |
|
|
454
|
+
| [Protocols](docs/protocols.md) | supported and unsupported protocol features |
|
|
472
455
|
| [AP2](docs/ap2.md) | mandate verification and the trust model |
|
|
473
456
|
| [Configuration](docs/configuration.md) | `config.yaml` reference |
|
|
474
457
|
| [OpenAPI import](docs/openapi-import.md) | generate resources from an existing API |
|
package/dist/ap2.d.ts
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
import { E as EnabledAp2Config } from './types-CJtwLu1c.js';
|
|
2
2
|
export { A as AP2_CHECKOUT_MANDATE_VCT, a as AP2_CHECKOUT_PROFILE, b as AP2_DEFAULT_CLOCK_SKEW_SECONDS, c as AP2_MAX_CLOCK_SKEW_SECONDS, d as AP2_SIGNING_ALGORITHM, e as AP2_SPEC_VERSION, f as Ap2AuthorizationConfig, g as Ap2Mode, h as Ap2TrustedIssuer, i as Ap2TrustedKey } from './types-CJtwLu1c.js';
|
|
3
|
-
import { A as AuthorizationProvider } from './authorization-
|
|
4
|
-
import { C as Clock, L as Logger } from './runtime-
|
|
3
|
+
import { A as AuthorizationProvider } from './authorization-DA7mjy_O.js';
|
|
4
|
+
import { C as Clock, L as Logger } from './runtime-DC5XQ9Cc.js';
|
|
5
5
|
|
|
6
6
|
/**
|
|
7
7
|
* A private ES256 key: either a private JWK (the pair of the public one in the
|
|
@@ -139,8 +139,8 @@ interface Ap2ReplayStore {
|
|
|
139
139
|
* The AP2 authorization provider: the seam between core's generic contract and
|
|
140
140
|
* the mandate machinery.
|
|
141
141
|
*
|
|
142
|
-
*
|
|
143
|
-
*
|
|
142
|
+
* The provider owns its replay store. The caller that creates the provider must
|
|
143
|
+
* call `close()`; `createGateway` does not close authorization providers.
|
|
144
144
|
*/
|
|
145
145
|
|
|
146
146
|
interface Ap2AuthorizationProviderOptions {
|
|
@@ -151,7 +151,7 @@ interface Ap2AuthorizationProviderOptions {
|
|
|
151
151
|
readonly replayStore?: Ap2ReplayStore;
|
|
152
152
|
}
|
|
153
153
|
interface Ap2AuthorizationProvider extends AuthorizationProvider {
|
|
154
|
-
/** Closes the replay
|
|
154
|
+
/** Closes the replay store */
|
|
155
155
|
close(): void;
|
|
156
156
|
}
|
|
157
157
|
/**
|
package/dist/ap2.js
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
|
-
import { AP2_CHECKOUT_MANDATE_VCT, AP2_SIGNING_ALGORITHM, AP2_DIGEST_ALGORITHM, AP2_CHECKOUT_PROFILE, AP2_SPEC_VERSION, AP2_KEY_TYPE, AP2_JWK_CURVE, openSqliteDatabase } from './chunk-
|
|
2
|
-
export { AP2_CHECKOUT_MANDATE_VCT, AP2_CHECKOUT_PROFILE, AP2_DEFAULT_CLOCK_SKEW_SECONDS, AP2_MAX_CLOCK_SKEW_SECONDS, AP2_SIGNING_ALGORITHM, AP2_SPEC_VERSION } from './chunk-
|
|
3
|
-
import { systemClock, NOOP_LOGGER, CommerceError, PACKAGE_VERSION } from './chunk-
|
|
1
|
+
import { AP2_CHECKOUT_MANDATE_VCT, AP2_SIGNING_ALGORITHM, AP2_DIGEST_ALGORITHM, AP2_CHECKOUT_PROFILE, AP2_SPEC_VERSION, AP2_KEY_TYPE, AP2_JWK_CURVE, openSqliteDatabase } from './chunk-US622BKF.js';
|
|
2
|
+
export { AP2_CHECKOUT_MANDATE_VCT, AP2_CHECKOUT_PROFILE, AP2_DEFAULT_CLOCK_SKEW_SECONDS, AP2_MAX_CLOCK_SKEW_SECONDS, AP2_SIGNING_ALGORITHM, AP2_SPEC_VERSION } from './chunk-US622BKF.js';
|
|
3
|
+
import { systemClock, NOOP_LOGGER, CommerceError, PACKAGE_VERSION } from './chunk-5GEWKNIH.js';
|
|
4
4
|
import { SignJWT, importPKCS8, importJWK, jwtVerify } from 'jose';
|
|
5
5
|
import canonicalize from 'canonicalize';
|
|
6
6
|
import { decodeSdJwt, splitSdJwt, getClaims } from '@sd-jwt/core';
|
|
@@ -81,6 +81,15 @@ async function computeInputHash(input) {
|
|
|
81
81
|
const digest = await crypto.subtle.digest("SHA-256", new TextEncoder().encode(canonical));
|
|
82
82
|
return Buffer.from(digest).toString("base64url");
|
|
83
83
|
}
|
|
84
|
+
var EVM_ADDRESS = /^0x[0-9a-f]{40}$/i;
|
|
85
|
+
function sameCoordinate(declared, expected) {
|
|
86
|
+
if (typeof declared === "string" && expected !== void 0) {
|
|
87
|
+
if (EVM_ADDRESS.test(declared) && EVM_ADDRESS.test(expected)) {
|
|
88
|
+
return declared.toLowerCase() === expected.toLowerCase();
|
|
89
|
+
}
|
|
90
|
+
}
|
|
91
|
+
return declared === expected;
|
|
92
|
+
}
|
|
84
93
|
function asRecord(value) {
|
|
85
94
|
return typeof value === "object" && value !== null && !Array.isArray(value) ? value : void 0;
|
|
86
95
|
}
|
|
@@ -115,7 +124,7 @@ async function bindMandateToPurchase(mandate, context, errorContext) {
|
|
|
115
124
|
]) {
|
|
116
125
|
const declared = profile[claim];
|
|
117
126
|
if (declared === void 0 && expected === void 0) continue;
|
|
118
|
-
if (declared
|
|
127
|
+
if (!sameCoordinate(declared, expected)) throw ap2Rejected("purchase_mismatch", errorContext);
|
|
119
128
|
}
|
|
120
129
|
return {
|
|
121
130
|
resourceId: profile["resource_id"],
|
|
@@ -226,7 +235,6 @@ var AP2_UNSUPPORTED = [
|
|
|
226
235
|
"digest algorithms other than sha-256",
|
|
227
236
|
// Roles this gateway does not play
|
|
228
237
|
"mandate issuance",
|
|
229
|
-
"merchant checkout JWT issuance",
|
|
230
238
|
"AP2 over the ACP checkout adapter"
|
|
231
239
|
];
|
|
232
240
|
function buildAp2Descriptor(implementationVersion) {
|
|
@@ -277,17 +285,17 @@ function createAp2ReplayStore(options) {
|
|
|
277
285
|
const reserveTx = db.transaction((request) => {
|
|
278
286
|
const at = new Date(now()).toISOString();
|
|
279
287
|
const existing = selectByReference.get(request.reference);
|
|
280
|
-
if (existing !== void 0) {
|
|
281
|
-
|
|
282
|
-
return { kind: "replayed", state: existing.state };
|
|
283
|
-
}
|
|
284
|
-
reReserve.run({ reference: request.reference, request_id: request.requestId, at });
|
|
285
|
-
return { kind: "reserved" };
|
|
288
|
+
if (existing !== void 0 && existing.state !== "released") {
|
|
289
|
+
return { kind: "replayed", state: existing.state };
|
|
286
290
|
}
|
|
287
291
|
const sameCheckout = selectLiveByJti.get(request.checkoutJti, request.reference);
|
|
288
292
|
if (sameCheckout !== void 0) {
|
|
289
293
|
return { kind: "replayed", state: sameCheckout.state };
|
|
290
294
|
}
|
|
295
|
+
if (existing !== void 0) {
|
|
296
|
+
reReserve.run({ reference: request.reference, request_id: request.requestId, at });
|
|
297
|
+
return { kind: "reserved" };
|
|
298
|
+
}
|
|
291
299
|
insert.run({
|
|
292
300
|
reference: request.reference,
|
|
293
301
|
checkout_jti: request.checkoutJti,
|