UNPKG

sdk-simple-auth

Version:

Universal JavaScript/TypeScript authentication SDK with multi-backend support, automatic token refresh, and React integration

3 lines (2 loc) 42.8 kB
import{useState as e,useRef as t,useEffect as s,useCallback as r}from"react";class TokenExtractor{static deepSearchByPaths(e,t){if(!e||"object"!=typeof e)return null;const s=`paths_${JSON.stringify(t)}_${this.generateObjectSignature(e)}`,r=this.searchCache.get(s);if(r&&Date.now()-r.timestamp<this.CACHE_TTL)return r.value;for(const r of t){if(""===r){const t=this.extractFromRoot(e);if(t)return this.searchCache.set(s,{value:t,timestamp:Date.now()}),t;continue}const t=this.getNestedValue(e,r);if(t&&"object"==typeof t)return this.searchCache.set(s,{value:t,timestamp:Date.now()}),t}return this.searchCache.set(s,{value:null,timestamp:Date.now()}),null}static extractFromRoot(e){return["id","_id","email","name","firstName","usuario"].some(t=>void 0!==e[t])?e:null}static getNestedValue(e,t){return t.split(".").reduce((e,t)=>e&&void 0!==e[t]?e[t]:null,e)}static generateObjectSignature(e){try{return Object.keys(e).sort().slice(0,10).join(",")}catch{return"unknown"}}static enhancedDeepSearch(e,t,s=5){if(!e||"object"!=typeof e||s<=0)return null;for(const s of t)if(e.hasOwnProperty(s)&&null!==e[s]&&void 0!==e[s])return e[s];const r=[];for(const[t,s]of Object.entries(e))s&&"object"==typeof s&&!Array.isArray(s)&&r.push({obj:s,depth:1});for(;r.length>0;){const{obj:e,depth:a}=r.shift();if(!(a>=s)){for(const s of t)if(e.hasOwnProperty(s)&&null!==e[s]&&void 0!==e[s])return e[s];for(const[t,s]of Object.entries(e))s&&"object"==typeof s&&!Array.isArray(s)&&r.push({obj:s,depth:a+1})}}return null}static normalizeExpirationTime(e){if(e){if("number"==typeof e){if(e>1609459200){const t=Math.floor(Date.now()/1e3);return Math.max(0,e-t)}return Math.max(0,e)}if("string"==typeof e){if(e.includes("T")||e.includes("-")||e.includes("/")){const t=new Date(e);if(!isNaN(t.getTime())){const e=Date.now(),s=t.getTime(),r=Math.floor((s-e)/1e3);return Math.max(0,r)}}const t=parseInt(e);if(!isNaN(t)){if(t>1609459200){const e=Math.floor(Date.now()/1e3);return Math.max(0,t-e)}return Math.max(0,t)}}}}static extractTokens(e){const t=this.enhancedDeepSearch(e,this.TOKEN_KEYS),s=this.enhancedDeepSearch(e,this.REFRESH_TOKEN_KEYS),r=this.enhancedDeepSearch(e,this.TOKEN_TYPE_KEYS);if(!t)throw new Error("No access token found in response");return{accessToken:t,refreshToken:s,expiresIn:this.extractExpirationTime(e),expiresAt:this.enhancedDeepSearch(e,["expires_at","expiresAt","rt_expires_at"]),tokenType:r||"Bearer",_originalTokenResponse:e}}static extractExpirationTime(e){const t=this.enhancedDeepSearch(e,this.EXPIRES_KEYS);return this.normalizeExpirationTime(t)}static extractUser(e){const t=this.deepSearchByPaths(e,this.USER_SEARCH_PATHS);if(!t||"object"!=typeof t)return this.buildUserFromScatteredFields(e);const s=this.detectBackendType(e,t),r=this.mapToStandardUser(t);return{...r,...this.preserveUnmappedFields(t,r),_originalUserResponse:e,_backendType:s}}static mapToStandardUser(e){return{id:this.findUserField(e,["_id","id","user_id","userId"])||"unknown",email:this.findUserField(e,["email","user_email","userEmail","correo"]),name:this.buildUserName(e),firstName:this.findUserField(e,["firstName","first_name","nombre"]),lastName:this.findUserField(e,["lastName","last_name","apellido"]),role:this.findUserField(e,["role","rol","roles","authorities"]),permissions:this.extractPermissions(e),isActive:this.findUserField(e,["isActive","is_active","active","activo"]),profile:this.findUserField(e,["profile","perfil","profileData"])}}static buildUserName(e){const t=this.findUserField(e,["firstName","first_name","nombre"]),s=this.findUserField(e,["lastName","last_name","apellido"]),r=this.findUserField(e,["name","fullName","full_name","nombreCompleto"]),a=this.findUserField(e,["email","correo"]);return r||(t&&s?`${t} ${s}`:t||(a||"Usuario"))}static findUserField(e,t){for(const s of t)if(void 0!==e[s]&&null!==e[s])return e[s]}static extractPermissions(e){const t=this.findUserField(e,["permissions","permisos","authorities","roles"]);return Array.isArray(t)?t:"string"==typeof t?[t]:[]}static preserveUnmappedFields(e,t){const s={},r=new Set(Object.keys(t));for(const[t,a]of Object.entries(e))r.has(t)||t.startsWith("_")||(s[t]=a);return s}static detectBackendType(e,t){return e.resultado?.data||e.token?.includes?.("|")?"laravel-sanctum":e.data?.user||void 0!==e.success?"node-express":e.accessToken&&!e.data?"jwt-standard":"unknown"}static buildUserFromScatteredFields(e){const t=this.enhancedDeepSearch(e,["id","_id","user_id","userId"]),s=this.enhancedDeepSearch(e,["email","user_email","userEmail"]),r=this.enhancedDeepSearch(e,["name","username","user_name","fullName"]);if(!t&&!s&&!r){const t=this.enhancedDeepSearch(e,this.TOKEN_KEYS);if(t){const s=this.parseUserFromToken(t);if(s)return{...s,_originalUserResponse:e,_backendType:"jwt-parsed"}}return null}return{id:t||"unknown",email:s,name:r||s||"Usuario",_originalUserResponse:e,_backendType:"scattered-fields"}}static parseUserFromToken(e){try{if(e.includes("|"))return null;const t=e.split(".");if(3!==t.length)return null;const s=t[1],r=s.padEnd(s.length+(4-s.length%4)%4,"="),a=JSON.parse(atob(r));return{id:a.sub||a.user_id||a.id||a.userId||"unknown",name:a.name||a.username||a.firstName||a.email||"Usuario",email:a.email,firstName:a.firstName||a.first_name,lastName:a.lastName||a.last_name,role:a.role||a.roles?.[0],permissions:a.permissions||a.authorities||[],...a}}catch(e){return null}}static debugResponse(e,t=0){" ".repeat(t);if(e&&"object"==typeof e){this.detectBackendType(e,e);Object.keys(e).filter(e=>this.TOKEN_KEYS.some(t=>e.toLowerCase().includes(t.toLowerCase()))).length;if(Object.keys(e).filter(e=>["user","data","profile","account"].some(t=>e.toLowerCase().includes(t.toLowerCase()))).length,t<2)for(const[s,r]of Object.entries(e))r&&"object"==typeof r&&!Array.isArray(r)&&this.debugResponse(r,t+1)}}static clearCache(){this.searchCache.clear()}static testExtraction(e){try{this.extractTokens(e),this.extractUser(e)}catch(e){}}}TokenExtractor.TOKEN_KEYS=["accessToken","access_token","token","authToken","auth_token","bearerToken","bearer_token","jwt","jwtToken","jwt_token"],TokenExtractor.REFRESH_TOKEN_KEYS=["refreshToken","refresh_token","renewToken","renew_token","rt_expires_at"],TokenExtractor.EXPIRES_KEYS=["expiresIn","expires_in","exp","expiration","expires_at","expiresAt","expiry","expiry_time","expiryTime","valid_until","validUntil","rt_expires_at"],TokenExtractor.TOKEN_TYPE_KEYS=["tokenType","token_type","type","authType","auth_type"],TokenExtractor.USER_SEARCH_PATHS=["data.user","resultado.data","user","data","profile","userInfo","account",""],TokenExtractor.searchCache=new Map,TokenExtractor.CACHE_TTL=5e3;class LocalStorageAdapter{async setItem(e,t){"undefined"!=typeof window&&localStorage.setItem(e,t)}async getItem(e){return"undefined"!=typeof window?localStorage.getItem(e):null}async removeItem(e){"undefined"!=typeof window&&localStorage.removeItem(e)}async clear(){"undefined"!=typeof window&&localStorage.clear()}}class IndexedDBAdapter{constructor(e="AuthSDK",t=1,s="auth_data"){this.db=null,this.dbName=e,this.dbVersion=t,this.storeName=s}async openDB(){return this.db?this.db:new Promise((e,t)=>{if("undefined"==typeof window||!window.indexedDB)return void t(new Error("IndexedDB not supported"));const s=window.indexedDB.open(this.dbName,this.dbVersion);s.onerror=()=>t(s.error),s.onsuccess=()=>{this.db=s.result,e(this.db)},s.onupgradeneeded=e=>{const t=e.target.result;t.objectStoreNames.contains(this.storeName)||t.createObjectStore(this.storeName,{keyPath:"key"})}})}async setItem(e,t){const s=await this.openDB();return new Promise((r,a)=>{const n=s.transaction([this.storeName],"readwrite").objectStore(this.storeName).put({key:e,value:t});n.onerror=()=>a(n.error),n.onsuccess=()=>r()})}async getItem(e){try{const t=await this.openDB();return new Promise((s,r)=>{const a=t.transaction([this.storeName],"readonly").objectStore(this.storeName).get(e);a.onerror=()=>r(a.error),a.onsuccess=()=>{const e=a.result;s(e?e.value:null)}})}catch(e){return null}}async removeItem(e){const t=await this.openDB();return new Promise((s,r)=>{const a=t.transaction([this.storeName],"readwrite").objectStore(this.storeName).delete(e);a.onerror=()=>r(a.error),a.onsuccess=()=>s()})}async clear(){const e=await this.openDB();return new Promise((t,s)=>{const r=e.transaction([this.storeName],"readwrite").objectStore(this.storeName).clear();r.onerror=()=>s(r.error),r.onsuccess=()=>t()})}}class StorageManager{constructor(e){this.config=e,this.storageAdapter=this.createStorageAdapter()}createStorageAdapter(){return"localStorage"===(this.config.type||"indexedDB")?new LocalStorageAdapter:new IndexedDBAdapter(this.config.dbName,this.config.dbVersion,this.config.storeName)}async storeTokens(e){try{const t=Math.floor(Date.now()/1e3),s={...e,storedAt:t,lastRefreshed:t,version:"1.2.3",sessionId:this.generateSessionId()};await this.storageAdapter.setItem(this.config.tokenKey,JSON.stringify(s)),e.refreshToken&&await this.storageAdapter.setItem(this.config.refreshTokenKey,e.refreshToken)}catch(e){throw new Error("Failed to store authentication tokens")}}async storeUser(e){try{const t={...e,lastUpdated:Math.floor(Date.now()/1e3),sessionId:await this.getCurrentSessionId()};await this.storageAdapter.setItem(this.config.userKey,JSON.stringify(t))}catch(e){throw new Error("Failed to store user information")}}async getStoredTokens(){try{const e=await this.storageAdapter.getItem(this.config.tokenKey);if(!e)return null;let t;try{t=JSON.parse(e)}catch{return{accessToken:e,refreshToken:await this.storageAdapter.getItem(this.config.refreshTokenKey)||void 0}}if(!t.accessToken)return await this.clearTokens(),null;if(t.expiresIn&&t.storedAt){const e=Math.floor(Date.now()/1e3)-t.storedAt,s=Math.max(0,t.expiresIn-e);t.expiresIn=s}const s=await this.storageAdapter.getItem(this.config.refreshTokenKey);return{accessToken:t.accessToken,refreshToken:s||t.refreshToken,expiresIn:t.expiresIn,expiresAt:t.expiresAt,tokenType:t.tokenType}}catch(e){return await this.clearTokens(),null}}async getStoredUser(){try{const e=await this.storageAdapter.getItem(this.config.userKey);if(!e)return null;try{const t=JSON.parse(e);return t.id||t.email?t:(await this.clearUser(),null)}catch{return await this.clearUser(),null}}catch(e){return null}}async getTokenMetadata(){try{const e=await this.storageAdapter.getItem(this.config.tokenKey);if(!e)return null;const t=JSON.parse(e);return{storedAt:t.storedAt,lastRefreshed:t.lastRefreshed,sessionId:t.sessionId,version:t.version}}catch(e){return null}}async updateLastRefreshTime(){try{const e=await this.storageAdapter.getItem(this.config.tokenKey);if(e){const t=JSON.parse(e);t.lastRefreshed=Math.floor(Date.now()/1e3),await this.storageAdapter.setItem(this.config.tokenKey,JSON.stringify(t))}}catch(e){}}async clearTokens(){try{await Promise.all([this.storageAdapter.removeItem(this.config.tokenKey),this.storageAdapter.removeItem(this.config.refreshTokenKey)])}catch(e){}}async clearUser(){try{await this.storageAdapter.removeItem(this.config.userKey)}catch(e){}}async clearAll(){try{await Promise.all([this.clearTokens(),this.clearUser()])}catch(e){}}async hasValidSession(){try{const e=await this.getStoredTokens(),t=await this.getStoredUser();return!(!e?.accessToken||!t?.id)}catch{return!1}}generateSessionId(){return`session_${Date.now()}_${Math.random().toString(36).substr(2,9)}`}async getCurrentSessionId(){try{const e=await this.getTokenMetadata();return e?.sessionId||null}catch{return null}}async migrateStorage(){try{const e=await this.getTokenMetadata();if(!e?.version){const e=await this.getStoredTokens(),t=await this.getStoredUser();e&&t&&(await this.storeTokens(e),await this.storeUser(t))}}catch(e){}}getAdapter(){return this.storageAdapter}getConfig(){return this.config}}class TokenHandler{static detectTokenType(e){if(!e||"string"!=typeof e)return"opaque";if(e.includes("|"))return"sanctum";const t=e.split(".");if(3===t.length)try{const e=t[1],s=e.padEnd(e.length+(4-e.length%4)%4,"=");return atob(s),"jwt"}catch{return"opaque"}return"opaque"}static parseToken(e){switch(this.detectTokenType(e)){case"jwt":return this.parseJWTToken(e);case"sanctum":return this.parseSanctumToken(e);default:return this.parseOpaqueToken(e)}}static parseJWTToken(e){try{const t=e.split(".")[1],s=t.padEnd(t.length+(4-t.length%4)%4,"="),r=atob(s),a=JSON.parse(r);return{type:"jwt",payload:a,exp:a.exp,isValid:!a.exp||a.exp>Math.floor(Date.now()/1e3)}}catch(e){return{type:"jwt",isValid:!1}}}static parseSanctumToken(e){const t=e.split("|");return{type:"sanctum",tokenId:t[0],payload:{tokenId:t[0],hash:t[1]},isValid:!0}}static parseOpaqueToken(e){return{type:"opaque",isValid:!0}}}class ExpirationHandler{static normalizeExpiration(e){if(e){if("number"==typeof e)return e;if("string"==typeof e){if(e.includes("T")||e.includes("-")){const t=new Date(e);if(!isNaN(t.getTime())){const e=Date.now(),s=t.getTime(),r=Math.floor((s-e)/1e3);return Math.max(0,r)}}const t=parseInt(e);if(!isNaN(t)&&t>1e9){const e=Math.floor(Date.now()/1e3);return Math.max(0,t-e)}const s=parseInt(e);if(!isNaN(s))return s}}}static calculateExpiration(e,t,s,r){if(s)return this.normalizeExpiration(s);if(t)return this.normalizeExpiration(t);const a=TokenHandler.parseToken(e);if("jwt"===a.type&&a.exp){const e=Math.floor(Date.now()/1e3);return Math.max(0,a.exp-e)}if(r&&t){const e=Math.floor(Date.now()/1e3)-r;return Math.max(0,t-e)}}}class RefreshManager{constructor(e,t,s,r){this.refreshTimer=null,this.isRefreshing=!1,this.refreshPromise=null,this.refreshAttempts=0,this.lastRefreshTime=0,this.config=e,this.storageManager=t,this.httpClient=s,this.onTokenRefresh=r?.onTokenRefresh,this.onRefreshError=r?.onRefreshError,this.onSessionRenewed=r?.onSessionRenewed}scheduleTokenRefresh(e){if(!this.config.tokenRefresh.enabled||!e.refreshToken)return;this.clearRefreshTimer();const t=ExpirationHandler.calculateExpiration(e.accessToken,e.expiresIn,e.expiresAt);if(!t){const t=1e3*("sanctum"===TokenHandler.parseToken(e.accessToken).type?86400:3600)-1e3*this.config.tokenRefresh.bufferTime;return void(t>0&&this.scheduleRefreshTimer(t))}if(t<(this.config.tokenRefresh.minimumTokenLifetime||300)){const e=1e3*(this.config.tokenRefresh.gracePeriod||60);return void this.scheduleRefreshTimer(e)}const s=1e3*t-1e3*this.config.tokenRefresh.bufferTime,r=Math.max(s,3e4);r>0&&this.scheduleRefreshTimer(r)}async refreshTokens(){if(!this.config.tokenRefresh.enabled)throw new Error("Token refresh is disabled");if(this.isRefreshing&&this.refreshPromise)return this.refreshPromise;const e=Date.now();if(e-this.lastRefreshTime<5e3)throw new Error("Refresh rate limit exceeded");if(e-this.lastRefreshTime>6e4&&(this.refreshAttempts=0),this.refreshAttempts>=this.config.tokenRefresh.maxRetries)throw this.refreshAttempts=0,new Error("Maximum refresh attempts exceeded");this.isRefreshing=!0,this.refreshAttempts++,this.refreshPromise=this.performRefresh();try{const t=await this.refreshPromise;return this.refreshAttempts=0,this.lastRefreshTime=e,t}catch(e){if(this.refreshAttempts<this.config.tokenRefresh.maxRetries){const e=Math.min(2e3*this.refreshAttempts,3e4);setTimeout(()=>{this.storageManager.getStoredTokens().then(e=>{e?.refreshToken?this.refreshTokens().catch(console.error):this.refreshAttempts=0})},e)}else this.refreshAttempts=0;throw e}finally{this.isRefreshing=!1,this.refreshPromise=null}}shouldRefreshToken(e){if(!this.config.tokenRefresh.enabled)return!1;const t=TokenHandler.parseToken(e);if("jwt"===t.type&&t.exp){const e=Math.floor(Date.now()/1e3);return t.exp-e<this.config.tokenRefresh.bufferTime}return!1}async shouldRefreshTokenAsync(e){if(!this.config.tokenRefresh.enabled)return!1;const t=TokenHandler.parseToken(e);if("jwt"===t.type&&t.exp){const e=Math.floor(Date.now()/1e3);return t.exp-e<this.config.tokenRefresh.bufferTime}return this.shouldRefreshBasedOnMetadata()}clearRefreshTimer(){this.refreshTimer&&(clearTimeout(this.refreshTimer),this.refreshTimer=null)}getRefreshStatus(){return{isRefreshing:this.isRefreshing,refreshAttempts:this.refreshAttempts,lastRefreshTime:this.lastRefreshTime,nextRefreshScheduled:null!==this.refreshTimer}}async forceRefresh(){return this.clearRefreshTimer(),this.refreshAttempts=0,this.refreshTokens()}async performRefresh(){const e=await this.storageManager.getStoredTokens(),t=e?.refreshToken;if(!t)throw new Error("No refresh token available");try{const e=`${this.config.authServiceUrl}${this.config.endpoints.refresh}`;let s;s="sanctum"===TokenHandler.parseToken(t).type?await this.httpClient.post(e,{refresh_token:t},{headers:{Authorization:`Bearer ${t}`}}):await this.httpClient.post(e,{refresh_token:t});const r=this.processRefreshResponse(s,t);return await this.storageManager.storeTokens(r),await this.storageManager.updateLastRefreshTime(),this.scheduleTokenRefresh(r),this.onTokenRefresh?.(r),this.onSessionRenewed?.(r),r}catch(e){const t=e instanceof Error?e.message:"Token refresh failed";throw(t.includes("inválidos")||t.includes("invalid")||t.includes("expired")||t.includes("requerido"))&&(await this.storageManager.clearAll(),this.refreshAttempts=this.config.tokenRefresh.maxRetries),this.onRefreshError?.(e instanceof Error?e:new Error(t)),e}}processRefreshResponse(e,t){try{const s=TokenExtractor.extractTokens(e);return s.refreshToken||(s.refreshToken=t),s}catch(t){throw TokenExtractor.debugResponse(e),new Error("Invalid refresh response format")}}scheduleRefreshTimer(e){try{this.refreshTimer=setTimeout(()=>{this.refreshTokens().catch(e=>{this.onRefreshError?.(e)})},e)}catch(e){}}async shouldRefreshBasedOnMetadata(){try{const e=await this.storageManager.getTokenMetadata(),t=await this.storageManager.getStoredTokens();if(!e?.storedAt||!t?.expiresIn)return!1;const s=Math.floor(Date.now()/1e3)-e.storedAt;return t.expiresIn-s<this.config.tokenRefresh.bufferTime}catch(e){return!1}}reset(){this.clearRefreshTimer(),this.isRefreshing=!1,this.refreshPromise=null,this.refreshAttempts=0,this.lastRefreshTime=0}async canRefresh(){try{const e=await this.storageManager.getStoredTokens();return!(!this.config.tokenRefresh.enabled||!e?.refreshToken||this.isRefreshing)}catch{return!1}}}class AuthSDK{constructor(e,t){this.expirationTimer=null,this.stateChangeListeners=[],this.isInitialized=!1,this.config=this.buildConfig(e),this.callbacks=t||{},this.storageManager=new StorageManager(this.config.storage),this.refreshManager=new RefreshManager(this.config,this.storageManager,this.config.httpClient,{onTokenRefresh:e=>{this.handleTokenRefresh(e)},onRefreshError:e=>{this.callbacks.onError?.(e.message)},onSessionRenewed:e=>{this.callbacks.onTokenRefresh?.(e)}}),this.state={isAuthenticated:!1,user:null,tokens:null,loading:!1,error:null,backendType:"unknown",capabilities:{canRefresh:Boolean(this.config.tokenRefresh?.enabled),hasProfile:!0,supportsOTP:!1,supportsBiometric:!1}},this.initializeFromStorage()}buildConfig(e){return{authServiceUrl:e.authServiceUrl,endpoints:{login:"/auth/login",register:"/auth/register",refresh:"/auth/refreshToken",logout:"/auth/logout",profile:"/auth/profile",...e.endpoints},storage:{type:"indexedDB",dbName:"AuthSDK",dbVersion:1,storeName:"auth_data",tokenKey:"auth_access_token",refreshTokenKey:"auth_refresh_token",userKey:"auth_user",...e.storage},tokenRefresh:{enabled:!0,bufferTime:900,maxRetries:3,minimumTokenLifetime:300,gracePeriod:60,...e.tokenRefresh},httpClient:e.httpClient||this.createDefaultHttpClient(),backend:{type:e.backend?.type||"jwt-standard",userSearchPaths:e.backend?.userSearchPaths||["user","data.user"],fieldMappings:e.backend?.fieldMappings||{},preserveOriginalData:e.backend?.preserveOriginalData??!1}}}async login(e){this.setLoading(!0),this.setError(null);try{const t=`${this.config.authServiceUrl}${this.config.endpoints.login}`,s=await this.config.httpClient.post(t,e),r=TokenExtractor.extractTokens(s),a=TokenExtractor.extractUser(s);if(!a)throw new Error("No user information found in login response");return await this.establishSession(r,a),this.callbacks.onLogin?.(a,r),a}catch(e){const t=e instanceof Error?e.message:"Login failed";throw this.setError(t),this.callbacks.onError?.(t),e}finally{this.setLoading(!1)}}async register(e){this.setLoading(!0),this.setError(null);try{const t=`${this.config.authServiceUrl}${this.config.endpoints.register}`,s=await this.config.httpClient.post(t,e);try{const e=TokenExtractor.extractTokens(s),t=TokenExtractor.extractUser(s);if(!t)throw new Error("No user information found in register response");return await this.establishSession(e,t),this.callbacks.onLogin?.(t,e),t}catch(t){const r=TokenExtractor.extractUser(s);return r||{id:"unknown",name:e.name||e.email||"User",email:e.email}}}catch(e){const t=e instanceof Error?e.message:"Registration failed";throw this.setError(t),this.callbacks.onError?.(t),e}finally{this.setLoading(!1)}}async logout(){try{if(this.state.tokens?.accessToken)try{const e=`${this.config.authServiceUrl}${this.config.endpoints.logout}`;await this.config.httpClient.post(e,{},{headers:{Authorization:`Bearer ${this.state.tokens.accessToken}`}})}catch(e){}}finally{await this.clearSession(),this.callbacks.onLogout?.()}}async refreshTokens(){return this.refreshManager.refreshTokens()}onAuthStateChanged(e){return this.stateChangeListeners.push(e),this.isInitialized&&e(this.getState()),()=>{const t=this.stateChangeListeners.indexOf(e);t>-1&&this.stateChangeListeners.splice(t,1)}}getState(){return{...this.state}}getCurrentUser(){return this.state.user}getAccessToken(){return this.state.tokens?.accessToken||null}getRefreshToken(){return this.state.tokens?.refreshToken||null}async isAuthenticated(){return!(!this.state.isAuthenticated||!this.state.tokens?.accessToken)&&this.isTokenValid(this.state.tokens.accessToken)}async getValidAccessToken(){if(!this.state.tokens?.accessToken)return null;if(!this.config.tokenRefresh.enabled){return await this.isTokenValid(this.state.tokens.accessToken)?this.state.tokens.accessToken:null}if(await this.refreshManager.shouldRefreshTokenAsync(this.state.tokens.accessToken)&&await this.refreshManager.canRefresh())try{return(await this.refreshManager.refreshTokens()).accessToken}catch(e){return null}return await this.isTokenValid(this.state.tokens.accessToken)?this.state.tokens.accessToken:null}async getAuthHeaders(){const e=await this.getValidAccessToken();if(!e)throw new Error("No valid authentication token available");return{Authorization:`Bearer ${e}`}}debugToken(e){const t=e||this.state.tokens?.accessToken;if(!t)return;const s=TokenHandler.parseToken(t);if("jwt"===s.type&&s.payload&&s.exp){const e=new Date(1e3*s.exp),t=new Date;Math.max(0,Math.floor((e.getTime()-t.getTime())/1e3))}}debugResponse(e){TokenExtractor.debugResponse(e);try{TokenExtractor.extractTokens(e)}catch(e){}try{TokenExtractor.extractUser(e)}catch(e){}}async forceRefreshTokens(){return this.refreshManager.forceRefresh()}async getExtendedSessionInfo(){const e=await this.storageManager.getStoredTokens(),t=await this.storageManager.getTokenMetadata();return{isValid:!!e?.accessToken&&await this.isTokenValid(e.accessToken),user:this.state.user,tokens:this.state.tokens,tokenType:e?.tokenType||null,tokenFormat:this.detectTokenFormat(e?.accessToken),expiresIn:e?.expiresIn||null,refreshAvailable:await this.refreshManager.canRefresh(),canRefresh:Boolean(this.config.tokenRefresh?.enabled)&&await this.refreshManager.canRefresh(),sessionId:t?.sessionId||null,backendType:this.state.backendType||null,storedAt:t?.storedAt||null,lastRefreshed:t?.lastRefreshed||null,originalResponse:this.state.user?._originalUserResponse||null}}async getSessionInfo(){const e=await this.getExtendedSessionInfo();return{isValid:e.isValid,user:e.user,tokenType:e.tokenType,expiresIn:e.expiresIn,refreshAvailable:e.refreshAvailable,sessionId:e.sessionId}}testExtraction(e){try{TokenExtractor.extractTokens(e),TokenExtractor.extractUser(e)}catch(e){}}detectTokenFormat(e){return e?e.includes("|")?"sanctum":3===e.split(".").length?"jwt":"opaque":null}async initializeFromStorage(){try{await this.storageManager.migrateStorage();const[e,t]=await Promise.all([this.storageManager.getStoredTokens(),this.storageManager.getStoredUser()]);if(e?.accessToken&&t){await this.isTokenValid(e.accessToken)?(this.state={isAuthenticated:!0,user:t,tokens:e,loading:!1,error:null},this.config.tokenRefresh.enabled&&e.refreshToken&&this.refreshManager.scheduleTokenRefresh(e),this.scheduleTokenExpiration(e)):await this.storageManager.clearAll()}else await this.storageManager.clearAll()}catch(e){await this.storageManager.clearAll()}finally{this.isInitialized=!0,this.notifyStateChange()}}async establishSession(e,t){await Promise.all([this.storageManager.storeTokens(e),this.storageManager.storeUser(t)]),this.state={isAuthenticated:!0,user:t,tokens:e,loading:!1,error:null},this.config.tokenRefresh.enabled&&e.refreshToken&&this.refreshManager.scheduleTokenRefresh(e),this.scheduleTokenExpiration(e),this.notifyStateChange()}async clearSession(){await this.storageManager.clearAll(),this.clearExpirationTimer(),this.refreshManager.clearRefreshTimer(),this.refreshManager.reset(),this.state={isAuthenticated:!1,user:null,tokens:null,loading:!1,error:null,isRefreshing:!1,lastActivity:Date.now(),backendType:"unknown",capabilities:{canRefresh:Boolean(this.config.tokenRefresh?.enabled),hasProfile:!0,supportsOTP:!1,supportsBiometric:!1}},this.notifyStateChange()}handleTokenRefresh(e){this.state.tokens=e,this.scheduleTokenExpiration(e),this.notifyStateChange()}scheduleTokenExpiration(e){this.clearExpirationTimer();const t=ExpirationHandler.calculateExpiration(e.accessToken,e.expiresIn,e.expiresAt);t&&t>0&&(this.expirationTimer=setTimeout(()=>{this.handleTokenExpiration()},1e3*t))}async handleTokenExpiration(){if(this.config.tokenRefresh.enabled&&await this.refreshManager.canRefresh())try{return void await this.refreshManager.refreshTokens()}catch(e){}await this.logout(),this.callbacks.onTokenExpired?.()}clearExpirationTimer(){this.expirationTimer&&(clearTimeout(this.expirationTimer),this.expirationTimer=null)}async isTokenValid(e){if(!e)return!1;const t=TokenHandler.parseToken(e);switch(t.type){case"jwt":return t.isValid;case"sanctum":case"opaque":return this.validateStoredToken(e);default:return!1}}async validateStoredToken(e){try{const e=await this.storageManager.getTokenMetadata(),t=await this.storageManager.getStoredTokens();if(!e?.storedAt||!t?.expiresIn)return!0;const s=Math.floor(Date.now()/1e3);return s-e.storedAt<t.expiresIn}catch{return!1}}createDefaultHttpClient(){const makeRequest=async(e,t)=>{const s=await fetch(e,{headers:{"Content-Type":"application/json",...t.headers},...t});if(!s.ok){const e=await s.json().catch(()=>({message:`HTTP ${s.status}: ${s.statusText}`}));throw new Error(e.message||`Request failed with status ${s.status}`)}return s.json()};return{post:async(e,t,s)=>makeRequest(e,{method:"POST",body:t?JSON.stringify(t):void 0,...s}),get:async(e,t)=>makeRequest(e,{method:"GET",...t}),put:async(e,t,s)=>makeRequest(e,{method:"PUT",body:t?JSON.stringify(t):void 0,...s}),delete:async(e,t)=>makeRequest(e,{method:"DELETE",...t})}}setLoading(e){this.state.loading=e,this.notifyStateChange()}setError(e){this.state.error=e,this.notifyStateChange()}notifyStateChange(){const e=this.getState();this.callbacks.onAuthStateChanged?.(e),this.stateChangeListeners.forEach(t=>{try{t(e)}catch(e){}})}debugSession(){this.state.tokens?.accessToken&&this.debugToken(this.state.tokens.accessToken),this.state.user}}function useAuth(a){const[n,i]=e(a.getState()),[o,c]=e(null),h=t(!0);s(()=>()=>{h.current=!1},[]),s(()=>{const e=a.onAuthStateChanged(e=>{h.current&&i(e)});return(async()=>{try{const e=await a.getSessionInfo();h.current&&c({isValid:e.isValid,refreshAvailable:e.refreshAvailable,sessionId:e.sessionId})}catch(e){}})(),e},[a]);const l=r(async e=>{try{const t=await a.login(e),s=await a.getSessionInfo();return h.current&&c({isValid:s.isValid,refreshAvailable:s.refreshAvailable,sessionId:s.sessionId}),t}catch(e){throw e}},[a]),u=r(async e=>{try{const t=await a.register(e),s=await a.getSessionInfo();return h.current&&c({isValid:s.isValid,refreshAvailable:s.refreshAvailable,sessionId:s.sessionId}),t}catch(e){throw e}},[a]),d=r(async()=>{try{await a.logout(),h.current&&c(null)}catch(e){throw e}},[a]),f=r(async()=>{try{const e=await a.refreshTokens(),t=await a.getSessionInfo();return h.current&&c({isValid:t.isValid,refreshAvailable:t.refreshAvailable,sessionId:t.sessionId}),e}catch(e){throw e}},[a]),p=r(async()=>{try{const e=await a.forceRefreshTokens(),t=await a.getSessionInfo();return h.current&&c({isValid:t.isValid,refreshAvailable:t.refreshAvailable,sessionId:t.sessionId}),e}catch(e){throw e}},[a]),m=r(async()=>{try{return await a.getAuthHeaders()}catch(e){throw e}},[a]),k=r(async()=>{try{return await a.getValidAccessToken()}catch(e){throw e}},[a]),g=r(async()=>{try{const e=await a.isAuthenticated(),t=await a.getSessionInfo();return h.current&&c({isValid:t.isValid,refreshAvailable:t.refreshAvailable,sessionId:t.sessionId}),e}catch(e){return!1}},[a]),T=r(e=>{a.debugToken(e)},[a]),y=r(e=>{a.debugResponse(e)},[a]);return{...n,sessionInfo:o,login:l,register:u,logout:d,refreshTokens:f,forceRefreshTokens:p,getAuthHeaders:m,getValidAccessToken:k,checkAuthStatus:g,debugToken:T,debugResponse:y,hasValidSession:n.isAuthenticated&&o?.isValid,canRefresh:o?.refreshAvailable||!1,sessionId:o?.sessionId||null}}const a={"node-express":{userSearchPaths:["data.user","user","data",""],fieldMappings:{userId:["_id","id","userId"],email:["email"],name:["name","username"],firstName:["firstName"],lastName:["lastName"],role:["role"],permissions:["permissions"],token:["accessToken","access_token","token"],refreshToken:["refreshToken","refresh_token"],expires:["expiresIn","expires_in","exp"]},preserveOriginalData:!0,tokenFormat:"jwt"},"laravel-sanctum":{userSearchPaths:["resultado.data","data",""],fieldMappings:{userId:["id","user_id"],email:["email"],name:["name","full_name"],firstName:["first_name","name"],lastName:["last_name"],role:["rol","role"],permissions:["permissions","abilities"],token:["token","access_token"],refreshToken:["refresh_token"],expires:["expires_at","rt_expires_at","expires_in"]},preserveOriginalData:!0,tokenFormat:"opaque"},"jwt-standard":{userSearchPaths:["","user","data"],fieldMappings:{userId:["sub","id","user_id"],email:["email"],name:["name","username"],firstName:["given_name","firstName"],lastName:["family_name","lastName"],role:["role","roles"],permissions:["permissions","scope"],token:["access_token","token"],refreshToken:["refresh_token"],expires:["exp","expires_in"]},preserveOriginalData:!0,tokenFormat:"jwt"},custom:{userSearchPaths:[""],fieldMappings:{userId:["id"],email:["email"],name:["name"],firstName:["firstName"],lastName:["lastName"],role:["role"],permissions:["permissions"],token:["token"],refreshToken:["refreshToken"],expires:["expiresIn"]},preserveOriginalData:!0,tokenFormat:"mixed"}};class AuthSDKFactory{static create(e,t={}){const s=a[e];if(!s)throw new Error(`Backend preset '${e}' not found. Available: ${Object.keys(a).join(", ")}`);const r={authServiceUrl:t.authServiceUrl||"http://localhost:3000",...t,backend:{type:e,userSearchPaths:t.backend?.userSearchPaths||s.userSearchPaths,fieldMappings:(e=>{const t={};for(const[s,r]of Object.entries(e||{}))Array.isArray(r)&&(t[s]=r);return t})(t.backend?.fieldMappings||s.fieldMappings),preserveOriginalData:t.backend?.preserveOriginalData??s.preserveOriginalData}};return new AuthSDK(r)}static createCustom(e){return new AuthSDK(e)}static analyzeResponse(e){const t={backendType:"unknown",structure:{hasUser:!1,hasTokens:!1,userPath:null,tokenFields:[],userFields:[]},extraction:{tokensExtracted:!1,userExtracted:!1,missingFields:[]},recommendations:[]};e.resultado?.data?t.backendType="laravel-sanctum":e.data?.user||void 0!==e.success?t.backendType="node-express":(e.access_token||e.token)&&(t.backendType="jwt-standard");const s=this.getAllKeys(e);t.structure.tokenFields=s.filter(e=>["token","access","bearer","jwt","auth"].some(t=>e.toLowerCase().includes(t))),t.structure.userFields=s.filter(e=>["user","data","profile","account","me"].some(t=>e.toLowerCase().includes(t))),t.structure.hasTokens=t.structure.tokenFields.length>0,t.structure.hasUser=t.structure.userFields.length>0,t.structure.userFields.length>0&&(t.structure.userPath=t.structure.userFields[0]);try{const{TokenExtractor:s}=require("../core/TokenManager");s.extractTokens(e),t.extraction.tokensExtracted=!0}catch(e){t.extraction.missingFields.push("accessToken")}try{const{TokenExtractor:s}=require("../core/TokenManager"),r=s.extractUser(e);t.extraction.userExtracted=!!r}catch(e){t.extraction.missingFields.push("user")}return t.recommendations=this.generateRecommendations(t),t}static testAllPresets(e){const t={};for(const[s,r]of Object.entries(a))try{const{TokenExtractor:r}=require("../core/TokenManager"),a=r.extractTokens(e),n=r.extractUser(e);t[s]={success:!0,extracted:{tokens:a,user:n}}}catch(e){t[s]={success:!1,error:e instanceof Error?e.message:"Unknown error"}}return t}static generateCustomConfig(e,t){const s=this.analyzeResponse(e);return{authServiceUrl:t,backend:{type:"custom",userSearchPaths:s.structure.userPath?[s.structure.userPath]:[""],fieldMappings:{token:s.structure.tokenFields.slice(0,3),userId:["id","_id","user_id"],email:["email","correo"],name:["name","nombre","full_name"]},preserveOriginalData:!0}}}static getAllKeys(e,t=""){const s=[];if(e&&"object"==typeof e)for(const[r,a]of Object.entries(e)){const e=t?`${t}.${r}`:r;s.push(e),a&&"object"==typeof a&&!Array.isArray(a)&&s.push(...this.getAllKeys(a,e))}return s}static generateRecommendations(e){const t=[];return e.extraction.tokensExtracted||t.push(`⚠️ Configure token extraction. Found possible fields: ${e.structure.tokenFields.join(", ")}`),e.extraction.userExtracted||t.push(`⚠️ Configure user extraction. Found possible fields: ${e.structure.userFields.join(", ")}`),"unknown"===e.backendType?(t.push("💡 Consider using custom backend configuration"),t.push("🔧 Use AuthSDKFactory.generateCustomConfig() for automatic setup")):t.push(`✅ Use '${e.backendType}' preset: AuthSDKFactory.create('${e.backendType}')`),e.extraction.tokensExtracted&&e.extraction.userExtracted&&t.push("🎉 Response is fully compatible! No additional configuration needed."),t}}function createNodeExpressAuth(e="http://localhost:3000",t){return AuthSDKFactory.create("node-express",{authServiceUrl:e,...t})}function createLaravelSanctumAuth(e="http://localhost:8000/api",t){return AuthSDKFactory.create("laravel-sanctum",{authServiceUrl:e,...t})}function createJWTStandardAuth(e,t){return AuthSDKFactory.create("jwt-standard",{authServiceUrl:e,...t})}function createAutoDetectAuth(e,t){const s=AuthSDKFactory.analyzeResponse(e);if("unknown"!==s.backendType)return AuthSDKFactory.create(s.backendType,{authServiceUrl:t});{const s=AuthSDKFactory.generateCustomConfig(e,t);return AuthSDKFactory.createCustom(s)}}function testBackendResponse(e,t=!0){AuthSDKFactory.analyzeResponse(e).recommendations.forEach(e=>{});const s=AuthSDKFactory.testAllPresets(e);Object.entries(s).filter(([e,t])=>t.success).forEach(([e,t])=>{})}function createDevAuth(e="node-express",t="http://localhost:3000"){const s=AuthSDKFactory.create(e,{authServiceUrl:t});return s.onAuthStateChanged(e=>{}),s}function runMockTests(){testBackendResponse({success:!0,message:"Inicio de sesión exitoso",data:{user:{_id:"687fd4d0b0b1db461b716dbc",email:"test@test.com",firstName:"Test",lastName:"User",role:"admin",permissions:["*"],isActive:!0,profile:{},createdAt:"2025-07-22T18:06:29.082Z",lastLogin:"2025-07-22T18:06:29.082Z"},accessToken:"eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9...",refreshToken:"eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9...",expiresIn:3600}},!1),testBackendResponse({status:"success",code:200,message:"Inicio de sesión exitoso.",resultado:{status:"success",code:200,message:"Inicio de sesión exitoso.",data:{token:"539|S1O3LzUcTVyjE0UQVMc15RquzYXyvpPP1ktrGbYPe65008ec",expires_at:"2025-07-22 15:20:27",refresh_token:"540|9AP2QMCXKhzDt3u6YHzPq6tE3eT8jdsk50X6dtoV6b8dc0b4",rt_expires_at:"2025-07-23 14:20:27",token_type:"Bearer",name:"olivio",full_name:"Olivio Subelza",sucursales:[{id:1,sucursal:"CENTRAL",sigla:"T01",nombre_comercial:null,rol:"Administrador"},{id:2,sucursal:"Sucursal 2",sigla:"T02",nombre_comercial:null,rol:"Administrador"}]}}},!1),testBackendResponse({access_token:"eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJzdWIiOiIxMjM0NTY3ODkwIiwibmFtZSI6IkpvaG4gRG9lIiwiaWF0IjoxNTE2MjM5MDIyfQ.SflKxwRJSMeKKF2QT4fwpMeJf36POk6yJV_adQssw5c",refresh_token:"refresh_token_here",expires_in:3600,token_type:"Bearer",name:"John Doe",email:"john@example.com"},!1)}async function ejemplo1_BackendActual(){const e=createNodeExpressAuth("http://localhost:3000");try{await e.login({email:"subelzacabezasolivio@gmail.com",password:"tu-password"}),await e.getExtendedSessionInfo(),await e.getValidAccessToken()}catch(e){}}async function ejemplo2_LaravelSanctum(){createLaravelSanctumAuth("http://localhost:8000/api").testExtraction({status:"success",resultado:{data:{token:"539|S1O3LzUcTVyjE0UQVMc15RquzYXyvpPP1ktrGbYPe65008ec",expires_at:"2025-07-22 15:20:27",name:"olivio",full_name:"Olivio Subelza",sucursales:[{id:1,sucursal:"CENTRAL",rol:"Administrador"}]}}})}function ejemplo3_AutoDeteccion(){Object.entries({nodeExpress:{success:!0,data:{user:{_id:"123",email:"test@test.com"},accessToken:"jwt-token"}},laravelSanctum:{resultado:{data:{token:"123|sanctum-token",name:"Usuario Test"}}},jwtStandard:{access_token:"jwt.token.here",name:"User",email:"user@test.com"}}).forEach(([e,t])=>{testBackendResponse(t,!1)})}function ejemplo4_ConfiguracionPersonalizada(){AuthSDKFactory.createCustom({authServiceUrl:"https://mi-api-especial.com",backend:{type:"custom",userSearchPaths:["response.userData","payload.user","data.profile"],fieldMappings:{userId:["usuario_id","id_usuario","id"],email:["correo_electronico","email"],name:["nombre_completo","nombre"],token:["token_acceso","access_token"],expires:["expira_en","tiempo_vida"]},preserveOriginalData:!0},tokenRefresh:{enabled:!0,bufferTime:300}}).testExtraction({response:{userData:{usuario_id:"123",correo_electronico:"test@test.com",nombre_completo:"Usuario Prueba",datos_extra:"información específica"}},token_acceso:"mi-token-custom",expira_en:7200})}function ejemplo5_DebuggingAvanzado(){const e=createNodeExpressAuth(),t={success:!0,data:{user:{_id:"687fd4d0b0b1db461b716dbc",email:"test@test.com",firstName:"Test",lastName:"User",role:"proctor",permissions:["session.monitor","exam.proctor","student.verify"],customField:"valor personalizado"},accessToken:"eyJhbGciOiJIUzI1NiIs...",expiresIn:3600}};AuthSDKFactory.analyzeResponse(t);e.testExtraction(t),AuthSDKFactory.testAllPresets(t)}async function ejemplo6_MigracionDatos(){createNodeExpressAuth();const e={id:"123",email:"user@test.com",name:"Usuario Test"},t="token-antiguo",s=createNodeExpressAuth(),r={success:!0,data:{user:{...e,lastLogin:new Date,preferences:{theme:"dark"},metadata:{source:"migration"}},accessToken:t,expiresIn:3600}};s.testExtraction(r)}function ejemplo7_TestingCompleto(){runMockTests();const e={success:!0,message:"Usuario registrado exitosamente",data:{user:{email:"subelzacabezasolivio@gmail.com",firstName:"olivio",lastName:"olivio",role:"admin",isActive:!0,permissions:["*"],profile:{},createdAt:"2025-07-22T18:06:29.082Z",updatedAt:"2025-07-22T18:06:29.082Z",_id:"687fd3259e7f5bab1712d9ea"},accessToken:"eyJhbGciOiJIUzI1Ni......",refreshToken:"eyJhbGciOiJ.......",expiresIn:3600}};testBackendResponse(e);createNodeExpressAuth("http://localhost:3000").testExtraction(e)}async function ejecutarTodosLosEjemplos(){try{ejemplo3_AutoDeteccion(),ejemplo4_ConfiguracionPersonalizada(),ejemplo5_DebuggingAvanzado(),await ejemplo6_MigracionDatos(),ejemplo7_TestingCompleto()}catch(e){}}function testearTusRespuestas(){const e={success:!0,message:"Inicio de sesión exitoso",data:{user:{_id:"687f1dc236e46ee3b734907a",email:"subelzaolivitocabezas@gmail.com",firstName:"Olivio",lastName:"Cabezas",role:"admin",isActive:!0,permissions:["*"],profile:{},createdAt:"2025-07-22T05:12:34.303Z",updatedAt:"2025-07-22T05:13:14.934Z",lastLogin:"2025-07-22T05:13:14.934Z"},accessToken:"eyJhbGciOiJI.......",refreshToken:"eyJhbGciOiJIUzI1NiIs.......",expiresIn:3600}},t={status:"success",code:200,message:"Successfuly Connected",resultado:{status:"success",code:200,message:"Inicio de sesión exitoso.",data:{token:"539|S1O3LzUcTVyjE0UQVMc15RquzYXyvpPP1ktrGbYPe65008ec",expires_at:"2025-07-22 15:20:27",refresh_token:"540|9AP2QMCXKhzDt3u6YHzPq6tE3eT8jdsk50X6dtoV6b8dc0b4",rt_expires_at:"2025-07-23 14:20:27",token_type:"Bearer",name:"olivio",full_name:"Olivio Subelza",sucursales:[{id:1,sucursal:"CENTRAL",sigla:"T01",nombre_comercial:null,rol:"Administrador"},{id:2,sucursal:"Sucursal 2",sigla:"T02",nombre_comercial:null,rol:"Administrador"}]}}};testBackendResponse(e),testBackendResponse(t);createNodeExpressAuth().testExtraction(e);createLaravelSanctumAuth().testExtraction(t)}"undefined"!=typeof window&&(window.sdkExamples={ejecutarTodosLosEjemplos:ejecutarTodosLosEjemplos,testearTusRespuestas:testearTusRespuestas,ejemplo1_BackendActual:ejemplo1_BackendActual,ejemplo2_LaravelSanctum:ejemplo2_LaravelSanctum,ejemplo3_AutoDeteccion:ejemplo3_AutoDeteccion,ejemplo4_ConfiguracionPersonalizada:ejemplo4_ConfiguracionPersonalizada,ejemplo5_DebuggingAvanzado:ejemplo5_DebuggingAvanzado,ejemplo6_MigracionDatos:ejemplo6_MigracionDatos,ejemplo7_TestingCompleto:ejemplo7_TestingCompleto});var n={ejecutarTodosLosEjemplos:ejecutarTodosLosEjemplos,testearTusRespuestas:testearTusRespuestas,ejemplo1_BackendActual:ejemplo1_BackendActual,ejemplo2_LaravelSanctum:ejemplo2_LaravelSanctum,ejemplo3_AutoDeteccion:ejemplo3_AutoDeteccion,ejemplo4_ConfiguracionPersonalizada:ejemplo4_ConfiguracionPersonalizada,ejemplo5_DebuggingAvanzado:ejemplo5_DebuggingAvanzado,ejemplo6_MigracionDatos:ejemplo6_MigracionDatos,ejemplo7_TestingCompleto:ejemplo7_TestingCompleto};function createQuickNodeAuth(e="http://localhost:3000"){return createNodeExpressAuth(e)}function createQuickSanctumAuth(e="http://localhost:8000/api"){return createLaravelSanctumAuth(e)}function quickAnalyzeAndCreate(e,t){return createAutoDetectAuth(e,t)}function quickTest(e){return testBackendResponse(e)}const i="2.0.0-enhanced-fixed",o={multiBackend:!0,dataPreservation:!0,autoDetection:!0,advancedDebugging:!0,backwardCompatible:!0,esmFixed:!0};export{AuthSDK,AuthSDKFactory,a as BACKEND_PRESETS,IndexedDBAdapter,LocalStorageAdapter,RefreshManager,o as SDK_FEATURES,i as SDK_VERSION,StorageManager,TokenExtractor,createAutoDetectAuth,createDevAuth,createJWTStandardAuth,createLaravelSanctumAuth,createNodeExpressAuth,createQuickNodeAuth,createQuickSanctumAuth,AuthSDKFactory as default,n as examples,quickAnalyzeAndCreate,quickTest,runMockTests,testBackendResponse,useAuth}; //# sourceMappingURL=index.esm.min.js.map