@classic-homes/auth 1.0.0 → 1.0.2

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.
@@ -0,0 +1,3 @@
1
+ export { authActions, authStore, currentUser, isAuthenticated } from './chunk-GWOTYGQI.js';
2
+ import './chunk-7DW44JGU.js';
3
+ import './chunk-S4TOKARB.js';
@@ -1,6 +1,6 @@
1
- import { authService } from './chunk-VVREZ25E.js';
2
- import { authStore, currentUser, isAuthenticated, authActions } from './chunk-QBTMNWJH.js';
3
- import { isInitialized, initAuth, getUserRoles } from './chunk-O47YKG2F.js';
1
+ import { authService } from './chunk-LIRO3PU2.js';
2
+ import { authStore, currentUser, isAuthenticated, authActions } from './chunk-GWOTYGQI.js';
3
+ import { isInitialized, initAuth, getUserRoles } from './chunk-S4TOKARB.js';
4
4
 
5
5
  // src/svelte/guards/auth-guard.ts
6
6
  function checkAuth(options = {}) {
@@ -1,4 +1,4 @@
1
- import { getConfig, getStorage, getFetch, isValidRedirectUrl } from './chunk-O47YKG2F.js';
1
+ import { getConfig, getStorage, getFetch, isValidRedirectUrl } from './chunk-S4TOKARB.js';
2
2
 
3
3
  // src/core/client.ts
4
4
  var isRefreshing = false;
@@ -14,17 +14,23 @@ function subscribeTokenRefresh(cb) {
14
14
  if (idx > -1) refreshSubscribers.splice(idx, 1);
15
15
  };
16
16
  }
17
- function onTokenRefreshed(token) {
17
+ function flushRefreshSubscribers(token, terminal = false) {
18
18
  const subs = refreshSubscribers;
19
19
  refreshSubscribers = [];
20
20
  subs.forEach((cb) => {
21
21
  try {
22
- cb(token);
22
+ cb(token, terminal);
23
23
  } catch (e) {
24
24
  console.error("Token refresh subscriber error:", e);
25
25
  }
26
26
  });
27
27
  }
28
+ function onTokenRefreshed(token) {
29
+ flushRefreshSubscribers(token);
30
+ }
31
+ function onTokenRefreshFailed(terminal) {
32
+ flushRefreshSubscribers(null, terminal);
33
+ }
28
34
  function getAccessToken() {
29
35
  const config = getConfig();
30
36
  const storage = getStorage();
@@ -71,7 +77,7 @@ function updateStoredTokens(accessToken, refreshToken) {
71
77
  parsed.accessToken = accessToken;
72
78
  parsed.refreshToken = refreshToken;
73
79
  storage.setItem(storageKey, JSON.stringify(parsed));
74
- import('./auth.svelte-J62VV4TA.js').then(({ authStore }) => {
80
+ import('./auth.svelte-FUE2KVI4.js').then(({ authStore }) => {
75
81
  authStore.updateTokens(accessToken, refreshToken);
76
82
  }).catch(() => {
77
83
  });
@@ -83,12 +89,21 @@ function clearStoredAuth() {
83
89
  storage.removeItem(config.storageKey ?? "classic_auth");
84
90
  storage.removeItem(getSessionTokenKey());
85
91
  }
92
+ async function expireSession() {
93
+ clearStoredAuth();
94
+ try {
95
+ const { authStore } = await import('./auth.svelte-FUE2KVI4.js');
96
+ authStore.handleSessionExpired();
97
+ } catch {
98
+ }
99
+ getConfig().onLogout?.();
100
+ }
86
101
  async function refreshAccessToken() {
87
102
  const refreshToken = getRefreshToken();
88
103
  const config = getConfig();
89
104
  const fetchFn = getFetch();
90
105
  if (!refreshToken) {
91
- return false;
106
+ return "rejected";
92
107
  }
93
108
  const timeoutMs = config.requestTimeout ?? 3e4;
94
109
  const controller = new AbortController();
@@ -109,13 +124,13 @@ async function refreshAccessToken() {
109
124
  try {
110
125
  apiResponse = await response.json();
111
126
  } catch {
112
- return false;
127
+ return "unavailable";
113
128
  }
114
129
  } else {
115
130
  try {
116
131
  apiResponse = await response.json();
117
132
  } catch {
118
- return false;
133
+ return "unavailable";
119
134
  }
120
135
  }
121
136
  const data = apiResponse?.data;
@@ -124,15 +139,20 @@ async function refreshAccessToken() {
124
139
  const newRefreshToken = tokens.refreshToken ?? refreshToken;
125
140
  updateStoredTokens(tokens.accessToken, newRefreshToken);
126
141
  onTokenRefreshed(tokens.accessToken);
127
- return true;
142
+ return "refreshed";
128
143
  }
144
+ return "unavailable";
129
145
  }
146
+ if (response.status >= 500) {
147
+ return "unavailable";
148
+ }
149
+ return "rejected";
130
150
  } catch (error) {
131
151
  config.onAuthError?.(error instanceof Error ? error : new Error("Token refresh failed"));
152
+ return "unavailable";
132
153
  } finally {
133
154
  clearTimeout(timeoutId);
134
155
  }
135
- return false;
136
156
  }
137
157
  function extractData(response) {
138
158
  if (response && typeof response === "object" && "data" in response) {
@@ -188,25 +208,27 @@ async function apiRequestInternal(endpoint, options, isRetry) {
188
208
  clearTimeout(timeoutId);
189
209
  if (response.status === 401 && authenticated && typeof window !== "undefined") {
190
210
  if (isRetry) {
191
- clearStoredAuth();
192
- config.onLogout?.();
211
+ await expireSession();
193
212
  throw new Error("Authentication failed. Please sign in again.");
194
213
  }
195
214
  if (!isRefreshing) {
196
215
  isRefreshing = true;
197
- let refreshed = false;
216
+ let refreshResult = "unavailable";
198
217
  try {
199
- refreshed = await refreshAccessToken();
218
+ refreshResult = await refreshAccessToken();
200
219
  } finally {
201
220
  isRefreshing = false;
202
221
  }
203
- if (refreshed) {
222
+ if (refreshResult === "refreshed") {
204
223
  return apiRequestInternal(endpoint, options, true);
205
- } else {
206
- clearStoredAuth();
207
- config.onLogout?.();
224
+ }
225
+ if (refreshResult === "rejected") {
226
+ onTokenRefreshFailed(true);
227
+ await expireSession();
208
228
  throw new Error("Authentication failed. Please sign in again.");
209
229
  }
230
+ onTokenRefreshFailed(false);
231
+ throw new Error("Authentication service unavailable. Please try again.");
210
232
  } else {
211
233
  const REFRESH_TIMEOUT_MS = 3e4;
212
234
  return new Promise((resolve, reject) => {
@@ -220,11 +242,19 @@ async function apiRequestInternal(endpoint, options, isRetry) {
220
242
  }, REFRESH_TIMEOUT_MS);
221
243
  let unsubscribe = null;
222
244
  try {
223
- unsubscribe = subscribeTokenRefresh(() => {
245
+ unsubscribe = subscribeTokenRefresh((token, terminal) => {
224
246
  if (!settled) {
225
247
  settled = true;
226
248
  clearTimeout(refreshTimeoutId);
227
- apiRequestInternal(endpoint, options, true).then(resolve).catch(reject);
249
+ if (token) {
250
+ apiRequestInternal(endpoint, options, true).then(resolve).catch(reject);
251
+ } else {
252
+ reject(
253
+ new Error(
254
+ terminal ? "Authentication failed. Please sign in again." : "Authentication service unavailable. Please try again."
255
+ )
256
+ );
257
+ }
228
258
  }
229
259
  });
230
260
  } catch (subscribeError) {
@@ -1,5 +1,5 @@
1
- import { authApi } from './chunk-2N2MDCWL.js';
2
- import { isInitialized, getConfig, hasRole, hasAnyRole, hasAllRoles, decodeJWT, getStorage, getDefaultStorage } from './chunk-O47YKG2F.js';
1
+ import { authApi } from './chunk-7DW44JGU.js';
2
+ import { isInitialized, getConfig, hasRole, hasAnyRole, hasAllRoles, decodeJWT, getStorage, getDefaultStorage } from './chunk-S4TOKARB.js';
3
3
 
4
4
  // src/svelte/stores/auth.svelte.ts
5
5
  var STORAGE_VERSION = 2;
@@ -1,5 +1,5 @@
1
- import { authApi } from './chunk-2N2MDCWL.js';
2
- import { getUserRoles, hasAnyRole } from './chunk-O47YKG2F.js';
1
+ import { authApi } from './chunk-7DW44JGU.js';
2
+ import { getUserRoles, hasAnyRole } from './chunk-S4TOKARB.js';
3
3
 
4
4
  // src/core/guards.ts
5
5
  function isMfaChallengeResponse(response) {
@@ -59,7 +59,7 @@ var AuthService = class {
59
59
  }
60
60
  if (options?.autoSetAuth !== false && !isMfaChallengeResponse(response)) {
61
61
  try {
62
- const { authStore } = await import('./auth.svelte-J62VV4TA.js');
62
+ const { authStore } = await import('./auth.svelte-FUE2KVI4.js');
63
63
  authStore.setAuth(
64
64
  response.accessToken,
65
65
  response.refreshToken,
@@ -243,7 +243,7 @@ var AuthService = class {
243
243
  }
244
244
  if (options?.autoSetAuth !== false) {
245
245
  try {
246
- const { authStore } = await import('./auth.svelte-J62VV4TA.js');
246
+ const { authStore } = await import('./auth.svelte-FUE2KVI4.js');
247
247
  authStore.setAuth(
248
248
  response.accessToken,
249
249
  response.refreshToken,
@@ -120,7 +120,7 @@ function isTokenExpired(token) {
120
120
  return true;
121
121
  }
122
122
  const CLOCK_SKEW_MS = 3e4;
123
- return payload.exp * 1e3 < Date.now() - CLOCK_SKEW_MS;
123
+ return payload.exp * 1e3 < Date.now() + CLOCK_SKEW_MS;
124
124
  }
125
125
  function getTokenRemainingTime(token) {
126
126
  const payload = decodeJWT(token);
@@ -1,3 +1,3 @@
1
- export { AuthService, RoleDeniedError, authService, formatUserRoles, getAvailableMethods, getAvatarFallback, getDisplayName, getGreeting, getMfaToken, getUserEmail, getUserInitials, isLoginSuccessResponse, isMfaChallengeResponse, isRoleDeniedError } from '../chunk-VVREZ25E.js';
2
- export { api, apiRequest, authApi, clearStoredAuth, extractData, getAccessToken, getRefreshToken, getSessionToken, updateStoredTokens } from '../chunk-2N2MDCWL.js';
3
- export { ROLE_HIERARCHY, ROLE_NAMES, computePrimaryRole, createMemoryStorage, createSessionStorage, decodeJWT, extractClaims, getConfig, getDefaultStorage, getEffectiveLevel, getFetch, getStorage, getTokenExpiration, getTokenRemainingTime, getUserRoles, hasAllRoles, hasAnyRole, hasRole, initAuth, isInitialized, isTokenExpired, resetConfig } from '../chunk-O47YKG2F.js';
1
+ export { AuthService, RoleDeniedError, authService, formatUserRoles, getAvailableMethods, getAvatarFallback, getDisplayName, getGreeting, getMfaToken, getUserEmail, getUserInitials, isLoginSuccessResponse, isMfaChallengeResponse, isRoleDeniedError } from '../chunk-LIRO3PU2.js';
2
+ export { api, apiRequest, authApi, clearStoredAuth, extractData, getAccessToken, getRefreshToken, getSessionToken, updateStoredTokens } from '../chunk-7DW44JGU.js';
3
+ export { ROLE_HIERARCHY, ROLE_NAMES, computePrimaryRole, createMemoryStorage, createSessionStorage, decodeJWT, extractClaims, getConfig, getDefaultStorage, getEffectiveLevel, getFetch, getStorage, getTokenExpiration, getTokenRemainingTime, getUserRoles, hasAllRoles, hasAnyRole, hasRole, initAuth, isInitialized, isTokenExpired, resetConfig } from '../chunk-S4TOKARB.js';
package/dist/index.js CHANGED
@@ -1,5 +1,5 @@
1
- export { canAccess, checkAuth, createAuthClient, createAuthGuard, createAuthHook, createNavFilter, filterByAccess, filterNavSections, matchesRoute, protectedLoad, requireAuth, requirePermission, requireRole, routePatterns } from './chunk-ILRNO4WH.js';
2
- export { AuthService, RoleDeniedError, authService, formatUserRoles, getAvailableMethods, getAvatarFallback, getDisplayName, getGreeting, getMfaToken, getUserEmail, getUserInitials, isLoginSuccessResponse, isMfaChallengeResponse, isRoleDeniedError } from './chunk-VVREZ25E.js';
3
- export { authActions, authStore, currentUser, isAuthenticated } from './chunk-QBTMNWJH.js';
4
- export { api, apiRequest, authApi, clearStoredAuth, extractData, getAccessToken, getRefreshToken, getSessionToken, updateStoredTokens } from './chunk-2N2MDCWL.js';
5
- export { ROLE_HIERARCHY, ROLE_NAMES, computePrimaryRole, createMemoryStorage, createSessionStorage, decodeJWT, extractClaims, getConfig, getDefaultStorage, getEffectiveLevel, getFetch, getStorage, getTokenExpiration, getTokenRemainingTime, getUserRoles, hasAllRoles, hasAnyRole, hasRole, initAuth, isInitialized, isTokenExpired, resetConfig } from './chunk-O47YKG2F.js';
1
+ export { canAccess, checkAuth, createAuthClient, createAuthGuard, createAuthHook, createNavFilter, filterByAccess, filterNavSections, matchesRoute, protectedLoad, requireAuth, requirePermission, requireRole, routePatterns } from './chunk-6VABYYP2.js';
2
+ export { AuthService, RoleDeniedError, authService, formatUserRoles, getAvailableMethods, getAvatarFallback, getDisplayName, getGreeting, getMfaToken, getUserEmail, getUserInitials, isLoginSuccessResponse, isMfaChallengeResponse, isRoleDeniedError } from './chunk-LIRO3PU2.js';
3
+ export { authActions, authStore, currentUser, isAuthenticated } from './chunk-GWOTYGQI.js';
4
+ export { api, apiRequest, authApi, clearStoredAuth, extractData, getAccessToken, getRefreshToken, getSessionToken, updateStoredTokens } from './chunk-7DW44JGU.js';
5
+ export { ROLE_HIERARCHY, ROLE_NAMES, computePrimaryRole, createMemoryStorage, createSessionStorage, decodeJWT, extractClaims, getConfig, getDefaultStorage, getEffectiveLevel, getFetch, getStorage, getTokenExpiration, getTokenRemainingTime, getUserRoles, hasAllRoles, hasAnyRole, hasRole, initAuth, isInitialized, isTokenExpired, resetConfig } from './chunk-S4TOKARB.js';
@@ -1,5 +1,5 @@
1
- export { canAccess, checkAuth, createAuthClient, createAuthGuard, createAuthHook, createNavFilter, filterByAccess, filterNavSections, matchesRoute, protectedLoad, requireAuth, requirePermission, requireRole, routePatterns } from '../chunk-ILRNO4WH.js';
2
- export { RoleDeniedError, formatUserRoles, getAvatarFallback, getDisplayName, getGreeting, getUserEmail, getUserInitials, isRoleDeniedError } from '../chunk-VVREZ25E.js';
3
- export { authActions, authStore, currentUser, isAuthenticated } from '../chunk-QBTMNWJH.js';
4
- import '../chunk-2N2MDCWL.js';
5
- export { initAuth, isInitialized } from '../chunk-O47YKG2F.js';
1
+ export { canAccess, checkAuth, createAuthClient, createAuthGuard, createAuthHook, createNavFilter, filterByAccess, filterNavSections, matchesRoute, protectedLoad, requireAuth, requirePermission, requireRole, routePatterns } from '../chunk-6VABYYP2.js';
2
+ export { RoleDeniedError, formatUserRoles, getAvatarFallback, getDisplayName, getGreeting, getUserEmail, getUserInitials, isRoleDeniedError } from '../chunk-LIRO3PU2.js';
3
+ export { authActions, authStore, currentUser, isAuthenticated } from '../chunk-GWOTYGQI.js';
4
+ import '../chunk-7DW44JGU.js';
5
+ export { initAuth, isInitialized } from '../chunk-S4TOKARB.js';
@@ -1,4 +1,4 @@
1
- import { hasRole, hasAnyRole, hasAllRoles, initAuth, resetConfig, getUserRoles, isTokenExpired, decodeJWT } from '../chunk-O47YKG2F.js';
1
+ import { hasRole, hasAnyRole, hasAllRoles, initAuth, resetConfig, getUserRoles, isTokenExpired, decodeJWT } from '../chunk-S4TOKARB.js';
2
2
 
3
3
  // src/testing/fixtures/users.ts
4
4
  var mockUser = {
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@classic-homes/auth",
3
- "version": "1.0.0",
3
+ "version": "1.0.2",
4
4
  "description": "Authentication services and Svelte bindings for Classic Theme apps",
5
5
  "type": "module",
6
6
  "main": "dist/index.js",
@@ -1,3 +0,0 @@
1
- export { authActions, authStore, currentUser, isAuthenticated } from './chunk-QBTMNWJH.js';
2
- import './chunk-2N2MDCWL.js';
3
- import './chunk-O47YKG2F.js';