@payware/mcp-server 1.0.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 (106) hide show
  1. package/.env.example +92 -0
  2. package/MCP-SETUP.md +190 -0
  3. package/README.md +483 -0
  4. package/check-keys.js +52 -0
  5. package/keys/README.md +112 -0
  6. package/mcp-config.json +9 -0
  7. package/package.json +66 -0
  8. package/payware-mcp-config.json +12 -0
  9. package/src/auth/rsa-keys.js +82 -0
  10. package/src/auth/sandbox-setup.js +187 -0
  11. package/src/config/env.js +229 -0
  12. package/src/config/partner-types.js +143 -0
  13. package/src/core/auth/jwt-factory.js +182 -0
  14. package/src/core/auth/jwt-token.js +735 -0
  15. package/src/core/utils/json-serializer.js +100 -0
  16. package/src/core/utils/key-utils.js +133 -0
  17. package/src/index.js +237 -0
  18. package/src/isv/data/index.js +291 -0
  19. package/src/isv/deep-links/delete-product-link.js +154 -0
  20. package/src/isv/deep-links/delete-transaction-link.js +154 -0
  21. package/src/isv/deep-links/get-product-link.js +167 -0
  22. package/src/isv/deep-links/get-transaction-link.js +167 -0
  23. package/src/isv/deep-links/index.js +23 -0
  24. package/src/isv/index.js +103 -0
  25. package/src/isv/oauth2/create-token-simple.js +46 -0
  26. package/src/isv/oauth2/get-token-info.js +157 -0
  27. package/src/isv/oauth2/obtain-token.js +189 -0
  28. package/src/isv/oauth2/token-helper.js +151 -0
  29. package/src/isv/products/audios.js +470 -0
  30. package/src/isv/products/create-product.js +314 -0
  31. package/src/isv/products/delete-product.js +119 -0
  32. package/src/isv/products/get-product-image.js +247 -0
  33. package/src/isv/products/get-product.js +168 -0
  34. package/src/isv/products/index.js +65 -0
  35. package/src/isv/products/list-products.js +136 -0
  36. package/src/isv/products/schedules.js +522 -0
  37. package/src/isv/products/update-product.js +265 -0
  38. package/src/isv/transactions/cancel-transaction.js +129 -0
  39. package/src/isv/transactions/create-transaction.js +361 -0
  40. package/src/isv/transactions/get-status.js +217 -0
  41. package/src/isv/transactions/process-transaction.js +145 -0
  42. package/src/isv/transactions/simulate-callback.js +146 -0
  43. package/src/isv/transactions/transaction-history.js +186 -0
  44. package/src/isv/utils/auth.js +159 -0
  45. package/src/mcp-proxy.js +150 -0
  46. package/src/merchant/data/export-report.js +108 -0
  47. package/src/merchant/data/generate-report.js +151 -0
  48. package/src/merchant/data/get-report-status.js +120 -0
  49. package/src/merchant/data/index.js +351 -0
  50. package/src/merchant/deep-links/delete-product-link.js +121 -0
  51. package/src/merchant/deep-links/delete-transaction-link.js +121 -0
  52. package/src/merchant/deep-links/get-product-link.js +134 -0
  53. package/src/merchant/deep-links/get-transaction-link.js +134 -0
  54. package/src/merchant/deep-links/index.js +23 -0
  55. package/src/merchant/index.js +92 -0
  56. package/src/merchant/products/audios.js +606 -0
  57. package/src/merchant/products/create-product.js +288 -0
  58. package/src/merchant/products/delete-product.js +111 -0
  59. package/src/merchant/products/get-product-image.js +252 -0
  60. package/src/merchant/products/get-product.js +144 -0
  61. package/src/merchant/products/index.js +65 -0
  62. package/src/merchant/products/list-products.js +112 -0
  63. package/src/merchant/products/schedules.js +646 -0
  64. package/src/merchant/products/update-product.js +282 -0
  65. package/src/merchant/transactions/cancel-transaction.js +241 -0
  66. package/src/merchant/transactions/create-transaction.js +482 -0
  67. package/src/merchant/transactions/get-status.js +196 -0
  68. package/src/merchant/transactions/process-transaction.js +349 -0
  69. package/src/merchant/transactions/simulate-callback.js +246 -0
  70. package/src/merchant/transactions/transaction-history.js +258 -0
  71. package/src/payment-institution/data/index.js +280 -0
  72. package/src/payment-institution/deep-links/delete-transaction-link.js +128 -0
  73. package/src/payment-institution/deep-links/get-transaction-link.js +141 -0
  74. package/src/payment-institution/deep-links/index.js +17 -0
  75. package/src/payment-institution/index.js +92 -0
  76. package/src/payment-institution/transactions/create-pi-transaction.js +484 -0
  77. package/src/payment-institution/transactions/finalize-transaction.js +340 -0
  78. package/src/payment-institution/transactions/get-transaction-history.js +269 -0
  79. package/src/payment-institution/transactions/get-transaction-status.js +234 -0
  80. package/src/payment-institution/transactions/process-pi-transaction.js +421 -0
  81. package/src/payment-institution/transactions/simulate-pi-callback.js +326 -0
  82. package/src/payment-institution/transactions/soundbite-transaction.js +269 -0
  83. package/src/proxy-server.js +205 -0
  84. package/src/shared/data/data-api.js +372 -0
  85. package/src/shared/deep-links/api.js +214 -0
  86. package/src/shared/index.js +44 -0
  87. package/src/shared/products/products-api.js +872 -0
  88. package/src/tools/advanced-code-generator.js +2247 -0
  89. package/src/utils/code-examples/common/auth-examples.js +1482 -0
  90. package/src/utils/code-examples/common/helpers.js +416 -0
  91. package/src/utils/code-examples/common/utils-examples.js +591 -0
  92. package/src/utils/code-examples/frameworks/examples.js +859 -0
  93. package/src/utils/code-examples/index.js +441 -0
  94. package/src/utils/code-examples/isv/oauth2.js +600 -0
  95. package/src/utils/code-examples/isv/products.js +666 -0
  96. package/src/utils/code-examples/isv/transactions.js +813 -0
  97. package/src/utils/code-examples/merchant/products.js +497 -0
  98. package/src/utils/code-examples/merchant/transactions.js +623 -0
  99. package/src/utils/code-examples/payment-institution/transactions.js +388 -0
  100. package/src/utils/code-examples/shared/data.js +607 -0
  101. package/src/utils/code-examples/shared/deep-links.js +662 -0
  102. package/src/utils/code-examples/shared/soundbites.js +808 -0
  103. package/src/utils/code-examples.js +646 -0
  104. package/src/utils/format-request.js +363 -0
  105. package/src/utils/json-formatter.js +249 -0
  106. package/src/utils/server-info.js +132 -0
@@ -0,0 +1,145 @@
1
+ import axios from 'axios';
2
+ import { createJWTForPartner } from '../../core/auth/jwt-factory.js';
3
+ import { getSandboxUrl, getProductionUrl, getPartnerIdSafe, getPrivateKeySafe } from '../../config/env.js';
4
+
5
+ /**
6
+ * Process (finalize) a transaction via payware API as an ISV
7
+ */
8
+ export async function processTransaction({ transactionId, merchantPartnerId, oauth2Token, action = 'CONFIRMED', useSandbox = true }) {
9
+ if (!transactionId) {
10
+ throw new Error('Transaction ID is required');
11
+ }
12
+
13
+ if (!merchantPartnerId) {
14
+ throw new Error('Merchant Partner ID is required for ISV operations');
15
+ }
16
+
17
+ if (!oauth2Token) {
18
+ throw new Error('OAuth2 token is required for ISV operations');
19
+ }
20
+
21
+ if (!['CONFIRMED', 'DECLINED'].includes(action)) {
22
+ throw new Error('Action must be either CONFIRMED or DECLINED');
23
+ }
24
+
25
+ const isvPartnerId = getPartnerIdSafe();
26
+ const privateKey = getPrivateKeySafe(useSandbox);
27
+
28
+ const requestBody = { action };
29
+
30
+ const jwtData = await createJWTForPartner({
31
+ partnerId: isvPartnerId,
32
+ privateKey,
33
+ requestBody,
34
+ merchantId: merchantPartnerId,
35
+ oauth2Token
36
+ });
37
+
38
+ // Use the same JSON serialization method as the JWT factory for MD5 calculation
39
+ const { createMinimizedJSON } = await import('../../core/utils/json-serializer.js');
40
+ const minimizedBodyString = createMinimizedJSON(requestBody);
41
+
42
+ try {
43
+ const baseUrl = useSandbox ? getSandboxUrl() : getProductionUrl();
44
+ // Send the exact minimized JSON string that was used for MD5 calculation
45
+ const response = await axios.patch(`${baseUrl}/transactions/${transactionId}`, minimizedBodyString, {
46
+ headers: {
47
+ 'Authorization': `Bearer ${jwtData.token}`,
48
+ 'Content-Type': 'application/json',
49
+ 'Api-Version': '1'
50
+ },
51
+ // Tell axios to send the string as-is, don't serialize it again
52
+ transformRequest: [(data) => data]
53
+ });
54
+
55
+ return response.data;
56
+ } catch (error) {
57
+ if (error.response) {
58
+ throw new Error(`payware API Error: ${error.response.status} - ${JSON.stringify(error.response.data)}`);
59
+ }
60
+ throw error;
61
+ }
62
+ }
63
+
64
+ export const processTransactionTool = {
65
+ name: 'payware_operations_process_transaction',
66
+ description: `Process (finalize) a transaction as an ISV on behalf of a merchant.
67
+
68
+ Allows confirming or declining a transaction. Only ACTIVE transactions can be processed.
69
+ Requires ISV authentication with merchant partner ID and OAuth2 token.`,
70
+
71
+ inputSchema: {
72
+ type: 'object',
73
+ required: ['transactionId', 'merchantPartnerId', 'oauth2Token'],
74
+ properties: {
75
+ transactionId: {
76
+ type: 'string',
77
+ description: 'Transaction ID to process'
78
+ },
79
+ merchantPartnerId: {
80
+ type: 'string',
81
+ description: 'Partner ID of the target merchant'
82
+ },
83
+ oauth2Token: {
84
+ type: 'string',
85
+ description: 'OAuth2 access token obtained from the merchant'
86
+ },
87
+ action: {
88
+ type: 'string',
89
+ enum: ['CONFIRMED', 'DECLINED'],
90
+ default: 'CONFIRMED',
91
+ description: 'Action to perform on the transaction'
92
+ },
93
+ useSandbox: {
94
+ type: 'boolean',
95
+ description: 'Use sandbox environment for testing',
96
+ default: true
97
+ }
98
+ }
99
+ },
100
+
101
+ async handler(params) {
102
+ try {
103
+ const result = await processTransaction(params);
104
+
105
+ const actionEmoji = params.action === 'CONFIRMED' ? '✅' : '❌';
106
+
107
+ return {
108
+ content: [{
109
+ type: 'text',
110
+ text: `${actionEmoji} Transaction ${params.action} Successfully (ISV -> Merchant: ${params.merchantPartnerId})
111
+
112
+ 📋 **Processing Details:**
113
+ - **Transaction ID**: ${params.transactionId}
114
+ - **Action**: ${params.action}
115
+ - **New Status**: ${result.status || params.action}
116
+ - **ISV Partner**: ${getPartnerIdSafe()}
117
+ - **Target Merchant**: ${params.merchantPartnerId}
118
+
119
+ **Raw Response:**
120
+ \`\`\`json
121
+ ${JSON.stringify(result, null, 2)}
122
+ \`\`\``
123
+ }]
124
+ };
125
+ } catch (error) {
126
+ return {
127
+ content: [{
128
+ type: 'text',
129
+ text: `❌ Transaction Processing Failed
130
+
131
+ **Error**: ${error.message}
132
+
133
+ **Processing Attempt:**
134
+ - Transaction ID: ${params.transactionId}
135
+ - Action: ${params.action}
136
+ - Merchant: ${params.merchantPartnerId}
137
+
138
+ **ISV Authentication:**
139
+ - OAuth2 Token: ${params.oauth2Token ? 'Provided' : 'Missing'}
140
+ - ISV Partner ID: ${getPartnerIdSafe()}`
141
+ }]
142
+ };
143
+ }
144
+ }
145
+ };
@@ -0,0 +1,146 @@
1
+ import axios from 'axios';
2
+ import { createJWTForPartner } from '../../core/auth/jwt-factory.js';
3
+ import { getSandboxUrl, getProductionUrl, getPartnerIdSafe, getPrivateKeySafe } from '../../config/env.js';
4
+
5
+ /**
6
+ * Simulate a transaction callback via payware API as an ISV
7
+ */
8
+ export async function simulateCallback({ transactionId, merchantPartnerId, oauth2Token, action = 'CONFIRMED', useSandbox = true }) {
9
+ if (!transactionId) {
10
+ throw new Error('Transaction ID is required');
11
+ }
12
+
13
+ if (!merchantPartnerId) {
14
+ throw new Error('Merchant Partner ID is required for ISV operations');
15
+ }
16
+
17
+ if (!oauth2Token) {
18
+ throw new Error('OAuth2 token is required for ISV operations');
19
+ }
20
+
21
+ if (!['CONFIRMED', 'DECLINED'].includes(action)) {
22
+ throw new Error('Action must be either CONFIRMED or DECLINED');
23
+ }
24
+
25
+ const isvPartnerId = getPartnerIdSafe();
26
+ const privateKey = getPrivateKeySafe(useSandbox);
27
+
28
+ const requestBody = { action };
29
+
30
+ const jwtData = await createJWTForPartner({
31
+ partnerId: isvPartnerId,
32
+ privateKey,
33
+ requestBody,
34
+ merchantId: merchantPartnerId,
35
+ oauth2Token
36
+ });
37
+
38
+ // Use the same JSON serialization method as the JWT factory for MD5 calculation
39
+ const { createMinimizedJSON } = await import('../../core/utils/json-serializer.js');
40
+ const minimizedBodyString = createMinimizedJSON(requestBody);
41
+
42
+ try {
43
+ const baseUrl = useSandbox ? getSandboxUrl() : getProductionUrl();
44
+ // Send the exact minimized JSON string that was used for MD5 calculation
45
+ const response = await axios.post(`${baseUrl}/transactions/${transactionId}/simulate-callback`, minimizedBodyString, {
46
+ headers: {
47
+ 'Authorization': `Bearer ${jwtData.token}`,
48
+ 'Content-Type': 'application/json',
49
+ 'Api-Version': '1'
50
+ },
51
+ // Tell axios to send the string as-is, don't serialize it again
52
+ transformRequest: [(data) => data]
53
+ });
54
+
55
+ return response.data;
56
+ } catch (error) {
57
+ if (error.response) {
58
+ throw new Error(`payware API Error: ${error.response.status} - ${JSON.stringify(error.response.data)}`);
59
+ }
60
+ throw error;
61
+ }
62
+ }
63
+
64
+ export const simulateCallbackTool = {
65
+ name: 'payware_operations_simulate_callback',
66
+ description: `Simulate a transaction callback as an ISV on behalf of a merchant.
67
+
68
+ Triggers a callback to test webhook integration in sandbox environment.
69
+ Requires ISV authentication with merchant partner ID and OAuth2 token.`,
70
+
71
+ inputSchema: {
72
+ type: 'object',
73
+ required: ['transactionId', 'merchantPartnerId', 'oauth2Token'],
74
+ properties: {
75
+ transactionId: {
76
+ type: 'string',
77
+ description: 'Transaction ID to simulate callback for'
78
+ },
79
+ merchantPartnerId: {
80
+ type: 'string',
81
+ description: 'Partner ID of the target merchant'
82
+ },
83
+ oauth2Token: {
84
+ type: 'string',
85
+ description: 'OAuth2 access token obtained from the merchant'
86
+ },
87
+ action: {
88
+ type: 'string',
89
+ enum: ['CONFIRMED', 'DECLINED'],
90
+ default: 'CONFIRMED',
91
+ description: 'Action to simulate in the callback'
92
+ },
93
+ useSandbox: {
94
+ type: 'boolean',
95
+ description: 'Use sandbox environment for testing',
96
+ default: true
97
+ }
98
+ }
99
+ },
100
+
101
+ async handler(params) {
102
+ try {
103
+ const result = await simulateCallback(params);
104
+
105
+ const actionEmoji = params.action === 'CONFIRMED' ? '✅' : '❌';
106
+
107
+ return {
108
+ content: [{
109
+ type: 'text',
110
+ text: `🔔 Callback Simulated Successfully (ISV -> Merchant: ${params.merchantPartnerId})
111
+
112
+ **Callback Details:**
113
+ - **Transaction ID**: ${params.transactionId}
114
+ - **Simulated Action**: ${actionEmoji} ${params.action}
115
+ - **ISV Partner**: ${getPartnerIdSafe()}
116
+ - **Target Merchant**: ${params.merchantPartnerId}
117
+
118
+ **Use Case**: Testing webhook integration in sandbox environment
119
+
120
+ **Raw Response:**
121
+ \`\`\`json
122
+ ${JSON.stringify(result, null, 2)}
123
+ \`\`\``
124
+ }]
125
+ };
126
+ } catch (error) {
127
+ return {
128
+ content: [{
129
+ type: 'text',
130
+ text: `❌ Callback Simulation Failed
131
+
132
+ **Error**: ${error.message}
133
+
134
+ **Simulation Attempt:**
135
+ - Transaction ID: ${params.transactionId}
136
+ - Action: ${params.action}
137
+ - Merchant: ${params.merchantPartnerId}
138
+
139
+ **ISV Authentication:**
140
+ - OAuth2 Token: ${params.oauth2Token ? 'Provided' : 'Missing'}
141
+ - ISV Partner ID: ${getPartnerIdSafe()}`
142
+ }]
143
+ };
144
+ }
145
+ }
146
+ };
@@ -0,0 +1,186 @@
1
+ import axios from 'axios';
2
+ import { createJWTForPartner } from '../../core/auth/jwt-factory.js';
3
+ import { getSandboxUrl, getProductionUrl, getPartnerIdSafe, getPrivateKeySafe } from '../../config/env.js';
4
+
5
+ /**
6
+ * Get transaction history from payware API as an ISV
7
+ */
8
+ export async function getTransactionHistory({
9
+ merchantPartnerId,
10
+ oauth2Token,
11
+ partnerId,
12
+ transactionId,
13
+ limit = 50,
14
+ offset = 0,
15
+ status,
16
+ from,
17
+ to,
18
+ useSandbox = true
19
+ }) {
20
+ if (!merchantPartnerId) {
21
+ throw new Error('Merchant Partner ID is required for ISV operations');
22
+ }
23
+
24
+ if (!oauth2Token) {
25
+ throw new Error('OAuth2 token is required for ISV operations');
26
+ }
27
+
28
+ const isvPartnerId = getPartnerIdSafe();
29
+ const privateKey = getPrivateKeySafe(useSandbox);
30
+
31
+ const jwtData = await createJWTForPartner({
32
+ partnerId: isvPartnerId,
33
+ privateKey,
34
+ requestBody: null,
35
+ merchantId: merchantPartnerId,
36
+ oauth2Token
37
+ });
38
+
39
+ const params = new URLSearchParams();
40
+ if (partnerId) params.append('partnerId', partnerId);
41
+ if (transactionId) params.append('transactionId', transactionId);
42
+ if (limit) params.append('limit', limit.toString());
43
+ if (offset) params.append('offset', offset.toString());
44
+ if (status) params.append('status', status);
45
+ if (from) params.append('from', from);
46
+ if (to) params.append('to', to);
47
+
48
+ try {
49
+ const baseUrl = useSandbox ? getSandboxUrl() : getProductionUrl();
50
+ const url = `${baseUrl}/transactions-history?${params.toString()}`;
51
+ const response = await axios.get(url, {
52
+ headers: {
53
+ 'Authorization': `Bearer ${jwtData.token}`,
54
+ 'Content-Type': 'application/json',
55
+ 'Api-Version': '1'
56
+ }
57
+ });
58
+
59
+ return response.data;
60
+ } catch (error) {
61
+ if (error.response) {
62
+ throw new Error(`payware API Error: ${error.response.status} - ${JSON.stringify(error.response.data)}`);
63
+ }
64
+ throw error;
65
+ }
66
+ }
67
+
68
+ export const getTransactionHistoryTool = {
69
+ name: 'payware_operations_get_transaction_history',
70
+ description: `Get transaction history as an ISV on behalf of a merchant.
71
+
72
+ Retrieves both active and completed transactions with optional filtering.
73
+ Requires ISV authentication with merchant partner ID and OAuth2 token.`,
74
+
75
+ inputSchema: {
76
+ type: 'object',
77
+ required: ['merchantPartnerId', 'oauth2Token'],
78
+ properties: {
79
+ merchantPartnerId: {
80
+ type: 'string',
81
+ description: 'Partner ID of the target merchant'
82
+ },
83
+ oauth2Token: {
84
+ type: 'string',
85
+ description: 'OAuth2 access token obtained from the merchant'
86
+ },
87
+ partnerId: {
88
+ type: 'string',
89
+ description: 'Filter by partner ID (optional)'
90
+ },
91
+ transactionId: {
92
+ type: 'string',
93
+ description: 'Filter by specific transaction ID (optional)'
94
+ },
95
+ limit: {
96
+ type: 'number',
97
+ default: 50,
98
+ description: 'Maximum number of results to return'
99
+ },
100
+ offset: {
101
+ type: 'number',
102
+ default: 0,
103
+ description: 'Number of results to skip for pagination'
104
+ },
105
+ status: {
106
+ type: 'string',
107
+ enum: ['ACTIVE', 'CONFIRMED', 'DECLINED', 'FAILED', 'EXPIRED', 'CANCELLED'],
108
+ description: 'Filter by transaction status'
109
+ },
110
+ from: {
111
+ type: 'string',
112
+ description: 'Start date for filtering (YYYY-MM-DD format)'
113
+ },
114
+ to: {
115
+ type: 'string',
116
+ description: 'End date for filtering (YYYY-MM-DD format)'
117
+ },
118
+ useSandbox: {
119
+ type: 'boolean',
120
+ description: 'Use sandbox environment for testing',
121
+ default: true
122
+ }
123
+ }
124
+ },
125
+
126
+ async handler(params) {
127
+ try {
128
+ const result = await getTransactionHistory(params);
129
+
130
+ const transactions = result.transactions || [];
131
+ const totalCount = result.totalCount || transactions.length;
132
+
133
+ const formatTransaction = (tx) => {
134
+ const statusEmojis = {
135
+ 'ACTIVE': '⏳',
136
+ 'CONFIRMED': '✅',
137
+ 'DECLINED': '❌',
138
+ 'FAILED': '⚠️',
139
+ 'EXPIRED': '⏰',
140
+ 'CANCELLED': '🚫'
141
+ };
142
+ const emoji = statusEmojis[tx.status] || '❓';
143
+ return ` ${emoji} **${tx.id}** - ${tx.trData?.amount || '0.00'} ${tx.trData?.currency || 'EUR'} - ${tx.status} - ${tx.createdAt || 'N/A'}`;
144
+ };
145
+
146
+ return {
147
+ content: [{
148
+ type: 'text',
149
+ text: `📈 **Transaction History Retrieved (ISV -> Merchant: ${params.merchantPartnerId})**
150
+
151
+ **ISV Integration:**
152
+ - ISV Partner: ${getPartnerIdSafe()}
153
+ - Target Merchant: ${params.merchantPartnerId}
154
+ - OAuth2 Token: ${params.oauth2Token.substring(0, 8)}...
155
+
156
+ **Results:** ${transactions.length} of ${totalCount} transactions
157
+
158
+ **Transactions:**
159
+ ${transactions.length > 0 ? transactions.map(formatTransaction).join('\n') : ' No transactions found'}
160
+
161
+ **Applied Filters:**
162
+ ${params.status ? `- Status: ${params.status}\n` : ''}${params.from ? `- From: ${params.from}\n` : ''}${params.to ? `- To: ${params.to}\n` : ''}${params.limit ? `- Limit: ${params.limit}\n` : ''}${params.offset ? `- Offset: ${params.offset}\n` : ''}
163
+
164
+ **Raw Response:**
165
+ \`\`\`json
166
+ ${JSON.stringify(result, null, 2)}
167
+ \`\`\``
168
+ }]
169
+ };
170
+ } catch (error) {
171
+ return {
172
+ content: [{
173
+ type: 'text',
174
+ text: `❌ Transaction History Request Failed
175
+
176
+ **Error**: ${error.message}
177
+
178
+ **ISV Authentication:**
179
+ - Merchant Partner ID: ${params.merchantPartnerId}
180
+ - OAuth2 Token: ${params.oauth2Token ? 'Provided' : 'Missing'}
181
+ - ISV Partner ID: ${getPartnerIdSafe()}`
182
+ }]
183
+ };
184
+ }
185
+ }
186
+ };
@@ -0,0 +1,159 @@
1
+ /**
2
+ * ISV-specific authentication utilities
3
+ * Handles OAuth2 and JWT token creation for ISV partners
4
+ */
5
+
6
+ import { createJWTForPartner, getAuthHeaders } from '../../core/auth/jwt-factory.js';
7
+ import { getPartnerIdSafe, getPrivateKeySafe } from '../../config/env.js';
8
+
9
+ /**
10
+ * Create ISV JWT token for API requests
11
+ * @param {Object} options - JWT creation options
12
+ * @param {string} options.merchantPartnerId - Target merchant partner ID (required for API calls)
13
+ * @param {string} options.oauth2Token - OAuth2 token (required for API calls)
14
+ * @param {Object} options.requestBody - Request body for POST/PUT/PATCH requests
15
+ * @param {string} options.audience - JWT audience (defaults to merchant partner ID, or https://payware.eu for OAuth2 requests)
16
+ * @param {boolean} options.isOAuth2Request - Set to true for OAuth2 endpoint requests
17
+ * @param {boolean} options.isGetRequest - Set to true for GET requests (no body)
18
+ * @returns {string} JWT token string
19
+ */
20
+ export async function createISVJWT(options = {}) {
21
+ const {
22
+ merchantPartnerId,
23
+ oauth2Token,
24
+ requestBody = null,
25
+ audience = null,
26
+ isOAuth2Request = false,
27
+ isGetRequest = false
28
+ } = options;
29
+
30
+ const isvPartnerId = getPartnerIdSafe();
31
+ const privateKey = getPrivateKeySafe();
32
+
33
+ // For OAuth2 requests, we need special handling
34
+ if (isOAuth2Request) {
35
+ return await createOAuth2JWT({
36
+ isvPartnerId,
37
+ privateKey,
38
+ requestBody,
39
+ audience: audience || 'https://payware.eu'
40
+ });
41
+ }
42
+
43
+ // For regular API requests, we need merchant partner ID and OAuth2 token
44
+ if (!merchantPartnerId) {
45
+ throw new Error('Merchant Partner ID is required for ISV API requests');
46
+ }
47
+
48
+ if (!oauth2Token) {
49
+ throw new Error('OAuth2 token is required for ISV API requests');
50
+ }
51
+
52
+ const jwtData = await createJWTForPartner({
53
+ partnerId: isvPartnerId,
54
+ privateKey,
55
+ requestBody: isGetRequest ? null : requestBody,
56
+ merchantId: merchantPartnerId,
57
+ oauth2Token
58
+ });
59
+
60
+ return jwtData.token;
61
+ }
62
+
63
+ /**
64
+ * Create JWT specifically for OAuth2 endpoint requests
65
+ * @param {Object} options - OAuth2 JWT options
66
+ * @returns {string} JWT token string
67
+ */
68
+ async function createOAuth2JWT({ isvPartnerId, privateKey, requestBody, audience }) {
69
+ // Dynamic imports to avoid circular dependencies
70
+ const jwt = await import('jsonwebtoken');
71
+ const crypto = await import('crypto');
72
+ const { normalizePrivateKey } = await import('../../core/utils/key-utils.js');
73
+
74
+ const normalizedKey = normalizePrivateKey(privateKey);
75
+ const now = Math.floor(Date.now() / 1000);
76
+
77
+ // JWT Header
78
+ const header = {
79
+ alg: 'RS256',
80
+ typ: 'JWT'
81
+ };
82
+
83
+ // Add contentMd5 to header if request body exists
84
+ if (requestBody) {
85
+ // Use standard JSON.stringify to match axios serialization (preserves property order)
86
+ const bodyString = JSON.stringify(requestBody);
87
+ header.contentMd5 = crypto.default.createHash('md5').update(bodyString, 'utf8').digest('base64');
88
+ }
89
+
90
+ // JWT Payload for OAuth2 requests
91
+ const payload = {
92
+ iss: isvPartnerId, // ISV's partner ID
93
+ aud: audience, // https://payware.eu for OAuth2 requests
94
+ iat: now
95
+ };
96
+
97
+ const token = jwt.default.sign(payload, normalizedKey, {
98
+ algorithm: 'RS256',
99
+ header: header
100
+ });
101
+
102
+ return token;
103
+ }
104
+
105
+ /**
106
+ * Create authentication headers for ISV requests
107
+ * @param {string} jwt - JWT token
108
+ * @param {boolean} isOAuth2Request - Whether this is for OAuth2 endpoints (no Api-Version header)
109
+ * @returns {Object} Headers object with Authorization and Content-Type
110
+ */
111
+ export function createISVAuthHeaders(jwt, isOAuth2Request = false) {
112
+ if (isOAuth2Request) {
113
+ // OAuth2 endpoints don't need Api-Version header
114
+ return {
115
+ 'Authorization': `Bearer ${jwt}`,
116
+ 'Content-Type': 'application/json'
117
+ };
118
+ }
119
+
120
+ // Regular API endpoints need Api-Version header
121
+ return getAuthHeaders(jwt);
122
+ }
123
+
124
+ /**
125
+ * Validate ISV request parameters
126
+ * @param {Object} params - Parameters to validate
127
+ * @param {boolean} params.requireMerchant - Whether merchant partner ID is required
128
+ * @param {boolean} params.requireToken - Whether OAuth2 token is required
129
+ * @throws {Error} If validation fails
130
+ */
131
+ export function validateISVParams({ merchantPartnerId, oauth2Token, requireMerchant = true, requireToken = true }) {
132
+ if (requireMerchant && !merchantPartnerId) {
133
+ throw new Error('Merchant Partner ID is required for ISV operations');
134
+ }
135
+
136
+ if (requireToken && !oauth2Token) {
137
+ throw new Error('OAuth2 token is required for ISV API operations');
138
+ }
139
+
140
+ // Validate partner ID format (basic validation)
141
+ if (merchantPartnerId && !/^[A-Z0-9]{8}$/.test(merchantPartnerId)) {
142
+ console.warn('Merchant Partner ID should be 8 alphanumeric characters (e.g., "PZAYNMVE")');
143
+ }
144
+ }
145
+
146
+ /**
147
+ * Extract partner information from ISV context
148
+ * @returns {Object} Partner information
149
+ */
150
+ export function getISVPartnerInfo() {
151
+ const partnerId = getPartnerIdSafe();
152
+ const privateKey = getPrivateKeySafe();
153
+
154
+ return {
155
+ isvPartnerId: partnerId,
156
+ hasPrivateKey: !!privateKey,
157
+ partnerType: 'isv'
158
+ };
159
+ }