@classic-homes/auth 0.1.43 → 0.1.44

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,414 @@
1
+ import { L as LoginCredentials, h as LoginResponse, j as LogoutResponse, R as RegisterData, k as RegisterResponse, U as User, u as ProfileUpdateData, l as Session, m as ApiKey, C as CreateApiKeyRequest, n as CreateApiKeyResponse, o as MFAStatus, M as MFASetupResponse, p as MFAChallengeData, D as Device, q as UserPreferences, s as LinkedAccount, t as SecurityEvent, P as Pagination } from './types-Ct5g1Nbj.js';
2
+
3
+ /**
4
+ * Auth Service
5
+ *
6
+ * Business logic layer for authentication operations.
7
+ * Wraps authApi calls and provides a clean interface for components.
8
+ */
9
+
10
+ interface LoginOptions {
11
+ /**
12
+ * Automatically update the auth store after successful login.
13
+ * Set to false to manually handle auth state.
14
+ * @default true
15
+ */
16
+ autoSetAuth?: boolean;
17
+ /**
18
+ * Required roles for login. If the user doesn't have any of these roles,
19
+ * a RoleDeniedError is thrown instead of completing the login.
20
+ * This prevents users from logging into apps they can't access.
21
+ *
22
+ * @example
23
+ * ```typescript
24
+ * await authService.login(credentials, {
25
+ * allowedRoles: ['admin', 'manager', 'agent'],
26
+ * });
27
+ * ```
28
+ */
29
+ allowedRoles?: string[];
30
+ /**
31
+ * Redirect path to include in RoleDeniedError when role validation fails.
32
+ * Useful for redirecting to a specific error page.
33
+ *
34
+ * @example
35
+ * ```typescript
36
+ * await authService.login(credentials, {
37
+ * allowedRoles: ['admin'],
38
+ * onRoleDeniedRedirect: '/auth/login?error=insufficient_permissions',
39
+ * });
40
+ * ```
41
+ */
42
+ onRoleDeniedRedirect?: string;
43
+ }
44
+ interface MFAVerifyOptions {
45
+ /**
46
+ * Automatically update the auth store after successful MFA verification.
47
+ * Set to false to manually handle auth state.
48
+ * @default true
49
+ */
50
+ autoSetAuth?: boolean;
51
+ /**
52
+ * Required roles for login. If the user doesn't have any of these roles,
53
+ * a RoleDeniedError is thrown instead of completing the login.
54
+ */
55
+ allowedRoles?: string[];
56
+ /**
57
+ * Redirect path to include in RoleDeniedError when role validation fails.
58
+ */
59
+ onRoleDeniedRedirect?: string;
60
+ }
61
+ /**
62
+ * AuthService
63
+ *
64
+ * Provides a clean interface for authentication operations.
65
+ * Can be instantiated for testing or used via the singleton export.
66
+ */
67
+ declare class AuthService {
68
+ /**
69
+ * Login with username and password.
70
+ * By default, automatically sets the auth state on successful login (unless MFA is required).
71
+ * @param credentials - Username and password
72
+ * @param options - Optional settings for login behavior
73
+ */
74
+ login(credentials: LoginCredentials, options?: LoginOptions): Promise<LoginResponse>;
75
+ /**
76
+ * Logout the current user.
77
+ * Returns SSO logout URL if applicable for SSO users.
78
+ */
79
+ logout(): Promise<LogoutResponse>;
80
+ /**
81
+ * Register a new user.
82
+ */
83
+ register(data: RegisterData): Promise<RegisterResponse>;
84
+ /**
85
+ * Request a password reset email.
86
+ */
87
+ forgotPassword(email: string): Promise<void>;
88
+ /**
89
+ * Reset password with a token.
90
+ */
91
+ resetPassword(token: string, newPassword: string): Promise<void>;
92
+ /**
93
+ * Change the current user's password.
94
+ */
95
+ changePassword(currentPassword: string, newPassword: string): Promise<void>;
96
+ /**
97
+ * Refresh the access token.
98
+ */
99
+ refreshToken(refreshToken: string): Promise<{
100
+ accessToken: string;
101
+ refreshToken: string;
102
+ }>;
103
+ /**
104
+ * Initiate SSO login (redirects to SSO provider).
105
+ * @param options.callbackUrl - The URL where the SSO provider should redirect after auth
106
+ * @param options.redirectUrl - The final URL to redirect to after processing the callback
107
+ */
108
+ initiateSSOLogin(options?: {
109
+ callbackUrl?: string;
110
+ redirectUrl?: string;
111
+ }): void;
112
+ /**
113
+ * Get the current user's profile.
114
+ */
115
+ getProfile(customFetch?: typeof fetch): Promise<User>;
116
+ /**
117
+ * Update the current user's profile.
118
+ */
119
+ updateProfile(data: ProfileUpdateData): Promise<User>;
120
+ /**
121
+ * Resend email verification.
122
+ */
123
+ resendVerification(): Promise<void>;
124
+ /**
125
+ * Verify email with a token.
126
+ */
127
+ verifyEmail(token: string): Promise<{
128
+ message: string;
129
+ user?: User;
130
+ }>;
131
+ /**
132
+ * Get all active sessions.
133
+ */
134
+ getSessions(customFetch?: typeof fetch): Promise<{
135
+ sessions: Session[];
136
+ total: number;
137
+ }>;
138
+ /**
139
+ * Revoke a specific session.
140
+ */
141
+ revokeSession(sessionId: string): Promise<void>;
142
+ /**
143
+ * Revoke all sessions except the current one.
144
+ */
145
+ revokeAllSessions(): Promise<void>;
146
+ /**
147
+ * Get all API keys.
148
+ */
149
+ getApiKeys(customFetch?: typeof fetch): Promise<{
150
+ apiKeys: ApiKey[];
151
+ }>;
152
+ /**
153
+ * Create a new API key.
154
+ */
155
+ createApiKey(data: CreateApiKeyRequest): Promise<CreateApiKeyResponse>;
156
+ /**
157
+ * Revoke an API key.
158
+ */
159
+ revokeApiKey(keyId: string): Promise<void>;
160
+ /**
161
+ * Update an API key's name.
162
+ */
163
+ updateApiKey(keyId: string, name: string): Promise<void>;
164
+ /**
165
+ * Get MFA status for the current user.
166
+ */
167
+ getMFAStatus(): Promise<MFAStatus>;
168
+ /**
169
+ * Setup MFA (get QR code and backup codes).
170
+ */
171
+ setupMFA(): Promise<MFASetupResponse>;
172
+ /**
173
+ * Verify MFA setup with a code.
174
+ */
175
+ verifyMFASetup(code: string): Promise<void>;
176
+ /**
177
+ * Disable MFA.
178
+ */
179
+ disableMFA(password: string): Promise<void>;
180
+ /**
181
+ * Regenerate MFA backup codes.
182
+ */
183
+ regenerateBackupCodes(password: string): Promise<{
184
+ backupCodes: string[];
185
+ }>;
186
+ /**
187
+ * Verify MFA challenge during login.
188
+ * By default, automatically sets the auth state on successful verification.
189
+ * @param data - MFA challenge data including token and code
190
+ * @param options - Optional settings for verification behavior
191
+ */
192
+ verifyMFAChallenge(data: MFAChallengeData, options?: MFAVerifyOptions): Promise<LoginResponse>;
193
+ /**
194
+ * Get all devices.
195
+ */
196
+ getDevices(customFetch?: typeof fetch): Promise<{
197
+ devices: Device[];
198
+ }>;
199
+ /**
200
+ * Trust a device.
201
+ */
202
+ trustDevice(deviceId: string): Promise<void>;
203
+ /**
204
+ * Revoke device trust.
205
+ */
206
+ revokeDevice(deviceId: string): Promise<void>;
207
+ /**
208
+ * Remove a device completely.
209
+ */
210
+ removeDevice(deviceId: string): Promise<void>;
211
+ /**
212
+ * Approve a device with a token.
213
+ */
214
+ approveDevice(token: string): Promise<{
215
+ message: string;
216
+ device?: Device;
217
+ }>;
218
+ /**
219
+ * Block a device with a token.
220
+ */
221
+ blockDevice(token: string): Promise<{
222
+ message: string;
223
+ device?: Device;
224
+ }>;
225
+ /**
226
+ * Get user preferences.
227
+ */
228
+ getPreferences(customFetch?: typeof fetch): Promise<UserPreferences>;
229
+ /**
230
+ * Update user preferences.
231
+ */
232
+ updatePreferences(data: Partial<UserPreferences>): Promise<void>;
233
+ /**
234
+ * Get SSO linked accounts.
235
+ */
236
+ getLinkedAccounts(customFetch?: typeof fetch): Promise<LinkedAccount[]>;
237
+ /**
238
+ * Link an SSO account (redirects to SSO provider).
239
+ */
240
+ linkAccount(provider?: string): Promise<void>;
241
+ /**
242
+ * Unlink an SSO account.
243
+ */
244
+ unlinkAccount(provider: string, password?: string): Promise<void>;
245
+ /**
246
+ * Get security event history.
247
+ */
248
+ getSecurityEvents(params?: {
249
+ page?: number;
250
+ limit?: number;
251
+ type?: string;
252
+ }, customFetch?: typeof fetch): Promise<{
253
+ events: SecurityEvent[];
254
+ pagination: Pagination;
255
+ }>;
256
+ }
257
+ /** Singleton instance of AuthService */
258
+ declare const authService: AuthService;
259
+
260
+ /**
261
+ * Auth Errors
262
+ *
263
+ * Custom error types for authentication operations.
264
+ */
265
+
266
+ /**
267
+ * Error thrown when a user successfully authenticates but doesn't have
268
+ * any of the required roles to access the application.
269
+ *
270
+ * This allows apps to validate roles during login and provide specific
271
+ * error handling (e.g., redirect with error message) rather than silently
272
+ * logging in users who can't access any features.
273
+ *
274
+ * @example
275
+ * ```typescript
276
+ * try {
277
+ * const response = await authService.login(credentials, {
278
+ * allowedRoles: ['admin', 'manager', 'agent'],
279
+ * });
280
+ * } catch (error) {
281
+ * if (error instanceof RoleDeniedError) {
282
+ * // User authenticated but lacks required role
283
+ * console.log('User roles:', error.user.roles);
284
+ * console.log('Required roles:', error.requiredRoles);
285
+ * goto('/auth/login?error=insufficient_permissions');
286
+ * }
287
+ * }
288
+ * ```
289
+ */
290
+ declare class RoleDeniedError extends Error {
291
+ readonly name = "RoleDeniedError";
292
+ /**
293
+ * The authenticated user (allows logging before redirect)
294
+ */
295
+ readonly user: User;
296
+ /**
297
+ * The roles that were required (user has none of these)
298
+ */
299
+ readonly requiredRoles: string[];
300
+ /**
301
+ * Optional redirect path for convenience
302
+ */
303
+ readonly redirectTo?: string;
304
+ constructor(user: User, requiredRoles: string[], redirectTo?: string);
305
+ }
306
+ /**
307
+ * Type guard to check if an error is a RoleDeniedError.
308
+ */
309
+ declare function isRoleDeniedError(error: unknown): error is RoleDeniedError;
310
+
311
+ /**
312
+ * User Display Utilities
313
+ *
314
+ * Helper functions for displaying user information in the UI.
315
+ */
316
+
317
+ /**
318
+ * Get a display-friendly name for a user.
319
+ *
320
+ * Priority:
321
+ * 1. Full name (firstName + lastName) if both exist
322
+ * 2. First name only
323
+ * 3. Username
324
+ * 4. Email
325
+ * 5. "Unknown" as fallback
326
+ *
327
+ * @example
328
+ * ```typescript
329
+ * const name = getDisplayName(user);
330
+ * // "John Doe", "John", "johndoe", or "john@example.com"
331
+ * ```
332
+ */
333
+ declare function getDisplayName(user: User | null | undefined): string;
334
+ /**
335
+ * Get initials from a user's name for avatar fallbacks.
336
+ *
337
+ * - Full name: "JD" for "John Doe"
338
+ * - Single name: "J" for "John"
339
+ * - Unknown: "?"
340
+ *
341
+ * @param user - The user object
342
+ * @param maxLength - Maximum number of initials (default: 2)
343
+ *
344
+ * @example
345
+ * ```typescript
346
+ * const initials = getUserInitials(user);
347
+ * // "JD" or "J" or "?"
348
+ * ```
349
+ */
350
+ declare function getUserInitials(user: User | null | undefined, maxLength?: number): string;
351
+ /**
352
+ * Get avatar fallback text for a user.
353
+ * Alias for getUserInitials for semantic clarity.
354
+ *
355
+ * @example
356
+ * ```typescript
357
+ * <Avatar>
358
+ * <AvatarFallback>{getAvatarFallback(user)}</AvatarFallback>
359
+ * </Avatar>
360
+ * ```
361
+ */
362
+ declare function getAvatarFallback(user: User | null | undefined): string;
363
+ /**
364
+ * Get the user's primary email for display.
365
+ * Returns a masked version if needed for privacy.
366
+ *
367
+ * @param user - The user object
368
+ * @param masked - Whether to mask the email (default: false)
369
+ *
370
+ * @example
371
+ * ```typescript
372
+ * getUserEmail(user); // "john@example.com"
373
+ * getUserEmail(user, true); // "j***@example.com"
374
+ * ```
375
+ */
376
+ declare function getUserEmail(user: User | null | undefined, masked?: boolean): string;
377
+ /**
378
+ * Get a greeting for the user based on time of day.
379
+ *
380
+ * @param user - The user object
381
+ * @param includeTime - Whether to include time-based greeting (default: true)
382
+ *
383
+ * @example
384
+ * ```typescript
385
+ * getGreeting(user); // "Good morning, John"
386
+ * getGreeting(user, false); // "Hello, John"
387
+ * ```
388
+ */
389
+ declare function getGreeting(user: User | null | undefined, includeTime?: boolean): string;
390
+ /**
391
+ * Format user roles for display.
392
+ *
393
+ * @param user - The user object
394
+ * @param options - Formatting options
395
+ *
396
+ * @example
397
+ * ```typescript
398
+ * formatUserRoles(user); // "Admin, Manager"
399
+ * formatUserRoles(user, { max: 1 }); // "Admin +1 more"
400
+ * formatUserRoles(user, { lowercase: true }); // "admin, manager"
401
+ * ```
402
+ */
403
+ declare function formatUserRoles(user: User | null | undefined, options?: {
404
+ /** Maximum roles to show before "+N more" */
405
+ max?: number;
406
+ /** Separator between roles (default: ", ") */
407
+ separator?: string;
408
+ /** Convert to lowercase (default: false) */
409
+ lowercase?: boolean;
410
+ /** Capitalize first letter of each role (default: true) */
411
+ capitalize?: boolean;
412
+ }): string;
413
+
414
+ export { AuthService as A, type LoginOptions as L, type MFAVerifyOptions as M, RoleDeniedError as R, authService as a, getUserInitials as b, getAvatarFallback as c, getUserEmail as d, getGreeting as e, formatUserRoles as f, getDisplayName as g, isRoleDeniedError as i };
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@classic-homes/auth",
3
- "version": "0.1.43",
3
+ "version": "0.1.44",
4
4
  "description": "Authentication services and Svelte bindings for Classic Theme apps",
5
5
  "type": "module",
6
6
  "main": "dist/index.js",
@@ -1,66 +0,0 @@
1
- import { authStore } from './chunk-7M4DUK45.js';
2
-
3
- // src/svelte/guards/auth-guard.ts
4
- function checkAuth(options = {}) {
5
- const { roles, permissions, requireAllRoles, requireAllPermissions } = options;
6
- if (!authStore.isAuthenticated) {
7
- return {
8
- allowed: false,
9
- reason: "not_authenticated",
10
- redirectTo: "/login"
11
- };
12
- }
13
- if (roles && roles.length > 0) {
14
- const hasRoles = requireAllRoles ? authStore.hasAllRoles(roles) : authStore.hasAnyRole(roles);
15
- if (!hasRoles) {
16
- return {
17
- allowed: false,
18
- reason: "missing_role",
19
- redirectTo: "/unauthorized"
20
- };
21
- }
22
- }
23
- if (permissions && permissions.length > 0) {
24
- const hasPermissions = requireAllPermissions ? authStore.hasAllPermissions(permissions) : authStore.hasAnyPermission(permissions);
25
- if (!hasPermissions) {
26
- return {
27
- allowed: false,
28
- reason: "missing_permission",
29
- redirectTo: "/unauthorized"
30
- };
31
- }
32
- }
33
- return { allowed: true };
34
- }
35
- function createAuthGuard(options = {}) {
36
- return (onDenied) => {
37
- const result = checkAuth(options);
38
- if (!result.allowed) {
39
- onDenied(result.redirectTo ?? "/login", result.reason ?? "not_authenticated");
40
- return false;
41
- }
42
- return true;
43
- };
44
- }
45
- function requireAuth() {
46
- return checkAuth();
47
- }
48
- function requireRole(roles, requireAll = false) {
49
- const roleArray = Array.isArray(roles) ? roles : [roles];
50
- return checkAuth({ roles: roleArray, requireAllRoles: requireAll });
51
- }
52
- function requirePermission(permissions, requireAll = false) {
53
- const permArray = Array.isArray(permissions) ? permissions : [permissions];
54
- return checkAuth({ permissions: permArray, requireAllPermissions: requireAll });
55
- }
56
- function protectedLoad(options, loadFn) {
57
- return async (event) => {
58
- const result = checkAuth(options);
59
- if (!result.allowed) {
60
- return { redirect: result.redirectTo ?? "/login" };
61
- }
62
- return loadFn(event);
63
- };
64
- }
65
-
66
- export { checkAuth, createAuthGuard, protectedLoad, requireAuth, requirePermission, requireRole };
@@ -1,86 +0,0 @@
1
- /**
2
- * Auth Configuration
3
- *
4
- * Manages global configuration for the auth package.
5
- * Must be initialized via initAuth() before using auth services.
6
- */
7
- interface SSOConfig {
8
- /** Whether SSO is enabled */
9
- enabled: boolean;
10
- /** SSO provider name (e.g., 'authentik', 'okta') */
11
- provider: string;
12
- /** Override the default authorize URL (defaults to /auth/sso/authorize) */
13
- authorizeUrl?: string;
14
- }
15
- interface StorageAdapter {
16
- getItem(key: string): string | null;
17
- setItem(key: string, value: string): void;
18
- removeItem(key: string): void;
19
- }
20
- interface AuthConfig {
21
- /** Base URL for the API (e.g., 'https://api.example.com/v1') */
22
- baseUrl: string;
23
- /** Custom fetch implementation (useful for SSR or testing) */
24
- fetch?: typeof fetch;
25
- /** Storage adapter for token persistence (defaults to localStorage in browser) */
26
- storage?: StorageAdapter;
27
- /** Storage key prefix for auth data */
28
- storageKey?: string;
29
- /** Callback when auth errors occur (e.g., for logging or analytics) */
30
- onAuthError?: (error: Error) => void;
31
- /** Callback when tokens are refreshed */
32
- onTokenRefresh?: (tokens: {
33
- accessToken: string;
34
- refreshToken: string;
35
- }) => void;
36
- /** Callback when user is logged out (e.g., for redirect) */
37
- onLogout?: () => void;
38
- /** SSO configuration */
39
- sso?: SSOConfig;
40
- }
41
- /**
42
- * Initialize the auth package with configuration.
43
- * Must be called before using any auth services.
44
- *
45
- * @example
46
- * ```typescript
47
- * import { initAuth } from '@classic-homes/auth';
48
- *
49
- * initAuth({
50
- * baseUrl: import.meta.env.PUBLIC_API_URL,
51
- * sso: {
52
- * enabled: true,
53
- * provider: 'authentik',
54
- * },
55
- * });
56
- * ```
57
- */
58
- declare function initAuth(options: AuthConfig): void;
59
- /**
60
- * Get the current auth configuration.
61
- * Throws if initAuth() has not been called.
62
- */
63
- declare function getConfig(): AuthConfig;
64
- /**
65
- * Check if auth has been initialized.
66
- */
67
- declare function isInitialized(): boolean;
68
- /**
69
- * Reset the auth configuration (useful for testing).
70
- */
71
- declare function resetConfig(): void;
72
- /**
73
- * Get the default storage adapter.
74
- * Returns localStorage in browser, or a no-op adapter in SSR.
75
- */
76
- declare function getDefaultStorage(): StorageAdapter;
77
- /**
78
- * Get the storage adapter from config or use default.
79
- */
80
- declare function getStorage(): StorageAdapter;
81
- /**
82
- * Get the fetch implementation from config or use global fetch.
83
- */
84
- declare function getFetch(): typeof fetch;
85
-
86
- export { type AuthConfig as A, type SSOConfig as S, isInitialized as a, getDefaultStorage as b, getStorage as c, getFetch as d, type StorageAdapter as e, getConfig as g, initAuth as i, resetConfig as r };