@devlab.group/agent-commerce 1.5.0 → 1.6.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 +73 -71
- package/dist/ap2.d.ts +20 -23
- package/dist/ap2.js +53 -75
- package/dist/ap2.js.map +1 -1
- package/dist/authorization-BpbWGGrf.d.ts +115 -0
- package/dist/{chunk-PBYN7EK2.js → chunk-74BSEXB5.js} +10 -9
- package/dist/chunk-74BSEXB5.js.map +1 -0
- package/dist/chunk-AFI2CEZS.js +10 -0
- package/dist/chunk-AFI2CEZS.js.map +1 -0
- package/dist/{chunk-NKNXVDHN.js → chunk-ATTWSFQP.js} +45 -66
- package/dist/chunk-ATTWSFQP.js.map +1 -0
- package/dist/{chunk-5GEWKNIH.js → chunk-IVJC5YLE.js} +63 -27
- package/dist/chunk-IVJC5YLE.js.map +1 -0
- package/dist/{chunk-US622BKF.js → chunk-RAJGPGJG.js} +5 -8
- package/dist/chunk-RAJGPGJG.js.map +1 -0
- package/dist/{chunk-6D2EZ5ME.js → chunk-V2V2E7HX.js} +2 -2
- package/dist/{chunk-6D2EZ5ME.js.map → chunk-V2V2E7HX.js.map} +1 -1
- package/dist/cli/index.js +501 -494
- package/dist/cli/index.js.map +1 -1
- package/dist/{constants-6mypC60h.d.ts → constants-Bkq04FRZ.d.ts} +1 -3
- package/dist/guardrails-71XwtXlT.d.ts +31 -0
- package/dist/index.d.ts +230 -265
- package/dist/index.js +1050 -607
- package/dist/index.js.map +1 -1
- package/dist/mcp.d.ts +6 -59
- package/dist/mcp.js +61 -53
- package/dist/mcp.js.map +1 -1
- package/dist/mpp.d.ts +4 -4
- package/dist/mpp.js +21 -19
- package/dist/mpp.js.map +1 -1
- package/dist/protocol-adapter-DTkrXTev.d.ts +238 -0
- package/dist/runtime-CiYbgGpi.d.ts +303 -0
- package/dist/{types-CJtwLu1c.d.ts → types-O6lg3Q5V.d.ts} +17 -23
- package/dist/x402.d.ts +43 -75
- package/dist/x402.js +10 -9
- package/dist/x402.js.map +1 -1
- package/package.json +1 -1
- package/dist/authorization-DA7mjy_O.d.ts +0 -123
- package/dist/chunk-5GEWKNIH.js.map +0 -1
- package/dist/chunk-NKNXVDHN.js.map +0 -1
- package/dist/chunk-PBYN7EK2.js.map +0 -1
- package/dist/chunk-US622BKF.js.map +0 -1
- package/dist/guardrails-Dmwi63KB.d.ts +0 -38
- package/dist/protocol-adapter-APRjs1E2.d.ts +0 -273
- package/dist/runtime-DC5XQ9Cc.d.ts +0 -351
|
@@ -1,273 +0,0 @@
|
|
|
1
|
-
import { IncomingMessage, ServerResponse } from 'node:http';
|
|
2
|
-
import { I as IsoTimestamp, n as PaymentResult, r as ProtocolName, b as PaymentSubmission, m as PaymentRequirement, A as AdapterDescriptor, R as ResourceRegistry, L as Logger, C as Clock, e as IdGenerator, c as AdapterHealth } from './runtime-DC5XQ9Cc.js';
|
|
3
|
-
import { d as AuthorizationRecord, b as AuthorizationSubmission, a as AuthorizationRequirement } from './authorization-DA7mjy_O.js';
|
|
4
|
-
|
|
5
|
-
/**
|
|
6
|
-
* Canonical commerce events.
|
|
7
|
-
*
|
|
8
|
-
* FROZEN CONTRACT. Every event in a single flow shares one `requestId` so that
|
|
9
|
-
* logs, payment attempts, backend calls and receipts are correlatable.
|
|
10
|
-
*/
|
|
11
|
-
|
|
12
|
-
declare const COMMERCE_EVENT_TYPES: readonly ["resource.discovered", "resource.requested", "payment.required", "payment.rejected", "payment.verified", "payment.settled", "authorization.verified", "authorization.rejected", "backend.called", "backend.failed", "resource.delivered"];
|
|
13
|
-
type CommerceEventType = (typeof COMMERCE_EVENT_TYPES)[number];
|
|
14
|
-
interface CommerceEvent {
|
|
15
|
-
readonly id: string;
|
|
16
|
-
readonly type: CommerceEventType;
|
|
17
|
-
readonly requestId: string;
|
|
18
|
-
readonly resourceId?: string;
|
|
19
|
-
readonly at: IsoTimestamp;
|
|
20
|
-
/** Protocol adapter that originated the request, e.g. 'mcp' or 'http'. */
|
|
21
|
-
readonly adapter?: string;
|
|
22
|
-
readonly paymentProvider?: string;
|
|
23
|
-
readonly durationMs?: number;
|
|
24
|
-
readonly status?: 'ok' | 'error';
|
|
25
|
-
/** Non-secret, structured detail. Must never contain keys, headers or proofs. */
|
|
26
|
-
readonly data?: Readonly<Record<string, unknown>>;
|
|
27
|
-
}
|
|
28
|
-
/**
|
|
29
|
-
* Sink for canonical events.
|
|
30
|
-
*
|
|
31
|
-
* Implementations must be non-throwing from the caller's perspective: an event
|
|
32
|
-
* sink failure must never fail an otherwise successful commerce flow.
|
|
33
|
-
*/
|
|
34
|
-
interface EventSink {
|
|
35
|
-
emit(event: CommerceEvent): Promise<void>;
|
|
36
|
-
}
|
|
37
|
-
|
|
38
|
-
/**
|
|
39
|
-
* Canonical receipt model.
|
|
40
|
-
*
|
|
41
|
-
* FROZEN CONTRACT.
|
|
42
|
-
*/
|
|
43
|
-
|
|
44
|
-
interface CommerceReceipt {
|
|
45
|
-
readonly id: string;
|
|
46
|
-
readonly requestId: string;
|
|
47
|
-
readonly resourceId: string;
|
|
48
|
-
/** Absent for free resources. */
|
|
49
|
-
readonly payment?: PaymentResult;
|
|
50
|
-
/**
|
|
51
|
-
* Present only when the resource required one. A method and a digest, so the
|
|
52
|
-
* receipt records that consent existed without storing the proof of it.
|
|
53
|
-
*/
|
|
54
|
-
readonly authorization?: AuthorizationRecord;
|
|
55
|
-
readonly deliveredAt: IsoTimestamp;
|
|
56
|
-
readonly backendStatus: number;
|
|
57
|
-
readonly durationMs?: number;
|
|
58
|
-
readonly protocol?: string;
|
|
59
|
-
/** Non-secret summary only. Never the full backend body if it is sensitive. */
|
|
60
|
-
readonly metadata?: Readonly<Record<string, unknown>>;
|
|
61
|
-
}
|
|
62
|
-
/** Record of a single payment authorisation seen by the gateway. */
|
|
63
|
-
interface PaymentAttempt {
|
|
64
|
-
readonly id: string;
|
|
65
|
-
readonly requestId: string;
|
|
66
|
-
readonly resourceId: string;
|
|
67
|
-
readonly provider: string;
|
|
68
|
-
/** See PaymentResult.replayKey — unique across the store. */
|
|
69
|
-
readonly replayKey: string;
|
|
70
|
-
/**
|
|
71
|
-
* State of the authorisation, as far as the gateway can prove it.
|
|
72
|
-
*
|
|
73
|
-
* `settlement-uncertain` is deliberately distinct from `failed`: the
|
|
74
|
-
* settlement was attempted and no verdict came back (RPC timeout, dropped
|
|
75
|
-
* connection, a facilitator that accepted the transfer and then lost the
|
|
76
|
-
* response). "The facilitator did not answer" and "the transfer did not
|
|
77
|
-
* happen" are different facts, and recording the first as the second makes
|
|
78
|
-
* the merchant's reconciliation artefact wrong in exactly the case where
|
|
79
|
-
* reconciliation matters. `externalReference` carries the broadcast
|
|
80
|
-
* transaction hash when one is known, which is often not: the response
|
|
81
|
-
* that would have carried it is usually the thing that went missing. An
|
|
82
|
-
* attempt in this state is unresolved rather than terminal, and needs
|
|
83
|
-
* evidence from the chain, not a retry.
|
|
84
|
-
*
|
|
85
|
-
* `failed` is no longer written by the execution pipeline, because a throw
|
|
86
|
-
* out of settle() is never proof that nothing moved. It stays in the union
|
|
87
|
-
* because existing databases hold rows recorded under the old reading.
|
|
88
|
-
*/
|
|
89
|
-
readonly status: 'reserved' | 'verified' | 'settled' | 'rejected' | 'failed' | 'settlement-uncertain';
|
|
90
|
-
readonly amount: string;
|
|
91
|
-
readonly currency: string;
|
|
92
|
-
readonly payer?: string;
|
|
93
|
-
readonly payee?: string;
|
|
94
|
-
readonly externalReference?: string;
|
|
95
|
-
readonly rejectionReason?: string;
|
|
96
|
-
readonly createdAt: IsoTimestamp;
|
|
97
|
-
readonly updatedAt: IsoTimestamp;
|
|
98
|
-
}
|
|
99
|
-
|
|
100
|
-
/**
|
|
101
|
-
* Canonical request/response model for the execution pipeline.
|
|
102
|
-
*
|
|
103
|
-
* FROZEN CONTRACT. Protocol adapters normalise into `CanonicalRequest` and map
|
|
104
|
-
* `ExecutionOutcome` (or a thrown `CommerceError`) back into their own wire
|
|
105
|
-
* format. Adapters must never call merchant backends directly.
|
|
106
|
-
*/
|
|
107
|
-
|
|
108
|
-
interface CanonicalRequest {
|
|
109
|
-
/** Correlation id for the entire flow. Generated by the protocol adapter. */
|
|
110
|
-
readonly requestId: string;
|
|
111
|
-
readonly resourceId: string;
|
|
112
|
-
/** Raw, unvalidated resource input. Validated against the resource schema. */
|
|
113
|
-
readonly input: unknown;
|
|
114
|
-
readonly protocol: ProtocolName;
|
|
115
|
-
/** Payment proof, when the client is retrying after a challenge. */
|
|
116
|
-
readonly payment?: PaymentSubmission;
|
|
117
|
-
/**
|
|
118
|
-
* Authorization proof, when the resource requires one. Independent of
|
|
119
|
-
* `payment`: neither substitutes for the other, and a resource requiring
|
|
120
|
-
* authorization needs both.
|
|
121
|
-
*/
|
|
122
|
-
readonly authorization?: AuthorizationSubmission;
|
|
123
|
-
readonly receivedAt: IsoTimestamp;
|
|
124
|
-
/**
|
|
125
|
-
* Stable name for the side-effecting operation this request performs, when
|
|
126
|
-
* the protocol has one. Carried through to `BackendRequest` so the merchant
|
|
127
|
-
* can recognise a retry as the same operation. Never `requestId`, which is
|
|
128
|
-
* new on every call.
|
|
129
|
-
*/
|
|
130
|
-
readonly idempotencyKey?: string;
|
|
131
|
-
/** Non-secret transport metadata (client id, user agent, …). */
|
|
132
|
-
readonly metadata?: Readonly<Record<string, unknown>>;
|
|
133
|
-
}
|
|
134
|
-
/** Successful delivery of a resource. */
|
|
135
|
-
interface DeliveredOutcome {
|
|
136
|
-
readonly kind: 'delivered';
|
|
137
|
-
readonly requestId: string;
|
|
138
|
-
readonly resourceId: string;
|
|
139
|
-
readonly backendStatus: number;
|
|
140
|
-
readonly body: unknown;
|
|
141
|
-
readonly headers?: Readonly<Record<string, string>>;
|
|
142
|
-
readonly payment?: PaymentResult;
|
|
143
|
-
readonly receipt: CommerceReceipt;
|
|
144
|
-
readonly durationMs: number;
|
|
145
|
-
}
|
|
146
|
-
/** The resource costs money and no acceptable proof was supplied. */
|
|
147
|
-
interface PaymentRequiredOutcome {
|
|
148
|
-
readonly kind: 'payment-required';
|
|
149
|
-
readonly requestId: string;
|
|
150
|
-
readonly resourceId: string;
|
|
151
|
-
readonly requirement: PaymentRequirement;
|
|
152
|
-
/**
|
|
153
|
-
* Authorization the buyer must also present on the retry, when the resource
|
|
154
|
-
* requires one. Absent for the ordinary paid resource.
|
|
155
|
-
*/
|
|
156
|
-
readonly authorization?: readonly AuthorizationRequirement[];
|
|
157
|
-
}
|
|
158
|
-
/**
|
|
159
|
-
* Result of a pipeline execution.
|
|
160
|
-
*
|
|
161
|
-
* Every other condition (unknown resource, invalid input, rejected payment,
|
|
162
|
-
* backend failure, storage failure) is signalled by throwing a `CommerceError`.
|
|
163
|
-
*/
|
|
164
|
-
type ExecutionOutcome = DeliveredOutcome | PaymentRequiredOutcome;
|
|
165
|
-
/**
|
|
166
|
-
* The single execution path every protocol adapter converges on.
|
|
167
|
-
*
|
|
168
|
-
* NOTE — two different signalling styles, deliberately:
|
|
169
|
-
*
|
|
170
|
-
* - `payment-required` is a normal RETURN VALUE (`PaymentRequiredOutcome`).
|
|
171
|
-
* It is an expected step in the protocol, not a failure: the caller is
|
|
172
|
-
* meant to read the challenge and retry with a proof.
|
|
173
|
-
* - Everything else that goes wrong — including a *rejected* payment — is a
|
|
174
|
-
* THROWN `CommerceError`.
|
|
175
|
-
*
|
|
176
|
-
* So `payment-required` and `payment-invalid` arrive through different
|
|
177
|
-
* channels despite sounding symmetrical. Adapters must handle both:
|
|
178
|
-
*
|
|
179
|
-
* try {
|
|
180
|
-
* const outcome = await pipeline.execute(request);
|
|
181
|
-
* if (outcome.kind === 'payment-required') return toPaymentRequiredEnvelope(outcome);
|
|
182
|
-
* return renderDelivered(outcome);
|
|
183
|
-
* } catch (error) {
|
|
184
|
-
* return toErrorEnvelope(toCommerceError(error));
|
|
185
|
-
* }
|
|
186
|
-
*/
|
|
187
|
-
interface ExecutionPipeline {
|
|
188
|
-
execute(request: CanonicalRequest): Promise<ExecutionOutcome>;
|
|
189
|
-
}
|
|
190
|
-
|
|
191
|
-
/**
|
|
192
|
-
* Protocol adapter boundary.
|
|
193
|
-
*
|
|
194
|
-
* FROZEN CONTRACT. An adapter translates a protocol's wire format into a
|
|
195
|
-
* `CanonicalRequest`, hands it to the execution pipeline and maps the outcome
|
|
196
|
-
* back. It must not call merchant backends, implement payment logic, or hold
|
|
197
|
-
* its own copy of the canonical model.
|
|
198
|
-
*
|
|
199
|
-
* Adapter isolation: a failure while starting or serving one adapter must not
|
|
200
|
-
* prevent the others from operating.
|
|
201
|
-
*/
|
|
202
|
-
|
|
203
|
-
/** Everything an adapter is given. Nothing else is available to it. */
|
|
204
|
-
interface ProtocolAdapterContext {
|
|
205
|
-
readonly pipeline: ExecutionPipeline;
|
|
206
|
-
readonly resources: ResourceRegistry;
|
|
207
|
-
readonly events: EventSink;
|
|
208
|
-
readonly logger: Logger;
|
|
209
|
-
readonly clock: Clock;
|
|
210
|
-
readonly ids: IdGenerator;
|
|
211
|
-
/** Externally reachable base URL of the gateway, from config. */
|
|
212
|
-
readonly publicBaseUrl: string;
|
|
213
|
-
}
|
|
214
|
-
interface ProtocolAdapter {
|
|
215
|
-
readonly name: ProtocolName;
|
|
216
|
-
readonly descriptor: AdapterDescriptor;
|
|
217
|
-
start(context: ProtocolAdapterContext): Promise<void>;
|
|
218
|
-
health(): Promise<AdapterHealth>;
|
|
219
|
-
stop(): Promise<void>;
|
|
220
|
-
}
|
|
221
|
-
/**
|
|
222
|
-
* A protocol adapter served over HTTP.
|
|
223
|
-
*
|
|
224
|
-
* The gateway mounts `handleHttp` at `mountPath` using raw Node request and
|
|
225
|
-
* response objects, so adapters stay independent of the HTTP framework.
|
|
226
|
-
*
|
|
227
|
-
* GUARANTEE — the request body is **unconsumed**.
|
|
228
|
-
*
|
|
229
|
-
* `req` is handed over with its stream unread: the gateway suppresses every
|
|
230
|
-
* body parser on this mount, so an adapter whose SDK reads the body itself
|
|
231
|
-
* (MCP's Streamable HTTP transport does) can do so. The adapter owns reading,
|
|
232
|
-
* size-limiting beyond the gateway's own cap, and parsing.
|
|
233
|
-
*
|
|
234
|
-
* This is load-bearing and easy to break silently. Fastify pre-registers
|
|
235
|
-
* exact-match parsers for `application/json` and `text/plain` and prefers them
|
|
236
|
-
* over a `'*'` wildcard, so registering only a wildcard no-op leaves the
|
|
237
|
-
* built-in JSON parser draining the body first — the adapter then reads an
|
|
238
|
-
* empty stream and every request fails to parse. That exact regression shipped
|
|
239
|
-
* once and no unit test caught it, because adapter conformance suites drive
|
|
240
|
-
* `handleHttp` over a bare `node:http` server and never traverse the gateway.
|
|
241
|
-
*
|
|
242
|
-
* Any change to how adapters are mounted must be covered by a test that POSTs
|
|
243
|
-
* a real JSON body through the real gateway and asserts the adapter received
|
|
244
|
-
* it intact.
|
|
245
|
-
*/
|
|
246
|
-
interface HttpProtocolAdapter extends ProtocolAdapter {
|
|
247
|
-
/** Path prefix the gateway mounts this adapter at, e.g. '/mcp'. */
|
|
248
|
-
readonly mountPath: string;
|
|
249
|
-
handleHttp(req: IncomingMessage, res: ServerResponse): Promise<void>;
|
|
250
|
-
/**
|
|
251
|
-
* Fixed paths this adapter owns *outside* its mount, for protocols whose
|
|
252
|
-
* specification pins a discovery URL (A2A's `/.well-known/agent-card.json`).
|
|
253
|
-
* The gateway mounts them with the same guarantees as `mountPath` — same
|
|
254
|
-
* unconsumed body, same concurrency cap, same failure isolation — so the
|
|
255
|
-
* gateway needs no per-protocol routing knowledge.
|
|
256
|
-
*
|
|
257
|
-
* Omitted by adapters that need none.
|
|
258
|
-
*/
|
|
259
|
-
readonly additionalHttpRoutes?: readonly AdapterHttpRoute[];
|
|
260
|
-
}
|
|
261
|
-
/**
|
|
262
|
-
* One fixed, method-scoped route owned by an adapter. Unlike `mountPath` it
|
|
263
|
-
* registers no wildcard: it matches exactly the path given.
|
|
264
|
-
*/
|
|
265
|
-
interface AdapterHttpRoute {
|
|
266
|
-
readonly method: 'GET' | 'POST';
|
|
267
|
-
/** Absolute gateway path, e.g. '/.well-known/agent-card.json'. */
|
|
268
|
-
readonly path: string;
|
|
269
|
-
handleHttp(req: IncomingMessage, res: ServerResponse): Promise<void>;
|
|
270
|
-
}
|
|
271
|
-
declare function isHttpProtocolAdapter(adapter: ProtocolAdapter): adapter is HttpProtocolAdapter;
|
|
272
|
-
|
|
273
|
-
export { type AdapterHttpRoute as A, type CommerceEvent as C, type DeliveredOutcome as D, type ExecutionPipeline as E, type HttpProtocolAdapter as H, type PaymentRequiredOutcome as P, type PaymentAttempt as a, type CommerceReceipt as b, type ProtocolAdapter as c, type ProtocolAdapterContext as d, COMMERCE_EVENT_TYPES as e, type CanonicalRequest as f, type CommerceEventType as g, type EventSink as h, type ExecutionOutcome as i, isHttpProtocolAdapter as j };
|
|
@@ -1,351 +0,0 @@
|
|
|
1
|
-
/**
|
|
2
|
-
* Shared primitive aliases used across the canonical domain model.
|
|
3
|
-
*
|
|
4
|
-
* FROZEN CONTRACT. Every consumer codes against these shapes; changing one
|
|
5
|
-
* is a breaking change.
|
|
6
|
-
*/
|
|
7
|
-
/**
|
|
8
|
-
* A JSON Schema document (draft 2020-12 subset in practice).
|
|
9
|
-
*
|
|
10
|
-
* Deliberately loose: protocol adapters translate this to their own schema
|
|
11
|
-
* representation, and the gateway only validates structurally at trust
|
|
12
|
-
* boundaries. Never treat this as trusted input without validation.
|
|
13
|
-
*/
|
|
14
|
-
type JsonSchema = Record<string, unknown>;
|
|
15
|
-
/**
|
|
16
|
-
* Protocol surfaces a resource can be exposed through.
|
|
17
|
-
*
|
|
18
|
-
* The runtime list is the definition and the type is derived from it, so a
|
|
19
|
-
* caller that has to *check* a name (config validation, the OpenAPI
|
|
20
|
-
* importer's `--expose`) reads the same strings the type is built from
|
|
21
|
-
* rather than keeping a second copy that can drift.
|
|
22
|
-
*/
|
|
23
|
-
type ProtocolName = 'http' | 'mcp' | 'a2a' | 'acp';
|
|
24
|
-
/**
|
|
25
|
-
* The same names as a value, for code that has to *check* one at
|
|
26
|
-
* runtime - config validation, the OpenAPI importer's `--expose`. Typed
|
|
27
|
-
* against `ProtocolName` so an unsupported name cannot enter the list, which
|
|
28
|
-
* is what keeps this from becoming a second definition that drifts.
|
|
29
|
-
*/
|
|
30
|
-
declare const PROTOCOL_NAMES: readonly ProtocolName[];
|
|
31
|
-
/**
|
|
32
|
-
* Payment rails a resource can accept.
|
|
33
|
-
*
|
|
34
|
-
* This is an ordered candidate list, not a buyer-selected menu. The pipeline
|
|
35
|
-
* uses the first method with a configured provider; a rejection ends the
|
|
36
|
-
* request instead of trying another rail. Config requires at least one named
|
|
37
|
-
* rail to be enabled but permits additional unavailable candidates.
|
|
38
|
-
*/
|
|
39
|
-
type PaymentMethodName = 'x402' | 'mpp';
|
|
40
|
-
/**
|
|
41
|
-
* The same names as a value, for config validation, which checks a name at
|
|
42
|
-
* runtime. The annotation rejects an entry that is not a
|
|
43
|
-
* `PaymentMethodName`, but nothing makes the list exhaustive, so a new rail
|
|
44
|
-
* has to be added here as well as to the type.
|
|
45
|
-
*/
|
|
46
|
-
declare const PAYMENT_METHOD_NAMES: readonly PaymentMethodName[];
|
|
47
|
-
/**
|
|
48
|
-
* Authorization methods a resource can require.
|
|
49
|
-
*
|
|
50
|
-
* Deliberately not a `ProtocolName` and not a `PaymentMethodName`: an
|
|
51
|
-
* authorization method is neither a transport nor a payment rail. It proves
|
|
52
|
-
* the purchase was approved, and sits beside the payment rather than
|
|
53
|
-
* replacing it.
|
|
54
|
-
*/
|
|
55
|
-
type AuthorizationMethodName = 'ap2';
|
|
56
|
-
/** ISO-8601 timestamp string, always UTC with millisecond precision. */
|
|
57
|
-
type IsoTimestamp = string;
|
|
58
|
-
/**
|
|
59
|
-
* A decimal amount expressed as a string in the *display* unit of the currency
|
|
60
|
-
* (for example "0.01" USDC), never as a float and never in base units.
|
|
61
|
-
*
|
|
62
|
-
* Conversion to on-chain base units is a payment-provider responsibility.
|
|
63
|
-
*/
|
|
64
|
-
type DecimalAmount = string;
|
|
65
|
-
/** Health of an individual adapter or subsystem. */
|
|
66
|
-
interface AdapterHealth {
|
|
67
|
-
readonly status: 'pass' | 'warn' | 'fail';
|
|
68
|
-
readonly detail?: string;
|
|
69
|
-
readonly checkedAt: IsoTimestamp;
|
|
70
|
-
readonly durationMs?: number;
|
|
71
|
-
}
|
|
72
|
-
/**
|
|
73
|
-
* Describes an adapter's supported surface for diagnostics
|
|
74
|
-
*/
|
|
75
|
-
interface AdapterDescriptor {
|
|
76
|
-
readonly name: string;
|
|
77
|
-
readonly kind: 'protocol' | 'payment' | 'storage' | 'authorization';
|
|
78
|
-
/** Version of this adapter implementation (independent of the spec). */
|
|
79
|
-
readonly implementationVersion: string;
|
|
80
|
-
/** Exact pinned specification revision this adapter targets. */
|
|
81
|
-
readonly supportedSpec: string;
|
|
82
|
-
readonly capabilities: readonly string[];
|
|
83
|
-
readonly status: 'stable' | 'experimental' | 'planned';
|
|
84
|
-
/** Capabilities explicitly NOT implemented, surfaced by `doctor`. */
|
|
85
|
-
readonly unsupported?: readonly string[];
|
|
86
|
-
}
|
|
87
|
-
|
|
88
|
-
/**
|
|
89
|
-
* Canonical resource model.
|
|
90
|
-
*
|
|
91
|
-
* FROZEN CONTRACT.
|
|
92
|
-
*/
|
|
93
|
-
|
|
94
|
-
/** HTTP methods a backend handler may use. */
|
|
95
|
-
type BackendMethod = 'GET' | 'POST' | 'PUT' | 'PATCH' | 'DELETE';
|
|
96
|
-
/**
|
|
97
|
-
* Describes how the gateway calls the merchant's existing backend.
|
|
98
|
-
*
|
|
99
|
-
* Backend URLs are administrator-controlled configuration only. User- or
|
|
100
|
-
* agent-controlled backend URLs are forbidden (see docs/security.md, SSRF).
|
|
101
|
-
* Secret header values must come from `${ENV_VAR}` placeholders resolved by
|
|
102
|
-
* the config loader, never from plaintext configuration.
|
|
103
|
-
*/
|
|
104
|
-
interface BackendHandler {
|
|
105
|
-
readonly type: 'http';
|
|
106
|
-
readonly method: BackendMethod;
|
|
107
|
-
readonly url: string;
|
|
108
|
-
readonly headers?: Readonly<Record<string, string>>;
|
|
109
|
-
/** Hard upper bound on the backend call. Defaults to DEFAULT_BACKEND_TIMEOUT_MS. */
|
|
110
|
-
readonly timeoutMs?: number;
|
|
111
|
-
/**
|
|
112
|
-
* Names the top-level input properties carrying each part of the request.
|
|
113
|
-
*
|
|
114
|
-
* Absent (the default) keeps the original mapping: `{param}` values are read
|
|
115
|
-
* from top-level input and everything left over becomes either the query
|
|
116
|
-
* string (GET/DELETE) or the entire JSON body (POST/PUT/PATCH). That mapping
|
|
117
|
-
* cannot express `POST /users/{userId}/orders?notify=true` with a JSON body
|
|
118
|
-
* - one perfectly ordinary REST operation with all three parts at once.
|
|
119
|
-
*
|
|
120
|
-
* When present, each group is sourced independently and top-level input that
|
|
121
|
-
* no binding names is not forwarded to the backend at all.
|
|
122
|
-
*/
|
|
123
|
-
readonly inputBindings?: {
|
|
124
|
-
readonly path?: string;
|
|
125
|
-
readonly query?: string;
|
|
126
|
-
readonly body?: string;
|
|
127
|
-
};
|
|
128
|
-
}
|
|
129
|
-
/** Default backend timeout when a resource does not specify one. */
|
|
130
|
-
declare const DEFAULT_BACKEND_TIMEOUT_MS = 10000;
|
|
131
|
-
/**
|
|
132
|
-
* Canonical pricing.
|
|
133
|
-
*
|
|
134
|
-
* `dynamic` exists in the type system for forward compatibility but is
|
|
135
|
-
* REJECTED by config validation in this release.
|
|
136
|
-
*/
|
|
137
|
-
type Pricing = {
|
|
138
|
-
readonly type: 'free';
|
|
139
|
-
} | {
|
|
140
|
-
readonly type: 'fixed';
|
|
141
|
-
readonly amount: DecimalAmount;
|
|
142
|
-
readonly currency: string;
|
|
143
|
-
} | {
|
|
144
|
-
readonly type: 'dynamic';
|
|
145
|
-
readonly resolver: string;
|
|
146
|
-
};
|
|
147
|
-
/**
|
|
148
|
-
* A merchant capability exposed to agents.
|
|
149
|
-
*
|
|
150
|
-
* The canonical resource is the single source of truth: protocol adapters map
|
|
151
|
-
* it outward, they never define their own parallel notion of a resource.
|
|
152
|
-
*/
|
|
153
|
-
interface CommerceResource {
|
|
154
|
-
readonly id: string;
|
|
155
|
-
readonly name: string;
|
|
156
|
-
readonly description?: string;
|
|
157
|
-
readonly inputSchema?: JsonSchema;
|
|
158
|
-
readonly outputSchema?: JsonSchema;
|
|
159
|
-
readonly handler: BackendHandler;
|
|
160
|
-
readonly pricing: Pricing;
|
|
161
|
-
readonly exposedVia: readonly ProtocolName[];
|
|
162
|
-
readonly paymentMethods: readonly PaymentMethodName[];
|
|
163
|
-
/**
|
|
164
|
-
* Authorization the buyer must present in addition to payment.
|
|
165
|
-
*
|
|
166
|
-
* Opt-in per resource and absent by default, so every resource configured
|
|
167
|
-
* before this existed behaves exactly as it did. It sits beside
|
|
168
|
-
* `paymentMethods` rather than inside it: an authorization method is not a
|
|
169
|
-
* payment rail and must never be selectable as one.
|
|
170
|
-
*/
|
|
171
|
-
readonly authorization?: {
|
|
172
|
-
readonly required: readonly AuthorizationMethodName[];
|
|
173
|
-
};
|
|
174
|
-
}
|
|
175
|
-
/** Read-only view of every configured resource. */
|
|
176
|
-
interface ResourceRegistry {
|
|
177
|
-
get(id: string): CommerceResource | undefined;
|
|
178
|
-
list(): readonly CommerceResource[];
|
|
179
|
-
/** Resources exposed through a given protocol surface. */
|
|
180
|
-
listExposedVia(protocol: ProtocolName): readonly CommerceResource[];
|
|
181
|
-
has(id: string): boolean;
|
|
182
|
-
}
|
|
183
|
-
|
|
184
|
-
/**
|
|
185
|
-
* Canonical payment model.
|
|
186
|
-
*
|
|
187
|
-
* FROZEN CONTRACT.
|
|
188
|
-
*
|
|
189
|
-
* Core decides *that* a payment is required and for how much.
|
|
190
|
-
* Payment providers decide *how* the challenge is encoded, verified and settled.
|
|
191
|
-
* No x402/EVM-specific type may appear in this file.
|
|
192
|
-
*/
|
|
193
|
-
|
|
194
|
-
/**
|
|
195
|
-
* Provider-native payment challenge, opaque to core.
|
|
196
|
-
*
|
|
197
|
-
* For x402 the `accepts` entries are x402 `PaymentRequirements` objects; core
|
|
198
|
-
* passes them through to protocol adapters verbatim and never inspects them.
|
|
199
|
-
*/
|
|
200
|
-
interface PaymentChallenge {
|
|
201
|
-
readonly provider: PaymentMethodName;
|
|
202
|
-
/** Provider protocol version, e.g. the x402 `x402Version` value as a string. */
|
|
203
|
-
readonly version: string;
|
|
204
|
-
readonly accepts: readonly Readonly<Record<string, unknown>>[];
|
|
205
|
-
/**
|
|
206
|
-
* The provider's own challenge document, verbatim — for x402 v2 the
|
|
207
|
-
* `PaymentRequired` object a buyer's client consumes.
|
|
208
|
-
*
|
|
209
|
-
* `accepts` alone is not that document: v2 moves the resource description
|
|
210
|
-
* out of the individual requirements and up onto the envelope, and the
|
|
211
|
-
* protocol version rides there too. Protocol adapters with a native channel
|
|
212
|
-
* for it (x402's `PAYMENT-REQUIRED` header, MPP's `WWW-Authenticate`) send
|
|
213
|
-
* it there rather than reassembling it, so every surface offers the same
|
|
214
|
-
* challenge instead of each building its own from parts. Opaque to core.
|
|
215
|
-
*/
|
|
216
|
-
readonly envelope?: Readonly<Record<string, unknown>>;
|
|
217
|
-
}
|
|
218
|
-
/**
|
|
219
|
-
* What the buyer must pay, in canonical terms, plus the provider-native
|
|
220
|
-
* challenge the buyer's client needs in order to construct a payment.
|
|
221
|
-
*/
|
|
222
|
-
interface PaymentRequirement {
|
|
223
|
-
readonly id: string;
|
|
224
|
-
readonly requestId: string;
|
|
225
|
-
readonly resourceId: string;
|
|
226
|
-
readonly provider: PaymentMethodName;
|
|
227
|
-
readonly amount: DecimalAmount;
|
|
228
|
-
readonly currency: string;
|
|
229
|
-
/** Merchant-controlled settlement destination. Never a gateway-owned wallet. */
|
|
230
|
-
readonly destination: string;
|
|
231
|
-
readonly network?: string;
|
|
232
|
-
readonly asset?: string;
|
|
233
|
-
readonly expiresAt?: IsoTimestamp;
|
|
234
|
-
readonly challenge: PaymentChallenge;
|
|
235
|
-
readonly metadata?: Readonly<Record<string, unknown>>;
|
|
236
|
-
}
|
|
237
|
-
/**
|
|
238
|
-
* Opaque payment proof supplied by the buyer's client.
|
|
239
|
-
*
|
|
240
|
-
* For x402 over HTTP this is the base64 `PAYMENT-SIGNATURE` header value; over
|
|
241
|
-
* MCP it is the same string carried in the tool input's `_payment` field.
|
|
242
|
-
*/
|
|
243
|
-
interface PaymentSubmission {
|
|
244
|
-
readonly method: PaymentMethodName;
|
|
245
|
-
readonly payload: string;
|
|
246
|
-
}
|
|
247
|
-
/** Outcome of verification or settlement. */
|
|
248
|
-
interface PaymentResult {
|
|
249
|
-
readonly status: 'verified' | 'settled' | 'rejected';
|
|
250
|
-
readonly provider: PaymentMethodName;
|
|
251
|
-
/** Settlement reference, e.g. an on-chain transaction hash. */
|
|
252
|
-
readonly externalReference?: string;
|
|
253
|
-
readonly payer?: string;
|
|
254
|
-
readonly payee?: string;
|
|
255
|
-
readonly amount: DecimalAmount;
|
|
256
|
-
readonly currency: string;
|
|
257
|
-
readonly network?: string;
|
|
258
|
-
readonly asset?: string;
|
|
259
|
-
/**
|
|
260
|
-
* Stable, provider-computed identity of the payment authorisation itself.
|
|
261
|
-
*
|
|
262
|
-
* The gateway reserves this key before settlement and rejects any second
|
|
263
|
-
* request presenting the same key (see PAYMENT_REPLAYED). Providers MUST
|
|
264
|
-
* derive it only from the authorisation (payer, nonce, asset, network) so
|
|
265
|
-
* that the same authorisation always maps to the same key.
|
|
266
|
-
*/
|
|
267
|
-
readonly replayKey?: string;
|
|
268
|
-
/** Machine-readable rejection reason when status is `rejected`. */
|
|
269
|
-
readonly rejectionReason?: string;
|
|
270
|
-
readonly settledAt?: IsoTimestamp;
|
|
271
|
-
readonly metadata?: Readonly<Record<string, unknown>>;
|
|
272
|
-
}
|
|
273
|
-
/** Input to {@link PaymentProvider.createRequirement}. */
|
|
274
|
-
interface PaymentContext {
|
|
275
|
-
readonly requestId: string;
|
|
276
|
-
readonly resource: CommerceResource;
|
|
277
|
-
readonly amount: DecimalAmount;
|
|
278
|
-
readonly currency: string;
|
|
279
|
-
readonly requestedAt: IsoTimestamp;
|
|
280
|
-
readonly metadata?: Readonly<Record<string, unknown>>;
|
|
281
|
-
}
|
|
282
|
-
/** Input to {@link PaymentProvider.verify}. */
|
|
283
|
-
interface PaymentVerificationContext {
|
|
284
|
-
readonly requestId: string;
|
|
285
|
-
readonly resource: CommerceResource;
|
|
286
|
-
readonly requirement: PaymentRequirement;
|
|
287
|
-
readonly submission: PaymentSubmission;
|
|
288
|
-
}
|
|
289
|
-
/** Input to {@link PaymentProvider.settle}. */
|
|
290
|
-
interface PaymentSettlementContext extends PaymentVerificationContext {
|
|
291
|
-
readonly verification: PaymentResult;
|
|
292
|
-
}
|
|
293
|
-
/**
|
|
294
|
-
* Contract every payment rail implements.
|
|
295
|
-
*
|
|
296
|
-
* Implementations must be non-custodial: they orchestrate an external payment
|
|
297
|
-
* protocol and must never hold buyer or merchant production signing keys.
|
|
298
|
-
*/
|
|
299
|
-
interface PaymentProvider {
|
|
300
|
-
readonly name: PaymentMethodName;
|
|
301
|
-
readonly descriptor: AdapterDescriptor;
|
|
302
|
-
/** Build the challenge presented to an unpaid request. */
|
|
303
|
-
createRequirement(context: PaymentContext): Promise<PaymentRequirement>;
|
|
304
|
-
/**
|
|
305
|
-
* Validate a submitted proof against the requirement.
|
|
306
|
-
*
|
|
307
|
-
* Must return `rejected` (or throw a CommerceError) rather than throwing an
|
|
308
|
-
* untyped error. Must never have side effects that move funds.
|
|
309
|
-
*/
|
|
310
|
-
verify(context: PaymentVerificationContext): Promise<PaymentResult>;
|
|
311
|
-
/** Execute settlement. Called only after `verify` returned `verified`. */
|
|
312
|
-
settle(context: PaymentSettlementContext): Promise<PaymentResult>;
|
|
313
|
-
health(): Promise<AdapterHealth>;
|
|
314
|
-
}
|
|
315
|
-
|
|
316
|
-
/**
|
|
317
|
-
* Minimal structural logger interface.
|
|
318
|
-
*
|
|
319
|
-
* Core must not depend on pino directly; the gateway injects a pino instance
|
|
320
|
-
* that satisfies this shape. Never log secrets: private keys, seed phrases,
|
|
321
|
-
* Authorization headers or payment authorisation payloads.
|
|
322
|
-
*/
|
|
323
|
-
interface Logger {
|
|
324
|
-
debug(obj: Record<string, unknown>, msg?: string): void;
|
|
325
|
-
info(obj: Record<string, unknown>, msg?: string): void;
|
|
326
|
-
warn(obj: Record<string, unknown>, msg?: string): void;
|
|
327
|
-
error(obj: Record<string, unknown>, msg?: string): void;
|
|
328
|
-
child(bindings: Record<string, unknown>): Logger;
|
|
329
|
-
}
|
|
330
|
-
/** A logger that discards everything. Useful in unit tests. */
|
|
331
|
-
declare const NOOP_LOGGER: Logger;
|
|
332
|
-
|
|
333
|
-
/**
|
|
334
|
-
* Injected runtime primitives.
|
|
335
|
-
*
|
|
336
|
-
* Everything non-deterministic (time, ids) is injected so tests can be exact.
|
|
337
|
-
*/
|
|
338
|
-
|
|
339
|
-
interface Clock {
|
|
340
|
-
now(): Date;
|
|
341
|
-
nowIso(): IsoTimestamp;
|
|
342
|
-
/** Milliseconds since an arbitrary origin; use for durations only. */
|
|
343
|
-
monotonicMs(): number;
|
|
344
|
-
}
|
|
345
|
-
interface IdGenerator {
|
|
346
|
-
/** Opaque, collision-resistant identifier. */
|
|
347
|
-
next(prefix?: string): string;
|
|
348
|
-
}
|
|
349
|
-
declare const systemClock: Clock;
|
|
350
|
-
|
|
351
|
-
export { type AdapterDescriptor as A, type BackendHandler as B, type Clock as C, type DecimalAmount as D, type IsoTimestamp as I, type JsonSchema as J, type Logger as L, NOOP_LOGGER as N, type PaymentMethodName as P, type ResourceRegistry as R, type CommerceResource as a, type PaymentSubmission as b, type AdapterHealth as c, type PaymentProvider as d, type IdGenerator as e, type AuthorizationMethodName as f, type BackendMethod as g, DEFAULT_BACKEND_TIMEOUT_MS as h, PAYMENT_METHOD_NAMES as i, PROTOCOL_NAMES as j, type PaymentChallenge as k, type PaymentContext as l, type PaymentRequirement as m, type PaymentResult as n, type PaymentSettlementContext as o, type PaymentVerificationContext as p, type Pricing as q, type ProtocolName as r, systemClock as s };
|