@strands.gg/accui 2.6.5 → 2.6.7
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/accui.css +1 -1
- package/dist/nuxt/runtime/composables/useStrandsAuth.cjs.js +1 -1
- package/dist/nuxt/runtime/composables/useStrandsAuth.es.js +1 -1
- package/dist/strands-auth-ui.cjs.js +1 -1
- package/dist/strands-auth-ui.es.js +474 -208
- package/dist/useStrandsAuth-BqNW7g0R.cjs.js +1 -0
- package/dist/{useStrandsAuth-B0jI8Gbq.es.js → useStrandsAuth-GX6lPddh.es.js} +45 -11
- package/package.json +1 -1
- package/dist/useStrandsAuth-Dt4KTg73.cjs.js +0 -1
|
@@ -0,0 +1 @@
|
|
|
1
|
+
"use strict";const e=require("vue"),t=require("./useStrandsConfig-BUmt8HfH.cjs.js"),n=new class{cache=new Map;DEFAULT_TTL=3e5;async fetch(e,t,n=this.DEFAULT_TTL){const a=Date.now(),i=this.cache.get(e);if(i&&a-i.timestamp<i.ttl)return i.promise;this.cleanExpired();const r=t().finally(()=>{setTimeout(()=>{this.cache.delete(e)},n)});return this.cache.set(e,{promise:r,timestamp:a,ttl:n}),r}clear(){this.cache.clear()}invalidate(e){this.cache.delete(e)}cleanExpired(){const e=Date.now();for(const[t,n]of this.cache.entries())e-n.timestamp>n.ttl&&this.cache.delete(t)}getStats(){return{size:this.cache.size,entries:Array.from(this.cache.keys())}}},a=function(){let e=null;return(...t)=>{e&&clearTimeout(e),e=setTimeout(()=>{((e,t)=>{"undefined"!=typeof window&&localStorage.setItem(e,t)})(...t)},300)}}(),i=e=>({id:e.id,email:e.email,firstName:e.first_name||e.firstName||"",lastName:e.last_name||e.lastName||"",avatar:e.avatar_url||e.avatar,mfaEnabled:e.mfa_enabled??e.mfaEnabled??0,emailVerified:e.email_verified??e.emailVerified??0,passwordUpdatedAt:e.password_updated_at||e.passwordUpdatedAt,settings:e.settings||{},xp:e.xp||0,level:e.level||1,next_level_xp:e.next_level_xp||e.next_level_xp||4,username:e.username,usernameLastChangedAt:e.username_last_changed_at||e.usernameLastChangedAt,createdAt:e.created_at||e.createdAt,updatedAt:e.updated_at||e.updatedAt||(new Date).toISOString()}),r={currentUser:e.ref(null),currentSession:e.ref(null),loadingStates:e.ref({initializing:1,signingIn:0,signingUp:0,signingOut:0,refreshingToken:0,sendingMfaEmail:0,verifyingMfa:0,loadingProfile:0}),isInitialized:e.ref(0),mfaRequired:e.ref(0),mfaSessionId:e.ref(null),availableMfaMethods:e.ref([])};let o=null,s=null;exports.useStrandsAuth=function(){const{getUrl:d,config:c}=t.useStrandsConfig(),{fetch:l,clear:u,invalidate:h}={fetch:n.fetch.bind(n),clear:n.clear.bind(n),invalidate:n.invalidate.bind(n),getStats:n.getStats.bind(n)},{currentUser:f,currentSession:w,loadingStates:y,isInitialized:g,mfaRequired:m,mfaSessionId:p,availableMfaMethods:S}=r,_=()=>{if(f.value=null,w.value=null,m.value=0,p.value=null,S.value=[],"undefined"!=typeof window&&(localStorage.removeItem("strands_auth_session"),localStorage.removeItem("strands_auth_user")),D(),s=null,u(),"undefined"!=typeof window&&c.value?.onSignOutUrl){const e=window.location.pathname+window.location.search,t=c.value.onSignOutUrl;e!==t&&(window.location.href=t)}},T=e.computed(()=>y.value.initializing),E=e.computed(()=>y.value.signingIn),O=e.computed(()=>y.value.signingUp),v=e.computed(()=>y.value.signingOut),A=e.computed(()=>y.value.refreshingToken),$=e.computed(()=>y.value.sendingMfaEmail),N=e.computed(()=>y.value.verifyingMfa);e.computed(()=>y.value.loadingProfile);const b=e.computed(()=>y.value.signingIn||y.value.signingUp||y.value.signingOut||y.value.refreshingToken||y.value.sendingMfaEmail||y.value.verifyingMfa||y.value.loadingProfile),k=e.computed(()=>y.value.initializing||b.value),C=e.computed(()=>{const e=y.value;return e.initializing?"Checking authentication...":e.signingIn?"Signing you in...":e.signingUp?"Creating your account...":e.signingOut?"Signing you out...":e.refreshingToken?"Refreshing session...":e.sendingMfaEmail?"Sending verification code...":e.verifyingMfa?"Verifying code...":e.loadingProfile?"Loading profile...":"Loading..."}),J=()=>{const e={};return w.value?.accessToken&&(e.Authorization=`Bearer ${w.value.accessToken}`),w.value?.refreshToken&&(e["x-refresh-token"]=w.value.refreshToken),e},P=e.computed(()=>null!==f.value),F=async()=>{if(!w.value?.refreshToken)return 0;if(s)return await s;s=(async()=>{y.value.refreshingToken=1;try{const e=await fetch(d("refresh"),{method:"POST",headers:{"Content-Type":"application/json"},body:JSON.stringify({refresh_token:w.value.refreshToken})});if(!e.ok){if(401===e.status)return _(),0;throw new Error(`Token refresh failed: ${e.status} ${e.statusText}`)}const t=await e.json();t.user&&(f.value=i(t.user),f.value&&"undefined"!=typeof window&&localStorage.setItem("strands_auth_user",JSON.stringify(f.value)));const n={accessToken:t.access_token,refreshToken:t.refresh_token,expiresAt:new Date(Date.now()+3e5),userId:t.user?.id||f.value?.id};return w.value=n,"undefined"!=typeof window&&localStorage.setItem("strands_auth_session",JSON.stringify(n)),U(),h(`sessions:${w.value.accessToken.slice(0,20)}`),1}catch(e){return _(),0}finally{y.value.refreshingToken=0}})();const e=await s;return s=null,e},M=async e=>{try{e.user&&(f.value=i(e.user));const t={accessToken:e.access_token,refreshToken:e.refresh_token,expiresAt:new Date(Date.now()+3e5),userId:f.value?.id||e.user?.id};w.value=t,"undefined"!=typeof window&&(localStorage.setItem("strands_auth_session",JSON.stringify(t)),f.value&&localStorage.setItem("strands_auth_user",JSON.stringify(f.value))),U()}catch(t){}},U=()=>{if(o&&clearTimeout(o),!w.value)return;if("undefined"!=typeof document&&"hidden"===document.visibilityState)return;const e=new Date,t=w.value.expiresAt.getTime()-e.getTime()-6e4;t<=0?F():o=setTimeout(async()=>{"undefined"!=typeof document&&"visible"!==document.visibilityState||await F()&&U()},t)},D=()=>{o&&(clearTimeout(o),o=null)},I=async()=>{if(!g.value){y.value.initializing=1;try{if("undefined"!=typeof window){const t=localStorage.getItem("strands_auth_session"),n=localStorage.getItem("strands_auth_user");if(t&&n)try{const e=JSON.parse(t),a=JSON.parse(n);e.expiresAt=new Date(e.expiresAt),e.expiresAt<=new Date&&e.refreshToken?(w.value=e,f.value=a,await F()||_()):e.expiresAt>new Date?(w.value=e,f.value=a,U()):(localStorage.removeItem("strands_auth_session"),localStorage.removeItem("strands_auth_user"))}catch(e){localStorage.removeItem("strands_auth_session"),localStorage.removeItem("strands_auth_user")}}g.value=1,await new Promise(e=>setTimeout(e,50))}catch(e){}finally{y.value.initializing=0}}};"undefined"!=typeof document&&document.addEventListener("visibilitychange",()=>{"visible"===document.visibilityState&&w.value?(U(),j()):"hidden"===document.visibilityState&&D()}),"undefined"!=typeof window&&window.addEventListener("storage",e=>{"strands_auth_session"!==e.key&&"strands_auth_user"!==e.key||!e.newValue&&f.value&&_()});const j=()=>{if("undefined"!=typeof window&&f.value&&w.value){const e=localStorage.getItem("strands_auth_session"),t=localStorage.getItem("strands_auth_user");e&&t||_()}},R=()=>{D(),u()};try{e.onUnmounted(R)}catch(z){}return g.value||I(),{user:e.computed(()=>f.value),currentUser:e.computed(()=>f.value),currentSession:e.computed(()=>w.value),isAuthenticated:P,isLoading:e.computed(()=>k.value||!g.value),loading:e.computed(()=>b.value),loadingMessage:C,isInitializing:T,isSigningIn:E,isSigningUp:O,isSigningOut:v,isRefreshingToken:A,isSendingMfaEmail:$,isVerifyingMfa:N,mfaRequired:e.computed(()=>m.value),mfaSessionId:e.computed(()=>p.value),availableMfaMethods:e.computed(()=>S.value),signIn:async e=>{y.value.signingIn=1;try{m.value=0,p.value=null,S.value=[];const t={"Content-Type":"application/json"};"undefined"!=typeof window&&window.location&&(t.Origin=window.location.origin);const n=await fetch(d("signIn"),{method:"POST",headers:t,body:JSON.stringify(e)});if(!n.ok)throw 401===n.status?new Error("Invalid email or password"):403===n.status?new Error("Please verify your email address before signing in"):new Error(`Sign in failed: ${n.status} ${n.statusText}`);const a=await n.json();if(a.mfa_required){m.value=1,p.value=a.mfa_session_id||null;const e=(a.available_mfa_methods||[]).map(e=>{let t=`${e.device_type.charAt(0).toUpperCase()+e.device_type.slice(1)} Authentication`;return"hardware"===e.device_type?t=e.device_name||"Security Key":"totp"===e.device_type?t=e.device_name||"Authenticator App":"email"===e.device_type&&(t=e.device_name||"Email Verification"),{id:e.device_id,device_type:e.device_type,device_name:e.device_name||t,is_active:1,created_at:(new Date).toISOString(),last_used_at:e.last_used_at,credential_id:e.credential_id,device_info:e.device_info}});return S.value=e,y.value.signingIn=0,a}return await M(a),a}catch(t){throw t}finally{y.value.signingIn=0}},signUp:async e=>{y.value.signingUp=1;try{throw new Error("Sign up not implemented - please integrate with auth SDK")}finally{y.value.signingUp=0}},signOut:async()=>{y.value.signingOut=1;try{D(),s=null,u(),f.value=null,w.value=null,m.value=0,p.value=null,S.value=[],"undefined"!=typeof window&&(localStorage.removeItem("strands_auth_session"),localStorage.removeItem("strands_auth_user"))}finally{y.value.signingOut=0}},refreshToken:F,fetchProfile:async()=>{const e=`profile:${w.value.accessToken.slice(0,20)}`;y.value.loadingProfile=1;try{return await l(e,async()=>{const e=await fetch(d("profile"),{method:"GET",headers:{"Content-Type":"application/json",Authorization:`Bearer ${w.value?.accessToken}`}});if(!e.ok)throw 401===e.status?new Error("Authentication expired. Please sign in again."):new Error(`Failed to fetch profile: ${e.status} ${e.statusText}`);const t=await e.json();return f.value=i(t),f.value&&"undefined"!=typeof window&&localStorage.setItem("strands_auth_user",JSON.stringify(f.value)),f.value})}finally{y.value.loadingProfile=0}},updateProfile:async e=>{y.value.loadingProfile=1;try{const t=await fetch(d("profile"),{method:"POST",headers:{"Content-Type":"application/json",Authorization:`Bearer ${w.value.accessToken}`},body:JSON.stringify({first_name:e.firstName,last_name:e.lastName})});if(!t.ok)throw 401===t.status?new Error("Authentication expired. Please sign in again."):new Error(`Profile update failed: ${t.status} ${t.statusText}`);const n=await t.json();return f.value=i(n),f.value&&a("strands_auth_user",JSON.stringify(f.value)),f.value}finally{y.value.loadingProfile=0}},updateUserSettings:async e=>{y.value.loadingProfile=1;try{const t=await fetch(d("settings"),{method:"POST",headers:{"Content-Type":"application/json",Authorization:`Bearer ${w.value.accessToken}`},body:JSON.stringify({settings:e})});if(!t.ok)throw 401===t.status?new Error("Authentication expired. Please sign in again."):new Error(`Settings update failed: ${t.status} ${t.statusText}`);const n=await t.json();return f.value=i(n),f.value&&a("strands_auth_user",JSON.stringify(f.value)),f.value}finally{y.value.loadingProfile=0}},changeEmail:async(e,t)=>{y.value.loadingProfile=1;try{const n=await fetch(d("changeEmail"),{method:"POST",headers:{"Content-Type":"application/json",Authorization:`Bearer ${w.value.accessToken}`},body:JSON.stringify({new_email:e,password:t})});if(!n.ok){if(401===n.status)throw new Error("Authentication expired. Please sign in again.");{const e=await n.json().catch(()=>({}));throw new Error(e.message||`Email change failed: ${n.status} ${n.statusText}`)}}const a=await n.json();return f.value&&(f.value={...f.value,email:e,emailVerified:0,updatedAt:(new Date).toISOString()},"undefined"!=typeof window&&localStorage.setItem("strands_auth_user",JSON.stringify(f.value))),a}finally{y.value.loadingProfile=0}},changeUsername:async e=>{y.value.loadingProfile=1;try{const t=await fetch(d("changeUsername"),{method:"POST",headers:{"Content-Type":"application/json",Authorization:`Bearer ${w.value.accessToken}`},body:JSON.stringify({username:e})});if(!t.ok){const e=await t.json().catch(()=>({}));if(409===t.status)throw new Error("Username is already taken");if(e.cooldown_end)throw new Error(`You can only change your username once every 30 days. You can change it again on ${new Date(e.cooldown_end).toLocaleDateString()}`);throw new Error(e.message||`Username change failed: ${t.status} ${t.statusText}`)}const n=await t.json();return f.value&&(f.value={...f.value,username:e,usernameLastChangedAt:(new Date).toISOString(),updatedAt:(new Date).toISOString()},"undefined"!=typeof window&&localStorage.setItem("strands_auth_user",JSON.stringify(f.value))),n}finally{y.value.loadingProfile=0}},getUsernameCooldown:async()=>{const e=await fetch(d("usernameCooldown"),{method:"GET",headers:{Authorization:`Bearer ${w.value.accessToken}`}});if(!e.ok)throw new Error(`Failed to get username cooldown: ${e.status} ${e.statusText}`);return e.json()},checkUsernameAvailability:async e=>{const t=d("checkUsernameAvailability").replace("{username}",encodeURIComponent(e)),n=await fetch(t,{method:"GET",headers:{"Content-Type":"application/json"}});if(!n.ok)throw new Error(`Failed to check username availability: ${n.status} ${n.statusText}`);return n.json()},getUserSessions:async()=>{const e=`sessions:${w.value?.accessToken?.slice(0,20)||"no-token"}`;try{return await l(e,async()=>{const e=J(),t=await fetch(d("sessions"),{method:"GET",headers:e});if(!t.ok)throw await t.text(),new Error(`Failed to get user sessions: ${t.status} ${t.statusText}`);return t.json()},12e4)}catch(t){throw t}},getSessionStats:async()=>{const e=await fetch(d("sessionsStats"),{method:"GET",headers:J()});if(!e.ok)throw new Error(`Failed to get session stats: ${e.status} ${e.statusText}`);return e.json()},revokeSession:async e=>{const t=d("sessionRevoke").replace("{session_id}",encodeURIComponent(e)),n=await fetch(t,{method:"POST",headers:J()});if(!n.ok)throw new Error(`Failed to revoke session: ${n.status} ${n.statusText}`);return 200===n.status},revokeAllOtherSessions:async()=>{const e=await fetch(d("sessionsRevokeAll"),{method:"POST",headers:J()});if(!e.ok)throw new Error(`Failed to revoke all other sessions: ${e.status} ${e.statusText}`);return 200===e.status},initialize:I,setAuthData:M,verifyMfa:async(e,t,n=0)=>{if(!p.value)throw new Error("No MFA session available");y.value.verifyingMfa=1;try{const a=d(n?"mfaBackupCodeVerify":"mfaSigninVerify"),i=n?{mfa_session_id:p.value,backup_code:t}:{mfa_session_id:p.value,device_id:e,code:t},r=await fetch(a,{method:"POST",headers:{"Content-Type":"application/json"},body:JSON.stringify(i)});if(!r.ok){const e=await r.text();let t="MFA verification failed";try{const n=JSON.parse(e);t=n.message||n.error||e}catch{t=e||"MFA verification failed"}throw new Error(t)}const o=await r.json();return m.value=0,p.value=null,S.value=[],await M(o),o}finally{y.value.verifyingMfa=0}},sendMfaEmailCode:async e=>{if(!p.value)throw new Error("No MFA session available");y.value.sendingMfaEmail=1;try{const t=await fetch(d("mfaSigninSendEmail"),{method:"POST",headers:{"Content-Type":"application/json"},body:JSON.stringify({mfa_session_id:p.value,device_id:e})});if(!t.ok){const e=await t.text();let n="Failed to send MFA email code";try{const t=JSON.parse(e);n=t.message||t.error||e}catch{n=e||"Failed to send MFA email code"}throw new Error(n)}return await t.json()}finally{y.value.sendingMfaEmail=0}},getMfaWebAuthnChallenge:async e=>{if(!p.value)throw new Error("No MFA session available");const t=await fetch(d("mfaWebAuthnChallenge"),{method:"POST",headers:{"Content-Type":"application/json"},body:JSON.stringify({mfa_session_id:p.value,device_id:e})});if(!t.ok){const e=await t.text();let n="Failed to get WebAuthn challenge";try{const t=JSON.parse(e);n=t.message||t.error||e}catch{n=e||n}throw new Error(n)}return t.json()},registerHardwareKey:async(e,t,n="hardware")=>{const a=await fetch(d("mfaHardwareStartRegistration"),{method:"POST",headers:{"Content-Type":"application/json",Authorization:`Bearer ${w.value.accessToken}`},body:JSON.stringify({device_name:e,device_type:n})});if(!a.ok){const e=await a.text();let t="Failed to start hardware key registration";try{const n=JSON.parse(e);t=n.message||n.error||e}catch{t=e||"Failed to start hardware key registration"}throw new Error(t)}return a.json()},completeHardwareKeyRegistration:async(e,t,n)=>{const a=await fetch(d("mfaHardwareCompleteRegistration"),{method:"POST",headers:{"Content-Type":"application/json",Authorization:`Bearer ${w.value.accessToken}`},body:JSON.stringify({device_id:e,credential:t})});if(!a.ok){const e=await a.text();let t="Failed to complete hardware key registration";try{const n=JSON.parse(e);t=n.message||n.error||e}catch{t=e||"Failed to complete hardware key registration"}throw new Error(t)}return a.json()},startTokenRefreshTimer:U,stopTokenRefreshTimer:D,getAuthHeaders:J,forceReInit:()=>{g.value=0,y.value.initializing=1,I()}}};
|
|
@@ -125,9 +125,30 @@ const globalState = {
|
|
|
125
125
|
let refreshTimer = null;
|
|
126
126
|
let refreshPromise = null;
|
|
127
127
|
function useStrandsAuth() {
|
|
128
|
-
const { getUrl } = useStrandsConfig();
|
|
128
|
+
const { getUrl, config } = useStrandsConfig();
|
|
129
129
|
const { fetch: cachedFetch, clear: clearCache, invalidate } = useRequestCache();
|
|
130
130
|
const { currentUser, currentSession, loadingStates, isInitialized, mfaRequired, mfaSessionId, availableMfaMethods } = globalState;
|
|
131
|
+
const handleAuthLoss = () => {
|
|
132
|
+
currentUser.value = null;
|
|
133
|
+
currentSession.value = null;
|
|
134
|
+
mfaRequired.value = false;
|
|
135
|
+
mfaSessionId.value = null;
|
|
136
|
+
availableMfaMethods.value = [];
|
|
137
|
+
if (typeof window !== "undefined") {
|
|
138
|
+
localStorage.removeItem("strands_auth_session");
|
|
139
|
+
localStorage.removeItem("strands_auth_user");
|
|
140
|
+
}
|
|
141
|
+
stopTokenRefreshTimer();
|
|
142
|
+
refreshPromise = null;
|
|
143
|
+
clearCache();
|
|
144
|
+
if (typeof window !== "undefined" && config.value?.onSignOutUrl) {
|
|
145
|
+
const currentPath = window.location.pathname + window.location.search;
|
|
146
|
+
const signOutUrl = config.value.onSignOutUrl;
|
|
147
|
+
if (currentPath !== signOutUrl) {
|
|
148
|
+
window.location.href = signOutUrl;
|
|
149
|
+
}
|
|
150
|
+
}
|
|
151
|
+
};
|
|
131
152
|
const isInitializing = computed(() => loadingStates.value.initializing);
|
|
132
153
|
const isSigningIn = computed(() => loadingStates.value.signingIn);
|
|
133
154
|
const isSigningUp = computed(() => loadingStates.value.signingUp);
|
|
@@ -325,7 +346,7 @@ function useStrandsAuth() {
|
|
|
325
346
|
});
|
|
326
347
|
if (!response.ok) {
|
|
327
348
|
if (response.status === 401) {
|
|
328
|
-
|
|
349
|
+
handleAuthLoss();
|
|
329
350
|
return false;
|
|
330
351
|
}
|
|
331
352
|
throw new Error(`Token refresh failed: ${response.status} ${response.statusText}`);
|
|
@@ -352,7 +373,7 @@ function useStrandsAuth() {
|
|
|
352
373
|
invalidate(`sessions:${currentSession.value.accessToken.slice(0, 20)}`);
|
|
353
374
|
return true;
|
|
354
375
|
} catch (error) {
|
|
355
|
-
|
|
376
|
+
handleAuthLoss();
|
|
356
377
|
return false;
|
|
357
378
|
} finally {
|
|
358
379
|
loadingStates.value.refreshingToken = false;
|
|
@@ -653,10 +674,7 @@ function useStrandsAuth() {
|
|
|
653
674
|
currentUser.value = user;
|
|
654
675
|
const refreshSuccess = await refreshToken();
|
|
655
676
|
if (!refreshSuccess) {
|
|
656
|
-
|
|
657
|
-
localStorage.removeItem("strands_auth_user");
|
|
658
|
-
currentSession.value = null;
|
|
659
|
-
currentUser.value = null;
|
|
677
|
+
handleAuthLoss();
|
|
660
678
|
}
|
|
661
679
|
} else if (session.expiresAt > /* @__PURE__ */ new Date()) {
|
|
662
680
|
currentSession.value = session;
|
|
@@ -797,18 +815,34 @@ function useStrandsAuth() {
|
|
|
797
815
|
document.addEventListener("visibilitychange", () => {
|
|
798
816
|
if (document.visibilityState === "visible" && currentSession.value) {
|
|
799
817
|
startTokenRefreshTimer();
|
|
818
|
+
checkAuthState();
|
|
800
819
|
} else if (document.visibilityState === "hidden") {
|
|
801
820
|
stopTokenRefreshTimer();
|
|
802
821
|
}
|
|
803
822
|
});
|
|
804
823
|
}
|
|
824
|
+
if (typeof window !== "undefined") {
|
|
825
|
+
window.addEventListener("storage", (event) => {
|
|
826
|
+
if (event.key === "strands_auth_session" || event.key === "strands_auth_user") {
|
|
827
|
+
if (!event.newValue && currentUser.value) {
|
|
828
|
+
handleAuthLoss();
|
|
829
|
+
}
|
|
830
|
+
}
|
|
831
|
+
});
|
|
832
|
+
}
|
|
833
|
+
const checkAuthState = () => {
|
|
834
|
+
if (typeof window === "undefined") return;
|
|
835
|
+
if (currentUser.value && currentSession.value) {
|
|
836
|
+
const storedSession = localStorage.getItem("strands_auth_session");
|
|
837
|
+
const storedUser = localStorage.getItem("strands_auth_user");
|
|
838
|
+
if (!storedSession || !storedUser) {
|
|
839
|
+
handleAuthLoss();
|
|
840
|
+
}
|
|
841
|
+
}
|
|
842
|
+
};
|
|
805
843
|
const cleanup = () => {
|
|
806
844
|
stopTokenRefreshTimer();
|
|
807
845
|
clearCache();
|
|
808
|
-
if (typeof document !== "undefined") {
|
|
809
|
-
document.removeEventListener("visibilitychange", () => {
|
|
810
|
-
});
|
|
811
|
-
}
|
|
812
846
|
};
|
|
813
847
|
try {
|
|
814
848
|
onUnmounted(cleanup);
|
package/package.json
CHANGED
|
@@ -1 +0,0 @@
|
|
|
1
|
-
"use strict";const e=require("vue"),t=require("./useStrandsConfig-BUmt8HfH.cjs.js"),a=new class{cache=new Map;DEFAULT_TTL=3e5;async fetch(e,t,a=this.DEFAULT_TTL){const n=Date.now(),i=this.cache.get(e);if(i&&n-i.timestamp<i.ttl)return i.promise;this.cleanExpired();const r=t().finally(()=>{setTimeout(()=>{this.cache.delete(e)},a)});return this.cache.set(e,{promise:r,timestamp:n,ttl:a}),r}clear(){this.cache.clear()}invalidate(e){this.cache.delete(e)}cleanExpired(){const e=Date.now();for(const[t,a]of this.cache.entries())e-a.timestamp>a.ttl&&this.cache.delete(t)}getStats(){return{size:this.cache.size,entries:Array.from(this.cache.keys())}}},n=function(){let e=null;return(...t)=>{e&&clearTimeout(e),e=setTimeout(()=>{((e,t)=>{"undefined"!=typeof window&&localStorage.setItem(e,t)})(...t)},300)}}(),i=e=>({id:e.id,email:e.email,firstName:e.first_name||e.firstName||"",lastName:e.last_name||e.lastName||"",avatar:e.avatar_url||e.avatar,mfaEnabled:e.mfa_enabled??e.mfaEnabled??0,emailVerified:e.email_verified??e.emailVerified??0,passwordUpdatedAt:e.password_updated_at||e.passwordUpdatedAt,settings:e.settings||{},xp:e.xp||0,level:e.level||1,next_level_xp:e.next_level_xp||e.next_level_xp||4,username:e.username,usernameLastChangedAt:e.username_last_changed_at||e.usernameLastChangedAt,createdAt:e.created_at||e.createdAt,updatedAt:e.updated_at||e.updatedAt||(new Date).toISOString()}),r={currentUser:e.ref(null),currentSession:e.ref(null),loadingStates:e.ref({initializing:1,signingIn:0,signingUp:0,signingOut:0,refreshingToken:0,sendingMfaEmail:0,verifyingMfa:0,loadingProfile:0}),isInitialized:e.ref(0),mfaRequired:e.ref(0),mfaSessionId:e.ref(null),availableMfaMethods:e.ref([])};let o=null,s=null;exports.useStrandsAuth=function(){const{getUrl:c}=t.useStrandsConfig(),{fetch:d,clear:l,invalidate:h}={fetch:a.fetch.bind(a),clear:a.clear.bind(a),invalidate:a.invalidate.bind(a),getStats:a.getStats.bind(a)},{currentUser:u,currentSession:f,loadingStates:w,isInitialized:y,mfaRequired:g,mfaSessionId:m,availableMfaMethods:p}=r,S=e.computed(()=>w.value.initializing),_=e.computed(()=>w.value.signingIn),T=e.computed(()=>w.value.signingUp),E=e.computed(()=>w.value.signingOut),v=e.computed(()=>w.value.refreshingToken),O=e.computed(()=>w.value.sendingMfaEmail),A=e.computed(()=>w.value.verifyingMfa);e.computed(()=>w.value.loadingProfile);const $=e.computed(()=>w.value.signingIn||w.value.signingUp||w.value.signingOut||w.value.refreshingToken||w.value.sendingMfaEmail||w.value.verifyingMfa||w.value.loadingProfile),N=e.computed(()=>w.value.initializing||$.value),b=e.computed(()=>{const e=w.value;return e.initializing?"Checking authentication...":e.signingIn?"Signing you in...":e.signingUp?"Creating your account...":e.signingOut?"Signing you out...":e.refreshingToken?"Refreshing session...":e.sendingMfaEmail?"Sending verification code...":e.verifyingMfa?"Verifying code...":e.loadingProfile?"Loading profile...":"Loading..."}),k=()=>{const e={};return f.value?.accessToken&&(e.Authorization=`Bearer ${f.value.accessToken}`),f.value?.refreshToken&&(e["x-refresh-token"]=f.value.refreshToken),e},C=e.computed(()=>null!==u.value),J=async()=>{w.value.signingOut=1;try{U(),s=null,l(),u.value=null,f.value=null,g.value=0,m.value=null,p.value=[],"undefined"!=typeof window&&(localStorage.removeItem("strands_auth_session"),localStorage.removeItem("strands_auth_user"))}finally{w.value.signingOut=0}},P=async()=>{if(!f.value?.refreshToken)return 0;if(s)return await s;s=(async()=>{w.value.refreshingToken=1;try{const e=await fetch(c("refresh"),{method:"POST",headers:{"Content-Type":"application/json"},body:JSON.stringify({refresh_token:f.value.refreshToken})});if(!e.ok){if(401===e.status)return await J(),0;throw new Error(`Token refresh failed: ${e.status} ${e.statusText}`)}const t=await e.json();t.user&&(u.value=i(t.user),u.value&&"undefined"!=typeof window&&localStorage.setItem("strands_auth_user",JSON.stringify(u.value)));const a={accessToken:t.access_token,refreshToken:t.refresh_token,expiresAt:new Date(Date.now()+3e5),userId:t.user?.id||u.value?.id};return f.value=a,"undefined"!=typeof window&&localStorage.setItem("strands_auth_session",JSON.stringify(a)),M(),h(`sessions:${f.value.accessToken.slice(0,20)}`),1}catch(e){return await J(),0}finally{w.value.refreshingToken=0}})();const e=await s;return s=null,e},F=async e=>{try{e.user&&(u.value=i(e.user));const t={accessToken:e.access_token,refreshToken:e.refresh_token,expiresAt:new Date(Date.now()+3e5),userId:u.value?.id||e.user?.id};f.value=t,"undefined"!=typeof window&&(localStorage.setItem("strands_auth_session",JSON.stringify(t)),u.value&&localStorage.setItem("strands_auth_user",JSON.stringify(u.value))),M()}catch(t){}},M=()=>{if(o&&clearTimeout(o),!f.value)return;if("undefined"!=typeof document&&"hidden"===document.visibilityState)return;const e=new Date,t=f.value.expiresAt.getTime()-e.getTime()-6e4;t<=0?P():o=setTimeout(async()=>{"undefined"!=typeof document&&"visible"!==document.visibilityState||await P()&&M()},t)},U=()=>{o&&(clearTimeout(o),o=null)},D=async()=>{if(!y.value){w.value.initializing=1;try{if("undefined"!=typeof window){const t=localStorage.getItem("strands_auth_session"),a=localStorage.getItem("strands_auth_user");if(t&&a)try{const e=JSON.parse(t),n=JSON.parse(a);e.expiresAt=new Date(e.expiresAt),e.expiresAt<=new Date&&e.refreshToken?(f.value=e,u.value=n,await P()||(localStorage.removeItem("strands_auth_session"),localStorage.removeItem("strands_auth_user"),f.value=null,u.value=null)):e.expiresAt>new Date?(f.value=e,u.value=n,M()):(localStorage.removeItem("strands_auth_session"),localStorage.removeItem("strands_auth_user"))}catch(e){localStorage.removeItem("strands_auth_session"),localStorage.removeItem("strands_auth_user")}}y.value=1,await new Promise(e=>setTimeout(e,50))}catch(e){}finally{w.value.initializing=0}}};"undefined"!=typeof document&&document.addEventListener("visibilitychange",()=>{"visible"===document.visibilityState&&f.value?M():"hidden"===document.visibilityState&&U()});const I=()=>{U(),l(),"undefined"!=typeof document&&document.removeEventListener("visibilitychange",()=>{})};try{e.onUnmounted(I)}catch(j){}return y.value||D(),{user:e.computed(()=>u.value),currentUser:e.computed(()=>u.value),currentSession:e.computed(()=>f.value),isAuthenticated:C,isLoading:e.computed(()=>N.value||!y.value),loading:e.computed(()=>$.value),loadingMessage:b,isInitializing:S,isSigningIn:_,isSigningUp:T,isSigningOut:E,isRefreshingToken:v,isSendingMfaEmail:O,isVerifyingMfa:A,mfaRequired:e.computed(()=>g.value),mfaSessionId:e.computed(()=>m.value),availableMfaMethods:e.computed(()=>p.value),signIn:async e=>{w.value.signingIn=1;try{g.value=0,m.value=null,p.value=[];const t={"Content-Type":"application/json"};"undefined"!=typeof window&&window.location&&(t.Origin=window.location.origin);const a=await fetch(c("signIn"),{method:"POST",headers:t,body:JSON.stringify(e)});if(!a.ok)throw 401===a.status?new Error("Invalid email or password"):403===a.status?new Error("Please verify your email address before signing in"):new Error(`Sign in failed: ${a.status} ${a.statusText}`);const n=await a.json();if(n.mfa_required){g.value=1,m.value=n.mfa_session_id||null;const e=(n.available_mfa_methods||[]).map(e=>{let t=`${e.device_type.charAt(0).toUpperCase()+e.device_type.slice(1)} Authentication`;return"hardware"===e.device_type?t=e.device_name||"Security Key":"totp"===e.device_type?t=e.device_name||"Authenticator App":"email"===e.device_type&&(t=e.device_name||"Email Verification"),{id:e.device_id,device_type:e.device_type,device_name:e.device_name||t,is_active:1,created_at:(new Date).toISOString(),last_used_at:e.last_used_at,credential_id:e.credential_id,device_info:e.device_info}});return p.value=e,w.value.signingIn=0,n}return await F(n),n}catch(t){throw t}finally{w.value.signingIn=0}},signUp:async e=>{w.value.signingUp=1;try{throw new Error("Sign up not implemented - please integrate with auth SDK")}finally{w.value.signingUp=0}},signOut:J,refreshToken:P,fetchProfile:async()=>{const e=`profile:${f.value.accessToken.slice(0,20)}`;w.value.loadingProfile=1;try{return await d(e,async()=>{const e=await fetch(c("profile"),{method:"GET",headers:{"Content-Type":"application/json",Authorization:`Bearer ${f.value?.accessToken}`}});if(!e.ok)throw 401===e.status?new Error("Authentication expired. Please sign in again."):new Error(`Failed to fetch profile: ${e.status} ${e.statusText}`);const t=await e.json();return u.value=i(t),u.value&&"undefined"!=typeof window&&localStorage.setItem("strands_auth_user",JSON.stringify(u.value)),u.value})}finally{w.value.loadingProfile=0}},updateProfile:async e=>{w.value.loadingProfile=1;try{const t=await fetch(c("profile"),{method:"POST",headers:{"Content-Type":"application/json",Authorization:`Bearer ${f.value.accessToken}`},body:JSON.stringify({first_name:e.firstName,last_name:e.lastName})});if(!t.ok)throw 401===t.status?new Error("Authentication expired. Please sign in again."):new Error(`Profile update failed: ${t.status} ${t.statusText}`);const a=await t.json();return u.value=i(a),u.value&&n("strands_auth_user",JSON.stringify(u.value)),u.value}finally{w.value.loadingProfile=0}},updateUserSettings:async e=>{w.value.loadingProfile=1;try{const t=await fetch(c("settings"),{method:"POST",headers:{"Content-Type":"application/json",Authorization:`Bearer ${f.value.accessToken}`},body:JSON.stringify({settings:e})});if(!t.ok)throw 401===t.status?new Error("Authentication expired. Please sign in again."):new Error(`Settings update failed: ${t.status} ${t.statusText}`);const a=await t.json();return u.value=i(a),u.value&&n("strands_auth_user",JSON.stringify(u.value)),u.value}finally{w.value.loadingProfile=0}},changeEmail:async(e,t)=>{w.value.loadingProfile=1;try{const a=await fetch(c("changeEmail"),{method:"POST",headers:{"Content-Type":"application/json",Authorization:`Bearer ${f.value.accessToken}`},body:JSON.stringify({new_email:e,password:t})});if(!a.ok){if(401===a.status)throw new Error("Authentication expired. Please sign in again.");{const e=await a.json().catch(()=>({}));throw new Error(e.message||`Email change failed: ${a.status} ${a.statusText}`)}}const n=await a.json();return u.value&&(u.value={...u.value,email:e,emailVerified:0,updatedAt:(new Date).toISOString()},"undefined"!=typeof window&&localStorage.setItem("strands_auth_user",JSON.stringify(u.value))),n}finally{w.value.loadingProfile=0}},changeUsername:async e=>{w.value.loadingProfile=1;try{const t=await fetch(c("changeUsername"),{method:"POST",headers:{"Content-Type":"application/json",Authorization:`Bearer ${f.value.accessToken}`},body:JSON.stringify({username:e})});if(!t.ok){const e=await t.json().catch(()=>({}));if(409===t.status)throw new Error("Username is already taken");if(e.cooldown_end)throw new Error(`You can only change your username once every 30 days. You can change it again on ${new Date(e.cooldown_end).toLocaleDateString()}`);throw new Error(e.message||`Username change failed: ${t.status} ${t.statusText}`)}const a=await t.json();return u.value&&(u.value={...u.value,username:e,usernameLastChangedAt:(new Date).toISOString(),updatedAt:(new Date).toISOString()},"undefined"!=typeof window&&localStorage.setItem("strands_auth_user",JSON.stringify(u.value))),a}finally{w.value.loadingProfile=0}},getUsernameCooldown:async()=>{const e=await fetch(c("usernameCooldown"),{method:"GET",headers:{Authorization:`Bearer ${f.value.accessToken}`}});if(!e.ok)throw new Error(`Failed to get username cooldown: ${e.status} ${e.statusText}`);return e.json()},checkUsernameAvailability:async e=>{const t=c("checkUsernameAvailability").replace("{username}",encodeURIComponent(e)),a=await fetch(t,{method:"GET",headers:{"Content-Type":"application/json"}});if(!a.ok)throw new Error(`Failed to check username availability: ${a.status} ${a.statusText}`);return a.json()},getUserSessions:async()=>{const e=`sessions:${f.value?.accessToken?.slice(0,20)||"no-token"}`;try{return await d(e,async()=>{const e=k(),t=await fetch(c("sessions"),{method:"GET",headers:e});if(!t.ok)throw await t.text(),new Error(`Failed to get user sessions: ${t.status} ${t.statusText}`);return t.json()},12e4)}catch(t){throw t}},getSessionStats:async()=>{const e=await fetch(c("sessionsStats"),{method:"GET",headers:k()});if(!e.ok)throw new Error(`Failed to get session stats: ${e.status} ${e.statusText}`);return e.json()},revokeSession:async e=>{const t=c("sessionRevoke").replace("{session_id}",encodeURIComponent(e)),a=await fetch(t,{method:"POST",headers:k()});if(!a.ok)throw new Error(`Failed to revoke session: ${a.status} ${a.statusText}`);return 200===a.status},revokeAllOtherSessions:async()=>{const e=await fetch(c("sessionsRevokeAll"),{method:"POST",headers:k()});if(!e.ok)throw new Error(`Failed to revoke all other sessions: ${e.status} ${e.statusText}`);return 200===e.status},initialize:D,setAuthData:F,verifyMfa:async(e,t,a=0)=>{if(!m.value)throw new Error("No MFA session available");w.value.verifyingMfa=1;try{const n=c(a?"mfaBackupCodeVerify":"mfaSigninVerify"),i=a?{mfa_session_id:m.value,backup_code:t}:{mfa_session_id:m.value,device_id:e,code:t},r=await fetch(n,{method:"POST",headers:{"Content-Type":"application/json"},body:JSON.stringify(i)});if(!r.ok){const e=await r.text();let t="MFA verification failed";try{const a=JSON.parse(e);t=a.message||a.error||e}catch{t=e||"MFA verification failed"}throw new Error(t)}const o=await r.json();return g.value=0,m.value=null,p.value=[],await F(o),o}finally{w.value.verifyingMfa=0}},sendMfaEmailCode:async e=>{if(!m.value)throw new Error("No MFA session available");w.value.sendingMfaEmail=1;try{const t=await fetch(c("mfaSigninSendEmail"),{method:"POST",headers:{"Content-Type":"application/json"},body:JSON.stringify({mfa_session_id:m.value,device_id:e})});if(!t.ok){const e=await t.text();let a="Failed to send MFA email code";try{const t=JSON.parse(e);a=t.message||t.error||e}catch{a=e||"Failed to send MFA email code"}throw new Error(a)}return await t.json()}finally{w.value.sendingMfaEmail=0}},getMfaWebAuthnChallenge:async e=>{if(!m.value)throw new Error("No MFA session available");const t=await fetch(c("mfaWebAuthnChallenge"),{method:"POST",headers:{"Content-Type":"application/json"},body:JSON.stringify({mfa_session_id:m.value,device_id:e})});if(!t.ok){const e=await t.text();let a="Failed to get WebAuthn challenge";try{const t=JSON.parse(e);a=t.message||t.error||e}catch{a=e||a}throw new Error(a)}return t.json()},registerHardwareKey:async(e,t,a="hardware")=>{const n=await fetch(c("mfaHardwareStartRegistration"),{method:"POST",headers:{"Content-Type":"application/json",Authorization:`Bearer ${f.value.accessToken}`},body:JSON.stringify({device_name:e,device_type:a})});if(!n.ok){const e=await n.text();let t="Failed to start hardware key registration";try{const a=JSON.parse(e);t=a.message||a.error||e}catch{t=e||"Failed to start hardware key registration"}throw new Error(t)}return n.json()},completeHardwareKeyRegistration:async(e,t,a)=>{const n=await fetch(c("mfaHardwareCompleteRegistration"),{method:"POST",headers:{"Content-Type":"application/json",Authorization:`Bearer ${f.value.accessToken}`},body:JSON.stringify({device_id:e,credential:t})});if(!n.ok){const e=await n.text();let t="Failed to complete hardware key registration";try{const a=JSON.parse(e);t=a.message||a.error||e}catch{t=e||"Failed to complete hardware key registration"}throw new Error(t)}return n.json()},startTokenRefreshTimer:M,stopTokenRefreshTimer:U,getAuthHeaders:k,forceReInit:()=>{y.value=0,w.value.initializing=1,D()}}};
|