@nevermined-io/payments 1.12.0 → 1.13.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (54) hide show
  1. package/README.md +33 -0
  2. package/dist/a2a/clientRegistry.d.ts +10 -1
  3. package/dist/a2a/clientRegistry.d.ts.map +1 -1
  4. package/dist/a2a/clientRegistry.js +13 -4
  5. package/dist/a2a/clientRegistry.js.map +1 -1
  6. package/dist/a2a/paymentsClient.d.ts +60 -3
  7. package/dist/a2a/paymentsClient.d.ts.map +1 -1
  8. package/dist/a2a/paymentsClient.js +129 -8
  9. package/dist/a2a/paymentsClient.js.map +1 -1
  10. package/dist/a2a/types.d.ts +5 -0
  11. package/dist/a2a/types.d.ts.map +1 -1
  12. package/dist/a2a/types.js.map +1 -1
  13. package/dist/common/types.d.ts +87 -0
  14. package/dist/common/types.d.ts.map +1 -1
  15. package/dist/common/types.js.map +1 -1
  16. package/dist/index.d.ts +2 -1
  17. package/dist/index.d.ts.map +1 -1
  18. package/dist/index.js +1 -0
  19. package/dist/index.js.map +1 -1
  20. package/dist/mcp/core/paywall.d.ts.map +1 -1
  21. package/dist/mcp/core/paywall.js +10 -0
  22. package/dist/mcp/core/paywall.js.map +1 -1
  23. package/dist/mpp/fetch.d.ts +8 -3
  24. package/dist/mpp/fetch.d.ts.map +1 -1
  25. package/dist/mpp/fetch.js +6 -0
  26. package/dist/mpp/fetch.js.map +1 -1
  27. package/dist/mpp/mpp-api.d.ts +11 -5
  28. package/dist/mpp/mpp-api.d.ts.map +1 -1
  29. package/dist/mpp/mpp-api.js +10 -3
  30. package/dist/mpp/mpp-api.js.map +1 -1
  31. package/dist/x402/express/middleware.d.ts.map +1 -1
  32. package/dist/x402/express/middleware.js +98 -1
  33. package/dist/x402/express/middleware.js.map +1 -1
  34. package/dist/x402/facilitator-api.d.ts +90 -7
  35. package/dist/x402/facilitator-api.d.ts.map +1 -1
  36. package/dist/x402/facilitator-api.js +64 -3
  37. package/dist/x402/facilitator-api.js.map +1 -1
  38. package/dist/x402/index.d.ts +3 -2
  39. package/dist/x402/index.d.ts.map +1 -1
  40. package/dist/x402/index.js +1 -0
  41. package/dist/x402/index.js.map +1 -1
  42. package/dist/x402/token-request.d.ts +8 -0
  43. package/dist/x402/token-request.d.ts.map +1 -1
  44. package/dist/x402/token-request.js +101 -1
  45. package/dist/x402/token-request.js.map +1 -1
  46. package/dist/x402/token-version.d.ts +97 -0
  47. package/dist/x402/token-version.d.ts.map +1 -0
  48. package/dist/x402/token-version.js +127 -0
  49. package/dist/x402/token-version.js.map +1 -0
  50. package/dist/x402/token.d.ts +33 -2
  51. package/dist/x402/token.d.ts.map +1 -1
  52. package/dist/x402/token.js +47 -2
  53. package/dist/x402/token.js.map +1 -1
  54. package/package.json +1 -1
package/dist/index.js CHANGED
@@ -14,6 +14,7 @@ export { OrdersAPI } from './api/orders-api.js';
14
14
  export { OrganizationMemberRole, OrganizationType, OrganizationActivityEventType, } from './api/organizations-api/types.js';
15
15
  // x402 utilities and types
16
16
  export { buildPaymentRequired, resolveNetwork, resolveScheme } from './x402/facilitator-api.js';
17
+ export { detectAccessTokenVersion, isSingleUseAccessToken, isAccessTokenAlreadyUsed, X402_TOKEN_ALREADY_USED_CODE, } from './x402/token-version.js';
17
18
  export { DelegationAPI } from './x402/delegation-api.js';
18
19
  // MPP (Machine Payments Protocol) public surface
19
20
  export * from './mpp/index.js';
package/dist/index.js.map CHANGED
@@ -1 +1 @@
1
- {"version":3,"file":"index.js","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"AAAA,cAAc,mBAAmB,CAAA;AACjC,cAAc,eAAe,CAAA;AAC7B,cAAc,YAAY,CAAA;AAC1B,cAAc,yBAAyB,CAAA;AACvC,cAAc,mBAAmB,CAAA;AACjC,cAAc,4BAA4B,CAAA;AAC1C,cAAc,oBAAoB,CAAA;AAClC,cAAc,oBAAoB,CAAA;AAClC,cAAc,8CAA8C,CAAA;AAE5D,OAAO,EAAE,YAAY,EAAE,MAAM,wBAAwB,CAAA;AACrD,OAAO,EAAE,qBAAqB,EAAE,MAAM,wBAAwB,CAAA;AAE9D,OAAO,EAAE,gBAAgB,EAAE,MAAM,8CAA8C,CAAA;AAC/E,OAAO,EAAE,SAAS,EAAE,MAAM,qBAAqB,CAAA;AAE/C,OAAO,EACL,sBAAsB,EACtB,gBAAgB,EAChB,6BAA6B,GAC9B,MAAM,kCAAkC,CAAA;AAQzC,2BAA2B;AAC3B,OAAO,EAAE,oBAAoB,EAAE,cAAc,EAAE,aAAa,EAAE,MAAM,2BAA2B,CAAA;AAC/F,OAAO,EAAE,aAAa,EAAE,MAAM,0BAA0B,CAAA;AAqBxD,iDAAiD;AACjD,cAAc,gBAAgB,CAAA;AAwB9B,qBAAqB;AACrB,OAAO,EAAE,2BAA2B,EAAE,MAAM,4BAA4B,CAAA;AAqBxE,4EAA4E;AAC5E,OAAO,EACL,YAAY,EACZ,YAAY,EACZ,eAAe,EACf,4BAA4B,EAC5B,aAAa,IAAI,gBAAgB,GAClC,MAAM,mBAAmB,CAAA;AAC1B,OAAO,EACL,sBAAsB,EACtB,yBAAyB,EACzB,0BAA0B,EAC1B,iCAAiC,GAClC,MAAM,qBAAqB,CAAA","sourcesContent":["export * from './environments.js'\nexport * from './payments.js'\nexport * from './utils.js'\nexport * from './common/api-version.js'\nexport * from './common/types.js'\nexport * from './common/payments.error.js'\nexport * from './common/helper.js'\nexport * from './api/query-api.js'\nexport * from './api/observability-api/observability-api.js'\nexport type { BackendApiOptions } from './api/nvm-api.js'\nexport { ContractsAPI } from './api/contracts-api.js'\nexport { CURRENT_ORG_ID_HEADER } from './api/base-payments.js'\nexport type { PublicationOptions } from './api/base-payments.js'\nexport { OrganizationsAPI } from './api/organizations-api/organizations-api.js'\nexport { OrdersAPI } from './api/orders-api.js'\nexport type { CreateOrderOptions, CreateOrderResult, Order, OrderStatus } from './api/orders-api.js'\nexport {\n OrganizationMemberRole,\n OrganizationType,\n OrganizationActivityEventType,\n} from './api/organizations-api/types.js'\nexport type {\n MyMembership,\n OrganizationActivityEvent,\n OrganizationActivityFilters,\n OrganizationActivityPage,\n} from './api/organizations-api/types.js'\n\n// x402 utilities and types\nexport { buildPaymentRequired, resolveNetwork, resolveScheme } from './x402/facilitator-api.js'\nexport { DelegationAPI } from './x402/delegation-api.js'\nexport type {\n PaymentMethodSummary,\n UpdatePaymentMethodDto,\n DelegationSummary,\n DelegationListResponse,\n PurchasingPower,\n ListOptions,\n} from './x402/delegation-api.js'\nexport type {\n X402PaymentRequired,\n X402PaymentAccepted,\n X402Resource,\n X402Scheme,\n X402SchemeExtra,\n VerifyPermissionsParams,\n VerifyPermissionsResult,\n SettlePermissionsParams,\n SettlePermissionsResult,\n} from './x402/facilitator-api.js'\n\n// MPP (Machine Payments Protocol) public surface\nexport * from './mpp/index.js'\n\n// MCP public types\nexport type {\n CreditsContext,\n CreditsOption,\n PaywallOptions,\n McpConfig,\n PaywallContext,\n AuthResult,\n} from './mcp/types/paywall.types.js'\n\n// MCP HTTP types\nexport type {\n OAuthUrls,\n OAuthConfig,\n HttpRouterConfig,\n HttpServerConfig,\n HttpServerResult,\n} from './mcp/types/http.types.js'\n\n// MCP extended config type\nexport type { ExtendedMcpConfig } from './mcp/index.js'\n\n// MCP HTTP utilities\nexport { createRequireAuthMiddleware } from './mcp/http/oauth-router.js'\n\nexport type {\n AgentCard,\n TaskHandlerResult,\n TaskStatusUpdateEvent,\n ExecutionEventBus,\n AgentExecutor,\n RequestContext,\n PushNotificationConfig,\n Task,\n MessageSendParams,\n SendMessageResponse,\n TaskQueryParams,\n GetTaskResponse,\n TaskPushNotificationConfig,\n SetTaskPushNotificationConfigResponse,\n TaskIdParams,\n GetTaskPushNotificationConfigResponse,\n} from './a2a/types.js'\n\n// x402 v2 A2A in-band transport utilities (mirrors the Python X402A2AUtils)\nexport {\n X402A2AUtils,\n x402A2AUtils,\n X402A2AMetadata,\n X402_SETTLEMENT_DEFERRED_KEY,\n PaymentStatus as A2APaymentStatus,\n} from './a2a/x402-a2a.js'\nexport {\n A2A_X402_EXTENSION_URI,\n NVM_PAYMENT_EXTENSION_URI,\n AGENT_CARD_WELL_KNOWN_PATH,\n LEGACY_AGENT_CARD_WELL_KNOWN_PATH,\n} from './a2a/agent-card.js'\n"]}
1
+ {"version":3,"file":"index.js","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"AAAA,cAAc,mBAAmB,CAAA;AACjC,cAAc,eAAe,CAAA;AAC7B,cAAc,YAAY,CAAA;AAC1B,cAAc,yBAAyB,CAAA;AACvC,cAAc,mBAAmB,CAAA;AACjC,cAAc,4BAA4B,CAAA;AAC1C,cAAc,oBAAoB,CAAA;AAClC,cAAc,oBAAoB,CAAA;AAClC,cAAc,8CAA8C,CAAA;AAE5D,OAAO,EAAE,YAAY,EAAE,MAAM,wBAAwB,CAAA;AACrD,OAAO,EAAE,qBAAqB,EAAE,MAAM,wBAAwB,CAAA;AAE9D,OAAO,EAAE,gBAAgB,EAAE,MAAM,8CAA8C,CAAA;AAC/E,OAAO,EAAE,SAAS,EAAE,MAAM,qBAAqB,CAAA;AAE/C,OAAO,EACL,sBAAsB,EACtB,gBAAgB,EAChB,6BAA6B,GAC9B,MAAM,kCAAkC,CAAA;AAQzC,2BAA2B;AAC3B,OAAO,EAAE,oBAAoB,EAAE,cAAc,EAAE,aAAa,EAAE,MAAM,2BAA2B,CAAA;AAC/F,OAAO,EACL,wBAAwB,EACxB,sBAAsB,EACtB,wBAAwB,EACxB,4BAA4B,GAC7B,MAAM,yBAAyB,CAAA;AAChC,OAAO,EAAE,aAAa,EAAE,MAAM,0BAA0B,CAAA;AAsBxD,iDAAiD;AACjD,cAAc,gBAAgB,CAAA;AAwB9B,qBAAqB;AACrB,OAAO,EAAE,2BAA2B,EAAE,MAAM,4BAA4B,CAAA;AAqBxE,4EAA4E;AAC5E,OAAO,EACL,YAAY,EACZ,YAAY,EACZ,eAAe,EACf,4BAA4B,EAC5B,aAAa,IAAI,gBAAgB,GAClC,MAAM,mBAAmB,CAAA;AAC1B,OAAO,EACL,sBAAsB,EACtB,yBAAyB,EACzB,0BAA0B,EAC1B,iCAAiC,GAClC,MAAM,qBAAqB,CAAA","sourcesContent":["export * from './environments.js'\nexport * from './payments.js'\nexport * from './utils.js'\nexport * from './common/api-version.js'\nexport * from './common/types.js'\nexport * from './common/payments.error.js'\nexport * from './common/helper.js'\nexport * from './api/query-api.js'\nexport * from './api/observability-api/observability-api.js'\nexport type { BackendApiOptions } from './api/nvm-api.js'\nexport { ContractsAPI } from './api/contracts-api.js'\nexport { CURRENT_ORG_ID_HEADER } from './api/base-payments.js'\nexport type { PublicationOptions } from './api/base-payments.js'\nexport { OrganizationsAPI } from './api/organizations-api/organizations-api.js'\nexport { OrdersAPI } from './api/orders-api.js'\nexport type { CreateOrderOptions, CreateOrderResult, Order, OrderStatus } from './api/orders-api.js'\nexport {\n OrganizationMemberRole,\n OrganizationType,\n OrganizationActivityEventType,\n} from './api/organizations-api/types.js'\nexport type {\n MyMembership,\n OrganizationActivityEvent,\n OrganizationActivityFilters,\n OrganizationActivityPage,\n} from './api/organizations-api/types.js'\n\n// x402 utilities and types\nexport { buildPaymentRequired, resolveNetwork, resolveScheme } from './x402/facilitator-api.js'\nexport {\n detectAccessTokenVersion,\n isSingleUseAccessToken,\n isAccessTokenAlreadyUsed,\n X402_TOKEN_ALREADY_USED_CODE,\n} from './x402/token-version.js'\nexport { DelegationAPI } from './x402/delegation-api.js'\nexport type {\n PaymentMethodSummary,\n UpdatePaymentMethodDto,\n DelegationSummary,\n DelegationListResponse,\n PurchasingPower,\n ListOptions,\n} from './x402/delegation-api.js'\nexport type {\n X402PaymentRequired,\n X402PaymentAccepted,\n X402Resource,\n X402Scheme,\n X402SchemeExtra,\n VerifyPermissionsParams,\n VerifyPermissionsResult,\n SettlePermissionsParams,\n SettlePermissionsResult,\n X402BillingModel,\n} from './x402/facilitator-api.js'\n\n// MPP (Machine Payments Protocol) public surface\nexport * from './mpp/index.js'\n\n// MCP public types\nexport type {\n CreditsContext,\n CreditsOption,\n PaywallOptions,\n McpConfig,\n PaywallContext,\n AuthResult,\n} from './mcp/types/paywall.types.js'\n\n// MCP HTTP types\nexport type {\n OAuthUrls,\n OAuthConfig,\n HttpRouterConfig,\n HttpServerConfig,\n HttpServerResult,\n} from './mcp/types/http.types.js'\n\n// MCP extended config type\nexport type { ExtendedMcpConfig } from './mcp/index.js'\n\n// MCP HTTP utilities\nexport { createRequireAuthMiddleware } from './mcp/http/oauth-router.js'\n\nexport type {\n AgentCard,\n TaskHandlerResult,\n TaskStatusUpdateEvent,\n ExecutionEventBus,\n AgentExecutor,\n RequestContext,\n PushNotificationConfig,\n Task,\n MessageSendParams,\n SendMessageResponse,\n TaskQueryParams,\n GetTaskResponse,\n TaskPushNotificationConfig,\n SetTaskPushNotificationConfigResponse,\n TaskIdParams,\n GetTaskPushNotificationConfigResponse,\n} from './a2a/types.js'\n\n// x402 v2 A2A in-band transport utilities (mirrors the Python X402A2AUtils)\nexport {\n X402A2AUtils,\n x402A2AUtils,\n X402A2AMetadata,\n X402_SETTLEMENT_DEFERRED_KEY,\n PaymentStatus as A2APaymentStatus,\n} from './a2a/x402-a2a.js'\nexport {\n A2A_X402_EXTENSION_URI,\n NVM_PAYMENT_EXTENSION_URI,\n AGENT_CARD_WELL_KNOWN_PATH,\n LEGACY_AGENT_CARD_WELL_KNOWN_PATH,\n} from './a2a/agent-card.js'\n"]}
@@ -1 +1 @@
1
- {"version":3,"file":"paywall.d.ts","sourceRoot":"","sources":["../../../src/mcp/core/paywall.ts"],"names":[],"mappings":"AAIA,OAAO,KAAK,EAAE,QAAQ,EAAE,MAAM,mBAAmB,CAAA;AAQjD,OAAO,EAEL,SAAS,EAET,aAAa,EACb,eAAe,EACf,WAAW,EACZ,MAAM,2BAA2B,CAAA;AAalC,OAAO,EAAE,oBAAoB,EAAE,MAAM,WAAW,CAAA;AAChD,OAAO,EAAE,sBAAsB,EAAE,MAAM,sBAAsB,CAAA;AAM7D;;GAEG;AACH,qBAAa,gBAAgB;IAQzB,OAAO,CAAC,QAAQ;IAChB,OAAO,CAAC,aAAa;IACrB,OAAO,CAAC,cAAc;IARxB,OAAO,CAAC,MAAM,CAGb;gBAGS,QAAQ,EAAE,QAAQ,EAClB,aAAa,EAAE,oBAAoB,EACnC,cAAc,EAAE,sBAAsB;IAGhD;;OAEG;IACH,SAAS,CAAC,OAAO,EAAE,SAAS,GAAG,IAAI;IAQnC;;OAEG;IAEH,OAAO,CAAC,KAAK,GAAG,GAAG,EACjB,OAAO,EAAE,CAAC,IAAI,EAAE,KAAK,EAAE,KAAK,CAAC,EAAE,GAAG,KAAK,OAAO,CAAC,GAAG,CAAC,GAAG,GAAG,EACzD,OAAO,EAAE,WAAW,GAAG,aAAa,GACnC,CAAC,IAAI,EAAE,KAAK,EAAE,KAAK,CAAC,EAAE,GAAG,KAAK,OAAO,CAAC,GAAG,CAAC;IAC7C,OAAO,CACL,OAAO,EAAE,CACP,GAAG,EAAE,GAAG,EACR,SAAS,EAAE,MAAM,CAAC,MAAM,EAAE,MAAM,GAAG,MAAM,EAAE,CAAC,EAC5C,KAAK,CAAC,EAAE,GAAG,KACR,OAAO,CAAC,GAAG,CAAC,GAAG,GAAG,EACvB,OAAO,EAAE,eAAe,GACvB,CAAC,GAAG,EAAE,GAAG,EAAE,SAAS,EAAE,MAAM,CAAC,MAAM,EAAE,MAAM,GAAG,MAAM,EAAE,CAAC,EAAE,KAAK,CAAC,EAAE,GAAG,KAAK,OAAO,CAAC,GAAG,CAAC;IAKxF;;OAEG;IACH,OAAO,CAAC,oBAAoB;IA6K5B;;;;OAIG;IACH,OAAO,CAAC,4BAA4B;IAYpC;;OAEG;YACW,aAAa;CAyE5B"}
1
+ {"version":3,"file":"paywall.d.ts","sourceRoot":"","sources":["../../../src/mcp/core/paywall.ts"],"names":[],"mappings":"AAIA,OAAO,KAAK,EAAE,QAAQ,EAAE,MAAM,mBAAmB,CAAA;AAQjD,OAAO,EAEL,SAAS,EAET,aAAa,EACb,eAAe,EACf,WAAW,EACZ,MAAM,2BAA2B,CAAA;AAalC,OAAO,EAAE,oBAAoB,EAAE,MAAM,WAAW,CAAA;AAChD,OAAO,EAAE,sBAAsB,EAAE,MAAM,sBAAsB,CAAA;AAM7D;;GAEG;AACH,qBAAa,gBAAgB;IAQzB,OAAO,CAAC,QAAQ;IAChB,OAAO,CAAC,aAAa;IACrB,OAAO,CAAC,cAAc;IARxB,OAAO,CAAC,MAAM,CAGb;gBAGS,QAAQ,EAAE,QAAQ,EAClB,aAAa,EAAE,oBAAoB,EACnC,cAAc,EAAE,sBAAsB;IAGhD;;OAEG;IACH,SAAS,CAAC,OAAO,EAAE,SAAS,GAAG,IAAI;IAQnC;;OAEG;IAEH,OAAO,CAAC,KAAK,GAAG,GAAG,EACjB,OAAO,EAAE,CAAC,IAAI,EAAE,KAAK,EAAE,KAAK,CAAC,EAAE,GAAG,KAAK,OAAO,CAAC,GAAG,CAAC,GAAG,GAAG,EACzD,OAAO,EAAE,WAAW,GAAG,aAAa,GACnC,CAAC,IAAI,EAAE,KAAK,EAAE,KAAK,CAAC,EAAE,GAAG,KAAK,OAAO,CAAC,GAAG,CAAC;IAC7C,OAAO,CACL,OAAO,EAAE,CACP,GAAG,EAAE,GAAG,EACR,SAAS,EAAE,MAAM,CAAC,MAAM,EAAE,MAAM,GAAG,MAAM,EAAE,CAAC,EAC5C,KAAK,CAAC,EAAE,GAAG,KACR,OAAO,CAAC,GAAG,CAAC,GAAG,GAAG,EACvB,OAAO,EAAE,eAAe,GACvB,CAAC,GAAG,EAAE,GAAG,EAAE,SAAS,EAAE,MAAM,CAAC,MAAM,EAAE,MAAM,GAAG,MAAM,EAAE,CAAC,EAAE,KAAK,CAAC,EAAE,GAAG,KAAK,OAAO,CAAC,GAAG,CAAC;IAKxF;;OAEG;IACH,OAAO,CAAC,oBAAoB;IAmL5B;;;;OAIG;IACH,OAAO,CAAC,4BAA4B;IAYpC;;OAEG;YACW,aAAa;CAyE5B"}
@@ -133,10 +133,16 @@ export class PaywallDecorator {
133
133
  ...(creditsResult && { [X402_PAYMENT_RESPONSE_META_KEY]: creditsResult }),
134
134
  [NEVERMINED_CREDITS_META_KEY]: {
135
135
  ...(creditsResult?.transaction && { txHash: creditsResult.transaction }),
136
+ // `creditsRedeemed` is meaningless without this: a pay-as-you-go plan
137
+ // holds no balance, so it reads '0' on a settle that DID charge the
138
+ // buyer. Omitted (not '') when the settle carried no discriminator,
139
+ // so a consumer can tell "absent" from "present and empty".
140
+ ...(creditsResult?.billingModel && { billingModel: creditsResult.billingModel }),
136
141
  creditsRedeemed: creditsResult?.success
137
142
  ? (creditsResult.creditsRedeemed ?? credits.toString())
138
143
  : '0',
139
144
  remainingBalance: creditsResult?.remainingBalance,
145
+ ...(creditsResult?.orderTx && { orderTx: creditsResult.orderTx }),
140
146
  planId: authResult.planId,
141
147
  subscriberAddress: authResult.subscriberAddress,
142
148
  success: creditsResult ? creditsResult.success : true,
@@ -268,10 +274,14 @@ function wrapAsyncIterable(iterable, onFinally, planId, subscriberAddress, credi
268
274
  // Nevermined-namespaced observability (NOT part of the x402 spec).
269
275
  [NEVERMINED_CREDITS_META_KEY]: {
270
276
  ...(settlement?.transaction && { txHash: settlement.transaction }),
277
+ // See the non-streaming site: without `billingModel`, `creditsRedeemed`
278
+ // cannot be read — it is '0' on a pay-as-you-go settle that charged.
279
+ ...(settlement?.billingModel && { billingModel: settlement.billingModel }),
271
280
  creditsRedeemed: settlement?.success
272
281
  ? (settlement.creditsRedeemed ?? credits.toString())
273
282
  : '0',
274
283
  remainingBalance: settlement?.remainingBalance,
284
+ ...(settlement?.orderTx && { orderTx: settlement.orderTx }),
275
285
  planId,
276
286
  subscriberAddress,
277
287
  success: settlement ? settlement.success : true,
@@ -1 +1 @@
1
- {"version":3,"file":"paywall.js","sourceRoot":"","sources":["../../../src/mcp/core/paywall.ts"],"names":[],"mappings":"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","sourcesContent":["/**\n * Main paywall decorator for MCP handlers (tools, resources, prompts)\n */\nimport { Address, isValidScheme } from '../../common/types.js'\nimport type { Payments } from '../../payments.js'\nimport { decodeAccessToken, encodeAccessToken } from '../../utils.js'\nimport {\n buildPaymentRequired,\n buildPaymentRequiredForPlans,\n type SettlePermissionsResult,\n type X402PaymentRequired,\n} from '../../x402/facilitator-api.js'\nimport {\n AuthResult,\n McpConfig,\n PaywallOptions,\n PromptOptions,\n ResourceOptions,\n ToolOptions,\n} from '../types/paywall.types.js'\nimport {\n ERROR_CODES,\n PaymentRequiredError,\n SettlementFailedError,\n createRpcError,\n} from '../utils/errors.js'\nimport {\n NEVERMINED_CREDITS_META_KEY,\n X402_PAYMENT_RESPONSE_META_KEY,\n paymentRequiredResult,\n readPaymentPayload,\n} from '../utils/meta.js'\nimport { PaywallAuthenticator } from './auth.js'\nimport { CreditsContextProvider } from './credits-context.js'\n\n// Emit the Authorization-header deprecation notice at most once per process to\n// avoid log spam on high-traffic servers still using the legacy header path.\nlet authHeaderDeprecationWarned = false\n\n/**\n * Main class for creating paywall-protected MCP handlers\n */\nexport class PaywallDecorator {\n // Internal config ensures serverName is always a concrete string\n private config: { planId: string; agentId?: string; serverName: string } = {\n planId: '',\n serverName: 'mcp-server',\n }\n\n constructor(\n private payments: Payments,\n private authenticator: PaywallAuthenticator,\n private creditsContext: CreditsContextProvider,\n ) {}\n\n /**\n * Configure the paywall with agent and server information\n */\n configure(options: McpConfig): void {\n this.config = {\n planId: options.planId || this.config.planId,\n agentId: options.agentId ?? this.config.agentId,\n serverName: options.serverName ?? this.config.serverName,\n }\n }\n\n /**\n * Create a paywall-protected handler (uncurried version only)\n */\n // Overloads per kind for stronger typing\n protect<TArgs = any>(\n handler: (args: TArgs, extra?: any) => Promise<any> | any,\n options: ToolOptions | PromptOptions,\n ): (args: TArgs, extra?: any) => Promise<any>\n protect(\n handler: (\n uri: URL,\n variables: Record<string, string | string[]>,\n extra?: any,\n ) => Promise<any> | any,\n options: ResourceOptions,\n ): (uri: URL, variables: Record<string, string | string[]>, extra?: any) => Promise<any>\n protect(handler: any, options: PaywallOptions): any {\n return this.createWrappedHandler(handler, options)\n }\n\n /**\n * Internal method to create the wrapped handler\n */\n private createWrappedHandler<TArgs = any>(\n handler: (args: TArgs, extra?: any) => Promise<any> | any,\n options: PaywallOptions,\n ): (...allArgs: any[]) => Promise<any> {\n return async (...allArgs: any[]): Promise<any> => {\n // Validate configuration: a planId must be resolvable (per-tool option or\n // server-level config). agentId is optional under the plan-centric model\n // (the facilitator resolves everything from planId + token).\n const configuredPlanId = options?.planId ?? this.config.planId\n if (!configuredPlanId) {\n throw createRpcError(\n ERROR_CODES.Misconfiguration,\n 'Server misconfiguration: missing planId',\n )\n }\n\n const kind = options?.kind ?? 'tool'\n const name = options?.name ?? 'unnamed'\n\n // Detect resource signature: (url, variables, extra)\n const isResource = allArgs.length >= 2 && allArgs[0] instanceof URL\n const extra = isResource ? allArgs[2] : allArgs[1]\n const argsOrVars = isResource ? allArgs[1] : allArgs[0]\n\n try {\n // x402 v2 MCP transport: prefer the in-band payment payload from\n // params._meta[\"x402/payment\"]. Re-encode it into the access token\n // string the verify/settle path expects and present it via the same\n // extra/headers shape the auth flow reads, so the in-band payload takes\n // precedence over the Authorization header (kept as a deprecated\n // fallback when the in-band payload is absent). The RAW extra is still\n // forwarded to the user handler below.\n const paymentPayload = readPaymentPayload(extra)\n let authExtra = extra\n if (paymentPayload) {\n const token = encodeAccessToken(paymentPayload)\n // Synthesize an auth-only extra carrying the in-band token. This\n // intentionally drops the rest of `extra` for the AUTH call only; the\n // RAW `extra` (with `_meta`) is still forwarded to the user handler below.\n authExtra = { requestInfo: { headers: { authorization: `Bearer ${token}` } } }\n } else if (!authHeaderDeprecationWarned) {\n authHeaderDeprecationWarned = true\n console.warn(\n '[x402] No _meta[\"x402/payment\"] on the MCP request; falling back to the ' +\n 'Authorization header (deprecated under the x402 v2 MCP transport).',\n )\n }\n\n // 1. Authenticate request\n const authResult = await this.authenticator.authenticate(\n authExtra,\n { planId: configuredPlanId, maxAmount: options?.maxAmount },\n this.config.agentId,\n this.config.serverName,\n name,\n kind,\n argsOrVars,\n )\n\n // 2. Pre-calculate credits if they are fixed (not a function)\n // This allows handlers to access credits during execution\n const creditsOption = options?.credits\n const isFixedCredits = typeof creditsOption === 'bigint' || creditsOption === undefined\n const preCalculatedCredits = isFixedCredits\n ? this.creditsContext.resolve(creditsOption, argsOrVars, null, authResult)\n : undefined\n\n // Determine effective planId: explicit option overrides token-derived value\n const effectivePlanId = options?.planId ?? authResult.planId\n\n // 3. Build PaywallContext for handler (with extra wrapper for backward compatibility)\n const paywallContext = {\n authResult,\n credits: preCalculatedCredits,\n planId: authResult.planId,\n subscriberAddress: authResult.subscriberAddress,\n agentRequest: authResult.agentRequest,\n }\n\n // 4. Execute original handler with context\n const result = await (handler as any)(...allArgs, paywallContext)\n\n // 5. Resolve final credits to burn (may be different if credits are dynamic)\n const credits = isFixedCredits\n ? (preCalculatedCredits ?? 1n)\n : this.creditsContext.resolve(creditsOption, argsOrVars, result, authResult)\n\n // Update context with final resolved credits\n paywallContext.credits = credits\n\n // 6. If the result is an AsyncIterable (stream), redeem on completion\n if (isAsyncIterable(result)) {\n const onFinally = async () => {\n return await this.redeemCredits(\n effectivePlanId,\n authResult.token,\n authResult.subscriberAddress,\n credits,\n options,\n authResult.agentId,\n authResult.logicalUrl,\n authResult.httpUrl,\n 'POST',\n )\n }\n return wrapAsyncIterable(\n result,\n onFinally,\n effectivePlanId,\n authResult.subscriberAddress,\n credits,\n )\n }\n\n // 7. Non-streaming: redeem immediately\n const creditsResult = await this.redeemCredits(\n effectivePlanId,\n authResult.token,\n authResult.subscriberAddress,\n credits,\n options,\n authResult.agentId,\n authResult.logicalUrl,\n // fix: pre-existing arg order — fallbackEndpoint=httpUrl, httpVerb='POST'\n // (matches the streaming site above)\n authResult.httpUrl,\n 'POST',\n )\n\n // Settlement failed AFTER the tool executed: per the x402 v2 MCP\n // transport spec, do NOT return the tool's content — surface only the\n // payment error so a paid result is never delivered without payment\n // landing. (onRedeemError \"ignore\" therefore no longer delivers paid\n // content; \"propagate\" already threw a Misconfiguration in redeemCredits.)\n if (creditsResult && !creditsResult.success) {\n console.error(\n `[x402] settlement failed after tool execution; suppressing tool content. reason=${creditsResult.errorReason}`,\n )\n throw new SettlementFailedError(this.buildPaymentRequiredFromAuth(authResult))\n }\n\n // creditsResult is undefined for free / no-credit calls (no settlement\n // performed) — in that case the spec receipt is omitted. On success the\n // full receipt goes under the spec key; Nevermined observability is kept\n // under a namespaced key so it never collides with the spec shape.\n result._meta = {\n ...result._meta,\n ...(creditsResult && { [X402_PAYMENT_RESPONSE_META_KEY]: creditsResult }),\n [NEVERMINED_CREDITS_META_KEY]: {\n ...(creditsResult?.transaction && { txHash: creditsResult.transaction }),\n creditsRedeemed: creditsResult?.success\n ? (creditsResult.creditsRedeemed ?? credits.toString())\n : '0',\n remainingBalance: creditsResult?.remainingBalance,\n planId: authResult.planId,\n subscriberAddress: authResult.subscriberAddress,\n success: creditsResult ? creditsResult.success : true,\n },\n }\n return result\n } catch (error) {\n // Payment-required (pre-execution, from auth) and settlement-failure\n // (post-execution) are surfaced in band as an error tool result for\n // tools. Resources/prompts have no tool-result error channel, so the\n // error propagates as a JSON-RPC error instead.\n if (error instanceof PaymentRequiredError && kind === 'tool') {\n return paymentRequiredResult(error.paymentRequired)\n }\n throw error\n }\n }\n }\n\n /**\n * Build a spec-shaped `PaymentRequired` dict for a settlement failure, from\n * the authenticated request context. Surfaced (with tool content suppressed)\n * when settlement fails after the tool has executed.\n */\n private buildPaymentRequiredFromAuth(authResult: AuthResult): Record<string, any> {\n const planId = authResult.planId || ''\n const paymentRequired = buildPaymentRequiredForPlans(planId ? [planId] : [''], {\n endpoint: authResult.logicalUrl || authResult.httpUrl,\n agentId: authResult.agentId,\n httpVerb: 'POST',\n environment: this.payments.getEnvironmentName(),\n }) as X402PaymentRequired & { error?: string }\n paymentRequired.error = 'settlement failed'\n return paymentRequired\n }\n\n /**\n * Redeem credits after successful request\n */\n private async redeemCredits(\n planId: string,\n token: string,\n subscriberAddress: Address,\n credits: bigint,\n options: PaywallOptions,\n agentId?: string,\n endpoint?: string,\n fallbackEndpoint?: string,\n httpVerb?: string,\n ): Promise<SettlePermissionsResult | undefined> {\n // No settlement for free / no-credit calls — signalled to the caller as\n // `undefined` so the spec receipt (_meta[\"x402/payment-response\"]) is omitted.\n if (!(credits && credits > 0n && subscriberAddress && planId)) {\n return undefined\n }\n\n const decoded = decodeAccessToken(token)\n const scheme = isValidScheme(decoded?.accepted?.scheme)\n ? decoded.accepted.scheme\n : 'nvm:erc4337'\n try {\n const paymentRequired: X402PaymentRequired = buildPaymentRequired(planId, {\n endpoint: endpoint || '',\n agentId,\n httpVerb,\n scheme,\n environment: this.payments.getEnvironmentName(),\n })\n\n return await this.payments.facilitator.settlePermissions({\n paymentRequired,\n x402AccessToken: token,\n maxAmount: credits,\n })\n } catch (primaryError) {\n // If logical URL fails and we have an HTTP URL fallback, retry with it\n let lastError: unknown = primaryError\n if (fallbackEndpoint) {\n try {\n const paymentRequired: X402PaymentRequired = buildPaymentRequired(planId, {\n endpoint: fallbackEndpoint,\n agentId,\n httpVerb,\n scheme,\n environment: this.payments.getEnvironmentName(),\n })\n\n return await this.payments.facilitator.settlePermissions({\n paymentRequired,\n x402AccessToken: token,\n maxAmount: credits,\n })\n } catch (fallbackError) {\n // Fallback also failed, use fallback error as the reported error\n lastError = fallbackError\n }\n }\n\n const errorReason = lastError instanceof Error ? lastError.message : String(lastError)\n console.error(`[x402] settle failed: ${errorReason}`)\n if (options.onRedeemError === 'propagate') {\n throw createRpcError(\n ERROR_CODES.Misconfiguration,\n `Failed to redeem credits: ${errorReason}`,\n )\n }\n // Default (\"ignore\"): return a failed result so the caller suppresses the\n // tool content and surfaces the in-band payment error (always-suppress\n // under the x402 v2 MCP transport).\n return { success: false, transaction: '', network: '', errorReason }\n }\n }\n}\n\n/**\n * Type guard to detect AsyncIterable values.\n */\nfunction isAsyncIterable<T = unknown>(value: any): value is AsyncIterable<T> {\n return value != null && typeof value[Symbol.asyncIterator] === 'function'\n}\n\n/**\n * Wrap an AsyncIterable with metadata injection at the end of the stream\n */\nfunction wrapAsyncIterable<T>(\n iterable: AsyncIterable<T>,\n onFinally: () => Promise<any>,\n planId: string,\n subscriberAddress: Address,\n credits: bigint,\n) {\n async function* generator() {\n let creditsResult: any = null\n try {\n for await (const chunk of iterable) {\n yield chunk as T\n }\n } finally {\n creditsResult = await onFinally()\n }\n\n // Yield a _meta chunk at the end with the redemption result.\n // NOTE: a stream cannot retroactively suppress already-yielded chunks, so a\n // post-execution settlement failure on a stream is only reported here in the\n // final _meta chunk (under nevermined/credits) — it cannot withhold content\n // the way a non-streaming tool result does. `creditsResult` is undefined for\n // free / no-credit calls.\n const settlement = creditsResult || undefined\n const metadataChunk = {\n _meta: {\n // Spec receipt only on a successful settlement.\n ...(settlement?.success && { [X402_PAYMENT_RESPONSE_META_KEY]: settlement }),\n // Nevermined-namespaced observability (NOT part of the x402 spec).\n [NEVERMINED_CREDITS_META_KEY]: {\n ...(settlement?.transaction && { txHash: settlement.transaction }),\n creditsRedeemed: settlement?.success\n ? (settlement.creditsRedeemed ?? credits.toString())\n : '0',\n remainingBalance: settlement?.remainingBalance,\n planId,\n subscriberAddress,\n success: settlement ? settlement.success : true,\n ...(settlement?.errorReason && { errorReason: settlement.errorReason }),\n },\n },\n }\n yield metadataChunk as T\n }\n return generator()\n}\n"]}
1
+ {"version":3,"file":"paywall.js","sourceRoot":"","sources":["../../../src/mcp/core/paywall.ts"],"names":[],"mappings":"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","sourcesContent":["/**\n * Main paywall decorator for MCP handlers (tools, resources, prompts)\n */\nimport { Address, isValidScheme } from '../../common/types.js'\nimport type { Payments } from '../../payments.js'\nimport { decodeAccessToken, encodeAccessToken } from '../../utils.js'\nimport {\n buildPaymentRequired,\n buildPaymentRequiredForPlans,\n type SettlePermissionsResult,\n type X402PaymentRequired,\n} from '../../x402/facilitator-api.js'\nimport {\n AuthResult,\n McpConfig,\n PaywallOptions,\n PromptOptions,\n ResourceOptions,\n ToolOptions,\n} from '../types/paywall.types.js'\nimport {\n ERROR_CODES,\n PaymentRequiredError,\n SettlementFailedError,\n createRpcError,\n} from '../utils/errors.js'\nimport {\n NEVERMINED_CREDITS_META_KEY,\n X402_PAYMENT_RESPONSE_META_KEY,\n paymentRequiredResult,\n readPaymentPayload,\n} from '../utils/meta.js'\nimport { PaywallAuthenticator } from './auth.js'\nimport { CreditsContextProvider } from './credits-context.js'\n\n// Emit the Authorization-header deprecation notice at most once per process to\n// avoid log spam on high-traffic servers still using the legacy header path.\nlet authHeaderDeprecationWarned = false\n\n/**\n * Main class for creating paywall-protected MCP handlers\n */\nexport class PaywallDecorator {\n // Internal config ensures serverName is always a concrete string\n private config: { planId: string; agentId?: string; serverName: string } = {\n planId: '',\n serverName: 'mcp-server',\n }\n\n constructor(\n private payments: Payments,\n private authenticator: PaywallAuthenticator,\n private creditsContext: CreditsContextProvider,\n ) {}\n\n /**\n * Configure the paywall with agent and server information\n */\n configure(options: McpConfig): void {\n this.config = {\n planId: options.planId || this.config.planId,\n agentId: options.agentId ?? this.config.agentId,\n serverName: options.serverName ?? this.config.serverName,\n }\n }\n\n /**\n * Create a paywall-protected handler (uncurried version only)\n */\n // Overloads per kind for stronger typing\n protect<TArgs = any>(\n handler: (args: TArgs, extra?: any) => Promise<any> | any,\n options: ToolOptions | PromptOptions,\n ): (args: TArgs, extra?: any) => Promise<any>\n protect(\n handler: (\n uri: URL,\n variables: Record<string, string | string[]>,\n extra?: any,\n ) => Promise<any> | any,\n options: ResourceOptions,\n ): (uri: URL, variables: Record<string, string | string[]>, extra?: any) => Promise<any>\n protect(handler: any, options: PaywallOptions): any {\n return this.createWrappedHandler(handler, options)\n }\n\n /**\n * Internal method to create the wrapped handler\n */\n private createWrappedHandler<TArgs = any>(\n handler: (args: TArgs, extra?: any) => Promise<any> | any,\n options: PaywallOptions,\n ): (...allArgs: any[]) => Promise<any> {\n return async (...allArgs: any[]): Promise<any> => {\n // Validate configuration: a planId must be resolvable (per-tool option or\n // server-level config). agentId is optional under the plan-centric model\n // (the facilitator resolves everything from planId + token).\n const configuredPlanId = options?.planId ?? this.config.planId\n if (!configuredPlanId) {\n throw createRpcError(\n ERROR_CODES.Misconfiguration,\n 'Server misconfiguration: missing planId',\n )\n }\n\n const kind = options?.kind ?? 'tool'\n const name = options?.name ?? 'unnamed'\n\n // Detect resource signature: (url, variables, extra)\n const isResource = allArgs.length >= 2 && allArgs[0] instanceof URL\n const extra = isResource ? allArgs[2] : allArgs[1]\n const argsOrVars = isResource ? allArgs[1] : allArgs[0]\n\n try {\n // x402 v2 MCP transport: prefer the in-band payment payload from\n // params._meta[\"x402/payment\"]. Re-encode it into the access token\n // string the verify/settle path expects and present it via the same\n // extra/headers shape the auth flow reads, so the in-band payload takes\n // precedence over the Authorization header (kept as a deprecated\n // fallback when the in-band payload is absent). The RAW extra is still\n // forwarded to the user handler below.\n const paymentPayload = readPaymentPayload(extra)\n let authExtra = extra\n if (paymentPayload) {\n const token = encodeAccessToken(paymentPayload)\n // Synthesize an auth-only extra carrying the in-band token. This\n // intentionally drops the rest of `extra` for the AUTH call only; the\n // RAW `extra` (with `_meta`) is still forwarded to the user handler below.\n authExtra = { requestInfo: { headers: { authorization: `Bearer ${token}` } } }\n } else if (!authHeaderDeprecationWarned) {\n authHeaderDeprecationWarned = true\n console.warn(\n '[x402] No _meta[\"x402/payment\"] on the MCP request; falling back to the ' +\n 'Authorization header (deprecated under the x402 v2 MCP transport).',\n )\n }\n\n // 1. Authenticate request\n const authResult = await this.authenticator.authenticate(\n authExtra,\n { planId: configuredPlanId, maxAmount: options?.maxAmount },\n this.config.agentId,\n this.config.serverName,\n name,\n kind,\n argsOrVars,\n )\n\n // 2. Pre-calculate credits if they are fixed (not a function)\n // This allows handlers to access credits during execution\n const creditsOption = options?.credits\n const isFixedCredits = typeof creditsOption === 'bigint' || creditsOption === undefined\n const preCalculatedCredits = isFixedCredits\n ? this.creditsContext.resolve(creditsOption, argsOrVars, null, authResult)\n : undefined\n\n // Determine effective planId: explicit option overrides token-derived value\n const effectivePlanId = options?.planId ?? authResult.planId\n\n // 3. Build PaywallContext for handler (with extra wrapper for backward compatibility)\n const paywallContext = {\n authResult,\n credits: preCalculatedCredits,\n planId: authResult.planId,\n subscriberAddress: authResult.subscriberAddress,\n agentRequest: authResult.agentRequest,\n }\n\n // 4. Execute original handler with context\n const result = await (handler as any)(...allArgs, paywallContext)\n\n // 5. Resolve final credits to burn (may be different if credits are dynamic)\n const credits = isFixedCredits\n ? (preCalculatedCredits ?? 1n)\n : this.creditsContext.resolve(creditsOption, argsOrVars, result, authResult)\n\n // Update context with final resolved credits\n paywallContext.credits = credits\n\n // 6. If the result is an AsyncIterable (stream), redeem on completion\n if (isAsyncIterable(result)) {\n const onFinally = async () => {\n return await this.redeemCredits(\n effectivePlanId,\n authResult.token,\n authResult.subscriberAddress,\n credits,\n options,\n authResult.agentId,\n authResult.logicalUrl,\n authResult.httpUrl,\n 'POST',\n )\n }\n return wrapAsyncIterable(\n result,\n onFinally,\n effectivePlanId,\n authResult.subscriberAddress,\n credits,\n )\n }\n\n // 7. Non-streaming: redeem immediately\n const creditsResult = await this.redeemCredits(\n effectivePlanId,\n authResult.token,\n authResult.subscriberAddress,\n credits,\n options,\n authResult.agentId,\n authResult.logicalUrl,\n // fix: pre-existing arg order — fallbackEndpoint=httpUrl, httpVerb='POST'\n // (matches the streaming site above)\n authResult.httpUrl,\n 'POST',\n )\n\n // Settlement failed AFTER the tool executed: per the x402 v2 MCP\n // transport spec, do NOT return the tool's content — surface only the\n // payment error so a paid result is never delivered without payment\n // landing. (onRedeemError \"ignore\" therefore no longer delivers paid\n // content; \"propagate\" already threw a Misconfiguration in redeemCredits.)\n if (creditsResult && !creditsResult.success) {\n console.error(\n `[x402] settlement failed after tool execution; suppressing tool content. reason=${creditsResult.errorReason}`,\n )\n throw new SettlementFailedError(this.buildPaymentRequiredFromAuth(authResult))\n }\n\n // creditsResult is undefined for free / no-credit calls (no settlement\n // performed) — in that case the spec receipt is omitted. On success the\n // full receipt goes under the spec key; Nevermined observability is kept\n // under a namespaced key so it never collides with the spec shape.\n result._meta = {\n ...result._meta,\n ...(creditsResult && { [X402_PAYMENT_RESPONSE_META_KEY]: creditsResult }),\n [NEVERMINED_CREDITS_META_KEY]: {\n ...(creditsResult?.transaction && { txHash: creditsResult.transaction }),\n // `creditsRedeemed` is meaningless without this: a pay-as-you-go plan\n // holds no balance, so it reads '0' on a settle that DID charge the\n // buyer. Omitted (not '') when the settle carried no discriminator,\n // so a consumer can tell \"absent\" from \"present and empty\".\n ...(creditsResult?.billingModel && { billingModel: creditsResult.billingModel }),\n creditsRedeemed: creditsResult?.success\n ? (creditsResult.creditsRedeemed ?? credits.toString())\n : '0',\n remainingBalance: creditsResult?.remainingBalance,\n ...(creditsResult?.orderTx && { orderTx: creditsResult.orderTx }),\n planId: authResult.planId,\n subscriberAddress: authResult.subscriberAddress,\n success: creditsResult ? creditsResult.success : true,\n },\n }\n return result\n } catch (error) {\n // Payment-required (pre-execution, from auth) and settlement-failure\n // (post-execution) are surfaced in band as an error tool result for\n // tools. Resources/prompts have no tool-result error channel, so the\n // error propagates as a JSON-RPC error instead.\n if (error instanceof PaymentRequiredError && kind === 'tool') {\n return paymentRequiredResult(error.paymentRequired)\n }\n throw error\n }\n }\n }\n\n /**\n * Build a spec-shaped `PaymentRequired` dict for a settlement failure, from\n * the authenticated request context. Surfaced (with tool content suppressed)\n * when settlement fails after the tool has executed.\n */\n private buildPaymentRequiredFromAuth(authResult: AuthResult): Record<string, any> {\n const planId = authResult.planId || ''\n const paymentRequired = buildPaymentRequiredForPlans(planId ? [planId] : [''], {\n endpoint: authResult.logicalUrl || authResult.httpUrl,\n agentId: authResult.agentId,\n httpVerb: 'POST',\n environment: this.payments.getEnvironmentName(),\n }) as X402PaymentRequired & { error?: string }\n paymentRequired.error = 'settlement failed'\n return paymentRequired\n }\n\n /**\n * Redeem credits after successful request\n */\n private async redeemCredits(\n planId: string,\n token: string,\n subscriberAddress: Address,\n credits: bigint,\n options: PaywallOptions,\n agentId?: string,\n endpoint?: string,\n fallbackEndpoint?: string,\n httpVerb?: string,\n ): Promise<SettlePermissionsResult | undefined> {\n // No settlement for free / no-credit calls — signalled to the caller as\n // `undefined` so the spec receipt (_meta[\"x402/payment-response\"]) is omitted.\n if (!(credits && credits > 0n && subscriberAddress && planId)) {\n return undefined\n }\n\n const decoded = decodeAccessToken(token)\n const scheme = isValidScheme(decoded?.accepted?.scheme)\n ? decoded.accepted.scheme\n : 'nvm:erc4337'\n try {\n const paymentRequired: X402PaymentRequired = buildPaymentRequired(planId, {\n endpoint: endpoint || '',\n agentId,\n httpVerb,\n scheme,\n environment: this.payments.getEnvironmentName(),\n })\n\n return await this.payments.facilitator.settlePermissions({\n paymentRequired,\n x402AccessToken: token,\n maxAmount: credits,\n })\n } catch (primaryError) {\n // If logical URL fails and we have an HTTP URL fallback, retry with it\n let lastError: unknown = primaryError\n if (fallbackEndpoint) {\n try {\n const paymentRequired: X402PaymentRequired = buildPaymentRequired(planId, {\n endpoint: fallbackEndpoint,\n agentId,\n httpVerb,\n scheme,\n environment: this.payments.getEnvironmentName(),\n })\n\n return await this.payments.facilitator.settlePermissions({\n paymentRequired,\n x402AccessToken: token,\n maxAmount: credits,\n })\n } catch (fallbackError) {\n // Fallback also failed, use fallback error as the reported error\n lastError = fallbackError\n }\n }\n\n const errorReason = lastError instanceof Error ? lastError.message : String(lastError)\n console.error(`[x402] settle failed: ${errorReason}`)\n if (options.onRedeemError === 'propagate') {\n throw createRpcError(\n ERROR_CODES.Misconfiguration,\n `Failed to redeem credits: ${errorReason}`,\n )\n }\n // Default (\"ignore\"): return a failed result so the caller suppresses the\n // tool content and surfaces the in-band payment error (always-suppress\n // under the x402 v2 MCP transport).\n return { success: false, transaction: '', network: '', errorReason }\n }\n }\n}\n\n/**\n * Type guard to detect AsyncIterable values.\n */\nfunction isAsyncIterable<T = unknown>(value: any): value is AsyncIterable<T> {\n return value != null && typeof value[Symbol.asyncIterator] === 'function'\n}\n\n/**\n * Wrap an AsyncIterable with metadata injection at the end of the stream\n */\nfunction wrapAsyncIterable<T>(\n iterable: AsyncIterable<T>,\n onFinally: () => Promise<any>,\n planId: string,\n subscriberAddress: Address,\n credits: bigint,\n) {\n async function* generator() {\n let creditsResult: any = null\n try {\n for await (const chunk of iterable) {\n yield chunk as T\n }\n } finally {\n creditsResult = await onFinally()\n }\n\n // Yield a _meta chunk at the end with the redemption result.\n // NOTE: a stream cannot retroactively suppress already-yielded chunks, so a\n // post-execution settlement failure on a stream is only reported here in the\n // final _meta chunk (under nevermined/credits) — it cannot withhold content\n // the way a non-streaming tool result does. `creditsResult` is undefined for\n // free / no-credit calls.\n const settlement = creditsResult || undefined\n const metadataChunk = {\n _meta: {\n // Spec receipt only on a successful settlement.\n ...(settlement?.success && { [X402_PAYMENT_RESPONSE_META_KEY]: settlement }),\n // Nevermined-namespaced observability (NOT part of the x402 spec).\n [NEVERMINED_CREDITS_META_KEY]: {\n ...(settlement?.transaction && { txHash: settlement.transaction }),\n // See the non-streaming site: without `billingModel`, `creditsRedeemed`\n // cannot be read — it is '0' on a pay-as-you-go settle that charged.\n ...(settlement?.billingModel && { billingModel: settlement.billingModel }),\n creditsRedeemed: settlement?.success\n ? (settlement.creditsRedeemed ?? credits.toString())\n : '0',\n remainingBalance: settlement?.remainingBalance,\n ...(settlement?.orderTx && { orderTx: settlement.orderTx }),\n planId,\n subscriberAddress,\n success: settlement ? settlement.success : true,\n ...(settlement?.errorReason && { errorReason: settlement.errorReason }),\n },\n },\n }\n yield metadataChunk as T\n }\n return generator()\n}\n"]}
@@ -17,7 +17,7 @@
17
17
  * environment. A caller branching on `instanceof MppError` to mean
18
18
  * "the payment failed" gets exactly that, and no more.
19
19
  */
20
- import type { DelegationConfig, X402TokenOptions } from '../common/types.js';
20
+ import type { DelegationConfig, MppTokenOptions } from '../common/types.js';
21
21
  import type { MppReceipt } from './types.js';
22
22
  /**
23
23
  * Options for {@link mppFetch} / `MppAPI.fetch`.
@@ -139,8 +139,13 @@ export interface MppFetchResult {
139
139
  */
140
140
  paid: boolean;
141
141
  }
142
- /** Mints an MPP access token for a plan. Supplied by `MppAPI`. */
143
- export type MppTokenMinter = (planId: string, agentId?: string, tokenOptions?: X402TokenOptions) => Promise<{
142
+ /**
143
+ * Mints an MPP access token for a plan. Supplied by `MppAPI`.
144
+ *
145
+ * No `tokenVersion`: MPP carries none (nvm-monorepo#3266) — see
146
+ * {@link MppTokenOptions}.
147
+ */
148
+ export type MppTokenMinter = (planId: string, agentId?: string, tokenOptions?: MppTokenOptions) => Promise<{
144
149
  accessToken: string;
145
150
  }>;
146
151
  /**
@@ -1 +1 @@
1
- {"version":3,"file":"fetch.d.ts","sourceRoot":"","sources":["../../src/mpp/fetch.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;;;;GAkBG;AAGH,OAAO,KAAK,EAAE,gBAAgB,EAAE,gBAAgB,EAAE,MAAM,oBAAoB,CAAA;AAI5E,OAAO,KAAK,EAAgB,UAAU,EAAE,MAAM,YAAY,CAAA;AAE1D;;;;;;;;;;;;;GAaG;AACH,MAAM,WAAW,eAAe;IAC9B,sEAAsE;IACtE,gBAAgB,EAAE,gBAAgB,CAAA;IAClC;;;;;;OAMG;IACH,OAAO,CAAC,EAAE,MAAM,CAAA;IAChB,6EAA6E;IAC7E,MAAM,CAAC,EAAE,MAAM,CAAA;IACf;;;;;;;;;;;;OAYG;IACH,UAAU,CAAC,EAAE,MAAM,GAAG,MAAM,GAAG,MAAM,CAAA;CACtC;AAED;;;;;GAKG;AACH,MAAM,WAAW,cAAc;IAC7B,iEAAiE;IACjE,QAAQ,EAAE,QAAQ,CAAA;IAClB;;;;;OAKG;IACH,OAAO,CAAC,EAAE,UAAU,CAAA;IACpB;;;;;;;;;;;;;;;;;OAiBG;IACH,OAAO,EAAE,OAAO,CAAA;IAChB;;;;;;;OAOG;IACH,oBAAoB,EAAE,MAAM,CAAA;IAC5B;;;;;;;;;;;;;;;;OAgBG;IACH,gBAAgB,CAAC,EAAE,MAAM,CAAA;IACzB;;;;;;;;;;;;;OAaG;IACH,IAAI,EAAE,OAAO,CAAA;CACd;AAED,kEAAkE;AAClE,MAAM,MAAM,cAAc,GAAG,CAC3B,MAAM,EAAE,MAAM,EACd,OAAO,CAAC,EAAE,MAAM,EAChB,YAAY,CAAC,EAAE,gBAAgB,KAC5B,OAAO,CAAC;IAAE,WAAW,EAAE,MAAM,CAAA;CAAE,CAAC,CAAA;AAuPrC;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;GAgDG;AACH,wBAAsB,QAAQ,CAC5B,SAAS,EAAE,cAAc,EACzB,KAAK,EAAE,MAAM,GAAG,GAAG,EACnB,IAAI,EAAE,WAAW,GAAG,SAAS,EAC7B,OAAO,EAAE,eAAe,GACvB,OAAO,CAAC,cAAc,CAAC,CAoKzB"}
1
+ {"version":3,"file":"fetch.d.ts","sourceRoot":"","sources":["../../src/mpp/fetch.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;;;;GAkBG;AAGH,OAAO,KAAK,EAAE,gBAAgB,EAAE,eAAe,EAAE,MAAM,oBAAoB,CAAA;AAI3E,OAAO,KAAK,EAAgB,UAAU,EAAE,MAAM,YAAY,CAAA;AAE1D;;;;;;;;;;;;;GAaG;AACH,MAAM,WAAW,eAAe;IAC9B,sEAAsE;IACtE,gBAAgB,EAAE,gBAAgB,CAAA;IAClC;;;;;;OAMG;IACH,OAAO,CAAC,EAAE,MAAM,CAAA;IAChB,6EAA6E;IAC7E,MAAM,CAAC,EAAE,MAAM,CAAA;IACf;;;;;;;;;;;;OAYG;IACH,UAAU,CAAC,EAAE,MAAM,GAAG,MAAM,GAAG,MAAM,CAAA;CACtC;AAED;;;;;GAKG;AACH,MAAM,WAAW,cAAc;IAC7B,iEAAiE;IACjE,QAAQ,EAAE,QAAQ,CAAA;IAClB;;;;;OAKG;IACH,OAAO,CAAC,EAAE,UAAU,CAAA;IACpB;;;;;;;;;;;;;;;;;OAiBG;IACH,OAAO,EAAE,OAAO,CAAA;IAChB;;;;;;;OAOG;IACH,oBAAoB,EAAE,MAAM,CAAA;IAC5B;;;;;;;;;;;;;;;;OAgBG;IACH,gBAAgB,CAAC,EAAE,MAAM,CAAA;IACzB;;;;;;;;;;;;;OAaG;IACH,IAAI,EAAE,OAAO,CAAA;CACd;AAED;;;;;GAKG;AACH,MAAM,MAAM,cAAc,GAAG,CAC3B,MAAM,EAAE,MAAM,EACd,OAAO,CAAC,EAAE,MAAM,EAChB,YAAY,CAAC,EAAE,eAAe,KAC3B,OAAO,CAAC;IAAE,WAAW,EAAE,MAAM,CAAA;CAAE,CAAC,CAAA;AAuPrC;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;GAgDG;AACH,wBAAsB,QAAQ,CAC5B,SAAS,EAAE,cAAc,EACzB,KAAK,EAAE,MAAM,GAAG,GAAG,EACnB,IAAI,EAAE,WAAW,GAAG,SAAS,EAC7B,OAAO,EAAE,eAAe,GACvB,OAAO,CAAC,cAAc,CAAC,CA0KzB"}
package/dist/mpp/fetch.js CHANGED
@@ -368,6 +368,12 @@ export async function mppFetch(mintToken, input, init, options) {
368
368
  'so the 402 challenge from this endpoint cannot be replayed. Pass a replayable body ' +
369
369
  'instead — a string, Buffer/ArrayBuffer/typed array, URLSearchParams, FormData or Blob.');
370
370
  }
371
+ // No resource/verb binding and no `tokenVersion` here: MPP carries no
372
+ // token version at all (nvm-monorepo#3266). One MPP access token is
373
+ // presented across many challenges — genuinely distinct operations, not
374
+ // retries of one — so a per-token nonce would kill every buyer's second
375
+ // challenge, which is why the two protocols stopped sharing a version
376
+ // ladder. This loop mints a fresh token per credential regardless.
371
377
  const { accessToken } = await mintToken(planId, options.agentId ?? challenge.request.agentId, { delegationConfig: options.delegationConfig });
372
378
  const headers = new Headers(init?.headers ?? {});
373
379
  const existingAuth = headers.get('authorization');
@@ -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"]}
@@ -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 { PaymentOptions, X402TokenOptions } from '../common/types.js';
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 what keeps the two
93
- * protocols isolated even though the tokens are byte-identical on the wire.
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?: X402TokenOptions): Promise<{
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,cAAc,EAAE,gBAAgB,EAAE,MAAM,oBAAoB,CAAA;AAC1E,OAAO,KAAK,EAAE,uBAAuB,EAAE,uBAAuB,EAAE,MAAM,4BAA4B,CAAA;AAGlG,OAAO,EAAY,KAAK,eAAe,EAAE,KAAK,cAAc,EAAE,MAAM,YAAY,CAAA;AAShF;;;;;;;;;;;;;;GAcG;AACH,wBAAgB,gBAAgB,CAAC,OAAO,EAAE,MAAM,GAAG,MAAM,GAAG,MAAM,GAAG,MAAM,CAsB1E;AAmDD,MAAM,WAAW,uBAAuB;IACtC,0DAA0D;IAC1D,MAAM,EAAE,MAAM,CAAA;IACd,sEAAsE;IACtE,OAAO,EAAE,MAAM,GAAG,MAAM,GAAG,MAAM,CAAA;IACjC,OAAO,CAAC,EAAE,MAAM,CAAA;IAChB,mFAAmF;IACnF,QAAQ,EAAE,MAAM,CAAA;IAChB,4DAA4D;IAC5D,QAAQ,EAAE,MAAM,CAAA;IAChB,2EAA2E;IAC3E,MAAM,CAAC,EAAE,MAAM,CAAA;IACf,WAAW,CAAC,EAAE,MAAM,CAAA;CACrB;AAED,MAAM,WAAW,eAAe;IAC9B,mEAAmE;IACnE,UAAU,EAAE,MAAM,CAAA;IAClB,4DAA4D;IAC5D,QAAQ,EAAE,MAAM,CAAA;IAChB,wDAAwD;IACxD,QAAQ,EAAE,MAAM,CAAA;IAChB,0EAA0E;IAC1E,UAAU,CAAC,EAAE,MAAM,CAAA;CACpB;AAED;;;;;;GAMG;AACH,MAAM,MAAM,eAAe,GACvB,CAAC,uBAAuB,GAAG;IAAE,OAAO,EAAE,IAAI,CAAC;IAAC,cAAc,EAAE,MAAM,CAAA;CAAE,CAAC,GACrE,CAAC,uBAAuB,GAAG;IAAE,OAAO,EAAE,KAAK,CAAC;IAAC,cAAc,CAAC,EAAE,MAAM,CAAA;CAAE,CAAC,CAAA;AAE3E,qBAAa,MAAO,SAAQ,eAAe;IACzC,MAAM,CAAC,WAAW,CAAC,OAAO,EAAE,cAAc,GAAG,MAAM;IAInD;;;;;;OAMG;IACG,cAAc,CAClB,MAAM,EAAE,uBAAuB,GAC9B,OAAO,CAAC;QAAE,SAAS,EAAE,MAAM,CAAC;QAAC,EAAE,EAAE,MAAM,CAAA;KAAE,CAAC;IAa7C,yEAAyE;IACnE,gBAAgB,CAAC,MAAM,EAAE,eAAe,GAAG,OAAO,CAAC,uBAAuB,CAAC;IAIjF;;;;OAIG;IACG,gBAAgB,CAAC,MAAM,EAAE,eAAe,GAAG,OAAO,CAAC,eAAe,CAAC;IAMzE;;;;;;OAMG;IACG,iBAAiB,CACrB,MAAM,EAAE,MAAM,EACd,OAAO,CAAC,EAAE,MAAM,EAChB,YAAY,CAAC,EAAE,gBAAgB,GAC9B,OAAO,CAAC;QAAE,WAAW,EAAE,MAAM,CAAA;KAAE,CAAC;IAUnC;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;OA8BG;IACG,KAAK,CACT,KAAK,EAAE,MAAM,GAAG,GAAG,EACnB,IAAI,EAAE,WAAW,GAAG,SAAS,EAC7B,OAAO,EAAE,eAAe,GACvB,OAAO,CAAC,cAAc,CAAC;IAiB1B,OAAO,CAAC,UAAU;IAUlB;;;;;;;;;;;;;;;;;;;OAmBG;YACW,IAAI;CA4FnB"}
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"}
@@ -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 what keeps the two
142
- * protocols isolated even though the tokens are byte-identical on the wire.
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
  }