@sp-api-sdk/auth
Advanced tools
+170
| "use strict"; | ||
| var __create = Object.create; | ||
| var __defProp = Object.defineProperty; | ||
| var __getOwnPropDesc = Object.getOwnPropertyDescriptor; | ||
| var __getOwnPropNames = Object.getOwnPropertyNames; | ||
| var __getProtoOf = Object.getPrototypeOf; | ||
| var __hasOwnProp = Object.prototype.hasOwnProperty; | ||
| var __export = (target, all) => { | ||
| for (var name in all) | ||
| __defProp(target, name, { get: all[name], enumerable: true }); | ||
| }; | ||
| var __copyProps = (to, from, except, desc) => { | ||
| if (from && typeof from === "object" || typeof from === "function") { | ||
| for (let key of __getOwnPropNames(from)) | ||
| if (!__hasOwnProp.call(to, key) && key !== except) | ||
| __defProp(to, key, { get: () => from[key], enumerable: !(desc = __getOwnPropDesc(from, key)) || desc.enumerable }); | ||
| } | ||
| return to; | ||
| }; | ||
| var __toESM = (mod, isNodeMode, target) => (target = mod != null ? __create(__getProtoOf(mod)) : {}, __copyProps( | ||
| // If the importer is in node compatibility mode or this is not an ESM | ||
| // file that has been converted to a CommonJS file using a Babel- | ||
| // compatible transform (i.e. "__esModule" has not been set), then set | ||
| // "default" to the CommonJS "module.exports" for node compatibility. | ||
| isNodeMode || !mod || !mod.__esModule ? __defProp(target, "default", { value: mod, enumerable: true }) : target, | ||
| mod | ||
| )); | ||
| var __toCommonJS = (mod) => __copyProps(__defProp({}, "__esModule", { value: true }), mod); | ||
| // src/index.ts | ||
| var index_exports = {}; | ||
| __export(index_exports, { | ||
| AuthorizationScope: () => AuthorizationScope, | ||
| SellingPartnerApiAuth: () => SellingPartnerApiAuth, | ||
| SellingPartnerApiAuthError: () => SellingPartnerApiAuthError | ||
| }); | ||
| module.exports = __toCommonJS(index_exports); | ||
| var import_node_process = __toESM(require("process"), 1); | ||
| var import_axios3 = require("axios"); | ||
| // src/error.ts | ||
| var import_axios = require("axios"); | ||
| var SellingPartnerApiAuthError = class extends import_axios.AxiosError { | ||
| /** The original error message from the failed HTTP request. */ | ||
| innerMessage; | ||
| constructor(error) { | ||
| const message = error.response ? `access-token error: Response code ${error.response.status}` : "access-token error: No response"; | ||
| super(message, error.code, error.config, error.request, error.response); | ||
| this.innerMessage = error.message; | ||
| this.name = this.constructor.name; | ||
| } | ||
| }; | ||
| // src/utils/axios.ts | ||
| var import_axios2 = __toESM(require("axios"), 1); | ||
| // src/utils/package.ts | ||
| var import_read_pkg_up = require("read-pkg-up"); | ||
| var result = (0, import_read_pkg_up.sync)(); | ||
| var packageJson = result?.packageJson ?? { | ||
| _id: "", | ||
| readme: "", | ||
| name: "@sp-api-sdk/auth", | ||
| version: "unknown" | ||
| }; | ||
| // src/utils/axios.ts | ||
| var axios = import_axios2.default.create({ | ||
| baseURL: "https://api.amazon.com/auth/", | ||
| timeout: 3e4, | ||
| headers: { | ||
| "user-agent": `${packageJson.name}/${packageJson.version}` | ||
| } | ||
| }); | ||
| // src/types/scope.ts | ||
| var AuthorizationScope = /* @__PURE__ */ ((AuthorizationScope2) => { | ||
| AuthorizationScope2["NOTIFICATIONS"] = "sellingpartnerapi::notifications"; | ||
| AuthorizationScope2["CLIENT_CREDENTIAL_ROTATION"] = "sellingpartnerapi::client_credential:rotation"; | ||
| return AuthorizationScope2; | ||
| })(AuthorizationScope || {}); | ||
| // src/index.ts | ||
| var SellingPartnerApiAuth = class { | ||
| clientId; | ||
| clientSecret; | ||
| refreshToken; | ||
| scopes; | ||
| #accessToken; | ||
| #accessTokenExpiration; | ||
| #pendingTokenRequest; | ||
| constructor(parameters) { | ||
| const clientId = parameters.clientId ?? import_node_process.default.env.LWA_CLIENT_ID; | ||
| const clientSecret = parameters.clientSecret ?? import_node_process.default.env.LWA_CLIENT_SECRET; | ||
| const refreshToken = parameters.refreshToken ?? import_node_process.default.env.LWA_REFRESH_TOKEN; | ||
| if (!clientId) { | ||
| throw new Error("Missing required `clientId` configuration value"); | ||
| } | ||
| if (!clientSecret) { | ||
| throw new Error("Missing required `clientSecret` configuration value"); | ||
| } | ||
| if (!refreshToken && !parameters.scopes) { | ||
| throw new TypeError("Either `refreshToken` or `scopes` must be specified"); | ||
| } | ||
| this.clientId = clientId; | ||
| this.clientSecret = clientSecret; | ||
| this.refreshToken = refreshToken; | ||
| this.scopes = parameters.scopes; | ||
| } | ||
| /** | ||
| * Returns a valid LWA access token, refreshing it if expired. | ||
| * | ||
| * Concurrent calls while a refresh is in progress share the same request. | ||
| * | ||
| * @returns The access token string. | ||
| */ | ||
| async getAccessToken() { | ||
| if (this.#accessToken && (!this.#accessTokenExpiration || Date.now() < this.#accessTokenExpiration.getTime())) { | ||
| return this.#accessToken; | ||
| } | ||
| if (this.#pendingTokenRequest) { | ||
| return this.#pendingTokenRequest; | ||
| } | ||
| this.#pendingTokenRequest = this.#refreshAccessToken(); | ||
| try { | ||
| return await this.#pendingTokenRequest; | ||
| } finally { | ||
| this.#pendingTokenRequest = void 0; | ||
| } | ||
| } | ||
| async #refreshAccessToken() { | ||
| const body = { | ||
| client_id: this.clientId, | ||
| client_secret: this.clientSecret, | ||
| ...this.refreshToken ? { | ||
| grant_type: "refresh_token", | ||
| refresh_token: this.refreshToken | ||
| } : { | ||
| grant_type: "client_credentials", | ||
| scope: this.scopes.join(" ") | ||
| } | ||
| }; | ||
| try { | ||
| const expiration = /* @__PURE__ */ new Date(); | ||
| const { data } = await axios.post("/o2/token", body); | ||
| expiration.setSeconds(expiration.getSeconds() + data.expires_in); | ||
| this.#accessToken = data.access_token; | ||
| this.#accessTokenExpiration = expiration; | ||
| return data.access_token; | ||
| } catch (error) { | ||
| if (error instanceof import_axios3.AxiosError) { | ||
| throw new SellingPartnerApiAuthError(error); | ||
| } | ||
| throw error; | ||
| } | ||
| } | ||
| /** | ||
| * Expiration date of the currently cached access token, or `undefined` if no token has been fetched yet. | ||
| */ | ||
| get accessTokenExpiration() { | ||
| return this.#accessTokenExpiration; | ||
| } | ||
| }; | ||
| // Annotate the CommonJS export names for ESM import in node: | ||
| 0 && (module.exports = { | ||
| AuthorizationScope, | ||
| SellingPartnerApiAuth, | ||
| SellingPartnerApiAuthError | ||
| }); | ||
| //# sourceMappingURL=index.cjs.map |
| {"version":3,"sources":["../src/index.ts","../src/error.ts","../src/utils/axios.ts","../src/utils/package.ts","../src/types/scope.ts"],"sourcesContent":["import process from 'node:process'\n\nimport {AxiosError} from 'axios'\nimport {type RequireExactlyOne} from 'type-fest'\n\nimport {SellingPartnerApiAuthError} from './error.js'\nimport {type AccessTokenData, type AccessTokenQuery} from './types/access-token.js'\nimport {type AuthorizationScope} from './types/scope.js'\nimport {axios} from './utils/axios.js'\n\n/**\n * Configuration parameters for Selling Partner API authentication.\n *\n * Both `clientId` and `clientSecret` fall back to the `LWA_CLIENT_ID` and\n * `LWA_CLIENT_SECRET` environment variables when omitted.\n * `refreshToken` falls back to `LWA_REFRESH_TOKEN`.\n */\nexport interface SellingPartnerAuthParameters {\n /** LWA client identifier. Defaults to the `LWA_CLIENT_ID` environment variable. */\n clientId?: string\n /** LWA client secret. Defaults to the `LWA_CLIENT_SECRET` environment variable. */\n clientSecret?: string\n /** LWA refresh token. Defaults to the `LWA_REFRESH_TOKEN` environment variable. Mutually exclusive with `scopes`. */\n refreshToken?: string\n /** Authorization scopes for grantless operations. Mutually exclusive with `refreshToken`. */\n scopes?: AuthorizationScope[]\n}\n\n/**\n * Handles Login with Amazon (LWA) OAuth token management for the Selling Partner API.\n *\n * Supports both refresh-token and grantless (scope-based) authentication flows.\n * Tokens are cached and automatically refreshed when expired. Concurrent calls\n * to {@link getAccessToken} are deduplicated into a single request.\n */\nexport class SellingPartnerApiAuth {\n private readonly clientId: string\n private readonly clientSecret: string\n private readonly refreshToken?: string\n private readonly scopes?: AuthorizationScope[]\n\n #accessToken?: string\n #accessTokenExpiration?: Date\n #pendingTokenRequest?: Promise<string>\n\n constructor(\n parameters: RequireExactlyOne<SellingPartnerAuthParameters, 'refreshToken' | 'scopes'>,\n ) {\n const clientId = parameters.clientId ?? process.env.LWA_CLIENT_ID\n const clientSecret = parameters.clientSecret ?? process.env.LWA_CLIENT_SECRET\n const refreshToken = parameters.refreshToken ?? process.env.LWA_REFRESH_TOKEN\n\n if (!clientId) {\n throw new Error('Missing required `clientId` configuration value')\n }\n\n if (!clientSecret) {\n throw new Error('Missing required `clientSecret` configuration value')\n }\n\n if (!refreshToken && !parameters.scopes) {\n throw new TypeError('Either `refreshToken` or `scopes` must be specified')\n }\n\n this.clientId = clientId\n this.clientSecret = clientSecret\n\n this.refreshToken = refreshToken\n this.scopes = parameters.scopes\n }\n\n /**\n * Returns a valid LWA access token, refreshing it if expired.\n *\n * Concurrent calls while a refresh is in progress share the same request.\n *\n * @returns The access token string.\n */\n async getAccessToken() {\n if (\n this.#accessToken &&\n (!this.#accessTokenExpiration || Date.now() < this.#accessTokenExpiration.getTime())\n ) {\n return this.#accessToken\n }\n\n // Deduplicate concurrent calls: share the same in-flight request\n if (this.#pendingTokenRequest) {\n return this.#pendingTokenRequest\n }\n\n this.#pendingTokenRequest = this.#refreshAccessToken()\n\n try {\n return await this.#pendingTokenRequest\n } finally {\n this.#pendingTokenRequest = undefined\n }\n }\n\n async #refreshAccessToken() {\n const body: AccessTokenQuery = {\n client_id: this.clientId,\n client_secret: this.clientSecret,\n ...(this.refreshToken\n ? {\n grant_type: 'refresh_token',\n refresh_token: this.refreshToken,\n }\n : {\n grant_type: 'client_credentials',\n scope: this.scopes!.join(' '),\n }),\n }\n\n try {\n const expiration = new Date()\n\n const {data} = await axios.post<AccessTokenData>('/o2/token', body)\n\n expiration.setSeconds(expiration.getSeconds() + data.expires_in)\n\n this.#accessToken = data.access_token\n this.#accessTokenExpiration = expiration\n\n return data.access_token\n } catch (error: unknown) {\n if (error instanceof AxiosError) {\n throw new SellingPartnerApiAuthError(error)\n }\n\n throw error\n }\n }\n\n /**\n * Expiration date of the currently cached access token, or `undefined` if no token has been fetched yet.\n */\n protected get accessTokenExpiration() {\n return this.#accessTokenExpiration\n }\n}\n\nexport {SellingPartnerApiAuthError} from './error.js'\nexport {AuthorizationScope} from './types/scope.js'\n","import {AxiosError} from 'axios'\n\nimport type {AccessTokenData, AccessTokenQuery} from './types/access-token.js'\n\n/**\n * Error thrown when an LWA token request fails.\n *\n * Wraps the underlying Axios error with a human-readable message that includes\n * the HTTP status code (or \"No response\" for network errors).\n */\nexport class SellingPartnerApiAuthError extends AxiosError<AccessTokenData, AccessTokenQuery> {\n /** The original error message from the failed HTTP request. */\n public readonly innerMessage: string\n\n constructor(error: AxiosError<AccessTokenData, AccessTokenQuery>) {\n const message = error.response\n ? `access-token error: Response code ${error.response.status}`\n : 'access-token error: No response'\n\n super(message, error.code, error.config, error.request, error.response)\n\n this.innerMessage = error.message\n this.name = this.constructor.name\n }\n}\n","import globalAxios from 'axios'\n\nimport {packageJson} from './package.js'\n\nexport const axios = globalAxios.create({\n baseURL: 'https://api.amazon.com/auth/',\n timeout: 30_000,\n headers: {\n 'user-agent': `${packageJson.name}/${packageJson.version}`,\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/auth',\n version: 'unknown',\n}\n","/** Authorization scopes for grantless Selling Partner API operations. */\nexport enum AuthorizationScope {\n /** Scope for the Notifications API. */\n NOTIFICATIONS = 'sellingpartnerapi::notifications',\n /** Scope for rotating application client credentials. */\n CLIENT_CREDENTIAL_ROTATION = 'sellingpartnerapi::client_credential:rotation',\n}\n"],"mappings":"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","names":["import_axios","import_axios","readPackageJson","globalAxios","AuthorizationScope","process"]} |
| import { RequireExactlyOne } from 'type-fest'; | ||
| import { AxiosError } from 'axios'; | ||
| /** Authorization scopes for grantless Selling Partner API operations. */ | ||
| declare enum AuthorizationScope { | ||
| /** Scope for the Notifications API. */ | ||
| NOTIFICATIONS = "sellingpartnerapi::notifications", | ||
| /** Scope for rotating application client credentials. */ | ||
| CLIENT_CREDENTIAL_ROTATION = "sellingpartnerapi::client_credential:rotation" | ||
| } | ||
| interface BaseAccessTokenQuery { | ||
| client_id: string; | ||
| client_secret: string; | ||
| } | ||
| type RefreshTokenAccessTokenQuery = { | ||
| grant_type: 'refresh_token'; | ||
| refresh_token: string; | ||
| } & BaseAccessTokenQuery; | ||
| type ClientCredentialsAccessTokenQuery = { | ||
| grant_type: 'client_credentials'; | ||
| scope: string; | ||
| } & BaseAccessTokenQuery; | ||
| /** Request body for the LWA token endpoint. */ | ||
| type AccessTokenQuery = RefreshTokenAccessTokenQuery | ClientCredentialsAccessTokenQuery; | ||
| /** Response body from the LWA token endpoint. */ | ||
| interface AccessTokenData { | ||
| access_token: string; | ||
| refresh_token?: string; | ||
| token_type: string; | ||
| expires_in: number; | ||
| } | ||
| /** | ||
| * Error thrown when an LWA token request fails. | ||
| * | ||
| * Wraps the underlying Axios error with a human-readable message that includes | ||
| * the HTTP status code (or "No response" for network errors). | ||
| */ | ||
| declare class SellingPartnerApiAuthError extends AxiosError<AccessTokenData, AccessTokenQuery> { | ||
| /** The original error message from the failed HTTP request. */ | ||
| readonly innerMessage: string; | ||
| constructor(error: AxiosError<AccessTokenData, AccessTokenQuery>); | ||
| } | ||
| /** | ||
| * Configuration parameters for Selling Partner API authentication. | ||
| * | ||
| * Both `clientId` and `clientSecret` fall back to the `LWA_CLIENT_ID` and | ||
| * `LWA_CLIENT_SECRET` environment variables when omitted. | ||
| * `refreshToken` falls back to `LWA_REFRESH_TOKEN`. | ||
| */ | ||
| interface SellingPartnerAuthParameters { | ||
| /** LWA client identifier. Defaults to the `LWA_CLIENT_ID` environment variable. */ | ||
| clientId?: string; | ||
| /** LWA client secret. Defaults to the `LWA_CLIENT_SECRET` environment variable. */ | ||
| clientSecret?: string; | ||
| /** LWA refresh token. Defaults to the `LWA_REFRESH_TOKEN` environment variable. Mutually exclusive with `scopes`. */ | ||
| refreshToken?: string; | ||
| /** Authorization scopes for grantless operations. Mutually exclusive with `refreshToken`. */ | ||
| scopes?: AuthorizationScope[]; | ||
| } | ||
| /** | ||
| * Handles Login with Amazon (LWA) OAuth token management for the Selling Partner API. | ||
| * | ||
| * Supports both refresh-token and grantless (scope-based) authentication flows. | ||
| * Tokens are cached and automatically refreshed when expired. Concurrent calls | ||
| * to {@link getAccessToken} are deduplicated into a single request. | ||
| */ | ||
| declare class SellingPartnerApiAuth { | ||
| #private; | ||
| private readonly clientId; | ||
| private readonly clientSecret; | ||
| private readonly refreshToken?; | ||
| private readonly scopes?; | ||
| constructor(parameters: RequireExactlyOne<SellingPartnerAuthParameters, 'refreshToken' | 'scopes'>); | ||
| /** | ||
| * Returns a valid LWA access token, refreshing it if expired. | ||
| * | ||
| * Concurrent calls while a refresh is in progress share the same request. | ||
| * | ||
| * @returns The access token string. | ||
| */ | ||
| getAccessToken(): Promise<string>; | ||
| /** | ||
| * Expiration date of the currently cached access token, or `undefined` if no token has been fetched yet. | ||
| */ | ||
| protected get accessTokenExpiration(): Date | undefined; | ||
| } | ||
| export { AuthorizationScope, SellingPartnerApiAuth, SellingPartnerApiAuthError, type SellingPartnerAuthParameters }; |
| import { RequireExactlyOne } from 'type-fest'; | ||
| import { AxiosError } from 'axios'; | ||
| /** Authorization scopes for grantless Selling Partner API operations. */ | ||
| declare enum AuthorizationScope { | ||
| /** Scope for the Notifications API. */ | ||
| NOTIFICATIONS = "sellingpartnerapi::notifications", | ||
| /** Scope for rotating application client credentials. */ | ||
| CLIENT_CREDENTIAL_ROTATION = "sellingpartnerapi::client_credential:rotation" | ||
| } | ||
| interface BaseAccessTokenQuery { | ||
| client_id: string; | ||
| client_secret: string; | ||
| } | ||
| type RefreshTokenAccessTokenQuery = { | ||
| grant_type: 'refresh_token'; | ||
| refresh_token: string; | ||
| } & BaseAccessTokenQuery; | ||
| type ClientCredentialsAccessTokenQuery = { | ||
| grant_type: 'client_credentials'; | ||
| scope: string; | ||
| } & BaseAccessTokenQuery; | ||
| /** Request body for the LWA token endpoint. */ | ||
| type AccessTokenQuery = RefreshTokenAccessTokenQuery | ClientCredentialsAccessTokenQuery; | ||
| /** Response body from the LWA token endpoint. */ | ||
| interface AccessTokenData { | ||
| access_token: string; | ||
| refresh_token?: string; | ||
| token_type: string; | ||
| expires_in: number; | ||
| } | ||
| /** | ||
| * Error thrown when an LWA token request fails. | ||
| * | ||
| * Wraps the underlying Axios error with a human-readable message that includes | ||
| * the HTTP status code (or "No response" for network errors). | ||
| */ | ||
| declare class SellingPartnerApiAuthError extends AxiosError<AccessTokenData, AccessTokenQuery> { | ||
| /** The original error message from the failed HTTP request. */ | ||
| readonly innerMessage: string; | ||
| constructor(error: AxiosError<AccessTokenData, AccessTokenQuery>); | ||
| } | ||
| /** | ||
| * Configuration parameters for Selling Partner API authentication. | ||
| * | ||
| * Both `clientId` and `clientSecret` fall back to the `LWA_CLIENT_ID` and | ||
| * `LWA_CLIENT_SECRET` environment variables when omitted. | ||
| * `refreshToken` falls back to `LWA_REFRESH_TOKEN`. | ||
| */ | ||
| interface SellingPartnerAuthParameters { | ||
| /** LWA client identifier. Defaults to the `LWA_CLIENT_ID` environment variable. */ | ||
| clientId?: string; | ||
| /** LWA client secret. Defaults to the `LWA_CLIENT_SECRET` environment variable. */ | ||
| clientSecret?: string; | ||
| /** LWA refresh token. Defaults to the `LWA_REFRESH_TOKEN` environment variable. Mutually exclusive with `scopes`. */ | ||
| refreshToken?: string; | ||
| /** Authorization scopes for grantless operations. Mutually exclusive with `refreshToken`. */ | ||
| scopes?: AuthorizationScope[]; | ||
| } | ||
| /** | ||
| * Handles Login with Amazon (LWA) OAuth token management for the Selling Partner API. | ||
| * | ||
| * Supports both refresh-token and grantless (scope-based) authentication flows. | ||
| * Tokens are cached and automatically refreshed when expired. Concurrent calls | ||
| * to {@link getAccessToken} are deduplicated into a single request. | ||
| */ | ||
| declare class SellingPartnerApiAuth { | ||
| #private; | ||
| private readonly clientId; | ||
| private readonly clientSecret; | ||
| private readonly refreshToken?; | ||
| private readonly scopes?; | ||
| constructor(parameters: RequireExactlyOne<SellingPartnerAuthParameters, 'refreshToken' | 'scopes'>); | ||
| /** | ||
| * Returns a valid LWA access token, refreshing it if expired. | ||
| * | ||
| * Concurrent calls while a refresh is in progress share the same request. | ||
| * | ||
| * @returns The access token string. | ||
| */ | ||
| getAccessToken(): Promise<string>; | ||
| /** | ||
| * Expiration date of the currently cached access token, or `undefined` if no token has been fetched yet. | ||
| */ | ||
| protected get accessTokenExpiration(): Date | undefined; | ||
| } | ||
| export { AuthorizationScope, SellingPartnerApiAuth, SellingPartnerApiAuthError, type SellingPartnerAuthParameters }; |
+133
| // src/index.ts | ||
| import process from "process"; | ||
| import { AxiosError as AxiosError2 } from "axios"; | ||
| // src/error.ts | ||
| import { AxiosError } from "axios"; | ||
| var SellingPartnerApiAuthError = class extends AxiosError { | ||
| /** The original error message from the failed HTTP request. */ | ||
| innerMessage; | ||
| constructor(error) { | ||
| const message = error.response ? `access-token error: Response code ${error.response.status}` : "access-token error: No response"; | ||
| super(message, error.code, error.config, error.request, error.response); | ||
| this.innerMessage = error.message; | ||
| this.name = this.constructor.name; | ||
| } | ||
| }; | ||
| // src/utils/axios.ts | ||
| import globalAxios from "axios"; | ||
| // src/utils/package.ts | ||
| import { sync as readPackageJson } from "read-pkg-up"; | ||
| var result = readPackageJson(); | ||
| var packageJson = result?.packageJson ?? { | ||
| _id: "", | ||
| readme: "", | ||
| name: "@sp-api-sdk/auth", | ||
| version: "unknown" | ||
| }; | ||
| // src/utils/axios.ts | ||
| var axios = globalAxios.create({ | ||
| baseURL: "https://api.amazon.com/auth/", | ||
| timeout: 3e4, | ||
| headers: { | ||
| "user-agent": `${packageJson.name}/${packageJson.version}` | ||
| } | ||
| }); | ||
| // src/types/scope.ts | ||
| var AuthorizationScope = /* @__PURE__ */ ((AuthorizationScope2) => { | ||
| AuthorizationScope2["NOTIFICATIONS"] = "sellingpartnerapi::notifications"; | ||
| AuthorizationScope2["CLIENT_CREDENTIAL_ROTATION"] = "sellingpartnerapi::client_credential:rotation"; | ||
| return AuthorizationScope2; | ||
| })(AuthorizationScope || {}); | ||
| // src/index.ts | ||
| var SellingPartnerApiAuth = class { | ||
| clientId; | ||
| clientSecret; | ||
| refreshToken; | ||
| scopes; | ||
| #accessToken; | ||
| #accessTokenExpiration; | ||
| #pendingTokenRequest; | ||
| constructor(parameters) { | ||
| const clientId = parameters.clientId ?? process.env.LWA_CLIENT_ID; | ||
| const clientSecret = parameters.clientSecret ?? process.env.LWA_CLIENT_SECRET; | ||
| const refreshToken = parameters.refreshToken ?? process.env.LWA_REFRESH_TOKEN; | ||
| if (!clientId) { | ||
| throw new Error("Missing required `clientId` configuration value"); | ||
| } | ||
| if (!clientSecret) { | ||
| throw new Error("Missing required `clientSecret` configuration value"); | ||
| } | ||
| if (!refreshToken && !parameters.scopes) { | ||
| throw new TypeError("Either `refreshToken` or `scopes` must be specified"); | ||
| } | ||
| this.clientId = clientId; | ||
| this.clientSecret = clientSecret; | ||
| this.refreshToken = refreshToken; | ||
| this.scopes = parameters.scopes; | ||
| } | ||
| /** | ||
| * Returns a valid LWA access token, refreshing it if expired. | ||
| * | ||
| * Concurrent calls while a refresh is in progress share the same request. | ||
| * | ||
| * @returns The access token string. | ||
| */ | ||
| async getAccessToken() { | ||
| if (this.#accessToken && (!this.#accessTokenExpiration || Date.now() < this.#accessTokenExpiration.getTime())) { | ||
| return this.#accessToken; | ||
| } | ||
| if (this.#pendingTokenRequest) { | ||
| return this.#pendingTokenRequest; | ||
| } | ||
| this.#pendingTokenRequest = this.#refreshAccessToken(); | ||
| try { | ||
| return await this.#pendingTokenRequest; | ||
| } finally { | ||
| this.#pendingTokenRequest = void 0; | ||
| } | ||
| } | ||
| async #refreshAccessToken() { | ||
| const body = { | ||
| client_id: this.clientId, | ||
| client_secret: this.clientSecret, | ||
| ...this.refreshToken ? { | ||
| grant_type: "refresh_token", | ||
| refresh_token: this.refreshToken | ||
| } : { | ||
| grant_type: "client_credentials", | ||
| scope: this.scopes.join(" ") | ||
| } | ||
| }; | ||
| try { | ||
| const expiration = /* @__PURE__ */ new Date(); | ||
| const { data } = await axios.post("/o2/token", body); | ||
| expiration.setSeconds(expiration.getSeconds() + data.expires_in); | ||
| this.#accessToken = data.access_token; | ||
| this.#accessTokenExpiration = expiration; | ||
| return data.access_token; | ||
| } catch (error) { | ||
| if (error instanceof AxiosError2) { | ||
| throw new SellingPartnerApiAuthError(error); | ||
| } | ||
| throw error; | ||
| } | ||
| } | ||
| /** | ||
| * Expiration date of the currently cached access token, or `undefined` if no token has been fetched yet. | ||
| */ | ||
| get accessTokenExpiration() { | ||
| return this.#accessTokenExpiration; | ||
| } | ||
| }; | ||
| export { | ||
| AuthorizationScope, | ||
| SellingPartnerApiAuth, | ||
| SellingPartnerApiAuthError | ||
| }; | ||
| //# sourceMappingURL=index.js.map |
| {"version":3,"sources":["../src/index.ts","../src/error.ts","../src/utils/axios.ts","../src/utils/package.ts","../src/types/scope.ts"],"sourcesContent":["import process from 'node:process'\n\nimport {AxiosError} from 'axios'\nimport {type RequireExactlyOne} from 'type-fest'\n\nimport {SellingPartnerApiAuthError} from './error.js'\nimport {type AccessTokenData, type AccessTokenQuery} from './types/access-token.js'\nimport {type AuthorizationScope} from './types/scope.js'\nimport {axios} from './utils/axios.js'\n\n/**\n * Configuration parameters for Selling Partner API authentication.\n *\n * Both `clientId` and `clientSecret` fall back to the `LWA_CLIENT_ID` and\n * `LWA_CLIENT_SECRET` environment variables when omitted.\n * `refreshToken` falls back to `LWA_REFRESH_TOKEN`.\n */\nexport interface SellingPartnerAuthParameters {\n /** LWA client identifier. Defaults to the `LWA_CLIENT_ID` environment variable. */\n clientId?: string\n /** LWA client secret. Defaults to the `LWA_CLIENT_SECRET` environment variable. */\n clientSecret?: string\n /** LWA refresh token. Defaults to the `LWA_REFRESH_TOKEN` environment variable. Mutually exclusive with `scopes`. */\n refreshToken?: string\n /** Authorization scopes for grantless operations. Mutually exclusive with `refreshToken`. */\n scopes?: AuthorizationScope[]\n}\n\n/**\n * Handles Login with Amazon (LWA) OAuth token management for the Selling Partner API.\n *\n * Supports both refresh-token and grantless (scope-based) authentication flows.\n * Tokens are cached and automatically refreshed when expired. Concurrent calls\n * to {@link getAccessToken} are deduplicated into a single request.\n */\nexport class SellingPartnerApiAuth {\n private readonly clientId: string\n private readonly clientSecret: string\n private readonly refreshToken?: string\n private readonly scopes?: AuthorizationScope[]\n\n #accessToken?: string\n #accessTokenExpiration?: Date\n #pendingTokenRequest?: Promise<string>\n\n constructor(\n parameters: RequireExactlyOne<SellingPartnerAuthParameters, 'refreshToken' | 'scopes'>,\n ) {\n const clientId = parameters.clientId ?? process.env.LWA_CLIENT_ID\n const clientSecret = parameters.clientSecret ?? process.env.LWA_CLIENT_SECRET\n const refreshToken = parameters.refreshToken ?? process.env.LWA_REFRESH_TOKEN\n\n if (!clientId) {\n throw new Error('Missing required `clientId` configuration value')\n }\n\n if (!clientSecret) {\n throw new Error('Missing required `clientSecret` configuration value')\n }\n\n if (!refreshToken && !parameters.scopes) {\n throw new TypeError('Either `refreshToken` or `scopes` must be specified')\n }\n\n this.clientId = clientId\n this.clientSecret = clientSecret\n\n this.refreshToken = refreshToken\n this.scopes = parameters.scopes\n }\n\n /**\n * Returns a valid LWA access token, refreshing it if expired.\n *\n * Concurrent calls while a refresh is in progress share the same request.\n *\n * @returns The access token string.\n */\n async getAccessToken() {\n if (\n this.#accessToken &&\n (!this.#accessTokenExpiration || Date.now() < this.#accessTokenExpiration.getTime())\n ) {\n return this.#accessToken\n }\n\n // Deduplicate concurrent calls: share the same in-flight request\n if (this.#pendingTokenRequest) {\n return this.#pendingTokenRequest\n }\n\n this.#pendingTokenRequest = this.#refreshAccessToken()\n\n try {\n return await this.#pendingTokenRequest\n } finally {\n this.#pendingTokenRequest = undefined\n }\n }\n\n async #refreshAccessToken() {\n const body: AccessTokenQuery = {\n client_id: this.clientId,\n client_secret: this.clientSecret,\n ...(this.refreshToken\n ? {\n grant_type: 'refresh_token',\n refresh_token: this.refreshToken,\n }\n : {\n grant_type: 'client_credentials',\n scope: this.scopes!.join(' '),\n }),\n }\n\n try {\n const expiration = new Date()\n\n const {data} = await axios.post<AccessTokenData>('/o2/token', body)\n\n expiration.setSeconds(expiration.getSeconds() + data.expires_in)\n\n this.#accessToken = data.access_token\n this.#accessTokenExpiration = expiration\n\n return data.access_token\n } catch (error: unknown) {\n if (error instanceof AxiosError) {\n throw new SellingPartnerApiAuthError(error)\n }\n\n throw error\n }\n }\n\n /**\n * Expiration date of the currently cached access token, or `undefined` if no token has been fetched yet.\n */\n protected get accessTokenExpiration() {\n return this.#accessTokenExpiration\n }\n}\n\nexport {SellingPartnerApiAuthError} from './error.js'\nexport {AuthorizationScope} from './types/scope.js'\n","import {AxiosError} from 'axios'\n\nimport type {AccessTokenData, AccessTokenQuery} from './types/access-token.js'\n\n/**\n * Error thrown when an LWA token request fails.\n *\n * Wraps the underlying Axios error with a human-readable message that includes\n * the HTTP status code (or \"No response\" for network errors).\n */\nexport class SellingPartnerApiAuthError extends AxiosError<AccessTokenData, AccessTokenQuery> {\n /** The original error message from the failed HTTP request. */\n public readonly innerMessage: string\n\n constructor(error: AxiosError<AccessTokenData, AccessTokenQuery>) {\n const message = error.response\n ? `access-token error: Response code ${error.response.status}`\n : 'access-token error: No response'\n\n super(message, error.code, error.config, error.request, error.response)\n\n this.innerMessage = error.message\n this.name = this.constructor.name\n }\n}\n","import globalAxios from 'axios'\n\nimport {packageJson} from './package.js'\n\nexport const axios = globalAxios.create({\n baseURL: 'https://api.amazon.com/auth/',\n timeout: 30_000,\n headers: {\n 'user-agent': `${packageJson.name}/${packageJson.version}`,\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/auth',\n version: 'unknown',\n}\n","/** Authorization scopes for grantless Selling Partner API operations. */\nexport enum AuthorizationScope {\n /** Scope for the Notifications API. */\n NOTIFICATIONS = 'sellingpartnerapi::notifications',\n /** Scope for rotating application client credentials. */\n CLIENT_CREDENTIAL_ROTATION = 'sellingpartnerapi::client_credential:rotation',\n}\n"],"mappings":"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","names":["AxiosError","AuthorizationScope","AxiosError"]} |
+22
-11
@@ -5,19 +5,30 @@ { | ||
| "description": "Amazon Selling Partner API authentication package", | ||
| "version": "2.2.25", | ||
| "main": "dist/cjs/index.js", | ||
| "module": "dist/es/index.js", | ||
| "types": "dist/types/index.d.ts", | ||
| "version": "3.0.0", | ||
| "license": "MIT", | ||
| "type": "module", | ||
| "sideEffects": false, | ||
| "source": "./src/index.ts", | ||
| "main": "./dist/index.cjs", | ||
| "module": "./dist/index.js", | ||
| "types": "./dist/index.d.ts", | ||
| "exports": { | ||
| ".": { | ||
| "import": { | ||
| "types": "./dist/index.d.ts", | ||
| "default": "./dist/index.js" | ||
| }, | ||
| "require": { | ||
| "types": "./dist/index.d.cts", | ||
| "default": "./dist/index.cjs" | ||
| } | ||
| } | ||
| }, | ||
| "publishConfig": { | ||
| "access": "public" | ||
| }, | ||
| "directories": { | ||
| "lib": "dist" | ||
| }, | ||
| "files": [ | ||
| "dist/**/*.js", | ||
| "dist/**/*.d.ts" | ||
| "dist" | ||
| ], | ||
| "dependencies": { | ||
| "axios": "^1.15.2", | ||
| "axios": "^1.16.1", | ||
| "read-pkg-up": "^7.0.1" | ||
@@ -44,3 +55,3 @@ }, | ||
| ], | ||
| "gitHead": "cc3ed7e58346bf7a4110ed8f1353aae840f294e2" | ||
| "gitHead": "40177b741b5e9299d449d10c8e41a9a798aec593" | ||
| } |
+6
-6
@@ -23,6 +23,6 @@ # `@sp-api-sdk/auth` | ||
| // `clientId` and `clientSecret` default to the `LWA_CLIENT_ID` and | ||
| // `LWA_CLIENT_SECRET` environment variables. | ||
| const auth = new SellingPartnerApiAuth({ | ||
| clientId: process.env.LWA_CLIENT_ID, | ||
| clientSecret: process.env.LWA_CLIENT_SECRET, | ||
| refreshToken: "Atzr|…", | ||
| refreshToken: await getRefreshTokenForSeller(sellerId), | ||
| }); | ||
@@ -35,3 +35,3 @@ | ||
| These constructor options can be passed using environment variables: | ||
| The following constructor options default to environment variables when omitted. You can still pass them explicitly to override the defaults. | ||
@@ -53,5 +53,5 @@ | Property Name | Environment variable | | ||
| // `clientId` and `clientSecret` default to the `LWA_CLIENT_ID` and | ||
| // `LWA_CLIENT_SECRET` environment variables. | ||
| const auth = new SellingPartnerApiAuth({ | ||
| clientId: process.env.LWA_CLIENT_ID, | ||
| clientSecret: process.env.LWA_CLIENT_SECRET, | ||
| scopes: [AuthorizationScope.NOTIFICATIONS], | ||
@@ -58,0 +58,0 @@ }); |
| "use strict"; | ||
| Object.defineProperty(exports, "__esModule", { value: true }); | ||
| exports.SellingPartnerApiAuthError = void 0; | ||
| const axios_1 = require("axios"); | ||
| /** | ||
| * Error thrown when an LWA token request fails. | ||
| * | ||
| * Wraps the underlying Axios error with a human-readable message that includes | ||
| * the HTTP status code (or "No response" for network errors). | ||
| */ | ||
| class SellingPartnerApiAuthError extends axios_1.AxiosError { | ||
| /** The original error message from the failed HTTP request. */ | ||
| innerMessage; | ||
| constructor(error) { | ||
| const message = error.response | ||
| ? `access-token error: Response code ${error.response.status}` | ||
| : 'access-token error: No response'; | ||
| super(message, error.code, error.config, error.request, error.response); | ||
| this.innerMessage = error.message; | ||
| this.name = this.constructor.name; | ||
| } | ||
| } | ||
| exports.SellingPartnerApiAuthError = SellingPartnerApiAuthError; |
| "use strict"; | ||
| var __importDefault = (this && this.__importDefault) || function (mod) { | ||
| return (mod && mod.__esModule) ? mod : { "default": mod }; | ||
| }; | ||
| Object.defineProperty(exports, "__esModule", { value: true }); | ||
| exports.AuthorizationScope = exports.SellingPartnerApiAuthError = exports.SellingPartnerApiAuth = void 0; | ||
| const node_process_1 = __importDefault(require("node:process")); | ||
| const axios_1 = require("axios"); | ||
| const error_1 = require("./error"); | ||
| const axios_2 = require("./utils/axios"); | ||
| /** | ||
| * Handles Login with Amazon (LWA) OAuth token management for the Selling Partner API. | ||
| * | ||
| * Supports both refresh-token and grantless (scope-based) authentication flows. | ||
| * Tokens are cached and automatically refreshed when expired. Concurrent calls | ||
| * to {@link getAccessToken} are deduplicated into a single request. | ||
| */ | ||
| class SellingPartnerApiAuth { | ||
| clientId; | ||
| clientSecret; | ||
| refreshToken; | ||
| scopes; | ||
| #accessToken; | ||
| #accessTokenExpiration; | ||
| #pendingTokenRequest; | ||
| constructor(parameters) { | ||
| const clientId = parameters.clientId ?? node_process_1.default.env.LWA_CLIENT_ID; | ||
| const clientSecret = parameters.clientSecret ?? node_process_1.default.env.LWA_CLIENT_SECRET; | ||
| const refreshToken = parameters.refreshToken ?? node_process_1.default.env.LWA_REFRESH_TOKEN; | ||
| if (!clientId) { | ||
| throw new Error('Missing required `clientId` configuration value'); | ||
| } | ||
| if (!clientSecret) { | ||
| throw new Error('Missing required `clientSecret` configuration value'); | ||
| } | ||
| if (!refreshToken && !parameters.scopes) { | ||
| throw new TypeError('Either `refreshToken` or `scopes` must be specified'); | ||
| } | ||
| this.clientId = clientId; | ||
| this.clientSecret = clientSecret; | ||
| this.refreshToken = refreshToken; | ||
| this.scopes = parameters.scopes; | ||
| } | ||
| /** | ||
| * Returns a valid LWA access token, refreshing it if expired. | ||
| * | ||
| * Concurrent calls while a refresh is in progress share the same request. | ||
| * | ||
| * @returns The access token string. | ||
| */ | ||
| async getAccessToken() { | ||
| if (this.#accessToken && | ||
| (!this.#accessTokenExpiration || Date.now() < this.#accessTokenExpiration.getTime())) { | ||
| return this.#accessToken; | ||
| } | ||
| // Deduplicate concurrent calls: share the same in-flight request | ||
| if (this.#pendingTokenRequest) { | ||
| return this.#pendingTokenRequest; | ||
| } | ||
| this.#pendingTokenRequest = this.#refreshAccessToken(); | ||
| try { | ||
| return await this.#pendingTokenRequest; | ||
| } | ||
| finally { | ||
| this.#pendingTokenRequest = undefined; | ||
| } | ||
| } | ||
| async #refreshAccessToken() { | ||
| const body = { | ||
| client_id: this.clientId, | ||
| client_secret: this.clientSecret, | ||
| ...(this.refreshToken | ||
| ? { | ||
| grant_type: 'refresh_token', | ||
| refresh_token: this.refreshToken, | ||
| } | ||
| : { | ||
| grant_type: 'client_credentials', | ||
| scope: this.scopes.join(' '), | ||
| }), | ||
| }; | ||
| try { | ||
| const expiration = new Date(); | ||
| const { data } = await axios_2.axios.post('/o2/token', body); | ||
| expiration.setSeconds(expiration.getSeconds() + data.expires_in); | ||
| this.#accessToken = data.access_token; | ||
| this.#accessTokenExpiration = expiration; | ||
| return data.access_token; | ||
| } | ||
| catch (error) { | ||
| if (error instanceof axios_1.AxiosError) { | ||
| throw new error_1.SellingPartnerApiAuthError(error); | ||
| } | ||
| throw error; | ||
| } | ||
| } | ||
| /** | ||
| * Expiration date of the currently cached access token, or `undefined` if no token has been fetched yet. | ||
| */ | ||
| get accessTokenExpiration() { | ||
| return this.#accessTokenExpiration; | ||
| } | ||
| } | ||
| exports.SellingPartnerApiAuth = SellingPartnerApiAuth; | ||
| var error_2 = require("./error"); | ||
| Object.defineProperty(exports, "SellingPartnerApiAuthError", { enumerable: true, get: function () { return error_2.SellingPartnerApiAuthError; } }); | ||
| var scope_1 = require("./types/scope"); | ||
| Object.defineProperty(exports, "AuthorizationScope", { enumerable: true, get: function () { return scope_1.AuthorizationScope; } }); |
| "use strict"; | ||
| Object.defineProperty(exports, "__esModule", { value: true }); |
| "use strict"; | ||
| Object.defineProperty(exports, "__esModule", { value: true }); | ||
| exports.AuthorizationScope = void 0; | ||
| /** Authorization scopes for grantless Selling Partner API operations. */ | ||
| var AuthorizationScope; | ||
| (function (AuthorizationScope) { | ||
| /** Scope for the Notifications API. */ | ||
| AuthorizationScope["NOTIFICATIONS"] = "sellingpartnerapi::notifications"; | ||
| /** Scope for rotating application client credentials. */ | ||
| AuthorizationScope["CLIENT_CREDENTIAL_ROTATION"] = "sellingpartnerapi::client_credential:rotation"; | ||
| })(AuthorizationScope || (exports.AuthorizationScope = AuthorizationScope = {})); |
| "use strict"; | ||
| var __importDefault = (this && this.__importDefault) || function (mod) { | ||
| return (mod && mod.__esModule) ? mod : { "default": mod }; | ||
| }; | ||
| Object.defineProperty(exports, "__esModule", { value: true }); | ||
| exports.axios = void 0; | ||
| const axios_1 = __importDefault(require("axios")); | ||
| const package_1 = require("./package"); | ||
| exports.axios = axios_1.default.create({ | ||
| baseURL: 'https://api.amazon.com/auth/', | ||
| timeout: 30_000, | ||
| headers: { | ||
| 'user-agent': `${package_1.packageJson.name}/${package_1.packageJson.version}`, | ||
| }, | ||
| }); |
| "use strict"; | ||
| Object.defineProperty(exports, "__esModule", { value: true }); | ||
| exports.packageJson = void 0; | ||
| const read_pkg_up_1 = require("read-pkg-up"); | ||
| const result = (0, read_pkg_up_1.sync)(); | ||
| exports.packageJson = result?.packageJson ?? { | ||
| _id: '', | ||
| readme: '', | ||
| name: '@sp-api-sdk/auth', | ||
| version: 'unknown', | ||
| }; |
| import { AxiosError } from 'axios'; | ||
| /** | ||
| * Error thrown when an LWA token request fails. | ||
| * | ||
| * Wraps the underlying Axios error with a human-readable message that includes | ||
| * the HTTP status code (or "No response" for network errors). | ||
| */ | ||
| export class SellingPartnerApiAuthError extends AxiosError { | ||
| /** The original error message from the failed HTTP request. */ | ||
| innerMessage; | ||
| constructor(error) { | ||
| const message = error.response | ||
| ? `access-token error: Response code ${error.response.status}` | ||
| : 'access-token error: No response'; | ||
| super(message, error.code, error.config, error.request, error.response); | ||
| this.innerMessage = error.message; | ||
| this.name = this.constructor.name; | ||
| } | ||
| } |
| import process from 'node:process'; | ||
| import { AxiosError } from 'axios'; | ||
| import { SellingPartnerApiAuthError } from './error'; | ||
| import { axios } from './utils/axios'; | ||
| /** | ||
| * Handles Login with Amazon (LWA) OAuth token management for the Selling Partner API. | ||
| * | ||
| * Supports both refresh-token and grantless (scope-based) authentication flows. | ||
| * Tokens are cached and automatically refreshed when expired. Concurrent calls | ||
| * to {@link getAccessToken} are deduplicated into a single request. | ||
| */ | ||
| export class SellingPartnerApiAuth { | ||
| clientId; | ||
| clientSecret; | ||
| refreshToken; | ||
| scopes; | ||
| #accessToken; | ||
| #accessTokenExpiration; | ||
| #pendingTokenRequest; | ||
| constructor(parameters) { | ||
| const clientId = parameters.clientId ?? process.env.LWA_CLIENT_ID; | ||
| const clientSecret = parameters.clientSecret ?? process.env.LWA_CLIENT_SECRET; | ||
| const refreshToken = parameters.refreshToken ?? process.env.LWA_REFRESH_TOKEN; | ||
| if (!clientId) { | ||
| throw new Error('Missing required `clientId` configuration value'); | ||
| } | ||
| if (!clientSecret) { | ||
| throw new Error('Missing required `clientSecret` configuration value'); | ||
| } | ||
| if (!refreshToken && !parameters.scopes) { | ||
| throw new TypeError('Either `refreshToken` or `scopes` must be specified'); | ||
| } | ||
| this.clientId = clientId; | ||
| this.clientSecret = clientSecret; | ||
| this.refreshToken = refreshToken; | ||
| this.scopes = parameters.scopes; | ||
| } | ||
| /** | ||
| * Returns a valid LWA access token, refreshing it if expired. | ||
| * | ||
| * Concurrent calls while a refresh is in progress share the same request. | ||
| * | ||
| * @returns The access token string. | ||
| */ | ||
| async getAccessToken() { | ||
| if (this.#accessToken && | ||
| (!this.#accessTokenExpiration || Date.now() < this.#accessTokenExpiration.getTime())) { | ||
| return this.#accessToken; | ||
| } | ||
| // Deduplicate concurrent calls: share the same in-flight request | ||
| if (this.#pendingTokenRequest) { | ||
| return this.#pendingTokenRequest; | ||
| } | ||
| this.#pendingTokenRequest = this.#refreshAccessToken(); | ||
| try { | ||
| return await this.#pendingTokenRequest; | ||
| } | ||
| finally { | ||
| this.#pendingTokenRequest = undefined; | ||
| } | ||
| } | ||
| async #refreshAccessToken() { | ||
| const body = { | ||
| client_id: this.clientId, | ||
| client_secret: this.clientSecret, | ||
| ...(this.refreshToken | ||
| ? { | ||
| grant_type: 'refresh_token', | ||
| refresh_token: this.refreshToken, | ||
| } | ||
| : { | ||
| grant_type: 'client_credentials', | ||
| scope: this.scopes.join(' '), | ||
| }), | ||
| }; | ||
| try { | ||
| const expiration = new Date(); | ||
| const { data } = await axios.post('/o2/token', body); | ||
| expiration.setSeconds(expiration.getSeconds() + data.expires_in); | ||
| this.#accessToken = data.access_token; | ||
| this.#accessTokenExpiration = expiration; | ||
| return data.access_token; | ||
| } | ||
| catch (error) { | ||
| if (error instanceof AxiosError) { | ||
| throw new SellingPartnerApiAuthError(error); | ||
| } | ||
| throw error; | ||
| } | ||
| } | ||
| /** | ||
| * Expiration date of the currently cached access token, or `undefined` if no token has been fetched yet. | ||
| */ | ||
| get accessTokenExpiration() { | ||
| return this.#accessTokenExpiration; | ||
| } | ||
| } | ||
| export { SellingPartnerApiAuthError } from './error'; | ||
| export { AuthorizationScope } from './types/scope'; |
| export {}; |
| /** Authorization scopes for grantless Selling Partner API operations. */ | ||
| export var AuthorizationScope; | ||
| (function (AuthorizationScope) { | ||
| /** Scope for the Notifications API. */ | ||
| AuthorizationScope["NOTIFICATIONS"] = "sellingpartnerapi::notifications"; | ||
| /** Scope for rotating application client credentials. */ | ||
| AuthorizationScope["CLIENT_CREDENTIAL_ROTATION"] = "sellingpartnerapi::client_credential:rotation"; | ||
| })(AuthorizationScope || (AuthorizationScope = {})); |
| import globalAxios from 'axios'; | ||
| import { packageJson } from './package'; | ||
| export const axios = globalAxios.create({ | ||
| baseURL: 'https://api.amazon.com/auth/', | ||
| timeout: 30_000, | ||
| headers: { | ||
| 'user-agent': `${packageJson.name}/${packageJson.version}`, | ||
| }, | ||
| }); |
| import { sync as readPackageJson } from 'read-pkg-up'; | ||
| const result = readPackageJson(); | ||
| export const packageJson = result?.packageJson ?? { | ||
| _id: '', | ||
| readme: '', | ||
| name: '@sp-api-sdk/auth', | ||
| version: 'unknown', | ||
| }; |
| import { AxiosError } from 'axios'; | ||
| import type { AccessTokenData, AccessTokenQuery } from './types/access-token'; | ||
| /** | ||
| * Error thrown when an LWA token request fails. | ||
| * | ||
| * Wraps the underlying Axios error with a human-readable message that includes | ||
| * the HTTP status code (or "No response" for network errors). | ||
| */ | ||
| export declare class SellingPartnerApiAuthError extends AxiosError<AccessTokenData, AccessTokenQuery> { | ||
| /** The original error message from the failed HTTP request. */ | ||
| readonly innerMessage: string; | ||
| constructor(error: AxiosError<AccessTokenData, AccessTokenQuery>); | ||
| } |
| import { type RequireExactlyOne } from 'type-fest'; | ||
| import { type AuthorizationScope } from './types/scope'; | ||
| /** | ||
| * Configuration parameters for Selling Partner API authentication. | ||
| * | ||
| * Both `clientId` and `clientSecret` fall back to the `LWA_CLIENT_ID` and | ||
| * `LWA_CLIENT_SECRET` environment variables when omitted. | ||
| * `refreshToken` falls back to `LWA_REFRESH_TOKEN`. | ||
| */ | ||
| export interface SellingPartnerAuthParameters { | ||
| /** LWA client identifier. Defaults to the `LWA_CLIENT_ID` environment variable. */ | ||
| clientId?: string; | ||
| /** LWA client secret. Defaults to the `LWA_CLIENT_SECRET` environment variable. */ | ||
| clientSecret?: string; | ||
| /** LWA refresh token. Defaults to the `LWA_REFRESH_TOKEN` environment variable. Mutually exclusive with `scopes`. */ | ||
| refreshToken?: string; | ||
| /** Authorization scopes for grantless operations. Mutually exclusive with `refreshToken`. */ | ||
| scopes?: AuthorizationScope[]; | ||
| } | ||
| /** | ||
| * Handles Login with Amazon (LWA) OAuth token management for the Selling Partner API. | ||
| * | ||
| * Supports both refresh-token and grantless (scope-based) authentication flows. | ||
| * Tokens are cached and automatically refreshed when expired. Concurrent calls | ||
| * to {@link getAccessToken} are deduplicated into a single request. | ||
| */ | ||
| export declare class SellingPartnerApiAuth { | ||
| #private; | ||
| private readonly clientId; | ||
| private readonly clientSecret; | ||
| private readonly refreshToken?; | ||
| private readonly scopes?; | ||
| constructor(parameters: RequireExactlyOne<SellingPartnerAuthParameters, 'refreshToken' | 'scopes'>); | ||
| /** | ||
| * Returns a valid LWA access token, refreshing it if expired. | ||
| * | ||
| * Concurrent calls while a refresh is in progress share the same request. | ||
| * | ||
| * @returns The access token string. | ||
| */ | ||
| getAccessToken(): Promise<string>; | ||
| /** | ||
| * Expiration date of the currently cached access token, or `undefined` if no token has been fetched yet. | ||
| */ | ||
| protected get accessTokenExpiration(): Date | undefined; | ||
| } | ||
| export { SellingPartnerApiAuthError } from './error'; | ||
| export { AuthorizationScope } from './types/scope'; |
| interface BaseAccessTokenQuery { | ||
| client_id: string; | ||
| client_secret: string; | ||
| } | ||
| type RefreshTokenAccessTokenQuery = { | ||
| grant_type: 'refresh_token'; | ||
| refresh_token: string; | ||
| } & BaseAccessTokenQuery; | ||
| type ClientCredentialsAccessTokenQuery = { | ||
| grant_type: 'client_credentials'; | ||
| scope: string; | ||
| } & BaseAccessTokenQuery; | ||
| /** Request body for the LWA token endpoint. */ | ||
| export type AccessTokenQuery = RefreshTokenAccessTokenQuery | ClientCredentialsAccessTokenQuery; | ||
| /** Response body from the LWA token endpoint. */ | ||
| export interface AccessTokenData { | ||
| access_token: string; | ||
| refresh_token?: string; | ||
| token_type: string; | ||
| expires_in: number; | ||
| } | ||
| export {}; |
| /** Authorization scopes for grantless Selling Partner API operations. */ | ||
| export declare enum AuthorizationScope { | ||
| /** Scope for the Notifications API. */ | ||
| NOTIFICATIONS = "sellingpartnerapi::notifications", | ||
| /** Scope for rotating application client credentials. */ | ||
| CLIENT_CREDENTIAL_ROTATION = "sellingpartnerapi::client_credential:rotation" | ||
| } |
| import globalAxios from 'axios'; | ||
| export declare const axios: globalAxios.AxiosInstance; |
| import { type NormalizedPackageJson } from 'read-pkg-up'; | ||
| export declare const packageJson: NormalizedPackageJson; |
Major refactor
Supply chain riskPackage has recently undergone a major refactor. It may be unstable or indicate significant internal changes. Use caution when updating to versions that include significant changes.
Found 1 instance in 1 package
41432
88.22%Yes
NaN9
-57.14%374
-8.33%1
Infinity%Updated