@startsimpli/auth 0.1.3 → 0.1.4

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.
@@ -130,5 +130,5 @@ function validatePasswordConfirm(password, confirm) {
130
130
  }
131
131
 
132
132
  export { EMAIL_REGEX, decodeToken, deleteCookie, getCookie, getCsrfToken, getTokenExpiresAt, getTokenPayload, isTokenExpired, setCookie, shouldRefreshToken, validateEmail, validatePassword, validatePasswordConfirm };
133
- //# sourceMappingURL=chunk-S6J5FYQY.mjs.map
134
- //# sourceMappingURL=chunk-S6J5FYQY.mjs.map
133
+ //# sourceMappingURL=chunk-AADTGAI2.mjs.map
134
+ //# sourceMappingURL=chunk-AADTGAI2.mjs.map
@@ -1 +1 @@
1
- {"version":3,"sources":["../src/utils/token.ts","../src/utils/cookies.ts","../src/validation/index.ts"],"names":[],"mappings":"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","file":"chunk-S6J5FYQY.mjs","sourcesContent":["/**\n * JWT token utilities\n */\n\nimport type { TokenPayload, DecodedToken } from '../types';\n\n/**\n * Decode JWT token payload (does NOT verify signature)\n */\nexport function decodeToken(token: string): TokenPayload | null {\n try {\n const parts = token.split('.');\n if (parts.length !== 3) {\n return null;\n }\n\n const payload = parts[1];\n const decoded = JSON.parse(atob(payload));\n return decoded as TokenPayload;\n } catch (error) {\n console.error('Failed to decode token:', error);\n return null;\n }\n}\n\n/**\n * Check if token is expired\n */\nexport function isTokenExpired(token: string): boolean {\n const payload = decodeToken(token);\n if (!payload) {\n return true;\n }\n\n const now = Math.floor(Date.now() / 1000);\n return payload.exp <= now;\n}\n\n/**\n * Get token expiration time in milliseconds\n */\nexport function getTokenExpiresAt(token: string): number | null {\n const payload = decodeToken(token);\n if (!payload) {\n return null;\n }\n\n return payload.exp * 1000;\n}\n\n/**\n * Get raw JWT payload as a generic record — framework and backend agnostic.\n * Does NOT verify the signature; use only for reading claims client-side.\n */\nexport function getTokenPayload(token: string): DecodedToken | null {\n try {\n const parts = token.split('.');\n if (parts.length !== 3) {\n return null;\n }\n\n const payload = parts[1];\n const decoded = JSON.parse(atob(payload));\n\n if (typeof decoded !== 'object' || decoded === null) {\n return null;\n }\n\n return decoded as DecodedToken;\n } catch {\n return null;\n }\n}\n\n/**\n * Check if token needs refresh (expires in less than 5 minutes)\n */\nexport function shouldRefreshToken(token: string): boolean {\n const expiresAt = getTokenExpiresAt(token);\n if (!expiresAt) {\n return true;\n }\n\n const now = Date.now();\n const timeUntilExpiry = expiresAt - now;\n const FIVE_MINUTES = 5 * 60 * 1000;\n\n return timeUntilExpiry < FIVE_MINUTES;\n}\n","/**\n * Cookie utilities for client-side access\n */\n\n/**\n * Get cookie value by name\n */\nexport function getCookie(name: string): string | null {\n if (typeof document === 'undefined') {\n return null;\n }\n\n const value = `; ${document.cookie}`;\n const parts = value.split(`; ${name}=`);\n\n if (parts.length === 2) {\n return parts.pop()?.split(';').shift() || null;\n }\n\n return null;\n}\n\n/**\n * Set cookie with options\n */\nexport function setCookie(\n name: string,\n value: string,\n options: {\n maxAge?: number;\n path?: string;\n domain?: string;\n secure?: boolean;\n sameSite?: 'strict' | 'lax' | 'none';\n } = {}\n): void {\n if (typeof document === 'undefined') {\n return;\n }\n\n const {\n maxAge,\n path = '/',\n domain,\n secure = true,\n sameSite = 'lax',\n } = options;\n\n let cookie = `${name}=${value}`;\n\n if (maxAge) {\n cookie += `; Max-Age=${maxAge}`;\n }\n\n cookie += `; Path=${path}`;\n\n if (domain) {\n cookie += `; Domain=${domain}`;\n }\n\n if (secure) {\n cookie += '; Secure';\n }\n\n cookie += `; SameSite=${sameSite}`;\n\n document.cookie = cookie;\n}\n\n/**\n * Get the Django CSRF token from cookies\n */\nexport function getCsrfToken(): string | null {\n return getCookie('csrftoken');\n}\n\n/**\n * Delete cookie by name\n */\nexport function deleteCookie(name: string, path: string = '/'): void {\n if (typeof document === 'undefined') {\n return;\n }\n\n document.cookie = `${name}=; Path=${path}; Expires=Thu, 01 Jan 1970 00:00:00 GMT`;\n}\n","export const EMAIL_REGEX = /^[^\\s@]+@[^\\s@]+\\.[^\\s@]+$/;\n\nexport function validateEmail(email: string): boolean {\n return EMAIL_REGEX.test(email);\n}\n\nexport interface PasswordValidationResult {\n isValid: boolean;\n error?: string;\n}\n\n// Canonical password rules for all StartSimpli apps\nexport function validatePassword(password: string): PasswordValidationResult {\n if (password.length < 8) {\n return { isValid: false, error: 'Password must be at least 8 characters' };\n }\n if (!/[A-Z]/.test(password)) {\n return { isValid: false, error: 'Password must contain at least one uppercase letter' };\n }\n if (!/[a-z]/.test(password)) {\n return { isValid: false, error: 'Password must contain at least one lowercase letter' };\n }\n if (!/[0-9]/.test(password)) {\n return { isValid: false, error: 'Password must contain at least one number' };\n }\n return { isValid: true };\n}\n\nexport function validatePasswordConfirm(password: string, confirm: string): PasswordValidationResult {\n if (password !== confirm) {\n return { isValid: false, error: 'Passwords do not match' };\n }\n return validatePassword(password);\n}\n"]}
1
+ {"version":3,"sources":["../src/utils/token.ts","../src/utils/cookies.ts","../src/validation/index.ts"],"names":[],"mappings":"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","file":"chunk-AADTGAI2.mjs","sourcesContent":["/**\n * JWT token utilities\n */\n\nimport type { TokenPayload, DecodedToken } from '../types';\n\n/**\n * Decode JWT token payload (does NOT verify signature)\n */\nexport function decodeToken(token: string): TokenPayload | null {\n try {\n const parts = token.split('.');\n if (parts.length !== 3) {\n return null;\n }\n\n const payload = parts[1];\n const decoded = JSON.parse(atob(payload));\n return decoded as TokenPayload;\n } catch (error) {\n console.error('Failed to decode token:', error);\n return null;\n }\n}\n\n/**\n * Check if token is expired\n */\nexport function isTokenExpired(token: string): boolean {\n const payload = decodeToken(token);\n if (!payload) {\n return true;\n }\n\n const now = Math.floor(Date.now() / 1000);\n return payload.exp <= now;\n}\n\n/**\n * Get token expiration time in milliseconds\n */\nexport function getTokenExpiresAt(token: string): number | null {\n const payload = decodeToken(token);\n if (!payload) {\n return null;\n }\n\n return payload.exp * 1000;\n}\n\n/**\n * Get raw JWT payload as a generic record — framework and backend agnostic.\n * Does NOT verify the signature; use only for reading claims client-side.\n */\nexport function getTokenPayload(token: string): DecodedToken | null {\n try {\n const parts = token.split('.');\n if (parts.length !== 3) {\n return null;\n }\n\n const payload = parts[1];\n const decoded = JSON.parse(atob(payload));\n\n if (typeof decoded !== 'object' || decoded === null) {\n return null;\n }\n\n return decoded as DecodedToken;\n } catch {\n return null;\n }\n}\n\n/**\n * Check if token needs refresh (expires in less than 5 minutes)\n */\nexport function shouldRefreshToken(token: string): boolean {\n const expiresAt = getTokenExpiresAt(token);\n if (!expiresAt) {\n return true;\n }\n\n const now = Date.now();\n const timeUntilExpiry = expiresAt - now;\n const FIVE_MINUTES = 5 * 60 * 1000;\n\n return timeUntilExpiry < FIVE_MINUTES;\n}\n","/**\n * Cookie utilities for client-side access\n */\n\n/**\n * Get cookie value by name\n */\nexport function getCookie(name: string): string | null {\n if (typeof document === 'undefined') {\n return null;\n }\n\n const value = `; ${document.cookie}`;\n const parts = value.split(`; ${name}=`);\n\n if (parts.length === 2) {\n return parts.pop()?.split(';').shift() || null;\n }\n\n return null;\n}\n\n/**\n * Set cookie with options\n */\nexport function setCookie(\n name: string,\n value: string,\n options: {\n maxAge?: number;\n path?: string;\n domain?: string;\n secure?: boolean;\n sameSite?: 'strict' | 'lax' | 'none';\n } = {}\n): void {\n if (typeof document === 'undefined') {\n return;\n }\n\n const {\n maxAge,\n path = '/',\n domain,\n secure = true,\n sameSite = 'lax',\n } = options;\n\n let cookie = `${name}=${value}`;\n\n if (maxAge) {\n cookie += `; Max-Age=${maxAge}`;\n }\n\n cookie += `; Path=${path}`;\n\n if (domain) {\n cookie += `; Domain=${domain}`;\n }\n\n if (secure) {\n cookie += '; Secure';\n }\n\n cookie += `; SameSite=${sameSite}`;\n\n document.cookie = cookie;\n}\n\n/**\n * Get the Django CSRF token from cookies\n */\nexport function getCsrfToken(): string | null {\n return getCookie('csrftoken');\n}\n\n/**\n * Delete cookie by name\n */\nexport function deleteCookie(name: string, path: string = '/'): void {\n if (typeof document === 'undefined') {\n return;\n }\n\n document.cookie = `${name}=; Path=${path}; Expires=Thu, 01 Jan 1970 00:00:00 GMT`;\n}\n","export const EMAIL_REGEX = /^[^\\s@]+@[^\\s@]+\\.[^\\s@]+$/;\n\nexport function validateEmail(email: string): boolean {\n return EMAIL_REGEX.test(email);\n}\n\nexport interface PasswordValidationResult {\n isValid: boolean;\n error?: string;\n}\n\n// Canonical password rules for all StartSimpli apps\nexport function validatePassword(password: string): PasswordValidationResult {\n if (password.length < 8) {\n return { isValid: false, error: 'Password must be at least 8 characters' };\n }\n if (!/[A-Z]/.test(password)) {\n return { isValid: false, error: 'Password must contain at least one uppercase letter' };\n }\n if (!/[a-z]/.test(password)) {\n return { isValid: false, error: 'Password must contain at least one lowercase letter' };\n }\n if (!/[0-9]/.test(password)) {\n return { isValid: false, error: 'Password must contain at least one number' };\n }\n return { isValid: true };\n}\n\nexport function validatePasswordConfirm(password: string, confirm: string): PasswordValidationResult {\n if (password !== confirm) {\n return { isValid: false, error: 'Passwords do not match' };\n }\n return validatePassword(password);\n}\n"]}
@@ -33,5 +33,5 @@ var ValidationErrorCode = /* @__PURE__ */ ((ValidationErrorCode2) => {
33
33
  })(ValidationErrorCode || {});
34
34
 
35
35
  export { EmailErrorCode, PasswordErrorCode, ROLE_HIERARCHY, ValidationErrorCode, hasRolePermission };
36
- //# sourceMappingURL=chunk-TA46ASDJ.mjs.map
37
- //# sourceMappingURL=chunk-TA46ASDJ.mjs.map
36
+ //# sourceMappingURL=chunk-QAXZGJNQ.mjs.map
37
+ //# sourceMappingURL=chunk-QAXZGJNQ.mjs.map
@@ -1 +1 @@
1
- {"version":3,"sources":["../src/types/index.ts"],"names":["PasswordErrorCode","EmailErrorCode","ValidationErrorCode"],"mappings":";AA8HO,IAAM,cAAA,GAA8C;AAAA,EACzD,KAAA,EAAO,CAAA;AAAA,EACP,KAAA,EAAO,CAAA;AAAA,EACP,MAAA,EAAQ,CAAA;AAAA,EACR,MAAA,EAAQ;AACV;AAKO,SAAS,iBAAA,CACd,UACA,YAAA,EACS;AACT,EAAA,OAAO,cAAA,CAAe,QAAQ,CAAA,IAAK,cAAA,CAAe,YAAY,CAAA;AAChE;AAyEO,IAAK,iBAAA,qBAAAA,kBAAAA,KAAL;AACL,EAAAA,mBAAA,WAAA,CAAA,GAAY,oBAAA;AACZ,EAAAA,mBAAA,YAAA,CAAA,GAAa,qBAAA;AACb,EAAAA,mBAAA,kBAAA,CAAA,GAAmB,2BAAA;AACnB,EAAAA,mBAAA,aAAA,CAAA,GAAc,sBAAA;AACd,EAAAA,mBAAA,UAAA,CAAA,GAAW,mBAAA;AACX,EAAAA,mBAAA,UAAA,CAAA,GAAW,mBAAA;AAND,EAAA,OAAAA,kBAAAA;AAAA,CAAA,EAAA,iBAAA,IAAA,EAAA;AAYL,IAAK,cAAA,qBAAAC,eAAAA,KAAL;AACL,EAAAA,gBAAA,gBAAA,CAAA,GAAiB,sBAAA;AACjB,EAAAA,gBAAA,UAAA,CAAA,GAAW,gBAAA;AACX,EAAAA,gBAAA,WAAA,CAAA,GAAY,iBAAA;AACZ,EAAAA,gBAAA,gBAAA,CAAA,GAAiB,sBAAA;AAJP,EAAA,OAAAA,eAAAA;AAAA,CAAA,EAAA,cAAA,IAAA,EAAA;AAUL,IAAK,mBAAA,qBAAAC,oBAAAA,KAAL;AACL,EAAAA,qBAAA,UAAA,CAAA,GAAW,UAAA;AACX,EAAAA,qBAAA,SAAA,CAAA,GAAU,SAAA;AACV,EAAAA,qBAAA,WAAA,CAAA,GAAY,WAAA;AACZ,EAAAA,qBAAA,UAAA,CAAA,GAAW,UAAA;AAJD,EAAA,OAAAA,oBAAAA;AAAA,CAAA,EAAA,mBAAA,IAAA,EAAA","file":"chunk-TA46ASDJ.mjs","sourcesContent":["/**\n * Authentication types for StartSimpli apps\n */\n\n/**\n * Generic token pair (access + optional refresh)\n */\nexport interface TokenPair {\n access: string;\n refresh?: string;\n}\n\n/**\n * Generic decoded JWT payload — framework and backend agnostic\n */\nexport interface DecodedToken {\n sub?: string;\n email?: string;\n exp?: number;\n iat?: number;\n [key: string]: unknown;\n}\n\n/**\n * Generic auth session — framework agnostic\n */\nexport interface AuthSession {\n user: {\n id: string;\n email: string;\n [key: string]: unknown;\n };\n accessToken: string;\n refreshToken?: string;\n}\n\n/**\n * User profile from Django backend\n */\nexport interface AuthUser {\n id: string;\n email: string;\n firstName: string;\n lastName: string;\n isEmailVerified: boolean;\n createdAt: string;\n updatedAt: string;\n // Company/team context (if applicable)\n companies?: Array<{\n id: string;\n name: string;\n role: 'owner' | 'admin' | 'member' | 'viewer';\n }>;\n currentCompanyId?: string;\n}\n\n/**\n * JWT token payload structure\n */\nexport interface TokenPayload {\n token_type: 'access';\n exp: number;\n iat: number;\n jti: string;\n user_id: string;\n}\n\n/**\n * Session data stored in client\n */\nexport interface Session {\n user: AuthUser;\n accessToken: string;\n expiresAt: number;\n}\n\n/**\n * Login response from Django backend\n */\nexport interface LoginResponse {\n access: string;\n user: AuthUser;\n}\n\n/**\n * Token refresh response\n */\nexport interface RefreshResponse {\n access: string;\n}\n\n/**\n * Permission check result\n */\nexport interface PermissionCheck {\n hasPermission: boolean;\n reason?: string;\n}\n\n/**\n * Auth configuration options\n */\nexport interface AuthConfig {\n apiBaseUrl: string;\n tokenRefreshInterval?: number; // milliseconds, default 4 minutes\n onSessionExpired?: () => void;\n onUnauthorized?: () => void;\n}\n\n/**\n * Auth state for React context\n */\nexport interface AuthState {\n session: Session | null;\n isLoading: boolean;\n isAuthenticated: boolean;\n}\n\n/**\n * Company role hierarchy\n */\nexport type CompanyRole = 'owner' | 'admin' | 'member' | 'viewer';\n\n/**\n * Role hierarchy map (higher number = more permissions)\n */\nexport const ROLE_HIERARCHY: Record<CompanyRole, number> = {\n owner: 4,\n admin: 3,\n member: 2,\n viewer: 1,\n};\n\n/**\n * Check if role has sufficient permissions\n */\nexport function hasRolePermission(\n userRole: CompanyRole,\n requiredRole: CompanyRole\n): boolean {\n return ROLE_HIERARCHY[userRole] >= ROLE_HIERARCHY[requiredRole];\n}\n\n/**\n * Password reset request payload\n * Initiates password reset flow by sending reset email\n */\nexport interface PasswordResetRequest {\n email: string;\n clientMetadata?: Record<string, any>;\n}\n\n/**\n * Password reset confirmation payload\n * Completes password reset with token and new password\n */\nexport interface PasswordResetConfirm {\n token: string;\n password: string;\n passwordConfirm: string;\n}\n\n/**\n * Email verification request payload\n * Verifies user email with token from verification email\n */\nexport interface EmailVerificationRequest {\n token: string;\n}\n\n/**\n * Email verification response\n * Returns updated user data after successful verification\n */\nexport interface EmailVerificationResponse {\n detail: string;\n user: {\n id: string;\n email: string;\n isEmailVerified: boolean;\n };\n}\n\n/**\n * API error response from Django backend\n * Standard error format for all API errors\n */\nexport interface ApiErrorResponse {\n detail?: string;\n message?: string;\n errors?: Record<string, string[]>;\n code?: string;\n status?: number;\n}\n\n/**\n * Validation error detail\n * Individual field validation error\n */\nexport interface ValidationError {\n field: string;\n message: string;\n code?: string;\n}\n\n/**\n * Validation errors map\n * Maps field names to error messages\n */\nexport type ValidationErrorsMap = Record<string, string[]>;\n\n/**\n * Password validation error codes\n */\nexport enum PasswordErrorCode {\n TOO_SHORT = 'password_too_short',\n TOO_COMMON = 'password_too_common',\n ENTIRELY_NUMERIC = 'password_entirely_numeric',\n TOO_SIMILAR = 'password_too_similar',\n MISMATCH = 'password_mismatch',\n REQUIRED = 'password_required',\n}\n\n/**\n * Email validation error codes\n */\nexport enum EmailErrorCode {\n INVALID_FORMAT = 'email_invalid_format',\n REQUIRED = 'email_required',\n NOT_FOUND = 'email_not_found',\n ALREADY_EXISTS = 'email_already_exists',\n}\n\n/**\n * General validation error codes\n */\nexport enum ValidationErrorCode {\n REQUIRED = 'required',\n INVALID = 'invalid',\n TOO_SHORT = 'too_short',\n TOO_LONG = 'too_long',\n}\n"]}
1
+ {"version":3,"sources":["../src/types/index.ts"],"names":["PasswordErrorCode","EmailErrorCode","ValidationErrorCode"],"mappings":";AA8HO,IAAM,cAAA,GAA8C;AAAA,EACzD,KAAA,EAAO,CAAA;AAAA,EACP,KAAA,EAAO,CAAA;AAAA,EACP,MAAA,EAAQ,CAAA;AAAA,EACR,MAAA,EAAQ;AACV;AAKO,SAAS,iBAAA,CACd,UACA,YAAA,EACS;AACT,EAAA,OAAO,cAAA,CAAe,QAAQ,CAAA,IAAK,cAAA,CAAe,YAAY,CAAA;AAChE;AAyEO,IAAK,iBAAA,qBAAAA,kBAAAA,KAAL;AACL,EAAAA,mBAAA,WAAA,CAAA,GAAY,oBAAA;AACZ,EAAAA,mBAAA,YAAA,CAAA,GAAa,qBAAA;AACb,EAAAA,mBAAA,kBAAA,CAAA,GAAmB,2BAAA;AACnB,EAAAA,mBAAA,aAAA,CAAA,GAAc,sBAAA;AACd,EAAAA,mBAAA,UAAA,CAAA,GAAW,mBAAA;AACX,EAAAA,mBAAA,UAAA,CAAA,GAAW,mBAAA;AAND,EAAA,OAAAA,kBAAAA;AAAA,CAAA,EAAA,iBAAA,IAAA,EAAA;AAYL,IAAK,cAAA,qBAAAC,eAAAA,KAAL;AACL,EAAAA,gBAAA,gBAAA,CAAA,GAAiB,sBAAA;AACjB,EAAAA,gBAAA,UAAA,CAAA,GAAW,gBAAA;AACX,EAAAA,gBAAA,WAAA,CAAA,GAAY,iBAAA;AACZ,EAAAA,gBAAA,gBAAA,CAAA,GAAiB,sBAAA;AAJP,EAAA,OAAAA,eAAAA;AAAA,CAAA,EAAA,cAAA,IAAA,EAAA;AAUL,IAAK,mBAAA,qBAAAC,oBAAAA,KAAL;AACL,EAAAA,qBAAA,UAAA,CAAA,GAAW,UAAA;AACX,EAAAA,qBAAA,SAAA,CAAA,GAAU,SAAA;AACV,EAAAA,qBAAA,WAAA,CAAA,GAAY,WAAA;AACZ,EAAAA,qBAAA,UAAA,CAAA,GAAW,UAAA;AAJD,EAAA,OAAAA,oBAAAA;AAAA,CAAA,EAAA,mBAAA,IAAA,EAAA","file":"chunk-QAXZGJNQ.mjs","sourcesContent":["/**\n * Authentication types for StartSimpli apps\n */\n\n/**\n * Generic token pair (access + optional refresh)\n */\nexport interface TokenPair {\n access: string;\n refresh?: string;\n}\n\n/**\n * Generic decoded JWT payload — framework and backend agnostic\n */\nexport interface DecodedToken {\n sub?: string;\n email?: string;\n exp?: number;\n iat?: number;\n [key: string]: unknown;\n}\n\n/**\n * Generic auth session — framework agnostic\n */\nexport interface AuthSession {\n user: {\n id: string;\n email: string;\n [key: string]: unknown;\n };\n accessToken: string;\n refreshToken?: string;\n}\n\n/**\n * User profile from Django backend\n */\nexport interface AuthUser {\n id: string;\n email: string;\n firstName: string;\n lastName: string;\n isEmailVerified: boolean;\n createdAt: string;\n updatedAt: string;\n // Company/team context (if applicable)\n companies?: Array<{\n id: string;\n name: string;\n role: 'owner' | 'admin' | 'member' | 'viewer';\n }>;\n currentCompanyId?: string;\n}\n\n/**\n * JWT token payload structure\n */\nexport interface TokenPayload {\n token_type: 'access';\n exp: number;\n iat: number;\n jti: string;\n user_id: string;\n}\n\n/**\n * Session data stored in client\n */\nexport interface Session {\n user: AuthUser;\n accessToken: string;\n expiresAt: number;\n}\n\n/**\n * Login response from Django backend\n */\nexport interface LoginResponse {\n access: string;\n user: AuthUser;\n}\n\n/**\n * Token refresh response\n */\nexport interface RefreshResponse {\n access: string;\n}\n\n/**\n * Permission check result\n */\nexport interface PermissionCheck {\n hasPermission: boolean;\n reason?: string;\n}\n\n/**\n * Auth configuration options\n */\nexport interface AuthConfig {\n apiBaseUrl: string;\n tokenRefreshInterval?: number; // milliseconds, default 4 minutes\n onSessionExpired?: () => void;\n onUnauthorized?: () => void;\n}\n\n/**\n * Auth state for React context\n */\nexport interface AuthState {\n session: Session | null;\n isLoading: boolean;\n isAuthenticated: boolean;\n}\n\n/**\n * Company role hierarchy\n */\nexport type CompanyRole = 'owner' | 'admin' | 'member' | 'viewer';\n\n/**\n * Role hierarchy map (higher number = more permissions)\n */\nexport const ROLE_HIERARCHY: Record<CompanyRole, number> = {\n owner: 4,\n admin: 3,\n member: 2,\n viewer: 1,\n};\n\n/**\n * Check if role has sufficient permissions\n */\nexport function hasRolePermission(\n userRole: CompanyRole,\n requiredRole: CompanyRole\n): boolean {\n return ROLE_HIERARCHY[userRole] >= ROLE_HIERARCHY[requiredRole];\n}\n\n/**\n * Password reset request payload\n * Initiates password reset flow by sending reset email\n */\nexport interface PasswordResetRequest {\n email: string;\n clientMetadata?: Record<string, any>;\n}\n\n/**\n * Password reset confirmation payload\n * Completes password reset with token and new password\n */\nexport interface PasswordResetConfirm {\n token: string;\n password: string;\n passwordConfirm: string;\n}\n\n/**\n * Email verification request payload\n * Verifies user email with token from verification email\n */\nexport interface EmailVerificationRequest {\n token: string;\n}\n\n/**\n * Email verification response\n * Returns updated user data after successful verification\n */\nexport interface EmailVerificationResponse {\n detail: string;\n user: {\n id: string;\n email: string;\n isEmailVerified: boolean;\n };\n}\n\n/**\n * API error response from Django backend\n * Standard error format for all API errors\n */\nexport interface ApiErrorResponse {\n detail?: string;\n message?: string;\n errors?: Record<string, string[]>;\n code?: string;\n status?: number;\n}\n\n/**\n * Validation error detail\n * Individual field validation error\n */\nexport interface ValidationError {\n field: string;\n message: string;\n code?: string;\n}\n\n/**\n * Validation errors map\n * Maps field names to error messages\n */\nexport type ValidationErrorsMap = Record<string, string[]>;\n\n/**\n * Password validation error codes\n */\nexport enum PasswordErrorCode {\n TOO_SHORT = 'password_too_short',\n TOO_COMMON = 'password_too_common',\n ENTIRELY_NUMERIC = 'password_entirely_numeric',\n TOO_SIMILAR = 'password_too_similar',\n MISMATCH = 'password_mismatch',\n REQUIRED = 'password_required',\n}\n\n/**\n * Email validation error codes\n */\nexport enum EmailErrorCode {\n INVALID_FORMAT = 'email_invalid_format',\n REQUIRED = 'email_required',\n NOT_FOUND = 'email_not_found',\n ALREADY_EXISTS = 'email_already_exists',\n}\n\n/**\n * General validation error codes\n */\nexport enum ValidationErrorCode {\n REQUIRED = 'required',\n INVALID = 'invalid',\n TOO_SHORT = 'too_short',\n TOO_LONG = 'too_long',\n}\n"]}
@@ -1,5 +1,5 @@
1
- import { getTokenExpiresAt, isTokenExpired, shouldRefreshToken, getCsrfToken } from './chunk-S6J5FYQY.mjs';
2
- import { hasRolePermission } from './chunk-TA46ASDJ.mjs';
1
+ import { getTokenExpiresAt, isTokenExpired, shouldRefreshToken, getCsrfToken } from './chunk-AADTGAI2.mjs';
2
+ import { hasRolePermission } from './chunk-QAXZGJNQ.mjs';
3
3
  import { createContext, useState, useEffect, useCallback, useContext, useMemo } from 'react';
4
4
  import { jsx } from 'react/jsx-runtime';
5
5
 
@@ -763,5 +763,5 @@ function hasGroup(user, group) {
763
763
  }
764
764
 
765
765
  export { AuthClient, AuthProvider, authFetch, completeGoogleOAuth, getAccessToken, getMe, hasGroup, hasPermission, initiateGoogleOAuth, refreshAccessToken, registerAccount, requestPasswordReset, resendVerification, resetPassword, resolveAuthUrl, setAccessToken, signInWithCredentials, signOut, useAuth, useAuthContext, usePermissions, verifyEmail };
766
- //# sourceMappingURL=chunk-CDNZRZ7Q.mjs.map
767
- //# sourceMappingURL=chunk-CDNZRZ7Q.mjs.map
766
+ //# sourceMappingURL=chunk-VIG3K6ZR.mjs.map
767
+ //# sourceMappingURL=chunk-VIG3K6ZR.mjs.map
@@ -1 +1 @@
1
- {"version":3,"sources":["../src/client/auth-client.ts","../src/client/auth-context.tsx","../src/client/use-auth.ts","../src/client/use-permissions.ts","../src/client/functions.ts"],"names":["getAccessToken"],"mappings":";;;;;;AAcO,IAAM,aAAN,MAAiB;AAAA,EAOtB,YAAY,MAAA,EAAoB;AALhC,IAAA,IAAA,CAAQ,OAAA,GAA0B,IAAA;AAClC,IAAA,IAAA,CAAQ,YAAA,GAAsC,IAAA;AAC9C,IAAA,IAAA,CAAQ,YAAA,GAAe,KAAA;AACvB,IAAA,IAAA,CAAQ,cAAA,GAAyC,IAAA;AAG/C,IAAA,IAAA,CAAK,MAAA,GAAS;AAAA,MACZ,oBAAA,EAAsB,IAAI,EAAA,GAAK,GAAA;AAAA;AAAA,MAC/B,kBAAkB,MAAM;AAAA,MAAC,CAAA;AAAA,MACzB,gBAAgB,MAAM;AAAA,MAAC,CAAA;AAAA,MACvB,GAAG;AAAA,KACL;AAAA,EACF;AAAA;AAAA;AAAA;AAAA,EAKA,MAAM,KAAA,CAAM,KAAA,EAAe,QAAA,EAAoC;AAC7D,IAAA,MAAM,WAAW,MAAM,KAAA,CAAM,GAAG,IAAA,CAAK,MAAA,CAAO,UAAU,CAAA,mBAAA,CAAA,EAAuB;AAAA,MAC3E,MAAA,EAAQ,MAAA;AAAA,MACR,OAAA,EAAS,EAAE,cAAA,EAAgB,kBAAA,EAAmB;AAAA,MAC9C,WAAA,EAAa,SAAA;AAAA;AAAA,MACb,MAAM,IAAA,CAAK,SAAA,CAAU,EAAE,KAAA,EAAO,UAAU;AAAA,KACzC,CAAA;AAED,IAAA,IAAI,CAAC,SAAS,EAAA,EAAI;AAChB,MAAA,MAAM,KAAA,GAAQ,MAAM,QAAA,CAAS,IAAA,EAAK,CAAE,MAAM,OAAO,EAAE,MAAA,EAAQ,cAAA,EAAe,CAAE,CAAA;AAC5E,MAAA,MAAM,IAAI,KAAA,CAAM,KAAA,CAAM,MAAA,IAAU,cAAc,CAAA;AAAA,IAChD;AAEA,IAAA,MAAM,IAAA,GAAY,MAAM,QAAA,CAAS,IAAA,EAAK;AACtC,IAAA,MAAM,SAAA,GAAY,iBAAA,CAAkB,IAAA,CAAK,MAAM,CAAA;AAE/C,IAAA,IAAI,CAAC,SAAA,EAAW;AACd,MAAA,MAAM,IAAI,MAAM,wBAAwB,CAAA;AAAA,IAC1C;AAGA,IAAA,MAAM,WAAA,GAAc;AAAA,MAClB,MAAM,IAAA,CAAK,IAAA,IAAQ,EAAE,EAAA,EAAI,IAAI,KAAA,EAAO,EAAA,EAAI,SAAA,EAAW,EAAA,EAAI,UAAU,EAAA,EAAI,eAAA,EAAiB,OAAO,SAAA,EAAW,EAAA,EAAI,WAAW,EAAA,EAAG;AAAA,MAC1H,aAAa,IAAA,CAAK,MAAA;AAAA,MAClB;AAAA,KACF;AAEA,IAAA,IAAA,CAAK,OAAA,GAAU,WAAA;AAGf,IAAA,IAAI,CAAC,KAAK,IAAA,EAAM;AACd,MAAA,IAAI;AACF,QAAA,MAAM,IAAA,GAAO,MAAM,IAAA,CAAK,cAAA,EAAe;AACvC,QAAA,IAAA,CAAK,QAAQ,IAAA,GAAO,IAAA;AAAA,MACtB,SAAS,KAAA,EAAO;AACd,QAAA,OAAA,CAAQ,KAAA,CAAM,0CAA0C,KAAK,CAAA;AAAA,MAE/D;AAAA,IACF;AAEA,IAAA,IAAA,CAAK,iBAAA,EAAkB;AACvB,IAAA,OAAO,IAAA,CAAK,OAAA;AAAA,EACd;AAAA;AAAA;AAAA;AAAA,EAKA,MAAM,MAAA,GAAwB;AAC5B,IAAA,IAAI;AACF,MAAA,MAAM,KAAA,CAAM,CAAA,EAAG,IAAA,CAAK,MAAA,CAAO,UAAU,CAAA,oBAAA,CAAA,EAAwB;AAAA,QAC3D,MAAA,EAAQ,MAAA;AAAA,QACR,OAAA,EAAS,KAAK,cAAA,EAAe;AAAA,QAC7B,WAAA,EAAa;AAAA,OACd,CAAA;AAAA,IACH,SAAS,KAAA,EAAO;AACd,MAAA,OAAA,CAAQ,KAAA,CAAM,iBAAiB,KAAK,CAAA;AAAA,IACtC,CAAA,SAAE;AACA,MAAA,IAAA,CAAK,YAAA,EAAa;AAAA,IACpB;AAAA,EACF;AAAA;AAAA;AAAA;AAAA,EAKA,MAAM,YAAA,GAAgC;AAEpC,IAAA,IAAI,IAAA,CAAK,YAAA,IAAgB,IAAA,CAAK,cAAA,EAAgB;AAC5C,MAAA,OAAO,IAAA,CAAK,cAAA;AAAA,IACd;AAEA,IAAA,IAAA,CAAK,YAAA,GAAe,IAAA;AACpB,IAAA,IAAA,CAAK,cAAA,GAAiB,KAAK,mBAAA,EAAoB;AAE/C,IAAA,IAAI;AACF,MAAA,MAAM,QAAA,GAAW,MAAM,IAAA,CAAK,cAAA;AAC5B,MAAA,OAAO,QAAA;AAAA,IACT,CAAA,SAAE;AACA,MAAA,IAAA,CAAK,YAAA,GAAe,KAAA;AACpB,MAAA,IAAA,CAAK,cAAA,GAAiB,IAAA;AAAA,IACxB;AAAA,EACF;AAAA,EAEA,MAAc,mBAAA,GAAuC;AACnD,IAAA,MAAM,WAAW,MAAM,KAAA,CAAM,GAAG,IAAA,CAAK,MAAA,CAAO,UAAU,CAAA,2BAAA,CAAA,EAA+B;AAAA,MACnF,MAAA,EAAQ,MAAA;AAAA,MACR,OAAA,EAAS,EAAE,cAAA,EAAgB,kBAAA,EAAmB;AAAA,MAC9C,WAAA,EAAa;AAAA;AAAA,KACd,CAAA;AAED,IAAA,IAAI,CAAC,SAAS,EAAA,EAAI;AAChB,MAAA,IAAA,CAAK,YAAA,EAAa;AAClB,MAAA,IAAA,CAAK,OAAO,gBAAA,EAAiB;AAC7B,MAAA,MAAM,IAAI,MAAM,sBAAsB,CAAA;AAAA,IACxC;AAEA,IAAA,MAAM,IAAA,GAAwB,MAAM,QAAA,CAAS,IAAA,EAAK;AAClD,IAAA,MAAM,SAAA,GAAY,iBAAA,CAAkB,IAAA,CAAK,MAAM,CAAA;AAE/C,IAAA,IAAI,CAAC,SAAA,EAAW;AACd,MAAA,MAAM,IAAI,MAAM,wBAAwB,CAAA;AAAA,IAC1C;AAEA,IAAA,IAAI,KAAK,OAAA,EAAS;AAChB,MAAA,IAAA,CAAK,OAAA,CAAQ,cAAc,IAAA,CAAK,MAAA;AAChC,MAAA,IAAA,CAAK,QAAQ,SAAA,GAAY,SAAA;AAAA,IAC3B;AAEA,IAAA,IAAA,CAAK,iBAAA,EAAkB;AACvB,IAAA,OAAO,IAAA,CAAK,MAAA;AAAA,EACd;AAAA;AAAA;AAAA;AAAA,EAKA,MAAM,cAAA,GAAoC;AACxC,IAAA,MAAM,WAAW,MAAM,KAAA,CAAM,GAAG,IAAA,CAAK,MAAA,CAAO,UAAU,CAAA,gBAAA,CAAA,EAAoB;AAAA,MACxE,OAAA,EAAS,KAAK,cAAA,EAAe;AAAA,MAC7B,WAAA,EAAa;AAAA,KACd,CAAA;AAED,IAAA,IAAI,CAAC,SAAS,EAAA,EAAI;AAChB,MAAA,IAAI,QAAA,CAAS,WAAW,GAAA,EAAK;AAC3B,QAAA,IAAA,CAAK,OAAO,cAAA,EAAe;AAAA,MAC7B;AACA,MAAA,MAAM,IAAI,MAAM,2BAA2B,CAAA;AAAA,IAC7C;AAEA,IAAA,MAAM,IAAA,GAAO,MAAM,QAAA,CAAS,IAAA,EAAK;AACjC,IAAA,MAAM,GAAA,GAAM,KAAK,IAAA,IAAQ,IAAA;AACzB,IAAA,MAAM,IAAA,GAAiB;AAAA,MACrB,IAAI,GAAA,CAAI,EAAA;AAAA,MACR,OAAO,GAAA,CAAI,KAAA;AAAA,MACX,SAAA,EAAW,GAAA,CAAI,UAAA,IAAc,GAAA,CAAI,SAAA,IAAa,EAAA;AAAA,MAC9C,QAAA,EAAU,GAAA,CAAI,SAAA,IAAa,GAAA,CAAI,QAAA,IAAY,EAAA;AAAA,MAC3C,eAAA,EAAiB,GAAA,CAAI,iBAAA,IAAqB,GAAA,CAAI,eAAA,IAAmB,KAAA;AAAA,MACjE,SAAA,EAAW,GAAA,CAAI,UAAA,IAAc,GAAA,CAAI,SAAA,IAAa,EAAA;AAAA,MAC9C,SAAA,EAAW,GAAA,CAAI,UAAA,IAAc,GAAA,CAAI,SAAA,IAAa;AAAA,KAChD;AAEA,IAAA,IAAI,KAAK,OAAA,EAAS;AAChB,MAAA,IAAA,CAAK,QAAQ,IAAA,GAAO,IAAA;AAAA,IACtB;AAEA,IAAA,OAAO,IAAA;AAAA,EACT;AAAA;AAAA;AAAA;AAAA,EAKA,UAAA,GAA6B;AAC3B,IAAA,IAAI,CAAC,KAAK,OAAA,EAAS;AACjB,MAAA,OAAO,IAAA;AAAA,IACT;AAEA,IAAA,IAAI,cAAA,CAAe,IAAA,CAAK,OAAA,CAAQ,WAAW,CAAA,EAAG;AAC5C,MAAA,IAAA,CAAK,YAAA,EAAa;AAClB,MAAA,IAAA,CAAK,OAAO,gBAAA,EAAiB;AAC7B,MAAA,OAAO,IAAA;AAAA,IACT;AAEA,IAAA,OAAO,IAAA,CAAK,OAAA;AAAA,EACd;AAAA;AAAA;AAAA;AAAA,EAKA,WAAW,OAAA,EAAwB;AACjC,IAAA,IAAA,CAAK,OAAA,GAAU,OAAA;AACf,IAAA,IAAA,CAAK,iBAAA,EAAkB;AAAA,EACzB;AAAA;AAAA;AAAA;AAAA,EAKA,cAAA,GAAyC;AACvC,IAAA,MAAM,OAAA,GAAU,KAAK,UAAA,EAAW;AAChC,IAAA,IAAI,CAAC,OAAA,EAAS;AACZ,MAAA,OAAO,EAAC;AAAA,IACV;AAEA,IAAA,OAAO;AAAA,MACL,aAAA,EAAe,CAAA,OAAA,EAAU,OAAA,CAAQ,WAAW,CAAA;AAAA,KAC9C;AAAA,EACF;AAAA;AAAA;AAAA;AAAA,EAKA,MAAM,cAAA,GAAyC;AAC7C,IAAA,MAAM,OAAA,GAAU,KAAK,UAAA,EAAW;AAChC,IAAA,IAAI,CAAC,OAAA,EAAS;AACZ,MAAA,OAAO,IAAA;AAAA,IACT;AAEA,IAAA,IAAI,kBAAA,CAAmB,OAAA,CAAQ,WAAW,CAAA,EAAG;AAC3C,MAAA,IAAI;AACF,QAAA,OAAO,MAAM,KAAK,YAAA,EAAa;AAAA,MACjC,SAAS,KAAA,EAAO;AACd,QAAA,OAAA,CAAQ,KAAA,CAAM,yBAAyB,KAAK,CAAA;AAC5C,QAAA,OAAO,IAAA;AAAA,MACT;AAAA,IACF;AAEA,IAAA,OAAO,OAAA,CAAQ,WAAA;AAAA,EACjB;AAAA;AAAA;AAAA;AAAA,EAKQ,iBAAA,GAA0B;AAChC,IAAA,IAAI,KAAK,YAAA,EAAc;AACrB,MAAA,aAAA,CAAc,KAAK,YAAY,CAAA;AAAA,IACjC;AAEA,IAAA,IAAA,CAAK,YAAA,GAAe,YAAY,MAAM;AACpC,MAAA,MAAM,OAAA,GAAU,KAAK,UAAA,EAAW;AAChC,MAAA,IAAI,OAAA,IAAW,kBAAA,CAAmB,OAAA,CAAQ,WAAW,CAAA,EAAG;AACtD,QAAA,IAAA,CAAK,YAAA,EAAa,CAAE,KAAA,CAAM,CAAC,KAAA,KAAU;AACnC,UAAA,OAAA,CAAQ,KAAA,CAAM,wBAAwB,KAAK,CAAA;AAAA,QAC7C,CAAC,CAAA;AAAA,MACH;AAAA,IACF,CAAA,EAAG,IAAA,CAAK,MAAA,CAAO,oBAAoB,CAAA;AAAA,EACrC;AAAA;AAAA;AAAA;AAAA,EAKQ,YAAA,GAAqB;AAC3B,IAAA,IAAA,CAAK,OAAA,GAAU,IAAA;AACf,IAAA,IAAI,KAAK,YAAA,EAAc;AACrB,MAAA,aAAA,CAAc,KAAK,YAAY,CAAA;AAC/B,MAAA,IAAA,CAAK,YAAA,GAAe,IAAA;AAAA,IACtB;AAAA,EACF;AAAA;AAAA;AAAA;AAAA,EAKA,OAAA,GAAgB;AACd,IAAA,IAAA,CAAK,YAAA,EAAa;AAAA,EACpB;AACF;AC1PA,IAAM,WAAA,GAAc,cAA4C,MAAS,CAAA;AAQlE,SAAS,YAAA,CAAa;AAAA,EAC3B,QAAA;AAAA,EACA,MAAA;AAAA,EACA;AACF,CAAA,EAAsB;AACpB,EAAA,MAAM,CAAC,UAAU,CAAA,GAAI,QAAA,CAAS,MAAM,IAAI,UAAA,CAAW,MAAM,CAAC,CAAA;AAC1D,EAAA,MAAM,CAAC,KAAA,EAAO,QAAQ,CAAA,GAAI,SAAoB,OAAO;AAAA,IACnD,SAAS,cAAA,IAAkB,IAAA;AAAA,IAC3B,WAAW,CAAC,cAAA;AAAA,IACZ,eAAA,EAAiB,CAAC,CAAC;AAAA,GACrB,CAAE,CAAA;AAGF,EAAA,SAAA,CAAU,MAAM;AACd,IAAA,IAAI,cAAA,EAAgB;AAClB,MAAA,UAAA,CAAW,WAAW,cAAc,CAAA;AACpC,MAAA,QAAA,CAAS;AAAA,QACP,OAAA,EAAS,cAAA;AAAA,QACT,SAAA,EAAW,KAAA;AAAA,QACX,eAAA,EAAiB;AAAA,OAClB,CAAA;AAAA,IACH,CAAA,MAAO;AAEL,MAAA,MAAM,OAAA,GAAU,WAAW,UAAA,EAAW;AACtC,MAAA,QAAA,CAAS;AAAA,QACP,OAAA;AAAA,QACA,SAAA,EAAW,KAAA;AAAA,QACX,eAAA,EAAiB,CAAC,CAAC;AAAA,OACpB,CAAA;AAAA,IACH;AAAA,EACF,CAAA,EAAG,CAAC,UAAA,EAAY,cAAc,CAAC,CAAA;AAG/B,EAAA,SAAA,CAAU,MAAM;AACd,IAAA,MAAM,oBAAoB,MAAA,CAAO,gBAAA;AACjC,IAAA,MAAA,CAAO,mBAAmB,MAAM;AAC9B,MAAA,QAAA,CAAS;AAAA,QACP,OAAA,EAAS,IAAA;AAAA,QACT,SAAA,EAAW,KAAA;AAAA,QACX,eAAA,EAAiB;AAAA,OAClB,CAAA;AACD,MAAA,iBAAA,IAAoB;AAAA,IACtB,CAAA;AAEA,IAAA,OAAO,MAAM;AACX,MAAA,UAAA,CAAW,OAAA,EAAQ;AAAA,IACrB,CAAA;AAAA,EACF,CAAA,EAAG,CAAC,UAAA,EAAY,MAAM,CAAC,CAAA;AAEvB,EAAA,MAAM,KAAA,GAAQ,WAAA;AAAA,IACZ,OAAO,OAAe,QAAA,KAAqB;AACzC,MAAA,QAAA,CAAS,CAAC,IAAA,MAAU,EAAE,GAAG,IAAA,EAAM,SAAA,EAAW,MAAK,CAAE,CAAA;AAEjD,MAAA,IAAI;AACF,QAAA,MAAM,OAAA,GAAU,MAAM,UAAA,CAAW,KAAA,CAAM,OAAO,QAAQ,CAAA;AACtD,QAAA,QAAA,CAAS;AAAA,UACP,OAAA;AAAA,UACA,SAAA,EAAW,KAAA;AAAA,UACX,eAAA,EAAiB;AAAA,SAClB,CAAA;AAAA,MACH,SAAS,KAAA,EAAO;AACd,QAAA,QAAA,CAAS,CAAC,IAAA,MAAU,EAAE,GAAG,IAAA,EAAM,SAAA,EAAW,OAAM,CAAE,CAAA;AAClD,QAAA,MAAM,KAAA;AAAA,MACR;AAAA,IACF,CAAA;AAAA,IACA,CAAC,UAAU;AAAA,GACb;AAEA,EAAA,MAAM,MAAA,GAAS,YAAY,YAAY;AACrC,IAAA,QAAA,CAAS,CAAC,IAAA,MAAU,EAAE,GAAG,IAAA,EAAM,SAAA,EAAW,MAAK,CAAE,CAAA;AAEjD,IAAA,IAAI;AACF,MAAA,MAAM,WAAW,MAAA,EAAO;AAAA,IAC1B,CAAA,SAAE;AACA,MAAA,QAAA,CAAS;AAAA,QACP,OAAA,EAAS,IAAA;AAAA,QACT,SAAA,EAAW,KAAA;AAAA,QACX,eAAA,EAAiB;AAAA,OAClB,CAAA;AAAA,IACH;AAAA,EACF,CAAA,EAAG,CAAC,UAAU,CAAC,CAAA;AAEf,EAAA,MAAM,WAAA,GAAc,YAAY,YAAY;AAC1C,IAAA,IAAI;AACF,MAAA,MAAM,IAAA,GAAO,MAAM,UAAA,CAAW,cAAA,EAAe;AAC7C,MAAA,QAAA,CAAS,CAAC,IAAA,MAAU;AAAA,QAClB,GAAG,IAAA;AAAA,QACH,OAAA,EAAS,KAAK,OAAA,GACV,EAAE,GAAG,IAAA,CAAK,OAAA,EAAS,MAAK,GACxB;AAAA,OACN,CAAE,CAAA;AAAA,IACJ,SAAS,KAAA,EAAO;AACd,MAAA,OAAA,CAAQ,KAAA,CAAM,2BAA2B,KAAK,CAAA;AAAA,IAChD;AAAA,EACF,CAAA,EAAG,CAAC,UAAU,CAAC,CAAA;AAEf,EAAA,MAAMA,eAAAA,GAAiB,YAAY,YAAY;AAC7C,IAAA,OAAO,WAAW,cAAA,EAAe;AAAA,EACnC,CAAA,EAAG,CAAC,UAAU,CAAC,CAAA;AAEf,EAAA,MAAM,KAAA,GAA0B;AAAA,IAC9B,GAAG,KAAA;AAAA,IACH,KAAA;AAAA,IACA,MAAA;AAAA,IACA,WAAA;AAAA,IACA,cAAA,EAAAA;AAAA,GACF;AAEA,EAAA,uBAAO,GAAA,CAAC,WAAA,CAAY,QAAA,EAAZ,EAAqB,OAAe,QAAA,EAAS,CAAA;AACvD;AAKO,SAAS,cAAA,GAAmC;AACjD,EAAA,MAAM,OAAA,GAAU,WAAW,WAAW,CAAA;AACtC,EAAA,IAAI,CAAC,OAAA,EAAS;AACZ,IAAA,MAAM,IAAI,MAAM,iDAAiD,CAAA;AAAA,EACnE;AACA,EAAA,OAAO,OAAA;AACT;;;ACjIO,SAAS,OAAA,GAAyB;AACvC,EAAA,MAAM;AAAA,IACJ,OAAA;AAAA,IACA,SAAA;AAAA,IACA,eAAA;AAAA,IACA,KAAA;AAAA,IACA,MAAA;AAAA,IACA,WAAA;AAAA,IACA,cAAA,EAAAA;AAAA,MACE,cAAA,EAAe;AAEnB,EAAA,OAAO;AAAA,IACL,IAAA,EAAM,SAAS,IAAA,IAAQ,IAAA;AAAA,IACvB,OAAA;AAAA,IACA,SAAA;AAAA,IACA,eAAA;AAAA,IACA,KAAA;AAAA,IACA,MAAA;AAAA,IACA,WAAA;AAAA,IACA,cAAA,EAAAA;AAAA,GACF;AACF;ACpBO,SAAS,cAAA,GAAuC;AACrD,EAAA,MAAM,EAAE,IAAA,EAAK,GAAI,OAAA,EAAQ;AAEzB,EAAA,MAAM,gBAAA,GAAmB,MAAM,gBAAA,IAAoB,IAAA;AAEnD,EAAA,MAAM,cAAA,GAAiB,QAAQ,MAAM;AACnC,IAAA,IAAI,CAAC,IAAA,EAAM,SAAA,IAAa,CAAC,gBAAA,EAAkB;AACzC,MAAA,OAAO,IAAA;AAAA,IACT;AACA,IAAA,OAAO,KAAK,SAAA,CAAU,IAAA,CAAK,CAAC,CAAA,KAAM,CAAA,CAAE,OAAO,gBAAgB,CAAA;AAAA,EAC7D,CAAA,EAAG,CAAC,IAAA,EAAM,gBAAgB,CAAC,CAAA;AAE3B,EAAA,MAAM,WAAA,GAAc,gBAAgB,IAAA,IAAQ,IAAA;AAE5C,EAAA,MAAM,OAAA,GAAU,CAAC,YAAA,EAA2B,SAAA,KAAgC;AAC1E,IAAA,IAAI,CAAC,MAAM,SAAA,EAAW;AACpB,MAAA,OAAO,KAAA;AAAA,IACT;AAEA,IAAA,MAAM,kBAAkB,SAAA,IAAa,gBAAA;AACrC,IAAA,IAAI,CAAC,eAAA,EAAiB;AACpB,MAAA,OAAO,KAAA;AAAA,IACT;AAEA,IAAA,MAAM,OAAA,GAAU,KAAK,SAAA,CAAU,IAAA,CAAK,CAAC,CAAA,KAAM,CAAA,CAAE,OAAO,eAAe,CAAA;AACnE,IAAA,IAAI,CAAC,OAAA,EAAS;AACZ,MAAA,OAAO,KAAA;AAAA,IACT;AAEA,IAAA,OAAO,iBAAA,CAAkB,OAAA,CAAQ,IAAA,EAAM,YAAY,CAAA;AAAA,EACrD,CAAA;AAEA,EAAA,MAAM,OAAA,GAAU,CAAC,SAAA,KAAgC;AAC/C,IAAA,OAAO,OAAA,CAAQ,SAAS,SAAS,CAAA;AAAA,EACnC,CAAA;AAEA,EAAA,MAAM,OAAA,GAAU,CAAC,SAAA,KAAgC;AAC/C,IAAA,OAAO,OAAA,CAAQ,SAAS,SAAS,CAAA;AAAA,EACnC,CAAA;AAEA,EAAA,MAAM,OAAA,GAAU,CAAC,SAAA,KAAgC;AAC/C,IAAA,OAAO,OAAA,CAAQ,UAAU,SAAS,CAAA;AAAA,EACpC,CAAA;AAEA,EAAA,MAAM,OAAA,GAAU,CAAC,SAAA,KAAgC;AAC/C,IAAA,OAAO,OAAA,CAAQ,UAAU,SAAS,CAAA;AAAA,EACpC,CAAA;AAEA,EAAA,OAAO;AAAA,IACL,OAAA;AAAA,IACA,OAAA;AAAA,IACA,OAAA;AAAA,IACA,OAAA;AAAA,IACA,OAAA;AAAA,IACA,WAAA;AAAA,IACA;AAAA,GACF;AACF;;;ACvDA,IAAM,QAAA,GAAW,SAAA;AAEjB,IAAM,UAAA,GAAa;AAAA,EACjB,KAAA,EAAO,GAAG,QAAQ,CAAA,YAAA,CAAA;AAAA,EAClB,aAAA,EAAe,GAAG,QAAQ,CAAA,oBAAA,CAAA;AAAA,EAC1B,QAAA,EAAU,GAAG,QAAQ,CAAA,eAAA,CAAA;AAAA,EACrB,MAAA,EAAQ,GAAG,QAAQ,CAAA,aAAA,CAAA;AAAA,EACnB,eAAA,EAAiB,GAAG,QAAQ,CAAA,sBAAA,CAAA;AAAA,EAC5B,cAAA,EAAgB,GAAG,QAAQ,CAAA,qBAAA,CAAA;AAAA,EAC3B,YAAA,EAAc,GAAG,QAAQ,CAAA,mBAAA,CAAA;AAAA,EACzB,mBAAA,EAAqB,GAAG,QAAQ,CAAA,0BAAA,CAAA;AAAA,EAChC,qBAAA,EAAuB,GAAG,QAAQ,CAAA,4BAAA,CAAA;AAAA,EAClC,qBAAA,EAAuB,GAAG,QAAQ,CAAA,4BAAA,CAAA;AAAA,EAClC,EAAA,EAAI,GAAG,QAAQ,CAAA,SAAA;AACjB,CAAA;AAIA,IAAM,aAAA,GACH,OAAO,OAAA,KAAY,WAAA,KACjB,QAAQ,GAAA,CAAI,mBAAA,IAAuB,OAAA,CAAQ,GAAA,CAAI,wBAAA,CAAA,IAClD,EAAA;AACF,IAAM,qBAAA,GAAwB,eAAA,CAAgB,IAAA,CAAK,aAAa,CAAA;AAEhE,SAAS,cAAc,GAAA,EAAa;AAClC,EAAA,OAAO,eAAA,CAAgB,KAAK,GAAG,CAAA;AACjC;AAEO,SAAS,eAAe,IAAA,EAAsB;AACnD,EAAA,IAAI,aAAA,CAAc,IAAI,CAAA,EAAG,OAAO,IAAA;AAEhC,EAAA,MAAM,aAAa,IAAA,CAAK,UAAA,CAAW,GAAG,CAAA,GAAI,IAAA,GAAO,IAAI,IAAI,CAAA,CAAA;AACzD,EAAA,IAAI,qBAAA,EAAuB;AACzB,IAAA,OAAO,IAAI,GAAA,CAAI,UAAA,EAAY,aAAa,EAAE,QAAA,EAAS;AAAA,EACrD;AACA,EAAA,IAAI,UAAA,CAAW,UAAA,CAAW,OAAO,CAAA,EAAG,OAAO,UAAA;AAC3C,EAAA,IAAI,CAAC,eAAe,OAAO,UAAA;AAE3B,EAAA,IAAI,cAAc,QAAA,CAAS,GAAG,KAAK,UAAA,CAAW,UAAA,CAAW,GAAG,CAAA,EAAG;AAC7D,IAAA,OAAO,GAAG,aAAA,CAAc,KAAA,CAAM,GAAG,EAAE,CAAC,GAAG,UAAU,CAAA,CAAA;AAAA,EACnD;AAEA,EAAA,OAAO,CAAA,EAAG,aAAa,CAAA,EAAG,UAAU,CAAA,CAAA;AACtC;AAOA,IAAM,iBAAA,GAAoB,mBAAA;AAE1B,IAAI,SAAA,GAA2B,IAAA;AAE/B,SAAS,wBAAA,GAAoC;AAC3C,EAAA,IAAI;AACF,IAAA,OAAO,OAAO,MAAA,KAAW,WAAA,IAAe,CAAC,CAAC,MAAA,CAAO,cAAA;AAAA,EACnD,CAAA,CAAA,MAAQ;AACN,IAAA,OAAO,KAAA;AAAA,EACT;AACF;AAEO,SAAS,cAAA,GAAgC;AAC9C,EAAA,IAAI,0BAAyB,EAAG;AAC9B,IAAA,OAAO,cAAA,CAAe,QAAQ,iBAAiB,CAAA;AAAA,EACjD;AACA,EAAA,OAAO,SAAA;AACT;AAEO,SAAS,eAAe,KAAA,EAA4B;AACzD,EAAA,IAAI,0BAAyB,EAAG;AAC9B,IAAA,IAAI,UAAU,IAAA,EAAM;AAClB,MAAA,cAAA,CAAe,WAAW,iBAAiB,CAAA;AAAA,IAC7C,CAAA,MAAO;AACL,MAAA,cAAA,CAAe,OAAA,CAAQ,mBAAmB,KAAK,CAAA;AAAA,IACjD;AACA,IAAA;AAAA,EACF;AACA,EAAA,SAAA,GAAY,KAAA;AACd;AAIA,IAAM,eAAA,GAAkB,IAAA;AAGxB,SAAS,eAAA,CAAgB,GAA4B,QAAA,EAA0B;AAE7E,EAAA,IAAI,OAAO,CAAA,CAAE,MAAA,KAAW,QAAA,SAAiB,CAAA,CAAE,MAAA;AAE3C,EAAA,KAAA,MAAW,GAAA,IAAO,MAAA,CAAO,MAAA,CAAO,CAAC,CAAA,EAAG;AAClC,IAAA,IAAI,OAAO,GAAA,KAAQ,QAAA,EAAU,OAAO,GAAA;AACpC,IAAA,IAAI,KAAA,CAAM,OAAA,CAAQ,GAAG,CAAA,IAAK,IAAI,MAAA,GAAS,CAAA,IAAK,OAAO,GAAA,CAAI,CAAC,CAAA,KAAM,QAAA,EAAU,OAAO,IAAI,CAAC,CAAA;AAAA,EACtF;AACA,EAAA,OAAO,QAAA;AACT;AAEA,SAAS,gBAAA,CAAiB,KAAa,OAAA,EAAyC;AAC9E,EAAA,MAAM,UAAA,GAAa,IAAI,eAAA,EAAgB;AACvC,EAAA,MAAM,QAAQ,UAAA,CAAW,MAAM,UAAA,CAAW,KAAA,IAAS,eAAe,CAAA;AAClE,EAAA,OAAO,KAAA,CAAM,KAAK,EAAE,GAAG,SAAS,MAAA,EAAQ,UAAA,CAAW,MAAA,EAAQ,CAAA,CAAE,OAAA;AAAA,IAAQ,MACnE,aAAa,KAAK;AAAA,GACpB;AACF;AAEA,SAAS,cAAc,GAAA,EAA+B;AACpD,EAAA,IAAI,CAAC,GAAA,IAAO,OAAO,GAAA,KAAQ,UAAU,OAAO,IAAA;AAC5C,EAAA,MAAM,GAAA,GAAM,GAAA;AACZ,EAAA,MAAM,OAAA,GAAW,IAAI,IAAA,IAAQ,OAAO,IAAI,IAAA,KAAS,QAAA,GAAW,IAAI,IAAA,GAAO,GAAA;AACvE,EAAA,IAAI,CAAC,OAAA,EAAS,EAAA,IAAM,CAAC,OAAA,EAAS,OAAO,OAAO,IAAA;AAE5C,EAAA,MAAM,SAAA,GAAa,OAAA,CAAQ,UAAA,IAAc,OAAA,CAAQ,SAAA,IAAa,IAAA;AAC9D,EAAA,MAAM,QAAA,GAAY,OAAA,CAAQ,SAAA,IAAa,OAAA,CAAQ,QAAA,IAAY,IAAA;AAC3D,EAAA,MAAM,IAAA,GACH,OAAA,CAAQ,IAAA,KACR,CAAC,SAAA,EAAW,QAAQ,CAAA,CAAE,MAAA,CAAO,OAAO,CAAA,CAAE,IAAA,CAAK,GAAG,CAAA,IAAK,IAAA,CAAA;AAEtD,EAAA,OAAO;AAAA,IACL,IAAI,OAAA,CAAQ,EAAA;AAAA,IACZ,OAAO,OAAA,CAAQ,KAAA;AAAA,IACf,IAAA;AAAA,IACA,SAAA;AAAA,IACA,QAAA;AAAA,IACA,MAAA,EAAQ,MAAM,OAAA,CAAQ,OAAA,CAAQ,MAAM,CAAA,GAAK,OAAA,CAAQ,SAAsB,EAAC;AAAA,IACxE,WAAA,EAAa,MAAM,OAAA,CAAQ,OAAA,CAAQ,WAAW,CAAA,GAAK,OAAA,CAAQ,cAA2B,EAAC;AAAA,IACvF,QAAA,EAAW,OAAA,CAAQ,QAAA,IAAY,OAAA,CAAQ,SAAA;AAAA,IACvC,eAAA,EAAkB,OAAA,CAAQ,eAAA,IAAmB,OAAA,CAAQ;AAAA,GACvD;AACF;AAEA,SAAS,kBAAkB,IAAA,EAAqD;AAC9E,EAAA,IAAI,CAAC,IAAA,IAAQ,OAAO,IAAA,KAAS,QAAA,SAAiB,EAAC;AAC/C,EAAA,MAAM,GAAA,GAAM,IAAA;AACZ,EAAA,MAAM,OAAA,GAAW,IAAI,IAAA,IAAQ,OAAO,IAAI,IAAA,KAAS,QAAA,GAAW,IAAI,IAAA,GAAO,GAAA;AACvE,EAAA,MAAM,MAAA,GAAU,OAAA,CAAQ,MAAA,IAAU,OAAA,CAAQ,gBAAgB,OAAA,CAAQ,KAAA;AAClE,EAAA,MAAM,UAAU,OAAA,CAAQ,IAAA,IAAQ,OAAA,CAAQ,EAAA,IAAM,QAAQ,OAAA,IAAW,OAAA;AACjE,EAAA,MAAM,IAAA,GAAO,cAAc,OAAO,CAAA;AAClC,EAAA,OAAO,EAAE,MAAA,EAAQ,IAAA,EAAM,IAAA,IAAQ,MAAA,EAAU;AAC3C;AAIA,eAAsB,qBAAA,CAAsB,OAAe,QAAA,EAAkB;AAC3E,EAAA,MAAM,WAAW,MAAM,gBAAA,CAAiB,cAAA,CAAe,UAAA,CAAW,KAAK,CAAA,EAAG;AAAA,IACxE,MAAA,EAAQ,MAAA;AAAA,IACR,OAAA,EAAS,EAAE,cAAA,EAAgB,kBAAA,EAAmB;AAAA,IAC9C,WAAA,EAAa,SAAA;AAAA,IACb,MAAM,IAAA,CAAK,SAAA,CAAU,EAAE,KAAA,EAAO,UAAU;AAAA,GACzC,CAAA;AAED,EAAA,MAAM,IAAA,GAAO,MAAM,QAAA,CAAS,IAAA,GAAO,KAAA,CAAM,OAAO,EAAC,CAAE,CAAA;AAEnD,EAAA,IAAI,CAAC,SAAS,EAAA,EAAI;AAChB,IAAA,MAAM,CAAA,GAAI,IAAA;AACV,IAAA,IAAI,CAAA,EAAG,KAAA,KAAU,gBAAA,IAAoB,CAAA,EAAG,YAAA,EAAc;AACpD,MAAA,MAAM,IAAI,KAAA,CAAM,CAAA,qBAAA,EAAwB,IAAI,IAAA,CAAK,EAAE,YAAsB,CAAA,CAAE,kBAAA,EAAoB,CAAA,CAAE,CAAA;AAAA,IACnG;AACA,IAAA,MAAM,OAAA,GAAW,CAAA,EAAG,MAAA,IAAU,CAAA,EAAG,KAAA,IAAS,uBAAA;AAC1C,IAAA,MAAM,IAAI,MAAM,OAAO,CAAA;AAAA,EACzB;AAEA,EAAA,MAAM,MAAA,GAAS,kBAAkB,IAAI,CAAA;AACrC,EAAA,IAAI,OAAO,MAAA,EAAQ;AACjB,IAAA,cAAA,CAAe,OAAO,MAAM,CAAA;AAAA,EAC9B;AAEA,EAAA,OAAO,MAAA;AACT;AAEA,eAAsB,gBAAgB,OAAA,EAOnC;AACD,EAAA,MAAM,OAAA,GAAU,OAAA,CAAQ,IAAA,EAAM,IAAA,EAAK,IAAK,EAAA;AACxC,EAAA,MAAM,CAAC,aAAA,EAAe,GAAG,IAAI,CAAA,GAAI,UAAU,OAAA,CAAQ,KAAA,CAAM,KAAK,CAAA,GAAI,EAAC;AACnE,EAAA,MAAM,eAAe,IAAA,CAAK,MAAA,GAAS,IAAA,CAAK,IAAA,CAAK,GAAG,CAAA,GAAI,MAAA;AAEpD,EAAA,MAAM,WAAW,MAAM,gBAAA,CAAiB,cAAA,CAAe,UAAA,CAAW,QAAQ,CAAA,EAAG;AAAA,IAC3E,MAAA,EAAQ,MAAA;AAAA,IACR,OAAA,EAAS,EAAE,cAAA,EAAgB,kBAAA,EAAmB;AAAA,IAC9C,WAAA,EAAa,SAAA;AAAA,IACb,IAAA,EAAM,KAAK,SAAA,CAAU;AAAA,MACnB,OAAO,OAAA,CAAQ,KAAA;AAAA,MACf,UAAU,OAAA,CAAQ,QAAA;AAAA,MAClB,kBAAkB,OAAA,CAAQ,eAAA;AAAA,MAC1B,UAAA,EAAY,OAAA,CAAQ,SAAA,IAAa,aAAA,IAAiB,MAAA;AAAA,MAClD,SAAA,EAAW,OAAA,CAAQ,QAAA,IAAY,YAAA,IAAgB;AAAA,KAChD;AAAA,GACF,CAAA;AAED,EAAA,MAAM,IAAA,GAAO,MAAM,QAAA,CAAS,IAAA,GAAO,KAAA,CAAM,OAAO,EAAC,CAAE,CAAA;AAEnD,EAAA,IAAI,CAAC,SAAS,EAAA,EAAI;AAChB,IAAA,MAAM,IAAI,KAAA,CAAM,eAAA,CAAgB,IAAA,EAAiC,qBAAqB,CAAC,CAAA;AAAA,EACzF;AAEA,EAAA,MAAM,MAAA,GAAS,kBAAkB,IAAI,CAAA;AACrC,EAAA,IAAI,OAAO,MAAA,EAAQ;AACjB,IAAA,cAAA,CAAe,OAAO,MAAM,CAAA;AAAA,EAC9B;AAEA,EAAA,OAAO,MAAA;AACT;AAEA,eAAsB,qBAAqB,KAAA,EAA8B;AACvE,EAAA,MAAM,WAAW,MAAM,KAAA,CAAM,cAAA,CAAe,UAAA,CAAW,eAAe,CAAA,EAAG;AAAA,IACvE,MAAA,EAAQ,MAAA;AAAA,IACR,OAAA,EAAS,EAAE,cAAA,EAAgB,kBAAA,EAAmB;AAAA,IAC9C,IAAA,EAAM,IAAA,CAAK,SAAA,CAAU,EAAE,OAAO;AAAA,GAC/B,CAAA;AAED,EAAA,IAAI,CAAC,SAAS,EAAA,EAAI;AAChB,IAAA,MAAM,IAAA,GAAO,MAAM,QAAA,CAAS,IAAA,GAAO,KAAA,CAAM,OAAO,EAAC,CAAE,CAAA;AACnD,IAAA,MAAM,CAAA,GAAI,IAAA;AACV,IAAA,MAAM,OAAA,GAAW,CAAA,EAAG,MAAA,IAAU,CAAA,EAAG,KAAA,IAAS,2BAAA;AAC1C,IAAA,MAAM,IAAI,MAAM,OAAO,CAAA;AAAA,EACzB;AACF;AAEA,eAAsB,cAAc,OAAA,EAKlB;AAChB,EAAA,MAAM,WAAW,MAAM,gBAAA,CAAiB,cAAA,CAAe,UAAA,CAAW,cAAc,CAAA,EAAG;AAAA,IACjF,MAAA,EAAQ,MAAA;AAAA,IACR,OAAA,EAAS,EAAE,cAAA,EAAgB,kBAAA,EAAmB;AAAA,IAC9C,IAAA,EAAM,KAAK,SAAA,CAAU;AAAA,MACnB,OAAO,OAAA,CAAQ,KAAA;AAAA,MACf,UAAU,OAAA,CAAQ,QAAA;AAAA,MAClB,kBAAkB,OAAA,CAAQ,eAAA;AAAA,MAC1B,GAAI,QAAQ,KAAA,GAAQ,EAAE,OAAO,OAAA,CAAQ,KAAA,KAAU;AAAC,KACjD;AAAA,GACF,CAAA;AAED,EAAA,IAAI,CAAC,SAAS,EAAA,EAAI;AAChB,IAAA,MAAM,IAAA,GAAO,MAAM,QAAA,CAAS,IAAA,GAAO,KAAA,CAAM,OAAO,EAAC,CAAE,CAAA;AACnD,IAAA,MAAM,CAAA,GAAI,IAAA;AACV,IAAA,MAAM,OAAA,GAAW,CAAA,EAAG,MAAA,IAAU,CAAA,EAAG,KAAA,IAAS,0BAAA;AAC1C,IAAA,MAAM,IAAI,MAAM,OAAO,CAAA;AAAA,EACzB;AACF;AAEA,eAAsB,YAAY,KAAA,EAA8B;AAC9D,EAAA,MAAM,WAAW,MAAM,gBAAA,CAAiB,cAAA,CAAe,UAAA,CAAW,YAAY,CAAA,EAAG;AAAA,IAC/E,MAAA,EAAQ,MAAA;AAAA,IACR,OAAA,EAAS,EAAE,cAAA,EAAgB,kBAAA,EAAmB;AAAA,IAC9C,IAAA,EAAM,IAAA,CAAK,SAAA,CAAU,EAAE,OAAO;AAAA,GAC/B,CAAA;AAED,EAAA,IAAI,CAAC,SAAS,EAAA,EAAI;AAChB,IAAA,MAAM,IAAA,GAAO,MAAM,QAAA,CAAS,IAAA,GAAO,KAAA,CAAM,OAAO,EAAC,CAAE,CAAA;AACnD,IAAA,MAAM,CAAA,GAAI,IAAA;AACV,IAAA,MAAM,OAAA,GAAW,CAAA,EAAG,MAAA,IAAU,CAAA,EAAG,KAAA,IAAS,wBAAA;AAC1C,IAAA,MAAM,IAAI,MAAM,OAAO,CAAA;AAAA,EACzB;AACF;AAEA,eAAsB,mBAAmB,MAAA,EAAuC;AAC9E,EAAA,MAAM,WAAW,MAAM,KAAA,CAAM,cAAA,CAAe,UAAA,CAAW,mBAAmB,CAAA,EAAG;AAAA,IAC3E,MAAA,EAAQ,MAAA;AAAA,IACR,OAAA,EAAS;AAAA,MACP,cAAA,EAAgB,kBAAA;AAAA,MAChB,GAAI,SAAS,EAAE,aAAA,EAAe,UAAU,MAAM,CAAA,CAAA,KAAO;AAAC,KACxD;AAAA,IACA,WAAA,EAAa;AAAA,GACd,CAAA;AAED,EAAA,IAAI,CAAC,SAAS,EAAA,EAAI;AAChB,IAAA,MAAM,IAAA,GAAO,MAAM,QAAA,CAAS,IAAA,GAAO,KAAA,CAAM,OAAO,EAAC,CAAE,CAAA;AACnD,IAAA,MAAM,CAAA,GAAI,IAAA;AACV,IAAA,MAAM,OAAA,GAAW,CAAA,EAAG,MAAA,IAAU,CAAA,EAAG,KAAA,IAAS,qCAAA;AAC1C,IAAA,MAAM,IAAI,MAAM,OAAO,CAAA;AAAA,EACzB;AACF;AAGA,eAAsB,oBAAoB,WAAA,EAAmC;AAC3E,EAAA,MAAM,WAAW,MAAM,KAAA,CAAM,cAAA,CAAe,UAAA,CAAW,qBAAqB,CAAA,EAAG;AAAA,IAC7E,MAAA,EAAQ,MAAA;AAAA,IACR,OAAA,EAAS,EAAE,cAAA,EAAgB,kBAAA,EAAmB;AAAA,IAC9C,WAAA,EAAa,SAAA;AAAA,IACb,MAAM,IAAA,CAAK,SAAA,CAAU,EAAE,YAAA,EAAc,aAAa;AAAA,GACnD,CAAA;AAED,EAAA,MAAM,IAAA,GAAO,MAAM,QAAA,CAAS,IAAA,GAAO,KAAA,CAAM,OAAO,EAAC,CAAE,CAAA;AAEnD,EAAA,IAAI,CAAC,SAAS,EAAA,EAAI;AAChB,IAAA,MAAM,CAAA,GAAI,IAAA;AACV,IAAA,MAAM,OAAA,GAAW,CAAA,EAAG,MAAA,IAAU,CAAA,EAAG,KAAA,IAAS,iCAAA;AAC1C,IAAA,MAAM,IAAI,MAAM,OAAO,CAAA;AAAA,EACzB;AAEA,EAAA,OAAO,IAAA;AACT;AAEA,eAAsB,mBAAA,CAAoB,MAAc,KAAA,EAAe;AACrE,EAAA,MAAM,WAAW,MAAM,gBAAA;AAAA,IACrB,cAAA;AAAA,MACE,CAAA,EAAG,UAAA,CAAW,qBAAqB,CAAA,MAAA,EAAS,kBAAA,CAAmB,IAAI,CAAC,CAAA,OAAA,EAAU,kBAAA,CAAmB,KAAK,CAAC,CAAA;AAAA,KACzG;AAAA,IACA,EAAE,aAAa,SAAA;AAAU,GAC3B;AAEA,EAAA,MAAM,IAAA,GAAO,MAAM,QAAA,CAAS,IAAA,GAAO,KAAA,CAAM,OAAO,EAAC,CAAE,CAAA;AAEnD,EAAA,IAAI,CAAC,SAAS,EAAA,EAAI;AAChB,IAAA,MAAM,CAAA,GAAI,IAAA;AACV,IAAA,MAAM,OAAA,GAAW,CAAA,EAAG,MAAA,IAAU,CAAA,EAAG,KAAA,IAAS,6BAAA;AAC1C,IAAA,MAAM,IAAI,MAAM,OAAO,CAAA;AAAA,EACzB;AAEA,EAAA,MAAM,MAAA,GAAS,kBAAkB,IAAI,CAAA;AACrC,EAAA,IAAI,OAAO,MAAA,EAAQ;AACjB,IAAA,cAAA,CAAe,OAAO,MAAM,CAAA;AAAA,EAC9B;AAEA,EAAA,OAAO,MAAA;AACT;AAEA,eAAe,cAAA,GAAgC;AAC7C,EAAA,IAAI,cAAa,EAAG;AACpB,EAAA,IAAI;AACF,IAAA,MAAM,KAAA,CAAM,cAAA,CAAe,CAAA,EAAG,QAAQ,aAAa,CAAA,EAAG;AAAA,MACpD,WAAA,EAAa,SAAA;AAAA,MACb,KAAA,EAAO;AAAA,KACR,CAAA;AAAA,EACH,SAAS,GAAA,EAAK;AACZ,IAAA,OAAA,CAAQ,IAAA,CAAK,kEAA6D,GAAG,CAAA;AAAA,EAC/E;AACF;AAEA,eAAsB,kBAAA,GAA6C;AACjE,EAAA,MAAM,cAAA,EAAe;AACrB,EAAA,MAAM,YAAY,YAAA,EAAa;AAC/B,EAAA,IAAI,CAAC,WAAW,OAAO,IAAA;AAEvB,EAAA,MAAM,WAAW,MAAM,gBAAA,CAAiB,cAAA,CAAe,UAAA,CAAW,aAAa,CAAA,EAAG;AAAA,IAChF,MAAA,EAAQ,MAAA;AAAA,IACR,OAAA,EAAS;AAAA,MACP,cAAA,EAAgB,kBAAA;AAAA,MAChB,aAAA,EAAe;AAAA,KACjB;AAAA,IACA,WAAA,EAAa;AAAA,GACd,CAAA;AAED,EAAA,MAAM,IAAA,GAAO,MAAM,QAAA,CAAS,IAAA,GAAO,KAAA,CAAM,OAAO,EAAC,CAAE,CAAA;AAEnD,EAAA,IAAI,CAAC,SAAS,EAAA,EAAI;AAChB,IAAA,OAAO,IAAA;AAAA,EACT;AAEA,EAAA,MAAM,MAAA,GAAS,kBAAkB,IAAI,CAAA;AACrC,EAAA,IAAI,OAAO,MAAA,EAAQ;AACjB,IAAA,cAAA,CAAe,OAAO,MAAM,CAAA;AAC5B,IAAA,OAAO,MAAA,CAAO,MAAA;AAAA,EAChB;AAEA,EAAA,OAAO,IAAA;AACT;AAEA,eAAsB,KAAA,GAAkC;AACtD,EAAA,MAAM,QAAQ,cAAA,EAAe;AAC7B,EAAA,IAAI,CAAC,OAAO,OAAO,IAAA;AAEnB,EAAA,MAAM,WAAW,MAAM,KAAA,CAAM,cAAA,CAAe,UAAA,CAAW,EAAE,CAAA,EAAG;AAAA,IAC1D,OAAA,EAAS;AAAA,MACP,aAAA,EAAe,UAAU,KAAK,CAAA;AAAA,KAChC;AAAA,IACA,WAAA,EAAa,SAAA;AAAA,IACb,KAAA,EAAO;AAAA,GACR,CAAA;AAED,EAAA,IAAI,CAAC,SAAS,EAAA,EAAI;AAChB,IAAA,OAAO,IAAA;AAAA,EACT;AAEA,EAAA,MAAM,IAAA,GAAO,MAAM,QAAA,CAAS,IAAA,GAAO,KAAA,CAAM,OAAO,EAAC,CAAE,CAAA;AACnD,EAAA,MAAM,GAAA,GAAM,IAAA;AACZ,EAAA,MAAM,OAAA,GAAU,IAAI,IAAA,IAAQ,OAAO,IAAI,IAAA,KAAS,QAAA,GAAW,IAAI,IAAA,GAAO,GAAA;AACtE,EAAA,MAAM,OAAA,GAAW,QAAoC,IAAA,IAAQ,OAAA;AAC7D,EAAA,OAAO,cAAc,OAAO,CAAA;AAC9B;AAEA,eAAsB,OAAA,GAAyB;AAC7C,EAAA,MAAM,YAAY,YAAA,EAAa;AAC/B,EAAA,MAAM,QAAQ,cAAA,EAAe;AAE7B,EAAA,IAAI;AACF,IAAA,MAAM,KAAA,CAAM,cAAA,CAAe,UAAA,CAAW,MAAM,CAAA,EAAG;AAAA,MAC7C,MAAA,EAAQ,MAAA;AAAA,MACR,OAAA,EAAS;AAAA,QACP,cAAA,EAAgB,kBAAA;AAAA,QAChB,GAAI,SAAA,GAAY,EAAE,aAAA,EAAe,SAAA,KAAc,EAAC;AAAA,QAChD,GAAI,QAAQ,EAAE,aAAA,EAAe,UAAU,KAAK,CAAA,CAAA,KAAO;AAAC,OACtD;AAAA,MACA,WAAA,EAAa;AAAA,KACd,CAAA;AAAA,EACH,CAAA,SAAE;AACA,IAAA,cAAA,CAAe,IAAI,CAAA;AAAA,EACrB;AACF;AAGA,IAAI,eAAA,GAAiD,IAAA;AAErD,SAAS,YAAA,GAAuC;AAC9C,EAAA,IAAI,CAAC,eAAA,EAAiB;AACpB,IAAA,eAAA,GAAkB,kBAAA,EAAmB,CAAE,OAAA,CAAQ,MAAM;AACnD,MAAA,eAAA,GAAkB,IAAA;AAAA,IACpB,CAAC,CAAA;AAAA,EACH;AACA,EAAA,OAAO,eAAA;AACT;AAEA,eAAsB,SAAA,CACpB,KAAA,EACA,IAAA,GAAoB,EAAC,EACF;AACnB,EAAA,MAAM,QAAQ,cAAA,EAAe;AAC7B,EAAA,MAAM,UAAU,IAAI,OAAA,CAAQ,IAAA,CAAK,OAAA,IAAW,EAAE,CAAA;AAE9C,EAAA,IAAI,KAAA,IAAS,CAAC,OAAA,CAAQ,GAAA,CAAI,eAAe,CAAA,EAAG;AAC1C,IAAA,OAAA,CAAQ,GAAA,CAAI,eAAA,EAAiB,CAAA,OAAA,EAAU,KAAK,CAAA,CAAE,CAAA;AAAA,EAChD;AAEA,EAAA,MAAM,gBAAgB,OAAO,KAAA,KAAU,QAAA,GAAW,cAAA,CAAe,KAAK,CAAA,GAAI,KAAA;AAE1E,EAAA,MAAM,QAAA,GAAW,MAAM,KAAA,CAAM,aAAA,EAAe;AAAA,IAC1C,GAAG,IAAA;AAAA,IACH,OAAA;AAAA,IACA,WAAA,EAAa,KAAK,WAAA,IAAe;AAAA,GAClC,CAAA;AAED,EAAA,IAAI,QAAA,CAAS,WAAW,GAAA,EAAK;AAC3B,IAAA,MAAM,SAAA,GAAY,MAAM,YAAA,EAAa;AACrC,IAAA,IAAI,SAAA,EAAW;AACb,MAAA,MAAM,eAAe,IAAI,OAAA,CAAQ,IAAA,CAAK,OAAA,IAAW,EAAE,CAAA;AACnD,MAAA,YAAA,CAAa,GAAA,CAAI,eAAA,EAAiB,CAAA,OAAA,EAAU,SAAS,CAAA,CAAE,CAAA;AAEvD,MAAA,OAAO,MAAM,aAAA,EAAe;AAAA,QAC1B,GAAG,IAAA;AAAA,QACH,OAAA,EAAS,YAAA;AAAA,QACT,WAAA,EAAa,KAAK,WAAA,IAAe;AAAA,OAClC,CAAA;AAAA,IACH;AAAA,EACF;AAEA,EAAA,OAAO,QAAA;AACT;AAEO,SAAS,aAAA,CAAc,MAAmC,UAAA,EAA6B;AAC5F,EAAA,IAAI,CAAC,MAAM,OAAO,KAAA;AAClB,EAAA,IAAI,CAAC,IAAA,CAAK,WAAA,IAAe,KAAK,WAAA,CAAY,MAAA,KAAW,GAAG,OAAO,KAAA;AAC/D,EAAA,OAAO,IAAA,CAAK,WAAA,CAAY,QAAA,CAAS,UAAU,CAAA;AAC7C;AAEO,SAAS,QAAA,CAAS,MAAmC,KAAA,EAAwB;AAClF,EAAA,IAAI,CAAC,MAAM,OAAO,KAAA;AAClB,EAAA,IAAI,CAAC,IAAA,CAAK,MAAA,IAAU,KAAK,MAAA,CAAO,MAAA,KAAW,GAAG,OAAO,KAAA;AACrD,EAAA,OAAO,IAAA,CAAK,MAAA,CAAO,QAAA,CAAS,KAAK,CAAA;AACnC","file":"chunk-CDNZRZ7Q.mjs","sourcesContent":["/**\n * Client-side authentication manager\n * Handles JWT tokens, login/logout, and token refresh\n */\n\nimport type {\n AuthConfig,\n Session,\n LoginResponse,\n RefreshResponse,\n AuthUser,\n} from '../types';\nimport { isTokenExpired, getTokenExpiresAt, shouldRefreshToken } from '../utils';\n\nexport class AuthClient {\n private config: Required<AuthConfig>;\n private session: Session | null = null;\n private refreshTimer: NodeJS.Timeout | null = null;\n private isRefreshing = false;\n private refreshPromise: Promise<string> | null = null;\n\n constructor(config: AuthConfig) {\n this.config = {\n tokenRefreshInterval: 4 * 60 * 1000, // 4 minutes\n onSessionExpired: () => {},\n onUnauthorized: () => {},\n ...config,\n };\n }\n\n /**\n * Login with email and password\n */\n async login(email: string, password: string): Promise<Session> {\n const response = await fetch(`${this.config.apiBaseUrl}/api/v1/auth/token/`, {\n method: 'POST',\n headers: { 'Content-Type': 'application/json' },\n credentials: 'include', // Include cookies for refresh token\n body: JSON.stringify({ email, password }),\n });\n\n if (!response.ok) {\n const error = await response.json().catch(() => ({ detail: 'Login failed' }));\n throw new Error(error.detail || 'Login failed');\n }\n\n const data: any = await response.json();\n const expiresAt = getTokenExpiresAt(data.access);\n\n if (!expiresAt) {\n throw new Error('Invalid token received');\n }\n\n // Django might not include user in token response, so fetch it separately\n const tempSession = {\n user: data.user || { id: '', email: '', firstName: '', lastName: '', isEmailVerified: false, createdAt: '', updatedAt: '' },\n accessToken: data.access,\n expiresAt,\n };\n\n this.session = tempSession;\n\n // Fetch user data if not included in login response\n if (!data.user) {\n try {\n const user = await this.getCurrentUser();\n this.session.user = user;\n } catch (error) {\n console.error('Failed to fetch user data after login:', error);\n // Continue anyway - some user data is better than none\n }\n }\n\n this.startRefreshTimer();\n return this.session;\n }\n\n /**\n * Logout and clear session\n */\n async logout(): Promise<void> {\n try {\n await fetch(`${this.config.apiBaseUrl}/api/v1/auth/logout/`, {\n method: 'POST',\n headers: this.getAuthHeaders(),\n credentials: 'include',\n });\n } catch (error) {\n console.error('Logout error:', error);\n } finally {\n this.clearSession();\n }\n }\n\n /**\n * Refresh access token using refresh token cookie\n */\n async refreshToken(): Promise<string> {\n // Prevent multiple simultaneous refresh requests\n if (this.isRefreshing && this.refreshPromise) {\n return this.refreshPromise;\n }\n\n this.isRefreshing = true;\n this.refreshPromise = this.performTokenRefresh();\n\n try {\n const newToken = await this.refreshPromise;\n return newToken;\n } finally {\n this.isRefreshing = false;\n this.refreshPromise = null;\n }\n }\n\n private async performTokenRefresh(): Promise<string> {\n const response = await fetch(`${this.config.apiBaseUrl}/api/v1/auth/token/refresh/`, {\n method: 'POST',\n headers: { 'Content-Type': 'application/json' },\n credentials: 'include', // Send refresh token cookie\n });\n\n if (!response.ok) {\n this.clearSession();\n this.config.onSessionExpired();\n throw new Error('Token refresh failed');\n }\n\n const data: RefreshResponse = await response.json();\n const expiresAt = getTokenExpiresAt(data.access);\n\n if (!expiresAt) {\n throw new Error('Invalid token received');\n }\n\n if (this.session) {\n this.session.accessToken = data.access;\n this.session.expiresAt = expiresAt;\n }\n\n this.startRefreshTimer();\n return data.access;\n }\n\n /**\n * Get current user data from backend\n */\n async getCurrentUser(): Promise<AuthUser> {\n const response = await fetch(`${this.config.apiBaseUrl}/api/v1/auth/me/`, {\n headers: this.getAuthHeaders(),\n credentials: 'include',\n });\n\n if (!response.ok) {\n if (response.status === 401) {\n this.config.onUnauthorized();\n }\n throw new Error('Failed to fetch user data');\n }\n\n const data = await response.json();\n const raw = data.user || data;\n const user: AuthUser = {\n id: raw.id,\n email: raw.email,\n firstName: raw.first_name || raw.firstName || '',\n lastName: raw.last_name || raw.lastName || '',\n isEmailVerified: raw.is_email_verified ?? raw.isEmailVerified ?? false,\n createdAt: raw.created_at || raw.createdAt || '',\n updatedAt: raw.updated_at || raw.updatedAt || '',\n };\n\n if (this.session) {\n this.session.user = user;\n }\n\n return user;\n }\n\n /**\n * Get current session\n */\n getSession(): Session | null {\n if (!this.session) {\n return null;\n }\n\n if (isTokenExpired(this.session.accessToken)) {\n this.clearSession();\n this.config.onSessionExpired();\n return null;\n }\n\n return this.session;\n }\n\n /**\n * Set session (for SSR/hydration)\n */\n setSession(session: Session): void {\n this.session = session;\n this.startRefreshTimer();\n }\n\n /**\n * Get auth headers for API requests\n */\n getAuthHeaders(): Record<string, string> {\n const session = this.getSession();\n if (!session) {\n return {};\n }\n\n return {\n Authorization: `Bearer ${session.accessToken}`,\n };\n }\n\n /**\n * Get valid access token (refreshes if needed)\n */\n async getAccessToken(): Promise<string | null> {\n const session = this.getSession();\n if (!session) {\n return null;\n }\n\n if (shouldRefreshToken(session.accessToken)) {\n try {\n return await this.refreshToken();\n } catch (error) {\n console.error('Token refresh failed:', error);\n return null;\n }\n }\n\n return session.accessToken;\n }\n\n /**\n * Start automatic token refresh timer\n */\n private startRefreshTimer(): void {\n if (this.refreshTimer) {\n clearInterval(this.refreshTimer);\n }\n\n this.refreshTimer = setInterval(() => {\n const session = this.getSession();\n if (session && shouldRefreshToken(session.accessToken)) {\n this.refreshToken().catch((error) => {\n console.error('Auto-refresh failed:', error);\n });\n }\n }, this.config.tokenRefreshInterval);\n }\n\n /**\n * Clear session and stop refresh timer\n */\n private clearSession(): void {\n this.session = null;\n if (this.refreshTimer) {\n clearInterval(this.refreshTimer);\n this.refreshTimer = null;\n }\n }\n\n /**\n * Cleanup resources\n */\n destroy(): void {\n this.clearSession();\n }\n}\n","/**\n * React context provider for authentication\n */\n\n'use client';\n\nimport {\n createContext,\n useContext,\n useEffect,\n useState,\n useCallback,\n type ReactNode,\n} from 'react';\nimport { AuthClient } from './auth-client';\nimport type { AuthConfig, AuthState, Session, AuthUser } from '../types';\n\ninterface AuthContextValue extends AuthState {\n login: (email: string, password: string) => Promise<void>;\n logout: () => Promise<void>;\n refreshUser: () => Promise<void>;\n getAccessToken: () => Promise<string | null>;\n}\n\nconst AuthContext = createContext<AuthContextValue | undefined>(undefined);\n\ninterface AuthProviderProps {\n children: ReactNode;\n config: AuthConfig;\n initialSession?: Session | null;\n}\n\nexport function AuthProvider({\n children,\n config,\n initialSession,\n}: AuthProviderProps) {\n const [authClient] = useState(() => new AuthClient(config));\n const [state, setState] = useState<AuthState>(() => ({\n session: initialSession || null,\n isLoading: !initialSession,\n isAuthenticated: !!initialSession,\n }));\n\n // Initialize session from SSR or check for existing session\n useEffect(() => {\n if (initialSession) {\n authClient.setSession(initialSession);\n setState({\n session: initialSession,\n isLoading: false,\n isAuthenticated: true,\n });\n } else {\n // Try to get session from client\n const session = authClient.getSession();\n setState({\n session,\n isLoading: false,\n isAuthenticated: !!session,\n });\n }\n }, [authClient, initialSession]);\n\n // Session expiration handler\n useEffect(() => {\n const originalOnExpired = config.onSessionExpired;\n config.onSessionExpired = () => {\n setState({\n session: null,\n isLoading: false,\n isAuthenticated: false,\n });\n originalOnExpired?.();\n };\n\n return () => {\n authClient.destroy();\n };\n }, [authClient, config]);\n\n const login = useCallback(\n async (email: string, password: string) => {\n setState((prev) => ({ ...prev, isLoading: true }));\n\n try {\n const session = await authClient.login(email, password);\n setState({\n session,\n isLoading: false,\n isAuthenticated: true,\n });\n } catch (error) {\n setState((prev) => ({ ...prev, isLoading: false }));\n throw error;\n }\n },\n [authClient]\n );\n\n const logout = useCallback(async () => {\n setState((prev) => ({ ...prev, isLoading: true }));\n\n try {\n await authClient.logout();\n } finally {\n setState({\n session: null,\n isLoading: false,\n isAuthenticated: false,\n });\n }\n }, [authClient]);\n\n const refreshUser = useCallback(async () => {\n try {\n const user = await authClient.getCurrentUser();\n setState((prev) => ({\n ...prev,\n session: prev.session\n ? { ...prev.session, user }\n : null,\n }));\n } catch (error) {\n console.error('Failed to refresh user:', error);\n }\n }, [authClient]);\n\n const getAccessToken = useCallback(async () => {\n return authClient.getAccessToken();\n }, [authClient]);\n\n const value: AuthContextValue = {\n ...state,\n login,\n logout,\n refreshUser,\n getAccessToken,\n };\n\n return <AuthContext.Provider value={value}>{children}</AuthContext.Provider>;\n}\n\n/**\n * Hook to access auth context\n */\nexport function useAuthContext(): AuthContextValue {\n const context = useContext(AuthContext);\n if (!context) {\n throw new Error('useAuthContext must be used within AuthProvider');\n }\n return context;\n}\n","/**\n * React hook for authentication\n */\n\n'use client';\n\nimport { useAuthContext } from './auth-context';\nimport type { AuthUser, Session } from '../types';\n\nexport interface UseAuthReturn {\n user: AuthUser | null;\n session: Session | null;\n isLoading: boolean;\n isAuthenticated: boolean;\n login: (email: string, password: string) => Promise<void>;\n logout: () => Promise<void>;\n refreshUser: () => Promise<void>;\n getAccessToken: () => Promise<string | null>;\n}\n\n/**\n * Hook to access authentication state and methods\n */\nexport function useAuth(): UseAuthReturn {\n const {\n session,\n isLoading,\n isAuthenticated,\n login,\n logout,\n refreshUser,\n getAccessToken,\n } = useAuthContext();\n\n return {\n user: session?.user || null,\n session,\n isLoading,\n isAuthenticated,\n login,\n logout,\n refreshUser,\n getAccessToken,\n };\n}\n","/**\n * React hook for permission checks\n */\n\n'use client';\n\nimport { useMemo } from 'react';\nimport { useAuth } from './use-auth';\nimport type { CompanyRole } from '../types';\nimport { hasRolePermission } from '../types';\n\nexport interface UsePermissionsReturn {\n hasRole: (requiredRole: CompanyRole, companyId?: string) => boolean;\n isOwner: (companyId?: string) => boolean;\n isAdmin: (companyId?: string) => boolean;\n canEdit: (companyId?: string) => boolean;\n canView: (companyId?: string) => boolean;\n currentRole: CompanyRole | null;\n currentCompanyId: string | null;\n}\n\n/**\n * Hook to check user permissions\n */\nexport function usePermissions(): UsePermissionsReturn {\n const { user } = useAuth();\n\n const currentCompanyId = user?.currentCompanyId || null;\n\n const currentCompany = useMemo(() => {\n if (!user?.companies || !currentCompanyId) {\n return null;\n }\n return user.companies.find((c) => c.id === currentCompanyId);\n }, [user, currentCompanyId]);\n\n const currentRole = currentCompany?.role || null;\n\n const hasRole = (requiredRole: CompanyRole, companyId?: string): boolean => {\n if (!user?.companies) {\n return false;\n }\n\n const targetCompanyId = companyId || currentCompanyId;\n if (!targetCompanyId) {\n return false;\n }\n\n const company = user.companies.find((c) => c.id === targetCompanyId);\n if (!company) {\n return false;\n }\n\n return hasRolePermission(company.role, requiredRole);\n };\n\n const isOwner = (companyId?: string): boolean => {\n return hasRole('owner', companyId);\n };\n\n const isAdmin = (companyId?: string): boolean => {\n return hasRole('admin', companyId);\n };\n\n const canEdit = (companyId?: string): boolean => {\n return hasRole('member', companyId);\n };\n\n const canView = (companyId?: string): boolean => {\n return hasRole('viewer', companyId);\n };\n\n return {\n hasRole,\n isOwner,\n isAdmin,\n canEdit,\n canView,\n currentRole,\n currentCompanyId,\n };\n}\n","/**\n * Functional auth API for Django backend\n *\n * Stateless functions for authentication flows: sign in, register, OAuth, token refresh, etc.\n * Uses fetch (browser/Node) and getCsrfToken from shared utils.\n * No Next.js dependency.\n */\n\nimport { getCsrfToken } from '../utils/cookies';\n\n// --- Types ---\n\nexport interface AuthUser {\n id: string;\n email: string;\n name?: string | null;\n firstName?: string | null;\n lastName?: string | null;\n groups?: string[];\n permissions?: string[];\n isActive?: boolean;\n isEmailVerified?: boolean;\n}\n\n// --- Endpoint paths (Django backend defaults) ---\n\nconst API_BASE = '/api/v1';\n\nconst AUTH_PATHS = {\n TOKEN: `${API_BASE}/auth/token/`,\n TOKEN_REFRESH: `${API_BASE}/auth/token/refresh/`,\n REGISTER: `${API_BASE}/auth/register/`,\n LOGOUT: `${API_BASE}/auth/logout/`,\n FORGOT_PASSWORD: `${API_BASE}/auth/forgot-password/`,\n RESET_PASSWORD: `${API_BASE}/auth/reset-password/`,\n VERIFY_EMAIL: `${API_BASE}/auth/verify-email/`,\n RESEND_VERIFICATION: `${API_BASE}/auth/resend-verification/`,\n OAUTH_GOOGLE_INITIATE: `${API_BASE}/auth/oauth/google/initiate/`,\n OAUTH_GOOGLE_CALLBACK: `${API_BASE}/auth/oauth/google/callback/`,\n ME: `${API_BASE}/auth/me/`,\n} as const;\n\n// --- Base URL resolution ---\n\nconst AUTH_BASE_URL =\n (typeof process !== 'undefined' &&\n (process.env.NEXT_PUBLIC_API_URL || process.env.NEXT_PUBLIC_API_BASE_URL)) ||\n '';\nconst AUTH_BASE_IS_ABSOLUTE = /^https?:\\/\\//i.test(AUTH_BASE_URL);\n\nfunction isAbsoluteUrl(url: string) {\n return /^https?:\\/\\//i.test(url);\n}\n\nexport function resolveAuthUrl(path: string): string {\n if (isAbsoluteUrl(path)) return path;\n\n const normalized = path.startsWith('/') ? path : `/${path}`;\n if (AUTH_BASE_IS_ABSOLUTE) {\n return new URL(normalized, AUTH_BASE_URL).toString();\n }\n if (normalized.startsWith('/api/')) return normalized;\n if (!AUTH_BASE_URL) return normalized;\n\n if (AUTH_BASE_URL.endsWith('/') && normalized.startsWith('/')) {\n return `${AUTH_BASE_URL.slice(0, -1)}${normalized}`;\n }\n\n return `${AUTH_BASE_URL}${normalized}`;\n}\n\n// --- Token storage ---\n// Uses sessionStorage when available (browser) so the token is scoped to the\n// current tab and cleared automatically when the tab closes. Falls back to a\n// module-level variable for SSR environments where sessionStorage is absent.\n\nconst TOKEN_STORAGE_KEY = 'auth_access_token';\n\nlet _memToken: string | null = null;\n\nfunction _sessionStorageAvailable(): boolean {\n try {\n return typeof window !== 'undefined' && !!window.sessionStorage;\n } catch {\n return false;\n }\n}\n\nexport function getAccessToken(): string | null {\n if (_sessionStorageAvailable()) {\n return sessionStorage.getItem(TOKEN_STORAGE_KEY);\n }\n return _memToken;\n}\n\nexport function setAccessToken(token: string | null): void {\n if (_sessionStorageAvailable()) {\n if (token === null) {\n sessionStorage.removeItem(TOKEN_STORAGE_KEY);\n } else {\n sessionStorage.setItem(TOKEN_STORAGE_KEY, token);\n }\n return;\n }\n _memToken = token;\n}\n\n// --- Internal helpers ---\n\nconst AUTH_TIMEOUT_MS = 15_000;\n\n/** Extract a human-readable message from a Django REST Framework error response body. */\nfunction extractApiError(d: Record<string, unknown>, fallback: string): string {\n // Standard DRF: { detail: \"...\" }\n if (typeof d.detail === 'string') return d.detail\n // Field-level: { email: [\"already exists\"] } or { non_field_errors: [\"...\"] }\n for (const val of Object.values(d)) {\n if (typeof val === 'string') return val\n if (Array.isArray(val) && val.length > 0 && typeof val[0] === 'string') return val[0]\n }\n return fallback\n}\n\nfunction fetchWithTimeout(url: string, options: RequestInit): Promise<Response> {\n const controller = new AbortController();\n const timer = setTimeout(() => controller.abort(), AUTH_TIMEOUT_MS);\n return fetch(url, { ...options, signal: controller.signal }).finally(() =>\n clearTimeout(timer)\n );\n}\n\nfunction normalizeUser(raw: unknown): AuthUser | null {\n if (!raw || typeof raw !== 'object') return null;\n const obj = raw as Record<string, unknown>;\n const payload = (obj.user && typeof obj.user === 'object' ? obj.user : obj) as Record<string, unknown>;\n if (!payload?.id || !payload?.email) return null;\n\n const firstName = (payload.first_name ?? payload.firstName ?? null) as string | null;\n const lastName = (payload.last_name ?? payload.lastName ?? null) as string | null;\n const name =\n (payload.name as string | null) ??\n ([firstName, lastName].filter(Boolean).join(' ') || null);\n\n return {\n id: payload.id as string,\n email: payload.email as string,\n name,\n firstName,\n lastName,\n groups: Array.isArray(payload.groups) ? (payload.groups as string[]) : [],\n permissions: Array.isArray(payload.permissions) ? (payload.permissions as string[]) : [],\n isActive: (payload.isActive ?? payload.is_active) as boolean | undefined,\n isEmailVerified: (payload.isEmailVerified ?? payload.is_email_verified) as boolean | undefined,\n };\n}\n\nfunction parseAuthResponse(data: unknown): { access?: string; user?: AuthUser } {\n if (!data || typeof data !== 'object') return {};\n const obj = data as Record<string, unknown>;\n const payload = (obj.data && typeof obj.data === 'object' ? obj.data : obj) as Record<string, unknown>;\n const access = (payload.access || payload.access_token || payload.token) as string | undefined;\n const userRaw = payload.user || payload.me || payload.profile || payload;\n const user = normalizeUser(userRaw);\n return { access, user: user ?? undefined };\n}\n\n// --- Auth functions ---\n\nexport async function signInWithCredentials(email: string, password: string) {\n const response = await fetchWithTimeout(resolveAuthUrl(AUTH_PATHS.TOKEN), {\n method: 'POST',\n headers: { 'Content-Type': 'application/json' },\n credentials: 'include',\n body: JSON.stringify({ email, password }),\n });\n\n const data = await response.json().catch(() => ({}));\n\n if (!response.ok) {\n const d = data as Record<string, unknown>;\n if (d?.error === 'ACCOUNT_LOCKED' && d?.locked_until) {\n throw new Error(`Account locked until ${new Date(d.locked_until as string).toLocaleTimeString()}`);\n }\n const message = (d?.detail || d?.error || 'Authentication failed') as string;\n throw new Error(message);\n }\n\n const parsed = parseAuthResponse(data);\n if (parsed.access) {\n setAccessToken(parsed.access);\n }\n\n return parsed;\n}\n\nexport async function registerAccount(payload: {\n email: string;\n password: string;\n passwordConfirm: string;\n name?: string;\n firstName?: string;\n lastName?: string;\n}) {\n const rawName = payload.name?.trim() || '';\n const [firstFromName, ...rest] = rawName ? rawName.split(/\\s+/) : [];\n const lastFromName = rest.length ? rest.join(' ') : undefined;\n\n const response = await fetchWithTimeout(resolveAuthUrl(AUTH_PATHS.REGISTER), {\n method: 'POST',\n headers: { 'Content-Type': 'application/json' },\n credentials: 'include',\n body: JSON.stringify({\n email: payload.email,\n password: payload.password,\n password_confirm: payload.passwordConfirm,\n first_name: payload.firstName ?? firstFromName ?? undefined,\n last_name: payload.lastName ?? lastFromName ?? undefined,\n }),\n });\n\n const data = await response.json().catch(() => ({}));\n\n if (!response.ok) {\n throw new Error(extractApiError(data as Record<string, unknown>, 'Registration failed'));\n }\n\n const parsed = parseAuthResponse(data);\n if (parsed.access) {\n setAccessToken(parsed.access);\n }\n\n return parsed;\n}\n\nexport async function requestPasswordReset(email: string): Promise<void> {\n const response = await fetch(resolveAuthUrl(AUTH_PATHS.FORGOT_PASSWORD), {\n method: 'POST',\n headers: { 'Content-Type': 'application/json' },\n body: JSON.stringify({ email }),\n });\n\n if (!response.ok) {\n const data = await response.json().catch(() => ({}));\n const d = data as Record<string, unknown>;\n const message = (d?.detail || d?.error || 'Failed to send reset link') as string;\n throw new Error(message);\n }\n}\n\nexport async function resetPassword(payload: {\n token: string;\n password: string;\n passwordConfirm: string;\n email?: string;\n}): Promise<void> {\n const response = await fetchWithTimeout(resolveAuthUrl(AUTH_PATHS.RESET_PASSWORD), {\n method: 'POST',\n headers: { 'Content-Type': 'application/json' },\n body: JSON.stringify({\n token: payload.token,\n password: payload.password,\n password_confirm: payload.passwordConfirm,\n ...(payload.email ? { email: payload.email } : {}),\n }),\n });\n\n if (!response.ok) {\n const data = await response.json().catch(() => ({}));\n const d = data as Record<string, unknown>;\n const message = (d?.detail || d?.error || 'Failed to reset password') as string;\n throw new Error(message);\n }\n}\n\nexport async function verifyEmail(token: string): Promise<void> {\n const response = await fetchWithTimeout(resolveAuthUrl(AUTH_PATHS.VERIFY_EMAIL), {\n method: 'POST',\n headers: { 'Content-Type': 'application/json' },\n body: JSON.stringify({ token }),\n });\n\n if (!response.ok) {\n const data = await response.json().catch(() => ({}));\n const d = data as Record<string, unknown>;\n const message = (d?.detail || d?.error || 'Failed to verify email') as string;\n throw new Error(message);\n }\n}\n\nexport async function resendVerification(access?: string | null): Promise<void> {\n const response = await fetch(resolveAuthUrl(AUTH_PATHS.RESEND_VERIFICATION), {\n method: 'POST',\n headers: {\n 'Content-Type': 'application/json',\n ...(access ? { Authorization: `Bearer ${access}` } : {}),\n },\n credentials: 'include',\n });\n\n if (!response.ok) {\n const data = await response.json().catch(() => ({}));\n const d = data as Record<string, unknown>;\n const message = (d?.detail || d?.error || 'Failed to resend verification email') as string;\n throw new Error(message);\n }\n}\n\n// eslint-disable-next-line @typescript-eslint/no-explicit-any\nexport async function initiateGoogleOAuth(redirectUri: string): Promise<any> {\n const response = await fetch(resolveAuthUrl(AUTH_PATHS.OAUTH_GOOGLE_INITIATE), {\n method: 'POST',\n headers: { 'Content-Type': 'application/json' },\n credentials: 'include',\n body: JSON.stringify({ redirect_uri: redirectUri }),\n });\n\n const data = await response.json().catch(() => ({}));\n\n if (!response.ok) {\n const d = data as Record<string, unknown>;\n const message = (d?.detail || d?.error || 'Failed to initiate Google OAuth') as string;\n throw new Error(message);\n }\n\n return data;\n}\n\nexport async function completeGoogleOAuth(code: string, state: string) {\n const response = await fetchWithTimeout(\n resolveAuthUrl(\n `${AUTH_PATHS.OAUTH_GOOGLE_CALLBACK}?code=${encodeURIComponent(code)}&state=${encodeURIComponent(state)}`\n ),\n { credentials: 'include' }\n );\n\n const data = await response.json().catch(() => ({}));\n\n if (!response.ok) {\n const d = data as Record<string, unknown>;\n const message = (d?.detail || d?.error || 'OAuth authentication failed') as string;\n throw new Error(message);\n }\n\n const parsed = parseAuthResponse(data);\n if (parsed.access) {\n setAccessToken(parsed.access);\n }\n\n return parsed;\n}\n\nasync function fetchCsrfToken(): Promise<void> {\n if (getCsrfToken()) return;\n try {\n await fetch(resolveAuthUrl(`${API_BASE}/auth/csrf/`), {\n credentials: 'include',\n cache: 'no-store',\n });\n } catch (err) {\n console.warn('[auth] CSRF token fetch failed — token refresh will fail:', err)\n }\n}\n\nexport async function refreshAccessToken(): Promise<string | null> {\n await fetchCsrfToken();\n const csrfToken = getCsrfToken();\n if (!csrfToken) return null;\n\n const response = await fetchWithTimeout(resolveAuthUrl(AUTH_PATHS.TOKEN_REFRESH), {\n method: 'POST',\n headers: {\n 'Content-Type': 'application/json',\n 'X-CSRFToken': csrfToken,\n },\n credentials: 'include',\n });\n\n const data = await response.json().catch(() => ({}));\n\n if (!response.ok) {\n return null;\n }\n\n const parsed = parseAuthResponse(data);\n if (parsed.access) {\n setAccessToken(parsed.access);\n return parsed.access;\n }\n\n return null;\n}\n\nexport async function getMe(): Promise<AuthUser | null> {\n const token = getAccessToken();\n if (!token) return null;\n\n const response = await fetch(resolveAuthUrl(AUTH_PATHS.ME), {\n headers: {\n Authorization: `Bearer ${token}`,\n },\n credentials: 'include',\n cache: 'no-store',\n });\n\n if (!response.ok) {\n return null;\n }\n\n const data = await response.json().catch(() => ({}));\n const obj = data as Record<string, unknown>;\n const payload = obj.data && typeof obj.data === 'object' ? obj.data : obj;\n const userRaw = (payload as Record<string, unknown>).user || payload;\n return normalizeUser(userRaw);\n}\n\nexport async function signOut(): Promise<void> {\n const csrfToken = getCsrfToken();\n const token = getAccessToken();\n\n try {\n await fetch(resolveAuthUrl(AUTH_PATHS.LOGOUT), {\n method: 'POST',\n headers: {\n 'Content-Type': 'application/json',\n ...(csrfToken ? { 'X-CSRFToken': csrfToken } : {}),\n ...(token ? { Authorization: `Bearer ${token}` } : {}),\n },\n credentials: 'include',\n });\n } finally {\n setAccessToken(null);\n }\n}\n\n// Singleton refresh promise — ensures concurrent 401s share one refresh call\nlet _refreshPromise: Promise<string | null> | null = null;\n\nfunction _refreshOnce(): Promise<string | null> {\n if (!_refreshPromise) {\n _refreshPromise = refreshAccessToken().finally(() => {\n _refreshPromise = null;\n });\n }\n return _refreshPromise;\n}\n\nexport async function authFetch(\n input: RequestInfo | URL,\n init: RequestInit = {}\n): Promise<Response> {\n const token = getAccessToken();\n const headers = new Headers(init.headers || {});\n\n if (token && !headers.has('Authorization')) {\n headers.set('Authorization', `Bearer ${token}`);\n }\n\n const resolvedInput = typeof input === 'string' ? resolveAuthUrl(input) : input;\n\n const response = await fetch(resolvedInput, {\n ...init,\n headers,\n credentials: init.credentials ?? 'include',\n });\n\n if (response.status === 401) {\n const refreshed = await _refreshOnce();\n if (refreshed) {\n const retryHeaders = new Headers(init.headers || {});\n retryHeaders.set('Authorization', `Bearer ${refreshed}`);\n\n return fetch(resolvedInput, {\n ...init,\n headers: retryHeaders,\n credentials: init.credentials ?? 'include',\n });\n }\n }\n\n return response;\n}\n\nexport function hasPermission(user: AuthUser | null | undefined, permission: string): boolean {\n if (!user) return false;\n if (!user.permissions || user.permissions.length === 0) return false;\n return user.permissions.includes(permission);\n}\n\nexport function hasGroup(user: AuthUser | null | undefined, group: string): boolean {\n if (!user) return false;\n if (!user.groups || user.groups.length === 0) return false;\n return user.groups.includes(group);\n}\n"]}
1
+ {"version":3,"sources":["../src/client/auth-client.ts","../src/client/auth-context.tsx","../src/client/use-auth.ts","../src/client/use-permissions.ts","../src/client/functions.ts"],"names":["getAccessToken"],"mappings":"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","file":"chunk-VIG3K6ZR.mjs","sourcesContent":["/**\n * Client-side authentication manager\n * Handles JWT tokens, login/logout, and token refresh\n */\n\nimport type {\n AuthConfig,\n Session,\n LoginResponse,\n RefreshResponse,\n AuthUser,\n} from '../types';\nimport { isTokenExpired, getTokenExpiresAt, shouldRefreshToken } from '../utils';\n\nexport class AuthClient {\n private config: Required<AuthConfig>;\n private session: Session | null = null;\n private refreshTimer: NodeJS.Timeout | null = null;\n private isRefreshing = false;\n private refreshPromise: Promise<string> | null = null;\n\n constructor(config: AuthConfig) {\n this.config = {\n tokenRefreshInterval: 4 * 60 * 1000, // 4 minutes\n onSessionExpired: () => {},\n onUnauthorized: () => {},\n ...config,\n };\n }\n\n /**\n * Login with email and password\n */\n async login(email: string, password: string): Promise<Session> {\n const response = await fetch(`${this.config.apiBaseUrl}/api/v1/auth/token/`, {\n method: 'POST',\n headers: { 'Content-Type': 'application/json' },\n credentials: 'include', // Include cookies for refresh token\n body: JSON.stringify({ email, password }),\n });\n\n if (!response.ok) {\n const error = await response.json().catch(() => ({ detail: 'Login failed' }));\n throw new Error(error.detail || 'Login failed');\n }\n\n const data: any = await response.json();\n const expiresAt = getTokenExpiresAt(data.access);\n\n if (!expiresAt) {\n throw new Error('Invalid token received');\n }\n\n // Django might not include user in token response, so fetch it separately\n const tempSession = {\n user: data.user || { id: '', email: '', firstName: '', lastName: '', isEmailVerified: false, createdAt: '', updatedAt: '' },\n accessToken: data.access,\n expiresAt,\n };\n\n this.session = tempSession;\n\n // Fetch user data if not included in login response\n if (!data.user) {\n try {\n const user = await this.getCurrentUser();\n this.session.user = user;\n } catch (error) {\n console.error('Failed to fetch user data after login:', error);\n // Continue anyway - some user data is better than none\n }\n }\n\n this.startRefreshTimer();\n return this.session;\n }\n\n /**\n * Logout and clear session\n */\n async logout(): Promise<void> {\n try {\n await fetch(`${this.config.apiBaseUrl}/api/v1/auth/logout/`, {\n method: 'POST',\n headers: this.getAuthHeaders(),\n credentials: 'include',\n });\n } catch (error) {\n console.error('Logout error:', error);\n } finally {\n this.clearSession();\n }\n }\n\n /**\n * Refresh access token using refresh token cookie\n */\n async refreshToken(): Promise<string> {\n // Prevent multiple simultaneous refresh requests\n if (this.isRefreshing && this.refreshPromise) {\n return this.refreshPromise;\n }\n\n this.isRefreshing = true;\n this.refreshPromise = this.performTokenRefresh();\n\n try {\n const newToken = await this.refreshPromise;\n return newToken;\n } finally {\n this.isRefreshing = false;\n this.refreshPromise = null;\n }\n }\n\n private async performTokenRefresh(): Promise<string> {\n const response = await fetch(`${this.config.apiBaseUrl}/api/v1/auth/token/refresh/`, {\n method: 'POST',\n headers: { 'Content-Type': 'application/json' },\n credentials: 'include', // Send refresh token cookie\n });\n\n if (!response.ok) {\n this.clearSession();\n this.config.onSessionExpired();\n throw new Error('Token refresh failed');\n }\n\n const data: RefreshResponse = await response.json();\n const expiresAt = getTokenExpiresAt(data.access);\n\n if (!expiresAt) {\n throw new Error('Invalid token received');\n }\n\n if (this.session) {\n this.session.accessToken = data.access;\n this.session.expiresAt = expiresAt;\n }\n\n this.startRefreshTimer();\n return data.access;\n }\n\n /**\n * Get current user data from backend\n */\n async getCurrentUser(): Promise<AuthUser> {\n const response = await fetch(`${this.config.apiBaseUrl}/api/v1/auth/me/`, {\n headers: this.getAuthHeaders(),\n credentials: 'include',\n });\n\n if (!response.ok) {\n if (response.status === 401) {\n this.config.onUnauthorized();\n }\n throw new Error('Failed to fetch user data');\n }\n\n const data = await response.json();\n const raw = data.user || data;\n const user: AuthUser = {\n id: raw.id,\n email: raw.email,\n firstName: raw.first_name || raw.firstName || '',\n lastName: raw.last_name || raw.lastName || '',\n isEmailVerified: raw.is_email_verified ?? raw.isEmailVerified ?? false,\n createdAt: raw.created_at || raw.createdAt || '',\n updatedAt: raw.updated_at || raw.updatedAt || '',\n };\n\n if (this.session) {\n this.session.user = user;\n }\n\n return user;\n }\n\n /**\n * Get current session\n */\n getSession(): Session | null {\n if (!this.session) {\n return null;\n }\n\n if (isTokenExpired(this.session.accessToken)) {\n this.clearSession();\n this.config.onSessionExpired();\n return null;\n }\n\n return this.session;\n }\n\n /**\n * Set session (for SSR/hydration)\n */\n setSession(session: Session): void {\n this.session = session;\n this.startRefreshTimer();\n }\n\n /**\n * Get auth headers for API requests\n */\n getAuthHeaders(): Record<string, string> {\n const session = this.getSession();\n if (!session) {\n return {};\n }\n\n return {\n Authorization: `Bearer ${session.accessToken}`,\n };\n }\n\n /**\n * Get valid access token (refreshes if needed)\n */\n async getAccessToken(): Promise<string | null> {\n const session = this.getSession();\n if (!session) {\n return null;\n }\n\n if (shouldRefreshToken(session.accessToken)) {\n try {\n return await this.refreshToken();\n } catch (error) {\n console.error('Token refresh failed:', error);\n return null;\n }\n }\n\n return session.accessToken;\n }\n\n /**\n * Start automatic token refresh timer\n */\n private startRefreshTimer(): void {\n if (this.refreshTimer) {\n clearInterval(this.refreshTimer);\n }\n\n this.refreshTimer = setInterval(() => {\n const session = this.getSession();\n if (session && shouldRefreshToken(session.accessToken)) {\n this.refreshToken().catch((error) => {\n console.error('Auto-refresh failed:', error);\n });\n }\n }, this.config.tokenRefreshInterval);\n }\n\n /**\n * Clear session and stop refresh timer\n */\n private clearSession(): void {\n this.session = null;\n if (this.refreshTimer) {\n clearInterval(this.refreshTimer);\n this.refreshTimer = null;\n }\n }\n\n /**\n * Cleanup resources\n */\n destroy(): void {\n this.clearSession();\n }\n}\n","/**\n * React context provider for authentication\n */\n\n'use client';\n\nimport {\n createContext,\n useContext,\n useEffect,\n useState,\n useCallback,\n type ReactNode,\n} from 'react';\nimport { AuthClient } from './auth-client';\nimport type { AuthConfig, AuthState, Session, AuthUser } from '../types';\n\ninterface AuthContextValue extends AuthState {\n login: (email: string, password: string) => Promise<void>;\n logout: () => Promise<void>;\n refreshUser: () => Promise<void>;\n getAccessToken: () => Promise<string | null>;\n}\n\nconst AuthContext = createContext<AuthContextValue | undefined>(undefined);\n\ninterface AuthProviderProps {\n children: ReactNode;\n config: AuthConfig;\n initialSession?: Session | null;\n}\n\nexport function AuthProvider({\n children,\n config,\n initialSession,\n}: AuthProviderProps) {\n const [authClient] = useState(() => new AuthClient(config));\n const [state, setState] = useState<AuthState>(() => ({\n session: initialSession || null,\n isLoading: !initialSession,\n isAuthenticated: !!initialSession,\n }));\n\n // Initialize session from SSR or check for existing session\n useEffect(() => {\n if (initialSession) {\n authClient.setSession(initialSession);\n setState({\n session: initialSession,\n isLoading: false,\n isAuthenticated: true,\n });\n } else {\n // Try to get session from client\n const session = authClient.getSession();\n setState({\n session,\n isLoading: false,\n isAuthenticated: !!session,\n });\n }\n }, [authClient, initialSession]);\n\n // Session expiration handler\n useEffect(() => {\n const originalOnExpired = config.onSessionExpired;\n config.onSessionExpired = () => {\n setState({\n session: null,\n isLoading: false,\n isAuthenticated: false,\n });\n originalOnExpired?.();\n };\n\n return () => {\n authClient.destroy();\n };\n }, [authClient, config]);\n\n const login = useCallback(\n async (email: string, password: string) => {\n setState((prev) => ({ ...prev, isLoading: true }));\n\n try {\n const session = await authClient.login(email, password);\n setState({\n session,\n isLoading: false,\n isAuthenticated: true,\n });\n } catch (error) {\n setState((prev) => ({ ...prev, isLoading: false }));\n throw error;\n }\n },\n [authClient]\n );\n\n const logout = useCallback(async () => {\n setState((prev) => ({ ...prev, isLoading: true }));\n\n try {\n await authClient.logout();\n } finally {\n setState({\n session: null,\n isLoading: false,\n isAuthenticated: false,\n });\n }\n }, [authClient]);\n\n const refreshUser = useCallback(async () => {\n try {\n const user = await authClient.getCurrentUser();\n setState((prev) => ({\n ...prev,\n session: prev.session\n ? { ...prev.session, user }\n : null,\n }));\n } catch (error) {\n console.error('Failed to refresh user:', error);\n }\n }, [authClient]);\n\n const getAccessToken = useCallback(async () => {\n return authClient.getAccessToken();\n }, [authClient]);\n\n const value: AuthContextValue = {\n ...state,\n login,\n logout,\n refreshUser,\n getAccessToken,\n };\n\n return <AuthContext.Provider value={value}>{children}</AuthContext.Provider>;\n}\n\n/**\n * Hook to access auth context\n */\nexport function useAuthContext(): AuthContextValue {\n const context = useContext(AuthContext);\n if (!context) {\n throw new Error('useAuthContext must be used within AuthProvider');\n }\n return context;\n}\n","/**\n * React hook for authentication\n */\n\n'use client';\n\nimport { useAuthContext } from './auth-context';\nimport type { AuthUser, Session } from '../types';\n\nexport interface UseAuthReturn {\n user: AuthUser | null;\n session: Session | null;\n isLoading: boolean;\n isAuthenticated: boolean;\n login: (email: string, password: string) => Promise<void>;\n logout: () => Promise<void>;\n refreshUser: () => Promise<void>;\n getAccessToken: () => Promise<string | null>;\n}\n\n/**\n * Hook to access authentication state and methods\n */\nexport function useAuth(): UseAuthReturn {\n const {\n session,\n isLoading,\n isAuthenticated,\n login,\n logout,\n refreshUser,\n getAccessToken,\n } = useAuthContext();\n\n return {\n user: session?.user || null,\n session,\n isLoading,\n isAuthenticated,\n login,\n logout,\n refreshUser,\n getAccessToken,\n };\n}\n","/**\n * React hook for permission checks\n */\n\n'use client';\n\nimport { useMemo } from 'react';\nimport { useAuth } from './use-auth';\nimport type { CompanyRole } from '../types';\nimport { hasRolePermission } from '../types';\n\nexport interface UsePermissionsReturn {\n hasRole: (requiredRole: CompanyRole, companyId?: string) => boolean;\n isOwner: (companyId?: string) => boolean;\n isAdmin: (companyId?: string) => boolean;\n canEdit: (companyId?: string) => boolean;\n canView: (companyId?: string) => boolean;\n currentRole: CompanyRole | null;\n currentCompanyId: string | null;\n}\n\n/**\n * Hook to check user permissions\n */\nexport function usePermissions(): UsePermissionsReturn {\n const { user } = useAuth();\n\n const currentCompanyId = user?.currentCompanyId || null;\n\n const currentCompany = useMemo(() => {\n if (!user?.companies || !currentCompanyId) {\n return null;\n }\n return user.companies.find((c) => c.id === currentCompanyId);\n }, [user, currentCompanyId]);\n\n const currentRole = currentCompany?.role || null;\n\n const hasRole = (requiredRole: CompanyRole, companyId?: string): boolean => {\n if (!user?.companies) {\n return false;\n }\n\n const targetCompanyId = companyId || currentCompanyId;\n if (!targetCompanyId) {\n return false;\n }\n\n const company = user.companies.find((c) => c.id === targetCompanyId);\n if (!company) {\n return false;\n }\n\n return hasRolePermission(company.role, requiredRole);\n };\n\n const isOwner = (companyId?: string): boolean => {\n return hasRole('owner', companyId);\n };\n\n const isAdmin = (companyId?: string): boolean => {\n return hasRole('admin', companyId);\n };\n\n const canEdit = (companyId?: string): boolean => {\n return hasRole('member', companyId);\n };\n\n const canView = (companyId?: string): boolean => {\n return hasRole('viewer', companyId);\n };\n\n return {\n hasRole,\n isOwner,\n isAdmin,\n canEdit,\n canView,\n currentRole,\n currentCompanyId,\n };\n}\n","/**\n * Functional auth API for Django backend\n *\n * Stateless functions for authentication flows: sign in, register, OAuth, token refresh, etc.\n * Uses fetch (browser/Node) and getCsrfToken from shared utils.\n * No Next.js dependency.\n */\n\nimport { getCsrfToken } from '../utils/cookies';\n\n// --- Types ---\n\nexport interface AuthUser {\n id: string;\n email: string;\n name?: string | null;\n firstName?: string | null;\n lastName?: string | null;\n groups?: string[];\n permissions?: string[];\n isActive?: boolean;\n isEmailVerified?: boolean;\n}\n\n// --- Endpoint paths (Django backend defaults) ---\n\nconst API_BASE = '/api/v1';\n\nconst AUTH_PATHS = {\n TOKEN: `${API_BASE}/auth/token/`,\n TOKEN_REFRESH: `${API_BASE}/auth/token/refresh/`,\n REGISTER: `${API_BASE}/auth/register/`,\n LOGOUT: `${API_BASE}/auth/logout/`,\n FORGOT_PASSWORD: `${API_BASE}/auth/forgot-password/`,\n RESET_PASSWORD: `${API_BASE}/auth/reset-password/`,\n VERIFY_EMAIL: `${API_BASE}/auth/verify-email/`,\n RESEND_VERIFICATION: `${API_BASE}/auth/resend-verification/`,\n OAUTH_GOOGLE_INITIATE: `${API_BASE}/auth/oauth/google/initiate/`,\n OAUTH_GOOGLE_CALLBACK: `${API_BASE}/auth/oauth/google/callback/`,\n ME: `${API_BASE}/auth/me/`,\n} as const;\n\n// --- Base URL resolution ---\n\nconst AUTH_BASE_URL =\n (typeof process !== 'undefined' &&\n (process.env.NEXT_PUBLIC_API_URL || process.env.NEXT_PUBLIC_API_BASE_URL)) ||\n '';\nconst AUTH_BASE_IS_ABSOLUTE = /^https?:\\/\\//i.test(AUTH_BASE_URL);\n\nfunction isAbsoluteUrl(url: string) {\n return /^https?:\\/\\//i.test(url);\n}\n\nexport function resolveAuthUrl(path: string): string {\n if (isAbsoluteUrl(path)) return path;\n\n const normalized = path.startsWith('/') ? path : `/${path}`;\n if (AUTH_BASE_IS_ABSOLUTE) {\n return new URL(normalized, AUTH_BASE_URL).toString();\n }\n if (normalized.startsWith('/api/')) return normalized;\n if (!AUTH_BASE_URL) return normalized;\n\n if (AUTH_BASE_URL.endsWith('/') && normalized.startsWith('/')) {\n return `${AUTH_BASE_URL.slice(0, -1)}${normalized}`;\n }\n\n return `${AUTH_BASE_URL}${normalized}`;\n}\n\n// --- Token storage ---\n// Uses sessionStorage when available (browser) so the token is scoped to the\n// current tab and cleared automatically when the tab closes. Falls back to a\n// module-level variable for SSR environments where sessionStorage is absent.\n\nconst TOKEN_STORAGE_KEY = 'auth_access_token';\n\nlet _memToken: string | null = null;\n\nfunction _sessionStorageAvailable(): boolean {\n try {\n return typeof window !== 'undefined' && !!window.sessionStorage;\n } catch {\n return false;\n }\n}\n\nexport function getAccessToken(): string | null {\n if (_sessionStorageAvailable()) {\n return sessionStorage.getItem(TOKEN_STORAGE_KEY);\n }\n return _memToken;\n}\n\nexport function setAccessToken(token: string | null): void {\n if (_sessionStorageAvailable()) {\n if (token === null) {\n sessionStorage.removeItem(TOKEN_STORAGE_KEY);\n } else {\n sessionStorage.setItem(TOKEN_STORAGE_KEY, token);\n }\n return;\n }\n _memToken = token;\n}\n\n// --- Internal helpers ---\n\nconst AUTH_TIMEOUT_MS = 15_000;\n\n/** Extract a human-readable message from a Django REST Framework error response body. */\nfunction extractApiError(d: Record<string, unknown>, fallback: string): string {\n // Standard DRF: { detail: \"...\" }\n if (typeof d.detail === 'string') return d.detail\n // Field-level: { email: [\"already exists\"] } or { non_field_errors: [\"...\"] }\n for (const val of Object.values(d)) {\n if (typeof val === 'string') return val\n if (Array.isArray(val) && val.length > 0 && typeof val[0] === 'string') return val[0]\n }\n return fallback\n}\n\nfunction fetchWithTimeout(url: string, options: RequestInit): Promise<Response> {\n const controller = new AbortController();\n const timer = setTimeout(() => controller.abort(), AUTH_TIMEOUT_MS);\n return fetch(url, { ...options, signal: controller.signal }).finally(() =>\n clearTimeout(timer)\n );\n}\n\nfunction normalizeUser(raw: unknown): AuthUser | null {\n if (!raw || typeof raw !== 'object') return null;\n const obj = raw as Record<string, unknown>;\n const payload = (obj.user && typeof obj.user === 'object' ? obj.user : obj) as Record<string, unknown>;\n if (!payload?.id || !payload?.email) return null;\n\n const firstName = (payload.first_name ?? payload.firstName ?? null) as string | null;\n const lastName = (payload.last_name ?? payload.lastName ?? null) as string | null;\n const name =\n (payload.name as string | null) ??\n ([firstName, lastName].filter(Boolean).join(' ') || null);\n\n return {\n id: payload.id as string,\n email: payload.email as string,\n name,\n firstName,\n lastName,\n groups: Array.isArray(payload.groups) ? (payload.groups as string[]) : [],\n permissions: Array.isArray(payload.permissions) ? (payload.permissions as string[]) : [],\n isActive: (payload.isActive ?? payload.is_active) as boolean | undefined,\n isEmailVerified: (payload.isEmailVerified ?? payload.is_email_verified) as boolean | undefined,\n };\n}\n\nfunction parseAuthResponse(data: unknown): { access?: string; user?: AuthUser } {\n if (!data || typeof data !== 'object') return {};\n const obj = data as Record<string, unknown>;\n const payload = (obj.data && typeof obj.data === 'object' ? obj.data : obj) as Record<string, unknown>;\n const access = (payload.access || payload.access_token || payload.token) as string | undefined;\n const userRaw = payload.user || payload.me || payload.profile || payload;\n const user = normalizeUser(userRaw);\n return { access, user: user ?? undefined };\n}\n\n// --- Auth functions ---\n\nexport async function signInWithCredentials(email: string, password: string) {\n const response = await fetchWithTimeout(resolveAuthUrl(AUTH_PATHS.TOKEN), {\n method: 'POST',\n headers: { 'Content-Type': 'application/json' },\n credentials: 'include',\n body: JSON.stringify({ email, password }),\n });\n\n const data = await response.json().catch(() => ({}));\n\n if (!response.ok) {\n const d = data as Record<string, unknown>;\n if (d?.error === 'ACCOUNT_LOCKED' && d?.locked_until) {\n throw new Error(`Account locked until ${new Date(d.locked_until as string).toLocaleTimeString()}`);\n }\n const message = (d?.detail || d?.error || 'Authentication failed') as string;\n throw new Error(message);\n }\n\n const parsed = parseAuthResponse(data);\n if (parsed.access) {\n setAccessToken(parsed.access);\n }\n\n return parsed;\n}\n\nexport async function registerAccount(payload: {\n email: string;\n password: string;\n passwordConfirm: string;\n name?: string;\n firstName?: string;\n lastName?: string;\n}) {\n const rawName = payload.name?.trim() || '';\n const [firstFromName, ...rest] = rawName ? rawName.split(/\\s+/) : [];\n const lastFromName = rest.length ? rest.join(' ') : undefined;\n\n const response = await fetchWithTimeout(resolveAuthUrl(AUTH_PATHS.REGISTER), {\n method: 'POST',\n headers: { 'Content-Type': 'application/json' },\n credentials: 'include',\n body: JSON.stringify({\n email: payload.email,\n password: payload.password,\n password_confirm: payload.passwordConfirm,\n first_name: payload.firstName ?? firstFromName ?? undefined,\n last_name: payload.lastName ?? lastFromName ?? undefined,\n }),\n });\n\n const data = await response.json().catch(() => ({}));\n\n if (!response.ok) {\n throw new Error(extractApiError(data as Record<string, unknown>, 'Registration failed'));\n }\n\n const parsed = parseAuthResponse(data);\n if (parsed.access) {\n setAccessToken(parsed.access);\n }\n\n return parsed;\n}\n\nexport async function requestPasswordReset(email: string): Promise<void> {\n const response = await fetch(resolveAuthUrl(AUTH_PATHS.FORGOT_PASSWORD), {\n method: 'POST',\n headers: { 'Content-Type': 'application/json' },\n body: JSON.stringify({ email }),\n });\n\n if (!response.ok) {\n const data = await response.json().catch(() => ({}));\n const d = data as Record<string, unknown>;\n const message = (d?.detail || d?.error || 'Failed to send reset link') as string;\n throw new Error(message);\n }\n}\n\nexport async function resetPassword(payload: {\n token: string;\n password: string;\n passwordConfirm: string;\n email?: string;\n}): Promise<void> {\n const response = await fetchWithTimeout(resolveAuthUrl(AUTH_PATHS.RESET_PASSWORD), {\n method: 'POST',\n headers: { 'Content-Type': 'application/json' },\n body: JSON.stringify({\n token: payload.token,\n password: payload.password,\n password_confirm: payload.passwordConfirm,\n ...(payload.email ? { email: payload.email } : {}),\n }),\n });\n\n if (!response.ok) {\n const data = await response.json().catch(() => ({}));\n const d = data as Record<string, unknown>;\n const message = (d?.detail || d?.error || 'Failed to reset password') as string;\n throw new Error(message);\n }\n}\n\nexport async function verifyEmail(token: string): Promise<void> {\n const response = await fetchWithTimeout(resolveAuthUrl(AUTH_PATHS.VERIFY_EMAIL), {\n method: 'POST',\n headers: { 'Content-Type': 'application/json' },\n body: JSON.stringify({ token }),\n });\n\n if (!response.ok) {\n const data = await response.json().catch(() => ({}));\n const d = data as Record<string, unknown>;\n const message = (d?.detail || d?.error || 'Failed to verify email') as string;\n throw new Error(message);\n }\n}\n\nexport async function resendVerification(access?: string | null): Promise<void> {\n const response = await fetch(resolveAuthUrl(AUTH_PATHS.RESEND_VERIFICATION), {\n method: 'POST',\n headers: {\n 'Content-Type': 'application/json',\n ...(access ? { Authorization: `Bearer ${access}` } : {}),\n },\n credentials: 'include',\n });\n\n if (!response.ok) {\n const data = await response.json().catch(() => ({}));\n const d = data as Record<string, unknown>;\n const message = (d?.detail || d?.error || 'Failed to resend verification email') as string;\n throw new Error(message);\n }\n}\n\n// eslint-disable-next-line @typescript-eslint/no-explicit-any\nexport async function initiateGoogleOAuth(redirectUri: string): Promise<any> {\n const response = await fetch(resolveAuthUrl(AUTH_PATHS.OAUTH_GOOGLE_INITIATE), {\n method: 'POST',\n headers: { 'Content-Type': 'application/json' },\n credentials: 'include',\n body: JSON.stringify({ redirect_uri: redirectUri }),\n });\n\n const data = await response.json().catch(() => ({}));\n\n if (!response.ok) {\n const d = data as Record<string, unknown>;\n const message = (d?.detail || d?.error || 'Failed to initiate Google OAuth') as string;\n throw new Error(message);\n }\n\n return data;\n}\n\nexport async function completeGoogleOAuth(code: string, state: string) {\n const response = await fetchWithTimeout(\n resolveAuthUrl(\n `${AUTH_PATHS.OAUTH_GOOGLE_CALLBACK}?code=${encodeURIComponent(code)}&state=${encodeURIComponent(state)}`\n ),\n { credentials: 'include' }\n );\n\n const data = await response.json().catch(() => ({}));\n\n if (!response.ok) {\n const d = data as Record<string, unknown>;\n const message = (d?.detail || d?.error || 'OAuth authentication failed') as string;\n throw new Error(message);\n }\n\n const parsed = parseAuthResponse(data);\n if (parsed.access) {\n setAccessToken(parsed.access);\n }\n\n return parsed;\n}\n\nasync function fetchCsrfToken(): Promise<void> {\n if (getCsrfToken()) return;\n try {\n await fetch(resolveAuthUrl(`${API_BASE}/auth/csrf/`), {\n credentials: 'include',\n cache: 'no-store',\n });\n } catch (err) {\n console.warn('[auth] CSRF token fetch failed — token refresh will fail:', err)\n }\n}\n\nexport async function refreshAccessToken(): Promise<string | null> {\n await fetchCsrfToken();\n const csrfToken = getCsrfToken();\n if (!csrfToken) return null;\n\n const response = await fetchWithTimeout(resolveAuthUrl(AUTH_PATHS.TOKEN_REFRESH), {\n method: 'POST',\n headers: {\n 'Content-Type': 'application/json',\n 'X-CSRFToken': csrfToken,\n },\n credentials: 'include',\n });\n\n const data = await response.json().catch(() => ({}));\n\n if (!response.ok) {\n return null;\n }\n\n const parsed = parseAuthResponse(data);\n if (parsed.access) {\n setAccessToken(parsed.access);\n return parsed.access;\n }\n\n return null;\n}\n\nexport async function getMe(): Promise<AuthUser | null> {\n const token = getAccessToken();\n if (!token) return null;\n\n const response = await fetch(resolveAuthUrl(AUTH_PATHS.ME), {\n headers: {\n Authorization: `Bearer ${token}`,\n },\n credentials: 'include',\n cache: 'no-store',\n });\n\n if (!response.ok) {\n return null;\n }\n\n const data = await response.json().catch(() => ({}));\n const obj = data as Record<string, unknown>;\n const payload = obj.data && typeof obj.data === 'object' ? obj.data : obj;\n const userRaw = (payload as Record<string, unknown>).user || payload;\n return normalizeUser(userRaw);\n}\n\nexport async function signOut(): Promise<void> {\n const csrfToken = getCsrfToken();\n const token = getAccessToken();\n\n try {\n await fetch(resolveAuthUrl(AUTH_PATHS.LOGOUT), {\n method: 'POST',\n headers: {\n 'Content-Type': 'application/json',\n ...(csrfToken ? { 'X-CSRFToken': csrfToken } : {}),\n ...(token ? { Authorization: `Bearer ${token}` } : {}),\n },\n credentials: 'include',\n });\n } finally {\n setAccessToken(null);\n }\n}\n\n// Singleton refresh promise — ensures concurrent 401s share one refresh call\nlet _refreshPromise: Promise<string | null> | null = null;\n\nfunction _refreshOnce(): Promise<string | null> {\n if (!_refreshPromise) {\n _refreshPromise = refreshAccessToken().finally(() => {\n _refreshPromise = null;\n });\n }\n return _refreshPromise;\n}\n\nexport async function authFetch(\n input: RequestInfo | URL,\n init: RequestInit = {}\n): Promise<Response> {\n const token = getAccessToken();\n const headers = new Headers(init.headers || {});\n\n if (token && !headers.has('Authorization')) {\n headers.set('Authorization', `Bearer ${token}`);\n }\n\n const resolvedInput = typeof input === 'string' ? resolveAuthUrl(input) : input;\n\n const response = await fetch(resolvedInput, {\n ...init,\n headers,\n credentials: init.credentials ?? 'include',\n });\n\n if (response.status === 401) {\n const refreshed = await _refreshOnce();\n if (refreshed) {\n const retryHeaders = new Headers(init.headers || {});\n retryHeaders.set('Authorization', `Bearer ${refreshed}`);\n\n return fetch(resolvedInput, {\n ...init,\n headers: retryHeaders,\n credentials: init.credentials ?? 'include',\n });\n }\n }\n\n return response;\n}\n\nexport function hasPermission(user: AuthUser | null | undefined, permission: string): boolean {\n if (!user) return false;\n if (!user.permissions || user.permissions.length === 0) return false;\n return user.permissions.includes(permission);\n}\n\nexport function hasGroup(user: AuthUser | null | undefined, group: string): boolean {\n if (!user) return false;\n if (!user.groups || user.groups.length === 0) return false;\n return user.groups.includes(group);\n}\n"]}
@@ -1,5 +1,5 @@
1
- export { AuthClient, AuthProvider, authFetch, completeGoogleOAuth, getAccessToken, getMe, hasGroup, hasPermission, initiateGoogleOAuth, refreshAccessToken, registerAccount, requestPasswordReset, resendVerification, resetPassword, resolveAuthUrl, setAccessToken, signInWithCredentials, signOut, useAuth, useAuthContext, usePermissions, verifyEmail } from '../chunk-CDNZRZ7Q.mjs';
2
- import '../chunk-S6J5FYQY.mjs';
3
- import '../chunk-TA46ASDJ.mjs';
1
+ export { AuthClient, AuthProvider, authFetch, completeGoogleOAuth, getAccessToken, getMe, hasGroup, hasPermission, initiateGoogleOAuth, refreshAccessToken, registerAccount, requestPasswordReset, resendVerification, resetPassword, resolveAuthUrl, setAccessToken, signInWithCredentials, signOut, useAuth, useAuthContext, usePermissions, verifyEmail } from '../chunk-VIG3K6ZR.mjs';
2
+ import '../chunk-AADTGAI2.mjs';
3
+ import '../chunk-QAXZGJNQ.mjs';
4
4
  //# sourceMappingURL=index.mjs.map
5
5
  //# sourceMappingURL=index.mjs.map
package/dist/index.mjs CHANGED
@@ -1,5 +1,5 @@
1
- export { AuthClient, AuthProvider, authFetch, completeGoogleOAuth, getAccessToken, getMe, hasGroup, hasPermission, initiateGoogleOAuth, refreshAccessToken, registerAccount, requestPasswordReset, resendVerification, resetPassword, resolveAuthUrl, setAccessToken, signInWithCredentials, signOut, useAuth, useAuthContext, usePermissions, verifyEmail } from './chunk-CDNZRZ7Q.mjs';
2
- export { EMAIL_REGEX, decodeToken, deleteCookie, getCookie, getCsrfToken, getTokenExpiresAt, getTokenPayload, isTokenExpired, setCookie, shouldRefreshToken, validateEmail, validatePassword, validatePasswordConfirm } from './chunk-S6J5FYQY.mjs';
3
- export { EmailErrorCode, PasswordErrorCode, ROLE_HIERARCHY, ValidationErrorCode, hasRolePermission } from './chunk-TA46ASDJ.mjs';
1
+ export { AuthClient, AuthProvider, authFetch, completeGoogleOAuth, getAccessToken, getMe, hasGroup, hasPermission, initiateGoogleOAuth, refreshAccessToken, registerAccount, requestPasswordReset, resendVerification, resetPassword, resolveAuthUrl, setAccessToken, signInWithCredentials, signOut, useAuth, useAuthContext, usePermissions, verifyEmail } from './chunk-VIG3K6ZR.mjs';
2
+ export { EMAIL_REGEX, decodeToken, deleteCookie, getCookie, getCsrfToken, getTokenExpiresAt, getTokenPayload, isTokenExpired, setCookie, shouldRefreshToken, validateEmail, validatePassword, validatePasswordConfirm } from './chunk-AADTGAI2.mjs';
3
+ export { EmailErrorCode, PasswordErrorCode, ROLE_HIERARCHY, ValidationErrorCode, hasRolePermission } from './chunk-QAXZGJNQ.mjs';
4
4
  //# sourceMappingURL=index.mjs.map
5
5
  //# sourceMappingURL=index.mjs.map
@@ -3,8 +3,6 @@
3
3
  var headers = require('next/headers');
4
4
  var server = require('next/server');
5
5
 
6
- // src/server/session.ts
7
-
8
6
  // src/utils/token.ts
9
7
  function decodeToken(token) {
10
8
  try {
@@ -1 +1 @@
1
- {"version":3,"sources":["../../src/utils/token.ts","../../src/server/session.ts","../../src/server/middleware.ts","../../src/types/index.ts","../../src/server/guards.ts"],"names":["cookies","NextResponse"],"mappings":"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","file":"index.js","sourcesContent":["/**\n * JWT token utilities\n */\n\nimport type { TokenPayload, DecodedToken } from '../types';\n\n/**\n * Decode JWT token payload (does NOT verify signature)\n */\nexport function decodeToken(token: string): TokenPayload | null {\n try {\n const parts = token.split('.');\n if (parts.length !== 3) {\n return null;\n }\n\n const payload = parts[1];\n const decoded = JSON.parse(atob(payload));\n return decoded as TokenPayload;\n } catch (error) {\n console.error('Failed to decode token:', error);\n return null;\n }\n}\n\n/**\n * Check if token is expired\n */\nexport function isTokenExpired(token: string): boolean {\n const payload = decodeToken(token);\n if (!payload) {\n return true;\n }\n\n const now = Math.floor(Date.now() / 1000);\n return payload.exp <= now;\n}\n\n/**\n * Get token expiration time in milliseconds\n */\nexport function getTokenExpiresAt(token: string): number | null {\n const payload = decodeToken(token);\n if (!payload) {\n return null;\n }\n\n return payload.exp * 1000;\n}\n\n/**\n * Get raw JWT payload as a generic record — framework and backend agnostic.\n * Does NOT verify the signature; use only for reading claims client-side.\n */\nexport function getTokenPayload(token: string): DecodedToken | null {\n try {\n const parts = token.split('.');\n if (parts.length !== 3) {\n return null;\n }\n\n const payload = parts[1];\n const decoded = JSON.parse(atob(payload));\n\n if (typeof decoded !== 'object' || decoded === null) {\n return null;\n }\n\n return decoded as DecodedToken;\n } catch {\n return null;\n }\n}\n\n/**\n * Check if token needs refresh (expires in less than 5 minutes)\n */\nexport function shouldRefreshToken(token: string): boolean {\n const expiresAt = getTokenExpiresAt(token);\n if (!expiresAt) {\n return true;\n }\n\n const now = Date.now();\n const timeUntilExpiry = expiresAt - now;\n const FIVE_MINUTES = 5 * 60 * 1000;\n\n return timeUntilExpiry < FIVE_MINUTES;\n}\n","/**\n * Server-side session validation\n * For Next.js API routes and server components\n */\n\nimport { cookies } from 'next/headers';\nimport type { Session, AuthUser, TokenPayload } from '../types';\nimport { decodeToken, isTokenExpired } from '../utils';\n\n/**\n * Get session from server-side cookies and headers\n */\nexport async function getServerSession(\n apiBaseUrl: string\n): Promise<Session | null> {\n const cookieStore = await cookies();\n const accessToken = cookieStore.get('access_token')?.value;\n\n if (!accessToken) {\n return null;\n }\n\n if (isTokenExpired(accessToken)) {\n return null;\n }\n\n try {\n const user = await fetchUser(apiBaseUrl, accessToken);\n const payload = decodeToken(accessToken);\n\n if (!payload) {\n return null;\n }\n\n return {\n user,\n accessToken,\n expiresAt: payload.exp * 1000,\n };\n } catch (error) {\n console.error('Failed to get server session:', error);\n return null;\n }\n}\n\n/**\n * Fetch user data from Django backend\n */\nasync function fetchUser(\n apiBaseUrl: string,\n accessToken: string\n): Promise<AuthUser> {\n const response = await fetch(`${apiBaseUrl}/api/v1/auth/me/`, {\n headers: {\n Authorization: `Bearer ${accessToken}`,\n },\n cache: 'no-store',\n });\n\n if (!response.ok) {\n throw new Error('Failed to fetch user');\n }\n\n return response.json();\n}\n\n/**\n * Validate session and return user or null\n */\nexport async function validateSession(\n apiBaseUrl: string\n): Promise<AuthUser | null> {\n const session = await getServerSession(apiBaseUrl);\n return session?.user || null;\n}\n\n/**\n * Require authenticated session (throws if not authenticated)\n */\nexport async function requireAuth(apiBaseUrl: string): Promise<Session> {\n const session = await getServerSession(apiBaseUrl);\n\n if (!session) {\n throw new Error('Unauthorized');\n }\n\n return session;\n}\n\n/**\n * Refresh access token using refresh token cookie\n */\nexport async function refreshServerToken(\n apiBaseUrl: string\n): Promise<string | null> {\n try {\n const response = await fetch(`${apiBaseUrl}/api/v1/auth/token/refresh/`, {\n method: 'POST',\n headers: {\n 'Content-Type': 'application/json',\n },\n credentials: 'include',\n });\n\n if (!response.ok) {\n return null;\n }\n\n const data = await response.json();\n return data.access;\n } catch (error) {\n console.error('Token refresh failed:', error);\n return null;\n }\n}\n","/**\n * Next.js middleware helpers for authentication\n */\n\nimport { NextRequest, NextResponse } from 'next/server';\nimport { isTokenExpired } from '../utils';\n\nexport interface AuthMiddlewareConfig {\n apiBaseUrl: string;\n publicPaths?: string[];\n loginPath?: string;\n}\n\n/**\n * Create auth middleware for Next.js\n */\nexport function createAuthMiddleware(config: AuthMiddlewareConfig) {\n const {\n apiBaseUrl,\n publicPaths = ['/login', '/register', '/forgot-password'],\n loginPath = '/login',\n } = config;\n\n return async function authMiddleware(request: NextRequest) {\n const { pathname } = request.nextUrl;\n\n const isPublicPath = publicPaths.some((path) =>\n pathname.startsWith(path)\n );\n\n if (isPublicPath) {\n return NextResponse.next();\n }\n\n const accessToken = request.cookies.get('access_token')?.value;\n\n if (!accessToken || isTokenExpired(accessToken)) {\n const url = request.nextUrl.clone();\n url.pathname = loginPath;\n url.searchParams.set('from', pathname);\n return NextResponse.redirect(url);\n }\n\n return NextResponse.next();\n };\n}\n\n/**\n * Check if request has valid auth token\n */\nexport function hasValidToken(request: NextRequest): boolean {\n const accessToken = request.cookies.get('access_token')?.value;\n\n if (!accessToken) {\n return false;\n }\n\n return !isTokenExpired(accessToken);\n}\n\n/**\n * Get access token from request\n */\nexport function getRequestToken(request: NextRequest): string | null {\n const accessToken = request.cookies.get('access_token')?.value;\n\n if (!accessToken) {\n return null;\n }\n\n if (isTokenExpired(accessToken)) {\n return null;\n }\n\n return accessToken;\n}\n\n/**\n * Extract bearer token from a standard Request (Authorization header or access_token cookie).\n * Framework-agnostic — works with any Request-compatible object (Next.js, Node, edge runtimes).\n * Returns the raw token string without expiry validation.\n */\nexport function getTokenFromRequest(req: Request): string | undefined {\n // Authorization: Bearer <token>\n const authHeader = req.headers.get('authorization');\n if (authHeader?.startsWith('Bearer ')) {\n const token = authHeader.slice(7).trim();\n if (token) return token;\n }\n\n // Fallback: access_token cookie (parsed from Cookie header)\n const cookieHeader = req.headers.get('cookie');\n if (cookieHeader) {\n const match = cookieHeader\n .split(';')\n .map((part) => part.trim())\n .find((part) => part.startsWith('access_token='));\n\n if (match) {\n const token = match.slice('access_token='.length).trim();\n if (token) return token;\n }\n }\n\n return undefined;\n}\n","/**\n * Authentication types for StartSimpli apps\n */\n\n/**\n * Generic token pair (access + optional refresh)\n */\nexport interface TokenPair {\n access: string;\n refresh?: string;\n}\n\n/**\n * Generic decoded JWT payload — framework and backend agnostic\n */\nexport interface DecodedToken {\n sub?: string;\n email?: string;\n exp?: number;\n iat?: number;\n [key: string]: unknown;\n}\n\n/**\n * Generic auth session — framework agnostic\n */\nexport interface AuthSession {\n user: {\n id: string;\n email: string;\n [key: string]: unknown;\n };\n accessToken: string;\n refreshToken?: string;\n}\n\n/**\n * User profile from Django backend\n */\nexport interface AuthUser {\n id: string;\n email: string;\n firstName: string;\n lastName: string;\n isEmailVerified: boolean;\n createdAt: string;\n updatedAt: string;\n // Company/team context (if applicable)\n companies?: Array<{\n id: string;\n name: string;\n role: 'owner' | 'admin' | 'member' | 'viewer';\n }>;\n currentCompanyId?: string;\n}\n\n/**\n * JWT token payload structure\n */\nexport interface TokenPayload {\n token_type: 'access';\n exp: number;\n iat: number;\n jti: string;\n user_id: string;\n}\n\n/**\n * Session data stored in client\n */\nexport interface Session {\n user: AuthUser;\n accessToken: string;\n expiresAt: number;\n}\n\n/**\n * Login response from Django backend\n */\nexport interface LoginResponse {\n access: string;\n user: AuthUser;\n}\n\n/**\n * Token refresh response\n */\nexport interface RefreshResponse {\n access: string;\n}\n\n/**\n * Permission check result\n */\nexport interface PermissionCheck {\n hasPermission: boolean;\n reason?: string;\n}\n\n/**\n * Auth configuration options\n */\nexport interface AuthConfig {\n apiBaseUrl: string;\n tokenRefreshInterval?: number; // milliseconds, default 4 minutes\n onSessionExpired?: () => void;\n onUnauthorized?: () => void;\n}\n\n/**\n * Auth state for React context\n */\nexport interface AuthState {\n session: Session | null;\n isLoading: boolean;\n isAuthenticated: boolean;\n}\n\n/**\n * Company role hierarchy\n */\nexport type CompanyRole = 'owner' | 'admin' | 'member' | 'viewer';\n\n/**\n * Role hierarchy map (higher number = more permissions)\n */\nexport const ROLE_HIERARCHY: Record<CompanyRole, number> = {\n owner: 4,\n admin: 3,\n member: 2,\n viewer: 1,\n};\n\n/**\n * Check if role has sufficient permissions\n */\nexport function hasRolePermission(\n userRole: CompanyRole,\n requiredRole: CompanyRole\n): boolean {\n return ROLE_HIERARCHY[userRole] >= ROLE_HIERARCHY[requiredRole];\n}\n\n/**\n * Password reset request payload\n * Initiates password reset flow by sending reset email\n */\nexport interface PasswordResetRequest {\n email: string;\n clientMetadata?: Record<string, any>;\n}\n\n/**\n * Password reset confirmation payload\n * Completes password reset with token and new password\n */\nexport interface PasswordResetConfirm {\n token: string;\n password: string;\n passwordConfirm: string;\n}\n\n/**\n * Email verification request payload\n * Verifies user email with token from verification email\n */\nexport interface EmailVerificationRequest {\n token: string;\n}\n\n/**\n * Email verification response\n * Returns updated user data after successful verification\n */\nexport interface EmailVerificationResponse {\n detail: string;\n user: {\n id: string;\n email: string;\n isEmailVerified: boolean;\n };\n}\n\n/**\n * API error response from Django backend\n * Standard error format for all API errors\n */\nexport interface ApiErrorResponse {\n detail?: string;\n message?: string;\n errors?: Record<string, string[]>;\n code?: string;\n status?: number;\n}\n\n/**\n * Validation error detail\n * Individual field validation error\n */\nexport interface ValidationError {\n field: string;\n message: string;\n code?: string;\n}\n\n/**\n * Validation errors map\n * Maps field names to error messages\n */\nexport type ValidationErrorsMap = Record<string, string[]>;\n\n/**\n * Password validation error codes\n */\nexport enum PasswordErrorCode {\n TOO_SHORT = 'password_too_short',\n TOO_COMMON = 'password_too_common',\n ENTIRELY_NUMERIC = 'password_entirely_numeric',\n TOO_SIMILAR = 'password_too_similar',\n MISMATCH = 'password_mismatch',\n REQUIRED = 'password_required',\n}\n\n/**\n * Email validation error codes\n */\nexport enum EmailErrorCode {\n INVALID_FORMAT = 'email_invalid_format',\n REQUIRED = 'email_required',\n NOT_FOUND = 'email_not_found',\n ALREADY_EXISTS = 'email_already_exists',\n}\n\n/**\n * General validation error codes\n */\nexport enum ValidationErrorCode {\n REQUIRED = 'required',\n INVALID = 'invalid',\n TOO_SHORT = 'too_short',\n TOO_LONG = 'too_long',\n}\n","/**\n * Auth guards for API routes\n */\n\nimport { NextRequest, NextResponse } from 'next/server';\nimport type { CompanyRole } from '../types';\nimport { hasRolePermission } from '../types';\nimport { getRequestToken } from './middleware';\n\n/**\n * Auth guard result\n */\nexport interface GuardResult {\n authorized: boolean;\n response?: NextResponse;\n token?: string;\n}\n\n/**\n * Require authentication for API route\n */\nexport async function requireAuthGuard(\n request: NextRequest\n): Promise<GuardResult> {\n const token = getRequestToken(request);\n\n if (!token) {\n return {\n authorized: false,\n response: NextResponse.json(\n { error: 'Unauthorized' },\n { status: 401 }\n ),\n };\n }\n\n return {\n authorized: true,\n token,\n };\n}\n\n/**\n * Require specific role for API route\n */\nexport async function requireRoleGuard(\n request: NextRequest,\n requiredRole: CompanyRole,\n getUserRole: () => Promise<CompanyRole | null>\n): Promise<GuardResult> {\n const authResult = await requireAuthGuard(request);\n\n if (!authResult.authorized) {\n return authResult;\n }\n\n const userRole = await getUserRole();\n\n if (!userRole || !hasRolePermission(userRole, requiredRole)) {\n return {\n authorized: false,\n response: NextResponse.json(\n { error: 'Forbidden' },\n { status: 403 }\n ),\n };\n }\n\n return {\n authorized: true,\n token: authResult.token,\n };\n}\n\n/**\n * Higher-order function to wrap API route with auth guard\n */\nexport function withAuth<T = any>(\n handler: (request: NextRequest, token: string) => Promise<NextResponse<T>>\n) {\n return async (request: NextRequest): Promise<NextResponse> => {\n const guardResult = await requireAuthGuard(request);\n\n if (!guardResult.authorized) {\n return guardResult.response!;\n }\n\n return handler(request, guardResult.token!);\n };\n}\n\n/**\n * Higher-order function to wrap API route with role guard\n */\nexport function withRole<T = any>(\n requiredRole: CompanyRole,\n getUserRole: () => Promise<CompanyRole | null>,\n handler: (request: NextRequest, token: string) => Promise<NextResponse<T>>\n) {\n return async (request: NextRequest): Promise<NextResponse> => {\n const guardResult = await requireRoleGuard(\n request,\n requiredRole,\n getUserRole\n );\n\n if (!guardResult.authorized) {\n return guardResult.response!;\n }\n\n return handler(request, guardResult.token!);\n };\n}\n"]}
1
+ {"version":3,"sources":["../../src/utils/token.ts","../../src/server/session.ts","../../src/server/middleware.ts","../../src/types/index.ts","../../src/server/guards.ts"],"names":["cookies","NextResponse"],"mappings":";;;;;;AASO,SAAS,YAAY,KAAA,EAAoC;AAC9D,EAAA,IAAI;AACF,IAAA,MAAM,KAAA,GAAQ,KAAA,CAAM,KAAA,CAAM,GAAG,CAAA;AAC7B,IAAA,IAAI,KAAA,CAAM,WAAW,CAAA,EAAG;AACtB,MAAA,OAAO,IAAA;AAAA,IACT;AAEA,IAAA,MAAM,OAAA,GAAU,MAAM,CAAC,CAAA;AACvB,IAAA,MAAM,OAAA,GAAU,IAAA,CAAK,KAAA,CAAM,IAAA,CAAK,OAAO,CAAC,CAAA;AACxC,IAAA,OAAO,OAAA;AAAA,EACT,SAAS,KAAA,EAAO;AACd,IAAA,OAAA,CAAQ,KAAA,CAAM,2BAA2B,KAAK,CAAA;AAC9C,IAAA,OAAO,IAAA;AAAA,EACT;AACF;AAKO,SAAS,eAAe,KAAA,EAAwB;AACrD,EAAA,MAAM,OAAA,GAAU,YAAY,KAAK,CAAA;AACjC,EAAA,IAAI,CAAC,OAAA,EAAS;AACZ,IAAA,OAAO,IAAA;AAAA,EACT;AAEA,EAAA,MAAM,MAAM,IAAA,CAAK,KAAA,CAAM,IAAA,CAAK,GAAA,KAAQ,GAAI,CAAA;AACxC,EAAA,OAAO,QAAQ,GAAA,IAAO,GAAA;AACxB;;;ACxBA,eAAsB,iBACpB,UAAA,EACyB;AACzB,EAAA,MAAM,WAAA,GAAc,MAAMA,eAAA,EAAQ;AAClC,EAAA,MAAM,WAAA,GAAc,WAAA,CAAY,GAAA,CAAI,cAAc,CAAA,EAAG,KAAA;AAErD,EAAA,IAAI,CAAC,WAAA,EAAa;AAChB,IAAA,OAAO,IAAA;AAAA,EACT;AAEA,EAAA,IAAI,cAAA,CAAe,WAAW,CAAA,EAAG;AAC/B,IAAA,OAAO,IAAA;AAAA,EACT;AAEA,EAAA,IAAI;AACF,IAAA,MAAM,IAAA,GAAO,MAAM,SAAA,CAAU,UAAA,EAAY,WAAW,CAAA;AACpD,IAAA,MAAM,OAAA,GAAU,YAAY,WAAW,CAAA;AAEvC,IAAA,IAAI,CAAC,OAAA,EAAS;AACZ,MAAA,OAAO,IAAA;AAAA,IACT;AAEA,IAAA,OAAO;AAAA,MACL,IAAA;AAAA,MACA,WAAA;AAAA,MACA,SAAA,EAAW,QAAQ,GAAA,GAAM;AAAA,KAC3B;AAAA,EACF,SAAS,KAAA,EAAO;AACd,IAAA,OAAA,CAAQ,KAAA,CAAM,iCAAiC,KAAK,CAAA;AACpD,IAAA,OAAO,IAAA;AAAA,EACT;AACF;AAKA,eAAe,SAAA,CACb,YACA,WAAA,EACmB;AACnB,EAAA,MAAM,QAAA,GAAW,MAAM,KAAA,CAAM,CAAA,EAAG,UAAU,CAAA,gBAAA,CAAA,EAAoB;AAAA,IAC5D,OAAA,EAAS;AAAA,MACP,aAAA,EAAe,UAAU,WAAW,CAAA;AAAA,KACtC;AAAA,IACA,KAAA,EAAO;AAAA,GACR,CAAA;AAED,EAAA,IAAI,CAAC,SAAS,EAAA,EAAI;AAChB,IAAA,MAAM,IAAI,MAAM,sBAAsB,CAAA;AAAA,EACxC;AAEA,EAAA,OAAO,SAAS,IAAA,EAAK;AACvB;AAKA,eAAsB,gBACpB,UAAA,EAC0B;AAC1B,EAAA,MAAM,OAAA,GAAU,MAAM,gBAAA,CAAiB,UAAU,CAAA;AACjD,EAAA,OAAO,SAAS,IAAA,IAAQ,IAAA;AAC1B;AAKA,eAAsB,YAAY,UAAA,EAAsC;AACtE,EAAA,MAAM,OAAA,GAAU,MAAM,gBAAA,CAAiB,UAAU,CAAA;AAEjD,EAAA,IAAI,CAAC,OAAA,EAAS;AACZ,IAAA,MAAM,IAAI,MAAM,cAAc,CAAA;AAAA,EAChC;AAEA,EAAA,OAAO,OAAA;AACT;AAKA,eAAsB,mBACpB,UAAA,EACwB;AACxB,EAAA,IAAI;AACF,IAAA,MAAM,QAAA,GAAW,MAAM,KAAA,CAAM,CAAA,EAAG,UAAU,CAAA,2BAAA,CAAA,EAA+B;AAAA,MACvE,MAAA,EAAQ,MAAA;AAAA,MACR,OAAA,EAAS;AAAA,QACP,cAAA,EAAgB;AAAA,OAClB;AAAA,MACA,WAAA,EAAa;AAAA,KACd,CAAA;AAED,IAAA,IAAI,CAAC,SAAS,EAAA,EAAI;AAChB,MAAA,OAAO,IAAA;AAAA,IACT;AAEA,IAAA,MAAM,IAAA,GAAO,MAAM,QAAA,CAAS,IAAA,EAAK;AACjC,IAAA,OAAO,IAAA,CAAK,MAAA;AAAA,EACd,SAAS,KAAA,EAAO;AACd,IAAA,OAAA,CAAQ,KAAA,CAAM,yBAAyB,KAAK,CAAA;AAC5C,IAAA,OAAO,IAAA;AAAA,EACT;AACF;AClGO,SAAS,qBAAqB,MAAA,EAA8B;AACjE,EAAA,MAAM;AAAA,IACJ,UAAA;AAAA,IACA,WAAA,GAAc,CAAC,QAAA,EAAU,WAAA,EAAa,kBAAkB,CAAA;AAAA,IACxD,SAAA,GAAY;AAAA,GACd,GAAI,MAAA;AAEJ,EAAA,OAAO,eAAe,eAAe,OAAA,EAAsB;AACzD,IAAA,MAAM,EAAE,QAAA,EAAS,GAAI,OAAA,CAAQ,OAAA;AAE7B,IAAA,MAAM,eAAe,WAAA,CAAY,IAAA;AAAA,MAAK,CAAC,IAAA,KACrC,QAAA,CAAS,UAAA,CAAW,IAAI;AAAA,KAC1B;AAEA,IAAA,IAAI,YAAA,EAAc;AAChB,MAAA,OAAOC,oBAAa,IAAA,EAAK;AAAA,IAC3B;AAEA,IAAA,MAAM,WAAA,GAAc,OAAA,CAAQ,OAAA,CAAQ,GAAA,CAAI,cAAc,CAAA,EAAG,KAAA;AAEzD,IAAA,IAAI,CAAC,WAAA,IAAe,cAAA,CAAe,WAAW,CAAA,EAAG;AAC/C,MAAA,MAAM,GAAA,GAAM,OAAA,CAAQ,OAAA,CAAQ,KAAA,EAAM;AAClC,MAAA,GAAA,CAAI,QAAA,GAAW,SAAA;AACf,MAAA,GAAA,CAAI,YAAA,CAAa,GAAA,CAAI,MAAA,EAAQ,QAAQ,CAAA;AACrC,MAAA,OAAOA,mBAAA,CAAa,SAAS,GAAG,CAAA;AAAA,IAClC;AAEA,IAAA,OAAOA,oBAAa,IAAA,EAAK;AAAA,EAC3B,CAAA;AACF;AAKO,SAAS,cAAc,OAAA,EAA+B;AAC3D,EAAA,MAAM,WAAA,GAAc,OAAA,CAAQ,OAAA,CAAQ,GAAA,CAAI,cAAc,CAAA,EAAG,KAAA;AAEzD,EAAA,IAAI,CAAC,WAAA,EAAa;AAChB,IAAA,OAAO,KAAA;AAAA,EACT;AAEA,EAAA,OAAO,CAAC,eAAe,WAAW,CAAA;AACpC;AAKO,SAAS,gBAAgB,OAAA,EAAqC;AACnE,EAAA,MAAM,WAAA,GAAc,OAAA,CAAQ,OAAA,CAAQ,GAAA,CAAI,cAAc,CAAA,EAAG,KAAA;AAEzD,EAAA,IAAI,CAAC,WAAA,EAAa;AAChB,IAAA,OAAO,IAAA;AAAA,EACT;AAEA,EAAA,IAAI,cAAA,CAAe,WAAW,CAAA,EAAG;AAC/B,IAAA,OAAO,IAAA;AAAA,EACT;AAEA,EAAA,OAAO,WAAA;AACT;AAOO,SAAS,oBAAoB,GAAA,EAAkC;AAEpE,EAAA,MAAM,UAAA,GAAa,GAAA,CAAI,OAAA,CAAQ,GAAA,CAAI,eAAe,CAAA;AAClD,EAAA,IAAI,UAAA,EAAY,UAAA,CAAW,SAAS,CAAA,EAAG;AACrC,IAAA,MAAM,KAAA,GAAQ,UAAA,CAAW,KAAA,CAAM,CAAC,EAAE,IAAA,EAAK;AACvC,IAAA,IAAI,OAAO,OAAO,KAAA;AAAA,EACpB;AAGA,EAAA,MAAM,YAAA,GAAe,GAAA,CAAI,OAAA,CAAQ,GAAA,CAAI,QAAQ,CAAA;AAC7C,EAAA,IAAI,YAAA,EAAc;AAChB,IAAA,MAAM,QAAQ,YAAA,CACX,KAAA,CAAM,GAAG,CAAA,CACT,GAAA,CAAI,CAAC,IAAA,KAAS,IAAA,CAAK,IAAA,EAAM,EACzB,IAAA,CAAK,CAAC,SAAS,IAAA,CAAK,UAAA,CAAW,eAAe,CAAC,CAAA;AAElD,IAAA,IAAI,KAAA,EAAO;AACT,MAAA,MAAM,QAAQ,KAAA,CAAM,KAAA,CAAM,eAAA,CAAgB,MAAM,EAAE,IAAA,EAAK;AACvD,MAAA,IAAI,OAAO,OAAO,KAAA;AAAA,IACpB;AAAA,EACF;AAEA,EAAA,OAAO,MAAA;AACT;;;ACqBO,IAAM,cAAA,GAA8C;AAAA,EACzD,KAAA,EAAO,CAAA;AAAA,EACP,KAAA,EAAO,CAAA;AAAA,EACP,MAAA,EAAQ,CAAA;AAAA,EACR,MAAA,EAAQ;AACV,CAAA;AAKO,SAAS,iBAAA,CACd,UACA,YAAA,EACS;AACT,EAAA,OAAO,cAAA,CAAe,QAAQ,CAAA,IAAK,cAAA,CAAe,YAAY,CAAA;AAChE;;;ACxHA,eAAsB,iBACpB,OAAA,EACsB;AACtB,EAAA,MAAM,KAAA,GAAQ,gBAAgB,OAAO,CAAA;AAErC,EAAA,IAAI,CAAC,KAAA,EAAO;AACV,IAAA,OAAO;AAAA,MACL,UAAA,EAAY,KAAA;AAAA,MACZ,UAAUA,mBAAAA,CAAa,IAAA;AAAA,QACrB,EAAE,OAAO,cAAA,EAAe;AAAA,QACxB,EAAE,QAAQ,GAAA;AAAI;AAChB,KACF;AAAA,EACF;AAEA,EAAA,OAAO;AAAA,IACL,UAAA,EAAY,IAAA;AAAA,IACZ;AAAA,GACF;AACF;AAKA,eAAsB,gBAAA,CACpB,OAAA,EACA,YAAA,EACA,WAAA,EACsB;AACtB,EAAA,MAAM,UAAA,GAAa,MAAM,gBAAA,CAAiB,OAAO,CAAA;AAEjD,EAAA,IAAI,CAAC,WAAW,UAAA,EAAY;AAC1B,IAAA,OAAO,UAAA;AAAA,EACT;AAEA,EAAA,MAAM,QAAA,GAAW,MAAM,WAAA,EAAY;AAEnC,EAAA,IAAI,CAAC,QAAA,IAAY,CAAC,iBAAA,CAAkB,QAAA,EAAU,YAAY,CAAA,EAAG;AAC3D,IAAA,OAAO;AAAA,MACL,UAAA,EAAY,KAAA;AAAA,MACZ,UAAUA,mBAAAA,CAAa,IAAA;AAAA,QACrB,EAAE,OAAO,WAAA,EAAY;AAAA,QACrB,EAAE,QAAQ,GAAA;AAAI;AAChB,KACF;AAAA,EACF;AAEA,EAAA,OAAO;AAAA,IACL,UAAA,EAAY,IAAA;AAAA,IACZ,OAAO,UAAA,CAAW;AAAA,GACpB;AACF;AAKO,SAAS,SACd,OAAA,EACA;AACA,EAAA,OAAO,OAAO,OAAA,KAAgD;AAC5D,IAAA,MAAM,WAAA,GAAc,MAAM,gBAAA,CAAiB,OAAO,CAAA;AAElD,IAAA,IAAI,CAAC,YAAY,UAAA,EAAY;AAC3B,MAAA,OAAO,WAAA,CAAY,QAAA;AAAA,IACrB;AAEA,IAAA,OAAO,OAAA,CAAQ,OAAA,EAAS,WAAA,CAAY,KAAM,CAAA;AAAA,EAC5C,CAAA;AACF;AAKO,SAAS,QAAA,CACd,YAAA,EACA,WAAA,EACA,OAAA,EACA;AACA,EAAA,OAAO,OAAO,OAAA,KAAgD;AAC5D,IAAA,MAAM,cAAc,MAAM,gBAAA;AAAA,MACxB,OAAA;AAAA,MACA,YAAA;AAAA,MACA;AAAA,KACF;AAEA,IAAA,IAAI,CAAC,YAAY,UAAA,EAAY;AAC3B,MAAA,OAAO,WAAA,CAAY,QAAA;AAAA,IACrB;AAEA,IAAA,OAAO,OAAA,CAAQ,OAAA,EAAS,WAAA,CAAY,KAAM,CAAA;AAAA,EAC5C,CAAA;AACF","file":"index.js","sourcesContent":["/**\n * JWT token utilities\n */\n\nimport type { TokenPayload, DecodedToken } from '../types';\n\n/**\n * Decode JWT token payload (does NOT verify signature)\n */\nexport function decodeToken(token: string): TokenPayload | null {\n try {\n const parts = token.split('.');\n if (parts.length !== 3) {\n return null;\n }\n\n const payload = parts[1];\n const decoded = JSON.parse(atob(payload));\n return decoded as TokenPayload;\n } catch (error) {\n console.error('Failed to decode token:', error);\n return null;\n }\n}\n\n/**\n * Check if token is expired\n */\nexport function isTokenExpired(token: string): boolean {\n const payload = decodeToken(token);\n if (!payload) {\n return true;\n }\n\n const now = Math.floor(Date.now() / 1000);\n return payload.exp <= now;\n}\n\n/**\n * Get token expiration time in milliseconds\n */\nexport function getTokenExpiresAt(token: string): number | null {\n const payload = decodeToken(token);\n if (!payload) {\n return null;\n }\n\n return payload.exp * 1000;\n}\n\n/**\n * Get raw JWT payload as a generic record — framework and backend agnostic.\n * Does NOT verify the signature; use only for reading claims client-side.\n */\nexport function getTokenPayload(token: string): DecodedToken | null {\n try {\n const parts = token.split('.');\n if (parts.length !== 3) {\n return null;\n }\n\n const payload = parts[1];\n const decoded = JSON.parse(atob(payload));\n\n if (typeof decoded !== 'object' || decoded === null) {\n return null;\n }\n\n return decoded as DecodedToken;\n } catch {\n return null;\n }\n}\n\n/**\n * Check if token needs refresh (expires in less than 5 minutes)\n */\nexport function shouldRefreshToken(token: string): boolean {\n const expiresAt = getTokenExpiresAt(token);\n if (!expiresAt) {\n return true;\n }\n\n const now = Date.now();\n const timeUntilExpiry = expiresAt - now;\n const FIVE_MINUTES = 5 * 60 * 1000;\n\n return timeUntilExpiry < FIVE_MINUTES;\n}\n","/**\n * Server-side session validation\n * For Next.js API routes and server components\n */\n\nimport { cookies } from 'next/headers';\nimport type { Session, AuthUser, TokenPayload } from '../types';\nimport { decodeToken, isTokenExpired } from '../utils';\n\n/**\n * Get session from server-side cookies and headers\n */\nexport async function getServerSession(\n apiBaseUrl: string\n): Promise<Session | null> {\n const cookieStore = await cookies();\n const accessToken = cookieStore.get('access_token')?.value;\n\n if (!accessToken) {\n return null;\n }\n\n if (isTokenExpired(accessToken)) {\n return null;\n }\n\n try {\n const user = await fetchUser(apiBaseUrl, accessToken);\n const payload = decodeToken(accessToken);\n\n if (!payload) {\n return null;\n }\n\n return {\n user,\n accessToken,\n expiresAt: payload.exp * 1000,\n };\n } catch (error) {\n console.error('Failed to get server session:', error);\n return null;\n }\n}\n\n/**\n * Fetch user data from Django backend\n */\nasync function fetchUser(\n apiBaseUrl: string,\n accessToken: string\n): Promise<AuthUser> {\n const response = await fetch(`${apiBaseUrl}/api/v1/auth/me/`, {\n headers: {\n Authorization: `Bearer ${accessToken}`,\n },\n cache: 'no-store',\n });\n\n if (!response.ok) {\n throw new Error('Failed to fetch user');\n }\n\n return response.json();\n}\n\n/**\n * Validate session and return user or null\n */\nexport async function validateSession(\n apiBaseUrl: string\n): Promise<AuthUser | null> {\n const session = await getServerSession(apiBaseUrl);\n return session?.user || null;\n}\n\n/**\n * Require authenticated session (throws if not authenticated)\n */\nexport async function requireAuth(apiBaseUrl: string): Promise<Session> {\n const session = await getServerSession(apiBaseUrl);\n\n if (!session) {\n throw new Error('Unauthorized');\n }\n\n return session;\n}\n\n/**\n * Refresh access token using refresh token cookie\n */\nexport async function refreshServerToken(\n apiBaseUrl: string\n): Promise<string | null> {\n try {\n const response = await fetch(`${apiBaseUrl}/api/v1/auth/token/refresh/`, {\n method: 'POST',\n headers: {\n 'Content-Type': 'application/json',\n },\n credentials: 'include',\n });\n\n if (!response.ok) {\n return null;\n }\n\n const data = await response.json();\n return data.access;\n } catch (error) {\n console.error('Token refresh failed:', error);\n return null;\n }\n}\n","/**\n * Next.js middleware helpers for authentication\n */\n\nimport { NextRequest, NextResponse } from 'next/server';\nimport { isTokenExpired } from '../utils';\n\nexport interface AuthMiddlewareConfig {\n apiBaseUrl: string;\n publicPaths?: string[];\n loginPath?: string;\n}\n\n/**\n * Create auth middleware for Next.js\n */\nexport function createAuthMiddleware(config: AuthMiddlewareConfig) {\n const {\n apiBaseUrl,\n publicPaths = ['/login', '/register', '/forgot-password'],\n loginPath = '/login',\n } = config;\n\n return async function authMiddleware(request: NextRequest) {\n const { pathname } = request.nextUrl;\n\n const isPublicPath = publicPaths.some((path) =>\n pathname.startsWith(path)\n );\n\n if (isPublicPath) {\n return NextResponse.next();\n }\n\n const accessToken = request.cookies.get('access_token')?.value;\n\n if (!accessToken || isTokenExpired(accessToken)) {\n const url = request.nextUrl.clone();\n url.pathname = loginPath;\n url.searchParams.set('from', pathname);\n return NextResponse.redirect(url);\n }\n\n return NextResponse.next();\n };\n}\n\n/**\n * Check if request has valid auth token\n */\nexport function hasValidToken(request: NextRequest): boolean {\n const accessToken = request.cookies.get('access_token')?.value;\n\n if (!accessToken) {\n return false;\n }\n\n return !isTokenExpired(accessToken);\n}\n\n/**\n * Get access token from request\n */\nexport function getRequestToken(request: NextRequest): string | null {\n const accessToken = request.cookies.get('access_token')?.value;\n\n if (!accessToken) {\n return null;\n }\n\n if (isTokenExpired(accessToken)) {\n return null;\n }\n\n return accessToken;\n}\n\n/**\n * Extract bearer token from a standard Request (Authorization header or access_token cookie).\n * Framework-agnostic — works with any Request-compatible object (Next.js, Node, edge runtimes).\n * Returns the raw token string without expiry validation.\n */\nexport function getTokenFromRequest(req: Request): string | undefined {\n // Authorization: Bearer <token>\n const authHeader = req.headers.get('authorization');\n if (authHeader?.startsWith('Bearer ')) {\n const token = authHeader.slice(7).trim();\n if (token) return token;\n }\n\n // Fallback: access_token cookie (parsed from Cookie header)\n const cookieHeader = req.headers.get('cookie');\n if (cookieHeader) {\n const match = cookieHeader\n .split(';')\n .map((part) => part.trim())\n .find((part) => part.startsWith('access_token='));\n\n if (match) {\n const token = match.slice('access_token='.length).trim();\n if (token) return token;\n }\n }\n\n return undefined;\n}\n","/**\n * Authentication types for StartSimpli apps\n */\n\n/**\n * Generic token pair (access + optional refresh)\n */\nexport interface TokenPair {\n access: string;\n refresh?: string;\n}\n\n/**\n * Generic decoded JWT payload — framework and backend agnostic\n */\nexport interface DecodedToken {\n sub?: string;\n email?: string;\n exp?: number;\n iat?: number;\n [key: string]: unknown;\n}\n\n/**\n * Generic auth session — framework agnostic\n */\nexport interface AuthSession {\n user: {\n id: string;\n email: string;\n [key: string]: unknown;\n };\n accessToken: string;\n refreshToken?: string;\n}\n\n/**\n * User profile from Django backend\n */\nexport interface AuthUser {\n id: string;\n email: string;\n firstName: string;\n lastName: string;\n isEmailVerified: boolean;\n createdAt: string;\n updatedAt: string;\n // Company/team context (if applicable)\n companies?: Array<{\n id: string;\n name: string;\n role: 'owner' | 'admin' | 'member' | 'viewer';\n }>;\n currentCompanyId?: string;\n}\n\n/**\n * JWT token payload structure\n */\nexport interface TokenPayload {\n token_type: 'access';\n exp: number;\n iat: number;\n jti: string;\n user_id: string;\n}\n\n/**\n * Session data stored in client\n */\nexport interface Session {\n user: AuthUser;\n accessToken: string;\n expiresAt: number;\n}\n\n/**\n * Login response from Django backend\n */\nexport interface LoginResponse {\n access: string;\n user: AuthUser;\n}\n\n/**\n * Token refresh response\n */\nexport interface RefreshResponse {\n access: string;\n}\n\n/**\n * Permission check result\n */\nexport interface PermissionCheck {\n hasPermission: boolean;\n reason?: string;\n}\n\n/**\n * Auth configuration options\n */\nexport interface AuthConfig {\n apiBaseUrl: string;\n tokenRefreshInterval?: number; // milliseconds, default 4 minutes\n onSessionExpired?: () => void;\n onUnauthorized?: () => void;\n}\n\n/**\n * Auth state for React context\n */\nexport interface AuthState {\n session: Session | null;\n isLoading: boolean;\n isAuthenticated: boolean;\n}\n\n/**\n * Company role hierarchy\n */\nexport type CompanyRole = 'owner' | 'admin' | 'member' | 'viewer';\n\n/**\n * Role hierarchy map (higher number = more permissions)\n */\nexport const ROLE_HIERARCHY: Record<CompanyRole, number> = {\n owner: 4,\n admin: 3,\n member: 2,\n viewer: 1,\n};\n\n/**\n * Check if role has sufficient permissions\n */\nexport function hasRolePermission(\n userRole: CompanyRole,\n requiredRole: CompanyRole\n): boolean {\n return ROLE_HIERARCHY[userRole] >= ROLE_HIERARCHY[requiredRole];\n}\n\n/**\n * Password reset request payload\n * Initiates password reset flow by sending reset email\n */\nexport interface PasswordResetRequest {\n email: string;\n clientMetadata?: Record<string, any>;\n}\n\n/**\n * Password reset confirmation payload\n * Completes password reset with token and new password\n */\nexport interface PasswordResetConfirm {\n token: string;\n password: string;\n passwordConfirm: string;\n}\n\n/**\n * Email verification request payload\n * Verifies user email with token from verification email\n */\nexport interface EmailVerificationRequest {\n token: string;\n}\n\n/**\n * Email verification response\n * Returns updated user data after successful verification\n */\nexport interface EmailVerificationResponse {\n detail: string;\n user: {\n id: string;\n email: string;\n isEmailVerified: boolean;\n };\n}\n\n/**\n * API error response from Django backend\n * Standard error format for all API errors\n */\nexport interface ApiErrorResponse {\n detail?: string;\n message?: string;\n errors?: Record<string, string[]>;\n code?: string;\n status?: number;\n}\n\n/**\n * Validation error detail\n * Individual field validation error\n */\nexport interface ValidationError {\n field: string;\n message: string;\n code?: string;\n}\n\n/**\n * Validation errors map\n * Maps field names to error messages\n */\nexport type ValidationErrorsMap = Record<string, string[]>;\n\n/**\n * Password validation error codes\n */\nexport enum PasswordErrorCode {\n TOO_SHORT = 'password_too_short',\n TOO_COMMON = 'password_too_common',\n ENTIRELY_NUMERIC = 'password_entirely_numeric',\n TOO_SIMILAR = 'password_too_similar',\n MISMATCH = 'password_mismatch',\n REQUIRED = 'password_required',\n}\n\n/**\n * Email validation error codes\n */\nexport enum EmailErrorCode {\n INVALID_FORMAT = 'email_invalid_format',\n REQUIRED = 'email_required',\n NOT_FOUND = 'email_not_found',\n ALREADY_EXISTS = 'email_already_exists',\n}\n\n/**\n * General validation error codes\n */\nexport enum ValidationErrorCode {\n REQUIRED = 'required',\n INVALID = 'invalid',\n TOO_SHORT = 'too_short',\n TOO_LONG = 'too_long',\n}\n","/**\n * Auth guards for API routes\n */\n\nimport { NextRequest, NextResponse } from 'next/server';\nimport type { CompanyRole } from '../types';\nimport { hasRolePermission } from '../types';\nimport { getRequestToken } from './middleware';\n\n/**\n * Auth guard result\n */\nexport interface GuardResult {\n authorized: boolean;\n response?: NextResponse;\n token?: string;\n}\n\n/**\n * Require authentication for API route\n */\nexport async function requireAuthGuard(\n request: NextRequest\n): Promise<GuardResult> {\n const token = getRequestToken(request);\n\n if (!token) {\n return {\n authorized: false,\n response: NextResponse.json(\n { error: 'Unauthorized' },\n { status: 401 }\n ),\n };\n }\n\n return {\n authorized: true,\n token,\n };\n}\n\n/**\n * Require specific role for API route\n */\nexport async function requireRoleGuard(\n request: NextRequest,\n requiredRole: CompanyRole,\n getUserRole: () => Promise<CompanyRole | null>\n): Promise<GuardResult> {\n const authResult = await requireAuthGuard(request);\n\n if (!authResult.authorized) {\n return authResult;\n }\n\n const userRole = await getUserRole();\n\n if (!userRole || !hasRolePermission(userRole, requiredRole)) {\n return {\n authorized: false,\n response: NextResponse.json(\n { error: 'Forbidden' },\n { status: 403 }\n ),\n };\n }\n\n return {\n authorized: true,\n token: authResult.token,\n };\n}\n\n/**\n * Higher-order function to wrap API route with auth guard\n */\nexport function withAuth<T = any>(\n handler: (request: NextRequest, token: string) => Promise<NextResponse<T>>\n) {\n return async (request: NextRequest): Promise<NextResponse> => {\n const guardResult = await requireAuthGuard(request);\n\n if (!guardResult.authorized) {\n return guardResult.response!;\n }\n\n return handler(request, guardResult.token!);\n };\n}\n\n/**\n * Higher-order function to wrap API route with role guard\n */\nexport function withRole<T = any>(\n requiredRole: CompanyRole,\n getUserRole: () => Promise<CompanyRole | null>,\n handler: (request: NextRequest, token: string) => Promise<NextResponse<T>>\n) {\n return async (request: NextRequest): Promise<NextResponse> => {\n const guardResult = await requireRoleGuard(\n request,\n requiredRole,\n getUserRole\n );\n\n if (!guardResult.authorized) {\n return guardResult.response!;\n }\n\n return handler(request, guardResult.token!);\n };\n}\n"]}
@@ -1,5 +1,5 @@
1
- import { isTokenExpired, decodeToken } from '../chunk-S6J5FYQY.mjs';
2
- import { hasRolePermission } from '../chunk-TA46ASDJ.mjs';
1
+ import { isTokenExpired, decodeToken } from '../chunk-AADTGAI2.mjs';
2
+ import { hasRolePermission } from '../chunk-QAXZGJNQ.mjs';
3
3
  import { cookies } from 'next/headers';
4
4
  import { NextResponse } from 'next/server';
5
5
 
@@ -1,3 +1,3 @@
1
- export { EmailErrorCode, PasswordErrorCode, ROLE_HIERARCHY, ValidationErrorCode, hasRolePermission } from '../chunk-TA46ASDJ.mjs';
1
+ export { EmailErrorCode, PasswordErrorCode, ROLE_HIERARCHY, ValidationErrorCode, hasRolePermission } from '../chunk-QAXZGJNQ.mjs';
2
2
  //# sourceMappingURL=index.mjs.map
3
3
  //# sourceMappingURL=index.mjs.map
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@startsimpli/auth",
3
- "version": "0.1.3",
3
+ "version": "0.1.4",
4
4
  "description": "Shared authentication package for StartSimpli Next.js apps",
5
5
  "main": "./dist/index.js",
6
6
  "types": "./dist/index.d.ts",