@nevermined-io/payments 1.9.0 → 1.11.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.
Files changed (98) hide show
  1. package/dist/api/base-payments.d.ts +11 -0
  2. package/dist/api/base-payments.d.ts.map +1 -1
  3. package/dist/api/base-payments.js +28 -3
  4. package/dist/api/base-payments.js.map +1 -1
  5. package/dist/api/nvm-api.d.ts +4 -0
  6. package/dist/api/nvm-api.d.ts.map +1 -1
  7. package/dist/api/nvm-api.js +7 -0
  8. package/dist/api/nvm-api.js.map +1 -1
  9. package/dist/api/organizations-api/organizations-api.d.ts +19 -1
  10. package/dist/api/organizations-api/organizations-api.d.ts.map +1 -1
  11. package/dist/api/organizations-api/organizations-api.js +49 -0
  12. package/dist/api/organizations-api/organizations-api.js.map +1 -1
  13. package/dist/api/organizations-api/types.d.ts +27 -0
  14. package/dist/api/organizations-api/types.d.ts.map +1 -1
  15. package/dist/api/organizations-api/types.js.map +1 -1
  16. package/dist/common/api-version.d.ts +1 -1
  17. package/dist/common/api-version.js +1 -1
  18. package/dist/common/api-version.js.map +1 -1
  19. package/dist/common/types.d.ts +9 -4
  20. package/dist/common/types.d.ts.map +1 -1
  21. package/dist/common/types.js.map +1 -1
  22. package/dist/environments.d.ts +12 -0
  23. package/dist/environments.d.ts.map +1 -1
  24. package/dist/environments.js +31 -0
  25. package/dist/environments.js.map +1 -1
  26. package/dist/index.d.ts +1 -0
  27. package/dist/index.d.ts.map +1 -1
  28. package/dist/index.js +2 -0
  29. package/dist/index.js.map +1 -1
  30. package/dist/mcp/core/server-manager.d.ts.map +1 -1
  31. package/dist/mcp/core/server-manager.js +3 -0
  32. package/dist/mcp/core/server-manager.js.map +1 -1
  33. package/dist/mcp/http/mcp-handler.d.ts +7 -0
  34. package/dist/mcp/http/mcp-handler.d.ts.map +1 -1
  35. package/dist/mcp/http/mcp-handler.js +8 -1
  36. package/dist/mcp/http/mcp-handler.js.map +1 -1
  37. package/dist/mcp/http/oauth-metadata.d.ts.map +1 -1
  38. package/dist/mcp/http/oauth-metadata.js +31 -6
  39. package/dist/mcp/http/oauth-metadata.js.map +1 -1
  40. package/dist/mcp/http/oauth-router.d.ts +17 -16
  41. package/dist/mcp/http/oauth-router.d.ts.map +1 -1
  42. package/dist/mcp/http/oauth-router.js +56 -28
  43. package/dist/mcp/http/oauth-router.js.map +1 -1
  44. package/dist/mpp/codec.d.ts +92 -0
  45. package/dist/mpp/codec.d.ts.map +1 -0
  46. package/dist/mpp/codec.js +405 -0
  47. package/dist/mpp/codec.js.map +1 -0
  48. package/dist/mpp/errors.d.ts +165 -0
  49. package/dist/mpp/errors.d.ts.map +1 -0
  50. package/dist/mpp/errors.js +177 -0
  51. package/dist/mpp/errors.js.map +1 -0
  52. package/dist/mpp/fetch.d.ts +196 -0
  53. package/dist/mpp/fetch.d.ts.map +1 -0
  54. package/dist/mpp/fetch.js +493 -0
  55. package/dist/mpp/fetch.js.map +1 -0
  56. package/dist/mpp/index.d.ts +11 -0
  57. package/dist/mpp/index.d.ts.map +1 -0
  58. package/dist/mpp/index.js +20 -0
  59. package/dist/mpp/index.js.map +1 -0
  60. package/dist/mpp/mpp-api.d.ts +153 -0
  61. package/dist/mpp/mpp-api.d.ts.map +1 -0
  62. package/dist/mpp/mpp-api.js +298 -0
  63. package/dist/mpp/mpp-api.js.map +1 -0
  64. package/dist/mpp/types.d.ts +43 -0
  65. package/dist/mpp/types.d.ts.map +1 -0
  66. package/dist/mpp/types.js +9 -0
  67. package/dist/mpp/types.js.map +1 -0
  68. package/dist/payments.d.ts +13 -0
  69. package/dist/payments.d.ts.map +1 -1
  70. package/dist/payments.js +3 -0
  71. package/dist/payments.js.map +1 -1
  72. package/dist/x402/delegation-api.d.ts +3 -1
  73. package/dist/x402/delegation-api.d.ts.map +1 -1
  74. package/dist/x402/delegation-api.js.map +1 -1
  75. package/dist/x402/express/index.d.ts +2 -0
  76. package/dist/x402/express/index.d.ts.map +1 -1
  77. package/dist/x402/express/index.js +2 -0
  78. package/dist/x402/express/index.js.map +1 -1
  79. package/dist/x402/express/middleware.d.ts +33 -1
  80. package/dist/x402/express/middleware.d.ts.map +1 -1
  81. package/dist/x402/express/middleware.js +831 -1
  82. package/dist/x402/express/middleware.js.map +1 -1
  83. package/dist/x402/express/mpp-support.d.ts +58 -0
  84. package/dist/x402/express/mpp-support.d.ts.map +1 -0
  85. package/dist/x402/express/mpp-support.js +67 -0
  86. package/dist/x402/express/mpp-support.js.map +1 -0
  87. package/dist/x402/express/raw-body.d.ts +24 -0
  88. package/dist/x402/express/raw-body.d.ts.map +1 -0
  89. package/dist/x402/express/raw-body.js +34 -0
  90. package/dist/x402/express/raw-body.js.map +1 -0
  91. package/dist/x402/token-request.d.ts +15 -0
  92. package/dist/x402/token-request.d.ts.map +1 -0
  93. package/dist/x402/token-request.js +66 -0
  94. package/dist/x402/token-request.js.map +1 -0
  95. package/dist/x402/token.d.ts.map +1 -1
  96. package/dist/x402/token.js +7 -51
  97. package/dist/x402/token.js.map +1 -1
  98. package/package.json +3 -1
@@ -0,0 +1,153 @@
1
+ /**
2
+ * The Machine Payments Protocol (MPP) API.
3
+ *
4
+ * MPP is a second payment framing over the unchanged Nevermined core: the same
5
+ * plan, the same delegation and the same credit burn as x402, negotiated with
6
+ * MPP headers. Sellers issue a challenge and redeem a credential; buyers mint
7
+ * an MPP-domain access token and present it as a credential.
8
+ */
9
+ import { BasePaymentsAPI } from '../api/base-payments.js';
10
+ import type { PaymentOptions, X402TokenOptions } from '../common/types.js';
11
+ import type { SettlePermissionsResult, VerifyPermissionsResult } from '../x402/facilitator-api.js';
12
+ import { type MppFetchOptions, type MppFetchResult } from './fetch.js';
13
+ /**
14
+ * Normalizes `credits` to the exact decimal-string amount that gets sealed
15
+ * into the challenge and burned. A bare `.toString()` on a JS `number` can
16
+ * emit scientific notation (`1e+21`), `"NaN"` or `"Infinity"` — all
17
+ * forwarded unvalidated into an amount this PR's own docs describe as
18
+ * having "no post-hoc re-pricing as there is with x402": a corrupted amount
19
+ * here is not correctable downstream, it IS the amount.
20
+ *
21
+ * `BigInt(x)` renders an integer-valued number exactly (no scientific
22
+ * notation) and throws `RangeError` on a non-integer, `NaN` or `Infinity`
23
+ * instead of silently stringifying them — which is why non-string inputs go
24
+ * through it. The `string` arm gets its own check instead of relying on
25
+ * `BigInt`'s string parsing, which is far more permissive than a decimal
26
+ * string contract should be.
27
+ */
28
+ export declare function normalizeCredits(credits: string | number | bigint): string;
29
+ export interface IssueMppChallengeParams {
30
+ /** The Nevermined plan the credits are burned against. */
31
+ planId: string;
32
+ /** Credits the buyer is asked to redeem. Sent as a decimal string. */
33
+ credits: string | number | bigint;
34
+ agentId?: string;
35
+ /** The protected resource. Sealed into the challenge and re-asserted at redeem. */
36
+ resource: string;
37
+ /** HTTP verb of that resource. Part of the same binding. */
38
+ httpVerb: string;
39
+ /** `sha-256=<base64>` digest binding the challenge to one request body. */
40
+ digest?: string;
41
+ description?: string;
42
+ }
43
+ export interface RedeemMppParams {
44
+ /** The `Authorization: Payment …` value presented by the buyer. */
45
+ credential: string;
46
+ /** Must equal the resource the challenge was issued for. */
47
+ resource: string;
48
+ /** Must equal the verb the challenge was issued for. */
49
+ httpVerb: string;
50
+ /** Digest of the body actually received, when the challenge bound one. */
51
+ bodyDigest?: string;
52
+ }
53
+ /**
54
+ * A discriminated union rather than a flat `paymentReceipt: string`: a
55
+ * settlement can fail, and `SettlePermissionsResult.success` already says
56
+ * so, but the flat shape let `{ success: false }` with no receipt typecheck
57
+ * — a state the seller middleware then had no way to reject at compile time
58
+ * even though it could not safely attach a receipt header for it.
59
+ */
60
+ export type MppSettleResult = (SettlePermissionsResult & {
61
+ success: true;
62
+ paymentReceipt: string;
63
+ }) | (SettlePermissionsResult & {
64
+ success: false;
65
+ paymentReceipt?: string;
66
+ });
67
+ export declare class MppAPI extends BasePaymentsAPI {
68
+ static getInstance(options: PaymentOptions): MppAPI;
69
+ /**
70
+ * Mints the challenge a plan-protected endpoint returns with its 402.
71
+ *
72
+ * Each call returns a distinct challenge even for identical inputs — the id
73
+ * doubles as the burn idempotency key, so two requests sharing one would
74
+ * settle as a single burn.
75
+ */
76
+ issueChallenge(params: IssueMppChallengeParams): Promise<{
77
+ challenge: string;
78
+ id: string;
79
+ }>;
80
+ /** Runs the full credential and plan checks without burning anything. */
81
+ verifyCredential(params: RedeemMppParams): Promise<VerifyPermissionsResult>;
82
+ /**
83
+ * Verifies and burns through the same chokepoint an x402 settlement uses, so
84
+ * the credits charged are identical on both protocols. Settling the same
85
+ * credential twice burns once.
86
+ */
87
+ settleCredential(params: RedeemMppParams): Promise<MppSettleResult>;
88
+ /**
89
+ * Mints an access token signed under the `Nevermined-MPP` EIP-712 domain.
90
+ *
91
+ * Same inputs and same settlement rail as {@link X402TokenAPI.getX402AccessToken};
92
+ * the token verifies only on the MPP routes, which is what keeps the two
93
+ * protocols isolated even though the tokens are byte-identical on the wire.
94
+ */
95
+ getMppAccessToken(planId: string, agentId?: string, tokenOptions?: X402TokenOptions): Promise<{
96
+ accessToken: string;
97
+ }>;
98
+ /**
99
+ * Performs an HTTP request, paying an MPP challenge if the endpoint returns
100
+ * one.
101
+ *
102
+ * The buyer needs no new plan, delegation or credential: the delegation that
103
+ * works for x402 works here unchanged.
104
+ *
105
+ * `init.body`, if set, must be replayable **if the endpoint may challenge
106
+ * the request**: a `ReadableStream` throws a typed {@link PaymentsError}
107
+ * once a 402 challenge actually requires a retry, since the stream cannot
108
+ * be resent. A request that is never challenged sends a stream body exactly
109
+ * once, exactly like plain `fetch` — the `paid: false` / untouched-response
110
+ * guarantee still holds. A `string`, `Buffer`/`ArrayBuffer`/typed array,
111
+ * `URLSearchParams`, `FormData` or `Blob` body all work unchanged either way.
112
+ *
113
+ * `options.delegationConfig` must carry a `delegationId` — this call
114
+ * refuses the deprecated inline create-on-the-fly shape (no `delegationId`)
115
+ * that {@link X402TokenAPI.getX402AccessToken} otherwise tolerates with a
116
+ * warning: the retry loop here can mint an access token twice per call, so
117
+ * that shape could silently create two delegations as a side effect of
118
+ * paying.
119
+ *
120
+ * @example
121
+ * ```typescript
122
+ * const { response, receipt } = await payments.mpp.fetch(
123
+ * 'https://agent.example/ask',
124
+ * { method: 'POST', body: JSON.stringify({ q: 'hello' }) },
125
+ * { delegationConfig: { delegationId }, planId },
126
+ * )
127
+ * ```
128
+ */
129
+ fetch(input: string | URL, init: RequestInit | undefined, options: MppFetchOptions): Promise<MppFetchResult>;
130
+ private redeemBody;
131
+ /**
132
+ * One place for the POST + error translation both surfaces share.
133
+ *
134
+ * `burns` marks a call where "no answer" is not the same as "did not
135
+ * happen" — currently only `settleCredential`. For that call alone, a
136
+ * fetch rejection caused by OUR OWN `AbortSignal.timeout()` firing (not
137
+ * some other network failure) is raised as {@link MppSettlementOutcomeUnknownError}
138
+ * instead of the generic `network_error` `MppError` used everywhere else,
139
+ * so a caller can tell "definitely nothing happened" apart from "the
140
+ * backend may have already burned the credits; we just didn't hear back".
141
+ * `error.name === 'TimeoutError'` combined with `instanceof DOMException`
142
+ * is the documented, empirically-confirmed shape Node's `fetch` throws
143
+ * when an `AbortSignal.timeout()` deadline fires — as opposed to, say,
144
+ * connection-refused, which surfaces as a plain `TypeError`.
145
+ *
146
+ * The same reasoning covers the other two ways a burning call can end
147
+ * without a definite answer: an upstream 5xx/408, and a 2xx whose body
148
+ * could not be read. All three raise {@link MppSettlementOutcomeUnknownError};
149
+ * only a 4xx — the backend deliberately rejecting — is a definite failure.
150
+ */
151
+ private post;
152
+ }
153
+ //# sourceMappingURL=mpp-api.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"mpp-api.d.ts","sourceRoot":"","sources":["../../src/mpp/mpp-api.ts"],"names":[],"mappings":"AAAA;;;;;;;GAOG;AAEH,OAAO,EAAE,eAAe,EAAE,MAAM,yBAAyB,CAAA;AAQzD,OAAO,KAAK,EAAE,cAAc,EAAE,gBAAgB,EAAE,MAAM,oBAAoB,CAAA;AAC1E,OAAO,KAAK,EAAE,uBAAuB,EAAE,uBAAuB,EAAE,MAAM,4BAA4B,CAAA;AAGlG,OAAO,EAAY,KAAK,eAAe,EAAE,KAAK,cAAc,EAAE,MAAM,YAAY,CAAA;AAShF;;;;;;;;;;;;;;GAcG;AACH,wBAAgB,gBAAgB,CAAC,OAAO,EAAE,MAAM,GAAG,MAAM,GAAG,MAAM,GAAG,MAAM,CAsB1E;AAmDD,MAAM,WAAW,uBAAuB;IACtC,0DAA0D;IAC1D,MAAM,EAAE,MAAM,CAAA;IACd,sEAAsE;IACtE,OAAO,EAAE,MAAM,GAAG,MAAM,GAAG,MAAM,CAAA;IACjC,OAAO,CAAC,EAAE,MAAM,CAAA;IAChB,mFAAmF;IACnF,QAAQ,EAAE,MAAM,CAAA;IAChB,4DAA4D;IAC5D,QAAQ,EAAE,MAAM,CAAA;IAChB,2EAA2E;IAC3E,MAAM,CAAC,EAAE,MAAM,CAAA;IACf,WAAW,CAAC,EAAE,MAAM,CAAA;CACrB;AAED,MAAM,WAAW,eAAe;IAC9B,mEAAmE;IACnE,UAAU,EAAE,MAAM,CAAA;IAClB,4DAA4D;IAC5D,QAAQ,EAAE,MAAM,CAAA;IAChB,wDAAwD;IACxD,QAAQ,EAAE,MAAM,CAAA;IAChB,0EAA0E;IAC1E,UAAU,CAAC,EAAE,MAAM,CAAA;CACpB;AAED;;;;;;GAMG;AACH,MAAM,MAAM,eAAe,GACvB,CAAC,uBAAuB,GAAG;IAAE,OAAO,EAAE,IAAI,CAAC;IAAC,cAAc,EAAE,MAAM,CAAA;CAAE,CAAC,GACrE,CAAC,uBAAuB,GAAG;IAAE,OAAO,EAAE,KAAK,CAAC;IAAC,cAAc,CAAC,EAAE,MAAM,CAAA;CAAE,CAAC,CAAA;AAE3E,qBAAa,MAAO,SAAQ,eAAe;IACzC,MAAM,CAAC,WAAW,CAAC,OAAO,EAAE,cAAc,GAAG,MAAM;IAInD;;;;;;OAMG;IACG,cAAc,CAClB,MAAM,EAAE,uBAAuB,GAC9B,OAAO,CAAC;QAAE,SAAS,EAAE,MAAM,CAAC;QAAC,EAAE,EAAE,MAAM,CAAA;KAAE,CAAC;IAa7C,yEAAyE;IACnE,gBAAgB,CAAC,MAAM,EAAE,eAAe,GAAG,OAAO,CAAC,uBAAuB,CAAC;IAIjF;;;;OAIG;IACG,gBAAgB,CAAC,MAAM,EAAE,eAAe,GAAG,OAAO,CAAC,eAAe,CAAC;IAMzE;;;;;;OAMG;IACG,iBAAiB,CACrB,MAAM,EAAE,MAAM,EACd,OAAO,CAAC,EAAE,MAAM,EAChB,YAAY,CAAC,EAAE,gBAAgB,GAC9B,OAAO,CAAC;QAAE,WAAW,EAAE,MAAM,CAAA;KAAE,CAAC;IAUnC;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;OA8BG;IACG,KAAK,CACT,KAAK,EAAE,MAAM,GAAG,GAAG,EACnB,IAAI,EAAE,WAAW,GAAG,SAAS,EAC7B,OAAO,EAAE,eAAe,GACvB,OAAO,CAAC,cAAc,CAAC;IAiB1B,OAAO,CAAC,UAAU;IAUlB;;;;;;;;;;;;;;;;;;;OAmBG;YACW,IAAI;CA4FnB"}
@@ -0,0 +1,298 @@
1
+ /**
2
+ * The Machine Payments Protocol (MPP) API.
3
+ *
4
+ * MPP is a second payment framing over the unchanged Nevermined core: the same
5
+ * plan, the same delegation and the same credit burn as x402, negotiated with
6
+ * MPP headers. Sellers issue a challenge and redeem a credential; buyers mint
7
+ * an MPP-domain access token and present it as a credential.
8
+ */
9
+ import { BasePaymentsAPI } from '../api/base-payments.js';
10
+ import { API_URL_MPP_CHALLENGE, API_URL_MPP_CREATE_PERMISSION, API_URL_MPP_SETTLE, API_URL_MPP_VERIFY, } from '../api/nvm-api.js';
11
+ import { PaymentsError } from '../common/payments.error.js';
12
+ import { buildX402TokenRequestBody } from '../x402/token-request.js';
13
+ import { MppError, MppSettlementOutcomeUnknownError, toMppError } from './errors.js';
14
+ import { mppFetch } from './fetch.js';
15
+ /** Only whole, non-negative decimal digits — no sign, no leading/trailing
16
+ * whitespace, no hex/octal/binary prefix, no fractional part. `BigInt(x)`
17
+ * silently accepts all of those for a string input (`BigInt('0x10')` is 16,
18
+ * `BigInt('')` is 0n, `BigInt(' 5 ')` is 5n), which a decimal-string
19
+ * contract must reject rather than accept quietly. */
20
+ const DECIMAL_INTEGER_STRING = /^\d+$/;
21
+ /**
22
+ * Normalizes `credits` to the exact decimal-string amount that gets sealed
23
+ * into the challenge and burned. A bare `.toString()` on a JS `number` can
24
+ * emit scientific notation (`1e+21`), `"NaN"` or `"Infinity"` — all
25
+ * forwarded unvalidated into an amount this PR's own docs describe as
26
+ * having "no post-hoc re-pricing as there is with x402": a corrupted amount
27
+ * here is not correctable downstream, it IS the amount.
28
+ *
29
+ * `BigInt(x)` renders an integer-valued number exactly (no scientific
30
+ * notation) and throws `RangeError` on a non-integer, `NaN` or `Infinity`
31
+ * instead of silently stringifying them — which is why non-string inputs go
32
+ * through it. The `string` arm gets its own check instead of relying on
33
+ * `BigInt`'s string parsing, which is far more permissive than a decimal
34
+ * string contract should be.
35
+ */
36
+ export function normalizeCredits(credits) {
37
+ if (typeof credits === 'string') {
38
+ if (!DECIMAL_INTEGER_STRING.test(credits)) {
39
+ throw new MppError(`credits must be a non-negative integer decimal string, got ${JSON.stringify(credits)}`);
40
+ }
41
+ return credits;
42
+ }
43
+ let normalized;
44
+ try {
45
+ normalized = BigInt(credits).toString();
46
+ }
47
+ catch (error) {
48
+ throw new MppError(`credits must be a non-negative integer, got ${credits}: ${error instanceof Error ? error.message : String(error)}`);
49
+ }
50
+ if (normalized.startsWith('-')) {
51
+ throw new MppError(`credits must be a non-negative integer, got ${credits}`);
52
+ }
53
+ return normalized;
54
+ }
55
+ /** Deadline on an outbound MPP request so a hung backend cannot hold the
56
+ * caller's connection open indefinitely — `middleware.ts` defers the
57
+ * buyer's own response until settlement resolves. */
58
+ const REQUEST_TIMEOUT_MS = 30000;
59
+ /**
60
+ * Socket-level failures that can only happen once the request was already on
61
+ * the wire, so on a burning call the backend may have completed the burn and
62
+ * only the answer was lost.
63
+ *
64
+ * `ECONNRESET` / `EPIPE` mean the peer tore down (or we wrote into) a
65
+ * connection that had been established; `UND_ERR_SOCKET` is undici's wrapper
66
+ * for the same thing, and `UND_ERR_ABORTED` covers a mid-flight abort that
67
+ * did not come through the `TimeoutError` path.
68
+ */
69
+ const OUTCOME_UNKNOWN_SOCKET_CODES = new Set([
70
+ 'ECONNRESET',
71
+ 'EPIPE',
72
+ 'UND_ERR_SOCKET',
73
+ 'UND_ERR_ABORTED',
74
+ ]);
75
+ /**
76
+ * Whether a `fetch` rejection is a connection that died AFTER the request was
77
+ * written — i.e. an unknown settlement outcome rather than a definite failure.
78
+ *
79
+ * Deliberately an ALLOW-LIST, not a blanket promotion of every network error.
80
+ * `ECONNREFUSED`, `ENOTFOUND` and `EAI_AGAIN` all mean the request never
81
+ * reached anything that could burn, so reporting them as "may have burned"
82
+ * would inflate a seller's records with burns that never happened — the same
83
+ * corruption as the 4xx case one screen down, in the other direction. Any code
84
+ * not named here keeps the definite `network_error` classification.
85
+ *
86
+ * Node's `fetch` surfaces the underlying socket error as `error.cause`, so the
87
+ * code is read from there first and off the error itself as a fallback.
88
+ */
89
+ function isPostRequestSocketFailure(error) {
90
+ if (!(error instanceof Error))
91
+ return false;
92
+ // `cause` is read off a widened shape rather than `Error.cause`: the
93
+ // package's lib target predates ES2022, so the property is not on the
94
+ // declared `Error` type even though Node populates it.
95
+ const { cause, code: ownCode } = error;
96
+ const causeCode = cause?.code;
97
+ return ((typeof causeCode === 'string' && OUTCOME_UNKNOWN_SOCKET_CODES.has(causeCode)) ||
98
+ (typeof ownCode === 'string' && OUTCOME_UNKNOWN_SOCKET_CODES.has(ownCode)));
99
+ }
100
+ export class MppAPI extends BasePaymentsAPI {
101
+ static getInstance(options) {
102
+ return new MppAPI(options);
103
+ }
104
+ /**
105
+ * Mints the challenge a plan-protected endpoint returns with its 402.
106
+ *
107
+ * Each call returns a distinct challenge even for identical inputs — the id
108
+ * doubles as the burn idempotency key, so two requests sharing one would
109
+ * settle as a single burn.
110
+ */
111
+ async issueChallenge(params) {
112
+ const { planId, credits, agentId, resource, httpVerb, digest, description } = params;
113
+ return this.post(API_URL_MPP_CHALLENGE, {
114
+ planId,
115
+ credits: normalizeCredits(credits),
116
+ resource,
117
+ httpVerb,
118
+ ...(agentId && { agentId }),
119
+ ...(digest && { digest }),
120
+ ...(description && { description }),
121
+ });
122
+ }
123
+ /** Runs the full credential and plan checks without burning anything. */
124
+ async verifyCredential(params) {
125
+ return this.post(API_URL_MPP_VERIFY, this.redeemBody(params));
126
+ }
127
+ /**
128
+ * Verifies and burns through the same chokepoint an x402 settlement uses, so
129
+ * the credits charged are identical on both protocols. Settling the same
130
+ * credential twice burns once.
131
+ */
132
+ async settleCredential(params) {
133
+ return this.post(API_URL_MPP_SETTLE, this.redeemBody(params), {
134
+ burns: true,
135
+ });
136
+ }
137
+ /**
138
+ * Mints an access token signed under the `Nevermined-MPP` EIP-712 domain.
139
+ *
140
+ * Same inputs and same settlement rail as {@link X402TokenAPI.getX402AccessToken};
141
+ * the token verifies only on the MPP routes, which is what keeps the two
142
+ * protocols isolated even though the tokens are byte-identical on the wire.
143
+ */
144
+ async getMppAccessToken(planId, agentId, tokenOptions) {
145
+ const body = buildX402TokenRequestBody({
146
+ planId,
147
+ agentId,
148
+ tokenOptions,
149
+ environmentName: this.environmentName,
150
+ });
151
+ return this.post(API_URL_MPP_CREATE_PERMISSION, body);
152
+ }
153
+ /**
154
+ * Performs an HTTP request, paying an MPP challenge if the endpoint returns
155
+ * one.
156
+ *
157
+ * The buyer needs no new plan, delegation or credential: the delegation that
158
+ * works for x402 works here unchanged.
159
+ *
160
+ * `init.body`, if set, must be replayable **if the endpoint may challenge
161
+ * the request**: a `ReadableStream` throws a typed {@link PaymentsError}
162
+ * once a 402 challenge actually requires a retry, since the stream cannot
163
+ * be resent. A request that is never challenged sends a stream body exactly
164
+ * once, exactly like plain `fetch` — the `paid: false` / untouched-response
165
+ * guarantee still holds. A `string`, `Buffer`/`ArrayBuffer`/typed array,
166
+ * `URLSearchParams`, `FormData` or `Blob` body all work unchanged either way.
167
+ *
168
+ * `options.delegationConfig` must carry a `delegationId` — this call
169
+ * refuses the deprecated inline create-on-the-fly shape (no `delegationId`)
170
+ * that {@link X402TokenAPI.getX402AccessToken} otherwise tolerates with a
171
+ * warning: the retry loop here can mint an access token twice per call, so
172
+ * that shape could silently create two delegations as a side effect of
173
+ * paying.
174
+ *
175
+ * @example
176
+ * ```typescript
177
+ * const { response, receipt } = await payments.mpp.fetch(
178
+ * 'https://agent.example/ask',
179
+ * { method: 'POST', body: JSON.stringify({ q: 'hello' }) },
180
+ * { delegationConfig: { delegationId }, planId },
181
+ * )
182
+ * ```
183
+ */
184
+ async fetch(input, init, options) {
185
+ if (!options?.delegationConfig?.delegationId) {
186
+ throw PaymentsError.validation('payments.mpp.fetch requires delegationConfig.delegationId. Create a delegation first ' +
187
+ 'with payments.delegation.createDelegation(), then pass { delegationId }. An inline ' +
188
+ 'create-on-the-fly delegationConfig (no delegationId) is not accepted here — the retry ' +
189
+ 'loop can mint against it twice per call, which would create two delegations.');
190
+ }
191
+ return mppFetch((planId, agentId, tokenOptions) => this.getMppAccessToken(planId, agentId, tokenOptions), input, init, options);
192
+ }
193
+ redeemBody(params) {
194
+ const { credential, resource, httpVerb, bodyDigest } = params;
195
+ return {
196
+ credential,
197
+ resource,
198
+ httpVerb,
199
+ ...(bodyDigest && { bodyDigest }),
200
+ };
201
+ }
202
+ /**
203
+ * One place for the POST + error translation both surfaces share.
204
+ *
205
+ * `burns` marks a call where "no answer" is not the same as "did not
206
+ * happen" — currently only `settleCredential`. For that call alone, a
207
+ * fetch rejection caused by OUR OWN `AbortSignal.timeout()` firing (not
208
+ * some other network failure) is raised as {@link MppSettlementOutcomeUnknownError}
209
+ * instead of the generic `network_error` `MppError` used everywhere else,
210
+ * so a caller can tell "definitely nothing happened" apart from "the
211
+ * backend may have already burned the credits; we just didn't hear back".
212
+ * `error.name === 'TimeoutError'` combined with `instanceof DOMException`
213
+ * is the documented, empirically-confirmed shape Node's `fetch` throws
214
+ * when an `AbortSignal.timeout()` deadline fires — as opposed to, say,
215
+ * connection-refused, which surfaces as a plain `TypeError`.
216
+ *
217
+ * The same reasoning covers the other two ways a burning call can end
218
+ * without a definite answer: an upstream 5xx/408, and a 2xx whose body
219
+ * could not be read. All three raise {@link MppSettlementOutcomeUnknownError};
220
+ * only a 4xx — the backend deliberately rejecting — is a definite failure.
221
+ */
222
+ async post(path, body, options = {}) {
223
+ const url = new URL(path, this.environment.backend);
224
+ const requestOptions = {
225
+ ...this.getBackendHTTPOptions('POST', body),
226
+ signal: AbortSignal.timeout(REQUEST_TIMEOUT_MS),
227
+ };
228
+ let response;
229
+ try {
230
+ response = await fetch(url, requestOptions);
231
+ }
232
+ catch (error) {
233
+ if (options.burns && error instanceof DOMException && error.name === 'TimeoutError') {
234
+ throw new MppSettlementOutcomeUnknownError();
235
+ }
236
+ if (options.burns && isPostRequestSocketFailure(error)) {
237
+ throw new MppSettlementOutcomeUnknownError(`The connection to the backend failed after the settle request was written: ${error instanceof Error ? error.message : String(error)}`);
238
+ }
239
+ throw toMppError('network_error', `Network error during MPP request: ${error instanceof Error ? error.message : String(error)}`);
240
+ }
241
+ if (!response.ok) {
242
+ let message = `MPP request to ${path} failed`;
243
+ let code = `http_${response.status}`;
244
+ try {
245
+ const errorData = await response.json();
246
+ if (errorData.message)
247
+ message = errorData.message;
248
+ if (errorData.code)
249
+ code = errorData.code;
250
+ if (errorData.hint)
251
+ message = `${message} — ${errorData.hint}`;
252
+ }
253
+ catch {
254
+ // Keep the default message.
255
+ }
256
+ // On a burning call, a 5xx (or a 408) is an UNKNOWN outcome, not a
257
+ // failure. A 504 in particular means an intermediary gave up waiting on
258
+ // the backend — it says nothing about whether the burn committed, which
259
+ // is the exact condition MppSettlementOutcomeUnknownError exists for,
260
+ // and the argument the docstring below makes for an unreadable 2xx
261
+ // applies word for word. Classified as a definite failure, the
262
+ // middleware logs "settlement failed" and skips onAfterSettle for
263
+ // credits that may well be gone.
264
+ //
265
+ // Confined to 5xx/408: the backend's own rejections (BCK.MPP.0003 and
266
+ // friends) come back as 4xx and ARE definite — reporting those as
267
+ // unknown would corrupt the accounting in the other direction.
268
+ if (options.burns && (response.status >= 500 || response.status === 408)) {
269
+ throw new MppSettlementOutcomeUnknownError(`The backend answered ${response.status} without a definite settlement outcome: ${message}`);
270
+ }
271
+ throw toMppError(code, message);
272
+ }
273
+ // The success path is not exempt from a malformed body: a WAF
274
+ // interstitial, a gateway HTML page, or a truncated 2xx response would
275
+ // otherwise raise a raw SyntaxError here — the one call site in this
276
+ // method that was NOT already wrapped and converted to a typed error.
277
+ try {
278
+ return (await response.json());
279
+ }
280
+ catch (error) {
281
+ // On a burning call this is an UNKNOWN outcome, not a failure. The
282
+ // backend already answered 2xx — the burn committed — and only the
283
+ // body was lost (our own AbortSignal.timeout() also aborts the body
284
+ // stream, and a mid-body reset lands here too). Reporting it as a
285
+ // definite failure is exactly the accounting corruption
286
+ // MppSettlementOutcomeUnknownError exists to prevent: the middleware
287
+ // would log "settlement failed" and skip onAfterSettle for credits
288
+ // that were in fact burned. If anything this case is MORE likely to
289
+ // have burned than the pre-response timeout the error was introduced
290
+ // for.
291
+ if (options.burns) {
292
+ throw new MppSettlementOutcomeUnknownError(`The backend answered ${response.status} but its body could not be read: ${error instanceof Error ? error.message : String(error)}`);
293
+ }
294
+ throw toMppError(`http_${response.status}`, `MPP response from ${path} was not valid JSON: ${error instanceof Error ? error.message : String(error)}`);
295
+ }
296
+ }
297
+ }
298
+ //# sourceMappingURL=mpp-api.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"mpp-api.js","sourceRoot":"","sources":["../../src/mpp/mpp-api.ts"],"names":[],"mappings":"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","sourcesContent":["/**\n * The Machine Payments Protocol (MPP) API.\n *\n * MPP is a second payment framing over the unchanged Nevermined core: the same\n * plan, the same delegation and the same credit burn as x402, negotiated with\n * MPP headers. Sellers issue a challenge and redeem a credential; buyers mint\n * an MPP-domain access token and present it as a credential.\n */\n\nimport { BasePaymentsAPI } from '../api/base-payments.js'\nimport {\n API_URL_MPP_CHALLENGE,\n API_URL_MPP_CREATE_PERMISSION,\n API_URL_MPP_SETTLE,\n API_URL_MPP_VERIFY,\n} from '../api/nvm-api.js'\nimport { PaymentsError } from '../common/payments.error.js'\nimport type { PaymentOptions, X402TokenOptions } from '../common/types.js'\nimport type { SettlePermissionsResult, VerifyPermissionsResult } from '../x402/facilitator-api.js'\nimport { buildX402TokenRequestBody } from '../x402/token-request.js'\nimport { MppError, MppSettlementOutcomeUnknownError, toMppError } from './errors.js'\nimport { mppFetch, type MppFetchOptions, type MppFetchResult } from './fetch.js'\n\n/** Only whole, non-negative decimal digits — no sign, no leading/trailing\n * whitespace, no hex/octal/binary prefix, no fractional part. `BigInt(x)`\n * silently accepts all of those for a string input (`BigInt('0x10')` is 16,\n * `BigInt('')` is 0n, `BigInt(' 5 ')` is 5n), which a decimal-string\n * contract must reject rather than accept quietly. */\nconst DECIMAL_INTEGER_STRING = /^\\d+$/\n\n/**\n * Normalizes `credits` to the exact decimal-string amount that gets sealed\n * into the challenge and burned. A bare `.toString()` on a JS `number` can\n * emit scientific notation (`1e+21`), `\"NaN\"` or `\"Infinity\"` — all\n * forwarded unvalidated into an amount this PR's own docs describe as\n * having \"no post-hoc re-pricing as there is with x402\": a corrupted amount\n * here is not correctable downstream, it IS the amount.\n *\n * `BigInt(x)` renders an integer-valued number exactly (no scientific\n * notation) and throws `RangeError` on a non-integer, `NaN` or `Infinity`\n * instead of silently stringifying them — which is why non-string inputs go\n * through it. The `string` arm gets its own check instead of relying on\n * `BigInt`'s string parsing, which is far more permissive than a decimal\n * string contract should be.\n */\nexport function normalizeCredits(credits: string | number | bigint): string {\n if (typeof credits === 'string') {\n if (!DECIMAL_INTEGER_STRING.test(credits)) {\n throw new MppError(\n `credits must be a non-negative integer decimal string, got ${JSON.stringify(credits)}`,\n )\n }\n return credits\n }\n\n let normalized: string\n try {\n normalized = BigInt(credits).toString()\n } catch (error) {\n throw new MppError(\n `credits must be a non-negative integer, got ${credits}: ${error instanceof Error ? error.message : String(error)}`,\n )\n }\n if (normalized.startsWith('-')) {\n throw new MppError(`credits must be a non-negative integer, got ${credits}`)\n }\n return normalized\n}\n\n/** Deadline on an outbound MPP request so a hung backend cannot hold the\n * caller's connection open indefinitely — `middleware.ts` defers the\n * buyer's own response until settlement resolves. */\nconst REQUEST_TIMEOUT_MS = 30_000\n\n/**\n * Socket-level failures that can only happen once the request was already on\n * the wire, so on a burning call the backend may have completed the burn and\n * only the answer was lost.\n *\n * `ECONNRESET` / `EPIPE` mean the peer tore down (or we wrote into) a\n * connection that had been established; `UND_ERR_SOCKET` is undici's wrapper\n * for the same thing, and `UND_ERR_ABORTED` covers a mid-flight abort that\n * did not come through the `TimeoutError` path.\n */\nconst OUTCOME_UNKNOWN_SOCKET_CODES = new Set([\n 'ECONNRESET',\n 'EPIPE',\n 'UND_ERR_SOCKET',\n 'UND_ERR_ABORTED',\n])\n\n/**\n * Whether a `fetch` rejection is a connection that died AFTER the request was\n * written — i.e. an unknown settlement outcome rather than a definite failure.\n *\n * Deliberately an ALLOW-LIST, not a blanket promotion of every network error.\n * `ECONNREFUSED`, `ENOTFOUND` and `EAI_AGAIN` all mean the request never\n * reached anything that could burn, so reporting them as \"may have burned\"\n * would inflate a seller's records with burns that never happened — the same\n * corruption as the 4xx case one screen down, in the other direction. Any code\n * not named here keeps the definite `network_error` classification.\n *\n * Node's `fetch` surfaces the underlying socket error as `error.cause`, so the\n * code is read from there first and off the error itself as a fallback.\n */\nfunction isPostRequestSocketFailure(error: unknown): boolean {\n if (!(error instanceof Error)) return false\n // `cause` is read off a widened shape rather than `Error.cause`: the\n // package's lib target predates ES2022, so the property is not on the\n // declared `Error` type even though Node populates it.\n const { cause, code: ownCode } = error as unknown as { cause?: unknown; code?: unknown }\n const causeCode = (cause as { code?: unknown } | undefined)?.code\n return (\n (typeof causeCode === 'string' && OUTCOME_UNKNOWN_SOCKET_CODES.has(causeCode)) ||\n (typeof ownCode === 'string' && OUTCOME_UNKNOWN_SOCKET_CODES.has(ownCode))\n )\n}\n\nexport interface IssueMppChallengeParams {\n /** The Nevermined plan the credits are burned against. */\n planId: string\n /** Credits the buyer is asked to redeem. Sent as a decimal string. */\n credits: string | number | bigint\n agentId?: string\n /** The protected resource. Sealed into the challenge and re-asserted at redeem. */\n resource: string\n /** HTTP verb of that resource. Part of the same binding. */\n httpVerb: string\n /** `sha-256=<base64>` digest binding the challenge to one request body. */\n digest?: string\n description?: string\n}\n\nexport interface RedeemMppParams {\n /** The `Authorization: Payment …` value presented by the buyer. */\n credential: string\n /** Must equal the resource the challenge was issued for. */\n resource: string\n /** Must equal the verb the challenge was issued for. */\n httpVerb: string\n /** Digest of the body actually received, when the challenge bound one. */\n bodyDigest?: string\n}\n\n/**\n * A discriminated union rather than a flat `paymentReceipt: string`: a\n * settlement can fail, and `SettlePermissionsResult.success` already says\n * so, but the flat shape let `{ success: false }` with no receipt typecheck\n * — a state the seller middleware then had no way to reject at compile time\n * even though it could not safely attach a receipt header for it.\n */\nexport type MppSettleResult =\n | (SettlePermissionsResult & { success: true; paymentReceipt: string })\n | (SettlePermissionsResult & { success: false; paymentReceipt?: string })\n\nexport class MppAPI extends BasePaymentsAPI {\n static getInstance(options: PaymentOptions): MppAPI {\n return new MppAPI(options)\n }\n\n /**\n * Mints the challenge a plan-protected endpoint returns with its 402.\n *\n * Each call returns a distinct challenge even for identical inputs — the id\n * doubles as the burn idempotency key, so two requests sharing one would\n * settle as a single burn.\n */\n async issueChallenge(\n params: IssueMppChallengeParams,\n ): Promise<{ challenge: string; id: string }> {\n const { planId, credits, agentId, resource, httpVerb, digest, description } = params\n return this.post<{ challenge: string; id: string }>(API_URL_MPP_CHALLENGE, {\n planId,\n credits: normalizeCredits(credits),\n resource,\n httpVerb,\n ...(agentId && { agentId }),\n ...(digest && { digest }),\n ...(description && { description }),\n })\n }\n\n /** Runs the full credential and plan checks without burning anything. */\n async verifyCredential(params: RedeemMppParams): Promise<VerifyPermissionsResult> {\n return this.post<VerifyPermissionsResult>(API_URL_MPP_VERIFY, this.redeemBody(params))\n }\n\n /**\n * Verifies and burns through the same chokepoint an x402 settlement uses, so\n * the credits charged are identical on both protocols. Settling the same\n * credential twice burns once.\n */\n async settleCredential(params: RedeemMppParams): Promise<MppSettleResult> {\n return this.post<MppSettleResult>(API_URL_MPP_SETTLE, this.redeemBody(params), {\n burns: true,\n })\n }\n\n /**\n * Mints an access token signed under the `Nevermined-MPP` EIP-712 domain.\n *\n * Same inputs and same settlement rail as {@link X402TokenAPI.getX402AccessToken};\n * the token verifies only on the MPP routes, which is what keeps the two\n * protocols isolated even though the tokens are byte-identical on the wire.\n */\n async getMppAccessToken(\n planId: string,\n agentId?: string,\n tokenOptions?: X402TokenOptions,\n ): Promise<{ accessToken: string }> {\n const body = buildX402TokenRequestBody({\n planId,\n agentId,\n tokenOptions,\n environmentName: this.environmentName,\n })\n return this.post<{ accessToken: string }>(API_URL_MPP_CREATE_PERMISSION, body)\n }\n\n /**\n * Performs an HTTP request, paying an MPP challenge if the endpoint returns\n * one.\n *\n * The buyer needs no new plan, delegation or credential: the delegation that\n * works for x402 works here unchanged.\n *\n * `init.body`, if set, must be replayable **if the endpoint may challenge\n * the request**: a `ReadableStream` throws a typed {@link PaymentsError}\n * once a 402 challenge actually requires a retry, since the stream cannot\n * be resent. A request that is never challenged sends a stream body exactly\n * once, exactly like plain `fetch` — the `paid: false` / untouched-response\n * guarantee still holds. A `string`, `Buffer`/`ArrayBuffer`/typed array,\n * `URLSearchParams`, `FormData` or `Blob` body all work unchanged either way.\n *\n * `options.delegationConfig` must carry a `delegationId` — this call\n * refuses the deprecated inline create-on-the-fly shape (no `delegationId`)\n * that {@link X402TokenAPI.getX402AccessToken} otherwise tolerates with a\n * warning: the retry loop here can mint an access token twice per call, so\n * that shape could silently create two delegations as a side effect of\n * paying.\n *\n * @example\n * ```typescript\n * const { response, receipt } = await payments.mpp.fetch(\n * 'https://agent.example/ask',\n * { method: 'POST', body: JSON.stringify({ q: 'hello' }) },\n * { delegationConfig: { delegationId }, planId },\n * )\n * ```\n */\n async fetch(\n input: string | URL,\n init: RequestInit | undefined,\n options: MppFetchOptions,\n ): Promise<MppFetchResult> {\n if (!options?.delegationConfig?.delegationId) {\n throw PaymentsError.validation(\n 'payments.mpp.fetch requires delegationConfig.delegationId. Create a delegation first ' +\n 'with payments.delegation.createDelegation(), then pass { delegationId }. An inline ' +\n 'create-on-the-fly delegationConfig (no delegationId) is not accepted here — the retry ' +\n 'loop can mint against it twice per call, which would create two delegations.',\n )\n }\n return mppFetch(\n (planId, agentId, tokenOptions) => this.getMppAccessToken(planId, agentId, tokenOptions),\n input,\n init,\n options,\n )\n }\n\n private redeemBody(params: RedeemMppParams): Record<string, unknown> {\n const { credential, resource, httpVerb, bodyDigest } = params\n return {\n credential,\n resource,\n httpVerb,\n ...(bodyDigest && { bodyDigest }),\n }\n }\n\n /**\n * One place for the POST + error translation both surfaces share.\n *\n * `burns` marks a call where \"no answer\" is not the same as \"did not\n * happen\" — currently only `settleCredential`. For that call alone, a\n * fetch rejection caused by OUR OWN `AbortSignal.timeout()` firing (not\n * some other network failure) is raised as {@link MppSettlementOutcomeUnknownError}\n * instead of the generic `network_error` `MppError` used everywhere else,\n * so a caller can tell \"definitely nothing happened\" apart from \"the\n * backend may have already burned the credits; we just didn't hear back\".\n * `error.name === 'TimeoutError'` combined with `instanceof DOMException`\n * is the documented, empirically-confirmed shape Node's `fetch` throws\n * when an `AbortSignal.timeout()` deadline fires — as opposed to, say,\n * connection-refused, which surfaces as a plain `TypeError`.\n *\n * The same reasoning covers the other two ways a burning call can end\n * without a definite answer: an upstream 5xx/408, and a 2xx whose body\n * could not be read. All three raise {@link MppSettlementOutcomeUnknownError};\n * only a 4xx — the backend deliberately rejecting — is a definite failure.\n */\n private async post<T>(\n path: string,\n body: Record<string, unknown>,\n options: { burns?: boolean } = {},\n ): Promise<T> {\n const url = new URL(path, this.environment.backend)\n const requestOptions = {\n ...this.getBackendHTTPOptions('POST', body),\n signal: AbortSignal.timeout(REQUEST_TIMEOUT_MS),\n }\n\n let response: Response\n try {\n response = await fetch(url, requestOptions)\n } catch (error) {\n if (options.burns && error instanceof DOMException && error.name === 'TimeoutError') {\n throw new MppSettlementOutcomeUnknownError()\n }\n if (options.burns && isPostRequestSocketFailure(error)) {\n throw new MppSettlementOutcomeUnknownError(\n `The connection to the backend failed after the settle request was written: ${\n error instanceof Error ? error.message : String(error)\n }`,\n )\n }\n throw toMppError(\n 'network_error',\n `Network error during MPP request: ${error instanceof Error ? error.message : String(error)}`,\n )\n }\n\n if (!response.ok) {\n let message = `MPP request to ${path} failed`\n let code: string | undefined = `http_${response.status}`\n try {\n const errorData = await response.json()\n if (errorData.message) message = errorData.message\n if (errorData.code) code = errorData.code\n if (errorData.hint) message = `${message} — ${errorData.hint}`\n } catch {\n // Keep the default message.\n }\n // On a burning call, a 5xx (or a 408) is an UNKNOWN outcome, not a\n // failure. A 504 in particular means an intermediary gave up waiting on\n // the backend — it says nothing about whether the burn committed, which\n // is the exact condition MppSettlementOutcomeUnknownError exists for,\n // and the argument the docstring below makes for an unreadable 2xx\n // applies word for word. Classified as a definite failure, the\n // middleware logs \"settlement failed\" and skips onAfterSettle for\n // credits that may well be gone.\n //\n // Confined to 5xx/408: the backend's own rejections (BCK.MPP.0003 and\n // friends) come back as 4xx and ARE definite — reporting those as\n // unknown would corrupt the accounting in the other direction.\n if (options.burns && (response.status >= 500 || response.status === 408)) {\n throw new MppSettlementOutcomeUnknownError(\n `The backend answered ${response.status} without a definite settlement outcome: ${message}`,\n )\n }\n throw toMppError(code, message)\n }\n\n // The success path is not exempt from a malformed body: a WAF\n // interstitial, a gateway HTML page, or a truncated 2xx response would\n // otherwise raise a raw SyntaxError here — the one call site in this\n // method that was NOT already wrapped and converted to a typed error.\n try {\n return (await response.json()) as T\n } catch (error) {\n // On a burning call this is an UNKNOWN outcome, not a failure. The\n // backend already answered 2xx — the burn committed — and only the\n // body was lost (our own AbortSignal.timeout() also aborts the body\n // stream, and a mid-body reset lands here too). Reporting it as a\n // definite failure is exactly the accounting corruption\n // MppSettlementOutcomeUnknownError exists to prevent: the middleware\n // would log \"settlement failed\" and skip onAfterSettle for credits\n // that were in fact burned. If anything this case is MORE likely to\n // have burned than the pre-response timeout the error was introduced\n // for.\n if (options.burns) {\n throw new MppSettlementOutcomeUnknownError(\n `The backend answered ${response.status} but its body could not be read: ${\n error instanceof Error ? error.message : String(error)\n }`,\n )\n }\n throw toMppError(\n `http_${response.status}`,\n `MPP response from ${path} was not valid JSON: ${error instanceof Error ? error.message : String(error)}`,\n )\n }\n }\n}\n"]}
@@ -0,0 +1,43 @@
1
+ /**
2
+ * Public types for the Machine Payments Protocol (MPP) surface.
3
+ *
4
+ * MPP is a second payment framing over the unchanged plans/credits/delegations
5
+ * core: the same plan, the same delegation and the same credit burn as x402,
6
+ * negotiated with different HTTP headers.
7
+ */
8
+ /** What the buyer is being asked to pay for. Sealed inside the challenge HMAC. */
9
+ export interface MppChallengeRequest {
10
+ /** The Nevermined plan the credits are burned against. */
11
+ planId: string;
12
+ /** Credits to redeem, as a decimal string. */
13
+ credits: string;
14
+ /** Agent the request is addressed to. */
15
+ agentId?: string;
16
+ }
17
+ /**
18
+ * A parsed `WWW-Authenticate: Payment …` challenge.
19
+ *
20
+ * `requestEncoded` and `opaque` are kept as the exact base64url strings the
21
+ * server sent: the challenge id is an HMAC over them, so re-encoding either one
22
+ * would invalidate the credential built from this challenge.
23
+ */
24
+ export interface MppChallenge {
25
+ id: string;
26
+ realm: string;
27
+ method: string;
28
+ intent: string;
29
+ request: MppChallengeRequest;
30
+ requestEncoded: string;
31
+ expires?: string;
32
+ digest?: string;
33
+ opaque?: string;
34
+ description?: string;
35
+ }
36
+ /** A decoded `Payment-Receipt`. Unsigned by design, and carries no balance. */
37
+ export interface MppReceipt {
38
+ method: string;
39
+ reference: string;
40
+ status: string;
41
+ timestamp: string;
42
+ }
43
+ //# sourceMappingURL=types.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"types.d.ts","sourceRoot":"","sources":["../../src/mpp/types.ts"],"names":[],"mappings":"AAAA;;;;;;GAMG;AAEH,kFAAkF;AAClF,MAAM,WAAW,mBAAmB;IAClC,0DAA0D;IAC1D,MAAM,EAAE,MAAM,CAAA;IACd,8CAA8C;IAC9C,OAAO,EAAE,MAAM,CAAA;IACf,yCAAyC;IACzC,OAAO,CAAC,EAAE,MAAM,CAAA;CACjB;AAED;;;;;;GAMG;AACH,MAAM,WAAW,YAAY;IAC3B,EAAE,EAAE,MAAM,CAAA;IACV,KAAK,EAAE,MAAM,CAAA;IACb,MAAM,EAAE,MAAM,CAAA;IACd,MAAM,EAAE,MAAM,CAAA;IACd,OAAO,EAAE,mBAAmB,CAAA;IAC5B,cAAc,EAAE,MAAM,CAAA;IACtB,OAAO,CAAC,EAAE,MAAM,CAAA;IAChB,MAAM,CAAC,EAAE,MAAM,CAAA;IACf,MAAM,CAAC,EAAE,MAAM,CAAA;IACf,WAAW,CAAC,EAAE,MAAM,CAAA;CACrB;AAED,+EAA+E;AAC/E,MAAM,WAAW,UAAU;IACzB,MAAM,EAAE,MAAM,CAAA;IACd,SAAS,EAAE,MAAM,CAAA;IACjB,MAAM,EAAE,MAAM,CAAA;IACd,SAAS,EAAE,MAAM,CAAA;CAClB"}
@@ -0,0 +1,9 @@
1
+ /**
2
+ * Public types for the Machine Payments Protocol (MPP) surface.
3
+ *
4
+ * MPP is a second payment framing over the unchanged plans/credits/delegations
5
+ * core: the same plan, the same delegation and the same credit burn as x402,
6
+ * negotiated with different HTTP headers.
7
+ */
8
+ export {};
9
+ //# sourceMappingURL=types.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"types.js","sourceRoot":"","sources":["../../src/mpp/types.ts"],"names":[],"mappings":"AAAA;;;;;;GAMG","sourcesContent":["/**\n * Public types for the Machine Payments Protocol (MPP) surface.\n *\n * MPP is a second payment framing over the unchanged plans/credits/delegations\n * core: the same plan, the same delegation and the same credit burn as x402,\n * negotiated with different HTTP headers.\n */\n\n/** What the buyer is being asked to pay for. Sealed inside the challenge HMAC. */\nexport interface MppChallengeRequest {\n /** The Nevermined plan the credits are burned against. */\n planId: string\n /** Credits to redeem, as a decimal string. */\n credits: string\n /** Agent the request is addressed to. */\n agentId?: string\n}\n\n/**\n * A parsed `WWW-Authenticate: Payment …` challenge.\n *\n * `requestEncoded` and `opaque` are kept as the exact base64url strings the\n * server sent: the challenge id is an HMAC over them, so re-encoding either one\n * would invalidate the credential built from this challenge.\n */\nexport interface MppChallenge {\n id: string\n realm: string\n method: string\n intent: string\n request: MppChallengeRequest\n requestEncoded: string\n expires?: string\n digest?: string\n opaque?: string\n description?: string\n}\n\n/** A decoded `Payment-Receipt`. Unsigned by design, and carries no balance. */\nexport interface MppReceipt {\n method: string\n reference: string\n status: string\n timestamp: string\n}\n"]}
@@ -13,6 +13,7 @@ import { OrganizationsAPI } from './api/organizations-api/organizations-api.js';
13
13
  import { FacilitatorAPI } from './x402/facilitator-api.js';
14
14
  import { X402TokenAPI } from './x402/token.js';
15
15
  import { DelegationAPI } from './x402/delegation-api.js';
16
+ import { MppAPI } from './mpp/mpp-api.js';
16
17
  /**
17
18
  * Main class that interacts with the Nevermined payments API.
18
19
  * Use `Payments.getInstance` for server-side usage or `Payments.getBrowserInstance` for browser usage.
@@ -36,6 +37,18 @@ export declare class Payments extends BasePaymentsAPI {
36
37
  contracts: ContractsAPI;
37
38
  facilitator: FacilitatorAPI;
38
39
  x402: X402TokenAPI;
40
+ /**
41
+ * MPP (Machine Payments Protocol) surface — challenge/credential framing over
42
+ * the same plans, delegations and credit burn as x402.
43
+ *
44
+ * @experimental Shipped ahead of its epic's declared MVP scope, so that the
45
+ * Express middleware's own dependency on it is reachable rather than hidden
46
+ * behind an internal handle. The NAME is settled — `payments.mpp` beside
47
+ * `payments.x402` is what a seller will guess, and renaming it after a tag
48
+ * costs a major. The SHAPE is not: this surface may change in a minor
49
+ * release until the epic adopts it.
50
+ */
51
+ mpp: MppAPI;
39
52
  private _a2aRegistry?;
40
53
  private _delegation?;
41
54
  /**
@@ -1 +1 @@
1
- {"version":3,"file":"payments.d.ts","sourceRoot":"","sources":["../src/payments.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,UAAU,EAAE,MAAM,oBAAoB,CAAA;AAE/C,OAAO,EAAE,cAAc,EAAE,MAAM,mBAAmB,CAAA;AAClD,OAAO,EAAE,eAAe,EAAE,MAAM,wBAAwB,CAAA;AACxD,OAAO,EAAE,QAAQ,EAAE,MAAM,oBAAoB,CAAA;AAC7C,OAAO,EAAE,YAAY,EAAE,MAAM,wBAAwB,CAAA;AACrD,OAAO,EAAE,SAAS,EAAE,MAAM,qBAAqB,CAAA;AAC/C,OAAO,EAAE,gBAAgB,EAAE,MAAM,uBAAuB,CAAA;AACxD,OAAO,EAAE,gBAAgB,EAAE,MAAM,8CAA8C,CAAA;AAE/E,OAAO,KAAK,EAAE,wBAAwB,EAAE,uBAAuB,EAAE,MAAM,iBAAiB,CAAA;AAExF,OAAO,EAAE,qBAAqB,EAAE,MAAM,qBAAqB,CAAA;AAC3D,OAAO,KAAK,SAAS,MAAM,gBAAgB,CAAA;AAC3C,OAAO,EAAE,gBAAgB,EAAE,MAAM,8CAA8C,CAAA;AAC/E,OAAO,EAAE,cAAc,EAAE,MAAM,2BAA2B,CAAA;AAC1D,OAAO,EAAE,YAAY,EAAE,MAAM,iBAAiB,CAAA;AAC9C,OAAO,EAAE,aAAa,EAAE,MAAM,0BAA0B,CAAA;AAExD;;;;;;;;;;;;GAYG;AACH,qBAAa,QAAS,SAAQ,eAAe;IACpC,KAAK,EAAG,UAAU,CAAA;IAClB,KAAK,EAAG,QAAQ,CAAA;IAChB,MAAM,EAAG,SAAS,CAAA;IAClB,QAAQ,EAAG,gBAAgB,CAAA;IAC3B,aAAa,EAAG,gBAAgB,CAAA;IAChC,aAAa,EAAG,gBAAgB,CAAA;IAChC,SAAS,EAAG,YAAY,CAAA;IACxB,WAAW,EAAG,cAAc,CAAA;IAC5B,IAAI,EAAG,YAAY,CAAA;IAC1B,OAAO,CAAC,YAAY,CAAC,CAAgB;IACrC,OAAO,CAAC,WAAW,CAAC,CAAe;IAEnC;;;;OAIG;IACH,OAAO,CAAC,eAAe,CAAC,CAAkD;IAE1E;;;OAGG;IACH,IAAW,GAAG;QAEV;;;WAGG;yBAEQ,IAAI,CAAC,wBAAwB,EAAE,iBAAiB,CAAC,KACzD,uBAAuB;QAE1B;;;;WAIG;6BACwB,GAAG;MAOjC;IAED;;;OAGG;IACH,IAAW,GAAG;;;sDA+JO,CAAA,cAAc,CAAC,2LAEgC,CAAC;sDAE/C,CAAC,cAAc,CAAC,uEAGrC,CAAA;oFAGsC,CAAC,cAC1B,CAAC,mLAGwC,CAAC;;;;;;;6FA4B4yB,CAAC,cAAc,CAAC;8IAAwd,CAAC,cAAwB,CAAC;+FAAyc,CAAC,cAAc,CAAC;;;kBAJvyD,CAAC;;;;mBAIqvK,CAAC;;;;;;;;;MApM9wK;IAED;;;;;;;OAOG;IACH,IAAW,UAAU,IAAI,aAAa,CAUrC;IAED;;;OAGG;IACH,MAAM,CAAC,GAAG;;MAA4B;IAEtC;;;;;;;;;;;;;OAaG;IACH,MAAM,CAAC,WAAW,CAAC,OAAO,EAAE,cAAc;IAO1C;;;;;;;;;;;;;;;;;;OAkBG;IACH,MAAM,CAAC,kBAAkB,CAAC,OAAO,EAAE,cAAc;IAoBjD;;;;;OAKG;IACH,OAAO;IAOP;;OAEG;IACH,OAAO,CAAC,aAAa;IAYrB;;;;;;;;;;OAUG;IACI,OAAO;IAMd;;;;;;;;;OASG;IACI,MAAM;IAIb;;;;;;;;;;;;;;;;;;;;OAoBG;IACa,iBAAiB,CAAC,cAAc,EAAE,MAAM,GAAG,IAAI,GAAG,IAAI;IAgBtE;;;;;;;OAOG;IACH,IAAI,UAAU,IAAI,OAAO,CAExB;CACF"}
1
+ {"version":3,"file":"payments.d.ts","sourceRoot":"","sources":["../src/payments.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,UAAU,EAAE,MAAM,oBAAoB,CAAA;AAE/C,OAAO,EAAE,cAAc,EAAE,MAAM,mBAAmB,CAAA;AAClD,OAAO,EAAE,eAAe,EAAE,MAAM,wBAAwB,CAAA;AACxD,OAAO,EAAE,QAAQ,EAAE,MAAM,oBAAoB,CAAA;AAC7C,OAAO,EAAE,YAAY,EAAE,MAAM,wBAAwB,CAAA;AACrD,OAAO,EAAE,SAAS,EAAE,MAAM,qBAAqB,CAAA;AAC/C,OAAO,EAAE,gBAAgB,EAAE,MAAM,uBAAuB,CAAA;AACxD,OAAO,EAAE,gBAAgB,EAAE,MAAM,8CAA8C,CAAA;AAE/E,OAAO,KAAK,EAAE,wBAAwB,EAAE,uBAAuB,EAAE,MAAM,iBAAiB,CAAA;AAExF,OAAO,EAAE,qBAAqB,EAAE,MAAM,qBAAqB,CAAA;AAC3D,OAAO,KAAK,SAAS,MAAM,gBAAgB,CAAA;AAC3C,OAAO,EAAE,gBAAgB,EAAE,MAAM,8CAA8C,CAAA;AAC/E,OAAO,EAAE,cAAc,EAAE,MAAM,2BAA2B,CAAA;AAC1D,OAAO,EAAE,YAAY,EAAE,MAAM,iBAAiB,CAAA;AAC9C,OAAO,EAAE,aAAa,EAAE,MAAM,0BAA0B,CAAA;AACxD,OAAO,EAAE,MAAM,EAAE,MAAM,kBAAkB,CAAA;AAEzC;;;;;;;;;;;;GAYG;AACH,qBAAa,QAAS,SAAQ,eAAe;IACpC,KAAK,EAAG,UAAU,CAAA;IAClB,KAAK,EAAG,QAAQ,CAAA;IAChB,MAAM,EAAG,SAAS,CAAA;IAClB,QAAQ,EAAG,gBAAgB,CAAA;IAC3B,aAAa,EAAG,gBAAgB,CAAA;IAChC,aAAa,EAAG,gBAAgB,CAAA;IAChC,SAAS,EAAG,YAAY,CAAA;IACxB,WAAW,EAAG,cAAc,CAAA;IAC5B,IAAI,EAAG,YAAY,CAAA;IAC1B;;;;;;;;;;OAUG;IACI,GAAG,EAAG,MAAM,CAAA;IACnB,OAAO,CAAC,YAAY,CAAC,CAAgB;IACrC,OAAO,CAAC,WAAW,CAAC,CAAe;IAEnC;;;;OAIG;IACH,OAAO,CAAC,eAAe,CAAC,CAAkD;IAE1E;;;OAGG;IACH,IAAW,GAAG;QAEV;;;WAGG;yBAEQ,IAAI,CAAC,wBAAwB,EAAE,iBAAiB,CAAC,KACzD,uBAAuB;QAE1B;;;;WAIG;6BACwB,GAAG;MAOjC;IAED;;;OAGG;IACH,IAAW,GAAG;;;sDAuIoC,CAAC,cAAc,CAAC,2LAKnC,CAAC;sDAK/B,CAAC,cACK,CAAC,uEAIO,CAAC;oFAKoC,CAAC,cACpD,CAAD,mLAGS,CAAC;;;;;;;6FA4C2H,CAAC,cAAc,CAAC;8IAAwd,CAAC,cAAwB,CAAC;+FAAyc,CAAC,cAAc,CAAC;;;kBAxBxjC,CAAC;;;;mBAwBsgJ,CAAC;;;;;;;;;MAtM/iJ;IAED;;;;;;;OAOG;IACH,IAAW,UAAU,IAAI,aAAa,CAUrC;IAED;;;OAGG;IACH,MAAM,CAAC,GAAG;;MAA4B;IAEtC;;;;;;;;;;;;;OAaG;IACH,MAAM,CAAC,WAAW,CAAC,OAAO,EAAE,cAAc;IAO1C;;;;;;;;;;;;;;;;;;OAkBG;IACH,MAAM,CAAC,kBAAkB,CAAC,OAAO,EAAE,cAAc;IAoBjD;;;;;OAKG;IACH,OAAO;IAOP;;OAEG;IACH,OAAO,CAAC,aAAa;IAarB;;;;;;;;;;OAUG;IACI,OAAO;IAMd;;;;;;;;;OASG;IACI,MAAM;IAIb;;;;;;;;;;;;;;;;;;;;OAoBG;IACa,iBAAiB,CAAC,cAAc,EAAE,MAAM,GAAG,IAAI,GAAG,IAAI;IAiBtE;;;;;;;OAOG;IACH,IAAI,UAAU,IAAI,OAAO,CAExB;CACF"}
package/dist/payments.js CHANGED
@@ -14,6 +14,7 @@ import { OrganizationsAPI } from './api/organizations-api/organizations-api.js';
14
14
  import { FacilitatorAPI } from './x402/facilitator-api.js';
15
15
  import { X402TokenAPI } from './x402/token.js';
16
16
  import { DelegationAPI } from './x402/delegation-api.js';
17
+ import { MppAPI } from './mpp/mpp-api.js';
17
18
  /**
18
19
  * Main class that interacts with the Nevermined payments API.
19
20
  * Use `Payments.getInstance` for server-side usage or `Payments.getBrowserInstance` for browser usage.
@@ -160,6 +161,7 @@ export class Payments extends BasePaymentsAPI {
160
161
  this.contracts = new ContractsAPI(options);
161
162
  this.facilitator = FacilitatorAPI.getInstance(options);
162
163
  this.x402 = X402TokenAPI.getInstance(options);
164
+ this.mpp = MppAPI.getInstance(options);
163
165
  }
164
166
  /**
165
167
  * Initiates the connect flow. The user's browser will be redirected to
@@ -222,6 +224,7 @@ export class Payments extends BasePaymentsAPI {
222
224
  this.contracts?.setOrganizationId(organizationId);
223
225
  this.facilitator?.setOrganizationId(organizationId);
224
226
  this.x402?.setOrganizationId(organizationId);
227
+ this.mpp?.setOrganizationId(organizationId);
225
228
  // `_delegation` is lazy — the getter forwards `currentOrganizationId`
226
229
  // on first access, so only propagate to an already-built instance.
227
230
  // (Eagerly constructing it here would change the lazy contract.)