@nevermined-io/payments 1.1.3 → 1.1.5

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 (43) hide show
  1. package/dist/a2a/paymentsRequestHandler.d.ts.map +1 -1
  2. package/dist/a2a/paymentsRequestHandler.js +2 -0
  3. package/dist/a2a/paymentsRequestHandler.js.map +1 -1
  4. package/dist/a2a/server.d.ts.map +1 -1
  5. package/dist/a2a/server.js +1 -0
  6. package/dist/a2a/server.js.map +1 -1
  7. package/dist/api/base-payments.d.ts +5 -0
  8. package/dist/api/base-payments.d.ts.map +1 -1
  9. package/dist/api/base-payments.js +7 -0
  10. package/dist/api/base-payments.js.map +1 -1
  11. package/dist/common/types.d.ts +11 -1
  12. package/dist/common/types.d.ts.map +1 -1
  13. package/dist/common/types.js +25 -1
  14. package/dist/common/types.js.map +1 -1
  15. package/dist/mcp/core/auth.d.ts.map +1 -1
  16. package/dist/mcp/core/auth.js +1 -0
  17. package/dist/mcp/core/auth.js.map +1 -1
  18. package/dist/mcp/core/paywall.d.ts.map +1 -1
  19. package/dist/mcp/core/paywall.js +2 -0
  20. package/dist/mcp/core/paywall.js.map +1 -1
  21. package/dist/x402/express/middleware.d.ts.map +1 -1
  22. package/dist/x402/express/middleware.js +1 -0
  23. package/dist/x402/express/middleware.js.map +1 -1
  24. package/dist/x402/facilitator-api.d.ts +2 -0
  25. package/dist/x402/facilitator-api.d.ts.map +1 -1
  26. package/dist/x402/facilitator-api.js +3 -3
  27. package/dist/x402/facilitator-api.js.map +1 -1
  28. package/dist/x402/index.d.ts +1 -1
  29. package/dist/x402/index.d.ts.map +1 -1
  30. package/dist/x402/index.js +1 -1
  31. package/dist/x402/index.js.map +1 -1
  32. package/dist/x402/langchain/decorator.d.ts +146 -0
  33. package/dist/x402/langchain/decorator.d.ts.map +1 -0
  34. package/dist/x402/langchain/decorator.js +190 -0
  35. package/dist/x402/langchain/decorator.js.map +1 -0
  36. package/dist/x402/langchain/index.d.ts +5 -0
  37. package/dist/x402/langchain/index.d.ts.map +1 -0
  38. package/dist/x402/langchain/index.js +5 -0
  39. package/dist/x402/langchain/index.js.map +1 -0
  40. package/dist/x402/token.d.ts.map +1 -1
  41. package/dist/x402/token.js +2 -2
  42. package/dist/x402/token.js.map +1 -1
  43. package/package.json +10 -2
@@ -1 +1 @@
1
- {"version":3,"file":"types.js","sourceRoot":"","sources":["../../src/common/types.ts"],"names":[],"mappings":"AA0IA;;;;;;GAMG;AACH,MAAM,CAAN,IAAY,aAIX;AAJD,WAAY,aAAa;IACvB,+DAAW,CAAA;IACX,yEAAgB,CAAA;IAChB,iFAAoB,CAAA;AACtB,CAAC,EAJW,aAAa,KAAb,aAAa,QAIxB;AAED;;;;;;GAMG;AACH,MAAM,CAAN,IAAY,eAIX;AAJD,WAAY,eAAe;IACzB,+DAAS,CAAA;IACT,uDAAK,CAAA;IACL,2DAAO,CAAA;AACT,CAAC,EAJW,eAAe,KAAf,eAAe,QAI1B;AAED;;;;;;;GAOG;AACH,MAAM,CAAN,IAAY,kBAKX;AALD,WAAY,kBAAkB;IAC5B,mFAAoB,CAAA;IACpB,uEAAc,CAAA;IACd,+EAAkB,CAAA;IAClB,iFAAmB,CAAA;AACrB,CAAC,EALW,kBAAkB,KAAlB,kBAAkB,QAK7B;AAoKD;;GAEG;AACH,MAAM,OAAO,iBAAiB;IAsB5B;;;OAGG;IACH,YAAY,OAAoC;QApBhD;;;WAGG;QACH,cAAS,GAAmB,MAAM,CAAA;QAClC;;;WAGG;QACH,SAAI,GAAG,CAAC,CAAA;QACR;;;WAGG;QACH,WAAM,GAAG,EAAE,CAAA;QAOT,IAAI,OAAO,EAAE,CAAC;YACZ,IAAI,CAAC,MAAM,GAAG,OAAO,CAAC,MAAM,CAAA;YAC5B,IAAI,CAAC,SAAS,GAAG,OAAO,CAAC,SAAS,IAAI,MAAM,CAAA;YAC5C,IAAI,CAAC,IAAI,GAAG,OAAO,CAAC,IAAI,IAAI,CAAC,CAAA;YAC7B,IAAI,CAAC,MAAM,GAAG,OAAO,CAAC,MAAM,IAAI,EAAE,CAAA;QACpC,CAAC;IACH,CAAC;IAED;;;;OAIG;IACH,aAAa;QACX,MAAM,MAAM,GAA2B,EAAE,CAAA;QACzC,IAAI,IAAI,CAAC,MAAM,EAAE,CAAC;YAChB,MAAM,CAAC,MAAM,GAAG,IAAI,CAAC,MAAM,CAAA;QAC7B,CAAC;QACD,MAAM,CAAC,SAAS,GAAG,IAAI,CAAC,SAAS,CAAA;QACjC,MAAM,CAAC,IAAI,GAAG,IAAI,CAAC,IAAI,CAAC,QAAQ,EAAE,CAAA;QAClC,MAAM,CAAC,QAAQ,GAAG,IAAI,CAAC,MAAM,CAAC,QAAQ,EAAE,CAAA;QAExC,OAAO,IAAI,eAAe,CAAC,MAAM,CAAC,CAAC,QAAQ,EAAE,CAAA;IAC/C,CAAC;CACF;AAED;;GAEG;AACH,MAAM,CAAN,IAAY,eAIX;AAJD,WAAY,eAAe;IACzB,sCAAmB,CAAA;IACnB,oCAAiB,CAAA;IACjB,sCAAmB,CAAA;AACrB,CAAC,EAJW,eAAe,KAAf,eAAe,QAI1B;AA+CD;;GAEG;AACH,MAAM,CAAC,MAAM,oBAAoB,GAAmC;IAClE,aAAa,EAAE,cAAc;IAC7B,qBAAqB,EAAE,QAAQ;CAChC,CAAA;AAED;;GAEG;AACH,MAAM,UAAU,aAAa,CAAC,CAAU;IACtC,OAAO,CAAC,KAAK,aAAa,IAAI,CAAC,KAAK,qBAAqB,CAAA;AAC3D,CAAC","sourcesContent":["import { EnvironmentName } from '../environments.js'\n\n/**\n * The payment scheme to use.\n * - 'nvm' (default): Nevermined credit-based payments via ERC-4337 smart accounts.\n * - 'visa': Visa Token Service fiat payments via x402 HTTP transport.\n */\nexport type PaymentScheme = 'nvm' | 'visa'\n\nexport interface PaymentOptions {\n /**\n * The Nevermined environment to connect to.\n * If you are developing an agent it's recommended to use the \"sandbox\" environment.\n * When deploying to live use the \"live\" environment.\n */\n environment: EnvironmentName\n\n /**\n * The Nevermined API Key. This key identify your user and is required to interact with the Nevermined API.\n * You can get your API key by logging in to the Nevermined App.\n * Required for 'nvm' scheme. Optional for 'visa' scheme.\n * @see https://nevermined.ai/docs/tutorials/integration/nvm-api-keys\n */\n nvmApiKey: string\n\n /**\n * The payment scheme to use. Defaults to 'nvm'.\n * - 'nvm': Nevermined credit-based payments\n * - 'visa': Visa Token Service fiat payments\n */\n scheme?: PaymentScheme\n\n /**\n * The URL to return to the app after a successful login.\n */\n returnUrl?: string\n\n /**\n * The app id. This attribute is optional and helps to associate assets registered into Nevermined with a common identifier.\n */\n appId?: string\n\n /**\n * The version of the API to use.\n */\n version?: string\n}\n\nexport interface Endpoint {\n [verb: string]: string\n}\n\nexport interface ApiResponse<T> {\n success: boolean\n data?: T\n error?: string\n}\n\nexport type Address = `0x${string}`\n\n/**\n * Definition of the price configuration for a Payment Plan\n */\nexport interface PlanPriceConfig {\n /**\n * The address of the token (ERC20 or Native if zero address) for paying the plan\n */\n tokenAddress?: Address\n /**\n * The amounts to be paid for the plan\n */\n amounts: bigint[]\n /**\n * The receivers of the payments of the plan\n */\n receivers: string[]\n /**\n * The address of the smart contract that calculates the price\n */\n contractAddress?: Address\n /**\n * The address of the fee controller contract, if any\n * @remarks if not given, the fee controller is the default one\n */\n feeController?: Address\n /**\n * The address of the external price contract, if any\n */\n externalPriceAddress?: Address\n /**\n * The address of the template contract, if any\n */\n templateAddress?: Address\n /**\n * Whether this is a crypto payment (true) or fiat payment (false)\n */\n isCrypto: boolean\n}\n\n/**\n * Definition of the credits configuration for a payment plan\n */\nexport interface PlanCreditsConfig {\n /**\n * Whether the redemption amount is fixed (true) or dynamic (false)\n */\n isRedemptionAmountFixed: boolean\n /**\n * How the credits can be redeemed\n */\n redemptionType: PlanRedemptionType\n /**\n * Whether the credits burn proof signed by the user is required\n */\n proofRequired: boolean\n /**\n * The duration of the credits in seconds\n * @remarks 0 means non-expirable\n */\n durationSecs: bigint\n /**\n * The amount of credits that are granted when purchasing the plan (as string for API)\n */\n amount: bigint\n /**\n * The minimum number of credits redeemed when using the plan\n */\n minAmount: bigint\n /**\n * The maximum number of credits redeemed when using the plan\n */\n maxAmount: bigint\n /**\n * The address of the NFT contract that represents the plan's credits\n */\n nftAddress?: Address\n}\n\n/**\n * Different types of prices that can be configured for a plan\n * @remarks 0 - FIXED_PRICE, 1 - FIXED_FIAT_PRICE, 2 - SMART_CONTRACT_PRICE\n * If FIXED_PRICE it means the plan can be paid in crypto by a fixed amount of a ERC20 or Native token\n * If FIXED_FIAT_PRICE it means the plan can be paid in fiat by a fixed amount (typically USD)\n * If SMART_CONTRACT_PRICE it means the plan can be paid in crypto and the amount to be paid is calculated by a smart contract\n */\nexport enum PlanPriceType {\n FIXED_PRICE,\n FIXED_FIAT_PRICE,\n SMART_CONTRACT_PRICE,\n}\n\n/**\n * Different types of credits that can be obtained when purchasing a plan\n * @remarks 0 - EXPIRABLE, 1 - FIXED, 2 - DYNAMIC\n * If EXPIRABLE it means the credits can be used for a fixed amount of time (calculated in seconds)\n * If FIXED it means the credits can be used for a fixed amount of times\n * If DYNAMIC it means the credits can be used but the redemption amount is dynamic\n */\nexport enum PlanCreditsType {\n EXPIRABLE,\n FIXED,\n DYNAMIC,\n}\n\n/**\n * Different types of redemptions criterias that can be used when redeeming credits\n * @remarks 0 - ONLY_GLOBAL_ROLE, 1 - ONLY_OWNER, 2 - ROLE_AND_OWNER\n * If ONLY_GLOBAL_ROLE it means the credits can be redeemed only by an account with the `CREDITS_BURNER_ROLE`\n * If ONLY_OWNER it means the credits can be redeemed only by the owner of the Plan\n * If ONLY_PLAN_ROLE it means the credits can be redeemed by an account with specifics grants for the plan\n * If ONLY_SUBSCRIBER means only the subscriber (the one who holds the credits NFT) can redeem\n */\nexport enum PlanRedemptionType {\n ONLY_GLOBAL_ROLE = 0, // NVM Proxy can burn\n ONLY_OWNER = 1, // Agent can burn\n ONLY_PLAN_ROLE = 2,\n ONLY_SUBSCRIBER = 4, // Subscriber who ordered the plan can redeem\n}\n\nexport interface PlanBalance {\n planId: string\n planName: string\n planType: string\n holderAddress: Address\n balance: bigint\n creditsContract: Address\n isSubscriber: boolean\n pricePerCredit: number\n}\n\nexport interface StartAgentRequest {\n agentRequestId: string\n agentName: string\n agentId: string\n balance: PlanBalance\n urlMatching: string\n verbMatching: string\n batch: boolean\n}\n\nexport interface ValidationAgentRequest {\n balance: PlanBalance\n urlMatching: string\n verbMatching: string\n}\n\nexport interface AgentAccessCredentials {\n accessToken: string\n proxies?: string[]\n}\n\nexport interface SubscriberRequestStatus {\n planId: string\n agentId: string\n isValid: boolean\n code: number\n message?: string\n}\n\nexport interface NvmAPIResult {\n success: boolean\n message?: string\n txHash?: string\n httpStatus?: number\n data?: APIOutputData\n when?: Date\n}\n\nexport interface APIOutputData {\n [key: string]: any\n}\n\nexport interface StripeCheckoutResult {\n stripeCheckoutSessionId: string\n checkoutLink: string\n clientReferenceId: string\n paymentStatus?: string\n linkCreatedAt: number\n linkExpiresAt: number\n}\n\n/**\n * Metadata attributes describing the AI Agent.\n */\nexport interface AgentMetadata {\n /**\n * Name of the Agent\n */\n name: string\n /**\n * Description of the Agent\n */\n description?: string\n /**\n * The author of the Agent (organization or person) that own the Agent.\n */\n author?: string\n /**\n * The author of the Agent (organization or person) that own the Agent.\n */\n license?: string\n /**\n * Tags describing the AI Agent\n */\n tags?: string[]\n /**\n * Some description or instructions about how to integrate the Agent.\n */\n integration?: string\n /**\n * A link to some same usage of the Agent.\n */\n sampleLink?: string\n /**\n * Text describing the API of the Agent.\n */\n apiDescription?: string\n /**\n * The date when the Agent was created.\n */\n dateCreated?: Date\n\n // internalAttributes?: any\n}\n\n/**\n * Metadata attributes describing the Payment Plan.\n */\nexport interface PlanMetadata extends AgentMetadata {\n /**\n * Indicates if a payment plan is a Trial plan.\n * A Trial plan is a plan that allows users to test the AI Agents associated with it typically without any cost.\n * @remarks A Trial plan only can be purchased once by a user.\n */\n isTrialPlan?: boolean\n /**\n * Indicates if a payment plan is limited by credits.\n * If 'time', the plan will be limited by time.\n * If 'credits', the plan will be limited by credits.\n */\n accessLimit?: 'credits' | 'time'\n}\n\n/**\n * It describes the API exposed by an AI Agent.\n * This information is necessary to query the AI Agent and to know which endpoints are available.\n */\nexport interface AgentAPIAttributes {\n /**\n * The list endpoints of the upstream service. All these endpoints are protected and only accessible to subscribers of the Payment Plan.\n */\n endpoints: Endpoint[]\n /**\n * The list of endpoints of the upstream service that publicly available. The access to these endpoints don't require subscription to the Payment Plan. They are useful to expose documentation, etc.\n */\n openEndpoints?: string[]\n /**\n * The URL to the agent definition. Can be an OpenAPI spec, MCP Manifest, or A2A agent card. This field is mandatory and defines how the agent/service can be discovered and queried.\n */\n agentDefinitionUrl: string\n\n /////// AUTHORIZATION ///////\n\n /**\n * The upstream agent/service authentication type ('none', 'basic', 'bearer' or 'oauth').\n */\n authType?: 'none' | 'basic' | 'oauth' | 'bearer'\n /**\n * The upstream agent/service username for authentication. Only if `authType` is 'basic'.\n */\n username?: string\n /**\n * The upstream agent/service password for authentication. Only if `authType` is 'basic'.\n */\n password?: string\n /**\n * The upstream agent/service bearer token for authentication. Only if `authType` is 'bearer' or 'oauth'.\n */\n token?: string\n}\n\n/**\n * Options for pagination in API requests to the Nevermined API.\n */\nexport class PaginationOptions {\n /**\n * The field to sort the results by.\n * If not provided, the default sorting defined by the API will be applied.\n */\n sortBy?: string\n /**\n * The order in which to sort the results.\n * Default is 'desc' (descending).\n */\n sortOrder: 'asc' | 'desc' = 'desc'\n /**\n * The page number to retrieve.\n * Default is 1.\n */\n page = 1\n /**\n * The number of items per page.\n * Default is 10.\n */\n offset = 10\n\n /**\n * Constructs a new PaginationOptions instance.\n * @param options - Optional initial values for the pagination options.\n */\n constructor(options?: Partial<PaginationOptions>) {\n if (options) {\n this.sortBy = options.sortBy\n this.sortOrder = options.sortOrder || 'desc'\n this.page = options.page || 1\n this.offset = options.offset || 10\n }\n }\n\n /**\n * It returns a string representation of the pagination options\n * @returns A string representation of the pagination options as URL query parameters.\n * This can be used to append to API requests for pagination.\n */\n asQueryParams(): string {\n const params: Record<string, string> = {}\n if (this.sortBy) {\n params.sortBy = this.sortBy\n }\n params.sortOrder = this.sortOrder\n params.page = this.page.toString()\n params.pageSize = this.offset.toString()\n\n return new URLSearchParams(params).toString()\n }\n}\n\n/**\n * Status of an agent task\n */\nexport enum AgentTaskStatus {\n SUCCESS = 'SUCCESS',\n FAILED = 'FAILED',\n PENDING = 'PENDING',\n}\n\n/**\n * Data transfer object for tracking agent sub tasks\n */\nexport interface TrackAgentSubTaskDto {\n /**\n * The unique identifier of the agent task\n */\n agentRequestId: string\n\n /**\n * The number of credits burned in this agent sub task (optional)\n * @defaultValue 0\n */\n creditsToRedeem?: number\n\n /**\n * A tag to categorize this agent sub task (optional)\n */\n tag?: string\n\n /**\n * A description of this agent sub task (optional)\n */\n description?: string\n\n /**\n * The status of the agent sub task (optional)\n */\n status?: AgentTaskStatus\n}\n\nexport type SimulationRequestOptions = {\n agentName?: string\n planName?: string\n batch?: boolean\n pricePerCredit?: number\n}\n\n/**\n * x402 payment scheme type.\n * - 'nvm:erc4337': Crypto payments via ERC-4337 smart accounts\n * - 'nvm:card-delegation': Fiat/Stripe card delegation payments\n */\nexport type X402SchemeType = 'nvm:erc4337' | 'nvm:card-delegation'\n\n/**\n * Default network for each x402 scheme.\n */\nexport const X402_SCHEME_NETWORKS: Record<X402SchemeType, string> = {\n 'nvm:erc4337': 'eip155:84532',\n 'nvm:card-delegation': 'stripe',\n}\n\n/**\n * Type guard to check if a value is a valid x402 scheme type.\n */\nexport function isValidScheme(s: unknown): s is X402SchemeType {\n return s === 'nvm:erc4337' || s === 'nvm:card-delegation'\n}\n\n/**\n * Configuration for card delegation (fiat/Stripe) payments.\n */\nexport interface CardDelegationConfig {\n /** Stripe payment method ID (e.g., 'pm_...') */\n providerPaymentMethodId: string\n /** Maximum spending limit in cents */\n spendingLimitCents: number\n /** Duration of the delegation in seconds */\n durationSecs: number\n /** Currency code (default: 'usd') */\n currency?: string\n /** Stripe Connect merchant account ID */\n merchantAccountId?: string\n /** Maximum number of transactions allowed */\n maxTransactions?: number\n}\n\n/**\n * Options for x402 token generation that control scheme and delegation behavior.\n */\nexport interface X402TokenOptions {\n /** The x402 scheme to use (defaults to 'nvm:erc4337') */\n scheme?: X402SchemeType\n /** Network identifier (auto-derived from scheme if omitted) */\n network?: string\n /** Card delegation configuration (only for 'nvm:card-delegation' scheme) */\n delegationConfig?: CardDelegationConfig\n}\n"]}
1
+ {"version":3,"file":"types.js","sourceRoot":"","sources":["../../src/common/types.ts"],"names":[],"mappings":"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","sourcesContent":["import { EnvironmentName } from '../environments.js'\n\n/**\n * The payment scheme to use.\n * - 'nvm' (default): Nevermined credit-based payments via ERC-4337 smart accounts.\n * - 'visa': Visa Token Service fiat payments via x402 HTTP transport.\n */\nexport type PaymentScheme = 'nvm' | 'visa'\n\nexport interface PaymentOptions {\n /**\n * The Nevermined environment to connect to.\n * If you are developing an agent it's recommended to use the \"sandbox\" environment.\n * When deploying to live use the \"live\" environment.\n */\n environment: EnvironmentName\n\n /**\n * The Nevermined API Key. This key identify your user and is required to interact with the Nevermined API.\n * You can get your API key by logging in to the Nevermined App.\n * Required for 'nvm' scheme. Optional for 'visa' scheme.\n * @see https://nevermined.ai/docs/tutorials/integration/nvm-api-keys\n */\n nvmApiKey: string\n\n /**\n * The payment scheme to use. Defaults to 'nvm'.\n * - 'nvm': Nevermined credit-based payments\n * - 'visa': Visa Token Service fiat payments\n */\n scheme?: PaymentScheme\n\n /**\n * The URL to return to the app after a successful login.\n */\n returnUrl?: string\n\n /**\n * The app id. This attribute is optional and helps to associate assets registered into Nevermined with a common identifier.\n */\n appId?: string\n\n /**\n * The version of the API to use.\n */\n version?: string\n}\n\nexport interface Endpoint {\n [verb: string]: string\n}\n\nexport interface ApiResponse<T> {\n success: boolean\n data?: T\n error?: string\n}\n\nexport type Address = `0x${string}`\n\n/**\n * Definition of the price configuration for a Payment Plan\n */\nexport interface PlanPriceConfig {\n /**\n * The address of the token (ERC20 or Native if zero address) for paying the plan\n */\n tokenAddress?: Address\n /**\n * The amounts to be paid for the plan\n */\n amounts: bigint[]\n /**\n * The receivers of the payments of the plan\n */\n receivers: string[]\n /**\n * The address of the smart contract that calculates the price\n */\n contractAddress?: Address\n /**\n * The address of the fee controller contract, if any\n * @remarks if not given, the fee controller is the default one\n */\n feeController?: Address\n /**\n * The address of the external price contract, if any\n */\n externalPriceAddress?: Address\n /**\n * The address of the template contract, if any\n */\n templateAddress?: Address\n /**\n * Whether this is a crypto payment (true) or fiat payment (false)\n */\n isCrypto: boolean\n}\n\n/**\n * Definition of the credits configuration for a payment plan\n */\nexport interface PlanCreditsConfig {\n /**\n * Whether the redemption amount is fixed (true) or dynamic (false)\n */\n isRedemptionAmountFixed: boolean\n /**\n * How the credits can be redeemed\n */\n redemptionType: PlanRedemptionType\n /**\n * Whether the credits burn proof signed by the user is required\n */\n proofRequired: boolean\n /**\n * The duration of the credits in seconds\n * @remarks 0 means non-expirable\n */\n durationSecs: bigint\n /**\n * The amount of credits that are granted when purchasing the plan (as string for API)\n */\n amount: bigint\n /**\n * The minimum number of credits redeemed when using the plan\n */\n minAmount: bigint\n /**\n * The maximum number of credits redeemed when using the plan\n */\n maxAmount: bigint\n /**\n * The address of the NFT contract that represents the plan's credits\n */\n nftAddress?: Address\n}\n\n/**\n * Different types of prices that can be configured for a plan\n * @remarks 0 - FIXED_PRICE, 1 - FIXED_FIAT_PRICE, 2 - SMART_CONTRACT_PRICE\n * If FIXED_PRICE it means the plan can be paid in crypto by a fixed amount of a ERC20 or Native token\n * If FIXED_FIAT_PRICE it means the plan can be paid in fiat by a fixed amount (typically USD)\n * If SMART_CONTRACT_PRICE it means the plan can be paid in crypto and the amount to be paid is calculated by a smart contract\n */\nexport enum PlanPriceType {\n FIXED_PRICE,\n FIXED_FIAT_PRICE,\n SMART_CONTRACT_PRICE,\n}\n\n/**\n * Different types of credits that can be obtained when purchasing a plan\n * @remarks 0 - EXPIRABLE, 1 - FIXED, 2 - DYNAMIC\n * If EXPIRABLE it means the credits can be used for a fixed amount of time (calculated in seconds)\n * If FIXED it means the credits can be used for a fixed amount of times\n * If DYNAMIC it means the credits can be used but the redemption amount is dynamic\n */\nexport enum PlanCreditsType {\n EXPIRABLE,\n FIXED,\n DYNAMIC,\n}\n\n/**\n * Different types of redemptions criterias that can be used when redeeming credits\n * @remarks 0 - ONLY_GLOBAL_ROLE, 1 - ONLY_OWNER, 2 - ROLE_AND_OWNER\n * If ONLY_GLOBAL_ROLE it means the credits can be redeemed only by an account with the `CREDITS_BURNER_ROLE`\n * If ONLY_OWNER it means the credits can be redeemed only by the owner of the Plan\n * If ONLY_PLAN_ROLE it means the credits can be redeemed by an account with specifics grants for the plan\n * If ONLY_SUBSCRIBER means only the subscriber (the one who holds the credits NFT) can redeem\n */\nexport enum PlanRedemptionType {\n ONLY_GLOBAL_ROLE = 0, // NVM Proxy can burn\n ONLY_OWNER = 1, // Agent can burn\n ONLY_PLAN_ROLE = 2,\n ONLY_SUBSCRIBER = 4, // Subscriber who ordered the plan can redeem\n}\n\nexport interface PlanBalance {\n planId: string\n planName: string\n planType: string\n holderAddress: Address\n balance: bigint\n creditsContract: Address\n isSubscriber: boolean\n pricePerCredit: number\n}\n\nexport interface StartAgentRequest {\n agentRequestId: string\n agentName: string\n agentId: string\n balance: PlanBalance\n urlMatching: string\n verbMatching: string\n batch: boolean\n}\n\nexport interface ValidationAgentRequest {\n balance: PlanBalance\n urlMatching: string\n verbMatching: string\n}\n\nexport interface AgentAccessCredentials {\n accessToken: string\n proxies?: string[]\n}\n\nexport interface SubscriberRequestStatus {\n planId: string\n agentId: string\n isValid: boolean\n code: number\n message?: string\n}\n\nexport interface NvmAPIResult {\n success: boolean\n message?: string\n txHash?: string\n httpStatus?: number\n data?: APIOutputData\n when?: Date\n}\n\nexport interface APIOutputData {\n [key: string]: any\n}\n\nexport interface StripeCheckoutResult {\n stripeCheckoutSessionId: string\n checkoutLink: string\n clientReferenceId: string\n paymentStatus?: string\n linkCreatedAt: number\n linkExpiresAt: number\n}\n\n/**\n * Metadata attributes describing the AI Agent.\n */\nexport interface AgentMetadata {\n /**\n * Name of the Agent\n */\n name: string\n /**\n * Description of the Agent\n */\n description?: string\n /**\n * The author of the Agent (organization or person) that own the Agent.\n */\n author?: string\n /**\n * The author of the Agent (organization or person) that own the Agent.\n */\n license?: string\n /**\n * Tags describing the AI Agent\n */\n tags?: string[]\n /**\n * Some description or instructions about how to integrate the Agent.\n */\n integration?: string\n /**\n * A link to some same usage of the Agent.\n */\n sampleLink?: string\n /**\n * Text describing the API of the Agent.\n */\n apiDescription?: string\n /**\n * The date when the Agent was created.\n */\n dateCreated?: Date\n\n // internalAttributes?: any\n}\n\n/**\n * Metadata attributes describing the Payment Plan.\n */\nexport interface PlanMetadata extends AgentMetadata {\n /**\n * Indicates if a payment plan is a Trial plan.\n * A Trial plan is a plan that allows users to test the AI Agents associated with it typically without any cost.\n * @remarks A Trial plan only can be purchased once by a user.\n */\n isTrialPlan?: boolean\n /**\n * Indicates if a payment plan is limited by credits.\n * If 'time', the plan will be limited by time.\n * If 'credits', the plan will be limited by credits.\n */\n accessLimit?: 'credits' | 'time'\n}\n\n/**\n * It describes the API exposed by an AI Agent.\n * This information is necessary to query the AI Agent and to know which endpoints are available.\n */\nexport interface AgentAPIAttributes {\n /**\n * The list endpoints of the upstream service. All these endpoints are protected and only accessible to subscribers of the Payment Plan.\n */\n endpoints: Endpoint[]\n /**\n * The list of endpoints of the upstream service that publicly available. The access to these endpoints don't require subscription to the Payment Plan. They are useful to expose documentation, etc.\n */\n openEndpoints?: string[]\n /**\n * The URL to the agent definition. Can be an OpenAPI spec, MCP Manifest, or A2A agent card. This field is mandatory and defines how the agent/service can be discovered and queried.\n */\n agentDefinitionUrl: string\n\n /////// AUTHORIZATION ///////\n\n /**\n * The upstream agent/service authentication type ('none', 'basic', 'bearer' or 'oauth').\n */\n authType?: 'none' | 'basic' | 'oauth' | 'bearer'\n /**\n * The upstream agent/service username for authentication. Only if `authType` is 'basic'.\n */\n username?: string\n /**\n * The upstream agent/service password for authentication. Only if `authType` is 'basic'.\n */\n password?: string\n /**\n * The upstream agent/service bearer token for authentication. Only if `authType` is 'bearer' or 'oauth'.\n */\n token?: string\n}\n\n/**\n * Options for pagination in API requests to the Nevermined API.\n */\nexport class PaginationOptions {\n /**\n * The field to sort the results by.\n * If not provided, the default sorting defined by the API will be applied.\n */\n sortBy?: string\n /**\n * The order in which to sort the results.\n * Default is 'desc' (descending).\n */\n sortOrder: 'asc' | 'desc' = 'desc'\n /**\n * The page number to retrieve.\n * Default is 1.\n */\n page = 1\n /**\n * The number of items per page.\n * Default is 10.\n */\n offset = 10\n\n /**\n * Constructs a new PaginationOptions instance.\n * @param options - Optional initial values for the pagination options.\n */\n constructor(options?: Partial<PaginationOptions>) {\n if (options) {\n this.sortBy = options.sortBy\n this.sortOrder = options.sortOrder || 'desc'\n this.page = options.page || 1\n this.offset = options.offset || 10\n }\n }\n\n /**\n * It returns a string representation of the pagination options\n * @returns A string representation of the pagination options as URL query parameters.\n * This can be used to append to API requests for pagination.\n */\n asQueryParams(): string {\n const params: Record<string, string> = {}\n if (this.sortBy) {\n params.sortBy = this.sortBy\n }\n params.sortOrder = this.sortOrder\n params.page = this.page.toString()\n params.pageSize = this.offset.toString()\n\n return new URLSearchParams(params).toString()\n }\n}\n\n/**\n * Status of an agent task\n */\nexport enum AgentTaskStatus {\n SUCCESS = 'SUCCESS',\n FAILED = 'FAILED',\n PENDING = 'PENDING',\n}\n\n/**\n * Data transfer object for tracking agent sub tasks\n */\nexport interface TrackAgentSubTaskDto {\n /**\n * The unique identifier of the agent task\n */\n agentRequestId: string\n\n /**\n * The number of credits burned in this agent sub task (optional)\n * @defaultValue 0\n */\n creditsToRedeem?: number\n\n /**\n * A tag to categorize this agent sub task (optional)\n */\n tag?: string\n\n /**\n * A description of this agent sub task (optional)\n */\n description?: string\n\n /**\n * The status of the agent sub task (optional)\n */\n status?: AgentTaskStatus\n}\n\nexport type SimulationRequestOptions = {\n agentName?: string\n planName?: string\n batch?: boolean\n pricePerCredit?: number\n}\n\n/**\n * x402 payment scheme type.\n * - 'nvm:erc4337': Crypto payments via ERC-4337 smart accounts\n * - 'nvm:card-delegation': Fiat/Stripe card delegation payments\n */\nexport type X402SchemeType = 'nvm:erc4337' | 'nvm:card-delegation'\n\n/**\n * Default network for each x402 scheme (backward-compat: defaults to Base Sepolia).\n */\nexport const X402_SCHEME_NETWORKS: Record<X402SchemeType, string> = {\n 'nvm:erc4337': 'eip155:84532',\n 'nvm:card-delegation': 'stripe',\n}\n\n/**\n * Environment-specific network for the erc4337 scheme.\n */\nconst ERC4337_NETWORK_BY_ENV: Record<string, string> = {\n sandbox: 'eip155:84532', // Base Sepolia\n staging_sandbox: 'eip155:84532', // Base Sepolia\n live: 'eip155:8453', // Base Mainnet\n staging_live: 'eip155:8453', // Base Mainnet\n}\n\n/**\n * Return the default network for a scheme, accounting for the environment.\n *\n * For `nvm:erc4337`, the network depends on the environment:\n * - sandbox / staging_sandbox → `eip155:84532` (Base Sepolia)\n * - live / staging_live → `eip155:8453` (Base Mainnet)\n *\n * Falls back to `X402_SCHEME_NETWORKS` when no environment is given.\n */\nexport function getDefaultNetwork(scheme: X402SchemeType, environment?: EnvironmentName): string {\n if (scheme === 'nvm:erc4337' && environment) {\n return ERC4337_NETWORK_BY_ENV[environment] ?? 'eip155:84532'\n }\n return X402_SCHEME_NETWORKS[scheme]\n}\n\n/**\n * Type guard to check if a value is a valid x402 scheme type.\n */\nexport function isValidScheme(s: unknown): s is X402SchemeType {\n return s === 'nvm:erc4337' || s === 'nvm:card-delegation'\n}\n\n/**\n * Configuration for card delegation (fiat/Stripe) payments.\n */\nexport interface CardDelegationConfig {\n /** Stripe payment method ID (e.g., 'pm_...') */\n providerPaymentMethodId: string\n /** Maximum spending limit in cents */\n spendingLimitCents: number\n /** Duration of the delegation in seconds */\n durationSecs: number\n /** Currency code (default: 'usd') */\n currency?: string\n /** Stripe Connect merchant account ID */\n merchantAccountId?: string\n /** Maximum number of transactions allowed */\n maxTransactions?: number\n}\n\n/**\n * Options for x402 token generation that control scheme and delegation behavior.\n */\nexport interface X402TokenOptions {\n /** The x402 scheme to use (defaults to 'nvm:erc4337') */\n scheme?: X402SchemeType\n /** Network identifier (auto-derived from scheme if omitted) */\n network?: string\n /** Card delegation configuration (only for 'nvm:card-delegation' scheme) */\n delegationConfig?: CardDelegationConfig\n}\n"]}
@@ -1 +1 @@
1
- {"version":3,"file":"auth.d.ts","sourceRoot":"","sources":["../../../src/mcp/core/auth.ts"],"names":[],"mappings":"AAAA;;GAEG;AACH,OAAO,KAAK,EAAE,QAAQ,EAAE,MAAM,mBAAmB,CAAA;AAGjD,OAAO,EAAE,UAAU,EAAE,MAAM,2BAA2B,CAAA;AAgBtD;;GAEG;AACH,qBAAa,oBAAoB;IACnB,OAAO,CAAC,QAAQ;gBAAR,QAAQ,EAAE,QAAQ;IAEtC;;;;;;OAMG;IACH,OAAO,CAAC,4BAA4B;IAepC;;;;OAIG;IACH,OAAO,CAAC,uBAAuB;IAuB/B;;;OAGG;YACW,kBAAkB;IAoEhC;;;OAGG;YACW,kBAAkB;IAsDhC;;OAEG;IACG,YAAY,CAChB,KAAK,EAAE,GAAG,EACV,OAAO,EAAE;QAAE,MAAM,CAAC,EAAE,MAAM,CAAC;QAAC,SAAS,CAAC,EAAE,MAAM,CAAA;KAAE,YAAK,EACrD,OAAO,EAAE,MAAM,EACf,UAAU,EAAE,MAAM,EAClB,IAAI,EAAE,MAAM,EACZ,IAAI,EAAE,MAAM,GAAG,UAAU,GAAG,QAAQ,EACpC,UAAU,EAAE,GAAG,GACd,OAAO,CAAC,UAAU,CAAC;IAkBtB;;;OAGG;IACG,gBAAgB,CACpB,KAAK,EAAE,GAAG,EACV,OAAO,EAAE;QAAE,MAAM,CAAC,EAAE,MAAM,CAAC;QAAC,SAAS,CAAC,EAAE,MAAM,CAAA;KAAE,YAAK,EACrD,OAAO,EAAE,MAAM,EACf,UAAU,EAAE,MAAM,EAClB,MAAM,EAAE,MAAM,GACb,OAAO,CAAC,UAAU,CAAC;CAiBvB"}
1
+ {"version":3,"file":"auth.d.ts","sourceRoot":"","sources":["../../../src/mcp/core/auth.ts"],"names":[],"mappings":"AAAA;;GAEG;AACH,OAAO,KAAK,EAAE,QAAQ,EAAE,MAAM,mBAAmB,CAAA;AAGjD,OAAO,EAAE,UAAU,EAAE,MAAM,2BAA2B,CAAA;AAgBtD;;GAEG;AACH,qBAAa,oBAAoB;IACnB,OAAO,CAAC,QAAQ;gBAAR,QAAQ,EAAE,QAAQ;IAEtC;;;;;;OAMG;IACH,OAAO,CAAC,4BAA4B;IAepC;;;;OAIG;IACH,OAAO,CAAC,uBAAuB;IAuB/B;;;OAGG;YACW,kBAAkB;IAoEhC;;;OAGG;YACW,kBAAkB;IAuDhC;;OAEG;IACG,YAAY,CAChB,KAAK,EAAE,GAAG,EACV,OAAO,EAAE;QAAE,MAAM,CAAC,EAAE,MAAM,CAAC;QAAC,SAAS,CAAC,EAAE,MAAM,CAAA;KAAE,YAAK,EACrD,OAAO,EAAE,MAAM,EACf,UAAU,EAAE,MAAM,EAClB,IAAI,EAAE,MAAM,EACZ,IAAI,EAAE,MAAM,GAAG,UAAU,GAAG,QAAQ,EACpC,UAAU,EAAE,GAAG,GACd,OAAO,CAAC,UAAU,CAAC;IAkBtB;;;OAGG;IACG,gBAAgB,CACpB,KAAK,EAAE,GAAG,EACV,OAAO,EAAE;QAAE,MAAM,CAAC,EAAE,MAAM,CAAC;QAAC,SAAS,CAAC,EAAE,MAAM,CAAA;KAAE,YAAK,EACrD,OAAO,EAAE,MAAM,EACf,UAAU,EAAE,MAAM,EAClB,MAAM,EAAE,MAAM,GACb,OAAO,CAAC,UAAU,CAAC;CAiBvB"}
@@ -146,6 +146,7 @@ export class PaywallAuthenticator {
146
146
  agentId,
147
147
  httpVerb: 'POST',
148
148
  scheme,
149
+ environment: this.payments.getEnvironmentName(),
149
150
  });
150
151
  const result = await this.payments.facilitator.verifyPermissions({
151
152
  paymentRequired,
@@ -1 +1 @@
1
- {"version":3,"file":"auth.js","sourceRoot":"","sources":["../../../src/mcp/core/auth.ts"],"names":[],"mappings":"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","sourcesContent":["/**\n * Authentication handler for MCP paywall using X402 tokens\n */\nimport type { Payments } from '../../payments.js'\nimport { decodeAccessToken } from '../../utils.js'\nimport { getCurrentRequestContext } from '../http/mcp-handler.js'\nimport { AuthResult } from '../types/paywall.types.js'\nimport { ERROR_CODES, createRpcError } from '../utils/errors.js'\nimport { Address, isValidScheme } from '../../common/types.js'\nimport { buildLogicalMetaUrl, buildLogicalUrl } from '../utils/logical-url.js'\nimport { extractAuthHeader, stripBearer } from '../utils/request.js'\nimport { buildPaymentRequired, type X402PaymentRequired } from '../../x402/facilitator-api.js'\n\ninterface VerifyContext {\n accessToken: string\n logicalUrl: string\n httpUrl: string | undefined\n maxAmount: bigint\n agentId: string\n planIdOverride?: string\n}\n\n/**\n * Handles authentication and authorization for MCP requests\n */\nexport class PaywallAuthenticator {\n constructor(private payments: Payments) {}\n\n /**\n * Extract authorization header from extra context or AsyncLocalStorage.\n * Tries SDK's extra context first, then falls back to HTTP request context.\n *\n * @param extra - MCP extra context from SDK\n * @returns Authorization header value or undefined\n */\n private extractAuthHeaderFromContext(extra: any): string | undefined {\n // Try to extract auth header from SDK's extra context first\n let authHeader = extractAuthHeader(extra)\n\n if (!authHeader) {\n const requestContext = getCurrentRequestContext()\n if (requestContext?.headers) {\n // Build an extra-like object for extractAuthHeader\n authHeader = extractAuthHeader({ requestInfo: { headers: requestContext.headers } })\n }\n }\n\n return authHeader\n }\n\n /**\n * Build HTTP endpoint URL from request context.\n *\n * @returns HTTP endpoint URL or undefined if context is not available\n */\n private buildHttpUrlFromContext(): string | undefined {\n const requestContext = getCurrentRequestContext()\n if (!requestContext) {\n return undefined\n }\n\n try {\n const host = requestContext.headers?.['host'] || requestContext.headers?.['x-forwarded-host']\n if (!host || typeof host !== 'string') {\n return undefined\n }\n\n const protocol = requestContext.headers?.['x-forwarded-proto'] || 'http'\n const baseUrl = `${protocol}://${host}`\n\n // Use requestContext.url if available (e.g., '/mcp'), otherwise default to '/mcp'\n const path = requestContext.url || '/mcp'\n return `${baseUrl}${path}`\n } catch {\n return undefined\n }\n }\n\n /**\n * Core verification logic shared by authenticate and authenticateMeta.\n * Tries logical URL first, falls back to HTTP URL if available.\n */\n private async verifyWithFallback(ctx: VerifyContext): Promise<AuthResult> {\n const { accessToken, logicalUrl, httpUrl, maxAmount, agentId, planIdOverride } = ctx\n\n // Try logical URL first\n try {\n const result = await this.verifyWithEndpoint(\n accessToken,\n logicalUrl,\n agentId,\n maxAmount,\n planIdOverride,\n )\n return {\n token: accessToken,\n agentId,\n logicalUrl,\n httpUrl,\n planId: result.planId,\n subscriberAddress: result.subscriberAddress,\n agentRequest: result.agentRequest,\n }\n } catch {\n // If logical URL fails and we have an HTTP URL, try that\n }\n\n if (httpUrl) {\n try {\n const result = await this.verifyWithEndpoint(\n accessToken,\n httpUrl,\n agentId,\n maxAmount,\n planIdOverride,\n )\n return {\n token: accessToken,\n agentId,\n logicalUrl,\n httpUrl,\n planId: result.planId,\n subscriberAddress: result.subscriberAddress,\n agentRequest: result.agentRequest,\n }\n } catch {\n // HTTP fallback also failed\n }\n }\n\n // Both attempts failed — enrich denial with suggested plans (best-effort)\n let plansMsg = ''\n try {\n const plans = await this.payments.agents.getAgentPlans(agentId)\n if (plans && Array.isArray(plans.plans) && plans.plans.length > 0) {\n const top = plans.plans.slice(0, 3)\n const summary = top\n .map((p: any) => `${p.planId || p.id || 'plan'}${p.name ? ` (${p.name})` : ''}`)\n .join(', ')\n plansMsg = summary ? ` Available plans: ${summary}...` : ''\n }\n } catch {\n // Ignore errors fetching plans - best effort only\n }\n\n throw createRpcError(ERROR_CODES.PaymentRequired, `Payment required.${plansMsg}`, {\n reason: 'invalid',\n })\n }\n\n /**\n * Verify permissions against a single endpoint URL.\n * Resolves planId from the token or from the agent's plans as fallback.\n */\n private async verifyWithEndpoint(\n accessToken: string,\n endpoint: string,\n agentId: string,\n maxAmount: bigint,\n planIdOverride?: string,\n ): Promise<{ planId: string; subscriberAddress: Address; agentRequest?: any }> {\n const decodedAccessToken = decodeAccessToken(accessToken)\n if (!decodedAccessToken) {\n throw new Error('Invalid access token')\n }\n\n let planId = planIdOverride ?? decodedAccessToken.accepted?.planId\n const subscriberAddress = decodedAccessToken.payload?.authorization?.from\n\n // If planId is not available, try to get it from the agent's plans\n if (!planId) {\n try {\n const agentPlans = await this.payments.agents.getAgentPlans(agentId)\n if (agentPlans && Array.isArray(agentPlans.plans) && agentPlans.plans.length > 0) {\n planId = agentPlans.plans[0].planId || agentPlans.plans[0].id\n }\n } catch {\n // Ignore errors fetching plans\n }\n }\n\n if (!planId || !subscriberAddress) {\n throw new Error(\n 'Cannot determine plan_id or subscriber_address from token (expected accepted.planId and payload.authorization.from)',\n )\n }\n\n const scheme = isValidScheme(decodedAccessToken?.accepted?.scheme) ? decodedAccessToken.accepted.scheme : 'nvm:erc4337'\n const paymentRequired: X402PaymentRequired = buildPaymentRequired(planId, {\n endpoint,\n agentId,\n httpVerb: 'POST',\n scheme,\n })\n\n const result = await this.payments.facilitator.verifyPermissions({\n paymentRequired,\n x402AccessToken: accessToken,\n maxAmount,\n })\n\n if (!result.isValid) {\n throw new Error('Permission verification failed')\n }\n\n return { planId, subscriberAddress, agentRequest: result.agentRequest }\n }\n\n /**\n * Authenticate an MCP request\n */\n async authenticate(\n extra: any,\n options: { planId?: string; maxAmount?: bigint } = {},\n agentId: string,\n serverName: string,\n name: string,\n kind: 'tool' | 'resource' | 'prompt',\n argsOrVars: any,\n ): Promise<AuthResult> {\n const authHeader = this.extractAuthHeaderFromContext(extra)\n if (!authHeader) {\n throw createRpcError(ERROR_CODES.PaymentRequired, 'Authorization required', {\n reason: 'missing',\n })\n }\n\n return this.verifyWithFallback({\n accessToken: stripBearer(authHeader),\n logicalUrl: buildLogicalUrl({ kind, serverName, name, argsOrVars }),\n httpUrl: this.buildHttpUrlFromContext(),\n maxAmount: options.maxAmount ?? 1n,\n agentId,\n planIdOverride: options.planId,\n })\n }\n\n /**\n * Authenticate generic MCP meta operations (e.g., initialize, tools/list, resources/list, prompts/list).\n * Returns an AuthResult compatible with paywall flows (without redeem step).\n */\n async authenticateMeta(\n extra: any,\n options: { planId?: string; maxAmount?: bigint } = {},\n agentId: string,\n serverName: string,\n method: string,\n ): Promise<AuthResult> {\n const authHeader = this.extractAuthHeaderFromContext(extra)\n if (!authHeader) {\n throw createRpcError(ERROR_CODES.PaymentRequired, 'Authorization required', {\n reason: 'missing',\n })\n }\n\n return this.verifyWithFallback({\n accessToken: stripBearer(authHeader),\n logicalUrl: buildLogicalMetaUrl(serverName, method),\n httpUrl: this.buildHttpUrlFromContext(),\n maxAmount: options.maxAmount ?? 1n,\n agentId,\n planIdOverride: options.planId,\n })\n }\n}\n"]}
1
+ {"version":3,"file":"auth.js","sourceRoot":"","sources":["../../../src/mcp/core/auth.ts"],"names":[],"mappings":"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","sourcesContent":["/**\n * Authentication handler for MCP paywall using X402 tokens\n */\nimport type { Payments } from '../../payments.js'\nimport { decodeAccessToken } from '../../utils.js'\nimport { getCurrentRequestContext } from '../http/mcp-handler.js'\nimport { AuthResult } from '../types/paywall.types.js'\nimport { ERROR_CODES, createRpcError } from '../utils/errors.js'\nimport { Address, isValidScheme } from '../../common/types.js'\nimport { buildLogicalMetaUrl, buildLogicalUrl } from '../utils/logical-url.js'\nimport { extractAuthHeader, stripBearer } from '../utils/request.js'\nimport { buildPaymentRequired, type X402PaymentRequired } from '../../x402/facilitator-api.js'\n\ninterface VerifyContext {\n accessToken: string\n logicalUrl: string\n httpUrl: string | undefined\n maxAmount: bigint\n agentId: string\n planIdOverride?: string\n}\n\n/**\n * Handles authentication and authorization for MCP requests\n */\nexport class PaywallAuthenticator {\n constructor(private payments: Payments) {}\n\n /**\n * Extract authorization header from extra context or AsyncLocalStorage.\n * Tries SDK's extra context first, then falls back to HTTP request context.\n *\n * @param extra - MCP extra context from SDK\n * @returns Authorization header value or undefined\n */\n private extractAuthHeaderFromContext(extra: any): string | undefined {\n // Try to extract auth header from SDK's extra context first\n let authHeader = extractAuthHeader(extra)\n\n if (!authHeader) {\n const requestContext = getCurrentRequestContext()\n if (requestContext?.headers) {\n // Build an extra-like object for extractAuthHeader\n authHeader = extractAuthHeader({ requestInfo: { headers: requestContext.headers } })\n }\n }\n\n return authHeader\n }\n\n /**\n * Build HTTP endpoint URL from request context.\n *\n * @returns HTTP endpoint URL or undefined if context is not available\n */\n private buildHttpUrlFromContext(): string | undefined {\n const requestContext = getCurrentRequestContext()\n if (!requestContext) {\n return undefined\n }\n\n try {\n const host = requestContext.headers?.['host'] || requestContext.headers?.['x-forwarded-host']\n if (!host || typeof host !== 'string') {\n return undefined\n }\n\n const protocol = requestContext.headers?.['x-forwarded-proto'] || 'http'\n const baseUrl = `${protocol}://${host}`\n\n // Use requestContext.url if available (e.g., '/mcp'), otherwise default to '/mcp'\n const path = requestContext.url || '/mcp'\n return `${baseUrl}${path}`\n } catch {\n return undefined\n }\n }\n\n /**\n * Core verification logic shared by authenticate and authenticateMeta.\n * Tries logical URL first, falls back to HTTP URL if available.\n */\n private async verifyWithFallback(ctx: VerifyContext): Promise<AuthResult> {\n const { accessToken, logicalUrl, httpUrl, maxAmount, agentId, planIdOverride } = ctx\n\n // Try logical URL first\n try {\n const result = await this.verifyWithEndpoint(\n accessToken,\n logicalUrl,\n agentId,\n maxAmount,\n planIdOverride,\n )\n return {\n token: accessToken,\n agentId,\n logicalUrl,\n httpUrl,\n planId: result.planId,\n subscriberAddress: result.subscriberAddress,\n agentRequest: result.agentRequest,\n }\n } catch {\n // If logical URL fails and we have an HTTP URL, try that\n }\n\n if (httpUrl) {\n try {\n const result = await this.verifyWithEndpoint(\n accessToken,\n httpUrl,\n agentId,\n maxAmount,\n planIdOverride,\n )\n return {\n token: accessToken,\n agentId,\n logicalUrl,\n httpUrl,\n planId: result.planId,\n subscriberAddress: result.subscriberAddress,\n agentRequest: result.agentRequest,\n }\n } catch {\n // HTTP fallback also failed\n }\n }\n\n // Both attempts failed — enrich denial with suggested plans (best-effort)\n let plansMsg = ''\n try {\n const plans = await this.payments.agents.getAgentPlans(agentId)\n if (plans && Array.isArray(plans.plans) && plans.plans.length > 0) {\n const top = plans.plans.slice(0, 3)\n const summary = top\n .map((p: any) => `${p.planId || p.id || 'plan'}${p.name ? ` (${p.name})` : ''}`)\n .join(', ')\n plansMsg = summary ? ` Available plans: ${summary}...` : ''\n }\n } catch {\n // Ignore errors fetching plans - best effort only\n }\n\n throw createRpcError(ERROR_CODES.PaymentRequired, `Payment required.${plansMsg}`, {\n reason: 'invalid',\n })\n }\n\n /**\n * Verify permissions against a single endpoint URL.\n * Resolves planId from the token or from the agent's plans as fallback.\n */\n private async verifyWithEndpoint(\n accessToken: string,\n endpoint: string,\n agentId: string,\n maxAmount: bigint,\n planIdOverride?: string,\n ): Promise<{ planId: string; subscriberAddress: Address; agentRequest?: any }> {\n const decodedAccessToken = decodeAccessToken(accessToken)\n if (!decodedAccessToken) {\n throw new Error('Invalid access token')\n }\n\n let planId = planIdOverride ?? decodedAccessToken.accepted?.planId\n const subscriberAddress = decodedAccessToken.payload?.authorization?.from\n\n // If planId is not available, try to get it from the agent's plans\n if (!planId) {\n try {\n const agentPlans = await this.payments.agents.getAgentPlans(agentId)\n if (agentPlans && Array.isArray(agentPlans.plans) && agentPlans.plans.length > 0) {\n planId = agentPlans.plans[0].planId || agentPlans.plans[0].id\n }\n } catch {\n // Ignore errors fetching plans\n }\n }\n\n if (!planId || !subscriberAddress) {\n throw new Error(\n 'Cannot determine plan_id or subscriber_address from token (expected accepted.planId and payload.authorization.from)',\n )\n }\n\n const scheme = isValidScheme(decodedAccessToken?.accepted?.scheme) ? decodedAccessToken.accepted.scheme : 'nvm:erc4337'\n const paymentRequired: X402PaymentRequired = buildPaymentRequired(planId, {\n endpoint,\n agentId,\n httpVerb: 'POST',\n scheme,\n environment: this.payments.getEnvironmentName(),\n })\n\n const result = await this.payments.facilitator.verifyPermissions({\n paymentRequired,\n x402AccessToken: accessToken,\n maxAmount,\n })\n\n if (!result.isValid) {\n throw new Error('Permission verification failed')\n }\n\n return { planId, subscriberAddress, agentRequest: result.agentRequest }\n }\n\n /**\n * Authenticate an MCP request\n */\n async authenticate(\n extra: any,\n options: { planId?: string; maxAmount?: bigint } = {},\n agentId: string,\n serverName: string,\n name: string,\n kind: 'tool' | 'resource' | 'prompt',\n argsOrVars: any,\n ): Promise<AuthResult> {\n const authHeader = this.extractAuthHeaderFromContext(extra)\n if (!authHeader) {\n throw createRpcError(ERROR_CODES.PaymentRequired, 'Authorization required', {\n reason: 'missing',\n })\n }\n\n return this.verifyWithFallback({\n accessToken: stripBearer(authHeader),\n logicalUrl: buildLogicalUrl({ kind, serverName, name, argsOrVars }),\n httpUrl: this.buildHttpUrlFromContext(),\n maxAmount: options.maxAmount ?? 1n,\n agentId,\n planIdOverride: options.planId,\n })\n }\n\n /**\n * Authenticate generic MCP meta operations (e.g., initialize, tools/list, resources/list, prompts/list).\n * Returns an AuthResult compatible with paywall flows (without redeem step).\n */\n async authenticateMeta(\n extra: any,\n options: { planId?: string; maxAmount?: bigint } = {},\n agentId: string,\n serverName: string,\n method: string,\n ): Promise<AuthResult> {\n const authHeader = this.extractAuthHeaderFromContext(extra)\n if (!authHeader) {\n throw createRpcError(ERROR_CODES.PaymentRequired, 'Authorization required', {\n reason: 'missing',\n })\n }\n\n return this.verifyWithFallback({\n accessToken: stripBearer(authHeader),\n logicalUrl: buildLogicalMetaUrl(serverName, method),\n httpUrl: this.buildHttpUrlFromContext(),\n maxAmount: options.maxAmount ?? 1n,\n agentId,\n planIdOverride: options.planId,\n })\n }\n}\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;AAOjD,OAAO,EACL,SAAS,EAET,aAAa,EACb,eAAe,EACf,WAAW,EACZ,MAAM,2BAA2B,CAAA;AAElC,OAAO,EAAE,oBAAoB,EAAE,MAAM,WAAW,CAAA;AAChD,OAAO,EAAE,sBAAsB,EAAE,MAAM,sBAAsB,CAAA;AAE7D;;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;IAOnC;;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;IAiH5B;;OAEG;YACW,aAAa;CAkE5B"}
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;AAOjD,OAAO,EACL,SAAS,EAET,aAAa,EACb,eAAe,EACf,WAAW,EACZ,MAAM,2BAA2B,CAAA;AAElC,OAAO,EAAE,oBAAoB,EAAE,MAAM,WAAW,CAAA;AAChD,OAAO,EAAE,sBAAsB,EAAE,MAAM,sBAAsB,CAAA;AAE7D;;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;IAOnC;;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;IAiH5B;;OAEG;YACW,aAAa;CAoE5B"}
@@ -113,6 +113,7 @@ export class PaywallDecorator {
113
113
  agentId,
114
114
  httpVerb,
115
115
  scheme,
116
+ environment: this.payments.getEnvironmentName(),
116
117
  });
117
118
  ret = await this.payments.facilitator.settlePermissions({
118
119
  paymentRequired,
@@ -131,6 +132,7 @@ export class PaywallDecorator {
131
132
  agentId,
132
133
  httpVerb,
133
134
  scheme,
135
+ environment: this.payments.getEnvironmentName(),
134
136
  });
135
137
  ret = await this.payments.facilitator.settlePermissions({
136
138
  paymentRequired,
@@ -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 } from '../../utils.js'\nimport {\n buildPaymentRequired,\n type SettlePermissionsResult,\n type X402PaymentRequired,\n} from '../../x402/facilitator-api.js'\nimport {\n McpConfig,\n PaywallOptions,\n PromptOptions,\n ResourceOptions,\n ToolOptions,\n} from '../types/paywall.types.js'\nimport { ERROR_CODES, createRpcError } from '../utils/errors.js'\nimport { PaywallAuthenticator } from './auth.js'\nimport { CreditsContextProvider } from './credits-context.js'\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: { agentId: string; serverName: string } = {\n agentId: '',\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 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\n if (!this.config.agentId) {\n throw createRpcError(\n ERROR_CODES.Misconfiguration,\n 'Server misconfiguration: missing agentId',\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 // 1. Authenticate request\n const authResult = await this.authenticator.authenticate(\n extra,\n { planId: options?.planId, 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 'POST',\n authResult.httpUrl,\n )\n result._meta = {\n ...result._meta,\n ...(creditsResult.transaction && { txHash: creditsResult.transaction }),\n creditsRedeemed: creditsResult.success ? (creditsResult.creditsRedeemed ?? credits.toString()) : '0',\n remainingBalance: creditsResult.remainingBalance,\n planId: authResult.planId,\n subscriberAddress: authResult.subscriberAddress,\n success: creditsResult.success,\n ...(creditsResult.errorReason && { errorReason: creditsResult.errorReason }),\n }\n return result\n }\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> {\n let ret: SettlePermissionsResult = {\n success: true,\n transaction: '',\n network: '',\n }\n const decoded = decodeAccessToken(token)\n const scheme = isValidScheme(decoded?.accepted?.scheme) ? decoded.accepted.scheme : 'nvm:erc4337'\n try {\n if (credits && credits > 0n && subscriberAddress && planId) {\n const paymentRequired: X402PaymentRequired = buildPaymentRequired(planId, {\n endpoint: endpoint || '',\n agentId,\n httpVerb,\n scheme,\n })\n\n ret = await this.payments.facilitator.settlePermissions({\n paymentRequired,\n x402AccessToken: token,\n maxAmount: credits,\n })\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 })\n\n ret = await this.payments.facilitator.settlePermissions({\n paymentRequired,\n x402AccessToken: token,\n maxAmount: credits,\n })\n return ret\n } catch (fallbackError) {\n // Fallback also failed, use fallback error as the reported error\n lastError = fallbackError\n }\n }\n\n ret.success = false\n ret.errorReason = lastError instanceof Error ? lastError.message : String(lastError)\n if (options.onRedeemError === 'propagate') {\n throw createRpcError(ERROR_CODES.Misconfiguration, `Failed to redeem credits: ${ret.errorReason}`)\n }\n // Default: attach error to result but don't throw\n }\n return ret\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 const metadataChunk = {\n _meta: {\n // Only include txHash if it has a value\n ...(creditsResult?.transaction && { txHash: creditsResult.transaction }),\n creditsRedeemed: creditsResult?.success ? (creditsResult.creditsRedeemed ?? credits.toString()) : '0',\n remainingBalance: creditsResult?.remainingBalance,\n planId,\n subscriberAddress,\n success: creditsResult?.success || false,\n ...(creditsResult?.errorReason && { errorReason: creditsResult.errorReason }),\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 } from '../../utils.js'\nimport {\n buildPaymentRequired,\n type SettlePermissionsResult,\n type X402PaymentRequired,\n} from '../../x402/facilitator-api.js'\nimport {\n McpConfig,\n PaywallOptions,\n PromptOptions,\n ResourceOptions,\n ToolOptions,\n} from '../types/paywall.types.js'\nimport { ERROR_CODES, createRpcError } from '../utils/errors.js'\nimport { PaywallAuthenticator } from './auth.js'\nimport { CreditsContextProvider } from './credits-context.js'\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: { agentId: string; serverName: string } = {\n agentId: '',\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 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\n if (!this.config.agentId) {\n throw createRpcError(\n ERROR_CODES.Misconfiguration,\n 'Server misconfiguration: missing agentId',\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 // 1. Authenticate request\n const authResult = await this.authenticator.authenticate(\n extra,\n { planId: options?.planId, 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 'POST',\n authResult.httpUrl,\n )\n result._meta = {\n ...result._meta,\n ...(creditsResult.transaction && { txHash: creditsResult.transaction }),\n creditsRedeemed: creditsResult.success ? (creditsResult.creditsRedeemed ?? credits.toString()) : '0',\n remainingBalance: creditsResult.remainingBalance,\n planId: authResult.planId,\n subscriberAddress: authResult.subscriberAddress,\n success: creditsResult.success,\n ...(creditsResult.errorReason && { errorReason: creditsResult.errorReason }),\n }\n return result\n }\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> {\n let ret: SettlePermissionsResult = {\n success: true,\n transaction: '',\n network: '',\n }\n const decoded = decodeAccessToken(token)\n const scheme = isValidScheme(decoded?.accepted?.scheme) ? decoded.accepted.scheme : 'nvm:erc4337'\n try {\n if (credits && credits > 0n && subscriberAddress && planId) {\n const paymentRequired: X402PaymentRequired = buildPaymentRequired(planId, {\n endpoint: endpoint || '',\n agentId,\n httpVerb,\n scheme,\n environment: this.payments.getEnvironmentName(),\n })\n\n ret = await this.payments.facilitator.settlePermissions({\n paymentRequired,\n x402AccessToken: token,\n maxAmount: credits,\n })\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 ret = await this.payments.facilitator.settlePermissions({\n paymentRequired,\n x402AccessToken: token,\n maxAmount: credits,\n })\n return ret\n } catch (fallbackError) {\n // Fallback also failed, use fallback error as the reported error\n lastError = fallbackError\n }\n }\n\n ret.success = false\n ret.errorReason = lastError instanceof Error ? lastError.message : String(lastError)\n if (options.onRedeemError === 'propagate') {\n throw createRpcError(ERROR_CODES.Misconfiguration, `Failed to redeem credits: ${ret.errorReason}`)\n }\n // Default: attach error to result but don't throw\n }\n return ret\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 const metadataChunk = {\n _meta: {\n // Only include txHash if it has a value\n ...(creditsResult?.transaction && { txHash: creditsResult.transaction }),\n creditsRedeemed: creditsResult?.success ? (creditsResult.creditsRedeemed ?? credits.toString()) : '0',\n remainingBalance: creditsResult?.remainingBalance,\n planId,\n subscriberAddress,\n success: creditsResult?.success || false,\n ...(creditsResult?.errorReason && { errorReason: creditsResult.errorReason }),\n },\n }\n yield metadataChunk as T\n }\n return generator()\n}\n"]}
@@ -1 +1 @@
1
- {"version":3,"file":"middleware.d.ts","sourceRoot":"","sources":["../../../src/x402/express/middleware.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;GA8CG;AAEH,OAAO,KAAK,EAAE,OAAO,EAAE,QAAQ,EAAE,YAAY,EAAE,MAAM,SAAS,CAAA;AAE9D;;;;GAIG;AACH,MAAM,MAAM,iBAAiB,GAAG,CAAC,GAAG,EAAE,OAAO,EAAE,GAAG,EAAE,QAAQ,EAAE,IAAI,EAAE,YAAY,KAAK,IAAI,CAAA;AACzF,OAAO,KAAK,EAAE,QAAQ,EAAE,MAAM,mBAAmB,CAAA;AACjD,OAAO,KAAK,EAAE,iBAAiB,EAAE,cAAc,EAAE,MAAM,uBAAuB,CAAA;AAC9E,OAAO,EAGL,KAAK,mBAAmB,EACxB,KAAK,uBAAuB,EAC7B,MAAM,uBAAuB,CAAA;AAE9B;;GAEG;AACH,MAAM,WAAW,WAAW;IAC1B,sDAAsD;IACtD,MAAM,EAAE,MAAM,CAAA;IACd,8DAA8D;IAC9D,OAAO,CAAC,EAAE,MAAM,GAAG,CAAC,CAAC,GAAG,EAAE,OAAO,EAAE,GAAG,EAAE,QAAQ,KAAK,MAAM,GAAG,OAAO,CAAC,MAAM,CAAC,CAAC,CAAA;IAC9E,wBAAwB;IACxB,OAAO,CAAC,EAAE,MAAM,CAAA;IAChB,6DAA6D;IAC7D,OAAO,CAAC,EAAE,MAAM,CAAA;IAChB,yEAAyE;IACzE,MAAM,CAAC,EAAE,cAAc,CAAA;CACxB;AAED;;GAEG;AACH,MAAM,MAAM,cAAc,GAAG,MAAM,CAAC,MAAM,EAAE,WAAW,CAAC,CAAA;AAExD;;;GAGG;AACH,eAAO,MAAM,YAAY;IACvB,gDAAgD;;IAEhD,mEAAmE;;IAEnE,sEAAsE;;CAE9D,CAAA;AAEV;;;GAGG;AACH,MAAM,WAAW,cAAc;IAC7B,4BAA4B;IAC5B,KAAK,EAAE,MAAM,CAAA;IACb,kCAAkC;IAClC,eAAe,EAAE,mBAAmB,CAAA;IACpC,kCAAkC;IAClC,eAAe,EAAE,MAAM,CAAA;IACvB,0CAA0C;IAC1C,QAAQ,EAAE,OAAO,CAAA;IACjB,2EAA2E;IAC3E,YAAY,CAAC,EAAE,iBAAiB,CAAA;IAChC,kDAAkD;IAClD,cAAc,CAAC,EAAE,MAAM,CAAA;CACxB;AAED;;GAEG;AACH,MAAM,WAAW,wBAAwB;IACvC;;;OAGG;IACH,WAAW,CAAC,EAAE,MAAM,GAAG,MAAM,EAAE,CAAA;IAC/B,gDAAgD;IAChD,cAAc,CAAC,EAAE,CAAC,KAAK,EAAE,KAAK,EAAE,GAAG,EAAE,OAAO,EAAE,GAAG,EAAE,QAAQ,KAAK,IAAI,CAAA;IACpE,sCAAsC;IACtC,cAAc,CAAC,EAAE,CAAC,GAAG,EAAE,OAAO,EAAE,eAAe,EAAE,mBAAmB,KAAK,IAAI,GAAG,OAAO,CAAC,IAAI,CAAC,CAAA;IAC7F;;;OAGG;IACH,aAAa,CAAC,EAAE,CAAC,GAAG,EAAE,OAAO,EAAE,YAAY,EAAE,uBAAuB,KAAK,IAAI,GAAG,OAAO,CAAC,IAAI,CAAC,CAAA;IAC7F,8CAA8C;IAC9C,aAAa,CAAC,EAAE,CAAC,GAAG,EAAE,OAAO,EAAE,WAAW,EAAE,MAAM,EAAE,MAAM,EAAE,OAAO,KAAK,IAAI,GAAG,OAAO,CAAC,IAAI,CAAC,CAAA;CAC7F;AAyGD,wBAAgB,iBAAiB,CAC/B,QAAQ,EAAE,QAAQ,EAClB,MAAM,EAAE,cAAc,EACtB,OAAO,GAAE,wBAA6B,GACrC,iBAAiB,CAwKnB;AAED,eAAe,iBAAiB,CAAA"}
1
+ {"version":3,"file":"middleware.d.ts","sourceRoot":"","sources":["../../../src/x402/express/middleware.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;GA8CG;AAEH,OAAO,KAAK,EAAE,OAAO,EAAE,QAAQ,EAAE,YAAY,EAAE,MAAM,SAAS,CAAA;AAE9D;;;;GAIG;AACH,MAAM,MAAM,iBAAiB,GAAG,CAAC,GAAG,EAAE,OAAO,EAAE,GAAG,EAAE,QAAQ,EAAE,IAAI,EAAE,YAAY,KAAK,IAAI,CAAA;AACzF,OAAO,KAAK,EAAE,QAAQ,EAAE,MAAM,mBAAmB,CAAA;AACjD,OAAO,KAAK,EAAE,iBAAiB,EAAE,cAAc,EAAE,MAAM,uBAAuB,CAAA;AAC9E,OAAO,EAGL,KAAK,mBAAmB,EACxB,KAAK,uBAAuB,EAC7B,MAAM,uBAAuB,CAAA;AAE9B;;GAEG;AACH,MAAM,WAAW,WAAW;IAC1B,sDAAsD;IACtD,MAAM,EAAE,MAAM,CAAA;IACd,8DAA8D;IAC9D,OAAO,CAAC,EAAE,MAAM,GAAG,CAAC,CAAC,GAAG,EAAE,OAAO,EAAE,GAAG,EAAE,QAAQ,KAAK,MAAM,GAAG,OAAO,CAAC,MAAM,CAAC,CAAC,CAAA;IAC9E,wBAAwB;IACxB,OAAO,CAAC,EAAE,MAAM,CAAA;IAChB,6DAA6D;IAC7D,OAAO,CAAC,EAAE,MAAM,CAAA;IAChB,yEAAyE;IACzE,MAAM,CAAC,EAAE,cAAc,CAAA;CACxB;AAED;;GAEG;AACH,MAAM,MAAM,cAAc,GAAG,MAAM,CAAC,MAAM,EAAE,WAAW,CAAC,CAAA;AAExD;;;GAGG;AACH,eAAO,MAAM,YAAY;IACvB,gDAAgD;;IAEhD,mEAAmE;;IAEnE,sEAAsE;;CAE9D,CAAA;AAEV;;;GAGG;AACH,MAAM,WAAW,cAAc;IAC7B,4BAA4B;IAC5B,KAAK,EAAE,MAAM,CAAA;IACb,kCAAkC;IAClC,eAAe,EAAE,mBAAmB,CAAA;IACpC,kCAAkC;IAClC,eAAe,EAAE,MAAM,CAAA;IACvB,0CAA0C;IAC1C,QAAQ,EAAE,OAAO,CAAA;IACjB,2EAA2E;IAC3E,YAAY,CAAC,EAAE,iBAAiB,CAAA;IAChC,kDAAkD;IAClD,cAAc,CAAC,EAAE,MAAM,CAAA;CACxB;AAED;;GAEG;AACH,MAAM,WAAW,wBAAwB;IACvC;;;OAGG;IACH,WAAW,CAAC,EAAE,MAAM,GAAG,MAAM,EAAE,CAAA;IAC/B,gDAAgD;IAChD,cAAc,CAAC,EAAE,CAAC,KAAK,EAAE,KAAK,EAAE,GAAG,EAAE,OAAO,EAAE,GAAG,EAAE,QAAQ,KAAK,IAAI,CAAA;IACpE,sCAAsC;IACtC,cAAc,CAAC,EAAE,CAAC,GAAG,EAAE,OAAO,EAAE,eAAe,EAAE,mBAAmB,KAAK,IAAI,GAAG,OAAO,CAAC,IAAI,CAAC,CAAA;IAC7F;;;OAGG;IACH,aAAa,CAAC,EAAE,CAAC,GAAG,EAAE,OAAO,EAAE,YAAY,EAAE,uBAAuB,KAAK,IAAI,GAAG,OAAO,CAAC,IAAI,CAAC,CAAA;IAC7F,8CAA8C;IAC9C,aAAa,CAAC,EAAE,CAAC,GAAG,EAAE,OAAO,EAAE,WAAW,EAAE,MAAM,EAAE,MAAM,EAAE,OAAO,KAAK,IAAI,GAAG,OAAO,CAAC,IAAI,CAAC,CAAA;CAC7F;AAyGD,wBAAgB,iBAAiB,CAC/B,QAAQ,EAAE,QAAQ,EAClB,MAAM,EAAE,cAAc,EACtB,OAAO,GAAE,wBAA6B,GACrC,iBAAiB,CAyKnB;AAED,eAAe,iBAAiB,CAAA"}
@@ -169,6 +169,7 @@ export function paymentMiddleware(payments, routes, options = {}) {
169
169
  httpVerb: req.method,
170
170
  network,
171
171
  scheme,
172
+ environment: payments.getEnvironmentName(),
172
173
  });
173
174
  // Extract token from headers (x402 v2: payment-signature)
174
175
  const token = extractToken(req, tokenHeader);
@@ -1 +1 @@
1
- {"version":3,"file":"middleware.js","sourceRoot":"","sources":["../../../src/x402/express/middleware.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;GA8CG;AAYH,OAAO,EACL,oBAAoB,EACpB,aAAa,GAGd,MAAM,uBAAuB,CAAA;AAuB9B;;;GAGG;AACH,MAAM,CAAC,MAAM,YAAY,GAAG;IAC1B,gDAAgD;IAChD,iBAAiB,EAAE,mBAAmB;IACtC,mEAAmE;IACnE,gBAAgB,EAAE,kBAAkB;IACpC,sEAAsE;IACtE,gBAAgB,EAAE,kBAAkB;CAC5B,CAAA;AA2CV;;GAEG;AACH,MAAM,qBAAqB,GAAG,CAAC,YAAY,CAAC,iBAAiB,CAAC,CAAA;AAE9D;;;GAGG;AACH,SAAS,YAAY,CAAC,GAAY,EAAE,WAA8B;IAChE,MAAM,OAAO,GAAG,KAAK,CAAC,OAAO,CAAC,WAAW,CAAC,CAAC,CAAC,CAAC,WAAW,CAAC,CAAC,CAAC,CAAC,WAAW,CAAC,CAAA;IAExE,KAAK,MAAM,UAAU,IAAI,OAAO,EAAE,CAAC;QACjC,MAAM,MAAM,GAAG,GAAG,CAAC,OAAO,CAAC,UAAU,CAAC,WAAW,EAAE,CAAC,CAAA;QACpD,IAAI,MAAM,IAAI,OAAO,MAAM,KAAK,QAAQ,EAAE,CAAC;YACzC,OAAO,MAAM,CAAA;QACf,CAAC;IACH,CAAC;IAED,OAAO,IAAI,CAAA;AACb,CAAC;AAED;;;GAGG;AACH,SAAS,UAAU,CAAC,GAAY,EAAE,MAAsB;IACtD,MAAM,MAAM,GAAG,GAAG,CAAC,MAAM,CAAC,WAAW,EAAE,CAAA;IACvC,MAAM,IAAI,GAAG,GAAG,CAAC,IAAI,CAAA;IAErB,qCAAqC;IACrC,MAAM,QAAQ,GAAG,GAAG,MAAM,IAAI,IAAI,EAAE,CAAA;IACpC,IAAI,MAAM,CAAC,QAAQ,CAAC,EAAE,CAAC;QACrB,OAAO,MAAM,CAAC,QAAQ,CAAC,CAAA;IACzB,CAAC;IAED,4CAA4C;IAC5C,KAAK,MAAM,CAAC,QAAQ,EAAE,MAAM,CAAC,IAAI,MAAM,CAAC,OAAO,CAAC,MAAM,CAAC,EAAE,CAAC;QACxD,MAAM,CAAC,WAAW,EAAE,SAAS,CAAC,GAAG,QAAQ,CAAC,KAAK,CAAC,GAAG,CAAC,CAAA;QACpD,IAAI,WAAW,KAAK,MAAM;YAAE,SAAQ;QAEpC,oDAAoD;QACpD,MAAM,UAAU,GAAG,SAAS,CAAC,KAAK,CAAC,GAAG,CAAC,CAAA;QACvC,MAAM,SAAS,GAAG,IAAI,CAAC,KAAK,CAAC,GAAG,CAAC,CAAA;QAEjC,IAAI,UAAU,CAAC,MAAM,KAAK,SAAS,CAAC,MAAM;YAAE,SAAQ;QAEpD,IAAI,KAAK,GAAG,IAAI,CAAA;QAChB,KAAK,IAAI,CAAC,GAAG,CAAC,EAAE,CAAC,GAAG,UAAU,CAAC,MAAM,EAAE,CAAC,EAAE,EAAE,CAAC;YAC3C,IAAI,UAAU,CAAC,CAAC,CAAC,CAAC,UAAU,CAAC,GAAG,CAAC;gBAAE,SAAQ,CAAC,6BAA6B;YACzE,IAAI,UAAU,CAAC,CAAC,CAAC,KAAK,SAAS,CAAC,CAAC,CAAC,EAAE,CAAC;gBACnC,KAAK,GAAG,KAAK,CAAA;gBACb,MAAK;YACP,CAAC;QACH,CAAC;QAED,IAAI,KAAK;YAAE,OAAO,MAAM,CAAA;IAC1B,CAAC;IAED,OAAO,IAAI,CAAA;AACb,CAAC;AAED;;;;;;;;;;;;;;;;;;;;;;;GAuBG;AACH;;GAEG;AACH,SAAS,mBAAmB,CAC1B,GAAa,EACb,eAAoC,EACpC,OAAe;IAEf,0EAA0E;IAC1E,MAAM,qBAAqB,GAAG,MAAM,CAAC,IAAI,CAAC,IAAI,CAAC,SAAS,CAAC,eAAe,CAAC,CAAC,CAAC,QAAQ,CAAC,QAAQ,CAAC,CAAA;IAE7F,GAAG,CAAC,MAAM,CAAC,GAAG,CAAC,CAAC,SAAS,CAAC,YAAY,CAAC,gBAAgB,EAAE,qBAAqB,CAAC,CAAC,IAAI,CAAC;QACnF,KAAK,EAAE,kBAAkB;QACzB,OAAO;KACR,CAAC,CAAA;AACJ,CAAC;AAED,MAAM,UAAU,iBAAiB,CAC/B,QAAkB,EAClB,MAAsB,EACtB,UAAoC,EAAE;IAEtC,MAAM,EACJ,WAAW,GAAG,qBAAqB,EACnC,cAAc,EACd,cAAc,EACd,aAAa,EACb,aAAa,GACd,GAAG,OAAO,CAAA;IAEX,OAAO,CAAC,GAAY,EAAE,GAAa,EAAE,IAAkB,EAAQ,EAAE;QAC/D,+CAA+C;QAC/C,MAAM,aAAa,GAAG,KAAK,IAAmB,EAAE;YAC9C,uCAAuC;YACvC,MAAM,WAAW,GAAG,UAAU,CAAC,GAAG,EAAE,MAAM,CAAC,CAAA;YAC3C,IAAI,CAAC,WAAW,EAAE,CAAC;gBACjB,qCAAqC;gBACrC,IAAI,EAAE,CAAA;gBACN,OAAM;YACR,CAAC;YAED,MAAM,EAAE,MAAM,EAAE,OAAO,GAAG,CAAC,EAAE,OAAO,EAAE,OAAO,EAAE,MAAM,EAAE,cAAc,EAAE,GAAG,WAAW,CAAA;YAErF,kEAAkE;YAClE,MAAM,MAAM,GAAG,MAAM,aAAa,CAAC,QAAQ,EAAE,MAAM,EAAE,cAAc,CAAC,CAAA;YAEpE,mFAAmF;YACnF,MAAM,eAAe,GAAG,oBAAoB,CAAC,MAAM,EAAE;gBACnD,QAAQ,EAAE,GAAG,CAAC,WAAW,IAAI,GAAG,CAAC,GAAG;gBACpC,OAAO;gBACP,QAAQ,EAAE,GAAG,CAAC,MAAM;gBACpB,OAAO;gBACP,MAAM;aACP,CAAC,CAAA;YAEF,0DAA0D;YAC1D,MAAM,KAAK,GAAG,YAAY,CAAC,GAAG,EAAE,WAAW,CAAC,CAAA;YAC5C,IAAI,CAAC,KAAK,EAAE,CAAC;gBACX,MAAM,KAAK,GAAG,IAAI,KAAK,CAAC,6CAA6C,CAAC,CAAA;gBACtE,IAAI,cAAc,EAAE,CAAC;oBACnB,cAAc,CAAC,KAAK,EAAE,GAAG,EAAE,GAAG,CAAC,CAAA;oBAC/B,OAAM;gBACR,CAAC;gBACD,mBAAmB,CACjB,GAAG,EACH,eAAe,EACf,6CAA6C,YAAY,CAAC,iBAAiB,UAAU,CACtF,CAAA;gBACD,OAAM;YACR,CAAC;YAED,8BAA8B;YAC9B,MAAM,eAAe,GAAG,OAAO,OAAO,KAAK,UAAU,CAAC,CAAC,CAAC,MAAM,OAAO,CAAC,GAAG,EAAE,GAAG,CAAC,CAAC,CAAC,CAAC,OAAO,CAAA;YAEzF,IAAI,CAAC;gBACH,4BAA4B;gBAC5B,IAAI,cAAc,EAAE,CAAC;oBACnB,MAAM,cAAc,CAAC,GAAG,EAAE,eAAe,CAAC,CAAA;gBAC5C,CAAC;gBAED,qBAAqB;gBACrB,MAAM,YAAY,GAAG,MAAM,QAAQ,CAAC,WAAW,CAAC,iBAAiB,CAAC;oBAChE,eAAe;oBACf,eAAe,EAAE,KAAK;oBACtB,SAAS,EAAE,MAAM,CAAC,eAAe,CAAC;iBACnC,CAAC,CAAA;gBAEF,IAAI,CAAC,YAAY,CAAC,OAAO,EAAE,CAAC;oBAC1B,MAAM,KAAK,GAAG,IAAI,KAAK,CAAC,YAAY,CAAC,aAAa,IAAI,6BAA6B,CAAC,CAAA;oBACpF,IAAI,cAAc,EAAE,CAAC;wBACnB,cAAc,CAAC,KAAK,EAAE,GAAG,EAAE,GAAG,CAAC,CAAA;wBAC/B,OAAM;oBACR,CAAC;oBACD,mBAAmB,CACjB,GAAG,EACH,eAAe,EACf,YAAY,CAAC,aAAa,IAAI,uCAAuC,CACtE,CAAA;oBACD,OAAM;gBACR,CAAC;gBAED,yDAAyD;gBACzD,IAAI,aAAa,EAAE,CAAC;oBAClB,MAAM,aAAa,CAAC,GAAG,EAAE,YAAY,CAAC,CAAA;gBACxC,CAAC;gBAED,gEAAgE;gBAChE,MAAM,cAAc,GAAmB;oBACrC,KAAK;oBACL,eAAe;oBACf,eAAe,EAAE,eAAe;oBAChC,QAAQ,EAAE,IAAI;oBACd,YAAY,EAAE,YAAY,CAAC,YAAY;oBACvC,cAAc,EAAE,YAAY,CAAC,YAAY,EAAE,cAAc,IAAI,YAAY,CAAC,cAAc;iBACzF,CAGA;gBAAC,GAAqD,CAAC,cAAc,GAAG,cAAc,CAAA;gBAEvF,sDAAsD;gBACtD,0EAA0E;gBAC1E,MAAM,YAAY,GAAG,GAAG,CAAC,IAAI,CAAC,IAAI,CAAC,GAAG,CAAC,CAAA;gBACvC,GAAG,CAAC,IAAI,GAAG,UAAU,IAAa;oBAChC,+DAA+D;oBAC/D,wEAAwE;oBACxE,MAAM,aAAa,GAAG,CACpB,OAAO,OAAO,KAAK,UAAU;wBAC3B,CAAC,CAAC,OAAO,CAAC,OAAO,CAAC,OAAO,CAAC,GAAG,EAAE,GAAG,CAAC,CAAC;wBACpC,CAAC,CAAC,OAAO,CAAC,OAAO,CAAC,eAAe,CAAC,CACrC,CAAC,IAAI,CAAC,CAAC,eAAe,EAAE,EAAE;wBACzB,sEAAsE;wBACtE,cAAc,CAAC,eAAe,GAAG,eAAe,CAAA;wBAEhD,yCAAyC;wBACzC,sDAAsD;wBACtD,OAAO,QAAQ,CAAC,WAAW;6BACxB,iBAAiB,CAAC;4BACjB,eAAe;4BACf,eAAe,EAAE,KAAK;4BACtB,SAAS,EAAE,MAAM,CAAC,eAAe,CAAC;4BAClC,cAAc,EAAE,cAAc,CAAC,cAAc;yBAC9C,CAAC;6BACD,IAAI,CAAC,CAAC,UAAU,EAAE,EAAE;4BACnB,gEAAgE;4BAChE,MAAM,gBAAgB,GAAG,MAAM,CAAC,IAAI,CAAC,IAAI,CAAC,SAAS,CAAC,UAAU,CAAC,CAAC,CAAC,QAAQ,CAAC,QAAQ,CAAC,CAAA;4BACnF,GAAG,CAAC,SAAS,CAAC,YAAY,CAAC,gBAAgB,EAAE,gBAAgB,CAAC,CAAA;4BAE9D,yBAAyB;4BACzB,IAAI,aAAa,EAAE,CAAC;gCAClB,OAAO,OAAO,CAAC,OAAO,CAAC,aAAa,CAAC,GAAG,EAAE,eAAe,EAAE,UAAU,CAAC,CAAC,CAAC,IAAI,CAC1E,GAAG,EAAE,CAAC,UAAU,CACjB,CAAA;4BACH,CAAC;4BACD,OAAO,UAAU,CAAA;wBACnB,CAAC,CAAC,CAAA;oBACN,CAAC,CAAC,CAAA;oBAEF,aAAa;yBACV,KAAK,CAAC,CAAC,WAAW,EAAE,EAAE;wBACrB,OAAO,CAAC,KAAK,CAAC,4BAA4B,EAAE,WAAW,CAAC,CAAA;wBACxD,+CAA+C;oBACjD,CAAC,CAAC;yBACD,OAAO,CAAC,GAAG,EAAE;wBACZ,sDAAsD;wBACtD,YAAY,CAAC,IAAI,CAAC,CAAA;oBACpB,CAAC,CAAC,CAAA;oBAEJ,4CAA4C;oBAC5C,OAAO,GAAG,CAAA;gBACZ,CAAC,CAAA;gBAED,4BAA4B;gBAC5B,IAAI,EAAE,CAAA;YACR,CAAC;YAAC,OAAO,KAAK,EAAE,CAAC;gBACf,IAAI,cAAc,EAAE,CAAC;oBACnB,cAAc,CAAC,KAAc,EAAE,GAAG,EAAE,GAAG,CAAC,CAAA;oBACxC,OAAM;gBACR,CAAC;gBACD,mBAAmB,CACjB,GAAG,EACH,eAAe,EACf,KAAK,YAAY,KAAK,CAAC,CAAC,CAAC,KAAK,CAAC,OAAO,CAAC,CAAC,CAAC,6BAA6B,CACvE,CAAA;YACH,CAAC;QACH,CAAC,CAAA;QAED,4CAA4C;QAC5C,aAAa,EAAE,CAAC,KAAK,CAAC,IAAI,CAAC,CAAA;IAC7B,CAAC,CAAA;AACH,CAAC;AAED,eAAe,iBAAiB,CAAA","sourcesContent":["/**\n * Express middleware for Nevermined payment protection using the x402 protocol.\n *\n * This middleware provides a simple way to protect Express routes with\n * Nevermined payment verification and settlement.\n *\n * ## x402 HTTP Transport Headers\n *\n * Following the x402 spec (https://github.com/coinbase/x402/blob/main/specs/transports-v2/http.md):\n *\n * - **Client → Server**: `payment-signature` header with base64-encoded token\n * - **Server → Client (402)**: `payment-required` header with base64-encoded PaymentRequired\n * - **Server → Client (success)**: `payment-response` header with settlement receipt\n *\n * @example\n * ```typescript\n * import express from 'express'\n * import { Payments } from '@nevermined-io/payments'\n * import { paymentMiddleware } from '@nevermined-io/payments/express'\n *\n * const app = express()\n * const payments = Payments.getInstance({ nvmApiKey: '...', environment: 'testing' })\n *\n * // Protect routes with payment middleware\n * app.use(paymentMiddleware(payments, {\n * 'POST /ask': { planId: '123', credits: 1 },\n * 'POST /generate': { planId: '123', credits: 5 },\n * }))\n *\n * // Route handlers - no payment logic needed!\n * app.post('/ask', (req, res) => res.json({ answer: '...' }))\n * ```\n *\n * @example Client usage\n * ```typescript\n * const token = await payments.x402.getX402AccessToken(planId)\n *\n * const response = await fetch('/ask', {\n * method: 'POST',\n * headers: {\n * 'Content-Type': 'application/json',\n * 'payment-signature': token.accessToken, // x402 header\n * },\n * body: JSON.stringify({ query: 'Hello!' }),\n * })\n * ```\n */\n\nimport type { Request, Response, NextFunction } from 'express'\n\n/**\n * Express middleware function type.\n * Using explicit signature instead of RequestHandler to avoid type resolution issues\n * when SDK's \\@types/express version differs from consumer's.\n */\nexport type ExpressMiddleware = (req: Request, res: Response, next: NextFunction) => void\nimport type { Payments } from '../../payments.js'\nimport type { StartAgentRequest, X402SchemeType } from '../../common/types.js'\nimport {\n buildPaymentRequired,\n resolveScheme,\n type X402PaymentRequired,\n type VerifyPermissionsResult,\n} from '../facilitator-api.js'\n\n/**\n * Configuration for a protected route\n */\nexport interface RouteConfig {\n /** The Nevermined plan ID that protects this route */\n planId: string\n /** Number of credits to charge for this route (default: 1) */\n credits?: number | ((req: Request, res: Response) => number | Promise<number>)\n /** Optional agent ID */\n agentId?: string\n /** Network identifier (default: auto-derived from scheme) */\n network?: string\n /** x402 scheme override (auto-detected from plan metadata if omitted) */\n scheme?: X402SchemeType\n}\n\n/**\n * Route configuration map: \"METHOD \\/path\" -> RouteConfig\n */\nexport type RouteConfigMap = Record<string, RouteConfig>\n\n/**\n * x402 HTTP Transport header names (v2 spec)\n * @see https://github.com/coinbase/x402/blob/main/specs/transports-v2/http.md\n */\nexport const X402_HEADERS = {\n /** Client sends payment token in this header */\n PAYMENT_SIGNATURE: 'payment-signature',\n /** Server sends PaymentRequired in this header (base64-encoded) */\n PAYMENT_REQUIRED: 'payment-required',\n /** Server sends settlement receipt in this header (base64-encoded) */\n PAYMENT_RESPONSE: 'payment-response',\n} as const\n\n/**\n * Payment context attached to the request after verification.\n * Available as `req.paymentContext` in route handlers.\n */\nexport interface PaymentContext {\n /** The x402 access token */\n token: string\n /** The payment required object */\n paymentRequired: X402PaymentRequired\n /** Number of credits to settle */\n creditsToSettle: number\n /** Whether verification was successful */\n verified: boolean\n /** Agent request context for observability (from verification response) */\n agentRequest?: StartAgentRequest\n /** Agent request ID for observability tracking */\n agentRequestId?: string\n}\n\n/**\n * Options for the payment middleware\n */\nexport interface PaymentMiddlewareOptions {\n /**\n * Header name(s) to check for the x402 access token.\n * Default: 'payment-signature' (x402 v2 compliant)\n */\n tokenHeader?: string | string[]\n /** Custom error handler for payment failures */\n onPaymentError?: (error: Error, req: Request, res: Response) => void\n /** Hook called before verification */\n onBeforeVerify?: (req: Request, paymentRequired: X402PaymentRequired) => void | Promise<void>\n /**\n * Hook called after successful verification.\n * Use this to access agentRequest for observability configuration.\n */\n onAfterVerify?: (req: Request, verification: VerifyPermissionsResult) => void | Promise<void>\n /** Hook called after successful settlement */\n onAfterSettle?: (req: Request, creditsUsed: number, result: unknown) => void | Promise<void>\n}\n\n/**\n * Default header for token extraction (x402 v2 compliant)\n */\nconst DEFAULT_TOKEN_HEADERS = [X402_HEADERS.PAYMENT_SIGNATURE]\n\n/**\n * Extract the x402 access token from the request headers.\n * Checks multiple headers in priority order.\n */\nfunction extractToken(req: Request, headerNames: string | string[]): string | null {\n const headers = Array.isArray(headerNames) ? headerNames : [headerNames]\n\n for (const headerName of headers) {\n const header = req.headers[headerName.toLowerCase()]\n if (header && typeof header === 'string') {\n return header\n }\n }\n\n return null\n}\n\n/**\n * Match a request to a route config.\n * Returns the config if found, null otherwise.\n */\nfunction matchRoute(req: Request, routes: RouteConfigMap): RouteConfig | null {\n const method = req.method.toUpperCase()\n const path = req.path\n\n // Try exact match first: \"POST /ask\"\n const exactKey = `${method} ${path}`\n if (routes[exactKey]) {\n return routes[exactKey]\n }\n\n // Try pattern matching with path parameters\n for (const [routeKey, config] of Object.entries(routes)) {\n const [routeMethod, routePath] = routeKey.split(' ')\n if (routeMethod !== method) continue\n\n // Simple pattern matching: /users/:id -> /users/123\n const routeParts = routePath.split('/')\n const pathParts = path.split('/')\n\n if (routeParts.length !== pathParts.length) continue\n\n let match = true\n for (let i = 0; i < routeParts.length; i++) {\n if (routeParts[i].startsWith(':')) continue // Parameter - always matches\n if (routeParts[i] !== pathParts[i]) {\n match = false\n break\n }\n }\n\n if (match) return config\n }\n\n return null\n}\n\n/**\n * Create an Express middleware that protects routes with Nevermined payments.\n *\n * The middleware:\n * 1. Checks if the request matches a protected route\n * 2. Extracts the x402 token from headers\n * 3. Verifies the subscriber has sufficient credits\n * 4. Lets the route handler execute\n * 5. Settles (burns) the credits after successful response\n *\n * @param payments - The Payments instance\n * @param routes - Map of routes to protect: \\{ \"METHOD \\/path\": \\{ planId, credits \\} \\}\n * @param options - Optional middleware configuration\n * @returns Express middleware function\n *\n * @example\n * ```typescript\n * app.use(paymentMiddleware(payments, {\n * 'POST /ask': { planId: PLAN_ID, credits: 1 },\n * 'POST /generate': { planId: PLAN_ID, credits: 5 },\n * 'GET /status/:id': { planId: PLAN_ID, credits: 0 }, // Free but requires auth\n * }))\n * ```\n */\n/**\n * Helper to send a 402 Payment Required response with proper x402 headers.\n */\nfunction sendPaymentRequired(\n res: Response,\n paymentRequired: X402PaymentRequired,\n message: string,\n): void {\n // Base64 encode the PaymentRequired object for the header (per x402 spec)\n const paymentRequiredBase64 = Buffer.from(JSON.stringify(paymentRequired)).toString('base64')\n\n res.status(402).setHeader(X402_HEADERS.PAYMENT_REQUIRED, paymentRequiredBase64).json({\n error: 'Payment Required',\n message,\n })\n}\n\nexport function paymentMiddleware(\n payments: Payments,\n routes: RouteConfigMap,\n options: PaymentMiddlewareOptions = {},\n): ExpressMiddleware {\n const {\n tokenHeader = DEFAULT_TOKEN_HEADERS,\n onPaymentError,\n onBeforeVerify,\n onAfterVerify,\n onAfterSettle,\n } = options\n\n return (req: Request, res: Response, next: NextFunction): void => {\n // Wrap async logic to handle promises properly\n const handleRequest = async (): Promise<void> => {\n // Check if this route requires payment\n const routeConfig = matchRoute(req, routes)\n if (!routeConfig) {\n // Route not protected - pass through\n next()\n return\n }\n\n const { planId, credits = 1, agentId, network, scheme: explicitScheme } = routeConfig\n\n // Resolve scheme from plan metadata (cached) or explicit override\n const scheme = await resolveScheme(payments, planId, explicitScheme)\n\n // Build payment required object (needed for both error responses and verification)\n const paymentRequired = buildPaymentRequired(planId, {\n endpoint: req.originalUrl || req.url,\n agentId,\n httpVerb: req.method,\n network,\n scheme,\n })\n\n // Extract token from headers (x402 v2: payment-signature)\n const token = extractToken(req, tokenHeader)\n if (!token) {\n const error = new Error('Payment required: missing x402 access token')\n if (onPaymentError) {\n onPaymentError(error, req, res)\n return\n }\n sendPaymentRequired(\n res,\n paymentRequired,\n `Missing x402 payment token. Send token in ${X402_HEADERS.PAYMENT_SIGNATURE} header.`,\n )\n return\n }\n\n // Calculate credits to verify\n const creditsToVerify = typeof credits === 'function' ? await credits(req, res) : credits\n\n try {\n // Hook: before verification\n if (onBeforeVerify) {\n await onBeforeVerify(req, paymentRequired)\n }\n\n // Verify permissions\n const verification = await payments.facilitator.verifyPermissions({\n paymentRequired,\n x402AccessToken: token,\n maxAmount: BigInt(creditsToVerify),\n })\n\n if (!verification.isValid) {\n const error = new Error(verification.invalidReason || 'Payment verification failed')\n if (onPaymentError) {\n onPaymentError(error, req, res)\n return\n }\n sendPaymentRequired(\n res,\n paymentRequired,\n verification.invalidReason || 'Insufficient credits or invalid token',\n )\n return\n }\n\n // Hook: after verification (use for observability setup)\n if (onAfterVerify) {\n await onAfterVerify(req, verification)\n }\n\n // Store payment context for settlement and route handler access\n const paymentContext: PaymentContext = {\n token,\n paymentRequired,\n creditsToSettle: creditsToVerify,\n verified: true,\n agentRequest: verification.agentRequest,\n agentRequestId: verification.agentRequest?.agentRequestId || verification.agentRequestId,\n }\n\n // Attach to request for potential use by route handler\n ;(req as Request & { paymentContext?: PaymentContext }).paymentContext = paymentContext\n\n // Override res.json to settle BEFORE sending response\n // This ensures credits are burned and payment-response header is included\n const originalJson = res.json.bind(res)\n res.json = function (body: unknown) {\n // Re-evaluate dynamic credits now that the handler has run and\n // res.locals is populated. For fixed (numeric) credits this is a no-op.\n const settlePromise = (\n typeof credits === 'function'\n ? Promise.resolve(credits(req, res))\n : Promise.resolve(creditsToVerify)\n ).then((creditsToSettle) => {\n // Update payment context so downstream consumers see the actual value\n paymentContext.creditsToSettle = creditsToSettle\n\n // Settle credits before sending response\n // Pass agentRequestId to enable observability updates\n return payments.facilitator\n .settlePermissions({\n paymentRequired,\n x402AccessToken: token,\n maxAmount: BigInt(creditsToSettle),\n agentRequestId: paymentContext.agentRequestId,\n })\n .then((settlement) => {\n // Add settlement response header (base64-encoded per x402 spec)\n const settlementBase64 = Buffer.from(JSON.stringify(settlement)).toString('base64')\n res.setHeader(X402_HEADERS.PAYMENT_RESPONSE, settlementBase64)\n\n // Hook: after settlement\n if (onAfterSettle) {\n return Promise.resolve(onAfterSettle(req, creditsToSettle, settlement)).then(\n () => settlement,\n )\n }\n return settlement\n })\n })\n\n settlePromise\n .catch((settleError) => {\n console.error('Payment settlement failed:', settleError)\n // Still send response even if settlement fails\n })\n .finally(() => {\n // Send the actual response after settlement completes\n originalJson(body)\n })\n\n // Return res for chaining (Express pattern)\n return res\n }\n\n // Continue to route handler\n next()\n } catch (error) {\n if (onPaymentError) {\n onPaymentError(error as Error, req, res)\n return\n }\n sendPaymentRequired(\n res,\n paymentRequired,\n error instanceof Error ? error.message : 'Payment verification failed',\n )\n }\n }\n\n // Execute async handler with error handling\n handleRequest().catch(next)\n }\n}\n\nexport default paymentMiddleware\n"]}
1
+ {"version":3,"file":"middleware.js","sourceRoot":"","sources":["../../../src/x402/express/middleware.ts"],"names":[],"mappings":"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","sourcesContent":["/**\n * Express middleware for Nevermined payment protection using the x402 protocol.\n *\n * This middleware provides a simple way to protect Express routes with\n * Nevermined payment verification and settlement.\n *\n * ## x402 HTTP Transport Headers\n *\n * Following the x402 spec (https://github.com/coinbase/x402/blob/main/specs/transports-v2/http.md):\n *\n * - **Client → Server**: `payment-signature` header with base64-encoded token\n * - **Server → Client (402)**: `payment-required` header with base64-encoded PaymentRequired\n * - **Server → Client (success)**: `payment-response` header with settlement receipt\n *\n * @example\n * ```typescript\n * import express from 'express'\n * import { Payments } from '@nevermined-io/payments'\n * import { paymentMiddleware } from '@nevermined-io/payments/express'\n *\n * const app = express()\n * const payments = Payments.getInstance({ nvmApiKey: '...', environment: 'testing' })\n *\n * // Protect routes with payment middleware\n * app.use(paymentMiddleware(payments, {\n * 'POST /ask': { planId: '123', credits: 1 },\n * 'POST /generate': { planId: '123', credits: 5 },\n * }))\n *\n * // Route handlers - no payment logic needed!\n * app.post('/ask', (req, res) => res.json({ answer: '...' }))\n * ```\n *\n * @example Client usage\n * ```typescript\n * const token = await payments.x402.getX402AccessToken(planId)\n *\n * const response = await fetch('/ask', {\n * method: 'POST',\n * headers: {\n * 'Content-Type': 'application/json',\n * 'payment-signature': token.accessToken, // x402 header\n * },\n * body: JSON.stringify({ query: 'Hello!' }),\n * })\n * ```\n */\n\nimport type { Request, Response, NextFunction } from 'express'\n\n/**\n * Express middleware function type.\n * Using explicit signature instead of RequestHandler to avoid type resolution issues\n * when SDK's \\@types/express version differs from consumer's.\n */\nexport type ExpressMiddleware = (req: Request, res: Response, next: NextFunction) => void\nimport type { Payments } from '../../payments.js'\nimport type { StartAgentRequest, X402SchemeType } from '../../common/types.js'\nimport {\n buildPaymentRequired,\n resolveScheme,\n type X402PaymentRequired,\n type VerifyPermissionsResult,\n} from '../facilitator-api.js'\n\n/**\n * Configuration for a protected route\n */\nexport interface RouteConfig {\n /** The Nevermined plan ID that protects this route */\n planId: string\n /** Number of credits to charge for this route (default: 1) */\n credits?: number | ((req: Request, res: Response) => number | Promise<number>)\n /** Optional agent ID */\n agentId?: string\n /** Network identifier (default: auto-derived from scheme) */\n network?: string\n /** x402 scheme override (auto-detected from plan metadata if omitted) */\n scheme?: X402SchemeType\n}\n\n/**\n * Route configuration map: \"METHOD \\/path\" -> RouteConfig\n */\nexport type RouteConfigMap = Record<string, RouteConfig>\n\n/**\n * x402 HTTP Transport header names (v2 spec)\n * @see https://github.com/coinbase/x402/blob/main/specs/transports-v2/http.md\n */\nexport const X402_HEADERS = {\n /** Client sends payment token in this header */\n PAYMENT_SIGNATURE: 'payment-signature',\n /** Server sends PaymentRequired in this header (base64-encoded) */\n PAYMENT_REQUIRED: 'payment-required',\n /** Server sends settlement receipt in this header (base64-encoded) */\n PAYMENT_RESPONSE: 'payment-response',\n} as const\n\n/**\n * Payment context attached to the request after verification.\n * Available as `req.paymentContext` in route handlers.\n */\nexport interface PaymentContext {\n /** The x402 access token */\n token: string\n /** The payment required object */\n paymentRequired: X402PaymentRequired\n /** Number of credits to settle */\n creditsToSettle: number\n /** Whether verification was successful */\n verified: boolean\n /** Agent request context for observability (from verification response) */\n agentRequest?: StartAgentRequest\n /** Agent request ID for observability tracking */\n agentRequestId?: string\n}\n\n/**\n * Options for the payment middleware\n */\nexport interface PaymentMiddlewareOptions {\n /**\n * Header name(s) to check for the x402 access token.\n * Default: 'payment-signature' (x402 v2 compliant)\n */\n tokenHeader?: string | string[]\n /** Custom error handler for payment failures */\n onPaymentError?: (error: Error, req: Request, res: Response) => void\n /** Hook called before verification */\n onBeforeVerify?: (req: Request, paymentRequired: X402PaymentRequired) => void | Promise<void>\n /**\n * Hook called after successful verification.\n * Use this to access agentRequest for observability configuration.\n */\n onAfterVerify?: (req: Request, verification: VerifyPermissionsResult) => void | Promise<void>\n /** Hook called after successful settlement */\n onAfterSettle?: (req: Request, creditsUsed: number, result: unknown) => void | Promise<void>\n}\n\n/**\n * Default header for token extraction (x402 v2 compliant)\n */\nconst DEFAULT_TOKEN_HEADERS = [X402_HEADERS.PAYMENT_SIGNATURE]\n\n/**\n * Extract the x402 access token from the request headers.\n * Checks multiple headers in priority order.\n */\nfunction extractToken(req: Request, headerNames: string | string[]): string | null {\n const headers = Array.isArray(headerNames) ? headerNames : [headerNames]\n\n for (const headerName of headers) {\n const header = req.headers[headerName.toLowerCase()]\n if (header && typeof header === 'string') {\n return header\n }\n }\n\n return null\n}\n\n/**\n * Match a request to a route config.\n * Returns the config if found, null otherwise.\n */\nfunction matchRoute(req: Request, routes: RouteConfigMap): RouteConfig | null {\n const method = req.method.toUpperCase()\n const path = req.path\n\n // Try exact match first: \"POST /ask\"\n const exactKey = `${method} ${path}`\n if (routes[exactKey]) {\n return routes[exactKey]\n }\n\n // Try pattern matching with path parameters\n for (const [routeKey, config] of Object.entries(routes)) {\n const [routeMethod, routePath] = routeKey.split(' ')\n if (routeMethod !== method) continue\n\n // Simple pattern matching: /users/:id -> /users/123\n const routeParts = routePath.split('/')\n const pathParts = path.split('/')\n\n if (routeParts.length !== pathParts.length) continue\n\n let match = true\n for (let i = 0; i < routeParts.length; i++) {\n if (routeParts[i].startsWith(':')) continue // Parameter - always matches\n if (routeParts[i] !== pathParts[i]) {\n match = false\n break\n }\n }\n\n if (match) return config\n }\n\n return null\n}\n\n/**\n * Create an Express middleware that protects routes with Nevermined payments.\n *\n * The middleware:\n * 1. Checks if the request matches a protected route\n * 2. Extracts the x402 token from headers\n * 3. Verifies the subscriber has sufficient credits\n * 4. Lets the route handler execute\n * 5. Settles (burns) the credits after successful response\n *\n * @param payments - The Payments instance\n * @param routes - Map of routes to protect: \\{ \"METHOD \\/path\": \\{ planId, credits \\} \\}\n * @param options - Optional middleware configuration\n * @returns Express middleware function\n *\n * @example\n * ```typescript\n * app.use(paymentMiddleware(payments, {\n * 'POST /ask': { planId: PLAN_ID, credits: 1 },\n * 'POST /generate': { planId: PLAN_ID, credits: 5 },\n * 'GET /status/:id': { planId: PLAN_ID, credits: 0 }, // Free but requires auth\n * }))\n * ```\n */\n/**\n * Helper to send a 402 Payment Required response with proper x402 headers.\n */\nfunction sendPaymentRequired(\n res: Response,\n paymentRequired: X402PaymentRequired,\n message: string,\n): void {\n // Base64 encode the PaymentRequired object for the header (per x402 spec)\n const paymentRequiredBase64 = Buffer.from(JSON.stringify(paymentRequired)).toString('base64')\n\n res.status(402).setHeader(X402_HEADERS.PAYMENT_REQUIRED, paymentRequiredBase64).json({\n error: 'Payment Required',\n message,\n })\n}\n\nexport function paymentMiddleware(\n payments: Payments,\n routes: RouteConfigMap,\n options: PaymentMiddlewareOptions = {},\n): ExpressMiddleware {\n const {\n tokenHeader = DEFAULT_TOKEN_HEADERS,\n onPaymentError,\n onBeforeVerify,\n onAfterVerify,\n onAfterSettle,\n } = options\n\n return (req: Request, res: Response, next: NextFunction): void => {\n // Wrap async logic to handle promises properly\n const handleRequest = async (): Promise<void> => {\n // Check if this route requires payment\n const routeConfig = matchRoute(req, routes)\n if (!routeConfig) {\n // Route not protected - pass through\n next()\n return\n }\n\n const { planId, credits = 1, agentId, network, scheme: explicitScheme } = routeConfig\n\n // Resolve scheme from plan metadata (cached) or explicit override\n const scheme = await resolveScheme(payments, planId, explicitScheme)\n\n // Build payment required object (needed for both error responses and verification)\n const paymentRequired = buildPaymentRequired(planId, {\n endpoint: req.originalUrl || req.url,\n agentId,\n httpVerb: req.method,\n network,\n scheme,\n environment: payments.getEnvironmentName(),\n })\n\n // Extract token from headers (x402 v2: payment-signature)\n const token = extractToken(req, tokenHeader)\n if (!token) {\n const error = new Error('Payment required: missing x402 access token')\n if (onPaymentError) {\n onPaymentError(error, req, res)\n return\n }\n sendPaymentRequired(\n res,\n paymentRequired,\n `Missing x402 payment token. Send token in ${X402_HEADERS.PAYMENT_SIGNATURE} header.`,\n )\n return\n }\n\n // Calculate credits to verify\n const creditsToVerify = typeof credits === 'function' ? await credits(req, res) : credits\n\n try {\n // Hook: before verification\n if (onBeforeVerify) {\n await onBeforeVerify(req, paymentRequired)\n }\n\n // Verify permissions\n const verification = await payments.facilitator.verifyPermissions({\n paymentRequired,\n x402AccessToken: token,\n maxAmount: BigInt(creditsToVerify),\n })\n\n if (!verification.isValid) {\n const error = new Error(verification.invalidReason || 'Payment verification failed')\n if (onPaymentError) {\n onPaymentError(error, req, res)\n return\n }\n sendPaymentRequired(\n res,\n paymentRequired,\n verification.invalidReason || 'Insufficient credits or invalid token',\n )\n return\n }\n\n // Hook: after verification (use for observability setup)\n if (onAfterVerify) {\n await onAfterVerify(req, verification)\n }\n\n // Store payment context for settlement and route handler access\n const paymentContext: PaymentContext = {\n token,\n paymentRequired,\n creditsToSettle: creditsToVerify,\n verified: true,\n agentRequest: verification.agentRequest,\n agentRequestId: verification.agentRequest?.agentRequestId || verification.agentRequestId,\n }\n\n // Attach to request for potential use by route handler\n ;(req as Request & { paymentContext?: PaymentContext }).paymentContext = paymentContext\n\n // Override res.json to settle BEFORE sending response\n // This ensures credits are burned and payment-response header is included\n const originalJson = res.json.bind(res)\n res.json = function (body: unknown) {\n // Re-evaluate dynamic credits now that the handler has run and\n // res.locals is populated. For fixed (numeric) credits this is a no-op.\n const settlePromise = (\n typeof credits === 'function'\n ? Promise.resolve(credits(req, res))\n : Promise.resolve(creditsToVerify)\n ).then((creditsToSettle) => {\n // Update payment context so downstream consumers see the actual value\n paymentContext.creditsToSettle = creditsToSettle\n\n // Settle credits before sending response\n // Pass agentRequestId to enable observability updates\n return payments.facilitator\n .settlePermissions({\n paymentRequired,\n x402AccessToken: token,\n maxAmount: BigInt(creditsToSettle),\n agentRequestId: paymentContext.agentRequestId,\n })\n .then((settlement) => {\n // Add settlement response header (base64-encoded per x402 spec)\n const settlementBase64 = Buffer.from(JSON.stringify(settlement)).toString('base64')\n res.setHeader(X402_HEADERS.PAYMENT_RESPONSE, settlementBase64)\n\n // Hook: after settlement\n if (onAfterSettle) {\n return Promise.resolve(onAfterSettle(req, creditsToSettle, settlement)).then(\n () => settlement,\n )\n }\n return settlement\n })\n })\n\n settlePromise\n .catch((settleError) => {\n console.error('Payment settlement failed:', settleError)\n // Still send response even if settlement fails\n })\n .finally(() => {\n // Send the actual response after settlement completes\n originalJson(body)\n })\n\n // Return res for chaining (Express pattern)\n return res\n }\n\n // Continue to route handler\n next()\n } catch (error) {\n if (onPaymentError) {\n onPaymentError(error as Error, req, res)\n return\n }\n sendPaymentRequired(\n res,\n paymentRequired,\n error instanceof Error ? error.message : 'Payment verification failed',\n )\n }\n }\n\n // Execute async handler with error handling\n handleRequest().catch(next)\n }\n}\n\nexport default paymentMiddleware\n"]}
@@ -42,6 +42,7 @@
42
42
  */
43
43
  import { BasePaymentsAPI } from '../api/base-payments.js';
44
44
  import { PaymentOptions, StartAgentRequest, X402SchemeType } from '../common/types.js';
45
+ import type { EnvironmentName } from '../environments.js';
45
46
  import type { Payments } from '../payments.js';
46
47
  import type { VisaPaymentRequired } from './visa-facilitator-api.js';
47
48
  /**
@@ -215,6 +216,7 @@ export declare function buildPaymentRequired(planId: string, options?: {
215
216
  network?: string;
216
217
  description?: string;
217
218
  scheme?: X402SchemeType;
219
+ environment?: EnvironmentName;
218
220
  }): X402PaymentRequired;
219
221
  /**
220
222
  * Resolve the x402 scheme for a plan by fetching plan metadata (cached).
@@ -1 +1 @@
1
- {"version":3,"file":"facilitator-api.d.ts","sourceRoot":"","sources":["../../src/x402/facilitator-api.ts"],"names":[],"mappings":"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"}
1
+ {"version":3,"file":"facilitator-api.d.ts","sourceRoot":"","sources":["../../src/x402/facilitator-api.ts"],"names":[],"mappings":"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"}
@@ -43,7 +43,7 @@
43
43
  import { BasePaymentsAPI } from '../api/base-payments.js';
44
44
  import { API_URL_SETTLE_PERMISSIONS, API_URL_VERIFY_PERMISSIONS } from '../api/nvm-api.js';
45
45
  import { PaymentsError } from '../common/payments.error.js';
46
- import { X402_SCHEME_NETWORKS } from '../common/types.js';
46
+ import { getDefaultNetwork } from '../common/types.js';
47
47
  /**
48
48
  * Build an X402PaymentRequired object for verify/settle operations.
49
49
  *
@@ -72,8 +72,8 @@ import { X402_SCHEME_NETWORKS } from '../common/types.js';
72
72
  * ```
73
73
  */
74
74
  export function buildPaymentRequired(planId, options) {
75
- const { endpoint, agentId, httpVerb, scheme = 'nvm:erc4337', network, description, } = options || {};
76
- const resolvedNetwork = network ?? X402_SCHEME_NETWORKS[scheme];
75
+ const { endpoint, agentId, httpVerb, scheme = 'nvm:erc4337', network, description, environment, } = options || {};
76
+ const resolvedNetwork = network ?? getDefaultNetwork(scheme, environment);
77
77
  // Build extra fields if any are provided
78
78
  const extra = agentId || httpVerb
79
79
  ? {
@@ -1 +1 @@
1
- {"version":3,"file":"facilitator-api.js","sourceRoot":"","sources":["../../src/x402/facilitator-api.ts"],"names":[],"mappings":"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","sourcesContent":["/**\n * The FacilitatorAPI class provides methods to verify and settle AI agent permissions using X402 access tokens.\n * This allows AI agents to act as facilitators, verifying and settling credits on behalf of subscribers.\n *\n * @example\n * ```typescript\n * import { Payments, X402PaymentRequired } from '@nevermined-io/payments'\n *\n * // Initialize the Payments instance\n * const payments = Payments.getInstance({\n * nvmApiKey: 'your-nvm-api-key',\n * environment: 'sandbox'\n * })\n *\n * // The server's 402 PaymentRequired response\n * const paymentRequired: X402PaymentRequired = buildPaymentRequired('123456789', {\n * endpoint: '/api/v1/agents/task',\n * agentId: '987654321',\n * httpVerb: 'POST'\n * })\n *\n * // Get X402 access token from subscriber (x402 v2: payment-signature header)\n * const x402Token = req.headers['payment-signature'] as string\n *\n * // Verify if subscriber has sufficient permissions/credits\n * const verification = await payments.facilitator.verifyPermissions({\n * paymentRequired,\n * x402AccessToken: x402Token,\n * maxAmount: 2n\n * })\n *\n * if (verification.isValid) {\n * // Settle (burn) the credits\n * const settlement = await payments.facilitator.settlePermissions({\n * paymentRequired,\n * x402AccessToken: x402Token,\n * maxAmount: 2n\n * })\n * console.log(`Credits redeemed: ${settlement.creditsRedeemed}`)\n * }\n * ```\n */\n\nimport { BasePaymentsAPI } from '../api/base-payments.js'\nimport { API_URL_SETTLE_PERMISSIONS, API_URL_VERIFY_PERMISSIONS } from '../api/nvm-api.js'\nimport { PaymentsError } from '../common/payments.error.js'\nimport { PaymentOptions, StartAgentRequest, X402SchemeType, X402_SCHEME_NETWORKS } from '../common/types.js'\nimport type { Payments } from '../payments.js'\nimport type { VisaPaymentRequired } from './visa-facilitator-api.js'\n\n/**\n * x402 Resource information\n */\nexport interface X402Resource {\n /** The protected resource URL */\n url: string\n /** Human-readable description */\n description?: string\n /** Expected response MIME type (e.g., \"application/json\") */\n mimeType?: string\n}\n\n/**\n * x402 Scheme extra fields for nvm:erc4337\n */\nexport interface X402SchemeExtra {\n /** Scheme version (e.g., \"1\") */\n version?: string\n /** Agent identifier */\n agentId?: string\n /** HTTP method for the endpoint */\n httpVerb?: string\n}\n\n/**\n * x402 Scheme definition (nvm:erc4337)\n */\nexport interface X402Scheme {\n /** Payment scheme identifier (e.g., \"nvm:erc4337\") */\n scheme: string\n /** Blockchain network in CAIP-2 format (e.g., \"eip155:84532\") */\n network: string\n /** 256-bit plan identifier */\n planId: string\n /** Scheme-specific extra fields */\n extra?: X402SchemeExtra\n}\n\n/**\n * x402 PaymentRequired response (402 response from server)\n */\nexport interface X402PaymentRequired {\n /** x402 protocol version (always 2) */\n x402Version: number\n /** Human-readable error message */\n error?: string\n /** Protected resource information */\n resource: X402Resource\n /** Array of accepted payment schemes */\n accepts: X402Scheme[]\n /** Extensions object (empty object for nvm:erc4337) */\n extensions: Record<string, unknown>\n}\n\n/**\n * x402 PaymentAccepted response (accepted payment scheme)\n */\nexport interface X402PaymentAccepted {\n /** The x402 version */\n x402Version: number\n /** The accepted payment scheme (nvm:erc4337) */\n accepted: X402Scheme\n /** The payload of the payment accepted */\n payload: {\n signature: string\n authorization: {\n from: string\n sessionKeysProvider: string\n sessionKeys: string[]\n }\n }\n extensions: Record<string, unknown>\n}\n\n/**\n * Parameters for verifying permissions\n */\nexport interface VerifyPermissionsParams {\n /** The server's 402 PaymentRequired response (NVM or Visa flavored) */\n paymentRequired: X402PaymentRequired | VisaPaymentRequired\n /** The X402 access token (base64-encoded) */\n x402AccessToken: string\n /** Maximum credits to verify (optional) */\n maxAmount?: bigint\n}\n\n/**\n * x402 Verify Response - per x402 facilitator spec\n * @see https://github.com/coinbase/x402/blob/main/specs/x402-specification-v2.md\n */\nexport interface VerifyPermissionsResult {\n /** Whether the payment authorization is valid */\n isValid: boolean\n /** Reason for invalidity (only present if isValid is false) */\n invalidReason?: string\n /** Address of the payer's wallet */\n payer?: string\n /** Agent request ID for observability tracking (Nevermined extension) */\n agentRequestId?: string\n /** URL pattern that matched the endpoint (Nevermined extension) */\n urlMatching?: string\n /** Agent request context for observability (Nevermined extension) */\n agentRequest?: StartAgentRequest\n}\n\n/**\n * Parameters for settling permissions\n */\nexport interface SettlePermissionsParams {\n /** The server's 402 PaymentRequired response (NVM or Visa flavored) */\n paymentRequired: X402PaymentRequired | VisaPaymentRequired\n /** The X402 access token (base64-encoded) */\n x402AccessToken: string\n /** Number of credits to burn (optional) */\n maxAmount?: bigint\n /** Agent request ID for observability tracking. Returned by verifyPermissions. */\n agentRequestId?: string\n /** Whether this is a batch request (multiple LLM calls under one agentRequestId) */\n batch?: boolean\n /** Margin percentage (0-10) for credit calculation. Mutually exclusive with maxAmount when agentRequestId provided. */\n marginPercent?: number\n}\n\n/**\n * x402 Settle Response - per x402 facilitator spec\n * @see https://github.com/coinbase/x402/blob/main/specs/x402-specification-v2.md\n */\nexport interface SettlePermissionsResult {\n /** Whether settlement was successful */\n success: boolean\n /** Reason for settlement failure (only present if success is false) */\n errorReason?: string\n /** Address of the payer's wallet */\n payer?: string\n /** Blockchain transaction hash (empty string if settlement failed) */\n transaction: string\n /** Blockchain network identifier in CAIP-2 format */\n network: string\n /** Number of credits redeemed (Nevermined extension) */\n creditsRedeemed?: string\n /** Subscriber's remaining balance (Nevermined extension) */\n remainingBalance?: string\n /** Transaction hash of the order operation if auto top-up occurred (Nevermined extension) */\n orderTx?: string\n}\n\n/**\n * Build an X402PaymentRequired object for verify/settle operations.\n *\n * This helper simplifies the creation of payment requirement objects\n * that are needed for the facilitator API.\n *\n * @param planId - The Nevermined plan identifier (required)\n * @param options - Optional configuration with endpoint, agentId, httpVerb, network, description\n * @returns X402PaymentRequired object ready to use with verifyPermissions/settlePermissions\n *\n * @example\n * ```typescript\n * import { buildPaymentRequired } from '@nevermined-io/payments'\n *\n * const paymentRequired = buildPaymentRequired('123456789', {\n * endpoint: '/api/v1/agents/task',\n * agentId: '987654321',\n * httpVerb: 'POST'\n * })\n *\n * const result = await payments.facilitator.verifyPermissions({\n * paymentRequired,\n * x402AccessToken: token,\n * maxAmount: 2n\n * })\n * ```\n */\nexport function buildPaymentRequired(\n planId: string,\n options?: {\n endpoint?: string\n agentId?: string\n httpVerb?: string\n network?: string\n description?: string\n scheme?: X402SchemeType\n },\n): X402PaymentRequired {\n const {\n endpoint,\n agentId,\n httpVerb,\n scheme = 'nvm:erc4337',\n network,\n description,\n } = options || {}\n const resolvedNetwork = network ?? X402_SCHEME_NETWORKS[scheme]\n\n // Build extra fields if any are provided\n const extra: X402SchemeExtra | undefined =\n agentId || httpVerb\n ? {\n ...(agentId && { agentId }),\n ...(httpVerb && { httpVerb }),\n }\n : undefined\n\n return {\n x402Version: 2,\n resource: {\n url: endpoint || '',\n ...(description && { description }),\n },\n accepts: [\n {\n scheme,\n network: resolvedNetwork,\n planId,\n ...(extra && { extra }),\n },\n ],\n extensions: {},\n }\n}\n\ninterface CachedPlanMetadata {\n scheme: X402SchemeType\n cachedAt: number\n}\n\nconst CACHE_TTL_MS = 5 * 60 * 1000 // 5 minutes\nconst planMetadataCache = new Map<string, CachedPlanMetadata>()\n\nasync function fetchPlanMetadata(\n payments: Payments,\n planId: string,\n): Promise<{ scheme: X402SchemeType }> {\n const cached = planMetadataCache.get(planId)\n if (cached && Date.now() - cached.cachedAt < CACHE_TTL_MS) {\n return { scheme: cached.scheme }\n }\n try {\n const plan = await payments.plans.getPlan(planId)\n const isCrypto = plan.registry?.price?.isCrypto\n const scheme: X402SchemeType =\n isCrypto === false ? 'nvm:card-delegation' : 'nvm:erc4337'\n planMetadataCache.set(planId, { scheme, cachedAt: Date.now() })\n return { scheme }\n } catch {\n return { scheme: 'nvm:erc4337' }\n }\n}\n\n/**\n * Resolve the x402 scheme for a plan by fetching plan metadata (cached).\n * Used in callsites that don't have a token to extract scheme from\n * (402 responses and token generation).\n *\n * @param payments - The Payments instance for API access\n * @param planId - The plan identifier\n * @param explicitScheme - Optional explicit override; returned immediately if provided\n * @returns The resolved scheme type\n */\nexport async function resolveScheme(\n payments: Payments,\n planId: string,\n explicitScheme?: X402SchemeType,\n): Promise<X402SchemeType> {\n if (explicitScheme) return explicitScheme\n const metadata = await fetchPlanMetadata(payments, planId)\n return metadata.scheme\n}\n\n/**\n * The FacilitatorAPI class provides methods to verify and settle AI agent permissions.\n * It enables AI agents to act as facilitators, managing credit verification and settlement\n * for subscribers using X402 access tokens.\n */\nexport class FacilitatorAPI extends BasePaymentsAPI {\n /**\n * Get a singleton instance of the FacilitatorAPI class.\n *\n * @param options - The options to initialize the payments class\n * @returns The instance of the FacilitatorAPI class\n */\n static getInstance(options: PaymentOptions): FacilitatorAPI {\n return new FacilitatorAPI(options)\n }\n\n /**\n * Verify if a subscriber has permission to use credits from a payment plan.\n * This method simulates the credit usage without actually burning credits,\n * checking if the subscriber has sufficient balance and permissions.\n *\n * The planId and subscriberAddress are extracted from the x402AccessToken.\n *\n * @param params - Verification parameters (see {@link VerifyPermissionsParams}).\n * - paymentRequired: x402 PaymentRequired from 402 response (required, for validation)\n * - x402AccessToken: X402 access token (contains planId, subscriberAddress, agentId)\n * - maxAmount: maximum credits to verify (optional, bigint)\n * @returns A promise that resolves to a verification result with 'isValid' boolean\n *\n * @throws PaymentsError if verification fails\n */\n async verifyPermissions(params: VerifyPermissionsParams): Promise<VerifyPermissionsResult> {\n const { paymentRequired, x402AccessToken, maxAmount } = params\n\n const url = new URL(API_URL_VERIFY_PERMISSIONS, this.environment.backend)\n\n const body: Record<string, unknown> = {\n paymentRequired,\n x402AccessToken,\n }\n\n if (maxAmount !== undefined) {\n body.maxAmount = maxAmount.toString()\n }\n\n const options = this.getPublicHTTPOptions('POST', body)\n\n try {\n const response = await fetch(url, options)\n if (!response.ok) {\n let errorMessage = 'Permission verification failed'\n try {\n const errorData = await response.json()\n errorMessage = errorData.message || errorMessage\n } catch {\n // Use default error message\n }\n throw PaymentsError.fromBackend(errorMessage, {\n message: errorMessage,\n code: `HTTP ${response.status}`,\n })\n }\n return await response.json()\n } catch (error) {\n if (error instanceof PaymentsError) {\n throw error\n }\n throw PaymentsError.fromBackend('Network error during permission verification', {\n message: error instanceof Error ? error.message : String(error),\n code: 'network_error',\n })\n }\n }\n\n /**\n * Settle (burn) credits from a subscriber's payment plan.\n * This method executes the actual credit consumption, burning the specified\n * number of credits from the subscriber's balance. If the subscriber doesn't\n * have enough credits, it will attempt to order more before settling.\n *\n * The planId and subscriberAddress are extracted from the x402AccessToken.\n *\n * @param params - Settlement parameters (see {@link SettlePermissionsParams}).\n * - paymentRequired: x402 PaymentRequired from 402 response (required, for validation)\n * - x402AccessToken: X402 access token (contains planId, subscriberAddress, agentId)\n * - maxAmount: number of credits to burn (optional, bigint)\n * - agentRequestId: Agent request ID for observability tracking (optional)\n * - batch: Whether this is a batch request (optional)\n * - marginPercent: Margin percentage for credit calculation (optional)\n * @returns A promise that resolves to a settlement result with transaction details\n *\n * @throws PaymentsError if settlement fails\n */\n async settlePermissions(params: SettlePermissionsParams): Promise<SettlePermissionsResult> {\n const { paymentRequired, x402AccessToken, maxAmount, agentRequestId, batch, marginPercent } =\n params\n\n const url = new URL(API_URL_SETTLE_PERMISSIONS, this.environment.backend)\n\n const body: Record<string, unknown> = {\n paymentRequired,\n x402AccessToken,\n }\n\n if (maxAmount !== undefined) {\n body.maxAmount = maxAmount.toString()\n }\n if (agentRequestId !== undefined) {\n body.agentRequestId = agentRequestId\n }\n if (batch !== undefined) {\n body.batch = batch\n }\n if (marginPercent !== undefined) {\n body.marginPercent = marginPercent\n }\n\n const options = this.getPublicHTTPOptions('POST', body)\n\n try {\n const response = await fetch(url, options)\n if (!response.ok) {\n let errorMessage = 'Permission settlement failed'\n try {\n const errorData = await response.json()\n errorMessage = errorData.message || errorMessage\n } catch {\n // Use default error message\n }\n throw PaymentsError.fromBackend(errorMessage, {\n message: errorMessage,\n code: `HTTP ${response.status}`,\n })\n }\n return await response.json()\n } catch (error) {\n if (error instanceof PaymentsError) {\n throw error\n }\n throw PaymentsError.fromBackend('Network error during permission settlement', {\n message: error instanceof Error ? error.message : String(error),\n code: 'network_error',\n })\n }\n }\n}\n"]}
1
+ {"version":3,"file":"facilitator-api.js","sourceRoot":"","sources":["../../src/x402/facilitator-api.ts"],"names":[],"mappings":"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","sourcesContent":["/**\n * The FacilitatorAPI class provides methods to verify and settle AI agent permissions using X402 access tokens.\n * This allows AI agents to act as facilitators, verifying and settling credits on behalf of subscribers.\n *\n * @example\n * ```typescript\n * import { Payments, X402PaymentRequired } from '@nevermined-io/payments'\n *\n * // Initialize the Payments instance\n * const payments = Payments.getInstance({\n * nvmApiKey: 'your-nvm-api-key',\n * environment: 'sandbox'\n * })\n *\n * // The server's 402 PaymentRequired response\n * const paymentRequired: X402PaymentRequired = buildPaymentRequired('123456789', {\n * endpoint: '/api/v1/agents/task',\n * agentId: '987654321',\n * httpVerb: 'POST'\n * })\n *\n * // Get X402 access token from subscriber (x402 v2: payment-signature header)\n * const x402Token = req.headers['payment-signature'] as string\n *\n * // Verify if subscriber has sufficient permissions/credits\n * const verification = await payments.facilitator.verifyPermissions({\n * paymentRequired,\n * x402AccessToken: x402Token,\n * maxAmount: 2n\n * })\n *\n * if (verification.isValid) {\n * // Settle (burn) the credits\n * const settlement = await payments.facilitator.settlePermissions({\n * paymentRequired,\n * x402AccessToken: x402Token,\n * maxAmount: 2n\n * })\n * console.log(`Credits redeemed: ${settlement.creditsRedeemed}`)\n * }\n * ```\n */\n\nimport { BasePaymentsAPI } from '../api/base-payments.js'\nimport { API_URL_SETTLE_PERMISSIONS, API_URL_VERIFY_PERMISSIONS } from '../api/nvm-api.js'\nimport { PaymentsError } from '../common/payments.error.js'\nimport { PaymentOptions, StartAgentRequest, X402SchemeType, getDefaultNetwork } from '../common/types.js'\nimport type { EnvironmentName } from '../environments.js'\nimport type { Payments } from '../payments.js'\nimport type { VisaPaymentRequired } from './visa-facilitator-api.js'\n\n/**\n * x402 Resource information\n */\nexport interface X402Resource {\n /** The protected resource URL */\n url: string\n /** Human-readable description */\n description?: string\n /** Expected response MIME type (e.g., \"application/json\") */\n mimeType?: string\n}\n\n/**\n * x402 Scheme extra fields for nvm:erc4337\n */\nexport interface X402SchemeExtra {\n /** Scheme version (e.g., \"1\") */\n version?: string\n /** Agent identifier */\n agentId?: string\n /** HTTP method for the endpoint */\n httpVerb?: string\n}\n\n/**\n * x402 Scheme definition (nvm:erc4337)\n */\nexport interface X402Scheme {\n /** Payment scheme identifier (e.g., \"nvm:erc4337\") */\n scheme: string\n /** Blockchain network in CAIP-2 format (e.g., \"eip155:84532\") */\n network: string\n /** 256-bit plan identifier */\n planId: string\n /** Scheme-specific extra fields */\n extra?: X402SchemeExtra\n}\n\n/**\n * x402 PaymentRequired response (402 response from server)\n */\nexport interface X402PaymentRequired {\n /** x402 protocol version (always 2) */\n x402Version: number\n /** Human-readable error message */\n error?: string\n /** Protected resource information */\n resource: X402Resource\n /** Array of accepted payment schemes */\n accepts: X402Scheme[]\n /** Extensions object (empty object for nvm:erc4337) */\n extensions: Record<string, unknown>\n}\n\n/**\n * x402 PaymentAccepted response (accepted payment scheme)\n */\nexport interface X402PaymentAccepted {\n /** The x402 version */\n x402Version: number\n /** The accepted payment scheme (nvm:erc4337) */\n accepted: X402Scheme\n /** The payload of the payment accepted */\n payload: {\n signature: string\n authorization: {\n from: string\n sessionKeysProvider: string\n sessionKeys: string[]\n }\n }\n extensions: Record<string, unknown>\n}\n\n/**\n * Parameters for verifying permissions\n */\nexport interface VerifyPermissionsParams {\n /** The server's 402 PaymentRequired response (NVM or Visa flavored) */\n paymentRequired: X402PaymentRequired | VisaPaymentRequired\n /** The X402 access token (base64-encoded) */\n x402AccessToken: string\n /** Maximum credits to verify (optional) */\n maxAmount?: bigint\n}\n\n/**\n * x402 Verify Response - per x402 facilitator spec\n * @see https://github.com/coinbase/x402/blob/main/specs/x402-specification-v2.md\n */\nexport interface VerifyPermissionsResult {\n /** Whether the payment authorization is valid */\n isValid: boolean\n /** Reason for invalidity (only present if isValid is false) */\n invalidReason?: string\n /** Address of the payer's wallet */\n payer?: string\n /** Agent request ID for observability tracking (Nevermined extension) */\n agentRequestId?: string\n /** URL pattern that matched the endpoint (Nevermined extension) */\n urlMatching?: string\n /** Agent request context for observability (Nevermined extension) */\n agentRequest?: StartAgentRequest\n}\n\n/**\n * Parameters for settling permissions\n */\nexport interface SettlePermissionsParams {\n /** The server's 402 PaymentRequired response (NVM or Visa flavored) */\n paymentRequired: X402PaymentRequired | VisaPaymentRequired\n /** The X402 access token (base64-encoded) */\n x402AccessToken: string\n /** Number of credits to burn (optional) */\n maxAmount?: bigint\n /** Agent request ID for observability tracking. Returned by verifyPermissions. */\n agentRequestId?: string\n /** Whether this is a batch request (multiple LLM calls under one agentRequestId) */\n batch?: boolean\n /** Margin percentage (0-10) for credit calculation. Mutually exclusive with maxAmount when agentRequestId provided. */\n marginPercent?: number\n}\n\n/**\n * x402 Settle Response - per x402 facilitator spec\n * @see https://github.com/coinbase/x402/blob/main/specs/x402-specification-v2.md\n */\nexport interface SettlePermissionsResult {\n /** Whether settlement was successful */\n success: boolean\n /** Reason for settlement failure (only present if success is false) */\n errorReason?: string\n /** Address of the payer's wallet */\n payer?: string\n /** Blockchain transaction hash (empty string if settlement failed) */\n transaction: string\n /** Blockchain network identifier in CAIP-2 format */\n network: string\n /** Number of credits redeemed (Nevermined extension) */\n creditsRedeemed?: string\n /** Subscriber's remaining balance (Nevermined extension) */\n remainingBalance?: string\n /** Transaction hash of the order operation if auto top-up occurred (Nevermined extension) */\n orderTx?: string\n}\n\n/**\n * Build an X402PaymentRequired object for verify/settle operations.\n *\n * This helper simplifies the creation of payment requirement objects\n * that are needed for the facilitator API.\n *\n * @param planId - The Nevermined plan identifier (required)\n * @param options - Optional configuration with endpoint, agentId, httpVerb, network, description\n * @returns X402PaymentRequired object ready to use with verifyPermissions/settlePermissions\n *\n * @example\n * ```typescript\n * import { buildPaymentRequired } from '@nevermined-io/payments'\n *\n * const paymentRequired = buildPaymentRequired('123456789', {\n * endpoint: '/api/v1/agents/task',\n * agentId: '987654321',\n * httpVerb: 'POST'\n * })\n *\n * const result = await payments.facilitator.verifyPermissions({\n * paymentRequired,\n * x402AccessToken: token,\n * maxAmount: 2n\n * })\n * ```\n */\nexport function buildPaymentRequired(\n planId: string,\n options?: {\n endpoint?: string\n agentId?: string\n httpVerb?: string\n network?: string\n description?: string\n scheme?: X402SchemeType\n environment?: EnvironmentName\n },\n): X402PaymentRequired {\n const {\n endpoint,\n agentId,\n httpVerb,\n scheme = 'nvm:erc4337',\n network,\n description,\n environment,\n } = options || {}\n const resolvedNetwork = network ?? getDefaultNetwork(scheme, environment)\n\n // Build extra fields if any are provided\n const extra: X402SchemeExtra | undefined =\n agentId || httpVerb\n ? {\n ...(agentId && { agentId }),\n ...(httpVerb && { httpVerb }),\n }\n : undefined\n\n return {\n x402Version: 2,\n resource: {\n url: endpoint || '',\n ...(description && { description }),\n },\n accepts: [\n {\n scheme,\n network: resolvedNetwork,\n planId,\n ...(extra && { extra }),\n },\n ],\n extensions: {},\n }\n}\n\ninterface CachedPlanMetadata {\n scheme: X402SchemeType\n cachedAt: number\n}\n\nconst CACHE_TTL_MS = 5 * 60 * 1000 // 5 minutes\nconst planMetadataCache = new Map<string, CachedPlanMetadata>()\n\nasync function fetchPlanMetadata(\n payments: Payments,\n planId: string,\n): Promise<{ scheme: X402SchemeType }> {\n const cached = planMetadataCache.get(planId)\n if (cached && Date.now() - cached.cachedAt < CACHE_TTL_MS) {\n return { scheme: cached.scheme }\n }\n try {\n const plan = await payments.plans.getPlan(planId)\n const isCrypto = plan.registry?.price?.isCrypto\n const scheme: X402SchemeType =\n isCrypto === false ? 'nvm:card-delegation' : 'nvm:erc4337'\n planMetadataCache.set(planId, { scheme, cachedAt: Date.now() })\n return { scheme }\n } catch {\n return { scheme: 'nvm:erc4337' }\n }\n}\n\n/**\n * Resolve the x402 scheme for a plan by fetching plan metadata (cached).\n * Used in callsites that don't have a token to extract scheme from\n * (402 responses and token generation).\n *\n * @param payments - The Payments instance for API access\n * @param planId - The plan identifier\n * @param explicitScheme - Optional explicit override; returned immediately if provided\n * @returns The resolved scheme type\n */\nexport async function resolveScheme(\n payments: Payments,\n planId: string,\n explicitScheme?: X402SchemeType,\n): Promise<X402SchemeType> {\n if (explicitScheme) return explicitScheme\n const metadata = await fetchPlanMetadata(payments, planId)\n return metadata.scheme\n}\n\n/**\n * The FacilitatorAPI class provides methods to verify and settle AI agent permissions.\n * It enables AI agents to act as facilitators, managing credit verification and settlement\n * for subscribers using X402 access tokens.\n */\nexport class FacilitatorAPI extends BasePaymentsAPI {\n /**\n * Get a singleton instance of the FacilitatorAPI class.\n *\n * @param options - The options to initialize the payments class\n * @returns The instance of the FacilitatorAPI class\n */\n static getInstance(options: PaymentOptions): FacilitatorAPI {\n return new FacilitatorAPI(options)\n }\n\n /**\n * Verify if a subscriber has permission to use credits from a payment plan.\n * This method simulates the credit usage without actually burning credits,\n * checking if the subscriber has sufficient balance and permissions.\n *\n * The planId and subscriberAddress are extracted from the x402AccessToken.\n *\n * @param params - Verification parameters (see {@link VerifyPermissionsParams}).\n * - paymentRequired: x402 PaymentRequired from 402 response (required, for validation)\n * - x402AccessToken: X402 access token (contains planId, subscriberAddress, agentId)\n * - maxAmount: maximum credits to verify (optional, bigint)\n * @returns A promise that resolves to a verification result with 'isValid' boolean\n *\n * @throws PaymentsError if verification fails\n */\n async verifyPermissions(params: VerifyPermissionsParams): Promise<VerifyPermissionsResult> {\n const { paymentRequired, x402AccessToken, maxAmount } = params\n\n const url = new URL(API_URL_VERIFY_PERMISSIONS, this.environment.backend)\n\n const body: Record<string, unknown> = {\n paymentRequired,\n x402AccessToken,\n }\n\n if (maxAmount !== undefined) {\n body.maxAmount = maxAmount.toString()\n }\n\n const options = this.getPublicHTTPOptions('POST', body)\n\n try {\n const response = await fetch(url, options)\n if (!response.ok) {\n let errorMessage = 'Permission verification failed'\n try {\n const errorData = await response.json()\n errorMessage = errorData.message || errorMessage\n } catch {\n // Use default error message\n }\n throw PaymentsError.fromBackend(errorMessage, {\n message: errorMessage,\n code: `HTTP ${response.status}`,\n })\n }\n return await response.json()\n } catch (error) {\n if (error instanceof PaymentsError) {\n throw error\n }\n throw PaymentsError.fromBackend('Network error during permission verification', {\n message: error instanceof Error ? error.message : String(error),\n code: 'network_error',\n })\n }\n }\n\n /**\n * Settle (burn) credits from a subscriber's payment plan.\n * This method executes the actual credit consumption, burning the specified\n * number of credits from the subscriber's balance. If the subscriber doesn't\n * have enough credits, it will attempt to order more before settling.\n *\n * The planId and subscriberAddress are extracted from the x402AccessToken.\n *\n * @param params - Settlement parameters (see {@link SettlePermissionsParams}).\n * - paymentRequired: x402 PaymentRequired from 402 response (required, for validation)\n * - x402AccessToken: X402 access token (contains planId, subscriberAddress, agentId)\n * - maxAmount: number of credits to burn (optional, bigint)\n * - agentRequestId: Agent request ID for observability tracking (optional)\n * - batch: Whether this is a batch request (optional)\n * - marginPercent: Margin percentage for credit calculation (optional)\n * @returns A promise that resolves to a settlement result with transaction details\n *\n * @throws PaymentsError if settlement fails\n */\n async settlePermissions(params: SettlePermissionsParams): Promise<SettlePermissionsResult> {\n const { paymentRequired, x402AccessToken, maxAmount, agentRequestId, batch, marginPercent } =\n params\n\n const url = new URL(API_URL_SETTLE_PERMISSIONS, this.environment.backend)\n\n const body: Record<string, unknown> = {\n paymentRequired,\n x402AccessToken,\n }\n\n if (maxAmount !== undefined) {\n body.maxAmount = maxAmount.toString()\n }\n if (agentRequestId !== undefined) {\n body.agentRequestId = agentRequestId\n }\n if (batch !== undefined) {\n body.batch = batch\n }\n if (marginPercent !== undefined) {\n body.marginPercent = marginPercent\n }\n\n const options = this.getPublicHTTPOptions('POST', body)\n\n try {\n const response = await fetch(url, options)\n if (!response.ok) {\n let errorMessage = 'Permission settlement failed'\n try {\n const errorData = await response.json()\n errorMessage = errorData.message || errorMessage\n } catch {\n // Use default error message\n }\n throw PaymentsError.fromBackend(errorMessage, {\n message: errorMessage,\n code: `HTTP ${response.status}`,\n })\n }\n return await response.json()\n } catch (error) {\n if (error instanceof PaymentsError) {\n throw error\n }\n throw PaymentsError.fromBackend('Network error during permission settlement', {\n message: error instanceof Error ? error.message : String(error),\n code: 'network_error',\n })\n }\n }\n}\n"]}
@@ -7,7 +7,7 @@ export type { X402Resource, X402SchemeExtra, X402Scheme, X402PaymentRequired, X4
7
7
  export { DelegationAPI } from './delegation-api.js';
8
8
  export type { PaymentMethodSummary } from './delegation-api.js';
9
9
  export type { X402SchemeType, CardDelegationConfig, X402TokenOptions } from '../common/types.js';
10
- export { X402_SCHEME_NETWORKS, isValidScheme } from '../common/types.js';
10
+ export { X402_SCHEME_NETWORKS, getDefaultNetwork, isValidScheme } from '../common/types.js';
11
11
  export { VisaFacilitatorAPI, buildVisaPaymentRequired, VISA_X402_HEADERS } from './visa-facilitator-api.js';
12
12
  export type { VisaPaymentExtra, VisaPaymentRequirements, VisaPaymentRequired, VisaVerifyResponse, VisaSettlementResponse, } from './visa-facilitator-api.js';
13
13
  export { VisaTokenAPI } from './visa-token-api.js';
@@ -1 +1 @@
1
- {"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../src/x402/index.ts"],"names":[],"mappings":"AAAA;;GAEG;AAEH,OAAO,EAAE,YAAY,EAAE,MAAM,YAAY,CAAA;AACzC,OAAO,EAAE,cAAc,EAAE,oBAAoB,EAAE,aAAa,EAAE,MAAM,sBAAsB,CAAA;AAC1F,YAAY,EAEV,YAAY,EACZ,eAAe,EACf,UAAU,EACV,mBAAmB,EACnB,mBAAmB,EAEnB,uBAAuB,EACvB,uBAAuB,EACvB,uBAAuB,EACvB,uBAAuB,GACxB,MAAM,sBAAsB,CAAA;AAG7B,OAAO,EAAE,aAAa,EAAE,MAAM,qBAAqB,CAAA;AACnD,YAAY,EAAE,oBAAoB,EAAE,MAAM,qBAAqB,CAAA;AAG/D,YAAY,EAAE,cAAc,EAAE,oBAAoB,EAAE,gBAAgB,EAAE,MAAM,oBAAoB,CAAA;AAChG,OAAO,EAAE,oBAAoB,EAAE,aAAa,EAAE,MAAM,oBAAoB,CAAA;AAGxE,OAAO,EAAE,kBAAkB,EAAE,wBAAwB,EAAE,iBAAiB,EAAE,MAAM,2BAA2B,CAAA;AAC3G,YAAY,EACV,gBAAgB,EAChB,uBAAuB,EACvB,mBAAmB,EACnB,kBAAkB,EAClB,sBAAsB,GACvB,MAAM,2BAA2B,CAAA;AAClC,OAAO,EAAE,YAAY,EAAE,MAAM,qBAAqB,CAAA;AAClD,YAAY,EAAE,0BAA0B,EAAE,MAAM,qBAAqB,CAAA"}
1
+ {"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../src/x402/index.ts"],"names":[],"mappings":"AAAA;;GAEG;AAEH,OAAO,EAAE,YAAY,EAAE,MAAM,YAAY,CAAA;AACzC,OAAO,EAAE,cAAc,EAAE,oBAAoB,EAAE,aAAa,EAAE,MAAM,sBAAsB,CAAA;AAC1F,YAAY,EAEV,YAAY,EACZ,eAAe,EACf,UAAU,EACV,mBAAmB,EACnB,mBAAmB,EAEnB,uBAAuB,EACvB,uBAAuB,EACvB,uBAAuB,EACvB,uBAAuB,GACxB,MAAM,sBAAsB,CAAA;AAG7B,OAAO,EAAE,aAAa,EAAE,MAAM,qBAAqB,CAAA;AACnD,YAAY,EAAE,oBAAoB,EAAE,MAAM,qBAAqB,CAAA;AAG/D,YAAY,EAAE,cAAc,EAAE,oBAAoB,EAAE,gBAAgB,EAAE,MAAM,oBAAoB,CAAA;AAChG,OAAO,EAAE,oBAAoB,EAAE,iBAAiB,EAAE,aAAa,EAAE,MAAM,oBAAoB,CAAA;AAG3F,OAAO,EAAE,kBAAkB,EAAE,wBAAwB,EAAE,iBAAiB,EAAE,MAAM,2BAA2B,CAAA;AAC3G,YAAY,EACV,gBAAgB,EAChB,uBAAuB,EACvB,mBAAmB,EACnB,kBAAkB,EAClB,sBAAsB,GACvB,MAAM,2BAA2B,CAAA;AAClC,OAAO,EAAE,YAAY,EAAE,MAAM,qBAAqB,CAAA;AAClD,YAAY,EAAE,0BAA0B,EAAE,MAAM,qBAAqB,CAAA"}