UNPKG

amazon-seller-mcp

Version:

Model Context Protocol (MCP) client for Amazon Selling Partner API

240 lines 8.79 kB
/** * Inventory API client for Amazon Selling Partner API */ // Third-party dependencies import { z } from 'zod'; // Internal imports import { BaseApiClient } from './base-client.js'; /** * Inventory API client for Amazon Selling Partner API */ export class InventoryClient extends BaseApiClient { /** * API version */ apiVersion = 'fba/inventory/v1'; /** * Original authentication configuration */ authConfig; /** * Create a new InventoryClient instance * * @param authConfig Authentication configuration */ constructor(authConfig) { super(authConfig); this.authConfig = authConfig; } /** * Gets the client configuration * * @returns Authentication configuration */ getConfig() { return { ...this.authConfig }; } /** * Get inventory * * @param params Parameters for retrieving inventory * @returns Promise resolving to the inventory details */ async getInventory(params = {}) { const { sellerSkus, marketplaceId = this.config.marketplaceId, asins, fulfillmentChannels, startDateTime, endDateTime, pageSize, nextToken, } = params; // Build query parameters const query = { marketplaceId, }; if (sellerSkus && sellerSkus.length > 0) { query.sellerSkus = sellerSkus; } if (asins && asins.length > 0) { query.asins = asins; } if (fulfillmentChannels && fulfillmentChannels.length > 0) { query.fulfillmentChannels = fulfillmentChannels; } if (startDateTime) { query.startDateTime = startDateTime.toISOString(); } if (endDateTime) { query.endDateTime = endDateTime.toISOString(); } if (pageSize) { query.pageSize = Math.min(100, Math.max(1, pageSize)); // Ensure pageSize is between 1 and 100 } if (nextToken) { query.nextToken = nextToken; } // Make API request const requestOptions = { method: 'GET', path: `/${this.apiVersion}/inventories`, query: query, }; // Use cache for inventory (30 seconds TTL - shorter than listings because inventory changes frequently) const cacheKey = `inventory:${marketplaceId}:${sellerSkus?.join(',') || 'all'}:${asins?.join(',') || 'all'}:${fulfillmentChannels?.join(',') || 'all'}:${nextToken || 'first'}`; return this.withCache(cacheKey, async () => { const response = await this.request(requestOptions); return response.data.payload; }, 30 // 30 seconds TTL ); } /** * Get inventory for a specific SKU * * @param sku Seller SKU * @returns Promise resolving to the inventory item */ async getInventoryBySku(sku) { const result = await this.getInventory({ sellerSkus: [sku] }); if (!result.items || result.items.length === 0) { throw new Error(`Inventory for SKU ${sku} not found`); } return result.items[0]; } /** * Update inventory quantity * * @param params Parameters for updating inventory * @param emitNotification Whether to emit a notification event (default: true) * Note: This parameter is used by the notification system when it overrides this method * @returns Promise resolving to the update result */ async updateInventory(params, _emitNotification = true) { const { sku, quantity, fulfillmentChannel, restockDate } = params; // Validate inventory data this.validateInventoryUpdateData(params); // Build request body const requestBody = { inventory: { sku, fulfillmentChannel, quantity, ...(restockDate && { restockDate: restockDate.toISOString() }), }, }; // Make API request const requestOptions = { method: 'PUT', path: `/${this.apiVersion}/inventories/${sku}`, query: { marketplaceId: this.config.marketplaceId, }, data: requestBody, }; const response = await this.request(requestOptions); // Clear cache for this SKU this.clearCache(`inventory:*:${sku}:*`); return response.data.payload; } /** * Set inventory replenishment settings * * @param params Parameters for setting inventory replenishment settings * @returns Promise resolving to the update result */ async setInventoryReplenishment(params) { const { sku, restockLevel, targetLevel, maximumLevel, leadTimeDays } = params; // Validate replenishment data this.validateReplenishmentData(params); // Build request body const requestBody = { replenishmentSettings: { restockLevel, targetLevel, ...(maximumLevel !== undefined && { maximumLevel }), ...(leadTimeDays !== undefined && { leadTimeDays }), }, }; // Make API request const requestOptions = { method: 'PUT', path: `/${this.apiVersion}/inventories/${sku}/replenishment`, query: { marketplaceId: this.config.marketplaceId, }, data: requestBody, }; const response = await this.request(requestOptions); // Clear cache for this SKU this.clearCache(`inventory:*:${sku}:*`); return response.data.payload; } /** * Validate inventory update data * * @param params Inventory update parameters to validate * @throws Error if validation fails */ validateInventoryUpdateData(params) { // Define validation schema using zod const inventoryUpdateSchema = z.object({ sku: z.string().min(1, 'SKU is required'), quantity: z.number().int().min(0, 'Quantity must be a non-negative integer'), fulfillmentChannel: z.enum(['AMAZON', 'SELLER'], { errorMap: () => ({ message: "Fulfillment channel must be either 'AMAZON' or 'SELLER'" }), }), restockDate: z.date().optional(), }); try { // Validate against schema inventoryUpdateSchema.parse(params); } catch (error) { if (error instanceof z.ZodError) { // Format validation errors const formattedErrors = error.errors .map((err) => `${err.path.join('.')}: ${err.message}`) .join(', '); throw new Error(`Inventory update validation failed: ${formattedErrors}`); } throw error; } } /** * Validate replenishment data * * @param params Replenishment parameters to validate * @throws Error if validation fails */ validateReplenishmentData(params) { // Define validation schema using zod const replenishmentSchema = z .object({ sku: z.string().min(1, 'SKU is required'), restockLevel: z.number().int().min(0, 'Restock level must be a non-negative integer'), targetLevel: z.number().int().min(0, 'Target level must be a non-negative integer'), maximumLevel: z .number() .int() .min(0, 'Maximum level must be a non-negative integer') .optional(), leadTimeDays: z.number().int().min(1, 'Lead time must be a positive integer').optional(), }) .refine((data) => data.targetLevel >= data.restockLevel, { message: 'Target level must be greater than or equal to restock level', path: ['targetLevel'], }) .refine((data) => !data.maximumLevel || data.maximumLevel >= data.targetLevel, { message: 'Maximum level must be greater than or equal to target level', path: ['maximumLevel'], }); try { // Validate against schema replenishmentSchema.parse(params); } catch (error) { if (error instanceof z.ZodError) { // Format validation errors const formattedErrors = error.errors .map((err) => `${err.path.join('.')}: ${err.message}`) .join(', '); throw new Error(`Replenishment settings validation failed: ${formattedErrors}`); } throw error; } } } //# sourceMappingURL=inventory-client.js.map