UNPKG

@titamedia/delectable-sdk

Version:

SDK oficial para los servicios del chatbot Delectable

3 lines (2 loc) 23.3 kB
!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).DelectableSDK={})}(this,function(e){"use strict";const t={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 s{static _log(e,s,r,a=null){if(!t[e])return;const i=`[${(new Date).toISOString().split("T")[1].split(".")[0]}] [@delectable/sdk] [${e}]`;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(e){t.hasOwnProperty(e)?(t[e]=!0,console.log(`✅ [@delectable/sdk] Logger: Enabled category '${e}'`)):console.warn(`⚠️ [@delectable/sdk] Logger: Unknown category '${e}'`)}static disableCategory(e){t.hasOwnProperty(e)?(t[e]=!1,console.log(`❌ [@delectable/sdk] Logger: Disabled category '${e}'`)):console.warn(`⚠️ [@delectable/sdk] Logger: Unknown category '${e}'`)}static showConfig(){console.log("🔧 [@delectable/sdk] Logger Configuration:"),Object.entries(t).forEach(([e,t])=>{console.log(` ${t?"✅":"❌"} ${e}`)})}static enableAll(){Object.keys(t).forEach(e=>{t[e]=!0}),console.log("🔥 [@delectable/sdk] Logger: All categories enabled")}static disableAll(){Object.keys(t).forEach(e=>{"ERRORS"!==e&&"WARNINGS"!==e&&(t[e]=!1)}),console.log("🔇 [@delectable/sdk] Logger: All non-critical categories disabled")}}class r extends Error{constructor(e,t=null,s=null){super(e),this.name="DelectableError",this.status=t,this.data=s}}class a extends r{constructor(e){super(e),this.name="NetworkError"}}class i extends r{constructor(e){super(e),this.name="AuthenticationError",this.status=401}}class n extends r{constructor(e,t=null){super(e),this.name="ValidationError",this.status=422,this.validationErrors=t}}class o extends r{constructor(e){super(e),this.name="NotFoundError",this.status=404}}class c extends r{constructor(e){super(e),this.name="ServerError",this.status=500}}class l{constructor(e,t){this.http=e,this.config=t}async loginAnonymous(){s.userAuth("Attempting anonymous login");try{const e=await this.http.post(this.config.endpoints.LOGIN_ANONYMOUS);return s.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 s.apiError("Anonymous login failed",e),new i("Failed to authenticate anonymously")}}async login(e,t){if(!e||"undefined"===e||""===e.trim())throw new n("Valid username is required");if(!t)throw new n("Password is required");s.userAuth("Attempting user login",{username:e});const r=new URLSearchParams({grant_type:"password",username:e,password:t,scope:"",client_id:"",client_secret:""});try{const t=await this.http.request(this.config.endpoints.LOGIN,{method:"POST",headers:{"Content-Type":"application/x-www-form-urlencoded"},body:r.toString()});if(t&&t.access_token)return s.userAuth("User login successful",{username:e,session_id:t.session_id}),{access_token:t.access_token,token_type:t.token_type,session_id:t.session_id,user_id:e,token:t.access_token,sessionId:t.session_id,userId:e};throw new i(`Login failed for ${e}`)}catch(t){throw s.apiError("User login failed",t),new i(`Login failed for ${e}: ${t.message}`)}}async refreshToken(e){s.userAuth("Attempting token refresh");try{const e=await this.loginAnonymous();return s.userAuth("Token refreshed via anonymous login"),e.access_token}catch(e){throw s.apiError("Token refresh failed",e),new i("Failed to refresh authentication token")}}}class u{constructor(e,t){this.http=e,this.config=t}async fetchMealPlans({username:e,skip:t=0,limit:r=10}={}){if(!e)throw new n("Username is required for fetching meal plans");s.apiCall("Fetching meal plans",{username:e,skip:t,limit:r});const a=`${this.config.endpoints.MEAL_PLANS}/?skip=${t}&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){s.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 n("Meal plan ID is required for deletion");s.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){s.apiCall("Generating meal plan",e);const t=this._buildMealPlanFromForm(e);return await this.createMealPlan(t)}_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,t){throw s.apiError(`Meal plan operation failed: ${t}`,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 ${t}: ${e.message}`)}}class h{constructor(e,t){this.http=e,this.config=t}async getUserProfile(e){if(!e)throw new n("User ID is required");s.userData("Fetching user profile",{userId:e});const t=encodeURIComponent(e),r=`${this.config.endpoints.USERS}${t}`;try{const e=await this.http.get(r);return s.userData("User profile retrieved successfully",e),{UserObj:e}}catch(t){if(404===t.status)return s.userData("User profile not found",{userId:e}),null;throw t}}async updateUserProfile(e){if(!e||!e.id)throw new n("Profile data with ID is required");s.userData("Updating user profile",e);const t=encodeURIComponent(e.id),r=`${this.config.endpoints.USERS}${t}`;try{const t=await this.http.put(r,e);return s.userData("User profile updated successfully",t),{profileUpdateMSG:"Profile updated successfully!",data:t}}catch(e){throw s.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 n("Valid email is required");s.userData("Creating basic user",{email:e});const t=e.split("@"),r={username:e,password:this._generateSecurePassword(),user_source:"Delectable",agree_to_license:!0,email:e,first_name:t[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 i=`${this.config.endpoints.USERS}?${a.toString()}`;try{const e=await this.http.post(i,{});return s.userData("Basic user created successfully",e),{createUserMSG:"Basic user created successfully!",success:!0,data:e,userData:{...r,password:"[HIDDEN]"}}}catch(e){if(s.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 n("User ID is required");s.userData("Deleting user account",{userId:e});const t=encodeURIComponent(e),r=`${this.config.endpoints.USERS}${t}`;try{return await this.http.delete(r),s.userData("User account deleted successfully",{userId:e}),{deleteAccountMSG:"Account deleted successfully",success:!0}}catch(e){throw s.apiError("Failed to delete user account",e),new Error(`Failed to delete account: ${e.message}`)}}async getVtexProfile(e){if(!e)throw new n("Email is required for VTEX profile request");s.userData("Getting VTEX profile",{email:e});const t=encodeURIComponent(e),r=`${this.config.endpoints.VTEX_PROFILE}?email=${t}`;try{const e=await this.http.get(r);return s.userData("VTEX profile retrieved successfully",e),{vtexProfileMSG:"VTEX profile retrieved successfully",success:!0,...e}}catch(e){return s.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 n("Valid VTEX profile with email is required");s.userData("Creating user from VTEX profile",{email:e.email});const t={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(t).forEach(e=>{null!=t[e]&&""!==t[e]&&r.append(e,t[e])});const a=`${this.config.endpoints.USERS}?${r.toString()}`;try{const e=await this.http.post(a,{});return s.userData("User created from VTEX successfully",e),{createUserMSG:"User created successfully from VTEX profile!",success:!0,data:e,userData:{...t,password:"[HIDDEN]"}}}catch(e){if(s.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 d{constructor(e,t){this.httpClient=e,this.config=t,this.logger=new s("RecipesModule")}async fetchUserRecipes(e,t,s="*",r=100,o=!0){if(this.logger.info(`Fetching user recipes for: ${t}`),this.logger.debug("Request params:",{recipeQuery:s,numSuggestions:r,includeSponsored:o}),!e||!t)throw new n("Access token and username are required for recipes service");try{const t=new URLSearchParams({recipe_query:s,num_suggestions:r.toString(),include_sponsored:o.toString()}),a=`${this.config.endpoints.RECIPES}/user?${t}`;this.logger.debug(`Using endpoint: ${a}`);const i=await this.httpClient.request({method:"GET",url:a,headers:{Authorization:`Bearer ${e}`,"Content-Type":"application/json"}});return this.logger.debug("API response received:",{type:typeof i,isArray:Array.isArray(i),length:i?.length||0}),Array.isArray(i)?(this.logger.info(`Successfully fetched ${i.length} recipes`),i):(this.logger.warn("Unexpected response format, returning empty array"),[])}catch(e){throw this.logger.error("Error fetching user recipes:",e),401===e.status?new i("Invalid or expired access token"):e.status>=400&&e.status<500?new n(`Invalid request: ${e.message}`):new a(`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 n("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 n(`Invalid recipe response format for ID: ${s}`)}catch(e){throw this.logger.error("Error fetching recipe by ID:",e),401===e.status?new i("Invalid or expired access token"):404===e.status?new n(`Recipe not found: ${s}`):e.status>=400&&e.status<500?new n(`Invalid request: ${e.message}`):new a(`Failed to fetch recipe by ID: ${e.message}`)}}async selectRecipeForMeal(e,t,s,r=[],o=5,c=!0){if(this.logger.info(`Selecting recipe for meal: ${s}`),this.logger.debug("Request params:",{mealId:s,userPreferences:r,rating:o,generateIfNotFound:c}),!e||!t||!s)throw new n("Access token, username, and mealId are required for select recipe for meal service");try{const t=Array.isArray(r)&&r.length>0?r.join(", "):"User preferences applied",a=`${this.config.endpoints.RECIPES}/select-recipe-for-meal`,i={meal_id:s,generate_if_not_found:c,rating:o,notes:t};this.logger.debug(`Using endpoint: ${a}`),this.logger.debug("Request body:",i);const l=await this.httpClient.request({method:"POST",url:a,headers:{Authorization:`Bearer ${e}`,"Content-Type":"application/json"},data:i});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 n(`Invalid recipe response format for meal ID: ${s}`)}catch(e){throw this.logger.error("Error selecting recipe for meal:",e),401===e.status?new i("Invalid or expired access token"):404===e.status?new n(`Meal not found: ${s}`):e.status>=400&&e.status<500?new n(`Invalid request: ${e.message}`):new a(`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 i=await this.selectRecipeForMeal(e,t,s,r,a),o=d.extractBestRecipe(i);if(!o)throw new n(`No suitable recipe candidates found for meal: ${s}`);this.logger.debug(`Best candidate selected: "${o.name}" with score: ${o.similarity_score}`);return{candidates:i,bestCandidate:o,completeRecipe:await this.fetchRecipeById(e,t,o.id)}}}class p{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 g{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,t={}){const r=e.startsWith("http")?e:`${this.config.baseURL}${e}`,a={method:"GET",headers:{...this.defaultHeaders,...t.headers},timeout:this.config.timeout,...t};t.data&&"GET"!==a.method&&(a.body=JSON.stringify(t.data)),s.apiCall(`${a.method} ${r}`,{headers:Object.keys(a.headers),hasBody:!!a.body});try{const e=await this._makeRequest(r,a,t.isRetry),i=await this._handleResponse(e);return s.apiSuccess(`${a.method} ${r} completed`,{status:e.status,dataType:typeof i}),i}catch(e){throw s.apiError(`${a.method} ${r} failed`,e),this._handleError(e,r,a,t)}}async _makeRequest(e,t,r=!1){const a=new AbortController,n=setTimeout(()=>a.abort(),t.timeout);try{const o=await fetch(e,{...t,signal:a.signal,mode:"cors",credentials:"omit",referrerPolicy:"no-referrer"});if(clearTimeout(n),401===o.status&&this._tokenRefreshCallback&&!r){s.warn("Token appears to be expired, attempting refresh...");try{const r=await this._tokenRefreshCallback();if(r)return s.apiCall("Token refreshed successfully, retrying request"),t.headers.Authorization=`Bearer ${r}`,await this._makeRequest(e,t,!0)}catch(e){throw s.apiError("Token refresh failed",e),new i("Authentication expired and refresh failed")}}return o}catch(e){throw clearTimeout(n),e}}async _handleResponse(e){const t=e.headers.get("content-type");let s;if(s=t?.includes("application/json")?await e.json():await e.text(),!e.ok)throw new r(s.message||s.detail||`HTTP Error: ${e.status}`,e.status,s);return s}_handleError(e,t,s,l){return"AbortError"===e.name?new a(`Request timeout after ${s.timeout}ms`):401===e.status?new i("Authentication failed. Please log in again."):403===e.status?new i("Access denied. You do not have permission to access this resource."):404===e.status?new o("Resource not found. The service may be temporarily unavailable."):422===e.status?new n("Invalid data provided. Please check your input and try again.",e.data):e.status>=500?new c("Server error. Please try again later."):e instanceof r?e:e.message?.includes("Failed to fetch")||e.message?.includes("NetworkError")?new a("Unable to connect to the service. Please check your internet connection and try again."):e.message?.includes("CORS")?new a("There was a cross-origin request error. This may be a temporary server issue."):new a(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 f{constructor(e={}){this.config=new p(e),this.config.validate(),this.http=new g(this.config),this.http.setTokenRefreshCallback(this._refreshToken.bind(this)),this.auth=new l(this.http,this.config),this.mealPlans=new u(this.http,this.config),this.users=new h(this.http,this.config),this.recipes=new d(this.http,this.config),this._accessToken=null,this._user=null,this._refreshToken=null,e.accessToken&&this.setAccessToken(e.accessToken),s.debug("DelectableSDK initialized",{baseURL:this.config.baseURL,hasToken:!!this._accessToken})}setAccessToken(e){return this._accessToken=e,this.http.setDefaultHeader("Authorization",`Bearer ${e}`),s.userAuth("Access token configured"),this}setUser(e){return this._user=e,s.userData("Current user set",e),this}async initialize(e={}){s.debug("Initializing DelectableSDK");try{if(!this._accessToken&&!1!==e.autoAuth){s.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){s.debug("Fetching user profile",{userId:e.userId});try{const t=await this.users.getUserProfile(e.userId);t&&this.setUser(t.UserObj)}catch(e){s.warn("Failed to fetch user profile during initialization",e)}}return s.debug("DelectableSDK initialization completed"),this}catch(e){throw s.error("DelectableSDK initialization failed",e),new Error(`SDK initialization failed: ${e.message}`)}}async login(e,t){s.userAuth("Logging in with credentials",{username:e});try{const r=await this.auth.login(e,t);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){s.warn("Failed to fetch user profile after login",e)}return s.userAuth("Login successful",{username:e}),r}catch(e){throw s.apiError("Login failed",e),e}}logout(){s.userAuth("Logging out"),this._accessToken=null,this._refreshToken=null,this._user=null,this.http.setDefaultHeader("Authorization",null),s.userAuth("Logout completed")}async _refreshToken(){if(!this._refreshToken){s.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){s.apiError("Token refresh failed",e);const t=await this.auth.loginAnonymous();return this._refreshToken=t.refresh_token,t.access_token}}get isAuthenticated(){return!!this._accessToken}get currentUser(){return this._user}get accessToken(){return this._accessToken}setDebug(e){e?(s.enableCategory("DEBUG"),s.enableCategory("API_CALLS")):(s.disableCategory("DEBUG"),s.disableCategory("API_CALLS"))}getStatus(){return{isAuthenticated:this.isAuthenticated,hasUser:!!this._user,baseURL:this.config.baseURL,currentUser:this._user?.id||null,debug:this.config.debug}}}e.AuthModule=l,e.AuthenticationError=i,e.Config=p,e.DelectableError=r,e.DelectableSDK=f,e.HttpClient=g,e.Logger=s,e.MealPlansModule=u,e.NetworkError=a,e.NotFoundError=o,e.RecipesModule=d,e.ServerError=c,e.UsersModule=h,e.ValidationError=n,e.createSDK=function(e={}){return new f(e)},e.default=f,Object.defineProperty(e,"__esModule",{value:!0})}); //# sourceMappingURL=delectable-sdk.umd.js.map