@strands.gg/accui 2.17.66 → 2.19.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 (90) hide show
  1. package/dist/StrandsUIPlugin-5AOCDOcM.cjs.js +143 -0
  2. package/dist/StrandsUIPlugin-B0HUf-tm.es.js +20437 -0
  3. package/dist/StrandsUIPlugin-B98LOdrQ.cjs.js +143 -0
  4. package/dist/StrandsUIPlugin-BbeOau1G.cjs.js +143 -0
  5. package/dist/StrandsUIPlugin-BcARSDQF.cjs.js +143 -0
  6. package/dist/StrandsUIPlugin-CCRrewS9.es.js +20587 -0
  7. package/dist/StrandsUIPlugin-CMTkJfQt.cjs.js +143 -0
  8. package/dist/StrandsUIPlugin-CQONZWOX.es.js +20714 -0
  9. package/dist/StrandsUIPlugin-CQk56uZ2.es.js +19805 -0
  10. package/dist/StrandsUIPlugin-Cgmu6cTA.es.js +20440 -0
  11. package/dist/StrandsUIPlugin-CpBH0QFc.cjs.js +272 -0
  12. package/dist/StrandsUIPlugin-Ct91SLTy.es.js +20587 -0
  13. package/dist/StrandsUIPlugin-DHhawL07.cjs.js +143 -0
  14. package/dist/StrandsUIPlugin-DY7VCw7G.es.js +20437 -0
  15. package/dist/StrandsUIPlugin-Tpi8IoJc.cjs.js +143 -0
  16. package/dist/StrandsUIPlugin-lRGsfjf5.es.js +20440 -0
  17. package/dist/accui.css +1 -1
  18. package/dist/index.cjs.js +5 -5
  19. package/dist/index.es.js +5841 -5646
  20. package/dist/nuxt/module.cjs.js +6 -6
  21. package/dist/nuxt/module.es.js +22 -21
  22. package/dist/nuxt/runtime/composables/useStrandsAuth.cjs.js +1 -1
  23. package/dist/nuxt/runtime/composables/useStrandsAuth.d.ts +7 -1
  24. package/dist/nuxt/runtime/composables/useStrandsAuth.es.js +24 -19
  25. package/dist/nuxt/runtime/plugin.client.cjs.js +1 -1
  26. package/dist/nuxt/runtime/plugin.client.es.js +9 -12
  27. package/dist/nuxt/runtime/plugin.server.cjs.js +1 -1
  28. package/dist/nuxt/runtime/plugin.server.es.js +1 -1
  29. package/dist/types/composables.d.ts +6 -2
  30. package/dist/types/index.d.ts +21 -0
  31. package/dist/useDarkMode-Cew-NWjS.cjs.js +1 -0
  32. package/dist/useDarkMode-CvinMR9O.es.js +102 -0
  33. package/dist/useDarkMode-OZ_A8-6H.es.js +102 -0
  34. package/dist/useStrandsAuth-B7Fqq-Qp.es.js +717 -0
  35. package/dist/useStrandsAuth-BDTnh_c_.es.js +702 -0
  36. package/dist/useStrandsAuth-CEQ4UsKz.cjs.js +1 -0
  37. package/dist/useStrandsAuth-CboHAkjH.es.js +717 -0
  38. package/dist/useStrandsAuth-CetpoBNk.cjs.js +1 -0
  39. package/dist/useStrandsAuth-D2HvStMt.es.js +787 -0
  40. package/dist/useStrandsAuth-DSLFMDTj.es.js +717 -0
  41. package/dist/useStrandsAuth-Db5ZGvxL.cjs.js +1 -0
  42. package/dist/useStrandsAuth-Dz3Grglt.cjs.js +1 -0
  43. package/dist/useStrandsAuth-FVoni53L.es.js +666 -0
  44. package/dist/useStrandsAuth-Yp5OpRHU.cjs.js +1 -0
  45. package/dist/useStrandsConfig-48gZP9xV.es.js +209 -0
  46. package/dist/useStrandsConfig-B8h5hDy7.es.js +219 -0
  47. package/dist/useStrandsConfig-BGJg1LlC.es.js +213 -0
  48. package/dist/useStrandsConfig-BY_IIwK8.cjs.js +1 -0
  49. package/dist/useStrandsConfig-DRGldIzy.cjs.js +1 -0
  50. package/dist/vite.cjs.js +1 -1
  51. package/dist/vite.es.js +2 -2
  52. package/dist/vue/components/SignedIn.vue.d.ts +3 -1
  53. package/dist/vue/components/index.d.ts +1 -1
  54. package/dist/vue/composables/useKnownAccounts.d.ts +33 -0
  55. package/dist/vue/index.d.ts +1 -0
  56. package/dist/vue/ui/UiBunnyFontPicker.vue.d.ts +23 -0
  57. package/dist/vue/ui/UiCheckboxGroup.vue.d.ts +1 -0
  58. package/dist/vue/ui/UiInput/UiInput.Select.vue.d.ts +806 -0
  59. package/dist/vue/ui/UiMegaMenu.vue.d.ts +28 -1
  60. package/dist/vue/ui/UiRadioGroup.vue.d.ts +1 -0
  61. package/dist/vue/ui/UiTabs.vue.d.ts +2 -0
  62. package/dist/vue/ui/VirtualList.vue.d.ts +36 -0
  63. package/dist/webcomponents/define-element.d.ts +1 -1
  64. package/dist/webcomponents/entries/sl-alert.d.ts +2 -0
  65. package/dist/webcomponents/entries/sl-avatar-editor.d.ts +2 -0
  66. package/dist/webcomponents/entries/sl-button.d.ts +2 -0
  67. package/dist/webcomponents/entries/sl-card.d.ts +2 -0
  68. package/dist/webcomponents/entries/sl-checkbox-group.d.ts +2 -0
  69. package/dist/webcomponents/entries/sl-color-picker.d.ts +2 -0
  70. package/dist/webcomponents/entries/sl-datetime-picker.d.ts +2 -0
  71. package/dist/webcomponents/entries/sl-divider.d.ts +2 -0
  72. package/dist/webcomponents/entries/sl-font-picker.d.ts +2 -0
  73. package/dist/webcomponents/entries/sl-hero.d.ts +2 -0
  74. package/dist/webcomponents/entries/sl-input.d.ts +2 -0
  75. package/dist/webcomponents/entries/sl-level-progress.d.ts +2 -0
  76. package/dist/webcomponents/entries/sl-link.d.ts +2 -0
  77. package/dist/webcomponents/entries/sl-loader-spinner.d.ts +2 -0
  78. package/dist/webcomponents/entries/sl-mega-menu.d.ts +5 -0
  79. package/dist/webcomponents/entries/sl-modal.d.ts +2 -0
  80. package/dist/webcomponents/entries/sl-pill.d.ts +2 -0
  81. package/dist/webcomponents/entries/sl-radio-group.d.ts +2 -0
  82. package/dist/webcomponents/entries/sl-slider.d.ts +2 -0
  83. package/dist/webcomponents/entries/sl-table.d.ts +2 -0
  84. package/dist/webcomponents/entries/sl-tabs.d.ts +2 -0
  85. package/dist/webcomponents/entries/sl-theme-toggle.d.ts +2 -0
  86. package/dist/webcomponents/entries/sl-toggle.d.ts +2 -0
  87. package/dist/webcomponents/entries/sl-tooltip.d.ts +2 -0
  88. package/dist/webcomponents/loader.d.ts +3 -3
  89. package/dist/webcomponents/registry.d.ts +1 -1
  90. package/package.json +16 -16
@@ -0,0 +1,702 @@
1
+ import { computed as u, getCurrentInstance as he, onUnmounted as ge, ref as h } from "vue";
2
+ import { u as ve } from "./useStrandsConfig-BGJg1LlC.es.js";
3
+ class we {
4
+ cache = /* @__PURE__ */ new Map();
5
+ DEFAULT_TTL = 300 * 1e3;
6
+ // 5 minutes
7
+ /**
8
+ * Memoized fetch - prevents duplicate requests and caches results
9
+ */
10
+ async fetch(d, m, w = this.DEFAULT_TTL) {
11
+ const E = Date.now(), s = this.cache.get(d);
12
+ if (s && E - s.timestamp < s.ttl)
13
+ return s.promise;
14
+ this.cleanExpired();
15
+ const f = m().finally(() => {
16
+ setTimeout(() => {
17
+ this.cache.delete(d);
18
+ }, w);
19
+ });
20
+ return this.cache.set(d, {
21
+ promise: f,
22
+ timestamp: E,
23
+ ttl: w
24
+ }), f;
25
+ }
26
+ /**
27
+ * Clear all cached entries
28
+ */
29
+ clear() {
30
+ this.cache.clear();
31
+ }
32
+ /**
33
+ * Remove a specific cache entry
34
+ */
35
+ invalidate(d) {
36
+ this.cache.delete(d);
37
+ }
38
+ /**
39
+ * Clean expired cache entries
40
+ */
41
+ cleanExpired() {
42
+ const d = Date.now();
43
+ for (const [m, w] of this.cache.entries())
44
+ d - w.timestamp > w.ttl && this.cache.delete(m);
45
+ }
46
+ /**
47
+ * Get cache statistics (for debugging)
48
+ */
49
+ getStats() {
50
+ return {
51
+ size: this.cache.size,
52
+ entries: Array.from(this.cache.keys())
53
+ };
54
+ }
55
+ }
56
+ const y = new we();
57
+ function me() {
58
+ return {
59
+ fetch: y.fetch.bind(y),
60
+ clear: y.clear.bind(y),
61
+ invalidate: y.invalidate.bind(y),
62
+ getStats: y.getStats.bind(y)
63
+ };
64
+ }
65
+ function ye(a, d) {
66
+ let m = null;
67
+ return (...w) => {
68
+ m && clearTimeout(m), m = setTimeout(() => {
69
+ a(...w);
70
+ }, d);
71
+ };
72
+ }
73
+ const C = ye((a, d) => {
74
+ typeof window < "u" && localStorage.setItem(a, d);
75
+ }, 300), k = (a) => ({
76
+ id: a.id,
77
+ email: a.email,
78
+ firstName: a.first_name || a.firstName || "",
79
+ lastName: a.last_name || a.lastName || "",
80
+ avatar: a.avatar_url || a.avatar,
81
+ mfaEnabled: a.mfa_enabled ?? a.mfaEnabled ?? !1,
82
+ emailVerified: a.email_verified ?? a.emailVerified ?? !1,
83
+ passwordUpdatedAt: a.password_updated_at || a.passwordUpdatedAt,
84
+ settings: a.settings || {},
85
+ xp: a.xp || 0,
86
+ level: a.level || 1,
87
+ next_level_xp: a.next_level_xp || a.next_level_xp || 4,
88
+ username: a.username,
89
+ usernameLastChangedAt: a.username_last_changed_at || a.usernameLastChangedAt,
90
+ createdAt: a.created_at || a.createdAt,
91
+ updatedAt: a.updated_at || a.updatedAt || (/* @__PURE__ */ new Date()).toISOString()
92
+ }), pe = () => {
93
+ if (typeof window > "u")
94
+ return {
95
+ currentUser: h(null),
96
+ currentSession: h(null),
97
+ loadingStates: h({
98
+ initializing: !0,
99
+ signingIn: !1,
100
+ signingUp: !1,
101
+ signingOut: !1,
102
+ refreshingToken: !1,
103
+ sendingMfaEmail: !1,
104
+ verifyingMfa: !1,
105
+ loadingProfile: !1
106
+ }),
107
+ isInitialized: h(!1),
108
+ mfaRequired: h(!1),
109
+ mfaSessionId: h(null),
110
+ availableMfaMethods: h([]),
111
+ promise: null,
112
+ refreshTimer: null,
113
+ refreshPromise: null
114
+ };
115
+ const a = window;
116
+ return a.__STRANDS_AUTH_STATE__ || (a.__STRANDS_AUTH_STATE__ = {
117
+ currentUser: h(null),
118
+ currentSession: h(null),
119
+ loadingStates: h({
120
+ initializing: !0,
121
+ signingIn: !1,
122
+ signingUp: !1,
123
+ signingOut: !1,
124
+ refreshingToken: !1,
125
+ sendingMfaEmail: !1,
126
+ verifyingMfa: !1,
127
+ loadingProfile: !1
128
+ }),
129
+ isInitialized: h(!1),
130
+ mfaRequired: h(!1),
131
+ mfaSessionId: h(null),
132
+ availableMfaMethods: h([]),
133
+ promise: null,
134
+ refreshTimer: null,
135
+ refreshPromise: null
136
+ }), a.__STRANDS_AUTH_STATE__;
137
+ }, c = pe();
138
+ function _e() {
139
+ const { getUrl: a, config: d } = ve(), { fetch: m, clear: w, invalidate: E } = me(), { currentUser: s, currentSession: f, loadingStates: i, isInitialized: p, mfaRequired: T, mfaSessionId: g, availableMfaMethods: S } = c, I = () => {
140
+ if (s.value = null, f.value = null, T.value = !1, g.value = null, S.value = [], A(), c.refreshPromise = null, w(), typeof window < "u" && d.value?.onSignOutUrl) {
141
+ const t = window.location.pathname + window.location.search, e = d.value.onSignOutUrl;
142
+ t !== e && (window.location.href = e);
143
+ }
144
+ }, j = u(() => i.value.initializing), N = u(() => i.value.signingIn), F = u(() => i.value.signingUp), R = u(() => i.value.signingOut), z = u(() => i.value.refreshingToken), J = u(() => i.value.sendingMfaEmail), U = u(() => i.value.verifyingMfa);
145
+ u(() => i.value.loadingProfile);
146
+ const D = u(
147
+ () => i.value.signingIn || i.value.signingUp || i.value.signingOut || i.value.refreshingToken || i.value.sendingMfaEmail || i.value.verifyingMfa || i.value.loadingProfile
148
+ ), L = u(() => i.value.initializing || D.value), q = u(() => {
149
+ const t = i.value;
150
+ return t.initializing ? "Checking authentication..." : t.signingIn ? "Signing you in..." : t.signingUp ? "Creating your account..." : t.signingOut ? "Signing you out..." : t.refreshingToken ? "Refreshing session..." : t.sendingMfaEmail ? "Sending verification code..." : t.verifyingMfa ? "Verifying code..." : t.loadingProfile ? "Loading profile..." : "Loading...";
151
+ }), H = () => ({
152
+ "Content-Type": "application/json"
153
+ }), V = async () => {
154
+ try {
155
+ const t = await fetch(a("authStatus"), {
156
+ method: "GET",
157
+ credentials: "include"
158
+ });
159
+ if (!t.ok)
160
+ return !1;
161
+ const e = await t.json();
162
+ if (e.authenticated && e.user) {
163
+ s.value = k(e.user);
164
+ const n = e.expires_at ? new Date(e.expires_at * 1e3) : new Date(Date.now() + 300 * 1e3);
165
+ return f.value = {
166
+ accessToken: "",
167
+ // Token is in HttpOnly cookie
168
+ refreshToken: "",
169
+ // Token is in HttpOnly cookie
170
+ expiresAt: n,
171
+ userId: e.user.id
172
+ }, !0;
173
+ }
174
+ return !1;
175
+ } catch {
176
+ return !1;
177
+ }
178
+ }, G = async (t, e, n) => {
179
+ const r = await fetch(a("mfaHardwareCompleteRegistration"), {
180
+ method: "POST",
181
+ headers: {
182
+ "Content-Type": "application/json"
183
+ },
184
+ credentials: "include",
185
+ body: JSON.stringify({
186
+ device_id: t,
187
+ credential: e
188
+ })
189
+ });
190
+ if (!r.ok) {
191
+ const l = await r.text();
192
+ let o = "Failed to complete hardware key registration";
193
+ try {
194
+ const v = JSON.parse(l);
195
+ o = v.message || v.error || l;
196
+ } catch {
197
+ o = l || "Failed to complete hardware key registration";
198
+ }
199
+ throw new Error(o);
200
+ }
201
+ return r.json();
202
+ }, K = async (t, e, n = "hardware") => {
203
+ const r = await fetch(a("mfaHardwareStartRegistration"), {
204
+ method: "POST",
205
+ headers: {
206
+ "Content-Type": "application/json"
207
+ },
208
+ credentials: "include",
209
+ body: JSON.stringify({
210
+ device_name: t,
211
+ device_type: n
212
+ })
213
+ });
214
+ if (!r.ok) {
215
+ const l = await r.text();
216
+ let o = "Failed to start hardware key registration";
217
+ try {
218
+ const v = JSON.parse(l);
219
+ o = v.message || v.error || l;
220
+ } catch {
221
+ o = l || "Failed to start hardware key registration";
222
+ }
223
+ throw new Error(o);
224
+ }
225
+ return r.json();
226
+ }, W = u(() => s.value !== null), B = async (t) => {
227
+ i.value.signingIn = !0;
228
+ try {
229
+ T.value = !1, g.value = null, S.value = [];
230
+ const e = {
231
+ "Content-Type": "application/json"
232
+ };
233
+ typeof window < "u" && window.location && (e.Origin = window.location.origin);
234
+ const n = await fetch(a("signIn"), {
235
+ method: "POST",
236
+ headers: e,
237
+ credentials: "include",
238
+ // Include cookies for auth
239
+ body: JSON.stringify(t)
240
+ });
241
+ if (!n.ok)
242
+ throw n.status === 401 ? new Error("Invalid email or password") : n.status === 403 ? new Error("Please verify your email address before signing in") : new Error(`Sign in failed: ${n.status} ${n.statusText}`);
243
+ const r = await n.json();
244
+ if (r.mfa_required) {
245
+ T.value = !0, g.value = r.mfa_session_id || null;
246
+ const l = (r.available_mfa_methods || []).map((o) => {
247
+ let v = `${o.device_type.charAt(0).toUpperCase() + o.device_type.slice(1)} Authentication`;
248
+ return o.device_type === "hardware" ? v = o.device_name || "Security Key" : o.device_type === "totp" ? v = o.device_name || "Authenticator App" : o.device_type === "email" && (v = o.device_name || "Email Verification"), {
249
+ id: o.device_id,
250
+ device_type: o.device_type,
251
+ device_name: o.device_name || v,
252
+ is_active: !0,
253
+ created_at: (/* @__PURE__ */ new Date()).toISOString(),
254
+ last_used_at: o.last_used_at,
255
+ // Pass through additional metadata if available
256
+ credential_id: o.credential_id,
257
+ device_info: o.device_info
258
+ };
259
+ });
260
+ return S.value = l, i.value.signingIn = !1, r;
261
+ }
262
+ return await P(r), r;
263
+ } catch (e) {
264
+ throw e;
265
+ } finally {
266
+ i.value.signingIn = !1;
267
+ }
268
+ }, Y = async (t) => {
269
+ i.value.signingUp = !0;
270
+ try {
271
+ throw new Error("Sign up not implemented - please integrate with auth SDK");
272
+ } finally {
273
+ i.value.signingUp = !1;
274
+ }
275
+ }, Q = async () => {
276
+ i.value.signingOut = !0;
277
+ try {
278
+ await fetch(a("signOut"), {
279
+ method: "POST",
280
+ credentials: "include"
281
+ // Cookies will be cleared by server response
282
+ }), A(), c.refreshPromise = null, w(), s.value = null, f.value = null, T.value = !1, g.value = null, S.value = [], typeof window < "u" && d.value?.onSignOutUrl && (window.location.href = d.value.onSignOutUrl);
283
+ } finally {
284
+ i.value.signingOut = !1;
285
+ }
286
+ }, O = async () => {
287
+ if (c.refreshPromise)
288
+ return await c.refreshPromise;
289
+ c.refreshPromise = (async () => {
290
+ i.value.refreshingToken = !0;
291
+ try {
292
+ const e = await fetch(a("refresh"), {
293
+ method: "POST",
294
+ headers: {
295
+ "Content-Type": "application/json"
296
+ },
297
+ credentials: "include"
298
+ // Refresh token sent via cookie
299
+ });
300
+ if (!e.ok) {
301
+ if (e.status === 401)
302
+ return I(), !1;
303
+ throw new Error(`Token refresh failed: ${e.status} ${e.statusText}`);
304
+ }
305
+ const n = await e.json();
306
+ n.user && (s.value = k(n.user));
307
+ const r = {
308
+ accessToken: "",
309
+ // Token is in HttpOnly cookie
310
+ refreshToken: "",
311
+ // Token is in HttpOnly cookie
312
+ expiresAt: new Date(Date.now() + 300 * 1e3),
313
+ // 5 minutes from now
314
+ userId: n.user?.id || s.value?.id
315
+ };
316
+ return f.value = r, _(), E(`sessions:${s.value?.id || "unknown"}`), !0;
317
+ } catch {
318
+ return I(), !1;
319
+ } finally {
320
+ i.value.refreshingToken = !1;
321
+ }
322
+ })();
323
+ const t = await c.refreshPromise;
324
+ return c.refreshPromise = null, t;
325
+ }, X = async () => {
326
+ const t = `profile:${f.value.accessToken.slice(0, 20)}`;
327
+ i.value.loadingProfile = !0;
328
+ try {
329
+ return await m(t, async () => {
330
+ const e = await fetch(a("profile"), {
331
+ method: "GET",
332
+ headers: {
333
+ "Content-Type": "application/json",
334
+ Authorization: `Bearer ${f.value?.accessToken}`
335
+ }
336
+ });
337
+ if (!e.ok)
338
+ throw e.status === 401 ? new Error("Authentication expired. Please sign in again.") : new Error(`Failed to fetch profile: ${e.status} ${e.statusText}`);
339
+ const n = await e.json();
340
+ return s.value = k(n), s.value && typeof window < "u" && localStorage.setItem("strands_auth_user", JSON.stringify(s.value)), s.value;
341
+ });
342
+ } finally {
343
+ i.value.loadingProfile = !1;
344
+ }
345
+ }, Z = async (t) => {
346
+ i.value.loadingProfile = !0;
347
+ try {
348
+ const e = await fetch(a("profile"), {
349
+ method: "POST",
350
+ headers: {
351
+ "Content-Type": "application/json",
352
+ Authorization: `Bearer ${f.value.accessToken}`
353
+ },
354
+ body: JSON.stringify({
355
+ first_name: t.firstName,
356
+ last_name: t.lastName
357
+ })
358
+ });
359
+ if (!e.ok)
360
+ throw e.status === 401 ? new Error("Authentication expired. Please sign in again.") : new Error(`Profile update failed: ${e.status} ${e.statusText}`);
361
+ const n = await e.json();
362
+ return s.value = k(n), s.value && C("strands_auth_user", JSON.stringify(s.value)), s.value;
363
+ } finally {
364
+ i.value.loadingProfile = !1;
365
+ }
366
+ }, ee = async (t) => {
367
+ i.value.loadingProfile = !0;
368
+ try {
369
+ const e = await fetch(a("settings"), {
370
+ method: "POST",
371
+ headers: {
372
+ "Content-Type": "application/json",
373
+ Authorization: `Bearer ${f.value.accessToken}`
374
+ },
375
+ body: JSON.stringify({
376
+ settings: t
377
+ })
378
+ });
379
+ if (!e.ok)
380
+ throw e.status === 401 ? new Error("Authentication expired. Please sign in again.") : new Error(`Settings update failed: ${e.status} ${e.statusText}`);
381
+ const n = await e.json();
382
+ return s.value = k(n), s.value && C("strands_auth_user", JSON.stringify(s.value)), s.value;
383
+ } finally {
384
+ i.value.loadingProfile = !1;
385
+ }
386
+ }, te = async (t, e) => {
387
+ i.value.loadingProfile = !0;
388
+ try {
389
+ const n = await fetch(a("changeEmail"), {
390
+ method: "POST",
391
+ headers: {
392
+ "Content-Type": "application/json",
393
+ Authorization: `Bearer ${f.value.accessToken}`
394
+ },
395
+ body: JSON.stringify({
396
+ new_email: t,
397
+ password: e
398
+ })
399
+ });
400
+ if (!n.ok) {
401
+ if (n.status === 401)
402
+ throw new Error("Authentication expired. Please sign in again.");
403
+ {
404
+ const l = await n.json().catch(() => ({}));
405
+ throw new Error(l.message || `Email change failed: ${n.status} ${n.statusText}`);
406
+ }
407
+ }
408
+ const r = await n.json();
409
+ return s.value && (s.value = {
410
+ ...s.value,
411
+ email: t,
412
+ emailVerified: !1,
413
+ // Email needs to be verified again
414
+ updatedAt: (/* @__PURE__ */ new Date()).toISOString()
415
+ }, typeof window < "u" && localStorage.setItem("strands_auth_user", JSON.stringify(s.value))), r;
416
+ } finally {
417
+ i.value.loadingProfile = !1;
418
+ }
419
+ }, ae = async (t, e, n = !1) => {
420
+ if (!g.value)
421
+ throw new Error("No MFA session available");
422
+ i.value.verifyingMfa = !0;
423
+ try {
424
+ const r = a(n ? "mfaBackupCodeVerify" : "mfaSigninVerify"), l = n ? { mfa_session_id: g.value, backup_code: e } : { mfa_session_id: g.value, device_id: t, code: e }, o = await fetch(r, {
425
+ method: "POST",
426
+ headers: { "Content-Type": "application/json" },
427
+ credentials: "include",
428
+ body: JSON.stringify(l)
429
+ });
430
+ if (!o.ok) {
431
+ const b = await o.text();
432
+ let M = "MFA verification failed";
433
+ try {
434
+ const $ = JSON.parse(b);
435
+ M = $.message || $.error || b;
436
+ } catch {
437
+ M = b || "MFA verification failed";
438
+ }
439
+ throw new Error(M);
440
+ }
441
+ const v = await o.json();
442
+ return T.value = !1, g.value = null, S.value = [], await P(v), v;
443
+ } finally {
444
+ i.value.verifyingMfa = !1;
445
+ }
446
+ }, ne = async (t) => {
447
+ if (!g.value)
448
+ throw new Error("No MFA session available");
449
+ i.value.sendingMfaEmail = !0;
450
+ try {
451
+ const e = await fetch(a("mfaSigninSendEmail"), {
452
+ method: "POST",
453
+ headers: { "Content-Type": "application/json" },
454
+ credentials: "include",
455
+ body: JSON.stringify({
456
+ mfa_session_id: g.value,
457
+ device_id: t
458
+ })
459
+ });
460
+ if (!e.ok) {
461
+ const r = await e.text();
462
+ let l = "Failed to send MFA email code";
463
+ try {
464
+ const o = JSON.parse(r);
465
+ l = o.message || o.error || r;
466
+ } catch {
467
+ l = r || "Failed to send MFA email code";
468
+ }
469
+ throw new Error(l);
470
+ }
471
+ return await e.json();
472
+ } finally {
473
+ i.value.sendingMfaEmail = !1;
474
+ }
475
+ }, ie = async (t) => {
476
+ if (!g.value)
477
+ throw new Error("No MFA session available");
478
+ const e = await fetch(a("mfaWebAuthnChallenge"), {
479
+ method: "POST",
480
+ headers: { "Content-Type": "application/json" },
481
+ credentials: "include",
482
+ body: JSON.stringify({
483
+ mfa_session_id: g.value,
484
+ device_id: t
485
+ })
486
+ });
487
+ if (!e.ok) {
488
+ const n = await e.text();
489
+ let r = "Failed to get WebAuthn challenge";
490
+ try {
491
+ const l = JSON.parse(n);
492
+ r = l.message || l.error || n;
493
+ } catch {
494
+ r = n || r;
495
+ }
496
+ throw new Error(r);
497
+ }
498
+ return e.json();
499
+ }, P = async (t) => {
500
+ try {
501
+ t.user && (s.value = k(t.user));
502
+ const e = {
503
+ accessToken: "",
504
+ // Token is in HttpOnly cookie
505
+ refreshToken: "",
506
+ // Token is in HttpOnly cookie
507
+ expiresAt: new Date(Date.now() + 300 * 1e3),
508
+ // 5 minutes from now (matching API token expiry)
509
+ userId: s.value?.id || t.user?.id
510
+ };
511
+ f.value = e, _();
512
+ } catch {
513
+ }
514
+ }, _ = () => {
515
+ if (c.refreshTimer && clearTimeout(c.refreshTimer), !f.value || typeof document < "u" && document.visibilityState === "hidden")
516
+ return;
517
+ const t = /* @__PURE__ */ new Date(), n = f.value.expiresAt.getTime() - t.getTime() - 60 * 1e3;
518
+ if (n <= 0) {
519
+ O();
520
+ return;
521
+ }
522
+ c.refreshTimer = setTimeout(async () => {
523
+ (typeof document > "u" || document.visibilityState === "visible") && await O() && _();
524
+ }, n);
525
+ }, A = () => {
526
+ c.refreshTimer && (clearTimeout(c.refreshTimer), c.refreshTimer = null);
527
+ }, x = async () => {
528
+ if (p.value) {
529
+ i.value.initializing = !1;
530
+ return;
531
+ }
532
+ if (c.promise) {
533
+ await c.promise;
534
+ return;
535
+ }
536
+ i.value.initializing = !0;
537
+ const t = async () => {
538
+ try {
539
+ typeof window < "u" && (await Promise.race([
540
+ V(),
541
+ new Promise((r) => setTimeout(() => r(!1), 5e3))
542
+ ]) ? _() : (s.value = null, f.value = null)), p.value = !0, await new Promise((e) => setTimeout(e, 50));
543
+ } catch {
544
+ } finally {
545
+ i.value.initializing = !1, c.promise = null;
546
+ }
547
+ };
548
+ return c.promise = t(), c.promise;
549
+ }, se = async (t) => {
550
+ i.value.loadingProfile = !0;
551
+ try {
552
+ const e = await fetch(a("changeUsername"), {
553
+ method: "POST",
554
+ headers: {
555
+ "Content-Type": "application/json"
556
+ },
557
+ credentials: "include",
558
+ body: JSON.stringify({
559
+ username: t
560
+ })
561
+ });
562
+ if (!e.ok) {
563
+ const r = await e.json().catch(() => ({}));
564
+ throw e.status === 409 ? new Error("Username is already taken") : r.cooldown_end ? new Error(`You can only change your username once every 30 days. You can change it again on ${new Date(r.cooldown_end).toLocaleDateString()}`) : new Error(r.message || `Username change failed: ${e.status} ${e.statusText}`);
565
+ }
566
+ const n = await e.json();
567
+ return s.value && (s.value = {
568
+ ...s.value,
569
+ username: t,
570
+ usernameLastChangedAt: (/* @__PURE__ */ new Date()).toISOString(),
571
+ updatedAt: (/* @__PURE__ */ new Date()).toISOString()
572
+ }), n;
573
+ } finally {
574
+ i.value.loadingProfile = !1;
575
+ }
576
+ }, re = async () => {
577
+ const t = await fetch(a("usernameCooldown"), {
578
+ method: "GET",
579
+ credentials: "include"
580
+ });
581
+ if (!t.ok)
582
+ throw new Error(`Failed to get username cooldown: ${t.status} ${t.statusText}`);
583
+ return t.json();
584
+ }, oe = async (t) => {
585
+ const e = a("checkUsernameAvailability").replace("{username}", encodeURIComponent(t)), n = await fetch(e, {
586
+ method: "GET",
587
+ headers: {
588
+ "Content-Type": "application/json"
589
+ }
590
+ });
591
+ if (!n.ok)
592
+ throw new Error(`Failed to check username availability: ${n.status} ${n.statusText}`);
593
+ return n.json();
594
+ }, le = async () => {
595
+ const t = `sessions:${s.value?.id || "no-user"}`;
596
+ try {
597
+ return await m(t, async () => {
598
+ const e = await fetch(a("sessions"), {
599
+ method: "GET",
600
+ credentials: "include"
601
+ });
602
+ if (!e.ok)
603
+ throw await e.text(), new Error(`Failed to get user sessions: ${e.status} ${e.statusText}`);
604
+ return e.json();
605
+ }, 120 * 1e3);
606
+ } catch (e) {
607
+ throw e;
608
+ }
609
+ }, ue = async () => {
610
+ const t = await fetch(a("sessionsStats"), {
611
+ method: "GET",
612
+ credentials: "include"
613
+ });
614
+ if (!t.ok)
615
+ throw new Error(`Failed to get session stats: ${t.status} ${t.statusText}`);
616
+ return t.json();
617
+ }, ce = async (t) => {
618
+ const e = a("sessionRevoke").replace("{session_id}", encodeURIComponent(t)), n = await fetch(e, {
619
+ method: "POST",
620
+ credentials: "include"
621
+ });
622
+ if (!n.ok)
623
+ throw new Error(`Failed to revoke session: ${n.status} ${n.statusText}`);
624
+ return n.status === 200;
625
+ }, fe = async () => {
626
+ const t = await fetch(a("sessionsRevokeAll"), {
627
+ method: "POST",
628
+ credentials: "include"
629
+ });
630
+ if (!t.ok)
631
+ throw new Error(`Failed to revoke all other sessions: ${t.status} ${t.statusText}`);
632
+ return t.status === 200;
633
+ };
634
+ typeof document < "u" && document.addEventListener("visibilitychange", () => {
635
+ document.visibilityState === "visible" && f.value ? _() : document.visibilityState === "hidden" && A();
636
+ });
637
+ const de = () => {
638
+ A(), w();
639
+ };
640
+ try {
641
+ he() && ge(de);
642
+ } catch {
643
+ }
644
+ return p.value || x(), {
645
+ // State
646
+ user: u(() => s.value),
647
+ currentUser: u(() => s.value),
648
+ currentSession: u(() => f.value),
649
+ isAuthenticated: W,
650
+ isLoading: u(() => L.value || !p.value),
651
+ loading: D,
652
+ loadingMessage: q,
653
+ // Specific loading states
654
+ isInitializing: j,
655
+ isInitialized: u(() => p.value),
656
+ isSigningIn: N,
657
+ isSigningUp: F,
658
+ isSigningOut: R,
659
+ isRefreshingToken: z,
660
+ isSendingMfaEmail: J,
661
+ isVerifyingMfa: U,
662
+ // MFA State
663
+ mfaRequired: u(() => T.value),
664
+ mfaSessionId: u(() => g.value),
665
+ availableMfaMethods: u(() => S.value),
666
+ // Methods
667
+ signIn: B,
668
+ signUp: Y,
669
+ signOut: Q,
670
+ refreshToken: O,
671
+ fetchProfile: X,
672
+ updateProfile: Z,
673
+ updateUserSettings: ee,
674
+ changeEmail: te,
675
+ changeUsername: se,
676
+ getUsernameCooldown: re,
677
+ checkUsernameAvailability: oe,
678
+ // Session management
679
+ getUserSessions: le,
680
+ getSessionStats: ue,
681
+ revokeSession: ce,
682
+ revokeAllOtherSessions: fe,
683
+ initialize: x,
684
+ setAuthData: P,
685
+ verifyMfa: ae,
686
+ sendMfaEmailCode: ne,
687
+ getMfaWebAuthnChallenge: ie,
688
+ registerHardwareKey: K,
689
+ completeHardwareKeyRegistration: G,
690
+ // Token management
691
+ startTokenRefreshTimer: _,
692
+ stopTokenRefreshTimer: A,
693
+ getAuthHeaders: H,
694
+ // Force re-initialization (useful for testing or navigation)
695
+ forceReInit: () => {
696
+ p.value = !1, i.value.initializing = !0, x();
697
+ }
698
+ };
699
+ }
700
+ export {
701
+ _e as u
702
+ };