@strands.gg/accui 1.9.0 → 1.10.1

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.
Files changed (51) hide show
  1. package/dist/accui.css +1 -5802
  2. package/dist/nuxt/module.cjs.js +1 -109
  3. package/dist/nuxt/module.cjs.js.map +1 -1
  4. package/dist/nuxt/module.es.js +9 -1
  5. package/dist/nuxt/module.es.js.map +1 -1
  6. package/dist/nuxt/runtime/composables/useStrandsAuth.cjs.js +1 -57
  7. package/dist/nuxt/runtime/composables/useStrandsAuth.cjs.js.map +1 -1
  8. package/dist/nuxt/runtime/composables/useStrandsAuth.es.js +1 -2
  9. package/dist/nuxt/runtime/middleware/auth.global.cjs.js +1 -42
  10. package/dist/nuxt/runtime/middleware/auth.global.cjs.js.map +1 -1
  11. package/dist/nuxt/runtime/middleware/auth.global.es.js +0 -1
  12. package/dist/nuxt/runtime/plugin.client.cjs.js +1 -26
  13. package/dist/nuxt/runtime/plugin.client.cjs.js.map +1 -1
  14. package/dist/nuxt/runtime/plugin.client.es.js +2 -1
  15. package/dist/nuxt/runtime/plugin.client.es.js.map +1 -1
  16. package/dist/nuxt/runtime/plugin.server.cjs.js +1 -17
  17. package/dist/nuxt/runtime/plugin.server.cjs.js.map +1 -1
  18. package/dist/nuxt/runtime/plugin.server.es.js +0 -1
  19. package/dist/nuxt-v4/module.cjs.js +1 -119
  20. package/dist/nuxt-v4/module.cjs.js.map +1 -1
  21. package/dist/nuxt-v4/module.es.js +9 -1
  22. package/dist/nuxt-v4/module.es.js.map +1 -1
  23. package/dist/nuxt-v4/runtime/composables/useStrandsAuth.cjs.js +1 -70
  24. package/dist/nuxt-v4/runtime/composables/useStrandsAuth.cjs.js.map +1 -1
  25. package/dist/nuxt-v4/runtime/composables/useStrandsAuth.es.js +1 -2
  26. package/dist/nuxt-v4/runtime/middleware/auth.global.cjs.js +1 -42
  27. package/dist/nuxt-v4/runtime/middleware/auth.global.cjs.js.map +1 -1
  28. package/dist/nuxt-v4/runtime/middleware/auth.global.es.js +0 -1
  29. package/dist/nuxt-v4/runtime/plugin.client.cjs.js +1 -26
  30. package/dist/nuxt-v4/runtime/plugin.client.cjs.js.map +1 -1
  31. package/dist/nuxt-v4/runtime/plugin.client.es.js +2 -1
  32. package/dist/nuxt-v4/runtime/plugin.client.es.js.map +1 -1
  33. package/dist/nuxt-v4/runtime/plugin.server.cjs.js +1 -22
  34. package/dist/nuxt-v4/runtime/plugin.server.cjs.js.map +1 -1
  35. package/dist/nuxt-v4/runtime/plugin.server.es.js +0 -1
  36. package/dist/strands-auth-ui.cjs.js +1 -9840
  37. package/dist/strands-auth-ui.cjs.js.map +1 -1
  38. package/dist/strands-auth-ui.es.js +1398 -808
  39. package/dist/strands-auth-ui.es.js.map +1 -1
  40. package/dist/useStrandsAuth-CTlaiFqK.cjs +1 -0
  41. package/dist/useStrandsAuth-CTlaiFqK.cjs.map +1 -0
  42. package/dist/{useStrandsAuth-BA8qEUcp.js → useStrandsAuth-Cev-PTun.js} +289 -127
  43. package/dist/useStrandsAuth-Cev-PTun.js.map +1 -0
  44. package/dist/useStrandsConfig-Cxb360Os.js +0 -1
  45. package/dist/useStrandsConfig-Z9_36OcV.cjs +1 -0
  46. package/dist/{useStrandsConfig-Dms13Zd0.cjs.map → useStrandsConfig-Z9_36OcV.cjs.map} +1 -1
  47. package/package.json +1 -1
  48. package/dist/useStrandsAuth-BA8qEUcp.js.map +0 -1
  49. package/dist/useStrandsAuth-Co2lLH4X.cjs +0 -736
  50. package/dist/useStrandsAuth-Co2lLH4X.cjs.map +0 -1
  51. package/dist/useStrandsConfig-Dms13Zd0.cjs +0 -179
@@ -1,5 +1,89 @@
1
- import { ref, computed } from "vue";
1
+ import { ref, computed, onUnmounted } from "vue";
2
2
  import { u as useStrandsConfig } from "./useStrandsConfig-Cxb360Os.js";
3
+ class RequestCache {
4
+ cache = /* @__PURE__ */ new Map();
5
+ DEFAULT_TTL = 5 * 60 * 1e3;
6
+ // 5 minutes
7
+ /**
8
+ * Memoized fetch - prevents duplicate requests and caches results
9
+ */
10
+ async fetch(key, fetcher, ttl = this.DEFAULT_TTL) {
11
+ const now = Date.now();
12
+ const entry = this.cache.get(key);
13
+ if (entry && now - entry.timestamp < entry.ttl) {
14
+ return entry.promise;
15
+ }
16
+ this.cleanExpired();
17
+ const promise = fetcher().finally(() => {
18
+ setTimeout(() => {
19
+ this.cache.delete(key);
20
+ }, ttl);
21
+ });
22
+ this.cache.set(key, {
23
+ promise,
24
+ timestamp: now,
25
+ ttl
26
+ });
27
+ return promise;
28
+ }
29
+ /**
30
+ * Clear all cached entries
31
+ */
32
+ clear() {
33
+ this.cache.clear();
34
+ }
35
+ /**
36
+ * Remove a specific cache entry
37
+ */
38
+ invalidate(key) {
39
+ this.cache.delete(key);
40
+ }
41
+ /**
42
+ * Clean expired cache entries
43
+ */
44
+ cleanExpired() {
45
+ const now = Date.now();
46
+ for (const [key, entry] of this.cache.entries()) {
47
+ if (now - entry.timestamp > entry.ttl) {
48
+ this.cache.delete(key);
49
+ }
50
+ }
51
+ }
52
+ /**
53
+ * Get cache statistics (for debugging)
54
+ */
55
+ getStats() {
56
+ return {
57
+ size: this.cache.size,
58
+ entries: Array.from(this.cache.keys())
59
+ };
60
+ }
61
+ }
62
+ const requestCache = new RequestCache();
63
+ function useRequestCache() {
64
+ return {
65
+ fetch: requestCache.fetch.bind(requestCache),
66
+ clear: requestCache.clear.bind(requestCache),
67
+ invalidate: requestCache.invalidate.bind(requestCache),
68
+ getStats: requestCache.getStats.bind(requestCache)
69
+ };
70
+ }
71
+ function debounce(func, wait) {
72
+ let timeout = null;
73
+ return (...args) => {
74
+ if (timeout) {
75
+ clearTimeout(timeout);
76
+ }
77
+ timeout = setTimeout(() => {
78
+ func(...args);
79
+ }, wait);
80
+ };
81
+ }
82
+ const debouncedSetItem = debounce((key, value) => {
83
+ if (typeof window !== "undefined") {
84
+ localStorage.setItem(key, value);
85
+ }
86
+ }, 300);
3
87
  const mapApiUserToFrontend = (apiUser) => {
4
88
  return {
5
89
  id: apiUser.id,
@@ -20,39 +104,59 @@ const mapApiUserToFrontend = (apiUser) => {
20
104
  updatedAt: apiUser.updated_at || apiUser.updatedAt || (/* @__PURE__ */ new Date()).toISOString()
21
105
  };
22
106
  };
23
- const { getUrl } = useStrandsConfig();
24
- const currentUser = ref(null);
25
- const currentSession = ref(null);
26
- const isInitializing = ref(true);
27
- const isSigningIn = ref(false);
28
- const isSigningUp = ref(false);
29
- const isSigningOut = ref(false);
30
- const isRefreshingToken = ref(false);
31
- const isSendingMfaEmail = ref(false);
32
- const isVerifyingMfa = ref(false);
33
- const isLoadingProfile = ref(false);
34
- const loading = computed(() => isSigningIn.value || isSigningUp.value || isSigningOut.value || isRefreshingToken.value || isSendingMfaEmail.value || isVerifyingMfa.value || isLoadingProfile.value);
35
- const isLoading = computed(() => isInitializing.value || loading.value);
36
- const loadingMessage = computed(() => {
37
- if (isInitializing.value) return "Checking authentication...";
38
- if (isSigningIn.value) return "Signing you in...";
39
- if (isSigningUp.value) return "Creating your account...";
40
- if (isSigningOut.value) return "Signing you out...";
41
- if (isRefreshingToken.value) return "Refreshing session...";
42
- if (isSendingMfaEmail.value) return "Sending verification code...";
43
- if (isVerifyingMfa.value) return "Verifying code...";
44
- return "Loading...";
45
- });
46
- const isInitialized = ref(false);
47
- const mfaRequired = ref(false);
48
- const mfaSessionId = ref(null);
49
- const availableMfaMethods = ref([]);
107
+ const globalState = {
108
+ currentUser: ref(null),
109
+ currentSession: ref(null),
110
+ loadingStates: ref({
111
+ initializing: true,
112
+ signingIn: false,
113
+ signingUp: false,
114
+ signingOut: false,
115
+ refreshingToken: false,
116
+ sendingMfaEmail: false,
117
+ verifyingMfa: false,
118
+ loadingProfile: false
119
+ }),
120
+ isInitialized: ref(false),
121
+ mfaRequired: ref(false),
122
+ mfaSessionId: ref(null),
123
+ availableMfaMethods: ref([])
124
+ };
50
125
  let refreshTimer = null;
126
+ let refreshPromise = null;
51
127
  function useStrandsAuth() {
128
+ const { getUrl } = useStrandsConfig();
129
+ const { fetch: cachedFetch, clear: clearCache, invalidate } = useRequestCache();
130
+ const { currentUser, currentSession, loadingStates, isInitialized, mfaRequired, mfaSessionId, availableMfaMethods } = globalState;
131
+ const isInitializing = computed(() => loadingStates.value.initializing);
132
+ const isSigningIn = computed(() => loadingStates.value.signingIn);
133
+ const isSigningUp = computed(() => loadingStates.value.signingUp);
134
+ const isSigningOut = computed(() => loadingStates.value.signingOut);
135
+ const isRefreshingToken = computed(() => loadingStates.value.refreshingToken);
136
+ const isSendingMfaEmail = computed(() => loadingStates.value.sendingMfaEmail);
137
+ const isVerifyingMfa = computed(() => loadingStates.value.verifyingMfa);
138
+ computed(() => loadingStates.value.loadingProfile);
139
+ const loading = computed(
140
+ () => loadingStates.value.signingIn || loadingStates.value.signingUp || loadingStates.value.signingOut || loadingStates.value.refreshingToken || loadingStates.value.sendingMfaEmail || loadingStates.value.verifyingMfa || loadingStates.value.loadingProfile
141
+ );
142
+ const isLoading = computed(() => loadingStates.value.initializing || loading.value);
143
+ const loadingMessage = computed(() => {
144
+ const states = loadingStates.value;
145
+ if (states.initializing) return "Checking authentication...";
146
+ if (states.signingIn) return "Signing you in...";
147
+ if (states.signingUp) return "Creating your account...";
148
+ if (states.signingOut) return "Signing you out...";
149
+ if (states.refreshingToken) return "Refreshing session...";
150
+ if (states.sendingMfaEmail) return "Sending verification code...";
151
+ if (states.verifyingMfa) return "Verifying code...";
152
+ if (states.loadingProfile) return "Loading profile...";
153
+ return "Loading...";
154
+ });
52
155
  const getAuthHeaders = () => {
53
156
  if (!currentSession.value?.accessToken) {
54
157
  throw new Error("No access token available");
55
158
  }
159
+ currentSession.value.expiresAt;
56
160
  const headers = {
57
161
  "Authorization": `Bearer ${currentSession.value.accessToken}`
58
162
  };
@@ -119,16 +223,20 @@ function useStrandsAuth() {
119
223
  };
120
224
  const isAuthenticated = computed(() => currentUser.value !== null);
121
225
  const signIn = async (credentials) => {
122
- isSigningIn.value = true;
226
+ loadingStates.value.signingIn = true;
123
227
  try {
124
228
  mfaRequired.value = false;
125
229
  mfaSessionId.value = null;
126
230
  availableMfaMethods.value = [];
231
+ const headers = {
232
+ "Content-Type": "application/json"
233
+ };
234
+ if (typeof window !== "undefined" && window.location) {
235
+ headers["Origin"] = window.location.origin;
236
+ }
127
237
  const response = await fetch(getUrl("signIn"), {
128
238
  method: "POST",
129
- headers: {
130
- "Content-Type": "application/json"
131
- },
239
+ headers,
132
240
  body: JSON.stringify(credentials)
133
241
  });
134
242
  if (!response.ok) {
@@ -166,7 +274,7 @@ function useStrandsAuth() {
166
274
  };
167
275
  });
168
276
  availableMfaMethods.value = methods;
169
- isSigningIn.value = false;
277
+ loadingStates.value.signingIn = false;
170
278
  return authData;
171
279
  }
172
280
  await setAuthData(authData);
@@ -174,21 +282,23 @@ function useStrandsAuth() {
174
282
  } catch (error) {
175
283
  throw error;
176
284
  } finally {
177
- isSigningIn.value = false;
285
+ loadingStates.value.signingIn = false;
178
286
  }
179
287
  };
180
288
  const signUp = async (userData) => {
181
- isSigningUp.value = true;
289
+ loadingStates.value.signingUp = true;
182
290
  try {
183
291
  throw new Error("Sign up not implemented - please integrate with auth SDK");
184
292
  } finally {
185
- isSigningUp.value = false;
293
+ loadingStates.value.signingUp = false;
186
294
  }
187
295
  };
188
296
  const signOut = async () => {
189
- isSigningOut.value = true;
297
+ loadingStates.value.signingOut = true;
190
298
  try {
191
299
  stopTokenRefreshTimer();
300
+ refreshPromise = null;
301
+ clearCache();
192
302
  currentUser.value = null;
193
303
  currentSession.value = null;
194
304
  mfaRequired.value = false;
@@ -199,91 +309,106 @@ function useStrandsAuth() {
199
309
  localStorage.removeItem("strands_auth_user");
200
310
  }
201
311
  } finally {
202
- isSigningOut.value = false;
312
+ loadingStates.value.signingOut = false;
203
313
  }
204
314
  };
205
315
  const refreshToken = async () => {
206
316
  if (!currentSession.value?.refreshToken) {
207
317
  return false;
208
318
  }
209
- isRefreshingToken.value = true;
210
- try {
211
- const response = await fetch(getUrl("refresh"), {
212
- method: "POST",
213
- headers: {
214
- "Content-Type": "application/json"
215
- },
216
- body: JSON.stringify({
217
- refresh_token: currentSession.value.refreshToken
218
- })
219
- });
220
- if (!response.ok) {
221
- if (response.status === 401) {
222
- await signOut();
223
- return false;
319
+ if (refreshPromise) {
320
+ console.log("Token refresh already in progress, waiting for completion...");
321
+ return await refreshPromise;
322
+ }
323
+ refreshPromise = (async () => {
324
+ loadingStates.value.refreshingToken = true;
325
+ try {
326
+ const response = await fetch(getUrl("refresh"), {
327
+ method: "POST",
328
+ headers: {
329
+ "Content-Type": "application/json"
330
+ },
331
+ body: JSON.stringify({
332
+ refresh_token: currentSession.value.refreshToken
333
+ })
334
+ });
335
+ if (!response.ok) {
336
+ if (response.status === 401) {
337
+ await signOut();
338
+ return false;
339
+ }
340
+ throw new Error(`Token refresh failed: ${response.status} ${response.statusText}`);
224
341
  }
225
- throw new Error(`Token refresh failed: ${response.status} ${response.statusText}`);
226
- }
227
- const tokenData = await response.json();
228
- if (tokenData.user) {
229
- currentUser.value = mapApiUserToFrontend(tokenData.user);
342
+ const tokenData = await response.json();
343
+ if (tokenData.user) {
344
+ currentUser.value = mapApiUserToFrontend(tokenData.user);
345
+ if (currentUser.value && typeof window !== "undefined") {
346
+ localStorage.setItem("strands_auth_user", JSON.stringify(currentUser.value));
347
+ }
348
+ }
349
+ const newSession = {
350
+ accessToken: tokenData.access_token,
351
+ refreshToken: tokenData.refresh_token,
352
+ expiresAt: new Date(Date.now() + 5 * 60 * 1e3),
353
+ // 5 minutes from now
354
+ userId: tokenData.user?.id || currentUser.value?.id
355
+ };
356
+ currentSession.value = newSession;
230
357
  if (typeof window !== "undefined") {
231
- localStorage.setItem("strands_auth_user", JSON.stringify(currentUser.value));
358
+ localStorage.setItem("strands_auth_session", JSON.stringify(newSession));
232
359
  }
360
+ startTokenRefreshTimer();
361
+ invalidate(`sessions:${currentSession.value.accessToken.slice(0, 20)}`);
362
+ return true;
363
+ } catch (error) {
364
+ await signOut();
365
+ return false;
366
+ } finally {
367
+ loadingStates.value.refreshingToken = false;
233
368
  }
234
- const newSession = {
235
- accessToken: tokenData.access_token,
236
- refreshToken: tokenData.refresh_token,
237
- expiresAt: new Date(Date.now() + 5 * 60 * 1e3),
238
- // 5 minutes from now
239
- userId: tokenData.user?.id || currentUser.value?.id
240
- };
241
- currentSession.value = newSession;
242
- if (typeof window !== "undefined") {
243
- localStorage.setItem("strands_auth_session", JSON.stringify(newSession));
244
- }
245
- startTokenRefreshTimer();
246
- return true;
247
- } catch (error) {
248
- await signOut();
249
- return false;
250
- }
369
+ })();
370
+ const result = await refreshPromise;
371
+ refreshPromise = null;
372
+ return result;
251
373
  };
252
374
  const fetchProfile = async () => {
253
375
  if (!currentSession.value?.accessToken) {
254
376
  throw new Error("No access token available");
255
377
  }
256
- isLoadingProfile.value = true;
378
+ const cacheKey = `profile:${currentSession.value.accessToken.slice(0, 20)}`;
379
+ loadingStates.value.loadingProfile = true;
257
380
  try {
258
- const response = await fetch(getUrl("profile"), {
259
- method: "GET",
260
- headers: {
261
- "Content-Type": "application/json",
262
- "Authorization": `Bearer ${currentSession.value.accessToken}`
381
+ return await cachedFetch(cacheKey, async () => {
382
+ const response = await fetch(getUrl("profile"), {
383
+ method: "GET",
384
+ headers: {
385
+ "Content-Type": "application/json",
386
+ "Authorization": `Bearer ${currentSession.value?.accessToken}`
387
+ }
388
+ });
389
+ if (!response.ok) {
390
+ if (response.status === 401) {
391
+ throw new Error("Authentication expired. Please sign in again.");
392
+ } else {
393
+ throw new Error(`Failed to fetch profile: ${response.status} ${response.statusText}`);
394
+ }
263
395
  }
264
- });
265
- if (!response.ok) {
266
- if (response.status === 401) {
267
- throw new Error("Authentication expired. Please sign in again.");
268
- } else {
269
- throw new Error(`Failed to fetch profile: ${response.status} ${response.statusText}`);
396
+ const userData = await response.json();
397
+ currentUser.value = mapApiUserToFrontend(userData);
398
+ if (currentUser.value && typeof window !== "undefined") {
399
+ localStorage.setItem("strands_auth_user", JSON.stringify(currentUser.value));
270
400
  }
271
- }
272
- const userData = await response.json();
273
- currentUser.value = mapApiUserToFrontend(userData);
274
- if (typeof window !== "undefined") {
275
- localStorage.setItem("strands_auth_user", JSON.stringify(currentUser.value));
276
- }
277
- return currentUser.value;
401
+ return currentUser.value;
402
+ });
278
403
  } finally {
279
- isLoadingProfile.value = false;
404
+ loadingStates.value.loadingProfile = false;
280
405
  }
281
406
  };
282
407
  const updateProfile = async (profileData) => {
283
408
  if (!currentSession.value?.accessToken) {
284
409
  throw new Error("No access token available");
285
410
  }
286
- isLoadingProfile.value = true;
411
+ loadingStates.value.loadingProfile = true;
287
412
  try {
288
413
  const response = await fetch(getUrl("profile"), {
289
414
  method: "POST",
@@ -305,19 +430,19 @@ function useStrandsAuth() {
305
430
  }
306
431
  const updatedUserData = await response.json();
307
432
  currentUser.value = mapApiUserToFrontend(updatedUserData);
308
- if (typeof window !== "undefined") {
309
- localStorage.setItem("strands_auth_user", JSON.stringify(currentUser.value));
433
+ if (currentUser.value) {
434
+ debouncedSetItem("strands_auth_user", JSON.stringify(currentUser.value));
310
435
  }
311
436
  return currentUser.value;
312
437
  } finally {
313
- isLoadingProfile.value = false;
438
+ loadingStates.value.loadingProfile = false;
314
439
  }
315
440
  };
316
441
  const updateUserSettings = async (settings) => {
317
442
  if (!currentSession.value?.accessToken) {
318
443
  throw new Error("No access token available");
319
444
  }
320
- isLoadingProfile.value = true;
445
+ loadingStates.value.loadingProfile = true;
321
446
  try {
322
447
  const response = await fetch(getUrl("settings"), {
323
448
  method: "POST",
@@ -338,19 +463,19 @@ function useStrandsAuth() {
338
463
  }
339
464
  const updatedUserData = await response.json();
340
465
  currentUser.value = mapApiUserToFrontend(updatedUserData);
341
- if (typeof window !== "undefined") {
342
- localStorage.setItem("strands_auth_user", JSON.stringify(currentUser.value));
466
+ if (currentUser.value) {
467
+ debouncedSetItem("strands_auth_user", JSON.stringify(currentUser.value));
343
468
  }
344
469
  return currentUser.value;
345
470
  } finally {
346
- isLoadingProfile.value = false;
471
+ loadingStates.value.loadingProfile = false;
347
472
  }
348
473
  };
349
474
  const changeEmail = async (newEmail, password) => {
350
475
  if (!currentSession.value?.accessToken) {
351
476
  throw new Error("No access token available");
352
477
  }
353
- isLoadingProfile.value = true;
478
+ loadingStates.value.loadingProfile = true;
354
479
  try {
355
480
  const response = await fetch(getUrl("changeEmail"), {
356
481
  method: "POST",
@@ -386,14 +511,14 @@ function useStrandsAuth() {
386
511
  }
387
512
  return result;
388
513
  } finally {
389
- isLoadingProfile.value = false;
514
+ loadingStates.value.loadingProfile = false;
390
515
  }
391
516
  };
392
517
  const verifyMfa = async (deviceId, code, isBackupCode = false) => {
393
518
  if (!mfaSessionId.value) {
394
519
  throw new Error("No MFA session available");
395
520
  }
396
- isVerifyingMfa.value = true;
521
+ loadingStates.value.verifyingMfa = true;
397
522
  try {
398
523
  const endpoint = isBackupCode ? getUrl("mfaBackupCodeVerify") : getUrl("mfaSigninVerify");
399
524
  const body = isBackupCode ? { mfa_session_id: mfaSessionId.value, backup_code: code } : { mfa_session_id: mfaSessionId.value, device_id: deviceId, code };
@@ -420,14 +545,14 @@ function useStrandsAuth() {
420
545
  await setAuthData(authData);
421
546
  return authData;
422
547
  } finally {
423
- isVerifyingMfa.value = false;
548
+ loadingStates.value.verifyingMfa = false;
424
549
  }
425
550
  };
426
551
  const sendMfaEmailCode = async (deviceId) => {
427
552
  if (!mfaSessionId.value) {
428
553
  throw new Error("No MFA session available");
429
554
  }
430
- isSendingMfaEmail.value = true;
555
+ loadingStates.value.sendingMfaEmail = true;
431
556
  try {
432
557
  const response = await fetch(getUrl("mfaSigninSendEmail"), {
433
558
  method: "POST",
@@ -451,7 +576,7 @@ function useStrandsAuth() {
451
576
  const result = await response.json();
452
577
  return result;
453
578
  } finally {
454
- isSendingMfaEmail.value = false;
579
+ loadingStates.value.sendingMfaEmail = false;
455
580
  }
456
581
  };
457
582
  const getMfaWebAuthnChallenge = async (deviceId) => {
@@ -500,7 +625,6 @@ function useStrandsAuth() {
500
625
  }
501
626
  startTokenRefreshTimer();
502
627
  } catch (error) {
503
- console.error("Error setting auth data:", error);
504
628
  }
505
629
  };
506
630
  const startTokenRefreshTimer = () => {
@@ -508,6 +632,9 @@ function useStrandsAuth() {
508
632
  clearTimeout(refreshTimer);
509
633
  }
510
634
  if (!currentSession.value) return;
635
+ if (typeof document !== "undefined" && document.visibilityState === "hidden") {
636
+ return;
637
+ }
511
638
  const now = /* @__PURE__ */ new Date();
512
639
  const expiresAt = currentSession.value.expiresAt;
513
640
  const timeUntilRefresh = expiresAt.getTime() - now.getTime() - 1 * 60 * 1e3;
@@ -516,9 +643,11 @@ function useStrandsAuth() {
516
643
  return;
517
644
  }
518
645
  refreshTimer = setTimeout(async () => {
519
- const success = await refreshToken();
520
- if (success) {
521
- startTokenRefreshTimer();
646
+ if (typeof document === "undefined" || document.visibilityState === "visible") {
647
+ const success = await refreshToken();
648
+ if (success) {
649
+ startTokenRefreshTimer();
650
+ }
522
651
  }
523
652
  }, timeUntilRefresh);
524
653
  };
@@ -530,7 +659,7 @@ function useStrandsAuth() {
530
659
  };
531
660
  const initialize = async () => {
532
661
  if (isInitialized.value) return;
533
- isInitializing.value = true;
662
+ loadingStates.value.initializing = true;
534
663
  try {
535
664
  if (typeof window !== "undefined") {
536
665
  const storedSession = localStorage.getItem("strands_auth_session");
@@ -558,14 +687,14 @@ function useStrandsAuth() {
558
687
  await new Promise((resolve) => setTimeout(resolve, 50));
559
688
  } catch (error) {
560
689
  } finally {
561
- isInitializing.value = false;
690
+ loadingStates.value.initializing = false;
562
691
  }
563
692
  };
564
693
  const changeUsername = async (newUsername) => {
565
694
  if (!currentSession.value?.accessToken) {
566
695
  throw new Error("No access token available");
567
696
  }
568
- isLoadingProfile.value = true;
697
+ loadingStates.value.loadingProfile = true;
569
698
  try {
570
699
  const response = await fetch(getUrl("changeUsername"), {
571
700
  method: "POST",
@@ -600,7 +729,7 @@ function useStrandsAuth() {
600
729
  }
601
730
  return result;
602
731
  } finally {
603
- isLoadingProfile.value = false;
732
+ loadingStates.value.loadingProfile = false;
604
733
  }
605
734
  };
606
735
  const getUsernameCooldown = async () => {
@@ -632,14 +761,26 @@ function useStrandsAuth() {
632
761
  return response.json();
633
762
  };
634
763
  const getUserSessions = async () => {
635
- const response = await fetch(getUrl("sessions"), {
636
- method: "GET",
637
- headers: getAuthHeaders()
638
- });
639
- if (!response.ok) {
640
- throw new Error(`Failed to get user sessions: ${response.status} ${response.statusText}`);
764
+ if (!currentSession.value?.accessToken) {
765
+ throw new Error("No access token available");
766
+ }
767
+ const cacheKey = `sessions:${currentSession.value.accessToken.slice(0, 20)}`;
768
+ try {
769
+ return await cachedFetch(cacheKey, async () => {
770
+ const headers = getAuthHeaders();
771
+ const response = await fetch(getUrl("sessions"), {
772
+ method: "GET",
773
+ headers
774
+ });
775
+ if (!response.ok) {
776
+ const errorText = await response.text();
777
+ throw new Error(`Failed to get user sessions: ${response.status} ${response.statusText}`);
778
+ }
779
+ return response.json();
780
+ }, 2 * 60 * 1e3);
781
+ } catch (error) {
782
+ throw error;
641
783
  }
642
- return response.json();
643
784
  };
644
785
  const getSessionStats = async () => {
645
786
  const response = await fetch(getUrl("sessionsStats"), {
@@ -672,6 +813,27 @@ function useStrandsAuth() {
672
813
  }
673
814
  return response.status === 200;
674
815
  };
816
+ if (typeof document !== "undefined") {
817
+ document.addEventListener("visibilitychange", () => {
818
+ if (document.visibilityState === "visible" && currentSession.value) {
819
+ startTokenRefreshTimer();
820
+ } else if (document.visibilityState === "hidden") {
821
+ stopTokenRefreshTimer();
822
+ }
823
+ });
824
+ }
825
+ const cleanup = () => {
826
+ stopTokenRefreshTimer();
827
+ clearCache();
828
+ if (typeof document !== "undefined") {
829
+ document.removeEventListener("visibilitychange", () => {
830
+ });
831
+ }
832
+ };
833
+ try {
834
+ onUnmounted(cleanup);
835
+ } catch (e) {
836
+ }
675
837
  if (!isInitialized.value) {
676
838
  initialize();
677
839
  }
@@ -723,10 +885,11 @@ function useStrandsAuth() {
723
885
  // Token management
724
886
  startTokenRefreshTimer,
725
887
  stopTokenRefreshTimer,
888
+ getAuthHeaders,
726
889
  // Force re-initialization (useful for testing or navigation)
727
890
  forceReInit: () => {
728
891
  isInitialized.value = false;
729
- isInitializing.value = true;
892
+ loadingStates.value.initializing = true;
730
893
  initialize();
731
894
  }
732
895
  };
@@ -734,4 +897,3 @@ function useStrandsAuth() {
734
897
  export {
735
898
  useStrandsAuth as u
736
899
  };
737
- //# sourceMappingURL=useStrandsAuth-BA8qEUcp.js.map