@profplum700/etsy-v3-api-client
Version:
JavaScript/TypeScript client for the Etsy Open API v3 with OAuth 2.0 authentication
1 lines • 81.6 kB
JavaScript
!function(e,t){"object"==typeof exports&&"undefined"!=typeof module?t(exports):"function"==typeof define&&define.amd?define(["exports"],t):t((e="undefined"!=typeof globalThis?globalThis:e||self).EtsyApiClient={})}(this,function(e){"use strict";class t extends Error{constructor(e,t,s,i,r){if(super(e),this._statusCode=t,this._response=s,this._retryAfter=i,this.name="EtsyApiError",this.endpoint=r,this.timestamp=new Date,this.details={statusCode:t||0,retryAfter:i,endpoint:r,timestamp:this.timestamp},s&&"object"==typeof s){const e=s;this.details.errorCode=e.error_code||e.code,this.details.field=e.field,this.details.suggestion=e.suggestion||e.message,Array.isArray(e.errors)&&(this.details.validationErrors=e.errors.map(e=>{if(e&&"object"==typeof e){const t=e;return{field:String(t.field||"unknown"),message:String(t.message||"Validation error")}}return{field:"unknown",message:String(e)}}))}this.suggestions=this.generateSuggestions(),this.docsUrl=this.generateDocsUrl()}get statusCode(){return this._statusCode}get response(){return this._response}isRetryable(){if(!this._statusCode)return!1;if(429===this._statusCode)return!0;if(this._statusCode>=500&&this._statusCode<600)return!0;return!![408,409,423,425].includes(this._statusCode)}getRetryAfter(){return this._retryAfter||null}getRateLimitReset(){return 429===this._statusCode&&this._retryAfter?new Date(Date.now()+1e3*this._retryAfter):null}generateSuggestions(){const e=[];if(!this._statusCode)return["Check your network connection and try again"];switch(this._statusCode){case 400:e.push("Review the Etsy API documentation for this endpoint"),e.push("Check all required parameters are provided"),e.push("Validate parameter formats and types"),this.details.validationErrors&&this.details.validationErrors.length>0&&(e.push("\nValidation errors:"),this.details.validationErrors.forEach(t=>{e.push(` • ${t.field}: ${t.message}`)})),this.details.field&&e.push(`Field causing issue: ${this.details.field}`);break;case 401:e.push("Verify your access token is valid and not expired"),e.push("Check if you need to refresh the token"),e.push("Ensure you completed the OAuth flow correctly"),this.endpoint?.includes("/shops/")&&e.push("Verify the shop_id matches the authenticated user");break;case 403:e.push("Check if your OAuth app has the required scopes:"),this.endpoint?.includes("/listings")&&(e.push(" • listings_r (for reading listings)"),e.push(" • listings_w (for creating/updating listings)")),(this.endpoint?.includes("/receipts")||this.endpoint?.includes("/transactions"))&&e.push(" • transactions_r (for reading orders)"),this.endpoint?.includes("/shops")&&(e.push(" • shops_r (for reading shop data)"),e.push(" • shops_w (for updating shop data)")),e.push("Verify your app is approved for production access"),e.push("Check if the resource belongs to the authenticated user");break;case 404:e.push("Verify the resource ID exists and is spelled correctly"),this.endpoint?.includes("/listings/")&&(e.push("Check if the listing is active and not deleted"),e.push("Ensure the listing belongs to the authenticated shop")),this.endpoint?.includes("/shops/")&&e.push("Verify the shop ID is correct"),this.endpoint?.includes("/receipts/")&&(e.push("Check if the receipt ID is valid"),e.push("Ensure you have access to this shop's receipts"));break;case 409:e.push("Resource state conflict detected"),e.push("Check if the resource was modified by another process"),e.push("Try fetching the latest resource state before updating");break;case 429:{const t=this.getRateLimitReset(),s=t?t.toLocaleTimeString():"shortly";e.push(`Rate limit exceeded. Resets at ${s}`),e.push("Implement exponential backoff retry logic"),e.push("Consider caching responses to reduce API calls"),e.push("Check if you can batch multiple operations"),this._retryAfter&&e.push(`Wait ${this._retryAfter} seconds before retrying`);break}case 500:case 502:case 503:case 504:e.push("This is an Etsy server error, not your code"),e.push("Retry the request after a short delay (exponential backoff)"),e.push("Check Etsy API status: https://status.etsy.com"),this.isRetryable()&&e.push("This error is retryable - the request can be safely retried");break;default:e.push("Check the Etsy API documentation for this endpoint"),e.push("Review your request parameters and format"),this.details.suggestion&&e.push(`Etsy suggestion: ${this.details.suggestion}`)}return e}generateDocsUrl(){return`https://github.com/profplum700/etsy-v3-api-client/blob/main/docs/troubleshooting/ERROR_CODES.md#${this.details.errorCode?.toLowerCase()||this._statusCode?.toString()||"unknown"}`}getUserFriendlyMessage(){let e=this.message;if(this.details.suggestion&&(e+=`\nSuggestion: ${this.details.suggestion}`),this.isRetryable()){const t=this.getRetryAfter();e+=t?`\nRetry after ${t} seconds.`:"\nThis error can be retried."}return e}toString(){const e=[`EtsyApiError: ${this.message}`,`Status Code: ${this._statusCode||"Unknown"}`];return this.details.errorCode&&e.push(`Error Code: ${this.details.errorCode}`),this.endpoint&&e.push(`Endpoint: ${this.endpoint}`),e.push(`Timestamp: ${this.timestamp.toISOString()}`),this.suggestions.length>0&&(e.push("\nSuggestions:"),this.suggestions.forEach(t=>{t.startsWith(" •")?e.push(t):e.push(` • ${t}`)})),e.push(`\nDocumentation: ${this.docsUrl}`),e.join("\n")}toJSON(){return{name:this.name,message:this.message,statusCode:this._statusCode,errorCode:this.details.errorCode,endpoint:this.endpoint,suggestions:this.suggestions,docsUrl:this.docsUrl,timestamp:this.timestamp.toISOString(),details:this.details,isRetryable:this.isRetryable()}}}class s extends Error{constructor(e,t){super(e),this._code=t,this.name="EtsyAuthError"}get code(){return this._code}}class i extends Error{constructor(e,t,s="unknown"){super(e),this._retryAfter=t,this.name="EtsyRateLimitError",this.errorType=s}get retryAfter(){return this._retryAfter}isRetryable(){return"qpd_exhausted"!==this.errorType}}const r="undefined"!=typeof window&&void 0!==window.document,n=!1,a="function"==typeof globalThis.importScripts&&"undefined"!=typeof navigator,o="undefined"!=typeof fetch,c="undefined"!=typeof crypto&&void 0!==crypto.subtle,h=(()=>{try{return"undefined"!=typeof localStorage}catch{return!1}})(),l=(()=>{try{return"undefined"!=typeof sessionStorage}catch{return!1}})();function u(){if(!o)throw new Error("Fetch API is not available. Please use Node.js 18+ or a modern browser.")}class d{constructor(){this.tokens=null}async save(e){this.tokens={...e}}async load(){return this.tokens?{...this.tokens}:null}async clear(){this.tokens=null}}class g{constructor(e,t,s){this.currentTokens=null,this.keystring=e.keystring,this.refreshCallback=e.refreshSave,this.storage=t,this.rotationConfig=s,this.currentTokens={access_token:e.accessToken,refresh_token:e.refreshToken,expires_at:e.expiresAt,token_type:"Bearer",scope:""},this.rotationConfig?.enabled&&this.rotationConfig?.autoSchedule&&this.startRotationScheduler()}async getAccessToken(){if(!this.currentTokens&&(this.storage&&(this.currentTokens=await this.storage.load()),!this.currentTokens))throw new s("No tokens available","NO_TOKENS");const e=new Date,t=new Date(this.currentTokens.expires_at);return e.getTime()>=t.getTime()-6e4&&await this.refreshToken(),this.currentTokens.access_token}async refreshToken(){if(this.refreshPromise)return this.refreshPromise;if(!this.currentTokens)throw new s("No tokens available to refresh","NO_REFRESH_TOKEN");this.refreshPromise=this.performTokenRefresh();try{const e=await this.refreshPromise;return this.currentTokens=e,this.storage&&await this.storage.save(e),this.refreshCallback&&this.refreshCallback(e.access_token,e.refresh_token,e.expires_at),e}finally{this.refreshPromise=void 0}}async performTokenRefresh(){if(!this.currentTokens)throw new s("No tokens available","NO_TOKENS");const e=new URLSearchParams({grant_type:"refresh_token",client_id:this.keystring,refresh_token:this.currentTokens.refresh_token});try{const t=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:e.toString()});if(!t.ok)throw new s(`Token refresh failed: ${t.status} ${t.statusText}`,"TOKEN_REFRESH_FAILED");const i=await t.json();return{access_token:i.access_token,refresh_token:i.refresh_token,expires_at:new Date(Date.now()+1e3*i.expires_in),token_type:i.token_type,scope:i.scope}}catch(e){if(e instanceof s)throw e;throw new s(`Token refresh failed: ${e instanceof Error?e.message:"Unknown error"}`,"TOKEN_REFRESH_ERROR")}}getCurrentTokens(){return this.currentTokens?{...this.currentTokens}:null}updateTokens(e){this.currentTokens={...e}}isTokenExpired(){if(!this.currentTokens)return!0;const e=new Date,t=new Date(this.currentTokens.expires_at);return e.getTime()>=t.getTime()}willTokenExpireSoon(e=5){if(!this.currentTokens)return!0;const t=new Date,s=new Date(this.currentTokens.expires_at),i=60*e*1e3;return t.getTime()>=s.getTime()-i}async clearTokens(){this.currentTokens=null,this.storage&&await this.storage.clear()}getTimeUntilExpiration(){if(!this.currentTokens)return null;const e=new Date;return new Date(this.currentTokens.expires_at).getTime()-e.getTime()}needsProactiveRotation(){if(!this.rotationConfig?.enabled||!this.currentTokens)return!1;const e=this.getTimeUntilExpiration();if(null===e)return!1;return e<=(this.rotationConfig.rotateBeforeExpiry||9e5)}async rotateToken(){if(!this.currentTokens)throw new s("No tokens available to rotate","NO_TOKENS");const e={...this.currentTokens},t=await this.refreshToken();if(this.rotationConfig?.onRotation)try{await Promise.resolve(this.rotationConfig.onRotation(e,t))}catch(e){console.error("Token rotation callback failed:",e)}return t}startRotationScheduler(){if(!this.rotationConfig?.enabled)throw new Error("Token rotation is not enabled");this.stopRotationScheduler();const e=this.rotationConfig.checkInterval||6e4;this.rotationTimer=setInterval(async()=>{try{this.needsProactiveRotation()&&(console.log("Proactively rotating token before expiration"),await this.rotateToken())}catch(e){console.error("Failed to proactively rotate token:",e)}},e),this.rotationTimer.unref&&this.rotationTimer.unref()}stopRotationScheduler(){this.rotationTimer&&(clearInterval(this.rotationTimer),this.rotationTimer=void 0)}updateRotationConfig(e){const t=this.rotationConfig?.autoSchedule;this.rotationConfig=e,e.enabled&&e.autoSchedule&&!t?this.startRotationScheduler():e.enabled&&e.autoSchedule||this.stopRotationScheduler()}getRotationConfig(){return this.rotationConfig?{...this.rotationConfig}:void 0}async fetch(e,t){return u(),fetch(e,t)}}class p{constructor(e="etsy_tokens"){if(!h)throw new Error("localStorage is not available in this environment");this.storageKey=e}async save(e){const t=JSON.stringify(e);localStorage.setItem(this.storageKey,t)}async load(){try{const e=localStorage.getItem(this.storageKey);if(!e)return null;const t=JSON.parse(e);return t.expires_at&&(t.expires_at=new Date(t.expires_at)),t}catch{return null}}async clear(){localStorage.removeItem(this.storageKey)}}class m{constructor(e="etsy_tokens"){if(!l)throw new Error("sessionStorage is not available in this environment");this.storageKey=e}async save(e){const t=JSON.stringify(e);sessionStorage.setItem(this.storageKey,t)}async load(){try{const e=sessionStorage.getItem(this.storageKey);if(!e)return null;const t=JSON.parse(e);return t.expires_at&&(t.expires_at=new Date(t.expires_at)),t}catch{return null}}async clear(){sessionStorage.removeItem(this.storageKey)}}const y={MAX_REQUESTS_PER_DAY:5e3,MAX_REQUESTS_PER_SECOND:5,MIN_REQUEST_INTERVAL:200};class f{constructor(e){this.requestCount=0,this.dailyReset=new Date,this.lastRequestTime=0,this.isHeaderBasedLimiting=!1,this.currentRetryCount=0,this.config={maxRequestsPerDay:y.MAX_REQUESTS_PER_DAY,maxRequestsPerSecond:y.MAX_REQUESTS_PER_SECOND,minRequestInterval:y.MIN_REQUEST_INTERVAL,maxRetries:3,baseDelayMs:1e3,maxDelayMs:3e4,jitter:.1,qpdWarningThreshold:80,onApproachingLimit:void 0,...e},this.setNextDailyReset()}setNextDailyReset(){const e=new Date;this.dailyReset=new Date(e),this.dailyReset.setUTCDate(this.dailyReset.getUTCDate()+1),this.dailyReset.setUTCHours(0,0,0,0)}updateFromHeaders(e){if(!e)return;const t=this.parseRateLimitHeaders(e);void 0!==t.limitPerSecond&&(this.headerLimitPerSecond=t.limitPerSecond,this.isHeaderBasedLimiting=!0),void 0!==t.remainingThisSecond&&(this.headerRemainingThisSecond=t.remainingThisSecond),void 0!==t.limitPerDay&&(this.headerLimitPerDay=t.limitPerDay,this.isHeaderBasedLimiting=!0),void 0!==t.remainingToday&&(this.headerRemainingToday=t.remainingToday,this.checkApproachingLimit())}parseRateLimitHeaders(e){const t=t=>{if(e instanceof Headers)return e.get(t);const s=t.toLowerCase();for(const t of Object.keys(e))if(t.toLowerCase()===s)return e[t]??null;return null},s=e=>{if(null===e)return;const t=parseInt(e,10);return Number.isNaN(t)?void 0:t};return{limitPerSecond:s(t("x-limit-per-second")),remainingThisSecond:s(t("x-remaining-this-second")),limitPerDay:s(t("x-limit-per-day")),remainingToday:s(t("x-remaining-today")),retryAfter:s(t("retry-after"))}}checkApproachingLimit(){if(!this.config.onApproachingLimit)return;const e=this.headerLimitPerDay??this.config.maxRequestsPerDay,t=this.headerRemainingToday??this.getRemainingRequests(),s=(e-t)/e*100;s>=this.config.qpdWarningThreshold&&this.config.onApproachingLimit(t,e,s)}async handleRateLimitResponse(e){const t=e?this.parseRateLimitHeaders(e):{};if(this.updateFromHeaders(e),0===this.headerRemainingToday)throw new i("Daily rate limit exhausted. No requests remaining until limit resets.",t.retryAfter,"qpd_exhausted");if(this.currentRetryCount++,this.currentRetryCount>this.config.maxRetries)throw this.currentRetryCount=0,new i(`Max retries (${this.config.maxRetries}) exceeded for rate limit`,t.retryAfter,"qps_exhausted");return{shouldRetry:!0,delayMs:this.calculateBackoffDelay(this.currentRetryCount,t.retryAfter)}}calculateBackoffDelay(e,t){const s=t?1e3*t:0,i=this.config.baseDelayMs*Math.pow(2,e-1);let r=Math.min(i,this.config.maxDelayMs);if(r=Math.max(r,s),this.config.jitter>0){const e=r*this.config.jitter;r+=Math.random()*e*2-e}return Math.max(0,Math.floor(r))}resetRetryCount(){this.currentRetryCount=0}setApproachingLimitCallback(e){this.config.onApproachingLimit=e}setWarningThreshold(e){this.config.qpdWarningThreshold=e}getEffectiveMinInterval(){return void 0!==this.headerLimitPerSecond&&this.headerLimitPerSecond>0?Math.ceil(1e3/this.headerLimitPerSecond):this.config.minRequestInterval}async waitForRateLimit(){const e=Date.now();e>=this.dailyReset.getTime()&&(this.requestCount=0,this.setNextDailyReset());const t=this.headerLimitPerDay??this.config.maxRequestsPerDay;if((this.headerRemainingToday??t-this.requestCount)<=0){const s=this.dailyReset.getTime()-e;throw new i(`Daily rate limit exhausted (${t} requests). Reset in approximately ${Math.ceil(s/1e3/60)} minutes.`,Math.ceil(s/1e3),"qpd_exhausted")}const s=this.getEffectiveMinInterval(),r=e-this.lastRequestTime;if(r<s){const e=s-r;await new Promise(t=>setTimeout(t,e))}this.requestCount++,this.lastRequestTime=Date.now()}getRateLimitStatus(){const e=Date.now();e>=this.dailyReset.getTime()&&(this.requestCount=0,this.setNextDailyReset());const t=this.headerRemainingToday??Math.max(0,this.config.maxRequestsPerDay-this.requestCount);return{remainingRequests:t,resetTime:this.dailyReset,canMakeRequest:t>0&&e-this.lastRequestTime>=this.getEffectiveMinInterval(),isFromHeaders:this.isHeaderBasedLimiting,limitPerSecond:this.headerLimitPerSecond,remainingThisSecond:this.headerRemainingThisSecond,limitPerDay:this.headerLimitPerDay}}getRemainingRequests(){return this.headerRemainingToday??Math.max(0,this.config.maxRequestsPerDay-this.requestCount)}reset(){this.requestCount=0,this.lastRequestTime=0,this.currentRetryCount=0,this.headerLimitPerSecond=void 0,this.headerRemainingThisSecond=void 0,this.headerLimitPerDay=void 0,this.headerRemainingToday=void 0,this.isHeaderBasedLimiting=!1,this.setNextDailyReset()}canMakeRequest(){const e=Date.now();e>=this.dailyReset.getTime()&&(this.requestCount=0,this.setNextDailyReset());return!((this.headerRemainingToday??this.config.maxRequestsPerDay-this.requestCount)<=0)&&e-this.lastRequestTime>=this.getEffectiveMinInterval()}getTimeUntilNextRequest(){const e=Date.now()-this.lastRequestTime,t=this.getEffectiveMinInterval();return e>=t?0:t-e}getConfig(){return{...this.config}}}const w=new f;class S{constructor(e={}){this.concurrency=e.concurrency??5,this.stopOnError=e.stopOnError??!1,this.onProgress=e.onProgress,this.onItemComplete=e.onItemComplete,this.onItemError=e.onItemError}async executeBulk(e,t,s){const i=Date.now(),r=[],n=[];let a=0,o=0,c=0;const h=e.map((e,t)=>({item:e,index:t,id:s?s(e,t):t})),l=[];for(let s=0;s<Math.min(this.concurrency,e.length);s++)l.push(this.worker(h,t,r,n,()=>{a++;const t=r[r.length-1];t?.success?o++:c++,this.onProgress&&this.onProgress(a,e.length,t)}));await Promise.all(l);const u=Date.now()-i;return{total:e.length,successful:o,failed:c,results:r,errors:n,duration:u}}async worker(e,t,s,i,r){for(;e.length>0;){const n=e.shift();if(!n)break;const{item:a,index:o,id:c}=n;try{const e={success:!0,data:await t(a,o),id:c,index:o};s.push(e),this.onItemComplete&&this.onItemComplete(e),r()}catch(t){const n=t instanceof Error?t:new Error(String(t)),a={success:!1,error:n,id:c,index:o};s.push(a);const h={id:c,index:o,error:n};if(i.push(h),this.onItemError&&this.onItemError(h),r(),this.stopOnError){e.length=0;break}}}}setConcurrency(e){this.concurrency=Math.max(1,e)}getConcurrency(){return this.concurrency}}class R{constructor(){this.validators=[]}rule(e){return this.validators.push(e),this}validate(e){const t=[];for(const s of this.validators){const i=s(e);i&&t.push(i)}return{valid:0===t.length,errors:t}}}class v{constructor(e){this.field=e}required(e){return t=>{if("object"!=typeof t||null===t)return null;const s=t[this.field];return null==s||""===s?{field:this.field,message:e||`${this.field} is required`,value:s}:null}}string(e){return t=>{if("object"!=typeof t||null===t)return null;const s=t[this.field];return null==s?null:"string"!=typeof s?{field:this.field,message:e.message||`${this.field} must be a string`,value:s}:void 0!==e.min&&s.length<e.min?{field:this.field,message:e.message||`${this.field} must be at least ${e.min} characters`,value:s}:void 0!==e.max&&s.length>e.max?{field:this.field,message:e.message||`${this.field} must be at most ${e.max} characters`,value:s}:e.pattern&&!e.pattern.test(s)?{field:this.field,message:e.message||`${this.field} has invalid format`,value:s}:null}}number(e){return t=>{if("object"!=typeof t||null===t)return null;const s=t[this.field];return null==s?null:"number"!=typeof s||Number.isNaN(s)?{field:this.field,message:e.message||`${this.field} must be a number`,value:s}:e.integer&&!Number.isInteger(s)?{field:this.field,message:e.message||`${this.field} must be an integer`,value:s}:e.positive&&s<=0?{field:this.field,message:e.message||`${this.field} must be positive`,value:s}:void 0!==e.min&&s<e.min?{field:this.field,message:e.message||`${this.field} must be at least ${e.min}`,value:s}:void 0!==e.max&&s>e.max?{field:this.field,message:e.message||`${this.field} must be at most ${e.max}`,value:s}:null}}enum(e,t){return s=>{if("object"!=typeof s||null===s)return null;const i=s[this.field];return null==i||e.includes(i)?null:{field:this.field,message:t||`${this.field} must be one of: ${e.join(", ")}`,value:i}}}array(e){return t=>{if("object"!=typeof t||null===t)return null;const s=t[this.field];if(null==s)return null;if(!Array.isArray(s))return{field:this.field,message:e.message||`${this.field} must be an array`,value:s};if(void 0!==e.min&&s.length<e.min)return{field:this.field,message:e.message||`${this.field} must have at least ${e.min} items`,value:s};if(void 0!==e.max&&s.length>e.max)return{field:this.field,message:e.message||`${this.field} must have at most ${e.max} items`,value:s};if(e.itemValidator)for(let t=0;t<s.length;t++)if(!e.itemValidator(s[t]))return{field:this.field,message:e.message||`${this.field}[${t}] has invalid value`,value:s[t]};return null}}}function _(e){return new v(e)}const k=(new R).rule(_("quantity").required()).rule(_("quantity").number({min:1,integer:!0,message:"quantity must be a positive integer"})).rule(_("title").required()).rule(_("title").string({min:1,max:140,message:"title must be 1-140 characters"})).rule(_("description").string({max:65535,message:"description must be less than 65535 characters"})).rule(_("price").required()).rule(_("price").number({min:.2,max:5e4,message:"price must be between 0.20 and 50000.00"})).rule(_("who_made").enum(["i_did","someone_else","collective"],"who_made must be one of: i_did, someone_else, collective")).rule(_("when_made").enum(["made_to_order","2020_2024","2010_2019","2005_2009","2000_2004","1990s","1980s","1970s","1960s","1950s","1940s","1930s","1920s","1910s","1900s","1800s","1700s","before_1700"])).rule(_("taxonomy_id").required()).rule(_("taxonomy_id").number({integer:!0,positive:!0,message:"taxonomy_id must be a positive integer"})),E=(new R).rule(e=>"object"==typeof e&&null!==e&&"title"in e&&void 0!==e.title?_("title").string({min:1,max:140,message:"title must be 1-140 characters"})(e):null).rule(e=>"object"==typeof e&&null!==e&&"description"in e&&void 0!==e.description?_("description").string({max:65535,message:"description must be less than 65535 characters"})(e):null).rule(e=>void 0!==e.tags?_("tags").array({max:13,message:"tags must have at most 13 items"})(e):null).rule(e=>void 0!==e.materials?_("materials").array({max:13,message:"materials must have at most 13 items"})(e):null),T=(new R).rule(e=>"object"==typeof e&&null!==e&&"title"in e&&void 0!==e.title?_("title").string({min:1,max:55,message:"shop title must be 1-55 characters"})(e):null).rule(e=>"object"==typeof e&&null!==e&&"announcement"in e&&void 0!==e.announcement?_("announcement").string({max:5e3,message:"announcement must be less than 5000 characters"})(e):null);class $ extends Error{constructor(e,t){super(e),this.name="ValidationException",this.errors=t}}function x(e,t,s="Validation failed"){const i=t.validate(e);if(!i.valid)throw new $(s,i.errors)}class b{debug(e,...t){let s;{const e=window.location?.hostname;s="localhost"===e||"127.0.0.1"===e}s&&console.log(`[DEBUG] ${e}`,...t)}info(e,...t){console.log(`[INFO] ${e}`,...t)}warn(e,...t){console.warn(`[WARN] ${e}`,...t)}error(e,...t){console.error(`[ERROR] ${e}`,...t)}}class P{constructor(){this.cache=new Map}async get(e){const t=this.cache.get(e);return t?Date.now()>t.expires?(this.cache.delete(e),null):t.value:null}async set(e,t,s=3600){const i=Date.now()+1e3*s;this.cache.set(e,{value:t,expires:i})}async delete(e){this.cache.delete(e)}async clear(){this.cache.clear()}}class L{constructor(e){if(!e.sharedSecret)throw new s("sharedSecret is REQUIRED for Etsy API v3 application usage. See: https://github.com/profplum700/etsy-v3-api-client/issues/21");this.tokenManager=new g(e),this.baseUrl=e.baseUrl||"https://api.etsy.com/v3/application",this.logger=new b,this.keystring=e.keystring,this.sharedSecret=e.sharedSecret,!1!==e.rateLimiting?.enabled?this.rateLimiter=new f({maxRequestsPerDay:e.rateLimiting?.maxRequestsPerDay||y.MAX_REQUESTS_PER_DAY,maxRequestsPerSecond:e.rateLimiting?.maxRequestsPerSecond||y.MAX_REQUESTS_PER_SECOND,minRequestInterval:e.rateLimiting?.minRequestInterval??y.MIN_REQUEST_INTERVAL,maxRetries:e.rateLimiting?.maxRetries,baseDelayMs:e.rateLimiting?.baseDelayMs,maxDelayMs:e.rateLimiting?.maxDelayMs,jitter:e.rateLimiting?.jitter,qpdWarningThreshold:e.rateLimiting?.qpdWarningThreshold,onApproachingLimit:e.rateLimiting?.onApproachingLimit}):this.rateLimiter=new f(void 0),!1!==e.caching?.enabled&&(this.cache=e.caching?.storage||new P,this.cacheTtl=e.caching?.ttl||3600),this.bulkOperationManager=new S({concurrency:5,stopOnError:!1})}async makeRequest(e,t={},s=!0){const i=`${this.baseUrl}${e}`,r={method:"GET",...t},n=`${i}:${JSON.stringify(r)}`;if(s&&this.cache&&"GET"===r.method){const e=await this.cache.get(n);if(e)try{return JSON.parse(e)}catch{await this.cache.delete(n)}}await this.rateLimiter.waitForRateLimit();const a={Authorization:`Bearer ${await this.tokenManager.getAccessToken()}`,"x-api-key":this.getApiKey(),"Content-Type":"application/json",Accept:"application/json",...r.headers};return this.executeWithRetry(i,{...r,headers:a},n,s)}async executeWithRetry(e,r,n,a){for(;;)try{const s=await this.fetch(e,r);if(429===s.status){const{shouldRetry:e,delayMs:t}=await this.rateLimiter.handleRateLimitResponse(s.headers);if(e){this.logger.warn(`Rate limited. Retrying in ${t}ms...`),await this.sleep(t);continue}}if(!s.ok){const e=await s.text();throw new t(`Etsy API error: ${s.status} ${s.statusText}`,s.status,e)}if(this.rateLimiter.updateFromHeaders(s.headers),this.rateLimiter.resetRetryCount(),204===s.status)return;const i=s.headers?.get?.("content-length");if("0"===i)return;const o=await s.json();return a&&this.cache&&"GET"===r.method&&await this.cache.set(n,JSON.stringify(o),this.cacheTtl),o}catch(e){if(e instanceof i)throw e;if(e instanceof t||e instanceof s)throw e;throw new t(`Request failed: ${e instanceof Error?e.message:"Unknown error"}`,0,e)}}sleep(e){return new Promise(t=>setTimeout(t,e))}buildFormBody(e){const t=new URLSearchParams;for(const[s,i]of Object.entries(e))null!=i&&(Array.isArray(i)?t.append(s,i.filter(e=>null!=e).map(String).join(",")):t.append(s,String(i)));return t}getApiKey(){return`${this.keystring}:${this.sharedSecret}`}async getUser(){return this.makeRequest("/users/me")}async getShop(e){if(e)return this.makeRequest(`/shops/${e}`);const s=await this.getUser();if(!s.shop_id)throw new t("User does not have a shop",404);return this.makeRequest(`/shops/${s.shop_id}`)}async getShopByOwnerUserId(e){return this.makeRequest(`/users/${e}/shops`)}async getShopSections(e){let s=e;if(!s){const e=await this.getUser();if(!e.shop_id)throw new t("User does not have a shop",404);s=e.shop_id.toString()}const i=await this.makeRequest(`/shops/${s}/sections`);return this.logger.info(`Found ${i.results.length} shop sections`),i.results}async getShopSection(e,t){return this.makeRequest(`/shops/${e}/sections/${t}`)}async getListingsByShop(e,s={}){let i=e;if(!i){const e=await this.getUser();if(!e.shop_id)throw new t("User does not have a shop",404);i=e.shop_id.toString()}const r=new URLSearchParams;r.set("state",s.state||"active"),void 0!==s.limit&&r.set("limit",s.limit.toString()),void 0!==s.offset&&r.set("offset",s.offset.toString()),s.sort_on&&r.set("sort_on",s.sort_on),s.sort_order&&r.set("sort_order",s.sort_order),s.includes&&r.set("includes",s.includes.join(",")),void 0!==s.legacy&&r.set("legacy",s.legacy.toString());return(await this.makeRequest(`/shops/${i}/listings?${r.toString()}`)).results}async getListing(e,t){const s=Array.isArray(t)?{includes:t}:t,i=new URLSearchParams;s?.includes&&i.set("includes",s.includes.join(",")),s?.language&&i.set("language",s.language),void 0!==s?.legacy&&i.set("legacy",s.legacy.toString()),void 0!==s?.allow_suggested_title&&i.set("allow_suggested_title",s.allow_suggested_title.toString());const r=i.toString(),n=r?`?${r}`:"";return this.makeRequest(`/listings/${e}${n}`)}async findAllListingsActive(e={}){const t=new URLSearchParams;e.keywords&&t.set("keywords",e.keywords),void 0!==e.limit&&t.set("limit",e.limit.toString()),void 0!==e.offset&&t.set("offset",e.offset.toString()),e.sort_on&&t.set("sort_on",e.sort_on),e.sort_order&&t.set("sort_order",e.sort_order),void 0!==e.min_price&&t.set("min_price",e.min_price.toString()),void 0!==e.max_price&&t.set("max_price",e.max_price.toString()),void 0!==e.taxonomy_id&&t.set("taxonomy_id",e.taxonomy_id.toString()),e.shop_location&&t.set("shop_location",e.shop_location),void 0!==e.legacy&&t.set("legacy",e.legacy.toString());return(await this.makeRequest(`/listings/active?${t.toString()}`)).results}async getListingImages(e){return(await this.makeRequest(`/listings/${e}/images`)).results}async getListingInventory(e,t={}){const s=new URLSearchParams;void 0!==t.show_deleted&&s.set("show_deleted",t.show_deleted.toString()),t.includes&&s.set("includes",t.includes),void 0!==t.legacy&&s.set("legacy",t.legacy.toString());const i=s.toString(),r=i?`?${i}`:"";return this.makeRequest(`/listings/${e}/inventory${r}`)}async getReviewsByListing(e,t={}){const s=new URLSearchParams;void 0!==t.limit&&s.set("limit",t.limit.toString()),void 0!==t.offset&&s.set("offset",t.offset.toString()),void 0!==t.min_created&&s.set("min_created",t.min_created.toString()),void 0!==t.max_created&&s.set("max_created",t.max_created.toString());return(await this.makeRequest(`/listings/${e}/reviews?${s.toString()}`)).results}async getReviewsByShop(e,t={}){const s=new URLSearchParams;void 0!==t.limit&&s.set("limit",t.limit.toString()),void 0!==t.offset&&s.set("offset",t.offset.toString()),void 0!==t.min_created&&s.set("min_created",t.min_created.toString()),void 0!==t.max_created&&s.set("max_created",t.max_created.toString());return(await this.makeRequest(`/shops/${e}/reviews?${s.toString()}`)).results}async getSellerTaxonomyNodes(){return(await this.makeRequest("/seller-taxonomy/nodes")).results}async getUserShops(){const e=await this.getUser();return(await this.makeRequest(`/users/${e.user_id}/shops`)).results||[]}async updateShop(e,t,s){if(s?.validate){const e=s.validateSchema||T;if(!1!==s.throwOnValidationError)x(t,e,"Invalid shop update parameters");else{const s=e.validate(t);s.valid||this.logger.warn("Shop update validation failed",s.errors)}}const i=this.buildFormBody(t);return this.makeRequest(`/shops/${e}`,{method:"PUT",headers:{"Content-Type":"application/x-www-form-urlencoded"},body:i.toString()},!1)}async createShopSection(e,t){const s=this.buildFormBody(t);return this.makeRequest(`/shops/${e}/sections`,{method:"POST",headers:{"Content-Type":"application/x-www-form-urlencoded"},body:s.toString()},!1)}async updateShopSection(e,t,s){const i=this.buildFormBody(s);return this.makeRequest(`/shops/${e}/sections/${t}`,{method:"PUT",headers:{"Content-Type":"application/x-www-form-urlencoded"},body:i.toString()},!1)}async deleteShopSection(e,t){await this.makeRequest(`/shops/${e}/sections/${t}`,{method:"DELETE"},!1)}async createDraftListing(e,t,s){if(s?.validate){const e=s.validateSchema||k;if(!1!==s.throwOnValidationError)x(t,e,"Invalid listing parameters");else{const s=e.validate(t);s.valid||this.logger.warn("Listing validation failed",s.errors)}}const i=s?.legacy,r=void 0!==i?`?legacy=${i}`:"",n=this.buildFormBody(t);return this.makeRequest(`/shops/${e}/listings${r}`,{method:"POST",headers:{"Content-Type":"application/x-www-form-urlencoded"},body:n.toString()},!1)}async updateListing(e,t,s,i){if(i?.validate){const e=i.validateSchema||E;if(!1!==i.throwOnValidationError)x(s,e,"Invalid listing update parameters");else{const t=e.validate(s);t.valid||this.logger.warn("Listing update validation failed",t.errors)}}const r=i?.legacy,n=void 0!==r?`?legacy=${r}`:"",a=this.buildFormBody(s);return this.makeRequest(`/shops/${e}/listings/${t}${n}`,{method:"PATCH",headers:{"Content-Type":"application/x-www-form-urlencoded"},body:a.toString()},!1)}async deleteListing(e){await this.makeRequest(`/listings/${e}`,{method:"DELETE"},!1)}async updateListingInventory(e,t,s){const i=s?.legacy,r=void 0!==i?`?legacy=${i}`:"";return this.makeRequest(`/listings/${e}/inventory${r}`,{method:"PUT",body:JSON.stringify(t)},!1)}async uploadListingImage(e,s,i,r){const n=new FormData;n.append("image",i),void 0!==r?.rank&&n.append("rank",r.rank.toString()),void 0!==r?.overwrite&&n.append("overwrite",r.overwrite.toString()),void 0!==r?.is_watermarked&&n.append("is_watermarked",r.is_watermarked.toString()),r?.alt_text&&n.append("alt_text",r.alt_text);const a=`${this.baseUrl}/shops/${e}/listings/${s}/images`;await this.rateLimiter.waitForRateLimit();const o=await this.tokenManager.getAccessToken(),c=await this.fetch(a,{method:"POST",headers:{Authorization:`Bearer ${o}`,"x-api-key":this.getApiKey()},body:n});if(!c.ok){const e=await c.text();throw new t(`Failed to upload image: ${c.status} ${c.statusText}`,c.status,e)}return c.json()}async getListingImage(e,t){return this.makeRequest(`/listings/${e}/images/${t}`)}async deleteListingImage(e,t,s){await this.makeRequest(`/shops/${e}/listings/${t}/images/${s}`,{method:"DELETE"},!1)}async bulkUpdateListings(e,t,s){return(s?new S(s):this.bulkOperationManager).executeBulk(t,async t=>this.updateListing(e,t.listingId.toString(),t.updates),e=>e.listingId)}async bulkUploadImages(e,t,s,i){return(i?new S(i):this.bulkOperationManager).executeBulk(s,async s=>this.uploadListingImage(e,t,s.file,{rank:s.rank,alt_text:s.altText}))}setBulkOperationConcurrency(e){this.bulkOperationManager.setConcurrency(Math.max(1,Math.min(10,e)))}async getShopReceipts(e,t){const s=new URLSearchParams;void 0!==t?.limit&&s.set("limit",t.limit.toString()),void 0!==t?.offset&&s.set("offset",t.offset.toString()),t?.sort_on&&s.set("sort_on",t.sort_on),t?.sort_order&&s.set("sort_order",t.sort_order),void 0!==t?.min_created&&s.set("min_created",t.min_created.toString()),void 0!==t?.max_created&&s.set("max_created",t.max_created.toString()),void 0!==t?.min_last_modified&&s.set("min_last_modified",t.min_last_modified.toString()),void 0!==t?.max_last_modified&&s.set("max_last_modified",t.max_last_modified.toString()),void 0!==t?.was_paid&&s.set("was_paid",t.was_paid.toString()),void 0!==t?.was_shipped&&s.set("was_shipped",t.was_shipped.toString()),void 0!==t?.was_delivered&&s.set("was_delivered",t.was_delivered.toString()),void 0!==t?.was_canceled&&s.set("was_canceled",t.was_canceled.toString()),void 0!==t?.legacy&&s.set("legacy",t.legacy.toString());return(await this.makeRequest(`/shops/${e}/receipts?${s.toString()}`)).results}async getShopReceipt(e,t,s={}){const i=new URLSearchParams;void 0!==s.legacy&&i.set("legacy",s.legacy.toString());const r=i.toString(),n=r?`?${r}`:"";return this.makeRequest(`/shops/${e}/receipts/${t}${n}`)}async updateShopReceipt(e,t,s,i){const r=i?.legacy,n=void 0!==r?`?legacy=${r}`:"",a=this.buildFormBody(s);return this.makeRequest(`/shops/${e}/receipts/${t}${n}`,{method:"PUT",headers:{"Content-Type":"application/x-www-form-urlencoded"},body:a.toString()},!1)}async getShopReceiptTransactions(e,t,s={}){const i=new URLSearchParams;void 0!==s.legacy&&i.set("legacy",s.legacy.toString());const r=i.toString(),n=r?`?${r}`:"";return(await this.makeRequest(`/shops/${e}/receipts/${t}/transactions${n}`)).results}async getShopTransaction(e,t){return this.makeRequest(`/shops/${e}/transactions/${t}`)}async getShopShippingProfiles(e){return(await this.makeRequest(`/shops/${e}/shipping-profiles`)).results}async createShopShippingProfile(e,t){const s=this.buildFormBody(t);return this.makeRequest(`/shops/${e}/shipping-profiles`,{method:"POST",headers:{"Content-Type":"application/x-www-form-urlencoded"},body:s.toString()},!1)}async getShopShippingProfile(e,t){return this.makeRequest(`/shops/${e}/shipping-profiles/${t}`)}async updateShopShippingProfile(e,t,s){const i=this.buildFormBody(s);return this.makeRequest(`/shops/${e}/shipping-profiles/${t}`,{method:"PUT",headers:{"Content-Type":"application/x-www-form-urlencoded"},body:i.toString()},!1)}async deleteShopShippingProfile(e,t){await this.makeRequest(`/shops/${e}/shipping-profiles/${t}`,{method:"DELETE"},!1)}async getShopShippingProfileDestinations(e,t,s={}){const i=new URLSearchParams;void 0!==s.limit&&i.set("limit",s.limit.toString()),void 0!==s.offset&&i.set("offset",s.offset.toString());const r=i.toString(),n=r?`?${r}`:"";return(await this.makeRequest(`/shops/${e}/shipping-profiles/${t}/destinations${n}`)).results}async createShopShippingProfileDestination(e,t,s){const i=this.buildFormBody(s);return this.makeRequest(`/shops/${e}/shipping-profiles/${t}/destinations`,{method:"POST",headers:{"Content-Type":"application/x-www-form-urlencoded"},body:i.toString()},!1)}async updateShopShippingProfileDestination(e,t,s,i){const r=this.buildFormBody(i);return this.makeRequest(`/shops/${e}/shipping-profiles/${t}/destinations/${s}`,{method:"PUT",headers:{"Content-Type":"application/x-www-form-urlencoded"},body:r.toString()},!1)}async deleteShopShippingProfileDestination(e,t,s){await this.makeRequest(`/shops/${e}/shipping-profiles/${t}/destinations/${s}`,{method:"DELETE"},!1)}async getShopShippingProfileUpgrades(e,t){return(await this.makeRequest(`/shops/${e}/shipping-profiles/${t}/upgrades`)).results}async createReceiptShipment(e,t,s,i){const r=i?.legacy,n=void 0!==r?`?legacy=${r}`:"",a=this.buildFormBody(s);return this.makeRequest(`/shops/${e}/receipts/${t}/tracking${n}`,{method:"POST",headers:{"Content-Type":"application/x-www-form-urlencoded"},body:a.toString()},!1)}async getShopPaymentAccountLedgerEntries(e,t){const s=new URLSearchParams;s.set("min_created",t.min_created.toString()),s.set("max_created",t.max_created.toString()),void 0!==t.limit&&s.set("limit",t.limit.toString()),void 0!==t.offset&&s.set("offset",t.offset.toString());return(await this.makeRequest(`/shops/${e}/payment-account/ledger-entries?${s.toString()}`)).results}async getShopPaymentAccountLedgerEntry(e,t){return this.makeRequest(`/shops/${e}/payment-account/ledger-entries/${t}`)}async getPayments(e,t){const s=new URLSearchParams;s.set("payment_ids",t.join(","));return(await this.makeRequest(`/shops/${e}/payments?${s.toString()}`)).results}async getShopPayment(e,s){const i=await this.getPayments(e,[Number(s)]);if(0===i.length)throw new t("Payment not found",404);return i[0]}async getBuyerTaxonomyNodes(){return(await this.makeRequest("/buyer-taxonomy/nodes")).results}async getPropertiesByTaxonomyId(e){return(await this.makeRequest(`/seller-taxonomy/nodes/${e}/properties`)).results}async getListingProperties(e,t){return(await this.makeRequest(`/shops/${e}/listings/${t}/properties`)).results}async updateListingProperty(e){const{shopId:s,listingId:i,propertyId:r,valueIds:n,values:a,scaleId:o}=e,c=new URLSearchParams;c.append("value_ids",n.map(e=>e.toString()).join(",")),c.append("values",a.join(",")),void 0!==o&&c.append("scale_id",o.toString());const h=`${this.baseUrl}/shops/${s}/listings/${i}/properties/${r}`;await this.rateLimiter.waitForRateLimit();const l=await this.tokenManager.getAccessToken(),u=await this.fetch(h,{method:"PUT",headers:{Authorization:`Bearer ${l}`,"x-api-key":this.getApiKey(),"Content-Type":"application/x-www-form-urlencoded"},body:c.toString()});if(this.rateLimiter.updateFromHeaders(u.headers),this.rateLimiter.resetRetryCount(),!u.ok){const e=await u.text();throw new t(`Failed to update listing property: ${u.status} ${u.statusText}`,u.status,e)}return u.json()}async getShopProductionPartners(e){return(await this.makeRequest(`/shops/${e}/production-partners`)).results}async createShopReadinessStateDefinition(e,t){const s=this.buildFormBody(t);return this.makeRequest(`/shops/${e}/readiness-state-definitions`,{method:"POST",headers:{"Content-Type":"application/x-www-form-urlencoded"},body:s.toString()},!1)}async getShopReadinessStateDefinitions(e,t={}){const s=new URLSearchParams;void 0!==t.limit&&s.set("limit",t.limit.toString()),void 0!==t.offset&&s.set("offset",t.offset.toString());const i=s.toString(),r=i?`?${i}`:"";return(await this.makeRequest(`/shops/${e}/readiness-state-definitions${r}`)).results}async getShopReadinessStateDefinition(e,t){return this.makeRequest(`/shops/${e}/readiness-state-definitions/${t}`)}async updateShopReadinessStateDefinition(e,t,s){const i=this.buildFormBody(s);return this.makeRequest(`/shops/${e}/readiness-state-definitions/${t}`,{method:"PUT",headers:{"Content-Type":"application/x-www-form-urlencoded"},body:i.toString()},!1)}async deleteShopReadinessStateDefinition(e,t){await this.makeRequest(`/shops/${e}/readiness-state-definitions/${t}`,{method:"DELETE"},!1)}async createShopReturnPolicy(e,t){const s=this.buildFormBody(t);return this.makeRequest(`/shops/${e}/policies/return`,{method:"POST",headers:{"Content-Type":"application/x-www-form-urlencoded"},body:s.toString()},!1)}async getShopReturnPolicies(e){return(await this.makeRequest(`/shops/${e}/policies/return`)).results}async getShopReturnPolicy(e,t){return this.makeRequest(`/shops/${e}/policies/return/${t}`)}async updateShopReturnPolicy(e,t,s){const i=this.buildFormBody(s);return this.makeRequest(`/shops/${e}/policies/return/${t}`,{method:"PUT",headers:{"Content-Type":"application/x-www-form-urlencoded"},body:i.toString()},!1)}async deleteShopReturnPolicy(e,t){await this.makeRequest(`/shops/${e}/policies/return/${t}`,{method:"DELETE"},!1)}async consolidateShopReturnPolicies(e,t){const s=this.buildFormBody(t);return this.makeRequest(`/shops/${e}/policies/return/consolidate`,{method:"POST",headers:{"Content-Type":"application/x-www-form-urlencoded"},body:s.toString()},!1)}async getHolidayPreferences(e){return(await this.makeRequest(`/shops/${e}/holiday-preferences`)).results}async updateHolidayPreferences(e,t,s){const i=this.buildFormBody(s);return this.makeRequest(`/shops/${e}/holiday-preferences/${t}`,{method:"PUT",headers:{"Content-Type":"application/x-www-form-urlencoded"},body:i.toString()},!1)}async uploadListingFile(e,s,i,r){const n=new FormData;n.append("file",i),r?.name&&n.append("name",r.name),void 0!==r?.rank&&n.append("rank",r.rank.toString()),void 0!==r?.listing_file_id&&n.append("listing_file_id",r.listing_file_id.toString());const a=`${this.baseUrl}/shops/${e}/listings/${s}/files`;await this.rateLimiter.waitForRateLimit();const o=await this.tokenManager.getAccessToken(),c=await this.fetch(a,{method:"POST",headers:{Authorization:`Bearer ${o}`,"x-api-key":this.getApiKey()},body:n});if(!c.ok){const e=await c.text();throw new t(`Failed to upload file: ${c.status} ${c.statusText}`,c.status,e)}return c.json()}async getAllListingFiles(e,t){return(await this.makeRequest(`/shops/${e}/listings/${t}/files`)).results}async getListingFile(e,t,s){return this.makeRequest(`/shops/${e}/listings/${t}/files/${s}`)}async deleteListingFile(e,t,s){await this.makeRequest(`/shops/${e}/listings/${t}/files/${s}`,{method:"DELETE"},!1)}async uploadListingVideo(e,s,i,r){const n=new FormData;n.append("video",i),r?.name&&n.append("name",r.name),void 0!==r?.video_id&&n.append("video_id",r.video_id.toString());const a=`${this.baseUrl}/shops/${e}/listings/${s}/videos`;await this.rateLimiter.waitForRateLimit();const o=await this.tokenManager.getAccessToken(),c=await this.fetch(a,{method:"POST",headers:{Authorization:`Bearer ${o}`,"x-api-key":this.getApiKey()},body:n});if(!c.ok){const e=await c.text();throw new t(`Failed to upload video: ${c.status} ${c.statusText}`,c.status,e)}return c.json()}async getListingVideos(e){return(await this.makeRequest(`/listings/${e}/videos`)).results}async getListingVideo(e,t){return this.makeRequest(`/listings/${e}/videos/${t}`)}async deleteListingVideo(e,t,s){await this.makeRequest(`/shops/${e}/listings/${t}/videos/${s}`,{method:"DELETE"},!1)}async getListingPersonalizations(e){return this.makeRequest(`/listings/${e}/personalization`)}async updateListingPersonalization(e,t,s){const{supports_multiple_personalization_questions:i,...r}=s,n=i?"?supports_multiple_personalization_questions=true":"";return this.makeRequest(`/shops/${e}/listings/${t}/personalization${n}`,{method:"POST",body:JSON.stringify(r)},!1)}async deleteListingPersonalization(e,t){await this.makeRequest(`/shops/${e}/listings/${t}/personalization`,{method:"DELETE"},!1)}async createListingTranslation(e,t,s,i){const r=this.buildFormBody(i);return this.makeRequest(`/shops/${e}/listings/${t}/translations/${s}`,{method:"POST",headers:{"Content-Type":"application/x-www-form-urlencoded"},body:r.toString()},!1)}async getListingTranslation(e,t,s){return this.makeRequest(`/shops/${e}/listings/${t}/translations/${s}`)}async updateListingTranslation(e,t,s,i){const r=this.buildFormBody(i);return this.makeRequest(`/shops/${e}/listings/${t}/translations/${s}`,{method:"PUT",headers:{"Content-Type":"application/x-www-form-urlencoded"},body:r.toString()},!1)}async getListingVariationImages(e,t){return(await this.makeRequest(`/shops/${e}/listings/${t}/variation-images`)).results}async updateVariationImages(e,t,s){return(await this.makeRequest(`/shops/${e}/listings/${t}/variation-images`,{method:"POST",body:JSON.stringify(s)},!1)).results}async findAllActiveListingsByShop(e,t={}){const s=new URLSearchParams;void 0!==t.limit&&s.set("limit",t.limit.toString()),void 0!==t.offset&&s.set("offset",t.offset.toString()),t.sort_on&&s.set("sort_on",t.sort_on),t.sort_order&&s.set("sort_order",t.sort_order),t.keywords&&s.set("keywords",t.keywords),void 0!==t.legacy&&s.set("legacy",t.legacy.toString());const i=s.toString(),r=i?`?${i}`:"";return(await this.makeRequest(`/shops/${e}/listings/active${r}`)).results}async getFeaturedListingsByShop(e,t={}){const s=new URLSearchParams;void 0!==t.limit&&s.set("limit",t.limit.toString()),void 0!==t.offset&&s.set("offset",t.offset.toString()),void 0!==t.legacy&&s.set("legacy",t.legacy.toString());const i=s.toString(),r=i?`?${i}`:"";return(await this.makeRequest(`/shops/${e}/listings/featured${r}`)).results}async getListingsByListingIds(e){const t=new URLSearchParams;t.set("listing_ids",e.listing_ids.join(",")),e.includes&&t.set("includes",e.includes.join(",")),void 0!==e.legacy&&t.set("legacy",e.legacy.toString());return(await this.makeRequest(`/listings/batch?${t.toString()}`)).results}async getListingsByShopReceipt(e,t,s={}){const i=new URLSearchParams;void 0!==s.limit&&i.set("limit",s.limit.toString()),void 0!==s.offset&&i.set("offset",s.offset.toString()),void 0!==s.legacy&&i.set("legacy",s.legacy.toString());const r=i.toString(),n=r?`?${r}`:"";return(await this.makeRequest(`/shops/${e}/receipts/${t}/listings${n}`)).results}async getListingProperty(e,t){return this.makeRequest(`/listings/${e}/properties/${t}`)}async deleteListingProperty(e,t,s){await this.makeRequest(`/shops/${e}/listings/${t}/properties/${s}`,{method:"DELETE"},!1)}async getListingProduct(e,t){return this.makeRequest(`/listings/${e}/inventory/products/${t}`)}async getListingOffering(e,t,s){return this.makeRequest(`/listings/${e}/products/${t}/offerings/${s}`)}async getListingsByShopSectionId(e,t){const s=new URLSearchParams;s.set("shop_section_ids",t.shop_section_ids.join(",")),void 0!==t.limit&&s.set("limit",t.limit.toString()),void 0!==t.offset&&s.set("offset",t.offset.toString()),t.sort_on&&s.set("sort_on",t.sort_on),t.sort_order&&s.set("sort_order",t.sort_order),void 0!==t.legacy&&s.set("legacy",t.legacy.toString());return(await this.makeRequest(`/shops/${e}/shop-sections/listings?${s.toString()}`)).results}async getListingsByShopReturnPolicy(e,t,s={}){const i=new URLSearchParams;void 0!==s.legacy&&i.set("legacy",s.legacy.toString());const r=i.toString(),n=r?`?${r}`:"";return(await this.makeRequest(`/shops/${e}/policies/return/${t}/listings${n}`)).results}async findShops(e){const t=new URLSearchParams;t.set("shop_name",e.shop_name),void 0!==e.limit&&t.set("limit",e.limit.toString()),void 0!==e.offset&&t.set("offset",e.offset.toString());return(await this.makeRequest(`/shops?${t.toString()}`)).results}async createShopShippingProfileUpgrade(e,t,s){const i=this.buildFormBody(s);return this.makeRequest(`/shops/${e}/shipping-profiles/${t}/upgrades`,{method:"POST",headers:{"Content-Type":"application/x-www-form-urlencoded"},body:i.toString()},!1)}async updateShopShippingProfileUpgrade(e,t,s,i){const r=this.buildFormBody(i);return this.makeRequest(`/shops/${e}/shipping-profiles/${t}/upgrades/${s}`,{method:"PUT",headers:{"Content-Type":"application/x-www-form-urlencoded"},body:r.toString()},!1)}async deleteShopShippingProfileUpgrade(e,t,s){await this.makeRequest(`/shops/${e}/shipping-profiles/${t}/upgrades/${s}`,{method:"DELETE"},!1)}async getShippingCarriers(e){const t=new URLSearchParams;t.set("origin_country_iso",e);return(await this.makeRequest(`/shipping-carriers?${t.toString()}`)).results}async getShopReceiptTransactionsByListing(e,t,s={}){const i=new URLSearchParams;void 0!==s.limit&&i.set("limit",s.limit.toString()),void 0!==s.offset&&i.set("offset",s.offset.toString()),void 0!==s.legacy&&i.set("legacy",s.legacy.toString());const r=i.toString(),n=r?`?${r}`:"";return(await this.makeRequest(`/shops/${e}/listings/${t}/transactions${n}`)).results}async getShopReceiptTransactionsByShop(e,t={}){const s=new URLSearchParams;void 0!==t.limit&&s.set("limit",t.limit.toString()),void 0!==t.offset&&s.set("offset",t.offset.toString()),void 0!==t.legacy&&s.set("legacy",t.legacy.toString());const i=s.toString(),r=i?`?${i}`:"";return(await this.makeRequest(`/shops/${e}/transactions${r}`)).results}async getPaymentAccountLedgerEntryPayments(e,t){const s=new URLSearchParams;s.set("ledger_entry_ids",t.ledger_entry_ids.join(","));return(await this.makeRequest(`/shops/${e}/payment-account/ledger-entries/payments?${s.toString()}`)).results}async getShopPaymentByReceiptId(e,t){return(await this.makeRequest(`/shops/${e}/receipts/${t}/payments`)).results}async getMe(){return this.makeRequest("/users/me")}async getUserAddresses(){return(await this.makeRequest("/user/addresses")).results}async getUserAddress(e){return this.makeRequest(`/user/addresses/${e}`)}async deleteUserAddress(e){await this.makeRequest(`/user/addresses/${e}`,{method:"DELETE"},!1)}async getPropertiesByBuyerTaxonomyId(e){return(await this.makeRequest(`/buyer-taxonomy/nodes/${e}/properties`)).results}async ping(){return this.makeRequest("/openapi-ping",{},!1)}async tokenScopes(e){const t=this.buildFormBody(e);return this.makeRequest("/scopes",{method:"POST",headers:{"Content-Type":"application/x-www-form-urlencoded"},body:t.toString()},!1)}getRemainingRequests(){return this.rateLimiter.getRemainingRequests()}getRateLimitStatus(){return this.rateLimiter.getRateLimitStatus()}onApproachingRateLimit(e,t){void 0!==t&&this.rateLimiter.setWarningThreshold(t),this.rateLimiter.setApproachingLimitCallback(e)}async clearCache(){this.cache&&await this.cache.clear()}getCurrentTokens(){return this.tokenManager