@classic-homes/auth 1.0.0 → 1.1.0
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/auth.svelte-54WDRZ6V.js +3 -0
- package/dist/{chunk-ILRNO4WH.js → chunk-A2KRBRIC.js} +3 -3
- package/dist/{chunk-QBTMNWJH.js → chunk-B5LAK7V6.js} +2 -2
- package/dist/{chunk-2N2MDCWL.js → chunk-FDOOY3IL.js} +49 -19
- package/dist/{chunk-VVREZ25E.js → chunk-RCD423GF.js} +4 -4
- package/dist/{chunk-O47YKG2F.js → chunk-VFEGS6FR.js} +31 -1
- package/dist/core/index.d.ts +6 -4
- package/dist/core/index.js +3 -3
- package/dist/index.js +5 -5
- package/dist/svelte/index.js +5 -5
- package/dist/testing/index.js +1 -1
- package/package.json +1 -1
- package/dist/auth.svelte-J62VV4TA.js +0 -3
|
@@ -1,6 +1,6 @@
|
|
|
1
|
-
import { authService } from './chunk-
|
|
2
|
-
import { authStore, currentUser, isAuthenticated, authActions } from './chunk-
|
|
3
|
-
import { isInitialized, initAuth, getUserRoles } from './chunk-
|
|
1
|
+
import { authService } from './chunk-RCD423GF.js';
|
|
2
|
+
import { authStore, currentUser, isAuthenticated, authActions } from './chunk-B5LAK7V6.js';
|
|
3
|
+
import { isInitialized, initAuth, getUserRoles } from './chunk-VFEGS6FR.js';
|
|
4
4
|
|
|
5
5
|
// src/svelte/guards/auth-guard.ts
|
|
6
6
|
function checkAuth(options = {}) {
|
|
@@ -1,5 +1,5 @@
|
|
|
1
|
-
import { authApi } from './chunk-
|
|
2
|
-
import { isInitialized, getConfig, hasRole, hasAnyRole, hasAllRoles, decodeJWT, getStorage, getDefaultStorage } from './chunk-
|
|
1
|
+
import { authApi } from './chunk-FDOOY3IL.js';
|
|
2
|
+
import { isInitialized, getConfig, hasRole, hasAnyRole, hasAllRoles, decodeJWT, getStorage, getDefaultStorage } from './chunk-VFEGS6FR.js';
|
|
3
3
|
|
|
4
4
|
// src/svelte/stores/auth.svelte.ts
|
|
5
5
|
var STORAGE_VERSION = 2;
|
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import { getConfig, getStorage, getFetch, isValidRedirectUrl } from './chunk-
|
|
1
|
+
import { getConfig, getStorage, getFetch, isValidRedirectUrl } from './chunk-VFEGS6FR.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
|
|
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-
|
|
80
|
+
import('./auth.svelte-54WDRZ6V.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-54WDRZ6V.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
|
|
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
|
|
127
|
+
return "unavailable";
|
|
113
128
|
}
|
|
114
129
|
} else {
|
|
115
130
|
try {
|
|
116
131
|
apiResponse = await response.json();
|
|
117
132
|
} catch {
|
|
118
|
-
return
|
|
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
|
|
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
|
-
|
|
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
|
|
216
|
+
let refreshResult = "unavailable";
|
|
198
217
|
try {
|
|
199
|
-
|
|
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
|
-
}
|
|
206
|
-
|
|
207
|
-
|
|
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
|
-
|
|
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-
|
|
2
|
-
import { getUserRoles, hasAnyRole } from './chunk-
|
|
1
|
+
import { authApi } from './chunk-FDOOY3IL.js';
|
|
2
|
+
import { getUserRoles, hasAnyRole } from './chunk-VFEGS6FR.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-
|
|
62
|
+
const { authStore } = await import('./auth.svelte-54WDRZ6V.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-
|
|
246
|
+
const { authStore } = await import('./auth.svelte-54WDRZ6V.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()
|
|
123
|
+
return payload.exp * 1e3 < Date.now() + CLOCK_SKEW_MS;
|
|
124
124
|
}
|
|
125
125
|
function getTokenRemainingTime(token) {
|
|
126
126
|
const payload = decodeJWT(token);
|
|
@@ -159,6 +159,20 @@ var ROLE_NAMES = [
|
|
|
159
159
|
"builder",
|
|
160
160
|
"customer_service",
|
|
161
161
|
"demo",
|
|
162
|
+
"stormwater",
|
|
163
|
+
"accounting_staff",
|
|
164
|
+
"architecture_staff",
|
|
165
|
+
"construction_staff",
|
|
166
|
+
"crl_staff",
|
|
167
|
+
"design_staff",
|
|
168
|
+
"hr_staff",
|
|
169
|
+
"it_staff",
|
|
170
|
+
"landdev_staff",
|
|
171
|
+
"marketing_staff",
|
|
172
|
+
"purchasing_staff",
|
|
173
|
+
"sales_staff",
|
|
174
|
+
"warranty_staff",
|
|
175
|
+
"employee",
|
|
162
176
|
"user",
|
|
163
177
|
"vendor",
|
|
164
178
|
"customer",
|
|
@@ -171,10 +185,26 @@ var ROLE_HIERARCHY = {
|
|
|
171
185
|
vendor: 1,
|
|
172
186
|
customer: 1,
|
|
173
187
|
subcontractor: 1,
|
|
188
|
+
// Staff tier (2): the read-only `employee` floor, the field-app clones of
|
|
189
|
+
// `agent`, and every `<department>_staff` docs role.
|
|
190
|
+
employee: 2,
|
|
174
191
|
agent: 2,
|
|
175
192
|
builder: 2,
|
|
176
193
|
customer_service: 2,
|
|
177
194
|
demo: 2,
|
|
195
|
+
stormwater: 2,
|
|
196
|
+
accounting_staff: 2,
|
|
197
|
+
architecture_staff: 2,
|
|
198
|
+
construction_staff: 2,
|
|
199
|
+
crl_staff: 2,
|
|
200
|
+
design_staff: 2,
|
|
201
|
+
hr_staff: 2,
|
|
202
|
+
it_staff: 2,
|
|
203
|
+
landdev_staff: 2,
|
|
204
|
+
marketing_staff: 2,
|
|
205
|
+
purchasing_staff: 2,
|
|
206
|
+
sales_staff: 2,
|
|
207
|
+
warranty_staff: 2,
|
|
178
208
|
manager: 3,
|
|
179
209
|
admin: 4
|
|
180
210
|
};
|
package/dist/core/index.d.ts
CHANGED
|
@@ -469,11 +469,13 @@ declare function extractClaims<T extends string>(token: string, claims: T[]): Pi
|
|
|
469
469
|
* the first match, which is what makes the result deterministic when several
|
|
470
470
|
* roles share a tier (e.g. `agent` + `builder`).
|
|
471
471
|
*
|
|
472
|
-
* Mirrors `ROLE_NAMES` in the API. `builder`/`customer_service`/`demo
|
|
473
|
-
* staff-tier clones of `agent`; `
|
|
474
|
-
*
|
|
472
|
+
* Mirrors `ROLE_NAMES` in the API. `builder`/`customer_service`/`demo`/
|
|
473
|
+
* `stormwater` are staff-tier clones of `agent`; the `<department>_staff` roles
|
|
474
|
+
* are grant-on-top docs roles held alongside another role; `employee` is the
|
|
475
|
+
* read-only base staff floor (default for Authentik SSO); `vendor`/`customer`/
|
|
476
|
+
* `subcontractor` are clones of `user`, row-scoped to their own homes.
|
|
475
477
|
*/
|
|
476
|
-
declare const ROLE_NAMES: readonly ["admin", "manager", "agent", "builder", "customer_service", "demo", "user", "vendor", "customer", "subcontractor", "guest"];
|
|
478
|
+
declare const ROLE_NAMES: readonly ["admin", "manager", "agent", "builder", "customer_service", "demo", "stormwater", "accounting_staff", "architecture_staff", "construction_staff", "crl_staff", "design_staff", "hr_staff", "it_staff", "landdev_staff", "marketing_staff", "purchasing_staff", "sales_staff", "warranty_staff", "employee", "user", "vendor", "customer", "subcontractor", "guest"];
|
|
477
479
|
/**
|
|
478
480
|
* A known role name.
|
|
479
481
|
*
|
package/dist/core/index.js
CHANGED
|
@@ -1,3 +1,3 @@
|
|
|
1
|
-
export { AuthService, RoleDeniedError, authService, formatUserRoles, getAvailableMethods, getAvatarFallback, getDisplayName, getGreeting, getMfaToken, getUserEmail, getUserInitials, isLoginSuccessResponse, isMfaChallengeResponse, isRoleDeniedError } from '../chunk-
|
|
2
|
-
export { api, apiRequest, authApi, clearStoredAuth, extractData, getAccessToken, getRefreshToken, getSessionToken, updateStoredTokens } from '../chunk-
|
|
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-
|
|
1
|
+
export { AuthService, RoleDeniedError, authService, formatUserRoles, getAvailableMethods, getAvatarFallback, getDisplayName, getGreeting, getMfaToken, getUserEmail, getUserInitials, isLoginSuccessResponse, isMfaChallengeResponse, isRoleDeniedError } from '../chunk-RCD423GF.js';
|
|
2
|
+
export { api, apiRequest, authApi, clearStoredAuth, extractData, getAccessToken, getRefreshToken, getSessionToken, updateStoredTokens } from '../chunk-FDOOY3IL.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-VFEGS6FR.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-
|
|
2
|
-
export { AuthService, RoleDeniedError, authService, formatUserRoles, getAvailableMethods, getAvatarFallback, getDisplayName, getGreeting, getMfaToken, getUserEmail, getUserInitials, isLoginSuccessResponse, isMfaChallengeResponse, isRoleDeniedError } from './chunk-
|
|
3
|
-
export { authActions, authStore, currentUser, isAuthenticated } from './chunk-
|
|
4
|
-
export { api, apiRequest, authApi, clearStoredAuth, extractData, getAccessToken, getRefreshToken, getSessionToken, updateStoredTokens } from './chunk-
|
|
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-
|
|
1
|
+
export { canAccess, checkAuth, createAuthClient, createAuthGuard, createAuthHook, createNavFilter, filterByAccess, filterNavSections, matchesRoute, protectedLoad, requireAuth, requirePermission, requireRole, routePatterns } from './chunk-A2KRBRIC.js';
|
|
2
|
+
export { AuthService, RoleDeniedError, authService, formatUserRoles, getAvailableMethods, getAvatarFallback, getDisplayName, getGreeting, getMfaToken, getUserEmail, getUserInitials, isLoginSuccessResponse, isMfaChallengeResponse, isRoleDeniedError } from './chunk-RCD423GF.js';
|
|
3
|
+
export { authActions, authStore, currentUser, isAuthenticated } from './chunk-B5LAK7V6.js';
|
|
4
|
+
export { api, apiRequest, authApi, clearStoredAuth, extractData, getAccessToken, getRefreshToken, getSessionToken, updateStoredTokens } from './chunk-FDOOY3IL.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-VFEGS6FR.js';
|
package/dist/svelte/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-
|
|
2
|
-
export { RoleDeniedError, formatUserRoles, getAvatarFallback, getDisplayName, getGreeting, getUserEmail, getUserInitials, isRoleDeniedError } from '../chunk-
|
|
3
|
-
export { authActions, authStore, currentUser, isAuthenticated } from '../chunk-
|
|
4
|
-
import '../chunk-
|
|
5
|
-
export { initAuth, isInitialized } from '../chunk-
|
|
1
|
+
export { canAccess, checkAuth, createAuthClient, createAuthGuard, createAuthHook, createNavFilter, filterByAccess, filterNavSections, matchesRoute, protectedLoad, requireAuth, requirePermission, requireRole, routePatterns } from '../chunk-A2KRBRIC.js';
|
|
2
|
+
export { RoleDeniedError, formatUserRoles, getAvatarFallback, getDisplayName, getGreeting, getUserEmail, getUserInitials, isRoleDeniedError } from '../chunk-RCD423GF.js';
|
|
3
|
+
export { authActions, authStore, currentUser, isAuthenticated } from '../chunk-B5LAK7V6.js';
|
|
4
|
+
import '../chunk-FDOOY3IL.js';
|
|
5
|
+
export { initAuth, isInitialized } from '../chunk-VFEGS6FR.js';
|
package/dist/testing/index.js
CHANGED
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import { hasRole, hasAnyRole, hasAllRoles, initAuth, resetConfig, getUserRoles, isTokenExpired, decodeJWT } from '../chunk-
|
|
1
|
+
import { hasRole, hasAnyRole, hasAllRoles, initAuth, resetConfig, getUserRoles, isTokenExpired, decodeJWT } from '../chunk-VFEGS6FR.js';
|
|
2
2
|
|
|
3
3
|
// src/testing/fixtures/users.ts
|
|
4
4
|
var mockUser = {
|
package/package.json
CHANGED