@resk/core
Version:
An innovative TypeScript framework that empowers developers to build applications with a fully decorator-based architecture for efficient resource management. By combining the power of decorators with a resource-oriented design, DecorRes enhances code cla
1,137 lines (1,136 loc) • 89.9 kB
TypeScript
import { IObservable } from "../observable";
import { IResourceActionName, IResourceName } from "../resources/types";
import { IDict } from "../types/dictionary";
import "./types";
import { IAuthEvent, IAuthPerm, IAuthPerms, IAuthSessionStorage, IAuthUser } from "./types";
export * from "./types";
/***
* A class that provides methods for managing session data.
*
*/
declare class Session {
/**
* Retrieves a specific value from the session data based on the provided session name and key.
*
* This function first checks if the provided key is a non-null string. If it is not, it returns undefined.
* It then retrieves the session data using `getData` and returns the value associated with the specified key.
*
* @param sessionName - An optional string that represents the name of the session.
* @param key - A string representing the key of the value to retrieve from the session data.
*
* @returns The value associated with the specified key in the session data, or undefined if the key is invalid.
*
* @example
* // Example of retrieving a specific value from session data
* const value = get('mySession', 'userPreference'); // Returns: 'darkMode'
*
* @example
* // Example of trying to retrieve a value with an invalid key
* const value = get('mySession', null); // Returns: undefined
*/
static get(sessionName?: string, key?: string): any;
/**
* Sets a value or an object in the session data for a specific session name.
*
* This function retrieves the current session data using `getData`. If a valid key is provided, it sets the
* corresponding value in the session data. If an object is provided as the key, it replaces the entire session data.
* Finally, it saves the updated session data back to the session storage.
*
* @param sessionName - An optional string that represents the name of the session.
* @param key - A string representing the key to set a value for, or an object containing multiple key-value pairs.
* @param value - The value to set for the specified key. This parameter is ignored if an object is provided as the key.
*
* @returns The updated session data as an object.
*
* @example
* // Example of setting a single value in session data
* const updatedData = set('mySession', 'userPreference', 'darkMode'); // Returns: { userPreference: 'darkMode' }
*
* @example
* // Example of replacing the entire session data with an object
* const updatedData = set('mySession', { userPreference: 'lightMode', language: ' English' }); // Returns: { userPreference: 'lightMode', language: 'English' }
*/
static set(sessionName?: string, key?: string | IDict, value?: any): IDict;
/**
* Generates a unique session key based on the authenticated user's ID and an optional session name.
*
* The session key is constructed in the format: `auth-{userId}-{sessionName}`. If the user is not signed in,
* the user ID will be an empty string. This key is used to store and retrieve session data.
*
* @param sessionName - An optional string that represents the name of the session. If not provided,
* an empty string will be used in the key.
*
* @returns A string representing the unique session key.
*
* @example
* // Example of generating a session key for a user with ID '12345'
* const sessionKey = getKey('mySession'); // Returns: 'auth-12345-mySession'
*
* @example
* // Example of generating a session key when no user is signed in
* const sessionKey = getKey(); // Returns: 'auth--'
*/
static getKey(sessionName?: string): string;
/**
* Retrieves session data associated with a specific session name.
*
* This function checks if the provided session name is a non-null string. If it is not, an empty object is returned.
* Otherwise, it constructs a key using `getKey` and retrieves the corresponding data from the session storage.
*
* @param sessionName - An optional string that represents the name of the session. If not provided or invalid,
* an empty object will be returned.
*
* @returns An object containing the session data associated with the specified session name.
* If the session name is invalid, an empty object is returned.
*
* @example
* // Example of retrieving session data for a specific session name
* const sessionData = getData('mySession'); // Returns: { }
*
* @example
* // Example of retrieving session data with an invalid session name
* const sessionData = getData(null); // Returns: {}
*/
static getData(sessionName?: string): IDict;
/**
* Retrieves the authentication token from the session storage.
*
* This function checks the currently signed-in user and returns their token.
* If the user is not signed in or if there is no token available, it will return
* `undefined` or `null`.
*
* @returns {string | undefined | null} The authentication token of the signed user,
* or `undefined` if the user is not signed in, or `null` if there is no token.
*
* @example
* const token = getToken();
* if (token) {
* console.log("User token:", token);
* } else {
* console.log("No user is signed in or token is not available.");
* }
*/
static getToken(): string | undefined | null;
/**
* Sets the authentication token in the session storage for the currently signed-in user.
*
* This function updates the signed user's information by adding or updating the token
* in the session storage. If the token is `null`, it will remove the token from the user's
* session data.
*
* @param {string | null} token - The token to be set for the signed user.
* If `null`, the token will be removed from the user's session data.
*
* @returns {void} This function does not return a value.
*
* @example
* setToken("my-secret-token");
* // To remove the token
* setToken(null);
*/
static setToken(token: string | null): void;
/**
* Retrieves a session storage object that provides methods for managing session data.
*
* This function creates an object that allows you to interact with session storage
* using a specified session name. It provides methods to get, set, and retrieve data
* associated with the session, as well as to retrieve the session key.
*
* @param sessionName - An optional string that represents the name of the session.
* If provided, it will be used as a prefix for the keys stored
* in session storage. If not provided, the session will be
* treated as anonymous.
*
* @returns An object implementing the `IAuthSessionStorage` interface, which includes
* methods for session management:
* - `get(key?: string): any`: Retrieves the value associated with the specified key.
* - `set(key?: string | IDict, value?: any): void`: Stores a value under the specified key.
* - `getData(): IDict`: Returns all data stored in the session as a dictionary.
* - `getKey(): string`: Returns the session key used for storage.
*
* @example
* // Create a session storage object with a specific session name
* const session = getSessionStorage('userSession');
*
* // Set a value in the session storage
* session.set('token', 'abc123');
*
* // Retrieve the value from session storage
* const token = session.get('token'); // 'abc123'
*
* // Get all data stored in the session
* const allData = session.getData(); // { token: 'abc123' }
*
* // Get the session key
* const sessionKey = session.getKey(); // 'userSession'
*
* @remarks
* This function is particularly useful for managing user authentication sessions
* in web applications. By using session storage, data persists across page reloads
* but is cleared when the tab or browser is closed.
*
* Ensure that the keys used for storing data are unique to avoid collisions with
* other session data. Consider using a structured naming convention for keys.
*/
static getStorage(sessionName?: string): IAuthSessionStorage;
}
export declare class Auth {
/**
* Authentication event handler.
* Initializes an observable event handler for authentication Auth.events.
*
* This constant `events` is assigned an instance of `IObservable<IAuthEvent>`, which is used to manage
* authentication-related events in the application. The initialization checks if the global
* `Global.eventsResourcesObservableHandler` exists and is an object. If it does, it assigns it to
* `events`; otherwise, it defaults to an empty object cast as `IObservable<IAuthEvent>`.
*
* This pattern allows for flexible handling of events, ensuring that the application can respond
* to authentication actions such as sign-in, sign-out, and sign-up.
*
* @type {IObservable<IAuthEvent>}
*
* @example
* import {Auth} from '@resk/core';
* Auth.events.on('SIGN_IN', (user) => {
* console.log(`User signed in: ${user.username}`);
* });
*
* function userSignIn(user) {
* Auth.events.trigger('SIGN_IN', user);
* }
*/
static events: IObservable<IAuthEvent>;
private static localUserRef;
/**
* Checks if the user is a master admin.
*
* The `isMasterAdmin` function determines whether the provided user
* has master admin privileges. If no user is provided, it will
* attempt to retrieve the signed user from the session.
*
* ### Parameters
*
* - `user` (IAuthUser , optional): The user object to check. If not
* provided, the function will attempt to retrieve the signed user
* from the session.
*
* ### Returns
*
* - `boolean`: Returns `true` if the user is a master admin, or `false` otherwise.
*
* ### Example Usage
*
* ```typescript
* const user: IAuthUser = { id: "admin123" };
* Auth.isMasterAdmin = (user)=>{
* return checkSomeCondition(user);
* }; // false (assuming the user is not a master admin)
* ```
* @see {@link IAuthUser} for the `IAuthUser` type.
*/
static isMasterAdmin?: (user?: IAuthUser) => boolean;
private static _isMasterAdmin;
/**
* Retrieves the currently authenticated user from secure session storage.
*
* This method implements a secure user session retrieval system that handles encrypted
* user data storage. It first checks for a cached user reference in memory for performance
* optimization, then attempts to decrypt and parse the user data from session storage
* if no cached version exists. The method includes comprehensive error handling for
* decryption failures and data corruption scenarios.
*
* ### Security Features:
* - **Encrypted Storage**: User data is encrypted using AES encryption before storage
* - **Memory Caching**: Cached in `localUserRef` for improved performance and reduced decryption overhead
* - **Safe Parsing**: Uses `JsonHelper.parse` for secure JSON deserialization
* - **Error Recovery**: Gracefully handles corrupted or invalid session data
*
* ### Performance Optimization:
* The method implements a two-tier retrieval strategy:
* 1. **Memory Cache**: Returns immediately if user is already loaded in memory
* 2. **Session Storage**: Decrypts and parses data from persistent storage only when needed
*
* @returns The authenticated user object containing user information, permissions, and roles,
* or `null` if no user is currently signed in, session data is corrupted, or
* decryption fails. The returned object conforms to the `IAuthUser` interface.
*
* @example
* ```typescript
* // Basic usage - check if user is signed in
* const currentUser = Auth.getSignedUser();
* if (currentUser) {
* console.log(`Welcome back, ${currentUser.username}!`);
* console.log(`User ID: ${currentUser.id}`);
* } else {
* console.log("No user is currently signed in");
* }
* ```
*
* @example
* ```typescript
* // Using with permission checking
* const user = Auth.getSignedUser();
* if (user) {
* const canEditDocuments = Auth.checkUserPermission(user, "documents", "update");
* if (canEditDocuments) {
* showEditButton();
* }
* }
* ```
*
* @example
* ```typescript
* // Handling authentication state in React component
* function UserProfile() {
* const [user, setUser] = useState<IAuthUser | null>(null);
*
* useEffect(() => {
* const currentUser = Auth.getSignedUser();
* setUser(currentUser);
*
* if (!currentUser) {
* // Redirect to login page
* router.push('/login');
* }
* }, []);
*
* return user ? <div>Hello, {user.username}</div> : <div>Loading...</div>;
* }
* ```
*
* @example
* ```typescript
* // Using with authentication guards
* class AuthGuard {
* static requireAuth(): boolean {
* const user = Auth.getSignedUser();
* if (!user) {
* throw new Error("Authentication required");
* }
* return true;
* }
*
* static requireRole(roleName: string): boolean {
* const user = Auth.getSignedUser();
* return user?.roles?.some(role => role.name === roleName) ?? false;
* }
* }
* ```
*
* @example
* ```typescript
* // API request with user token
* async function makeAuthenticatedRequest(url: string) {
* const user = Auth.getSignedUser();
* if (!user?.token) {
* throw new Error("No valid authentication token");
* }
*
* return fetch(url, {
* headers: {
* 'Authorization': `Bearer ${user.token}`,
* 'Content-Type': 'application/json'
* }
* });
* }
* ```
*
* @throws {CryptoError} May throw during decryption if session data is corrupted
* @throws {SyntaxError} May throw during JSON parsing if decrypted data is malformed
*
* @see {@link IAuthUser} - Complete user object interface definition
* @see {@link setSignedUser} - Method to store user in session
* @see {@link signIn} - High-level user authentication method
* @see {@link signOut} - Method to clear user session
* @see {@link Session.getToken} - Utility to get user's authentication token
* @see {@link checkUserPermission} - Check specific user permissions
*
* @since 1.0.0
* @public
*
* @remarks
* **Security Considerations:**
* - Session data is automatically encrypted using AES encryption
* - The encryption key `SESSION_ENCRYPT_KEY` should be kept secure
* - User data includes sensitive information like tokens and permissions
* - Always validate user data before using in security-critical operations
*
* **Performance Notes:**
* - First call after page load requires decryption (slower)
* - Subsequent calls return cached data (faster)
* - Cache is automatically cleared when user signs out
* - Consider the performance impact in render loops
*
* **Error Handling:**
* - Returns `null` instead of throwing errors for better UX
* - Logs errors to console for debugging purposes
* - Gracefully handles session storage corruption
* - Automatically recovers from temporary decryption failures
*/
static getSignedUser(): IAuthUser | null;
/**
* Securely stores an authenticated user in encrypted session storage with event broadcasting.
*
* This method is the core user session management function that handles secure storage of user
* authentication data. It encrypts user information using AES encryption before persisting to
* session storage, maintains local memory cache for performance, and optionally broadcasts
* authentication events to notify other parts of the application about user state changes.
*
* ### Security Architecture:
* - **AES Encryption**: User data is encrypted before storage to protect sensitive information
* - **Session Timestamping**: Automatically adds `authSessionCreatedAt` timestamp for session tracking
* - **Error Isolation**: Encryption failures don't crash the application, user reference is safely cleared
* - **Memory Management**: Updates local cache reference for immediate access
*
* ### Event System Integration:
* The method integrates with the authentication event system to broadcast state changes:
* - **SIGN_IN Event**: Triggered when a valid user is stored with successful encryption
* - **SIGN_OUT Event**: Triggered when user is cleared (null) or encryption fails
* - **Event Payload**: Includes the user object for event handlers to process
*
* @param u - The user object to store in session, or `null` to clear the current session.
* When providing a user object, it should contain all necessary authentication
* information including permissions, roles, and tokens. The object will be
* automatically timestamped with `authSessionCreatedAt`.
*
* @param triggerEvent - Optional flag controlling whether to broadcast authentication events.
* When `true` (default), triggers either 'SIGN_IN' or 'SIGN_OUT' events
* based on the operation result. Set to `false` to perform silent
* session updates without notifying event listeners.
*
* @returns A promise that resolves to the result of the session storage operation.
* The promise completes after the encrypted data has been written to storage.
* Returns the storage operation result, typically indicating success or failure.
*
* @example
* ```typescript
* // Standard user sign-in with event broadcasting
* const user: IAuthUser = {
* id: "user123",
* username: "john_doe",
* email: "john@example.com",
* token: "eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9...",
* perms: { documents: ["read", "write"] },
* roles: [{ name: "editor", perms: { images: ["upload"] } }]
* };
*
* await Auth.setSignedUser(user, true);
* console.log("User signed in with events triggered");
* ```
*
* @example
* ```typescript
* // Silent session update without triggering events
* const updatedUser = { ...currentUser, lastActivity: new Date() };
* await Auth.setSignedUser(updatedUser, false);
* console.log("User session updated silently");
* ```
*
* @example
* ```typescript
* // Clear user session (sign out)
* await Auth.setSignedUser(null, true);
* console.log("User signed out, SIGN_OUT event triggered");
* ```
*
* @example
* ```typescript
* // Using with event listeners
* Auth.events.on('SIGN_IN', (user) => {
* console.log(`Welcome ${user.username}!`);
* initializeUserDashboard(user);
* trackUserLogin(user.id);
* });
*
* Auth.events.on('SIGN_OUT', () => {
* console.log('User signed out');
* clearUserDashboard();
* redirectToLogin();
* });
*
* // Now when we set a user, events will fire automatically
* await Auth.setSignedUser(authenticatedUser);
* ```
*
* @example
* ```typescript
* // Error handling with session management
* try {
* await Auth.setSignedUser(userFromAPI);
* showSuccessMessage("Login successful");
* } catch (error) {
* console.error("Failed to store user session:", error);
* showErrorMessage("Login failed, please try again");
* }
* ```
*
* @example
* ```typescript
* // Updating user permissions after role change
* const currentUser = Auth.getSignedUser();
* if (currentUser) {
* const updatedUser = {
* ...currentUser,
* roles: [...currentUser.roles, newRole],
* perms: { ...currentUser.perms, ...newPermissions }
* };
*
* await Auth.setSignedUser(updatedUser, false); // Silent update
* console.log("User permissions updated");
* }
* ```
*
* @throws {CryptoError} May throw if encryption fails due to invalid encryption key
* @throws {StorageError} May throw if session storage is unavailable or quota exceeded
*
* @see {@link IAuthUser} - Complete user object interface with all required fields
* @see {@link getSignedUser} - Retrieve the currently stored user from session
* @see {@link signIn} - High-level user authentication wrapper
* @see {@link signOut} - High-level user sign-out wrapper
* @see {@link Auth.events} - Authentication event system for state change notifications
* @see {@link IAuthEvent} - Available authentication event types and payloads
*
* @since 1.0.0
* @public
* @async
*
* @remarks
* **Security Best Practices:**
* - User objects should be validated before storage
* - Sensitive data like tokens are automatically encrypted
* - Session timestamps help with security auditing
* - Always handle encryption errors gracefully
*
* **Performance Considerations:**
* - Encryption/decryption adds computational overhead
* - Local cache is updated synchronously for immediate access
* - Event broadcasting may trigger multiple listeners
* - Consider batching multiple user updates to reduce I/O
*
* **Event System:**
* - Events are asynchronous and don't block the storage operation
* - Multiple listeners can subscribe to the same event
* - Event payload includes the full user object for flexibility
* - Use `triggerEvent: false` for internal operations to avoid recursion
*/
static setSignedUser(u: IAuthUser | null, triggerEvent?: boolean): Promise<IAuthUser | null>;
/**
* Authenticates a user and establishes a secure session with comprehensive validation.
*
* This high-level authentication method provides a complete user sign-in workflow with
* input validation, secure session establishment, and event broadcasting. It serves as
* the primary entry point for user authentication in applications, handling all the
* complexity of secure session management while providing a simple, promise-based API.
*
* ### Authentication Workflow:
* 1. **Input Validation**: Validates that the provided user object is properly structured
* 2. **Session Creation**: Calls `setSignedUser` to securely store user data
* 3. **Event Broadcasting**: Optionally triggers authentication events for app-wide notifications
* 4. **Return Confirmation**: Returns the authenticated user object on successful completion
*
* ### Security Features:
* - **Object Validation**: Ensures user object is valid before processing
* - **Encrypted Storage**: Leverages `setSignedUser` for secure data persistence
* - **Error Handling**: Provides meaningful error messages for failed authentication
* - **Session Timestamping**: Automatically tracks when authentication session was created
*
* @param user - The authenticated user object containing all necessary user information.
* Must be a valid object conforming to the `IAuthUser` interface, including
* properties like id, username, email, permissions, roles, and authentication token.
* The object should come from a successful authentication process (login API, OAuth, etc.).
*
* @param triggerEvent - Optional flag controlling whether to broadcast authentication events.
* When `true` (default), triggers a 'SIGN_IN' event that other parts of
* the application can listen to for initialization, analytics, or UI updates.
* Set to `false` for silent authentication without event notifications.
*
* @returns A promise that resolves to the authenticated user object when sign-in is successful.
* The returned user object is the same as the input but may include additional
* properties added during the authentication process (like session timestamps).
*
* @throws {Error} Throws an error with internationalized message if the user object is invalid,
* null, undefined, or not a proper object structure. The error message is
* retrieved from the i18n system using key "auth.invalidSignInUser".
*
* @example
* ```typescript
* // Basic user sign-in after successful API authentication
* try {
* const response = await fetch('/api/auth/login', {
* method: 'POST',
* body: JSON.stringify({ username, password }),
* headers: { 'Content-Type': 'application/json' }
* });
*
* const userData = await response.json();
* const authenticatedUser = await Auth.signIn(userData);
*
* console.log(`Welcome ${authenticatedUser.username}!`);
* router.push('/dashboard');
* } catch (error) {
* console.error('Sign-in failed:', error.message);
* showErrorMessage('Invalid credentials');
* }
* ```
*
* @example
* ```typescript
* // OAuth authentication workflow
* async function handleOAuthCallback(authCode: string) {
* try {
* // Exchange auth code for user data
* const tokenResponse = await exchangeCodeForToken(authCode);
* const userProfile = await fetchUserProfile(tokenResponse.access_token);
*
* const user: IAuthUser = {
* id: userProfile.id,
* username: userProfile.login,
* email: userProfile.email,
* token: tokenResponse.access_token,
* perms: await fetchUserPermissions(userProfile.id),
* roles: await fetchUserRoles(userProfile.id),
* provider: 'oauth'
* };
*
* await Auth.signIn(user);
* console.log('OAuth sign-in successful');
* } catch (error) {
* console.error('OAuth sign-in failed:', error);
* }
* }
* ```
*
* @example
* ```typescript
* // Silent authentication without triggering events
* async function silentAuth(sessionToken: string) {
* try {
* const userData = await validateSessionToken(sessionToken);
* const user = await Auth.signIn(userData, false); // No events
*
* console.log('Silent authentication successful');
* return user;
* } catch (error) {
* console.log('Silent auth failed, user needs to login');
* return null;
* }
* }
* ```
*
* @example
* ```typescript
* // Complete authentication flow with event handling
* // Set up event listeners first
* Auth.events.on('SIGN_IN', (user) => {
* // Initialize user-specific features
* initializeUserPreferences(user.id);
* loadUserDashboard(user.perms);
* trackAnalyticsEvent('user_signin', { userId: user.id });
*
* // Update UI state
* updateNavigationForUser(user.roles);
* showWelcomeMessage(user.username);
* });
*
* // Perform authentication
* async function loginUser(credentials: LoginCredentials) {
* try {
* const authResult = await authenticateWithAPI(credentials);
* const user = await Auth.signIn(authResult.user); // Events will fire
*
* return { success: true, user };
* } catch (error) {
* return { success: false, error: error.message };
* }
* }
* ```
*
* @example
* ```typescript
* // Multi-step authentication with role-based redirection
* async function signInWithRoleRedirect(userData: any) {
* try {
* const user = await Auth.signIn(userData);
*
* // Redirect based on user role
* if (user.roles?.some(role => role.name === 'admin')) {
* router.push('/admin/dashboard');
* } else if (user.roles?.some(role => role.name === 'moderator')) {
* router.push('/moderator/panel');
* } else {
* router.push('/user/dashboard');
* }
*
* return user;
* } catch (error) {
* console.error('Role-based sign-in failed:', error);
* throw error;
* }
* }
* ```
*
* @see {@link IAuthUser} - Complete user object interface specification
* @see {@link setSignedUser} - Lower-level method for secure user storage
* @see {@link getSignedUser} - Retrieve currently authenticated user
* @see {@link signOut} - Sign out and clear user session
* @see {@link Auth.events} - Authentication event system for state notifications
* @see {@link isAllowed} - Check user permissions for access control
*
* @since 1.0.0
* @public
* @async
*
* @remarks
* **Best Practices:**
* - Always validate user data before calling this method
* - Use try-catch blocks to handle authentication failures gracefully
* - Consider implementing token refresh logic for long-lived sessions
* - Use event listeners to initialize user-specific application features
*
* **Error Handling:**
* - The method throws immediately on invalid input for fast failure
* - Use internationalized error messages for better user experience
* - Consider logging authentication attempts for security monitoring
* - Implement retry logic for transient authentication failures
*
* **Integration Notes:**
* - Works seamlessly with any authentication provider (JWT, OAuth, custom)
* - Integrates with the permission system for access control
* - Compatible with SSR/SPA applications through secure session storage
* - Supports both traditional and modern authentication workflows
*/
static signIn(user: IAuthUser, triggerEvent?: boolean): Promise<IAuthUser>;
/**
* Signs out the currently authenticated user and securely clears their session.
*
* This method provides a high-level, convenient interface for user sign-out operations.
* It handles the complete user session termination workflow by clearing the encrypted
* user data from session storage, removing the cached user reference from memory, and
* optionally broadcasting sign-out events to notify other parts of the application
* about the authentication state change.
*
* ### Sign-Out Workflow:
* 1. **Session Clearing**: Calls `setSignedUser(null)` to remove user data from encrypted storage
* 2. **Memory Cleanup**: Clears the local user reference cache for immediate effect
* 3. **Event Broadcasting**: Optionally triggers 'SIGN_OUT' events for application-wide notifications
* 4. **Security Cleanup**: Ensures no sensitive user data remains in browser storage
*
* ### Security Features:
* - **Complete Data Removal**: Eliminates all traces of user session from storage
* - **Memory Safety**: Clears in-memory user references to prevent data leakage
* - **Event Coordination**: Allows other components to perform cleanup operations
* - **Immediate Effect**: Session termination is effective immediately after method completion
*
* ### Application Integration:
* The method integrates seamlessly with the authentication event system, allowing
* other parts of the application to react to sign-out events by clearing user-specific
* data, redirecting to login pages, or performing cleanup operations.
*
* @param triggerEvent - Optional flag controlling whether to broadcast authentication events.
* When `true` (default), triggers a 'SIGN_OUT' event that other parts
* of the application can listen to for cleanup operations, analytics,
* or UI state updates. Set to `false` to perform silent sign-out
* without notifying event listeners (useful for internal operations).
*
* @returns A promise that resolves when the sign-out operation is complete and all
* user session data has been successfully removed from storage. The promise
* resolves to `void` as no return value is needed after successful sign-out.
*
* @example
* ```typescript
* // Standard user sign-out with event broadcasting
* async function handleUserSignOut() {
* try {
* await Auth.signOut();
* console.log('User signed out successfully');
*
* // Redirect to login page
* window.location.href = '/login';
* } catch (error) {
* console.error('Sign-out failed:', error);
* showErrorMessage('Failed to sign out');
* }
* }
* ```
*
* @example
* ```typescript
* // Silent sign-out without triggering events
* async function silentSignOut() {
* await Auth.signOut(false); // No events triggered
* console.log('Silent sign-out completed');
*
* // Manually handle post-signout operations
* clearUserSpecificData();
* redirectToPublicArea();
* }
* ```
*
* @example
* ```typescript
* // Sign-out with comprehensive event handling
* // Set up event listener first
* Auth.events.on('SIGN_OUT', () => {
* console.log('User signed out - cleaning up...');
*
* // Clear user-specific application state
* clearUserPreferences();
* clearUserCache();
* resetApplicationState();
*
* // Update UI
* hideUserMenus();
* showGuestContent();
*
* // Analytics and logging
* trackAnalyticsEvent('user_signout');
* logSecurityEvent('session_terminated');
* });
*
* // Perform sign-out - events will fire automatically
* await Auth.signOut();
* ```
*
* @example
* ```typescript
* // Session timeout handling
* class SessionManager {
* private timeoutId: NodeJS.Timeout | null = null;
*
* startSessionTimer(durationMs: number) {
* this.clearSessionTimer();
*
* this.timeoutId = setTimeout(async () => {
* console.log('Session expired - signing out user');
* await Auth.signOut(); // Will trigger events
*
* showNotification('Session expired. Please sign in again.');
* }, durationMs);
* }
*
* clearSessionTimer() {
* if (this.timeoutId) {
* clearTimeout(this.timeoutId);
* this.timeoutId = null;
* }
* }
* }
* ```
*
* @example
* ```typescript
* // Multi-tab sign-out coordination
* // Listen for storage events to handle sign-out in other tabs
* window.addEventListener('storage', (event) => {
* if (event.key === USER_SESSION_KEY && event.newValue === null) {
* console.log('User signed out in another tab');
*
* // Perform silent sign-out in this tab without triggering events
* Auth.signOut(false);
*
* // Update UI to reflect signed-out state
* updateUIForSignedOutUser();
* }
* });
* ```
*
* @example
* ```typescript
* // Complete authentication flow with error handling
* class AuthenticationService {
* async performSignOut(): Promise<boolean> {
* try {
* // Check if user is actually signed in
* const currentUser = Auth.getSignedUser();
* if (!currentUser) {
* console.log('No user to sign out');
* return true;
* }
*
* // Perform API sign-out call if needed
* await this.notifyServerSignOut(currentUser.token);
*
* // Sign out locally
* await Auth.signOut();
*
* console.log('Complete sign-out successful');
* return true;
* } catch (error) {
* console.error('Sign-out process failed:', error);
*
* // Force local sign-out even if server call failed
* await Auth.signOut(false);
* return false;
* }
* }
*
* private async notifyServerSignOut(token: string): Promise<void> {
* await fetch('/api/auth/logout', {
* method: 'POST',
* headers: {
* 'Authorization': `Bearer ${token}`,
* 'Content-Type': 'application/json'
* }
* });
* }
* }
* ```
*
* @throws {StorageError} May throw if session storage is unavailable during cleanup
* @throws {CryptoError} May throw if there are issues clearing encrypted session data
*
* @see {@link setSignedUser} - Lower-level method used internally for session management
* @see {@link getSignedUser} - Check if a user is currently signed in before sign-out
* @see {@link signIn} - Corresponding method for user authentication
* @see {@link Auth.events} - Event system for handling sign-out notifications
* @see {@link IAuthEvent} - Authentication event types including 'SIGN_OUT'
* @see {@link USER_SESSION_KEY} - Storage key used for session data
*
* @since 1.0.0
* @public
* @async
*
* @remarks
* **Security Considerations:**
* - Always sign out users when suspicious activity is detected
* - Consider notifying the server about client-side sign-outs for security auditing
* - Be aware that local sign-out doesn't invalidate server-side sessions automatically
* - Use HTTPS to prevent session hijacking during the sign-out process
*
* **Best Practices:**
* - Always handle sign-out errors gracefully to avoid leaving users in inconsistent states
* - Use event listeners to coordinate sign-out across multiple application components
* - Consider implementing automatic sign-out for security-sensitive applications
* - Provide clear feedback to users about successful sign-out operations
*
* **Performance Notes:**
* - Sign-out is typically fast as it only involves storage cleanup
* - Event broadcasting may trigger multiple listeners, consider the performance impact
* - Silent sign-out (`triggerEvent: false`) is faster as it skips event processing
* - Consider batching multiple sign-out operations if needed programmatically
*
* **Multi-Tab Considerations:**
* - Sign-out in one tab affects session storage visible to all tabs
* - Other tabs should listen for storage events to stay synchronized
* - Consider implementing cross-tab communication for better user experience
* - Be careful with silent sign-outs in multi-tab scenarios to avoid confusion
*/
static signOut(triggerEvent?: boolean): Promise<IAuthUser | null>;
private static isResourceActionTupleArray;
private static isResourceActionTupleObject;
/**
* Determines whether a user has permission to access a resource or perform an action.
*
* This comprehensive authorization method evaluates various types of permission configurations
* to determine if the specified user (or currently signed-in user) is allowed to perform
* the requested operation. It supports multiple permission formats including boolean flags,
* function-based permissions, resource-action tuples, and complex permission arrays.
*
* The method follows a priority-based evaluation system:
* 1. Boolean permissions are returned directly
* 2. Master admin users are always granted access
* 3. Null/undefined permissions default to `true` (open access)
* 4. Function permissions are evaluated with the user context
* 5. Resource-action permissions are checked against user's role permissions
* 6. Array permissions are evaluated with OR logic (any match grants access)
*
* @template ResourceName - The resource name type, extending IResourceName
*
* @param perm - The permission configuration to evaluate. Can be:
* - `boolean`: Direct permission flag (true = allowed, false = denied)
* - `function`: Custom permission evaluator receiving user context
* - `IResourceActionTupleObject`: Object with resourceName and action properties
* - `IResourceActionTupleArray`: Array tuple [resourceName, action]
* - `Array<IAuthPerm>`: Multiple permission configurations (OR logic)
* - `null|undefined`: Defaults to allowing access
*
* @param user - Optional user object to check permissions against.
* If not provided, uses the currently signed-in user from session.
* The user object should contain permissions and role information.
*
* @returns `true` if the user is authorized to perform the action, `false` otherwise
*
* @example
* ```typescript
* // Boolean permission - direct access control
* const canAccess = Auth.isAllowed(true); // Returns: true
* const cannotAccess = Auth.isAllowed(false); // Returns: false
*
* // Function-based permission - custom logic
* const customPerm = (user: IAuthUser) => user.age >= 18;
* const canAccessAdultContent = Auth.isAllowed(customPerm); // Returns: true if user is 18+
* ```
*
* @example
* ```typescript
* // Resource-action tuple object - structured permissions
* const documentEditPerm = { resourceName: "documents", action: "update" };
* const canEditDocs = Auth.isAllowed(documentEditPerm);
* // Returns: true if user has "update" permission on "documents" resource
*
* // Resource-action tuple array - compact format
* const userDeletePerm: [string, string] = ["users", "delete"];
* const canDeleteUsers = Auth.isAllowed(userDeletePerm);
* // Returns: true if user has "delete" permission on "users" resource
* ```
*
* @example
* ```typescript
* // Array of permissions - OR logic (any match grants access)
* const multiplePerms = [
* { resourceName: "documents", action: "read" },
* { resourceName: "documents", action: "update" },
* ["admin", "all"]
* ];
* const canAccessDocs = Auth.isAllowed(multiplePerms);
* // Returns: true if user has any of the specified permissions
* ```
*
* @example
* ```typescript
* // Checking permissions for a specific user
* const specificUser: IAuthUser = {
* id: "user123",
* perms: { documents: ["read", "update"] },
* roles: [{ name: "editor", perms: { images: ["upload"] } }]
* };
*
* const canEdit = Auth.isAllowed(
* { resourceName: "documents", action: "update" },
* specificUser
* ); // Returns: true
* ```
*
* @example
* ```typescript
* // Master admin bypass - always returns true
* Auth.isMasterAdmin = (user) => user.id === "admin";
* const adminUser = { id: "admin" };
* const canDoAnything = Auth.isAllowed(
* { resourceName: "secret", action: "delete" },
* adminUser
* ); // Returns: true (master admin bypass)
* ```
*
* @see {@link IAuthPerm} - Permission configuration type definitions
* @see {@link IAuthUser} - User object structure with permissions and roles
* @see {@link IResourceName} - Valid resource name types
* @see {@link IResourceActionName} - Valid action name types
* @see {@link checkUserPermission} - Low-level permission checking
* @see {@link isMasterAdmin} - Master admin detection function
*
* @since 1.0.0
* @public
*/
static isAllowed<ResourceName extends IResourceName = IResourceName>(perm: IAuthPerm<ResourceName>, user?: IAuthUser): boolean;
/**
* Validates whether a specific user has permission to perform an action on a resource.
*
* This core authorization method performs comprehensive permission checking by evaluating
* both direct user permissions and role-based permissions. It serves as the foundation
* for access control throughout the application, providing a reliable and secure way to
* determine if a user is authorized to perform specific operations on protected resources.
*
* ### Permission Evaluation Strategy:
* The method implements a hierarchical permission checking system:
* 1. **Input Validation**: Ensures the user object is valid and properly structured
* 2. **Direct Permissions**: Checks permissions directly assigned to the user
* 3. **Role-Based Permissions**: Iterates through user roles to check role-specific permissions
* 4. **First Match Wins**: Returns `true` as soon as any valid permission is found
* 5. **Secure Default**: Returns `false` if no matching permissions are discovered
*
* ### Security Architecture:
* - **Fail-Safe Design**: Defaults to denying access when permissions are unclear
* - **Comprehensive Validation**: Validates user object structure and permission data
* - **Role Inheritance**: Supports complex permission models through role-based access
* - **Performance Optimized**: Uses early return to minimize computation time
*
* ### Permission Hierarchy:
* The method checks permissions in the following order:
* 1. User's direct permissions (`user.perms`)
* 2. Permissions inherited from user roles (`user.roles[].perms`)
*
* @param user - The user object containing permission and role information.
* Must be a valid `IAuthUser` object with properly structured
* permissions and roles. The object should include `perms` for
* direct permissions and optionally `roles` array for role-based permissions.
*
* @param resource - The resource name to check permissions against.
* Should be a valid resource identifier from the `IResourceName` type.
* Examples include "documents", "users", "admin", "reports", etc.
* The resource name is case-sensitive and should match exactly.
*
* @param action - The specific action to check permission for on the given resource.
* Defaults to "read" if not specified. Common actions include:
* "read", "create", "update", "delete", "all", or custom actions
* specific to your application's permission model.
*
* @returns `true` if the user has permission to perform the specified action
* on the resource, either through direct permissions or role inheritance.
* Returns `false` if the user lacks permission, has invalid data,
* or if any validation checks fail.
*
* @example
* ```typescript
* // Basic permission checking - user with direct permissions
* const user: IAuthUser = {
* id: "user123",
* username: "john_doe",
* perms: {
* documents: ["read", "create", "update"],
* reports: ["read"]
* }
* };
*
* const canReadDocs = Auth.checkUserPermission(user, "documents", "read");
* console.log(canReadDocs); // true
*
* const canDeleteDocs = Auth.checkUserPermission(user, "documents", "delete");
* console.log(canDeleteDocs); // false
* ```
*
* @example
* ```typescript
* // Role-based permission checking
* const userWithRoles: IAuthUser = {
* id: "user456",
* username: "jane_smith",
* perms: {
* profile: ["read", "update"]
* },
* roles: [
* {
* name: "editor",
* perms: {
* documents: ["read", "create", "update"],
* images: ["upload", "edit"]
* }
* },
* {
* name: "moderator",
* perms: {
* comments: ["read", "update", "delete"],
* users: ["read", "suspend"]
* }
* }
* ]
* };
*
* // Check direct permission
* const canUpdateProfile = Auth.checkUserPermission(userWithRoles, "profile", "update");
* console.log(canUpdateProfile); // true (from direct perms)
*
* // Check role-inherited permission
* const canEditDocs = Auth.checkUserPermission(userWithRoles, "documents", "update");
* console.log(canEditDocs); // true (from editor role)
*
* // Check another role permission
* const canDeleteComments = Auth.checkUserPermission(userWithRoles, "comments", "delete");
* console.log(canDeleteComments); // true (from moderator role)
* ```
*
* @example
* ```typescript
* // Default action parameter (read)
* const user: IAuthUser = {
* id: "reader",