@nevermined-io/payments 1.7.0 → 1.8.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (64) hide show
  1. package/dist/a2a/agent-card.d.ts +26 -0
  2. package/dist/a2a/agent-card.d.ts.map +1 -1
  3. package/dist/a2a/agent-card.js +36 -1
  4. package/dist/a2a/agent-card.js.map +1 -1
  5. package/dist/a2a/paymentsClient.d.ts +41 -1
  6. package/dist/a2a/paymentsClient.d.ts.map +1 -1
  7. package/dist/a2a/paymentsClient.js +120 -8
  8. package/dist/a2a/paymentsClient.js.map +1 -1
  9. package/dist/a2a/paymentsRequestHandler.d.ts +25 -2
  10. package/dist/a2a/paymentsRequestHandler.d.ts.map +1 -1
  11. package/dist/a2a/paymentsRequestHandler.js +240 -20
  12. package/dist/a2a/paymentsRequestHandler.js.map +1 -1
  13. package/dist/a2a/server.d.ts +2 -2
  14. package/dist/a2a/server.d.ts.map +1 -1
  15. package/dist/a2a/server.js +70 -20
  16. package/dist/a2a/server.js.map +1 -1
  17. package/dist/a2a/types.d.ts +31 -1
  18. package/dist/a2a/types.d.ts.map +1 -1
  19. package/dist/a2a/types.js.map +1 -1
  20. package/dist/a2a/x402-a2a.d.ts +142 -0
  21. package/dist/a2a/x402-a2a.d.ts.map +1 -0
  22. package/dist/a2a/x402-a2a.js +254 -0
  23. package/dist/a2a/x402-a2a.js.map +1 -0
  24. package/dist/api/agents-api.d.ts +19 -0
  25. package/dist/api/agents-api.d.ts.map +1 -1
  26. package/dist/api/agents-api.js +28 -1
  27. package/dist/api/agents-api.js.map +1 -1
  28. package/dist/api/nvm-api.d.ts +1 -0
  29. package/dist/api/nvm-api.d.ts.map +1 -1
  30. package/dist/api/nvm-api.js +4 -0
  31. package/dist/api/nvm-api.js.map +1 -1
  32. package/dist/api/plans-api.d.ts +12 -2
  33. package/dist/api/plans-api.d.ts.map +1 -1
  34. package/dist/api/plans-api.js +9 -2
  35. package/dist/api/plans-api.js.map +1 -1
  36. package/dist/index.d.ts +2 -0
  37. package/dist/index.d.ts.map +1 -1
  38. package/dist/index.js +3 -0
  39. package/dist/index.js.map +1 -1
  40. package/dist/mcp/core/auth.d.ts +14 -0
  41. package/dist/mcp/core/auth.d.ts.map +1 -1
  42. package/dist/mcp/core/auth.js +56 -23
  43. package/dist/mcp/core/auth.js.map +1 -1
  44. package/dist/mcp/core/paywall.d.ts +6 -0
  45. package/dist/mcp/core/paywall.d.ts.map +1 -1
  46. package/dist/mcp/core/paywall.js +170 -84
  47. package/dist/mcp/core/paywall.js.map +1 -1
  48. package/dist/mcp/utils/errors.d.ts +26 -0
  49. package/dist/mcp/utils/errors.d.ts.map +1 -1
  50. package/dist/mcp/utils/errors.js +32 -0
  51. package/dist/mcp/utils/errors.js.map +1 -1
  52. package/dist/mcp/utils/meta.d.ts +54 -0
  53. package/dist/mcp/utils/meta.d.ts.map +1 -0
  54. package/dist/mcp/utils/meta.js +72 -0
  55. package/dist/mcp/utils/meta.js.map +1 -0
  56. package/dist/utils.d.ts +27 -0
  57. package/dist/utils.d.ts.map +1 -1
  58. package/dist/utils.js +34 -0
  59. package/dist/utils.js.map +1 -1
  60. package/dist/x402/facilitator-api.d.ts +21 -0
  61. package/dist/x402/facilitator-api.d.ts.map +1 -1
  62. package/dist/x402/facilitator-api.js +39 -0
  63. package/dist/x402/facilitator-api.js.map +1 -1
  64. package/package.json +2 -2
@@ -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 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
+ {"version":3,"file":"paywall.js","sourceRoot":"","sources":["../../../src/mcp/core/paywall.ts"],"names":[],"mappings":"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","sourcesContent":["/**\n * Main paywall decorator for MCP handlers (tools, resources, prompts)\n */\nimport { Address, isValidScheme } from '../../common/types.js'\nimport type { Payments } from '../../payments.js'\nimport { decodeAccessToken, encodeAccessToken } from '../../utils.js'\nimport {\n buildPaymentRequired,\n buildPaymentRequiredForPlans,\n type SettlePermissionsResult,\n type X402PaymentRequired,\n} from '../../x402/facilitator-api.js'\nimport {\n AuthResult,\n McpConfig,\n PaywallOptions,\n PromptOptions,\n ResourceOptions,\n ToolOptions,\n} from '../types/paywall.types.js'\nimport {\n ERROR_CODES,\n PaymentRequiredError,\n SettlementFailedError,\n createRpcError,\n} from '../utils/errors.js'\nimport {\n NEVERMINED_CREDITS_META_KEY,\n X402_PAYMENT_RESPONSE_META_KEY,\n paymentRequiredResult,\n readPaymentPayload,\n} from '../utils/meta.js'\nimport { PaywallAuthenticator } from './auth.js'\nimport { CreditsContextProvider } from './credits-context.js'\n\n// Emit the Authorization-header deprecation notice at most once per process to\n// avoid log spam on high-traffic servers still using the legacy header path.\nlet authHeaderDeprecationWarned = false\n\n/**\n * Main class for creating paywall-protected MCP handlers\n */\nexport class PaywallDecorator {\n // Internal config ensures serverName is always a concrete string\n private config: { 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 try {\n // x402 v2 MCP transport: prefer the in-band payment payload from\n // params._meta[\"x402/payment\"]. Re-encode it into the access token\n // string the verify/settle path expects and present it via the same\n // extra/headers shape the auth flow reads, so the in-band payload takes\n // precedence over the Authorization header (kept as a deprecated\n // fallback when the in-band payload is absent). The RAW extra is still\n // forwarded to the user handler below.\n const paymentPayload = readPaymentPayload(extra)\n let authExtra = extra\n if (paymentPayload) {\n const token = encodeAccessToken(paymentPayload)\n // Synthesize an auth-only extra carrying the in-band token. This\n // intentionally drops the rest of `extra` for the AUTH call only; the\n // RAW `extra` (with `_meta`) is still forwarded to the user handler below.\n authExtra = { requestInfo: { headers: { authorization: `Bearer ${token}` } } }\n } else if (!authHeaderDeprecationWarned) {\n authHeaderDeprecationWarned = true\n console.warn(\n '[x402] No _meta[\"x402/payment\"] on the MCP request; falling back to the ' +\n 'Authorization header (deprecated under the x402 v2 MCP transport).',\n )\n }\n\n // 1. Authenticate request\n const authResult = await this.authenticator.authenticate(\n authExtra,\n { planId: 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 // fix: pre-existing arg order — fallbackEndpoint=httpUrl, httpVerb='POST'\n // (matches the streaming site above)\n authResult.httpUrl,\n 'POST',\n )\n\n // Settlement failed AFTER the tool executed: per the x402 v2 MCP\n // transport spec, do NOT return the tool's content — surface only the\n // payment error so a paid result is never delivered without payment\n // landing. (onRedeemError \"ignore\" therefore no longer delivers paid\n // content; \"propagate\" already threw a Misconfiguration in redeemCredits.)\n if (creditsResult && !creditsResult.success) {\n console.error(\n `[x402] settlement failed after tool execution; suppressing tool content. reason=${creditsResult.errorReason}`,\n )\n throw new SettlementFailedError(this.buildPaymentRequiredFromAuth(authResult))\n }\n\n // creditsResult is undefined for free / no-credit calls (no settlement\n // performed) — in that case the spec receipt is omitted. On success the\n // full receipt goes under the spec key; Nevermined observability is kept\n // under a namespaced key so it never collides with the spec shape.\n result._meta = {\n ...result._meta,\n ...(creditsResult && { [X402_PAYMENT_RESPONSE_META_KEY]: creditsResult }),\n [NEVERMINED_CREDITS_META_KEY]: {\n ...(creditsResult?.transaction && { txHash: creditsResult.transaction }),\n creditsRedeemed: creditsResult?.success\n ? (creditsResult.creditsRedeemed ?? credits.toString())\n : '0',\n remainingBalance: creditsResult?.remainingBalance,\n planId: authResult.planId,\n subscriberAddress: authResult.subscriberAddress,\n success: creditsResult ? creditsResult.success : true,\n },\n }\n return result\n } catch (error) {\n // Payment-required (pre-execution, from auth) and settlement-failure\n // (post-execution) are surfaced in band as an error tool result for\n // tools. Resources/prompts have no tool-result error channel, so the\n // error propagates as a JSON-RPC error instead.\n if (error instanceof PaymentRequiredError && kind === 'tool') {\n return paymentRequiredResult(error.paymentRequired)\n }\n throw error\n }\n }\n }\n\n /**\n * Build a spec-shaped `PaymentRequired` dict for a settlement failure, from\n * the authenticated request context. Surfaced (with tool content suppressed)\n * when settlement fails after the tool has executed.\n */\n private buildPaymentRequiredFromAuth(authResult: AuthResult): Record<string, any> {\n const planId = authResult.planId || ''\n const paymentRequired = buildPaymentRequiredForPlans(planId ? [planId] : [''], {\n endpoint: authResult.logicalUrl || authResult.httpUrl,\n agentId: authResult.agentId,\n httpVerb: 'POST',\n environment: this.payments.getEnvironmentName(),\n }) as X402PaymentRequired & { error?: string }\n paymentRequired.error = 'settlement failed'\n return paymentRequired\n }\n\n /**\n * Redeem credits after successful request\n */\n private async redeemCredits(\n planId: string,\n token: string,\n subscriberAddress: Address,\n credits: bigint,\n options: PaywallOptions,\n agentId?: string,\n endpoint?: string,\n fallbackEndpoint?: string,\n httpVerb?: string,\n ): Promise<SettlePermissionsResult | undefined> {\n // No settlement for free / no-credit calls — signalled to the caller as\n // `undefined` so the spec receipt (_meta[\"x402/payment-response\"]) is omitted.\n if (!(credits && credits > 0n && subscriberAddress && planId)) {\n return undefined\n }\n\n const decoded = decodeAccessToken(token)\n const scheme = isValidScheme(decoded?.accepted?.scheme)\n ? decoded.accepted.scheme\n : 'nvm:erc4337'\n try {\n const paymentRequired: X402PaymentRequired = buildPaymentRequired(planId, {\n endpoint: endpoint || '',\n agentId,\n httpVerb,\n scheme,\n environment: this.payments.getEnvironmentName(),\n })\n\n return await this.payments.facilitator.settlePermissions({\n paymentRequired,\n x402AccessToken: token,\n maxAmount: credits,\n })\n } catch (primaryError) {\n // If logical URL fails and we have an HTTP URL fallback, retry with it\n let lastError: unknown = primaryError\n if (fallbackEndpoint) {\n try {\n const paymentRequired: X402PaymentRequired = buildPaymentRequired(planId, {\n endpoint: fallbackEndpoint,\n agentId,\n httpVerb,\n scheme,\n environment: this.payments.getEnvironmentName(),\n })\n\n return await this.payments.facilitator.settlePermissions({\n paymentRequired,\n x402AccessToken: token,\n maxAmount: credits,\n })\n } catch (fallbackError) {\n // Fallback also failed, use fallback error as the reported error\n lastError = fallbackError\n }\n }\n\n const errorReason = lastError instanceof Error ? lastError.message : String(lastError)\n console.error(`[x402] settle failed: ${errorReason}`)\n if (options.onRedeemError === 'propagate') {\n throw createRpcError(\n ERROR_CODES.Misconfiguration,\n `Failed to redeem credits: ${errorReason}`,\n )\n }\n // Default (\"ignore\"): return a failed result so the caller suppresses the\n // tool content and surfaces the in-band payment error (always-suppress\n // under the x402 v2 MCP transport).\n return { success: false, transaction: '', network: '', errorReason }\n }\n }\n}\n\n/**\n * Type guard to detect AsyncIterable values.\n */\nfunction isAsyncIterable<T = unknown>(value: any): value is AsyncIterable<T> {\n return value != null && typeof value[Symbol.asyncIterator] === 'function'\n}\n\n/**\n * Wrap an AsyncIterable with metadata injection at the end of the stream\n */\nfunction wrapAsyncIterable<T>(\n iterable: AsyncIterable<T>,\n onFinally: () => Promise<any>,\n planId: string,\n subscriberAddress: Address,\n credits: bigint,\n) {\n async function* generator() {\n let creditsResult: any = null\n try {\n for await (const chunk of iterable) {\n yield chunk as T\n }\n } finally {\n creditsResult = await onFinally()\n }\n\n // Yield a _meta chunk at the end with the redemption result.\n // NOTE: a stream cannot retroactively suppress already-yielded chunks, so a\n // post-execution settlement failure on a stream is only reported here in the\n // final _meta chunk (under nevermined/credits) — it cannot withhold content\n // the way a non-streaming tool result does. `creditsResult` is undefined for\n // free / no-credit calls.\n const settlement = creditsResult || undefined\n const metadataChunk = {\n _meta: {\n // Spec receipt only on a successful settlement.\n ...(settlement?.success && { [X402_PAYMENT_RESPONSE_META_KEY]: settlement }),\n // Nevermined-namespaced observability (NOT part of the x402 spec).\n [NEVERMINED_CREDITS_META_KEY]: {\n ...(settlement?.transaction && { txHash: settlement.transaction }),\n creditsRedeemed: settlement?.success\n ? (settlement.creditsRedeemed ?? credits.toString())\n : '0',\n remainingBalance: settlement?.remainingBalance,\n planId,\n subscriberAddress,\n success: settlement ? settlement.success : true,\n ...(settlement?.errorReason && { errorReason: settlement.errorReason }),\n },\n },\n }\n yield metadataChunk as T\n }\n return generator()\n}\n"]}
@@ -14,4 +14,30 @@ export declare function createRpcError(code: ErrorCode, message: string, data?:
14
14
  code: number;
15
15
  data?: any;
16
16
  };
17
+ /**
18
+ * Raised by the paywall when payment is required (x402 v2 MCP transport).
19
+ *
20
+ * Carries the spec-shaped `PaymentRequired` object so the tool paywall wrapper
21
+ * can surface it *in band* as a `CallToolResult({ isError: true, ... })`. Also
22
+ * exposes a JSON-RPC `code` so that non-tool paths (resources / prompts), which
23
+ * cannot return a tool-result error, still degrade to a JSON-RPC error when the
24
+ * exception propagates. Note: the MCP SDK's low-level catch-all only forwards
25
+ * the error message (not `code`) to the wire for those paths.
26
+ */
27
+ export declare class PaymentRequiredError extends Error {
28
+ paymentRequired: Record<string, any>;
29
+ code: number;
30
+ constructor(paymentRequired: Record<string, any>, message?: string);
31
+ }
32
+ /**
33
+ * Raised when settlement fails AFTER the tool has already executed.
34
+ *
35
+ * Same in-band shape as {@link PaymentRequiredError}; the tool paywall wrapper
36
+ * suppresses the already-computed tool content and returns only the payment
37
+ * error, per the x402 v2 MCP transport spec ("do not return the tool's content
38
+ * if settlement fails").
39
+ */
40
+ export declare class SettlementFailedError extends PaymentRequiredError {
41
+ constructor(paymentRequired: Record<string, any>, message?: string);
42
+ }
17
43
  //# sourceMappingURL=errors.d.ts.map
@@ -1 +1 @@
1
- {"version":3,"file":"errors.d.ts","sourceRoot":"","sources":["../../../src/mcp/utils/errors.ts"],"names":[],"mappings":"AAAA;;GAEG;AAEH,eAAO,MAAM,WAAW;;;CAGd,CAAA;AAEV,MAAM,MAAM,SAAS,GAAG,CAAC,OAAO,WAAW,CAAC,CAAC,MAAM,OAAO,WAAW,CAAC,CAAA;AAEtE;;;GAGG;AACH,wBAAgB,cAAc,CAAC,IAAI,EAAE,SAAS,EAAE,OAAO,EAAE,MAAM,EAAE,IAAI,CAAC,EAAE,GAAG;UAClB,MAAM;WAAS,GAAG;EAK1E"}
1
+ {"version":3,"file":"errors.d.ts","sourceRoot":"","sources":["../../../src/mcp/utils/errors.ts"],"names":[],"mappings":"AAAA;;GAEG;AAEH,eAAO,MAAM,WAAW;;;CAGd,CAAA;AAEV,MAAM,MAAM,SAAS,GAAG,CAAC,OAAO,WAAW,CAAC,CAAC,MAAM,OAAO,WAAW,CAAC,CAAA;AAEtE;;;GAGG;AACH,wBAAgB,cAAc,CAAC,IAAI,EAAE,SAAS,EAAE,OAAO,EAAE,MAAM,EAAE,IAAI,CAAC,EAAE,GAAG;UAClB,MAAM;WAAS,GAAG;EAK1E;AAED;;;;;;;;;GASG;AACH,qBAAa,oBAAqB,SAAQ,KAAK;IAGpC,eAAe,EAAE,MAAM,CAAC,MAAM,EAAE,GAAG,CAAC;IAF7C,IAAI,EAAE,MAAM,CAA8B;gBAEjC,eAAe,EAAE,MAAM,CAAC,MAAM,EAAE,GAAG,CAAC,EAC3C,OAAO,SAAqB;CAK/B;AAED;;;;;;;GAOG;AACH,qBAAa,qBAAsB,SAAQ,oBAAoB;gBAE3D,eAAe,EAAE,MAAM,CAAC,MAAM,EAAE,GAAG,CAAC,EACpC,OAAO,SAA2C;CAKrD"}
@@ -17,4 +17,36 @@ export function createRpcError(code, message, data) {
17
17
  rpcError.data = data;
18
18
  return rpcError;
19
19
  }
20
+ /**
21
+ * Raised by the paywall when payment is required (x402 v2 MCP transport).
22
+ *
23
+ * Carries the spec-shaped `PaymentRequired` object so the tool paywall wrapper
24
+ * can surface it *in band* as a `CallToolResult({ isError: true, ... })`. Also
25
+ * exposes a JSON-RPC `code` so that non-tool paths (resources / prompts), which
26
+ * cannot return a tool-result error, still degrade to a JSON-RPC error when the
27
+ * exception propagates. Note: the MCP SDK's low-level catch-all only forwards
28
+ * the error message (not `code`) to the wire for those paths.
29
+ */
30
+ export class PaymentRequiredError extends Error {
31
+ constructor(paymentRequired, message = 'Payment required') {
32
+ super(message);
33
+ this.paymentRequired = paymentRequired;
34
+ this.code = ERROR_CODES.PaymentRequired;
35
+ this.name = 'PaymentRequiredError';
36
+ }
37
+ }
38
+ /**
39
+ * Raised when settlement fails AFTER the tool has already executed.
40
+ *
41
+ * Same in-band shape as {@link PaymentRequiredError}; the tool paywall wrapper
42
+ * suppresses the already-computed tool content and returns only the payment
43
+ * error, per the x402 v2 MCP transport spec ("do not return the tool's content
44
+ * if settlement fails").
45
+ */
46
+ export class SettlementFailedError extends PaymentRequiredError {
47
+ constructor(paymentRequired, message = 'Settlement failed after tool execution') {
48
+ super(paymentRequired, message);
49
+ this.name = 'SettlementFailedError';
50
+ }
51
+ }
20
52
  //# sourceMappingURL=errors.js.map
@@ -1 +1 @@
1
- {"version":3,"file":"errors.js","sourceRoot":"","sources":["../../../src/mcp/utils/errors.ts"],"names":[],"mappings":"AAAA;;GAEG;AAEH,MAAM,CAAC,MAAM,WAAW,GAAG;IACzB,gBAAgB,EAAE,CAAC,KAAK;IACxB,eAAe,EAAE,CAAC,KAAK;CACf,CAAA;AAIV;;;GAGG;AACH,MAAM,UAAU,cAAc,CAAC,IAAe,EAAE,OAAe,EAAE,IAAU;IACzE,MAAM,QAAQ,GAAG,IAAI,KAAK,CAAC,OAAO,CAAyC,CAAA;IAC3E,QAAQ,CAAC,IAAI,GAAG,cAAc,CAAA;IAC9B,QAAQ,CAAC,IAAI,GAAG,IAAI,CAAA;IACpB,IAAI,IAAI,KAAK,SAAS;QAAE,QAAQ,CAAC,IAAI,GAAG,IAAI,CAAA;IAC5C,OAAO,QAAQ,CAAA;AACjB,CAAC","sourcesContent":["/**\n * Error utilities and common JSON-RPC error codes used by the MCP paywall.\n */\n\nexport const ERROR_CODES = {\n Misconfiguration: -32002,\n PaymentRequired: -32003,\n} as const\n\nexport type ErrorCode = (typeof ERROR_CODES)[keyof typeof ERROR_CODES]\n\n/**\n * Create a JSON-RPC-like error object preserving numeric code and message.\n * Returns an Error instance augmented with a numeric `code` and optional `data`.\n */\nexport function createRpcError(code: ErrorCode, message: string, data?: any) {\n const rpcError = new Error(message) as Error & { code: number; data?: any }\n rpcError.name = 'JSONRpcError'\n rpcError.code = code\n if (data !== undefined) rpcError.data = data\n return rpcError\n}\n"]}
1
+ {"version":3,"file":"errors.js","sourceRoot":"","sources":["../../../src/mcp/utils/errors.ts"],"names":[],"mappings":"AAAA;;GAEG;AAEH,MAAM,CAAC,MAAM,WAAW,GAAG;IACzB,gBAAgB,EAAE,CAAC,KAAK;IACxB,eAAe,EAAE,CAAC,KAAK;CACf,CAAA;AAIV;;;GAGG;AACH,MAAM,UAAU,cAAc,CAAC,IAAe,EAAE,OAAe,EAAE,IAAU;IACzE,MAAM,QAAQ,GAAG,IAAI,KAAK,CAAC,OAAO,CAAyC,CAAA;IAC3E,QAAQ,CAAC,IAAI,GAAG,cAAc,CAAA;IAC9B,QAAQ,CAAC,IAAI,GAAG,IAAI,CAAA;IACpB,IAAI,IAAI,KAAK,SAAS;QAAE,QAAQ,CAAC,IAAI,GAAG,IAAI,CAAA;IAC5C,OAAO,QAAQ,CAAA;AACjB,CAAC;AAED;;;;;;;;;GASG;AACH,MAAM,OAAO,oBAAqB,SAAQ,KAAK;IAE7C,YACS,eAAoC,EAC3C,OAAO,GAAG,kBAAkB;QAE5B,KAAK,CAAC,OAAO,CAAC,CAAA;QAHP,oBAAe,GAAf,eAAe,CAAqB;QAF7C,SAAI,GAAW,WAAW,CAAC,eAAe,CAAA;QAMxC,IAAI,CAAC,IAAI,GAAG,sBAAsB,CAAA;IACpC,CAAC;CACF;AAED;;;;;;;GAOG;AACH,MAAM,OAAO,qBAAsB,SAAQ,oBAAoB;IAC7D,YACE,eAAoC,EACpC,OAAO,GAAG,wCAAwC;QAElD,KAAK,CAAC,eAAe,EAAE,OAAO,CAAC,CAAA;QAC/B,IAAI,CAAC,IAAI,GAAG,uBAAuB,CAAA;IACrC,CAAC;CACF","sourcesContent":["/**\n * Error utilities and common JSON-RPC error codes used by the MCP paywall.\n */\n\nexport const ERROR_CODES = {\n Misconfiguration: -32002,\n PaymentRequired: -32003,\n} as const\n\nexport type ErrorCode = (typeof ERROR_CODES)[keyof typeof ERROR_CODES]\n\n/**\n * Create a JSON-RPC-like error object preserving numeric code and message.\n * Returns an Error instance augmented with a numeric `code` and optional `data`.\n */\nexport function createRpcError(code: ErrorCode, message: string, data?: any) {\n const rpcError = new Error(message) as Error & { code: number; data?: any }\n rpcError.name = 'JSONRpcError'\n rpcError.code = code\n if (data !== undefined) rpcError.data = data\n return rpcError\n}\n\n/**\n * Raised by the paywall when payment is required (x402 v2 MCP transport).\n *\n * Carries the spec-shaped `PaymentRequired` object so the tool paywall wrapper\n * can surface it *in band* as a `CallToolResult({ isError: true, ... })`. Also\n * exposes a JSON-RPC `code` so that non-tool paths (resources / prompts), which\n * cannot return a tool-result error, still degrade to a JSON-RPC error when the\n * exception propagates. Note: the MCP SDK's low-level catch-all only forwards\n * the error message (not `code`) to the wire for those paths.\n */\nexport class PaymentRequiredError extends Error {\n code: number = ERROR_CODES.PaymentRequired\n constructor(\n public paymentRequired: Record<string, any>,\n message = 'Payment required',\n ) {\n super(message)\n this.name = 'PaymentRequiredError'\n }\n}\n\n/**\n * Raised when settlement fails AFTER the tool has already executed.\n *\n * Same in-band shape as {@link PaymentRequiredError}; the tool paywall wrapper\n * suppresses the already-computed tool content and returns only the payment\n * error, per the x402 v2 MCP transport spec (\"do not return the tool's content\n * if settlement fails\").\n */\nexport class SettlementFailedError extends PaymentRequiredError {\n constructor(\n paymentRequired: Record<string, any>,\n message = 'Settlement failed after tool execution',\n ) {\n super(paymentRequired, message)\n this.name = 'SettlementFailedError'\n }\n}\n"]}
@@ -0,0 +1,54 @@
1
+ /**
2
+ * In-band x402 metadata helpers for the MCP transport (x402 v2 MCP spec).
3
+ *
4
+ * The x402 v2 MCP transport signals payments *in band* via the MCP tool-call
5
+ * machinery instead of HTTP status codes / headers:
6
+ *
7
+ * - The client sends the `PaymentPayload` in the request params
8
+ * `_meta["x402/payment"]` (plain JSON).
9
+ * - The server returns the settlement receipt in the response
10
+ * `_meta["x402/payment-response"]` (plain JSON).
11
+ * - Payment-required is signalled as a tool result with `isError: true` whose
12
+ * `structuredContent` carries the `PaymentRequired` object and whose
13
+ * `content[0].text` is the JSON-stringified copy of it.
14
+ *
15
+ * Nevermined-specific observability (txHash, creditsRedeemed, …) is kept under
16
+ * a namespaced `_meta["nevermined/credits"]` key so it never collides with the
17
+ * spec-defined keys.
18
+ */
19
+ /** Spec-defined JSON-RPC `_meta` keys (x402 v2 MCP transport). */
20
+ export declare const X402_PAYMENT_META_KEY = "x402/payment";
21
+ export declare const X402_PAYMENT_RESPONSE_META_KEY = "x402/payment-response";
22
+ /** Nevermined-namespaced observability key (NOT part of the x402 spec). */
23
+ export declare const NEVERMINED_CREDITS_META_KEY = "nevermined/credits";
24
+ /**
25
+ * Read the in-band x402 payment payload from the current request's `_meta`.
26
+ *
27
+ * The MCP TS SDK exposes the incoming request `_meta` on the tool handler's
28
+ * `extra` argument (`extra._meta`), and its schema is a passthrough object, so
29
+ * non-standard keys like `"x402/payment"` survive parsing.
30
+ *
31
+ * @param extra - The MCP handler `extra` argument.
32
+ * @returns The decoded PaymentPayload object, or `undefined` when absent.
33
+ */
34
+ export declare function readPaymentPayload(extra: any): Record<string, any> | undefined;
35
+ /**
36
+ * Build a spec-shaped payment-required tool result.
37
+ *
38
+ * Per the x402 v2 MCP transport, payment-required is an *error* tool result
39
+ * that carries the `PaymentRequired` object in BOTH `structuredContent` (the
40
+ * object) and `content[0].text` (the JSON-stringified copy, for clients that
41
+ * cannot read structured content).
42
+ *
43
+ * @param paymentRequired - The `PaymentRequired` object.
44
+ * @returns A `CallToolResult`-shaped object with `isError: true`.
45
+ */
46
+ export declare function paymentRequiredResult(paymentRequired: Record<string, any>): {
47
+ isError: boolean;
48
+ structuredContent: Record<string, any>;
49
+ content: {
50
+ type: "text";
51
+ text: string;
52
+ }[];
53
+ };
54
+ //# sourceMappingURL=meta.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"meta.d.ts","sourceRoot":"","sources":["../../../src/mcp/utils/meta.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;;;GAiBG;AAEH,kEAAkE;AAClE,eAAO,MAAM,qBAAqB,iBAAiB,CAAA;AACnD,eAAO,MAAM,8BAA8B,0BAA0B,CAAA;AAErE,2EAA2E;AAC3E,eAAO,MAAM,2BAA2B,uBAAuB,CAAA;AAS/D;;;;;;;;;GASG;AACH,wBAAgB,kBAAkB,CAAC,KAAK,EAAE,GAAG,GAAG,MAAM,CAAC,MAAM,EAAE,GAAG,CAAC,GAAG,SAAS,CAa9E;AAED;;;;;;;;;;GAUG;AACH,wBAAgB,qBAAqB,CAAC,eAAe,EAAE,MAAM,CAAC,MAAM,EAAE,GAAG,CAAC;;;;;;;EAMzE"}
@@ -0,0 +1,72 @@
1
+ /**
2
+ * In-band x402 metadata helpers for the MCP transport (x402 v2 MCP spec).
3
+ *
4
+ * The x402 v2 MCP transport signals payments *in band* via the MCP tool-call
5
+ * machinery instead of HTTP status codes / headers:
6
+ *
7
+ * - The client sends the `PaymentPayload` in the request params
8
+ * `_meta["x402/payment"]` (plain JSON).
9
+ * - The server returns the settlement receipt in the response
10
+ * `_meta["x402/payment-response"]` (plain JSON).
11
+ * - Payment-required is signalled as a tool result with `isError: true` whose
12
+ * `structuredContent` carries the `PaymentRequired` object and whose
13
+ * `content[0].text` is the JSON-stringified copy of it.
14
+ *
15
+ * Nevermined-specific observability (txHash, creditsRedeemed, …) is kept under
16
+ * a namespaced `_meta["nevermined/credits"]` key so it never collides with the
17
+ * spec-defined keys.
18
+ */
19
+ /** Spec-defined JSON-RPC `_meta` keys (x402 v2 MCP transport). */
20
+ export const X402_PAYMENT_META_KEY = 'x402/payment';
21
+ export const X402_PAYMENT_RESPONSE_META_KEY = 'x402/payment-response';
22
+ /** Nevermined-namespaced observability key (NOT part of the x402 spec). */
23
+ export const NEVERMINED_CREDITS_META_KEY = 'nevermined/credits';
24
+ /**
25
+ * Upper bound on the serialized size of an in-band payment payload. The payload
26
+ * is untrusted client input that gets re-encoded into a token, so cap it as
27
+ * defense-in-depth (mirrors the Python sibling's `len(json.dumps(value))` guard).
28
+ */
29
+ const MAX_INBAND_PAYMENT_PAYLOAD_LEN = 64 * 1024;
30
+ /**
31
+ * Read the in-band x402 payment payload from the current request's `_meta`.
32
+ *
33
+ * The MCP TS SDK exposes the incoming request `_meta` on the tool handler's
34
+ * `extra` argument (`extra._meta`), and its schema is a passthrough object, so
35
+ * non-standard keys like `"x402/payment"` survive parsing.
36
+ *
37
+ * @param extra - The MCP handler `extra` argument.
38
+ * @returns The decoded PaymentPayload object, or `undefined` when absent.
39
+ */
40
+ export function readPaymentPayload(extra) {
41
+ const value = extra?._meta?.[X402_PAYMENT_META_KEY];
42
+ // Only a plain object is a valid PaymentPayload; reject null and arrays
43
+ // (`typeof [] === 'object'`), mirroring the Python `isinstance(value, dict)`.
44
+ if (value === null || typeof value !== 'object' || Array.isArray(value)) {
45
+ return undefined;
46
+ }
47
+ // Defense-in-depth: reject oversized client-supplied payloads before they are
48
+ // re-encoded into a token.
49
+ if (JSON.stringify(value).length > MAX_INBAND_PAYMENT_PAYLOAD_LEN) {
50
+ return undefined;
51
+ }
52
+ return value;
53
+ }
54
+ /**
55
+ * Build a spec-shaped payment-required tool result.
56
+ *
57
+ * Per the x402 v2 MCP transport, payment-required is an *error* tool result
58
+ * that carries the `PaymentRequired` object in BOTH `structuredContent` (the
59
+ * object) and `content[0].text` (the JSON-stringified copy, for clients that
60
+ * cannot read structured content).
61
+ *
62
+ * @param paymentRequired - The `PaymentRequired` object.
63
+ * @returns A `CallToolResult`-shaped object with `isError: true`.
64
+ */
65
+ export function paymentRequiredResult(paymentRequired) {
66
+ return {
67
+ isError: true,
68
+ structuredContent: paymentRequired,
69
+ content: [{ type: 'text', text: JSON.stringify(paymentRequired) }],
70
+ };
71
+ }
72
+ //# sourceMappingURL=meta.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"meta.js","sourceRoot":"","sources":["../../../src/mcp/utils/meta.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;;;GAiBG;AAEH,kEAAkE;AAClE,MAAM,CAAC,MAAM,qBAAqB,GAAG,cAAc,CAAA;AACnD,MAAM,CAAC,MAAM,8BAA8B,GAAG,uBAAuB,CAAA;AAErE,2EAA2E;AAC3E,MAAM,CAAC,MAAM,2BAA2B,GAAG,oBAAoB,CAAA;AAE/D;;;;GAIG;AACH,MAAM,8BAA8B,GAAG,EAAE,GAAG,IAAI,CAAA;AAEhD;;;;;;;;;GASG;AACH,MAAM,UAAU,kBAAkB,CAAC,KAAU;IAC3C,MAAM,KAAK,GAAG,KAAK,EAAE,KAAK,EAAE,CAAC,qBAAqB,CAAC,CAAA;IACnD,wEAAwE;IACxE,8EAA8E;IAC9E,IAAI,KAAK,KAAK,IAAI,IAAI,OAAO,KAAK,KAAK,QAAQ,IAAI,KAAK,CAAC,OAAO,CAAC,KAAK,CAAC,EAAE,CAAC;QACxE,OAAO,SAAS,CAAA;IAClB,CAAC;IACD,8EAA8E;IAC9E,2BAA2B;IAC3B,IAAI,IAAI,CAAC,SAAS,CAAC,KAAK,CAAC,CAAC,MAAM,GAAG,8BAA8B,EAAE,CAAC;QAClE,OAAO,SAAS,CAAA;IAClB,CAAC;IACD,OAAO,KAAK,CAAA;AACd,CAAC;AAED;;;;;;;;;;GAUG;AACH,MAAM,UAAU,qBAAqB,CAAC,eAAoC;IACxE,OAAO;QACL,OAAO,EAAE,IAAI;QACb,iBAAiB,EAAE,eAAe;QAClC,OAAO,EAAE,CAAC,EAAE,IAAI,EAAE,MAAe,EAAE,IAAI,EAAE,IAAI,CAAC,SAAS,CAAC,eAAe,CAAC,EAAE,CAAC;KAC5E,CAAA;AACH,CAAC","sourcesContent":["/**\n * In-band x402 metadata helpers for the MCP transport (x402 v2 MCP spec).\n *\n * The x402 v2 MCP transport signals payments *in band* via the MCP tool-call\n * machinery instead of HTTP status codes / headers:\n *\n * - The client sends the `PaymentPayload` in the request params\n * `_meta[\"x402/payment\"]` (plain JSON).\n * - The server returns the settlement receipt in the response\n * `_meta[\"x402/payment-response\"]` (plain JSON).\n * - Payment-required is signalled as a tool result with `isError: true` whose\n * `structuredContent` carries the `PaymentRequired` object and whose\n * `content[0].text` is the JSON-stringified copy of it.\n *\n * Nevermined-specific observability (txHash, creditsRedeemed, …) is kept under\n * a namespaced `_meta[\"nevermined/credits\"]` key so it never collides with the\n * spec-defined keys.\n */\n\n/** Spec-defined JSON-RPC `_meta` keys (x402 v2 MCP transport). */\nexport const X402_PAYMENT_META_KEY = 'x402/payment'\nexport const X402_PAYMENT_RESPONSE_META_KEY = 'x402/payment-response'\n\n/** Nevermined-namespaced observability key (NOT part of the x402 spec). */\nexport const NEVERMINED_CREDITS_META_KEY = 'nevermined/credits'\n\n/**\n * Upper bound on the serialized size of an in-band payment payload. The payload\n * is untrusted client input that gets re-encoded into a token, so cap it as\n * defense-in-depth (mirrors the Python sibling's `len(json.dumps(value))` guard).\n */\nconst MAX_INBAND_PAYMENT_PAYLOAD_LEN = 64 * 1024\n\n/**\n * Read the in-band x402 payment payload from the current request's `_meta`.\n *\n * The MCP TS SDK exposes the incoming request `_meta` on the tool handler's\n * `extra` argument (`extra._meta`), and its schema is a passthrough object, so\n * non-standard keys like `\"x402/payment\"` survive parsing.\n *\n * @param extra - The MCP handler `extra` argument.\n * @returns The decoded PaymentPayload object, or `undefined` when absent.\n */\nexport function readPaymentPayload(extra: any): Record<string, any> | undefined {\n const value = extra?._meta?.[X402_PAYMENT_META_KEY]\n // Only a plain object is a valid PaymentPayload; reject null and arrays\n // (`typeof [] === 'object'`), mirroring the Python `isinstance(value, dict)`.\n if (value === null || typeof value !== 'object' || Array.isArray(value)) {\n return undefined\n }\n // Defense-in-depth: reject oversized client-supplied payloads before they are\n // re-encoded into a token.\n if (JSON.stringify(value).length > MAX_INBAND_PAYMENT_PAYLOAD_LEN) {\n return undefined\n }\n return value\n}\n\n/**\n * Build a spec-shaped payment-required tool result.\n *\n * Per the x402 v2 MCP transport, payment-required is an *error* tool result\n * that carries the `PaymentRequired` object in BOTH `structuredContent` (the\n * object) and `content[0].text` (the JSON-stringified copy, for clients that\n * cannot read structured content).\n *\n * @param paymentRequired - The `PaymentRequired` object.\n * @returns A `CallToolResult`-shaped object with `isError: true`.\n */\nexport function paymentRequiredResult(paymentRequired: Record<string, any>) {\n return {\n isError: true,\n structuredContent: paymentRequired,\n content: [{ type: 'text' as const, text: JSON.stringify(paymentRequired) }],\n }\n}\n"]}
package/dist/utils.d.ts CHANGED
@@ -26,6 +26,33 @@ export declare const isStepIdValid: (stepId: string) => boolean;
26
26
  * @returns The decoded token data or null if invalid
27
27
  */
28
28
  export declare const decodeAccessToken: (accessToken: string) => Record<string, any> | null;
29
+ /**
30
+ * Encode a PaymentPayload object into an x402 access token string.
31
+ *
32
+ * Inverse of {@link decodeAccessToken}. Used by the MCP transport to turn the
33
+ * in-band `_meta["x402/payment"]` PaymentPayload object back into the
34
+ * base64url token string the facilitator's verify/settle APIs consume.
35
+ *
36
+ * The base64 envelope is transport-only: the EIP-712 signature lives inside
37
+ * `payload.authorization` / `payload.signature`, not over the base64 wrapper,
38
+ * so re-encoding a decoded (or foreign-encoded) payload is byte-safe for the
39
+ * facilitator — the invariant is semantic recovery, not byte-identity.
40
+ *
41
+ * Produces unpadded base64url with compact JSON (no spaces), matching the form
42
+ * {@link decodeAccessToken} accepts.
43
+ *
44
+ * Encodes UTF-8 bytes before base64 so it never throws on non-ASCII input — this
45
+ * runs on client-supplied `_meta["x402/payment"]`, and `btoa` alone throws a
46
+ * DOMException on code points > U+00FF. For ASCII JSON (all real x402
47
+ * PaymentPayloads: EIP-712 hex/decimal/signature fields) the output is
48
+ * byte-identical to `btoa(json)`, so the round-trip with {@link decodeAccessToken}
49
+ * is unchanged. `decodeAccessToken` is intentionally left as-is; a full UTF-8
50
+ * round-trip would additionally require decoding the bytes there.
51
+ *
52
+ * @param payload - The decoded PaymentPayload object (e.g. from `_meta["x402/payment"]`)
53
+ * @returns The base64url-encoded access token string (unpadded)
54
+ */
55
+ export declare const encodeAccessToken: (payload: Record<string, any>) => string;
29
56
  /**
30
57
  * It returns the list of endpoints that are used by agents/services implementing the Nevermined Query Protocol
31
58
  * @param serverHost - The host of the server where the agents/services are running
@@ -1 +1 @@
1
- {"version":3,"file":"utils.d.ts","sourceRoot":"","sources":["../src/utils.ts"],"names":[],"mappings":"AAIA,OAAO,EAAE,QAAQ,EAAE,MAAM,mBAAmB,CAAA;AAE5C;;;;GAIG;AACH,eAAO,MAAM,iBAAiB,GAAI,SAAS,MAAM,GAAG,SAAS,KAAG,OAG/D,CAAA;AAED,eAAO,MAAM,eAAe,GAAI,aAAU,KAAG,MAW5C,CAAA;AAED;;;GAGG;AACH,eAAO,MAAM,cAAc,QAAO,MAEjC,CAAA;AAED;;;;GAIG;AACH,eAAO,MAAM,aAAa,GAAI,QAAQ,MAAM,KAAG,OAG9C,CAAA;AAED;;;;;;;GAOG;AACH,eAAO,MAAM,iBAAiB,GAAI,aAAa,MAAM,KAAG,MAAM,CAAC,MAAM,EAAE,GAAG,CAAC,GAAG,IAsB7E,CAAA;AAED;;;;GAIG;AACH,eAAO,MAAM,yBAAyB,GAAI,YAAY,MAAM,KAAG,QAAQ,EAMtE,CAAA;AAED;;;;GAIG;AACH,eAAO,MAAM,kBAAkB,GAAI,YAAY,MAAM,KAAG,MAGvD,CAAA;AAKD,eAAO,MAAM,4BAA4B,GAAI,SAAS,MAAM,EAAE,YAAY,MAAM,KAAG,MAKlF,CAAA;AAGD,eAAO,MAAM,iBAAiB,QAAO,MAEpC,CAAA;AAGD,eAAO,MAAM,cAAc,GACzB,SAAS,MAAM,EACf,WAAW,MAAM,EACjB,kBAAqC,KACpC,IAsCF,CAAA"}
1
+ {"version":3,"file":"utils.d.ts","sourceRoot":"","sources":["../src/utils.ts"],"names":[],"mappings":"AAIA,OAAO,EAAE,QAAQ,EAAE,MAAM,mBAAmB,CAAA;AAE5C;;;;GAIG;AACH,eAAO,MAAM,iBAAiB,GAAI,SAAS,MAAM,GAAG,SAAS,KAAG,OAG/D,CAAA;AAED,eAAO,MAAM,eAAe,GAAI,aAAU,KAAG,MAW5C,CAAA;AAED;;;GAGG;AACH,eAAO,MAAM,cAAc,QAAO,MAEjC,CAAA;AAED;;;;GAIG;AACH,eAAO,MAAM,aAAa,GAAI,QAAQ,MAAM,KAAG,OAG9C,CAAA;AAED;;;;;;;GAOG;AACH,eAAO,MAAM,iBAAiB,GAAI,aAAa,MAAM,KAAG,MAAM,CAAC,MAAM,EAAE,GAAG,CAAC,GAAG,IAsB7E,CAAA;AAED;;;;;;;;;;;;;;;;;;;;;;;;;GAyBG;AACH,eAAO,MAAM,iBAAiB,GAAI,SAAS,MAAM,CAAC,MAAM,EAAE,GAAG,CAAC,KAAG,MAMhE,CAAA;AAED;;;;GAIG;AACH,eAAO,MAAM,yBAAyB,GAAI,YAAY,MAAM,KAAG,QAAQ,EAMtE,CAAA;AAED;;;;GAIG;AACH,eAAO,MAAM,kBAAkB,GAAI,YAAY,MAAM,KAAG,MAGvD,CAAA;AAKD,eAAO,MAAM,4BAA4B,GAAI,SAAS,MAAM,EAAE,YAAY,MAAM,KAAG,MAKlF,CAAA;AAGD,eAAO,MAAM,iBAAiB,QAAO,MAEpC,CAAA;AAGD,eAAO,MAAM,cAAc,GACzB,SAAS,MAAM,EACf,WAAW,MAAM,EACjB,kBAAqC,KACpC,IAsCF,CAAA"}
package/dist/utils.js CHANGED
@@ -69,6 +69,40 @@ export const decodeAccessToken = (accessToken) => {
69
69
  }
70
70
  return null;
71
71
  };
72
+ /**
73
+ * Encode a PaymentPayload object into an x402 access token string.
74
+ *
75
+ * Inverse of {@link decodeAccessToken}. Used by the MCP transport to turn the
76
+ * in-band `_meta["x402/payment"]` PaymentPayload object back into the
77
+ * base64url token string the facilitator's verify/settle APIs consume.
78
+ *
79
+ * The base64 envelope is transport-only: the EIP-712 signature lives inside
80
+ * `payload.authorization` / `payload.signature`, not over the base64 wrapper,
81
+ * so re-encoding a decoded (or foreign-encoded) payload is byte-safe for the
82
+ * facilitator — the invariant is semantic recovery, not byte-identity.
83
+ *
84
+ * Produces unpadded base64url with compact JSON (no spaces), matching the form
85
+ * {@link decodeAccessToken} accepts.
86
+ *
87
+ * Encodes UTF-8 bytes before base64 so it never throws on non-ASCII input — this
88
+ * runs on client-supplied `_meta["x402/payment"]`, and `btoa` alone throws a
89
+ * DOMException on code points > U+00FF. For ASCII JSON (all real x402
90
+ * PaymentPayloads: EIP-712 hex/decimal/signature fields) the output is
91
+ * byte-identical to `btoa(json)`, so the round-trip with {@link decodeAccessToken}
92
+ * is unchanged. `decodeAccessToken` is intentionally left as-is; a full UTF-8
93
+ * round-trip would additionally require decoding the bytes there.
94
+ *
95
+ * @param payload - The decoded PaymentPayload object (e.g. from `_meta["x402/payment"]`)
96
+ * @returns The base64url-encoded access token string (unpadded)
97
+ */
98
+ export const encodeAccessToken = (payload) => {
99
+ const json = JSON.stringify(payload);
100
+ const bytes = new TextEncoder().encode(json);
101
+ let binary = '';
102
+ for (const byte of bytes)
103
+ binary += String.fromCharCode(byte);
104
+ return btoa(binary).replace(/\+/g, '-').replace(/\//g, '_').replace(/=+$/, '');
105
+ };
72
106
  /**
73
107
  * It returns the list of endpoints that are used by agents/services implementing the Nevermined Query Protocol
74
108
  * @param serverHost - The host of the server where the agents/services are running
package/dist/utils.js.map CHANGED
@@ -1 +1 @@
1
- {"version":3,"file":"utils.js","sourceRoot":"","sources":["../src/utils.ts"],"names":[],"mappings":"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","sourcesContent":["import * as crypto from 'crypto'\nimport * as fs from 'fs'\nimport * as path from 'path'\nimport { v4 as uuidv4, validate as uuidValidate } from 'uuid'\nimport { Endpoint } from './common/types.js'\n\n/**\n * Validates if a string is a valid Ethereum address\n * @param address - the address to check\n * @returns true if it's a valid Ethereum address\n */\nexport const isEthereumAddress = (address: string | undefined): boolean => {\n if (address && address.match(/^0x[a-fA-F0-9]{40}$/) !== null) return true\n return false\n}\n\nexport const getRandomBigInt = (bits = 128): bigint => {\n const bytes = Math.ceil(bits / 8)\n const array = new Uint8Array(bytes)\n crypto.getRandomValues(array)\n\n let result = 0n\n for (const byte of array) {\n result = (result << 8n) | BigInt(byte)\n }\n\n return result\n}\n\n/**\n * It generates a random step id\n * @returns the step id\n */\nexport const generateStepId = (): string => {\n return `step-${uuidv4()}`\n}\n\n/**\n * It checks the step id has the right format\n * @param stepId - the step id to validate\n * @returns true if it's a valid step id\n */\nexport const isStepIdValid = (stepId: string): boolean => {\n if (!stepId.startsWith('step-')) return false\n return uuidValidate(stepId.substring(5))\n}\n\n/**\n * Decode an x402 access token to extract subscriber address and plan ID.\n * The x402 access token is a base64-encoded JSON document containing\n * session key information and permissions.\n *\n * @param accessToken - The x402 access token to decode (base64-encoded JSON)\n * @returns The decoded token data or null if invalid\n */\nexport const decodeAccessToken = (accessToken: string): Record<string, any> | null => {\n // Try base64-encoded JSON (x402 format)\n\n // Try URL-safe base64 first\n try {\n const padded = accessToken + '='.repeat((4 - (accessToken.length % 4)) % 4)\n const urlSafeDecoded = atob(padded.replace(/-/g, '+').replace(/_/g, '/'))\n return JSON.parse(urlSafeDecoded)\n } catch {\n // Continue to next attempt\n }\n\n // Try standard base64 (non-URL-safe)\n try {\n const padded = accessToken + '='.repeat((4 - (accessToken.length % 4)) % 4)\n const decoded = atob(padded)\n return JSON.parse(decoded)\n } catch {\n // Continue to return null\n }\n\n return null\n}\n\n/**\n * It returns the list of endpoints that are used by agents/services implementing the Nevermined Query Protocol\n * @param serverHost - The host of the server where the agents/services are running\n * @returns the list of endpoints\n */\nexport const getQueryProtocolEndpoints = (serverHost: string): Endpoint[] => {\n const url = new URL(serverHost)\n return [\n { POST: `${url.origin}/api/v1/agents/(.*)/tasks` },\n { GET: `${url.origin}/api/v1/agents/(.*)/tasks/(.*)` },\n ]\n}\n\n/**\n * Giving a server host it returns the URL to the OpenAPI documentation of the AI Hub\n * @param serverHost - the server host (i.e http://localhost:5000)\n * @returns\n */\nexport const getAIHubOpenApiUrl = (serverHost: string): string => {\n const url = new URL(serverHost)\n return `${url.origin}/api/v1/rest/docs-json`\n}\n\n///////////////////// OBSERVABILITY /////////////////////\n\n// Generate deterministic agent ID: if no argument, return AGENT_DID as is; if argument, hash it as before\nexport const generateDeterministicAgentId = (agentId: string, className?: string): string => {\n if (!className) return agentId\n const hash = crypto.createHash('sha256').update(className).digest('hex').substring(0, 32)\n // Format as UUID: 8-4-4-4-12\n return `${hash.substring(0, 8)}-${hash.substring(8, 12)}-${hash.substring(12, 16)}-${hash.substring(16, 20)}-${hash.substring(20, 32)}`\n}\n\n// Generate random session ID\nexport const generateSessionId = (): string => {\n return uuidv4()\n}\n\n// Log session information\nexport const logSessionInfo = (\n agentId: string,\n sessionId: string,\n agentName = 'SceneTechnicalExtractor',\n): void => {\n const timestamp = new Date().toISOString()\n const logsDir = path.join(__dirname, 'logs')\n\n // Ensure logs directory exists\n if (!fs.existsSync(logsDir)) {\n fs.mkdirSync(logsDir, { recursive: true })\n }\n\n // Create session-specific log file with timestamp format (YYYYMMDD_HHMMSS)\n const now = new Date()\n const timestampStr = now\n .toISOString()\n .replace(/[-:]/g, '') // Remove dashes and colons\n .replace(/T/, '_') // Replace T with underscore\n .substring(0, 15) // Take YYYYMMDD_HHMMSS format\n\n const sessionLogFile = path.join(logsDir, `session_${timestampStr}.txt`)\n\n // Check if session file already exists to avoid duplicating session ID\n let sessionExists = false\n if (fs.existsSync(sessionLogFile)) {\n sessionExists = true\n }\n\n // If session file doesn't exist, create it with session ID header\n if (!sessionExists) {\n const sessionHeader = `Session ID: ${sessionId}\\n`\n fs.writeFileSync(sessionLogFile, sessionHeader)\n }\n\n // Append agent information in the expected format\n const agentEntry = `${agentName}: ${agentId}\\n`\n fs.appendFileSync(sessionLogFile, agentEntry)\n\n console.log(\n `Session logged: Timestamp: ${timestamp}, Agent Name: ${agentName}, Agent ID: ${agentId}, Session ID: ${sessionId}`,\n )\n}\n"]}
1
+ {"version":3,"file":"utils.js","sourceRoot":"","sources":["../src/utils.ts"],"names":[],"mappings":"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","sourcesContent":["import * as crypto from 'crypto'\nimport * as fs from 'fs'\nimport * as path from 'path'\nimport { v4 as uuidv4, validate as uuidValidate } from 'uuid'\nimport { Endpoint } from './common/types.js'\n\n/**\n * Validates if a string is a valid Ethereum address\n * @param address - the address to check\n * @returns true if it's a valid Ethereum address\n */\nexport const isEthereumAddress = (address: string | undefined): boolean => {\n if (address && address.match(/^0x[a-fA-F0-9]{40}$/) !== null) return true\n return false\n}\n\nexport const getRandomBigInt = (bits = 128): bigint => {\n const bytes = Math.ceil(bits / 8)\n const array = new Uint8Array(bytes)\n crypto.getRandomValues(array)\n\n let result = 0n\n for (const byte of array) {\n result = (result << 8n) | BigInt(byte)\n }\n\n return result\n}\n\n/**\n * It generates a random step id\n * @returns the step id\n */\nexport const generateStepId = (): string => {\n return `step-${uuidv4()}`\n}\n\n/**\n * It checks the step id has the right format\n * @param stepId - the step id to validate\n * @returns true if it's a valid step id\n */\nexport const isStepIdValid = (stepId: string): boolean => {\n if (!stepId.startsWith('step-')) return false\n return uuidValidate(stepId.substring(5))\n}\n\n/**\n * Decode an x402 access token to extract subscriber address and plan ID.\n * The x402 access token is a base64-encoded JSON document containing\n * session key information and permissions.\n *\n * @param accessToken - The x402 access token to decode (base64-encoded JSON)\n * @returns The decoded token data or null if invalid\n */\nexport const decodeAccessToken = (accessToken: string): Record<string, any> | null => {\n // Try base64-encoded JSON (x402 format)\n\n // Try URL-safe base64 first\n try {\n const padded = accessToken + '='.repeat((4 - (accessToken.length % 4)) % 4)\n const urlSafeDecoded = atob(padded.replace(/-/g, '+').replace(/_/g, '/'))\n return JSON.parse(urlSafeDecoded)\n } catch {\n // Continue to next attempt\n }\n\n // Try standard base64 (non-URL-safe)\n try {\n const padded = accessToken + '='.repeat((4 - (accessToken.length % 4)) % 4)\n const decoded = atob(padded)\n return JSON.parse(decoded)\n } catch {\n // Continue to return null\n }\n\n return null\n}\n\n/**\n * Encode a PaymentPayload object into an x402 access token string.\n *\n * Inverse of {@link decodeAccessToken}. Used by the MCP transport to turn the\n * in-band `_meta[\"x402/payment\"]` PaymentPayload object back into the\n * base64url token string the facilitator's verify/settle APIs consume.\n *\n * The base64 envelope is transport-only: the EIP-712 signature lives inside\n * `payload.authorization` / `payload.signature`, not over the base64 wrapper,\n * so re-encoding a decoded (or foreign-encoded) payload is byte-safe for the\n * facilitator — the invariant is semantic recovery, not byte-identity.\n *\n * Produces unpadded base64url with compact JSON (no spaces), matching the form\n * {@link decodeAccessToken} accepts.\n *\n * Encodes UTF-8 bytes before base64 so it never throws on non-ASCII input — this\n * runs on client-supplied `_meta[\"x402/payment\"]`, and `btoa` alone throws a\n * DOMException on code points > U+00FF. For ASCII JSON (all real x402\n * PaymentPayloads: EIP-712 hex/decimal/signature fields) the output is\n * byte-identical to `btoa(json)`, so the round-trip with {@link decodeAccessToken}\n * is unchanged. `decodeAccessToken` is intentionally left as-is; a full UTF-8\n * round-trip would additionally require decoding the bytes there.\n *\n * @param payload - The decoded PaymentPayload object (e.g. from `_meta[\"x402/payment\"]`)\n * @returns The base64url-encoded access token string (unpadded)\n */\nexport const encodeAccessToken = (payload: Record<string, any>): string => {\n const json = JSON.stringify(payload)\n const bytes = new TextEncoder().encode(json)\n let binary = ''\n for (const byte of bytes) binary += String.fromCharCode(byte)\n return btoa(binary).replace(/\\+/g, '-').replace(/\\//g, '_').replace(/=+$/, '')\n}\n\n/**\n * It returns the list of endpoints that are used by agents/services implementing the Nevermined Query Protocol\n * @param serverHost - The host of the server where the agents/services are running\n * @returns the list of endpoints\n */\nexport const getQueryProtocolEndpoints = (serverHost: string): Endpoint[] => {\n const url = new URL(serverHost)\n return [\n { POST: `${url.origin}/api/v1/agents/(.*)/tasks` },\n { GET: `${url.origin}/api/v1/agents/(.*)/tasks/(.*)` },\n ]\n}\n\n/**\n * Giving a server host it returns the URL to the OpenAPI documentation of the AI Hub\n * @param serverHost - the server host (i.e http://localhost:5000)\n * @returns\n */\nexport const getAIHubOpenApiUrl = (serverHost: string): string => {\n const url = new URL(serverHost)\n return `${url.origin}/api/v1/rest/docs-json`\n}\n\n///////////////////// OBSERVABILITY /////////////////////\n\n// Generate deterministic agent ID: if no argument, return AGENT_DID as is; if argument, hash it as before\nexport const generateDeterministicAgentId = (agentId: string, className?: string): string => {\n if (!className) return agentId\n const hash = crypto.createHash('sha256').update(className).digest('hex').substring(0, 32)\n // Format as UUID: 8-4-4-4-12\n return `${hash.substring(0, 8)}-${hash.substring(8, 12)}-${hash.substring(12, 16)}-${hash.substring(16, 20)}-${hash.substring(20, 32)}`\n}\n\n// Generate random session ID\nexport const generateSessionId = (): string => {\n return uuidv4()\n}\n\n// Log session information\nexport const logSessionInfo = (\n agentId: string,\n sessionId: string,\n agentName = 'SceneTechnicalExtractor',\n): void => {\n const timestamp = new Date().toISOString()\n const logsDir = path.join(__dirname, 'logs')\n\n // Ensure logs directory exists\n if (!fs.existsSync(logsDir)) {\n fs.mkdirSync(logsDir, { recursive: true })\n }\n\n // Create session-specific log file with timestamp format (YYYYMMDD_HHMMSS)\n const now = new Date()\n const timestampStr = now\n .toISOString()\n .replace(/[-:]/g, '') // Remove dashes and colons\n .replace(/T/, '_') // Replace T with underscore\n .substring(0, 15) // Take YYYYMMDD_HHMMSS format\n\n const sessionLogFile = path.join(logsDir, `session_${timestampStr}.txt`)\n\n // Check if session file already exists to avoid duplicating session ID\n let sessionExists = false\n if (fs.existsSync(sessionLogFile)) {\n sessionExists = true\n }\n\n // If session file doesn't exist, create it with session ID header\n if (!sessionExists) {\n const sessionHeader = `Session ID: ${sessionId}\\n`\n fs.writeFileSync(sessionLogFile, sessionHeader)\n }\n\n // Append agent information in the expected format\n const agentEntry = `${agentName}: ${agentId}\\n`\n fs.appendFileSync(sessionLogFile, agentEntry)\n\n console.log(\n `Session logged: Timestamp: ${timestamp}, Agent Name: ${agentName}, Agent ID: ${agentId}, Session ID: ${sessionId}`,\n )\n}\n"]}
@@ -220,6 +220,27 @@ export declare function buildPaymentRequired(planId: string, options?: {
220
220
  scheme?: X402SchemeType;
221
221
  environment?: EnvironmentName;
222
222
  }): X402PaymentRequired;
223
+ /**
224
+ * Build an X402PaymentRequired object advertising one or more plans.
225
+ *
226
+ * Like {@link buildPaymentRequired} but produces one `accepts[]` entry per plan
227
+ * id, so a payment-required response can advertise every plan that unlocks the
228
+ * resource. For a single plan this is equivalent to {@link buildPaymentRequired}.
229
+ *
230
+ * @param planIds - The Nevermined plan identifiers (falls back to `['']` if empty)
231
+ * @param options - Same options as {@link buildPaymentRequired}
232
+ * @returns X402PaymentRequired object with one accepts entry per plan
233
+ */
234
+ export declare function buildPaymentRequiredForPlans(planIds: string[], options?: {
235
+ endpoint?: string;
236
+ agentId?: string;
237
+ httpVerb?: string;
238
+ network?: string;
239
+ description?: string;
240
+ mimeType?: string;
241
+ scheme?: X402SchemeType;
242
+ environment?: EnvironmentName;
243
+ }): X402PaymentRequired;
223
244
  /**
224
245
  * Resolve the network for a plan from its fiatPaymentProvider metadata.
225
246
  * For card-delegation plans, returns the provider ('stripe' or 'braintree').
@@ -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":"AAAA;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;GAyCG;AAEH,OAAO,EAAE,eAAe,EAAE,MAAM,yBAAyB,CAAA;AAGzD,OAAO,EACL,cAAc,EACd,iBAAiB,EACjB,cAAc,EAEf,MAAM,oBAAoB,CAAA;AAC3B,OAAO,KAAK,EAAE,eAAe,EAAE,MAAM,oBAAoB,CAAA;AACzD,OAAO,KAAK,EAAE,QAAQ,EAAE,MAAM,gBAAgB,CAAA;AAE9C;;GAEG;AACH,MAAM,WAAW,YAAY;IAC3B,iCAAiC;IACjC,GAAG,EAAE,MAAM,CAAA;IACX,iCAAiC;IACjC,WAAW,CAAC,EAAE,MAAM,CAAA;IACpB,6DAA6D;IAC7D,QAAQ,CAAC,EAAE,MAAM,CAAA;CAClB;AAED;;GAEG;AACH,MAAM,WAAW,eAAe;IAC9B,iCAAiC;IACjC,OAAO,CAAC,EAAE,MAAM,CAAA;IAChB,uBAAuB;IACvB,OAAO,CAAC,EAAE,MAAM,CAAA;IAChB,mCAAmC;IACnC,QAAQ,CAAC,EAAE,MAAM,CAAA;CAClB;AAED;;GAEG;AACH,MAAM,WAAW,UAAU;IACzB,sDAAsD;IACtD,MAAM,EAAE,MAAM,CAAA;IACd,iEAAiE;IACjE,OAAO,EAAE,MAAM,CAAA;IACf,8BAA8B;IAC9B,MAAM,EAAE,MAAM,CAAA;IACd,mCAAmC;IACnC,KAAK,CAAC,EAAE,eAAe,CAAA;CACxB;AAED;;GAEG;AACH,MAAM,WAAW,mBAAmB;IAClC,uCAAuC;IACvC,WAAW,EAAE,MAAM,CAAA;IACnB,mCAAmC;IACnC,KAAK,CAAC,EAAE,MAAM,CAAA;IACd,qCAAqC;IACrC,QAAQ,EAAE,YAAY,CAAA;IACtB,wCAAwC;IACxC,OAAO,EAAE,UAAU,EAAE,CAAA;IACrB,uDAAuD;IACvD,UAAU,EAAE,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,CAAA;CACpC;AAED;;GAEG;AACH,MAAM,WAAW,mBAAmB;IAClC,uBAAuB;IACvB,WAAW,EAAE,MAAM,CAAA;IACnB,gDAAgD;IAChD,QAAQ,EAAE,UAAU,CAAA;IACpB,0CAA0C;IAC1C,OAAO,EAAE;QACP,SAAS,EAAE,MAAM,CAAA;QACjB,aAAa,EAAE;YACb,IAAI,EAAE,MAAM,CAAA;YACZ,mBAAmB,EAAE,MAAM,CAAA;YAC3B,WAAW,EAAE,MAAM,EAAE,CAAA;SACtB,CAAA;KACF,CAAA;IACD,UAAU,EAAE,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,CAAA;CACpC;AAED;;GAEG;AACH,MAAM,WAAW,uBAAuB;IACtC,gDAAgD;IAChD,eAAe,EAAE,mBAAmB,CAAA;IACpC,6CAA6C;IAC7C,eAAe,EAAE,MAAM,CAAA;IACvB,2CAA2C;IAC3C,SAAS,CAAC,EAAE,MAAM,CAAA;CACnB;AAED;;;GAGG;AACH,MAAM,WAAW,uBAAuB;IACtC,iDAAiD;IACjD,OAAO,EAAE,OAAO,CAAA;IAChB,+DAA+D;IAC/D,aAAa,CAAC,EAAE,MAAM,CAAA;IACtB,oCAAoC;IACpC,KAAK,CAAC,EAAE,MAAM,CAAA;IACd,+EAA+E;IAC/E,OAAO,CAAC,EAAE,MAAM,CAAA;IAChB,yEAAyE;IACzE,cAAc,CAAC,EAAE,MAAM,CAAA;IACvB,mEAAmE;IACnE,WAAW,CAAC,EAAE,MAAM,CAAA;IACpB,qEAAqE;IACrE,YAAY,CAAC,EAAE,iBAAiB,CAAA;CACjC;AAED;;GAEG;AACH,MAAM,WAAW,uBAAuB;IACtC,gDAAgD;IAChD,eAAe,EAAE,mBAAmB,CAAA;IACpC,6CAA6C;IAC7C,eAAe,EAAE,MAAM,CAAA;IACvB,2CAA2C;IAC3C,SAAS,CAAC,EAAE,MAAM,CAAA;IAClB,kFAAkF;IAClF,cAAc,CAAC,EAAE,MAAM,CAAA;IACvB,oFAAoF;IACpF,KAAK,CAAC,EAAE,OAAO,CAAA;IACf,uHAAuH;IACvH,aAAa,CAAC,EAAE,MAAM,CAAA;CACvB;AAED;;;GAGG;AACH,MAAM,WAAW,uBAAuB;IACtC,wCAAwC;IACxC,OAAO,EAAE,OAAO,CAAA;IAChB,uEAAuE;IACvE,WAAW,CAAC,EAAE,MAAM,CAAA;IACpB,oCAAoC;IACpC,KAAK,CAAC,EAAE,MAAM,CAAA;IACd,sEAAsE;IACtE,WAAW,EAAE,MAAM,CAAA;IACnB,qDAAqD;IACrD,OAAO,EAAE,MAAM,CAAA;IACf,wDAAwD;IACxD,eAAe,CAAC,EAAE,MAAM,CAAA;IACxB,4DAA4D;IAC5D,gBAAgB,CAAC,EAAE,MAAM,CAAA;IACzB,6FAA6F;IAC7F,OAAO,CAAC,EAAE,MAAM,CAAA;CACjB;AAED;;;;;;;;;;;;;;;;;;;;;;;;;;GA0BG;AACH,wBAAgB,oBAAoB,CAClC,MAAM,EAAE,MAAM,EACd,OAAO,CAAC,EAAE;IACR,QAAQ,CAAC,EAAE,MAAM,CAAA;IACjB,OAAO,CAAC,EAAE,MAAM,CAAA;IAChB,QAAQ,CAAC,EAAE,MAAM,CAAA;IACjB,OAAO,CAAC,EAAE,MAAM,CAAA;IAChB,WAAW,CAAC,EAAE,MAAM,CAAA;IACpB,QAAQ,CAAC,EAAE,MAAM,CAAA;IACjB,MAAM,CAAC,EAAE,cAAc,CAAA;IACvB,WAAW,CAAC,EAAE,eAAe,CAAA;CAC9B,GACA,mBAAmB,CAqCrB;AAED;;;;;;;;;;GAUG;AACH,wBAAgB,4BAA4B,CAC1C,OAAO,EAAE,MAAM,EAAE,EACjB,OAAO,CAAC,EAAE;IACR,QAAQ,CAAC,EAAE,MAAM,CAAA;IACjB,OAAO,CAAC,EAAE,MAAM,CAAA;IAChB,QAAQ,CAAC,EAAE,MAAM,CAAA;IACjB,OAAO,CAAC,EAAE,MAAM,CAAA;IAChB,WAAW,CAAC,EAAE,MAAM,CAAA;IACpB,QAAQ,CAAC,EAAE,MAAM,CAAA;IACjB,MAAM,CAAC,EAAE,cAAc,CAAA;IACvB,WAAW,CAAC,EAAE,eAAe,CAAA;CAC9B,GACA,mBAAmB,CAuCrB;AAgCD;;;;GAIG;AACH,wBAAsB,cAAc,CAClC,QAAQ,EAAE,QAAQ,EAClB,MAAM,EAAE,MAAM,EACd,eAAe,CAAC,EAAE,MAAM,GACvB,OAAO,CAAC,MAAM,GAAG,SAAS,CAAC,CAK7B;AAED;;;;;;;;;GASG;AACH,wBAAsB,aAAa,CACjC,QAAQ,EAAE,QAAQ,EAClB,MAAM,EAAE,MAAM,EACd,cAAc,CAAC,EAAE,cAAc,GAC9B,OAAO,CAAC,cAAc,CAAC,CAIzB;AAED;;;;GAIG;AACH,qBAAa,cAAe,SAAQ,eAAe;IACjD;;;;;OAKG;IACH,MAAM,CAAC,WAAW,CAAC,OAAO,EAAE,cAAc,GAAG,cAAc;IAI3D;;;;;;;;;;;;;;OAcG;IACG,iBAAiB,CAAC,MAAM,EAAE,uBAAuB,GAAG,OAAO,CAAC,uBAAuB,CAAC;IAkD1F;;;;;;;;;;;;;;;;;;OAkBG;IACG,iBAAiB,CAAC,MAAM,EAAE,uBAAuB,GAAG,OAAO,CAAC,uBAAuB,CAAC;CA2D3F"}
@@ -98,6 +98,45 @@ export function buildPaymentRequired(planId, options) {
98
98
  extensions: {},
99
99
  };
100
100
  }
101
+ /**
102
+ * Build an X402PaymentRequired object advertising one or more plans.
103
+ *
104
+ * Like {@link buildPaymentRequired} but produces one `accepts[]` entry per plan
105
+ * id, so a payment-required response can advertise every plan that unlocks the
106
+ * resource. For a single plan this is equivalent to {@link buildPaymentRequired}.
107
+ *
108
+ * @param planIds - The Nevermined plan identifiers (falls back to `['']` if empty)
109
+ * @param options - Same options as {@link buildPaymentRequired}
110
+ * @returns X402PaymentRequired object with one accepts entry per plan
111
+ */
112
+ export function buildPaymentRequiredForPlans(planIds, options) {
113
+ const ids = planIds.length > 0 ? planIds : [''];
114
+ if (ids.length === 1) {
115
+ return buildPaymentRequired(ids[0], options);
116
+ }
117
+ const { endpoint, agentId, httpVerb, scheme = 'nvm:erc4337', network, description, mimeType, environment, } = options || {};
118
+ const resolvedNetwork = network ?? getDefaultNetwork(scheme, environment);
119
+ const extra = {
120
+ version: '1',
121
+ ...(agentId && { agentId }),
122
+ ...(httpVerb && { httpVerb }),
123
+ };
124
+ return {
125
+ x402Version: 2,
126
+ resource: {
127
+ url: endpoint || '',
128
+ ...(description && { description }),
129
+ ...(mimeType && { mimeType }),
130
+ },
131
+ accepts: ids.map((planId) => ({
132
+ scheme,
133
+ network: resolvedNetwork,
134
+ planId,
135
+ extra,
136
+ })),
137
+ extensions: {},
138
+ };
139
+ }
101
140
  const CACHE_TTL_MS = 5 * 60 * 1000; // 5 minutes
102
141
  const planMetadataCache = new Map();
103
142
  async function fetchPlanMetadata(payments, planId) {