@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,872 @@
1
+ import axios from 'axios';
2
+ import FormData from 'form-data';
3
+ import { createJWTToken } from '../../core/auth/jwt-token.js';
4
+ import { createJWTForPartner } from '../../core/auth/jwt-factory.js';
5
+ import { createMinimizedJSON } from '../../core/utils/json-serializer.js';
6
+ import { getSandboxUrl, getProductionUrl } from '../../config/env.js';
7
+
8
+ /**
9
+ * Product types
10
+ */
11
+ export const PRODUCT_TYPES = {
12
+ ITEM: 'ITEM',
13
+ SERVICE: 'SERVICE'
14
+ };
15
+
16
+ /**
17
+ * Price correction types for schedules
18
+ */
19
+ export const PRICE_CORRECTION_TYPES = {
20
+ DISCOUNT: 'DISCOUNT',
21
+ INCREMENT: 'INCREMENT'
22
+ };
23
+
24
+ /**
25
+ * Correction methods for schedules
26
+ */
27
+ export const CORRECTION_TYPES = {
28
+ PERCENTAGE: 'PERCENTAGE',
29
+ VALUE: 'VALUE'
30
+ };
31
+
32
+ /**
33
+ * Overlap priority options
34
+ */
35
+ export const OVERLAP_PRIORITY = {
36
+ LOWEST: 'LOWEST',
37
+ HIGHEST: 'HIGHEST'
38
+ };
39
+
40
+ /**
41
+ * QR code error correction levels
42
+ */
43
+ export const QR_ERROR_CORRECTION = {
44
+ LOW: 'LOW',
45
+ MEDIUM: 'MEDIUM',
46
+ QUARTILE: 'QUARTILE',
47
+ HIGH: 'HIGH'
48
+ };
49
+
50
+ /**
51
+ * Image formats
52
+ */
53
+ export const IMAGE_FORMATS = {
54
+ PNG: 'PNG',
55
+ SVG: 'SVG',
56
+ JPG: 'JPG'
57
+ };
58
+
59
+ /**
60
+ * Image types
61
+ */
62
+ export const IMAGE_TYPES = {
63
+ QR: 'QR',
64
+ BARCODE: 'BARCODE'
65
+ };
66
+
67
+ /**
68
+ * Barcode human readable locations
69
+ */
70
+ export const BARCODE_LOCATIONS = {
71
+ NONE: 'NONE',
72
+ BOTTOM: 'BOTTOM',
73
+ TOP: 'TOP'
74
+ };
75
+
76
+ /**
77
+ * Create authentication headers based on partner type
78
+ * @param {string} partnerType - merchant, isv, or payment_institution
79
+ * @param {Object} authParams - Authentication parameters
80
+ * @returns {Object} Headers for API request
81
+ */
82
+ async function createAuthHeaders(partnerType, authParams) {
83
+ const baseHeaders = {
84
+ 'Content-Type': 'application/json',
85
+ 'Api-Version': '1'
86
+ };
87
+
88
+ let tokenData;
89
+
90
+ switch (partnerType) {
91
+ case 'merchant':
92
+ case 'payment_institution':
93
+ // Standard JWT authentication
94
+ tokenData = createJWTToken(
95
+ authParams.partnerId,
96
+ authParams.privateKey,
97
+ authParams.requestBody
98
+ );
99
+ break;
100
+
101
+ case 'isv':
102
+ // ISV JWT with OAuth2
103
+ tokenData = await createJWTForPartner({
104
+ partnerId: authParams.isvPartnerId,
105
+ privateKey: authParams.privateKey,
106
+ merchantId: authParams.merchantPartnerId,
107
+ oauth2Token: authParams.oauth2Token,
108
+ requestBody: authParams.requestBody
109
+ });
110
+ break;
111
+
112
+ default:
113
+ throw new Error(`Unknown partner type: ${partnerType}`);
114
+ }
115
+
116
+ return {
117
+ ...baseHeaders,
118
+ 'Authorization': `Bearer ${tokenData.token}`
119
+ };
120
+ }
121
+
122
+ /**
123
+ * Create authentication headers for multipart/form-data requests
124
+ */
125
+ async function createMultipartAuthHeaders(partnerType, authParams) {
126
+ const headers = await createAuthHeaders(partnerType, authParams);
127
+ // Remove Content-Type to let axios set it with boundary for multipart
128
+ delete headers['Content-Type'];
129
+ return headers;
130
+ }
131
+
132
+ // ====================
133
+ // PRODUCT MANAGEMENT
134
+ // ====================
135
+
136
+ /**
137
+ * Create a new product
138
+ */
139
+ export async function createProduct({
140
+ name,
141
+ shortDescription,
142
+ longDescription,
143
+ sku,
144
+ upc,
145
+ shippable = 'FALSE',
146
+ active = 'FALSE',
147
+ shop,
148
+ prData = {},
149
+ prOptions = {},
150
+ partnerType,
151
+ useSandbox = false,
152
+ ...authParams
153
+ }) {
154
+ if (!name) {
155
+ throw new Error('Product name is required');
156
+ }
157
+
158
+ const requestBody = {
159
+ name,
160
+ shippable,
161
+ active
162
+ };
163
+
164
+ // Optional fields
165
+ if (shop) requestBody.shop = shop;
166
+ if (shortDescription) requestBody.shortDescription = shortDescription;
167
+ if (longDescription) requestBody.longDescription = longDescription;
168
+ if (sku) requestBody.sku = sku;
169
+ if (upc) requestBody.upc = upc;
170
+ if (Object.keys(prData).length > 0) requestBody.prData = prData;
171
+ if (Object.keys(prOptions).length > 0) requestBody.prOptions = prOptions;
172
+
173
+ const minimizedBody = createMinimizedJSON(requestBody);
174
+ const headers = await createAuthHeaders(partnerType, { ...authParams, requestBody: minimizedBody });
175
+ const baseUrl = useSandbox ? getSandboxUrl() : getProductionUrl();
176
+
177
+ try {
178
+ const response = await axios.post(
179
+ `${baseUrl}/products`,
180
+ minimizedBody,
181
+ { headers }
182
+ );
183
+
184
+ return {
185
+ success: true,
186
+ data: response.data,
187
+ requestInfo: {
188
+ url: `${baseUrl}/products`,
189
+ method: 'POST',
190
+ requestBody: minimizedBody,
191
+ statusCode: response.status
192
+ }
193
+ };
194
+ } catch (error) {
195
+ throw new Error(`Failed to create product: ${error.response?.data?.message || error.message}`);
196
+ }
197
+ }
198
+
199
+ /**
200
+ * Get list of products
201
+ */
202
+ export async function getProducts({
203
+ partnerType,
204
+ useSandbox = false,
205
+ ...authParams
206
+ }) {
207
+ const headers = await createAuthHeaders(partnerType, authParams);
208
+ const baseUrl = useSandbox ? getSandboxUrl() : getProductionUrl();
209
+
210
+ try {
211
+ const response = await axios.get(
212
+ `${baseUrl}/products`,
213
+ { headers }
214
+ );
215
+
216
+ return {
217
+ success: true,
218
+ data: response.data,
219
+ requestInfo: {
220
+ url: `${baseUrl}/products`,
221
+ method: 'GET',
222
+ statusCode: response.status
223
+ }
224
+ };
225
+ } catch (error) {
226
+ throw new Error(`Failed to get products: ${error.response?.data?.message || error.message}`);
227
+ }
228
+ }
229
+
230
+ /**
231
+ * Get product information by ID
232
+ */
233
+ export async function getProduct({
234
+ productId,
235
+ partnerType,
236
+ useSandbox = false,
237
+ ...authParams
238
+ }) {
239
+ if (!productId) {
240
+ throw new Error('productId is required');
241
+ }
242
+
243
+ const headers = await createAuthHeaders(partnerType, authParams);
244
+ const baseUrl = useSandbox ? getSandboxUrl() : getProductionUrl();
245
+
246
+ try {
247
+ const response = await axios.get(
248
+ `${baseUrl}/products/${productId}`,
249
+ { headers }
250
+ );
251
+
252
+ return {
253
+ success: true,
254
+ data: response.data,
255
+ requestInfo: {
256
+ url: `${baseUrl}/products/${productId}`,
257
+ method: 'GET',
258
+ statusCode: response.status
259
+ }
260
+ };
261
+ } catch (error) {
262
+ throw new Error(`Failed to get product: ${error.response?.data?.message || error.message}`);
263
+ }
264
+ }
265
+
266
+ /**
267
+ * Update product
268
+ */
269
+ export async function updateProduct({
270
+ productId,
271
+ name,
272
+ shortDescription,
273
+ longDescription,
274
+ sku,
275
+ upc,
276
+ shippable,
277
+ active,
278
+ shop,
279
+ prData = {},
280
+ prOptions = {},
281
+ partnerType,
282
+ useSandbox = false,
283
+ ...authParams
284
+ }) {
285
+ if (!productId) {
286
+ throw new Error('productId is required');
287
+ }
288
+
289
+ const requestBody = {};
290
+
291
+ // Only include fields that are provided
292
+ if (name !== undefined) requestBody.name = name;
293
+ if (shop !== undefined) requestBody.shop = shop;
294
+ if (shortDescription !== undefined) requestBody.shortDescription = shortDescription;
295
+ if (longDescription !== undefined) requestBody.longDescription = longDescription;
296
+ if (sku !== undefined) requestBody.sku = sku;
297
+ if (upc !== undefined) requestBody.upc = upc;
298
+ if (shippable !== undefined) requestBody.shippable = shippable;
299
+ if (active !== undefined) requestBody.active = active;
300
+ if (Object.keys(prData).length > 0) requestBody.prData = prData;
301
+ if (Object.keys(prOptions).length > 0) requestBody.prOptions = prOptions;
302
+
303
+ const minimizedBody = createMinimizedJSON(requestBody);
304
+ const headers = await createAuthHeaders(partnerType, { ...authParams, requestBody: minimizedBody });
305
+ const baseUrl = useSandbox ? getSandboxUrl() : getProductionUrl();
306
+
307
+ try {
308
+ const response = await axios.patch(
309
+ `${baseUrl}/products/${productId}`,
310
+ minimizedBody,
311
+ { headers }
312
+ );
313
+
314
+ return {
315
+ success: true,
316
+ data: response.data,
317
+ requestInfo: {
318
+ url: `${baseUrl}/products/${productId}`,
319
+ method: 'PATCH',
320
+ requestBody: minimizedBody,
321
+ statusCode: response.status
322
+ }
323
+ };
324
+ } catch (error) {
325
+ throw new Error(`Failed to update product: ${error.response?.data?.message || error.message}`);
326
+ }
327
+ }
328
+
329
+ /**
330
+ * Delete product
331
+ */
332
+ export async function deleteProduct({
333
+ productId,
334
+ partnerType,
335
+ useSandbox = false,
336
+ ...authParams
337
+ }) {
338
+ if (!productId) {
339
+ throw new Error('productId is required');
340
+ }
341
+
342
+ const headers = await createAuthHeaders(partnerType, authParams);
343
+ const baseUrl = useSandbox ? getSandboxUrl() : getProductionUrl();
344
+
345
+ try {
346
+ const response = await axios.delete(
347
+ `${baseUrl}/products/${productId}`,
348
+ { headers }
349
+ );
350
+
351
+ return {
352
+ success: true,
353
+ requestInfo: {
354
+ url: `${baseUrl}/products/${productId}`,
355
+ method: 'DELETE',
356
+ statusCode: response.status
357
+ }
358
+ };
359
+ } catch (error) {
360
+ throw new Error(`Failed to delete product: ${error.response?.data?.message || error.message}`);
361
+ }
362
+ }
363
+
364
+ /**
365
+ * Generate product image (QR code or barcode)
366
+ */
367
+ export async function getProductImage({
368
+ productId,
369
+ type = IMAGE_TYPES.QR,
370
+ qrOptions = {},
371
+ barOptions = {},
372
+ partnerType,
373
+ useSandbox = false,
374
+ ...authParams
375
+ }) {
376
+ if (!productId) {
377
+ throw new Error('productId is required');
378
+ }
379
+
380
+ const requestBody = {
381
+ type
382
+ };
383
+
384
+ if (type === IMAGE_TYPES.QR && Object.keys(qrOptions).length > 0) {
385
+ requestBody.qrOptions = qrOptions;
386
+ }
387
+ if (type === IMAGE_TYPES.BARCODE && Object.keys(barOptions).length > 0) {
388
+ requestBody.barOptions = barOptions;
389
+ }
390
+
391
+ const minimizedBody = createMinimizedJSON(requestBody);
392
+ const headers = await createAuthHeaders(partnerType, { ...authParams, requestBody: minimizedBody });
393
+ const baseUrl = useSandbox ? getSandboxUrl() : getProductionUrl();
394
+
395
+ try {
396
+ const response = await axios.post(
397
+ `${baseUrl}/products/${productId}/image`,
398
+ minimizedBody,
399
+ { headers }
400
+ );
401
+
402
+ return {
403
+ success: true,
404
+ data: response.data,
405
+ requestInfo: {
406
+ url: `${baseUrl}/products/${productId}/image`,
407
+ method: 'POST',
408
+ requestBody: minimizedBody,
409
+ statusCode: response.status
410
+ }
411
+ };
412
+ } catch (error) {
413
+ throw new Error(`Failed to get product image: ${error.response?.data?.message || error.message}`);
414
+ }
415
+ }
416
+
417
+ // ====================
418
+ // PRICE SCHEDULES
419
+ // ====================
420
+
421
+ /**
422
+ * Create price schedule for a product
423
+ */
424
+ export async function createPriceSchedule({
425
+ productId,
426
+ description,
427
+ priceCorrection = PRICE_CORRECTION_TYPES.DISCOUNT,
428
+ correctionType = CORRECTION_TYPES.PERCENTAGE,
429
+ correctionValue = '0.00',
430
+ dateFrom,
431
+ dateTo,
432
+ partnerType,
433
+ useSandbox = false,
434
+ ...authParams
435
+ }) {
436
+ if (!productId) {
437
+ throw new Error('productId is required');
438
+ }
439
+
440
+ const requestBody = {
441
+ priceCorrection,
442
+ correctionType,
443
+ correctionValue
444
+ };
445
+
446
+ if (description) requestBody.description = description;
447
+ if (dateFrom) requestBody.dateFrom = dateFrom;
448
+ if (dateTo) requestBody.dateTo = dateTo;
449
+
450
+ const minimizedBody = createMinimizedJSON(requestBody);
451
+ const headers = await createAuthHeaders(partnerType, { ...authParams, requestBody: minimizedBody });
452
+ const baseUrl = useSandbox ? getSandboxUrl() : getProductionUrl();
453
+
454
+ try {
455
+ const response = await axios.post(
456
+ `${baseUrl}/products/${productId}/schedules`,
457
+ minimizedBody,
458
+ { headers }
459
+ );
460
+
461
+ return {
462
+ success: true,
463
+ data: response.data,
464
+ requestInfo: {
465
+ url: `${baseUrl}/products/${productId}/schedules`,
466
+ method: 'POST',
467
+ requestBody: minimizedBody,
468
+ statusCode: response.status
469
+ }
470
+ };
471
+ } catch (error) {
472
+ throw new Error(`Failed to create price schedule: ${error.response?.data?.message || error.message}`);
473
+ }
474
+ }
475
+
476
+ /**
477
+ * Get product schedules
478
+ */
479
+ export async function getProductSchedules({
480
+ productId,
481
+ partnerType,
482
+ useSandbox = false,
483
+ ...authParams
484
+ }) {
485
+ if (!productId) {
486
+ throw new Error('productId is required');
487
+ }
488
+
489
+ const headers = await createAuthHeaders(partnerType, authParams);
490
+ const baseUrl = useSandbox ? getSandboxUrl() : getProductionUrl();
491
+
492
+ try {
493
+ const response = await axios.get(
494
+ `${baseUrl}/products/${productId}/schedules`,
495
+ { headers }
496
+ );
497
+
498
+ return {
499
+ success: true,
500
+ data: response.data,
501
+ requestInfo: {
502
+ url: `${baseUrl}/products/${productId}/schedules`,
503
+ method: 'GET',
504
+ statusCode: response.status
505
+ }
506
+ };
507
+ } catch (error) {
508
+ throw new Error(`Failed to get product schedules: ${error.response?.data?.message || error.message}`);
509
+ }
510
+ }
511
+
512
+ /**
513
+ * Get schedule information
514
+ */
515
+ export async function getSchedule({
516
+ productId,
517
+ scheduleId,
518
+ partnerType,
519
+ useSandbox = false,
520
+ ...authParams
521
+ }) {
522
+ if (!productId) {
523
+ throw new Error('productId is required');
524
+ }
525
+ if (!scheduleId) {
526
+ throw new Error('scheduleId is required');
527
+ }
528
+
529
+ const headers = await createAuthHeaders(partnerType, authParams);
530
+ const baseUrl = useSandbox ? getSandboxUrl() : getProductionUrl();
531
+
532
+ try {
533
+ const response = await axios.get(
534
+ `${baseUrl}/products/${productId}/schedules/${scheduleId}`,
535
+ { headers }
536
+ );
537
+
538
+ return {
539
+ success: true,
540
+ data: response.data,
541
+ requestInfo: {
542
+ url: `${baseUrl}/products/${productId}/schedules/${scheduleId}`,
543
+ method: 'GET',
544
+ statusCode: response.status
545
+ }
546
+ };
547
+ } catch (error) {
548
+ throw new Error(`Failed to get schedule: ${error.response?.data?.message || error.message}`);
549
+ }
550
+ }
551
+
552
+ /**
553
+ * Update price schedule
554
+ */
555
+ export async function updatePriceSchedule({
556
+ productId,
557
+ scheduleId,
558
+ description,
559
+ priceCorrection,
560
+ correctionType,
561
+ correctionValue,
562
+ dateFrom,
563
+ dateTo,
564
+ partnerType,
565
+ useSandbox = false,
566
+ ...authParams
567
+ }) {
568
+ if (!productId) {
569
+ throw new Error('productId is required');
570
+ }
571
+ if (!scheduleId) {
572
+ throw new Error('scheduleId is required');
573
+ }
574
+
575
+ const requestBody = {};
576
+
577
+ if (description !== undefined) requestBody.description = description;
578
+ if (priceCorrection !== undefined) requestBody.priceCorrection = priceCorrection;
579
+ if (correctionType !== undefined) requestBody.correctionType = correctionType;
580
+ if (correctionValue !== undefined) requestBody.correctionValue = correctionValue;
581
+ if (dateFrom !== undefined) requestBody.dateFrom = dateFrom;
582
+ if (dateTo !== undefined) requestBody.dateTo = dateTo;
583
+
584
+ const minimizedBody = createMinimizedJSON(requestBody);
585
+ const headers = await createAuthHeaders(partnerType, { ...authParams, requestBody: minimizedBody });
586
+ const baseUrl = useSandbox ? getSandboxUrl() : getProductionUrl();
587
+
588
+ try {
589
+ const response = await axios.patch(
590
+ `${baseUrl}/products/${productId}/schedules/${scheduleId}`,
591
+ minimizedBody,
592
+ { headers }
593
+ );
594
+
595
+ return {
596
+ success: true,
597
+ data: response.data,
598
+ requestInfo: {
599
+ url: `${baseUrl}/products/${productId}/schedules/${scheduleId}`,
600
+ method: 'PATCH',
601
+ requestBody: minimizedBody,
602
+ statusCode: response.status
603
+ }
604
+ };
605
+ } catch (error) {
606
+ throw new Error(`Failed to update schedule: ${error.response?.data?.message || error.message}`);
607
+ }
608
+ }
609
+
610
+ /**
611
+ * Delete price schedule
612
+ */
613
+ export async function deletePriceSchedule({
614
+ productId,
615
+ scheduleId,
616
+ partnerType,
617
+ useSandbox = false,
618
+ ...authParams
619
+ }) {
620
+ if (!productId) {
621
+ throw new Error('productId is required');
622
+ }
623
+ if (!scheduleId) {
624
+ throw new Error('scheduleId is required');
625
+ }
626
+
627
+ const headers = await createAuthHeaders(partnerType, authParams);
628
+ const baseUrl = useSandbox ? getSandboxUrl() : getProductionUrl();
629
+
630
+ try {
631
+ const response = await axios.delete(
632
+ `${baseUrl}/products/${productId}/schedules/${scheduleId}`,
633
+ { headers }
634
+ );
635
+
636
+ return {
637
+ success: true,
638
+ requestInfo: {
639
+ url: `${baseUrl}/products/${productId}/schedules/${scheduleId}`,
640
+ method: 'DELETE',
641
+ statusCode: response.status
642
+ }
643
+ };
644
+ } catch (error) {
645
+ throw new Error(`Failed to delete schedule: ${error.response?.data?.message || error.message}`);
646
+ }
647
+ }
648
+
649
+ // ====================
650
+ // AUDIO/SOUNDBITE MANAGEMENT
651
+ // ====================
652
+
653
+ /**
654
+ * Register audio file for a product
655
+ */
656
+ export async function registerAudio({
657
+ productId,
658
+ audioFile,
659
+ audioPath,
660
+ partnerType,
661
+ useSandbox = false,
662
+ ...authParams
663
+ }) {
664
+ if (!productId) {
665
+ throw new Error('productId is required');
666
+ }
667
+ if (!audioFile && !audioPath) {
668
+ throw new Error('Either audioFile buffer or audioPath is required');
669
+ }
670
+
671
+ const formData = new FormData();
672
+
673
+ if (audioFile) {
674
+ formData.append('file', audioFile);
675
+ } else if (audioPath) {
676
+ const fs = await import('fs');
677
+ formData.append('file', fs.createReadStream(audioPath));
678
+ }
679
+
680
+ const headers = await createMultipartAuthHeaders(partnerType, authParams);
681
+ const baseUrl = useSandbox ? getSandboxUrl() : getProductionUrl();
682
+
683
+ try {
684
+ const response = await axios.post(
685
+ `${baseUrl}/products/${productId}/audios/upload`,
686
+ formData,
687
+ {
688
+ headers: {
689
+ ...headers,
690
+ ...formData.getHeaders()
691
+ }
692
+ }
693
+ );
694
+
695
+ return {
696
+ success: true,
697
+ data: response.data,
698
+ requestInfo: {
699
+ url: `${baseUrl}/products/${productId}/audios/upload`,
700
+ method: 'POST',
701
+ statusCode: response.status
702
+ }
703
+ };
704
+ } catch (error) {
705
+ throw new Error(`Failed to register audio: ${error.response?.data?.message || error.message}`);
706
+ }
707
+ }
708
+
709
+ /**
710
+ * Get product audios
711
+ */
712
+ export async function getProductAudios({
713
+ productId,
714
+ partnerType,
715
+ useSandbox = false,
716
+ ...authParams
717
+ }) {
718
+ if (!productId) {
719
+ throw new Error('productId is required');
720
+ }
721
+
722
+ const headers = await createAuthHeaders(partnerType, authParams);
723
+ const baseUrl = useSandbox ? getSandboxUrl() : getProductionUrl();
724
+
725
+ try {
726
+ const response = await axios.get(
727
+ `${baseUrl}/products/${productId}/audios`,
728
+ { headers }
729
+ );
730
+
731
+ return {
732
+ success: true,
733
+ data: response.data,
734
+ requestInfo: {
735
+ url: `${baseUrl}/products/${productId}/audios`,
736
+ method: 'GET',
737
+ statusCode: response.status
738
+ }
739
+ };
740
+ } catch (error) {
741
+ throw new Error(`Failed to get product audios: ${error.response?.data?.message || error.message}`);
742
+ }
743
+ }
744
+
745
+ /**
746
+ * Get audio information
747
+ */
748
+ export async function getAudio({
749
+ productId,
750
+ audioId,
751
+ partnerType,
752
+ useSandbox = false,
753
+ ...authParams
754
+ }) {
755
+ if (!productId) {
756
+ throw new Error('productId is required');
757
+ }
758
+ if (!audioId) {
759
+ throw new Error('audioId is required');
760
+ }
761
+
762
+ const headers = await createAuthHeaders(partnerType, authParams);
763
+ const baseUrl = useSandbox ? getSandboxUrl() : getProductionUrl();
764
+
765
+ try {
766
+ const response = await axios.get(
767
+ `${baseUrl}/products/${productId}/audios/${audioId}`,
768
+ { headers }
769
+ );
770
+
771
+ return {
772
+ success: true,
773
+ data: response.data,
774
+ requestInfo: {
775
+ url: `${baseUrl}/products/${productId}/audios/${audioId}`,
776
+ method: 'GET',
777
+ statusCode: response.status
778
+ }
779
+ };
780
+ } catch (error) {
781
+ throw new Error(`Failed to get audio: ${error.response?.data?.message || error.message}`);
782
+ }
783
+ }
784
+
785
+ /**
786
+ * Update audio information
787
+ */
788
+ export async function updateAudio({
789
+ productId,
790
+ audioId,
791
+ title,
792
+ newProductId,
793
+ partnerType,
794
+ useSandbox = false,
795
+ ...authParams
796
+ }) {
797
+ if (!productId) {
798
+ throw new Error('productId is required');
799
+ }
800
+ if (!audioId) {
801
+ throw new Error('audioId is required');
802
+ }
803
+
804
+ const requestBody = {};
805
+
806
+ if (title !== undefined) requestBody.title = title;
807
+ if (newProductId !== undefined) requestBody.productId = newProductId;
808
+
809
+ const minimizedBody = createMinimizedJSON(requestBody);
810
+ const headers = await createAuthHeaders(partnerType, { ...authParams, requestBody: minimizedBody });
811
+ const baseUrl = useSandbox ? getSandboxUrl() : getProductionUrl();
812
+
813
+ try {
814
+ const response = await axios.patch(
815
+ `${baseUrl}/products/${productId}/audios/${audioId}`,
816
+ minimizedBody,
817
+ { headers }
818
+ );
819
+
820
+ return {
821
+ success: true,
822
+ data: response.data,
823
+ requestInfo: {
824
+ url: `${baseUrl}/products/${productId}/audios/${audioId}`,
825
+ method: 'PATCH',
826
+ requestBody: minimizedBody,
827
+ statusCode: response.status
828
+ }
829
+ };
830
+ } catch (error) {
831
+ throw new Error(`Failed to update audio: ${error.response?.data?.message || error.message}`);
832
+ }
833
+ }
834
+
835
+ /**
836
+ * Delete audio
837
+ */
838
+ export async function deleteAudio({
839
+ productId,
840
+ audioId,
841
+ partnerType,
842
+ useSandbox = false,
843
+ ...authParams
844
+ }) {
845
+ if (!productId) {
846
+ throw new Error('productId is required');
847
+ }
848
+ if (!audioId) {
849
+ throw new Error('audioId is required');
850
+ }
851
+
852
+ const headers = await createAuthHeaders(partnerType, authParams);
853
+ const baseUrl = useSandbox ? getSandboxUrl() : getProductionUrl();
854
+
855
+ try {
856
+ const response = await axios.delete(
857
+ `${baseUrl}/products/${productId}/audios/${audioId}`,
858
+ { headers }
859
+ );
860
+
861
+ return {
862
+ success: true,
863
+ requestInfo: {
864
+ url: `${baseUrl}/products/${productId}/audios/${audioId}`,
865
+ method: 'DELETE',
866
+ statusCode: response.status
867
+ }
868
+ };
869
+ } catch (error) {
870
+ throw new Error(`Failed to delete audio: ${error.response?.data?.message || error.message}`);
871
+ }
872
+ }