ebay-mcp-remote-edition 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 (129) hide show
  1. package/LICENSE +21 -0
  2. package/README.md +755 -0
  3. package/build/api/account-management/account.js +301 -0
  4. package/build/api/analytics-and-report/analytics.js +102 -0
  5. package/build/api/client-trading.js +96 -0
  6. package/build/api/client.js +173 -0
  7. package/build/api/communication/feedback.js +119 -0
  8. package/build/api/communication/message.js +131 -0
  9. package/build/api/communication/negotiation.js +97 -0
  10. package/build/api/communication/notification.js +373 -0
  11. package/build/api/developer/developer.js +81 -0
  12. package/build/api/index.js +109 -0
  13. package/build/api/listing-management/inventory.js +640 -0
  14. package/build/api/listing-metadata/metadata.js +485 -0
  15. package/build/api/listing-metadata/taxonomy.js +58 -0
  16. package/build/api/marketing-and-promotions/marketing.js +768 -0
  17. package/build/api/marketing-and-promotions/recommendation.js +32 -0
  18. package/build/api/order-management/dispute.js +69 -0
  19. package/build/api/order-management/fulfillment.js +89 -0
  20. package/build/api/other/compliance.js +47 -0
  21. package/build/api/other/edelivery.js +219 -0
  22. package/build/api/other/identity.js +24 -0
  23. package/build/api/other/translation.js +22 -0
  24. package/build/api/other/vero.js +48 -0
  25. package/build/api/trading/trading.js +78 -0
  26. package/build/auth/kv-store.js +40 -0
  27. package/build/auth/multi-user-store.js +120 -0
  28. package/build/auth/oauth-metadata.js +59 -0
  29. package/build/auth/oauth-middleware.js +99 -0
  30. package/build/auth/oauth-types.js +4 -0
  31. package/build/auth/oauth.js +235 -0
  32. package/build/auth/scope-utils.js +304 -0
  33. package/build/auth/token-store.js +46 -0
  34. package/build/auth/token-verifier.js +172 -0
  35. package/build/config/environment.js +297 -0
  36. package/build/index.d.ts +1 -0
  37. package/build/index.js +129 -0
  38. package/build/schemas/account-management/account.js +375 -0
  39. package/build/schemas/analytics/analytics.js +191 -0
  40. package/build/schemas/communication/messages.js +345 -0
  41. package/build/schemas/fulfillment/orders.js +338 -0
  42. package/build/schemas/index.js +68 -0
  43. package/build/schemas/inventory-management/inventory.js +471 -0
  44. package/build/schemas/marketing/marketing.js +1103 -0
  45. package/build/schemas/metadata/metadata.js +618 -0
  46. package/build/schemas/other/other-apis.js +390 -0
  47. package/build/schemas/taxonomy/taxonomy.js +575 -0
  48. package/build/scripts/auto-setup.js +364 -0
  49. package/build/scripts/dev-sync.js +512 -0
  50. package/build/scripts/diagnostics.js +301 -0
  51. package/build/scripts/download-specs.js +116 -0
  52. package/build/scripts/interactive-setup.js +757 -0
  53. package/build/scripts/setup.js +1515 -0
  54. package/build/scripts/update-api-status-doc.js +44 -0
  55. package/build/server-http.d.ts +1 -0
  56. package/build/server-http.js +581 -0
  57. package/build/tools/definitions/account-with-schemas.js +170 -0
  58. package/build/tools/definitions/account.js +428 -0
  59. package/build/tools/definitions/analytics.js +66 -0
  60. package/build/tools/definitions/communication.js +394 -0
  61. package/build/tools/definitions/developer.js +195 -0
  62. package/build/tools/definitions/fulfillment.js +326 -0
  63. package/build/tools/definitions/index.js +41 -0
  64. package/build/tools/definitions/inventory.js +464 -0
  65. package/build/tools/definitions/marketing.js +1486 -0
  66. package/build/tools/definitions/metadata.js +188 -0
  67. package/build/tools/definitions/other.js +309 -0
  68. package/build/tools/definitions/taxonomy.js +64 -0
  69. package/build/tools/definitions/token-management.js +148 -0
  70. package/build/tools/definitions/trading.js +71 -0
  71. package/build/tools/index.js +1200 -0
  72. package/build/tools/schemas.js +667 -0
  73. package/build/tools/tool-definitions.js +3534 -0
  74. package/build/types/application-settings/developerAnalyticsV1BetaOas3.js +5 -0
  75. package/build/types/application-settings/developerClientRegistrationV1Oas3.js +5 -0
  76. package/build/types/application-settings/developerKeyManagementV1Oas3.js +5 -0
  77. package/build/types/ebay-enums.js +1330 -0
  78. package/build/types/ebay.js +123 -0
  79. package/build/types/index.js +10 -0
  80. package/build/types/sell-apps/account-management/sellAccountV1Oas3.js +5 -0
  81. package/build/types/sell-apps/analytics-and-report/sellAnalyticsV1Oas3.js +5 -0
  82. package/build/types/sell-apps/communication/commerceFeedbackV1BetaOas3.js +5 -0
  83. package/build/types/sell-apps/communication/commerceMessageV1Oas3.js +5 -0
  84. package/build/types/sell-apps/communication/commerceNotificationV1Oas3.js +5 -0
  85. package/build/types/sell-apps/communication/sellNegotiationV1Oas3.js +5 -0
  86. package/build/types/sell-apps/listing-management/sellInventoryV1Oas3.js +5 -0
  87. package/build/types/sell-apps/listing-metadata/sellMetadataV1Oas3.js +5 -0
  88. package/build/types/sell-apps/markeitng-and-promotions/sellMarketingV1Oas3.js +5 -0
  89. package/build/types/sell-apps/markeitng-and-promotions/sellRecommendationV1Oas3.js +5 -0
  90. package/build/types/sell-apps/order-management/sellFulfillmentV1Oas3.js +5 -0
  91. package/build/types/sell-apps/other-apis/commerceIdentityV1Oas3.js +5 -0
  92. package/build/types/sell-apps/other-apis/commerceTranslationV1BetaOas3.js +5 -0
  93. package/build/types/sell-apps/other-apis/commerceVeroV1Oas3.js +5 -0
  94. package/build/types/sell-apps/other-apis/sellComplianceV1Oas3.js +5 -0
  95. package/build/types/sell-apps/other-apis/sellEdeliveryInternationalShippingOas3.js +5 -0
  96. package/build/types/sell-apps/other-apis/sellMarketingV1Oas3.js +5 -0
  97. package/build/types/sell-apps/other-apis/sellRecommendationV1Oas3.js +5 -0
  98. package/build/utils/account-management/account.js +831 -0
  99. package/build/utils/api-status-feed.js +83 -0
  100. package/build/utils/communication/feedback.js +216 -0
  101. package/build/utils/communication/message.js +242 -0
  102. package/build/utils/communication/negotiation.js +150 -0
  103. package/build/utils/communication/notification.js +369 -0
  104. package/build/utils/date-converter.js +160 -0
  105. package/build/utils/llm-client-detector.js +758 -0
  106. package/build/utils/logger.js +198 -0
  107. package/build/utils/oauth-helper.js +315 -0
  108. package/build/utils/order-management/dispute.js +369 -0
  109. package/build/utils/order-management/fulfillment.js +205 -0
  110. package/build/utils/other/compliance.js +76 -0
  111. package/build/utils/other/edelivery.js +241 -0
  112. package/build/utils/other/identity.js +13 -0
  113. package/build/utils/other/translation.js +41 -0
  114. package/build/utils/other/vero.js +90 -0
  115. package/build/utils/scope-helper.js +207 -0
  116. package/build/utils/security-checker.js +248 -0
  117. package/build/utils/setup-validator.js +305 -0
  118. package/build/utils/token-utils.js +40 -0
  119. package/build/utils/version.js +56 -0
  120. package/docs/auth/production_scopes.json +111 -0
  121. package/docs/auth/sandbox_scopes.json +142 -0
  122. package/package.json +122 -0
  123. package/public/icons/1024x1024.png +0 -0
  124. package/public/icons/128x128.png +0 -0
  125. package/public/icons/16x16.png +0 -0
  126. package/public/icons/256x256.png +0 -0
  127. package/public/icons/32x32.png +0 -0
  128. package/public/icons/48x48.png +0 -0
  129. package/public/icons/512x512.png +0 -0
@@ -0,0 +1,301 @@
1
+ /**
2
+ * Account API - Seller account configuration, policies, programs
3
+ * Based on: docs/sell-apps/account-management/sell_account_v1_oas3.json
4
+ */
5
+ export class AccountApi {
6
+ client;
7
+ basePath = '/sell/account/v1';
8
+ constructor(client) {
9
+ this.client = client;
10
+ }
11
+ /**
12
+ * Get custom policies for the seller
13
+ */
14
+ async getCustomPolicies(policyTypes) {
15
+ const params = policyTypes ? { policy_types: policyTypes } : undefined;
16
+ return await this.client.get(`${this.basePath}/custom_policy`, params);
17
+ }
18
+ /**
19
+ * Get a specific custom policy
20
+ */
21
+ async getCustomPolicy(customPolicyId) {
22
+ return await this.client.get(`${this.basePath}/custom_policy/${customPolicyId}`);
23
+ }
24
+ /**
25
+ * Get fulfillment policies
26
+ * @param marketplaceId - Required: The eBay marketplace ID
27
+ */
28
+ async getFulfillmentPolicies(marketplaceId) {
29
+ return await this.client.get(`${this.basePath}/fulfillment_policy`, {
30
+ marketplace_id: marketplaceId,
31
+ });
32
+ }
33
+ /**
34
+ * Get payment policies
35
+ * @param marketplaceId - Required: The eBay marketplace ID
36
+ */
37
+ async getPaymentPolicies(marketplaceId) {
38
+ return await this.client.get(`${this.basePath}/payment_policy`, {
39
+ marketplace_id: marketplaceId,
40
+ });
41
+ }
42
+ /**
43
+ * Get return policies
44
+ * @param marketplaceId - Required: The eBay marketplace ID
45
+ */
46
+ async getReturnPolicies(marketplaceId) {
47
+ return await this.client.get(`${this.basePath}/return_policy`, {
48
+ marketplace_id: marketplaceId,
49
+ });
50
+ }
51
+ /**
52
+ * Get seller account privileges
53
+ */
54
+ async getPrivileges() {
55
+ return await this.client.get(`${this.basePath}/privilege`);
56
+ }
57
+ // ============================================================
58
+ // Fulfillment Policy Methods
59
+ // ============================================================
60
+ /**
61
+ * Create a new fulfillment policy
62
+ */
63
+ async createFulfillmentPolicy(policy) {
64
+ return await this.client.post(`${this.basePath}/fulfillment_policy`, policy);
65
+ }
66
+ /**
67
+ * Get a specific fulfillment policy by ID
68
+ */
69
+ async getFulfillmentPolicy(fulfillmentPolicyId) {
70
+ return await this.client.get(`${this.basePath}/fulfillment_policy/${fulfillmentPolicyId}`);
71
+ }
72
+ /**
73
+ * Get a fulfillment policy by name
74
+ */
75
+ async getFulfillmentPolicyByName(marketplaceId, name) {
76
+ return await this.client.get(`${this.basePath}/fulfillment_policy_by_name`, {
77
+ marketplace_id: marketplaceId,
78
+ name,
79
+ });
80
+ }
81
+ /**
82
+ * Update a fulfillment policy
83
+ */
84
+ async updateFulfillmentPolicy(fulfillmentPolicyId, policy) {
85
+ return await this.client.put(`${this.basePath}/fulfillment_policy/${fulfillmentPolicyId}`, policy);
86
+ }
87
+ /**
88
+ * Delete a fulfillment policy
89
+ */
90
+ async deleteFulfillmentPolicy(fulfillmentPolicyId) {
91
+ return await this.client.delete(`${this.basePath}/fulfillment_policy/${fulfillmentPolicyId}`);
92
+ }
93
+ // ============================================================
94
+ // Payment Policy Methods
95
+ // ============================================================
96
+ /**
97
+ * Create a new payment policy
98
+ */
99
+ async createPaymentPolicy(policy) {
100
+ return await this.client.post(`${this.basePath}/payment_policy`, policy);
101
+ }
102
+ /**
103
+ * Get a specific payment policy by ID
104
+ */
105
+ async getPaymentPolicy(paymentPolicyId) {
106
+ return await this.client.get(`${this.basePath}/payment_policy/${paymentPolicyId}`);
107
+ }
108
+ /**
109
+ * Get a payment policy by name
110
+ */
111
+ async getPaymentPolicyByName(marketplaceId, name) {
112
+ return await this.client.get(`${this.basePath}/payment_policy_by_name`, {
113
+ marketplace_id: marketplaceId,
114
+ name,
115
+ });
116
+ }
117
+ /**
118
+ * Update a payment policy
119
+ */
120
+ async updatePaymentPolicy(paymentPolicyId, policy) {
121
+ return await this.client.put(`${this.basePath}/payment_policy/${paymentPolicyId}`, policy);
122
+ }
123
+ /**
124
+ * Delete a payment policy
125
+ */
126
+ async deletePaymentPolicy(paymentPolicyId) {
127
+ return await this.client.delete(`${this.basePath}/payment_policy/${paymentPolicyId}`);
128
+ }
129
+ // ============================================================
130
+ // Return Policy Methods
131
+ // ============================================================
132
+ /**
133
+ * Create a new return policy
134
+ */
135
+ async createReturnPolicy(policy) {
136
+ return await this.client.post(`${this.basePath}/return_policy`, policy);
137
+ }
138
+ /**
139
+ * Get a specific return policy by ID
140
+ */
141
+ async getReturnPolicy(returnPolicyId) {
142
+ return await this.client.get(`${this.basePath}/return_policy/${returnPolicyId}`);
143
+ }
144
+ /**
145
+ * Get a return policy by name
146
+ */
147
+ async getReturnPolicyByName(marketplaceId, name) {
148
+ return await this.client.get(`${this.basePath}/return_policy_by_name`, {
149
+ marketplace_id: marketplaceId,
150
+ name,
151
+ });
152
+ }
153
+ /**
154
+ * Update a return policy
155
+ */
156
+ async updateReturnPolicy(returnPolicyId, policy) {
157
+ return await this.client.put(`${this.basePath}/return_policy/${returnPolicyId}`, policy);
158
+ }
159
+ /**
160
+ * Delete a return policy
161
+ */
162
+ async deleteReturnPolicy(returnPolicyId) {
163
+ return await this.client.delete(`${this.basePath}/return_policy/${returnPolicyId}`);
164
+ }
165
+ // ============================================================
166
+ // Custom Policy Methods
167
+ // ============================================================
168
+ /**
169
+ * Create a new custom policy
170
+ */
171
+ async createCustomPolicy(policy) {
172
+ return await this.client.post(`${this.basePath}/custom_policy`, policy);
173
+ }
174
+ /**
175
+ * Update a custom policy
176
+ */
177
+ async updateCustomPolicy(customPolicyId, policy) {
178
+ return await this.client.put(`${this.basePath}/custom_policy/${customPolicyId}`, policy);
179
+ }
180
+ /**
181
+ * Delete a custom policy
182
+ */
183
+ async deleteCustomPolicy(customPolicyId) {
184
+ return await this.client.delete(`${this.basePath}/custom_policy/${customPolicyId}`);
185
+ }
186
+ // ============================================================
187
+ // KYC, Payments Program, Rate Tables, Sales Tax, Subscription, Programs
188
+ // ============================================================
189
+ /**
190
+ * Get KYC status
191
+ */
192
+ async getKyc() {
193
+ return await this.client.get(`${this.basePath}/kyc`);
194
+ }
195
+ /**
196
+ * Opt-in to a payments program
197
+ */
198
+ async optInToPaymentsProgram(marketplaceId, paymentsProgramType) {
199
+ return await this.client.post(`${this.basePath}/payments_program/${marketplaceId}/${paymentsProgramType}`, {});
200
+ }
201
+ /**
202
+ * Get payments program status
203
+ */
204
+ async getPaymentsProgramStatus(marketplaceId, paymentsProgramType) {
205
+ return await this.client.get(`${this.basePath}/payments_program/${marketplaceId}/${paymentsProgramType}`);
206
+ }
207
+ /**
208
+ * Get rate tables
209
+ */
210
+ async getRateTables() {
211
+ return await this.client.get(`${this.basePath}/rate_table`);
212
+ }
213
+ /**
214
+ * Create or replace sales tax table
215
+ */
216
+ async createOrReplaceSalesTax(countryCode, jurisdictionId, salesTaxBase) {
217
+ return await this.client.put(`${this.basePath}/sales_tax/${countryCode}/${jurisdictionId}`, salesTaxBase);
218
+ }
219
+ /**
220
+ * Bulk create or replace sales tax tables
221
+ */
222
+ async bulkCreateOrReplaceSalesTax(requests) {
223
+ return await this.client.post(`${this.basePath}/sales_tax/bulk_create_or_replace`, {
224
+ requests,
225
+ });
226
+ }
227
+ /**
228
+ * Delete sales tax table
229
+ */
230
+ async deleteSalesTax(countryCode, jurisdictionId) {
231
+ return await this.client.delete(`${this.basePath}/sales_tax/${countryCode}/${jurisdictionId}`);
232
+ }
233
+ /**
234
+ * Get sales tax table
235
+ */
236
+ async getSalesTax(countryCode, jurisdictionId) {
237
+ return await this.client.get(`${this.basePath}/sales_tax/${countryCode}/${jurisdictionId}`);
238
+ }
239
+ /**
240
+ * Get all sales tax tables
241
+ * @param countryCode - Required: Two-letter ISO 3166-1 country code
242
+ */
243
+ async getSalesTaxes(countryCode) {
244
+ return await this.client.get(`${this.basePath}/sales_tax`, {
245
+ country_code: countryCode,
246
+ });
247
+ }
248
+ /**
249
+ * Get subscription information
250
+ */
251
+ async getSubscription(limitType) {
252
+ const params = limitType ? { limit: limitType } : undefined;
253
+ return await this.client.get(`${this.basePath}/subscription`, params);
254
+ }
255
+ /**
256
+ * Opt-in to a program
257
+ */
258
+ async optInToProgram(request) {
259
+ return await this.client.post(`${this.basePath}/program/opt_in`, request);
260
+ }
261
+ /**
262
+ * Opt-out of a program
263
+ */
264
+ async optOutOfProgram(request) {
265
+ return await this.client.post(`${this.basePath}/program/opt_out`, request);
266
+ }
267
+ /**
268
+ * Get opted-in programs
269
+ */
270
+ async getOptedInPrograms() {
271
+ return await this.client.get(`${this.basePath}/program`);
272
+ }
273
+ /**
274
+ * Get seller eligibility for advertising programs
275
+ * This method allows developers to check the seller eligibility status for eBay advertising programs.
276
+ * @param programTypes - Optional comma-separated list of program types to check
277
+ * @param marketplaceId - Required eBay marketplace ID (passed in X-EBAY-C-MARKETPLACE-ID header)
278
+ */
279
+ async getAdvertisingEligibility(marketplaceId, programTypes) {
280
+ const params = programTypes ? { program_types: programTypes } : undefined;
281
+ return await this.client.get(`${this.basePath}/advertising_eligibility`, params);
282
+ }
283
+ /**
284
+ * Get payments program status for a marketplace
285
+ * Note: This method is deprecated as all seller accounts globally have been enabled for the new eBay payment and checkout flow.
286
+ * @param marketplaceId - The eBay marketplace ID
287
+ * @param paymentsProgramType - The type of payments program
288
+ */
289
+ async getPaymentsProgram(marketplaceId, paymentsProgramType) {
290
+ return await this.client.get(`${this.basePath}/payments_program/${marketplaceId}/${paymentsProgramType}`);
291
+ }
292
+ /**
293
+ * Get payments program onboarding information
294
+ * Note: This method is deprecated as all seller accounts globally have been enabled for the new eBay payment and checkout flow.
295
+ * @param marketplaceId - The eBay marketplace ID
296
+ * @param paymentsProgramType - The type of payments program
297
+ */
298
+ async getPaymentsProgramOnboarding(marketplaceId, paymentsProgramType) {
299
+ return await this.client.get(`${this.basePath}/payments_program/${marketplaceId}/${paymentsProgramType}/onboarding`);
300
+ }
301
+ }
@@ -0,0 +1,102 @@
1
+ /**
2
+ * Analytics API - Sales and traffic analytics
3
+ * Based on: docs/sell-apps/analytics-and-report/sell_analytics_v1_oas3.json
4
+ */
5
+ export class AnalyticsApi {
6
+ client;
7
+ basePath = '/sell/analytics/v1';
8
+ constructor(client) {
9
+ this.client = client;
10
+ }
11
+ /**
12
+ * Get traffic report for listings
13
+ * @throws Error if required parameters are missing or invalid
14
+ */
15
+ async getTrafficReport(dimension, filter, metric, sort) {
16
+ // Input validation
17
+ if (!dimension || typeof dimension !== 'string') {
18
+ throw new Error('dimension is required and must be a string');
19
+ }
20
+ if (!filter || typeof filter !== 'string') {
21
+ throw new Error('filter is required and must be a string');
22
+ }
23
+ if (!metric || typeof metric !== 'string') {
24
+ throw new Error('metric is required and must be a string');
25
+ }
26
+ if (sort !== undefined && typeof sort !== 'string') {
27
+ throw new Error('sort must be a string when provided');
28
+ }
29
+ const params = {
30
+ dimension,
31
+ filter,
32
+ metric,
33
+ };
34
+ if (sort)
35
+ params.sort = sort;
36
+ try {
37
+ return await this.client.get(`${this.basePath}/traffic_report`, params);
38
+ }
39
+ catch (error) {
40
+ throw new Error(`Failed to get traffic report: ${error instanceof Error ? error.message : 'Unknown error'}`);
41
+ }
42
+ }
43
+ /**
44
+ * Find all seller standards profiles
45
+ * Endpoint: GET /seller_standards_profile
46
+ * @throws Error if the request fails
47
+ */
48
+ async findSellerStandardsProfiles() {
49
+ try {
50
+ return await this.client.get(`${this.basePath}/seller_standards_profile`);
51
+ }
52
+ catch (error) {
53
+ throw new Error(`Failed to find seller standards profiles: ${error instanceof Error ? error.message : 'Unknown error'}`);
54
+ }
55
+ }
56
+ /**
57
+ * Get a specific seller standards profile
58
+ * Endpoint: GET /seller_standards_profile/{program}/{cycle}
59
+ * @throws Error if required parameters are missing or invalid
60
+ */
61
+ async getSellerStandardsProfile(program, cycle) {
62
+ // Input validation
63
+ if (!program || typeof program !== 'string') {
64
+ throw new Error('program is required and must be a string');
65
+ }
66
+ if (!cycle || typeof cycle !== 'string') {
67
+ throw new Error('cycle is required and must be a string');
68
+ }
69
+ try {
70
+ return await this.client.get(`${this.basePath}/seller_standards_profile/${program}/${cycle}`);
71
+ }
72
+ catch (error) {
73
+ throw new Error(`Failed to get seller standards profile: ${error instanceof Error ? error.message : 'Unknown error'}`);
74
+ }
75
+ }
76
+ /**
77
+ * Get customer service metrics
78
+ * Endpoint: GET /customer_service_metric/{customer_service_metric_type}/{evaluation_type}
79
+ * @throws Error if required parameters are missing or invalid
80
+ */
81
+ async getCustomerServiceMetric(customerServiceMetricType, evaluationType, evaluationMarketplaceId) {
82
+ // Input validation
83
+ if (!customerServiceMetricType || typeof customerServiceMetricType !== 'string') {
84
+ throw new Error('customerServiceMetricType is required and must be a string');
85
+ }
86
+ if (!evaluationType || typeof evaluationType !== 'string') {
87
+ throw new Error('evaluationType is required and must be a string');
88
+ }
89
+ if (!evaluationMarketplaceId || typeof evaluationMarketplaceId !== 'string') {
90
+ throw new Error('evaluationMarketplaceId is required and must be a string');
91
+ }
92
+ const params = {
93
+ evaluation_marketplace_id: evaluationMarketplaceId,
94
+ };
95
+ try {
96
+ return await this.client.get(`${this.basePath}/customer_service_metric/${customerServiceMetricType}/${evaluationType}`, params);
97
+ }
98
+ catch (error) {
99
+ throw new Error(`Failed to get customer service metric: ${error instanceof Error ? error.message : 'Unknown error'}`);
100
+ }
101
+ }
102
+ }
@@ -0,0 +1,96 @@
1
+ import axios from 'axios';
2
+ import { XMLBuilder, XMLParser } from 'fast-xml-parser';
3
+ import { apiLogger } from '../utils/logger.js';
4
+ const COMPAT_LEVEL = '1451';
5
+ const SITE_ID = '0';
6
+ export class TradingApiClient {
7
+ restClient;
8
+ baseUrl;
9
+ parser;
10
+ builder;
11
+ constructor(restClient) {
12
+ this.restClient = restClient;
13
+ const env = restClient.getConfig().environment;
14
+ this.baseUrl = env === 'sandbox' ? 'https://api.sandbox.ebay.com' : 'https://api.ebay.com';
15
+ this.parser = new XMLParser({
16
+ ignoreAttributes: false,
17
+ removeNSPrefix: true,
18
+ parseTagValue: true,
19
+ isArray: (_name) => {
20
+ const arrayTags = [
21
+ 'Item',
22
+ 'Errors',
23
+ 'Error',
24
+ 'NameValueList',
25
+ 'Value',
26
+ 'ShippingServiceOptions',
27
+ 'InternationalShippingServiceOption',
28
+ 'PaymentMethods',
29
+ 'PictureURL',
30
+ 'CompatibilityList',
31
+ 'Variation',
32
+ ];
33
+ return arrayTags.includes(_name);
34
+ },
35
+ });
36
+ this.builder = new XMLBuilder({
37
+ ignoreAttributes: false,
38
+ format: true,
39
+ suppressEmptyNode: true,
40
+ });
41
+ }
42
+ getBaseUrl() {
43
+ return this.baseUrl;
44
+ }
45
+ async execute(callName, params) {
46
+ const token = await this.restClient.getOAuthClient().getAccessToken();
47
+ const requestTag = `${callName}Request`;
48
+ const responseTag = `${callName}Response`;
49
+ const xmlObj = {};
50
+ xmlObj[requestTag] = {
51
+ '@_xmlns': 'urn:ebay:apis:eBLBaseComponents',
52
+ ...params,
53
+ };
54
+ const xmlBody = `<?xml version="1.0" encoding="utf-8"?>\n${this.builder.build(xmlObj)}`;
55
+ apiLogger.debug(`Trading API ${callName}`, { xmlBody });
56
+ let response;
57
+ try {
58
+ response = await axios.post(`${this.baseUrl}/ws/api.dll`, xmlBody, {
59
+ headers: {
60
+ 'X-EBAY-API-SITEID': SITE_ID,
61
+ 'X-EBAY-API-COMPATIBILITY-LEVEL': COMPAT_LEVEL,
62
+ 'X-EBAY-API-CALL-NAME': callName,
63
+ 'X-EBAY-API-IAF-TOKEN': token,
64
+ 'Content-Type': 'text/xml',
65
+ },
66
+ timeout: 30000,
67
+ });
68
+ }
69
+ catch (error) {
70
+ const message = error instanceof Error ? error.message : 'Unknown HTTP error';
71
+ throw new Error(`Trading API ${callName} request failed: ${message}`);
72
+ }
73
+ let parsed;
74
+ try {
75
+ parsed = this.parser.parse(response.data);
76
+ }
77
+ catch (e) {
78
+ throw new Error(`Failed to parse Trading API ${callName} response: ${e instanceof Error ? e.message : String(e)}`);
79
+ }
80
+ const result = (parsed[responseTag] || parsed);
81
+ // Log warnings without failing
82
+ if (result.Ack === 'Warning') {
83
+ apiLogger.warn(`Trading API ${callName} returned warnings`, {
84
+ errors: result.Errors,
85
+ });
86
+ }
87
+ // Check for eBay errors
88
+ if (result.Ack === 'Failure' || result.Ack === 'PartialFailure') {
89
+ const errors = result.Errors;
90
+ const firstError = Array.isArray(errors) ? errors[0] : errors;
91
+ const message = firstError?.ShortMessage || firstError?.LongMessage || 'Unknown Trading API error';
92
+ throw new Error(message);
93
+ }
94
+ return result;
95
+ }
96
+ }
@@ -0,0 +1,173 @@
1
+ import { EbayOAuthClient } from '../auth/oauth.js';
2
+ import { getBaseUrl } from '../config/environment.js';
3
+ import axios from 'axios';
4
+ import { logRequest, logResponse, logErrorResponse } from '../utils/logger.js';
5
+ class RateLimitTracker {
6
+ requestTimestamps = [];
7
+ windowMs = 60000;
8
+ maxRequests = 5000;
9
+ canMakeRequest() {
10
+ const now = Date.now();
11
+ this.requestTimestamps = this.requestTimestamps.filter((timestamp) => now - timestamp < this.windowMs);
12
+ return this.requestTimestamps.length < this.maxRequests;
13
+ }
14
+ recordRequest() {
15
+ this.requestTimestamps.push(Date.now());
16
+ }
17
+ getStats() {
18
+ const now = Date.now();
19
+ this.requestTimestamps = this.requestTimestamps.filter((timestamp) => now - timestamp < this.windowMs);
20
+ return {
21
+ current: this.requestTimestamps.length,
22
+ max: this.maxRequests,
23
+ windowMs: this.windowMs,
24
+ };
25
+ }
26
+ }
27
+ export class EbayApiClient {
28
+ httpClient;
29
+ authClient;
30
+ baseUrl;
31
+ rateLimitTracker;
32
+ config;
33
+ getDefaultHeaders() {
34
+ const headers = {
35
+ 'Content-Type': 'application/json',
36
+ Accept: 'application/json',
37
+ };
38
+ if (this.config.contentLanguage) {
39
+ headers['Content-Language'] = this.config.contentLanguage;
40
+ }
41
+ if (this.config.marketplaceId) {
42
+ headers['X-EBAY-C-MARKETPLACE-ID'] = this.config.marketplaceId;
43
+ }
44
+ return headers;
45
+ }
46
+ constructor(config, context) {
47
+ this.config = config;
48
+ this.authClient = new EbayOAuthClient(config, context);
49
+ this.baseUrl = getBaseUrl(config.environment);
50
+ this.rateLimitTracker = new RateLimitTracker();
51
+ this.httpClient = axios.create({
52
+ baseURL: this.baseUrl,
53
+ timeout: 30000,
54
+ headers: this.getDefaultHeaders(),
55
+ });
56
+ this.httpClient.interceptors.request.use(async (config) => {
57
+ if (!this.rateLimitTracker.canMakeRequest()) {
58
+ const stats = this.rateLimitTracker.getStats();
59
+ throw new Error(`Rate limit exceeded: ${stats.current}/${stats.max} requests in ${stats.windowMs}ms window.`);
60
+ }
61
+ const token = await this.authClient.getAccessToken();
62
+ config.headers.Authorization = `Bearer ${token}`;
63
+ this.rateLimitTracker.recordRequest();
64
+ logRequest(config.method || 'GET', `${config.baseURL}${config.url}`, config.params, config.data);
65
+ return config;
66
+ });
67
+ this.httpClient.interceptors.response.use((response) => {
68
+ const remaining = response.headers['x-ebay-c-ratelimit-remaining'];
69
+ const limit = response.headers['x-ebay-c-ratelimit-limit'];
70
+ logResponse(response.status, response.statusText, response.data, remaining, limit);
71
+ return response;
72
+ }, async (error) => {
73
+ const config = error.config;
74
+ if (error.response) {
75
+ logErrorResponse(error.response.status, error.response.statusText, `${config?.baseURL}${config?.url}`, error.response.data);
76
+ }
77
+ if (error.response?.status === 401 && config) {
78
+ const retryCount = config.__authRetryCount || 0;
79
+ if (retryCount === 0) {
80
+ config.__authRetryCount = 1;
81
+ await this.authClient.refreshUserToken();
82
+ const newToken = await this.authClient.getAccessToken();
83
+ if (config.headers) {
84
+ config.headers.Authorization = `Bearer ${newToken}`;
85
+ }
86
+ return await this.httpClient.request(config);
87
+ }
88
+ const ebayError = error.response?.data;
89
+ const errorMessage = ebayError.errors?.[0]?.longMessage ||
90
+ ebayError.errors?.[0]?.message ||
91
+ 'Invalid access token';
92
+ throw new Error(`${errorMessage}. Automatic token refresh failed.`);
93
+ }
94
+ if (error.response?.status === 429) {
95
+ const retryAfter = error.response.headers['retry-after'];
96
+ const waitTime = retryAfter ? parseInt(retryAfter) * 1000 : 60000;
97
+ throw new Error(`eBay API rate limit exceeded. Retry after ${waitTime / 1000} seconds.`);
98
+ }
99
+ if (error.response?.status && error.response.status >= 500 && config) {
100
+ const retryCount = config.__retryCount || 0;
101
+ if (retryCount < 3) {
102
+ config.__retryCount = retryCount + 1;
103
+ const delay = Math.pow(2, retryCount) * 1000;
104
+ await new Promise((resolve) => {
105
+ setTimeout(resolve, Math.min(delay, 5000));
106
+ });
107
+ return await this.httpClient.request(config);
108
+ }
109
+ }
110
+ if (axios.isAxiosError(error) && error.response?.data) {
111
+ const ebayError = error.response.data;
112
+ const errorMessage = ebayError.errors?.[0]?.longMessage || ebayError.errors?.[0]?.message || error.message;
113
+ throw new Error(`eBay API Error: ${errorMessage}`);
114
+ }
115
+ throw error;
116
+ });
117
+ }
118
+ async initialize() {
119
+ await this.authClient.initialize();
120
+ }
121
+ isAuthenticated() {
122
+ return this.authClient.isAuthenticated();
123
+ }
124
+ hasUserTokens() {
125
+ return this.authClient.hasUserTokens();
126
+ }
127
+ async setUserTokens(accessToken, refreshToken, accessTokenExpiry, refreshTokenExpiry) {
128
+ await this.authClient.setUserTokens(accessToken, refreshToken, accessTokenExpiry, refreshTokenExpiry);
129
+ }
130
+ getTokenInfo() {
131
+ return this.authClient.getTokenInfo();
132
+ }
133
+ getOAuthClient() {
134
+ return this.authClient;
135
+ }
136
+ getRateLimitStats() {
137
+ return this.rateLimitTracker.getStats();
138
+ }
139
+ getConfig() {
140
+ return this.config;
141
+ }
142
+ async refreshUserToken() {
143
+ await this.authClient.refreshUserToken();
144
+ }
145
+ async get(url, params) {
146
+ const response = await this.httpClient.get(url, { params });
147
+ return response.data;
148
+ }
149
+ async post(url, data, params) {
150
+ const response = await this.httpClient.post(url, data, { params });
151
+ return response.data;
152
+ }
153
+ async put(url, data, params) {
154
+ const response = await this.httpClient.put(url, data, { params });
155
+ return response.data;
156
+ }
157
+ async delete(url, params) {
158
+ const response = await this.httpClient.delete(url, { params });
159
+ return response.data;
160
+ }
161
+ async getWithFullUrl(fullUrl, params) {
162
+ const token = await this.authClient.getAccessToken();
163
+ const response = await axios.get(fullUrl, {
164
+ params,
165
+ headers: {
166
+ Authorization: `Bearer ${token}`,
167
+ ...this.getDefaultHeaders(),
168
+ },
169
+ timeout: 30000,
170
+ });
171
+ return response.data;
172
+ }
173
+ }