UNPKG

@sp-api-sdk/common

Version:

Common library for the Amazon Selling Partner API (SP-API) SDK: Axios factory, regions, rate limiting and errors

1 lines 13 kB
{"version":3,"file":"index.cjs","names":["AxiosError","URL","SellingPartnerApiAuthError"],"sources":["../src/regions.ts","../src/errors.ts","../src/utils/package.ts","../src/axios.ts"],"sourcesContent":["/** Selling Partner API region identifier. */\nexport type SellingPartnerRegion = 'na' | 'eu' | 'fe'\n\ninterface RegionConfiguration {\n endpoints: {\n production: string\n sandbox: string\n }\n}\n\n/** Endpoint mapping for each Selling Partner API region. */\nexport const sellingPartnerRegions: Record<SellingPartnerRegion, RegionConfiguration> = {\n na: {\n endpoints: {\n production: 'https://sellingpartnerapi-na.amazon.com',\n sandbox: 'https://sandbox.sellingpartnerapi-na.amazon.com',\n },\n },\n eu: {\n endpoints: {\n production: 'https://sellingpartnerapi-eu.amazon.com',\n sandbox: 'https://sandbox.sellingpartnerapi-eu.amazon.com',\n },\n },\n fe: {\n endpoints: {\n production: 'https://sellingpartnerapi-fe.amazon.com',\n sandbox: 'https://sandbox.sellingpartnerapi-fe.amazon.com',\n },\n },\n}\n","import {URL} from 'node:url'\n\nimport {AxiosError} from 'axios'\n\n/**\n Error thrown when a Selling Partner API request fails.\n\n Wraps the underlying Axios error with a message that includes the API name,\n version, and HTTP status code (or \"No response\" for network errors).\n */\nexport class SellingPartnerApiError<T = unknown, D = any> extends AxiosError<T, D> {\n /** The original error message from the failed HTTP request. */\n public readonly innerMessage: string\n /** The API name extracted from the request URL path (e.g. `\"orders\"`). */\n public readonly apiName?: string\n /** The API version extracted from the request URL path (e.g. `\"v0\"`). */\n public readonly apiVersion?: string\n\n constructor(error: AxiosError<T, D>) {\n super('Unknown error', error.code, error.config, error.request, error.response)\n\n this.innerMessage = error.message\n\n if (error.config!.url) {\n const [apiName, apiVersion] = new URL(error.config!.url).pathname.split('/').slice(1)\n const apiPrefix = `${apiName} (${apiVersion})`\n\n this.apiName = apiName\n this.apiVersion = apiVersion\n this.message = error.response\n ? `${apiPrefix} error: Response code ${error.response.status}`\n : `${apiPrefix} error: No response`\n }\n\n this.name = this.constructor.name\n }\n}\n","import {type NormalizedPackageJson, sync as readPackageJson} from 'read-pkg-up'\n\nconst result = readPackageJson()\n\nexport const packageJson: NormalizedPackageJson = result?.packageJson ?? {\n _id: '',\n readme: '',\n name: '@sp-api-sdk/common',\n version: 'unknown',\n}\n","import axios, {type AxiosError, isAxiosError, type Method} from 'axios'\nimport {errorLogger, requestLogger, responseLogger} from 'axios-logger'\nimport axiosRetry from 'axios-retry'\n\nimport {type SellingPartnerApiAuth, SellingPartnerApiAuthError} from '@sp-api-sdk/auth'\n\nimport {SellingPartnerApiError} from './errors.js'\nimport {type SellingPartnerRegion, sellingPartnerRegions} from './regions.js'\nimport {packageJson} from './utils/package.js'\n\ntype RequestLogConfig = Exclude<Parameters<typeof requestLogger>[1], undefined>\ntype ResponseLogConfig = Exclude<Parameters<typeof responseLogger>[1], undefined>\ntype ErrorLogConfig = Exclude<Parameters<typeof errorLogger>[1], undefined>\n\n/** Per-endpoint rate limit definition used for retry delay calculation. */\nexport interface RateLimit {\n /** Regular expression matched against the request URL pathname. */\n urlRegex: RegExp\n /** Sustained request rate in requests per second. */\n rate: number\n /** Maximum burst size (number of requests allowed before throttling). */\n burst: number\n /** HTTP method this rate limit applies to. */\n method: Method\n}\n\n/** Parameters passed to the {@link ClientConfiguration.rateLimiting} `onRetry` callback. */\nexport interface OnRetryParameters {\n /** Delay in milliseconds before the next retry attempt. */\n delay: number\n /** Rate limit (requests per second) used to calculate the delay, if available. */\n rateLimit?: number\n /** Number of retry attempts so far. */\n retryCount: number\n /** The Axios error that triggered the retry. */\n error: AxiosError\n}\n\n/** Configuration options for creating a Selling Partner API Axios instance. */\nexport interface ClientConfiguration {\n /** Authentication handler that provides LWA access tokens. */\n auth: SellingPartnerApiAuth\n /** Restricted Data Token to use instead of the standard access token. */\n restrictedDataToken?: string\n /** Selling Partner API region to send requests to. */\n region: SellingPartnerRegion\n /** Custom `User-Agent` header value. */\n userAgent?: string\n /** When `true`, requests are sent to the sandbox endpoint. Defaults to `false`. */\n sandbox?: boolean\n /** Rate-limiting and retry configuration for 429 responses. */\n rateLimiting?: {\n /** When `true`, automatically retries throttled (HTTP 429) requests. */\n retry: boolean\n /** Optional callback invoked before each retry attempt. */\n onRetry?: (retryInfo: OnRetryParameters) => void\n }\n /** Axios request/response/error logging configuration. Pass `true` to use defaults. */\n logging?: {\n /** Log outgoing requests. */\n request?: RequestLogConfig | true\n /** Log incoming responses. */\n response?: ResponseLogConfig | true\n /** Log request errors. */\n error?: ErrorLogConfig | true\n }\n}\n\n/**\n Creates a pre-configured Axios instance for a Selling Partner API client.\n\n The instance handles authentication, rate-limit retries, error wrapping,\n and optional request/response logging.\n\n @param configuration - Client configuration options.\n @param rateLimits - Per-endpoint rate limits used for retry delay calculation.\n @returns An object containing the configured Axios instance and the resolved API endpoint.\n */\nexport function createAxiosInstance(\n {\n auth,\n restrictedDataToken,\n region,\n userAgent = `${packageJson.name}/${packageJson.version}`,\n sandbox = false,\n rateLimiting,\n logging,\n }: ClientConfiguration,\n rateLimits: RateLimit[],\n) {\n if (!Object.hasOwn(sellingPartnerRegions, region)) {\n throw new TypeError(`Unknown or unsupported region: ${region}`)\n }\n\n const regionConfiguration = sellingPartnerRegions[region]\n\n const instance = axios.create({\n headers: {\n 'user-agent': userAgent,\n },\n })\n\n const endpoint = regionConfiguration.endpoints[sandbox ? 'sandbox' : 'production']\n\n if (rateLimiting?.retry) {\n axiosRetry(instance, {\n retryCondition: (error) => error.response?.status === 429,\n retryDelay(retryCount, error) {\n const url = new URL(error.config!.url!)\n const method = error.config!.method?.toLowerCase()\n const amznRateLimitHeader: string | undefined =\n error.response?.headers['x-amzn-ratelimit-limit']\n const amznRateLimit = amznRateLimitHeader ? Number(amznRateLimitHeader) : NaN\n\n const rateLimit = Number.isNaN(amznRateLimit)\n ? rateLimits.find(\n (rateLimit) =>\n rateLimit.method.toLowerCase() === method && rateLimit.urlRegex.test(url.pathname),\n )?.rate\n : amznRateLimit\n\n const requestInterval =\n rateLimit !== undefined && rateLimit > 0 ? 1000 / rateLimit : undefined\n const delay = requestInterval === undefined ? 60_000 : requestInterval + 1500\n\n if (rateLimiting.onRetry) {\n rateLimiting.onRetry({delay, rateLimit, retryCount, error})\n }\n\n return delay\n },\n })\n }\n\n // Set x-amz-access-token to each request\n instance.interceptors.request.use(async (config) => {\n config.headers['x-amz-access-token'] = restrictedDataToken ?? (await auth.getAccessToken())\n\n return config\n })\n\n instance.interceptors.response.use(\n async (response) => response,\n async (error: unknown) => {\n if (isAxiosError(error) && !(error instanceof SellingPartnerApiAuthError)) {\n throw new SellingPartnerApiError(error)\n }\n\n throw error\n },\n )\n\n if (logging?.request !== undefined) {\n const requestLoggerOptions = logging.request === true ? undefined : logging.request\n\n if (requestLoggerOptions?.headers) {\n console.warn(\n 'WARNING: You have enabled logging of request headers, this can leak authentication information, you should disable in production.',\n )\n }\n\n instance.interceptors.request.use((config) => {\n const logger = requestLogger(config, {\n prefixText: `sp-api-sdk/${region}`,\n dateFormat: 'isoDateTime',\n method: true,\n url: true,\n params: false,\n data: true,\n headers: false,\n logger: console.info,\n ...requestLoggerOptions,\n })\n\n return {\n ...logger,\n headers: config.headers,\n }\n })\n }\n\n if (logging?.response !== undefined) {\n const responseLoggerOptions = logging.response === true ? undefined : logging.response\n\n instance.interceptors.response.use((response) =>\n responseLogger(response, {\n prefixText: `sp-api-sdk/${region}`,\n dateFormat: 'isoDateTime',\n status: true,\n statusText: false,\n params: false,\n data: false,\n headers: true,\n logger: console.info,\n ...responseLoggerOptions,\n }),\n )\n }\n\n if (logging?.error !== undefined) {\n const errorLoggerOptions = logging.error === true ? undefined : logging.error\n\n instance.interceptors.response.use(\n (response) => response,\n async (error) =>\n errorLogger(error, {\n prefixText: `sp-api-sdk/${region}`,\n dateFormat: 'isoDateTime',\n status: true,\n statusText: false,\n params: false,\n data: false,\n headers: true,\n logger: console.error,\n ...errorLoggerOptions,\n }),\n )\n }\n\n return {axios: instance, endpoint}\n}\n"],"mappings":";;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;AAWA,MAAa,wBAA2E;CACtF,IAAI,EACF,WAAW;EACT,YAAY;EACZ,SAAS;CACX,EACF;CACA,IAAI,EACF,WAAW;EACT,YAAY;EACZ,SAAS;CACX,EACF;CACA,IAAI,EACF,WAAW;EACT,YAAY;EACZ,SAAS;CACX,EACF;AACF;;;;;;;;;ACpBA,IAAa,yBAAb,cAAkEA,MAAAA,WAAiB;;CAEjF;;CAEA;;CAEA;CAEA,YAAY,OAAyB;EACnC,MAAM,iBAAiB,MAAM,MAAM,MAAM,QAAQ,MAAM,SAAS,MAAM,QAAQ;EAE9E,KAAK,eAAe,MAAM;EAE1B,IAAI,MAAM,OAAQ,KAAK;GACrB,MAAM,CAAC,SAAS,cAAc,IAAIC,SAAAA,IAAI,MAAM,OAAQ,GAAG,CAAC,CAAC,SAAS,MAAM,GAAG,CAAC,CAAC,MAAM,CAAC;GACpF,MAAM,YAAY,GAAG,QAAQ,IAAI,WAAW;GAE5C,KAAK,UAAU;GACf,KAAK,aAAa;GAClB,KAAK,UAAU,MAAM,WACjB,GAAG,UAAU,wBAAwB,MAAM,SAAS,WACpD,GAAG,UAAU;EACnB;EAEA,KAAK,OAAO,KAAK,YAAY;CAC/B;AACF;AChCA,MAAa,eAFP,GAAA,YAAA,KAAA,CAE4C,CAAA,EAAQ,eAAe;CACvE,KAAK;CACL,QAAQ;CACR,MAAM;CACN,SAAS;AACX;;;;;;;;;;;;;ACqEA,SAAgB,oBACd,EACE,MACA,qBACA,QACA,YAAY,GAAG,YAAY,KAAK,GAAG,YAAY,WAC/C,UAAU,OACV,cACA,WAEF,YACA;CACA,IAAI,CAAC,OAAO,OAAO,uBAAuB,MAAM,GAC9C,MAAM,IAAI,UAAU,kCAAkC,QAAQ;CAGhE,MAAM,sBAAsB,sBAAsB;CAElD,MAAM,WAAW,MAAA,QAAM,OAAO,EAC5B,SAAS,EACP,cAAc,UAChB,EACF,CAAC;CAED,MAAM,WAAW,oBAAoB,UAAU,UAAU,YAAY;CAErE,IAAI,cAAc,OAChB,CAAA,GAAA,YAAA,QAAA,CAAW,UAAU;EACnB,iBAAiB,UAAU,MAAM,UAAU,WAAW;EACtD,WAAW,YAAY,OAAO;GAC5B,MAAM,MAAM,IAAI,IAAI,MAAM,OAAQ,GAAI;GACtC,MAAM,SAAS,MAAM,OAAQ,QAAQ,YAAY;GACjD,MAAM,sBACJ,MAAM,UAAU,QAAQ;GAC1B,MAAM,gBAAgB,sBAAsB,OAAO,mBAAmB,IAAI;GAE1E,MAAM,YAAY,OAAO,MAAM,aAAa,IACxC,WAAW,MACR,cACC,UAAU,OAAO,YAAY,MAAM,UAAU,UAAU,SAAS,KAAK,IAAI,QAAQ,CACrF,CAAC,EAAE,OACH;GAEJ,MAAM,kBACJ,cAAc,KAAA,KAAa,YAAY,IAAI,MAAO,YAAY,KAAA;GAChE,MAAM,QAAQ,oBAAoB,KAAA,IAAY,MAAS,kBAAkB;GAEzE,IAAI,aAAa,SACf,aAAa,QAAQ;IAAC;IAAO;IAAW;IAAY;GAAK,CAAC;GAG5D,OAAO;EACT;CACF,CAAC;CAIH,SAAS,aAAa,QAAQ,IAAI,OAAO,WAAW;EAClD,OAAO,QAAQ,wBAAwB,uBAAwB,MAAM,KAAK,eAAe;EAEzF,OAAO;CACT,CAAC;CAED,SAAS,aAAa,SAAS,IAC7B,OAAO,aAAa,UACpB,OAAO,UAAmB;EACxB,KAAA,GAAA,MAAA,aAAA,CAAiB,KAAK,KAAK,EAAE,iBAAiBC,iBAAAA,6BAC5C,MAAM,IAAI,uBAAuB,KAAK;EAGxC,MAAM;CACR,CACF;CAEA,IAAI,SAAS,YAAY,KAAA,GAAW;EAClC,MAAM,uBAAuB,QAAQ,YAAY,OAAO,KAAA,IAAY,QAAQ;EAE5E,IAAI,sBAAsB,SACxB,QAAQ,KACN,mIACF;EAGF,SAAS,aAAa,QAAQ,KAAK,WAAW;GAa5C,OAAO;IACL,IAAA,GAAA,aAAA,cAAA,CAb2B,QAAQ;KACnC,YAAY,cAAc;KAC1B,YAAY;KACZ,QAAQ;KACR,KAAK;KACL,QAAQ;KACR,MAAM;KACN,SAAS;KACT,QAAQ,QAAQ;KAChB,GAAG;IACL,CAGU;IACR,SAAS,OAAO;GAClB;EACF,CAAC;CACH;CAEA,IAAI,SAAS,aAAa,KAAA,GAAW;EACnC,MAAM,wBAAwB,QAAQ,aAAa,OAAO,KAAA,IAAY,QAAQ;EAE9E,SAAS,aAAa,SAAS,KAAK,cAAA,GAAA,aAAA,eAAA,CACnB,UAAU;GACvB,YAAY,cAAc;GAC1B,YAAY;GACZ,QAAQ;GACR,YAAY;GACZ,QAAQ;GACR,MAAM;GACN,SAAS;GACT,QAAQ,QAAQ;GAChB,GAAG;EACL,CAAC,CACH;CACF;CAEA,IAAI,SAAS,UAAU,KAAA,GAAW;EAChC,MAAM,qBAAqB,QAAQ,UAAU,OAAO,KAAA,IAAY,QAAQ;EAExE,SAAS,aAAa,SAAS,KAC5B,aAAa,UACd,OAAO,WAAA,GAAA,aAAA,YAAA,CACO,OAAO;GACjB,YAAY,cAAc;GAC1B,YAAY;GACZ,QAAQ;GACR,YAAY;GACZ,QAAQ;GACR,MAAM;GACN,SAAS;GACT,QAAQ,QAAQ;GAChB,GAAG;EACL,CAAC,CACL;CACF;CAEA,OAAO;EAAC,OAAO;EAAU;CAAQ;AACnC"}