@titamedia/delectable-sdk
Version:
SDK oficial para los servicios del chatbot Delectable
3 lines (2 loc) • 23.1 kB
JavaScript
const e={API_CALLS:!1,API_ERRORS:!0,CHAT_MESSAGES:!1,CHAT_ACTIONS:!1,USER_DATA:!1,USER_AUTH:!1,CART_OPERATIONS:!1,SHOPPING_LIST:!1,DEBUG:!1,PERFORMANCE:!1,ERRORS:!0,WARNINGS:!0};class t{static _log(t,s,r,a=null){if(!e[t])return;const i=`[${(new Date).toISOString().split("T")[1].split(".")[0]}] [/sdk] [${t}]`;switch(s){case"error":console.error(`❌ ${i}`,r,a||"");break;case"warn":console.warn(`⚠️ ${i}`,r,a||"");break;case"info":console.info(`ℹ️ ${i}`,r,a||"");break;case"success":console.log(`✅ ${i}`,r,a||"");break;default:console.log(`🔍 ${i}`,r,a||"")}}static apiCall(e,t){this._log("API_CALLS","info",e,t)}static apiError(e,t){this._log("API_ERRORS","error",e,t)}static apiSuccess(e,t){this._log("API_CALLS","success",e,t)}static userData(e,t){this._log("USER_DATA","info",e,t)}static userAuth(e,t){this._log("USER_AUTH","info",e,t)}static cartOp(e,t){this._log("CART_OPERATIONS","info",e,t)}static shoppingList(e,t){this._log("SHOPPING_LIST","info",e,t)}static debug(e,t){this._log("DEBUG","debug",e,t)}static error(e,t){this._log("ERRORS","error",e,t)}static warn(e,t){this._log("WARNINGS","warn",e,t)}static enableCategory(t){e.hasOwnProperty(t)?(e[t]=!0,console.log(`✅ [/sdk] Logger: Enabled category '${t}'`)):console.warn(`⚠️ [/sdk] Logger: Unknown category '${t}'`)}static disableCategory(t){e.hasOwnProperty(t)?(e[t]=!1,console.log(`❌ [/sdk] Logger: Disabled category '${t}'`)):console.warn(`⚠️ [/sdk] Logger: Unknown category '${t}'`)}static showConfig(){console.log("🔧 [@delectable/sdk] Logger Configuration:"),Object.entries(e).forEach(([e,t])=>{console.log(` ${t?"✅":"❌"} ${e}`)})}static enableAll(){Object.keys(e).forEach(t=>{e[t]=!0}),console.log("🔥 [@delectable/sdk] Logger: All categories enabled")}static disableAll(){Object.keys(e).forEach(t=>{"ERRORS"!==t&&"WARNINGS"!==t&&(e[t]=!1)}),console.log("🔇 [@delectable/sdk] Logger: All non-critical categories disabled")}}class s extends Error{constructor(e,t=null,s=null){super(e),this.name="DelectableError",this.status=t,this.data=s}}class r extends s{constructor(e){super(e),this.name="NetworkError"}}class a extends s{constructor(e){super(e),this.name="AuthenticationError",this.status=401}}class i extends s{constructor(e,t=null){super(e),this.name="ValidationError",this.status=422,this.validationErrors=t}}class n extends s{constructor(e){super(e),this.name="NotFoundError",this.status=404}}class o extends s{constructor(e){super(e),this.name="ServerError",this.status=500}}class c{constructor(e,t){this.http=e,this.config=t}async loginAnonymous(){t.userAuth("Attempting anonymous login");try{const e=await this.http.post(this.config.endpoints.LOGIN_ANONYMOUS);return t.userAuth("Anonymous login successful",{user_id:e.user_id,session_id:e.session_id}),{access_token:e.access_token,token_type:e.token_type,session_id:e.session_id,user_id:e.user_id,token:e.access_token,sessionId:e.session_id,userId:e.user_id}}catch(e){throw t.apiError("Anonymous login failed",e),new a("Failed to authenticate anonymously")}}async login(e,s){if(!e||"undefined"===e||""===e.trim())throw new i("Valid username is required");if(!s)throw new i("Password is required");t.userAuth("Attempting user login",{username:e});const r=new URLSearchParams({grant_type:"password",username:e,password:s,scope:"",client_id:"",client_secret:""});try{const s=await this.http.request(this.config.endpoints.LOGIN,{method:"POST",headers:{"Content-Type":"application/x-www-form-urlencoded"},body:r.toString()});if(s&&s.access_token)return t.userAuth("User login successful",{username:e,session_id:s.session_id}),{access_token:s.access_token,token_type:s.token_type,session_id:s.session_id,user_id:e,token:s.access_token,sessionId:s.session_id,userId:e};throw new a(`Login failed for ${e}`)}catch(s){throw t.apiError("User login failed",s),new a(`Login failed for ${e}: ${s.message}`)}}async refreshToken(e){t.userAuth("Attempting token refresh");try{const e=await this.loginAnonymous();return t.userAuth("Token refreshed via anonymous login"),e.access_token}catch(e){throw t.apiError("Token refresh failed",e),new a("Failed to refresh authentication token")}}}class l{constructor(e,t){this.http=e,this.config=t}async fetchMealPlans({username:e,skip:s=0,limit:r=10}={}){if(!e)throw new i("Username is required for fetching meal plans");t.apiCall("Fetching meal plans",{username:e,skip:s,limit:r});const a=`${this.config.endpoints.MEAL_PLANS}/?skip=${s}&limit=${r}&created_by=${encodeURIComponent(e)}`;try{const e=await this.http.get(a);return{type:"direct_data",data:{items:e.items||[],total:e.total||0,page:e.page||1,size:e.size||r,pages:e.pages||1},full_response:e}}catch(e){throw this._handleMealPlanError(e,"fetch meal plans")}}async createMealPlan(e){t.apiCall("Creating meal plan",e);try{return await this.http.post(this.config.endpoints.MEAL_PLANS,e)}catch(e){throw this._handleMealPlanError(e,"create meal plan")}}async deleteMealPlan(e){if(!e)throw new i("Meal plan ID is required for deletion");t.apiCall("Deleting meal plan",{mealPlanId:e});try{return await this.http.delete(`${this.config.endpoints.MEAL_PLANS}/${e}`)}catch(e){throw this._handleMealPlanError(e,"delete meal plan")}}async generateMealPlan(e){t.apiCall("Generating meal plan",e);const s=this._buildMealPlanFromForm(e);return await this.createMealPlan(s)}_buildMealPlanFromForm(e){return{name:e.name||`Meal Plan ${(new Date).toLocaleDateString()}`,description:this._buildMealPlanDescription(e),start_date:e.startDate||(new Date).toISOString().split("T")[0],end_date:e.endDate||new Date(Date.now()+5184e5).toISOString().split("T")[0],days:this._buildMealPlanDays(e),created_by:e.username||"user"}}_buildMealPlanDescription(e){const t=[];return e.dietType&&t.push(`Diet: ${e.dietType}`),e.cookingTime&&t.push(`Cooking time: ${e.cookingTime}`),e.servings&&t.push(`Servings: ${e.servings}`),t.join(", ")}_buildMealPlanDays(e){const t=[],s=new Date(e.startDate||Date.now());for(let r=0;r<7;r++){const a=new Date(s);a.setDate(s.getDate()+r),t.push({date:a.toISOString().split("T")[0],meals:this._buildMealsForDay(e,r)})}return t}_buildMealsForDay(e,t){const s=[];return(e.mealTypes||["breakfast","lunch","dinner"]).forEach(e=>{s.push({type:e,name:`${e.charAt(0).toUpperCase()+e.slice(1)} Day ${t+1}`,ingredients:this._generateSampleIngredients(e)})}),s}_generateSampleIngredients(e){return{breakfast:["Oats","Milk","Berries","Honey"],lunch:["Chicken","Rice","Vegetables","Olive Oil"],dinner:["Salmon","Quinoa","Broccoli","Lemon"]}[e]||["Ingredient 1","Ingredient 2"]}_handleMealPlanError(e,s){throw t.apiError(`Meal plan operation failed: ${s}`,e),401===e.status?new Error("Authentication failed. Please log in again to access meal plans."):403===e.status?new Error("Access denied. You do not have permission to access meal plans."):404===e.status?new Error("Meal plans service not found. The service may be temporarily unavailable."):new Error(`Failed to ${s}: ${e.message}`)}}class u{constructor(e,t){this.http=e,this.config=t}async getUserProfile(e){if(!e)throw new i("User ID is required");t.userData("Fetching user profile",{userId:e});const s=encodeURIComponent(e),r=`${this.config.endpoints.USERS}${s}`;try{const e=await this.http.get(r);return t.userData("User profile retrieved successfully",e),{UserObj:e}}catch(s){if(404===s.status)return t.userData("User profile not found",{userId:e}),null;throw s}}async updateUserProfile(e){if(!e||!e.id)throw new i("Profile data with ID is required");t.userData("Updating user profile",e);const s=encodeURIComponent(e.id),r=`${this.config.endpoints.USERS}${s}`;try{const s=await this.http.put(r,e);return t.userData("User profile updated successfully",s),{profileUpdateMSG:"Profile updated successfully!",data:s}}catch(e){throw t.apiError("Failed to update user profile",e),new Error(`Failed to update profile: ${e.message}`)}}async createBasicUser(e){if(!e||!this._isValidEmail(e))throw new i("Valid email is required");t.userData("Creating basic user",{email:e});const s=e.split("@"),r={username:e,password:this._generateSecurePassword(),user_source:"Delectable",agree_to_license:!0,email:e,first_name:s[0],last_name:"",phone:"",created_by:"delectabot"},a=new URLSearchParams;Object.keys(r).forEach(e=>{null!=r[e]&&""!==r[e]&&a.append(e,r[e])});const n=`${this.config.endpoints.USERS}?${a.toString()}`;try{const e=await this.http.post(n,{});return t.userData("Basic user created successfully",e),{createUserMSG:"Basic user created successfully!",success:!0,data:e,userData:{...r,password:"[HIDDEN]"}}}catch(e){if(t.apiError("Failed to create basic user",e),409===e.status)return{createUserMSG:"User already exists with this email",success:!1,errorCode:"USER_EXISTS"};throw new Error(`Failed to create user: ${e.message}`)}}async deleteUserAccount(e){if(!e)throw new i("User ID is required");t.userData("Deleting user account",{userId:e});const s=encodeURIComponent(e),r=`${this.config.endpoints.USERS}${s}`;try{return await this.http.delete(r),t.userData("User account deleted successfully",{userId:e}),{deleteAccountMSG:"Account deleted successfully",success:!0}}catch(e){throw t.apiError("Failed to delete user account",e),new Error(`Failed to delete account: ${e.message}`)}}async getVtexProfile(e){if(!e)throw new i("Email is required for VTEX profile request");t.userData("Getting VTEX profile",{email:e});const s=encodeURIComponent(e),r=`${this.config.endpoints.VTEX_PROFILE}?email=${s}`;try{const e=await this.http.get(r);return t.userData("VTEX profile retrieved successfully",e),{vtexProfileMSG:"VTEX profile retrieved successfully",success:!0,...e}}catch(e){return t.apiError("Failed to get VTEX profile",e),{vtexProfileMSG:`Failed to get VTEX profile: ${e.message}`,success:!1,vtex_profile:null}}}async createUserFromVtex(e){if(!e||!e.email)throw new i("Valid VTEX profile with email is required");t.userData("Creating user from VTEX profile",{email:e.email});const s={username:e.email,password:this._generateSecurePassword(),user_source:"Delectable",agree_to_license:!0,email:e.email,first_name:e.firstName||"",last_name:e.lastName||"",phone:e.homePhone||e.phone||"",created_by:"delectabot"},r=new URLSearchParams;Object.keys(s).forEach(e=>{null!=s[e]&&""!==s[e]&&r.append(e,s[e])});const a=`${this.config.endpoints.USERS}?${r.toString()}`;try{const e=await this.http.post(a,{});return t.userData("User created from VTEX successfully",e),{createUserMSG:"User created successfully from VTEX profile!",success:!0,data:e,userData:{...s,password:"[HIDDEN]"}}}catch(e){if(t.apiError("Failed to create user from VTEX",e),409===e.status)return{createUserMSG:"User already exists with this email",success:!1,errorCode:"USER_EXISTS"};throw new Error(`Failed to create user from VTEX: ${e.message}`)}}_isValidEmail(e){return/^[^\s@]+@[^\s@]+\.[^\s@]+$/.test(e)}_generateSecurePassword(){const e="ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789!@#$%^&*";let t="";for(let s=0;s<12;s++)t+=e.charAt(Math.floor(70*Math.random()));return t}}class h{constructor(e,s){this.httpClient=e,this.config=s,this.logger=new t("RecipesModule")}async fetchUserRecipes(e,t,s="*",n=100,o=!0){if(this.logger.info(`Fetching user recipes for: ${t}`),this.logger.debug("Request params:",{recipeQuery:s,numSuggestions:n,includeSponsored:o}),!e||!t)throw new i("Access token and username are required for recipes service");try{const t=new URLSearchParams({recipe_query:s,num_suggestions:n.toString(),include_sponsored:o.toString()}),r=`${this.config.endpoints.RECIPES}/user?${t}`;this.logger.debug(`Using endpoint: ${r}`);const a=await this.httpClient.request({method:"GET",url:r,headers:{Authorization:`Bearer ${e}`,"Content-Type":"application/json"}});return this.logger.debug("API response received:",{type:typeof a,isArray:Array.isArray(a),length:a?.length||0}),Array.isArray(a)?(this.logger.info(`Successfully fetched ${a.length} recipes`),a):(this.logger.warn("Unexpected response format, returning empty array"),[])}catch(e){throw this.logger.error("Error fetching user recipes:",e),401===e.status?new a("Invalid or expired access token"):e.status>=400&&e.status<500?new i(`Invalid request: ${e.message}`):new r(`Failed to fetch user recipes: ${e.message}`)}}async fetchRecipeById(e,t,s){if(this.logger.info(`Fetching recipe by ID: ${s}`),!e||!t||!s)throw new i("Access token, username, and recipeId are required for recipe by ID service");try{const t=`${this.config.endpoints.RECIPES}/${s}`;this.logger.debug(`Using endpoint: ${t}`);const r=await this.httpClient.request({method:"GET",url:t,headers:{Authorization:`Bearer ${e}`,"Content-Type":"application/json"}});if(this.logger.debug("Recipe details received:",{id:r?.id,name:r?.name,hasIngredients:!!r?.ingredientNames?.length,hasInstructions:!!r?.instructions?.length}),r&&"object"==typeof r)return this.logger.info("Successfully fetched recipe details"),r;throw new i(`Invalid recipe response format for ID: ${s}`)}catch(e){throw this.logger.error("Error fetching recipe by ID:",e),401===e.status?new a("Invalid or expired access token"):404===e.status?new i(`Recipe not found: ${s}`):e.status>=400&&e.status<500?new i(`Invalid request: ${e.message}`):new r(`Failed to fetch recipe by ID: ${e.message}`)}}async selectRecipeForMeal(e,t,s,n=[],o=5,c=!0){if(this.logger.info(`Selecting recipe for meal: ${s}`),this.logger.debug("Request params:",{mealId:s,userPreferences:n,rating:o,generateIfNotFound:c}),!e||!t||!s)throw new i("Access token, username, and mealId are required for select recipe for meal service");try{const t=Array.isArray(n)&&n.length>0?n.join(", "):"User preferences applied",r=`${this.config.endpoints.RECIPES}/select-recipe-for-meal`,a={meal_id:s,generate_if_not_found:c,rating:o,notes:t};this.logger.debug(`Using endpoint: ${r}`),this.logger.debug("Request body:",a);const l=await this.httpClient.request({method:"POST",url:r,headers:{Authorization:`Bearer ${e}`,"Content-Type":"application/json"},data:a});if(this.logger.debug("Meal recipe selection response received:",{mealId:l?.meal_id,mealName:l?.meal_name,candidatesCount:l?.existing_recipes_from_database?.length||0,hasGeneratedRecipes:l?.recipes_that_could_be_generated?.length>0}),l&&"object"==typeof l)return this.logger.info("Successfully received recipe candidates for meal"),l;throw new i(`Invalid recipe response format for meal ID: ${s}`)}catch(e){throw this.logger.error("Error selecting recipe for meal:",e),401===e.status?new a("Invalid or expired access token"):404===e.status?new i(`Meal not found: ${s}`):e.status>=400&&e.status<500?new i(`Invalid request: ${e.message}`):new r(`Failed to select recipe for meal: ${e.message}`)}}static extractBestRecipe(e){if(!e?.existing_recipes_from_database?.length)return null;let t=null,s=-1;return e.existing_recipes_from_database.forEach(e=>{e.similarity_score>s&&(s=e.similarity_score,t=e)}),t}async getCompleteRecipeForMeal(e,t,s,r=[],a=5){this.logger.info(`Getting complete recipe for meal (2-step flow): ${s}`);const n=await this.selectRecipeForMeal(e,t,s,r,a),o=h.extractBestRecipe(n);if(!o)throw new i(`No suitable recipe candidates found for meal: ${s}`);this.logger.debug(`Best candidate selected: "${o.name}" with score: ${o.similarity_score}`);return{candidates:n,bestCandidate:o,completeRecipe:await this.fetchRecipeById(e,t,o.id)}}}class d{constructor(e={}){this.baseURL=e.baseURL||this._getDefaultBaseURL(),this.apiKey=e.apiKey||this._getDefaultApiKey(),this.vtex={appKey:e.vtex?.appKey||this._getEnvVar("VTEX_APP_KEY"),appToken:e.vtex?.appToken||this._getEnvVar("VTEX_APP_TOKEN"),domain:e.vtex?.domain||"delectablegrocery.myvtex.com"},this.timeout=e.timeout||3e4,this.retries=e.retries||3,this.debug=e.debug||!1,this.cache={enabled:e.cache?.enabled??!0,ttl:e.cache?.ttl||3e5},this.endpoints={LOGIN_ANONYMOUS:"/api/v1/auth/anonymous",LOGIN:"/api/v1/auth/token",LLM:"/api/v1/llm",LLM_ACTION:"/api/v1/llm/select_action",RECIPES:"/api/v1/recipes",IMAGES:"/api/v1/images/",PRODUCTS:"/api/v1/products/",USERS:"/api/v1/users/",LISTS_SKU:"/api/v1/shoplist/{list_id}/items/{item_id}",LISTS_IMAGE:"/api/v1/shoplist/{list_id}/items/image",ADD_PREF:"/api/v1/users/{username}/prefs",REMOVE_PREF:"/api/v1/users/{username}/prefs",GET_PREFS:"/api/v1/users/{username}/prefs",VTEX_PROFILE:"/api/v1/vtex/profile",MEAL_PLANS:"/api/v1/meal-plans"}}_getDefaultBaseURL(){return"undefined"!=typeof window?"https:"===window.location.protocol?"https://dai-chat-service-public-826633408444.us-central1.run.app":"https://localhost:4001":process.env.DELECTABLE_BASE_URL||"https://dai-chat-service-public-826633408444.us-central1.run.app"}_getDefaultApiKey(){return this._getEnvVar("DELECTABLE_API_KEY")||"abc123"}_getEnvVar(e){return"undefined"!=typeof process&&process.env?process.env[e]:null}getEndpointURL(e){return`${this.baseURL}${this.endpoints[e]||e}`}validate(){const e=[];if(this.baseURL||e.push("baseURL is required"),this.apiKey||e.push("apiKey is required"),e.length>0)throw new Error(`Configuration validation failed: ${e.join(", ")}`);return!0}}class p{constructor(e){this.config=e,this.defaultHeaders={Accept:"application/json","Content-Type":"application/json","api-key":e.apiKey},this._tokenRefreshCallback=null}setDefaultHeader(e,t){null==t?delete this.defaultHeaders[e]:this.defaultHeaders[e]=t}setTokenRefreshCallback(e){this._tokenRefreshCallback=e}async request(e,s={}){const r=e.startsWith("http")?e:`${this.config.baseURL}${e}`,a={method:"GET",headers:{...this.defaultHeaders,...s.headers},timeout:this.config.timeout,...s};s.data&&"GET"!==a.method&&(a.body=JSON.stringify(s.data)),t.apiCall(`${a.method} ${r}`,{headers:Object.keys(a.headers),hasBody:!!a.body});try{const e=await this._makeRequest(r,a,s.isRetry),i=await this._handleResponse(e);return t.apiSuccess(`${a.method} ${r} completed`,{status:e.status,dataType:typeof i}),i}catch(e){throw t.apiError(`${a.method} ${r} failed`,e),this._handleError(e,r,a,s)}}async _makeRequest(e,s,r=!1){const i=new AbortController,n=setTimeout(()=>i.abort(),s.timeout);try{const o=await fetch(e,{...s,signal:i.signal,mode:"cors",credentials:"omit",referrerPolicy:"no-referrer"});if(clearTimeout(n),401===o.status&&this._tokenRefreshCallback&&!r){t.warn("Token appears to be expired, attempting refresh...");try{const r=await this._tokenRefreshCallback();if(r)return t.apiCall("Token refreshed successfully, retrying request"),s.headers.Authorization=`Bearer ${r}`,await this._makeRequest(e,s,!0)}catch(e){throw t.apiError("Token refresh failed",e),new a("Authentication expired and refresh failed")}}return o}catch(e){throw clearTimeout(n),e}}async _handleResponse(e){const t=e.headers.get("content-type");let r;if(r=t?.includes("application/json")?await e.json():await e.text(),!e.ok)throw new s(r.message||r.detail||`HTTP Error: ${e.status}`,e.status,r);return r}_handleError(e,t,c,l){return"AbortError"===e.name?new r(`Request timeout after ${c.timeout}ms`):401===e.status?new a("Authentication failed. Please log in again."):403===e.status?new a("Access denied. You do not have permission to access this resource."):404===e.status?new n("Resource not found. The service may be temporarily unavailable."):422===e.status?new i("Invalid data provided. Please check your input and try again.",e.data):e.status>=500?new o("Server error. Please try again later."):e instanceof s?e:e.message?.includes("Failed to fetch")||e.message?.includes("NetworkError")?new r("Unable to connect to the service. Please check your internet connection and try again."):e.message?.includes("CORS")?new r("There was a cross-origin request error. This may be a temporary server issue."):new r(e.message||"Network error")}get(e,t={}){return this.request(e,{...t,method:"GET"})}post(e,t,s={}){return this.request(e,{...s,method:"POST",data:t})}put(e,t,s={}){return this.request(e,{...s,method:"PUT",data:t})}delete(e,t={}){return this.request(e,{...t,method:"DELETE"})}}class g{constructor(e={}){this.config=new d(e),this.config.validate(),this.http=new p(this.config),this.http.setTokenRefreshCallback(this._refreshToken.bind(this)),this.auth=new c(this.http,this.config),this.mealPlans=new l(this.http,this.config),this.users=new u(this.http,this.config),this.recipes=new h(this.http,this.config),this._accessToken=null,this._user=null,this._refreshToken=null,e.accessToken&&this.setAccessToken(e.accessToken),t.debug("DelectableSDK initialized",{baseURL:this.config.baseURL,hasToken:!!this._accessToken})}setAccessToken(e){return this._accessToken=e,this.http.setDefaultHeader("Authorization",`Bearer ${e}`),t.userAuth("Access token configured"),this}setUser(e){return this._user=e,t.userData("Current user set",e),this}async initialize(e={}){t.debug("Initializing DelectableSDK");try{if(!this._accessToken&&!1!==e.autoAuth){t.debug("No access token found, attempting anonymous authentication");const e=await this.auth.loginAnonymous();this.setAccessToken(e.access_token),e.refresh_token&&(this._refreshToken=e.refresh_token)}if(e.userId){t.debug("Fetching user profile",{userId:e.userId});try{const t=await this.users.getUserProfile(e.userId);t&&this.setUser(t.UserObj)}catch(e){t.warn("Failed to fetch user profile during initialization",e)}}return t.debug("DelectableSDK initialization completed"),this}catch(e){throw t.error("DelectableSDK initialization failed",e),new Error(`SDK initialization failed: ${e.message}`)}}async login(e,s){t.userAuth("Logging in with credentials",{username:e});try{const r=await this.auth.login(e,s);this.setAccessToken(r.access_token),r.refresh_token&&(this._refreshToken=r.refresh_token);try{const t=await this.users.getUserProfile(e);t&&this.setUser(t.UserObj)}catch(e){t.warn("Failed to fetch user profile after login",e)}return t.userAuth("Login successful",{username:e}),r}catch(e){throw t.apiError("Login failed",e),e}}logout(){t.userAuth("Logging out"),this._accessToken=null,this._refreshToken=null,this._user=null,this.http.setDefaultHeader("Authorization",null),t.userAuth("Logout completed")}async _refreshToken(){if(!this._refreshToken){t.warn("No refresh token available, attempting anonymous login");return(await this.auth.loginAnonymous()).access_token}try{return await this.auth.refreshToken(this._refreshToken)}catch(e){t.apiError("Token refresh failed",e);const s=await this.auth.loginAnonymous();return this._refreshToken=s.refresh_token,s.access_token}}get isAuthenticated(){return!!this._accessToken}get currentUser(){return this._user}get accessToken(){return this._accessToken}setDebug(e){e?(t.enableCategory("DEBUG"),t.enableCategory("API_CALLS")):(t.disableCategory("DEBUG"),t.disableCategory("API_CALLS"))}getStatus(){return{isAuthenticated:this.isAuthenticated,hasUser:!!this._user,baseURL:this.config.baseURL,currentUser:this._user?.id||null,debug:this.config.debug}}}function f(e={}){return new g(e)}export{c as AuthModule,a as AuthenticationError,d as Config,s as DelectableError,g as DelectableSDK,p as HttpClient,t as Logger,l as MealPlansModule,r as NetworkError,n as NotFoundError,h as RecipesModule,o as ServerError,u as UsersModule,i as ValidationError,f as createSDK,g as default};
//# sourceMappingURL=delectable-sdk.esm.min.js.map