@classic-homes/auth 0.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/README.md +255 -0
- package/dist/core/index.d.ts +631 -0
- package/dist/core/index.js +887 -0
- package/dist/index.d.ts +3 -0
- package/dist/index.js +1197 -0
- package/dist/svelte/index.d.ts +212 -0
- package/dist/svelte/index.js +341 -0
- package/dist/types-exFUQyBX.d.ts +197 -0
- package/package.json +60 -0
|
@@ -0,0 +1,212 @@
|
|
|
1
|
+
import { A as AuthState, U as User } from '../types-exFUQyBX.js';
|
|
2
|
+
|
|
3
|
+
/**
|
|
4
|
+
* Auth Store
|
|
5
|
+
*
|
|
6
|
+
* Authentication state management.
|
|
7
|
+
* Uses a simple observable pattern that works with Svelte's reactivity.
|
|
8
|
+
*
|
|
9
|
+
* Note: This store is designed to work with Svelte 5 runes in components.
|
|
10
|
+
* The store itself doesn't use runes to avoid build complexity.
|
|
11
|
+
*/
|
|
12
|
+
|
|
13
|
+
type Subscriber<T> = (value: T) => void;
|
|
14
|
+
type Unsubscriber = () => void;
|
|
15
|
+
declare class AuthStore {
|
|
16
|
+
private state;
|
|
17
|
+
private subscribers;
|
|
18
|
+
constructor();
|
|
19
|
+
/**
|
|
20
|
+
* Subscribe to state changes (Svelte store contract).
|
|
21
|
+
*/
|
|
22
|
+
subscribe(subscriber: Subscriber<AuthState>): Unsubscriber;
|
|
23
|
+
private notify;
|
|
24
|
+
get accessToken(): string | null;
|
|
25
|
+
get refreshToken(): string | null;
|
|
26
|
+
get user(): User | null;
|
|
27
|
+
get isAuthenticated(): boolean;
|
|
28
|
+
/**
|
|
29
|
+
* Get the current auth state snapshot.
|
|
30
|
+
*/
|
|
31
|
+
getState(): AuthState;
|
|
32
|
+
/**
|
|
33
|
+
* Set auth data after successful login.
|
|
34
|
+
*/
|
|
35
|
+
setAuth(accessToken: string, refreshToken: string, user: User, sessionToken?: string): void;
|
|
36
|
+
/**
|
|
37
|
+
* Update tokens (e.g., after refresh).
|
|
38
|
+
*/
|
|
39
|
+
updateTokens(accessToken: string, refreshToken: string): void;
|
|
40
|
+
/**
|
|
41
|
+
* Update user data (e.g., after profile update).
|
|
42
|
+
*/
|
|
43
|
+
updateUser(user: User): void;
|
|
44
|
+
/**
|
|
45
|
+
* Clear auth state (logout).
|
|
46
|
+
*/
|
|
47
|
+
logout(): void;
|
|
48
|
+
/**
|
|
49
|
+
* Check if user has a specific permission.
|
|
50
|
+
*/
|
|
51
|
+
hasPermission(permission: string): boolean;
|
|
52
|
+
/**
|
|
53
|
+
* Check if user has a specific role.
|
|
54
|
+
*/
|
|
55
|
+
hasRole(role: string): boolean;
|
|
56
|
+
/**
|
|
57
|
+
* Check if user has any of the specified roles.
|
|
58
|
+
*/
|
|
59
|
+
hasAnyRole(roles: string[]): boolean;
|
|
60
|
+
/**
|
|
61
|
+
* Check if user has all of the specified roles.
|
|
62
|
+
*/
|
|
63
|
+
hasAllRoles(roles: string[]): boolean;
|
|
64
|
+
/**
|
|
65
|
+
* Check if user has any of the specified permissions.
|
|
66
|
+
*/
|
|
67
|
+
hasAnyPermission(permissions: string[]): boolean;
|
|
68
|
+
/**
|
|
69
|
+
* Check if user has all of the specified permissions.
|
|
70
|
+
*/
|
|
71
|
+
hasAllPermissions(permissions: string[]): boolean;
|
|
72
|
+
/**
|
|
73
|
+
* Re-hydrate state from storage (useful after config changes).
|
|
74
|
+
*/
|
|
75
|
+
rehydrate(): void;
|
|
76
|
+
}
|
|
77
|
+
/** Singleton auth store instance */
|
|
78
|
+
declare const authStore: AuthStore;
|
|
79
|
+
/**
|
|
80
|
+
* Auth actions for modifying auth state.
|
|
81
|
+
* Provides a stable reference for use in callbacks.
|
|
82
|
+
*/
|
|
83
|
+
declare const authActions: {
|
|
84
|
+
setAuth: (accessToken: string, refreshToken: string, user: User, sessionToken?: string) => void;
|
|
85
|
+
updateTokens: (accessToken: string, refreshToken: string) => void;
|
|
86
|
+
updateUser: (user: User) => void;
|
|
87
|
+
logout: () => void;
|
|
88
|
+
hasPermission: (permission: string) => boolean;
|
|
89
|
+
hasRole: (role: string) => boolean;
|
|
90
|
+
hasAnyRole: (roles: string[]) => boolean;
|
|
91
|
+
hasAllRoles: (roles: string[]) => boolean;
|
|
92
|
+
hasAnyPermission: (permissions: string[]) => boolean;
|
|
93
|
+
hasAllPermissions: (permissions: string[]) => boolean;
|
|
94
|
+
rehydrate: () => void;
|
|
95
|
+
};
|
|
96
|
+
/**
|
|
97
|
+
* Derived stores for common auth values.
|
|
98
|
+
* These follow the Svelte store contract for use with $store syntax.
|
|
99
|
+
*/
|
|
100
|
+
declare const isAuthenticated: {
|
|
101
|
+
subscribe: (subscriber: Subscriber<boolean>) => Unsubscriber;
|
|
102
|
+
};
|
|
103
|
+
declare const currentUser: {
|
|
104
|
+
subscribe: (subscriber: Subscriber<User | null>) => Unsubscriber;
|
|
105
|
+
};
|
|
106
|
+
|
|
107
|
+
/**
|
|
108
|
+
* Auth Guards
|
|
109
|
+
*
|
|
110
|
+
* Route protection utilities for SvelteKit applications.
|
|
111
|
+
*/
|
|
112
|
+
/**
|
|
113
|
+
* Options for auth guard checks.
|
|
114
|
+
*/
|
|
115
|
+
interface AuthGuardOptions {
|
|
116
|
+
/** Required roles (user must have at least one) */
|
|
117
|
+
roles?: string[];
|
|
118
|
+
/** Required permissions (user must have at least one) */
|
|
119
|
+
permissions?: string[];
|
|
120
|
+
/** Require all specified roles (default: false, any role matches) */
|
|
121
|
+
requireAllRoles?: boolean;
|
|
122
|
+
/** Require all specified permissions (default: false, any permission matches) */
|
|
123
|
+
requireAllPermissions?: boolean;
|
|
124
|
+
}
|
|
125
|
+
/**
|
|
126
|
+
* Result of an auth guard check.
|
|
127
|
+
*/
|
|
128
|
+
interface AuthGuardResult {
|
|
129
|
+
/** Whether the user is allowed */
|
|
130
|
+
allowed: boolean;
|
|
131
|
+
/** Reason for denial (if not allowed) */
|
|
132
|
+
reason?: 'not_authenticated' | 'missing_role' | 'missing_permission';
|
|
133
|
+
/** Redirect URL suggestion */
|
|
134
|
+
redirectTo?: string;
|
|
135
|
+
}
|
|
136
|
+
/**
|
|
137
|
+
* Check if the current user passes the auth guard.
|
|
138
|
+
*
|
|
139
|
+
* @example
|
|
140
|
+
* ```typescript
|
|
141
|
+
* // In a +page.ts load function
|
|
142
|
+
* import { checkAuth } from '@classic-homes/auth/svelte';
|
|
143
|
+
* import { redirect } from '@sveltejs/kit';
|
|
144
|
+
*
|
|
145
|
+
* export function load() {
|
|
146
|
+
* const result = checkAuth({ roles: ['admin'] });
|
|
147
|
+
* if (!result.allowed) {
|
|
148
|
+
* throw redirect(302, result.redirectTo ?? '/login');
|
|
149
|
+
* }
|
|
150
|
+
* }
|
|
151
|
+
* ```
|
|
152
|
+
*/
|
|
153
|
+
declare function checkAuth(options?: AuthGuardOptions): AuthGuardResult;
|
|
154
|
+
/**
|
|
155
|
+
* Create a guard function for use in SvelteKit load functions.
|
|
156
|
+
*
|
|
157
|
+
* @example
|
|
158
|
+
* ```typescript
|
|
159
|
+
* // In a +page.ts
|
|
160
|
+
* import { createAuthGuard } from '@classic-homes/auth/svelte';
|
|
161
|
+
* import { redirect } from '@sveltejs/kit';
|
|
162
|
+
*
|
|
163
|
+
* const requireAdmin = createAuthGuard({ roles: ['admin'] });
|
|
164
|
+
*
|
|
165
|
+
* export function load() {
|
|
166
|
+
* requireAdmin((redirectTo) => {
|
|
167
|
+
* throw redirect(302, redirectTo);
|
|
168
|
+
* });
|
|
169
|
+
* // Continue with protected logic
|
|
170
|
+
* }
|
|
171
|
+
* ```
|
|
172
|
+
*/
|
|
173
|
+
declare function createAuthGuard(options?: AuthGuardOptions): (onDenied: (redirectTo: string, reason: string) => void) => boolean;
|
|
174
|
+
/**
|
|
175
|
+
* Simple authentication check (just checks if authenticated).
|
|
176
|
+
*/
|
|
177
|
+
declare function requireAuth(): AuthGuardResult;
|
|
178
|
+
/**
|
|
179
|
+
* Check if user has specific role(s).
|
|
180
|
+
*/
|
|
181
|
+
declare function requireRole(roles: string | string[], requireAll?: boolean): AuthGuardResult;
|
|
182
|
+
/**
|
|
183
|
+
* Check if user has specific permission(s).
|
|
184
|
+
*/
|
|
185
|
+
declare function requirePermission(permissions: string | string[], requireAll?: boolean): AuthGuardResult;
|
|
186
|
+
/**
|
|
187
|
+
* Utility to protect a load function.
|
|
188
|
+
*
|
|
189
|
+
* @example
|
|
190
|
+
* ```typescript
|
|
191
|
+
* // In +page.ts
|
|
192
|
+
* import { protectedLoad } from '@classic-homes/auth/svelte';
|
|
193
|
+
*
|
|
194
|
+
* export const load = protectedLoad(
|
|
195
|
+
* { roles: ['admin'] },
|
|
196
|
+
* async ({ fetch }) => {
|
|
197
|
+
* // This only runs if auth check passes
|
|
198
|
+
* const data = await fetch('/api/admin/data');
|
|
199
|
+
* return { data };
|
|
200
|
+
* }
|
|
201
|
+
* );
|
|
202
|
+
* ```
|
|
203
|
+
*/
|
|
204
|
+
declare function protectedLoad<T>(options: AuthGuardOptions, loadFn: (event: {
|
|
205
|
+
fetch: typeof fetch;
|
|
206
|
+
}) => Promise<T>): (event: {
|
|
207
|
+
fetch: typeof fetch;
|
|
208
|
+
}) => Promise<T | {
|
|
209
|
+
redirect: string;
|
|
210
|
+
}>;
|
|
211
|
+
|
|
212
|
+
export { type AuthGuardOptions, type AuthGuardResult, AuthState, User, authActions, authStore, checkAuth, createAuthGuard, currentUser, isAuthenticated, protectedLoad, requireAuth, requirePermission, requireRole };
|
|
@@ -0,0 +1,341 @@
|
|
|
1
|
+
// src/core/config.ts
|
|
2
|
+
function getDefaultStorage() {
|
|
3
|
+
if (typeof window !== "undefined" && window.localStorage) {
|
|
4
|
+
return {
|
|
5
|
+
getItem: (key) => localStorage.getItem(key),
|
|
6
|
+
setItem: (key, value) => localStorage.setItem(key, value),
|
|
7
|
+
removeItem: (key) => localStorage.removeItem(key)
|
|
8
|
+
};
|
|
9
|
+
}
|
|
10
|
+
return {
|
|
11
|
+
getItem: () => null,
|
|
12
|
+
setItem: () => {
|
|
13
|
+
},
|
|
14
|
+
removeItem: () => {
|
|
15
|
+
}
|
|
16
|
+
};
|
|
17
|
+
}
|
|
18
|
+
|
|
19
|
+
// src/core/jwt.ts
|
|
20
|
+
function decodeJWT(token) {
|
|
21
|
+
try {
|
|
22
|
+
const parts = token.split(".");
|
|
23
|
+
if (parts.length !== 3) {
|
|
24
|
+
return null;
|
|
25
|
+
}
|
|
26
|
+
const payload = parts[1];
|
|
27
|
+
const decoded = atob(payload.replace(/-/g, "+").replace(/_/g, "/"));
|
|
28
|
+
return JSON.parse(decoded);
|
|
29
|
+
} catch {
|
|
30
|
+
return null;
|
|
31
|
+
}
|
|
32
|
+
}
|
|
33
|
+
|
|
34
|
+
// src/svelte/stores/auth.svelte.ts
|
|
35
|
+
function getStorageKey() {
|
|
36
|
+
return "classic_auth";
|
|
37
|
+
}
|
|
38
|
+
function getStorageAdapter() {
|
|
39
|
+
return getDefaultStorage();
|
|
40
|
+
}
|
|
41
|
+
function loadAuthFromStorage() {
|
|
42
|
+
try {
|
|
43
|
+
const storage = getStorageAdapter();
|
|
44
|
+
const data = storage.getItem(getStorageKey());
|
|
45
|
+
if (!data) {
|
|
46
|
+
return {
|
|
47
|
+
accessToken: null,
|
|
48
|
+
refreshToken: null,
|
|
49
|
+
user: null,
|
|
50
|
+
isAuthenticated: false
|
|
51
|
+
};
|
|
52
|
+
}
|
|
53
|
+
const parsed = JSON.parse(data);
|
|
54
|
+
return {
|
|
55
|
+
accessToken: parsed.accessToken ?? null,
|
|
56
|
+
refreshToken: parsed.refreshToken ?? null,
|
|
57
|
+
user: parsed.user ?? null,
|
|
58
|
+
isAuthenticated: !!parsed.accessToken && !!parsed.user
|
|
59
|
+
};
|
|
60
|
+
} catch {
|
|
61
|
+
return {
|
|
62
|
+
accessToken: null,
|
|
63
|
+
refreshToken: null,
|
|
64
|
+
user: null,
|
|
65
|
+
isAuthenticated: false
|
|
66
|
+
};
|
|
67
|
+
}
|
|
68
|
+
}
|
|
69
|
+
function saveAuthToStorage(state) {
|
|
70
|
+
try {
|
|
71
|
+
const storage = getStorageAdapter();
|
|
72
|
+
const key = getStorageKey();
|
|
73
|
+
if (!state.accessToken) {
|
|
74
|
+
storage.removeItem(key);
|
|
75
|
+
} else {
|
|
76
|
+
storage.setItem(key, JSON.stringify(state));
|
|
77
|
+
}
|
|
78
|
+
} catch {
|
|
79
|
+
}
|
|
80
|
+
}
|
|
81
|
+
var AuthStore = class {
|
|
82
|
+
constructor() {
|
|
83
|
+
this.subscribers = /* @__PURE__ */ new Set();
|
|
84
|
+
this.state = loadAuthFromStorage();
|
|
85
|
+
}
|
|
86
|
+
/**
|
|
87
|
+
* Subscribe to state changes (Svelte store contract).
|
|
88
|
+
*/
|
|
89
|
+
subscribe(subscriber) {
|
|
90
|
+
this.subscribers.add(subscriber);
|
|
91
|
+
subscriber(this.state);
|
|
92
|
+
return () => this.subscribers.delete(subscriber);
|
|
93
|
+
}
|
|
94
|
+
notify() {
|
|
95
|
+
this.subscribers.forEach((sub) => sub(this.state));
|
|
96
|
+
}
|
|
97
|
+
// Getters for direct access
|
|
98
|
+
get accessToken() {
|
|
99
|
+
return this.state.accessToken;
|
|
100
|
+
}
|
|
101
|
+
get refreshToken() {
|
|
102
|
+
return this.state.refreshToken;
|
|
103
|
+
}
|
|
104
|
+
get user() {
|
|
105
|
+
return this.state.user;
|
|
106
|
+
}
|
|
107
|
+
get isAuthenticated() {
|
|
108
|
+
return this.state.isAuthenticated;
|
|
109
|
+
}
|
|
110
|
+
/**
|
|
111
|
+
* Get the current auth state snapshot.
|
|
112
|
+
*/
|
|
113
|
+
getState() {
|
|
114
|
+
return { ...this.state };
|
|
115
|
+
}
|
|
116
|
+
/**
|
|
117
|
+
* Set auth data after successful login.
|
|
118
|
+
*/
|
|
119
|
+
setAuth(accessToken, refreshToken, user, sessionToken) {
|
|
120
|
+
const jwtPayload = decodeJWT(accessToken);
|
|
121
|
+
const userWithPermissions = {
|
|
122
|
+
...user,
|
|
123
|
+
permissions: user.permissions || jwtPayload?.permissions || [],
|
|
124
|
+
roles: user.roles || jwtPayload?.roles || (user.role ? [user.role] : [])
|
|
125
|
+
};
|
|
126
|
+
this.state = {
|
|
127
|
+
accessToken,
|
|
128
|
+
refreshToken,
|
|
129
|
+
user: userWithPermissions,
|
|
130
|
+
isAuthenticated: true
|
|
131
|
+
};
|
|
132
|
+
saveAuthToStorage(this.state);
|
|
133
|
+
if (sessionToken && typeof window !== "undefined") {
|
|
134
|
+
getStorageAdapter().setItem("sessionToken", sessionToken);
|
|
135
|
+
}
|
|
136
|
+
if (typeof window !== "undefined") {
|
|
137
|
+
window.dispatchEvent(
|
|
138
|
+
new CustomEvent("auth:login", {
|
|
139
|
+
detail: { user: userWithPermissions }
|
|
140
|
+
})
|
|
141
|
+
);
|
|
142
|
+
}
|
|
143
|
+
this.notify();
|
|
144
|
+
}
|
|
145
|
+
/**
|
|
146
|
+
* Update tokens (e.g., after refresh).
|
|
147
|
+
*/
|
|
148
|
+
updateTokens(accessToken, refreshToken) {
|
|
149
|
+
const jwtPayload = decodeJWT(accessToken);
|
|
150
|
+
const updatedUser = this.state.user ? {
|
|
151
|
+
...this.state.user,
|
|
152
|
+
permissions: jwtPayload?.permissions || this.state.user.permissions || [],
|
|
153
|
+
roles: jwtPayload?.roles || this.state.user.roles || (this.state.user.role ? [this.state.user.role] : [])
|
|
154
|
+
} : null;
|
|
155
|
+
this.state = {
|
|
156
|
+
...this.state,
|
|
157
|
+
accessToken,
|
|
158
|
+
refreshToken,
|
|
159
|
+
user: updatedUser
|
|
160
|
+
};
|
|
161
|
+
saveAuthToStorage(this.state);
|
|
162
|
+
if (typeof window !== "undefined") {
|
|
163
|
+
window.dispatchEvent(new CustomEvent("auth:token-refresh"));
|
|
164
|
+
}
|
|
165
|
+
this.notify();
|
|
166
|
+
}
|
|
167
|
+
/**
|
|
168
|
+
* Update user data (e.g., after profile update).
|
|
169
|
+
*/
|
|
170
|
+
updateUser(user) {
|
|
171
|
+
const jwtPayload = this.state.accessToken ? decodeJWT(this.state.accessToken) : null;
|
|
172
|
+
const updatedUser = {
|
|
173
|
+
...user,
|
|
174
|
+
permissions: user.permissions || jwtPayload?.permissions || [],
|
|
175
|
+
roles: user.roles || jwtPayload?.roles || (user.role ? [user.role] : [])
|
|
176
|
+
};
|
|
177
|
+
this.state = {
|
|
178
|
+
...this.state,
|
|
179
|
+
user: updatedUser
|
|
180
|
+
};
|
|
181
|
+
saveAuthToStorage(this.state);
|
|
182
|
+
if (typeof window !== "undefined") {
|
|
183
|
+
window.dispatchEvent(
|
|
184
|
+
new CustomEvent("auth:profile-update", {
|
|
185
|
+
detail: { user: updatedUser }
|
|
186
|
+
})
|
|
187
|
+
);
|
|
188
|
+
}
|
|
189
|
+
this.notify();
|
|
190
|
+
}
|
|
191
|
+
/**
|
|
192
|
+
* Clear auth state (logout).
|
|
193
|
+
*/
|
|
194
|
+
logout() {
|
|
195
|
+
this.state = {
|
|
196
|
+
accessToken: null,
|
|
197
|
+
refreshToken: null,
|
|
198
|
+
user: null,
|
|
199
|
+
isAuthenticated: false
|
|
200
|
+
};
|
|
201
|
+
const storage = getStorageAdapter();
|
|
202
|
+
storage.removeItem(getStorageKey());
|
|
203
|
+
storage.removeItem("sessionToken");
|
|
204
|
+
if (typeof window !== "undefined") {
|
|
205
|
+
window.dispatchEvent(new CustomEvent("auth:logout"));
|
|
206
|
+
}
|
|
207
|
+
this.notify();
|
|
208
|
+
}
|
|
209
|
+
/**
|
|
210
|
+
* Check if user has a specific permission.
|
|
211
|
+
*/
|
|
212
|
+
hasPermission(permission) {
|
|
213
|
+
return this.state.user?.permissions?.includes(permission) ?? false;
|
|
214
|
+
}
|
|
215
|
+
/**
|
|
216
|
+
* Check if user has a specific role.
|
|
217
|
+
*/
|
|
218
|
+
hasRole(role) {
|
|
219
|
+
return this.state.user?.roles?.includes(role) ?? false;
|
|
220
|
+
}
|
|
221
|
+
/**
|
|
222
|
+
* Check if user has any of the specified roles.
|
|
223
|
+
*/
|
|
224
|
+
hasAnyRole(roles) {
|
|
225
|
+
return roles.some((role) => this.state.user?.roles?.includes(role)) ?? false;
|
|
226
|
+
}
|
|
227
|
+
/**
|
|
228
|
+
* Check if user has all of the specified roles.
|
|
229
|
+
*/
|
|
230
|
+
hasAllRoles(roles) {
|
|
231
|
+
return roles.every((role) => this.state.user?.roles?.includes(role)) ?? false;
|
|
232
|
+
}
|
|
233
|
+
/**
|
|
234
|
+
* Check if user has any of the specified permissions.
|
|
235
|
+
*/
|
|
236
|
+
hasAnyPermission(permissions) {
|
|
237
|
+
return permissions.some((perm) => this.state.user?.permissions?.includes(perm)) ?? false;
|
|
238
|
+
}
|
|
239
|
+
/**
|
|
240
|
+
* Check if user has all of the specified permissions.
|
|
241
|
+
*/
|
|
242
|
+
hasAllPermissions(permissions) {
|
|
243
|
+
return permissions.every((perm) => this.state.user?.permissions?.includes(perm)) ?? false;
|
|
244
|
+
}
|
|
245
|
+
/**
|
|
246
|
+
* Re-hydrate state from storage (useful after config changes).
|
|
247
|
+
*/
|
|
248
|
+
rehydrate() {
|
|
249
|
+
this.state = loadAuthFromStorage();
|
|
250
|
+
this.notify();
|
|
251
|
+
}
|
|
252
|
+
};
|
|
253
|
+
var authStore = new AuthStore();
|
|
254
|
+
var authActions = {
|
|
255
|
+
setAuth: (accessToken, refreshToken, user, sessionToken) => authStore.setAuth(accessToken, refreshToken, user, sessionToken),
|
|
256
|
+
updateTokens: (accessToken, refreshToken) => authStore.updateTokens(accessToken, refreshToken),
|
|
257
|
+
updateUser: (user) => authStore.updateUser(user),
|
|
258
|
+
logout: () => authStore.logout(),
|
|
259
|
+
hasPermission: (permission) => authStore.hasPermission(permission),
|
|
260
|
+
hasRole: (role) => authStore.hasRole(role),
|
|
261
|
+
hasAnyRole: (roles) => authStore.hasAnyRole(roles),
|
|
262
|
+
hasAllRoles: (roles) => authStore.hasAllRoles(roles),
|
|
263
|
+
hasAnyPermission: (permissions) => authStore.hasAnyPermission(permissions),
|
|
264
|
+
hasAllPermissions: (permissions) => authStore.hasAllPermissions(permissions),
|
|
265
|
+
rehydrate: () => authStore.rehydrate()
|
|
266
|
+
};
|
|
267
|
+
var isAuthenticated = {
|
|
268
|
+
subscribe: (subscriber) => {
|
|
269
|
+
return authStore.subscribe((state) => subscriber(state.isAuthenticated));
|
|
270
|
+
}
|
|
271
|
+
};
|
|
272
|
+
var currentUser = {
|
|
273
|
+
subscribe: (subscriber) => {
|
|
274
|
+
return authStore.subscribe((state) => subscriber(state.user));
|
|
275
|
+
}
|
|
276
|
+
};
|
|
277
|
+
|
|
278
|
+
// src/svelte/guards/auth-guard.ts
|
|
279
|
+
function checkAuth(options = {}) {
|
|
280
|
+
const { roles, permissions, requireAllRoles, requireAllPermissions } = options;
|
|
281
|
+
if (!authStore.isAuthenticated) {
|
|
282
|
+
return {
|
|
283
|
+
allowed: false,
|
|
284
|
+
reason: "not_authenticated",
|
|
285
|
+
redirectTo: "/login"
|
|
286
|
+
};
|
|
287
|
+
}
|
|
288
|
+
if (roles && roles.length > 0) {
|
|
289
|
+
const hasRoles = requireAllRoles ? authStore.hasAllRoles(roles) : authStore.hasAnyRole(roles);
|
|
290
|
+
if (!hasRoles) {
|
|
291
|
+
return {
|
|
292
|
+
allowed: false,
|
|
293
|
+
reason: "missing_role",
|
|
294
|
+
redirectTo: "/unauthorized"
|
|
295
|
+
};
|
|
296
|
+
}
|
|
297
|
+
}
|
|
298
|
+
if (permissions && permissions.length > 0) {
|
|
299
|
+
const hasPermissions = requireAllPermissions ? authStore.hasAllPermissions(permissions) : authStore.hasAnyPermission(permissions);
|
|
300
|
+
if (!hasPermissions) {
|
|
301
|
+
return {
|
|
302
|
+
allowed: false,
|
|
303
|
+
reason: "missing_permission",
|
|
304
|
+
redirectTo: "/unauthorized"
|
|
305
|
+
};
|
|
306
|
+
}
|
|
307
|
+
}
|
|
308
|
+
return { allowed: true };
|
|
309
|
+
}
|
|
310
|
+
function createAuthGuard(options = {}) {
|
|
311
|
+
return (onDenied) => {
|
|
312
|
+
const result = checkAuth(options);
|
|
313
|
+
if (!result.allowed) {
|
|
314
|
+
onDenied(result.redirectTo ?? "/login", result.reason ?? "not_authenticated");
|
|
315
|
+
return false;
|
|
316
|
+
}
|
|
317
|
+
return true;
|
|
318
|
+
};
|
|
319
|
+
}
|
|
320
|
+
function requireAuth() {
|
|
321
|
+
return checkAuth();
|
|
322
|
+
}
|
|
323
|
+
function requireRole(roles, requireAll = false) {
|
|
324
|
+
const roleArray = Array.isArray(roles) ? roles : [roles];
|
|
325
|
+
return checkAuth({ roles: roleArray, requireAllRoles: requireAll });
|
|
326
|
+
}
|
|
327
|
+
function requirePermission(permissions, requireAll = false) {
|
|
328
|
+
const permArray = Array.isArray(permissions) ? permissions : [permissions];
|
|
329
|
+
return checkAuth({ permissions: permArray, requireAllPermissions: requireAll });
|
|
330
|
+
}
|
|
331
|
+
function protectedLoad(options, loadFn) {
|
|
332
|
+
return async (event) => {
|
|
333
|
+
const result = checkAuth(options);
|
|
334
|
+
if (!result.allowed) {
|
|
335
|
+
return { redirect: result.redirectTo ?? "/login" };
|
|
336
|
+
}
|
|
337
|
+
return loadFn(event);
|
|
338
|
+
};
|
|
339
|
+
}
|
|
340
|
+
|
|
341
|
+
export { authActions, authStore, checkAuth, createAuthGuard, currentUser, isAuthenticated, protectedLoad, requireAuth, requirePermission, requireRole };
|