@nevermined-io/payments 1.0.0-rc0 → 1.0.0-rc2

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 (71) hide show
  1. package/dist/a2a/agent-card.d.ts +85 -0
  2. package/dist/a2a/agent-card.d.ts.map +1 -0
  3. package/dist/a2a/agent-card.js +79 -0
  4. package/dist/a2a/agent-card.js.map +1 -0
  5. package/dist/a2a/index.d.ts +23 -0
  6. package/dist/a2a/index.d.ts.map +1 -0
  7. package/dist/a2a/index.js +42 -0
  8. package/dist/a2a/index.js.map +1 -0
  9. package/dist/a2a/paymentsRequestHandler.d.ts +107 -0
  10. package/dist/a2a/paymentsRequestHandler.d.ts.map +1 -0
  11. package/dist/a2a/paymentsRequestHandler.js +333 -0
  12. package/dist/a2a/paymentsRequestHandler.js.map +1 -0
  13. package/dist/a2a/server.d.ts +126 -0
  14. package/dist/a2a/server.d.ts.map +1 -0
  15. package/dist/a2a/server.js +189 -0
  16. package/dist/a2a/server.js.map +1 -0
  17. package/dist/a2a/types.d.ts +91 -0
  18. package/dist/a2a/types.d.ts.map +1 -0
  19. package/dist/a2a/types.js +16 -0
  20. package/dist/a2a/types.js.map +1 -0
  21. package/dist/api/agents-api.d.ts +196 -0
  22. package/dist/api/agents-api.d.ts.map +1 -0
  23. package/dist/api/agents-api.js +281 -0
  24. package/dist/api/agents-api.js.map +1 -0
  25. package/dist/api/base-payments.d.ts +35 -0
  26. package/dist/api/base-payments.d.ts.map +1 -0
  27. package/dist/api/base-payments.js +62 -0
  28. package/dist/api/base-payments.js.map +1 -0
  29. package/dist/api/nvm-api.d.ts +12 -12
  30. package/dist/api/nvm-api.d.ts.map +1 -1
  31. package/dist/api/nvm-api.js +57 -59
  32. package/dist/api/nvm-api.js.map +1 -1
  33. package/dist/api/plans-api.d.ts +349 -0
  34. package/dist/api/plans-api.d.ts.map +1 -0
  35. package/dist/api/plans-api.js +465 -0
  36. package/dist/api/plans-api.js.map +1 -0
  37. package/dist/api/query-api.d.ts +12 -41
  38. package/dist/api/query-api.d.ts.map +1 -1
  39. package/dist/api/query-api.js +17 -46
  40. package/dist/api/query-api.js.map +1 -1
  41. package/dist/api/requests-api.d.ts +108 -0
  42. package/dist/api/requests-api.d.ts.map +1 -0
  43. package/dist/api/requests-api.js +171 -0
  44. package/dist/api/requests-api.js.map +1 -0
  45. package/dist/common/helper.js.map +1 -1
  46. package/dist/common/payments.error.d.ts +31 -1
  47. package/dist/common/payments.error.d.ts.map +1 -1
  48. package/dist/common/payments.error.js +39 -1
  49. package/dist/common/payments.error.js.map +1 -1
  50. package/dist/common/types.d.ts +57 -3
  51. package/dist/common/types.d.ts.map +1 -1
  52. package/dist/common/types.js +10 -1
  53. package/dist/common/types.js.map +1 -1
  54. package/dist/environments.d.ts +1 -1
  55. package/dist/environments.d.ts.map +1 -1
  56. package/dist/environments.js +19 -28
  57. package/dist/environments.js.map +1 -1
  58. package/dist/index.d.ts +2 -0
  59. package/dist/index.d.ts.map +1 -1
  60. package/dist/index.js +14 -0
  61. package/dist/index.js.map +1 -1
  62. package/dist/payments.d.ts +35 -408
  63. package/dist/payments.d.ts.map +1 -1
  64. package/dist/payments.js +71 -618
  65. package/dist/payments.js.map +1 -1
  66. package/dist/plans.js.map +1 -1
  67. package/dist/utils.d.ts +30 -0
  68. package/dist/utils.d.ts.map +1 -1
  69. package/dist/utils.js +74 -1
  70. package/dist/utils.js.map +1 -1
  71. package/package.json +13 -6
@@ -0,0 +1,333 @@
1
+ "use strict";
2
+ Object.defineProperty(exports, "__esModule", { value: true });
3
+ exports.PaymentsRequestHandler = void 0;
4
+ const uuid_1 = require("uuid");
5
+ const sdk_1 = require("@a2a-js/sdk");
6
+ const payments_error_1 = require("../common/payments.error");
7
+ const terminalStates = ['completed', 'failed', 'canceled', 'rejected'];
8
+ /**
9
+ * PaymentsRequestHandler extends DefaultRequestHandler to add payments validation and burning.
10
+ * It validates credits before executing a task and burns credits after successful execution.
11
+ * It also sends push notifications when a task reaches a terminal state.
12
+ */
13
+ class PaymentsRequestHandler extends sdk_1.DefaultRequestHandler {
14
+ /**
15
+ * Store HTTP context temporarily by messageId (used in middleware when taskId is not yet available).
16
+ * @param messageId - The messageId from the incoming message
17
+ * @param ctx - The HTTP context (bearerToken, url, method)
18
+ */
19
+ setHttpRequestContextForMessage(messageId, ctx) {
20
+ this.httpContextByMessageId.set(messageId, ctx);
21
+ }
22
+ /**
23
+ * Store HTTP context by taskId (used in middleware when taskId is available).
24
+ * @param taskId - The taskId of the task
25
+ * @param ctx - The HTTP context (bearerToken, url, method)
26
+ */
27
+ setHttpRequestContextForTask(taskId, ctx) {
28
+ this.httpContextByTaskId.set(taskId, ctx);
29
+ }
30
+ /**
31
+ * @param agentCard - The agent card
32
+ * @param taskStore - The task store
33
+ * @param agentExecutor - The business logic executor
34
+ * @param paymentsService - The payments service for validation and burning
35
+ * @param eventBusManager - The event bus manager (optional)
36
+ */
37
+ constructor(agentCard, taskStore, agentExecutor, paymentsService, eventBusManager) {
38
+ super(agentCard, taskStore, agentExecutor, eventBusManager);
39
+ /**
40
+ * Map to store HTTP context by taskId.
41
+ */
42
+ this.httpContextByTaskId = new Map();
43
+ /**
44
+ * Map to store temporary HTTP context by messageId (before taskId is known).
45
+ */
46
+ this.httpContextByMessageId = new Map();
47
+ /**
48
+ * Set to track which tasks already have a finalization listener attached.
49
+ */
50
+ this.finalizedTasksWithListener = new Set();
51
+ this.paymentsService = paymentsService;
52
+ }
53
+ /**
54
+ * Retrieve the HTTP context for a given taskId.
55
+ * @param taskId - The taskId of the task
56
+ * @returns The HTTP context (bearerToken, url, method) or undefined
57
+ */
58
+ getHttpRequestContextForTask(taskId) {
59
+ return this.httpContextByTaskId.get(taskId);
60
+ }
61
+ /**
62
+ * Retrieve the HTTP context for a given messageId.
63
+ * @param messageId - The messageId of the message
64
+ * @returns The HTTP context (bearerToken, url, method) or undefined
65
+ */
66
+ getHttpRequestContextForMessage(messageId) {
67
+ return this.httpContextByMessageId.get(messageId);
68
+ }
69
+ /**
70
+ * Sends a message, validating credits before execution and burning credits after.
71
+ * Also sends a push notification if the task reaches a terminal state.
72
+ * @param params - Message send parameters
73
+ * @returns The resulting message or task
74
+ */
75
+ async sendMessage(params) {
76
+ const incomingMessage = params.message;
77
+ // 1. Get HTTP context for the task or message
78
+ const taskId = incomingMessage.taskId;
79
+ let httpContext;
80
+ if (taskId) {
81
+ httpContext = this.getHttpRequestContextForTask(taskId);
82
+ }
83
+ else {
84
+ const messageId = incomingMessage.messageId;
85
+ if (messageId) {
86
+ httpContext = this.getHttpRequestContextForMessage(messageId);
87
+ }
88
+ }
89
+ if (!httpContext) {
90
+ throw payments_error_1.PaymentsError.internal('HTTP context not found for task or message.');
91
+ }
92
+ // 2. Extract bearer token
93
+ const { bearerToken, urlRequested, httpMethodRequested } = httpContext;
94
+ if (!bearerToken || !urlRequested || !httpMethodRequested) {
95
+ throw payments_error_1.PaymentsError.unauthorized('Missing bearer token for payment validation.');
96
+ }
97
+ // 3. Validate credits before executing the task
98
+ const agentCard = await this.getAgentCard();
99
+ const agentId = agentCard.capabilities?.extensions?.find((ext) => ext.uri === 'urn:nevermined:payment')?.params?.agentId;
100
+ if (!agentId) {
101
+ throw payments_error_1.PaymentsError.internal('Agent ID not found in payment extension.');
102
+ }
103
+ try {
104
+ const validation = await this.paymentsService.isValidRequest(agentId, bearerToken, urlRequested, httpMethodRequested);
105
+ if (!validation?.balance?.isSubscriber) {
106
+ throw payments_error_1.PaymentsError.paymentRequired('Insufficient credits or invalid request.');
107
+ }
108
+ }
109
+ catch (err) {
110
+ throw payments_error_1.PaymentsError.paymentRequired('Payment validation failed: ' + (err instanceof Error ? err.message : String(err)));
111
+ }
112
+ // 4. Call the base logic
113
+ const result = await super.sendMessage(params);
114
+ // 5. Only handle if result is a Task (not a Message)
115
+ if (result && result.kind === 'task') {
116
+ if (incomingMessage.messageId) {
117
+ this.migrateHttpRequestContextFromMessageToTask(incomingMessage.messageId, result.id);
118
+ }
119
+ const eventBus = this.getEventBusManager().createOrGetByTaskId(result.id);
120
+ if (!this.finalizedTasksWithListener.has(result.id)) {
121
+ this.finalizedTasksWithListener.add(result.id);
122
+ eventBus.on('event', (event) => {
123
+ if (event.kind === 'status-update' && terminalStates.includes(event.status?.state)) {
124
+ this.handleTaskFinalization(event, bearerToken);
125
+ }
126
+ });
127
+ }
128
+ }
129
+ return result;
130
+ }
131
+ /**
132
+ * Handles credits burning and push notification when a task reaches a terminal state.
133
+ * This is called asynchronously from the eventBus listener.
134
+ * @param event - The status-update event with final state
135
+ * @param bearerToken - The bearer token for payment validation
136
+ */
137
+ async handleTaskFinalization(event, bearerToken) {
138
+ const creditsToBurn = event.metadata?.creditsUsed;
139
+ if (creditsToBurn !== undefined &&
140
+ creditsToBurn !== null &&
141
+ bearerToken &&
142
+ (typeof creditsToBurn === 'string' ||
143
+ typeof creditsToBurn === 'number' ||
144
+ typeof creditsToBurn === 'bigint')) {
145
+ try {
146
+ await this.paymentsService.redeemCreditsFromRequest(bearerToken, BigInt(creditsToBurn));
147
+ }
148
+ catch (err) {
149
+ console.error('[Payments] Failed to redeem credits.', err);
150
+ }
151
+ }
152
+ try {
153
+ const taskPushNotificationConfig = await this.getTaskPushNotificationConfig({
154
+ id: event.taskId,
155
+ });
156
+ if (taskPushNotificationConfig) {
157
+ await this.sendPushNotification(event.taskId, event.status.state, taskPushNotificationConfig.pushNotificationConfig, { contextId: event.contextId });
158
+ }
159
+ }
160
+ catch (err) {
161
+ console.error('[PushNotification] Failed to send push notification.', err);
162
+ }
163
+ }
164
+ /**
165
+ * Streams messages and events for a task, with payments validation.
166
+ * Also sends a push notification if a terminal status-update event is emitted.
167
+ * @param params - Message send parameters
168
+ * @returns Async generator of events
169
+ */
170
+ async *sendMessageStream(params) {
171
+ // 0. Get HTTP context for the task or message
172
+ const taskId = params.message.taskId;
173
+ let httpContext;
174
+ if (taskId) {
175
+ httpContext = this.getHttpRequestContextForTask(taskId);
176
+ }
177
+ else {
178
+ const messageId = params.message.messageId;
179
+ if (messageId) {
180
+ httpContext = this.getHttpRequestContextForMessage(messageId);
181
+ }
182
+ }
183
+ if (!httpContext) {
184
+ throw payments_error_1.PaymentsError.internal('HTTP context not found for task or message.');
185
+ }
186
+ const { bearerToken, urlRequested, httpMethodRequested } = httpContext;
187
+ if (!bearerToken) {
188
+ throw payments_error_1.PaymentsError.unauthorized('Missing bearer token for payment validation.');
189
+ }
190
+ const agentCard = await this.getAgentCard();
191
+ const agentId = agentCard.capabilities?.extensions?.find((ext) => ext.uri === 'urn:nevermined:payment')?.params?.agentId;
192
+ if (!agentId) {
193
+ throw payments_error_1.PaymentsError.internal('Agent ID not found in payment extension.');
194
+ }
195
+ try {
196
+ const validation = await this.paymentsService.isValidRequest(agentId, bearerToken, urlRequested, httpMethodRequested);
197
+ if (!validation?.balance?.isSubscriber) {
198
+ throw payments_error_1.PaymentsError.paymentRequired('Insufficient credits or invalid request.');
199
+ }
200
+ }
201
+ catch (err) {
202
+ throw payments_error_1.PaymentsError.paymentRequired('Payment validation failed: ' + (err instanceof Error ? err.message : String(err)));
203
+ }
204
+ // 4. Create the task if it does not exist yet
205
+ // If params.message.taskId is not present, create and store a new Task
206
+ if (!params.message.taskId) {
207
+ const newTaskId = (0, uuid_1.v4)();
208
+ const newContextId = params.message.contextId || (0, uuid_1.v4)();
209
+ const newTask = {
210
+ kind: 'task',
211
+ id: newTaskId,
212
+ contextId: newContextId,
213
+ status: {
214
+ state: 'submitted',
215
+ timestamp: new Date().toISOString(),
216
+ },
217
+ history: [params.message],
218
+ metadata: params.message.metadata,
219
+ artifacts: [],
220
+ };
221
+ // Store the new task in the taskStore
222
+ await this.getTaskStore().save(newTask);
223
+ // Update the params.message with the new taskId and contextId
224
+ params.message.taskId = newTaskId;
225
+ params.message.contextId = newContextId;
226
+ }
227
+ // Call the base stream logic
228
+ const stream = super.sendMessageStream(params);
229
+ for await (const event of stream) {
230
+ // 1. Handle credits burning
231
+ if (event.kind === 'status-update' &&
232
+ event.final &&
233
+ event?.metadata?.creditsUsed !== undefined &&
234
+ event?.metadata?.creditsUsed !== null &&
235
+ bearerToken &&
236
+ (typeof event.metadata.creditsUsed === 'string' ||
237
+ typeof event.metadata.creditsUsed === 'number' ||
238
+ typeof event.metadata.creditsUsed === 'bigint')) {
239
+ try {
240
+ await this.paymentsService.redeemCreditsFromRequest(bearerToken, BigInt(event.metadata.creditsUsed));
241
+ }
242
+ catch (err) {
243
+ console.error('[Payments] Failed to redeem credits.', err);
244
+ }
245
+ }
246
+ // 2. Handle push notification
247
+ if (event.kind === 'status-update' &&
248
+ event.final &&
249
+ event.status?.state &&
250
+ terminalStates.includes(event.status.state)) {
251
+ try {
252
+ const taskPushNotificationConfig = await this.getTaskPushNotificationConfig({
253
+ id: event.taskId,
254
+ });
255
+ if (taskPushNotificationConfig) {
256
+ await this.sendPushNotification(event.taskId, event.status.state, taskPushNotificationConfig.pushNotificationConfig, {
257
+ contextId: event.contextId,
258
+ });
259
+ }
260
+ }
261
+ catch (err) {
262
+ console.error('[PushNotification] Failed to send push notification.', err);
263
+ }
264
+ }
265
+ yield event;
266
+ }
267
+ }
268
+ async sendPushNotification(taskId, state, pushNotificationConfig, payload = {}) {
269
+ const headers = {
270
+ 'Content-Type': 'application/json',
271
+ };
272
+ if (pushNotificationConfig.authentication) {
273
+ if (pushNotificationConfig.authentication.schemes.includes('basic')) {
274
+ const basic = Buffer.from(`${pushNotificationConfig.authentication.credentials}`).toString('base64');
275
+ headers['Authorization'] = `Basic ${basic}`;
276
+ }
277
+ else if (pushNotificationConfig.authentication.schemes.includes('bearer')) {
278
+ headers['Authorization'] = `Bearer ${pushNotificationConfig.authentication.credentials}`;
279
+ }
280
+ else if (pushNotificationConfig.authentication.schemes.includes('custom')) {
281
+ Object.assign(headers, pushNotificationConfig.authentication.credentials);
282
+ }
283
+ }
284
+ const body = JSON.stringify({
285
+ taskId,
286
+ state,
287
+ payload,
288
+ });
289
+ const response = await fetch(pushNotificationConfig.url, {
290
+ method: 'POST',
291
+ headers,
292
+ body,
293
+ });
294
+ if (!response.ok) {
295
+ throw payments_error_1.PaymentsError.internal('Failed to send push notification.');
296
+ }
297
+ }
298
+ /**
299
+ * Migrates the HTTP context from a messageId to a taskId and deletes the temporary messageId context.
300
+ * @param messageId - The messageId to migrate from
301
+ * @param taskId - The taskId to migrate to
302
+ */
303
+ migrateHttpRequestContextFromMessageToTask(messageId, taskId) {
304
+ const ctx = this.getHttpRequestContextForMessage(messageId);
305
+ if (ctx) {
306
+ this.setHttpRequestContextForTask(taskId, ctx);
307
+ this.deleteHttpRequestContextForMessage(messageId);
308
+ }
309
+ }
310
+ /**
311
+ * Deletes the HTTP context associated with a messageId.
312
+ * @param messageId - The messageId to delete context for
313
+ */
314
+ deleteHttpRequestContextForMessage(messageId) {
315
+ this.httpContextByMessageId.delete(messageId);
316
+ }
317
+ /**
318
+ * Protected getter to access the private taskStore property from the parent class.
319
+ * This is a workaround due to SDK limitations.
320
+ */
321
+ getTaskStore() {
322
+ return this.taskStore;
323
+ }
324
+ /**
325
+ * Protected getter to access the private eventBusManager property from the parent class.
326
+ * This is a workaround due to SDK limitations.
327
+ */
328
+ getEventBusManager() {
329
+ return this.eventBusManager;
330
+ }
331
+ }
332
+ exports.PaymentsRequestHandler = PaymentsRequestHandler;
333
+ //# sourceMappingURL=paymentsRequestHandler.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"paymentsRequestHandler.js","sourceRoot":"","sources":["../../src/a2a/paymentsRequestHandler.ts"],"names":[],"mappings":"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","sourcesContent":["import type {\n AgentCard,\n MessageSendParams,\n TaskState,\n ExecutionEventBusManager,\n TaskStore,\n PushNotificationConfig,\n TaskStatusUpdateEvent,\n Task,\n} from '@a2a-js/sdk'\nimport { v4 as uuidv4 } from 'uuid'\nimport { AgentExecutor, DefaultRequestHandler } from '@a2a-js/sdk'\nimport { PaymentsError } from '../common/payments.error'\nimport { AgentExecutionEvent } from '@a2a-js/sdk/build/src/server/events/execution_event_bus'\n\nconst terminalStates: TaskState[] = ['completed', 'failed', 'canceled', 'rejected']\n\n/**\n * HTTP context associated with a task or message.\n */\ntype HttpRequestContext = {\n bearerToken?: string\n urlRequested?: string\n httpMethodRequested?: string\n}\n\n/**\n * PaymentsRequestHandler extends DefaultRequestHandler to add payments validation and burning.\n * It validates credits before executing a task and burns credits after successful execution.\n * It also sends push notifications when a task reaches a terminal state.\n */\nexport class PaymentsRequestHandler extends DefaultRequestHandler {\n private paymentsService: any\n\n /**\n * Map to store HTTP context by taskId.\n */\n private httpContextByTaskId: Map<string, HttpRequestContext> = new Map()\n\n /**\n * Map to store temporary HTTP context by messageId (before taskId is known).\n */\n private httpContextByMessageId: Map<string, HttpRequestContext> = new Map()\n\n /**\n * Set to track which tasks already have a finalization listener attached.\n */\n private finalizedTasksWithListener: Set<string> = new Set()\n\n /**\n * Store HTTP context temporarily by messageId (used in middleware when taskId is not yet available).\n * @param messageId - The messageId from the incoming message\n * @param ctx - The HTTP context (bearerToken, url, method)\n */\n public setHttpRequestContextForMessage(messageId: string, ctx: HttpRequestContext) {\n this.httpContextByMessageId.set(messageId, ctx)\n }\n\n /**\n * Store HTTP context by taskId (used in middleware when taskId is available).\n * @param taskId - The taskId of the task\n * @param ctx - The HTTP context (bearerToken, url, method)\n */\n public setHttpRequestContextForTask(taskId: string, ctx: HttpRequestContext) {\n this.httpContextByTaskId.set(taskId, ctx)\n }\n\n /**\n * @param agentCard - The agent card\n * @param taskStore - The task store\n * @param agentExecutor - The business logic executor\n * @param paymentsService - The payments service for validation and burning\n * @param eventBusManager - The event bus manager (optional)\n */\n constructor(\n agentCard: AgentCard,\n taskStore: TaskStore,\n agentExecutor: AgentExecutor,\n paymentsService: any,\n eventBusManager?: ExecutionEventBusManager,\n ) {\n super(agentCard, taskStore, agentExecutor, eventBusManager)\n this.paymentsService = paymentsService\n }\n\n /**\n * Retrieve the HTTP context for a given taskId.\n * @param taskId - The taskId of the task\n * @returns The HTTP context (bearerToken, url, method) or undefined\n */\n private getHttpRequestContextForTask(taskId: string): HttpRequestContext | undefined {\n return this.httpContextByTaskId.get(taskId)\n }\n\n /**\n * Retrieve the HTTP context for a given messageId.\n * @param messageId - The messageId of the message\n * @returns The HTTP context (bearerToken, url, method) or undefined\n */\n private getHttpRequestContextForMessage(messageId: string): HttpRequestContext | undefined {\n return this.httpContextByMessageId.get(messageId)\n }\n\n /**\n * Sends a message, validating credits before execution and burning credits after.\n * Also sends a push notification if the task reaches a terminal state.\n * @param params - Message send parameters\n * @returns The resulting message or task\n */\n async sendMessage(params: MessageSendParams) {\n const incomingMessage = params.message\n\n // 1. Get HTTP context for the task or message\n const taskId = incomingMessage.taskId\n let httpContext: HttpRequestContext | undefined\n if (taskId) {\n httpContext = this.getHttpRequestContextForTask(taskId)\n } else {\n const messageId = incomingMessage.messageId\n if (messageId) {\n httpContext = this.getHttpRequestContextForMessage(messageId)\n }\n }\n\n if (!httpContext) {\n throw PaymentsError.internal('HTTP context not found for task or message.')\n }\n\n // 2. Extract bearer token\n const { bearerToken, urlRequested, httpMethodRequested } = httpContext\n if (!bearerToken || !urlRequested || !httpMethodRequested) {\n throw PaymentsError.unauthorized('Missing bearer token for payment validation.')\n }\n // 3. Validate credits before executing the task\n const agentCard = await this.getAgentCard()\n const agentId = agentCard.capabilities?.extensions?.find(\n (ext) => ext.uri === 'urn:nevermined:payment',\n )?.params?.agentId\n if (!agentId) {\n throw PaymentsError.internal('Agent ID not found in payment extension.')\n }\n try {\n const validation = await this.paymentsService.isValidRequest(\n agentId,\n bearerToken,\n urlRequested,\n httpMethodRequested,\n )\n if (!validation?.balance?.isSubscriber) {\n throw PaymentsError.paymentRequired('Insufficient credits or invalid request.')\n }\n } catch (err) {\n throw PaymentsError.paymentRequired(\n 'Payment validation failed: ' + (err instanceof Error ? err.message : String(err)),\n )\n }\n\n // 4. Call the base logic\n const result = await super.sendMessage(params)\n\n // 5. Only handle if result is a Task (not a Message)\n if (result && result.kind === 'task') {\n if (incomingMessage.messageId) {\n this.migrateHttpRequestContextFromMessageToTask(incomingMessage.messageId, result.id)\n }\n const eventBus = this.getEventBusManager().createOrGetByTaskId(result.id)\n if (!this.finalizedTasksWithListener.has(result.id)) {\n this.finalizedTasksWithListener.add(result.id)\n eventBus.on('event', (event: AgentExecutionEvent) => {\n if (event.kind === 'status-update' && terminalStates.includes(event.status?.state)) {\n this.handleTaskFinalization(event, bearerToken)\n }\n })\n }\n }\n return result\n }\n\n /**\n * Handles credits burning and push notification when a task reaches a terminal state.\n * This is called asynchronously from the eventBus listener.\n * @param event - The status-update event with final state\n * @param bearerToken - The bearer token for payment validation\n */\n private async handleTaskFinalization(event: TaskStatusUpdateEvent, bearerToken: string) {\n const creditsToBurn = event.metadata?.creditsUsed\n if (\n creditsToBurn !== undefined &&\n creditsToBurn !== null &&\n bearerToken &&\n (typeof creditsToBurn === 'string' ||\n typeof creditsToBurn === 'number' ||\n typeof creditsToBurn === 'bigint')\n ) {\n try {\n await this.paymentsService.redeemCreditsFromRequest(bearerToken, BigInt(creditsToBurn))\n } catch (err) {\n console.error('[Payments] Failed to redeem credits.', err)\n }\n }\n try {\n const taskPushNotificationConfig = await this.getTaskPushNotificationConfig({\n id: event.taskId,\n })\n if (taskPushNotificationConfig) {\n await this.sendPushNotification(\n event.taskId,\n event.status.state,\n taskPushNotificationConfig.pushNotificationConfig,\n { contextId: event.contextId },\n )\n }\n } catch (err) {\n console.error('[PushNotification] Failed to send push notification.', err)\n }\n }\n\n /**\n * Streams messages and events for a task, with payments validation.\n * Also sends a push notification if a terminal status-update event is emitted.\n * @param params - Message send parameters\n * @returns Async generator of events\n */\n async *sendMessageStream(params: MessageSendParams) {\n // 0. Get HTTP context for the task or message\n const taskId = params.message.taskId\n let httpContext: HttpRequestContext | undefined\n if (taskId) {\n httpContext = this.getHttpRequestContextForTask(taskId)\n } else {\n const messageId = params.message.messageId\n if (messageId) {\n httpContext = this.getHttpRequestContextForMessage(messageId)\n }\n }\n\n if (!httpContext) {\n throw PaymentsError.internal('HTTP context not found for task or message.')\n }\n const { bearerToken, urlRequested, httpMethodRequested } = httpContext\n if (!bearerToken) {\n throw PaymentsError.unauthorized('Missing bearer token for payment validation.')\n }\n const agentCard = await this.getAgentCard()\n const agentId = agentCard.capabilities?.extensions?.find(\n (ext) => ext.uri === 'urn:nevermined:payment',\n )?.params?.agentId\n if (!agentId) {\n throw PaymentsError.internal('Agent ID not found in payment extension.')\n }\n\n try {\n const validation = await this.paymentsService.isValidRequest(\n agentId,\n bearerToken,\n urlRequested,\n httpMethodRequested,\n )\n if (!validation?.balance?.isSubscriber) {\n throw PaymentsError.paymentRequired('Insufficient credits or invalid request.')\n }\n } catch (err) {\n throw PaymentsError.paymentRequired(\n 'Payment validation failed: ' + (err instanceof Error ? err.message : String(err)),\n )\n }\n\n // 4. Create the task if it does not exist yet\n // If params.message.taskId is not present, create and store a new Task\n if (!params.message.taskId) {\n const newTaskId = uuidv4()\n const newContextId = params.message.contextId || uuidv4()\n const newTask: Task = {\n kind: 'task',\n id: newTaskId,\n contextId: newContextId,\n status: {\n state: 'submitted',\n timestamp: new Date().toISOString(),\n },\n history: [params.message],\n metadata: params.message.metadata,\n artifacts: [],\n }\n // Store the new task in the taskStore\n await this.getTaskStore().save(newTask)\n // Update the params.message with the new taskId and contextId\n params.message.taskId = newTaskId\n params.message.contextId = newContextId\n }\n\n // Call the base stream logic\n const stream = super.sendMessageStream(params)\n for await (const event of stream) {\n // 1. Handle credits burning\n if (\n event.kind === 'status-update' &&\n event.final &&\n event?.metadata?.creditsUsed !== undefined &&\n event?.metadata?.creditsUsed !== null &&\n bearerToken &&\n (typeof event.metadata.creditsUsed === 'string' ||\n typeof event.metadata.creditsUsed === 'number' ||\n typeof event.metadata.creditsUsed === 'bigint')\n ) {\n try {\n await this.paymentsService.redeemCreditsFromRequest(\n bearerToken,\n BigInt(event.metadata.creditsUsed),\n )\n } catch (err) {\n console.error('[Payments] Failed to redeem credits.', err)\n }\n }\n // 2. Handle push notification\n if (\n event.kind === 'status-update' &&\n event.final &&\n event.status?.state &&\n terminalStates.includes(event.status.state)\n ) {\n try {\n const taskPushNotificationConfig = await this.getTaskPushNotificationConfig({\n id: event.taskId,\n })\n if (taskPushNotificationConfig) {\n await this.sendPushNotification(\n event.taskId,\n event.status.state,\n taskPushNotificationConfig.pushNotificationConfig,\n {\n contextId: event.contextId,\n },\n )\n }\n } catch (err) {\n console.error('[PushNotification] Failed to send push notification.', err)\n }\n }\n yield event\n }\n }\n\n private async sendPushNotification(\n taskId: string,\n state: TaskState,\n pushNotificationConfig: PushNotificationConfig,\n payload: Record<string, any> = {},\n ) {\n const headers: Record<string, string> = {\n 'Content-Type': 'application/json',\n }\n if (pushNotificationConfig.authentication) {\n if (pushNotificationConfig.authentication.schemes.includes('basic')) {\n const basic = Buffer.from(`${pushNotificationConfig.authentication.credentials}`).toString(\n 'base64',\n )\n headers['Authorization'] = `Basic ${basic}`\n } else if (pushNotificationConfig.authentication.schemes.includes('bearer')) {\n headers['Authorization'] = `Bearer ${pushNotificationConfig.authentication.credentials}`\n } else if (pushNotificationConfig.authentication.schemes.includes('custom')) {\n Object.assign(headers, pushNotificationConfig.authentication.credentials)\n }\n }\n const body = JSON.stringify({\n taskId,\n state,\n payload,\n })\n const response = await fetch(pushNotificationConfig.url, {\n method: 'POST',\n headers,\n body,\n })\n if (!response.ok) {\n throw PaymentsError.internal('Failed to send push notification.')\n }\n }\n\n /**\n * Migrates the HTTP context from a messageId to a taskId and deletes the temporary messageId context.\n * @param messageId - The messageId to migrate from\n * @param taskId - The taskId to migrate to\n */\n public migrateHttpRequestContextFromMessageToTask(messageId: string, taskId: string): void {\n const ctx = this.getHttpRequestContextForMessage(messageId)\n if (ctx) {\n this.setHttpRequestContextForTask(taskId, ctx)\n this.deleteHttpRequestContextForMessage(messageId)\n }\n }\n\n /**\n * Deletes the HTTP context associated with a messageId.\n * @param messageId - The messageId to delete context for\n */\n public deleteHttpRequestContextForMessage(messageId: string): void {\n this.httpContextByMessageId.delete(messageId)\n }\n\n /**\n * Protected getter to access the private taskStore property from the parent class.\n * This is a workaround due to SDK limitations.\n */\n protected getTaskStore(): TaskStore {\n return (this as any).taskStore as TaskStore\n }\n\n /**\n * Protected getter to access the private eventBusManager property from the parent class.\n * This is a workaround due to SDK limitations.\n */\n protected getEventBusManager(): ExecutionEventBusManager {\n return (this as any).eventBusManager as ExecutionEventBusManager\n }\n}\n"]}
@@ -0,0 +1,126 @@
1
+ /// <reference types="node" />
2
+ /**
3
+ * PaymentsA2AServer sets up and starts the A2A server for payments agents.
4
+ * Handles A2A protocol endpoints and allows optional custom endpoints.
5
+ *
6
+ * The server provides a complete A2A protocol implementation with:
7
+ * - JSON-RPC endpoint for A2A messages
8
+ * - Agent Card endpoint (.well-known/agent.json)
9
+ * - Bearer token extraction and validation
10
+ * - Credit validation and burning
11
+ * - Task execution and streaming
12
+ * - Customizable routes and handlers
13
+ */
14
+ import express from 'express';
15
+ import http from 'http';
16
+ import { AgentExecutor } from '@a2a-js/sdk';
17
+ import type { AgentCard } from './types';
18
+ import { PaymentsRequestHandler } from './paymentsRequestHandler';
19
+ /**
20
+ * Options for starting the PaymentsA2AServer.
21
+ * Provides comprehensive configuration for A2A server setup.
22
+ */
23
+ export interface PaymentsA2AServerOptions {
24
+ /** The agent card defining the agent's capabilities and metadata */
25
+ agentCard: AgentCard;
26
+ /** User-implemented executor for handling A2A tasks */
27
+ executor: AgentExecutor;
28
+ /** Payments service instance for credit validation and burning */
29
+ paymentsService: any;
30
+ /** Port number to bind the server to */
31
+ port: number;
32
+ /** Custom task store implementation (defaults to InMemoryTaskStore) */
33
+ taskStore?: any;
34
+ /** Base path for all A2A routes (defaults to '/') */
35
+ basePath?: string;
36
+ /** Whether to expose the agent card at .well-known/agent.json */
37
+ exposeAgentCard?: boolean;
38
+ /** Whether to expose default A2A JSON-RPC routes */
39
+ exposeDefaultRoutes?: boolean;
40
+ /** Custom Express app instance (defaults to new express()) */
41
+ expressApp?: express.Express;
42
+ /** Custom request handler to override JSON-RPC method handling */
43
+ customRequestHandler?: any;
44
+ /** Hooks for intercepting requests before/after processing */
45
+ hooks?: {
46
+ /** Called before processing any JSON-RPC request */
47
+ beforeRequest?: (method: string, params: any, req: express.Request) => Promise<void>;
48
+ /** Called after processing any JSON-RPC request */
49
+ afterRequest?: (method: string, result: any, req: express.Request) => Promise<void>;
50
+ /** Called when a JSON-RPC request fails */
51
+ onError?: (method: string, error: Error, req: express.Request) => Promise<void>;
52
+ };
53
+ }
54
+ /**
55
+ * Result returned by the server start method.
56
+ * Contains the Express app and HTTP server instances for further customization.
57
+ */
58
+ export interface PaymentsA2AServerResult {
59
+ /** The configured Express application */
60
+ app: express.Express;
61
+ /** The HTTP server instance */
62
+ server: http.Server;
63
+ /** The request handler instance for direct access if needed */
64
+ handler: PaymentsRequestHandler;
65
+ }
66
+ /**
67
+ * PaymentsA2AServer sets up the A2A endpoints and starts the server.
68
+ *
69
+ * This class provides a complete A2A protocol implementation with payment integration.
70
+ * It handles:
71
+ * - JSON-RPC message routing
72
+ * - Agent card exposure
73
+ * - Bearer token extraction
74
+ * - Credit validation and burning
75
+ * - Task execution and streaming
76
+ * - Customizable routes and handlers
77
+ *
78
+ * @example
79
+ * ```typescript
80
+ * const server = PaymentsA2AServer.start({
81
+ * agentCard: myAgentCard,
82
+ * executor: new MyExecutor(),
83
+ * paymentsService: payments,
84
+ * port: 41242,
85
+ * basePath: '/a2a/',
86
+ * hooks: {
87
+ * beforeRequest: async (method, params, req) => {
88
+ * console.log(`Processing ${method} request`)
89
+ * }
90
+ * }
91
+ * })
92
+ * ```
93
+ */
94
+ export declare class PaymentsA2AServer {
95
+ /**
96
+ * Starts the A2A server with the given options.
97
+ *
98
+ * This method sets up the complete A2A server infrastructure including:
99
+ * - Express app configuration
100
+ * - A2A route setup
101
+ * - Middleware for bearer token extraction
102
+ * - Agent card endpoint
103
+ * - HTTP server creation and binding
104
+ *
105
+ * @param options - Server configuration options
106
+ * @returns Server result containing app, server, adapter, and handler instances
107
+ *
108
+ * @example
109
+ * ```typescript
110
+ * const result = PaymentsA2AServer.start({
111
+ * agentCard: buildPaymentAgentCard(baseCard, paymentMetadata),
112
+ * executor: new MyPaymentsExecutor(),
113
+ * paymentsService: payments,
114
+ * port: 41242,
115
+ * basePath: '/a2a/',
116
+ * exposeAgentCard: true,
117
+ * exposeDefaultRoutes: true
118
+ * })
119
+ *
120
+ * // Access the Express app for additional routes
121
+ * result.app.get('/health', (req, res) => res.json({ status: 'ok' }))
122
+ * ```
123
+ */
124
+ static start(options: PaymentsA2AServerOptions): PaymentsA2AServerResult;
125
+ }
126
+ //# sourceMappingURL=server.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"server.d.ts","sourceRoot":"","sources":["../../src/a2a/server.ts"],"names":[],"mappings":";AAAA;;;;;;;;;;;GAWG;AACH,OAAO,OAAO,MAAM,SAAS,CAAA;AAC7B,OAAO,IAAI,MAAM,MAAM,CAAA;AACvB,OAAO,EAAoC,aAAa,EAAE,MAAM,aAAa,CAAA;AAC7E,OAAO,KAAK,EAAE,SAAS,EAAE,MAAM,SAAS,CAAA;AACxC,OAAO,EAAE,sBAAsB,EAAE,MAAM,0BAA0B,CAAA;AAEjE;;;GAGG;AACH,MAAM,WAAW,wBAAwB;IACvC,oEAAoE;IACpE,SAAS,EAAE,SAAS,CAAA;IACpB,uDAAuD;IACvD,QAAQ,EAAE,aAAa,CAAA;IACvB,kEAAkE;IAClE,eAAe,EAAE,GAAG,CAAA;IACpB,wCAAwC;IACxC,IAAI,EAAE,MAAM,CAAA;IACZ,uEAAuE;IACvE,SAAS,CAAC,EAAE,GAAG,CAAA;IACf,qDAAqD;IACrD,QAAQ,CAAC,EAAE,MAAM,CAAA;IACjB,iEAAiE;IACjE,eAAe,CAAC,EAAE,OAAO,CAAA;IACzB,oDAAoD;IACpD,mBAAmB,CAAC,EAAE,OAAO,CAAA;IAC7B,8DAA8D;IAC9D,UAAU,CAAC,EAAE,OAAO,CAAC,OAAO,CAAA;IAC5B,kEAAkE;IAClE,oBAAoB,CAAC,EAAE,GAAG,CAAA;IAC1B,8DAA8D;IAC9D,KAAK,CAAC,EAAE;QACN,oDAAoD;QACpD,aAAa,CAAC,EAAE,CAAC,MAAM,EAAE,MAAM,EAAE,MAAM,EAAE,GAAG,EAAE,GAAG,EAAE,OAAO,CAAC,OAAO,KAAK,OAAO,CAAC,IAAI,CAAC,CAAA;QACpF,mDAAmD;QACnD,YAAY,CAAC,EAAE,CAAC,MAAM,EAAE,MAAM,EAAE,MAAM,EAAE,GAAG,EAAE,GAAG,EAAE,OAAO,CAAC,OAAO,KAAK,OAAO,CAAC,IAAI,CAAC,CAAA;QACnF,2CAA2C;QAC3C,OAAO,CAAC,EAAE,CAAC,MAAM,EAAE,MAAM,EAAE,KAAK,EAAE,KAAK,EAAE,GAAG,EAAE,OAAO,CAAC,OAAO,KAAK,OAAO,CAAC,IAAI,CAAC,CAAA;KAChF,CAAA;CACF;AAED;;;GAGG;AACH,MAAM,WAAW,uBAAuB;IACtC,yCAAyC;IACzC,GAAG,EAAE,OAAO,CAAC,OAAO,CAAA;IACpB,+BAA+B;IAC/B,MAAM,EAAE,IAAI,CAAC,MAAM,CAAA;IACnB,+DAA+D;IAC/D,OAAO,EAAE,sBAAsB,CAAA;CAChC;AAyDD;;;;;;;;;;;;;;;;;;;;;;;;;;;GA2BG;AACH,qBAAa,iBAAiB;IAC5B;;;;;;;;;;;;;;;;;;;;;;;;;;;;OA4BG;IACH,MAAM,CAAC,KAAK,CAAC,OAAO,EAAE,wBAAwB,GAAG,uBAAuB;CAuFzE"}