@devlab.group/agent-commerce 1.3.0 → 1.4.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 +89 -66
- package/dist/ap2.d.ts +164 -0
- package/dist/ap2.js +669 -0
- package/dist/ap2.js.map +1 -0
- package/dist/authorization-CPDcpJVa.d.ts +123 -0
- package/dist/chunk-7NKWFGBY.js +68 -0
- package/dist/chunk-7NKWFGBY.js.map +1 -0
- package/dist/{chunk-TBZA6Z5B.js → chunk-IUR3Q7DE.js} +3 -3
- package/dist/{chunk-TBZA6Z5B.js.map → chunk-IUR3Q7DE.js.map} +1 -1
- package/dist/{chunk-N3DNLXGC.js → chunk-ZDVJ7EVL.js} +149 -66
- package/dist/chunk-ZDVJ7EVL.js.map +1 -0
- package/dist/cli/index.js +419 -53
- package/dist/cli/index.js.map +1 -1
- package/dist/index.d.ts +108 -6
- package/dist/index.js +454 -112
- package/dist/index.js.map +1 -1
- package/dist/mcp.d.ts +3 -2
- package/dist/mcp.js +10 -12
- package/dist/mcp.js.map +1 -1
- package/dist/{protocol-adapter-DTFGWGXq.d.ts → protocol-adapter-CaMZj6Wm.d.ts} +19 -2
- package/dist/{runtime-Plk5Peqi.d.ts → runtime-CKq3d_3K.d.ts} +22 -2
- package/dist/types-CJtwLu1c.d.ts +99 -0
- package/dist/x402.d.ts +1 -1
- package/dist/x402.js +3 -3
- package/package.json +26 -4
- package/dist/chunk-N3DNLXGC.js.map +0 -1
|
@@ -11,6 +11,10 @@ var COMMERCE_EVENT_TYPES = [
|
|
|
11
11
|
"payment.rejected",
|
|
12
12
|
"payment.verified",
|
|
13
13
|
"payment.settled",
|
|
14
|
+
// The same two types whatever the method, so an audit-trail reader never
|
|
15
|
+
// has to know what AP2 is
|
|
16
|
+
"authorization.verified",
|
|
17
|
+
"authorization.rejected",
|
|
14
18
|
"backend.called",
|
|
15
19
|
"backend.failed",
|
|
16
20
|
"resource.delivered"
|
|
@@ -19,68 +23,6 @@ var COMMERCE_EVENT_TYPES = [
|
|
|
19
23
|
// src/core/domain/resource.ts
|
|
20
24
|
var DEFAULT_BACKEND_TIMEOUT_MS = 1e4;
|
|
21
25
|
|
|
22
|
-
// src/core/domain/wire.ts
|
|
23
|
-
var PAYMENT_INPUT_FIELD = "_payment";
|
|
24
|
-
var PAYMENT_HEADER = "payment-signature";
|
|
25
|
-
var PAYMENT_RESPONSE_HEADER = "payment-response";
|
|
26
|
-
var PAYMENT_REQUIRED_HEADER = "payment-required";
|
|
27
|
-
var DELIVERY_SUMMARY_META_KEY = "agent-commerce/delivery";
|
|
28
|
-
function toDeliverySummary(outcome) {
|
|
29
|
-
const p = outcome.payment;
|
|
30
|
-
return {
|
|
31
|
-
requestId: outcome.requestId,
|
|
32
|
-
resourceId: outcome.resourceId,
|
|
33
|
-
receiptId: outcome.receipt.id,
|
|
34
|
-
deliveredAt: outcome.receipt.deliveredAt,
|
|
35
|
-
...p !== void 0 ? {
|
|
36
|
-
payment: {
|
|
37
|
-
status: p.status,
|
|
38
|
-
amount: p.amount,
|
|
39
|
-
currency: p.currency,
|
|
40
|
-
...p.externalReference !== void 0 ? { externalReference: p.externalReference } : {},
|
|
41
|
-
...p.network !== void 0 ? { network: p.network } : {}
|
|
42
|
-
}
|
|
43
|
-
} : {}
|
|
44
|
-
};
|
|
45
|
-
}
|
|
46
|
-
function toPaymentRequiredEnvelope(outcome) {
|
|
47
|
-
const r = outcome.requirement;
|
|
48
|
-
return {
|
|
49
|
-
status: "payment-required",
|
|
50
|
-
code: "PAYMENT_REQUIRED",
|
|
51
|
-
requestId: outcome.requestId,
|
|
52
|
-
resourceId: outcome.resourceId,
|
|
53
|
-
message: `Payment of ${r.amount} ${r.currency} is required for resource "${outcome.resourceId}". Retry with a ${r.provider} payment proof.`,
|
|
54
|
-
payment: {
|
|
55
|
-
provider: r.provider,
|
|
56
|
-
version: r.challenge.version,
|
|
57
|
-
amount: r.amount,
|
|
58
|
-
currency: r.currency,
|
|
59
|
-
destination: r.destination,
|
|
60
|
-
...r.network !== void 0 ? { network: r.network } : {},
|
|
61
|
-
...r.asset !== void 0 ? { asset: r.asset } : {},
|
|
62
|
-
...r.expiresAt !== void 0 ? { expiresAt: r.expiresAt } : {},
|
|
63
|
-
accepts: r.challenge.accepts,
|
|
64
|
-
...r.challenge.envelope !== void 0 ? { envelope: r.challenge.envelope } : {}
|
|
65
|
-
}
|
|
66
|
-
};
|
|
67
|
-
}
|
|
68
|
-
function toErrorEnvelope(error) {
|
|
69
|
-
const info = error.toInfo();
|
|
70
|
-
return {
|
|
71
|
-
status: "error",
|
|
72
|
-
code: info.code,
|
|
73
|
-
message: info.message,
|
|
74
|
-
retryable: info.retryable,
|
|
75
|
-
...info.requestId !== void 0 ? { requestId: info.requestId } : {},
|
|
76
|
-
...info.resourceId !== void 0 ? { resourceId: info.resourceId } : {},
|
|
77
|
-
...info.details !== void 0 ? { details: info.details } : {}
|
|
78
|
-
};
|
|
79
|
-
}
|
|
80
|
-
function isPaymentRequiredEnvelope(value) {
|
|
81
|
-
return typeof value === "object" && value !== null && value.status === "payment-required" && typeof value.payment === "object";
|
|
82
|
-
}
|
|
83
|
-
|
|
84
26
|
// src/core/errors/codes.ts
|
|
85
27
|
var COMMERCE_ERROR_CODES = [
|
|
86
28
|
"CONFIG_INVALID",
|
|
@@ -91,6 +33,10 @@ var COMMERCE_ERROR_CODES = [
|
|
|
91
33
|
"PAYMENT_REPLAYED",
|
|
92
34
|
"PAYMENT_PROVIDER_UNAVAILABLE",
|
|
93
35
|
"PAYMENT_SETTLEMENT_FAILED",
|
|
36
|
+
"AUTHORIZATION_REQUIRED",
|
|
37
|
+
"AUTHORIZATION_INVALID",
|
|
38
|
+
"AUTHORIZATION_REPLAYED",
|
|
39
|
+
"AUTHORIZATION_PROVIDER_UNAVAILABLE",
|
|
94
40
|
"BACKEND_TIMEOUT",
|
|
95
41
|
"BACKEND_ERROR",
|
|
96
42
|
"PROTOCOL_UNSUPPORTED",
|
|
@@ -107,6 +53,14 @@ var COMMERCE_ERROR_HTTP_STATUS = {
|
|
|
107
53
|
PAYMENT_REPLAYED: 409,
|
|
108
54
|
PAYMENT_PROVIDER_UNAVAILABLE: 503,
|
|
109
55
|
PAYMENT_SETTLEMENT_FAILED: 502,
|
|
56
|
+
// 403, not 402: the buyer's money is not the problem. A 402 tells a client
|
|
57
|
+
// "pay and retry", which cannot fix a missing or rejected mandate, and a
|
|
58
|
+
// client that auto-pays on 402 would be charged for a request that was
|
|
59
|
+
// never going to be delivered.
|
|
60
|
+
AUTHORIZATION_REQUIRED: 403,
|
|
61
|
+
AUTHORIZATION_INVALID: 403,
|
|
62
|
+
AUTHORIZATION_REPLAYED: 409,
|
|
63
|
+
AUTHORIZATION_PROVIDER_UNAVAILABLE: 503,
|
|
110
64
|
BACKEND_TIMEOUT: 504,
|
|
111
65
|
BACKEND_ERROR: 502,
|
|
112
66
|
PROTOCOL_UNSUPPORTED: 501,
|
|
@@ -116,6 +70,10 @@ var COMMERCE_ERROR_HTTP_STATUS = {
|
|
|
116
70
|
};
|
|
117
71
|
var RETRYABLE_ERROR_CODES = /* @__PURE__ */ new Set([
|
|
118
72
|
"PAYMENT_PROVIDER_UNAVAILABLE",
|
|
73
|
+
// Our verifier or our replay store was unreachable, so no verdict on the
|
|
74
|
+
// mandate was ever reached. That is an outage on our side, and the same
|
|
75
|
+
// proof will verify once it clears.
|
|
76
|
+
"AUTHORIZATION_PROVIDER_UNAVAILABLE",
|
|
119
77
|
"BACKEND_TIMEOUT",
|
|
120
78
|
// Load shedding is transient by definition: the caller should back off and
|
|
121
79
|
// try again. Before this code existed the MCP adapter's queue-full path threw
|
|
@@ -166,6 +124,131 @@ function toCommerceError(value, fallbackCode = "INTERNAL_ERROR", fallbackMessage
|
|
|
166
124
|
return new CommerceError(fallbackCode, fallbackMessage, { cause: value });
|
|
167
125
|
}
|
|
168
126
|
|
|
127
|
+
// src/core/domain/wire.ts
|
|
128
|
+
var PAYMENT_INPUT_FIELD = "_payment";
|
|
129
|
+
var PAYMENT_HEADER = "payment-signature";
|
|
130
|
+
var PAYMENT_RESPONSE_HEADER = "payment-response";
|
|
131
|
+
var AUTHORIZATION_INPUT_FIELD = "_authorization";
|
|
132
|
+
var RESERVED_INPUT_FIELDS = [
|
|
133
|
+
PAYMENT_INPUT_FIELD,
|
|
134
|
+
AUTHORIZATION_INPUT_FIELD
|
|
135
|
+
];
|
|
136
|
+
var AUTHORIZATION_HEADER = "agent-authorization";
|
|
137
|
+
var MAX_AUTHORIZATION_HEADER_BYTES = 8192;
|
|
138
|
+
var PAYMENT_REQUIRED_HEADER = "payment-required";
|
|
139
|
+
var DELIVERY_SUMMARY_META_KEY = "agent-commerce/delivery";
|
|
140
|
+
function toDeliverySummary(outcome) {
|
|
141
|
+
const p = outcome.payment;
|
|
142
|
+
return {
|
|
143
|
+
requestId: outcome.requestId,
|
|
144
|
+
resourceId: outcome.resourceId,
|
|
145
|
+
receiptId: outcome.receipt.id,
|
|
146
|
+
deliveredAt: outcome.receipt.deliveredAt,
|
|
147
|
+
...p !== void 0 ? {
|
|
148
|
+
payment: {
|
|
149
|
+
status: p.status,
|
|
150
|
+
amount: p.amount,
|
|
151
|
+
currency: p.currency,
|
|
152
|
+
...p.externalReference !== void 0 ? { externalReference: p.externalReference } : {},
|
|
153
|
+
...p.network !== void 0 ? { network: p.network } : {}
|
|
154
|
+
}
|
|
155
|
+
} : {}
|
|
156
|
+
};
|
|
157
|
+
}
|
|
158
|
+
function toPaymentRequiredEnvelope(outcome) {
|
|
159
|
+
const r = outcome.requirement;
|
|
160
|
+
return {
|
|
161
|
+
status: "payment-required",
|
|
162
|
+
code: "PAYMENT_REQUIRED",
|
|
163
|
+
requestId: outcome.requestId,
|
|
164
|
+
resourceId: outcome.resourceId,
|
|
165
|
+
message: `Payment of ${r.amount} ${r.currency} is required for resource "${outcome.resourceId}". Retry with a ${r.provider} payment proof.`,
|
|
166
|
+
payment: {
|
|
167
|
+
provider: r.provider,
|
|
168
|
+
version: r.challenge.version,
|
|
169
|
+
amount: r.amount,
|
|
170
|
+
currency: r.currency,
|
|
171
|
+
destination: r.destination,
|
|
172
|
+
...r.network !== void 0 ? { network: r.network } : {},
|
|
173
|
+
...r.asset !== void 0 ? { asset: r.asset } : {},
|
|
174
|
+
...r.expiresAt !== void 0 ? { expiresAt: r.expiresAt } : {},
|
|
175
|
+
accepts: r.challenge.accepts,
|
|
176
|
+
...r.challenge.envelope !== void 0 ? { envelope: r.challenge.envelope } : {}
|
|
177
|
+
},
|
|
178
|
+
...outcome.authorization !== void 0 && outcome.authorization.length > 0 ? { authorization: { required: outcome.authorization } } : {}
|
|
179
|
+
};
|
|
180
|
+
}
|
|
181
|
+
function toErrorEnvelope(error) {
|
|
182
|
+
const info = error.toInfo();
|
|
183
|
+
return {
|
|
184
|
+
status: "error",
|
|
185
|
+
code: info.code,
|
|
186
|
+
message: info.message,
|
|
187
|
+
retryable: info.retryable,
|
|
188
|
+
...info.requestId !== void 0 ? { requestId: info.requestId } : {},
|
|
189
|
+
...info.resourceId !== void 0 ? { resourceId: info.resourceId } : {},
|
|
190
|
+
...info.details !== void 0 ? { details: info.details } : {}
|
|
191
|
+
};
|
|
192
|
+
}
|
|
193
|
+
function isPaymentRequiredEnvelope(value) {
|
|
194
|
+
return typeof value === "object" && value !== null && value.status === "payment-required" && typeof value.payment === "object";
|
|
195
|
+
}
|
|
196
|
+
function parseAuthorizationSubmission(value, requestId) {
|
|
197
|
+
if (value === void 0 || value === null) return void 0;
|
|
198
|
+
const fail = (detail) => {
|
|
199
|
+
throw new CommerceError("AUTHORIZATION_INVALID", `Malformed authorization: ${detail}`, {
|
|
200
|
+
...requestId !== void 0 ? { requestId } : {}
|
|
201
|
+
});
|
|
202
|
+
};
|
|
203
|
+
if (typeof value !== "object" || Array.isArray(value)) {
|
|
204
|
+
fail(`expected an object with "method" and "payload", got ${typeof value}`);
|
|
205
|
+
}
|
|
206
|
+
const record = value;
|
|
207
|
+
const method = record["method"];
|
|
208
|
+
const payload = record["payload"];
|
|
209
|
+
if (method !== "ap2") {
|
|
210
|
+
fail(`unsupported method ${typeof method === "string" ? `"${method}"` : typeof method}`);
|
|
211
|
+
}
|
|
212
|
+
if (typeof payload !== "string" || payload.length === 0) {
|
|
213
|
+
fail('"payload" must be a non-empty string');
|
|
214
|
+
}
|
|
215
|
+
return { method: "ap2", payload };
|
|
216
|
+
}
|
|
217
|
+
function parseAuthorizationHeader(raw, requestId) {
|
|
218
|
+
const value = Array.isArray(raw) ? raw[0] : raw;
|
|
219
|
+
if (value === void 0 || value.length === 0) return void 0;
|
|
220
|
+
const fail = (detail) => {
|
|
221
|
+
throw new CommerceError("AUTHORIZATION_INVALID", `Malformed authorization: ${detail}`, {
|
|
222
|
+
...requestId !== void 0 ? { requestId } : {}
|
|
223
|
+
});
|
|
224
|
+
};
|
|
225
|
+
if (Buffer.byteLength(value, "utf8") > MAX_AUTHORIZATION_HEADER_BYTES) {
|
|
226
|
+
fail(`header exceeds the ${MAX_AUTHORIZATION_HEADER_BYTES}-byte limit`);
|
|
227
|
+
}
|
|
228
|
+
let decoded;
|
|
229
|
+
try {
|
|
230
|
+
decoded = JSON.parse(Buffer.from(value, "base64url").toString("utf8"));
|
|
231
|
+
} catch {
|
|
232
|
+
fail("header is not base64url-encoded JSON");
|
|
233
|
+
}
|
|
234
|
+
return parseAuthorizationSubmission(decoded, requestId);
|
|
235
|
+
}
|
|
236
|
+
function extractReservedInputFields(rawInput, resource, requestId) {
|
|
237
|
+
const {
|
|
238
|
+
[PAYMENT_INPUT_FIELD]: paymentValue,
|
|
239
|
+
[AUTHORIZATION_INPUT_FIELD]: authorizationValue,
|
|
240
|
+
...input
|
|
241
|
+
} = rawInput;
|
|
242
|
+
const method = resource?.paymentMethods[0];
|
|
243
|
+
const payment = typeof paymentValue === "string" && paymentValue.length > 0 && method !== void 0 ? { method, payload: paymentValue } : void 0;
|
|
244
|
+
const authorization = parseAuthorizationSubmission(authorizationValue, requestId);
|
|
245
|
+
return {
|
|
246
|
+
input,
|
|
247
|
+
...payment !== void 0 ? { payment } : {},
|
|
248
|
+
...authorization !== void 0 ? { authorization } : {}
|
|
249
|
+
};
|
|
250
|
+
}
|
|
251
|
+
|
|
169
252
|
// src/core/interfaces/logger.ts
|
|
170
253
|
var NOOP_LOGGER = {
|
|
171
254
|
debug: () => {
|
|
@@ -190,8 +273,8 @@ var systemClock = {
|
|
|
190
273
|
nowIso: () => (/* @__PURE__ */ new Date()).toISOString(),
|
|
191
274
|
monotonicMs: () => performance.now()
|
|
192
275
|
};
|
|
193
|
-
var PACKAGE_VERSION = "1.
|
|
276
|
+
var PACKAGE_VERSION = "1.4.0" ;
|
|
194
277
|
|
|
195
|
-
export { COMMERCE_ERROR_CODES, COMMERCE_ERROR_HTTP_STATUS, COMMERCE_EVENT_TYPES, CommerceError, DEFAULT_BACKEND_TIMEOUT_MS, DELIVERY_SUMMARY_META_KEY, NOOP_LOGGER, PACKAGE_VERSION, PAYMENT_HEADER, PAYMENT_INPUT_FIELD, PAYMENT_REQUIRED_HEADER, PAYMENT_RESPONSE_HEADER, PROTOCOL_NAMES, RETRYABLE_ERROR_CODES, isCommerceError, isHttpProtocolAdapter, isPaymentRequiredEnvelope, systemClock, toCommerceError, toDeliverySummary, toErrorEnvelope, toPaymentRequiredEnvelope };
|
|
196
|
-
//# sourceMappingURL=chunk-
|
|
197
|
-
//# sourceMappingURL=chunk-
|
|
278
|
+
export { AUTHORIZATION_HEADER, AUTHORIZATION_INPUT_FIELD, COMMERCE_ERROR_CODES, COMMERCE_ERROR_HTTP_STATUS, COMMERCE_EVENT_TYPES, CommerceError, DEFAULT_BACKEND_TIMEOUT_MS, DELIVERY_SUMMARY_META_KEY, MAX_AUTHORIZATION_HEADER_BYTES, NOOP_LOGGER, PACKAGE_VERSION, PAYMENT_HEADER, PAYMENT_INPUT_FIELD, PAYMENT_REQUIRED_HEADER, PAYMENT_RESPONSE_HEADER, PROTOCOL_NAMES, RESERVED_INPUT_FIELDS, RETRYABLE_ERROR_CODES, extractReservedInputFields, isCommerceError, isHttpProtocolAdapter, isPaymentRequiredEnvelope, parseAuthorizationHeader, parseAuthorizationSubmission, systemClock, toCommerceError, toDeliverySummary, toErrorEnvelope, toPaymentRequiredEnvelope };
|
|
279
|
+
//# sourceMappingURL=chunk-ZDVJ7EVL.js.map
|
|
280
|
+
//# sourceMappingURL=chunk-ZDVJ7EVL.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"sources":["../src/core/domain/common.ts","../src/core/domain/event.ts","../src/core/domain/resource.ts","../src/core/errors/codes.ts","../src/core/errors/commerce-error.ts","../src/core/domain/wire.ts","../src/core/interfaces/logger.ts","../src/core/interfaces/protocol-adapter.ts","../src/core/interfaces/runtime.ts","../src/version.ts"],"names":[],"mappings":"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","file":"chunk-ZDVJ7EVL.js","sourcesContent":["/**\n * Shared primitive aliases used across the canonical domain model.\n *\n * FROZEN CONTRACT. Every consumer codes against these shapes; changing one\n * is a breaking change.\n */\n\n/**\n * A JSON Schema document (draft 2020-12 subset in practice).\n *\n * Deliberately loose: protocol adapters translate this to their own schema\n * representation, and the gateway only validates structurally at trust\n * boundaries. Never treat this as trusted input without validation.\n */\nexport type JsonSchema = Record<string, unknown>;\n\n/**\n * Protocol surfaces a resource can be exposed through in this release.\n *\n * The runtime list is the definition and the type is derived from it, so a\n * caller that has to *check* a name (config validation, the OpenAPI\n * importer's `--expose`) reads the same strings the type is built from\n * rather than keeping a second copy that can drift.\n */\nexport type ProtocolName = 'http' | 'mcp' | 'a2a' | 'acp';\n\n/**\n * The same names as a value, for code that has to *check* one at\n * runtime - config validation, the OpenAPI importer's `--expose`. Typed\n * against `ProtocolName` so an unsupported name cannot enter the list, which\n * is what keeps this from becoming a second definition that drifts.\n */\nexport const PROTOCOL_NAMES: readonly ProtocolName[] = ['http', 'mcp', 'a2a', 'acp'];\n\n/** Payment methods a resource can accept in this release. */\nexport type PaymentMethodName = 'x402';\n\n/**\n * Authorization methods a resource can require in this release.\n *\n * Deliberately not a `ProtocolName` and not a `PaymentMethodName`: an\n * authorization method is neither a transport nor a payment rail. It proves\n * the purchase was approved, and sits beside the payment rather than\n * replacing it.\n */\nexport type AuthorizationMethodName = 'ap2';\n\n/** ISO-8601 timestamp string, always UTC with millisecond precision. */\nexport type IsoTimestamp = string;\n\n/**\n * A decimal amount expressed as a string in the *display* unit of the currency\n * (for example \"0.01\" USDC), never as a float and never in base units.\n *\n * Conversion to on-chain base units is a payment-provider responsibility.\n */\nexport type DecimalAmount = string;\n\n/** Health of an individual adapter or subsystem. */\nexport interface AdapterHealth {\n readonly status: 'pass' | 'warn' | 'fail';\n readonly detail?: string;\n readonly checkedAt: IsoTimestamp;\n readonly durationMs?: number;\n}\n\n/**\n * Self-description every adapter must expose so diagnostics can report exactly\n * what is supported instead of implying blanket protocol compatibility.\n *\n *\n */\nexport interface AdapterDescriptor {\n readonly name: string;\n readonly kind: 'protocol' | 'payment' | 'storage' | 'authorization';\n /** Version of this adapter implementation (independent of the spec). */\n readonly implementationVersion: string;\n /** Exact pinned specification revision this adapter targets. */\n readonly supportedSpec: string;\n readonly capabilities: readonly string[];\n readonly status: 'stable' | 'experimental' | 'planned';\n /** Capabilities explicitly NOT implemented, surfaced by `doctor`. */\n readonly unsupported?: readonly string[];\n}\n","/**\n * Canonical commerce events.\n *\n * FROZEN CONTRACT. Every event in a single flow shares one `requestId` so that\n * logs, payment attempts, backend calls and receipts are correlatable.\n */\nimport type { IsoTimestamp } from './common.js';\n\nexport const COMMERCE_EVENT_TYPES = [\n 'resource.discovered',\n 'resource.requested',\n 'payment.required',\n 'payment.rejected',\n 'payment.verified',\n 'payment.settled',\n // The same two types whatever the method, so an audit-trail reader never\n // has to know what AP2 is\n 'authorization.verified',\n 'authorization.rejected',\n 'backend.called',\n 'backend.failed',\n 'resource.delivered',\n] as const;\n\nexport type CommerceEventType = (typeof COMMERCE_EVENT_TYPES)[number];\n\nexport interface CommerceEvent {\n readonly id: string;\n readonly type: CommerceEventType;\n readonly requestId: string;\n readonly resourceId?: string;\n readonly at: IsoTimestamp;\n /** Protocol adapter that originated the request, e.g. 'mcp' or 'http'. */\n readonly adapter?: string;\n readonly paymentProvider?: string;\n readonly durationMs?: number;\n readonly status?: 'ok' | 'error';\n /** Non-secret, structured detail. Must never contain keys, headers or proofs. */\n readonly data?: Readonly<Record<string, unknown>>;\n}\n\n/**\n * Sink for canonical events.\n *\n * Implementations must be non-throwing from the caller's perspective: an event\n * sink failure must never fail an otherwise successful commerce flow.\n */\nexport interface EventSink {\n emit(event: CommerceEvent): Promise<void>;\n}\n","/**\n * Canonical resource model.\n *\n * FROZEN CONTRACT.\n */\nimport type {\n AuthorizationMethodName,\n DecimalAmount,\n JsonSchema,\n PaymentMethodName,\n ProtocolName,\n} from './common.js';\n\n/** HTTP methods a backend handler may use. */\nexport type BackendMethod = 'GET' | 'POST' | 'PUT' | 'PATCH' | 'DELETE';\n\n/**\n * Describes how the gateway calls the merchant's existing backend.\n *\n * Backend URLs are administrator-controlled configuration only. User- or\n * agent-controlled backend URLs are forbidden (see docs/security.md, SSRF).\n * Secret header values must come from `${ENV_VAR}` placeholders resolved by\n * the config loader, never from plaintext configuration.\n */\nexport interface BackendHandler {\n readonly type: 'http';\n readonly method: BackendMethod;\n readonly url: string;\n readonly headers?: Readonly<Record<string, string>>;\n /** Hard upper bound on the backend call. Defaults to DEFAULT_BACKEND_TIMEOUT_MS. */\n readonly timeoutMs?: number;\n /**\n * Names the top-level input properties carrying each part of the request.\n *\n * Absent (the default) keeps the original mapping: `{param}` values are read\n * from top-level input and everything left over becomes either the query\n * string (GET/DELETE) or the entire JSON body (POST/PUT/PATCH). That mapping\n * cannot express `POST /users/{userId}/orders?notify=true` with a JSON body\n * - one perfectly ordinary REST operation with all three parts at once.\n *\n * When present, each group is sourced independently and top-level input that\n * no binding names is not forwarded to the backend at all.\n */\n readonly inputBindings?: {\n readonly path?: string;\n readonly query?: string;\n readonly body?: string;\n };\n}\n\n/** Default backend timeout when a resource does not specify one. */\nexport const DEFAULT_BACKEND_TIMEOUT_MS = 10_000;\n\n/**\n * Canonical pricing.\n *\n * `dynamic` exists in the type system for forward compatibility but is\n * REJECTED by config validation in this release.\n */\nexport type Pricing =\n | { readonly type: 'free' }\n | {\n readonly type: 'fixed';\n readonly amount: DecimalAmount;\n readonly currency: string;\n }\n | {\n readonly type: 'dynamic';\n readonly resolver: string;\n };\n\n/**\n * A merchant capability exposed to agents.\n *\n * The canonical resource is the single source of truth: protocol adapters map\n * it outward, they never define their own parallel notion of a resource.\n */\nexport interface CommerceResource {\n readonly id: string;\n readonly name: string;\n readonly description?: string;\n readonly inputSchema?: JsonSchema;\n readonly outputSchema?: JsonSchema;\n readonly handler: BackendHandler;\n readonly pricing: Pricing;\n readonly exposedVia: readonly ProtocolName[];\n readonly paymentMethods: readonly PaymentMethodName[];\n /**\n * Authorization the buyer must present in addition to payment.\n *\n * Opt-in per resource and absent by default, so every resource configured\n * before this existed behaves exactly as it did. It sits beside\n * `paymentMethods` rather than inside it: an authorization method is not a\n * payment rail and must never be selectable as one.\n */\n readonly authorization?: {\n readonly required: readonly AuthorizationMethodName[];\n };\n}\n\n/** Read-only view of every configured resource. */\nexport interface ResourceRegistry {\n get(id: string): CommerceResource | undefined;\n list(): readonly CommerceResource[];\n /** Resources exposed through a given protocol surface. */\n listExposedVia(protocol: ProtocolName): readonly CommerceResource[];\n has(id: string): boolean;\n}\n","/**\n * Typed domain error codes.\n *\n * FROZEN CONTRACT. Protocol adapters map these codes into their own response\n * format. Never throw a bare string or untyped Error across a package boundary.\n */\nexport const COMMERCE_ERROR_CODES = [\n 'CONFIG_INVALID',\n 'RESOURCE_NOT_FOUND',\n 'INPUT_INVALID',\n 'PAYMENT_REQUIRED',\n 'PAYMENT_INVALID',\n 'PAYMENT_REPLAYED',\n 'PAYMENT_PROVIDER_UNAVAILABLE',\n 'PAYMENT_SETTLEMENT_FAILED',\n 'AUTHORIZATION_REQUIRED',\n 'AUTHORIZATION_INVALID',\n 'AUTHORIZATION_REPLAYED',\n 'AUTHORIZATION_PROVIDER_UNAVAILABLE',\n 'BACKEND_TIMEOUT',\n 'BACKEND_ERROR',\n 'PROTOCOL_UNSUPPORTED',\n 'GATEWAY_BUSY',\n 'STORAGE_ERROR',\n 'INTERNAL_ERROR',\n] as const;\n\nexport type CommerceErrorCode = (typeof COMMERCE_ERROR_CODES)[number];\n\n/**\n * Canonical HTTP status for each error code.\n *\n * Paid resources fail closed: every payment failure maps to a 4xx/5xx status\n * and never to a successful delivery.\n */\nexport const COMMERCE_ERROR_HTTP_STATUS: Readonly<Record<CommerceErrorCode, number>> = {\n CONFIG_INVALID: 500,\n RESOURCE_NOT_FOUND: 404,\n INPUT_INVALID: 400,\n PAYMENT_REQUIRED: 402,\n PAYMENT_INVALID: 402,\n PAYMENT_REPLAYED: 409,\n PAYMENT_PROVIDER_UNAVAILABLE: 503,\n PAYMENT_SETTLEMENT_FAILED: 502,\n // 403, not 402: the buyer's money is not the problem. A 402 tells a client\n // \"pay and retry\", which cannot fix a missing or rejected mandate, and a\n // client that auto-pays on 402 would be charged for a request that was\n // never going to be delivered.\n AUTHORIZATION_REQUIRED: 403,\n AUTHORIZATION_INVALID: 403,\n AUTHORIZATION_REPLAYED: 409,\n AUTHORIZATION_PROVIDER_UNAVAILABLE: 503,\n BACKEND_TIMEOUT: 504,\n BACKEND_ERROR: 502,\n PROTOCOL_UNSUPPORTED: 501,\n GATEWAY_BUSY: 503,\n STORAGE_ERROR: 500,\n INTERNAL_ERROR: 500,\n};\n\n/** Codes for which a client may reasonably retry the same request. */\nexport const RETRYABLE_ERROR_CODES: ReadonlySet<CommerceErrorCode> = new Set([\n 'PAYMENT_PROVIDER_UNAVAILABLE',\n // Our verifier or our replay store was unreachable, so no verdict on the\n // mandate was ever reached. That is an outage on our side, and the same\n // proof will verify once it clears.\n 'AUTHORIZATION_PROVIDER_UNAVAILABLE',\n 'BACKEND_TIMEOUT',\n // Load shedding is transient by definition: the caller should back off and\n // try again. Before this code existed the MCP adapter's queue-full path threw\n // PROTOCOL_UNSUPPORTED — HTTP 501, retryable:false — so an agent framework\n // keyed on the machine-readable flag (which exists precisely so clients need\n // not parse prose) would read a momentary throttle as a permanent capability\n // gap and stop calling the tool.\n 'GATEWAY_BUSY',\n]);\n","/**\n * The single error type crossing package boundaries.\n *\n * FROZEN CONTRACT.\n */\nimport {\n COMMERCE_ERROR_HTTP_STATUS,\n type CommerceErrorCode,\n RETRYABLE_ERROR_CODES,\n} from './codes.js';\n\nexport interface CommerceErrorOptions {\n /** Structured, non-secret detail safe to return to a client. */\n readonly details?: Readonly<Record<string, unknown>>;\n readonly cause?: unknown;\n readonly requestId?: string;\n readonly resourceId?: string;\n /** Override the default HTTP status for this code. */\n readonly httpStatus?: number;\n}\n\n/** Serialisable wire form of a CommerceError. */\nexport interface CommerceErrorInfo {\n readonly code: CommerceErrorCode;\n readonly message: string;\n readonly httpStatus: number;\n readonly retryable: boolean;\n readonly requestId?: string;\n readonly resourceId?: string;\n readonly details?: Readonly<Record<string, unknown>>;\n}\n\nexport class CommerceError extends Error {\n readonly code: CommerceErrorCode;\n readonly httpStatus: number;\n readonly retryable: boolean;\n readonly details?: Readonly<Record<string, unknown>>;\n readonly requestId?: string;\n readonly resourceId?: string;\n\n constructor(code: CommerceErrorCode, message: string, options: CommerceErrorOptions = {}) {\n super(message, options.cause !== undefined ? { cause: options.cause } : undefined);\n this.name = 'CommerceError';\n this.code = code;\n this.httpStatus = options.httpStatus ?? COMMERCE_ERROR_HTTP_STATUS[code];\n this.retryable = RETRYABLE_ERROR_CODES.has(code);\n if (options.details !== undefined) this.details = options.details;\n if (options.requestId !== undefined) this.requestId = options.requestId;\n if (options.resourceId !== undefined) this.resourceId = options.resourceId;\n Error.captureStackTrace?.(this, CommerceError);\n }\n\n /** Non-secret, client-safe representation. */\n toInfo(): CommerceErrorInfo {\n return {\n code: this.code,\n message: this.message,\n httpStatus: this.httpStatus,\n retryable: this.retryable,\n ...(this.requestId !== undefined ? { requestId: this.requestId } : {}),\n ...(this.resourceId !== undefined ? { resourceId: this.resourceId } : {}),\n ...(this.details !== undefined ? { details: this.details } : {}),\n };\n }\n}\n\nexport function isCommerceError(value: unknown): value is CommerceError {\n return value instanceof CommerceError;\n}\n\n/**\n * Normalise any thrown value into a CommerceError.\n *\n * Used at package boundaries so an unexpected failure never escapes untyped.\n *\n * SECURITY — do not \"improve\" this by propagating `value.message`.\n * `CommerceError.message` is client-visible: it is serialised by `toInfo()`\n * and `toErrorEnvelope()` and returned over HTTP and MCP. An arbitrary thrown\n * Error's message routinely carries internal detail — database connection\n * strings, internal hostnames, filesystem paths, backend URLs. Copying it into\n * a client-facing field turns every unexpected exception into an information\n * disclosure.\n *\n * The original value is preserved on `cause`, which is never serialised, so\n * logs and diagnostics keep the full detail while clients get only the\n * caller's deliberate, reviewed `fallbackMessage`.\n *\n * A caller that *wants* a specific client-facing message passes one:\n * toCommerceError(err, 'BACKEND_ERROR', 'Backend call failed')\n */\nexport function toCommerceError(\n value: unknown,\n fallbackCode: CommerceErrorCode = 'INTERNAL_ERROR',\n fallbackMessage = 'Unexpected internal error',\n): CommerceError {\n if (isCommerceError(value)) return value;\n return new CommerceError(fallbackCode, fallbackMessage, { cause: value });\n}\n","/**\n * Gateway-defined wire envelopes.\n *\n * FROZEN CONTRACT. These are the *only* representations of \"payment required\"\n * and \"error\" that leave the gateway, whichever protocol carries them. The HTTP\n * routes, the MCP adapter and the demo buyer agent all use these helpers so the\n * three can never drift apart.\n */\n\nimport { CommerceError, type CommerceErrorCode } from '../errors/index.js';\nimport type { AuthorizationRequirement, AuthorizationSubmission } from './authorization.js';\nimport type { DecimalAmount, IsoTimestamp, PaymentMethodName } from './common.js';\nimport type { PaymentSubmission } from './payment.js';\nimport type { DeliveredOutcome, PaymentRequiredOutcome } from './request.js';\nimport type { CommerceResource } from './resource.js';\n\n/**\n * Reserved input property carrying a payment proof on protocols that have no\n * header channel (MCP tool calls). Over HTTP the `PAYMENT-SIGNATURE` header is\n * used.\n */\nexport const PAYMENT_INPUT_FIELD = '_payment';\n\n/**\n * HTTP request header carrying the payment proof.\n *\n * x402 v2 header names, lowercased because that is how Node presents incoming\n * headers. v1's `X-PAYMENT` / `X-PAYMENT-RESPONSE` pair is not accepted: this\n * gateway speaks one protocol version, and quietly honouring both would mean\n * two verification paths for the same money.\n */\nexport const PAYMENT_HEADER = 'payment-signature';\n\n/** HTTP response header carrying the settlement result. */\nexport const PAYMENT_RESPONSE_HEADER = 'payment-response';\n\n/**\n * Reserved input property carrying an authorization proof, the authorization\n * counterpart of {@link PAYMENT_INPUT_FIELD}.\n *\n * Unlike `_payment`, which is a bare string, this one carries an object:\n * `{ method, payload }`. There is exactly one payment rail per resource, so a\n * payment proof's method can be inferred from the resource; an authorization\n * proof cannot lean on that, and guessing the method of a security control is\n * not a thing to do implicitly.\n */\nexport const AUTHORIZATION_INPUT_FIELD = '_authorization';\n\n/**\n * Every input property name the gateway claims for itself.\n *\n * One list, read by the config loader (which rejects a resource declaring any\n * of them), by the protocol adapters that lift them out of client input, and\n * by the pipeline that strips them again as defence in depth. Those three\n * agree by construction instead of by three copies of two strings.\n */\nexport const RESERVED_INPUT_FIELDS: readonly string[] = [\n PAYMENT_INPUT_FIELD,\n AUTHORIZATION_INPUT_FIELD,\n];\n\n/**\n * HTTP request header carrying the authorization proof, base64url-encoded\n * JSON of the same `{ method, payload }` envelope the reserved input field\n * carries.\n *\n * This is an Agent Commerce transport carrier, not a header defined by any\n * authorization specification, so it is namespaced rather than borrowing\n * `Authorization`, which already means something else on every one of these\n * routes.\n */\nexport const AUTHORIZATION_HEADER = 'agent-authorization';\n\n/**\n * Hard cap on the encoded `Agent-Authorization` header.\n *\n * Node's own limit is ~16 KiB across *all* request headers, so an\n * authorization near that size would start evicting everything else and fail\n * as an unreadable transport error rather than a legible one. Capping well\n * below it means an oversized proof gets a deterministic\n * AUTHORIZATION_INVALID naming the limit.\n */\nexport const MAX_AUTHORIZATION_HEADER_BYTES = 8192;\n\n/**\n * HTTP response header carrying the base64 payment challenge on a 402.\n *\n * The 402 body still carries {@link PaymentRequiredEnvelope} — richer, and the\n * only channel MCP has — but an x402 v2 client reads the challenge from this\n * header and ignores the body, so both are sent.\n */\nexport const PAYMENT_REQUIRED_HEADER = 'payment-required';\n\n/**\n * Key under which a protocol adapter attaches a {@link DeliverySummary} to its\n * result metadata — MCP's `CallToolResult._meta`, and anywhere else a protocol\n * offers an out-of-band metadata channel.\n *\n * Frozen deliberately. The bug this whole mechanism exists to fix was two\n * surfaces disagreeing about what a payer gets back; a key name enforced only\n * by one side's tests would reintroduce exactly that drift. Producer and\n * consumer both import this constant.\n *\n * Follows MCP's `<namespace>/<name>` convention for `_meta` keys.\n */\nexport const DELIVERY_SUMMARY_META_KEY = 'agent-commerce/delivery';\n\nexport interface PaymentRequiredEnvelope {\n readonly status: 'payment-required';\n readonly code: 'PAYMENT_REQUIRED';\n readonly requestId: string;\n readonly resourceId: string;\n readonly message: string;\n readonly payment: {\n readonly provider: PaymentMethodName;\n readonly version: string;\n readonly amount: DecimalAmount;\n readonly currency: string;\n readonly destination: string;\n readonly network?: string;\n readonly asset?: string;\n readonly expiresAt?: IsoTimestamp;\n /** Provider-native requirement objects, passed through verbatim. */\n readonly accepts: readonly Readonly<Record<string, unknown>>[];\n /**\n * The provider's own challenge document, verbatim — see\n * {@link PaymentChallenge.envelope}. Present for providers that have one;\n * a buyer's protocol client can hand this straight to its SDK.\n */\n readonly envelope?: Readonly<Record<string, unknown>>;\n };\n /**\n * Present only when the resource requires an authorization proof as well.\n *\n * Additive: a client that does not understand the field sees exactly the\n * envelope it saw before. A client that does learns, before it spends\n * anything, that paying alone will not get the resource delivered.\n *\n * This advertises a requirement; it does not issue anything. The proof is\n * obtained from the merchant's own approval flow, outside the gateway.\n */\n readonly authorization?: {\n readonly required: readonly AuthorizationRequirement[];\n };\n}\n\nexport interface ErrorEnvelope {\n readonly status: 'error';\n readonly code: CommerceErrorCode;\n readonly message: string;\n readonly retryable: boolean;\n readonly requestId?: string;\n readonly resourceId?: string;\n readonly details?: Readonly<Record<string, unknown>>;\n}\n\n/**\n * What a buyer learns about their own completed purchase.\n *\n * A payer is entitled to the record of their own transaction — the request it\n * belonged to, whether it settled, and the settlement reference they can check\n * on-chain. They are NOT entitled to the merchant's ledger, which is why\n * `/api/receipts` is an operator route behind `server.adminToken`.\n *\n * Before this existed the two surfaces disagreed: HTTP callers received a\n * settlement summary in the payment-response header while MCP callers received\n * nothing, so an MCP buyer's only route to their own receipt was the merchant's\n * ledger. Both surfaces now emit this same shape.\n */\nexport interface DeliverySummary {\n readonly requestId: string;\n readonly resourceId: string;\n readonly receiptId: string;\n readonly deliveredAt: IsoTimestamp;\n readonly payment?: {\n readonly status: 'verified' | 'settled' | 'rejected';\n readonly amount: DecimalAmount;\n readonly currency: string;\n /** Settlement reference, e.g. an on-chain transaction hash. */\n readonly externalReference?: string;\n readonly network?: string;\n };\n}\n\n/** Build the payer-facing summary of a delivered outcome. */\nexport function toDeliverySummary(outcome: DeliveredOutcome): DeliverySummary {\n const p = outcome.payment;\n return {\n requestId: outcome.requestId,\n resourceId: outcome.resourceId,\n receiptId: outcome.receipt.id,\n deliveredAt: outcome.receipt.deliveredAt,\n ...(p !== undefined\n ? {\n payment: {\n status: p.status,\n amount: p.amount,\n currency: p.currency,\n ...(p.externalReference !== undefined\n ? { externalReference: p.externalReference }\n : {}),\n ...(p.network !== undefined ? { network: p.network } : {}),\n },\n }\n : {}),\n };\n}\n\nexport function toPaymentRequiredEnvelope(\n outcome: PaymentRequiredOutcome,\n): PaymentRequiredEnvelope {\n const r = outcome.requirement;\n return {\n status: 'payment-required',\n code: 'PAYMENT_REQUIRED',\n requestId: outcome.requestId,\n resourceId: outcome.resourceId,\n message: `Payment of ${r.amount} ${r.currency} is required for resource \"${outcome.resourceId}\". Retry with a ${r.provider} payment proof.`,\n payment: {\n provider: r.provider,\n version: r.challenge.version,\n amount: r.amount,\n currency: r.currency,\n destination: r.destination,\n ...(r.network !== undefined ? { network: r.network } : {}),\n ...(r.asset !== undefined ? { asset: r.asset } : {}),\n ...(r.expiresAt !== undefined ? { expiresAt: r.expiresAt } : {}),\n accepts: r.challenge.accepts,\n ...(r.challenge.envelope !== undefined ? { envelope: r.challenge.envelope } : {}),\n },\n ...(outcome.authorization !== undefined && outcome.authorization.length > 0\n ? { authorization: { required: outcome.authorization } }\n : {}),\n };\n}\n\nexport function toErrorEnvelope(error: CommerceError): ErrorEnvelope {\n const info = error.toInfo();\n return {\n status: 'error',\n code: info.code,\n message: info.message,\n retryable: info.retryable,\n ...(info.requestId !== undefined ? { requestId: info.requestId } : {}),\n ...(info.resourceId !== undefined ? { resourceId: info.resourceId } : {}),\n ...(info.details !== undefined ? { details: info.details } : {}),\n };\n}\n\nexport function isPaymentRequiredEnvelope(value: unknown): value is PaymentRequiredEnvelope {\n return (\n typeof value === 'object' &&\n value !== null &&\n (value as PaymentRequiredEnvelope).status === 'payment-required' &&\n typeof (value as PaymentRequiredEnvelope).payment === 'object'\n );\n}\n\n/**\n * Parses the `{ method, payload }` authorization envelope, whichever carrier\n * brought it.\n *\n * Absent is `undefined`. Present but malformed throws, rather than being\n * dropped the way an unusable `_payment` is. A dropped payment leaves the\n * buyer holding a 402 they can act on. A silently dropped authorization would\n * come back as \"not authorized\" for a proof the client believes it sent, with\n * no way to tell a rejected mandate from a typo in the envelope around it.\n */\nexport function parseAuthorizationSubmission(\n value: unknown,\n requestId?: string,\n): AuthorizationSubmission | undefined {\n if (value === undefined || value === null) return undefined;\n\n const fail = (detail: string): never => {\n throw new CommerceError('AUTHORIZATION_INVALID', `Malformed authorization: ${detail}`, {\n ...(requestId !== undefined ? { requestId } : {}),\n });\n };\n\n if (typeof value !== 'object' || Array.isArray(value)) {\n fail(`expected an object with \"method\" and \"payload\", got ${typeof value}`);\n }\n const record = value as Record<string, unknown>;\n const method = record['method'];\n const payload = record['payload'];\n\n // 'ap2' is the only method in this release. Compared against the literal\n // rather than a registry: a second method means a second verifier, and that\n // is a deliberate addition, not a string that should start working because\n // a client sent it.\n if (method !== 'ap2') {\n fail(`unsupported method ${typeof method === 'string' ? `\"${method}\"` : typeof method}`);\n }\n if (typeof payload !== 'string' || payload.length === 0) {\n fail('\"payload\" must be a non-empty string');\n }\n\n return { method: 'ap2', payload: payload as string };\n}\n\n/**\n * Decodes the base64url-JSON `Agent-Authorization` header.\n *\n * The size check runs on the encoded value before any decoding, so an\n * oversized header costs a length comparison rather than a base64 decode and\n * a JSON parse of whatever a caller chose to send.\n */\nexport function parseAuthorizationHeader(\n raw: string | readonly string[] | undefined,\n requestId?: string,\n): AuthorizationSubmission | undefined {\n const value = Array.isArray(raw) ? raw[0] : (raw as string | undefined);\n if (value === undefined || value.length === 0) return undefined;\n\n const fail = (detail: string): never => {\n throw new CommerceError('AUTHORIZATION_INVALID', `Malformed authorization: ${detail}`, {\n ...(requestId !== undefined ? { requestId } : {}),\n });\n };\n\n if (Buffer.byteLength(value, 'utf8') > MAX_AUTHORIZATION_HEADER_BYTES) {\n fail(`header exceeds the ${MAX_AUTHORIZATION_HEADER_BYTES}-byte limit`);\n }\n\n let decoded: unknown;\n try {\n decoded = JSON.parse(Buffer.from(value, 'base64url').toString('utf8'));\n } catch {\n // Nothing from the exception is repeated back: a JSON parse error quotes\n // the input it choked on, which here is whatever the caller sent.\n fail('header is not base64url-encoded JSON');\n }\n return parseAuthorizationSubmission(decoded, requestId);\n}\n\n/**\n * Splits raw client input into resource input plus the reserved fields the\n * gateway claims, for every protocol that carries them in the input object\n * (MCP tool arguments, A2A message data). HTTP carries both in headers and\n * uses the two parse helpers directly.\n *\n * The payment method comes from the resource's own declaration. This is not\n * the place that decides which rail a resource uses, so a proof for a\n * resource with no configured rail is dropped rather than forwarded under an\n * invented method. The pipeline then treats the request as unpaid and decides\n * on its own terms.\n */\nexport function extractReservedInputFields(\n rawInput: Record<string, unknown>,\n resource: CommerceResource | undefined,\n requestId?: string,\n): {\n input: Record<string, unknown>;\n payment?: PaymentSubmission;\n authorization?: AuthorizationSubmission;\n} {\n const {\n [PAYMENT_INPUT_FIELD]: paymentValue,\n [AUTHORIZATION_INPUT_FIELD]: authorizationValue,\n ...input\n } = rawInput;\n\n const method = resource?.paymentMethods[0];\n const payment =\n typeof paymentValue === 'string' && paymentValue.length > 0 && method !== undefined\n ? ({ method, payload: paymentValue } satisfies PaymentSubmission)\n : undefined;\n const authorization = parseAuthorizationSubmission(authorizationValue, requestId);\n\n return {\n input,\n ...(payment !== undefined ? { payment } : {}),\n ...(authorization !== undefined ? { authorization } : {}),\n };\n}\n","/**\n * Minimal structural logger interface.\n *\n * Core must not depend on pino directly; the gateway injects a pino instance\n * that satisfies this shape. Never log secrets: private keys, seed phrases,\n * Authorization headers or payment authorisation payloads.\n */\nexport interface Logger {\n debug(obj: Record<string, unknown>, msg?: string): void;\n info(obj: Record<string, unknown>, msg?: string): void;\n warn(obj: Record<string, unknown>, msg?: string): void;\n error(obj: Record<string, unknown>, msg?: string): void;\n child(bindings: Record<string, unknown>): Logger;\n}\n\n/** A logger that discards everything. Useful in unit tests. */\nexport const NOOP_LOGGER: Logger = {\n debug: () => {},\n info: () => {},\n warn: () => {},\n error: () => {},\n child: () => NOOP_LOGGER,\n};\n","/**\n * Protocol adapter boundary.\n *\n * FROZEN CONTRACT. An adapter translates a protocol's wire format into a\n * `CanonicalRequest`, hands it to the execution pipeline and maps the outcome\n * back. It must not call merchant backends, implement payment logic, or hold\n * its own copy of the canonical model.\n *\n * Adapter isolation: a failure while starting or serving one adapter must not\n * prevent the others from operating.\n */\nimport type { IncomingMessage, ServerResponse } from 'node:http';\nimport type { AdapterDescriptor, AdapterHealth, ProtocolName } from '../domain/common.js';\nimport type { EventSink } from '../domain/event.js';\nimport type { ExecutionPipeline } from '../domain/request.js';\nimport type { ResourceRegistry } from '../domain/resource.js';\nimport type { Logger } from './logger.js';\nimport type { Clock, IdGenerator } from './runtime.js';\n\n/** Everything an adapter is given. Nothing else is available to it. */\nexport interface ProtocolAdapterContext {\n readonly pipeline: ExecutionPipeline;\n readonly resources: ResourceRegistry;\n readonly events: EventSink;\n readonly logger: Logger;\n readonly clock: Clock;\n readonly ids: IdGenerator;\n /** Externally reachable base URL of the gateway, from config. */\n readonly publicBaseUrl: string;\n}\n\nexport interface ProtocolAdapter {\n readonly name: ProtocolName;\n readonly descriptor: AdapterDescriptor;\n\n start(context: ProtocolAdapterContext): Promise<void>;\n health(): Promise<AdapterHealth>;\n stop(): Promise<void>;\n}\n\n/**\n * A protocol adapter served over HTTP.\n *\n * The gateway mounts `handleHttp` at `mountPath` using raw Node request and\n * response objects, so adapters stay independent of the HTTP framework.\n *\n * GUARANTEE — the request body is **unconsumed**.\n *\n * `req` is handed over with its stream unread: the gateway suppresses every\n * body parser on this mount, so an adapter whose SDK reads the body itself\n * (MCP's Streamable HTTP transport does) can do so. The adapter owns reading,\n * size-limiting beyond the gateway's own cap, and parsing.\n *\n * This is load-bearing and easy to break silently. Fastify pre-registers\n * exact-match parsers for `application/json` and `text/plain` and prefers them\n * over a `'*'` wildcard, so registering only a wildcard no-op leaves the\n * built-in JSON parser draining the body first — the adapter then reads an\n * empty stream and every request fails to parse. That exact regression shipped\n * once and no unit test caught it, because adapter conformance suites drive\n * `handleHttp` over a bare `node:http` server and never traverse the gateway.\n *\n * Any change to how adapters are mounted must be covered by a test that POSTs\n * a real JSON body through the real gateway and asserts the adapter received\n * it intact.\n */\nexport interface HttpProtocolAdapter extends ProtocolAdapter {\n /** Path prefix the gateway mounts this adapter at, e.g. '/mcp'. */\n readonly mountPath: string;\n handleHttp(req: IncomingMessage, res: ServerResponse): Promise<void>;\n /**\n * Fixed paths this adapter owns *outside* its mount, for protocols whose\n * specification pins a discovery URL (A2A's `/.well-known/agent-card.json`).\n * The gateway mounts them with the same guarantees as `mountPath` — same\n * unconsumed body, same concurrency cap, same failure isolation — so the\n * gateway needs no per-protocol routing knowledge.\n *\n * Omitted by adapters that need none.\n */\n readonly additionalHttpRoutes?: readonly AdapterHttpRoute[];\n}\n\n/**\n * One fixed, method-scoped route owned by an adapter. Unlike `mountPath` it\n * registers no wildcard: it matches exactly the path given.\n */\nexport interface AdapterHttpRoute {\n readonly method: 'GET' | 'POST';\n /** Absolute gateway path, e.g. '/.well-known/agent-card.json'. */\n readonly path: string;\n handleHttp(req: IncomingMessage, res: ServerResponse): Promise<void>;\n}\n\nexport function isHttpProtocolAdapter(adapter: ProtocolAdapter): adapter is HttpProtocolAdapter {\n return typeof (adapter as HttpProtocolAdapter).handleHttp === 'function';\n}\n","/**\n * Injected runtime primitives.\n *\n * Everything non-deterministic (time, ids) is injected so tests can be exact.\n */\nimport type { IsoTimestamp } from '../domain/common.js';\n\nexport interface Clock {\n now(): Date;\n nowIso(): IsoTimestamp;\n /** Milliseconds since an arbitrary origin; use for durations only. */\n monotonicMs(): number;\n}\n\nexport interface IdGenerator {\n /** Opaque, collision-resistant identifier. */\n next(prefix?: string): string;\n}\n\nexport const systemClock: Clock = {\n now: () => new Date(),\n nowIso: () => new Date().toISOString(),\n monotonicMs: () => performance.now(),\n};\n","/**\n * The package version, resolved once for the whole package.\n *\n * Two paths, deliberately:\n *\n * - **Development** reads the root manifest, so the number is always live.\n * - **The published bundle cannot.** tsup collapses `src/**` into\n * `dist/index.js` and `dist/cli/index.js`, so any `require('../../package.json')`\n * written against a source path resolves from the wrong depth once bundled —\n * which is exactly how this broke during the single-package refactor, and how\n * it earlier produced a CLI reporting `v0.0.0-unknown`. The build injects\n * `__OAC_PACKAGE_VERSION__` instead (see tsup.config.ts).\n *\n * `typeof` on an undeclared identifier is safe in JS, so the dev path is\n * unaffected by the constant not existing.\n */\nimport { createRequire } from 'node:module';\n\ndeclare const __OAC_PACKAGE_VERSION__: string | undefined;\n\nfunction readFromManifest(): string {\n try {\n const require = createRequire(import.meta.url);\n // src/version.ts -> repository root\n return (require('../package.json') as { version?: string }).version ?? '0.0.0-unknown';\n } catch {\n return '0.0.0-unknown';\n }\n}\n\nexport const PACKAGE_VERSION: string =\n typeof __OAC_PACKAGE_VERSION__ === 'string' ? __OAC_PACKAGE_VERSION__ : readFromManifest();\n"]}
|