web-mojo 2.1.682 → 2.1.698

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.
Files changed (65) hide show
  1. package/dist/admin.cjs.js +1 -1
  2. package/dist/admin.cjs.js.map +1 -1
  3. package/dist/admin.es.js +18 -10
  4. package/dist/admin.es.js.map +1 -1
  5. package/dist/auth.cjs.js +1 -1
  6. package/dist/auth.cjs.js.map +1 -1
  7. package/dist/auth.es.js +3 -3
  8. package/dist/auth.es.js.map +1 -1
  9. package/dist/charts.cjs.js +1 -1
  10. package/dist/charts.es.js +2 -2
  11. package/dist/chunks/{ChatView-rQxIKciq.js → ChatView-Cl4A2GG_.js} +11 -10
  12. package/dist/chunks/ChatView-Cl4A2GG_.js.map +1 -0
  13. package/dist/chunks/ChatView-DKHI5WSQ.js +2 -0
  14. package/dist/chunks/ChatView-DKHI5WSQ.js.map +1 -0
  15. package/dist/chunks/{ContextMenu-47O2lbsV.js → ContextMenu-C7VR2K56.js} +2 -2
  16. package/dist/chunks/{ContextMenu-47O2lbsV.js.map → ContextMenu-C7VR2K56.js.map} +1 -1
  17. package/dist/chunks/{ContextMenu-bEra2rOd.js → ContextMenu-ZMjPSCOL.js} +2 -2
  18. package/dist/chunks/{ContextMenu-bEra2rOd.js.map → ContextMenu-ZMjPSCOL.js.map} +1 -1
  19. package/dist/chunks/{DataView-Dp4LZC_P.js → DataView-BdDvQgda.js} +29 -15
  20. package/dist/chunks/DataView-BdDvQgda.js.map +1 -0
  21. package/dist/chunks/DataView-C2J-ES5x.js +2 -0
  22. package/dist/chunks/DataView-C2J-ES5x.js.map +1 -0
  23. package/dist/chunks/{Dialog-Dls3VAB8.js → Dialog-7Q6jVzma.js} +5 -5
  24. package/dist/chunks/{Dialog-Dls3VAB8.js.map → Dialog-7Q6jVzma.js.map} +1 -1
  25. package/dist/chunks/{Dialog-D-N9fnIq.js → Dialog-DcEsiySb.js} +2 -2
  26. package/dist/chunks/{Dialog-D-N9fnIq.js.map → Dialog-DcEsiySb.js.map} +1 -1
  27. package/dist/chunks/{FormView-BkBLv7Jy.js → FormView-D1GaAaSs.js} +98 -5
  28. package/dist/chunks/FormView-D1GaAaSs.js.map +1 -0
  29. package/dist/chunks/{FormView-jQkvTThx.js → FormView-NYlkp_rL.js} +2 -2
  30. package/dist/chunks/FormView-NYlkp_rL.js.map +1 -0
  31. package/dist/chunks/{MetricsMiniChartWidget-D0Eq9agy.js → MetricsMiniChartWidget-Cgl3z0P7.js} +21 -11
  32. package/dist/chunks/{MetricsMiniChartWidget-D0Eq9agy.js.map → MetricsMiniChartWidget-Cgl3z0P7.js.map} +1 -1
  33. package/dist/chunks/{MetricsMiniChartWidget-B9xu8Wzh.js → MetricsMiniChartWidget-DnvuJLYU.js} +2 -2
  34. package/dist/chunks/{MetricsMiniChartWidget-B9xu8Wzh.js.map → MetricsMiniChartWidget-DnvuJLYU.js.map} +1 -1
  35. package/dist/chunks/{PDFViewer-GCsxAgql.js → PDFViewer-0XGpnus3.js} +2 -2
  36. package/dist/chunks/{PDFViewer-GCsxAgql.js.map → PDFViewer-0XGpnus3.js.map} +1 -1
  37. package/dist/chunks/{PDFViewer-CtziqVkB.js → PDFViewer-Bm0_D3So.js} +3 -3
  38. package/dist/chunks/{PDFViewer-CtziqVkB.js.map → PDFViewer-Bm0_D3So.js.map} +1 -1
  39. package/dist/chunks/{Page-BnEgQPcR.js → Page-CusMiM2I.js} +2 -2
  40. package/dist/chunks/{Page-BnEgQPcR.js.map → Page-CusMiM2I.js.map} +1 -1
  41. package/dist/chunks/{Page-DlOiEuua.js → Page-dbGRgWFn.js} +2 -2
  42. package/dist/chunks/{Page-DlOiEuua.js.map → Page-dbGRgWFn.js.map} +1 -1
  43. package/dist/chunks/{TopNav-BDcnSuji.js → TopNav-BtI4SIXh.js} +2 -2
  44. package/dist/chunks/{TopNav-BDcnSuji.js.map → TopNav-BtI4SIXh.js.map} +1 -1
  45. package/dist/chunks/{TopNav-DVvNdyUm.js → TopNav-CG0_zVCD.js} +5 -5
  46. package/dist/chunks/{TopNav-DVvNdyUm.js.map → TopNav-CG0_zVCD.js.map} +1 -1
  47. package/dist/chunks/{WebApp--rBzVI7e.js → WebApp-B5MSTwfY.js} +2 -2
  48. package/dist/chunks/{WebApp--rBzVI7e.js.map → WebApp-B5MSTwfY.js.map} +1 -1
  49. package/dist/chunks/{WebApp-DF_USeWe.js → WebApp-BH3MsXRH.js} +13 -13
  50. package/dist/chunks/{WebApp-DF_USeWe.js.map → WebApp-BH3MsXRH.js.map} +1 -1
  51. package/dist/docit.cjs.js +1 -1
  52. package/dist/docit.es.js +5 -5
  53. package/dist/index.cjs.js +1 -1
  54. package/dist/index.es.js +11 -11
  55. package/dist/lightbox.cjs.js +1 -1
  56. package/dist/lightbox.es.js +4 -4
  57. package/package.json +1 -1
  58. package/dist/chunks/ChatView-ZaRZ-1wA.js +0 -2
  59. package/dist/chunks/ChatView-ZaRZ-1wA.js.map +0 -1
  60. package/dist/chunks/ChatView-rQxIKciq.js.map +0 -1
  61. package/dist/chunks/DataView-Dp4LZC_P.js.map +0 -1
  62. package/dist/chunks/DataView-I8leh-EL.js +0 -2
  63. package/dist/chunks/DataView-I8leh-EL.js.map +0 -1
  64. package/dist/chunks/FormView-BkBLv7Jy.js.map +0 -1
  65. package/dist/chunks/FormView-jQkvTThx.js.map +0 -1
@@ -1 +1 @@
1
- {"version":3,"file":"auth.es.js","sources":["../src/extensions/auth/AuthManager.js","../src/extensions/auth/pages/LoginPage.js","../src/extensions/auth/pages/RegisterPage.js","../src/extensions/auth/pages/ForgotPasswordPage.js","../src/extensions/auth/pages/ResetPasswordPage.js","../src/templates.js","../src/extensions/auth/AuthApp.js","../src/extensions/auth/plugins/PasskeyPlugin.js"],"sourcesContent":["/**\n * AuthManager - Simplified authentication state management for MOJO Framework\n * Handles auth state, integrates with AuthService and TokenManager, supports plugins\n */\n\nimport TokenManager from '@core/services/TokenManager.js';\n\nexport default class AuthManager {\n constructor(app, config = {}) {\n this.app = app;\n this.config = {\n autoRefresh: true,\n refreshThreshold: 5, // minutes before expiry\n plugins: {},\n ...config\n };\n\n // Core services\n this.tokenManager = new TokenManager();\n\n // Auth state\n this.isAuthenticated = false;\n this.user = null;\n this.refreshTimer = null;\n\n // Plugin registry\n this.plugins = new Map();\n\n // Initialize\n this.initialize();\n }\n\n /**\n * Initialize auth manager\n */\n initialize() {\n // Check for existing valid session\n this.checkAuthState();\n\n // Set up auto-refresh if enabled\n if (this.config.autoRefresh) {\n this.scheduleTokenRefresh();\n }\n\n // Make auth manager available to app\n if (this.app) {\n this.app.auth = this;\n }\n }\n\n /**\n * Check current authentication state from stored tokens\n */\n checkAuthState() {\n if (this.tokenManager.isValid()) {\n const userInfo = this.tokenManager.getUserInfo();\n if (userInfo) {\n this.setAuthState(userInfo);\n return true;\n }\n }\n\n this.clearAuthState();\n return false;\n }\n\n /**\n * Login with username/email and password\n * @param {string} username - Username or email\n * @param {string} password - Password\n * @param {boolean} rememberMe - Persist session\n * @returns {Promise<object>} Login result\n */\n async login(username, password, rememberMe = true) {\n const response = await this.app.rest.POST('/api/login', { username, password });\n\n if (response.success && response.data.status) {\n const { access_token, refresh_token, user } = response.data.data;\n\n // Store tokens\n this.tokenManager.setTokens(access_token, refresh_token, rememberMe);\n\n // Set auth state\n const userInfo = this.tokenManager.getUserInfo();\n this.setAuthState({ ...user, ...userInfo });\n\n // Schedule refresh\n if (this.config.autoRefresh) {\n this.scheduleTokenRefresh();\n }\n\n this.emit('login', this.user);\n return { success: true, user: this.user };\n }\n\n const message = response.data?.error || response.message || 'Login failed. Please try again.';\n this.emit('loginError', { message });\n return { success: false, message };\n }\n\n /**\n * Register new user\n * @param {object} userData - Registration data\n * @returns {Promise<object>} Registration result\n */\n async register(userData) {\n const response = await this.app.rest.POST('/api/register', userData);\n\n if (response.success && response.data.status) {\n const { token, refreshToken, user } = response.data.data;\n\n // Store tokens\n this.tokenManager.setTokens(token, refreshToken, true);\n\n // Set auth state\n const userInfo = this.tokenManager.getUserInfo();\n this.setAuthState({ ...user, ...userInfo });\n\n // Schedule refresh\n if (this.config.autoRefresh) {\n this.scheduleTokenRefresh();\n }\n\n this.emit('register', this.user);\n return { success: true, user: this.user };\n }\n\n const message = response.data?.error || response.message || 'Registration failed.';\n this.emit('registerError', { message });\n return { success: false, message };\n }\n\n /**\n * Logout current user\n */\n async logout() {\n try {\n const token = this.tokenManager.getToken();\n if (token) {\n // Call logout API but don't block logout on failure\n this.app.rest.POST('/api/auth/logout').catch(err => {\n console.warn('Server logout failed, proceeding with local logout.', err);\n });\n }\n } finally {\n this.clearAuthState();\n this.emit('logout');\n }\n }\n\n /**\n * Refresh access token\n * @returns {Promise<boolean>} Success status\n */\n async refreshToken() {\n const refreshToken = this.tokenManager.getRefreshToken();\n if (!refreshToken) {\n this.clearAuthState();\n this.emit('tokenExpired');\n return false;\n }\n\n const response = await this.app.rest.POST('/api/auth/token/refresh', { refreshToken });\n\n if (response.success && response.data.status) {\n const { token, refreshToken: newRefreshToken } = response.data.data;\n\n // Determine persistence from current storage\n const isPersistent = !!localStorage.getItem(this.tokenManager.tokenKey);\n\n // Store new tokens\n this.tokenManager.setTokens(token, newRefreshToken, isPersistent);\n\n // Update user info\n const userInfo = this.tokenManager.getUserInfo();\n if (userInfo) {\n this.user = { ...this.user, ...userInfo };\n }\n\n // Schedule next refresh\n this.scheduleTokenRefresh();\n\n this.emit('tokenRefreshed');\n return true;\n }\n\n console.error('Token refresh failed:', response.data?.error || response.message);\n this.clearAuthState();\n this.emit('tokenExpired');\n return false;\n }\n\n /**\n * Set authentication state\n * @param {object} user - User data\n */\n setAuthState(user) {\n this.isAuthenticated = true;\n this.user = user;\n\n if (this.app?.setState) {\n this.app.setState('auth', {\n isAuthenticated: true,\n user: user\n });\n }\n }\n\n /**\n * Clear authentication state\n */\n clearAuthState() {\n this.isAuthenticated = false;\n this.user = null;\n this.tokenManager.clearTokens();\n\n if (this.refreshTimer) {\n clearTimeout(this.refreshTimer);\n this.refreshTimer = null;\n }\n\n if (this.app?.setState) {\n this.app.setState('auth', {\n isAuthenticated: false,\n user: null\n });\n }\n }\n\n /**\n * Schedule automatic token refresh\n */\n scheduleTokenRefresh() {\n if (this.refreshTimer) {\n clearTimeout(this.refreshTimer);\n }\n\n if (!this.tokenManager.isValid()) {\n return;\n }\n\n if (this.tokenManager.isExpiringSoon(this.config.refreshThreshold)) {\n // Token expires soon, refresh immediately\n this.refreshToken();\n return;\n }\n\n // Schedule refresh before expiry\n const token = this.tokenManager.getToken();\n const payload = this.tokenManager.decode(token);\n if (payload?.exp) {\n const now = Math.floor(Date.now() / 1000);\n const timeUntilRefresh = (payload.exp - now - (this.config.refreshThreshold * 60)) * 1000;\n\n if (timeUntilRefresh > 0) {\n this.refreshTimer = setTimeout(() => {\n this.refreshToken();\n }, timeUntilRefresh);\n }\n }\n }\n\n /**\n * Register a plugin\n * @param {string} name - Plugin name\n * @param {object} plugin - Plugin instance\n */\n registerPlugin(name, plugin) {\n this.plugins.set(name, plugin);\n plugin.initialize(this, this.app);\n }\n\n /**\n * Get a plugin by name\n * @param {string} name - Plugin name\n * @returns {object|null} Plugin instance\n */\n getPlugin(name) {\n return this.plugins.get(name) || null;\n }\n\n /**\n * Request password reset\n * @param {string} email - User email\n * @returns {Promise<object>} Request result\n */\n async forgotPassword(email, method = 'code') {\n const response = await this.app.rest.POST('/api/auth/forgot', { email, method });\n\n if (response.success && response.data.status) {\n this.emit('forgotPasswordSuccess', { email, method });\n return { success: true, message: response.data.data?.message };\n }\n\n const message = response.data?.error || response.message || 'Failed to process request.';\n this.emit('forgotPasswordError', { message });\n return { success: false, message };\n }\n\n /**\n * Reset password with a token from an email link\n * @param {string} token - Reset token\n * @param {string} newPassword - New password\n * @returns {Promise<object>} Reset result\n */\n async resetPasswordWithToken(token, newPassword) {\n const payload = {\n token: token,\n new_password: newPassword\n };\n const response = await this.app.rest.POST('/api/auth/password/reset/token', payload);\n\n if (response.success && response.data.status) {\n this.emit('resetPasswordSuccess');\n return { success: true, message: response.data.data?.message };\n }\n\n const message = response.data?.error || response.message || 'Failed to reset password.';\n this.emit('resetPasswordError', { message });\n return { success: false, message };\n }\n\n /**\n * Reset password with an email and code\n * @param {string} email - User's email\n * @param {string} code - The verification code\n * @param {string} newPassword - New password\n * @returns {Promise<object>} Reset result\n */\n async resetPasswordWithCode(email, code, newPassword) {\n const payload = {\n email: email,\n code: code,\n new_password: newPassword\n };\n const response = await this.app.rest.POST('/api/auth/password/reset/code', payload);\n\n if (response.success && response.data.status) {\n this.emit('resetPasswordSuccess');\n return { success: true, message: response.data.data?.message };\n }\n\n const message = response.data?.error || response.message || 'Failed to reset password.';\n this.emit('resetPasswordError', { message });\n return { success: false, message };\n }\n\n /**\n * Get authorization header for API requests\n * @returns {string|null} Authorization header\n */\n getAuthHeader() {\n return this.tokenManager.getAuthHeader();\n }\n\n /**\n * Emit event to app\n * @param {string} event - Event name\n * @param {*} data - Event data\n */\n emit(event, data) {\n if (this.app?.events?.emit) {\n this.app.events.emit(`auth:${event}`, data);\n }\n }\n\n /**\n * Cleanup auth manager\n */\n destroy() {\n if (this.refreshTimer) {\n clearTimeout(this.refreshTimer);\n }\n\n this.plugins.forEach(plugin => {\n if (plugin.destroy) {\n plugin.destroy();\n }\n });\n\n this.plugins.clear();\n }\n}\n","/**\n * LoginPage - Simplified login page for MOJO Auth\n * Handles username/email and password authentication with optional passkey support\n */\n\nimport Page from '@core/Page.js';\nimport { VERSION } from '/src/version.js';\n\nexport default class LoginPage extends Page {\n static pageName = 'login';\n static title = 'Login';\n static icon = 'bi-box-arrow-in-right';\n static route = '/login';\n\n constructor(options = {}) {\n super({\n ...options,\n pageName: LoginPage.pageName,\n route: options.route || LoginPage.route,\n pageIcon: LoginPage.icon,\n template: options.template,\n });\n\n // Get auth config from options (passed from AuthApp)\n this.authConfig = options.authConfig || {\n ui: {\n title: 'My App',\n logoUrl: '/assets/logo.png',\n messages: {\n loginTitle: 'Welcome Back',\n loginSubtitle: 'Sign in to your account'\n }\n },\n features: {\n rememberMe: false,\n forgotPassword: true,\n registration: false\n }\n };\n }\n\n async onInit() {\n await super.onInit();\n\n // Initialize form data\n this.data = {\n\n // Form fields\n username: '',\n password: '',\n rememberMe: true,\n loginIcon: this.options.pageIcon,\n // UI state\n isLoading: false,\n error: null,\n showPassword: false,\n version: VERSION,\n // Feature availability\n passkeySupported: this.getApp().auth?.isPasskeySupported?.() || false,\n // Config data for template\n ...this.authConfig.ui,\n ...this.authConfig.features,\n\n };\n }\n\n async onEnter() {\n await super.onEnter();\n\n // Set page title\n document.title = `${LoginPage.title} - ${this.authConfig.ui.title}`;\n\n // Check if already authenticated\n const auth = this.getApp().auth;\n if (auth?.isAuthenticated) {\n this.getApp().navigate('/');\n return;\n }\n\n // Clear form and errors\n this.updateData({\n username: '',\n password: '',\n error: null,\n isLoading: false\n });\n }\n\n async onAfterRender() {\n await super.onAfterRender();\n\n // Focus on username input\n const usernameInput = this.element.querySelector('#loginUsername');\n if (usernameInput) {\n usernameInput.focus();\n }\n }\n\n /**\n * Handle field updates\n */\n async onActionUpdateField(event, element) {\n const field = element.dataset.field;\n const value = element.type === 'checkbox' ? element.checked : element.value;\n\n this.updateData({\n [field]: value,\n error: null // Clear error on input change\n });\n }\n\n /**\n * Toggle password visibility\n */\n async onActionTogglePassword(event) {\n event.preventDefault();\n this.updateData({ showPassword: !this.data.showPassword });\n\n // Update input type\n const passwordInput = this.element.querySelector('#loginPassword');\n if (passwordInput) {\n passwordInput.type = this.data.showPassword ? 'text' : 'password';\n }\n }\n\n /**\n * Handle login form submission\n */\n async onActionLogin(event) {\n event.preventDefault();\n\n // Manually get values from form inputs on submit\n this.data.username = this.element.querySelector('#loginUsername')?.value || '';\n this.data.password = this.element.querySelector('#loginPassword')?.value || '';\n\n await this.updateData({ error: null, isLoading: true }, true);\n\n const auth = this.getApp().auth;\n if (!auth) {\n await this.updateData({ error: 'Authentication system not available', isLoading: false }, true);\n return;\n }\n\n // Basic validation\n if (!this.data.username || !this.data.password) {\n await this.updateData({ error: 'Please enter both username and password', isLoading: false }, true);\n return;\n }\n\n const result = await auth.login(\n this.data.username,\n this.data.password,\n this.data.rememberMe\n );\n\n if (!result.success) {\n await this.updateData({\n error: result.message,\n isLoading: false\n }, true);\n\n // Focus password field for retry\n const passwordInput = this.element.querySelector('#loginPassword');\n if (passwordInput) {\n passwordInput.focus();\n passwordInput.select();\n }\n }\n // On success, the global 'auth:login' event will trigger navigation.\n }\n\n /**\n * Handle passkey login\n */\n async onActionLoginWithPasskey(event) {\n event.preventDefault();\n\n const auth = this.getApp().auth;\n if (!auth?.isPasskeySupported?.()) {\n this.getApp().showError('Passkey authentication is not supported');\n return;\n }\n\n this.updateData({ error: null, isLoading: true });\n\n try {\n const result = await auth.loginWithPasskey();\n\n if (result.success) {\n // Success handled by AuthApp event handlers\n console.log('Passkey login successful');\n }\n\n } catch (error) {\n console.error('Passkey login error:', error);\n this.updateData({\n error: 'Passkey authentication failed. Please try another method.',\n isLoading: false\n });\n }\n }\n\n /**\n * Navigate to registration page\n */\n async onActionRegister(event) {\n event.preventDefault();\n this.getApp().navigate('/register');\n }\n\n /**\n * Navigate to forgot password page\n */\n async onActionForgotPassword(event) {\n event.preventDefault();\n this.getApp().navigate('/forgot-password');\n }\n\n /**\n * Handle Enter key in form fields\n */\n async onActionHandleKeyPress(event, element) {\n if (event.key === 'Enter') {\n event.preventDefault();\n\n // Move focus or submit form\n if (element.id === 'loginUsername') {\n const passwordInput = this.element.querySelector('#loginPassword');\n if (passwordInput) {\n passwordInput.focus();\n }\n } else if (element.id === 'loginPassword') {\n await this.onActionLogin(event);\n }\n }\n }\n\n /**\n * Get view data for template rendering\n */\n async getViewData() {\n return {\n ...this.data\n };\n }\n}\n","/**\n * RegisterPage - Simplified registration page for MOJO Auth\n * Handles user registration with name, email/username, password, and optional terms acceptance\n */\n\nimport Page from '@core/Page.js';\n\nexport default class RegisterPage extends Page {\n static pageName = 'auth-register';\n static title = 'Register';\n static icon = 'bi-person-plus';\n static route = 'register';\n\n constructor(options = {}) {\n super({\n ...options,\n pageName: RegisterPage.pageName,\n route: options.route || RegisterPage.route,\n pageIcon: RegisterPage.icon,\n template: options.template\n });\n\n // Get auth config from options (passed from AuthApp)\n this.authConfig = options.authConfig || {\n ui: {\n title: 'My App',\n logoUrl: '/assets/logo.png',\n messages: {\n registerTitle: 'Create Account',\n registerSubtitle: 'Join us today'\n }\n },\n features: {\n registration: true\n }\n };\n }\n\n async onInit() {\n await super.onInit();\n\n // Initialize form data\n this.data = {\n // Config data for template\n ...this.authConfig.ui,\n ...this.authConfig.features,\n\n // Form fields\n name: '',\n email: '',\n password: '',\n confirmPassword: '',\n acceptTerms: false,\n\n // UI state\n isLoading: false,\n error: null,\n showPassword: false,\n showConfirmPassword: false,\n\n // Validation state\n passwordStrength: null,\n passwordMatch: true\n };\n }\n\n async onEnter() {\n await super.onEnter();\n\n // Set page title\n document.title = `${RegisterPage.title} - ${this.authConfig.ui.title}`;\n\n // Check if already authenticated\n const auth = this.getApp().auth;\n if (auth?.isAuthenticated) {\n this.getApp().navigate('/');\n return;\n }\n\n // Clear form and errors\n this.updateData({\n name: '',\n email: '',\n password: '',\n confirmPassword: '',\n acceptTerms: false,\n error: null,\n isLoading: false,\n passwordStrength: null,\n passwordMatch: true\n });\n }\n\n async onAfterRender() {\n await super.onAfterRender();\n\n // Focus on name input\n const nameInput = this.element.querySelector('#registerName');\n if (nameInput) {\n nameInput.focus();\n }\n }\n\n /**\n * Handle field updates\n */\n async onActionUpdateField(event, element) {\n const field = element.dataset.field;\n const value = element.type === 'checkbox' ? element.checked : element.value;\n\n this.updateData({ [field]: value });\n\n // Check password strength when password changes\n if (field === 'password') {\n this.checkPasswordStrength(value);\n }\n\n // Check password match when either password field changes\n if (field === 'password' || field === 'confirmPassword') {\n this.checkPasswordMatch();\n }\n\n // Clear error on input change\n if (this.data.error) {\n this.updateData({ error: null });\n }\n }\n\n /**\n * Check password strength\n */\n checkPasswordStrength(password) {\n let strength = null;\n\n if (password.length === 0) {\n strength = null;\n } else if (password.length < 6) {\n strength = 'weak';\n } else if (password.length < 8) {\n strength = 'fair';\n } else if (/^(?=.*[a-z])(?=.*[A-Z])(?=.*\\d)(?=.*[@$!%*?&])[A-Za-z\\d@$!%*?&]/.test(password)) {\n strength = 'strong';\n } else if (/^(?=.*[a-z])(?=.*[A-Z])(?=.*\\d)/.test(password)) {\n strength = 'good';\n } else {\n strength = 'fair';\n }\n\n this.updateData({ passwordStrength: strength }, true);\n }\n\n /**\n * Check if passwords match\n */\n checkPasswordMatch() {\n const match = !this.data.confirmPassword ||\n this.data.password === this.data.confirmPassword;\n this.updateData({ passwordMatch: match }, true);\n }\n\n /**\n * Toggle password visibility\n */\n async onActionTogglePassword(event, element) {\n event.preventDefault();\n const field = element.dataset.passwordField;\n\n if (field === 'password') {\n this.updateData({ showPassword: !this.data.showPassword });\n const input = this.element.querySelector('#registerPassword');\n if (input) {\n input.type = this.data.showPassword ? 'text' : 'password';\n }\n } else if (field === 'confirmPassword') {\n this.updateData({ showConfirmPassword: !this.data.showConfirmPassword });\n const input = this.element.querySelector('#registerConfirmPassword');\n if (input) {\n input.type = this.data.showConfirmPassword ? 'text' : 'password';\n }\n }\n }\n\n /**\n * Handle registration form submission\n */\n async onActionRegister(event) {\n event.preventDefault();\n await this.updateData({ error: null, isLoading: true }, true);\n\n // Validation\n if (!this.data.name || !this.data.email || !this.data.password || !this.data.confirmPassword) {\n await this.updateData({ error: 'Please fill in all required fields', isLoading: false }, true);\n return;\n }\n if (this.data.name.trim().length < 2) {\n await this.updateData({ error: 'Name must be at least 2 characters long', isLoading: false }, true);\n return;\n }\n const emailRegex = /^[^\\s@]+@[^\\s@]+\\.[^\\s@]+$/;\n if (!emailRegex.test(this.data.email)) {\n await this.updateData({ error: 'Please enter a valid email address', isLoading: false }, true);\n return;\n }\n if (this.data.password.length < 6) {\n await this.updateData({ error: 'Password must be at least 6 characters long', isLoading: false }, true);\n return;\n }\n if (this.data.password !== this.data.confirmPassword) {\n await this.updateData({ error: 'Passwords do not match', isLoading: false }, true);\n return;\n }\n\n const auth = this.getApp().auth;\n if (!auth) {\n await this.updateData({ error: 'Authentication system not available', isLoading: false }, true);\n return;\n }\n\n const registrationData = {\n name: this.data.name.trim(),\n email: this.data.email.toLowerCase().trim(),\n password: this.data.password,\n acceptedTerms: this.data.acceptTerms\n };\n\n const result = await auth.register(registrationData);\n\n if (!result.success) {\n await this.updateData({\n error: result.message || 'Registration failed. Please try again.',\n isLoading: false\n }, true);\n }\n // On success, the global 'auth:register' event will trigger navigation.\n }\n\n /**\n * Navigate to login page\n */\n async onActionLogin(event) {\n event.preventDefault();\n this.getApp().navigate('/login');\n }\n\n /**\n * Handle Enter key in form fields\n */\n async onActionHandleKeyPress(event, element) {\n if (event.key === 'Enter') {\n event.preventDefault();\n\n // Navigate through fields on Enter\n const fieldOrder = ['registerName', 'registerEmail', 'registerPassword', 'registerConfirmPassword'];\n const currentIndex = fieldOrder.indexOf(element.id);\n\n if (currentIndex >= 0 && currentIndex < fieldOrder.length - 1) {\n // Move to next field\n const nextField = this.element.querySelector(`#${fieldOrder[currentIndex + 1]}`);\n if (nextField) {\n nextField.focus();\n }\n } else if (currentIndex === fieldOrder.length - 1) {\n // Last field - submit form\n await this.onActionRegister(event);\n }\n }\n }\n\n /**\n * Get view data for template rendering\n */\n async getViewData() {\n return {\n ...this.data\n };\n }\n}\n","/**\n * ForgotPasswordPage - Simplified password reset page for MOJO Auth\n * Handles password reset request via email, supporting both 'link' and 'code' methods.\n */\nimport Page from '@core/Page.js';\n\nexport default class ForgotPasswordPage extends Page {\n static pageName = 'auth-forgot-password';\n static title = 'Forgot Password';\n static icon = 'bi-key';\n static route = 'forgot-password';\n\n constructor(options = {}) {\n super({ ...options, template: options.template });\n this.authConfig = options.authConfig || {\n passwordResetMethod: 'code',\n ui: { title: 'My App' },\n features: {}\n };\n }\n\n async onInit() {\n this.data = {\n ...this.authConfig.ui,\n ...this.authConfig.features,\n passwordResetMethod: this.authConfig.passwordResetMethod,\n step: 'email', // 'email', 'code', 'link_sent', 'success'\n isLoading: false,\n error: null,\n email: '' // Store email across steps\n };\n }\n\n async onEnter() {\n document.title = `${ForgotPasswordPage.title} - ${this.authConfig.ui.title}`;\n this.updateData({\n step: 'email',\n isLoading: false,\n error: null,\n email: ''\n });\n }\n\n /**\n * Gets data from the currently visible form.\n * @param {string} formSelector - The CSS selector for the form.\n * @returns {object} An object containing the form data.\n */\n getFormData(formSelector) {\n const form = this.element.querySelector(formSelector);\n if (!form) return {};\n const formData = new FormData(form);\n return Object.fromEntries(formData.entries());\n }\n\n /**\n * Handles the initial request to reset a password.\n */\n async onActionRequestReset() {\n const { email } = this.getFormData('#form-request-reset');\n await this.updateData({ isLoading: true, error: null, email }, true);\n\n if (!email) {\n return this.updateData({ error: 'Please enter your email address', isLoading: false }, true);\n }\n\n const auth = this.getApp().auth;\n const resetMethod = this.authConfig.passwordResetMethod || 'code';\n const response = await auth.forgotPassword(email, resetMethod);\n\n if (resetMethod === 'link') {\n await this.updateData({ step: 'link_sent', isLoading: false }, true);\n if (!response.success) console.error('Forgot password (link) error:', response.message);\n } else {\n if (response.success) {\n await this.updateData({ step: 'code', isLoading: false }, true);\n } else {\n await this.updateData({ error: response.message, isLoading: false }, true);\n }\n }\n }\n\n /**\n * Handles the final password reset using a verification code.\n */\n async onActionResetWithCode() {\n const { code, new_password, confirm_password } = this.getFormData('#form-reset-with-code');\n await this.updateData({ isLoading: true, error: null }, true);\n\n if (!code || !new_password) {\n return this.updateData({ error: 'Please enter the code and your new password', isLoading: false }, true);\n }\n if (new_password !== confirm_password) {\n return this.updateData({ error: 'Passwords do not match', isLoading: false }, true);\n }\n\n const auth = this.getApp().auth;\n const response = await auth.resetPasswordWithCode(this.data.email, code, new_password);\n\n if (response.success) {\n await this.updateData({ step: 'success', isLoading: false }, true);\n setTimeout(() => this.getApp().navigate('/login'), 3000);\n } else {\n await this.updateData({ error: response.message, isLoading: false }, true);\n }\n }\n\n async onActionBackToLogin() {\n this.getApp().navigate('/login');\n }\n\n // --- Template Getters for State ---\n\n get isStepEmail() {\n return this.data.step === 'email';\n }\n\n get isStepCode() {\n return this.data.step === 'code';\n }\n\n get isStepLinkSent() {\n return this.data.step === 'link_sent';\n }\n\n get isStepSuccess() {\n return this.data.step === 'success';\n }\n}\n","/**\n * ResetPasswordPage - Password reset completion page for MOJO Auth\n * Handles password reset when user clicks email link with reset token\n */\n\nimport Page from '@core/Page.js';\n\nexport default class ResetPasswordPage extends Page {\n static pageName = 'auth-reset-password';\n static title = 'Reset Password';\n static icon = 'bi-key-fill';\n static route = 'reset-password';\n\n constructor(options = {}) {\n super({\n ...options,\n pageName: ResetPasswordPage.pageName,\n route: options.route || ResetPasswordPage.route,\n pageIcon: ResetPasswordPage.icon,\n template: 'auth/pages/ResetPasswordPage.mst'\n });\n\n // Get auth config from options (passed from AuthApp)\n this.authConfig = options.authConfig || {\n ui: {\n title: 'My App',\n logoUrl: '/assets/logo.png',\n messages: {\n resetTitle: 'Set New Password',\n resetSubtitle: 'Choose a strong password'\n }\n },\n features: {\n registration: true\n }\n };\n\n // Extract reset token from URL\n this.resetToken = null;\n }\n\n async onInit() {\n await super.onInit();\n\n // Initialize form data\n this.data = {\n // Config data for template\n ...this.authConfig.ui,\n ...this.authConfig.features,\n\n // Form fields\n password: '',\n confirmPassword: '',\n resetToken: '',\n\n // UI state\n isLoading: false,\n error: null,\n success: false,\n successMessage: null,\n showPassword: false,\n showConfirmPassword: false,\n\n // Validation state\n passwordStrength: null,\n passwordMatch: true,\n tokenValid: false\n };\n }\n\n async onEnter() {\n await super.onEnter();\n\n // Set page title\n document.title = `${ResetPasswordPage.title} - ${this.authConfig.ui.title}`;\n\n // Extract reset token from URL parameters\n const urlParams = new URLSearchParams(window.location.search);\n this.resetToken = urlParams.get('token') || '';\n\n if (!this.resetToken) {\n // No token provided, show error\n this.updateData({\n error: 'Invalid or missing reset token. Please request a new password reset.',\n tokenValid: false\n });\n return;\n }\n\n // Token exists, mark as valid for UI\n this.updateData({\n resetToken: this.resetToken,\n tokenValid: true,\n error: null,\n success: false\n });\n }\n\n async onAfterRender() {\n await super.onAfterRender();\n\n // Focus on password input if token is valid\n if (this.data.tokenValid) {\n const passwordInput = this.element.querySelector('#resetPassword');\n if (passwordInput) {\n passwordInput.focus();\n }\n }\n }\n\n /**\n * Handle field updates\n */\n async onActionUpdateField(event, element) {\n const field = element.dataset.field;\n const value = element.value;\n\n this.updateData({ \n [field]: value,\n error: null // Clear error on input change\n });\n\n // Check password strength when password changes\n if (field === 'password') {\n this.checkPasswordStrength(value);\n }\n\n // Check password match when either password field changes\n if (field === 'password' || field === 'confirmPassword') {\n this.checkPasswordMatch();\n }\n }\n\n /**\n * Check password strength\n */\n checkPasswordStrength(password) {\n let strength = null;\n\n if (password.length === 0) {\n strength = null;\n } else if (password.length < 6) {\n strength = 'weak';\n } else if (password.length < 8) {\n strength = 'fair';\n } else if (/^(?=.*[a-z])(?=.*[A-Z])(?=.*\\d)(?=.*[@$!%*?&])[A-Za-z\\d@$!%*?&]/.test(password)) {\n strength = 'strong';\n } else if (/^(?=.*[a-z])(?=.*[A-Z])(?=.*\\d)/.test(password)) {\n strength = 'good';\n } else {\n strength = 'fair';\n }\n\n this.updateData({ passwordStrength: strength }, true);\n }\n\n /**\n * Check if passwords match\n */\n checkPasswordMatch() {\n const match = !this.data.confirmPassword ||\n this.data.password === this.data.confirmPassword;\n this.updateData({ passwordMatch: match }, true);\n }\n\n /**\n * Toggle password visibility\n */\n async onActionTogglePassword(event, element) {\n event.preventDefault();\n const field = element.dataset.passwordField;\n\n if (field === 'password') {\n this.updateData({ showPassword: !this.data.showPassword });\n const input = this.element.querySelector('#resetPassword');\n if (input) {\n input.type = this.data.showPassword ? 'text' : 'password';\n }\n } else if (field === 'confirmPassword') {\n this.updateData({ showConfirmPassword: !this.data.showConfirmPassword });\n const input = this.element.querySelector('#resetConfirmPassword');\n if (input) {\n input.type = this.data.showConfirmPassword ? 'text' : 'password';\n }\n }\n }\n\n /**\n * Handle password reset submission\n */\n async onActionResetPassword(event) {\n event.preventDefault();\n await this.updateData({ error: null, isLoading: true }, true);\n\n // Basic validation\n if (!this.data.password || !this.data.confirmPassword) {\n await this.updateData({ error: 'Please enter and confirm your new password', isLoading: false }, true);\n return;\n }\n if (this.data.password.length < 6) {\n await this.updateData({ error: 'Password must be at least 6 characters long', isLoading: false }, true);\n return;\n }\n if (this.data.password !== this.data.confirmPassword) {\n await this.updateData({ error: 'Passwords do not match', isLoading: false }, true);\n return;\n }\n\n const auth = this.getApp().auth;\n if (!auth) {\n await this.updateData({ error: 'Authentication system not available', isLoading: false }, true);\n return;\n }\n\n const response = await auth.resetPasswordWithToken(this.resetToken, this.data.password);\n\n if (response.success) {\n await this.updateData({\n success: true,\n successMessage: response.message || 'Password reset successful! You can now log in.',\n isLoading: false\n }, true);\n\n // Redirect to login after delay\n setTimeout(() => {\n this.getApp().showSuccess('Password reset complete. Please log in.');\n this.getApp().navigate('/login');\n }, 3000);\n } else {\n await this.updateData({\n error: response.message || 'Password reset failed. Please try again.',\n isLoading: false\n }, true);\n }\n }\n\n /**\n * Navigate to login page\n */\n async onActionBackToLogin(event) {\n event.preventDefault();\n this.getApp().navigate('/login');\n }\n\n /**\n * Navigate to registration page\n */\n async onActionRegister(event) {\n event.preventDefault();\n this.getApp().navigate('/register');\n }\n\n /**\n * Request new reset email\n */\n async onActionRequestNew(event) {\n event.preventDefault();\n this.getApp().navigate('/forgot-password');\n }\n\n /**\n * Handle Enter key in form fields\n */\n async onActionHandleKeyPress(event, element) {\n if (event.key === 'Enter') {\n event.preventDefault();\n\n // Navigate through fields on Enter\n const fieldOrder = ['resetPassword', 'resetConfirmPassword'];\n const currentIndex = fieldOrder.indexOf(element.id);\n\n if (currentIndex >= 0 && currentIndex < fieldOrder.length - 1) {\n // Move to next field\n const nextField = this.element.querySelector(`#${fieldOrder[currentIndex + 1]}`);\n if (nextField) {\n nextField.focus();\n }\n } else if (currentIndex === fieldOrder.length - 1) {\n // Last field - submit form\n await this.onActionResetPassword(event);\n }\n }\n }\n\n /**\n * Get view data for template rendering\n */\n async getViewData() {\n return {\n ...this.data\n };\n }\n}","/**\n * Auto-generated template module\n * Generated: 2025-10-04T01:54:53.124Z\n * Contains all framework templates compiled as JavaScript strings\n */\n\n// Template registry\nconst templates = {};\n\n// Template: extensions/auth/pages/ForgotPasswordPage.mst\ntemplates['extensions/auth/pages/ForgotPasswordPage.mst'] = `<div class=\"auth-page forgot-password-page min-vh-100 d-flex align-items-center py-4\">\n <div class=\"container\">\n <div class=\"row justify-content-center\">\n <div class=\"col-sm-8 col-md-8 col-lg-6 col-xl-5\">\n <div class=\"card shadow-lg border-0\">\n <div class=\"card-body p-4 p-md-5\">\n <!-- Header -->\n <div class=\"text-center mb-4\">\n {{#logoUrl}}<img src=\"{{logoUrl}}\" alt=\"{{title}}\" class=\"mb-3\" style=\"max-height: 60px;\">{{/logoUrl}}\n <h2 class=\"h3 mb-2\">{{messages.forgotTitle}}</h2>\n <p class=\"text-muted\">{{messages.forgotSubtitle}}</p>\n </div>\n\n <!-- Error Alert -->\n {{#error}}\n <div class=\"alert alert-danger d-flex align-items-center alert-dismissible fade show\" role=\"alert\">\n <i class=\"bi bi-exclamation-triangle-fill me-2\"></i>\n <div>{{error}}</div>\n <button type=\"button\" class=\"btn-close\" data-bs-dismiss=\"alert\" aria-label=\"Close\"></button>\n </div>\n {{/error}}\n\n <!-- Step 1: Email Form -->\n {{#isStepEmail}}\n <form id=\"form-request-reset\" novalidate>\n <div class=\"mb-3\">\n <label for=\"forgotEmail\" class=\"form-label\"><i class=\"bi bi-envelope me-1\"></i>Email Address</label>\n <input type=\"email\" class=\"form-control form-control-lg\" id=\"forgotEmail\" name=\"email\" placeholder=\"Enter your registered email\" required autofocus>\n <div class=\"form-text\">We'll send you instructions to reset your password.</div>\n </div>\n <button type=\"button\" class=\"btn btn-primary btn-lg w-100 mb-3\" data-action=\"requestReset\" {{#isLoading}}disabled{{/isLoading}}>\n {{#isLoading}}<span class=\"spinner-border spinner-border-sm me-2\"></span>Sending...{{/isLoading}}\n {{^isLoading}}<i class=\"bi bi-send me-2\"></i>Send Instructions{{/isLoading}}\n </button>\n <button type=\"button\" class=\"btn btn-outline-secondary btn-lg w-100\" data-action=\"backToLogin\" {{#isLoading}}disabled{{/isLoading}}>\n <i class=\"bi bi-arrow-left me-2\"></i>Back to Login\n </button>\n </form>\n <div class=\"text-center mt-4\">\n <p class=\"text-muted\">Remember your password? <a href=\"#\" class=\"text-decoration-none fw-semibold\" data-action=\"backToLogin\">Sign in</a></p>\n </div>\n {{/isStepEmail}}\n\n <!-- Step 2 (Link Method): Confirmation -->\n {{#isStepLinkSent}}\n <div class=\"text-center\">\n <div class=\"mb-4\"><i class=\"bi bi-envelope-check text-success\" style=\"font-size: 4rem;\"></i></div>\n <h3 class=\"h4 mb-3\">Check your email</h3>\n <p class=\"text-muted\">If an account exists for <strong>{{data.email}}</strong>, we have sent instructions for resetting your password.</p>\n <div class=\"d-grid gap-2 mt-4\">\n <button type=\"button\" class=\"btn btn-primary btn-lg\" data-action=\"backToLogin\"><i class=\"bi bi-arrow-left me-2\"></i>Back to Login</button>\n </div>\n </div>\n {{/isStepLinkSent}}\n\n <!-- Step 2 (Code Method): Code Entry Form -->\n {{#isStepCode}}\n <p class=\"text-muted text-center mb-3\">A verification code has been sent to <strong>{{data.email}}</strong>. Please enter it below.</p>\n <form id=\"form-reset-with-code\" novalidate>\n <div class=\"mb-3\">\n <label for=\"resetCode\" class=\"form-label\"><i class=\"bi bi-shield-lock me-1\"></i>Verification Code</label>\n <input type=\"text\" class=\"form-control form-control-lg\" id=\"resetCode\" name=\"code\" placeholder=\"Enter code\" required>\n </div>\n <div class=\"mb-3\">\n <label for=\"resetPassword\" class=\"form-label\"><i class=\"bi bi-lock me-1\"></i>New Password</label>\n <input type=\"password\" class=\"form-control form-control-lg\" id=\"resetPassword\" name=\"new_password\" placeholder=\"Enter new password\" required autocomplete=\"new-password\">\n </div>\n <div class=\"mb-3\">\n <label for=\"confirmPassword\" class=\"form-label\"><i class=\"bi bi-lock-fill me-1\"></i>Confirm New Password</label>\n <input type=\"password\" class=\"form-control form-control-lg\" id=\"confirmPassword\" name=\"confirm_password\" placeholder=\"Confirm new password\" required autocomplete=\"new-password\">\n </div>\n <button type=\"button\" class=\"btn btn-primary btn-lg w-100\" data-action=\"resetWithCode\" {{#isLoading}}disabled{{/isLoading}}>\n {{#isLoading}}<span class=\"spinner-border spinner-border-sm me-2\"></span>Resetting...{{/isLoading}}\n {{^isLoading}}<i class=\"bi bi-key me-2\"></i>Reset Password{{/isLoading}}\n </button>\n </form>\n {{/isStepCode}}\n\n <!-- Step 3 (Code Method): Success -->\n {{#isStepSuccess}}\n <div class=\"text-center\">\n <div class=\"mb-4\"><i class=\"bi bi-check-circle text-success\" style=\"font-size: 4rem;\"></i></div>\n <h3 class=\"h4 mb-3\">Password Reset!</h3>\n <p class=\"text-muted\">Your password has been changed successfully. You will be redirected to the login page shortly.</p>\n </div>\n {{/isStepSuccess}}\n\n </div>\n </div>\n </div>\n </div>\n </div>\n</div>\n`;\n\n// Template: extensions/auth/pages/LoginPage.mst\ntemplates['extensions/auth/pages/LoginPage.mst'] = `<div class=\"auth-page min-vh-100 d-flex align-items-center py-4\">\n <div class=\"container\">\n <div class=\"row justify-content-center\">\n <div class=\"col-sm-10 col-md-8 col-lg-6 col-xl-5\">\n <div class=\"card shadow-lg border-0\">\n <div class=\"card-body p-4 p-md-5\">\n <!-- Logo and Header -->\n <div class=\"text-center mb-4\">\n {{#data.logoUrl}}\n <img src=\"{{data.logoUrl}}\" alt=\"{{data.title}}\" class=\"mb-3\" style=\"max-height: 60px;\">\n {{/data.logoUrl}}\n {{#data.messages.loginTitle}}\n <h2 class=\"h3 mb-2\">{{#data.loginIcon}}<i class=\"{{data.loginIcon}}\"></i> {{/data.loginIcon}}{{data.messages.loginTitle}}</h2>\n {{/data.messages.loginTitle}}\n {{/data.messages.loginSubtitle}}\n <p class=\"text-muted\">{{data.messages.loginSubtitle}}</p>\n {{/data.messages.loginSubtitle}}\n </div>\n\n <!-- Error Alert -->\n {{#data.error}}\n <div class=\"alert alert-danger d-flex align-items-center alert-dismissible fade show\" role=\"alert\">\n <i class=\"bi bi-exclamation-triangle-fill me-2\"></i>\n <div>{{data.error}}</div>\n <button type=\"button\" class=\"btn-close\" data-bs-dismiss=\"alert\" aria-label=\"Close\"></button>\n </div>\n {{/data.error}}\n\n <!-- Login Form -->\n <form novalidate>\n <!-- Username/Email Field -->\n <div class=\"mb-3\">\n <label for=\"loginUsername\" class=\"form-label\">\n <i class=\"bi bi-person me-1\"></i>Username or Email\n </label>\n <input\n type=\"text\"\n class=\"form-control form-control-lg\"\n id=\"loginUsername\"\n placeholder=\"Enter your username or email\"\n value=\"{{username}}\"\n data-field=\"username\"\n data-action-keydown=\"handleKeyPress\"\n autocomplete=\"username\"\n required\n autofocus\n {{#isLoading}}disabled{{/isLoading}}>\n </div>\n\n <!-- Password Field -->\n <div class=\"mb-3\">\n <label for=\"loginPassword\" class=\"form-label\">\n <i class=\"bi bi-lock me-1\"></i>Password\n </label>\n <div class=\"input-group\">\n <input\n type=\"{{#showPassword}}text{{/showPassword}}{{^showPassword}}password{{/showPassword}}\"\n class=\"form-control form-control-lg\"\n id=\"loginPassword\"\n placeholder=\"Enter your password\"\n value=\"{{password}}\"\n data-field=\"password\"\n data-action-keydown=\"handleKeyPress\"\n autocomplete=\"current-password\"\n required\n {{#isLoading}}disabled{{/isLoading}}>\n <button\n class=\"btn btn-outline-secondary\"\n type=\"button\"\n data-action=\"togglePassword\"\n {{#isLoading}}disabled{{/isLoading}}>\n <i class=\"bi bi-eye{{#data.showPassword}}-slash{{/data.showPassword}}\"></i>\n </button>\n </div>\n </div>\n\n <!-- Remember Me & Forgot Password -->\n <div class=\"d-flex justify-content-between align-items-center mb-4\">\n {{#data.rememberMe}}\n <div class=\"form-check\">\n <input\n class=\"form-check-input\"\n type=\"checkbox\"\n id=\"rememberMe\"\n data-field=\"rememberMe\"\n data-change-action=\"updateField\"\n autocomplete=\"off\"\n {{#rememberMe}}checked{{/rememberMe}}\n {{#isLoading}}disabled{{/isLoading}}>\n <label class=\"form-check-label\" for=\"rememberMe\">\n Remember me\n </label>\n </div>\n {{/data.rememberMe}}\n {{^data.rememberMe}}<div></div>{{/data.rememberMe}}\n\n {{#data.forgotPassword}}\n <a href=\"?page=forgot-password\" class=\"text-decoration-none\" data-action=\"forgotPassword\">\n Forgot password?\n </a>\n {{/data.forgotPassword}}\n </div>\n\n <!-- Login Button -->\n <button\n type=\"button\"\n class=\"btn btn-primary btn-lg w-100 mb-3\"\n data-action=\"login\"\n {{#data.isLoading}}disabled{{/data.isLoading}}>\n {{#data.isLoading}}\n <span class=\"spinner-border spinner-border-sm me-2\" role=\"status\" aria-hidden=\"true\"></span>\n Signing in...\n {{/data.isLoading}}\n {{^data.isLoading}}\n <i class=\"bi bi-box-arrow-in-right me-2\"></i>Sign In\n {{/data.isLoading}}\n </button>\n\n <!-- Alternative Login Methods -->\n {{#data.passkeySupported}}\n <div class=\"position-relative my-3\">\n <hr class=\"text-muted\">\n <span class=\"position-absolute top-50 start-50 translate-middle bg-white px-3 text-muted small\">\n OR\n </span>\n </div>\n\n <button\n type=\"button\"\n class=\"btn btn-outline-primary btn-lg w-100 mb-2\"\n data-action=\"loginWithPasskey\"\n {{#data.isLoading}}disabled{{/data.isLoading}}>\n <i class=\"bi bi-fingerprint me-2\"></i>Sign in with Passkey\n </button>\n {{/data.passkeySupported}}\n </form>\n\n <!-- Register Link -->\n {{#data.registration}}\n <div class=\"text-center mt-4\">\n <p class=\"mb-0\">\n Don't have an account?\n <a href=\"#\" class=\"text-decoration-none fw-semibold\" data-action=\"register\">\n Sign up\n </a>\n </p>\n </div>\n {{/data.registration}}\n </div>\n </div>\n\n <!-- Security Notice -->\n <!-- TOS and Privacy Links -->\n <div class=\"text-center mt-3 auth-footer-links\">\n {{#data.termsUrl}}\n <small><a href=\"{{data.termsUrl}}\" target=\"_blank\" rel=\"noopener noreferrer\">Terms of Service</a></small>\n {{/data.termsUrl}}\n {{#data.termsUrl}}{{#data.privacyUrl}}\n <small class=\"mx-1 text-muted\">&middot;</small>\n {{/data.privacyUrl}}{{/data.termsUrl}}\n {{#data.privacyUrl}}\n <small><a href=\"{{data.privacyUrl}}\" target=\"_blank\" rel=\"noopener noreferrer\">Privacy Policy</a></small>\n {{/data.privacyUrl}}\n <div class=\"text-muted text-center mt-3\">\n <small>version {{data.version}}</small>\n </div>\n </div>\n </div>\n </div>\n </div>\n</div>\n`;\n\n// Template: extensions/auth/pages/RegisterPage.mst\ntemplates['extensions/auth/pages/RegisterPage.mst'] = `<div class=\"auth-page register-page min-vh-100 d-flex align-items-center py-4\">\n <div class=\"container\">\n <div class=\"row justify-content-center\">\n <div class=\"col-sm-10 col-md-8 col-lg-6 col-xl-5\">\n <div class=\"card shadow-lg border-0\">\n <div class=\"card-body p-4 p-md-5\">\n <!-- Logo and Header -->\n <div class=\"text-center mb-4\">\n {{#logoUrl}}\n <img src=\"{{logoUrl}}\" alt=\"{{title}}\" class=\"mb-3\" style=\"max-height: 60px;\">\n {{/logoUrl}}\n <h2 class=\"h3 mb-2\">{{messages.registerTitle}}</h2>\n <p class=\"text-muted\">{{messages.registerSubtitle}}</p>\n </div>\n\n <!-- Error Alert -->\n {{#error}}\n <div class=\"alert alert-danger d-flex align-items-center alert-dismissible fade show\" role=\"alert\">\n <i class=\"bi bi-exclamation-triangle-fill me-2\"></i>\n <div>{{error}}</div>\n <button type=\"button\" class=\"btn-close\" data-bs-dismiss=\"alert\" aria-label=\"Close\"></button>\n </div>\n {{/error}}\n\n <!-- Registration Form -->\n <form data-action=\"register\" novalidate>\n <!-- Name Field -->\n <div class=\"mb-3\">\n <label for=\"registerName\" class=\"form-label\">\n <i class=\"bi bi-person me-1\"></i>Full Name\n </label>\n <input\n type=\"text\"\n class=\"form-control form-control-lg\"\n id=\"registerName\"\n placeholder=\"Enter your full name\"\n value=\"{{name}}\"\n data-field=\"name\"\n data-change-action=\"updateField\"\n data-filter=\"live-search\"\n data-action-keydown=\"handleKeyPress\"\n autocomplete=\"name\"\n required\n autofocus\n {{#isLoading}}disabled{{/isLoading}}>\n </div>\n\n <!-- Email Field -->\n <div class=\"mb-3\">\n <label for=\"registerEmail\" class=\"form-label\">\n <i class=\"bi bi-envelope me-1\"></i>Email Address\n </label>\n <input\n type=\"email\"\n class=\"form-control form-control-lg\"\n id=\"registerEmail\"\n placeholder=\"name@example.com\"\n value=\"{{email}}\"\n data-field=\"email\"\n data-change-action=\"updateField\"\n data-filter=\"live-search\"\n data-action-keydown=\"handleKeyPress\"\n autocomplete=\"email\"\n required\n {{#isLoading}}disabled{{/isLoading}}>\n </div>\n\n <!-- Password Field -->\n <div class=\"mb-3\">\n <label for=\"registerPassword\" class=\"form-label\">\n <i class=\"bi bi-lock me-1\"></i>Password\n </label>\n <div class=\"input-group\">\n <input\n type=\"{{#showPassword}}text{{/showPassword}}{{^showPassword}}password{{/showPassword}}\"\n class=\"form-control form-control-lg\"\n id=\"registerPassword\"\n placeholder=\"Create a strong password\"\n value=\"{{password}}\"\n data-field=\"password\"\n data-change-action=\"updateField\"\n data-filter=\"live-search\"\n data-action-keydown=\"handleKeyPress\"\n autocomplete=\"new-password\"\n required\n {{#isLoading}}disabled{{/isLoading}}>\n <button\n class=\"btn btn-outline-secondary\"\n type=\"button\"\n data-password-field=\"password\"\n data-action=\"togglePassword\"\n {{#isLoading}}disabled{{/isLoading}}>\n <i class=\"bi bi-eye{{#showPassword}}-slash{{/showPassword}}\"></i>\n </button>\n </div>\n\n <!-- Password Strength Indicator -->\n {{#passwordStrength}}\n <div class=\"mt-2\">\n <div class=\"progress\" style=\"height: 4px;\">\n <div class=\"progress-bar\n {{#passwordStrength.weak}}bg-danger{{/passwordStrength.weak}}\n {{#passwordStrength.fair}}bg-warning{{/passwordStrength.fair}}\n {{#passwordStrength.good}}bg-info{{/passwordStrength.good}}\n {{#passwordStrength.strong}}bg-success{{/passwordStrength.strong}}\"\n role=\"progressbar\"\n style=\"width:\n {{#passwordStrength.weak}}25%{{/passwordStrength.weak}}\n {{#passwordStrength.fair}}50%{{/passwordStrength.fair}}\n {{#passwordStrength.good}}75%{{/passwordStrength.good}}\n {{#passwordStrength.strong}}100%{{/passwordStrength.strong}}\">\n </div>\n </div>\n <small class=\"text-muted mt-1\">\n Password strength: {{passwordStrength}}\n </small>\n </div>\n {{/passwordStrength}}\n </div>\n\n <!-- Confirm Password Field -->\n <div class=\"mb-3\">\n <label for=\"registerConfirmPassword\" class=\"form-label\">\n <i class=\"bi bi-lock-fill me-1\"></i>Confirm Password\n </label>\n <div class=\"input-group\">\n <input\n type=\"{{#showConfirmPassword}}text{{/showConfirmPassword}}{{^showConfirmPassword}}password{{/showConfirmPassword}}\"\n class=\"form-control form-control-lg {{^passwordMatch}}is-invalid{{/passwordMatch}}\"\n id=\"registerConfirmPassword\"\n placeholder=\"Re-enter your password\"\n value=\"{{confirmPassword}}\"\n data-field=\"confirmPassword\"\n data-change-action=\"updateField\"\n data-filter=\"live-search\"\n data-action-keydown=\"handleKeyPress\"\n autocomplete=\"new-password\"\n required\n {{#isLoading}}disabled{{/isLoading}}>\n <button\n class=\"btn btn-outline-secondary\"\n type=\"button\"\n data-password-field=\"confirmPassword\"\n data-action=\"togglePassword\"\n {{#isLoading}}disabled{{/isLoading}}>\n <i class=\"bi bi-eye{{#showConfirmPassword}}-slash{{/showConfirmPassword}}\"></i>\n </button>\n </div>\n {{^passwordMatch}}\n <div class=\"invalid-feedback\">\n Passwords do not match\n </div>\n {{/passwordMatch}}\n </div>\n\n <!-- Register Button -->\n <button\n type=\"submit\"\n class=\"btn btn-primary btn-lg w-100 mb-3\"\n {{#isLoading}}disabled{{/isLoading}}>\n {{#isLoading}}\n <span class=\"spinner-border spinner-border-sm me-2\" role=\"status\" aria-hidden=\"true\"></span>\n Creating account...\n {{/isLoading}}\n {{^isLoading}}\n <i class=\"bi bi-person-plus me-2\"></i>Create Account\n {{/isLoading}}\n </button>\n </form>\n\n <!-- Login Link -->\n <div class=\"text-center mt-4\">\n <p class=\"mb-0\">\n Already have an account?\n <a href=\"#\" class=\"text-decoration-none fw-semibold\" data-action=\"login\">\n Sign in\n </a>\n </p>\n </div>\n </div>\n </div>\n\n <!-- Security Notice -->\n <div class=\"text-center mt-3\">\n <small class=\"text-muted\">\n <i class=\"bi bi-shield-check me-1\"></i>Your information is secure and encrypted\n </small>\n </div>\n </div>\n </div>\n </div>\n</div>\n`;\n\n// Template: extensions/auth/pages/ResetPasswordPage.mst\ntemplates['extensions/auth/pages/ResetPasswordPage.mst'] = `<div class=\"auth-page reset-password-page min-vh-100 d-flex align-items-center py-4\">\n <div class=\"container\">\n <div class=\"row justify-content-center\">\n <div class=\"col-sm-10 col-md-8 col-lg-6 col-xl-5\">\n <div class=\"card shadow-lg border-0\">\n <div class=\"card-body p-4 p-md-5\">\n <!-- Logo and Header -->\n <div class=\"text-center mb-4\">\n {{#logoUrl}}\n <img src=\"{{logoUrl}}\" alt=\"{{title}}\" class=\"mb-3\" style=\"max-height: 60px;\">\n {{/logoUrl}}\n <h2 class=\"h3 mb-2\">{{messages.resetTitle}}</h2>\n <p class=\"text-muted\">{{messages.resetSubtitle}}</p>\n </div>\n\n <!-- Error Alert -->\n {{#error}}\n <div class=\"alert alert-danger d-flex align-items-center alert-dismissible fade show\" role=\"alert\">\n <i class=\"bi bi-exclamation-triangle-fill me-2\"></i>\n <div>{{error}}</div>\n <button type=\"button\" class=\"btn-close\" data-bs-dismiss=\"alert\" aria-label=\"Close\"></button>\n </div>\n {{/error}}\n\n <!-- Success State -->\n {{#success}}\n <div class=\"alert alert-success d-flex align-items-center\" role=\"alert\">\n <i class=\"bi bi-check-circle-fill me-2\"></i>\n <div>\n <strong>Password Reset Complete!</strong><br>\n {{#successMessage}}{{successMessage}}{{/successMessage}}\n {{^successMessage}}Your password has been reset successfully. You can now log in with your new password.{{/successMessage}}\n </div>\n </div>\n\n <div class=\"text-center\">\n <p class=\"mb-3\">\n <i class=\"bi bi-shield-check text-success\" style=\"font-size: 3rem;\"></i>\n </p>\n <p class=\"text-muted\">\n Redirecting you to the login page...\n </p>\n <div class=\"d-grid gap-2 mt-4\">\n <button\n class=\"btn btn-primary btn-lg\"\n data-action=\"backToLogin\">\n <i class=\"bi bi-box-arrow-in-right me-2\"></i>Continue to Login\n </button>\n </div>\n </div>\n {{/success}}\n\n <!-- Reset Form -->\n {{^success}}\n {{#tokenValid}}\n <form data-action=\"resetPassword\" novalidate>\n <!-- New Password Field -->\n <div class=\"mb-3\">\n <label for=\"resetPassword\" class=\"form-label\">\n <i class=\"bi bi-lock me-1\"></i>New Password\n </label>\n <div class=\"input-group\">\n <input\n type=\"{{#showPassword}}text{{/showPassword}}{{^showPassword}}password{{/showPassword}}\"\n class=\"form-control form-control-lg\"\n id=\"resetPassword\"\n placeholder=\"Enter your new password\"\n value=\"{{password}}\"\n data-field=\"password\"\n data-change-action=\"updateField\"\n data-filter=\"live-search\"\n data-action-keydown=\"handleKeyPress\"\n autocomplete=\"new-password\"\n required\n autofocus\n {{#isLoading}}disabled{{/isLoading}}>\n <button\n class=\"btn btn-outline-secondary\"\n type=\"button\"\n data-password-field=\"password\"\n data-action=\"togglePassword\"\n {{#isLoading}}disabled{{/isLoading}}>\n <i class=\"bi bi-eye{{#showPassword}}-slash{{/showPassword}}\"></i>\n </button>\n </div>\n\n <!-- Password Strength Indicator -->\n {{#passwordStrength}}\n <div class=\"mt-2\">\n <div class=\"progress\" style=\"height: 4px;\">\n <div class=\"progress-bar\n {{#passwordStrength.weak}}bg-danger{{/passwordStrength.weak}}\n {{#passwordStrength.fair}}bg-warning{{/passwordStrength.fair}}\n {{#passwordStrength.good}}bg-info{{/passwordStrength.good}}\n {{#passwordStrength.strong}}bg-success{{/passwordStrength.strong}}\"\n role=\"progressbar\"\n style=\"width:\n {{#passwordStrength.weak}}25%{{/passwordStrength.weak}}\n {{#passwordStrength.fair}}50%{{/passwordStrength.fair}}\n {{#passwordStrength.good}}75%{{/passwordStrength.good}}\n {{#passwordStrength.strong}}100%{{/passwordStrength.strong}}\">\n </div>\n </div>\n <small class=\"text-muted mt-1\">\n Password strength: {{passwordStrength}}\n </small>\n </div>\n {{/passwordStrength}}\n </div>\n\n <!-- Confirm Password Field -->\n <div class=\"mb-4\">\n <label for=\"resetConfirmPassword\" class=\"form-label\">\n <i class=\"bi bi-lock-fill me-1\"></i>Confirm New Password\n </label>\n <div class=\"input-group\">\n <input\n type=\"{{#showConfirmPassword}}text{{/showConfirmPassword}}{{^showConfirmPassword}}password{{/showConfirmPassword}}\"\n class=\"form-control form-control-lg {{^passwordMatch}}is-invalid{{/passwordMatch}}\"\n id=\"resetConfirmPassword\"\n placeholder=\"Re-enter your new password\"\n value=\"{{confirmPassword}}\"\n data-field=\"confirmPassword\"\n data-change-action=\"updateField\"\n data-filter=\"live-search\"\n data-action-keydown=\"handleKeyPress\"\n autocomplete=\"new-password\"\n required\n {{#isLoading}}disabled{{/isLoading}}>\n <button\n class=\"btn btn-outline-secondary\"\n type=\"button\"\n data-password-field=\"confirmPassword\"\n data-action=\"togglePassword\"\n {{#isLoading}}disabled{{/isLoading}}>\n <i class=\"bi bi-eye{{#showConfirmPassword}}-slash{{/showConfirmPassword}}\"></i>\n </button>\n </div>\n {{^passwordMatch}}\n <div class=\"invalid-feedback\">\n Passwords do not match\n </div>\n {{/passwordMatch}}\n </div>\n\n <!-- Reset Button -->\n <button\n type=\"submit\"\n class=\"btn btn-primary btn-lg w-100 mb-3\"\n {{#isLoading}}disabled{{/isLoading}}>\n {{#isLoading}}\n <span class=\"spinner-border spinner-border-sm me-2\" role=\"status\" aria-hidden=\"true\"></span>\n Resetting password...\n {{/isLoading}}\n {{^isLoading}}\n <i class=\"bi bi-key me-2\"></i>Reset Password\n {{/isLoading}}\n </button>\n\n <!-- Back to Login -->\n <button\n type=\"button\"\n class=\"btn btn-outline-secondary btn-lg w-100\"\n data-action=\"backToLogin\"\n {{#isLoading}}disabled{{/isLoading}}>\n <i class=\"bi bi-arrow-left me-2\"></i>Back to Login\n </button>\n </form>\n {{/tokenValid}}\n\n <!-- Invalid Token State -->\n {{^tokenValid}}\n <div class=\"text-center\">\n <div class=\"mb-4\">\n <i class=\"bi bi-exclamation-triangle text-warning\" style=\"font-size: 4rem;\"></i>\n </div>\n <h4 class=\"text-warning mb-3\">Invalid Reset Link</h4>\n <p class=\"text-muted mb-4\">\n This password reset link is invalid or has expired.\n Please request a new password reset.\n </p>\n <div class=\"d-grid gap-2\">\n <button\n class=\"btn btn-primary btn-lg\"\n data-action=\"requestNew\">\n <i class=\"bi bi-envelope me-2\"></i>Request New Reset\n </button>\n <button\n class=\"btn btn-outline-secondary btn-lg\"\n data-action=\"backToLogin\">\n <i class=\"bi bi-arrow-left me-2\"></i>Back to Login\n </button>\n </div>\n </div>\n {{/tokenValid}}\n\n <!-- Additional Links -->\n {{#tokenValid}}{{^success}}\n <div class=\"text-center mt-4\">\n <p class=\"text-muted mb-2\">\n Remember your password?\n <a href=\"#\" class=\"text-decoration-none fw-semibold\" data-action=\"backToLogin\">\n Sign in\n </a>\n </p>\n {{#registration}}\n <p class=\"text-muted mb-0\">\n Don't have an account?\n <a href=\"#\" class=\"text-decoration-none fw-semibold\" data-action=\"register\">\n Sign up\n </a>\n </p>\n {{/registration}}\n </div>\n {{/success}}{{/tokenValid}}\n {{/success}}\n </div>\n </div>\n\n <!-- Security Notice -->\n <div class=\"text-center mt-3\">\n <small class=\"text-muted\">\n <i class=\"bi bi-shield-lock me-1\"></i>\n Secure password reset with email verification\n </small>\n </div>\n </div>\n </div>\n </div>\n</div>\n`;\n\n// Export templates\nexport default templates;\n\n// Convenience exports for common templates\nexport const extensions_auth_pages_ForgotPasswordPage_mst = templates['extensions/auth/pages/ForgotPasswordPage.mst'];\nexport const extensions_auth_pages_LoginPage_mst = templates['extensions/auth/pages/LoginPage.mst'];\nexport const extensions_auth_pages_RegisterPage_mst = templates['extensions/auth/pages/RegisterPage.mst'];\nexport const extensions_auth_pages_ResetPasswordPage_mst = templates['extensions/auth/pages/ResetPasswordPage.mst'];\n\n// Helper functions\n\n/**\n * Get a template by key\n * @param {string} key - Template key (e.g., \"auth/pages/LoginPage.mst\")\n * @returns {string|undefined} Template content or undefined if not found\n */\nexport function getTemplate(key) {\n // Handle different path formats\n const normalizedKey = key\n .replace(/^\\//, \"\") // Remove leading slash\n .replace(/^src\\//, \"\") // Remove src/ prefix\n .replace(/\\\\/g, \"/\"); // Normalize path separators\n \n return templates[normalizedKey] || templates[key];\n}\n\n/**\n * Check if a template exists\n * @param {string} key - Template key\n * @returns {boolean} True if template exists\n */\nexport function hasTemplate(key) {\n return getTemplate(key) !== undefined;\n}\n\n/**\n * Get all template keys\n * @returns {string[]} Array of template keys\n */\nexport function getTemplateKeys() {\n return Object.keys(templates);\n}\n\n/**\n * Get template count\n * @returns {number} Number of templates\n */\nexport function getTemplateCount() {\n return Object.keys(templates).length;\n}","/**\n * AuthApp - A specialized WebApp with built-in authentication.\n * Extends the core WebApp to provide a seamless, out-of-the-box authentication system.\n */\nimport WebApp from '@core/WebApp.js';\nimport AuthManager from './AuthManager.js';\nimport LoginPage from '@ext/auth/pages/LoginPage.js';\nimport RegisterPage from '@ext/auth/pages/RegisterPage.js';\nimport ForgotPasswordPage from '@ext/auth/pages/ForgotPasswordPage.js';\nimport ResetPasswordPage from '@ext/auth/pages/ResetPasswordPage.js';\nimport { getTemplate } from '/src/templates.js';\n\nexport default class AuthApp extends WebApp {\n constructor(config = {}) {\n // Deep merge UI config to handle nested theme object\n const uiConfig = {\n title: config.name || 'My App',\n logoUrl: null,\n termsUrl: null,\n privacyUrl: null,\n theme: {\n background: 'auth-bg-light',\n panel: 'auth-panel-light',\n ...(config.ui?.theme || {})\n },\n messages: {\n loginTitle: 'Welcome Back',\n loginSubtitle: 'Sign in to your account',\n registerTitle: 'Create Account',\n registerSubtitle: 'Join us today',\n forgotTitle: 'Reset Password',\n forgotSubtitle: \"We'll send you reset instructions\",\n ...(config.ui?.messages || {})\n },\n ...(config.ui || {})\n };\n\n // Merge user config with auth defaults\n const authConfig = {\n ...config,\n routes: {\n login: '/login',\n register: '/register',\n forgot: '/forgot-password',\n reset: '/reset-password',\n ...(config.routes || {})\n },\n loginRedirect: config.loginRedirect || '/',\n logoutRedirect: config.logoutRedirect || '/login',\n features: {\n forgotPassword: true,\n registration: true,\n rememberMe: true,\n ...(config.features || {})\n },\n passwordResetMethod: config.passwordResetMethod || 'code',\n ui: uiConfig,\n };\n\n // Initialize the parent WebApp\n super(authConfig);\n\n // Initialize and attach the AuthManager\n this.auth = new AuthManager(this, authConfig);\n this.authConfig = authConfig;\n\n // Setup all authentication components\n this.applyAuthTheme();\n this.registerAuthPages();\n this.setupAuthIntegration();\n this.setupAuthGuards();\n }\n\n /**\n * Applies the configured background and panel themes to the body.\n */\n applyAuthTheme() {\n const theme = this.authConfig.ui.theme;\n if (!theme) return;\n\n // Clear any existing theme classes\n const classesToRemove = Array.from(document.body.classList).filter(\n c => c.startsWith('auth-bg-') || c.startsWith('auth-panel-')\n );\n if (classesToRemove.length) {\n document.body.classList.remove(...classesToRemove);\n }\n\n // Add new theme classes\n if (theme.background) {\n document.body.classList.add(theme.background);\n }\n if (theme.panel) {\n document.body.classList.add(theme.panel);\n }\n }\n\n /**\n * Registers all the standard authentication pages with the application.\n */\n registerAuthPages() {\n const cfg = this.authConfig;\n\n this.registerPage('login', LoginPage, {\n route: cfg.routes.login,\n title: 'Login',\n authConfig: cfg,\n template: getTemplate('extensions/auth/pages/LoginPage.mst')\n });\n\n if (cfg.features.registration) {\n this.registerPage('register', RegisterPage, {\n route: cfg.routes.register,\n title: 'Register',\n authConfig: cfg,\n template: getTemplate('extensions/auth/pages/RegisterPage.mst')\n });\n }\n\n if (cfg.features.forgotPassword) {\n this.registerPage('forgot-password', ForgotPasswordPage, {\n route: cfg.routes.forgot,\n title: 'Reset Password',\n authConfig: cfg,\n template: getTemplate('extensions/auth/pages/ForgotPasswordPage.mst')\n });\n\n this.registerPage('reset-password', ResetPasswordPage, {\n route: cfg.routes.reset,\n title: 'Set New Password',\n authConfig: cfg,\n template: getTemplate('extensions/auth/pages/ResetPasswordPage.mst')\n });\n }\n }\n\n /**\n * Sets up global event listeners to integrate AuthManager state with the app.\n */\n setupAuthIntegration() {\n this.events.on('auth:login', (user) => {\n this.showSuccess(`Welcome back, ${user.name || user.email}!`);\n this.navigateAfterLogin();\n });\n\n this.events.on('auth:logout', () => {\n this.navigate(this.authConfig.logoutRedirect);\n });\n\n this.events.on('auth:register', (user) => {\n this.showSuccess(`Welcome, ${user.name || user.email}! Your account is ready.`);\n this.navigate(this.authConfig.loginRedirect);\n });\n\n this.events.on('auth:tokenExpired', () => {\n this.showWarning('Your session has expired. Please login again.');\n this.navigate(this.authConfig.logoutRedirect);\n });\n }\n\n /**\n * Sets up route guards to protect pages.\n */\n setupAuthGuards() {\n this.events.on('route:changed', ({ pageName, path }) => {\n const page = this.getOrCreatePage(pageName);\n if (!page) return;\n\n const PageClass = page.constructor;\n const isAuthenticated = this.auth.isAuthenticated;\n const isAuthPage = ['login', 'register', 'forgot-password', 'reset-password'].includes(pageName);\n\n // If page requires auth and user is not logged in, redirect to login\n if (PageClass.requiresAuth && !isAuthenticated) {\n sessionStorage.setItem('auth_redirect', path);\n this.navigate(this.authConfig.routes.login);\n this.showWarning('Please login to access this page.');\n return;\n }\n\n // If user is logged in and tries to access an auth page, redirect away\n if (isAuthenticated && isAuthPage) {\n this.navigate(this.authConfig.loginRedirect);\n }\n });\n }\n\n /**\n * Navigates to the intended page after a successful login.\n */\n navigateAfterLogin() {\n const redirectPath = sessionStorage.getItem('auth_redirect');\n if (redirectPath) {\n sessionStorage.removeItem('auth_redirect');\n this.navigate(redirectPath);\n } else {\n this.navigate(this.authConfig.loginRedirect);\n }\n }\n\n /**\n * Helper to protect a Page class.\n * @param {Page} PageClass - The class to protect.\n * @returns {Page} The protected class.\n */\n static requireAuth(PageClass) {\n PageClass.requiresAuth = true;\n return PageClass;\n }\n}\n","/**\n * PasskeyPlugin - WebAuthn Passkey authentication plugin for MOJO Auth\n * Adds passkey login and setup capabilities to the authentication system\n */\n\nexport default class PasskeyPlugin {\n constructor(config = {}) {\n this.name = 'passkey';\n this.config = {\n rpName: 'MOJO App',\n rpId: window?.location?.hostname || 'localhost',\n timeout: 60000,\n userVerification: 'preferred',\n authenticatorAttachment: 'platform', // 'platform', 'cross-platform', or undefined\n ...config\n };\n\n this.authManager = null;\n this.app = null;\n this.authService = null;\n }\n\n /**\n * Initialize plugin with AuthManager and WebApp\n * @param {AuthManager} authManager - Auth manager instance\n * @param {WebApp} app - WebApp instance\n */\n async initialize(authManager, app) {\n this.authManager = authManager;\n this.app = app;\n\n // Check browser support\n if (!this.isSupported()) {\n console.warn('Passkey authentication is not supported in this browser');\n return;\n }\n\n // Add passkey methods to auth manager\n this.authManager.loginWithPasskey = this.loginWithPasskey.bind(this);\n this.authManager.setupPasskey = this.setupPasskey.bind(this);\n this.authManager.isPasskeySupported = this.isSupported.bind(this);\n\n console.log('PasskeyPlugin initialized successfully');\n }\n\n /**\n * Check if WebAuthn is supported in this browser\n * @returns {boolean} True if supported\n */\n isSupported() {\n return window.PublicKeyCredential !== undefined &&\n navigator.credentials !== undefined &&\n typeof navigator.credentials.create === 'function' &&\n typeof navigator.credentials.get === 'function';\n }\n\n /**\n * Login with passkey\n * @returns {Promise<object>} Login result with user data and tokens\n */\n async loginWithPasskey() {\n if (!this.isSupported()) {\n throw new Error('Passkey authentication is not supported in this browser');\n }\n\n try {\n // Step 1: Get authentication challenge from server\n const challengeResponse = await this.app.rest.POST('/api/auth/passkey/challenge');\n\n if (!challengeResponse.success || !challengeResponse.data.data.challenge) {\n throw new Error('No authentication challenge received from server');\n }\n const challengeData = challengeResponse.data.data;\n\n // Step 2: Create credential request options\n const credentialRequestOptions = {\n publicKey: {\n challenge: this.base64ToArrayBuffer(challengeData.challenge),\n timeout: this.config.timeout,\n userVerification: this.config.userVerification,\n rpId: this.config.rpId\n }\n };\n\n // Step 3: Get credential from authenticator\n const credential = await navigator.credentials.get(credentialRequestOptions);\n\n if (!credential) {\n throw new Error('No credential received from authenticator');\n }\n\n // Step 4: Prepare credential data for server verification\n const credentialData = {\n id: credential.id,\n rawId: this.arrayBufferToBase64(credential.rawId),\n type: credential.type,\n response: {\n authenticatorData: this.arrayBufferToBase64(credential.response.authenticatorData),\n clientDataJSON: this.arrayBufferToBase64(credential.response.clientDataJSON),\n signature: this.arrayBufferToBase64(credential.response.signature),\n userHandle: credential.response.userHandle ?\n this.arrayBufferToBase64(credential.response.userHandle) : null\n }\n };\n\n // Step 5: Send credential to server for verification and login\n const loginResponse = await this.app.rest.POST('/api/auth/passkey/verify', {\n credential: credentialData,\n challengeId: challengeData.challengeId\n });\n\n if (!loginResponse.success || !loginResponse.data.status) {\n throw new Error(loginResponse.data.error || 'Passkey verification failed');\n }\n\n const { token, refreshToken, user } = loginResponse.data.data;\n\n // Store tokens and set auth state\n this.authManager.tokenManager.setTokens(token, refreshToken, true);\n \n // Set auth state\n const userInfo = this.authManager.tokenManager.getUserInfo();\n this.authManager.setAuthState({ ...user, ...userInfo });\n \n // Schedule refresh\n if (this.authManager.config.autoRefresh) {\n this.authManager.scheduleTokenRefresh();\n }\n \n this.authManager.emit('login', this.authManager.user);\n\n return {\n success: true,\n user: this.authManager.user\n };\n\n } catch (error) {\n console.error('Passkey login error:', error);\n this.authManager.emit('loginError', error);\n throw new Error(error.message || 'Passkey authentication failed');\n }\n }\n\n /**\n * Setup passkey for current authenticated user\n * @returns {Promise<object>} Setup result\n */\n async setupPasskey() {\n if (!this.isSupported()) {\n throw new Error('Passkey authentication is not supported in this browser');\n }\n\n if (!this.authManager.isAuthenticated) {\n throw new Error('User must be authenticated to setup passkey');\n }\n\n try {\n // Step 1: Get registration options from server\n const optionsResponse = await this.app.rest.POST('/api/auth/passkey/register-options');\n\n if (!optionsResponse.success || !optionsResponse.data.data.options) {\n throw new Error('No registration options received from server');\n }\n\n const optionsData = optionsResponse.data.data;\n const options = optionsData.options;\n\n // Step 2: Create credential creation options\n const credentialCreationOptions = {\n publicKey: {\n challenge: this.base64ToArrayBuffer(options.challenge),\n rp: {\n name: this.config.rpName,\n id: this.config.rpId\n },\n user: {\n id: this.base64ToArrayBuffer(options.userId),\n name: options.userName,\n displayName: options.userDisplayName\n },\n pubKeyCredParams: [\n { alg: -7, type: 'public-key' }, // ES256\n { alg: -257, type: 'public-key' } // RS256\n ],\n authenticatorSelection: {\n userVerification: this.config.userVerification\n },\n timeout: this.config.timeout,\n attestation: 'none'\n }\n };\n\n // Add authenticator attachment preference if specified\n if (this.config.authenticatorAttachment) {\n credentialCreationOptions.publicKey.authenticatorSelection.authenticatorAttachment = \n this.config.authenticatorAttachment;\n }\n\n // Step 3: Create credential\n const credential = await navigator.credentials.create(credentialCreationOptions);\n\n if (!credential) {\n throw new Error('Failed to create credential');\n }\n\n // Step 4: Prepare credential data for server registration\n const credentialData = {\n id: credential.id,\n rawId: this.arrayBufferToBase64(credential.rawId),\n type: credential.type,\n response: {\n attestationObject: this.arrayBufferToBase64(credential.response.attestationObject),\n clientDataJSON: this.arrayBufferToBase64(credential.response.clientDataJSON)\n }\n };\n\n // Step 5: Register credential with server\n const registrationResponse = await this.app.rest.POST('/api/auth/passkey/register', {\n credential: credentialData,\n optionsId: optionsData.optionsId\n });\n\n if (!registrationResponse.success || !registrationResponse.data.status) {\n throw new Error(registrationResponse.data.error || 'Failed to register passkey');\n }\n\n // Emit success event\n this.authManager.emit('passkeySetupSuccess', registrationResponse.data.data);\n\n return {\n success: true,\n data: registrationResponse.data.data\n };\n\n } catch (error) {\n console.error('Passkey setup error:', error);\n this.authManager.emit('passkeySetupError', error);\n throw new Error(error.message || 'Failed to setup passkey');\n }\n }\n\n /**\n * Check if user has passkeys registered\n * @returns {Promise<object>} Result with passkey availability\n */\n async hasPasskeys() {\n if (!this.authManager.isAuthenticated) {\n return { success: false, hasPasskeys: false };\n }\n\n try {\n const response = await this.app.rest.GET('/api/auth/passkey/list');\n\n return {\n success: response.success,\n hasPasskeys: response.data.data?.passkeys && response.data.data.passkeys.length > 0,\n count: response.data.data?.passkeys ? response.data.data.passkeys.length : 0\n };\n } catch (error) {\n console.error('Error checking passkeys:', error);\n return { success: false, hasPasskeys: false };\n }\n }\n\n /**\n * Remove/revoke a specific passkey\n * @param {string} credentialId - ID of credential to remove\n * @returns {Promise<object>} Result of removal\n */\n async removePasskey(credentialId) {\n if (!this.authManager.isAuthenticated) {\n throw new Error('User must be authenticated to remove passkey');\n }\n\n try {\n const response = await this.app.rest.DELETE('/api/auth/passkey/remove', { credentialId });\n\n if (!response.success || !response.data.status) {\n throw new Error(response.data.error || 'Failed to remove passkey');\n }\n\n this.authManager.emit('passkeyRemoved', { credentialId });\n\n return {\n success: true,\n data: response.data.data\n };\n } catch (error) {\n console.error('Error removing passkey:', error);\n throw new Error(error.message || 'Failed to remove passkey');\n }\n }\n\n /**\n * Convert base64 string to ArrayBuffer\n * @param {string} base64 - Base64 string\n * @returns {ArrayBuffer} ArrayBuffer\n */\n base64ToArrayBuffer(base64) {\n const binaryString = atob(base64);\n const bytes = new Uint8Array(binaryString.length);\n for (let i = 0; i < binaryString.length; i++) {\n bytes[i] = binaryString.charCodeAt(i);\n }\n return bytes.buffer;\n }\n\n /**\n * Convert ArrayBuffer to base64 string\n * @param {ArrayBuffer} buffer - ArrayBuffer\n * @returns {string} Base64 string\n */\n arrayBufferToBase64(buffer) {\n const bytes = new Uint8Array(buffer);\n let binary = '';\n for (let i = 0; i < bytes.byteLength; i++) {\n binary += String.fromCharCode(bytes[i]);\n }\n return btoa(binary);\n }\n\n /**\n * Get browser compatibility info\n * @returns {object} Compatibility information\n */\n getBrowserCompatibility() {\n return {\n webAuthnSupported: !!window.PublicKeyCredential,\n credentialsSupported: !!navigator.credentials,\n platformSupported: this.config.authenticatorAttachment === 'platform' ? \n window.PublicKeyCredential?.isUserVerifyingPlatformAuthenticatorAvailable?.() : true,\n conditionalMediationSupported: window.PublicKeyCredential?.isConditionalMediationAvailable?.()\n };\n }\n\n /**\n * Plugin cleanup\n */\n destroy() {\n // Remove methods from auth manager\n if (this.authManager) {\n delete this.authManager.loginWithPasskey;\n delete this.authManager.setupPasskey;\n delete this.authManager.isPasskeySupported;\n }\n \n this.authManager = null;\n this.app = null;\n this.authService = null;\n }\n}"],"names":["c"],"mappings":"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AA;AAGlB,UAAU,8CAA8C,IAAI;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAgG5D,UAAU,qCAAqC,IAAI;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AA8KnD,UAAU,wCAAwC,IAAI;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAmMtD,UAAU,6CAA6C,IAAI;AAAA;AAAA;AAAA;AAAA;AA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"}
1
+ {"version":3,"file":"auth.es.js","sources":["../src/extensions/auth/AuthManager.js","../src/extensions/auth/pages/LoginPage.js","../src/extensions/auth/pages/RegisterPage.js","../src/extensions/auth/pages/ForgotPasswordPage.js","../src/extensions/auth/pages/ResetPasswordPage.js","../src/templates.js","../src/extensions/auth/AuthApp.js","../src/extensions/auth/plugins/PasskeyPlugin.js"],"sourcesContent":["/**\n * AuthManager - Simplified authentication state management for MOJO Framework\n * Handles auth state, integrates with AuthService and TokenManager, supports plugins\n */\n\nimport TokenManager from '@core/services/TokenManager.js';\n\nexport default class AuthManager {\n constructor(app, config = {}) {\n this.app = app;\n this.config = {\n autoRefresh: true,\n refreshThreshold: 5, // minutes before expiry\n plugins: {},\n ...config\n };\n\n // Core services\n this.tokenManager = new TokenManager();\n\n // Auth state\n this.isAuthenticated = false;\n this.user = null;\n this.refreshTimer = null;\n\n // Plugin registry\n this.plugins = new Map();\n\n // Initialize\n this.initialize();\n }\n\n /**\n * Initialize auth manager\n */\n initialize() {\n // Check for existing valid session\n this.checkAuthState();\n\n // Set up auto-refresh if enabled\n if (this.config.autoRefresh) {\n this.scheduleTokenRefresh();\n }\n\n // Make auth manager available to app\n if (this.app) {\n this.app.auth = this;\n }\n }\n\n /**\n * Check current authentication state from stored tokens\n */\n checkAuthState() {\n if (this.tokenManager.isValid()) {\n const userInfo = this.tokenManager.getUserInfo();\n if (userInfo) {\n this.setAuthState(userInfo);\n return true;\n }\n }\n\n this.clearAuthState();\n return false;\n }\n\n /**\n * Login with username/email and password\n * @param {string} username - Username or email\n * @param {string} password - Password\n * @param {boolean} rememberMe - Persist session\n * @returns {Promise<object>} Login result\n */\n async login(username, password, rememberMe = true) {\n const response = await this.app.rest.POST('/api/login', { username, password });\n\n if (response.success && response.data.status) {\n const { access_token, refresh_token, user } = response.data.data;\n\n // Store tokens\n this.tokenManager.setTokens(access_token, refresh_token, rememberMe);\n\n // Set auth state\n const userInfo = this.tokenManager.getUserInfo();\n this.setAuthState({ ...user, ...userInfo });\n\n // Schedule refresh\n if (this.config.autoRefresh) {\n this.scheduleTokenRefresh();\n }\n\n this.emit('login', this.user);\n return { success: true, user: this.user };\n }\n\n const message = response.data?.error || response.message || 'Login failed. Please try again.';\n this.emit('loginError', { message });\n return { success: false, message };\n }\n\n /**\n * Register new user\n * @param {object} userData - Registration data\n * @returns {Promise<object>} Registration result\n */\n async register(userData) {\n const response = await this.app.rest.POST('/api/register', userData);\n\n if (response.success && response.data.status) {\n const { token, refreshToken, user } = response.data.data;\n\n // Store tokens\n this.tokenManager.setTokens(token, refreshToken, true);\n\n // Set auth state\n const userInfo = this.tokenManager.getUserInfo();\n this.setAuthState({ ...user, ...userInfo });\n\n // Schedule refresh\n if (this.config.autoRefresh) {\n this.scheduleTokenRefresh();\n }\n\n this.emit('register', this.user);\n return { success: true, user: this.user };\n }\n\n const message = response.data?.error || response.message || 'Registration failed.';\n this.emit('registerError', { message });\n return { success: false, message };\n }\n\n /**\n * Logout current user\n */\n async logout() {\n try {\n const token = this.tokenManager.getToken();\n if (token) {\n // Call logout API but don't block logout on failure\n this.app.rest.POST('/api/auth/logout').catch(err => {\n console.warn('Server logout failed, proceeding with local logout.', err);\n });\n }\n } finally {\n this.clearAuthState();\n this.emit('logout');\n }\n }\n\n /**\n * Refresh access token\n * @returns {Promise<boolean>} Success status\n */\n async refreshToken() {\n const refreshToken = this.tokenManager.getRefreshToken();\n if (!refreshToken) {\n this.clearAuthState();\n this.emit('tokenExpired');\n return false;\n }\n\n const response = await this.app.rest.POST('/api/auth/token/refresh', { refreshToken });\n\n if (response.success && response.data.status) {\n const { token, refreshToken: newRefreshToken } = response.data.data;\n\n // Determine persistence from current storage\n const isPersistent = !!localStorage.getItem(this.tokenManager.tokenKey);\n\n // Store new tokens\n this.tokenManager.setTokens(token, newRefreshToken, isPersistent);\n\n // Update user info\n const userInfo = this.tokenManager.getUserInfo();\n if (userInfo) {\n this.user = { ...this.user, ...userInfo };\n }\n\n // Schedule next refresh\n this.scheduleTokenRefresh();\n\n this.emit('tokenRefreshed');\n return true;\n }\n\n console.error('Token refresh failed:', response.data?.error || response.message);\n this.clearAuthState();\n this.emit('tokenExpired');\n return false;\n }\n\n /**\n * Set authentication state\n * @param {object} user - User data\n */\n setAuthState(user) {\n this.isAuthenticated = true;\n this.user = user;\n\n if (this.app?.setState) {\n this.app.setState('auth', {\n isAuthenticated: true,\n user: user\n });\n }\n }\n\n /**\n * Clear authentication state\n */\n clearAuthState() {\n this.isAuthenticated = false;\n this.user = null;\n this.tokenManager.clearTokens();\n\n if (this.refreshTimer) {\n clearTimeout(this.refreshTimer);\n this.refreshTimer = null;\n }\n\n if (this.app?.setState) {\n this.app.setState('auth', {\n isAuthenticated: false,\n user: null\n });\n }\n }\n\n /**\n * Schedule automatic token refresh\n */\n scheduleTokenRefresh() {\n if (this.refreshTimer) {\n clearTimeout(this.refreshTimer);\n }\n\n if (!this.tokenManager.isValid()) {\n return;\n }\n\n if (this.tokenManager.isExpiringSoon(this.config.refreshThreshold)) {\n // Token expires soon, refresh immediately\n this.refreshToken();\n return;\n }\n\n // Schedule refresh before expiry\n const token = this.tokenManager.getToken();\n const payload = this.tokenManager.decode(token);\n if (payload?.exp) {\n const now = Math.floor(Date.now() / 1000);\n const timeUntilRefresh = (payload.exp - now - (this.config.refreshThreshold * 60)) * 1000;\n\n if (timeUntilRefresh > 0) {\n this.refreshTimer = setTimeout(() => {\n this.refreshToken();\n }, timeUntilRefresh);\n }\n }\n }\n\n /**\n * Register a plugin\n * @param {string} name - Plugin name\n * @param {object} plugin - Plugin instance\n */\n registerPlugin(name, plugin) {\n this.plugins.set(name, plugin);\n plugin.initialize(this, this.app);\n }\n\n /**\n * Get a plugin by name\n * @param {string} name - Plugin name\n * @returns {object|null} Plugin instance\n */\n getPlugin(name) {\n return this.plugins.get(name) || null;\n }\n\n /**\n * Request password reset\n * @param {string} email - User email\n * @returns {Promise<object>} Request result\n */\n async forgotPassword(email, method = 'code') {\n const response = await this.app.rest.POST('/api/auth/forgot', { email, method });\n\n if (response.success && response.data.status) {\n this.emit('forgotPasswordSuccess', { email, method });\n return { success: true, message: response.data.data?.message };\n }\n\n const message = response.data?.error || response.message || 'Failed to process request.';\n this.emit('forgotPasswordError', { message });\n return { success: false, message };\n }\n\n /**\n * Reset password with a token from an email link\n * @param {string} token - Reset token\n * @param {string} newPassword - New password\n * @returns {Promise<object>} Reset result\n */\n async resetPasswordWithToken(token, newPassword) {\n const payload = {\n token: token,\n new_password: newPassword\n };\n const response = await this.app.rest.POST('/api/auth/password/reset/token', payload);\n\n if (response.success && response.data.status) {\n this.emit('resetPasswordSuccess');\n return { success: true, message: response.data.data?.message };\n }\n\n const message = response.data?.error || response.message || 'Failed to reset password.';\n this.emit('resetPasswordError', { message });\n return { success: false, message };\n }\n\n /**\n * Reset password with an email and code\n * @param {string} email - User's email\n * @param {string} code - The verification code\n * @param {string} newPassword - New password\n * @returns {Promise<object>} Reset result\n */\n async resetPasswordWithCode(email, code, newPassword) {\n const payload = {\n email: email,\n code: code,\n new_password: newPassword\n };\n const response = await this.app.rest.POST('/api/auth/password/reset/code', payload);\n\n if (response.success && response.data.status) {\n this.emit('resetPasswordSuccess');\n return { success: true, message: response.data.data?.message };\n }\n\n const message = response.data?.error || response.message || 'Failed to reset password.';\n this.emit('resetPasswordError', { message });\n return { success: false, message };\n }\n\n /**\n * Get authorization header for API requests\n * @returns {string|null} Authorization header\n */\n getAuthHeader() {\n return this.tokenManager.getAuthHeader();\n }\n\n /**\n * Emit event to app\n * @param {string} event - Event name\n * @param {*} data - Event data\n */\n emit(event, data) {\n if (this.app?.events?.emit) {\n this.app.events.emit(`auth:${event}`, data);\n }\n }\n\n /**\n * Cleanup auth manager\n */\n destroy() {\n if (this.refreshTimer) {\n clearTimeout(this.refreshTimer);\n }\n\n this.plugins.forEach(plugin => {\n if (plugin.destroy) {\n plugin.destroy();\n }\n });\n\n this.plugins.clear();\n }\n}\n","/**\n * LoginPage - Simplified login page for MOJO Auth\n * Handles username/email and password authentication with optional passkey support\n */\n\nimport Page from '@core/Page.js';\nimport { VERSION } from '/src/version.js';\n\nexport default class LoginPage extends Page {\n static pageName = 'login';\n static title = 'Login';\n static icon = 'bi-box-arrow-in-right';\n static route = '/login';\n\n constructor(options = {}) {\n super({\n ...options,\n pageName: LoginPage.pageName,\n route: options.route || LoginPage.route,\n pageIcon: LoginPage.icon,\n template: options.template,\n });\n\n // Get auth config from options (passed from AuthApp)\n this.authConfig = options.authConfig || {\n ui: {\n title: 'My App',\n logoUrl: '/assets/logo.png',\n messages: {\n loginTitle: 'Welcome Back',\n loginSubtitle: 'Sign in to your account'\n }\n },\n features: {\n rememberMe: false,\n forgotPassword: true,\n registration: false\n }\n };\n }\n\n async onInit() {\n await super.onInit();\n\n // Initialize form data\n this.data = {\n\n // Form fields\n username: '',\n password: '',\n rememberMe: true,\n loginIcon: this.options.pageIcon,\n // UI state\n isLoading: false,\n error: null,\n showPassword: false,\n version: VERSION,\n // Feature availability\n passkeySupported: this.getApp().auth?.isPasskeySupported?.() || false,\n // Config data for template\n ...this.authConfig.ui,\n ...this.authConfig.features,\n\n };\n }\n\n async onEnter() {\n await super.onEnter();\n\n // Set page title\n document.title = `${LoginPage.title} - ${this.authConfig.ui.title}`;\n\n // Check if already authenticated\n const auth = this.getApp().auth;\n if (auth?.isAuthenticated) {\n this.getApp().navigate('/');\n return;\n }\n\n // Clear form and errors\n this.updateData({\n username: '',\n password: '',\n error: null,\n isLoading: false\n });\n }\n\n async onAfterRender() {\n await super.onAfterRender();\n\n // Focus on username input\n const usernameInput = this.element.querySelector('#loginUsername');\n if (usernameInput) {\n usernameInput.focus();\n }\n }\n\n /**\n * Handle field updates\n */\n async onActionUpdateField(event, element) {\n const field = element.dataset.field;\n const value = element.type === 'checkbox' ? element.checked : element.value;\n\n this.updateData({\n [field]: value,\n error: null // Clear error on input change\n });\n }\n\n /**\n * Toggle password visibility\n */\n async onActionTogglePassword(event) {\n event.preventDefault();\n this.updateData({ showPassword: !this.data.showPassword });\n\n // Update input type\n const passwordInput = this.element.querySelector('#loginPassword');\n if (passwordInput) {\n passwordInput.type = this.data.showPassword ? 'text' : 'password';\n }\n }\n\n /**\n * Handle login form submission\n */\n async onActionLogin(event) {\n event.preventDefault();\n\n // Manually get values from form inputs on submit\n this.data.username = this.element.querySelector('#loginUsername')?.value || '';\n this.data.password = this.element.querySelector('#loginPassword')?.value || '';\n\n await this.updateData({ error: null, isLoading: true }, true);\n\n const auth = this.getApp().auth;\n if (!auth) {\n await this.updateData({ error: 'Authentication system not available', isLoading: false }, true);\n return;\n }\n\n // Basic validation\n if (!this.data.username || !this.data.password) {\n await this.updateData({ error: 'Please enter both username and password', isLoading: false }, true);\n return;\n }\n\n const result = await auth.login(\n this.data.username,\n this.data.password,\n this.data.rememberMe\n );\n\n if (!result.success) {\n await this.updateData({\n error: result.message,\n isLoading: false\n }, true);\n\n // Focus password field for retry\n const passwordInput = this.element.querySelector('#loginPassword');\n if (passwordInput) {\n passwordInput.focus();\n passwordInput.select();\n }\n }\n // On success, the global 'auth:login' event will trigger navigation.\n }\n\n /**\n * Handle passkey login\n */\n async onActionLoginWithPasskey(event) {\n event.preventDefault();\n\n const auth = this.getApp().auth;\n if (!auth?.isPasskeySupported?.()) {\n this.getApp().showError('Passkey authentication is not supported');\n return;\n }\n\n this.updateData({ error: null, isLoading: true });\n\n try {\n const result = await auth.loginWithPasskey();\n\n if (result.success) {\n // Success handled by AuthApp event handlers\n console.log('Passkey login successful');\n }\n\n } catch (error) {\n console.error('Passkey login error:', error);\n this.updateData({\n error: 'Passkey authentication failed. Please try another method.',\n isLoading: false\n });\n }\n }\n\n /**\n * Navigate to registration page\n */\n async onActionRegister(event) {\n event.preventDefault();\n this.getApp().navigate('/register');\n }\n\n /**\n * Navigate to forgot password page\n */\n async onActionForgotPassword(event) {\n event.preventDefault();\n this.getApp().navigate('/forgot-password');\n }\n\n /**\n * Handle Enter key in form fields\n */\n async onActionHandleKeyPress(event, element) {\n if (event.key === 'Enter') {\n event.preventDefault();\n\n // Move focus or submit form\n if (element.id === 'loginUsername') {\n const passwordInput = this.element.querySelector('#loginPassword');\n if (passwordInput) {\n passwordInput.focus();\n }\n } else if (element.id === 'loginPassword') {\n await this.onActionLogin(event);\n }\n }\n }\n\n /**\n * Get view data for template rendering\n */\n async getViewData() {\n return {\n ...this.data\n };\n }\n}\n","/**\n * RegisterPage - Simplified registration page for MOJO Auth\n * Handles user registration with name, email/username, password, and optional terms acceptance\n */\n\nimport Page from '@core/Page.js';\n\nexport default class RegisterPage extends Page {\n static pageName = 'auth-register';\n static title = 'Register';\n static icon = 'bi-person-plus';\n static route = 'register';\n\n constructor(options = {}) {\n super({\n ...options,\n pageName: RegisterPage.pageName,\n route: options.route || RegisterPage.route,\n pageIcon: RegisterPage.icon,\n template: options.template\n });\n\n // Get auth config from options (passed from AuthApp)\n this.authConfig = options.authConfig || {\n ui: {\n title: 'My App',\n logoUrl: '/assets/logo.png',\n messages: {\n registerTitle: 'Create Account',\n registerSubtitle: 'Join us today'\n }\n },\n features: {\n registration: true\n }\n };\n }\n\n async onInit() {\n await super.onInit();\n\n // Initialize form data\n this.data = {\n // Config data for template\n ...this.authConfig.ui,\n ...this.authConfig.features,\n\n // Form fields\n name: '',\n email: '',\n password: '',\n confirmPassword: '',\n acceptTerms: false,\n\n // UI state\n isLoading: false,\n error: null,\n showPassword: false,\n showConfirmPassword: false,\n\n // Validation state\n passwordStrength: null,\n passwordMatch: true\n };\n }\n\n async onEnter() {\n await super.onEnter();\n\n // Set page title\n document.title = `${RegisterPage.title} - ${this.authConfig.ui.title}`;\n\n // Check if already authenticated\n const auth = this.getApp().auth;\n if (auth?.isAuthenticated) {\n this.getApp().navigate('/');\n return;\n }\n\n // Clear form and errors\n this.updateData({\n name: '',\n email: '',\n password: '',\n confirmPassword: '',\n acceptTerms: false,\n error: null,\n isLoading: false,\n passwordStrength: null,\n passwordMatch: true\n });\n }\n\n async onAfterRender() {\n await super.onAfterRender();\n\n // Focus on name input\n const nameInput = this.element.querySelector('#registerName');\n if (nameInput) {\n nameInput.focus();\n }\n }\n\n /**\n * Handle field updates\n */\n async onActionUpdateField(event, element) {\n const field = element.dataset.field;\n const value = element.type === 'checkbox' ? element.checked : element.value;\n\n this.updateData({ [field]: value });\n\n // Check password strength when password changes\n if (field === 'password') {\n this.checkPasswordStrength(value);\n }\n\n // Check password match when either password field changes\n if (field === 'password' || field === 'confirmPassword') {\n this.checkPasswordMatch();\n }\n\n // Clear error on input change\n if (this.data.error) {\n this.updateData({ error: null });\n }\n }\n\n /**\n * Check password strength\n */\n checkPasswordStrength(password) {\n let strength = null;\n\n if (password.length === 0) {\n strength = null;\n } else if (password.length < 6) {\n strength = 'weak';\n } else if (password.length < 8) {\n strength = 'fair';\n } else if (/^(?=.*[a-z])(?=.*[A-Z])(?=.*\\d)(?=.*[@$!%*?&])[A-Za-z\\d@$!%*?&]/.test(password)) {\n strength = 'strong';\n } else if (/^(?=.*[a-z])(?=.*[A-Z])(?=.*\\d)/.test(password)) {\n strength = 'good';\n } else {\n strength = 'fair';\n }\n\n this.updateData({ passwordStrength: strength }, true);\n }\n\n /**\n * Check if passwords match\n */\n checkPasswordMatch() {\n const match = !this.data.confirmPassword ||\n this.data.password === this.data.confirmPassword;\n this.updateData({ passwordMatch: match }, true);\n }\n\n /**\n * Toggle password visibility\n */\n async onActionTogglePassword(event, element) {\n event.preventDefault();\n const field = element.dataset.passwordField;\n\n if (field === 'password') {\n this.updateData({ showPassword: !this.data.showPassword });\n const input = this.element.querySelector('#registerPassword');\n if (input) {\n input.type = this.data.showPassword ? 'text' : 'password';\n }\n } else if (field === 'confirmPassword') {\n this.updateData({ showConfirmPassword: !this.data.showConfirmPassword });\n const input = this.element.querySelector('#registerConfirmPassword');\n if (input) {\n input.type = this.data.showConfirmPassword ? 'text' : 'password';\n }\n }\n }\n\n /**\n * Handle registration form submission\n */\n async onActionRegister(event) {\n event.preventDefault();\n await this.updateData({ error: null, isLoading: true }, true);\n\n // Validation\n if (!this.data.name || !this.data.email || !this.data.password || !this.data.confirmPassword) {\n await this.updateData({ error: 'Please fill in all required fields', isLoading: false }, true);\n return;\n }\n if (this.data.name.trim().length < 2) {\n await this.updateData({ error: 'Name must be at least 2 characters long', isLoading: false }, true);\n return;\n }\n const emailRegex = /^[^\\s@]+@[^\\s@]+\\.[^\\s@]+$/;\n if (!emailRegex.test(this.data.email)) {\n await this.updateData({ error: 'Please enter a valid email address', isLoading: false }, true);\n return;\n }\n if (this.data.password.length < 6) {\n await this.updateData({ error: 'Password must be at least 6 characters long', isLoading: false }, true);\n return;\n }\n if (this.data.password !== this.data.confirmPassword) {\n await this.updateData({ error: 'Passwords do not match', isLoading: false }, true);\n return;\n }\n\n const auth = this.getApp().auth;\n if (!auth) {\n await this.updateData({ error: 'Authentication system not available', isLoading: false }, true);\n return;\n }\n\n const registrationData = {\n name: this.data.name.trim(),\n email: this.data.email.toLowerCase().trim(),\n password: this.data.password,\n acceptedTerms: this.data.acceptTerms\n };\n\n const result = await auth.register(registrationData);\n\n if (!result.success) {\n await this.updateData({\n error: result.message || 'Registration failed. Please try again.',\n isLoading: false\n }, true);\n }\n // On success, the global 'auth:register' event will trigger navigation.\n }\n\n /**\n * Navigate to login page\n */\n async onActionLogin(event) {\n event.preventDefault();\n this.getApp().navigate('/login');\n }\n\n /**\n * Handle Enter key in form fields\n */\n async onActionHandleKeyPress(event, element) {\n if (event.key === 'Enter') {\n event.preventDefault();\n\n // Navigate through fields on Enter\n const fieldOrder = ['registerName', 'registerEmail', 'registerPassword', 'registerConfirmPassword'];\n const currentIndex = fieldOrder.indexOf(element.id);\n\n if (currentIndex >= 0 && currentIndex < fieldOrder.length - 1) {\n // Move to next field\n const nextField = this.element.querySelector(`#${fieldOrder[currentIndex + 1]}`);\n if (nextField) {\n nextField.focus();\n }\n } else if (currentIndex === fieldOrder.length - 1) {\n // Last field - submit form\n await this.onActionRegister(event);\n }\n }\n }\n\n /**\n * Get view data for template rendering\n */\n async getViewData() {\n return {\n ...this.data\n };\n }\n}\n","/**\n * ForgotPasswordPage - Simplified password reset page for MOJO Auth\n * Handles password reset request via email, supporting both 'link' and 'code' methods.\n */\nimport Page from '@core/Page.js';\n\nexport default class ForgotPasswordPage extends Page {\n static pageName = 'auth-forgot-password';\n static title = 'Forgot Password';\n static icon = 'bi-key';\n static route = 'forgot-password';\n\n constructor(options = {}) {\n super({ ...options, template: options.template });\n this.authConfig = options.authConfig || {\n passwordResetMethod: 'code',\n ui: { title: 'My App' },\n features: {}\n };\n }\n\n async onInit() {\n this.data = {\n ...this.authConfig.ui,\n ...this.authConfig.features,\n passwordResetMethod: this.authConfig.passwordResetMethod,\n step: 'email', // 'email', 'code', 'link_sent', 'success'\n isLoading: false,\n error: null,\n email: '' // Store email across steps\n };\n }\n\n async onEnter() {\n document.title = `${ForgotPasswordPage.title} - ${this.authConfig.ui.title}`;\n this.updateData({\n step: 'email',\n isLoading: false,\n error: null,\n email: ''\n });\n }\n\n /**\n * Gets data from the currently visible form.\n * @param {string} formSelector - The CSS selector for the form.\n * @returns {object} An object containing the form data.\n */\n getFormData(formSelector) {\n const form = this.element.querySelector(formSelector);\n if (!form) return {};\n const formData = new FormData(form);\n return Object.fromEntries(formData.entries());\n }\n\n /**\n * Handles the initial request to reset a password.\n */\n async onActionRequestReset() {\n const { email } = this.getFormData('#form-request-reset');\n await this.updateData({ isLoading: true, error: null, email }, true);\n\n if (!email) {\n return this.updateData({ error: 'Please enter your email address', isLoading: false }, true);\n }\n\n const auth = this.getApp().auth;\n const resetMethod = this.authConfig.passwordResetMethod || 'code';\n const response = await auth.forgotPassword(email, resetMethod);\n\n if (resetMethod === 'link') {\n await this.updateData({ step: 'link_sent', isLoading: false }, true);\n if (!response.success) console.error('Forgot password (link) error:', response.message);\n } else {\n if (response.success) {\n await this.updateData({ step: 'code', isLoading: false }, true);\n } else {\n await this.updateData({ error: response.message, isLoading: false }, true);\n }\n }\n }\n\n /**\n * Handles the final password reset using a verification code.\n */\n async onActionResetWithCode() {\n const { code, new_password, confirm_password } = this.getFormData('#form-reset-with-code');\n await this.updateData({ isLoading: true, error: null }, true);\n\n if (!code || !new_password) {\n return this.updateData({ error: 'Please enter the code and your new password', isLoading: false }, true);\n }\n if (new_password !== confirm_password) {\n return this.updateData({ error: 'Passwords do not match', isLoading: false }, true);\n }\n\n const auth = this.getApp().auth;\n const response = await auth.resetPasswordWithCode(this.data.email, code, new_password);\n\n if (response.success) {\n await this.updateData({ step: 'success', isLoading: false }, true);\n setTimeout(() => this.getApp().navigate('/login'), 3000);\n } else {\n await this.updateData({ error: response.message, isLoading: false }, true);\n }\n }\n\n async onActionBackToLogin() {\n this.getApp().navigate('/login');\n }\n\n // --- Template Getters for State ---\n\n get isStepEmail() {\n return this.data.step === 'email';\n }\n\n get isStepCode() {\n return this.data.step === 'code';\n }\n\n get isStepLinkSent() {\n return this.data.step === 'link_sent';\n }\n\n get isStepSuccess() {\n return this.data.step === 'success';\n }\n}\n","/**\n * ResetPasswordPage - Password reset completion page for MOJO Auth\n * Handles password reset when user clicks email link with reset token\n */\n\nimport Page from '@core/Page.js';\n\nexport default class ResetPasswordPage extends Page {\n static pageName = 'auth-reset-password';\n static title = 'Reset Password';\n static icon = 'bi-key-fill';\n static route = 'reset-password';\n\n constructor(options = {}) {\n super({\n ...options,\n pageName: ResetPasswordPage.pageName,\n route: options.route || ResetPasswordPage.route,\n pageIcon: ResetPasswordPage.icon,\n template: 'auth/pages/ResetPasswordPage.mst'\n });\n\n // Get auth config from options (passed from AuthApp)\n this.authConfig = options.authConfig || {\n ui: {\n title: 'My App',\n logoUrl: '/assets/logo.png',\n messages: {\n resetTitle: 'Set New Password',\n resetSubtitle: 'Choose a strong password'\n }\n },\n features: {\n registration: true\n }\n };\n\n // Extract reset token from URL\n this.resetToken = null;\n }\n\n async onInit() {\n await super.onInit();\n\n // Initialize form data\n this.data = {\n // Config data for template\n ...this.authConfig.ui,\n ...this.authConfig.features,\n\n // Form fields\n password: '',\n confirmPassword: '',\n resetToken: '',\n\n // UI state\n isLoading: false,\n error: null,\n success: false,\n successMessage: null,\n showPassword: false,\n showConfirmPassword: false,\n\n // Validation state\n passwordStrength: null,\n passwordMatch: true,\n tokenValid: false\n };\n }\n\n async onEnter() {\n await super.onEnter();\n\n // Set page title\n document.title = `${ResetPasswordPage.title} - ${this.authConfig.ui.title}`;\n\n // Extract reset token from URL parameters\n const urlParams = new URLSearchParams(window.location.search);\n this.resetToken = urlParams.get('token') || '';\n\n if (!this.resetToken) {\n // No token provided, show error\n this.updateData({\n error: 'Invalid or missing reset token. Please request a new password reset.',\n tokenValid: false\n });\n return;\n }\n\n // Token exists, mark as valid for UI\n this.updateData({\n resetToken: this.resetToken,\n tokenValid: true,\n error: null,\n success: false\n });\n }\n\n async onAfterRender() {\n await super.onAfterRender();\n\n // Focus on password input if token is valid\n if (this.data.tokenValid) {\n const passwordInput = this.element.querySelector('#resetPassword');\n if (passwordInput) {\n passwordInput.focus();\n }\n }\n }\n\n /**\n * Handle field updates\n */\n async onActionUpdateField(event, element) {\n const field = element.dataset.field;\n const value = element.value;\n\n this.updateData({ \n [field]: value,\n error: null // Clear error on input change\n });\n\n // Check password strength when password changes\n if (field === 'password') {\n this.checkPasswordStrength(value);\n }\n\n // Check password match when either password field changes\n if (field === 'password' || field === 'confirmPassword') {\n this.checkPasswordMatch();\n }\n }\n\n /**\n * Check password strength\n */\n checkPasswordStrength(password) {\n let strength = null;\n\n if (password.length === 0) {\n strength = null;\n } else if (password.length < 6) {\n strength = 'weak';\n } else if (password.length < 8) {\n strength = 'fair';\n } else if (/^(?=.*[a-z])(?=.*[A-Z])(?=.*\\d)(?=.*[@$!%*?&])[A-Za-z\\d@$!%*?&]/.test(password)) {\n strength = 'strong';\n } else if (/^(?=.*[a-z])(?=.*[A-Z])(?=.*\\d)/.test(password)) {\n strength = 'good';\n } else {\n strength = 'fair';\n }\n\n this.updateData({ passwordStrength: strength }, true);\n }\n\n /**\n * Check if passwords match\n */\n checkPasswordMatch() {\n const match = !this.data.confirmPassword ||\n this.data.password === this.data.confirmPassword;\n this.updateData({ passwordMatch: match }, true);\n }\n\n /**\n * Toggle password visibility\n */\n async onActionTogglePassword(event, element) {\n event.preventDefault();\n const field = element.dataset.passwordField;\n\n if (field === 'password') {\n this.updateData({ showPassword: !this.data.showPassword });\n const input = this.element.querySelector('#resetPassword');\n if (input) {\n input.type = this.data.showPassword ? 'text' : 'password';\n }\n } else if (field === 'confirmPassword') {\n this.updateData({ showConfirmPassword: !this.data.showConfirmPassword });\n const input = this.element.querySelector('#resetConfirmPassword');\n if (input) {\n input.type = this.data.showConfirmPassword ? 'text' : 'password';\n }\n }\n }\n\n /**\n * Handle password reset submission\n */\n async onActionResetPassword(event) {\n event.preventDefault();\n await this.updateData({ error: null, isLoading: true }, true);\n\n // Basic validation\n if (!this.data.password || !this.data.confirmPassword) {\n await this.updateData({ error: 'Please enter and confirm your new password', isLoading: false }, true);\n return;\n }\n if (this.data.password.length < 6) {\n await this.updateData({ error: 'Password must be at least 6 characters long', isLoading: false }, true);\n return;\n }\n if (this.data.password !== this.data.confirmPassword) {\n await this.updateData({ error: 'Passwords do not match', isLoading: false }, true);\n return;\n }\n\n const auth = this.getApp().auth;\n if (!auth) {\n await this.updateData({ error: 'Authentication system not available', isLoading: false }, true);\n return;\n }\n\n const response = await auth.resetPasswordWithToken(this.resetToken, this.data.password);\n\n if (response.success) {\n await this.updateData({\n success: true,\n successMessage: response.message || 'Password reset successful! You can now log in.',\n isLoading: false\n }, true);\n\n // Redirect to login after delay\n setTimeout(() => {\n this.getApp().showSuccess('Password reset complete. Please log in.');\n this.getApp().navigate('/login');\n }, 3000);\n } else {\n await this.updateData({\n error: response.message || 'Password reset failed. Please try again.',\n isLoading: false\n }, true);\n }\n }\n\n /**\n * Navigate to login page\n */\n async onActionBackToLogin(event) {\n event.preventDefault();\n this.getApp().navigate('/login');\n }\n\n /**\n * Navigate to registration page\n */\n async onActionRegister(event) {\n event.preventDefault();\n this.getApp().navigate('/register');\n }\n\n /**\n * Request new reset email\n */\n async onActionRequestNew(event) {\n event.preventDefault();\n this.getApp().navigate('/forgot-password');\n }\n\n /**\n * Handle Enter key in form fields\n */\n async onActionHandleKeyPress(event, element) {\n if (event.key === 'Enter') {\n event.preventDefault();\n\n // Navigate through fields on Enter\n const fieldOrder = ['resetPassword', 'resetConfirmPassword'];\n const currentIndex = fieldOrder.indexOf(element.id);\n\n if (currentIndex >= 0 && currentIndex < fieldOrder.length - 1) {\n // Move to next field\n const nextField = this.element.querySelector(`#${fieldOrder[currentIndex + 1]}`);\n if (nextField) {\n nextField.focus();\n }\n } else if (currentIndex === fieldOrder.length - 1) {\n // Last field - submit form\n await this.onActionResetPassword(event);\n }\n }\n }\n\n /**\n * Get view data for template rendering\n */\n async getViewData() {\n return {\n ...this.data\n };\n }\n}","/**\n * Auto-generated template module\n * Generated: 2025-10-05T00:16:47.242Z\n * Contains all framework templates compiled as JavaScript strings\n */\n\n// Template registry\nconst templates = {};\n\n// Template: extensions/auth/pages/ForgotPasswordPage.mst\ntemplates['extensions/auth/pages/ForgotPasswordPage.mst'] = `<div class=\"auth-page forgot-password-page min-vh-100 d-flex align-items-center py-4\">\n <div class=\"container\">\n <div class=\"row justify-content-center\">\n <div class=\"col-sm-8 col-md-8 col-lg-6 col-xl-5\">\n <div class=\"card shadow-lg border-0\">\n <div class=\"card-body p-4 p-md-5\">\n <!-- Header -->\n <div class=\"text-center mb-4\">\n {{#logoUrl}}<img src=\"{{logoUrl}}\" alt=\"{{title}}\" class=\"mb-3\" style=\"max-height: 60px;\">{{/logoUrl}}\n <h2 class=\"h3 mb-2\">{{messages.forgotTitle}}</h2>\n <p class=\"text-muted\">{{messages.forgotSubtitle}}</p>\n </div>\n\n <!-- Error Alert -->\n {{#error}}\n <div class=\"alert alert-danger d-flex align-items-center alert-dismissible fade show\" role=\"alert\">\n <i class=\"bi bi-exclamation-triangle-fill me-2\"></i>\n <div>{{error}}</div>\n <button type=\"button\" class=\"btn-close\" data-bs-dismiss=\"alert\" aria-label=\"Close\"></button>\n </div>\n {{/error}}\n\n <!-- Step 1: Email Form -->\n {{#isStepEmail}}\n <form id=\"form-request-reset\" novalidate>\n <div class=\"mb-3\">\n <label for=\"forgotEmail\" class=\"form-label\"><i class=\"bi bi-envelope me-1\"></i>Email Address</label>\n <input type=\"email\" class=\"form-control form-control-lg\" id=\"forgotEmail\" name=\"email\" placeholder=\"Enter your registered email\" required autofocus>\n <div class=\"form-text\">We'll send you instructions to reset your password.</div>\n </div>\n <button type=\"button\" class=\"btn btn-primary btn-lg w-100 mb-3\" data-action=\"requestReset\" {{#isLoading}}disabled{{/isLoading}}>\n {{#isLoading}}<span class=\"spinner-border spinner-border-sm me-2\"></span>Sending...{{/isLoading}}\n {{^isLoading}}<i class=\"bi bi-send me-2\"></i>Send Instructions{{/isLoading}}\n </button>\n <button type=\"button\" class=\"btn btn-outline-secondary btn-lg w-100\" data-action=\"backToLogin\" {{#isLoading}}disabled{{/isLoading}}>\n <i class=\"bi bi-arrow-left me-2\"></i>Back to Login\n </button>\n </form>\n <div class=\"text-center mt-4\">\n <p class=\"text-muted\">Remember your password? <a href=\"#\" class=\"text-decoration-none fw-semibold\" data-action=\"backToLogin\">Sign in</a></p>\n </div>\n {{/isStepEmail}}\n\n <!-- Step 2 (Link Method): Confirmation -->\n {{#isStepLinkSent}}\n <div class=\"text-center\">\n <div class=\"mb-4\"><i class=\"bi bi-envelope-check text-success\" style=\"font-size: 4rem;\"></i></div>\n <h3 class=\"h4 mb-3\">Check your email</h3>\n <p class=\"text-muted\">If an account exists for <strong>{{data.email}}</strong>, we have sent instructions for resetting your password.</p>\n <div class=\"d-grid gap-2 mt-4\">\n <button type=\"button\" class=\"btn btn-primary btn-lg\" data-action=\"backToLogin\"><i class=\"bi bi-arrow-left me-2\"></i>Back to Login</button>\n </div>\n </div>\n {{/isStepLinkSent}}\n\n <!-- Step 2 (Code Method): Code Entry Form -->\n {{#isStepCode}}\n <p class=\"text-muted text-center mb-3\">A verification code has been sent to <strong>{{data.email}}</strong>. Please enter it below.</p>\n <form id=\"form-reset-with-code\" novalidate>\n <div class=\"mb-3\">\n <label for=\"resetCode\" class=\"form-label\"><i class=\"bi bi-shield-lock me-1\"></i>Verification Code</label>\n <input type=\"text\" class=\"form-control form-control-lg\" id=\"resetCode\" name=\"code\" placeholder=\"Enter code\" required>\n </div>\n <div class=\"mb-3\">\n <label for=\"resetPassword\" class=\"form-label\"><i class=\"bi bi-lock me-1\"></i>New Password</label>\n <input type=\"password\" class=\"form-control form-control-lg\" id=\"resetPassword\" name=\"new_password\" placeholder=\"Enter new password\" required autocomplete=\"new-password\">\n </div>\n <div class=\"mb-3\">\n <label for=\"confirmPassword\" class=\"form-label\"><i class=\"bi bi-lock-fill me-1\"></i>Confirm New Password</label>\n <input type=\"password\" class=\"form-control form-control-lg\" id=\"confirmPassword\" name=\"confirm_password\" placeholder=\"Confirm new password\" required autocomplete=\"new-password\">\n </div>\n <button type=\"button\" class=\"btn btn-primary btn-lg w-100\" data-action=\"resetWithCode\" {{#isLoading}}disabled{{/isLoading}}>\n {{#isLoading}}<span class=\"spinner-border spinner-border-sm me-2\"></span>Resetting...{{/isLoading}}\n {{^isLoading}}<i class=\"bi bi-key me-2\"></i>Reset Password{{/isLoading}}\n </button>\n </form>\n {{/isStepCode}}\n\n <!-- Step 3 (Code Method): Success -->\n {{#isStepSuccess}}\n <div class=\"text-center\">\n <div class=\"mb-4\"><i class=\"bi bi-check-circle text-success\" style=\"font-size: 4rem;\"></i></div>\n <h3 class=\"h4 mb-3\">Password Reset!</h3>\n <p class=\"text-muted\">Your password has been changed successfully. You will be redirected to the login page shortly.</p>\n </div>\n {{/isStepSuccess}}\n\n </div>\n </div>\n </div>\n </div>\n </div>\n</div>\n`;\n\n// Template: extensions/auth/pages/LoginPage.mst\ntemplates['extensions/auth/pages/LoginPage.mst'] = `<div class=\"auth-page min-vh-100 d-flex align-items-center py-4\">\n <div class=\"container\">\n <div class=\"row justify-content-center\">\n <div class=\"col-sm-10 col-md-8 col-lg-6 col-xl-5\">\n <div class=\"card shadow-lg border-0\">\n <div class=\"card-body p-4 p-md-5\">\n <!-- Logo and Header -->\n <div class=\"text-center mb-4\">\n {{#data.logoUrl}}\n <img src=\"{{data.logoUrl}}\" alt=\"{{data.title}}\" class=\"mb-3\" style=\"max-height: 60px;\">\n {{/data.logoUrl}}\n {{#data.messages.loginTitle}}\n <h2 class=\"h3 mb-2\">{{#data.loginIcon}}<i class=\"{{data.loginIcon}}\"></i> {{/data.loginIcon}}{{data.messages.loginTitle}}</h2>\n {{/data.messages.loginTitle}}\n {{/data.messages.loginSubtitle}}\n <p class=\"text-muted\">{{data.messages.loginSubtitle}}</p>\n {{/data.messages.loginSubtitle}}\n </div>\n\n <!-- Error Alert -->\n {{#data.error}}\n <div class=\"alert alert-danger d-flex align-items-center alert-dismissible fade show\" role=\"alert\">\n <i class=\"bi bi-exclamation-triangle-fill me-2\"></i>\n <div>{{data.error}}</div>\n <button type=\"button\" class=\"btn-close\" data-bs-dismiss=\"alert\" aria-label=\"Close\"></button>\n </div>\n {{/data.error}}\n\n <!-- Login Form -->\n <form novalidate>\n <!-- Username/Email Field -->\n <div class=\"mb-3\">\n <label for=\"loginUsername\" class=\"form-label\">\n <i class=\"bi bi-person me-1\"></i>Username or Email\n </label>\n <input\n type=\"text\"\n class=\"form-control form-control-lg\"\n id=\"loginUsername\"\n placeholder=\"Enter your username or email\"\n value=\"{{username}}\"\n data-field=\"username\"\n data-action-keydown=\"handleKeyPress\"\n autocomplete=\"username\"\n required\n autofocus\n {{#isLoading}}disabled{{/isLoading}}>\n </div>\n\n <!-- Password Field -->\n <div class=\"mb-3\">\n <label for=\"loginPassword\" class=\"form-label\">\n <i class=\"bi bi-lock me-1\"></i>Password\n </label>\n <div class=\"input-group\">\n <input\n type=\"{{#showPassword}}text{{/showPassword}}{{^showPassword}}password{{/showPassword}}\"\n class=\"form-control form-control-lg\"\n id=\"loginPassword\"\n placeholder=\"Enter your password\"\n value=\"{{password}}\"\n data-field=\"password\"\n data-action-keydown=\"handleKeyPress\"\n autocomplete=\"current-password\"\n required\n {{#isLoading}}disabled{{/isLoading}}>\n <button\n class=\"btn btn-outline-secondary\"\n type=\"button\"\n data-action=\"togglePassword\"\n {{#isLoading}}disabled{{/isLoading}}>\n <i class=\"bi bi-eye{{#data.showPassword}}-slash{{/data.showPassword}}\"></i>\n </button>\n </div>\n </div>\n\n <!-- Remember Me & Forgot Password -->\n <div class=\"d-flex justify-content-between align-items-center mb-4\">\n {{#data.rememberMe}}\n <div class=\"form-check\">\n <input\n class=\"form-check-input\"\n type=\"checkbox\"\n id=\"rememberMe\"\n data-field=\"rememberMe\"\n data-change-action=\"updateField\"\n autocomplete=\"off\"\n {{#rememberMe}}checked{{/rememberMe}}\n {{#isLoading}}disabled{{/isLoading}}>\n <label class=\"form-check-label\" for=\"rememberMe\">\n Remember me\n </label>\n </div>\n {{/data.rememberMe}}\n {{^data.rememberMe}}<div></div>{{/data.rememberMe}}\n\n {{#data.forgotPassword}}\n <a href=\"?page=forgot-password\" class=\"text-decoration-none\" data-action=\"forgotPassword\">\n Forgot password?\n </a>\n {{/data.forgotPassword}}\n </div>\n\n <!-- Login Button -->\n <button\n type=\"button\"\n class=\"btn btn-primary btn-lg w-100 mb-3\"\n data-action=\"login\"\n {{#data.isLoading}}disabled{{/data.isLoading}}>\n {{#data.isLoading}}\n <span class=\"spinner-border spinner-border-sm me-2\" role=\"status\" aria-hidden=\"true\"></span>\n Signing in...\n {{/data.isLoading}}\n {{^data.isLoading}}\n <i class=\"bi bi-box-arrow-in-right me-2\"></i>Sign In\n {{/data.isLoading}}\n </button>\n\n <!-- Alternative Login Methods -->\n {{#data.passkeySupported}}\n <div class=\"position-relative my-3\">\n <hr class=\"text-muted\">\n <span class=\"position-absolute top-50 start-50 translate-middle bg-white px-3 text-muted small\">\n OR\n </span>\n </div>\n\n <button\n type=\"button\"\n class=\"btn btn-outline-primary btn-lg w-100 mb-2\"\n data-action=\"loginWithPasskey\"\n {{#data.isLoading}}disabled{{/data.isLoading}}>\n <i class=\"bi bi-fingerprint me-2\"></i>Sign in with Passkey\n </button>\n {{/data.passkeySupported}}\n </form>\n\n <!-- Register Link -->\n {{#data.registration}}\n <div class=\"text-center mt-4\">\n <p class=\"mb-0\">\n Don't have an account?\n <a href=\"#\" class=\"text-decoration-none fw-semibold\" data-action=\"register\">\n Sign up\n </a>\n </p>\n </div>\n {{/data.registration}}\n </div>\n </div>\n\n <!-- Security Notice -->\n <!-- TOS and Privacy Links -->\n <div class=\"text-center mt-3 auth-footer-links\">\n {{#data.termsUrl}}\n <small><a href=\"{{data.termsUrl}}\" target=\"_blank\" rel=\"noopener noreferrer\">Terms of Service</a></small>\n {{/data.termsUrl}}\n {{#data.termsUrl}}{{#data.privacyUrl}}\n <small class=\"mx-1 text-muted\">&middot;</small>\n {{/data.privacyUrl}}{{/data.termsUrl}}\n {{#data.privacyUrl}}\n <small><a href=\"{{data.privacyUrl}}\" target=\"_blank\" rel=\"noopener noreferrer\">Privacy Policy</a></small>\n {{/data.privacyUrl}}\n <div class=\"text-muted text-center mt-3\">\n <small>version {{data.version}}</small>\n </div>\n </div>\n </div>\n </div>\n </div>\n</div>\n`;\n\n// Template: extensions/auth/pages/RegisterPage.mst\ntemplates['extensions/auth/pages/RegisterPage.mst'] = `<div class=\"auth-page register-page min-vh-100 d-flex align-items-center py-4\">\n <div class=\"container\">\n <div class=\"row justify-content-center\">\n <div class=\"col-sm-10 col-md-8 col-lg-6 col-xl-5\">\n <div class=\"card shadow-lg border-0\">\n <div class=\"card-body p-4 p-md-5\">\n <!-- Logo and Header -->\n <div class=\"text-center mb-4\">\n {{#logoUrl}}\n <img src=\"{{logoUrl}}\" alt=\"{{title}}\" class=\"mb-3\" style=\"max-height: 60px;\">\n {{/logoUrl}}\n <h2 class=\"h3 mb-2\">{{messages.registerTitle}}</h2>\n <p class=\"text-muted\">{{messages.registerSubtitle}}</p>\n </div>\n\n <!-- Error Alert -->\n {{#error}}\n <div class=\"alert alert-danger d-flex align-items-center alert-dismissible fade show\" role=\"alert\">\n <i class=\"bi bi-exclamation-triangle-fill me-2\"></i>\n <div>{{error}}</div>\n <button type=\"button\" class=\"btn-close\" data-bs-dismiss=\"alert\" aria-label=\"Close\"></button>\n </div>\n {{/error}}\n\n <!-- Registration Form -->\n <form data-action=\"register\" novalidate>\n <!-- Name Field -->\n <div class=\"mb-3\">\n <label for=\"registerName\" class=\"form-label\">\n <i class=\"bi bi-person me-1\"></i>Full Name\n </label>\n <input\n type=\"text\"\n class=\"form-control form-control-lg\"\n id=\"registerName\"\n placeholder=\"Enter your full name\"\n value=\"{{name}}\"\n data-field=\"name\"\n data-change-action=\"updateField\"\n data-filter=\"live-search\"\n data-action-keydown=\"handleKeyPress\"\n autocomplete=\"name\"\n required\n autofocus\n {{#isLoading}}disabled{{/isLoading}}>\n </div>\n\n <!-- Email Field -->\n <div class=\"mb-3\">\n <label for=\"registerEmail\" class=\"form-label\">\n <i class=\"bi bi-envelope me-1\"></i>Email Address\n </label>\n <input\n type=\"email\"\n class=\"form-control form-control-lg\"\n id=\"registerEmail\"\n placeholder=\"name@example.com\"\n value=\"{{email}}\"\n data-field=\"email\"\n data-change-action=\"updateField\"\n data-filter=\"live-search\"\n data-action-keydown=\"handleKeyPress\"\n autocomplete=\"email\"\n required\n {{#isLoading}}disabled{{/isLoading}}>\n </div>\n\n <!-- Password Field -->\n <div class=\"mb-3\">\n <label for=\"registerPassword\" class=\"form-label\">\n <i class=\"bi bi-lock me-1\"></i>Password\n </label>\n <div class=\"input-group\">\n <input\n type=\"{{#showPassword}}text{{/showPassword}}{{^showPassword}}password{{/showPassword}}\"\n class=\"form-control form-control-lg\"\n id=\"registerPassword\"\n placeholder=\"Create a strong password\"\n value=\"{{password}}\"\n data-field=\"password\"\n data-change-action=\"updateField\"\n data-filter=\"live-search\"\n data-action-keydown=\"handleKeyPress\"\n autocomplete=\"new-password\"\n required\n {{#isLoading}}disabled{{/isLoading}}>\n <button\n class=\"btn btn-outline-secondary\"\n type=\"button\"\n data-password-field=\"password\"\n data-action=\"togglePassword\"\n {{#isLoading}}disabled{{/isLoading}}>\n <i class=\"bi bi-eye{{#showPassword}}-slash{{/showPassword}}\"></i>\n </button>\n </div>\n\n <!-- Password Strength Indicator -->\n {{#passwordStrength}}\n <div class=\"mt-2\">\n <div class=\"progress\" style=\"height: 4px;\">\n <div class=\"progress-bar\n {{#passwordStrength.weak}}bg-danger{{/passwordStrength.weak}}\n {{#passwordStrength.fair}}bg-warning{{/passwordStrength.fair}}\n {{#passwordStrength.good}}bg-info{{/passwordStrength.good}}\n {{#passwordStrength.strong}}bg-success{{/passwordStrength.strong}}\"\n role=\"progressbar\"\n style=\"width:\n {{#passwordStrength.weak}}25%{{/passwordStrength.weak}}\n {{#passwordStrength.fair}}50%{{/passwordStrength.fair}}\n {{#passwordStrength.good}}75%{{/passwordStrength.good}}\n {{#passwordStrength.strong}}100%{{/passwordStrength.strong}}\">\n </div>\n </div>\n <small class=\"text-muted mt-1\">\n Password strength: {{passwordStrength}}\n </small>\n </div>\n {{/passwordStrength}}\n </div>\n\n <!-- Confirm Password Field -->\n <div class=\"mb-3\">\n <label for=\"registerConfirmPassword\" class=\"form-label\">\n <i class=\"bi bi-lock-fill me-1\"></i>Confirm Password\n </label>\n <div class=\"input-group\">\n <input\n type=\"{{#showConfirmPassword}}text{{/showConfirmPassword}}{{^showConfirmPassword}}password{{/showConfirmPassword}}\"\n class=\"form-control form-control-lg {{^passwordMatch}}is-invalid{{/passwordMatch}}\"\n id=\"registerConfirmPassword\"\n placeholder=\"Re-enter your password\"\n value=\"{{confirmPassword}}\"\n data-field=\"confirmPassword\"\n data-change-action=\"updateField\"\n data-filter=\"live-search\"\n data-action-keydown=\"handleKeyPress\"\n autocomplete=\"new-password\"\n required\n {{#isLoading}}disabled{{/isLoading}}>\n <button\n class=\"btn btn-outline-secondary\"\n type=\"button\"\n data-password-field=\"confirmPassword\"\n data-action=\"togglePassword\"\n {{#isLoading}}disabled{{/isLoading}}>\n <i class=\"bi bi-eye{{#showConfirmPassword}}-slash{{/showConfirmPassword}}\"></i>\n </button>\n </div>\n {{^passwordMatch}}\n <div class=\"invalid-feedback\">\n Passwords do not match\n </div>\n {{/passwordMatch}}\n </div>\n\n <!-- Register Button -->\n <button\n type=\"submit\"\n class=\"btn btn-primary btn-lg w-100 mb-3\"\n {{#isLoading}}disabled{{/isLoading}}>\n {{#isLoading}}\n <span class=\"spinner-border spinner-border-sm me-2\" role=\"status\" aria-hidden=\"true\"></span>\n Creating account...\n {{/isLoading}}\n {{^isLoading}}\n <i class=\"bi bi-person-plus me-2\"></i>Create Account\n {{/isLoading}}\n </button>\n </form>\n\n <!-- Login Link -->\n <div class=\"text-center mt-4\">\n <p class=\"mb-0\">\n Already have an account?\n <a href=\"#\" class=\"text-decoration-none fw-semibold\" data-action=\"login\">\n Sign in\n </a>\n </p>\n </div>\n </div>\n </div>\n\n <!-- Security Notice -->\n <div class=\"text-center mt-3\">\n <small class=\"text-muted\">\n <i class=\"bi bi-shield-check me-1\"></i>Your information is secure and encrypted\n </small>\n </div>\n </div>\n </div>\n </div>\n</div>\n`;\n\n// Template: extensions/auth/pages/ResetPasswordPage.mst\ntemplates['extensions/auth/pages/ResetPasswordPage.mst'] = `<div class=\"auth-page reset-password-page min-vh-100 d-flex align-items-center py-4\">\n <div class=\"container\">\n <div class=\"row justify-content-center\">\n <div class=\"col-sm-10 col-md-8 col-lg-6 col-xl-5\">\n <div class=\"card shadow-lg border-0\">\n <div class=\"card-body p-4 p-md-5\">\n <!-- Logo and Header -->\n <div class=\"text-center mb-4\">\n {{#logoUrl}}\n <img src=\"{{logoUrl}}\" alt=\"{{title}}\" class=\"mb-3\" style=\"max-height: 60px;\">\n {{/logoUrl}}\n <h2 class=\"h3 mb-2\">{{messages.resetTitle}}</h2>\n <p class=\"text-muted\">{{messages.resetSubtitle}}</p>\n </div>\n\n <!-- Error Alert -->\n {{#error}}\n <div class=\"alert alert-danger d-flex align-items-center alert-dismissible fade show\" role=\"alert\">\n <i class=\"bi bi-exclamation-triangle-fill me-2\"></i>\n <div>{{error}}</div>\n <button type=\"button\" class=\"btn-close\" data-bs-dismiss=\"alert\" aria-label=\"Close\"></button>\n </div>\n {{/error}}\n\n <!-- Success State -->\n {{#success}}\n <div class=\"alert alert-success d-flex align-items-center\" role=\"alert\">\n <i class=\"bi bi-check-circle-fill me-2\"></i>\n <div>\n <strong>Password Reset Complete!</strong><br>\n {{#successMessage}}{{successMessage}}{{/successMessage}}\n {{^successMessage}}Your password has been reset successfully. You can now log in with your new password.{{/successMessage}}\n </div>\n </div>\n\n <div class=\"text-center\">\n <p class=\"mb-3\">\n <i class=\"bi bi-shield-check text-success\" style=\"font-size: 3rem;\"></i>\n </p>\n <p class=\"text-muted\">\n Redirecting you to the login page...\n </p>\n <div class=\"d-grid gap-2 mt-4\">\n <button\n class=\"btn btn-primary btn-lg\"\n data-action=\"backToLogin\">\n <i class=\"bi bi-box-arrow-in-right me-2\"></i>Continue to Login\n </button>\n </div>\n </div>\n {{/success}}\n\n <!-- Reset Form -->\n {{^success}}\n {{#tokenValid}}\n <form data-action=\"resetPassword\" novalidate>\n <!-- New Password Field -->\n <div class=\"mb-3\">\n <label for=\"resetPassword\" class=\"form-label\">\n <i class=\"bi bi-lock me-1\"></i>New Password\n </label>\n <div class=\"input-group\">\n <input\n type=\"{{#showPassword}}text{{/showPassword}}{{^showPassword}}password{{/showPassword}}\"\n class=\"form-control form-control-lg\"\n id=\"resetPassword\"\n placeholder=\"Enter your new password\"\n value=\"{{password}}\"\n data-field=\"password\"\n data-change-action=\"updateField\"\n data-filter=\"live-search\"\n data-action-keydown=\"handleKeyPress\"\n autocomplete=\"new-password\"\n required\n autofocus\n {{#isLoading}}disabled{{/isLoading}}>\n <button\n class=\"btn btn-outline-secondary\"\n type=\"button\"\n data-password-field=\"password\"\n data-action=\"togglePassword\"\n {{#isLoading}}disabled{{/isLoading}}>\n <i class=\"bi bi-eye{{#showPassword}}-slash{{/showPassword}}\"></i>\n </button>\n </div>\n\n <!-- Password Strength Indicator -->\n {{#passwordStrength}}\n <div class=\"mt-2\">\n <div class=\"progress\" style=\"height: 4px;\">\n <div class=\"progress-bar\n {{#passwordStrength.weak}}bg-danger{{/passwordStrength.weak}}\n {{#passwordStrength.fair}}bg-warning{{/passwordStrength.fair}}\n {{#passwordStrength.good}}bg-info{{/passwordStrength.good}}\n {{#passwordStrength.strong}}bg-success{{/passwordStrength.strong}}\"\n role=\"progressbar\"\n style=\"width:\n {{#passwordStrength.weak}}25%{{/passwordStrength.weak}}\n {{#passwordStrength.fair}}50%{{/passwordStrength.fair}}\n {{#passwordStrength.good}}75%{{/passwordStrength.good}}\n {{#passwordStrength.strong}}100%{{/passwordStrength.strong}}\">\n </div>\n </div>\n <small class=\"text-muted mt-1\">\n Password strength: {{passwordStrength}}\n </small>\n </div>\n {{/passwordStrength}}\n </div>\n\n <!-- Confirm Password Field -->\n <div class=\"mb-4\">\n <label for=\"resetConfirmPassword\" class=\"form-label\">\n <i class=\"bi bi-lock-fill me-1\"></i>Confirm New Password\n </label>\n <div class=\"input-group\">\n <input\n type=\"{{#showConfirmPassword}}text{{/showConfirmPassword}}{{^showConfirmPassword}}password{{/showConfirmPassword}}\"\n class=\"form-control form-control-lg {{^passwordMatch}}is-invalid{{/passwordMatch}}\"\n id=\"resetConfirmPassword\"\n placeholder=\"Re-enter your new password\"\n value=\"{{confirmPassword}}\"\n data-field=\"confirmPassword\"\n data-change-action=\"updateField\"\n data-filter=\"live-search\"\n data-action-keydown=\"handleKeyPress\"\n autocomplete=\"new-password\"\n required\n {{#isLoading}}disabled{{/isLoading}}>\n <button\n class=\"btn btn-outline-secondary\"\n type=\"button\"\n data-password-field=\"confirmPassword\"\n data-action=\"togglePassword\"\n {{#isLoading}}disabled{{/isLoading}}>\n <i class=\"bi bi-eye{{#showConfirmPassword}}-slash{{/showConfirmPassword}}\"></i>\n </button>\n </div>\n {{^passwordMatch}}\n <div class=\"invalid-feedback\">\n Passwords do not match\n </div>\n {{/passwordMatch}}\n </div>\n\n <!-- Reset Button -->\n <button\n type=\"submit\"\n class=\"btn btn-primary btn-lg w-100 mb-3\"\n {{#isLoading}}disabled{{/isLoading}}>\n {{#isLoading}}\n <span class=\"spinner-border spinner-border-sm me-2\" role=\"status\" aria-hidden=\"true\"></span>\n Resetting password...\n {{/isLoading}}\n {{^isLoading}}\n <i class=\"bi bi-key me-2\"></i>Reset Password\n {{/isLoading}}\n </button>\n\n <!-- Back to Login -->\n <button\n type=\"button\"\n class=\"btn btn-outline-secondary btn-lg w-100\"\n data-action=\"backToLogin\"\n {{#isLoading}}disabled{{/isLoading}}>\n <i class=\"bi bi-arrow-left me-2\"></i>Back to Login\n </button>\n </form>\n {{/tokenValid}}\n\n <!-- Invalid Token State -->\n {{^tokenValid}}\n <div class=\"text-center\">\n <div class=\"mb-4\">\n <i class=\"bi bi-exclamation-triangle text-warning\" style=\"font-size: 4rem;\"></i>\n </div>\n <h4 class=\"text-warning mb-3\">Invalid Reset Link</h4>\n <p class=\"text-muted mb-4\">\n This password reset link is invalid or has expired.\n Please request a new password reset.\n </p>\n <div class=\"d-grid gap-2\">\n <button\n class=\"btn btn-primary btn-lg\"\n data-action=\"requestNew\">\n <i class=\"bi bi-envelope me-2\"></i>Request New Reset\n </button>\n <button\n class=\"btn btn-outline-secondary btn-lg\"\n data-action=\"backToLogin\">\n <i class=\"bi bi-arrow-left me-2\"></i>Back to Login\n </button>\n </div>\n </div>\n {{/tokenValid}}\n\n <!-- Additional Links -->\n {{#tokenValid}}{{^success}}\n <div class=\"text-center mt-4\">\n <p class=\"text-muted mb-2\">\n Remember your password?\n <a href=\"#\" class=\"text-decoration-none fw-semibold\" data-action=\"backToLogin\">\n Sign in\n </a>\n </p>\n {{#registration}}\n <p class=\"text-muted mb-0\">\n Don't have an account?\n <a href=\"#\" class=\"text-decoration-none fw-semibold\" data-action=\"register\">\n Sign up\n </a>\n </p>\n {{/registration}}\n </div>\n {{/success}}{{/tokenValid}}\n {{/success}}\n </div>\n </div>\n\n <!-- Security Notice -->\n <div class=\"text-center mt-3\">\n <small class=\"text-muted\">\n <i class=\"bi bi-shield-lock me-1\"></i>\n Secure password reset with email verification\n </small>\n </div>\n </div>\n </div>\n </div>\n</div>\n`;\n\n// Export templates\nexport default templates;\n\n// Convenience exports for common templates\nexport const extensions_auth_pages_ForgotPasswordPage_mst = templates['extensions/auth/pages/ForgotPasswordPage.mst'];\nexport const extensions_auth_pages_LoginPage_mst = templates['extensions/auth/pages/LoginPage.mst'];\nexport const extensions_auth_pages_RegisterPage_mst = templates['extensions/auth/pages/RegisterPage.mst'];\nexport const extensions_auth_pages_ResetPasswordPage_mst = templates['extensions/auth/pages/ResetPasswordPage.mst'];\n\n// Helper functions\n\n/**\n * Get a template by key\n * @param {string} key - Template key (e.g., \"auth/pages/LoginPage.mst\")\n * @returns {string|undefined} Template content or undefined if not found\n */\nexport function getTemplate(key) {\n // Handle different path formats\n const normalizedKey = key\n .replace(/^\\//, \"\") // Remove leading slash\n .replace(/^src\\//, \"\") // Remove src/ prefix\n .replace(/\\\\/g, \"/\"); // Normalize path separators\n \n return templates[normalizedKey] || templates[key];\n}\n\n/**\n * Check if a template exists\n * @param {string} key - Template key\n * @returns {boolean} True if template exists\n */\nexport function hasTemplate(key) {\n return getTemplate(key) !== undefined;\n}\n\n/**\n * Get all template keys\n * @returns {string[]} Array of template keys\n */\nexport function getTemplateKeys() {\n return Object.keys(templates);\n}\n\n/**\n * Get template count\n * @returns {number} Number of templates\n */\nexport function getTemplateCount() {\n return Object.keys(templates).length;\n}","/**\n * AuthApp - A specialized WebApp with built-in authentication.\n * Extends the core WebApp to provide a seamless, out-of-the-box authentication system.\n */\nimport WebApp from '@core/WebApp.js';\nimport AuthManager from './AuthManager.js';\nimport LoginPage from '@ext/auth/pages/LoginPage.js';\nimport RegisterPage from '@ext/auth/pages/RegisterPage.js';\nimport ForgotPasswordPage from '@ext/auth/pages/ForgotPasswordPage.js';\nimport ResetPasswordPage from '@ext/auth/pages/ResetPasswordPage.js';\nimport { getTemplate } from '/src/templates.js';\n\nexport default class AuthApp extends WebApp {\n constructor(config = {}) {\n // Deep merge UI config to handle nested theme object\n const uiConfig = {\n title: config.name || 'My App',\n logoUrl: null,\n termsUrl: null,\n privacyUrl: null,\n theme: {\n background: 'auth-bg-light',\n panel: 'auth-panel-light',\n ...(config.ui?.theme || {})\n },\n messages: {\n loginTitle: 'Welcome Back',\n loginSubtitle: 'Sign in to your account',\n registerTitle: 'Create Account',\n registerSubtitle: 'Join us today',\n forgotTitle: 'Reset Password',\n forgotSubtitle: \"We'll send you reset instructions\",\n ...(config.ui?.messages || {})\n },\n ...(config.ui || {})\n };\n\n // Merge user config with auth defaults\n const authConfig = {\n ...config,\n routes: {\n login: '/login',\n register: '/register',\n forgot: '/forgot-password',\n reset: '/reset-password',\n ...(config.routes || {})\n },\n loginRedirect: config.loginRedirect || '/',\n logoutRedirect: config.logoutRedirect || '/login',\n features: {\n forgotPassword: true,\n registration: true,\n rememberMe: true,\n ...(config.features || {})\n },\n passwordResetMethod: config.passwordResetMethod || 'code',\n ui: uiConfig,\n };\n\n // Initialize the parent WebApp\n super(authConfig);\n\n // Initialize and attach the AuthManager\n this.auth = new AuthManager(this, authConfig);\n this.authConfig = authConfig;\n\n // Setup all authentication components\n this.applyAuthTheme();\n this.registerAuthPages();\n this.setupAuthIntegration();\n this.setupAuthGuards();\n }\n\n /**\n * Applies the configured background and panel themes to the body.\n */\n applyAuthTheme() {\n const theme = this.authConfig.ui.theme;\n if (!theme) return;\n\n // Clear any existing theme classes\n const classesToRemove = Array.from(document.body.classList).filter(\n c => c.startsWith('auth-bg-') || c.startsWith('auth-panel-')\n );\n if (classesToRemove.length) {\n document.body.classList.remove(...classesToRemove);\n }\n\n // Add new theme classes\n if (theme.background) {\n document.body.classList.add(theme.background);\n }\n if (theme.panel) {\n document.body.classList.add(theme.panel);\n }\n }\n\n /**\n * Registers all the standard authentication pages with the application.\n */\n registerAuthPages() {\n const cfg = this.authConfig;\n\n this.registerPage('login', LoginPage, {\n route: cfg.routes.login,\n title: 'Login',\n authConfig: cfg,\n template: getTemplate('extensions/auth/pages/LoginPage.mst')\n });\n\n if (cfg.features.registration) {\n this.registerPage('register', RegisterPage, {\n route: cfg.routes.register,\n title: 'Register',\n authConfig: cfg,\n template: getTemplate('extensions/auth/pages/RegisterPage.mst')\n });\n }\n\n if (cfg.features.forgotPassword) {\n this.registerPage('forgot-password', ForgotPasswordPage, {\n route: cfg.routes.forgot,\n title: 'Reset Password',\n authConfig: cfg,\n template: getTemplate('extensions/auth/pages/ForgotPasswordPage.mst')\n });\n\n this.registerPage('reset-password', ResetPasswordPage, {\n route: cfg.routes.reset,\n title: 'Set New Password',\n authConfig: cfg,\n template: getTemplate('extensions/auth/pages/ResetPasswordPage.mst')\n });\n }\n }\n\n /**\n * Sets up global event listeners to integrate AuthManager state with the app.\n */\n setupAuthIntegration() {\n this.events.on('auth:login', (user) => {\n this.showSuccess(`Welcome back, ${user.name || user.email}!`);\n this.navigateAfterLogin();\n });\n\n this.events.on('auth:logout', () => {\n this.navigate(this.authConfig.logoutRedirect);\n });\n\n this.events.on('auth:register', (user) => {\n this.showSuccess(`Welcome, ${user.name || user.email}! Your account is ready.`);\n this.navigate(this.authConfig.loginRedirect);\n });\n\n this.events.on('auth:tokenExpired', () => {\n this.showWarning('Your session has expired. Please login again.');\n this.navigate(this.authConfig.logoutRedirect);\n });\n }\n\n /**\n * Sets up route guards to protect pages.\n */\n setupAuthGuards() {\n this.events.on('route:changed', ({ pageName, path }) => {\n const page = this.getOrCreatePage(pageName);\n if (!page) return;\n\n const PageClass = page.constructor;\n const isAuthenticated = this.auth.isAuthenticated;\n const isAuthPage = ['login', 'register', 'forgot-password', 'reset-password'].includes(pageName);\n\n // If page requires auth and user is not logged in, redirect to login\n if (PageClass.requiresAuth && !isAuthenticated) {\n sessionStorage.setItem('auth_redirect', path);\n this.navigate(this.authConfig.routes.login);\n this.showWarning('Please login to access this page.');\n return;\n }\n\n // If user is logged in and tries to access an auth page, redirect away\n if (isAuthenticated && isAuthPage) {\n this.navigate(this.authConfig.loginRedirect);\n }\n });\n }\n\n /**\n * Navigates to the intended page after a successful login.\n */\n navigateAfterLogin() {\n const redirectPath = sessionStorage.getItem('auth_redirect');\n if (redirectPath) {\n sessionStorage.removeItem('auth_redirect');\n this.navigate(redirectPath);\n } else {\n this.navigate(this.authConfig.loginRedirect);\n }\n }\n\n /**\n * Helper to protect a Page class.\n * @param {Page} PageClass - The class to protect.\n * @returns {Page} The protected class.\n */\n static requireAuth(PageClass) {\n PageClass.requiresAuth = true;\n return PageClass;\n }\n}\n","/**\n * PasskeyPlugin - WebAuthn Passkey authentication plugin for MOJO Auth\n * Adds passkey login and setup capabilities to the authentication system\n */\n\nexport default class PasskeyPlugin {\n constructor(config = {}) {\n this.name = 'passkey';\n this.config = {\n rpName: 'MOJO App',\n rpId: window?.location?.hostname || 'localhost',\n timeout: 60000,\n userVerification: 'preferred',\n authenticatorAttachment: 'platform', // 'platform', 'cross-platform', or undefined\n ...config\n };\n\n this.authManager = null;\n this.app = null;\n this.authService = null;\n }\n\n /**\n * Initialize plugin with AuthManager and WebApp\n * @param {AuthManager} authManager - Auth manager instance\n * @param {WebApp} app - WebApp instance\n */\n async initialize(authManager, app) {\n this.authManager = authManager;\n this.app = app;\n\n // Check browser support\n if (!this.isSupported()) {\n console.warn('Passkey authentication is not supported in this browser');\n return;\n }\n\n // Add passkey methods to auth manager\n this.authManager.loginWithPasskey = this.loginWithPasskey.bind(this);\n this.authManager.setupPasskey = this.setupPasskey.bind(this);\n this.authManager.isPasskeySupported = this.isSupported.bind(this);\n\n console.log('PasskeyPlugin initialized successfully');\n }\n\n /**\n * Check if WebAuthn is supported in this browser\n * @returns {boolean} True if supported\n */\n isSupported() {\n return window.PublicKeyCredential !== undefined &&\n navigator.credentials !== undefined &&\n typeof navigator.credentials.create === 'function' &&\n typeof navigator.credentials.get === 'function';\n }\n\n /**\n * Login with passkey\n * @returns {Promise<object>} Login result with user data and tokens\n */\n async loginWithPasskey() {\n if (!this.isSupported()) {\n throw new Error('Passkey authentication is not supported in this browser');\n }\n\n try {\n // Step 1: Get authentication challenge from server\n const challengeResponse = await this.app.rest.POST('/api/auth/passkey/challenge');\n\n if (!challengeResponse.success || !challengeResponse.data.data.challenge) {\n throw new Error('No authentication challenge received from server');\n }\n const challengeData = challengeResponse.data.data;\n\n // Step 2: Create credential request options\n const credentialRequestOptions = {\n publicKey: {\n challenge: this.base64ToArrayBuffer(challengeData.challenge),\n timeout: this.config.timeout,\n userVerification: this.config.userVerification,\n rpId: this.config.rpId\n }\n };\n\n // Step 3: Get credential from authenticator\n const credential = await navigator.credentials.get(credentialRequestOptions);\n\n if (!credential) {\n throw new Error('No credential received from authenticator');\n }\n\n // Step 4: Prepare credential data for server verification\n const credentialData = {\n id: credential.id,\n rawId: this.arrayBufferToBase64(credential.rawId),\n type: credential.type,\n response: {\n authenticatorData: this.arrayBufferToBase64(credential.response.authenticatorData),\n clientDataJSON: this.arrayBufferToBase64(credential.response.clientDataJSON),\n signature: this.arrayBufferToBase64(credential.response.signature),\n userHandle: credential.response.userHandle ?\n this.arrayBufferToBase64(credential.response.userHandle) : null\n }\n };\n\n // Step 5: Send credential to server for verification and login\n const loginResponse = await this.app.rest.POST('/api/auth/passkey/verify', {\n credential: credentialData,\n challengeId: challengeData.challengeId\n });\n\n if (!loginResponse.success || !loginResponse.data.status) {\n throw new Error(loginResponse.data.error || 'Passkey verification failed');\n }\n\n const { token, refreshToken, user } = loginResponse.data.data;\n\n // Store tokens and set auth state\n this.authManager.tokenManager.setTokens(token, refreshToken, true);\n \n // Set auth state\n const userInfo = this.authManager.tokenManager.getUserInfo();\n this.authManager.setAuthState({ ...user, ...userInfo });\n \n // Schedule refresh\n if (this.authManager.config.autoRefresh) {\n this.authManager.scheduleTokenRefresh();\n }\n \n this.authManager.emit('login', this.authManager.user);\n\n return {\n success: true,\n user: this.authManager.user\n };\n\n } catch (error) {\n console.error('Passkey login error:', error);\n this.authManager.emit('loginError', error);\n throw new Error(error.message || 'Passkey authentication failed');\n }\n }\n\n /**\n * Setup passkey for current authenticated user\n * @returns {Promise<object>} Setup result\n */\n async setupPasskey() {\n if (!this.isSupported()) {\n throw new Error('Passkey authentication is not supported in this browser');\n }\n\n if (!this.authManager.isAuthenticated) {\n throw new Error('User must be authenticated to setup passkey');\n }\n\n try {\n // Step 1: Get registration options from server\n const optionsResponse = await this.app.rest.POST('/api/auth/passkey/register-options');\n\n if (!optionsResponse.success || !optionsResponse.data.data.options) {\n throw new Error('No registration options received from server');\n }\n\n const optionsData = optionsResponse.data.data;\n const options = optionsData.options;\n\n // Step 2: Create credential creation options\n const credentialCreationOptions = {\n publicKey: {\n challenge: this.base64ToArrayBuffer(options.challenge),\n rp: {\n name: this.config.rpName,\n id: this.config.rpId\n },\n user: {\n id: this.base64ToArrayBuffer(options.userId),\n name: options.userName,\n displayName: options.userDisplayName\n },\n pubKeyCredParams: [\n { alg: -7, type: 'public-key' }, // ES256\n { alg: -257, type: 'public-key' } // RS256\n ],\n authenticatorSelection: {\n userVerification: this.config.userVerification\n },\n timeout: this.config.timeout,\n attestation: 'none'\n }\n };\n\n // Add authenticator attachment preference if specified\n if (this.config.authenticatorAttachment) {\n credentialCreationOptions.publicKey.authenticatorSelection.authenticatorAttachment = \n this.config.authenticatorAttachment;\n }\n\n // Step 3: Create credential\n const credential = await navigator.credentials.create(credentialCreationOptions);\n\n if (!credential) {\n throw new Error('Failed to create credential');\n }\n\n // Step 4: Prepare credential data for server registration\n const credentialData = {\n id: credential.id,\n rawId: this.arrayBufferToBase64(credential.rawId),\n type: credential.type,\n response: {\n attestationObject: this.arrayBufferToBase64(credential.response.attestationObject),\n clientDataJSON: this.arrayBufferToBase64(credential.response.clientDataJSON)\n }\n };\n\n // Step 5: Register credential with server\n const registrationResponse = await this.app.rest.POST('/api/auth/passkey/register', {\n credential: credentialData,\n optionsId: optionsData.optionsId\n });\n\n if (!registrationResponse.success || !registrationResponse.data.status) {\n throw new Error(registrationResponse.data.error || 'Failed to register passkey');\n }\n\n // Emit success event\n this.authManager.emit('passkeySetupSuccess', registrationResponse.data.data);\n\n return {\n success: true,\n data: registrationResponse.data.data\n };\n\n } catch (error) {\n console.error('Passkey setup error:', error);\n this.authManager.emit('passkeySetupError', error);\n throw new Error(error.message || 'Failed to setup passkey');\n }\n }\n\n /**\n * Check if user has passkeys registered\n * @returns {Promise<object>} Result with passkey availability\n */\n async hasPasskeys() {\n if (!this.authManager.isAuthenticated) {\n return { success: false, hasPasskeys: false };\n }\n\n try {\n const response = await this.app.rest.GET('/api/auth/passkey/list');\n\n return {\n success: response.success,\n hasPasskeys: response.data.data?.passkeys && response.data.data.passkeys.length > 0,\n count: response.data.data?.passkeys ? response.data.data.passkeys.length : 0\n };\n } catch (error) {\n console.error('Error checking passkeys:', error);\n return { success: false, hasPasskeys: false };\n }\n }\n\n /**\n * Remove/revoke a specific passkey\n * @param {string} credentialId - ID of credential to remove\n * @returns {Promise<object>} Result of removal\n */\n async removePasskey(credentialId) {\n if (!this.authManager.isAuthenticated) {\n throw new Error('User must be authenticated to remove passkey');\n }\n\n try {\n const response = await this.app.rest.DELETE('/api/auth/passkey/remove', { credentialId });\n\n if (!response.success || !response.data.status) {\n throw new Error(response.data.error || 'Failed to remove passkey');\n }\n\n this.authManager.emit('passkeyRemoved', { credentialId });\n\n return {\n success: true,\n data: response.data.data\n };\n } catch (error) {\n console.error('Error removing passkey:', error);\n throw new Error(error.message || 'Failed to remove passkey');\n }\n }\n\n /**\n * Convert base64 string to ArrayBuffer\n * @param {string} base64 - Base64 string\n * @returns {ArrayBuffer} ArrayBuffer\n */\n base64ToArrayBuffer(base64) {\n const binaryString = atob(base64);\n const bytes = new Uint8Array(binaryString.length);\n for (let i = 0; i < binaryString.length; i++) {\n bytes[i] = binaryString.charCodeAt(i);\n }\n return bytes.buffer;\n }\n\n /**\n * Convert ArrayBuffer to base64 string\n * @param {ArrayBuffer} buffer - ArrayBuffer\n * @returns {string} Base64 string\n */\n arrayBufferToBase64(buffer) {\n const bytes = new Uint8Array(buffer);\n let binary = '';\n for (let i = 0; i < bytes.byteLength; i++) {\n binary += String.fromCharCode(bytes[i]);\n }\n return btoa(binary);\n }\n\n /**\n * Get browser compatibility info\n * @returns {object} Compatibility information\n */\n getBrowserCompatibility() {\n return {\n webAuthnSupported: !!window.PublicKeyCredential,\n credentialsSupported: !!navigator.credentials,\n platformSupported: this.config.authenticatorAttachment === 'platform' ? \n window.PublicKeyCredential?.isUserVerifyingPlatformAuthenticatorAvailable?.() : true,\n conditionalMediationSupported: window.PublicKeyCredential?.isConditionalMediationAvailable?.()\n };\n }\n\n /**\n * Plugin cleanup\n */\n destroy() {\n // Remove methods from auth manager\n if (this.authManager) {\n delete this.authManager.loginWithPasskey;\n delete this.authManager.setupPasskey;\n delete this.authManager.isPasskeySupported;\n }\n \n this.authManager = null;\n this.app = null;\n this.authService = null;\n }\n}"],"names":["c"],"mappings":"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AA;AAGlB,UAAU,8CAA8C,IAAI;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAgG5D,UAAU,qCAAqC,IAAI;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AA8KnD,UAAU,wCAAwC,IAAI;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAmMtD,UAAU,6CAA6C,IAAI;AAAA;AAAA;AAAA;AAAA;AA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"}