@profplum700/etsy-v3-api-client
Version:
JavaScript/TypeScript client for the Etsy Open API v3 with OAuth 2.0 authentication
989 lines (978 loc) • 33.3 kB
JavaScript
'use strict';
Object.defineProperty(exports, '__esModule', { value: true });
class EtsyApiError extends Error {
constructor(message, _statusCode, _response) {
super(message);
this._statusCode = _statusCode;
this._response = _response;
this.name = 'EtsyApiError';
}
get statusCode() {
return this._statusCode;
}
get response() {
return this._response;
}
}
class EtsyAuthError extends Error {
constructor(message, _code) {
super(message);
this._code = _code;
this.name = 'EtsyAuthError';
}
get code() {
return this._code;
}
}
class EtsyRateLimitError extends Error {
constructor(message, _retryAfter) {
super(message);
this._retryAfter = _retryAfter;
this.name = 'EtsyRateLimitError';
}
get retryAfter() {
return this._retryAfter;
}
}
const isBrowser$1 = typeof window !== 'undefined' && typeof window.document !== 'undefined';
const isNode$1 = typeof process !== 'undefined' && !!process.versions?.node;
const isWebWorker = typeof globalThis.importScripts === 'function' && typeof navigator !== 'undefined';
const hasFetch = typeof fetch !== 'undefined';
const hasWebCrypto = typeof crypto !== 'undefined' && typeof crypto.subtle !== 'undefined';
const hasLocalStorage = (() => {
try {
return typeof localStorage !== 'undefined';
}
catch {
return false;
}
})();
const hasSessionStorage = (() => {
try {
return typeof sessionStorage !== 'undefined';
}
catch {
return false;
}
})();
function getEnvironmentInfo() {
return {
isBrowser: isBrowser$1,
isNode: Boolean(isNode$1),
isWebWorker,
hasFetch,
hasWebCrypto,
hasLocalStorage,
hasSessionStorage,
userAgent: isBrowser$1 ? navigator.userAgent : 'Node.js',
nodeVersion: isNode$1 ? process.version : undefined,
};
}
function assertFetchSupport() {
if (!hasFetch) {
throw new Error('Fetch API is not available. Please use Node.js 18+ or a modern browser.');
}
}
function getAvailableStorage() {
if (isNode$1) {
return 'file';
}
else if (hasLocalStorage) {
return 'localStorage';
}
else if (hasSessionStorage) {
return 'sessionStorage';
}
else {
return 'memory';
}
}
class MemoryTokenStorage {
constructor() {
this.tokens = null;
}
async save(tokens) {
this.tokens = { ...tokens };
}
async load() {
return this.tokens ? { ...this.tokens } : null;
}
async clear() {
this.tokens = null;
}
}
class TokenManager {
constructor(config, storage) {
this.currentTokens = null;
this.keystring = config.keystring;
this.refreshCallback = config.refreshSave;
this.storage = storage;
this.currentTokens = {
access_token: config.accessToken,
refresh_token: config.refreshToken,
expires_at: config.expiresAt,
token_type: 'Bearer',
scope: ''
};
}
async getAccessToken() {
if (!this.currentTokens) {
if (this.storage) {
this.currentTokens = await this.storage.load();
}
if (!this.currentTokens) {
throw new EtsyAuthError('No tokens available', 'NO_TOKENS');
}
}
const now = new Date();
const expiresAt = new Date(this.currentTokens.expires_at);
const bufferTime = 60 * 1000;
if (now.getTime() >= (expiresAt.getTime() - bufferTime)) {
await this.refreshToken();
}
return this.currentTokens.access_token;
}
async refreshToken() {
if (this.refreshPromise) {
return this.refreshPromise;
}
if (!this.currentTokens) {
throw new EtsyAuthError('No tokens available to refresh', 'NO_REFRESH_TOKEN');
}
this.refreshPromise = this.performTokenRefresh();
try {
const newTokens = await this.refreshPromise;
this.currentTokens = newTokens;
if (this.storage) {
await this.storage.save(newTokens);
}
if (this.refreshCallback) {
this.refreshCallback(newTokens.access_token, newTokens.refresh_token, newTokens.expires_at);
}
return newTokens;
}
finally {
this.refreshPromise = undefined;
}
}
async performTokenRefresh() {
if (!this.currentTokens) {
throw new EtsyAuthError('No tokens available', 'NO_TOKENS');
}
const body = new URLSearchParams({
grant_type: 'refresh_token',
client_id: this.keystring,
refresh_token: this.currentTokens.refresh_token
});
try {
const response = await this.fetch('https://api.etsy.com/v3/public/oauth/token', {
method: 'POST',
headers: {
'Content-Type': 'application/x-www-form-urlencoded',
'Accept': 'application/json'
},
body: body.toString()
});
if (!response.ok) {
const errorText = await response.text();
throw new EtsyAuthError(`Token refresh failed: ${response.status} ${response.statusText} - ${errorText}`, 'TOKEN_REFRESH_FAILED');
}
const tokenResponse = await response.json();
return {
access_token: tokenResponse.access_token,
refresh_token: tokenResponse.refresh_token,
expires_at: new Date(Date.now() + (tokenResponse.expires_in * 1000)),
token_type: tokenResponse.token_type,
scope: tokenResponse.scope
};
}
catch (_error) {
if (_error instanceof EtsyAuthError) {
throw _error;
}
throw new EtsyAuthError(`Token refresh failed: ${_error instanceof Error ? _error.message : 'Unknown error'}`, 'TOKEN_REFRESH_ERROR');
}
}
getCurrentTokens() {
return this.currentTokens ? { ...this.currentTokens } : null;
}
updateTokens(tokens) {
this.currentTokens = { ...tokens };
}
isTokenExpired() {
if (!this.currentTokens) {
return true;
}
const now = new Date();
const expiresAt = new Date(this.currentTokens.expires_at);
return now.getTime() >= expiresAt.getTime();
}
willTokenExpireSoon(minutes = 5) {
if (!this.currentTokens) {
return true;
}
const now = new Date();
const expiresAt = new Date(this.currentTokens.expires_at);
const bufferTime = minutes * 60 * 1000;
return now.getTime() >= (expiresAt.getTime() - bufferTime);
}
async clearTokens() {
this.currentTokens = null;
if (this.storage) {
await this.storage.clear();
}
}
getTimeUntilExpiration() {
if (!this.currentTokens) {
return null;
}
const now = new Date();
const expiresAt = new Date(this.currentTokens.expires_at);
return expiresAt.getTime() - now.getTime();
}
async fetch(url, options) {
assertFetchSupport();
return fetch(url, options);
}
}
function createDefaultTokenStorage(options) {
if (isNode$1) {
return new FileTokenStorage(options?.filePath || './etsy-tokens.json');
}
else if (options?.preferSession && hasSessionStorage) {
return new SessionStorageTokenStorage(options?.storageKey);
}
else if (hasLocalStorage) {
return new LocalStorageTokenStorage(options?.storageKey);
}
else if (hasSessionStorage) {
return new SessionStorageTokenStorage(options?.storageKey);
}
else {
return new MemoryTokenStorage();
}
}
class LocalStorageTokenStorage {
constructor(storageKey = 'etsy_tokens') {
if (!hasLocalStorage) {
throw new Error('localStorage is not available in this environment');
}
this.storageKey = storageKey;
}
async save(tokens) {
const data = JSON.stringify(tokens);
localStorage.setItem(this.storageKey, data);
}
async load() {
try {
const data = localStorage.getItem(this.storageKey);
if (!data)
return null;
const tokens = JSON.parse(data);
if (tokens.expires_at) {
tokens.expires_at = new Date(tokens.expires_at);
}
return tokens;
}
catch {
return null;
}
}
async clear() {
localStorage.removeItem(this.storageKey);
}
}
class SessionStorageTokenStorage {
constructor(storageKey = 'etsy_tokens') {
if (!hasSessionStorage) {
throw new Error('sessionStorage is not available in this environment');
}
this.storageKey = storageKey;
}
async save(tokens) {
const data = JSON.stringify(tokens);
sessionStorage.setItem(this.storageKey, data);
}
async load() {
try {
const data = sessionStorage.getItem(this.storageKey);
if (!data)
return null;
const tokens = JSON.parse(data);
if (tokens.expires_at) {
tokens.expires_at = new Date(tokens.expires_at);
}
return tokens;
}
catch {
return null;
}
}
async clear() {
sessionStorage.removeItem(this.storageKey);
}
}
class FileTokenStorage {
constructor(filePath) {
if (!isNode$1) {
throw new Error('FileTokenStorage is only available in Node.js environments');
}
this.filePath = filePath;
}
async save(tokens) {
if (!isNode$1) {
throw new Error('FileTokenStorage is only available in Node.js');
}
try {
const data = JSON.stringify(tokens, null, 2);
await this._writeFile(this.filePath, data);
}
catch {
throw new Error('Failed to save tokens to file');
}
}
async load() {
if (!isNode$1) {
return null;
}
try {
const data = await this._readFile(this.filePath);
const tokens = JSON.parse(data);
if (tokens.expires_at) {
tokens.expires_at = new Date(tokens.expires_at);
}
return tokens;
}
catch {
return null;
}
}
async clear() {
if (!isNode$1) {
return;
}
try {
await this._deleteFile(this.filePath);
}
catch {
}
}
async _writeFile(filePath, data) {
if (typeof process === 'undefined')
return;
const fs = await import('fs');
await fs.promises.writeFile(filePath, data, 'utf8');
}
async _readFile(filePath) {
if (typeof process === 'undefined')
throw new Error('Not available');
const fs = await import('fs');
return await fs.promises.readFile(filePath, 'utf8');
}
async _deleteFile(filePath) {
if (typeof process === 'undefined')
return;
const fs = await import('fs');
await fs.promises.unlink(filePath);
}
}
class EtsyRateLimiter {
constructor(config) {
this.requestCount = 0;
this.dailyReset = new Date();
this.lastRequestTime = 0;
this.config = {
maxRequestsPerDay: 10000,
maxRequestsPerSecond: 10,
minRequestInterval: 100,
...config
};
this.setNextDailyReset();
}
setNextDailyReset() {
const now = new Date();
this.dailyReset = new Date(now);
this.dailyReset.setUTCDate(this.dailyReset.getUTCDate() + 1);
this.dailyReset.setUTCHours(0, 0, 0, 0);
}
async waitForRateLimit() {
const now = Date.now();
if (now >= this.dailyReset.getTime()) {
this.requestCount = 0;
this.setNextDailyReset();
}
if (this.requestCount >= this.config.maxRequestsPerDay) {
const timeUntilReset = this.dailyReset.getTime() - now;
throw new EtsyRateLimitError(`Daily rate limit of ${this.config.maxRequestsPerDay} requests exceeded. Reset in ${Math.ceil(timeUntilReset / 1000 / 60)} minutes.`, timeUntilReset);
}
const timeSinceLastRequest = now - this.lastRequestTime;
if (timeSinceLastRequest < this.config.minRequestInterval) {
const waitTime = this.config.minRequestInterval - timeSinceLastRequest;
await new Promise(resolve => setTimeout(resolve, waitTime));
}
this.requestCount++;
this.lastRequestTime = Date.now();
}
getRateLimitStatus() {
const now = Date.now();
if (now >= this.dailyReset.getTime()) {
this.requestCount = 0;
this.setNextDailyReset();
}
return {
remainingRequests: Math.max(0, this.config.maxRequestsPerDay - this.requestCount),
resetTime: this.dailyReset,
canMakeRequest: this.requestCount < this.config.maxRequestsPerDay &&
(now - this.lastRequestTime) >= this.config.minRequestInterval
};
}
getRemainingRequests() {
return Math.max(0, this.config.maxRequestsPerDay - this.requestCount);
}
reset() {
this.requestCount = 0;
this.lastRequestTime = 0;
this.setNextDailyReset();
}
canMakeRequest() {
const now = Date.now();
if (now >= this.dailyReset.getTime()) {
this.requestCount = 0;
this.setNextDailyReset();
}
if (this.requestCount >= this.config.maxRequestsPerDay) {
return false;
}
return (now - this.lastRequestTime) >= this.config.minRequestInterval;
}
getTimeUntilNextRequest() {
const now = Date.now();
const timeSinceLastRequest = now - this.lastRequestTime;
if (timeSinceLastRequest >= this.config.minRequestInterval) {
return 0;
}
return this.config.minRequestInterval - timeSinceLastRequest;
}
getConfig() {
return { ...this.config };
}
}
const defaultRateLimiter = new EtsyRateLimiter();
class DefaultLogger {
debug(message, ...args) {
const isDevelopment = isNode$1
? process.env.NODE_ENV === 'development'
: window.location?.hostname === 'localhost' || window.location?.hostname === '127.0.0.1';
if (isDevelopment) {
console.log(`[DEBUG] ${message}`, ...args);
}
}
info(message, ...args) {
console.log(`[INFO] ${message}`, ...args);
}
warn(message, ...args) {
console.warn(`[WARN] ${message}`, ...args);
}
error(message, ...args) {
console.error(`[ERROR] ${message}`, ...args);
}
}
class MemoryCache {
constructor() {
this.cache = new Map();
}
async get(key) {
const entry = this.cache.get(key);
if (!entry)
return null;
if (Date.now() > entry.expires) {
this.cache.delete(key);
return null;
}
return entry.value;
}
async set(key, value, ttl = 3600) {
const expires = Date.now() + (ttl * 1000);
this.cache.set(key, { value, expires });
}
async delete(key) {
this.cache.delete(key);
}
async clear() {
this.cache.clear();
}
}
class EtsyClient {
constructor(config) {
this.tokenManager = new TokenManager(config);
this.baseUrl = config.baseUrl || 'https://api.etsy.com/v3/application';
this.logger = new DefaultLogger();
this.keystring = config.keystring;
if (config.rateLimiting?.enabled !== false) {
this.rateLimiter = new EtsyRateLimiter({
maxRequestsPerDay: config.rateLimiting?.maxRequestsPerDay || 10000,
maxRequestsPerSecond: config.rateLimiting?.maxRequestsPerSecond || 10,
minRequestInterval: config.rateLimiting?.minRequestInterval ?? 100
});
}
else {
this.rateLimiter = new EtsyRateLimiter(undefined);
}
if (config.caching?.enabled !== false) {
this.cache = config.caching?.storage || new MemoryCache();
this.cacheTtl = config.caching?.ttl || 3600;
}
}
async makeRequest(endpoint, options = {}, useCache = true) {
const url = `${this.baseUrl}${endpoint}`;
const requestOptions = {
method: 'GET',
...options
};
const cacheKey = `${url}:${JSON.stringify(requestOptions)}`;
if (useCache && this.cache && requestOptions.method === 'GET') {
const cached = await this.cache.get(cacheKey);
if (cached) {
return JSON.parse(cached);
}
}
await this.rateLimiter.waitForRateLimit();
const accessToken = await this.tokenManager.getAccessToken();
const headers = {
'Authorization': `Bearer ${accessToken}`,
'x-api-key': this.getApiKey(),
'Content-Type': 'application/json',
'Accept': 'application/json',
...requestOptions.headers
};
try {
const response = await this.fetch(url, {
...requestOptions,
headers
});
if (!response.ok) {
const errorText = await response.text();
throw new EtsyApiError(`Etsy API error: ${response.status} ${response.statusText}`, response.status, errorText);
}
const data = await response.json();
if (useCache && this.cache && requestOptions.method === 'GET') {
await this.cache.set(cacheKey, JSON.stringify(data), this.cacheTtl);
}
return data;
}
catch (error) {
if (error instanceof EtsyApiError || error instanceof EtsyAuthError) {
throw error;
}
throw new EtsyApiError(`Request failed: ${error instanceof Error ? error.message : 'Unknown error'}`, 0, error);
}
}
getApiKey() {
return this.keystring;
}
async getUser() {
return this.makeRequest('/users/me');
}
async getShop(shopId) {
if (shopId) {
return this.makeRequest(`/shops/${shopId}`);
}
const user = await this.getUser();
if (!user.shop_id) {
throw new EtsyApiError('User does not have a shop', 404);
}
return this.makeRequest(`/shops/${user.shop_id}`);
}
async getShopByOwnerUserId(userId) {
return this.makeRequest(`/users/${userId}/shops`);
}
async getShopSections(shopId) {
let targetShopId = shopId;
if (!targetShopId) {
const user = await this.getUser();
if (!user.shop_id) {
throw new EtsyApiError('User does not have a shop', 404);
}
targetShopId = user.shop_id.toString();
}
const response = await this.makeRequest(`/shops/${targetShopId}/sections`);
this.logger.info(`Found ${response.results.length} shop sections`);
return response.results;
}
async getShopSection(shopId, sectionId) {
return this.makeRequest(`/shops/${shopId}/sections/${sectionId}`);
}
async getListingsByShop(shopId, params = {}) {
let targetShopId = shopId;
if (!targetShopId) {
const user = await this.getUser();
if (!user.shop_id) {
throw new EtsyApiError('User does not have a shop', 404);
}
targetShopId = user.shop_id.toString();
}
const searchParams = new URLSearchParams();
searchParams.set('state', params.state || 'active');
if (params.limit !== undefined)
searchParams.set('limit', params.limit.toString());
if (params.offset !== undefined)
searchParams.set('offset', params.offset.toString());
if (params.sort_on)
searchParams.set('sort_on', params.sort_on);
if (params.sort_order)
searchParams.set('sort_order', params.sort_order);
if (params.includes)
searchParams.set('includes', params.includes.join(','));
const response = await this.makeRequest(`/shops/${targetShopId}/listings?${searchParams.toString()}`);
return response.results;
}
async getListing(listingId, includes) {
const params = includes ? `?includes=${includes.join(',')}` : '';
return this.makeRequest(`/listings/${listingId}${params}`);
}
async findAllListingsActive(params = {}) {
const searchParams = new URLSearchParams();
if (params.keywords)
searchParams.set('keywords', params.keywords);
if (params.category)
searchParams.set('category', params.category);
if (params.limit !== undefined)
searchParams.set('limit', params.limit.toString());
if (params.offset !== undefined)
searchParams.set('offset', params.offset.toString());
if (params.sort_on)
searchParams.set('sort_on', params.sort_on);
if (params.sort_order)
searchParams.set('sort_order', params.sort_order);
if (params.min_price !== undefined)
searchParams.set('min_price', params.min_price.toString());
if (params.max_price !== undefined)
searchParams.set('max_price', params.max_price.toString());
if (params.tags)
searchParams.set('tags', params.tags.join(','));
if (params.location)
searchParams.set('location', params.location);
if (params.shop_location)
searchParams.set('shop_location', params.shop_location);
const response = await this.makeRequest(`/listings/active?${searchParams.toString()}`);
return response.results;
}
async getListingImages(listingId) {
const response = await this.makeRequest(`/listings/${listingId}/images`);
return response.results;
}
async getListingInventory(listingId) {
return this.makeRequest(`/listings/${listingId}/inventory`);
}
async getSellerTaxonomyNodes() {
const response = await this.makeRequest('/seller-taxonomy/nodes');
return response.results;
}
async getUserShops() {
const response = await this.makeRequest('/users/me/shops');
return response.results || [];
}
getRemainingRequests() {
return this.rateLimiter.getRemainingRequests();
}
getRateLimitStatus() {
return this.rateLimiter.getRateLimitStatus();
}
async clearCache() {
if (this.cache) {
await this.cache.clear();
}
}
getCurrentTokens() {
return this.tokenManager.getCurrentTokens();
}
isTokenExpired() {
return this.tokenManager.isTokenExpired();
}
async refreshToken() {
return this.tokenManager.refreshToken();
}
async fetch(url, options) {
assertFetchSupport();
return fetch(url, options);
}
}
const isBrowser = typeof window !== 'undefined';
const isNode = typeof process !== 'undefined' && process.versions?.node;
async function generateRandomBytes(length) {
if (isBrowser) {
const array = new Uint8Array(length);
crypto.getRandomValues(array);
return array;
}
else if (isNode) {
try {
const crypto = await import('crypto');
return new Uint8Array(crypto.randomBytes(length));
}
catch {
throw new Error('Node.js crypto module not available');
}
}
else {
throw new Error('Crypto functions are not available in this environment');
}
}
async function generateRandomBase64Url(length) {
const bytes = await generateRandomBytes(length);
return base64UrlEncode(bytes);
}
async function sha256(data) {
const encoder = new TextEncoder();
const dataBytes = typeof data === 'string' ? encoder.encode(data) : data;
if (isBrowser) {
const hashBuffer = await crypto.subtle.digest('SHA-256', dataBytes);
return new Uint8Array(hashBuffer);
}
else if (isNode) {
try {
const crypto = await import('crypto');
const hash = crypto.createHash('sha256');
hash.update(dataBytes);
return new Uint8Array(hash.digest());
}
catch {
throw new Error('Node.js crypto module not available');
}
}
else {
throw new Error('SHA256 is not available in this environment');
}
}
async function sha256Base64Url(data) {
const hash = await sha256(data);
return base64UrlEncode(hash);
}
function base64UrlEncode(bytes) {
if (isBrowser) {
const binaryString = String.fromCharCode(...bytes);
const base64 = btoa(binaryString);
return base64.replace(/\+/g, '-').replace(/\//g, '_').replace(/=/g, '');
}
else if (isNode) {
const base64 = Buffer.from(bytes).toString('base64');
return base64.replace(/\+/g, '-').replace(/\//g, '_').replace(/=/g, '');
}
else {
throw new Error('Base64URL encoding is not available in this environment');
}
}
async function generateCodeVerifier() {
return generateRandomBase64Url(32);
}
async function generateState() {
return generateRandomBase64Url(32);
}
async function createCodeChallenge(codeVerifier) {
return sha256Base64Url(codeVerifier);
}
class AuthHelper {
constructor(config) {
this.keystring = config.keystring;
this.redirectUri = config.redirectUri;
this.scopes = config.scopes;
this.codeVerifier = config.codeVerifier || '';
this.state = config.state || '';
this.initialized = this.initialize(config);
}
async initialize(config) {
if (!config.codeVerifier) {
this.codeVerifier = await generateCodeVerifier();
}
if (!config.state) {
this.state = await generateState();
}
}
async getAuthUrl() {
await this.initialized;
const codeChallenge = await createCodeChallenge(this.codeVerifier);
const params = new URLSearchParams({
response_type: 'code',
client_id: this.keystring,
redirect_uri: this.redirectUri,
scope: this.scopes.join(' '),
state: this.state,
code_challenge: codeChallenge,
code_challenge_method: 'S256'
});
return `https://www.etsy.com/oauth/connect?${params.toString()}`;
}
async setAuthorizationCode(code, state) {
await this.initialized;
if (state !== this.state) {
throw new EtsyAuthError('State parameter mismatch', 'INVALID_STATE');
}
this.authorizationCode = code;
this.receivedState = state;
}
async getAccessToken() {
if (!this.authorizationCode) {
throw new EtsyAuthError('Authorization code not set. Call setAuthorizationCode() first.', 'NO_AUTH_CODE');
}
const body = new URLSearchParams({
grant_type: 'authorization_code',
client_id: this.keystring,
redirect_uri: this.redirectUri,
code: this.authorizationCode,
code_verifier: this.codeVerifier
});
try {
assertFetchSupport();
const response = await fetch('https://api.etsy.com/v3/public/oauth/token', {
method: 'POST',
headers: {
'Content-Type': 'application/x-www-form-urlencoded',
'Accept': 'application/json'
},
body: body.toString()
});
if (!response.ok) {
const errorText = await response.text();
throw new EtsyAuthError(`Token exchange failed: ${response.status} ${response.statusText} - ${errorText}`, 'TOKEN_EXCHANGE_FAILED');
}
const tokenResponse = await response.json();
return {
access_token: tokenResponse.access_token,
refresh_token: tokenResponse.refresh_token,
expires_at: new Date(Date.now() + (tokenResponse.expires_in * 1000)),
token_type: tokenResponse.token_type,
scope: tokenResponse.scope
};
}
catch (error) {
if (error instanceof EtsyAuthError) {
throw error;
}
throw new EtsyAuthError(`Token exchange failed: ${error instanceof Error ? error.message : 'Unknown error'}`, 'TOKEN_EXCHANGE_ERROR');
}
}
async getState() {
await this.initialized;
return this.state;
}
async getCodeVerifier() {
await this.initialized;
return this.codeVerifier;
}
getScopes() {
return [...this.scopes];
}
getRedirectUri() {
return this.redirectUri;
}
}
const ETSY_SCOPES = {
LISTINGS_READ: 'listings_r',
SHOPS_READ: 'shops_r',
PROFILE_READ: 'profile_r',
FAVORITES_READ: 'favorites_r',
FEEDBACK_READ: 'feedback_r',
TREASURY_READ: 'treasury_r',
LISTINGS_WRITE: 'listings_w',
SHOPS_WRITE: 'shops_w',
PROFILE_WRITE: 'profile_w',
FAVORITES_WRITE: 'favorites_w',
FEEDBACK_WRITE: 'feedback_w',
TREASURY_WRITE: 'treasury_w',
LISTINGS_DELETE: 'listings_d',
SHOPS_DELETE: 'shops_d',
PROFILE_DELETE: 'profile_d',
FAVORITES_DELETE: 'favorites_d',
FEEDBACK_DELETE: 'feedback_d',
TREASURY_DELETE: 'treasury_d',
TRANSACTIONS_READ: 'transactions_r',
TRANSACTIONS_WRITE: 'transactions_w',
BILLING_READ: 'billing_r',
CART_READ: 'cart_r',
CART_WRITE: 'cart_w',
RECOMMEND_READ: 'recommend_r',
RECOMMEND_WRITE: 'recommend_w',
ADDRESS_READ: 'address_r',
ADDRESS_WRITE: 'address_w',
EMAIL_READ: 'email_r'
};
const COMMON_SCOPE_COMBINATIONS = {
SHOP_READ_ONLY: [
ETSY_SCOPES.SHOPS_READ,
ETSY_SCOPES.LISTINGS_READ,
ETSY_SCOPES.PROFILE_READ
],
SHOP_MANAGEMENT: [
ETSY_SCOPES.SHOPS_READ,
ETSY_SCOPES.SHOPS_WRITE,
ETSY_SCOPES.LISTINGS_READ,
ETSY_SCOPES.LISTINGS_WRITE,
ETSY_SCOPES.LISTINGS_DELETE,
ETSY_SCOPES.PROFILE_READ,
ETSY_SCOPES.TRANSACTIONS_READ
],
BASIC_ACCESS: [
ETSY_SCOPES.SHOPS_READ,
ETSY_SCOPES.LISTINGS_READ
]
};
function createEtsyClient(config) {
return new EtsyClient(config);
}
function createAuthHelper(config) {
return new AuthHelper(config);
}
function createTokenManager(config, storage) {
return new TokenManager(config, storage);
}
function createRateLimiter(config) {
return new EtsyRateLimiter(config);
}
const VERSION = '1.0.2';
const LIBRARY_NAME = 'etsy-v3-api-client';
function getLibraryInfo() {
return {
name: LIBRARY_NAME,
version: VERSION,
description: 'JavaScript/TypeScript client for the Etsy Open API v3 with OAuth 2.0 authentication',
author: 'profplum700',
license: 'MIT',
homepage: 'https://github.com/ForestHillArtsHouse/etsy-v3-api-client#readme'
};
}
exports.AuthHelper = AuthHelper;
exports.COMMON_SCOPE_COMBINATIONS = COMMON_SCOPE_COMBINATIONS;
exports.ETSY_SCOPES = ETSY_SCOPES;
exports.EtsyApiError = EtsyApiError;
exports.EtsyAuthError = EtsyAuthError;
exports.EtsyClient = EtsyClient;
exports.EtsyRateLimitError = EtsyRateLimitError;
exports.EtsyRateLimiter = EtsyRateLimiter;
exports.FileTokenStorage = FileTokenStorage;
exports.LIBRARY_NAME = LIBRARY_NAME;
exports.LocalStorageTokenStorage = LocalStorageTokenStorage;
exports.MemoryTokenStorage = MemoryTokenStorage;
exports.SessionStorageTokenStorage = SessionStorageTokenStorage;
exports.TokenManager = TokenManager;
exports.VERSION = VERSION;
exports.createAuthHelper = createAuthHelper;
exports.createCodeChallenge = createCodeChallenge;
exports.createDefaultTokenStorage = createDefaultTokenStorage;
exports.createEtsyClient = createEtsyClient;
exports.createRateLimiter = createRateLimiter;
exports.createTokenManager = createTokenManager;
exports.default = EtsyClient;
exports.defaultRateLimiter = defaultRateLimiter;
exports.generateCodeVerifier = generateCodeVerifier;
exports.generateRandomBase64Url = generateRandomBase64Url;
exports.generateState = generateState;
exports.getAvailableStorage = getAvailableStorage;
exports.getEnvironmentInfo = getEnvironmentInfo;
exports.getLibraryInfo = getLibraryInfo;
exports.hasLocalStorage = hasLocalStorage;
exports.hasSessionStorage = hasSessionStorage;
exports.isBrowser = isBrowser$1;
exports.isNode = isNode$1;
exports.sha256 = sha256;
exports.sha256Base64Url = sha256Base64Url;
//# sourceMappingURL=node.cjs.map