@nevermined-io/payments 1.12.0 → 1.14.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 +33 -0
- package/dist/a2a/clientRegistry.d.ts +10 -1
- package/dist/a2a/clientRegistry.d.ts.map +1 -1
- package/dist/a2a/clientRegistry.js +13 -4
- package/dist/a2a/clientRegistry.js.map +1 -1
- package/dist/a2a/paymentsClient.d.ts +60 -3
- package/dist/a2a/paymentsClient.d.ts.map +1 -1
- package/dist/a2a/paymentsClient.js +129 -8
- package/dist/a2a/paymentsClient.js.map +1 -1
- package/dist/a2a/paymentsRequestHandler.d.ts +5 -1
- package/dist/a2a/paymentsRequestHandler.d.ts.map +1 -1
- package/dist/a2a/paymentsRequestHandler.js +156 -13
- package/dist/a2a/paymentsRequestHandler.js.map +1 -1
- package/dist/a2a/types.d.ts +30 -0
- package/dist/a2a/types.d.ts.map +1 -1
- package/dist/a2a/types.js.map +1 -1
- package/dist/api/agents-api.d.ts +4 -3
- package/dist/api/agents-api.d.ts.map +1 -1
- package/dist/api/agents-api.js +7 -4
- package/dist/api/agents-api.js.map +1 -1
- package/dist/api/base-payments.d.ts +7 -2
- package/dist/api/base-payments.d.ts.map +1 -1
- package/dist/api/base-payments.js +15 -8
- package/dist/api/base-payments.js.map +1 -1
- package/dist/api/nvm-api.d.ts +5 -5
- package/dist/api/observability-api/types.d.ts +34 -6
- package/dist/api/observability-api/types.d.ts.map +1 -1
- package/dist/api/observability-api/types.js.map +1 -1
- package/dist/api/plans-api.d.ts +15 -12
- package/dist/api/plans-api.d.ts.map +1 -1
- package/dist/api/plans-api.js +17 -14
- package/dist/api/plans-api.js.map +1 -1
- package/dist/api/query-api.d.ts +1 -1
- package/dist/common/types.d.ts +175 -18
- package/dist/common/types.d.ts.map +1 -1
- package/dist/common/types.js.map +1 -1
- package/dist/index.d.ts +2 -1
- package/dist/index.d.ts.map +1 -1
- package/dist/index.js +1 -0
- package/dist/index.js.map +1 -1
- package/dist/mcp/core/paywall.d.ts.map +1 -1
- package/dist/mcp/core/paywall.js +69 -8
- package/dist/mcp/core/paywall.js.map +1 -1
- package/dist/mcp/http/index.d.ts +1 -1
- package/dist/mcp/http/index.d.ts.map +1 -1
- package/dist/mcp/http/index.js +1 -1
- package/dist/mcp/http/index.js.map +1 -1
- package/dist/mcp/http/oauth-metadata.d.ts +32 -0
- package/dist/mcp/http/oauth-metadata.d.ts.map +1 -1
- package/dist/mcp/http/oauth-metadata.js +329 -34
- package/dist/mcp/http/oauth-metadata.js.map +1 -1
- package/dist/mcp/index.d.ts +4 -4
- package/dist/mcp/index.d.ts.map +1 -1
- package/dist/mcp/index.js +5 -5
- package/dist/mcp/index.js.map +1 -1
- package/dist/mcp/types/http.types.d.ts +38 -3
- package/dist/mcp/types/http.types.d.ts.map +1 -1
- package/dist/mcp/types/http.types.js.map +1 -1
- package/dist/mcp/types/paywall.types.d.ts +19 -3
- package/dist/mcp/types/paywall.types.d.ts.map +1 -1
- package/dist/mcp/types/paywall.types.js.map +1 -1
- package/dist/mpp/fetch.d.ts +8 -3
- package/dist/mpp/fetch.d.ts.map +1 -1
- package/dist/mpp/fetch.js +6 -0
- package/dist/mpp/fetch.js.map +1 -1
- package/dist/mpp/mpp-api.d.ts +11 -5
- package/dist/mpp/mpp-api.d.ts.map +1 -1
- package/dist/mpp/mpp-api.js +10 -3
- package/dist/mpp/mpp-api.js.map +1 -1
- package/dist/payments.d.ts.map +1 -1
- package/dist/x402/delegation-api.d.ts +5 -17
- package/dist/x402/delegation-api.d.ts.map +1 -1
- package/dist/x402/delegation-api.js +2 -2
- package/dist/x402/delegation-api.js.map +1 -1
- package/dist/x402/express/middleware.d.ts.map +1 -1
- package/dist/x402/express/middleware.js +98 -1
- package/dist/x402/express/middleware.js.map +1 -1
- package/dist/x402/facilitator-api.d.ts +90 -7
- package/dist/x402/facilitator-api.d.ts.map +1 -1
- package/dist/x402/facilitator-api.js +64 -3
- package/dist/x402/facilitator-api.js.map +1 -1
- package/dist/x402/index.d.ts +3 -2
- package/dist/x402/index.d.ts.map +1 -1
- package/dist/x402/index.js +1 -0
- package/dist/x402/index.js.map +1 -1
- package/dist/x402/token-request.d.ts +8 -0
- package/dist/x402/token-request.d.ts.map +1 -1
- package/dist/x402/token-request.js +101 -1
- package/dist/x402/token-request.js.map +1 -1
- package/dist/x402/token-version.d.ts +97 -0
- package/dist/x402/token-version.d.ts.map +1 -0
- package/dist/x402/token-version.js +127 -0
- package/dist/x402/token-version.js.map +1 -0
- package/dist/x402/token.d.ts +33 -2
- package/dist/x402/token.d.ts.map +1 -1
- package/dist/x402/token.js +47 -2
- package/dist/x402/token.js.map +1 -1
- package/package.json +22 -13
package/dist/mpp/fetch.js.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"fetch.js","sourceRoot":"","sources":["../../src/mpp/fetch.ts"],"names":[],"mappings":"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","sourcesContent":["/**\n * The buyer half of MPP: pay a challenged endpoint with an existing Nevermined\n * delegation.\n *\n * The buyer learns nothing about MPP beyond calling this instead of `fetch`.\n * The plan comes out of the challenge, the credential is built from the\n * challenge plus an MPP-domain access token, and the request is retried once.\n *\n * Two error families are used deliberately:\n * - {@link PaymentsError} (`code: 'validation'`) for guards this call refuses\n * to even attempt — a bad argument, a challenge that violates a\n * caller-supplied constraint (`planId`, `maxCredits`), or a body that\n * cannot be replayed. None of these mean a payment failed; nothing was ever\n * attempted.\n * - {@link MppError} (and its typed subclasses) for what the wire actually\n * said: a rejected credential, a malformed challenge, an MPP-disabled\n * environment. A caller branching on `instanceof MppError` to mean\n * \"the payment failed\" gets exactly that, and no more.\n */\n\nimport { PaymentsError } from '../common/payments.error.js'\nimport type { DelegationConfig, X402TokenOptions } from '../common/types.js'\nimport { buildCredentialHeader, parseChallengeHeader, parseReceiptHeader } from './codec.js'\nimport { MppError, MppSpendOutcomeUnknownError, isRetryableMppCode, toMppError } from './errors.js'\nimport type { MppSpendReport } from './errors.js'\nimport type { MppChallenge, MppReceipt } from './types.js'\n\n/**\n * Options for {@link mppFetch} / `MppAPI.fetch`.\n *\n * @experimental The MPP buyer surface may change in a minor release.\n *\n * The request's `init.body`, if any, must be replayable **if the endpoint may\n * challenge the request**: a `ReadableStream` body throws a typed\n * {@link PaymentsError} once a 402 challenge actually requires a retry, since\n * the stream cannot be resent. A request that is never challenged sends a\n * stream body exactly once, exactly like plain `fetch`.\n *\n * This helper mints `nvm:erc4337` access tokens only in this release — a\n * buyer holding an `nvm:card-delegation` delegation cannot use it yet.\n */\nexport interface MppFetchOptions {\n /** The delegation that backs the payment — the same one x402 uses. */\n delegationConfig: DelegationConfig\n /**\n * Overrides the agent id the seller's challenge names — the minted token is\n * addressed to this agent id instead of whatever the challenge carries.\n * Unlike `planId`, this is not a guard: a mismatch is not checked or\n * refused, it simply replaces what the seller asked for. Leave unset to\n * honor the challenge as issued.\n */\n agentId?: string\n /** Fail before minting if the challenge names a different plan than this. */\n planId?: string\n /**\n * Budget for the WHOLE call, not for one challenge: the helper refuses to\n * mint whenever the credits named so far plus the credits this challenge\n * asks for would exceed it. A seller unilaterally names the price, and a\n * re-challenge names it again — a per-turn cap would therefore bound each\n * turn at `maxCredits` and the call at twice it, which is not what \"cap\"\n * reads as. `creditsPresented` on the result is the same running total, so\n * the two always speak about the same number.\n *\n * Must be a non-negative integer (a decimal string, a safe integer, or a\n * `bigint`); anything else is refused with a {@link PaymentsError} at entry,\n * before the first request, rather than mid-flight on the first 402.\n */\n maxCredits?: string | number | bigint\n}\n\n/**\n * What {@link mppFetch} / `MppAPI.fetch` resolves to.\n *\n * @experimental Fields may be added or change meaning in a minor release —\n * `settled` and `creditsPresented` both did during review.\n */\nexport interface MppFetchResult {\n /** The final response — the paid one when a payment happened. */\n response: Response\n /**\n * The decoded `Payment-Receipt`, when the server returned one and it\n * decoded cleanly. A malformed receipt never throws — it leaves this\n * absent (with a console warning) rather than destroying a response the\n * caller already paid for.\n */\n receipt?: MppReceipt\n /**\n * Whether the endpoint returned settlement evidence: a `Payment-Receipt` that\n * decoded cleanly and does not state failure outright. Never derived from the\n * HTTP status.\n *\n * `receipt.status` is read asymmetrically, on purpose. Success is NOT\n * recognized — `'success'` is the only value with agreement behind it, so\n * treating an unrecognized `'ok'`/`'completed'` as failure would report an\n * unpaid call that was in fact paid. An explicit negative (`'failed'`,\n * `'failure'`, `'declined'`, `'error'`) is a different thing from an unknown\n * vocabulary, and is excluded: `paid: true` on a receipt that says the\n * settlement failed is wrong in the one direction this field must never be\n * wrong. Anything else stays `settled: true` with `receipt` on the result, so\n * a caller paying third parties can judge the value itself.\n *\n * This SDK's own seller attaches a receipt only when settlement succeeded, so\n * the distinction is third-party exposure rather than in-ecosystem.\n */\n settled: boolean\n /**\n * How many credentials were minted and presented to the endpoint during\n * this call (0, 1 or 2). This is NOT the same as `settled`:\n * `credentialsPresented > 0` with `settled: false` means the seller may\n * already have burned credits for a credential whose fate is unknown to\n * the caller — treat that as \"do not blindly retry\", not as \"nothing\n * happened\".\n */\n credentialsPresented: number\n /**\n * TOTAL credits named by every challenge a credential was minted against\n * during this call, as a decimal string — summed, not the last turn's\n * amount, since a re-challenge is free to name a different price and the\n * caller is accounting for the call. Present whenever\n * `credentialsPresented > 0`.\n *\n * It is an **upper bound** on what may have burned, never a lower one. A\n * seller that answers a retryable code while replaying the identical\n * challenge id gets a second credential minted against that same challenge\n * (a code decides alone — see {@link mppFetch}), and against a seller that\n * keys single-use on the challenge id, as this SDK's middleware does, that\n * second credential is refused as a replay and burns nothing. The count is\n * deliberately not lowered for it: this field answers \"what could have left\",\n * and guessing which of a remote's credentials it honoured would answer a\n * question the buyer cannot see.\n */\n creditsPresented?: string\n /**\n * Whether a credential was presented AND the final response looks\n * successful: `response.ok && settled`. A 2xx with no receipt (a\n * settlement that silently failed) and a non-2xx with a receipt (settle-\n * then-error) are both `paid: false` — check `settled` and\n * `credentialsPresented` for the honest picture in either case.\n *\n * `ok: true, paid: false, credentialsPresented: 1` is a ROUTINE outcome, not\n * an exotic one: a seller whose handler streams or flushes has already sent\n * its headers when settlement runs, so `Payment-Receipt` cannot be attached\n * to a response that is already on the wire (this SDK's own middleware says\n * so where it settles detached). The credits were burned. Never read this\n * combination as \"the payment did not happen\" and retry.\n */\n paid: boolean\n}\n\n/** Mints an MPP access token for a plan. Supplied by `MppAPI`. */\nexport type MppTokenMinter = (\n planId: string,\n agentId?: string,\n tokenOptions?: X402TokenOptions,\n) => Promise<{ accessToken: string }>\n\n/**\n * Whether `body` is a `ReadableStream`.\n *\n * A stream is single-read: once a `fetch()` starts consuming it, the stream\n * is locked/disturbed, and a *second* `fetch()` with the same `init.body`\n * throws an opaque runtime `TypeError` rather than a typed error. Every other\n * `BodyInit` — `string`, `Buffer`/`ArrayBuffer`/typed arrays,\n * `URLSearchParams`, `FormData`, `Blob`, or no body at all — can be read more\n * than once, so a retry is safe.\n */\nfunction isNonReplayableBody(body: BodyInit | null | undefined): boolean {\n return typeof ReadableStream !== 'undefined' && body instanceof ReadableStream\n}\n\n/**\n * Cap on how much of a 402's error body is buffered before parsing it.\n *\n * The body is seller-controlled and read purely to look for a `code`, so a\n * hostile or broken endpoint answering a 402 with an unbounded stream must not\n * be able to exhaust the buyer's memory.\n *\n * A truncated read of a body large enough to matter will usually not parse; if\n * it does, the prefix necessarily contains the complete `code` object — a\n * truncated prefix of one JSON object can only parse once its closing brace is\n * inside the cap — so the classification is unchanged either way. The branch\n * keys on `JSON.parse` succeeding, never on \"truncated implies unparseable\",\n * which is false: `<complete JSON><whitespace><garbage>` parses after\n * truncation and throws before it.\n */\nconst MAX_ERROR_BODY_BYTES = 64 * 1024\n\n/**\n * Receipt `status` values that state failure outright, lower-cased.\n *\n * `MppReceipt.status` is a seller-set string and this SDK deliberately does not\n * try to recognize *success*: `'success'` is the only value with any agreement\n * behind it, so treating an unrecognized `'ok'`/`'completed'` as failure would\n * report an unpaid call that was in fact paid. The asymmetry is the point — an\n * explicit negative is not an unknown vocabulary, and reporting `paid: true`\n * for a receipt that says the settlement failed is wrong in the one direction\n * this field must never be wrong.\n *\n * Only unambiguous negatives belong here; anything genuinely ambiguous stays\n * unrecognized and is reported as settled, with `receipt` on the result for a\n * caller that wants to judge for itself.\n */\nconst EXPLICIT_FAILURE_RECEIPT_STATUSES: ReadonlySet<string> = new Set([\n 'failed',\n 'failure',\n 'declined',\n 'error',\n])\n\n/** Whether a decoded receipt states outright that the settlement did not happen. */\nfunction statesFailure(receipt: MppReceipt | undefined): boolean {\n return (\n receipt !== undefined &&\n typeof receipt.status === 'string' &&\n EXPLICIT_FAILURE_RECEIPT_STATUSES.has(receipt.status.trim().toLowerCase())\n )\n}\n\n/** The origin of `input`, or the raw value when it does not parse as a URL — used only to label a remote error. */\nfunction originOf(input: string | URL): string {\n try {\n return new URL(String(input)).origin\n } catch {\n return String(input)\n }\n}\n\n/**\n * Parses a challenge header, swallowing any decode failure into `null`.\n *\n * Used only to peek at a re-challenge's freshness inside the retry gate — a\n * garbled re-challenge is simply \"not a fresh challenge\", which the gate\n * already treats as terminal. The FIRST challenge of a 402 is never parsed\n * this leniently: see the `try`/`catch` around {@link parseChallengeHeader}\n * in {@link mppFetch}, which throws a typed error instead, since minting\n * against a challenge this function could not even parse would be worse.\n */\nfunction tryParseChallenge(headerValue: string): MppChallenge | null {\n try {\n return parseChallengeHeader(headerValue)\n } catch {\n return null\n }\n}\n\n/**\n * Refuses a challenge whose `credits` is not a decimal string before it is\n * ever minted against.\n *\n * `parseChallengeHeader` guarantees `credits` is a string OR a number and\n * coerces the number (`isValidChallengeRequestShape` / `toChallengeRequest` in\n * `codec.ts`), so what survives to here and still needs refusing is a string\n * that is not a non-negative integer — `'2.5'`, `'-1'`, `'1e3'`, `'abc'`. Each\n * of those would otherwise reach `BigInt()` in the cap comparison as a raw\n * `SyntaxError`, or the mint as a price nothing can account for.\n *\n * `planId` is NOT re-checked here: the codec already rejects a non-string or\n * empty `planId` outright, so a second guard for it was unreachable code that\n * read as coverage.\n */\nfunction assertValidChallengeRequest(challenge: MppChallenge, input: string | URL): void {\n const credits: unknown = challenge.request?.credits\n if (typeof credits !== 'string' || !/^\\d+$/.test(credits)) {\n throw new MppError(\n `The MPP challenge from ${originOf(input)} names a non-decimal-string credits value ` +\n `(${JSON.stringify(credits)}); refusing to mint.`,\n )\n }\n}\n\n/**\n * Validates `options.maxCredits` at entry and normalizes it to a `bigint`.\n *\n * At entry, not at the comparison: `maxCredits` is a caller argument, and a\n * caller mistake must surface before the first request rather than mid-flight\n * on whatever 402 happens to arrive — and as a {@link PaymentsError}, which is\n * what this module documents for bad arguments, rather than the raw\n * `SyntaxError`/`RangeError` that `BigInt('abc')` or `BigInt(1.5)` throws.\n */\nfunction parseMaxCredits(value: string | number | bigint | undefined): bigint | undefined {\n if (value === undefined) return undefined\n const refuse = () =>\n PaymentsError.validation(\n `maxCredits must be a non-negative integer (decimal string, safe integer or bigint), ` +\n `got ${JSON.stringify(typeof value === 'bigint' ? String(value) : value)}`,\n )\n if (typeof value === 'bigint') {\n if (value < 0n) throw refuse()\n return value\n }\n if (typeof value === 'number') {\n if (!Number.isSafeInteger(value) || value < 0) throw refuse()\n return BigInt(value)\n }\n if (typeof value === 'string' && /^\\d+$/.test(value.trim())) return BigInt(value.trim())\n throw refuse()\n}\n\n/**\n * Reads at most {@link MAX_ERROR_BODY_BYTES} of a response body as text.\n *\n * Streams the clone and stops at the cap instead of `text()`-ing it, so an\n * endpoint answering a 402 with an endless body cannot be used to exhaust the\n * buyer. A runtime whose `Response` exposes no readable `body` (or a test\n * double) falls back to `text()` with the same cap applied afterwards — the\n * bound is then advisory, which is why the streaming path is preferred.\n */\nasync function readBoundedText(response: Response): Promise<string> {\n const body = response.body\n if (!body || typeof body.getReader !== 'function') {\n return (await response.text()).slice(0, MAX_ERROR_BODY_BYTES)\n }\n const reader = body.getReader()\n const chunks: Uint8Array[] = []\n let size = 0\n try {\n for (;;) {\n const { done, value } = await reader.read()\n if (done) break\n if (!value) continue\n // Truncate the chunk that crosses the cap rather than retaining it whole:\n // the transport chooses the chunk size, so \"stop after the chunk that\n // crossed\" would let one huge chunk defeat the bound entirely.\n const room = MAX_ERROR_BODY_BYTES - size\n if (value.byteLength >= room) {\n chunks.push(value.subarray(0, room))\n size = MAX_ERROR_BODY_BYTES\n break\n }\n chunks.push(value)\n size += value.byteLength\n }\n } finally {\n // NOT awaited, deliberately: this reader is one branch of the tee that\n // `clone()` creates, and awaiting its cancel deadlocks while the sibling\n // branch (the response the caller still holds) is unread — verified, it\n // hangs rather than resolving. Signalling the cancel is enough.\n reader.cancel().catch(() => undefined)\n }\n const joined = new Uint8Array(size)\n let offset = 0\n for (const chunk of chunks) {\n joined.set(chunk, offset)\n offset += chunk.byteLength\n }\n return new TextDecoder().decode(joined)\n}\n\n/**\n * Reads the error body of a challenged retry.\n *\n * A retry that comes back 402 is either \"your credential was refused\"\n * (terminal) or \"here is a fresh challenge\" (retryable once). An unreadable\n * or non-JSON body — an HTML WAF/CDN page, a truncated response, a\n * disturbed-body clone failure — is neither: it is treated as terminal by\n * the caller, since it is not evidence of anything retryable.\n *\n * A body that is EMPTY or whitespace-only is not in that class. It is an\n * ordinary HTTP shape — the one the opening 402 is free to use — and carries no\n * code, so it is reported as \"no code\" rather than as unreadable. Reported as\n * unreadable it would suppress the documented fresh-challenge retry against a\n * seller that did nothing wrong, and blame a WAF that is not there. Truncated\n * bodies are non-empty by construction, so this cannot loosen that path.\n */\nasync function readMppErrorCode(\n response: Response,\n): Promise<{ code?: string; message: string; bodyUnreadable?: boolean }> {\n let raw: string\n try {\n raw = await readBoundedText(response.clone())\n } catch (err) {\n return {\n message: `MPP 402 body could not be read: ${err instanceof Error ? err.message : String(err)}`,\n bodyUnreadable: true,\n }\n }\n if (raw.trim() === '') return { message: 'MPP 402 carried no body' }\n try {\n const body = JSON.parse(raw)\n // A non-compliant seller can send a body shaped `{ error: { reason: '...' } }`\n // — no `message`, and `error` itself an object rather than a string.\n // Coerced to a string here, once, so every caller of this function (in\n // particular the terminal-throw's `message.slice(0, 200)`) can treat\n // `message` as always a string instead of risking a raw TypeError.\n const rawMessage = body?.message ?? body?.error\n const message = typeof rawMessage === 'string' ? rawMessage : 'MPP request failed'\n // `code` is only a code when it is a non-empty string. `{\"code\": null}` is\n // a routine way to serialize \"no code\", and taking it literally would both\n // store a `null` in a field typed `code?: string` and skip the\n // fresh-challenge fallback — which is gated on `code === undefined` — so a\n // legitimate re-challenge from such a seller would read as terminal.\n const code = typeof body?.code === 'string' && body.code !== '' ? body.code : undefined\n return { code, message }\n } catch {\n return {\n message: `MPP 402 was not JSON (likely a proxy or WAF page): ${raw.slice(0, 200)}`,\n bodyUnreadable: true,\n }\n }\n}\n\n/**\n * Performs the request, paying an MPP challenge if one comes back.\n *\n * At most one re-challenge cycle is followed: a seller that keeps challenging\n * a freshly paid credential is not going to be satisfied by looping, and a\n * loop would burn a credential per turn.\n *\n * The default on a retry-turn 402 is to STOP, not to pay again. **A code, when\n * present, decides alone**: one {@link isRetryableMppCode} accepts\n * (`BCK.MPP.0004` expired, `BCK.MPP.0005` body-digest mismatch) is retried,\n * every other code is terminal — including a non-`BCK.MPP.*` one, e.g. the\n * `network_error`/`http_500`-shaped code `MppAPI.post` can synthesize and this\n * repo's own seller forwards. The challenge id is not consulted on that path,\n * so a retryable code replaying the identical id does re-mint; `maxCredits`,\n * not id-freshness, is what bounds what that can cost.\n *\n * **With no code**, freshness is the whole signal: a challenge whose `id`\n * differs from the one just presented is a real re-challenge and is retried\n * once, while the identical id replayed, an unparseable challenge or an\n * unreadable body are terminal — a credential already proven invalid is never\n * paid for twice.\n *\n * ### What throws and what comes back as a 402\n *\n * Only a rejection the remote NAMED throws. Three dead ends RETURN the 402\n * instead, because the response is evidence the caller may need and throwing\n * would discard it:\n *\n * 1. A 402 with no USABLE `Payment` challenge (either turn): no\n * `WWW-Authenticate`, another scheme, or a `Payment` challenge missing a\n * required param — {@link parseChallengeHeader} yields nothing for all\n * three, so a seller that announced `Payment` and then sent it malformed\n * lands here too, not only one that does not speak MPP.\n * `credentialsPresented: 0`.\n * 2. A retry-turn 402 that IS retryable but carries no challenge to retry\n * against, so the next turn finds nothing to mint for.\n * 3. The one re-challenge cycle spent: two credentials presented and the\n * seller still answering 402.\n *\n * In cases 2 and 3 a credential WAS presented and may have been burned, so the\n * result is `paid: false` with a non-zero `credentialsPresented` and the last\n * 402 as `response`. Checking `response.ok` is therefore not optional — a\n * resolved promise does not mean the request was paid for.\n *\n * Every throw raised after a credential was presented carries the same\n * accounting as {@link MppSpendReport}, readable with `mppSpendOf(error)`,\n * including a transport failure on the credential-bearing retry (wrapped as\n * {@link MppSpendOutcomeUnknownError} so `instanceof MppError` catches it).\n */\nexport async function mppFetch(\n mintToken: MppTokenMinter,\n input: string | URL,\n init: RequestInit | undefined,\n options: MppFetchOptions,\n): Promise<MppFetchResult> {\n const maxCredits = parseMaxCredits(options.maxCredits)\n const maxChallenges = 2\n let response = await fetch(input, init)\n let credentialsPresented = 0\n let creditsPresentedTotal = 0n\n let lastChallengeId: string | undefined\n\n /** The accounting as it stands right now — reported identically on the return and the throw paths. */\n const spend = (): MppSpendReport => ({\n credentialsPresented,\n ...(credentialsPresented > 0 && { creditsPresented: creditsPresentedTotal.toString() }),\n ...(lastChallengeId !== undefined && { challengeId: lastChallengeId }),\n })\n\n for (let attempt = 0; attempt < maxChallenges; attempt++) {\n if (response.status !== 402) break\n\n const challengeHeader = response.headers.get('www-authenticate')\n if (!challengeHeader) break\n\n // Everything from here to the end of the turn can throw AFTER a credential\n // has been presented on an earlier turn — and, past the mint, after one has\n // been presented on this one. A single boundary attaches the accounting to\n // whatever comes out, so no exit from this function is silent about money.\n try {\n let challenge: MppChallenge | null\n try {\n challenge = parseChallengeHeader(challengeHeader)\n } catch (err) {\n throw new MppError(\n `The 402 from ${originOf(input)} carried a malformed MPP challenge ` +\n `(${err instanceof Error ? err.message : String(err)}). No payment was attempted.`,\n )\n }\n if (!challenge) break\n assertValidChallengeRequest(challenge, input)\n\n const planId = challenge.request.planId\n if (options.planId && options.planId !== planId) {\n throw PaymentsError.validation(\n `MPP challenge names plan ${planId}, but plan ${options.planId} was pinned by the caller`,\n )\n }\n\n // The cap bounds the CALL: what this challenge asks for is added to what\n // earlier turns already committed. Bounding each turn separately would\n // let a seller collect `maxCredits` twice by re-challenging once.\n const credits = BigInt(challenge.request.credits)\n if (maxCredits !== undefined && creditsPresentedTotal + credits > maxCredits) {\n throw PaymentsError.validation(\n `MPP challenge asks for ${challenge.request.credits} credits, which would take this call to ` +\n `${creditsPresentedTotal + credits}, above the caller's cap of ${maxCredits}` +\n (credentialsPresented > 0\n ? ` (${creditsPresentedTotal} already presented on ${credentialsPresented} credential(s))`\n : ''),\n )\n }\n\n // A retry resends init.body verbatim. A ReadableStream is single-read —\n // the first fetch() above already consumed it once — so replaying it now\n // would throw an opaque runtime TypeError. Checked here, at the point a\n // retry is actually about to happen, not before the (harmless) first\n // attempt: whether this endpoint ever challenges is not known ahead of\n // time, and a stream body against a non-challenging endpoint is fine.\n if (isNonReplayableBody(init?.body)) {\n throw PaymentsError.validation(\n 'payments.mpp.fetch cannot retry a ReadableStream request body: streams are single-read, ' +\n 'so the 402 challenge from this endpoint cannot be replayed. Pass a replayable body ' +\n 'instead — a string, Buffer/ArrayBuffer/typed array, URLSearchParams, FormData or Blob.',\n )\n }\n\n const { accessToken } = await mintToken(\n planId,\n options.agentId ?? challenge.request.agentId,\n { delegationConfig: options.delegationConfig },\n )\n\n const headers = new Headers(init?.headers ?? {})\n const existingAuth = headers.get('authorization')\n const credential = buildCredentialHeader(challenge, { accessToken })\n // Append, not replace: a caller authenticating to the resource server\n // with its own Authorization (the normal shape for a metered API) must\n // not have that credential stripped on the request that costs money.\n // Our own seller's extractPaymentScheme was hardened for exactly this\n // multi-scheme shape.\n headers.set('authorization', existingAuth ? `${credential}, ${existingAuth}` : credential)\n\n // Counted BEFORE the request, not after: the credential is on the wire as\n // soon as fetch() is called, so a rejection here (disconnect, DNS, the\n // caller's AbortSignal) must not report zero credentials presented. The\n // seller may already have verified and burned it.\n credentialsPresented += 1\n creditsPresentedTotal += credits\n lastChallengeId = challenge.id\n response = await fetch(input, { ...init, headers })\n\n if (response.status === 402) {\n const { code, message, bodyUnreadable } = await readMppErrorCode(response)\n\n let isFreshChallenge = false\n if (code === undefined && !bodyUnreadable) {\n const nextChallengeHeader = response.headers.get('www-authenticate')\n const nextChallenge = nextChallengeHeader ? tryParseChallenge(nextChallengeHeader) : null\n isFreshChallenge = !!nextChallenge && nextChallenge.id !== challenge.id\n }\n\n if (!isRetryableMppCode(code) && !isFreshChallenge) {\n throw toMppError(\n code,\n `${originOf(input)} rejected the credential: ${message.slice(0, 200)}`,\n )\n }\n // Otherwise the seller genuinely re-challenged (expired, a digest\n // mismatch, or — for a seller that sends no code, including THIS repo's\n // middleware when verification fails for infrastructure reasons — a\n // fresh id); the loop takes one more turn and mints a NEW credential\n // against the fresh challenge — the old one is not re-presented.\n continue\n }\n } catch (err) {\n throw asSpendAwareError(err, spend(), input)\n }\n\n const receiptHeader = response.headers.get('payment-receipt')\n let receipt: MppReceipt | undefined\n if (receiptHeader) {\n try {\n receipt = parseReceiptHeader(receiptHeader)\n } catch (err) {\n // The receipt is decorative (\"unsigned by design, and carries no\n // balance\" — see MppReceipt) and receipt? is optional precisely so\n // it can be absent. A failed decode must not destroy the response\n // the caller already paid for.\n console.warn(\n '[payments.mpp.fetch] payment may have succeeded but the Payment-Receipt could not be ' +\n `decoded: ${err instanceof Error ? err.message : String(err)}`,\n )\n }\n }\n\n const settled = receipt !== undefined && !statesFailure(receipt)\n return {\n response,\n settled,\n paid: response.ok && settled,\n credentialsPresented,\n ...(credentialsPresented > 0 && { creditsPresented: creditsPresentedTotal.toString() }),\n ...(receipt && { receipt }),\n }\n }\n\n // Every dead end documented on this function lands here: no challenge to pay,\n // a retryable 402 with no challenge to retry against, or the re-challenge\n // budget spent. `spend()` is what tells those apart — the last two carry a\n // non-zero `credentialsPresented`.\n return {\n response,\n settled: false,\n paid: false,\n credentialsPresented,\n ...(credentialsPresented > 0 && { creditsPresented: creditsPresentedTotal.toString() }),\n }\n}\n\n/**\n * Attaches spend accounting to whatever is escaping, and wraps a raw\n * transport failure that happened with a credential already on the wire.\n *\n * **Nothing is attached when nothing was presented.** `{ credentialsPresented: 0 }`\n * is a truthy object, so annotating a first-turn argument failure would send a\n * caller following the documented `if (mppSpendOf(err))` pattern into the\n * \"credits may already be burned, do not retry\" branch on a plain validation\n * error — making the field useless for the one decision it exists to inform.\n *\n * With that, three cases:\n * - An {@link MppError} (or the {@link PaymentsError} a caller-constraint guard\n * throws on the re-challenge turn) is annotated and rethrown AS-IS: the type\n * a caller branches on must not change just because money is now reported.\n * - Anything else with a credential already presented becomes an\n * {@link MppSpendOutcomeUnknownError}, so it reaches the `instanceof MppError`\n * handler this module documents instead of escaping as a raw `TypeError`.\n * - Anything else with nothing presented is rethrown untouched — nothing was\n * spent, and dressing up a plain network fault would only obscure it.\n */\nfunction asSpendAwareError(err: unknown, spend: MppSpendReport, input: string | URL): unknown {\n if (spend.credentialsPresented === 0) return err\n if (err instanceof MppError || err instanceof PaymentsError) {\n try {\n const annotated = err as { spend?: MppSpendReport }\n annotated.spend = spend\n return err\n } catch {\n // A frozen or otherwise non-extensible error cannot carry the report, and\n // silently returning it would recreate exactly the invisible-spend failure\n // this boundary exists to close. Fall through to the wrapper below, which\n // holds the report in its own field.\n }\n }\n const detail = err instanceof Error ? err.message : String(err)\n return new MppSpendOutcomeUnknownError(\n err instanceof MppError || err instanceof PaymentsError\n ? `The MPP credential was sent to ${originOf(input)} and the call then failed with an error that ` +\n `could not carry its own spend report (${detail}), so ${spend.creditsPresented} credits may or ` +\n 'may not have been burned. Do not blindly retry.'\n : `The MPP credential was sent to ${originOf(input)} but the request failed before any response ` +\n `was read (${detail}), so ${spend.creditsPresented} credits may or may not have been burned. ` +\n 'Do not blindly retry.',\n err,\n spend,\n )\n}\n"]}
|
|
1
|
+
{"version":3,"file":"fetch.js","sourceRoot":"","sources":["../../src/mpp/fetch.ts"],"names":[],"mappings":"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","sourcesContent":["/**\n * The buyer half of MPP: pay a challenged endpoint with an existing Nevermined\n * delegation.\n *\n * The buyer learns nothing about MPP beyond calling this instead of `fetch`.\n * The plan comes out of the challenge, the credential is built from the\n * challenge plus an MPP-domain access token, and the request is retried once.\n *\n * Two error families are used deliberately:\n * - {@link PaymentsError} (`code: 'validation'`) for guards this call refuses\n * to even attempt — a bad argument, a challenge that violates a\n * caller-supplied constraint (`planId`, `maxCredits`), or a body that\n * cannot be replayed. None of these mean a payment failed; nothing was ever\n * attempted.\n * - {@link MppError} (and its typed subclasses) for what the wire actually\n * said: a rejected credential, a malformed challenge, an MPP-disabled\n * environment. A caller branching on `instanceof MppError` to mean\n * \"the payment failed\" gets exactly that, and no more.\n */\n\nimport { PaymentsError } from '../common/payments.error.js'\nimport type { DelegationConfig, MppTokenOptions } from '../common/types.js'\nimport { buildCredentialHeader, parseChallengeHeader, parseReceiptHeader } from './codec.js'\nimport { MppError, MppSpendOutcomeUnknownError, isRetryableMppCode, toMppError } from './errors.js'\nimport type { MppSpendReport } from './errors.js'\nimport type { MppChallenge, MppReceipt } from './types.js'\n\n/**\n * Options for {@link mppFetch} / `MppAPI.fetch`.\n *\n * @experimental The MPP buyer surface may change in a minor release.\n *\n * The request's `init.body`, if any, must be replayable **if the endpoint may\n * challenge the request**: a `ReadableStream` body throws a typed\n * {@link PaymentsError} once a 402 challenge actually requires a retry, since\n * the stream cannot be resent. A request that is never challenged sends a\n * stream body exactly once, exactly like plain `fetch`.\n *\n * This helper mints `nvm:erc4337` access tokens only in this release — a\n * buyer holding an `nvm:card-delegation` delegation cannot use it yet.\n */\nexport interface MppFetchOptions {\n /** The delegation that backs the payment — the same one x402 uses. */\n delegationConfig: DelegationConfig\n /**\n * Overrides the agent id the seller's challenge names — the minted token is\n * addressed to this agent id instead of whatever the challenge carries.\n * Unlike `planId`, this is not a guard: a mismatch is not checked or\n * refused, it simply replaces what the seller asked for. Leave unset to\n * honor the challenge as issued.\n */\n agentId?: string\n /** Fail before minting if the challenge names a different plan than this. */\n planId?: string\n /**\n * Budget for the WHOLE call, not for one challenge: the helper refuses to\n * mint whenever the credits named so far plus the credits this challenge\n * asks for would exceed it. A seller unilaterally names the price, and a\n * re-challenge names it again — a per-turn cap would therefore bound each\n * turn at `maxCredits` and the call at twice it, which is not what \"cap\"\n * reads as. `creditsPresented` on the result is the same running total, so\n * the two always speak about the same number.\n *\n * Must be a non-negative integer (a decimal string, a safe integer, or a\n * `bigint`); anything else is refused with a {@link PaymentsError} at entry,\n * before the first request, rather than mid-flight on the first 402.\n */\n maxCredits?: string | number | bigint\n}\n\n/**\n * What {@link mppFetch} / `MppAPI.fetch` resolves to.\n *\n * @experimental Fields may be added or change meaning in a minor release —\n * `settled` and `creditsPresented` both did during review.\n */\nexport interface MppFetchResult {\n /** The final response — the paid one when a payment happened. */\n response: Response\n /**\n * The decoded `Payment-Receipt`, when the server returned one and it\n * decoded cleanly. A malformed receipt never throws — it leaves this\n * absent (with a console warning) rather than destroying a response the\n * caller already paid for.\n */\n receipt?: MppReceipt\n /**\n * Whether the endpoint returned settlement evidence: a `Payment-Receipt` that\n * decoded cleanly and does not state failure outright. Never derived from the\n * HTTP status.\n *\n * `receipt.status` is read asymmetrically, on purpose. Success is NOT\n * recognized — `'success'` is the only value with agreement behind it, so\n * treating an unrecognized `'ok'`/`'completed'` as failure would report an\n * unpaid call that was in fact paid. An explicit negative (`'failed'`,\n * `'failure'`, `'declined'`, `'error'`) is a different thing from an unknown\n * vocabulary, and is excluded: `paid: true` on a receipt that says the\n * settlement failed is wrong in the one direction this field must never be\n * wrong. Anything else stays `settled: true` with `receipt` on the result, so\n * a caller paying third parties can judge the value itself.\n *\n * This SDK's own seller attaches a receipt only when settlement succeeded, so\n * the distinction is third-party exposure rather than in-ecosystem.\n */\n settled: boolean\n /**\n * How many credentials were minted and presented to the endpoint during\n * this call (0, 1 or 2). This is NOT the same as `settled`:\n * `credentialsPresented > 0` with `settled: false` means the seller may\n * already have burned credits for a credential whose fate is unknown to\n * the caller — treat that as \"do not blindly retry\", not as \"nothing\n * happened\".\n */\n credentialsPresented: number\n /**\n * TOTAL credits named by every challenge a credential was minted against\n * during this call, as a decimal string — summed, not the last turn's\n * amount, since a re-challenge is free to name a different price and the\n * caller is accounting for the call. Present whenever\n * `credentialsPresented > 0`.\n *\n * It is an **upper bound** on what may have burned, never a lower one. A\n * seller that answers a retryable code while replaying the identical\n * challenge id gets a second credential minted against that same challenge\n * (a code decides alone — see {@link mppFetch}), and against a seller that\n * keys single-use on the challenge id, as this SDK's middleware does, that\n * second credential is refused as a replay and burns nothing. The count is\n * deliberately not lowered for it: this field answers \"what could have left\",\n * and guessing which of a remote's credentials it honoured would answer a\n * question the buyer cannot see.\n */\n creditsPresented?: string\n /**\n * Whether a credential was presented AND the final response looks\n * successful: `response.ok && settled`. A 2xx with no receipt (a\n * settlement that silently failed) and a non-2xx with a receipt (settle-\n * then-error) are both `paid: false` — check `settled` and\n * `credentialsPresented` for the honest picture in either case.\n *\n * `ok: true, paid: false, credentialsPresented: 1` is a ROUTINE outcome, not\n * an exotic one: a seller whose handler streams or flushes has already sent\n * its headers when settlement runs, so `Payment-Receipt` cannot be attached\n * to a response that is already on the wire (this SDK's own middleware says\n * so where it settles detached). The credits were burned. Never read this\n * combination as \"the payment did not happen\" and retry.\n */\n paid: boolean\n}\n\n/**\n * Mints an MPP access token for a plan. Supplied by `MppAPI`.\n *\n * No `tokenVersion`: MPP carries none (nvm-monorepo#3266) — see\n * {@link MppTokenOptions}.\n */\nexport type MppTokenMinter = (\n planId: string,\n agentId?: string,\n tokenOptions?: MppTokenOptions,\n) => Promise<{ accessToken: string }>\n\n/**\n * Whether `body` is a `ReadableStream`.\n *\n * A stream is single-read: once a `fetch()` starts consuming it, the stream\n * is locked/disturbed, and a *second* `fetch()` with the same `init.body`\n * throws an opaque runtime `TypeError` rather than a typed error. Every other\n * `BodyInit` — `string`, `Buffer`/`ArrayBuffer`/typed arrays,\n * `URLSearchParams`, `FormData`, `Blob`, or no body at all — can be read more\n * than once, so a retry is safe.\n */\nfunction isNonReplayableBody(body: BodyInit | null | undefined): boolean {\n return typeof ReadableStream !== 'undefined' && body instanceof ReadableStream\n}\n\n/**\n * Cap on how much of a 402's error body is buffered before parsing it.\n *\n * The body is seller-controlled and read purely to look for a `code`, so a\n * hostile or broken endpoint answering a 402 with an unbounded stream must not\n * be able to exhaust the buyer's memory.\n *\n * A truncated read of a body large enough to matter will usually not parse; if\n * it does, the prefix necessarily contains the complete `code` object — a\n * truncated prefix of one JSON object can only parse once its closing brace is\n * inside the cap — so the classification is unchanged either way. The branch\n * keys on `JSON.parse` succeeding, never on \"truncated implies unparseable\",\n * which is false: `<complete JSON><whitespace><garbage>` parses after\n * truncation and throws before it.\n */\nconst MAX_ERROR_BODY_BYTES = 64 * 1024\n\n/**\n * Receipt `status` values that state failure outright, lower-cased.\n *\n * `MppReceipt.status` is a seller-set string and this SDK deliberately does not\n * try to recognize *success*: `'success'` is the only value with any agreement\n * behind it, so treating an unrecognized `'ok'`/`'completed'` as failure would\n * report an unpaid call that was in fact paid. The asymmetry is the point — an\n * explicit negative is not an unknown vocabulary, and reporting `paid: true`\n * for a receipt that says the settlement failed is wrong in the one direction\n * this field must never be wrong.\n *\n * Only unambiguous negatives belong here; anything genuinely ambiguous stays\n * unrecognized and is reported as settled, with `receipt` on the result for a\n * caller that wants to judge for itself.\n */\nconst EXPLICIT_FAILURE_RECEIPT_STATUSES: ReadonlySet<string> = new Set([\n 'failed',\n 'failure',\n 'declined',\n 'error',\n])\n\n/** Whether a decoded receipt states outright that the settlement did not happen. */\nfunction statesFailure(receipt: MppReceipt | undefined): boolean {\n return (\n receipt !== undefined &&\n typeof receipt.status === 'string' &&\n EXPLICIT_FAILURE_RECEIPT_STATUSES.has(receipt.status.trim().toLowerCase())\n )\n}\n\n/** The origin of `input`, or the raw value when it does not parse as a URL — used only to label a remote error. */\nfunction originOf(input: string | URL): string {\n try {\n return new URL(String(input)).origin\n } catch {\n return String(input)\n }\n}\n\n/**\n * Parses a challenge header, swallowing any decode failure into `null`.\n *\n * Used only to peek at a re-challenge's freshness inside the retry gate — a\n * garbled re-challenge is simply \"not a fresh challenge\", which the gate\n * already treats as terminal. The FIRST challenge of a 402 is never parsed\n * this leniently: see the `try`/`catch` around {@link parseChallengeHeader}\n * in {@link mppFetch}, which throws a typed error instead, since minting\n * against a challenge this function could not even parse would be worse.\n */\nfunction tryParseChallenge(headerValue: string): MppChallenge | null {\n try {\n return parseChallengeHeader(headerValue)\n } catch {\n return null\n }\n}\n\n/**\n * Refuses a challenge whose `credits` is not a decimal string before it is\n * ever minted against.\n *\n * `parseChallengeHeader` guarantees `credits` is a string OR a number and\n * coerces the number (`isValidChallengeRequestShape` / `toChallengeRequest` in\n * `codec.ts`), so what survives to here and still needs refusing is a string\n * that is not a non-negative integer — `'2.5'`, `'-1'`, `'1e3'`, `'abc'`. Each\n * of those would otherwise reach `BigInt()` in the cap comparison as a raw\n * `SyntaxError`, or the mint as a price nothing can account for.\n *\n * `planId` is NOT re-checked here: the codec already rejects a non-string or\n * empty `planId` outright, so a second guard for it was unreachable code that\n * read as coverage.\n */\nfunction assertValidChallengeRequest(challenge: MppChallenge, input: string | URL): void {\n const credits: unknown = challenge.request?.credits\n if (typeof credits !== 'string' || !/^\\d+$/.test(credits)) {\n throw new MppError(\n `The MPP challenge from ${originOf(input)} names a non-decimal-string credits value ` +\n `(${JSON.stringify(credits)}); refusing to mint.`,\n )\n }\n}\n\n/**\n * Validates `options.maxCredits` at entry and normalizes it to a `bigint`.\n *\n * At entry, not at the comparison: `maxCredits` is a caller argument, and a\n * caller mistake must surface before the first request rather than mid-flight\n * on whatever 402 happens to arrive — and as a {@link PaymentsError}, which is\n * what this module documents for bad arguments, rather than the raw\n * `SyntaxError`/`RangeError` that `BigInt('abc')` or `BigInt(1.5)` throws.\n */\nfunction parseMaxCredits(value: string | number | bigint | undefined): bigint | undefined {\n if (value === undefined) return undefined\n const refuse = () =>\n PaymentsError.validation(\n `maxCredits must be a non-negative integer (decimal string, safe integer or bigint), ` +\n `got ${JSON.stringify(typeof value === 'bigint' ? String(value) : value)}`,\n )\n if (typeof value === 'bigint') {\n if (value < 0n) throw refuse()\n return value\n }\n if (typeof value === 'number') {\n if (!Number.isSafeInteger(value) || value < 0) throw refuse()\n return BigInt(value)\n }\n if (typeof value === 'string' && /^\\d+$/.test(value.trim())) return BigInt(value.trim())\n throw refuse()\n}\n\n/**\n * Reads at most {@link MAX_ERROR_BODY_BYTES} of a response body as text.\n *\n * Streams the clone and stops at the cap instead of `text()`-ing it, so an\n * endpoint answering a 402 with an endless body cannot be used to exhaust the\n * buyer. A runtime whose `Response` exposes no readable `body` (or a test\n * double) falls back to `text()` with the same cap applied afterwards — the\n * bound is then advisory, which is why the streaming path is preferred.\n */\nasync function readBoundedText(response: Response): Promise<string> {\n const body = response.body\n if (!body || typeof body.getReader !== 'function') {\n return (await response.text()).slice(0, MAX_ERROR_BODY_BYTES)\n }\n const reader = body.getReader()\n const chunks: Uint8Array[] = []\n let size = 0\n try {\n for (;;) {\n const { done, value } = await reader.read()\n if (done) break\n if (!value) continue\n // Truncate the chunk that crosses the cap rather than retaining it whole:\n // the transport chooses the chunk size, so \"stop after the chunk that\n // crossed\" would let one huge chunk defeat the bound entirely.\n const room = MAX_ERROR_BODY_BYTES - size\n if (value.byteLength >= room) {\n chunks.push(value.subarray(0, room))\n size = MAX_ERROR_BODY_BYTES\n break\n }\n chunks.push(value)\n size += value.byteLength\n }\n } finally {\n // NOT awaited, deliberately: this reader is one branch of the tee that\n // `clone()` creates, and awaiting its cancel deadlocks while the sibling\n // branch (the response the caller still holds) is unread — verified, it\n // hangs rather than resolving. Signalling the cancel is enough.\n reader.cancel().catch(() => undefined)\n }\n const joined = new Uint8Array(size)\n let offset = 0\n for (const chunk of chunks) {\n joined.set(chunk, offset)\n offset += chunk.byteLength\n }\n return new TextDecoder().decode(joined)\n}\n\n/**\n * Reads the error body of a challenged retry.\n *\n * A retry that comes back 402 is either \"your credential was refused\"\n * (terminal) or \"here is a fresh challenge\" (retryable once). An unreadable\n * or non-JSON body — an HTML WAF/CDN page, a truncated response, a\n * disturbed-body clone failure — is neither: it is treated as terminal by\n * the caller, since it is not evidence of anything retryable.\n *\n * A body that is EMPTY or whitespace-only is not in that class. It is an\n * ordinary HTTP shape — the one the opening 402 is free to use — and carries no\n * code, so it is reported as \"no code\" rather than as unreadable. Reported as\n * unreadable it would suppress the documented fresh-challenge retry against a\n * seller that did nothing wrong, and blame a WAF that is not there. Truncated\n * bodies are non-empty by construction, so this cannot loosen that path.\n */\nasync function readMppErrorCode(\n response: Response,\n): Promise<{ code?: string; message: string; bodyUnreadable?: boolean }> {\n let raw: string\n try {\n raw = await readBoundedText(response.clone())\n } catch (err) {\n return {\n message: `MPP 402 body could not be read: ${err instanceof Error ? err.message : String(err)}`,\n bodyUnreadable: true,\n }\n }\n if (raw.trim() === '') return { message: 'MPP 402 carried no body' }\n try {\n const body = JSON.parse(raw)\n // A non-compliant seller can send a body shaped `{ error: { reason: '...' } }`\n // — no `message`, and `error` itself an object rather than a string.\n // Coerced to a string here, once, so every caller of this function (in\n // particular the terminal-throw's `message.slice(0, 200)`) can treat\n // `message` as always a string instead of risking a raw TypeError.\n const rawMessage = body?.message ?? body?.error\n const message = typeof rawMessage === 'string' ? rawMessage : 'MPP request failed'\n // `code` is only a code when it is a non-empty string. `{\"code\": null}` is\n // a routine way to serialize \"no code\", and taking it literally would both\n // store a `null` in a field typed `code?: string` and skip the\n // fresh-challenge fallback — which is gated on `code === undefined` — so a\n // legitimate re-challenge from such a seller would read as terminal.\n const code = typeof body?.code === 'string' && body.code !== '' ? body.code : undefined\n return { code, message }\n } catch {\n return {\n message: `MPP 402 was not JSON (likely a proxy or WAF page): ${raw.slice(0, 200)}`,\n bodyUnreadable: true,\n }\n }\n}\n\n/**\n * Performs the request, paying an MPP challenge if one comes back.\n *\n * At most one re-challenge cycle is followed: a seller that keeps challenging\n * a freshly paid credential is not going to be satisfied by looping, and a\n * loop would burn a credential per turn.\n *\n * The default on a retry-turn 402 is to STOP, not to pay again. **A code, when\n * present, decides alone**: one {@link isRetryableMppCode} accepts\n * (`BCK.MPP.0004` expired, `BCK.MPP.0005` body-digest mismatch) is retried,\n * every other code is terminal — including a non-`BCK.MPP.*` one, e.g. the\n * `network_error`/`http_500`-shaped code `MppAPI.post` can synthesize and this\n * repo's own seller forwards. The challenge id is not consulted on that path,\n * so a retryable code replaying the identical id does re-mint; `maxCredits`,\n * not id-freshness, is what bounds what that can cost.\n *\n * **With no code**, freshness is the whole signal: a challenge whose `id`\n * differs from the one just presented is a real re-challenge and is retried\n * once, while the identical id replayed, an unparseable challenge or an\n * unreadable body are terminal — a credential already proven invalid is never\n * paid for twice.\n *\n * ### What throws and what comes back as a 402\n *\n * Only a rejection the remote NAMED throws. Three dead ends RETURN the 402\n * instead, because the response is evidence the caller may need and throwing\n * would discard it:\n *\n * 1. A 402 with no USABLE `Payment` challenge (either turn): no\n * `WWW-Authenticate`, another scheme, or a `Payment` challenge missing a\n * required param — {@link parseChallengeHeader} yields nothing for all\n * three, so a seller that announced `Payment` and then sent it malformed\n * lands here too, not only one that does not speak MPP.\n * `credentialsPresented: 0`.\n * 2. A retry-turn 402 that IS retryable but carries no challenge to retry\n * against, so the next turn finds nothing to mint for.\n * 3. The one re-challenge cycle spent: two credentials presented and the\n * seller still answering 402.\n *\n * In cases 2 and 3 a credential WAS presented and may have been burned, so the\n * result is `paid: false` with a non-zero `credentialsPresented` and the last\n * 402 as `response`. Checking `response.ok` is therefore not optional — a\n * resolved promise does not mean the request was paid for.\n *\n * Every throw raised after a credential was presented carries the same\n * accounting as {@link MppSpendReport}, readable with `mppSpendOf(error)`,\n * including a transport failure on the credential-bearing retry (wrapped as\n * {@link MppSpendOutcomeUnknownError} so `instanceof MppError` catches it).\n */\nexport async function mppFetch(\n mintToken: MppTokenMinter,\n input: string | URL,\n init: RequestInit | undefined,\n options: MppFetchOptions,\n): Promise<MppFetchResult> {\n const maxCredits = parseMaxCredits(options.maxCredits)\n const maxChallenges = 2\n let response = await fetch(input, init)\n let credentialsPresented = 0\n let creditsPresentedTotal = 0n\n let lastChallengeId: string | undefined\n\n /** The accounting as it stands right now — reported identically on the return and the throw paths. */\n const spend = (): MppSpendReport => ({\n credentialsPresented,\n ...(credentialsPresented > 0 && { creditsPresented: creditsPresentedTotal.toString() }),\n ...(lastChallengeId !== undefined && { challengeId: lastChallengeId }),\n })\n\n for (let attempt = 0; attempt < maxChallenges; attempt++) {\n if (response.status !== 402) break\n\n const challengeHeader = response.headers.get('www-authenticate')\n if (!challengeHeader) break\n\n // Everything from here to the end of the turn can throw AFTER a credential\n // has been presented on an earlier turn — and, past the mint, after one has\n // been presented on this one. A single boundary attaches the accounting to\n // whatever comes out, so no exit from this function is silent about money.\n try {\n let challenge: MppChallenge | null\n try {\n challenge = parseChallengeHeader(challengeHeader)\n } catch (err) {\n throw new MppError(\n `The 402 from ${originOf(input)} carried a malformed MPP challenge ` +\n `(${err instanceof Error ? err.message : String(err)}). No payment was attempted.`,\n )\n }\n if (!challenge) break\n assertValidChallengeRequest(challenge, input)\n\n const planId = challenge.request.planId\n if (options.planId && options.planId !== planId) {\n throw PaymentsError.validation(\n `MPP challenge names plan ${planId}, but plan ${options.planId} was pinned by the caller`,\n )\n }\n\n // The cap bounds the CALL: what this challenge asks for is added to what\n // earlier turns already committed. Bounding each turn separately would\n // let a seller collect `maxCredits` twice by re-challenging once.\n const credits = BigInt(challenge.request.credits)\n if (maxCredits !== undefined && creditsPresentedTotal + credits > maxCredits) {\n throw PaymentsError.validation(\n `MPP challenge asks for ${challenge.request.credits} credits, which would take this call to ` +\n `${creditsPresentedTotal + credits}, above the caller's cap of ${maxCredits}` +\n (credentialsPresented > 0\n ? ` (${creditsPresentedTotal} already presented on ${credentialsPresented} credential(s))`\n : ''),\n )\n }\n\n // A retry resends init.body verbatim. A ReadableStream is single-read —\n // the first fetch() above already consumed it once — so replaying it now\n // would throw an opaque runtime TypeError. Checked here, at the point a\n // retry is actually about to happen, not before the (harmless) first\n // attempt: whether this endpoint ever challenges is not known ahead of\n // time, and a stream body against a non-challenging endpoint is fine.\n if (isNonReplayableBody(init?.body)) {\n throw PaymentsError.validation(\n 'payments.mpp.fetch cannot retry a ReadableStream request body: streams are single-read, ' +\n 'so the 402 challenge from this endpoint cannot be replayed. Pass a replayable body ' +\n 'instead — a string, Buffer/ArrayBuffer/typed array, URLSearchParams, FormData or Blob.',\n )\n }\n\n // No resource/verb binding and no `tokenVersion` here: MPP carries no\n // token version at all (nvm-monorepo#3266). One MPP access token is\n // presented across many challenges — genuinely distinct operations, not\n // retries of one — so a per-token nonce would kill every buyer's second\n // challenge, which is why the two protocols stopped sharing a version\n // ladder. This loop mints a fresh token per credential regardless.\n const { accessToken } = await mintToken(\n planId,\n options.agentId ?? challenge.request.agentId,\n { delegationConfig: options.delegationConfig },\n )\n\n const headers = new Headers(init?.headers ?? {})\n const existingAuth = headers.get('authorization')\n const credential = buildCredentialHeader(challenge, { accessToken })\n // Append, not replace: a caller authenticating to the resource server\n // with its own Authorization (the normal shape for a metered API) must\n // not have that credential stripped on the request that costs money.\n // Our own seller's extractPaymentScheme was hardened for exactly this\n // multi-scheme shape.\n headers.set('authorization', existingAuth ? `${credential}, ${existingAuth}` : credential)\n\n // Counted BEFORE the request, not after: the credential is on the wire as\n // soon as fetch() is called, so a rejection here (disconnect, DNS, the\n // caller's AbortSignal) must not report zero credentials presented. The\n // seller may already have verified and burned it.\n credentialsPresented += 1\n creditsPresentedTotal += credits\n lastChallengeId = challenge.id\n response = await fetch(input, { ...init, headers })\n\n if (response.status === 402) {\n const { code, message, bodyUnreadable } = await readMppErrorCode(response)\n\n let isFreshChallenge = false\n if (code === undefined && !bodyUnreadable) {\n const nextChallengeHeader = response.headers.get('www-authenticate')\n const nextChallenge = nextChallengeHeader ? tryParseChallenge(nextChallengeHeader) : null\n isFreshChallenge = !!nextChallenge && nextChallenge.id !== challenge.id\n }\n\n if (!isRetryableMppCode(code) && !isFreshChallenge) {\n throw toMppError(\n code,\n `${originOf(input)} rejected the credential: ${message.slice(0, 200)}`,\n )\n }\n // Otherwise the seller genuinely re-challenged (expired, a digest\n // mismatch, or — for a seller that sends no code, including THIS repo's\n // middleware when verification fails for infrastructure reasons — a\n // fresh id); the loop takes one more turn and mints a NEW credential\n // against the fresh challenge — the old one is not re-presented.\n continue\n }\n } catch (err) {\n throw asSpendAwareError(err, spend(), input)\n }\n\n const receiptHeader = response.headers.get('payment-receipt')\n let receipt: MppReceipt | undefined\n if (receiptHeader) {\n try {\n receipt = parseReceiptHeader(receiptHeader)\n } catch (err) {\n // The receipt is decorative (\"unsigned by design, and carries no\n // balance\" — see MppReceipt) and receipt? is optional precisely so\n // it can be absent. A failed decode must not destroy the response\n // the caller already paid for.\n console.warn(\n '[payments.mpp.fetch] payment may have succeeded but the Payment-Receipt could not be ' +\n `decoded: ${err instanceof Error ? err.message : String(err)}`,\n )\n }\n }\n\n const settled = receipt !== undefined && !statesFailure(receipt)\n return {\n response,\n settled,\n paid: response.ok && settled,\n credentialsPresented,\n ...(credentialsPresented > 0 && { creditsPresented: creditsPresentedTotal.toString() }),\n ...(receipt && { receipt }),\n }\n }\n\n // Every dead end documented on this function lands here: no challenge to pay,\n // a retryable 402 with no challenge to retry against, or the re-challenge\n // budget spent. `spend()` is what tells those apart — the last two carry a\n // non-zero `credentialsPresented`.\n return {\n response,\n settled: false,\n paid: false,\n credentialsPresented,\n ...(credentialsPresented > 0 && { creditsPresented: creditsPresentedTotal.toString() }),\n }\n}\n\n/**\n * Attaches spend accounting to whatever is escaping, and wraps a raw\n * transport failure that happened with a credential already on the wire.\n *\n * **Nothing is attached when nothing was presented.** `{ credentialsPresented: 0 }`\n * is a truthy object, so annotating a first-turn argument failure would send a\n * caller following the documented `if (mppSpendOf(err))` pattern into the\n * \"credits may already be burned, do not retry\" branch on a plain validation\n * error — making the field useless for the one decision it exists to inform.\n *\n * With that, three cases:\n * - An {@link MppError} (or the {@link PaymentsError} a caller-constraint guard\n * throws on the re-challenge turn) is annotated and rethrown AS-IS: the type\n * a caller branches on must not change just because money is now reported.\n * - Anything else with a credential already presented becomes an\n * {@link MppSpendOutcomeUnknownError}, so it reaches the `instanceof MppError`\n * handler this module documents instead of escaping as a raw `TypeError`.\n * - Anything else with nothing presented is rethrown untouched — nothing was\n * spent, and dressing up a plain network fault would only obscure it.\n */\nfunction asSpendAwareError(err: unknown, spend: MppSpendReport, input: string | URL): unknown {\n if (spend.credentialsPresented === 0) return err\n if (err instanceof MppError || err instanceof PaymentsError) {\n try {\n const annotated = err as { spend?: MppSpendReport }\n annotated.spend = spend\n return err\n } catch {\n // A frozen or otherwise non-extensible error cannot carry the report, and\n // silently returning it would recreate exactly the invisible-spend failure\n // this boundary exists to close. Fall through to the wrapper below, which\n // holds the report in its own field.\n }\n }\n const detail = err instanceof Error ? err.message : String(err)\n return new MppSpendOutcomeUnknownError(\n err instanceof MppError || err instanceof PaymentsError\n ? `The MPP credential was sent to ${originOf(input)} and the call then failed with an error that ` +\n `could not carry its own spend report (${detail}), so ${spend.creditsPresented} credits may or ` +\n 'may not have been burned. Do not blindly retry.'\n : `The MPP credential was sent to ${originOf(input)} but the request failed before any response ` +\n `was read (${detail}), so ${spend.creditsPresented} credits may or may not have been burned. ` +\n 'Do not blindly retry.',\n err,\n spend,\n )\n}\n"]}
|
package/dist/mpp/mpp-api.d.ts
CHANGED
|
@@ -7,7 +7,7 @@
|
|
|
7
7
|
* an MPP-domain access token and present it as a credential.
|
|
8
8
|
*/
|
|
9
9
|
import { BasePaymentsAPI } from '../api/base-payments.js';
|
|
10
|
-
import type {
|
|
10
|
+
import type { MppTokenOptions, PaymentOptions } from '../common/types.js';
|
|
11
11
|
import type { SettlePermissionsResult, VerifyPermissionsResult } from '../x402/facilitator-api.js';
|
|
12
12
|
import { type MppFetchOptions, type MppFetchResult } from './fetch.js';
|
|
13
13
|
/**
|
|
@@ -88,11 +88,17 @@ export declare class MppAPI extends BasePaymentsAPI {
|
|
|
88
88
|
/**
|
|
89
89
|
* Mints an access token signed under the `Nevermined-MPP` EIP-712 domain.
|
|
90
90
|
*
|
|
91
|
-
* Same inputs and same settlement rail as {@link X402TokenAPI.getX402AccessToken}
|
|
92
|
-
* the token verifies only on the MPP routes, which is
|
|
93
|
-
*
|
|
91
|
+
* Same inputs and same settlement rail as {@link X402TokenAPI.getX402AccessToken}
|
|
92
|
+
* minus `tokenVersion`; the token verifies only on the MPP routes, which is
|
|
93
|
+
* what keeps the two protocols isolated.
|
|
94
|
+
*
|
|
95
|
+
* MPP carries **no token version** (nvm-monorepo#3266): its single-use unit is
|
|
96
|
+
* the challenge, not the token, so one MPP token is presented across many
|
|
97
|
+
* challenges by design. The parameter type says so, and a JavaScript caller
|
|
98
|
+
* that sends one anyway is refused before the request — the backend answers
|
|
99
|
+
* `BCK.MPP.0007` for any value, `2` included.
|
|
94
100
|
*/
|
|
95
|
-
getMppAccessToken(planId: string, agentId?: string, tokenOptions?:
|
|
101
|
+
getMppAccessToken(planId: string, agentId?: string, tokenOptions?: MppTokenOptions): Promise<{
|
|
96
102
|
accessToken: string;
|
|
97
103
|
}>;
|
|
98
104
|
/**
|
|
@@ -1 +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,
|
|
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,eAAe,EAAE,cAAc,EAAE,MAAM,oBAAoB,CAAA;AACzE,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;;;;;;;;;;;;OAYG;IACG,iBAAiB,CACrB,MAAM,EAAE,MAAM,EACd,OAAO,CAAC,EAAE,MAAM,EAChB,YAAY,CAAC,EAAE,eAAe,GAC7B,OAAO,CAAC;QAAE,WAAW,EAAE,MAAM,CAAA;KAAE,CAAC;IAWnC;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;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"}
|
package/dist/mpp/mpp-api.js
CHANGED
|
@@ -137,9 +137,15 @@ export class MppAPI extends BasePaymentsAPI {
|
|
|
137
137
|
/**
|
|
138
138
|
* Mints an access token signed under the `Nevermined-MPP` EIP-712 domain.
|
|
139
139
|
*
|
|
140
|
-
* Same inputs and same settlement rail as {@link X402TokenAPI.getX402AccessToken}
|
|
141
|
-
* the token verifies only on the MPP routes, which is
|
|
142
|
-
*
|
|
140
|
+
* Same inputs and same settlement rail as {@link X402TokenAPI.getX402AccessToken}
|
|
141
|
+
* minus `tokenVersion`; the token verifies only on the MPP routes, which is
|
|
142
|
+
* what keeps the two protocols isolated.
|
|
143
|
+
*
|
|
144
|
+
* MPP carries **no token version** (nvm-monorepo#3266): its single-use unit is
|
|
145
|
+
* the challenge, not the token, so one MPP token is presented across many
|
|
146
|
+
* challenges by design. The parameter type says so, and a JavaScript caller
|
|
147
|
+
* that sends one anyway is refused before the request — the backend answers
|
|
148
|
+
* `BCK.MPP.0007` for any value, `2` included.
|
|
143
149
|
*/
|
|
144
150
|
async getMppAccessToken(planId, agentId, tokenOptions) {
|
|
145
151
|
const body = buildX402TokenRequestBody({
|
|
@@ -147,6 +153,7 @@ export class MppAPI extends BasePaymentsAPI {
|
|
|
147
153
|
agentId,
|
|
148
154
|
tokenOptions,
|
|
149
155
|
environmentName: this.environmentName,
|
|
156
|
+
protocol: 'mpp',
|
|
150
157
|
});
|
|
151
158
|
return this.post(API_URL_MPP_CREATE_PERMISSION, body);
|
|
152
159
|
}
|
package/dist/mpp/mpp-api.js.map
CHANGED
|
@@ -1 +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"]}
|
|
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 { MppTokenOptions, PaymentOptions } 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 * minus `tokenVersion`; the token verifies only on the MPP routes, which is\n * what keeps the two protocols isolated.\n *\n * MPP carries **no token version** (nvm-monorepo#3266): its single-use unit is\n * the challenge, not the token, so one MPP token is presented across many\n * challenges by design. The parameter type says so, and a JavaScript caller\n * that sends one anyway is refused before the request — the backend answers\n * `BCK.MPP.0007` for any value, `2` included.\n */\n async getMppAccessToken(\n planId: string,\n agentId?: string,\n tokenOptions?: MppTokenOptions,\n ): Promise<{ accessToken: string }> {\n const body = buildX402TokenRequestBody({\n planId,\n agentId,\n tokenOptions,\n environmentName: this.environmentName,\n protocol: 'mpp',\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"]}
|
package/dist/payments.d.ts.map
CHANGED
|
@@ -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,SAAS,EAAE,MAAM,qBAAqB,CAAA;AAC/C,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;;;;;;;;;;;;;GAaG;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,MAAM,EAAG,SAAS,CAAA;IAClB,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;;;
|
|
1
|
+
{"version":3,"file":"payments.d.ts","sourceRoot":"","sources":["../src/payments.ts"],"names":[],"mappings":"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"}
|
|
@@ -5,20 +5,8 @@
|
|
|
5
5
|
* for use with the nvm:erc4337 and nvm:card-delegation x402 schemes.
|
|
6
6
|
*/
|
|
7
7
|
import { BasePaymentsAPI } from '../api/base-payments.js';
|
|
8
|
-
import { CreateDelegationPayload, CreateDelegationResponse, PaymentOptions } from '../common/types.js';
|
|
9
|
-
|
|
10
|
-
* Card-delegation providers exposed by the SDK. Use this when you want to
|
|
11
|
-
* restrict to card-shape entries only (e.g., filtering the heterogeneous
|
|
12
|
-
* list returned by {@link DelegationAPI.listPaymentMethods}).
|
|
13
|
-
*/
|
|
14
|
-
export type CardProvider = 'stripe' | 'braintree' | 'visa';
|
|
15
|
-
/**
|
|
16
|
-
* All delegation providers, including the crypto path. Matches the
|
|
17
|
-
* server-side union and aligns with {@link CreateDelegationPayload.provider}.
|
|
18
|
-
* `vgs` = a card tokenised in the VGS vault (e.g. Visa Agentic), surfaced by
|
|
19
|
-
* {@link DelegationAPI.listPaymentMethods}.
|
|
20
|
-
*/
|
|
21
|
-
export type DelegationProvider = CardProvider | 'vgs' | 'erc4337';
|
|
8
|
+
import { CreateDelegationPayload, CreateDelegationResponse, DelegationProvider, PaymentOptions } from '../common/types.js';
|
|
9
|
+
export type { CardProvider, DelegationProvider } from '../common/types.js';
|
|
22
10
|
/**
|
|
23
11
|
* Summary of a user's enrolled payment method.
|
|
24
12
|
*
|
|
@@ -47,7 +35,7 @@ export interface PaymentMethodSummary {
|
|
|
47
35
|
expYear: number;
|
|
48
36
|
/** Human-readable alias, if set */
|
|
49
37
|
alias?: string | null;
|
|
50
|
-
/** One of 'stripe' | 'braintree' | 'visa' | 'erc4337' */
|
|
38
|
+
/** One of 'vgs' | 'stripe' | 'braintree' | 'visa' | 'erc4337' */
|
|
51
39
|
provider?: DelegationProvider;
|
|
52
40
|
/** Current status ('Active' or 'Revoked') */
|
|
53
41
|
status?: string;
|
|
@@ -133,8 +121,8 @@ export declare class DelegationAPI extends BasePaymentsAPI {
|
|
|
133
121
|
*/
|
|
134
122
|
getPurchasingPower(): Promise<PurchasingPower>;
|
|
135
123
|
/**
|
|
136
|
-
* Create a new delegation for any supported provider (stripe,
|
|
137
|
-
*
|
|
124
|
+
* Create a new delegation for any supported provider (vgs, stripe, visa,
|
|
125
|
+
* or erc4337).
|
|
138
126
|
*
|
|
139
127
|
* Note: Visa delegations require a per-delegation device-binding ceremony
|
|
140
128
|
* (FIDO/passkey + assuranceData) that must be performed in the browser
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"delegation-api.d.ts","sourceRoot":"","sources":["../../src/x402/delegation-api.ts"],"names":[],"mappings":"AAAA;;;;;GAKG;AAEH,OAAO,EAAE,eAAe,EAAE,MAAM,yBAAyB,CAAA;AAEzD,OAAO,EACL,uBAAuB,EACvB,wBAAwB,EACxB,cAAc,EACf,MAAM,oBAAoB,CAAA;AAE3B
|
|
1
|
+
{"version":3,"file":"delegation-api.d.ts","sourceRoot":"","sources":["../../src/x402/delegation-api.ts"],"names":[],"mappings":"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"}
|
|
@@ -56,8 +56,8 @@ export class DelegationAPI extends BasePaymentsAPI {
|
|
|
56
56
|
};
|
|
57
57
|
}
|
|
58
58
|
/**
|
|
59
|
-
* Create a new delegation for any supported provider (stripe,
|
|
60
|
-
*
|
|
59
|
+
* Create a new delegation for any supported provider (vgs, stripe, visa,
|
|
60
|
+
* or erc4337).
|
|
61
61
|
*
|
|
62
62
|
* Note: Visa delegations require a per-delegation device-binding ceremony
|
|
63
63
|
* (FIDO/passkey + assuranceData) that must be performed in the browser
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"delegation-api.js","sourceRoot":"","sources":["../../src/x402/delegation-api.ts"],"names":[],"mappings":"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","sourcesContent":["/**\n * Delegation API for managing payment delegations (crypto and card schemes).\n *\n * Provides access to the user's enrolled payment methods and delegations\n * for use with the nvm:erc4337 and nvm:card-delegation x402 schemes.\n */\n\nimport { BasePaymentsAPI } from '../api/base-payments.js'\nimport { PaymentsError } from '../common/payments.error.js'\nimport {\n CreateDelegationPayload,\n CreateDelegationResponse,\n PaymentOptions,\n} from '../common/types.js'\n\n/**\n * Card-delegation providers exposed by the SDK. Use this when you want to\n * restrict to card-shape entries only (e.g., filtering the heterogeneous\n * list returned by {@link DelegationAPI.listPaymentMethods}).\n */\nexport type CardProvider = 'stripe' | 'braintree' | 'visa'\n\n/**\n * All delegation providers, including the crypto path. Matches the\n * server-side union and aligns with {@link CreateDelegationPayload.provider}.\n * `vgs` = a card tokenised in the VGS vault (e.g. Visa Agentic), surfaced by\n * {@link DelegationAPI.listPaymentMethods}.\n */\nexport type DelegationProvider = CardProvider | 'vgs' | 'erc4337'\n\n/**\n * Summary of a user's enrolled payment method.\n *\n * The list returned by {@link DelegationAPI.listPaymentMethods} is\n * heterogeneous: it includes enrolled cards (`provider` in\n * `stripe` / `braintree` / `visa`) AND, when the user has a smart account\n * configured, an entry for the user's ERC-4337 wallet\n * (`provider: 'erc4337'`, `type: 'crypto_wallet'`, `brand: 'ethereum'`).\n * Filter on `provider` when callers only want one shape.\n */\nexport interface PaymentMethodSummary {\n /** Payment method ID (Stripe 'pm_...', Braintree vault token, Visa Agentic\n * token id, or — for the erc4337 entry — the smart-account address) */\n id: string\n /** Payment method type ('card' | 'crypto_wallet' | 'paypal' | …) */\n type: string\n /** Card brand (e.g., 'visa', 'mastercard'), 'ethereum' for the erc4337\n * entry, or payment method type ('paypal', 'venmo') */\n brand: string\n /** Last 4 digits (cards), trailing 4 chars of the wallet address\n * (erc4337), or email/username (PayPal/Venmo) */\n last4: string\n /** Expiration month (0 for non-card methods) */\n expMonth: number\n /** Expiration year (0 for non-card methods) */\n expYear: number\n /** Human-readable alias, if set */\n alias?: string | null\n /** One of 'stripe' | 'braintree' | 'visa' | 'erc4337' */\n provider?: DelegationProvider\n /** Current status ('Active' or 'Revoked') */\n status?: string\n /** NVM API Key IDs allowed to use this payment method, or null if unrestricted */\n allowedApiKeyIds?: string[] | null\n}\n\n/**\n * Summary of a delegation (card or crypto spending).\n */\nexport interface DelegationSummary {\n delegationId: string\n provider: string\n providerPaymentMethodId: string\n status: string\n spendingLimitCents: string\n amountSpentCents: string\n remainingBudgetCents: string\n currency: string\n transactionCount: number\n expiresAt: string\n createdAt: string\n apiKeyId: string | null\n}\n\n/**\n * Paginated list of delegations returned by the API.\n */\nexport interface DelegationListResponse {\n delegations: DelegationSummary[]\n totalResults: number\n page: number\n offset: number\n}\n\n/**\n * Summary of an agent's purchasing power via card delegations.\n */\nexport interface PurchasingPower {\n cards: PaymentMethodSummary[]\n delegations: DelegationSummary[]\n totalRemainingBudgetCents: number\n currency: string\n}\n\n/**\n * DTO for updating a payment method's alias and allowed API keys.\n */\nexport interface UpdatePaymentMethodDto {\n alias?: string\n allowedApiKeyIds?: string[] | null\n}\n\n/**\n * Options for listing payment methods or delegations.\n */\nexport interface ListOptions {\n /** When true, return only items accessible to the requesting API key */\n accessible?: boolean\n /**\n * Restrict the result to payment methods backed by this provider\n * (e.g. `'stripe'`). Server-side filter for\n * {@link DelegationAPI.listPaymentMethods}; omit to return methods from every\n * provider (default). Has no effect on {@link DelegationAPI.listDelegations}.\n */\n provider?: DelegationProvider\n}\n\n/**\n * API for managing payment methods and delegations (card and crypto).\n */\nexport class DelegationAPI extends BasePaymentsAPI {\n static getInstance(options: PaymentOptions): DelegationAPI {\n return new DelegationAPI(options)\n }\n\n /**\n * List the user's enrolled payment methods for card delegation.\n * When `accessible: true`, only cards accessible to the requesting API key are returned.\n * When `provider` is set, only methods backed by that provider are returned\n * (server-side filter); omit it to return methods from every provider.\n */\n async listPaymentMethods(options?: ListOptions): Promise<PaymentMethodSummary[]> {\n const url = new URL('/api/v1/payment-methods', this.environment.backend)\n if (options?.accessible) url.searchParams.set('accessible', 'true')\n if (options?.provider) url.searchParams.set('provider', options.provider)\n return this.fetchJSON(url, 'GET', 'list payment methods')\n }\n\n /**\n * List the user's existing delegations.\n * When `accessible: true`, only usable delegations (Active, non-expired, with budget) are returned.\n */\n async listDelegations(options?: ListOptions): Promise<DelegationListResponse> {\n const url = new URL('/api/v1/delegation', this.environment.backend)\n if (options?.accessible) url.searchParams.set('accessible', 'true')\n return this.fetchJSON(url, 'GET', 'list delegations')\n }\n\n /**\n * Get the agent's purchasing power — accessible cards, active delegations,\n * and combined remaining budget.\n */\n async getPurchasingPower(): Promise<PurchasingPower> {\n const accessible = { accessible: true } satisfies ListOptions\n const [cards, { delegations }] = await Promise.all([\n this.listPaymentMethods(accessible),\n this.listDelegations(accessible),\n ])\n\n const totalRemainingBudgetCents = delegations.reduce(\n (sum, d) => sum + (parseInt(d.remainingBudgetCents, 10) || 0),\n 0,\n )\n\n return {\n cards,\n delegations,\n totalRemainingBudgetCents,\n currency: delegations[0]?.currency ?? 'usd',\n }\n }\n\n /**\n * Create a new delegation for any supported provider (stripe, braintree,\n * visa, or erc4337).\n *\n * Note: Visa delegations require a per-delegation device-binding ceremony\n * (FIDO/passkey + assuranceData) that must be performed in the browser\n * via the Nevermined webapp. The SDK can list and consume an already-\n * created Visa delegation but cannot create one programmatically.\n *\n * @param payload - The delegation creation parameters\n * @returns The created delegation ID (and token for card delegations)\n */\n async createDelegation(payload: CreateDelegationPayload): Promise<CreateDelegationResponse> {\n const url = new URL('/api/v1/delegation/create', this.environment.backend)\n return this.fetchJSON(url, 'POST', 'create delegation', payload)\n }\n\n /**\n * Update a payment method's alias and/or allowed API keys.\n */\n async updatePaymentMethod(\n paymentMethodId: string,\n dto: UpdatePaymentMethodDto,\n ): Promise<PaymentMethodSummary> {\n const url = new URL(`/api/v1/payment-methods/${paymentMethodId}`, this.environment.backend)\n return this.fetchJSON(url, 'PATCH', 'update payment method', dto)\n }\n\n // --- Private helpers ---\n\n private async fetchJSON<T>(url: URL, method: string, action: string, body?: unknown): Promise<T> {\n const options = this.getBackendHTTPOptions(method, body)\n try {\n const response = await fetch(url, options)\n if (!response.ok) {\n let msg = `Failed to ${action}`\n let code = `http_${response.status}`\n try {\n const err = await response.json()\n if (err.message) msg = err.message\n if (err.code) code = err.code\n if (err.hint) msg = `${msg} — ${err.hint}`\n } catch {\n // use default\n }\n throw new PaymentsError(`${msg} (HTTP ${response.status})`, code)\n }\n return await response.json()\n } catch (error) {\n if (error instanceof PaymentsError) throw error\n throw PaymentsError.internal(\n `Network error while ${action}: ${error instanceof Error ? error.message : String(error)}`,\n )\n }\n }\n}\n"]}
|
|
1
|
+
{"version":3,"file":"delegation-api.js","sourceRoot":"","sources":["../../src/x402/delegation-api.ts"],"names":[],"mappings":"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","sourcesContent":["/**\n * Delegation API for managing payment delegations (crypto and card schemes).\n *\n * Provides access to the user's enrolled payment methods and delegations\n * for use with the nvm:erc4337 and nvm:card-delegation x402 schemes.\n */\n\nimport { BasePaymentsAPI } from '../api/base-payments.js'\nimport { PaymentsError } from '../common/payments.error.js'\nimport {\n CreateDelegationPayload,\n CreateDelegationResponse,\n DelegationProvider,\n PaymentOptions,\n} from '../common/types.js'\n\nexport type { CardProvider, DelegationProvider } from '../common/types.js'\n\n/**\n * Summary of a user's enrolled payment method.\n *\n * The list returned by {@link DelegationAPI.listPaymentMethods} is\n * heterogeneous: it includes enrolled cards (`provider` in\n * `stripe` / `braintree` / `visa`) AND, when the user has a smart account\n * configured, an entry for the user's ERC-4337 wallet\n * (`provider: 'erc4337'`, `type: 'crypto_wallet'`, `brand: 'ethereum'`).\n * Filter on `provider` when callers only want one shape.\n */\nexport interface PaymentMethodSummary {\n /** Payment method ID (Stripe 'pm_...', Braintree vault token, Visa Agentic\n * token id, or — for the erc4337 entry — the smart-account address) */\n id: string\n /** Payment method type ('card' | 'crypto_wallet' | 'paypal' | …) */\n type: string\n /** Card brand (e.g., 'visa', 'mastercard'), 'ethereum' for the erc4337\n * entry, or payment method type ('paypal', 'venmo') */\n brand: string\n /** Last 4 digits (cards), trailing 4 chars of the wallet address\n * (erc4337), or email/username (PayPal/Venmo) */\n last4: string\n /** Expiration month (0 for non-card methods) */\n expMonth: number\n /** Expiration year (0 for non-card methods) */\n expYear: number\n /** Human-readable alias, if set */\n alias?: string | null\n /** One of 'vgs' | 'stripe' | 'braintree' | 'visa' | 'erc4337' */\n provider?: DelegationProvider\n /** Current status ('Active' or 'Revoked') */\n status?: string\n /** NVM API Key IDs allowed to use this payment method, or null if unrestricted */\n allowedApiKeyIds?: string[] | null\n}\n\n/**\n * Summary of a delegation (card or crypto spending).\n */\nexport interface DelegationSummary {\n delegationId: string\n provider: string\n providerPaymentMethodId: string\n status: string\n spendingLimitCents: string\n amountSpentCents: string\n remainingBudgetCents: string\n currency: string\n transactionCount: number\n expiresAt: string\n createdAt: string\n apiKeyId: string | null\n}\n\n/**\n * Paginated list of delegations returned by the API.\n */\nexport interface DelegationListResponse {\n delegations: DelegationSummary[]\n totalResults: number\n page: number\n offset: number\n}\n\n/**\n * Summary of an agent's purchasing power via card delegations.\n */\nexport interface PurchasingPower {\n cards: PaymentMethodSummary[]\n delegations: DelegationSummary[]\n totalRemainingBudgetCents: number\n currency: string\n}\n\n/**\n * DTO for updating a payment method's alias and allowed API keys.\n */\nexport interface UpdatePaymentMethodDto {\n alias?: string\n allowedApiKeyIds?: string[] | null\n}\n\n/**\n * Options for listing payment methods or delegations.\n */\nexport interface ListOptions {\n /** When true, return only items accessible to the requesting API key */\n accessible?: boolean\n /**\n * Restrict the result to payment methods backed by this provider\n * (e.g. `'stripe'`). Server-side filter for\n * {@link DelegationAPI.listPaymentMethods}; omit to return methods from every\n * provider (default). Has no effect on {@link DelegationAPI.listDelegations}.\n */\n provider?: DelegationProvider\n}\n\n/**\n * API for managing payment methods and delegations (card and crypto).\n */\nexport class DelegationAPI extends BasePaymentsAPI {\n static getInstance(options: PaymentOptions): DelegationAPI {\n return new DelegationAPI(options)\n }\n\n /**\n * List the user's enrolled payment methods for card delegation.\n * When `accessible: true`, only cards accessible to the requesting API key are returned.\n * When `provider` is set, only methods backed by that provider are returned\n * (server-side filter); omit it to return methods from every provider.\n */\n async listPaymentMethods(options?: ListOptions): Promise<PaymentMethodSummary[]> {\n const url = new URL('/api/v1/payment-methods', this.environment.backend)\n if (options?.accessible) url.searchParams.set('accessible', 'true')\n if (options?.provider) url.searchParams.set('provider', options.provider)\n return this.fetchJSON(url, 'GET', 'list payment methods')\n }\n\n /**\n * List the user's existing delegations.\n * When `accessible: true`, only usable delegations (Active, non-expired, with budget) are returned.\n */\n async listDelegations(options?: ListOptions): Promise<DelegationListResponse> {\n const url = new URL('/api/v1/delegation', this.environment.backend)\n if (options?.accessible) url.searchParams.set('accessible', 'true')\n return this.fetchJSON(url, 'GET', 'list delegations')\n }\n\n /**\n * Get the agent's purchasing power — accessible cards, active delegations,\n * and combined remaining budget.\n */\n async getPurchasingPower(): Promise<PurchasingPower> {\n const accessible = { accessible: true } satisfies ListOptions\n const [cards, { delegations }] = await Promise.all([\n this.listPaymentMethods(accessible),\n this.listDelegations(accessible),\n ])\n\n const totalRemainingBudgetCents = delegations.reduce(\n (sum, d) => sum + (parseInt(d.remainingBudgetCents, 10) || 0),\n 0,\n )\n\n return {\n cards,\n delegations,\n totalRemainingBudgetCents,\n currency: delegations[0]?.currency ?? 'usd',\n }\n }\n\n /**\n * Create a new delegation for any supported provider (vgs, stripe, visa,\n * or erc4337).\n *\n * Note: Visa delegations require a per-delegation device-binding ceremony\n * (FIDO/passkey + assuranceData) that must be performed in the browser\n * via the Nevermined webapp. The SDK can list and consume an already-\n * created Visa delegation but cannot create one programmatically.\n *\n * @param payload - The delegation creation parameters\n * @returns The created delegation ID (and token for card delegations)\n */\n async createDelegation(payload: CreateDelegationPayload): Promise<CreateDelegationResponse> {\n const url = new URL('/api/v1/delegation/create', this.environment.backend)\n return this.fetchJSON(url, 'POST', 'create delegation', payload)\n }\n\n /**\n * Update a payment method's alias and/or allowed API keys.\n */\n async updatePaymentMethod(\n paymentMethodId: string,\n dto: UpdatePaymentMethodDto,\n ): Promise<PaymentMethodSummary> {\n const url = new URL(`/api/v1/payment-methods/${paymentMethodId}`, this.environment.backend)\n return this.fetchJSON(url, 'PATCH', 'update payment method', dto)\n }\n\n // --- Private helpers ---\n\n private async fetchJSON<T>(url: URL, method: string, action: string, body?: unknown): Promise<T> {\n const options = this.getBackendHTTPOptions(method, body)\n try {\n const response = await fetch(url, options)\n if (!response.ok) {\n let msg = `Failed to ${action}`\n let code = `http_${response.status}`\n try {\n const err = await response.json()\n if (err.message) msg = err.message\n if (err.code) code = err.code\n if (err.hint) msg = `${msg} — ${err.hint}`\n } catch {\n // use default\n }\n throw new PaymentsError(`${msg} (HTTP ${response.status})`, code)\n }\n return await response.json()\n } catch (error) {\n if (error instanceof PaymentsError) throw error\n throw PaymentsError.internal(\n `Network error while ${action}: ${error instanceof Error ? error.message : String(error)}`,\n )\n }\n }\n}\n"]}
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"middleware.d.ts","sourceRoot":"","sources":["../../../src/x402/express/middleware.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;GA8CG;AAEH,OAAO,KAAK,EAAE,OAAO,EAAE,QAAQ,EAAE,YAAY,EAAE,MAAM,SAAS,CAAA;AAE9D;;;;GAIG;AACH,MAAM,MAAM,iBAAiB,GAAG,CAAC,GAAG,EAAE,OAAO,EAAE,GAAG,EAAE,QAAQ,EAAE,IAAI,EAAE,YAAY,KAAK,IAAI,CAAA;AACzF,OAAO,KAAK,EAAE,QAAQ,EAAE,MAAM,mBAAmB,CAAA;AACjD,OAAO,KAAK,EAAE,iBAAiB,EAAE,cAAc,EAAE,MAAM,uBAAuB,CAAA;AAC9E,OAAO,EAIL,KAAK,mBAAmB,EACxB,KAAK,uBAAuB,EAC7B,MAAM,uBAAuB,CAAA;AAC9B,OAAO,EAOL,KAAK,cAAc,EACpB,MAAM,kBAAkB,CAAA;
|
|
1
|
+
{"version":3,"file":"middleware.d.ts","sourceRoot":"","sources":["../../../src/x402/express/middleware.ts"],"names":[],"mappings":"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"}
|