ebay-mcp 1.17.0 → 1.18.2

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 (178) hide show
  1. package/README.md +92 -53
  2. package/build/api/account-management/accountV2.js +347 -0
  3. package/build/api/account-management/finances.js +289 -0
  4. package/build/api/analytics-and-report/analytics.js +1 -1
  5. package/build/api/{client.js → client/ebayApiClient.js} +83 -36
  6. package/build/api/{clientTrading.js → client/tradingApiClient.js} +22 -22
  7. package/build/api/communication/feedback.js +21 -21
  8. package/build/api/communication/message.js +23 -23
  9. package/build/api/communication/negotiation.js +7 -7
  10. package/build/api/communication/notification.js +52 -52
  11. package/build/api/developer/developer.js +3 -3
  12. package/build/api/{index.js → ebaySellerApi.js} +28 -4
  13. package/build/api/listing-management/feed.js +91 -0
  14. package/build/api/listing-management/feedReportTasks.js +107 -0
  15. package/build/api/listing-management/feedRequest.js +91 -0
  16. package/build/api/listing-management/feedSchedules.js +95 -0
  17. package/build/api/listing-management/feedTasks.js +91 -0
  18. package/build/api/listing-management/items.js +22 -22
  19. package/build/api/listing-management/locations.js +4 -4
  20. package/build/api/listing-management/media.js +14 -14
  21. package/build/api/listing-management/mediaAttach.js +14 -14
  22. package/build/api/listing-management/mediaResources.js +22 -39
  23. package/build/api/listing-management/offerFormat.js +1 -1
  24. package/build/api/listing-management/offers.js +23 -23
  25. package/build/api/listing-management/stores.js +203 -0
  26. package/build/api/listing-metadata/charity.js +76 -0
  27. package/build/api/listing-metadata/metadata.js +31 -11
  28. package/build/api/listing-metadata/metadataShipping.js +117 -0
  29. package/build/api/listing-metadata/taxonomy.js +52 -7
  30. package/build/api/marketing-and-promotions/ads.js +34 -34
  31. package/build/api/marketing-and-promotions/campaigns.js +21 -21
  32. package/build/api/marketing-and-promotions/promotions.js +24 -24
  33. package/build/api/marketing-and-promotions/reports.js +7 -7
  34. package/build/api/marketing-and-promotions/shared.js +0 -3
  35. package/build/api/order-management/dispute.js +11 -9
  36. package/build/api/order-management/fulfillment.js +4 -4
  37. package/build/api/order-management/logistics.js +150 -0
  38. package/build/api/other/browseMappers.js +15 -13
  39. package/build/api/other/browseValidators.js +4 -4
  40. package/build/api/other/edelivery.js +19 -19
  41. package/build/api/other/finding.js +13 -13
  42. package/build/api/other/translation.js +2 -2
  43. package/build/api/other/vero.js +2 -2
  44. package/build/api/shared/download.js +79 -0
  45. package/build/api/shared/location.js +33 -0
  46. package/build/api/shared/request.js +69 -11
  47. package/build/api/trading/listingFormat.js +37 -30
  48. package/build/api/trading/trading.js +33 -33
  49. package/build/auth/credentialSession.js +5 -5
  50. package/build/auth/oauth.js +3 -3
  51. package/build/auth/oauthHelper.js +24 -24
  52. package/build/auth/oauthMetadata.js +4 -4
  53. package/build/auth/oauthMiddleware.js +16 -16
  54. package/build/auth/scopeUtils.js +24 -3
  55. package/build/auth/tokenVerifier.js +23 -23
  56. package/build/config/environment.js +10 -45
  57. package/build/config/oauthScopes.js +132 -0
  58. package/build/config/toolFamilies.js +4 -0
  59. package/build/index.js +5 -5
  60. package/build/mcp/httpTransport.js +32 -20
  61. package/build/mcp/runtime.js +12 -12
  62. package/build/mcp/toolGating.js +6 -12
  63. package/build/mcp/uiBridge.js +3 -3
  64. package/build/schemas/account-management/account.js +2 -52
  65. package/build/schemas/account-management/accountV2.js +294 -0
  66. package/build/schemas/account-management/finances.js +143 -0
  67. package/build/schemas/analytics/analytics.js +2 -48
  68. package/build/schemas/communication/messages.js +2 -46
  69. package/build/schemas/developer/developer.js +1 -27
  70. package/build/schemas/fulfillment/logistics.js +115 -0
  71. package/build/schemas/fulfillment/orders.js +2 -47
  72. package/build/schemas/inventory-management/feed.js +217 -0
  73. package/build/schemas/inventory-management/inventory.js +2 -50
  74. package/build/schemas/inventory-management/media.js +2 -2
  75. package/build/schemas/inventory-management/mediaDocuments.js +1 -1
  76. package/build/schemas/inventory-management/stores.js +42 -0
  77. package/build/schemas/marketing/ads.js +2 -2
  78. package/build/schemas/marketing/campaigns.js +2 -2
  79. package/build/schemas/marketing/common.js +2 -2
  80. package/build/schemas/marketing/marketing.js +0 -1
  81. package/build/schemas/marketing/promotions.js +2 -2
  82. package/build/schemas/marketing/reports.js +2 -2
  83. package/build/schemas/metadata/metadata.js +2 -90
  84. package/build/schemas/metadata/shipping.js +16 -0
  85. package/build/schemas/other/browse.js +2 -2
  86. package/build/schemas/other/finding.js +2 -2
  87. package/build/schemas/other/otherApis.js +2 -114
  88. package/build/schemas/taxonomy/categoryTree.js +8 -0
  89. package/build/schemas/taxonomy/charity.js +41 -0
  90. package/build/schemas/taxonomy/taxonomy.js +2 -69
  91. package/build/scripts/autoSetup.js +3 -3
  92. package/build/scripts/{buildUi.js → buildMcpApps.js} +13 -13
  93. package/build/scripts/devSync.js +34 -70
  94. package/build/scripts/diagnostics.js +15 -16
  95. package/build/scripts/interactiveSetup.js +25 -25
  96. package/build/scripts/scopeHelper.js +2 -2
  97. package/build/scripts/securityChecker.js +20 -20
  98. package/build/scripts/setup.js +76 -76
  99. package/build/scripts/setupShared.js +5 -30
  100. package/build/scripts/setupValidator.js +9 -9
  101. package/build/scripts/setupWizard.js +23 -23
  102. package/build/scripts/skills.js +14 -17
  103. package/build/scripts/specRefs.js +55 -0
  104. package/build/scripts/specSources.js +144 -0
  105. package/build/serverHttp.js +4 -7
  106. package/build/skills/content.js +13 -13
  107. package/build/skills/install.js +9 -9
  108. package/build/skills/registrySnapshot.js +7 -3
  109. package/build/skills/render.js +2 -2
  110. package/build/tools/categories/accountV2.js +106 -0
  111. package/build/tools/categories/charity.js +21 -0
  112. package/build/tools/categories/communication.js +1 -1
  113. package/build/tools/categories/connector.js +19 -16
  114. package/build/tools/categories/feed.js +183 -0
  115. package/build/tools/categories/finances.js +86 -0
  116. package/build/tools/categories/fulfillment.js +4 -4
  117. package/build/tools/categories/index.js +12 -2
  118. package/build/tools/categories/inventory.js +1 -1
  119. package/build/tools/categories/logistics.js +52 -0
  120. package/build/tools/categories/metadata.js +38 -1
  121. package/build/tools/categories/stores.js +64 -0
  122. package/build/tools/categories/taxonomy.js +18 -1
  123. package/build/tools/categories/tokenManagement.js +8 -8
  124. package/build/tools/contracts.js +2 -2
  125. package/build/tools/defineTool.js +27 -12
  126. package/build/tools/fileResult.js +30 -0
  127. package/build/tools/registry.js +2 -2
  128. package/build/tools/schemas.js +2 -2
  129. package/build/tools/ui/mapHelpers.js +12 -12
  130. package/build/tools/ui/maps.js +101 -97
  131. package/build/tools/ui/viewModels.js +2 -2
  132. package/build/utils/apiStatusFeed.js +12 -12
  133. package/build/utils/communication/feedback.js +3 -3
  134. package/build/utils/communication/message.js +3 -3
  135. package/build/utils/communication/negotiation.js +3 -3
  136. package/build/utils/communication/notification.js +3 -3
  137. package/build/utils/entryModule.js +33 -0
  138. package/build/utils/envFile.js +47 -0
  139. package/build/utils/envParser.js +5 -5
  140. package/build/utils/errors.js +4 -4
  141. package/build/utils/http.js +60 -41
  142. package/build/utils/localFeedFiles.js +61 -0
  143. package/build/utils/localMedia.js +18 -6
  144. package/build/utils/logRedaction.js +21 -0
  145. package/build/utils/logger.js +52 -33
  146. package/build/utils/other/compliance.js +3 -3
  147. package/build/utils/other/identity.js +3 -3
  148. package/build/utils/other/translation.js +3 -3
  149. package/build/utils/other/vero.js +3 -3
  150. package/build/utils/schemaHelpers.js +2 -2
  151. package/build/utils/tokenUtils.js +2 -2
  152. package/build/utils/trading/trading.js +1 -1
  153. package/build/utils/version.js +1 -1
  154. package/build/utils/zodIssues.js +14 -0
  155. package/package.json +9 -12
  156. package/README.de.md +0 -422
  157. package/README.es.md +0 -422
  158. package/README.fr.md +0 -422
  159. package/README.ja.md +0 -422
  160. package/README.ko.md +0 -422
  161. package/README.pt-BR.md +0 -422
  162. package/README.ru.md +0 -422
  163. package/README.zh-CN.md +0 -422
  164. package/build/schemas/index.js +0 -76
  165. package/build/schemas/marketing/jsonSchemas.js +0 -118
  166. package/build/scripts/downloadSpecs.js +0 -117
  167. package/build/scripts/updateApiStatusDoc.js +0 -71
  168. package/build/utils/effectSchema.js +0 -203
  169. package/build/utils/effectSchemaAdapter.js +0 -121
  170. package/build/utils/effectSchemaChainMethods.js +0 -146
  171. package/build/utils/effectSchemaRefinements.js +0 -104
  172. package/build/utils/effectSchemaStringMethods.js +0 -63
  173. package/build/utils/effectSchemaTypes.js +0 -47
  174. package/docs/auth/production_scopes.json +0 -111
  175. package/docs/auth/sandbox_scopes.json +0 -142
  176. /package/build/api/{clientRequestError.js → client/ebayClientRequestError.js} +0 -0
  177. /package/build/api/{rateLimitTracker.js → client/rateLimitTracker.js} +0 -0
  178. /package/build/api/{clientTradingError.js → client/tradingApiFailure.js} +0 -0
@@ -0,0 +1,91 @@
1
+ import { requestDownloadEffect, } from '../../api/shared/download.js';
2
+ import { locatedResourceId } from '../../api/shared/location.js';
3
+ import { buildEndpointParams, EbayApiError, EndpointInputError, } from '../../api/shared/request.js';
4
+ import { Effect } from 'effect';
5
+ /** Feed API base path on the default `api` host. */
6
+ export const FEED_BASE_PATH = '/sell/feed/v1';
7
+ /**
8
+ * Feed API path of one resource, with its ID encoded as a single path segment.
9
+ *
10
+ * @param collection - Collection path below the base path, e.g. `/task`.
11
+ * @param id - Resource ID.
12
+ * @param suffix - Optional sub-path, e.g. `/download_result_file`.
13
+ * @returns The full REST path.
14
+ * @example feedResourcePath('/task', 'TASK-1', '/upload_file')
15
+ */
16
+ export const feedResourcePath = (collection, id, suffix = '') => `${FEED_BASE_PATH}${collection}/${encodeURIComponent(id)}${suffix}`;
17
+ /**
18
+ * Builds the query of a Feed API list endpoint with eBay's wire names.
19
+ *
20
+ * @param query - Decoded list filters and pagination.
21
+ * @returns Query params, or undefined when every value is omitted.
22
+ * @example feedListParams({ feedType: 'LMS_ORDER_REPORT', limit: 10 })
23
+ */
24
+ export const feedListParams = (query) => buildEndpointParams({
25
+ feedType: { wireName: 'feed_type', value: query.feedType },
26
+ scheduleId: { wireName: 'schedule_id', value: query.scheduleId },
27
+ dateRange: { wireName: 'date_range', value: query.dateRange },
28
+ lookBackDays: { wireName: 'look_back_days', value: query.lookBackDays },
29
+ limit: { wireName: 'limit', value: query.limit },
30
+ offset: { wireName: 'offset', value: query.offset },
31
+ });
32
+ /**
33
+ * Rejects the list filter pairs eBay documents as mutually exclusive (feedType with scheduleId,
34
+ * dateRange with lookBackDays) before any request is sent.
35
+ *
36
+ * @param query - Decoded list filters and pagination.
37
+ * @returns An Effect with the same query, or an EndpointInputError naming the conflicting filter.
38
+ * @example exclusiveFeedFilters({ feedType: 'LMS_ORDER_REPORT', lookBackDays: 10 })
39
+ */
40
+ export const exclusiveFeedFilters = (query) => {
41
+ if (query.feedType !== undefined && query.scheduleId !== undefined) {
42
+ return Effect.fail(new EndpointInputError({
43
+ parameter: 'scheduleId',
44
+ message: 'Pass feedType or scheduleId, not both',
45
+ }));
46
+ }
47
+ if (query.dateRange !== undefined && query.lookBackDays !== undefined) {
48
+ return Effect.fail(new EndpointInputError({
49
+ parameter: 'lookBackDays',
50
+ message: 'Pass dateRange or lookBackDays, not both',
51
+ }));
52
+ }
53
+ return Effect.succeed(query);
54
+ };
55
+ /**
56
+ * POSTs a Feed API create request whose new resource ID arrives only in `Location`.
57
+ *
58
+ * @param client - Shared authenticated HTTP client.
59
+ * @param collection - Collection path below the base path, e.g. `/schedule`.
60
+ * @param createRequest - Generated create-request DTO.
61
+ * @param config - Optional per-request headers.
62
+ * @returns An Effect with the decoded ID and Location, or an EbayApiError.
63
+ * @example postFeedResource(client, '/schedule', { feedType: 'LMS_ORDER_REPORT', scheduleTemplateId: 'T-1' })
64
+ */
65
+ export const postFeedResource = (client, collection, createRequest, config) => {
66
+ const path = `${FEED_BASE_PATH}${collection}`;
67
+ return Effect.tryPromise({
68
+ try: () => client.postForResponse(path, createRequest, config),
69
+ catch: (cause) => new EbayApiError({ method: 'POST', path, cause }), // allow-duplicate
70
+ }).pipe(Effect.flatMap((createdResponse) => locatedResourceId(createdResponse.headers.location, path)));
71
+ };
72
+ /**
73
+ * Creates a Feed API task (HTTP 202, no body) and returns the ID from its `Location`.
74
+ *
75
+ * @param client - Shared authenticated HTTP client.
76
+ * @param collection - Task collection path, e.g. `/order_task`.
77
+ * @param taskRequest - Generated create-task DTO.
78
+ * @param headers - Optional request headers such as Accept-Language.
79
+ * @returns An Effect with the new task ID and Location, or an EbayApiError.
80
+ * @example postFeedTask(client, '/task', { feedType: 'LMS_ORDER_ACK', schemaVersion: '1235' })
81
+ */
82
+ export const postFeedTask = (client, collection, taskRequest, headers) => postFeedResource(client, collection, taskRequest, headers ? { headers } : undefined).pipe(Effect.map(({ id, location }) => ({ taskId: id, location })));
83
+ /**
84
+ * Downloads a Feed API file (input, result or latest schedule report) as raw bytes.
85
+ *
86
+ * @param client - Shared authenticated HTTP client.
87
+ * @param path - Full Feed API download path.
88
+ * @returns An Effect with the bytes, content type and file name.
89
+ * @example downloadFeedFile(client, feedResourcePath('/task', 'TASK-1', '/download_result_file'))
90
+ */
91
+ export const downloadFeedFile = (client, path) => requestDownloadEffect(client, path, { headers: { Accept: 'application/octet-stream' } });
@@ -0,0 +1,95 @@
1
+ import { decodeEndpointInputEffect, EndpointInputError, requestDeleteEffect, requestGetEffect, requestPutEffect, } from '../../api/shared/request.js';
2
+ import { createFeedScheduleInputSchema, feedScheduleIdInputSchema, feedScheduleTemplateIdInputSchema, feedTypePageInputSchema, updateFeedScheduleInputSchema, } from '../../schemas/inventory-management/feed.js';
3
+ import { Effect } from 'effect';
4
+ import { downloadFeedFile, FEED_BASE_PATH, feedListParams, feedResourcePath, postFeedResource, } from './feedRequest.js';
5
+ /**
6
+ * Creates the Feed API `schedule` resource endpoints: recurring report schedules, their
7
+ * latest result file, and the templates schedules subscribe to.
8
+ * @param client - Shared authenticated HTTP client.
9
+ * @returns Endpoint Effects composed into FeedApi.
10
+ */
11
+ export const createFeedScheduleMethods = (client) => {
12
+ /**
13
+ * Lists the seller's schedules for a feed type.
14
+ * @param input - feedType (required), limit, offset.
15
+ * @returns Generated UserScheduleCollection.
16
+ * @example feed.getSchedules({ feedType: 'LMS_ORDER_REPORT' })
17
+ * @see https://developer.ebay.com/api-docs/sell/feed/resources/schedule/methods/getSchedules
18
+ */
19
+ const getSchedules = (input) => decodeEndpointInputEffect(feedTypePageInputSchema, input).pipe(Effect.flatMap((query) => requestGetEffect(client, `${FEED_BASE_PATH}/schedule`, feedListParams(query))));
20
+ /**
21
+ * Subscribes to a schedule template; eBay answers 201 with the new ID only in Location.
22
+ * @param input - CreateUserScheduleRequest body.
23
+ * @returns The new schedule ID and Location.
24
+ * @example feed.createSchedule({ schedule: { feedType: 'LMS_ORDER_REPORT', scheduleTemplateId: 'T-1' } })
25
+ * @see https://developer.ebay.com/api-docs/sell/feed/resources/schedule/methods/createSchedule
26
+ */
27
+ const createSchedule = (input) => decodeEndpointInputEffect(createFeedScheduleInputSchema, input).pipe(Effect.flatMap(({ schedule }) => {
28
+ const createScheduleRequest = schedule;
29
+ return postFeedResource(client, '/schedule', createScheduleRequest);
30
+ }), Effect.map(({ id, location }) => ({ scheduleId: id, location })));
31
+ /**
32
+ * Retrieves one schedule's details and status.
33
+ * @param input - Schedule identifier.
34
+ * @returns Generated UserScheduleResponse.
35
+ * @example feed.getSchedule({ scheduleId: 'S-1' })
36
+ * @see https://developer.ebay.com/api-docs/sell/feed/resources/schedule/methods/getSchedule
37
+ */
38
+ const getSchedule = (input) => decodeEndpointInputEffect(feedScheduleIdInputSchema, input).pipe(Effect.flatMap(({ scheduleId }) => requestGetEffect(client, feedResourcePath('/schedule', scheduleId))));
39
+ /**
40
+ * Updates a schedule; the input is validated against its (possibly changed) template.
41
+ * @param input - Schedule identifier and UpdateUserScheduleRequest body with at least one field.
42
+ * @returns An Effect completing on eBay's empty HTTP 204 response.
43
+ * @example feed.updateSchedule({ scheduleId: 'S-1', schedule: { preferredTriggerHour: '11Z' } })
44
+ * @see https://developer.ebay.com/api-docs/sell/feed/resources/schedule/methods/updateSchedule
45
+ */
46
+ const updateSchedule = (input) => decodeEndpointInputEffect(updateFeedScheduleInputSchema, input).pipe(Effect.filterOrFail(({ schedule }) => Object.keys(schedule).length > 0, () => new EndpointInputError({
47
+ parameter: 'schedule',
48
+ message: 'Provide at least one schedule field to update',
49
+ })), Effect.flatMap(({ scheduleId, schedule }) => {
50
+ const updateScheduleRequest = schedule;
51
+ return requestPutEffect(client, feedResourcePath('/schedule', scheduleId), updateScheduleRequest);
52
+ }));
53
+ /**
54
+ * Deletes a schedule; it stops generating reports.
55
+ * @param input - Schedule identifier.
56
+ * @returns An Effect completing on eBay's empty HTTP 204 response.
57
+ * @example feed.deleteSchedule({ scheduleId: 'S-1' })
58
+ * @see https://developer.ebay.com/api-docs/sell/feed/resources/schedule/methods/deleteSchedule
59
+ */
60
+ const deleteSchedule = (input) => decodeEndpointInputEffect(feedScheduleIdInputSchema, input).pipe(Effect.flatMap(({ scheduleId }) => requestDeleteEffect(client, feedResourcePath('/schedule', scheduleId))));
61
+ /**
62
+ * Downloads the latest report a schedule generated.
63
+ * @param input - Schedule identifier.
64
+ * @returns File bytes (compressed or plain CSV, XML or JSON) with eBay's type and name.
65
+ * @example feed.getLatestResultFile({ scheduleId: 'S-1' })
66
+ * @see https://developer.ebay.com/api-docs/sell/feed/resources/schedule/methods/getLatestResultFile
67
+ */
68
+ const getLatestResultFile = (input) => decodeEndpointInputEffect(feedScheduleIdInputSchema, input).pipe(Effect.flatMap(({ scheduleId }) => downloadFeedFile(client, feedResourcePath('/schedule', scheduleId, '/download_result_file'))));
69
+ /**
70
+ * Retrieves one schedule template, including the fields a schedule must supply.
71
+ * @param input - Schedule template identifier.
72
+ * @returns Generated ScheduleTemplateResponse.
73
+ * @example feed.getScheduleTemplate({ scheduleTemplateId: 'T-1' })
74
+ * @see https://developer.ebay.com/api-docs/sell/feed/resources/schedule/methods/getScheduleTemplate
75
+ */
76
+ const getScheduleTemplate = (input) => decodeEndpointInputEffect(feedScheduleTemplateIdInputSchema, input).pipe(Effect.flatMap(({ scheduleTemplateId }) => requestGetEffect(client, feedResourcePath('/schedule_template', scheduleTemplateId))));
77
+ /**
78
+ * Lists the schedule templates for a feed type.
79
+ * @param input - feedType (required), limit, offset.
80
+ * @returns Generated ScheduleTemplateCollection.
81
+ * @example feed.getScheduleTemplates({ feedType: 'LMS_ORDER_REPORT' })
82
+ * @see https://developer.ebay.com/api-docs/sell/feed/resources/schedule/methods/getScheduleTemplates
83
+ */
84
+ const getScheduleTemplates = (input) => decodeEndpointInputEffect(feedTypePageInputSchema, input).pipe(Effect.flatMap((query) => requestGetEffect(client, `${FEED_BASE_PATH}/schedule_template`, feedListParams(query))));
85
+ return {
86
+ getSchedules,
87
+ createSchedule,
88
+ getSchedule,
89
+ updateSchedule,
90
+ deleteSchedule,
91
+ getLatestResultFile,
92
+ getScheduleTemplate,
93
+ getScheduleTemplates,
94
+ };
95
+ };
@@ -0,0 +1,91 @@
1
+ import { decodeEndpointInputEffect, requestGetEffect, requestPostEffect, requireObjectEffect, requireStringEffect, } from '../../api/shared/request.js';
2
+ import { createFeedTaskInputSchema, feedTaskIdInputSchema, getFeedTasksInputSchema, } from '../../schemas/inventory-management/feed.js';
3
+ import { Effect } from 'effect';
4
+ import { downloadFeedFile, exclusiveFeedFilters, FEED_BASE_PATH, feedListParams, feedResourcePath, postFeedTask, } from './feedRequest.js';
5
+ /** Feed files can be up to 15 MB, far larger than JSON calls. */
6
+ const UPLOAD_TIMEOUT_MS = 10 * 60_000;
7
+ /** Multipart body documented for uploadFile: fileName, name=file, type=form-data, then the file. */
8
+ const feedFileForm = (file) => {
9
+ const form = new FormData();
10
+ form.append('fileName', file.fileName);
11
+ form.append('name', 'file');
12
+ form.append('type', 'form-data');
13
+ // Copy into a fresh ArrayBuffer-backed view: Blob rejects Node's ArrayBufferLike-typed views.
14
+ form.append('file', new Blob([new Uint8Array(file.bytes)], { type: file.mimeType }), file.fileName);
15
+ return form;
16
+ };
17
+ /**
18
+ * Creates the Feed API `task` resource endpoints: upload and download tasks without filter
19
+ * criteria, their input/result files, and feed file uploads.
20
+ * @param client - Shared authenticated HTTP client.
21
+ * @returns Endpoint Effects composed into FeedApi.
22
+ */
23
+ export const createFeedTaskMethods = (client) => {
24
+ /**
25
+ * Lists feed tasks by feed type or schedule, with creation-date filters and pagination.
26
+ * @param input - feedType or scheduleId (not both), dateRange or lookBackDays, limit, offset.
27
+ * @returns Generated TaskCollection.
28
+ * @example feed.getTasks({ feedType: 'LMS_ORDER_ACK', lookBackDays: 7 })
29
+ * @see https://developer.ebay.com/api-docs/sell/feed/resources/task/methods/getTasks
30
+ */
31
+ const getTasks = (input = {}) => decodeEndpointInputEffect(getFeedTasksInputSchema, input).pipe(Effect.flatMap(exclusiveFeedFilters), Effect.flatMap((query) => requestGetEffect(client, `${FEED_BASE_PATH}/task`, feedListParams(query))));
32
+ /**
33
+ * Creates an upload or download task for a feed type; eBay answers 202 with only a Location.
34
+ * @param input - CreateTaskRequest body plus optional marketplace and Accept-Language headers.
35
+ * @returns The new task ID and Location.
36
+ * @example feed.createTask({ task: { feedType: 'LMS_ADD_FIXED_PRICE_ITEM', schemaVersion: '1423' } })
37
+ * @see https://developer.ebay.com/api-docs/sell/feed/resources/task/methods/createTask
38
+ */
39
+ const createTask = (input) => Effect.gen(function* () {
40
+ const { task, marketplaceId, acceptLanguage } = yield* decodeEndpointInputEffect(createFeedTaskInputSchema, input);
41
+ const taskRequest = task;
42
+ const headers = {};
43
+ if (marketplaceId) {
44
+ headers['X-EBAY-C-MARKETPLACE-ID'] = marketplaceId;
45
+ }
46
+ if (acceptLanguage) {
47
+ headers['Accept-Language'] = acceptLanguage;
48
+ }
49
+ return yield* postFeedTask(client, '/task', taskRequest, headers);
50
+ });
51
+ /**
52
+ * Retrieves a feed task's status and upload summary.
53
+ * @param input - Task identifier.
54
+ * @returns Generated Task.
55
+ * @example feed.getTask({ taskId: 'TASK-1' })
56
+ * @see https://developer.ebay.com/api-docs/sell/feed/resources/task/methods/getTask
57
+ */
58
+ const getTask = (input) => decodeEndpointInputEffect(feedTaskIdInputSchema, input).pipe(Effect.flatMap(({ taskId }) => requestGetEffect(client, feedResourcePath('/task', taskId))));
59
+ /**
60
+ * Downloads the file previously uploaded to a task (not for LMS_ORDER_REPORT or
61
+ * LMS_ACTIVE_INVENTORY_REPORT tasks).
62
+ * @param input - Task identifier.
63
+ * @returns File bytes with eBay's content type and file name.
64
+ * @example feed.getInputFile({ taskId: 'TASK-1' })
65
+ * @see https://developer.ebay.com/api-docs/sell/feed/resources/task/methods/getInputFile
66
+ */
67
+ const getInputFile = (input) => decodeEndpointInputEffect(feedTaskIdInputSchema, input).pipe(Effect.flatMap(({ taskId }) => downloadFeedFile(client, feedResourcePath('/task', taskId, '/download_input_file'))));
68
+ /**
69
+ * Downloads a task's generated result file once it is COMPLETED or COMPLETED_WITH_ERROR.
70
+ * @param input - Task identifier.
71
+ * @returns File bytes (often csv.gz or zipped XML) with eBay's content type and file name.
72
+ * @example feed.getResultFile({ taskId: 'TASK-1' })
73
+ * @see https://developer.ebay.com/api-docs/sell/feed/resources/task/methods/getResultFile
74
+ */
75
+ const getResultFile = (input) => decodeEndpointInputEffect(feedTaskIdInputSchema, input).pipe(Effect.flatMap(({ taskId }) => downloadFeedFile(client, feedResourcePath('/task', taskId, '/download_result_file'))));
76
+ /**
77
+ * Uploads the feed file of an upload task as multipart/form-data; eBay then processes it
78
+ * asynchronously (QUEUED, IN_PROCESS, COMPLETED or COMPLETED_WITH_ERROR).
79
+ * @param input - Task identifier and a validated local feed file.
80
+ * @returns eBay's (empty) acknowledgement.
81
+ * @example feed.uploadFile({ taskId: 'TASK-1', file })
82
+ * @see https://developer.ebay.com/api-docs/sell/feed/resources/task/methods/uploadFile
83
+ */
84
+ const uploadFile = (input) => Effect.gen(function* () {
85
+ const { taskId } = yield* decodeEndpointInputEffect(feedTaskIdInputSchema, input);
86
+ const file = yield* requireObjectEffect(input.file, 'file');
87
+ yield* requireStringEffect(file.fileName, 'file.fileName');
88
+ return yield* requestPostEffect(client, feedResourcePath('/task', taskId, '/upload_file'), feedFileForm(file), { timeoutMs: UPLOAD_TIMEOUT_MS });
89
+ });
90
+ return { getTasks, createTask, getTask, getInputFile, getResultFile, uploadFile };
91
+ };
@@ -11,7 +11,7 @@ export const createInventoryItemsMethods = (client) => ({
11
11
  *
12
12
  * @example
13
13
  * ```ts
14
- * const items = await Effect.runPromise(inventoryApi.getInventoryItems({ limit: 25 }));
14
+ * const inventoryPage = await Effect.runPromise(inventoryApi.getInventoryItems({ limit: 25 }));
15
15
  * ```
16
16
  *
17
17
  * @see https://developer.ebay.com/api-docs/sell/inventory/resources/inventory_item/methods/getInventoryItems
@@ -37,7 +37,7 @@ export const createInventoryItemsMethods = (client) => ({
37
37
  *
38
38
  * @example
39
39
  * ```ts
40
- * const item = await Effect.runPromise(inventoryApi.getInventoryItem({ sku: 'SKU-1' }));
40
+ * const inventoryItem = await Effect.runPromise(inventoryApi.getInventoryItem({ sku: 'SKU-1' }));
41
41
  * ```
42
42
  *
43
43
  * @see https://developer.ebay.com/api-docs/sell/inventory/resources/inventory_item/methods/getInventoryItem
@@ -70,11 +70,11 @@ export const createInventoryItemsMethods = (client) => ({
70
70
  return Effect.gen(function* () {
71
71
  const validatedInput = yield* requireObjectEffect(input, 'input');
72
72
  const sku = yield* requireStringEffect(validatedInput.sku, 'sku');
73
- const body = yield* requireObjectEffect(validatedInput.body, 'body');
73
+ const inventoryItem = yield* requireObjectEffect(validatedInput.body, 'body');
74
74
  const config = validatedInput.contentLanguage === undefined
75
75
  ? undefined
76
76
  : { headers: { 'Content-Language': validatedInput.contentLanguage } };
77
- return yield* requestPutEffect(client, `${basePath}/inventory_item/${sku}`, body, config);
77
+ return yield* requestPutEffect(client, `${basePath}/inventory_item/${sku}`, inventoryItem, config);
78
78
  });
79
79
  },
80
80
  /**
@@ -106,7 +106,7 @@ export const createInventoryItemsMethods = (client) => ({
106
106
  *
107
107
  * @example
108
108
  * ```ts
109
- * const result = await Effect.runPromise(
109
+ * const inventoryItemResults = await Effect.runPromise(
110
110
  * inventoryApi.bulkCreateOrReplaceInventoryItem({ body: { requests: [] } }),
111
111
  * );
112
112
  * ```
@@ -117,8 +117,8 @@ export const createInventoryItemsMethods = (client) => ({
117
117
  const path = `${INVENTORY_BASE_PATH}/bulk_create_or_replace_inventory_item`;
118
118
  return Effect.gen(function* () {
119
119
  const validatedInput = yield* requireObjectEffect(input, 'input');
120
- const body = yield* requireObjectEffect(validatedInput.body, 'body');
121
- return yield* requestPostEffect(client, path, body);
120
+ const bulkInventoryItemRequest = yield* requireObjectEffect(validatedInput.body, 'body');
121
+ return yield* requestPostEffect(client, path, bulkInventoryItemRequest);
122
122
  });
123
123
  },
124
124
  /**
@@ -129,7 +129,7 @@ export const createInventoryItemsMethods = (client) => ({
129
129
  *
130
130
  * @example
131
131
  * ```ts
132
- * const result = await Effect.runPromise(
132
+ * const inventoryItems = await Effect.runPromise(
133
133
  * inventoryApi.bulkGetInventoryItem({ body: { requests: [{ sku: 'SKU-1' }] } }),
134
134
  * );
135
135
  * ```
@@ -140,8 +140,8 @@ export const createInventoryItemsMethods = (client) => ({
140
140
  const path = `${INVENTORY_BASE_PATH}/bulk_get_inventory_item`;
141
141
  return Effect.gen(function* () {
142
142
  const validatedInput = yield* requireObjectEffect(input, 'input');
143
- const body = yield* requireObjectEffect(validatedInput.body, 'body');
144
- return yield* requestPostEffect(client, path, body);
143
+ const bulkGetInventoryItemRequest = yield* requireObjectEffect(validatedInput.body, 'body');
144
+ return yield* requestPostEffect(client, path, bulkGetInventoryItemRequest);
145
145
  });
146
146
  },
147
147
  /**
@@ -152,7 +152,7 @@ export const createInventoryItemsMethods = (client) => ({
152
152
  *
153
153
  * @example
154
154
  * ```ts
155
- * const result = await Effect.runPromise(
155
+ * const priceQuantityResults = await Effect.runPromise(
156
156
  * inventoryApi.bulkUpdatePriceQuantity({ body: { requests: [] } }),
157
157
  * );
158
158
  * ```
@@ -163,8 +163,8 @@ export const createInventoryItemsMethods = (client) => ({
163
163
  const path = `${INVENTORY_BASE_PATH}/bulk_update_price_quantity`;
164
164
  return Effect.gen(function* () {
165
165
  const validatedInput = yield* requireObjectEffect(input, 'input');
166
- const body = yield* requireObjectEffect(validatedInput.body, 'body');
167
- return yield* requestPostEffect(client, path, body);
166
+ const bulkPriceQuantityRequest = yield* requireObjectEffect(validatedInput.body, 'body');
167
+ return yield* requestPostEffect(client, path, bulkPriceQuantityRequest);
168
168
  });
169
169
  },
170
170
  /**
@@ -210,8 +210,8 @@ export const createInventoryItemsMethods = (client) => ({
210
210
  return Effect.gen(function* () {
211
211
  const validatedInput = yield* requireObjectEffect(input, 'input');
212
212
  const sku = yield* requireStringEffect(validatedInput.sku, 'sku');
213
- const body = yield* requireObjectEffect(validatedInput.body, 'body');
214
- return yield* requestPutEffect(client, `${basePath}/inventory_item/${sku}/product_compatibility`, body);
213
+ const productCompatibility = yield* requireObjectEffect(validatedInput.body, 'body');
214
+ return yield* requestPutEffect(client, `${basePath}/inventory_item/${sku}/product_compatibility`, productCompatibility);
215
215
  });
216
216
  },
217
217
  /**
@@ -281,8 +281,8 @@ export const createInventoryItemsMethods = (client) => ({
281
281
  return Effect.gen(function* () {
282
282
  const validatedInput = yield* requireObjectEffect(input, 'input');
283
283
  const inventoryItemGroupKey = yield* requireStringEffect(validatedInput.inventoryItemGroupKey, 'inventoryItemGroupKey');
284
- const body = yield* requireObjectEffect(validatedInput.body, 'body');
285
- return yield* requestPutEffect(client, `${basePath}/inventory_item_group/${inventoryItemGroupKey}`, body);
284
+ const inventoryItemGroup = yield* requireObjectEffect(validatedInput.body, 'body');
285
+ return yield* requestPutEffect(client, `${basePath}/inventory_item_group/${inventoryItemGroupKey}`, inventoryItemGroup);
286
286
  });
287
287
  },
288
288
  /**
@@ -316,7 +316,7 @@ export const createInventoryItemsMethods = (client) => ({
316
316
  *
317
317
  * @example
318
318
  * ```ts
319
- * const result = await Effect.runPromise(
319
+ * const migratedListings = await Effect.runPromise(
320
320
  * inventoryApi.bulkMigrateListing({ body: { requests: [] } }),
321
321
  * );
322
322
  * ```
@@ -327,8 +327,8 @@ export const createInventoryItemsMethods = (client) => ({
327
327
  const path = `${INVENTORY_BASE_PATH}/bulk_migrate_listing`;
328
328
  return Effect.gen(function* () {
329
329
  const validatedInput = yield* requireObjectEffect(input, 'input');
330
- const body = yield* requireObjectEffect(validatedInput.body, 'body');
331
- return yield* requestPostEffect(client, path, body);
330
+ const bulkMigrateListingRequest = yield* requireObjectEffect(validatedInput.body, 'body');
331
+ return yield* requestPostEffect(client, path, bulkMigrateListingRequest);
332
332
  });
333
333
  },
334
334
  /**
@@ -380,8 +380,8 @@ export const createInventoryItemsMethods = (client) => ({
380
380
  const validatedInput = yield* requireObjectEffect(input, 'input');
381
381
  const listingId = yield* requireStringEffect(validatedInput.listingId, 'listingId');
382
382
  const sku = yield* requireStringEffect(validatedInput.sku, 'sku');
383
- const body = yield* requireObjectEffect(validatedInput.body, 'body');
384
- return yield* requestPutEffect(client, `${basePath}/listing/${listingId}/sku/${sku}/locations`, body);
383
+ const locationMapping = yield* requireObjectEffect(validatedInput.body, 'body');
384
+ return yield* requestPutEffect(client, `${basePath}/listing/${listingId}/sku/${sku}/locations`, locationMapping);
385
385
  });
386
386
  },
387
387
  /**
@@ -46,8 +46,8 @@ export const createInventoryLocationsMethods = (client) => ({
46
46
  return Effect.gen(function* () {
47
47
  const validatedInput = yield* requireObjectEffect(input, 'input');
48
48
  const merchantLocationKey = yield* requireStringEffect(validatedInput.merchantLocationKey, 'merchantLocationKey');
49
- const body = yield* requireObjectEffect(validatedInput.body, 'body');
50
- return yield* requestPostEffect(client, `${basePath}/location/${merchantLocationKey}`, body);
49
+ const inventoryLocation = yield* requireObjectEffect(validatedInput.body, 'body');
50
+ return yield* requestPostEffect(client, `${basePath}/location/${merchantLocationKey}`, inventoryLocation);
51
51
  });
52
52
  },
53
53
  /**
@@ -165,8 +165,8 @@ export const createInventoryLocationsMethods = (client) => ({
165
165
  return Effect.gen(function* () {
166
166
  const validatedInput = yield* requireObjectEffect(input, 'input');
167
167
  const merchantLocationKey = yield* requireStringEffect(validatedInput.merchantLocationKey, 'merchantLocationKey');
168
- const body = yield* requireObjectEffect(validatedInput.body, 'body');
169
- return yield* requestPostEffect(client, `${basePath}/location/${merchantLocationKey}/update_location_details`, body);
168
+ const inventoryLocationUpdate = yield* requireObjectEffect(validatedInput.body, 'body');
169
+ return yield* requestPostEffect(client, `${basePath}/location/${merchantLocationKey}/update_location_details`, inventoryLocationUpdate);
170
170
  });
171
171
  },
172
172
  });
@@ -33,23 +33,23 @@ const videoStatusFinal = (video) => video.status !== undefined && TERMINAL_VIDEO
33
33
  * standing still while status requests kept going, so the boundary is checked
34
34
  * before the first poll rather than inside the loop.
35
35
  *
36
- * @param value - Caller-supplied duration in milliseconds, or undefined.
36
+ * @param durationMs - Caller-supplied duration in milliseconds, or undefined.
37
37
  * @param fallback - Duration used when the caller supplied none.
38
38
  * @param name - Parameter name used in the validation message.
39
39
  * @param minimum - Smallest accepted value.
40
40
  * @returns An Effect with the duration to use, or a tagged input error.
41
41
  */
42
- const requireDurationMs = (value, fallback, name, minimum) => {
43
- if (value === undefined) {
42
+ const requireDurationMs = (durationMs, fallback, name, minimum) => {
43
+ if (durationMs === undefined) {
44
44
  return Effect.succeed(fallback);
45
45
  }
46
- if (!Number.isFinite(value) || value < minimum) {
46
+ if (!Number.isFinite(durationMs) || durationMs < minimum) {
47
47
  return Effect.fail(new EndpointInputError({
48
48
  parameter: name,
49
49
  message: `${name} must be a finite number of milliseconds of at least ${minimum} when provided`,
50
50
  }));
51
51
  }
52
- return Effect.succeed(value);
52
+ return Effect.succeed(durationMs);
53
53
  };
54
54
  /**
55
55
  * Media API client. Image and video uploads go to eBay's `apim` host and return
@@ -120,14 +120,14 @@ export class MediaApi {
120
120
  const form = new FormData();
121
121
  // Copy into a fresh ArrayBuffer-backed view: Blob rejects Node's ArrayBufferLike-typed views.
122
122
  form.append('image', new Blob([new Uint8Array(upload.bytes)], { type: upload.mimeType }), fileName);
123
- const response = yield* Effect.tryPromise({
123
+ const imageResponse = yield* Effect.tryPromise({
124
124
  try: () => client.postForResponse(url, form, {
125
125
  absolute: true,
126
126
  timeoutMs: UPLOAD_TIMEOUT_MS,
127
127
  }),
128
128
  catch: apiFailure('POST', path),
129
129
  });
130
- const imageUrl = response.data?.imageUrl;
130
+ const imageUrl = imageResponse.data?.imageUrl;
131
131
  if (!imageUrl) {
132
132
  return yield* Effect.fail(new EbayApiError({
133
133
  method: 'POST',
@@ -137,9 +137,9 @@ export class MediaApi {
137
137
  }
138
138
  return {
139
139
  source: upload.source,
140
- imageId: idFromLocation(response.headers.location),
140
+ imageId: idFromLocation(imageResponse.headers.location),
141
141
  imageUrl,
142
- expirationDate: response.data?.expirationDate,
142
+ expirationDate: imageResponse.data?.expirationDate,
143
143
  };
144
144
  });
145
145
  };
@@ -166,7 +166,7 @@ export class MediaApi {
166
166
  index,
167
167
  uploaded: [...uploaded],
168
168
  cause,
169
- message: `upload of ${file.source} (file ${index + 1} of ${files.length}) failed: ${getErrorMessage(cause)}${uploaded.length > 0 ? `; already uploaded: ${uploaded.map((item) => item.imageUrl).join(', ')}` : ''}`,
169
+ message: `upload of ${file.source} (file ${index + 1} of ${files.length}) failed: ${getErrorMessage(cause)}${uploaded.length > 0 ? `; already uploaded: ${uploaded.map((uploadedImage) => uploadedImage.imageUrl).join(', ')}` : ''}`,
170
170
  })));
171
171
  uploaded.push(image);
172
172
  }
@@ -218,17 +218,17 @@ export class MediaApi {
218
218
  return Effect.gen(function* () {
219
219
  const validated = yield* requireObjectEffect(input, 'input');
220
220
  const title = yield* requireStringEffect(validated.title, 'title');
221
- const body = {
221
+ const videoRequest = {
222
222
  title,
223
223
  size: validated.size,
224
224
  description: validated.description,
225
225
  classification: ['ITEM'],
226
226
  };
227
- const response = yield* Effect.tryPromise({
228
- try: () => client.postForResponse(url, body, { absolute: true }),
227
+ const videoResponse = yield* Effect.tryPromise({
228
+ try: () => client.postForResponse(url, videoRequest, { absolute: true }),
229
229
  catch: apiFailure('POST', path),
230
230
  });
231
- const videoId = idFromLocation(response.headers.location);
231
+ const videoId = idFromLocation(videoResponse.headers.location);
232
232
  if (!videoId) {
233
233
  return yield* Effect.fail(new EbayApiError({
234
234
  method: 'POST',
@@ -6,13 +6,13 @@ export class MediaAttachError extends Data.TaggedError('MediaAttachError') {
6
6
  }
7
7
  const dedupe = (values) => [...new Set(values)];
8
8
  /** Keeps only the fields createOrReplaceInventoryItem accepts (drops sku/group metadata). */
9
- const toInventoryItemBody = (item) => ({
10
- availability: item.availability,
11
- condition: item.condition,
12
- conditionDescription: item.conditionDescription,
13
- conditionDescriptors: item.conditionDescriptors,
14
- packageWeightAndSize: item.packageWeightAndSize,
15
- product: item.product,
9
+ const toInventoryItemBody = (inventoryItem) => ({
10
+ availability: inventoryItem.availability,
11
+ condition: inventoryItem.condition,
12
+ conditionDescription: inventoryItem.conditionDescription,
13
+ conditionDescriptors: inventoryItem.conditionDescriptors,
14
+ packageWeightAndSize: inventoryItem.packageWeightAndSize,
15
+ product: inventoryItem.product,
16
16
  });
17
17
  /** `Content-Language` value for an inventory item locale such as `en_US`. */
18
18
  const contentLanguageOf = (locale) => locale?.replace('_', '-');
@@ -68,9 +68,9 @@ const failedOutcome = (file, kind, cause) => ({
68
68
  status: 'failed',
69
69
  error: getErrorMessage(cause),
70
70
  });
71
- const attachFailure = (summary, result) => new MediaAttachError({
72
- message: `${summary}. Results: ${JSON.stringify({ images: result.images, videos: result.videos })}`,
73
- result,
71
+ const attachFailure = (summary, attachResult) => new MediaAttachError({
72
+ message: `${summary}. Results: ${JSON.stringify({ images: attachResult.images, videos: attachResult.videos })}`,
73
+ result: attachResult,
74
74
  });
75
75
  /** Uploads every file, turning each failure into a `failed` outcome instead of aborting. */
76
76
  const uploadAll = (media, input) => Effect.gen(function* () {
@@ -117,7 +117,7 @@ export const createMediaAttachMethods = (items, media) => ({
117
117
  const { images, videos } = yield* uploadAll(media, input);
118
118
  const failed = [...images, ...videos].filter((outcome) => outcome.status === 'failed');
119
119
  const uploaded = uploadedMedia(images, videos);
120
- const result = {
120
+ const attachResult = {
121
121
  sku: input.sku,
122
122
  updated: false,
123
123
  images,
@@ -125,10 +125,10 @@ export const createMediaAttachMethods = (items, media) => ({
125
125
  ...mergeMedia(snapshot.product ?? {}, input, uploaded),
126
126
  };
127
127
  if (failed.length > 0 && !input.allowPartial) {
128
- return yield* Effect.fail(attachFailure(`${failed.length} of ${total} uploads failed; inventory item ${input.sku} was not updated (pass allowPartial: true to attach the successful ones)`, result));
128
+ return yield* Effect.fail(attachFailure(`${failed.length} of ${total} uploads failed; inventory item ${input.sku} was not updated (pass allowPartial: true to attach the successful ones)`, attachResult));
129
129
  }
130
130
  if (uploaded.imageUrls.length + uploaded.videoIds.length === 0) {
131
- return yield* Effect.fail(attachFailure(`no media was uploaded successfully; inventory item ${input.sku} was not updated`, result));
131
+ return yield* Effect.fail(attachFailure(`no media was uploaded successfully; inventory item ${input.sku} was not updated`, attachResult));
132
132
  }
133
133
  // Re-read right before the complete-replacement PUT: the uploads can take
134
134
  // minutes, and the earlier snapshot must not overwrite edits made meanwhile.
@@ -140,6 +140,6 @@ export const createMediaAttachMethods = (items, media) => ({
140
140
  contentLanguage: contentLanguageOf(latest.locale),
141
141
  body: { ...toInventoryItemBody(latest), product: { ...product, ...merged } },
142
142
  });
143
- return { ...result, ...merged, updated: true };
143
+ return { ...attachResult, ...merged, updated: true };
144
144
  }),
145
145
  });