@nevermined-io/payments 1.1.4 → 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.
@@ -0,0 +1,146 @@
1
+ /**
2
+ * LangChain tool wrapper for Nevermined payment protection using the x402 protocol.
3
+ *
4
+ * Wraps a LangChain.js tool implementation function to:
5
+ *
6
+ * 1. Extract the x402 payment token from `config.configurable.payment_token`
7
+ * 2. Verify the subscriber has sufficient credits
8
+ * 3. Execute the wrapped tool function
9
+ * 4. Settle (burn) credits after successful execution
10
+ *
11
+ * Payment errors throw `PaymentRequiredError` so LangChain agents can catch and
12
+ * surface them to the user. The error carries the full `X402PaymentRequired`
13
+ * object for programmatic token acquisition.
14
+ *
15
+ * The `credits` option accepts two forms:
16
+ * - **Static number**: `credits: 1` — always charges 1 credit
17
+ * - **Function**: `credits: (ctx) => Math.max(1, ctx.result.length / 100)` — dynamic
18
+ *
19
+ * When `credits` is a function, it receives `{ args, result }` after tool execution.
20
+ *
21
+ * @example
22
+ * ```typescript
23
+ * import { tool } from '@langchain/core/tools'
24
+ * import { z } from 'zod'
25
+ * import { Payments } from '@nevermined-io/payments'
26
+ * import { requiresPayment } from '@nevermined-io/payments/langchain'
27
+ *
28
+ * const payments = Payments.getInstance({ nvmApiKey: '...', environment: 'testing' })
29
+ *
30
+ * const searchData = tool(
31
+ * requiresPayment(
32
+ * (args) => `Results for ${args.query}`,
33
+ * { payments, planId: PLAN_ID, credits: 1 }
34
+ * ),
35
+ * { name: 'search_data', description: 'Search for data', schema: z.object({ query: z.string() }) }
36
+ * )
37
+ *
38
+ * // Invoke with payment token
39
+ * const result = await searchData.invoke(
40
+ * { query: 'AI trends' },
41
+ * { configurable: { payment_token: accessToken } }
42
+ * )
43
+ * ```
44
+ */
45
+ import type { Payments } from '../../payments.js';
46
+ import { type X402PaymentRequired } from '../facilitator-api.js';
47
+ /**
48
+ * Context passed to a dynamic credits function after tool execution.
49
+ */
50
+ export interface CreditsContext {
51
+ /** The tool's input arguments */
52
+ args: Record<string, unknown>;
53
+ /** The tool's return value */
54
+ result: unknown;
55
+ }
56
+ /**
57
+ * Credits can be a static number or a function that receives
58
+ * `{ args, result }` and returns the number of credits to charge.
59
+ */
60
+ export type CreditsCallable = (ctx: CreditsContext) => number;
61
+ /**
62
+ * Options for the `requiresPayment` wrapper.
63
+ */
64
+ export interface RequiresPaymentOptions {
65
+ /** The Payments instance (with payments.facilitator) */
66
+ payments: Payments;
67
+ /** Single plan ID to accept */
68
+ planId: string;
69
+ /** Number of credits to charge, or a function for dynamic pricing (default: 1) */
70
+ credits?: number | CreditsCallable;
71
+ /** Optional agent identifier */
72
+ agentId?: string;
73
+ /** Blockchain network in CAIP-2 format (default: 'eip155:84532' for Base Sepolia) */
74
+ network?: string;
75
+ }
76
+ /**
77
+ * Thrown when payment verification fails or no token is provided.
78
+ *
79
+ * Carries the `X402PaymentRequired` object so callers can inspect
80
+ * accepted plans and acquire the correct payment token.
81
+ */
82
+ export declare class PaymentRequiredError extends Error {
83
+ /** The x402 PaymentRequired object for programmatic token acquisition */
84
+ paymentRequired: X402PaymentRequired | undefined;
85
+ constructor(message: string, paymentRequired?: X402PaymentRequired);
86
+ }
87
+ /**
88
+ * Payment context stored in `config.configurable.payment_context` after verification.
89
+ */
90
+ export interface PaymentContext {
91
+ /** The x402 access token */
92
+ token: string;
93
+ /** The payment required object */
94
+ paymentRequired: X402PaymentRequired;
95
+ /** Number of credits to settle */
96
+ creditsToSettle: number;
97
+ /** Whether verification was successful */
98
+ verified: boolean;
99
+ /** Agent request ID for observability tracking */
100
+ agentRequestId?: string;
101
+ /** Agent request context for observability */
102
+ agentRequest?: unknown;
103
+ }
104
+ /**
105
+ * Wraps a LangChain.js tool implementation with x402 payment verification and settlement.
106
+ *
107
+ * This is a higher-order function that takes the tool's implementation function and
108
+ * payment options, returning a new function with the same signature that:
109
+ *
110
+ * 1. Extracts the payment token from `config.configurable.payment_token`
111
+ * 2. Verifies the subscriber has sufficient credits
112
+ * 3. Calls the original tool function
113
+ * 4. Settles (burns) credits
114
+ * 5. Stores `payment_context` and `payment_settlement` in `config.configurable`
115
+ *
116
+ * @param fn - The tool implementation function: `(args, config?) => result`
117
+ * @param options - Payment configuration
118
+ * @returns Wrapped function with the same signature
119
+ *
120
+ * @example Static credits
121
+ * ```typescript
122
+ * const searchData = tool(
123
+ * requiresPayment(
124
+ * (args) => `Results for ${args.query}`,
125
+ * { payments, planId: PLAN_ID, credits: 1 }
126
+ * ),
127
+ * { name: 'search_data', description: 'Search', schema: z.object({ query: z.string() }) }
128
+ * )
129
+ * ```
130
+ *
131
+ * @example Dynamic credits
132
+ * ```typescript
133
+ * const summarize = tool(
134
+ * requiresPayment(
135
+ * (args) => `Summary of ${args.text}`,
136
+ * {
137
+ * payments, planId: PLAN_ID,
138
+ * credits: (ctx) => Math.max(1, Math.floor(String(ctx.result).length / 100)),
139
+ * }
140
+ * ),
141
+ * { name: 'summarize', description: 'Summarize text', schema: z.object({ text: z.string() }) }
142
+ * )
143
+ * ```
144
+ */
145
+ export declare function requiresPayment<TArgs extends Record<string, unknown>, TResult>(fn: (args: TArgs, config?: unknown) => TResult | Promise<TResult>, options: RequiresPaymentOptions): (args: TArgs, config?: unknown) => Promise<TResult>;
146
+ //# sourceMappingURL=decorator.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"decorator.d.ts","sourceRoot":"","sources":["../../../src/x402/langchain/decorator.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;GA2CG;AAEH,OAAO,KAAK,EAAE,QAAQ,EAAE,MAAM,mBAAmB,CAAA;AACjD,OAAO,EAEL,KAAK,mBAAmB,EAEzB,MAAM,uBAAuB,CAAA;AAE9B;;GAEG;AACH,MAAM,WAAW,cAAc;IAC7B,iCAAiC;IACjC,IAAI,EAAE,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,CAAA;IAC7B,8BAA8B;IAC9B,MAAM,EAAE,OAAO,CAAA;CAChB;AAED;;;GAGG;AACH,MAAM,MAAM,eAAe,GAAG,CAAC,GAAG,EAAE,cAAc,KAAK,MAAM,CAAA;AAE7D;;GAEG;AACH,MAAM,WAAW,sBAAsB;IACrC,wDAAwD;IACxD,QAAQ,EAAE,QAAQ,CAAA;IAClB,+BAA+B;IAC/B,MAAM,EAAE,MAAM,CAAA;IACd,kFAAkF;IAClF,OAAO,CAAC,EAAE,MAAM,GAAG,eAAe,CAAA;IAClC,gCAAgC;IAChC,OAAO,CAAC,EAAE,MAAM,CAAA;IAChB,qFAAqF;IACrF,OAAO,CAAC,EAAE,MAAM,CAAA;CACjB;AAED;;;;;GAKG;AACH,qBAAa,oBAAqB,SAAQ,KAAK;IAC7C,yEAAyE;IACzE,eAAe,EAAE,mBAAmB,GAAG,SAAS,CAAA;gBAEpC,OAAO,EAAE,MAAM,EAAE,eAAe,CAAC,EAAE,mBAAmB;CAKnE;AAED;;GAEG;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,kDAAkD;IAClD,cAAc,CAAC,EAAE,MAAM,CAAA;IACvB,8CAA8C;IAC9C,YAAY,CAAC,EAAE,OAAO,CAAA;CACvB;AA8BD;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;GAwCG;AACH,wBAAgB,eAAe,CAAC,KAAK,SAAS,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,EAAE,OAAO,EAC5E,EAAE,EAAE,CAAC,IAAI,EAAE,KAAK,EAAE,MAAM,CAAC,EAAE,OAAO,KAAK,OAAO,GAAG,OAAO,CAAC,OAAO,CAAC,EACjE,OAAO,EAAE,sBAAsB,GAC9B,CAAC,IAAI,EAAE,KAAK,EAAE,MAAM,CAAC,EAAE,OAAO,KAAK,OAAO,CAAC,OAAO,CAAC,CAiFrD"}
@@ -0,0 +1,190 @@
1
+ /**
2
+ * LangChain tool wrapper for Nevermined payment protection using the x402 protocol.
3
+ *
4
+ * Wraps a LangChain.js tool implementation function to:
5
+ *
6
+ * 1. Extract the x402 payment token from `config.configurable.payment_token`
7
+ * 2. Verify the subscriber has sufficient credits
8
+ * 3. Execute the wrapped tool function
9
+ * 4. Settle (burn) credits after successful execution
10
+ *
11
+ * Payment errors throw `PaymentRequiredError` so LangChain agents can catch and
12
+ * surface them to the user. The error carries the full `X402PaymentRequired`
13
+ * object for programmatic token acquisition.
14
+ *
15
+ * The `credits` option accepts two forms:
16
+ * - **Static number**: `credits: 1` — always charges 1 credit
17
+ * - **Function**: `credits: (ctx) => Math.max(1, ctx.result.length / 100)` — dynamic
18
+ *
19
+ * When `credits` is a function, it receives `{ args, result }` after tool execution.
20
+ *
21
+ * @example
22
+ * ```typescript
23
+ * import { tool } from '@langchain/core/tools'
24
+ * import { z } from 'zod'
25
+ * import { Payments } from '@nevermined-io/payments'
26
+ * import { requiresPayment } from '@nevermined-io/payments/langchain'
27
+ *
28
+ * const payments = Payments.getInstance({ nvmApiKey: '...', environment: 'testing' })
29
+ *
30
+ * const searchData = tool(
31
+ * requiresPayment(
32
+ * (args) => `Results for ${args.query}`,
33
+ * { payments, planId: PLAN_ID, credits: 1 }
34
+ * ),
35
+ * { name: 'search_data', description: 'Search for data', schema: z.object({ query: z.string() }) }
36
+ * )
37
+ *
38
+ * // Invoke with payment token
39
+ * const result = await searchData.invoke(
40
+ * { query: 'AI trends' },
41
+ * { configurable: { payment_token: accessToken } }
42
+ * )
43
+ * ```
44
+ */
45
+ import { buildPaymentRequired, } from '../facilitator-api.js';
46
+ /**
47
+ * Thrown when payment verification fails or no token is provided.
48
+ *
49
+ * Carries the `X402PaymentRequired` object so callers can inspect
50
+ * accepted plans and acquire the correct payment token.
51
+ */
52
+ export class PaymentRequiredError extends Error {
53
+ constructor(message, paymentRequired) {
54
+ super(message);
55
+ this.name = 'PaymentRequiredError';
56
+ this.paymentRequired = paymentRequired;
57
+ }
58
+ }
59
+ /**
60
+ * Extract the payment token from a LangChain RunnableConfig.
61
+ *
62
+ * In LangChain.js, the config is the optional second parameter to tool functions:
63
+ * `(args, config?) => ...` where config is a `RunnableConfig`.
64
+ */
65
+ function extractPaymentToken(config) {
66
+ if (config == null || typeof config !== 'object')
67
+ return null;
68
+ const configurable = config.configurable;
69
+ if (configurable == null || typeof configurable !== 'object')
70
+ return null;
71
+ const token = configurable.payment_token;
72
+ return typeof token === 'string' ? token : null;
73
+ }
74
+ /**
75
+ * Store a value in config.configurable if available.
76
+ */
77
+ function storeInConfigurable(config, key, value) {
78
+ if (config == null || typeof config !== 'object')
79
+ return;
80
+ const configurable = config.configurable;
81
+ if (configurable == null || typeof configurable !== 'object')
82
+ return;
83
+ configurable[key] = value;
84
+ }
85
+ /**
86
+ * Wraps a LangChain.js tool implementation with x402 payment verification and settlement.
87
+ *
88
+ * This is a higher-order function that takes the tool's implementation function and
89
+ * payment options, returning a new function with the same signature that:
90
+ *
91
+ * 1. Extracts the payment token from `config.configurable.payment_token`
92
+ * 2. Verifies the subscriber has sufficient credits
93
+ * 3. Calls the original tool function
94
+ * 4. Settles (burns) credits
95
+ * 5. Stores `payment_context` and `payment_settlement` in `config.configurable`
96
+ *
97
+ * @param fn - The tool implementation function: `(args, config?) => result`
98
+ * @param options - Payment configuration
99
+ * @returns Wrapped function with the same signature
100
+ *
101
+ * @example Static credits
102
+ * ```typescript
103
+ * const searchData = tool(
104
+ * requiresPayment(
105
+ * (args) => `Results for ${args.query}`,
106
+ * { payments, planId: PLAN_ID, credits: 1 }
107
+ * ),
108
+ * { name: 'search_data', description: 'Search', schema: z.object({ query: z.string() }) }
109
+ * )
110
+ * ```
111
+ *
112
+ * @example Dynamic credits
113
+ * ```typescript
114
+ * const summarize = tool(
115
+ * requiresPayment(
116
+ * (args) => `Summary of ${args.text}`,
117
+ * {
118
+ * payments, planId: PLAN_ID,
119
+ * credits: (ctx) => Math.max(1, Math.floor(String(ctx.result).length / 100)),
120
+ * }
121
+ * ),
122
+ * { name: 'summarize', description: 'Summarize text', schema: z.object({ text: z.string() }) }
123
+ * )
124
+ * ```
125
+ */
126
+ export function requiresPayment(fn, options) {
127
+ const { payments, planId, credits = 1, agentId, network } = options;
128
+ return async (args, config) => {
129
+ // Build payment required object
130
+ const paymentRequired = buildPaymentRequired(planId, {
131
+ endpoint: fn.name || 'tool',
132
+ agentId,
133
+ network,
134
+ });
135
+ // Extract token from config.configurable.payment_token
136
+ const token = extractPaymentToken(config);
137
+ if (!token) {
138
+ throw new PaymentRequiredError("Payment required: missing payment_token in config.configurable", paymentRequired);
139
+ }
140
+ // Resolve pre-execution credits (static only; callable deferred to post-execution)
141
+ const creditsToVerify = typeof credits === 'number' ? credits : 1;
142
+ // Verify permissions
143
+ let verification;
144
+ try {
145
+ verification = await payments.facilitator.verifyPermissions({
146
+ paymentRequired,
147
+ x402AccessToken: token,
148
+ maxAmount: BigInt(creditsToVerify),
149
+ });
150
+ }
151
+ catch (error) {
152
+ throw new PaymentRequiredError(`Payment verification failed: ${error instanceof Error ? error.message : String(error)}`, paymentRequired);
153
+ }
154
+ if (!verification.isValid) {
155
+ throw new PaymentRequiredError(`Payment verification failed: ${verification.invalidReason || 'Insufficient credits or invalid token'}`, paymentRequired);
156
+ }
157
+ // Store payment context
158
+ const paymentContext = {
159
+ token,
160
+ paymentRequired,
161
+ creditsToSettle: creditsToVerify,
162
+ verified: true,
163
+ agentRequestId: verification.agentRequest?.agentRequestId || verification.agentRequestId,
164
+ agentRequest: verification.agentRequest,
165
+ };
166
+ storeInConfigurable(config, 'payment_context', paymentContext);
167
+ // Execute the tool function
168
+ const result = await fn(args, config);
169
+ // Resolve final credits (may be dynamic based on result)
170
+ const finalCredits = typeof credits === 'function'
171
+ ? credits({ args: args, result })
172
+ : credits;
173
+ // Settle credits
174
+ try {
175
+ const settlement = await payments.facilitator.settlePermissions({
176
+ paymentRequired,
177
+ x402AccessToken: token,
178
+ maxAmount: BigInt(finalCredits),
179
+ agentRequestId: paymentContext.agentRequestId,
180
+ });
181
+ storeInConfigurable(config, 'payment_settlement', settlement);
182
+ }
183
+ catch (settleError) {
184
+ console.error('Payment settlement failed:', settleError);
185
+ // Still return result even if settlement fails
186
+ }
187
+ return result;
188
+ };
189
+ }
190
+ //# sourceMappingURL=decorator.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"decorator.js","sourceRoot":"","sources":["../../../src/x402/langchain/decorator.ts"],"names":[],"mappings":"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","sourcesContent":["/**\n * LangChain tool wrapper for Nevermined payment protection using the x402 protocol.\n *\n * Wraps a LangChain.js tool implementation function to:\n *\n * 1. Extract the x402 payment token from `config.configurable.payment_token`\n * 2. Verify the subscriber has sufficient credits\n * 3. Execute the wrapped tool function\n * 4. Settle (burn) credits after successful execution\n *\n * Payment errors throw `PaymentRequiredError` so LangChain agents can catch and\n * surface them to the user. The error carries the full `X402PaymentRequired`\n * object for programmatic token acquisition.\n *\n * The `credits` option accepts two forms:\n * - **Static number**: `credits: 1` — always charges 1 credit\n * - **Function**: `credits: (ctx) => Math.max(1, ctx.result.length / 100)` — dynamic\n *\n * When `credits` is a function, it receives `{ args, result }` after tool execution.\n *\n * @example\n * ```typescript\n * import { tool } from '@langchain/core/tools'\n * import { z } from 'zod'\n * import { Payments } from '@nevermined-io/payments'\n * import { requiresPayment } from '@nevermined-io/payments/langchain'\n *\n * const payments = Payments.getInstance({ nvmApiKey: '...', environment: 'testing' })\n *\n * const searchData = tool(\n * requiresPayment(\n * (args) => `Results for ${args.query}`,\n * { payments, planId: PLAN_ID, credits: 1 }\n * ),\n * { name: 'search_data', description: 'Search for data', schema: z.object({ query: z.string() }) }\n * )\n *\n * // Invoke with payment token\n * const result = await searchData.invoke(\n * { query: 'AI trends' },\n * { configurable: { payment_token: accessToken } }\n * )\n * ```\n */\n\nimport type { Payments } from '../../payments.js'\nimport {\n buildPaymentRequired,\n type X402PaymentRequired,\n type VerifyPermissionsResult,\n} from '../facilitator-api.js'\n\n/**\n * Context passed to a dynamic credits function after tool execution.\n */\nexport interface CreditsContext {\n /** The tool's input arguments */\n args: Record<string, unknown>\n /** The tool's return value */\n result: unknown\n}\n\n/**\n * Credits can be a static number or a function that receives\n * `{ args, result }` and returns the number of credits to charge.\n */\nexport type CreditsCallable = (ctx: CreditsContext) => number\n\n/**\n * Options for the `requiresPayment` wrapper.\n */\nexport interface RequiresPaymentOptions {\n /** The Payments instance (with payments.facilitator) */\n payments: Payments\n /** Single plan ID to accept */\n planId: string\n /** Number of credits to charge, or a function for dynamic pricing (default: 1) */\n credits?: number | CreditsCallable\n /** Optional agent identifier */\n agentId?: string\n /** Blockchain network in CAIP-2 format (default: 'eip155:84532' for Base Sepolia) */\n network?: string\n}\n\n/**\n * Thrown when payment verification fails or no token is provided.\n *\n * Carries the `X402PaymentRequired` object so callers can inspect\n * accepted plans and acquire the correct payment token.\n */\nexport class PaymentRequiredError extends Error {\n /** The x402 PaymentRequired object for programmatic token acquisition */\n paymentRequired: X402PaymentRequired | undefined\n\n constructor(message: string, paymentRequired?: X402PaymentRequired) {\n super(message)\n this.name = 'PaymentRequiredError'\n this.paymentRequired = paymentRequired\n }\n}\n\n/**\n * Payment context stored in `config.configurable.payment_context` after verification.\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 ID for observability tracking */\n agentRequestId?: string\n /** Agent request context for observability */\n agentRequest?: unknown\n}\n\n/**\n * Extract the payment token from a LangChain RunnableConfig.\n *\n * In LangChain.js, the config is the optional second parameter to tool functions:\n * `(args, config?) => ...` where config is a `RunnableConfig`.\n */\nfunction extractPaymentToken(config: unknown): string | null {\n if (config == null || typeof config !== 'object') return null\n\n const configurable = (config as Record<string, unknown>).configurable\n if (configurable == null || typeof configurable !== 'object') return null\n\n const token = (configurable as Record<string, unknown>).payment_token\n return typeof token === 'string' ? token : null\n}\n\n/**\n * Store a value in config.configurable if available.\n */\nfunction storeInConfigurable(config: unknown, key: string, value: unknown): void {\n if (config == null || typeof config !== 'object') return\n\n const configurable = (config as Record<string, unknown>).configurable\n if (configurable == null || typeof configurable !== 'object') return\n\n ;(configurable as Record<string, unknown>)[key] = value\n}\n\n/**\n * Wraps a LangChain.js tool implementation with x402 payment verification and settlement.\n *\n * This is a higher-order function that takes the tool's implementation function and\n * payment options, returning a new function with the same signature that:\n *\n * 1. Extracts the payment token from `config.configurable.payment_token`\n * 2. Verifies the subscriber has sufficient credits\n * 3. Calls the original tool function\n * 4. Settles (burns) credits\n * 5. Stores `payment_context` and `payment_settlement` in `config.configurable`\n *\n * @param fn - The tool implementation function: `(args, config?) => result`\n * @param options - Payment configuration\n * @returns Wrapped function with the same signature\n *\n * @example Static credits\n * ```typescript\n * const searchData = tool(\n * requiresPayment(\n * (args) => `Results for ${args.query}`,\n * { payments, planId: PLAN_ID, credits: 1 }\n * ),\n * { name: 'search_data', description: 'Search', schema: z.object({ query: z.string() }) }\n * )\n * ```\n *\n * @example Dynamic credits\n * ```typescript\n * const summarize = tool(\n * requiresPayment(\n * (args) => `Summary of ${args.text}`,\n * {\n * payments, planId: PLAN_ID,\n * credits: (ctx) => Math.max(1, Math.floor(String(ctx.result).length / 100)),\n * }\n * ),\n * { name: 'summarize', description: 'Summarize text', schema: z.object({ text: z.string() }) }\n * )\n * ```\n */\nexport function requiresPayment<TArgs extends Record<string, unknown>, TResult>(\n fn: (args: TArgs, config?: unknown) => TResult | Promise<TResult>,\n options: RequiresPaymentOptions,\n): (args: TArgs, config?: unknown) => Promise<TResult> {\n const { payments, planId, credits = 1, agentId, network } = options\n\n return async (args: TArgs, config?: unknown): Promise<TResult> => {\n // Build payment required object\n const paymentRequired = buildPaymentRequired(planId, {\n endpoint: fn.name || 'tool',\n agentId,\n network,\n })\n\n // Extract token from config.configurable.payment_token\n const token = extractPaymentToken(config)\n if (!token) {\n throw new PaymentRequiredError(\n \"Payment required: missing payment_token in config.configurable\",\n paymentRequired,\n )\n }\n\n // Resolve pre-execution credits (static only; callable deferred to post-execution)\n const creditsToVerify = typeof credits === 'number' ? credits : 1\n\n // Verify permissions\n let verification: VerifyPermissionsResult\n try {\n verification = await payments.facilitator.verifyPermissions({\n paymentRequired,\n x402AccessToken: token,\n maxAmount: BigInt(creditsToVerify),\n })\n } catch (error) {\n throw new PaymentRequiredError(\n `Payment verification failed: ${error instanceof Error ? error.message : String(error)}`,\n paymentRequired,\n )\n }\n\n if (!verification.isValid) {\n throw new PaymentRequiredError(\n `Payment verification failed: ${verification.invalidReason || 'Insufficient credits or invalid token'}`,\n paymentRequired,\n )\n }\n\n // Store payment context\n const paymentContext: PaymentContext = {\n token,\n paymentRequired,\n creditsToSettle: creditsToVerify,\n verified: true,\n agentRequestId: verification.agentRequest?.agentRequestId || verification.agentRequestId,\n agentRequest: verification.agentRequest,\n }\n storeInConfigurable(config, 'payment_context', paymentContext)\n\n // Execute the tool function\n const result = await fn(args, config)\n\n // Resolve final credits (may be dynamic based on result)\n const finalCredits =\n typeof credits === 'function'\n ? credits({ args: args as Record<string, unknown>, result })\n : credits\n\n // Settle credits\n try {\n const settlement = await payments.facilitator.settlePermissions({\n paymentRequired,\n x402AccessToken: token,\n maxAmount: BigInt(finalCredits),\n agentRequestId: paymentContext.agentRequestId,\n })\n storeInConfigurable(config, 'payment_settlement', settlement)\n } catch (settleError) {\n console.error('Payment settlement failed:', settleError)\n // Still return result even if settlement fails\n }\n\n return result\n }\n}\n"]}
@@ -0,0 +1,5 @@
1
+ /**
2
+ * LangChain integration for Nevermined payment protection using the x402 protocol.
3
+ */
4
+ export { requiresPayment, PaymentRequiredError, type RequiresPaymentOptions, type CreditsCallable, type CreditsContext, type PaymentContext, } from './decorator.js';
5
+ //# sourceMappingURL=index.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../../src/x402/langchain/index.ts"],"names":[],"mappings":"AAAA;;GAEG;AAEH,OAAO,EACL,eAAe,EACf,oBAAoB,EACpB,KAAK,sBAAsB,EAC3B,KAAK,eAAe,EACpB,KAAK,cAAc,EACnB,KAAK,cAAc,GACpB,MAAM,gBAAgB,CAAA"}
@@ -0,0 +1,5 @@
1
+ /**
2
+ * LangChain integration for Nevermined payment protection using the x402 protocol.
3
+ */
4
+ export { requiresPayment, PaymentRequiredError, } from './decorator.js';
5
+ //# sourceMappingURL=index.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"index.js","sourceRoot":"","sources":["../../../src/x402/langchain/index.ts"],"names":[],"mappings":"AAAA;;GAEG;AAEH,OAAO,EACL,eAAe,EACf,oBAAoB,GAKrB,MAAM,gBAAgB,CAAA","sourcesContent":["/**\n * LangChain integration for Nevermined payment protection using the x402 protocol.\n */\n\nexport {\n requiresPayment,\n PaymentRequiredError,\n type RequiresPaymentOptions,\n type CreditsCallable,\n type CreditsContext,\n type PaymentContext,\n} from './decorator.js'\n"]}
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@nevermined-io/payments",
3
- "version": "1.1.4",
3
+ "version": "1.1.5",
4
4
  "description": "Typescript SDK to interact with the Nevermined Payments Protocol",
5
5
  "main": "./dist/index.js",
6
6
  "types": "./dist/index.d.ts",
@@ -31,6 +31,10 @@
31
31
  "./express": {
32
32
  "types": "./dist/x402/express/index.d.ts",
33
33
  "import": "./dist/x402/express/index.js"
34
+ },
35
+ "./langchain": {
36
+ "types": "./dist/x402/langchain/index.d.ts",
37
+ "import": "./dist/x402/langchain/index.js"
34
38
  }
35
39
  },
36
40
  "scripts": {
@@ -89,7 +93,8 @@
89
93
  },
90
94
  "peerDependencies": {
91
95
  "@modelcontextprotocol/sdk": ">=1.25.0",
92
- "express": ">=4.0.0"
96
+ "express": ">=4.0.0",
97
+ "@langchain/core": ">=0.3.0"
93
98
  },
94
99
  "peerDependenciesMeta": {
95
100
  "@modelcontextprotocol/sdk": {
@@ -97,6 +102,9 @@
97
102
  },
98
103
  "express": {
99
104
  "optional": true
105
+ },
106
+ "@langchain/core": {
107
+ "optional": true
100
108
  }
101
109
  },
102
110
  "dependencies": {