viewlogic 1.0.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/LICENSE +21 -0
- package/README.md +519 -0
- package/dist/viewlogic-router.js +2476 -0
- package/dist/viewlogic-router.js.map +7 -0
- package/dist/viewlogic-router.min.js +53 -0
- package/dist/viewlogic-router.min.js.map +7 -0
- package/dist/viewlogic-router.umd.js +120 -0
- package/package.json +85 -0
- package/src/core/ComponentLoader.js +182 -0
- package/src/core/ErrorHandler.js +331 -0
- package/src/core/RouteLoader.js +368 -0
- package/src/plugins/AuthManager.js +505 -0
- package/src/plugins/CacheManager.js +352 -0
- package/src/plugins/I18nManager.js +507 -0
- package/src/plugins/QueryManager.js +402 -0
- package/src/viewlogic-router.js +465 -0
|
@@ -0,0 +1,7 @@
|
|
|
1
|
+
{
|
|
2
|
+
"version": 3,
|
|
3
|
+
"sources": ["../src/plugins/I18nManager.js", "../src/plugins/AuthManager.js", "../src/plugins/CacheManager.js", "../src/plugins/QueryManager.js", "../src/core/RouteLoader.js", "../src/core/ErrorHandler.js", "../src/core/ComponentLoader.js", "../src/viewlogic-router.js"],
|
|
4
|
+
"sourcesContent": ["/**\r\n * ViewLogic Internationalization System\r\n * \uB2E4\uAD6D\uC5B4 \uC9C0\uC6D0 \uC2DC\uC2A4\uD15C\r\n */\r\nexport class I18nManager {\r\n constructor(router, options = {}) {\r\n this.config = {\r\n enabled: options.useI18n !== undefined ? options.useI18n : true,\r\n defaultLanguage: options.defaultLanguage || 'ko',\r\n fallbackLanguage: options.defaultLanguage || 'ko',\r\n cacheKey: options.cacheKey || 'viewlogic_lang',\r\n dataCacheKey: options.dataCacheKey || 'viewlogic_i18n_data',\r\n cacheVersion: options.cacheVersion || '1.0.0',\r\n enableDataCache: options.enableDataCache !== false,\r\n debug: options.debug || false\r\n };\r\n \r\n // \uB77C\uC6B0\uD130 \uC778\uC2A4\uD134\uC2A4 \uCC38\uC870 (\uD544\uC694\uC2DC \uC5B8\uC5B4 \uBCC0\uACBD \uC2DC \uB77C\uC6B0\uD130 \uC0C1\uD0DC \uC5C5\uB370\uC774\uD2B8)\r\n this.router = router;\r\n \r\n this.messages = new Map();\r\n this.currentLanguage = this.config.defaultLanguage;\r\n this.isLoading = false;\r\n this.loadPromises = new Map();\r\n \r\n // \uC774\uBCA4\uD2B8 \uB9AC\uC2A4\uB108\uB4E4\r\n this.listeners = {\r\n languageChanged: []\r\n };\r\n \r\n // \uBE44\uB3D9\uAE30 \uCD08\uAE30\uD654 \uC2DC\uC791 (constructor \uB0B4\uC5D0\uC11C\uB294 await \uBD88\uAC00)\r\n this.initPromise = this.init();\r\n }\r\n\r\n async init() {\r\n // i18n\uC774 \uBE44\uD65C\uC131\uD654\uB41C \uACBD\uC6B0 \uCD08\uAE30\uD654\uD558\uC9C0 \uC54A\uC74C\r\n if (!this.config.enabled) {\r\n this.log('info', 'I18n system disabled');\r\n return;\r\n }\r\n \r\n // \uCE90\uC2DC\uC5D0\uC11C \uC5B8\uC5B4 \uC124\uC815 \uB85C\uB4DC\r\n this.loadLanguageFromCache();\r\n \r\n // \uAC1C\uBC1C \uBAA8\uB4DC\uC5D0\uC11C\uB294 \uCE90\uC2DC \uBE44\uD65C\uC131\uD654\r\n if (this.config.debug) {\r\n this.config.enableDataCache = false;\r\n this.log('debug', 'Data cache disabled in debug mode');\r\n }\r\n \r\n // \uCD08\uAE30 \uC5B8\uC5B4 \uD30C\uC77C \uC790\uB3D9 \uB85C\uB4DC (\uC544\uC9C1 \uB85C\uB4DC\uB418\uC9C0 \uC54A\uC740 \uACBD\uC6B0\uC5D0\uB9CC)\r\n if (!this.messages.has(this.currentLanguage)) {\r\n try {\r\n await this.loadMessages(this.currentLanguage);\r\n } catch (error) {\r\n this.log('error', 'Failed to load initial language file:', error);\r\n }\r\n } else {\r\n this.log('debug', 'Language messages already loaded:', this.currentLanguage);\r\n }\r\n }\r\n\r\n /**\r\n * \uCE90\uC2DC\uC5D0\uC11C \uC5B8\uC5B4 \uC124\uC815 \uB85C\uB4DC\r\n */\r\n loadLanguageFromCache() {\r\n try {\r\n const cachedLang = localStorage.getItem(this.config.cacheKey);\r\n if (cachedLang && this.isValidLanguage(cachedLang)) {\r\n this.currentLanguage = cachedLang;\r\n this.log('debug', 'Language loaded from cache:', cachedLang);\r\n }\r\n } catch (error) {\r\n this.log('warn', 'Failed to load language from cache:', error);\r\n }\r\n }\r\n\r\n\r\n /**\r\n * \uC5B8\uC5B4 \uC720\uD6A8\uC131 \uAC80\uC0AC\r\n */\r\n isValidLanguage(lang) {\r\n return typeof lang === 'string' && /^[a-z]{2}$/.test(lang);\r\n }\r\n\r\n /**\r\n * \uD604\uC7AC \uC5B8\uC5B4 \uBC18\uD658\r\n */\r\n getCurrentLanguage() {\r\n return this.currentLanguage;\r\n }\r\n\r\n /**\r\n * \uC5B8\uC5B4 \uBCC0\uACBD\r\n */\r\n async setLanguage(language) {\r\n if (!this.isValidLanguage(language)) {\r\n this.log('warn', 'Invalid language code:', language);\r\n return false;\r\n }\r\n\r\n if (this.currentLanguage === language) {\r\n this.log('debug', 'Language already set to:', language);\r\n return true;\r\n }\r\n\r\n const oldLanguage = this.currentLanguage;\r\n this.currentLanguage = language;\r\n\r\n try {\r\n // \uC5B8\uC5B4 \uD30C\uC77C \uB85C\uB4DC\r\n await this.loadMessages(language);\r\n \r\n // \uCE90\uC2DC\uC5D0 \uC800\uC7A5\r\n this.saveLanguageToCache(language);\r\n \r\n // \uC774\uBCA4\uD2B8 \uBC1C\uC0DD\r\n this.emit('languageChanged', {\r\n from: oldLanguage,\r\n to: language,\r\n messages: this.messages.get(language)\r\n });\r\n \r\n this.log('info', 'Language changed successfully', { from: oldLanguage, to: language });\r\n return true;\r\n } catch (error) {\r\n // \uC2E4\uD328 \uC2DC \uC774\uC804 \uC5B8\uC5B4\uB85C \uBCF5\uC6D0\r\n this.currentLanguage = oldLanguage;\r\n this.log('error', 'Failed to change language:', error);\r\n return false;\r\n }\r\n }\r\n\r\n /**\r\n * \uC5B8\uC5B4\uB97C \uCE90\uC2DC\uC5D0 \uC800\uC7A5\r\n */\r\n saveLanguageToCache(language) {\r\n try {\r\n localStorage.setItem(this.config.cacheKey, language);\r\n this.log('debug', 'Language saved to cache:', language);\r\n } catch (error) {\r\n this.log('warn', 'Failed to save language to cache:', error);\r\n }\r\n }\r\n\r\n /**\r\n * \uC5B8\uC5B4 \uBA54\uC2DC\uC9C0 \uD30C\uC77C \uB85C\uB4DC\r\n */\r\n async loadMessages(language) {\r\n // \uC774\uBBF8 \uB85C\uB4DC\uB41C \uACBD\uC6B0\r\n if (this.messages.has(language)) {\r\n this.log('debug', 'Messages already loaded for:', language);\r\n return this.messages.get(language);\r\n }\r\n\r\n // \uC774\uBBF8 \uB85C\uB529 \uC911\uC778 \uACBD\uC6B0\r\n if (this.loadPromises.has(language)) {\r\n this.log('debug', 'Messages loading in progress for:', language);\r\n return await this.loadPromises.get(language);\r\n }\r\n\r\n const loadPromise = this._loadMessagesFromFile(language);\r\n this.loadPromises.set(language, loadPromise);\r\n\r\n try {\r\n const messages = await loadPromise;\r\n this.messages.set(language, messages);\r\n this.loadPromises.delete(language);\r\n this.log('debug', 'Messages loaded successfully for:', language);\r\n return messages;\r\n } catch (error) {\r\n this.loadPromises.delete(language);\r\n throw error;\r\n }\r\n }\r\n\r\n /**\r\n * \uD30C\uC77C\uC5D0\uC11C \uBA54\uC2DC\uC9C0 \uB85C\uB4DC (\uCE90\uC2F1 \uC9C0\uC6D0)\r\n */\r\n async _loadMessagesFromFile(language) {\r\n // \uCE90\uC2DC\uC5D0\uC11C \uBA3C\uC800 \uC2DC\uB3C4\r\n if (this.config.enableDataCache) {\r\n const cachedData = this.getDataFromCache(language);\r\n if (cachedData) {\r\n this.log('debug', 'Messages loaded from cache:', language);\r\n return cachedData;\r\n }\r\n }\r\n \r\n try {\r\n // JSON \uD30C\uC77C\uB85C \uBCC0\uACBD\r\n const response = await fetch(`../i18n/${language}.json`);\r\n if (!response.ok) {\r\n throw new Error(`HTTP error! status: ${response.status}`);\r\n }\r\n const messages = await response.json();\r\n \r\n // \uCE90\uC2DC\uC5D0 \uC800\uC7A5\r\n if (this.config.enableDataCache) {\r\n this.saveDataToCache(language, messages);\r\n }\r\n \r\n return messages;\r\n } catch (error) {\r\n this.log('error', 'Failed to load messages file for:', language, error);\r\n \r\n // \uD3F4\uBC31 \uC5B8\uC5B4 \uC2DC\uB3C4\r\n if (language !== this.config.fallbackLanguage) {\r\n this.log('info', 'Trying fallback language:', this.config.fallbackLanguage);\r\n return await this._loadMessagesFromFile(this.config.fallbackLanguage);\r\n }\r\n \r\n throw new Error(`Failed to load messages for language: ${language}`);\r\n }\r\n }\r\n \r\n /**\r\n * \uC5B8\uC5B4 \uB370\uC774\uD130\uB97C \uCE90\uC2DC\uC5D0\uC11C \uAC00\uC838\uC624\uAE30\r\n */\r\n getDataFromCache(language) {\r\n try {\r\n const cacheKey = `${this.config.dataCacheKey}_${language}_${this.config.cacheVersion}`;\r\n const cachedItem = localStorage.getItem(cacheKey);\r\n \r\n if (cachedItem) {\r\n const { data, timestamp, version } = JSON.parse(cachedItem);\r\n \r\n // \uBC84\uC804 \uD655\uC778\r\n if (version !== this.config.cacheVersion) {\r\n this.log('debug', 'Cache version mismatch, clearing:', language);\r\n localStorage.removeItem(cacheKey);\r\n return null;\r\n }\r\n \r\n // TTL \uD655\uC778 (24\uC2DC\uAC04)\r\n const now = Date.now();\r\n const maxAge = 24 * 60 * 60 * 1000; // 24\uC2DC\uAC04\r\n \r\n if (now - timestamp > maxAge) {\r\n this.log('debug', 'Cache expired, removing:', language);\r\n localStorage.removeItem(cacheKey);\r\n return null;\r\n }\r\n \r\n return data;\r\n }\r\n } catch (error) {\r\n this.log('warn', 'Failed to read from cache:', error);\r\n }\r\n \r\n return null;\r\n }\r\n \r\n /**\r\n * \uC5B8\uC5B4 \uB370\uC774\uD130\uB97C \uCE90\uC2DC\uC5D0 \uC800\uC7A5\r\n */\r\n saveDataToCache(language, data) {\r\n try {\r\n const cacheKey = `${this.config.dataCacheKey}_${language}_${this.config.cacheVersion}`;\r\n const cacheItem = {\r\n data,\r\n timestamp: Date.now(),\r\n version: this.config.cacheVersion\r\n };\r\n \r\n localStorage.setItem(cacheKey, JSON.stringify(cacheItem));\r\n this.log('debug', 'Data saved to cache:', language);\r\n } catch (error) {\r\n this.log('warn', 'Failed to save to cache:', error);\r\n }\r\n }\r\n\r\n /**\r\n * \uBA54\uC2DC\uC9C0 \uBC88\uC5ED\r\n */\r\n t(key, params = {}) {\r\n // i18n\uC774 \uBE44\uD65C\uC131\uD654\uB41C \uACBD\uC6B0 \uD0A4 \uC790\uCCB4\uB97C \uBC18\uD658\r\n if (!this.config.enabled) {\r\n return key;\r\n }\r\n \r\n const messages = this.messages.get(this.currentLanguage);\r\n if (!messages) {\r\n this.log('warn', 'No messages loaded for current language:', this.currentLanguage);\r\n return key;\r\n }\r\n\r\n const message = this.getNestedValue(messages, key);\r\n if (message === undefined) {\r\n this.log('warn', 'Translation not found for key:', key);\r\n \r\n // \uD3F4\uBC31 \uC5B8\uC5B4\uC5D0\uC11C \uCC3E\uAE30\r\n const fallbackMessages = this.messages.get(this.config.fallbackLanguage);\r\n if (fallbackMessages && this.currentLanguage !== this.config.fallbackLanguage) {\r\n const fallbackMessage = this.getNestedValue(fallbackMessages, key);\r\n if (fallbackMessage !== undefined) {\r\n return this.interpolate(fallbackMessage, params);\r\n }\r\n }\r\n \r\n return key;\r\n }\r\n\r\n return this.interpolate(message, params);\r\n }\r\n\r\n /**\r\n * \uC911\uCCA9\uB41C \uAC1D\uCCB4\uC5D0\uC11C \uAC12 \uAC00\uC838\uC624\uAE30\r\n */\r\n getNestedValue(obj, path) {\r\n return path.split('.').reduce((current, key) => {\r\n return current && current[key] !== undefined ? current[key] : undefined;\r\n }, obj);\r\n }\r\n\r\n /**\r\n * \uBB38\uC790\uC5F4 \uBCF4\uAC04 \uCC98\uB9AC\r\n */\r\n interpolate(message, params) {\r\n if (typeof message !== 'string') {\r\n return message;\r\n }\r\n\r\n return message.replace(/\\{(\\w+)\\}/g, (match, key) => {\r\n return params.hasOwnProperty(key) ? params[key] : match;\r\n });\r\n }\r\n\r\n /**\r\n * \uBCF5\uC218\uD615 \uCC98\uB9AC\r\n */\r\n plural(key, count, params = {}) {\r\n const pluralKey = count === 1 ? `${key}.singular` : `${key}.plural`;\r\n return this.t(pluralKey, { ...params, count });\r\n }\r\n\r\n /**\r\n * \uC0AC\uC6A9 \uAC00\uB2A5\uD55C \uC5B8\uC5B4 \uBAA9\uB85D\r\n */\r\n getAvailableLanguages() {\r\n return ['ko', 'en']; // \uCD94\uD6C4 \uB3D9\uC801\uC73C\uB85C \uB85C\uB4DC\uD558\uB3C4\uB85D \uBCC0\uACBD \uAC00\uB2A5\r\n }\r\n\r\n /**\r\n * \uC5B8\uC5B4 \uBCC0\uACBD \uC774\uBCA4\uD2B8 \uB9AC\uC2A4\uB108 \uB4F1\uB85D\r\n */\r\n on(event, callback) {\r\n if (this.listeners[event]) {\r\n this.listeners[event].push(callback);\r\n }\r\n }\r\n\r\n /**\r\n * \uC5B8\uC5B4 \uBCC0\uACBD \uC774\uBCA4\uD2B8 \uB9AC\uC2A4\uB108 \uC81C\uAC70\r\n */\r\n off(event, callback) {\r\n if (this.listeners[event]) {\r\n const index = this.listeners[event].indexOf(callback);\r\n if (index > -1) {\r\n this.listeners[event].splice(index, 1);\r\n }\r\n }\r\n }\r\n\r\n /**\r\n * \uC774\uBCA4\uD2B8 \uBC1C\uC0DD\r\n */\r\n emit(event, data) {\r\n if (this.listeners[event]) {\r\n this.listeners[event].forEach(callback => {\r\n try {\r\n callback(data);\r\n } catch (error) {\r\n this.log('error', 'Error in event listener:', error);\r\n }\r\n });\r\n }\r\n }\r\n\r\n /**\r\n * \uD604\uC7AC \uC5B8\uC5B4\uC758 \uBAA8\uB4E0 \uBA54\uC2DC\uC9C0 \uBC18\uD658\r\n */\r\n getMessages() {\r\n return this.messages.get(this.currentLanguage) || {};\r\n }\r\n\r\n /**\r\n * \uC5B8\uC5B4\uBCC4 \uB0A0\uC9DC \uD3EC\uB9F7\uD305\r\n */\r\n formatDate(date, options = {}) {\r\n const locale = this.currentLanguage === 'ko' ? 'ko-KR' : 'en-US';\r\n return new Intl.DateTimeFormat(locale, options).format(new Date(date));\r\n }\r\n\r\n /**\r\n * \uC5B8\uC5B4\uBCC4 \uC22B\uC790 \uD3EC\uB9F7\uD305\r\n */\r\n formatNumber(number, options = {}) {\r\n const locale = this.currentLanguage === 'ko' ? 'ko-KR' : 'en-US';\r\n return new Intl.NumberFormat(locale, options).format(number);\r\n }\r\n\r\n /**\r\n * \uB85C\uAE45 \uB798\uD37C \uBA54\uC11C\uB4DC\r\n */\r\n log(level, ...args) {\r\n if (this.router?.errorHandler) {\r\n this.router.errorHandler.log(level, 'I18nManager', ...args);\r\n }\r\n }\r\n\r\n /**\r\n * i18n \uD65C\uC131\uD654 \uC5EC\uBD80 \uD655\uC778\r\n */\r\n isEnabled() {\r\n return this.config.enabled;\r\n }\r\n \r\n /**\r\n * \uCD08\uAE30 \uB85C\uB529\uC774 \uC644\uB8CC\uB418\uC5C8\uB294\uC9C0 \uD655\uC778\r\n */\r\n async isReady() {\r\n if (!this.config.enabled) {\r\n return true;\r\n }\r\n \r\n try {\r\n await this.initPromise;\r\n return true;\r\n } catch (error) {\r\n this.log('error', 'I18n initialization failed:', error);\r\n return false;\r\n }\r\n }\r\n \r\n /**\r\n * \uCE90\uC2DC \uCD08\uAE30\uD654 (\uBC84\uC804 \uBCC0\uACBD \uC2DC \uC0AC\uC6A9)\r\n */\r\n clearCache() {\r\n try {\r\n const keys = Object.keys(localStorage);\r\n const cacheKeys = keys.filter(key => key.startsWith(this.config.dataCacheKey));\r\n \r\n cacheKeys.forEach(key => {\r\n localStorage.removeItem(key);\r\n });\r\n \r\n this.log('debug', 'Cache cleared, removed', cacheKeys.length, 'items');\r\n } catch (error) {\r\n this.log('warn', 'Failed to clear cache:', error);\r\n }\r\n }\r\n \r\n /**\r\n * \uCE90\uC2DC \uC0C1\uD0DC \uD655\uC778\r\n */\r\n getCacheInfo() {\r\n const info = {\r\n enabled: this.config.enableDataCache,\r\n version: this.config.cacheVersion,\r\n languages: {}\r\n };\r\n \r\n try {\r\n const keys = Object.keys(localStorage);\r\n const cacheKeys = keys.filter(key => key.startsWith(this.config.dataCacheKey));\r\n \r\n cacheKeys.forEach(key => {\r\n const match = key.match(new RegExp(`${this.config.dataCacheKey}_(\\w+)_(.+)`));\r\n if (match) {\r\n const [, language, version] = match;\r\n const cachedItem = JSON.parse(localStorage.getItem(key));\r\n \r\n info.languages[language] = {\r\n version,\r\n timestamp: cachedItem.timestamp,\r\n age: Date.now() - cachedItem.timestamp\r\n };\r\n }\r\n });\r\n } catch (error) {\r\n this.log('warn', 'Failed to get cache info:', error);\r\n }\r\n \r\n return info;\r\n }\r\n \r\n /**\r\n * \uC2DC\uC2A4\uD15C \uCD08\uAE30\uD654 (\uD604\uC7AC \uC5B8\uC5B4\uC758 \uBA54\uC2DC\uC9C0 \uB85C\uB4DC)\r\n */\r\n async initialize() {\r\n if (!this.config.enabled) {\r\n this.log('info', 'I18n system is disabled, skipping initialization');\r\n return true;\r\n }\r\n \r\n try {\r\n // \uCD08\uAE30 \uC124\uC815\uC774 \uC644\uB8CC\uB420 \uB54C\uAE4C\uC9C0 \uB300\uAE30\r\n await this.initPromise;\r\n this.log('info', 'I18n system fully initialized');\r\n return true;\r\n } catch (error) {\r\n this.log('error', 'Failed to initialize I18n system:', error);\r\n return false;\r\n }\r\n }\r\n}", "/**\r\n * ViewLogic Authentication Management System\r\n * \uC778\uC99D \uAD00\uB9AC \uC2DC\uC2A4\uD15C\r\n */\r\nexport class AuthManager {\r\n constructor(router, options = {}) {\r\n this.config = {\r\n enabled: options.authEnabled || false,\r\n loginRoute: options.loginRoute || 'login',\r\n protectedRoutes: options.protectedRoutes || [],\r\n protectedPrefixes: options.protectedPrefixes || [],\r\n publicRoutes: options.publicRoutes || ['login', 'register', 'home'],\r\n checkAuthFunction: options.checkAuthFunction || null,\r\n redirectAfterLogin: options.redirectAfterLogin || 'home',\r\n // \uCFE0\uD0A4/\uC2A4\uD1A0\uB9AC\uC9C0 \uC124\uC815\r\n authCookieName: options.authCookieName || 'authToken',\r\n authFallbackCookieNames: options.authFallbackCookieNames || ['accessToken', 'token', 'jwt'],\r\n authStorage: options.authStorage || 'cookie',\r\n authCookieOptions: options.authCookieOptions || {},\r\n authSkipValidation: options.authSkipValidation || false,\r\n debug: options.debug || false\r\n };\r\n \r\n // \uB77C\uC6B0\uD130 \uC778\uC2A4\uD134\uC2A4 \uCC38\uC870 (\uD544\uC218 \uC758\uC874\uC131)\r\n this.router = router;\r\n \r\n // \uC774\uBCA4\uD2B8 \uB9AC\uC2A4\uB108\uB4E4\r\n this.eventListeners = new Map();\r\n \r\n this.log('info', 'AuthManager initialized', { enabled: this.config.enabled });\r\n }\r\n\r\n /**\r\n * \uB85C\uAE45 \uB798\uD37C \uBA54\uC11C\uB4DC\r\n */\r\n log(level, ...args) {\r\n if (this.router?.errorHandler) {\r\n this.router.errorHandler.log(level, 'AuthManager', ...args);\r\n }\r\n }\r\n\r\n /**\r\n * \uB77C\uC6B0\uD2B8 \uC778\uC99D \uD655\uC778\r\n */\r\n async checkAuthentication(routeName) {\r\n // \uC778\uC99D \uC2DC\uC2A4\uD15C\uC774 \uBE44\uD65C\uC131\uD654\uB41C \uACBD\uC6B0\r\n if (!this.config.enabled) {\r\n return { allowed: true, reason: 'auth_disabled' };\r\n }\r\n\r\n this.log('debug', `\uD83D\uDD10 Checking authentication for route: ${routeName}`);\r\n\r\n // \uACF5\uAC1C \uB77C\uC6B0\uD2B8\uC778\uC9C0 \uD655\uC778\r\n if (this.isPublicRoute(routeName)) {\r\n return { allowed: true, reason: 'public_route' };\r\n }\r\n\r\n // \uBCF4\uD638\uB41C \uB77C\uC6B0\uD2B8\uC778\uC9C0 \uD655\uC778\r\n const isProtected = this.isProtectedRoute(routeName);\r\n if (!isProtected) {\r\n return { allowed: true, reason: 'not_protected' };\r\n }\r\n\r\n // \uC0AC\uC6A9\uC790 \uC815\uC758 \uC778\uC99D \uCCB4\uD06C \uD568\uC218\uAC00 \uC788\uB294 \uACBD\uC6B0\r\n if (typeof this.config.checkAuthFunction === 'function') {\r\n try {\r\n const isAuthenticated = await this.config.checkAuthFunction(routeName);\r\n return {\r\n allowed: isAuthenticated, \r\n reason: isAuthenticated ? 'custom_auth_success' : 'custom_auth_failed',\r\n routeName\r\n };\r\n } catch (error) {\r\n this.log('error', 'Custom auth function failed:', error);\r\n return { allowed: false, reason: 'custom_auth_error', error };\r\n }\r\n }\r\n\r\n // \uAE30\uBCF8 \uC778\uC99D \uD655\uC778\r\n const isAuthenticated = this.isUserAuthenticated();\r\n return {\r\n allowed: isAuthenticated, \r\n reason: isAuthenticated ? 'authenticated' : 'not_authenticated',\r\n routeName\r\n };\r\n }\r\n\r\n /**\r\n * \uC0AC\uC6A9\uC790 \uC778\uC99D \uC0C1\uD0DC \uD655\uC778\r\n */\r\n isUserAuthenticated() {\r\n this.log('debug', '\uD83D\uDD0D Checking user authentication status');\r\n\r\n // 1. localStorage \uD655\uC778\r\n const token = localStorage.getItem('authToken') || localStorage.getItem('accessToken');\r\n if (token) {\r\n try {\r\n if (token.includes('.')) {\r\n const payload = JSON.parse(atob(token.split('.')[1]));\r\n if (payload.exp && Date.now() >= payload.exp * 1000) {\r\n this.log('debug', 'localStorage token expired, removing...');\r\n localStorage.removeItem('authToken');\r\n localStorage.removeItem('accessToken');\r\n return false;\r\n }\r\n }\r\n this.log('debug', '\u2705 Valid token found in localStorage');\r\n return true;\r\n } catch (error) {\r\n this.log('warn', 'Invalid token in localStorage:', error);\r\n }\r\n }\r\n\r\n // 2. sessionStorage \uD655\uC778\r\n const sessionToken = sessionStorage.getItem('authToken') || sessionStorage.getItem('accessToken');\r\n if (sessionToken) {\r\n this.log('debug', '\u2705 Token found in sessionStorage');\r\n return true;\r\n }\r\n\r\n // 3. \uCFE0\uD0A4 \uD655\uC778\r\n const authCookie = this.getAuthCookie();\r\n if (authCookie) {\r\n try {\r\n if (authCookie.includes('.')) {\r\n const payload = JSON.parse(atob(authCookie.split('.')[1]));\r\n if (payload.exp && Date.now() >= payload.exp * 1000) {\r\n this.log('debug', 'Cookie token expired, removing...');\r\n this.removeAuthCookie();\r\n return false;\r\n }\r\n }\r\n this.log('debug', '\u2705 Valid token found in cookies');\r\n return true;\r\n } catch (error) {\r\n this.log('warn', 'Cookie token validation failed:', error);\r\n }\r\n }\r\n\r\n // 4. \uC804\uC5ED \uBCC0\uC218 \uD655\uC778 (\uB808\uAC70\uC2DC \uC9C0\uC6D0)\r\n if (window.user || window.isAuthenticated) {\r\n this.log('debug', '\u2705 Global authentication variable found');\r\n return true;\r\n }\r\n\r\n this.log('debug', '\u274C No valid authentication found');\r\n return false;\r\n }\r\n\r\n /**\r\n * \uACF5\uAC1C \uB77C\uC6B0\uD2B8\uC778\uC9C0 \uD655\uC778\r\n */\r\n isPublicRoute(routeName) {\r\n return this.config.publicRoutes.includes(routeName);\r\n }\r\n\r\n /**\r\n * \uBCF4\uD638\uB41C \uB77C\uC6B0\uD2B8\uC778\uC9C0 \uD655\uC778\r\n */\r\n isProtectedRoute(routeName) {\r\n // \uD2B9\uC815 \uB77C\uC6B0\uD2B8\uAC00 \uBCF4\uD638\uB41C \uB77C\uC6B0\uD2B8 \uBAA9\uB85D\uC5D0 \uC788\uB294\uC9C0 \uD655\uC778\r\n if (this.config.protectedRoutes.includes(routeName)) {\r\n return true;\r\n }\r\n\r\n // prefix\uB85C \uBCF4\uD638\uB41C \uB77C\uC6B0\uD2B8\uC778\uC9C0 \uD655\uC778\r\n for (const prefix of this.config.protectedPrefixes) {\r\n if (routeName.startsWith(prefix)) {\r\n return true;\r\n }\r\n }\r\n\r\n return false;\r\n }\r\n\r\n /**\r\n * \uC778\uC99D \uCFE0\uD0A4 \uAC00\uC838\uC624\uAE30\r\n */\r\n getAuthCookie() {\r\n // \uC8FC \uCFE0\uD0A4 \uC774\uB984 \uD655\uC778\r\n const primaryCookie = this.getCookieValue(this.config.authCookieName);\r\n if (primaryCookie) {\r\n return primaryCookie;\r\n }\r\n\r\n // \uB300\uCCB4 \uCFE0\uD0A4 \uC774\uB984\uB4E4 \uD655\uC778\r\n for (const cookieName of this.config.authFallbackCookieNames) {\r\n const cookieValue = this.getCookieValue(cookieName);\r\n if (cookieValue) {\r\n this.log('debug', `Found auth token in fallback cookie: ${cookieName}`);\r\n return cookieValue;\r\n }\r\n }\r\n\r\n return null;\r\n }\r\n\r\n /**\r\n * \uCFE0\uD0A4 \uAC12 \uAC00\uC838\uC624\uAE30\r\n */\r\n getCookieValue(name) {\r\n const value = `; ${document.cookie}`;\r\n const parts = value.split(`; ${name}=`);\r\n if (parts.length === 2) {\r\n return decodeURIComponent(parts.pop().split(';').shift());\r\n }\r\n return null;\r\n }\r\n\r\n /**\r\n * \uC778\uC99D \uCFE0\uD0A4 \uC81C\uAC70\r\n */\r\n removeAuthCookie() {\r\n const cookiesToRemove = [this.config.authCookieName, ...this.config.authFallbackCookieNames];\r\n \r\n cookiesToRemove.forEach(cookieName => {\r\n // \uD604\uC7AC \uACBD\uB85C\uC640 \uB8E8\uD2B8 \uACBD\uB85C\uC5D0\uC11C \uBAA8\uB450 \uC81C\uAC70\r\n document.cookie = `${cookieName}=; expires=Thu, 01 Jan 1970 00:00:00 UTC; path=/;`;\r\n document.cookie = `${cookieName}=; expires=Thu, 01 Jan 1970 00:00:00 UTC; path=${window.location.pathname};`;\r\n });\r\n \r\n this.log('debug', 'Auth cookies removed');\r\n }\r\n\r\n /**\r\n * \uC561\uC138\uC2A4 \uD1A0\uD070 \uAC00\uC838\uC624\uAE30\r\n */\r\n getAccessToken() {\r\n // localStorage \uD655\uC778\r\n let token = localStorage.getItem('authToken') || localStorage.getItem('accessToken');\r\n if (token) return token;\r\n\r\n // sessionStorage \uD655\uC778\r\n token = sessionStorage.getItem('authToken') || sessionStorage.getItem('accessToken');\r\n if (token) return token;\r\n\r\n // \uCFE0\uD0A4 \uD655\uC778\r\n token = this.getAuthCookie();\r\n if (token) return token;\r\n\r\n return null;\r\n }\r\n\r\n /**\r\n * \uC561\uC138\uC2A4 \uD1A0\uD070 \uC124\uC815\r\n */\r\n setAccessToken(token, options = {}) {\r\n if (!token) {\r\n this.log('warn', 'Empty token provided');\r\n return false;\r\n }\r\n\r\n const {\r\n storage = this.config.authStorage,\r\n cookieOptions = this.config.authCookieOptions,\r\n skipValidation = this.config.authSkipValidation\r\n } = options;\r\n\r\n try {\r\n // JWT \uD1A0\uD070 \uAC80\uC99D (\uC635\uC158)\r\n if (!skipValidation && token.includes('.')) {\r\n try {\r\n const payload = JSON.parse(atob(token.split('.')[1]));\r\n if (payload.exp && Date.now() >= payload.exp * 1000) {\r\n this.log('warn', '\u274C Token is expired');\r\n return false;\r\n }\r\n this.log('debug', '\u2705 JWT token validated');\r\n } catch (error) {\r\n this.log('warn', '\u26A0\uFE0F JWT validation failed, but proceeding:', error.message);\r\n }\r\n }\r\n\r\n // \uC2A4\uD1A0\uB9AC\uC9C0\uBCC4 \uC800\uC7A5\r\n switch (storage) {\r\n case 'localStorage':\r\n localStorage.setItem('authToken', token);\r\n this.log('debug', 'Token saved to localStorage');\r\n break;\r\n\r\n case 'sessionStorage':\r\n sessionStorage.setItem('authToken', token);\r\n this.log('debug', 'Token saved to sessionStorage');\r\n break;\r\n\r\n case 'cookie':\r\n this.setAuthCookie(token, cookieOptions);\r\n break;\r\n\r\n default:\r\n // \uAE30\uBCF8\uAC12: localStorage\r\n localStorage.setItem('authToken', token);\r\n this.log('debug', 'Token saved to localStorage (default)');\r\n }\r\n\r\n this.emitAuthEvent('token_set', { \r\n storage,\r\n tokenLength: token.length,\r\n hasExpiration: token.includes('.')\r\n });\r\n\r\n return true;\r\n\r\n } catch (error) {\r\n this.log('Failed to set token:', error);\r\n return false;\r\n }\r\n }\r\n\r\n /**\r\n * \uC778\uC99D \uCFE0\uD0A4 \uC124\uC815\r\n */\r\n setAuthCookie(token, options = {}) {\r\n const {\r\n cookieName = this.config.authCookieName,\r\n secure = window.location.protocol === 'https:',\r\n sameSite = 'Strict',\r\n path = '/',\r\n domain = null\r\n } = options;\r\n\r\n let cookieString = `${cookieName}=${encodeURIComponent(token)}; path=${path}`;\r\n\r\n if (secure) {\r\n cookieString += '; Secure';\r\n }\r\n\r\n if (sameSite) {\r\n cookieString += `; SameSite=${sameSite}`;\r\n }\r\n\r\n if (domain) {\r\n cookieString += `; Domain=${domain}`;\r\n }\r\n\r\n // JWT\uC5D0\uC11C \uB9CC\uB8CC \uC2DC\uAC04 \uCD94\uCD9C\r\n try {\r\n if (token.includes('.')) {\r\n try {\r\n const payload = JSON.parse(atob(token.split('.')[1]));\r\n if (payload.exp) {\r\n const expireDate = new Date(payload.exp * 1000);\r\n cookieString += `; Expires=${expireDate.toUTCString()}`;\r\n }\r\n } catch (error) {\r\n this.log('Could not extract expiration from JWT token');\r\n }\r\n }\r\n } catch (error) {\r\n this.log('Token processing error:', error);\r\n }\r\n\r\n document.cookie = cookieString;\r\n this.log(`Auth cookie set: ${cookieName}`);\r\n }\r\n\r\n /**\r\n * \uD1A0\uD070 \uC81C\uAC70\r\n */\r\n removeAccessToken(storage = 'all') {\r\n switch (storage) {\r\n case 'localStorage':\r\n localStorage.removeItem('authToken');\r\n localStorage.removeItem('accessToken');\r\n break;\r\n\r\n case 'sessionStorage':\r\n sessionStorage.removeItem('authToken');\r\n sessionStorage.removeItem('accessToken');\r\n break;\r\n\r\n case 'cookie':\r\n this.removeAuthCookie();\r\n break;\r\n\r\n case 'all':\r\n default:\r\n localStorage.removeItem('authToken');\r\n localStorage.removeItem('accessToken');\r\n sessionStorage.removeItem('authToken');\r\n sessionStorage.removeItem('accessToken');\r\n this.removeAuthCookie();\r\n break;\r\n }\r\n\r\n this.emitAuthEvent('token_removed', { storage });\r\n this.log(`Token removed from: ${storage}`);\r\n }\r\n\r\n /**\r\n * \uB85C\uADF8\uC778 \uC131\uACF5 \uCC98\uB9AC\r\n */\r\n handleLoginSuccess(targetRoute = null) {\r\n const redirectRoute = targetRoute || this.config.redirectAfterLogin;\r\n \r\n this.log(`\uD83C\uDF89 Login success, redirecting to: ${redirectRoute}`);\r\n \r\n this.emitAuthEvent('login_success', { targetRoute: redirectRoute });\r\n \r\n // \uB77C\uC6B0\uD130 \uC778\uC2A4\uD134\uC2A4\uAC00 \uC788\uC73C\uBA74 \uC9C1\uC811 \uB124\uBE44\uAC8C\uC774\uC158\r\n if (this.router && typeof this.router.navigateTo === 'function') {\r\n this.router.navigateTo(redirectRoute);\r\n }\r\n \r\n return redirectRoute;\r\n }\r\n\r\n /**\r\n * \uB85C\uADF8\uC544\uC6C3 \uCC98\uB9AC\r\n */\r\n handleLogout() {\r\n this.log('\uD83D\uDC4B Logging out user');\r\n \r\n // \uBAA8\uB4E0 \uC800\uC7A5\uC18C\uC5D0\uC11C \uD1A0\uD070 \uC81C\uAC70\r\n this.removeAccessToken();\r\n \r\n // \uC804\uC5ED \uBCC0\uC218 \uC815\uB9AC\r\n if (window.user) window.user = null;\r\n if (window.isAuthenticated) window.isAuthenticated = false;\r\n \r\n this.emitAuthEvent('logout', {});\r\n \r\n // \uB77C\uC6B0\uD130 \uC778\uC2A4\uD134\uC2A4\uAC00 \uC788\uC73C\uBA74 \uC9C1\uC811 \uB124\uBE44\uAC8C\uC774\uC158\r\n if (this.router && typeof this.router.navigateTo === 'function') {\r\n this.router.navigateTo(this.config.loginRoute);\r\n }\r\n \r\n return this.config.loginRoute;\r\n }\r\n\r\n /**\r\n * \uC778\uC99D \uC774\uBCA4\uD2B8 \uBC1C\uC0DD\r\n */\r\n emitAuthEvent(eventType, data) {\r\n const event = new CustomEvent('router:auth', {\r\n detail: {\r\n type: eventType,\r\n timestamp: Date.now(),\r\n ...data\r\n }\r\n });\r\n \r\n document.dispatchEvent(event);\r\n \r\n // \uB0B4\uBD80 \uB9AC\uC2A4\uB108\uB4E4\uC5D0\uAC8C\uB3C4 \uC54C\uB9BC\r\n if (this.eventListeners.has(eventType)) {\r\n this.eventListeners.get(eventType).forEach(listener => {\r\n try {\r\n listener(data);\r\n } catch (error) {\r\n this.log('Event listener error:', error);\r\n }\r\n });\r\n }\r\n \r\n this.log(`\uD83D\uDD14 Auth event emitted: ${eventType}`, data);\r\n }\r\n\r\n /**\r\n * \uC774\uBCA4\uD2B8 \uB9AC\uC2A4\uB108 \uB4F1\uB85D\r\n */\r\n on(eventType, listener) {\r\n if (!this.eventListeners.has(eventType)) {\r\n this.eventListeners.set(eventType, []);\r\n }\r\n this.eventListeners.get(eventType).push(listener);\r\n }\r\n\r\n /**\r\n * \uC774\uBCA4\uD2B8 \uB9AC\uC2A4\uB108 \uC81C\uAC70\r\n */\r\n off(eventType, listener) {\r\n if (this.eventListeners.has(eventType)) {\r\n const listeners = this.eventListeners.get(eventType);\r\n const index = listeners.indexOf(listener);\r\n if (index > -1) {\r\n listeners.splice(index, 1);\r\n }\r\n }\r\n }\r\n\r\n /**\r\n * \uC778\uC99D \uC0C1\uD0DC \uD1B5\uACC4\r\n */\r\n getAuthStats() {\r\n return {\r\n enabled: this.config.enabled,\r\n isAuthenticated: this.isUserAuthenticated(),\r\n hasToken: !!this.getAccessToken(),\r\n protectedRoutesCount: this.config.protectedRoutes.length,\r\n protectedPrefixesCount: this.config.protectedPrefixes.length,\r\n publicRoutesCount: this.config.publicRoutes.length,\r\n storage: this.config.authStorage,\r\n loginRoute: this.config.loginRoute\r\n };\r\n }\r\n\r\n /**\r\n * \uC815\uB9AC (\uBA54\uBAA8\uB9AC \uB204\uC218 \uBC29\uC9C0)\r\n */\r\n destroy() {\r\n this.eventListeners.clear();\r\n this.log('debug', 'AuthManager destroyed');\r\n }\r\n}", "/**\r\n * ViewLogic Cache Management System\r\n * \uCE90\uC2DC \uAD00\uB9AC \uC2DC\uC2A4\uD15C\r\n */\r\nexport class CacheManager {\r\n constructor(router, options = {}) {\r\n this.config = {\r\n cacheMode: options.cacheMode || 'memory', // 'memory' \uB610\uB294 'lru'\r\n cacheTTL: options.cacheTTL || 300000, // 5\uBD84 (\uBC00\uB9AC\uCD08)\r\n maxCacheSize: options.maxCacheSize || 50, // LRU \uCE90\uC2DC \uCD5C\uB300 \uD06C\uAE30\r\n debug: options.debug || false\r\n };\r\n \r\n // \uB77C\uC6B0\uD130 \uC778\uC2A4\uD134\uC2A4 \uCC38\uC870 (\uD544\uC694\uC2DC \uB77C\uC6B0\uD130 \uC0C1\uD0DC \uD655\uC778\uC6A9)\r\n this.router = router;\r\n \r\n // \uCE90\uC2DC \uC800\uC7A5\uC18C\uB4E4\r\n this.cache = new Map();\r\n this.cacheTimestamps = new Map();\r\n this.lruOrder = []; // LRU \uC21C\uC11C \uCD94\uC801\r\n \r\n this.log('info', 'CacheManager initialized with config:', this.config);\r\n }\r\n\r\n /**\r\n * \uB85C\uAE45 \uB798\uD37C \uBA54\uC11C\uB4DC\r\n */\r\n log(level, ...args) {\r\n if (this.router?.errorHandler) {\r\n this.router.errorHandler.log(level, 'CacheManager', ...args);\r\n }\r\n }\r\n\r\n /**\r\n * \uCE90\uC2DC\uC5D0 \uAC12 \uC800\uC7A5\r\n */\r\n setCache(key, value) {\r\n const now = Date.now();\r\n \r\n if (this.config.cacheMode === 'lru') {\r\n // LRU \uCE90\uC2DC \uAD00\uB9AC\r\n if (this.cache.size >= this.config.maxCacheSize && !this.cache.has(key)) {\r\n const oldestKey = this.lruOrder.shift();\r\n if (oldestKey) {\r\n this.cache.delete(oldestKey);\r\n this.cacheTimestamps.delete(oldestKey);\r\n this.log('debug', `\uD83D\uDDD1\uFE0F LRU evicted cache key: ${oldestKey}`);\r\n }\r\n }\r\n \r\n // \uAE30\uC874 \uD0A4\uAC00 \uC788\uC73C\uBA74 LRU \uC21C\uC11C\uC5D0\uC11C \uC81C\uAC70\r\n const existingIndex = this.lruOrder.indexOf(key);\r\n if (existingIndex > -1) {\r\n this.lruOrder.splice(existingIndex, 1);\r\n }\r\n \r\n // \uCD5C\uC2E0 \uC21C\uC11C\uB85C \uCD94\uAC00\r\n this.lruOrder.push(key);\r\n }\r\n \r\n this.cache.set(key, value);\r\n this.cacheTimestamps.set(key, now);\r\n \r\n this.log('debug', `\uD83D\uDCBE Cached: ${key} (size: ${this.cache.size})`);\r\n }\r\n \r\n /**\r\n * \uCE90\uC2DC\uC5D0\uC11C \uAC12 \uAC00\uC838\uC624\uAE30\r\n */\r\n getFromCache(key) {\r\n const now = Date.now();\r\n const timestamp = this.cacheTimestamps.get(key);\r\n \r\n // TTL \uCCB4\uD06C\r\n if (timestamp && (now - timestamp) > this.config.cacheTTL) {\r\n this.cache.delete(key);\r\n this.cacheTimestamps.delete(key);\r\n \r\n if (this.config.cacheMode === 'lru') {\r\n const index = this.lruOrder.indexOf(key);\r\n if (index > -1) {\r\n this.lruOrder.splice(index, 1);\r\n }\r\n }\r\n \r\n this.log('debug', `\u23F0 Cache expired and removed: ${key}`);\r\n return null;\r\n }\r\n \r\n const value = this.cache.get(key);\r\n \r\n if (value && this.config.cacheMode === 'lru') {\r\n // LRU \uC21C\uC11C \uC5C5\uB370\uC774\uD2B8\r\n const index = this.lruOrder.indexOf(key);\r\n if (index > -1) {\r\n this.lruOrder.splice(index, 1);\r\n this.lruOrder.push(key);\r\n }\r\n }\r\n \r\n if (value) {\r\n this.log('debug', `\uD83C\uDFAF Cache hit: ${key}`);\r\n } else {\r\n this.log('debug', `\u274C Cache miss: ${key}`);\r\n }\r\n \r\n return value;\r\n }\r\n \r\n /**\r\n * \uCE90\uC2DC\uC5D0 \uD0A4\uAC00 \uC788\uB294\uC9C0 \uD655\uC778\r\n */\r\n hasCache(key) {\r\n return this.cache.has(key) && this.getFromCache(key) !== null;\r\n }\r\n \r\n /**\r\n * \uD2B9\uC815 \uD0A4 \uD328\uD134\uC758 \uCE90\uC2DC \uC0AD\uC81C\r\n */\r\n invalidateByPattern(pattern) {\r\n const keysToDelete = [];\r\n \r\n for (const key of this.cache.keys()) {\r\n if (key.includes(pattern) || key.startsWith(pattern)) {\r\n keysToDelete.push(key);\r\n }\r\n }\r\n \r\n keysToDelete.forEach(key => {\r\n this.cache.delete(key);\r\n this.cacheTimestamps.delete(key);\r\n \r\n if (this.config.cacheMode === 'lru') {\r\n const index = this.lruOrder.indexOf(key);\r\n if (index > -1) {\r\n this.lruOrder.splice(index, 1);\r\n }\r\n }\r\n });\r\n \r\n this.log('debug', `\uD83E\uDDF9 Invalidated ${keysToDelete.length} cache entries matching: ${pattern}`);\r\n return keysToDelete.length;\r\n }\r\n \r\n /**\r\n * \uD2B9\uC815 \uCEF4\uD3EC\uB10C\uD2B8 \uCE90\uC2DC \uBB34\uD6A8\uD654\r\n */\r\n invalidateComponentCache(routeName) {\r\n const patterns = [\r\n `component_${routeName}`,\r\n `script_${routeName}`,\r\n `template_${routeName}`,\r\n `style_${routeName}`,\r\n `layout_${routeName}`\r\n ];\r\n \r\n let totalInvalidated = 0;\r\n patterns.forEach(pattern => {\r\n totalInvalidated += this.invalidateByPattern(pattern);\r\n });\r\n \r\n this.log(`\uD83D\uDD04 Invalidated component cache for route: ${routeName} (${totalInvalidated} entries)`);\r\n return totalInvalidated;\r\n }\r\n \r\n /**\r\n * \uBAA8\uB4E0 \uCEF4\uD3EC\uB10C\uD2B8 \uCE90\uC2DC \uC0AD\uC81C\r\n */\r\n clearComponentCache() {\r\n const componentPatterns = ['component_', 'script_', 'template_', 'style_', 'layout_'];\r\n let totalCleared = 0;\r\n \r\n componentPatterns.forEach(pattern => {\r\n totalCleared += this.invalidateByPattern(pattern);\r\n });\r\n \r\n this.log(`\uD83E\uDDFD Cleared all component caches (${totalCleared} entries)`);\r\n return totalCleared;\r\n }\r\n \r\n /**\r\n * \uC804\uCCB4 \uCE90\uC2DC \uC0AD\uC81C\r\n */\r\n clearCache() {\r\n const size = this.cache.size;\r\n this.cache.clear();\r\n this.cacheTimestamps.clear();\r\n this.lruOrder = [];\r\n \r\n this.log(`\uD83D\uDD25 Cleared all cache (${size} entries)`);\r\n }\r\n \r\n /**\r\n * \uB9CC\uB8CC\uB41C \uCE90\uC2DC \uD56D\uBAA9\uB4E4 \uC815\uB9AC\r\n */\r\n cleanExpiredCache() {\r\n const now = Date.now();\r\n const expiredKeys = [];\r\n \r\n for (const [key, timestamp] of this.cacheTimestamps.entries()) {\r\n if ((now - timestamp) > this.config.cacheTTL) {\r\n expiredKeys.push(key);\r\n }\r\n }\r\n \r\n expiredKeys.forEach(key => {\r\n this.cache.delete(key);\r\n this.cacheTimestamps.delete(key);\r\n \r\n if (this.config.cacheMode === 'lru') {\r\n const index = this.lruOrder.indexOf(key);\r\n if (index > -1) {\r\n this.lruOrder.splice(index, 1);\r\n }\r\n }\r\n });\r\n \r\n if (expiredKeys.length > 0) {\r\n this.log(`\u23F1\uFE0F Cleaned ${expiredKeys.length} expired cache entries`);\r\n }\r\n \r\n return expiredKeys.length;\r\n }\r\n \r\n /**\r\n * \uCE90\uC2DC \uD1B5\uACC4 \uC815\uBCF4\r\n */\r\n getCacheStats() {\r\n return {\r\n size: this.cache.size,\r\n maxSize: this.config.maxCacheSize,\r\n mode: this.config.cacheMode,\r\n ttl: this.config.cacheTTL,\r\n memoryUsage: this.getMemoryUsage(),\r\n hitRatio: this.getHitRatio(),\r\n categories: this.getCategorizedStats()\r\n };\r\n }\r\n \r\n /**\r\n * \uBA54\uBAA8\uB9AC \uC0AC\uC6A9\uB7C9 \uCD94\uC815\r\n */\r\n getMemoryUsage() {\r\n let estimatedBytes = 0;\r\n \r\n for (const [key, value] of this.cache.entries()) {\r\n // \uD0A4 \uD06C\uAE30\r\n estimatedBytes += key.length * 2; // UTF-16\r\n \r\n // \uAC12 \uD06C\uAE30 \uCD94\uC815\r\n if (typeof value === 'string') {\r\n estimatedBytes += value.length * 2;\r\n } else if (typeof value === 'object' && value !== null) {\r\n estimatedBytes += JSON.stringify(value).length * 2;\r\n } else {\r\n estimatedBytes += 8; // \uB300\uB7B5\uC801\uC778 \uD06C\uAE30\r\n }\r\n }\r\n \r\n return {\r\n bytes: estimatedBytes,\r\n kb: Math.round(estimatedBytes / 1024 * 100) / 100,\r\n mb: Math.round(estimatedBytes / (1024 * 1024) * 100) / 100\r\n };\r\n }\r\n \r\n /**\r\n * \uD788\uD2B8 \uBE44\uC728 \uACC4\uC0B0 (\uAC04\uB2E8\uD55C \uCD94\uC815)\r\n */\r\n getHitRatio() {\r\n // \uC2E4\uC81C \uD788\uD2B8/\uBBF8\uC2A4 \uCD94\uC801\uC744 \uC704\uD574\uC11C\uB294 \uBCC4\uB3C4\uC758 \uCE74\uC6B4\uD130\uAC00 \uD544\uC694\r\n // \uD604\uC7AC\uB294 \uCE90\uC2DC \uD06C\uAE30 \uAE30\uBC18 \uCD94\uC815\uCE58 \uBC18\uD658\r\n const ratio = this.cache.size > 0 ? Math.min(this.cache.size / this.config.maxCacheSize, 1) : 0;\r\n return Math.round(ratio * 100);\r\n }\r\n \r\n /**\r\n * \uCE74\uD14C\uACE0\uB9AC\uBCC4 \uCE90\uC2DC \uD1B5\uACC4\r\n */\r\n getCategorizedStats() {\r\n const categories = {\r\n components: 0,\r\n scripts: 0,\r\n templates: 0,\r\n styles: 0,\r\n layouts: 0,\r\n others: 0\r\n };\r\n \r\n for (const key of this.cache.keys()) {\r\n if (key.startsWith('component_')) categories.components++;\r\n else if (key.startsWith('script_')) categories.scripts++;\r\n else if (key.startsWith('template_')) categories.templates++;\r\n else if (key.startsWith('style_')) categories.styles++;\r\n else if (key.startsWith('layout_')) categories.layouts++;\r\n else categories.others++;\r\n }\r\n \r\n return categories;\r\n }\r\n \r\n /**\r\n * \uCE90\uC2DC \uD0A4 \uBAA9\uB85D \uBC18\uD658\r\n */\r\n getCacheKeys() {\r\n return Array.from(this.cache.keys());\r\n }\r\n \r\n /**\r\n * \uD2B9\uC815 \uD328\uD134\uC758 \uCE90\uC2DC \uD0A4\uB4E4 \uBC18\uD658\r\n */\r\n getCacheKeysByPattern(pattern) {\r\n return this.getCacheKeys().filter(key => \r\n key.includes(pattern) || key.startsWith(pattern)\r\n );\r\n }\r\n \r\n /**\r\n * \uC790\uB3D9 \uC815\uB9AC \uC2DC\uC791 (\uBC31\uADF8\uB77C\uC6B4\uB4DC\uC5D0\uC11C \uB9CC\uB8CC\uB41C \uCE90\uC2DC \uC815\uB9AC)\r\n */\r\n startAutoCleanup(interval = 60000) { // \uAE30\uBCF8 1\uBD84 \uAC04\uACA9\r\n if (this.cleanupInterval) {\r\n clearInterval(this.cleanupInterval);\r\n }\r\n \r\n this.cleanupInterval = setInterval(() => {\r\n this.cleanExpiredCache();\r\n }, interval);\r\n \r\n this.log(`\uD83E\uDD16 Auto cleanup started (interval: ${interval}ms)`);\r\n }\r\n \r\n /**\r\n * \uC790\uB3D9 \uC815\uB9AC \uC911\uC9C0\r\n */\r\n stopAutoCleanup() {\r\n if (this.cleanupInterval) {\r\n clearInterval(this.cleanupInterval);\r\n this.cleanupInterval = null;\r\n this.log('debug', '\uD83D\uDED1 Auto cleanup stopped');\r\n }\r\n }\r\n \r\n /**\r\n * \uC815\uB9AC (\uBA54\uBAA8\uB9AC \uB204\uC218 \uBC29\uC9C0)\r\n */\r\n destroy() {\r\n this.stopAutoCleanup();\r\n this.clearCache();\r\n this.log('debug', 'CacheManager destroyed');\r\n }\r\n}", "/**\r\n * ViewLogic Query Management System\r\n * URL \uCFFC\uB9AC \uD30C\uB77C\uBBF8\uD130 \uAD00\uB9AC \uC2DC\uC2A4\uD15C\r\n */\r\nexport class QueryManager {\r\n constructor(router, options = {}) {\r\n this.config = {\r\n enableParameterValidation: options.enableParameterValidation !== false,\r\n logSecurityWarnings: options.logSecurityWarnings !== false,\r\n maxParameterLength: options.maxParameterLength || 1000,\r\n maxArraySize: options.maxArraySize || 100,\r\n maxParameterCount: options.maxParameterCount || 50,\r\n allowedKeyPattern: options.allowedKeyPattern || /^[a-zA-Z0-9_\\-]+$/,\r\n debug: options.debug || false\r\n };\r\n \r\n // \uB77C\uC6B0\uD130 \uC778\uC2A4\uD134\uC2A4 \uCC38\uC870\r\n this.router = router;\r\n \r\n // \uD604\uC7AC \uCFFC\uB9AC \uD30C\uB77C\uBBF8\uD130 \uC0C1\uD0DC\r\n this.currentQueryParams = {};\r\n \r\n this.log('info', 'QueryManager initialized with config:', this.config);\r\n }\r\n\r\n /**\r\n * \uB85C\uAE45 \uB798\uD37C \uBA54\uC11C\uB4DC\r\n */\r\n log(level, ...args) {\r\n if (this.router?.errorHandler) {\r\n this.router.errorHandler.log(level, 'QueryManager', ...args);\r\n }\r\n }\r\n\r\n /**\r\n * \uD30C\uB77C\uBBF8\uD130 \uAC12 sanitize (XSS, SQL Injection \uBC29\uC5B4)\r\n */\r\n sanitizeParameter(value) {\r\n if (typeof value !== 'string') return value;\r\n \r\n // XSS \uBC29\uC5B4: HTML \uD0DC\uADF8\uC640 \uC2A4\uD06C\uB9BD\uD2B8 \uC81C\uAC70\r\n let sanitized = value\r\n .replace(/<script\\b[^<]*(?:(?!<\\/script>)<[^<]*)*<\\/script>/gi, '') // script \uD0DC\uADF8 \uC81C\uAC70\r\n .replace(/<iframe\\b[^<]*(?:(?!<\\/iframe>)<[^<]*)*<\\/iframe>/gi, '') // iframe \uD0DC\uADF8 \uC81C\uAC70\r\n .replace(/<object\\b[^<]*(?:(?!<\\/object>)<[^<]*)*<\\/object>/gi, '') // object \uD0DC\uADF8 \uC81C\uAC70\r\n .replace(/<embed\\b[^<]*(?:(?!<\\/embed>)<[^<]*)*<\\/embed>/gi, '') // embed \uD0DC\uADF8 \uC81C\uAC70\r\n .replace(/<link\\b[^<]*>/gi, '') // link \uD0DC\uADF8 \uC81C\uAC70\r\n .replace(/<meta\\b[^<]*>/gi, '') // meta \uD0DC\uADF8 \uC81C\uAC70\r\n .replace(/javascript:/gi, '') // javascript: \uD504\uB85C\uD1A0\uCF5C \uC81C\uAC70\r\n .replace(/vbscript:/gi, '') // vbscript: \uD504\uB85C\uD1A0\uCF5C \uC81C\uAC70\r\n .replace(/data:/gi, '') // data: \uD504\uB85C\uD1A0\uCF5C \uC81C\uAC70\r\n .replace(/on\\w+\\s*=/gi, '') // \uC774\uBCA4\uD2B8 \uD578\uB4E4\uB7EC \uC81C\uAC70 (onclick, onload \uB4F1)\r\n .replace(/expression\\s*\\(/gi, '') // CSS expression \uC81C\uAC70\r\n .replace(/url\\s*\\(/gi, ''); // CSS url() \uC81C\uAC70\r\n \r\n // SQL Injection \uBC29\uC5B4: \uC704\uD5D8\uD55C SQL \uD0A4\uC6CC\uB4DC \uD544\uD130\uB9C1\r\n const sqlPatterns = [\r\n /(\\b(union|select|insert|update|delete|drop|create|alter|exec|execute|sp_|xp_)\\b)/gi,\r\n /(;|\\||&|\\*|%|<|>)/g, // \uC704\uD5D8\uD55C \uD2B9\uC218\uBB38\uC790\r\n /(--|\\/\\*|\\*\\/)/g, // SQL \uC8FC\uC11D\r\n /(\\bor\\b.*\\b=\\b|\\band\\b.*\\b=\\b)/gi, // OR/AND \uC870\uAC74\uBB38\r\n /('.*'|\".*\")/g, // \uB530\uC634\uD45C\uB85C \uB458\uB7EC\uC2F8\uC778 \uBB38\uC790\uC5F4\r\n /(\\\\\\w+)/g // \uBC31\uC2AC\uB798\uC2DC \uC774\uC2A4\uCF00\uC774\uD504\r\n ];\r\n \r\n for (const pattern of sqlPatterns) {\r\n sanitized = sanitized.replace(pattern, '');\r\n }\r\n \r\n // \uCD94\uAC00 \uBCF4\uC548: \uC5F0\uC18D\uB41C \uD2B9\uC218\uBB38\uC790 \uC81C\uAC70\r\n sanitized = sanitized.replace(/[<>'\"&]{2,}/g, '');\r\n \r\n // \uAE38\uC774 \uC81C\uD55C (DoS \uBC29\uC5B4)\r\n if (sanitized.length > this.config.maxParameterLength) {\r\n sanitized = sanitized.substring(0, this.config.maxParameterLength);\r\n }\r\n \r\n return sanitized.trim();\r\n }\r\n\r\n /**\r\n * \uD30C\uB77C\uBBF8\uD130 \uC720\uD6A8\uC131 \uAC80\uC99D\r\n */\r\n validateParameter(key, value) {\r\n // \uBCF4\uC548 \uAC80\uC99D\uC774 \uBE44\uD65C\uC131\uD654\uB41C \uACBD\uC6B0 \uD1B5\uACFC\r\n if (!this.config.enableParameterValidation) {\r\n return true;\r\n }\r\n \r\n // \uD30C\uB77C\uBBF8\uD130 \uD0A4 \uAC80\uC99D\r\n if (typeof key !== 'string' || key.length === 0) {\r\n return false;\r\n }\r\n \r\n // \uD0A4 \uC774\uB984 \uC81C\uD55C\r\n if (!this.config.allowedKeyPattern.test(key)) {\r\n if (this.config.logSecurityWarnings) {\r\n console.warn(`Invalid parameter key format: ${key}`);\r\n }\r\n return false;\r\n }\r\n \r\n // \uD0A4 \uAE38\uC774 \uC81C\uD55C\r\n if (key.length > 50) {\r\n if (this.config.logSecurityWarnings) {\r\n console.warn(`Parameter key too long: ${key}`);\r\n }\r\n return false;\r\n }\r\n \r\n // \uAC12 \uD0C0\uC785 \uAC80\uC99D\r\n if (value !== null && value !== undefined) {\r\n if (typeof value === 'string') {\r\n // \uBB38\uC790\uC5F4 \uAE38\uC774 \uC81C\uD55C\r\n if (value.length > this.config.maxParameterLength) {\r\n if (this.config.logSecurityWarnings) {\r\n console.warn(`Parameter value too long for key: ${key}`);\r\n }\r\n return false;\r\n }\r\n \r\n // \uC704\uD5D8\uD55C \uD328\uD134 \uAC10\uC9C0\r\n const dangerousPatterns = [\r\n /<script|<iframe|<object|<embed/gi,\r\n /javascript:|vbscript:|data:/gi,\r\n /union.*select|insert.*into|delete.*from/gi,\r\n /\\.\\.\\//g, // \uACBD\uB85C \uD0D0\uC0C9 \uACF5\uACA9\r\n /[<>'\"&]{3,}/g // \uC5F0\uC18D\uB41C \uD2B9\uC218\uBB38\uC790\r\n ];\r\n \r\n for (const pattern of dangerousPatterns) {\r\n if (pattern.test(value)) {\r\n if (this.config.logSecurityWarnings) {\r\n console.warn(`Dangerous pattern detected in parameter ${key}:`, value);\r\n }\r\n return false;\r\n }\r\n }\r\n } else if (Array.isArray(value)) {\r\n // \uBC30\uC5F4 \uAE38\uC774 \uC81C\uD55C\r\n if (value.length > this.config.maxArraySize) {\r\n if (this.config.logSecurityWarnings) {\r\n console.warn(`Parameter array too large for key: ${key}`);\r\n }\r\n return false;\r\n }\r\n \r\n // \uBC30\uC5F4 \uAC01 \uC694\uC18C \uAC80\uC99D\r\n for (const item of value) {\r\n if (!this.validateParameter(`${key}[]`, item)) {\r\n return false;\r\n }\r\n }\r\n }\r\n }\r\n \r\n return true;\r\n }\r\n\r\n /**\r\n * \uCFFC\uB9AC\uC2A4\uD2B8\uB9C1 \uD30C\uC2F1\r\n */\r\n parseQueryString(queryString) {\r\n const params = {};\r\n if (!queryString) return params;\r\n \r\n const pairs = queryString.split('&');\r\n for (const pair of pairs) {\r\n try {\r\n const [rawKey, rawValue] = pair.split('=');\r\n if (!rawKey) continue;\r\n \r\n let key, value;\r\n try {\r\n key = decodeURIComponent(rawKey);\r\n value = rawValue ? decodeURIComponent(rawValue) : '';\r\n } catch (e) {\r\n this.log('warn', 'Failed to decode URI component:', pair);\r\n continue;\r\n }\r\n \r\n // \uBCF4\uC548 \uAC80\uC99D\r\n if (!this.validateParameter(key, value)) {\r\n this.log('warn', `Parameter rejected by security filter: ${key}`);\r\n continue;\r\n }\r\n \r\n // \uAC12 sanitize\r\n const sanitizedValue = this.sanitizeParameter(value);\r\n \r\n // \uBC30\uC5F4 \uD615\uD0DC\uC758 \uD30C\uB77C\uBBF8\uD130 \uCC98\uB9AC (\uC608: tags[]=a&tags[]=b)\r\n if (key.endsWith('[]')) {\r\n const arrayKey = key.slice(0, -2);\r\n \r\n // \uBC30\uC5F4 \uD0A4\uB3C4 \uAC80\uC99D\r\n if (!this.validateParameter(arrayKey, [])) {\r\n continue;\r\n }\r\n \r\n if (!params[arrayKey]) params[arrayKey] = [];\r\n \r\n // \uBC30\uC5F4 \uD06C\uAE30 \uC81C\uD55C\r\n if (params[arrayKey].length < this.config.maxArraySize) {\r\n params[arrayKey].push(sanitizedValue);\r\n } else {\r\n if (this.config.logSecurityWarnings) {\r\n console.warn(`Array parameter ${arrayKey} size limit exceeded`);\r\n }\r\n }\r\n } else {\r\n params[key] = sanitizedValue;\r\n }\r\n } catch (error) {\r\n this.log('error', 'Error parsing query parameter:', pair, error);\r\n }\r\n }\r\n \r\n // \uC804\uCCB4 \uD30C\uB77C\uBBF8\uD130 \uAC1C\uC218 \uC81C\uD55C\r\n const paramCount = Object.keys(params).length;\r\n if (paramCount > this.config.maxParameterCount) {\r\n if (this.config.logSecurityWarnings) {\r\n console.warn(`Too many parameters (${paramCount}). Limiting to first ${this.config.maxParameterCount}.`);\r\n }\r\n const limitedParams = {};\r\n let count = 0;\r\n for (const [key, value] of Object.entries(params)) {\r\n if (count >= this.config.maxParameterCount) break;\r\n limitedParams[key] = value;\r\n count++;\r\n }\r\n return limitedParams;\r\n }\r\n \r\n return params;\r\n }\r\n\r\n /**\r\n * \uCFFC\uB9AC\uC2A4\uD2B8\uB9C1 \uC0DD\uC131\r\n */\r\n buildQueryString(params) {\r\n if (!params || Object.keys(params).length === 0) return '';\r\n \r\n const pairs = [];\r\n for (const [key, value] of Object.entries(params)) {\r\n if (Array.isArray(value)) {\r\n // \uBC30\uC5F4 \uD30C\uB77C\uBBF8\uD130 \uCC98\uB9AC\r\n for (const item of value) {\r\n pairs.push(`${encodeURIComponent(key)}[]=${encodeURIComponent(item)}`);\r\n }\r\n } else if (value !== undefined && value !== null) {\r\n pairs.push(`${encodeURIComponent(key)}=${encodeURIComponent(value)}`);\r\n }\r\n }\r\n return pairs.join('&');\r\n }\r\n\r\n /**\r\n * \uCFFC\uB9AC \uD30C\uB77C\uBBF8\uD130 \uBCC0\uACBD \uAC10\uC9C0\r\n */\r\n hasQueryParamsChanged(newParams) {\r\n if (!this.currentQueryParams && !newParams) return false;\r\n if (!this.currentQueryParams || !newParams) return true;\r\n \r\n const oldKeys = Object.keys(this.currentQueryParams);\r\n const newKeys = Object.keys(newParams);\r\n \r\n if (oldKeys.length !== newKeys.length) return true;\r\n \r\n for (const key of oldKeys) {\r\n if (JSON.stringify(this.currentQueryParams[key]) !== JSON.stringify(newParams[key])) {\r\n return true;\r\n }\r\n }\r\n return false;\r\n }\r\n\r\n /**\r\n * \uD604\uC7AC \uCFFC\uB9AC \uD30C\uB77C\uBBF8\uD130 \uC804\uCCB4 \uAC00\uC838\uC624\uAE30\r\n */\r\n getQueryParams() {\r\n return { ...this.currentQueryParams };\r\n }\r\n\r\n /**\r\n * \uD2B9\uC815 \uCFFC\uB9AC \uD30C\uB77C\uBBF8\uD130 \uAC00\uC838\uC624\uAE30\r\n */\r\n getQueryParam(key) {\r\n return this.currentQueryParams ? this.currentQueryParams[key] : undefined;\r\n }\r\n\r\n /**\r\n * \uCFFC\uB9AC \uD30C\uB77C\uBBF8\uD130 \uC124\uC815\r\n */\r\n setQueryParams(params, replace = false) {\r\n if (!params || typeof params !== 'object') {\r\n console.warn('Invalid parameters object provided to setQueryParams');\r\n return;\r\n }\r\n \r\n const currentParams = replace ? {} : { ...this.currentQueryParams };\r\n const sanitizedParams = {};\r\n \r\n // \uD30C\uB77C\uBBF8\uD130 \uAC80\uC99D \uBC0F sanitize\r\n for (const [key, value] of Object.entries(params)) {\r\n // \uD0A4\uC640 \uAC12 \uAC80\uC99D\r\n if (!this.validateParameter(key, value)) {\r\n console.warn(`Parameter ${key} rejected by security filter`);\r\n continue;\r\n }\r\n \r\n // \uAC12 \uCC98\uB9AC\r\n if (value !== undefined && value !== null) {\r\n if (Array.isArray(value)) {\r\n sanitizedParams[key] = value.map(item => this.sanitizeParameter(item));\r\n } else {\r\n sanitizedParams[key] = this.sanitizeParameter(value);\r\n }\r\n }\r\n }\r\n \r\n // \uD604\uC7AC \uD30C\uB77C\uBBF8\uD130 \uC5C5\uB370\uC774\uD2B8\r\n Object.assign(currentParams, sanitizedParams);\r\n \r\n // undefined\uB098 null \uAC12 \uC81C\uAC70\r\n for (const [key, value] of Object.entries(currentParams)) {\r\n if (value === undefined || value === null || value === '') {\r\n delete currentParams[key];\r\n }\r\n }\r\n \r\n // \uCD5C\uB300 \uD30C\uB77C\uBBF8\uD130 \uAC1C\uC218 \uD655\uC778\r\n const paramCount = Object.keys(currentParams).length;\r\n if (paramCount > this.config.maxParameterCount) {\r\n if (this.config.logSecurityWarnings) {\r\n console.warn(`Too many parameters after update (${paramCount}). Some parameters may be dropped.`);\r\n }\r\n }\r\n \r\n this.currentQueryParams = currentParams;\r\n this.updateURL();\r\n }\r\n\r\n /**\r\n * \uCFFC\uB9AC \uD30C\uB77C\uBBF8\uD130 \uC81C\uAC70\r\n */\r\n removeQueryParams(keys) {\r\n if (!keys) return;\r\n \r\n const keysToRemove = Array.isArray(keys) ? keys : [keys];\r\n for (const key of keysToRemove) {\r\n delete this.currentQueryParams[key];\r\n }\r\n \r\n this.updateURL();\r\n }\r\n\r\n /**\r\n * \uCFFC\uB9AC \uD30C\uB77C\uBBF8\uD130 \uCD08\uAE30\uD654\r\n */\r\n clearQueryParams() {\r\n this.currentQueryParams = {};\r\n this.updateURL();\r\n }\r\n\r\n /**\r\n * \uD604\uC7AC \uCFFC\uB9AC \uD30C\uB77C\uBBF8\uD130 \uC124\uC815 (\uB77C\uC6B0\uD130\uC5D0\uC11C \uD638\uCD9C)\r\n */\r\n setCurrentQueryParams(params) {\r\n this.currentQueryParams = params || {};\r\n }\r\n\r\n /**\r\n * URL \uC5C5\uB370\uC774\uD2B8 (\uB77C\uC6B0\uD130\uC758 updateURL \uBA54\uC18C\uB4DC \uD638\uCD9C)\r\n */\r\n updateURL() {\r\n if (this.router && typeof this.router.updateURL === 'function') {\r\n const route = this.router.currentHash || 'home';\r\n this.router.updateURL(route, this.currentQueryParams);\r\n }\r\n }\r\n\r\n /**\r\n * \uCFFC\uB9AC \uD30C\uB77C\uBBF8\uD130 \uD1B5\uACC4\r\n */\r\n getStats() {\r\n return {\r\n currentParams: Object.keys(this.currentQueryParams).length,\r\n maxAllowed: this.config.maxParameterCount,\r\n validationEnabled: this.config.enableParameterValidation,\r\n currentQueryString: this.buildQueryString(this.currentQueryParams)\r\n };\r\n }\r\n\r\n /**\r\n * \uC815\uB9AC (\uBA54\uBAA8\uB9AC \uB204\uC218 \uBC29\uC9C0)\r\n */\r\n destroy() {\r\n this.currentQueryParams = {};\r\n this.router = null;\r\n this.log('debug', 'QueryManager destroyed');\r\n }\r\n}", "/**\r\n * ViewLogic Route Loading System\r\n * \uB77C\uC6B0\uD2B8 \uB85C\uB529 \uBC0F \uCEF4\uD3EC\uB10C\uD2B8 \uAD00\uB9AC \uC2DC\uC2A4\uD15C\r\n */\r\nexport class RouteLoader {\r\n constructor(router, options = {}) {\r\n this.config = {\r\n basePath: options.basePath || '/src',\r\n routesPath: options.routesPath || '/routes',\r\n environment: options.environment || 'development',\r\n useLayout: options.useLayout !== false,\r\n defaultLayout: options.defaultLayout || 'default',\r\n useComponents: options.useComponents !== false,\r\n debug: options.debug || false\r\n };\r\n \r\n // \uB77C\uC6B0\uD130 \uC778\uC2A4\uD134\uC2A4 \uCC38\uC870\r\n this.router = router;\r\n this.log('debug', 'RouteLoader initialized with config:', this.config);\r\n }\r\n\r\n /**\r\n * \uC2A4\uD06C\uB9BD\uD2B8 \uD30C\uC77C \uB85C\uB4DC\r\n */\r\n async loadScript(routeName) {\r\n let script;\r\n try {\r\n if (this.config.environment === 'production') {\r\n // \uD504\uB85C\uB355\uC158 \uBAA8\uB4DC: routes \uD3F4\uB354\uC5D0\uC11C \uBE4C\uB4DC\uB41C JS \uB85C\uB4DC (\uC808\uB300 \uACBD\uB85C)\r\n const importPath = `${this.config.routesPath}/${routeName}.js`;\r\n this.log('debug', `Loading production route: ${importPath}`);\r\n const module = await import(importPath);\r\n script = module.default;\r\n } else {\r\n // \uAC1C\uBC1C \uBAA8\uB4DC: src \uD3F4\uB354\uC5D0\uC11C \uB85C\uB4DC (\uC808\uB300 \uACBD\uB85C)\r\n const importPath = `${this.config.basePath}/logic/${routeName}.js`;\r\n this.log('debug', `Loading development route: ${importPath}`);\r\n const module = await import(importPath);\r\n script = module.default;\r\n }\r\n \r\n if (!script) {\r\n throw new Error(`Route '${routeName}' not found - no default export`);\r\n }\r\n \r\n } catch (error) {\r\n // import \uC5D0\uB7EC\uB97C 404\uB85C \uBD84\uB958\r\n if (error.message.includes('Failed to resolve') || \r\n error.message.includes('Failed to fetch') ||\r\n error.message.includes('not found') ||\r\n error.name === 'TypeError') {\r\n throw new Error(`Route '${routeName}' not found - 404`);\r\n }\r\n // \uB2E4\uB978 \uC5D0\uB7EC\uB294 \uADF8\uB300\uB85C \uC804\uD30C\r\n throw error;\r\n }\r\n \r\n return script;\r\n }\r\n\r\n /**\r\n * \uD15C\uD50C\uB9BF \uD30C\uC77C \uB85C\uB4DC (\uC2E4\uD328\uC2DC \uAE30\uBCF8\uAC12 \uBC18\uD658)\r\n */\r\n async loadTemplate(routeName) {\r\n try {\r\n const response = await fetch(`${this.config.basePath}/views/${routeName}.html`);\r\n if (!response.ok) throw new Error(`Template not found: ${response.status}`);\r\n const template = await response.text();\r\n this.log('debug', `Template '${routeName}' loaded successfully`);\r\n return template;\r\n } catch (error) {\r\n this.log('warn', `Template '${routeName}' not found, using default:`, error.message);\r\n // \uAE30\uBCF8 \uD15C\uD50C\uB9BF \uBC18\uD658\r\n return this.generateDefaultTemplate(routeName);\r\n }\r\n }\r\n\r\n /**\r\n * \uC2A4\uD0C0\uC77C \uD30C\uC77C \uB85C\uB4DC (\uC2E4\uD328\uC2DC \uBE48 \uBB38\uC790\uC5F4 \uBC18\uD658)\r\n */\r\n async loadStyle(routeName) {\r\n try {\r\n const response = await fetch(`${this.config.basePath}/styles/${routeName}.css`);\r\n if (!response.ok) throw new Error(`Style not found: ${response.status}`);\r\n const style = await response.text();\r\n this.log('debug', `Style '${routeName}' loaded successfully`);\r\n return style;\r\n } catch (error) {\r\n this.log('debug', `Style '${routeName}' not found, no styles applied:`, error.message);\r\n // \uC2A4\uD0C0\uC77C\uC774 \uC5C6\uC73C\uBA74 \uBE48 \uBB38\uC790\uC5F4 \uBC18\uD658\r\n return '';\r\n }\r\n }\r\n\r\n /**\r\n * \uB808\uC774\uC544\uC6C3 \uD30C\uC77C \uB85C\uB4DC (\uC2E4\uD328\uC2DC null \uBC18\uD658)\r\n */\r\n async loadLayout(layoutName) {\r\n try {\r\n const response = await fetch(`${this.config.basePath}/layouts/${layoutName}.html`);\r\n if (!response.ok) throw new Error(`Layout not found: ${response.status}`);\r\n const layout = await response.text();\r\n \r\n this.log('debug', `Layout '${layoutName}' loaded successfully`);\r\n return layout;\r\n } catch (error) {\r\n this.log('debug', `Layout '${layoutName}' not found, no layout applied:`, error.message);\r\n return null;\r\n }\r\n }\r\n\r\n /**\r\n * \uB808\uC774\uC544\uC6C3\uACFC \uD15C\uD50C\uB9BF \uBCD1\uD569\r\n */\r\n mergeLayoutWithTemplate(routeName, layout, template) {\r\n let result;\r\n // \uB808\uC774\uC544\uC6C3\uC5D0\uC11C <slot name=\"content\"> \uBD80\uBD84\uC744 \uD15C\uD50C\uB9BF\uC73C\uB85C \uAD50\uCCB4\r\n if (layout.includes('{{ content }}')) {\r\n result = layout.replace(\r\n /{{ content }}/s,\r\n template\r\n );\r\n }\r\n // slot\uC774 \uC5C6\uC73C\uBA74 main-content \uD074\uB798\uC2A4 \uB0B4\uC6A9 \uAD50\uCCB4\r\n else if (layout.includes('class=\"main-content\"')) {\r\n this.log('debug', 'Using main-content replacement');\r\n result = layout.replace(\r\n /(<div class=\"container\">).*?(<\\/div>\\s*<\\/main>)/s,\r\n `$1${template}$2`\r\n );\r\n }\r\n // \uB9C8\uC9C0\uB9C9 \uB300\uC548: \uC804\uCCB4 \uB808\uC774\uC544\uC6C3\uC744 \uD15C\uD50C\uB9BF\uC73C\uB85C \uAC10\uC2F8\uAE30\r\n else {\r\n this.log('debug', 'Wrapping template with layout');\r\n result = `${layout}\\n${template}`;\r\n }\r\n \r\n return result;\r\n }\r\n\r\n\r\n /**\r\n * Vue \uCEF4\uD3EC\uB10C\uD2B8 \uC0DD\uC131\r\n */\r\n async createVueComponent(routeName) {\r\n // \uCE90\uC2DC\uB41C Vue \uCEF4\uD3EC\uB10C\uD2B8\uAC00 \uC788\uB294\uC9C0 \uD655\uC778\r\n const cacheKey = `component_${routeName}`;\r\n const cached = this.router.cacheManager?.getFromCache(cacheKey);\r\n if (cached) {\r\n return cached;\r\n }\r\n \r\n const script = await this.loadScript(routeName);\r\n const router = this.router;\r\n const isProduction = this.config.environment === 'production';\r\n \r\n // \uD658\uACBD\uBCC4 \uB9AC\uC18C\uC2A4 \uB85C\uB529\r\n let template, style = '', layout = null;\r\n \r\n if (isProduction) {\r\n // \uD504\uB85C\uB355\uC158: \uC2A4\uD06C\uB9BD\uD2B8\uC5D0 \uC788\uB294 \uD15C\uD50C\uB9BF \uC0AC\uC6A9 \uB610\uB294 \uAE30\uBCF8\uAC12\r\n template = script.template || this.generateDefaultTemplate(routeName);\r\n } else {\r\n // \uAC1C\uBC1C: \uAC1C\uBCC4 \uD30C\uC77C\uB4E4 \uB85C\uB4DC\r\n template = await this.loadTemplate(routeName);\r\n style = await this.loadStyle(routeName);\r\n layout = this.config.useLayout && script.layout !== null ? \r\n await this.loadLayout(script.layout || this.config.defaultLayout) : null;\r\n \r\n // \uB808\uC774\uC544\uC6C3\uACFC \uD15C\uD50C\uB9BF \uBCD1\uD569\r\n if (layout) {\r\n template = this.mergeLayoutWithTemplate(routeName, layout, template);\r\n }\r\n }\r\n \r\n // \uB2E8\uC77C \uCEF4\uD3EC\uB10C\uD2B8 \uC0DD\uC131\r\n const component = {\r\n ...script,\r\n name: script.name || this.toPascalCase(routeName),\r\n template,\r\n components: this.config.useComponents && router.componentLoader ? \r\n await router.componentLoader.loadAllComponents() : {},\r\n data() {\r\n const originalData = script.data ? script.data() : {};\r\n const commonData = {\r\n ...originalData,\r\n currentRoute: routeName,\r\n pageTitle: script.pageTitle || router.routeLoader.generatePageTitle(routeName),\r\n showHeader: script.showHeader !== false,\r\n headerTitle: script.headerTitle || router.routeLoader.generatePageTitle(routeName),\r\n headerSubtitle: script.headerSubtitle,\r\n $query: router.queryManager?.getQueryParams() || {},\r\n $lang: router.i18nManager?.getCurrentLanguage() || router.config.i18nDefaultLanguage,\r\n $dataLoading: false\r\n };\r\n \r\n return commonData;\r\n },\r\n computed: {\r\n ...(script.computed || {}),\r\n params() {\r\n return router.queryManager?.getQueryParams() || {};\r\n }\r\n },\r\n async mounted() {\r\n if (script.mounted) {\r\n await script.mounted.call(this);\r\n }\r\n if (script.dataURL) {\r\n await this.$fetchData();\r\n }\r\n },\r\n methods: {\r\n ...script.methods,\r\n // \uB77C\uC6B0\uD305 \uAD00\uB828\r\n navigateTo: (route, params) => router.navigateTo(route, params),\r\n getCurrentRoute: () => router.getCurrentRoute(),\r\n getQueryParams: () => router.queryManager?.getQueryParams() || {},\r\n getQueryParam: (key) => router.queryManager?.getQueryParam(key),\r\n setQueryParams: (params, replace) => router.queryManager?.setQueryParams(params, replace),\r\n removeQueryParams: (keys) => router.queryManager?.removeQueryParams(keys),\r\n // i18n \uAD00\uB828\r\n $t: (key, params) => router.i18nManager?.t(key, params) || key,\r\n $i18n: () => router.i18nManager || null,\r\n // \uC778\uC99D \uAD00\uB828\r\n $isAuthenticated: () => router.authManager?.isUserAuthenticated() || false,\r\n $logout: () => router.authManager ? router.navigateTo(router.authManager.handleLogout()) : null,\r\n $loginSuccess: (target) => router.authManager ? router.navigateTo(router.authManager.handleLoginSuccess(target)) : null,\r\n $checkAuth: (route) => router.authManager ? router.authManager.checkAuthentication(route) : Promise.resolve({ allowed: true, reason: 'auth_disabled' }),\r\n $getToken: () => router.authManager?.getAccessToken() || null,\r\n $setToken: (token, options) => router.authManager?.setAccessToken(token, options) || false,\r\n $removeToken: (storage) => router.authManager?.removeAccessToken(storage) || null,\r\n $getAuthCookie: () => router.authManager?.getAuthCookie() || null,\r\n $getCookie: (name) => router.authManager?.getCookieValue(name) || null,\r\n // \uB370\uC774\uD130 fetch\r\n async $fetchData() {\r\n if (!script.dataURL) return;\r\n \r\n this.$dataLoading = true;\r\n try {\r\n const data = await router.routeLoader.fetchComponentData(script.dataURL);\r\n if (router.errorHandler) router.errorHandler.debug('RouteLoader', `Data fetched for ${routeName}:`, data);\r\n Object.assign(this, data);\r\n this.$emit('data-loaded', data);\r\n } catch (error) {\r\n if (router.errorHandler) router.errorHandler.warn('RouteLoader', `Failed to fetch data for ${routeName}:`, error);\r\n this.$emit('data-error', error);\r\n } finally {\r\n this.$dataLoading = false;\r\n }\r\n }\r\n },\r\n _routeName: routeName\r\n };\r\n \r\n // \uAC1C\uBC1C \uBAA8\uB4DC\uC5D0\uC11C\uB9CC \uC2A4\uD0C0\uC77C \uBA54\uD0C0\uB370\uC774\uD130 \uC800\uC7A5 (\uB80C\uB354\uB9C1 \uC2DC \uC8FC\uC785\uC6A9)\r\n if (!isProduction && style) {\r\n component._style = style;\r\n }\r\n \r\n // \uCE90\uC2DC\uC5D0 \uC800\uC7A5\r\n this.router.cacheManager?.setCache(cacheKey, component);\r\n \r\n return component;\r\n }\r\n\r\n /**\r\n * \uBB38\uC790\uC5F4\uC744 PascalCase\uB85C \uBCC0\uD658\r\n */\r\n toPascalCase(str) {\r\n return str\r\n .split(/[-_\\s]+/) // \uD558\uC774\uD508, \uC5B8\uB354\uC2A4\uCF54\uC5B4, \uACF5\uBC31\uC73C\uB85C \uBD84\uB9AC\r\n .map(word => word.charAt(0).toUpperCase() + word.slice(1).toLowerCase())\r\n .join('');\r\n }\r\n\r\n /**\r\n * \uAE30\uBCF8 \uD15C\uD50C\uB9BF \uC0DD\uC131\r\n */\r\n generateDefaultTemplate(routeName) {\r\n return `<div class=\"route-${routeName}\"><h1>Route: ${routeName}</h1></div>`;\r\n }\r\n\r\n /**\r\n * \uCEF4\uD3EC\uB10C\uD2B8 \uB370\uC774\uD130 \uAC00\uC838\uC624\uAE30\r\n */\r\n async fetchComponentData(dataURL) {\r\n try {\r\n // \uD604\uC7AC \uCFFC\uB9AC \uD30C\uB77C\uBBF8\uD130\uB97C URL\uC5D0 \uCD94\uAC00\r\n const queryString = this.router.queryManager?.buildQueryString(this.router.queryManager?.getQueryParams()) || '';\r\n const fullURL = queryString ? `${dataURL}?${queryString}` : dataURL;\r\n \r\n this.log('debug', `Fetching data from: ${fullURL}`);\r\n \r\n const response = await fetch(fullURL, {\r\n method: 'GET',\r\n headers: {\r\n 'Content-Type': 'application/json',\r\n 'Accept': 'application/json'\r\n }\r\n });\r\n \r\n if (!response.ok) {\r\n throw new Error(`HTTP error! status: ${response.status}`);\r\n }\r\n \r\n const data = await response.json();\r\n \r\n // \uB370\uC774\uD130 \uC720\uD6A8\uC131 \uAC80\uC0AC\r\n if (typeof data !== 'object' || data === null) {\r\n throw new Error('Invalid data format: expected object');\r\n }\r\n \r\n return data;\r\n \r\n } catch (error) {\r\n this.log('error', 'Failed to fetch component data:', error);\r\n throw error;\r\n }\r\n }\r\n\r\n /**\r\n * \uCE90\uC2DC \uBB34\uD6A8\uD654\r\n */\r\n invalidateCache(routeName) {\r\n if (this.router.cacheManager) {\r\n this.router.cacheManager.invalidateComponentCache(routeName);\r\n }\r\n this.log('debug', `Cache invalidated for route: ${routeName}`);\r\n }\r\n\r\n /**\r\n * \uD1B5\uACC4 \uC815\uBCF4 \uBC18\uD658\r\n */\r\n getStats() {\r\n return {\r\n environment: this.config.environment,\r\n basePath: this.config.basePath,\r\n routesPath: this.config.routesPath,\r\n useLayout: this.config.useLayout,\r\n useComponents: this.config.useComponents\r\n };\r\n }\r\n\r\n /**\r\n * \uD398\uC774\uC9C0 \uC81C\uBAA9 \uC0DD\uC131\r\n */\r\n generatePageTitle(routeName) {\r\n return this.toPascalCase(routeName).replace(/([A-Z])/g, ' $1').trim();\r\n }\r\n\r\n /**\r\n * \uB85C\uAE45 \uB798\uD37C \uBA54\uC11C\uB4DC\r\n */\r\n log(level, ...args) {\r\n if (this.router?.errorHandler) {\r\n this.router.errorHandler.log(level, 'RouteLoader', ...args);\r\n }\r\n }\r\n\r\n /**\r\n * \uC815\uB9AC (\uBA54\uBAA8\uB9AC \uB204\uC218 \uBC29\uC9C0)\r\n */\r\n destroy() {\r\n this.log('debug', 'RouteLoader destroyed');\r\n this.router = null;\r\n }\r\n}", "/**\r\n * ViewLogic Error Handling System\r\n * \uB77C\uC6B0\uD2B8 \uBC0F \uC2DC\uC2A4\uD15C \uC5D0\uB7EC \uCC98\uB9AC \uC2DC\uC2A4\uD15C\r\n */\r\nexport class ErrorHandler {\r\n constructor(router, options = {}) {\r\n this.config = {\r\n enableErrorReporting: options.enableErrorReporting !== false,\r\n debug: options.debug || false,\r\n logLevel: options.logLevel || (options.debug ? 'debug' : 'info'),\r\n environment: options.environment || 'development'\r\n };\r\n \r\n // \uB77C\uC6B0\uD130 \uC778\uC2A4\uD134\uC2A4 \uCC38\uC870\r\n this.router = router;\r\n \r\n // \uB85C\uADF8 \uB808\uBCA8 \uB9E4\uD551\r\n this.logLevels = {\r\n error: 0,\r\n warn: 1, \r\n info: 2,\r\n debug: 3\r\n };\r\n \r\n this.log('info', 'ErrorHandler', 'ErrorHandler initialized with config:', this.config);\r\n }\r\n\r\n /**\r\n * \uB77C\uC6B0\uD2B8 \uC5D0\uB7EC \uCC98\uB9AC\r\n */\r\n async handleRouteError(routeName, error) {\r\n let errorCode = 500;\r\n let errorMessage = '\uD398\uC774\uC9C0\uB97C \uB85C\uB4DC\uD560 \uC218 \uC5C6\uC2B5\uB2C8\uB2E4.';\r\n \r\n this.debug('ErrorHandler', '\uC5D0\uB7EC \uC0C1\uC138:', error.message, error.name);\r\n \r\n // \uC5D0\uB7EC \uD0C0\uC785 \uBD84\uC11D (\uB354 \uC815\uD655\uD55C 404 \uAC10\uC9C0)\r\n if (error.message.includes('not found') || \r\n error.message.includes('404') ||\r\n error.message.includes('Failed to resolve') ||\r\n error.message.includes('Failed to fetch') ||\r\n (error.name === 'TypeError' && error.message.includes('resolve'))) {\r\n errorCode = 404;\r\n errorMessage = `'${routeName}' \uD398\uC774\uC9C0\uB97C \uCC3E\uC744 \uC218 \uC5C6\uC2B5\uB2C8\uB2E4.`;\r\n } else if (error.message.includes('network') && !error.message.includes('not found')) {\r\n errorCode = 503;\r\n errorMessage = '\uB124\uD2B8\uC6CC\uD06C \uC5F0\uACB0\uC744 \uD655\uC778\uD574 \uC8FC\uC138\uC694.';\r\n } else if (error.message.includes('permission') || error.message.includes('403')) {\r\n errorCode = 403;\r\n errorMessage = '\uD398\uC774\uC9C0\uC5D0 \uC811\uADFC\uD560 \uAD8C\uD55C\uC774 \uC5C6\uC2B5\uB2C8\uB2E4.';\r\n }\r\n \r\n this.debug('ErrorHandler', `\uC5D0\uB7EC \uCF54\uB4DC \uACB0\uC815: ${errorCode} (\uB77C\uC6B0\uD2B8: ${routeName})`);\r\n \r\n // \uC5D0\uB7EC \uB9AC\uD3EC\uD305\r\n if (this.config.enableErrorReporting) {\r\n this.reportError(routeName, error, errorCode);\r\n }\r\n \r\n try {\r\n // 404 \uD398\uC774\uC9C0 \uC804\uC6A9 \uCC98\uB9AC\r\n if (errorCode === 404) {\r\n await this.load404Page();\r\n } else {\r\n // \uC77C\uBC18 \uC5D0\uB7EC \uD398\uC774\uC9C0\r\n await this.loadErrorPage(errorCode, errorMessage);\r\n }\r\n } catch (fallbackError) {\r\n this.error('ErrorHandler', '\uC5D0\uB7EC \uD398\uC774\uC9C0 \uB85C\uB529 \uC2E4\uD328:', fallbackError);\r\n // \uBAA8\uB4E0 \uC5D0\uB7EC \uD398\uC774\uC9C0\uAC00 \uC2E4\uD328\uD588\uC744 \uB54C \uCD5C\uD6C4\uC758 \uD3F4\uBC31 \uD398\uC774\uC9C0 \uD45C\uC2DC\r\n this.showFallbackErrorPage(errorCode, errorMessage);\r\n }\r\n }\r\n\r\n /**\r\n * 404 \uD398\uC774\uC9C0 \uB85C\uB529\r\n */\r\n async load404Page() {\r\n try {\r\n this.info('ErrorHandler', 'Loading 404 page...');\r\n const component = await this.createVueComponent('404');\r\n await this.renderComponentWithTransition(component, '404');\r\n this.info('ErrorHandler', '404 page loaded successfully');\r\n } catch (error) {\r\n this.error('ErrorHandler', '404 page loading failed:', error);\r\n // 404 \uD398\uC774\uC9C0\uB3C4 \uC5C6\uC73C\uBA74 \uAC04\uB2E8\uD55C \uC5D0\uB7EC \uBA54\uC2DC\uC9C0 \uD45C\uC2DC\r\n this.showFallbackErrorPage('404', '\uD398\uC774\uC9C0\uB97C \uCC3E\uC744 \uC218 \uC5C6\uC2B5\uB2C8\uB2E4.');\r\n }\r\n }\r\n\r\n /**\r\n * \uC5D0\uB7EC \uD398\uC774\uC9C0 \uB85C\uB529\r\n */\r\n async loadErrorPage(errorCode, errorMessage) {\r\n try {\r\n this.info('ErrorHandler', `Loading error page for ${errorCode}...`);\r\n \r\n // \uC5D0\uB7EC \uCEF4\uD3EC\uB10C\uD2B8 \uC0DD\uC131\r\n const errorComponent = await this.createErrorComponent(errorCode, errorMessage);\r\n await this.renderComponentWithTransition(errorComponent, 'error');\r\n this.info('ErrorHandler', `Error page ${errorCode} loaded successfully`);\r\n } catch (error) {\r\n this.error('ErrorHandler', `Error page ${errorCode} loading failed:`, error);\r\n // \uC5D0\uB7EC \uD398\uC774\uC9C0\uB3C4 \uB85C\uB529 \uC2E4\uD328\uD558\uBA74 \uD3F4\uBC31 \uD45C\uC2DC\r\n this.showFallbackErrorPage(errorCode, errorMessage);\r\n }\r\n }\r\n\r\n /**\r\n * \uC5D0\uB7EC \uCEF4\uD3EC\uB10C\uD2B8 \uC0DD\uC131\r\n */\r\n async createErrorComponent(errorCode, errorMessage) {\r\n try {\r\n // \uC5D0\uB7EC \uCEF4\uD3EC\uB10C\uD2B8\uB97C \uB3D9\uC801\uC73C\uB85C \uB85C\uB4DC\r\n const component = await this.createVueComponent('error');\r\n \r\n // \uC5D0\uB7EC \uC815\uBCF4\uB97C props\uB85C \uC804\uB2EC\r\n const errorComponent = {\r\n ...component,\r\n data() {\r\n const originalData = component.data ? component.data() : {};\r\n return {\r\n ...originalData,\r\n errorCode,\r\n errorMessage,\r\n showRetry: true,\r\n showGoHome: true\r\n };\r\n }\r\n };\r\n \r\n return errorComponent;\r\n } catch (error) {\r\n // \uC5D0\uB7EC \uCEF4\uD3EC\uB10C\uD2B8\uB3C4 \uB85C\uB4DC\uD560 \uC218 \uC5C6\uB294 \uACBD\uC6B0 \uAC04\uB2E8\uD55C \uC5D0\uB7EC \uD45C\uC2DC\r\n this.error('ErrorHandler', 'Error component load failed:', error);\r\n throw new Error(`Cannot load error page: ${error.message}`);\r\n }\r\n }\r\n\r\n /**\r\n * \uD3F4\uBC31 \uC5D0\uB7EC \uD398\uC774\uC9C0 \uD45C\uC2DC (\uBAA8\uB4E0 \uC5D0\uB7EC \uD398\uC774\uC9C0\uAC00 \uC2E4\uD328\uD588\uC744 \uB54C)\r\n */\r\n showFallbackErrorPage(errorCode, errorMessage) {\r\n const appElement = document.getElementById('app');\r\n if (!appElement) return;\r\n\r\n const fallbackHTML = `\r\n <div class=\"fallback-error-page\" style=\"\r\n display: flex;\r\n flex-direction: column;\r\n align-items: center;\r\n justify-content: center;\r\n min-height: 100vh;\r\n padding: 2rem;\r\n text-align: center;\r\n background: #f8f9fa;\r\n font-family: -apple-system, BlinkMacSystemFont, 'Segoe UI', Roboto, sans-serif;\r\n \">\r\n <div style=\"\r\n background: white;\r\n padding: 3rem;\r\n border-radius: 12px;\r\n box-shadow: 0 4px 20px rgba(0,0,0,0.1);\r\n max-width: 500px;\r\n \">\r\n <h1 style=\"\r\n font-size: 4rem;\r\n margin: 0;\r\n color: #dc3545;\r\n font-weight: 300;\r\n \">${errorCode}</h1>\r\n <h2 style=\"\r\n margin: 1rem 0;\r\n color: #495057;\r\n font-weight: 400;\r\n \">${errorMessage}</h2>\r\n <p style=\"\r\n color: #6c757d;\r\n margin-bottom: 2rem;\r\n line-height: 1.5;\r\n \">\uC694\uCCAD\uD558\uC2E0 \uD398\uC774\uC9C0\uB97C \uCC3E\uC744 \uC218 \uC5C6\uC2B5\uB2C8\uB2E4.</p>\r\n <button onclick=\"window.location.hash = '#/'\" style=\"\r\n background: #007bff;\r\n color: white;\r\n border: none;\r\n padding: 12px 24px;\r\n border-radius: 6px;\r\n cursor: pointer;\r\n font-size: 1rem;\r\n transition: background 0.2s;\r\n \" onmouseover=\"this.style.background='#0056b3'\" onmouseout=\"this.style.background='#007bff'\">\r\n \uD648\uC73C\uB85C \uB3CC\uC544\uAC00\uAE30\r\n </button>\r\n </div>\r\n </div>\r\n `;\r\n\r\n // \uAE30\uC874 \uCEE8\uD14C\uC774\uB108\uB4E4 \uC815\uB9AC\r\n appElement.innerHTML = fallbackHTML;\r\n \r\n this.info('ErrorHandler', `Fallback error page displayed for ${errorCode}`);\r\n }\r\n\r\n /**\r\n * \uC5D0\uB7EC \uB9AC\uD3EC\uD305\r\n */\r\n reportError(routeName, error, errorCode) {\r\n const errorReport = {\r\n route: routeName,\r\n errorCode,\r\n errorMessage: error.message,\r\n stack: error.stack,\r\n url: window.location.href,\r\n userAgent: navigator.userAgent,\r\n timestamp: new Date().toISOString(),\r\n routerConfig: {\r\n environment: this.router.config.environment,\r\n mode: this.router.config.mode\r\n }\r\n };\r\n \r\n this.error('ErrorHandler', '\uB77C\uC6B0\uD130 \uC5D0\uB7EC \uB9AC\uD3EC\uD2B8:', errorReport);\r\n \r\n // \uCD94\uD6C4 \uC5D0\uB7EC \uCD94\uC801 \uC11C\uBE44\uC2A4\uB85C \uC804\uC1A1\uD560 \uC218 \uC788\uC74C\r\n // \uC608: analytics.track('router_error', errorReport);\r\n }\r\n\r\n /**\r\n * Vue \uCEF4\uD3EC\uB10C\uD2B8 \uC0DD\uC131 (RouteLoader \uC704\uC784)\r\n */\r\n async createVueComponent(routeName) {\r\n if (this.router.routeLoader) {\r\n return await this.router.routeLoader.createVueComponent(routeName);\r\n }\r\n throw new Error('RouteLoader not available');\r\n }\r\n\r\n /**\r\n * \uCEF4\uD3EC\uB10C\uD2B8 \uB80C\uB354\uB9C1 (ViewManager \uC704\uC784)\r\n */\r\n async renderComponentWithTransition(component, routeName) {\r\n if (this.router.renderComponentWithTransition) {\r\n return await this.router.renderComponentWithTransition(component, routeName);\r\n }\r\n throw new Error('Render function not available');\r\n }\r\n\r\n /**\r\n * \uD1B5\uD569 \uB85C\uAE45 \uC2DC\uC2A4\uD15C\r\n * @param {string} level - \uB85C\uADF8 \uB808\uBCA8 (error, warn, info, debug)\r\n * @param {string} component - \uCEF4\uD3EC\uB10C\uD2B8 \uC774\uB984 (\uC120\uD0DD\uC801)\r\n * @param {...any} args - \uB85C\uADF8 \uBA54\uC2DC\uC9C0\r\n */\r\n log(level, component, ...args) {\r\n // \uD558\uC704 \uD638\uD658\uC131: \uAE30\uC874 \uBC29\uC2DD\uB3C4 \uC9C0\uC6D0\r\n if (typeof level !== 'string' || !this.logLevels.hasOwnProperty(level)) {\r\n args = [component, ...args];\r\n component = level;\r\n level = this.config.debug ? 'debug' : 'info';\r\n }\r\n \r\n // \uB85C\uADF8 \uB808\uBCA8 \uD655\uC778\r\n const currentLevelValue = this.logLevels[this.config.logLevel] || this.logLevels.info;\r\n const messageLevelValue = this.logLevels[level] || this.logLevels.info;\r\n \r\n if (messageLevelValue > currentLevelValue) {\r\n return; // \uD604\uC7AC \uC124\uC815\uB41C \uB808\uBCA8\uBCF4\uB2E4 \uB192\uC73C\uBA74 \uCD9C\uB825 \uC548\uD568\r\n }\r\n \r\n // \uD504\uB85C\uB355\uC158 \uD658\uACBD\uC5D0\uC11C\uB294 error\uC640 warn\uB9CC \uCD9C\uB825\r\n if (this.config.environment === 'production' && messageLevelValue > this.logLevels.warn) {\r\n return;\r\n }\r\n \r\n const prefix = component ? `[${component}]` : '[ViewLogic]';\r\n const timestamp = new Date().toISOString().substring(11, 23); // HH:MM:SS.mmm\r\n \r\n switch (level) {\r\n case 'error':\r\n console.error(`${timestamp} ${prefix}`, ...args);\r\n break;\r\n case 'warn':\r\n console.warn(`${timestamp} ${prefix}`, ...args);\r\n break;\r\n case 'info':\r\n console.info(`${timestamp} ${prefix}`, ...args);\r\n break;\r\n case 'debug':\r\n console.log(`${timestamp} ${prefix}`, ...args);\r\n break;\r\n default:\r\n console.log(`${timestamp} ${prefix}`, ...args);\r\n }\r\n }\r\n \r\n /**\r\n * \uC5D0\uB7EC \uB85C\uADF8 (\uD56D\uC0C1 \uCD9C\uB825)\r\n */\r\n error(component, ...args) {\r\n this.log('error', component, ...args);\r\n }\r\n \r\n /**\r\n * \uACBD\uACE0 \uB85C\uADF8\r\n */\r\n warn(component, ...args) {\r\n this.log('warn', component, ...args);\r\n }\r\n \r\n /**\r\n * \uC815\uBCF4 \uB85C\uADF8\r\n */\r\n info(component, ...args) {\r\n this.log('info', component, ...args);\r\n }\r\n \r\n /**\r\n * \uB514\uBC84\uADF8 \uB85C\uADF8\r\n */\r\n debug(component, ...args) {\r\n this.log('debug', component, ...args);\r\n }\r\n\r\n /**\r\n * \uC815\uB9AC (\uBA54\uBAA8\uB9AC \uB204\uC218 \uBC29\uC9C0)\r\n */\r\n destroy() {\r\n this.router = null;\r\n this.info('ErrorHandler', 'ErrorHandler destroyed');\r\n }\r\n}", "/**\r\n * ComponentLoader\r\n * \uB3D9\uC801\uC73C\uB85C \uCEF4\uD3EC\uB10C\uD2B8\uB97C \uB85C\uB4DC\uD558\uACE0 \uB4F1\uB85D\uD558\uB294 \uC2DC\uC2A4\uD15C\r\n */\r\nexport class ComponentLoader {\r\n constructor(router = null, options = {}) {\r\n\r\n this.config = {\r\n basePath: options.basePath || '/src/components',\r\n debug: options.debug || false,\r\n environment: options.environment || 'development',\r\n ...options\r\n };\r\n \r\n this.router = router;\r\n this.loadingPromises = new Map();\r\n this.unifiedComponents = null;\r\n }\r\n \r\n /**\r\n * \uB85C\uAE45 \uB798\uD37C \uBA54\uC11C\uB4DC\r\n */\r\n log(level, ...args) {\r\n if (this.router?.errorHandler) {\r\n this.router.errorHandler.log(level, 'ComponentLoader', ...args);\r\n }\r\n }\r\n \r\n /**\r\n * \uCEF4\uD3EC\uB10C\uD2B8\uB97C \uBE44\uB3D9\uAE30\uB85C \uB85C\uB4DC\r\n */\r\n async loadComponent(componentName) {\r\n if (!componentName || typeof componentName !== 'string') {\r\n throw new Error('Component name must be a non-empty string');\r\n }\r\n \r\n // \uC774\uBBF8 \uB85C\uB529 \uC911\uC778 \uACBD\uC6B0 \uAE30\uC874 Promise \uBC18\uD658\r\n if (this.loadingPromises.has(componentName)) {\r\n return this.loadingPromises.get(componentName);\r\n }\r\n \r\n const loadPromise = this._loadComponentFromFile(componentName);\r\n this.loadingPromises.set(componentName, loadPromise);\r\n \r\n try {\r\n const component = await loadPromise;\r\n return component;\r\n } catch (error) {\r\n throw error;\r\n } finally {\r\n this.loadingPromises.delete(componentName);\r\n }\r\n }\r\n \r\n /**\r\n * \uD30C\uC77C\uC5D0\uC11C \uCEF4\uD3EC\uB10C\uD2B8 \uB85C\uB4DC\r\n */\r\n async _loadComponentFromFile(componentName) {\r\n const componentPath = `${this.config.basePath}/${componentName}.js`;\r\n \r\n try {\r\n const module = await import(componentPath);\r\n const component = module.default;\r\n \r\n if (!component) {\r\n throw new Error(`Component '${componentName}' has no default export`);\r\n }\r\n \r\n if (!component.name) {\r\n component.name = componentName;\r\n }\r\n \r\n this.log('debug', `Component '${componentName}' loaded successfully`);\r\n return component;\r\n \r\n } catch (error) {\r\n this.log('error', `Failed to load component '${componentName}':`, error);\r\n throw new Error(`Component '${componentName}' not found: ${error.message}`);\r\n }\r\n }\r\n \r\n /**\r\n * \uCEF4\uD3EC\uB10C\uD2B8 \uBAA8\uB4C8 \uD074\uB9AC\uC5B4\r\n */\r\n clearComponents() {\r\n this.loadingPromises.clear();\r\n this.unifiedComponents = null;\r\n this.log('debug', 'All components cleared');\r\n }\r\n \r\n /**\r\n * \uD658\uACBD\uC5D0 \uB530\uB978 \uBAA8\uB4E0 \uCEF4\uD3EC\uB10C\uD2B8 \uB85C\uB529 (\uCE90\uC2F1 \uC9C0\uC6D0)\r\n */\r\n async loadAllComponents() {\r\n // \uC774\uBBF8 \uB85C\uB4DC\uB41C unifiedComponents\uAC00 \uC788\uC73C\uBA74 \uBC18\uD658\r\n if (this.unifiedComponents) {\r\n this.log('debug', 'Using existing unified components');\r\n return this.unifiedComponents;\r\n }\r\n \r\n // \uC6B4\uC601 \uBAA8\uB4DC: \uD1B5\uD569 \uCEF4\uD3EC\uB10C\uD2B8 \uB85C\uB529 \uC2DC\uB3C4\r\n if (this.config.environment === 'production') {\r\n return await this._loadProductionComponents();\r\n }\r\n \r\n // \uAC1C\uBC1C \uBAA8\uB4DC: \uAC1C\uBCC4 \uCEF4\uD3EC\uB10C\uD2B8 \uB85C\uB529\r\n return await this._loadDevelopmentComponents();\r\n }\r\n \r\n /**\r\n * \uC6B4\uC601 \uBAA8\uB4DC: \uD1B5\uD569 \uCEF4\uD3EC\uB10C\uD2B8 \uB85C\uB529\r\n */\r\n async _loadProductionComponents() {\r\n try {\r\n const componentsPath = `${this.config.routesPath}/_components.js`;\r\n this.log('info', '[PRODUCTION] Loading unified components from:', componentsPath);\r\n \r\n const componentsModule = await import(componentsPath);\r\n \r\n if (typeof componentsModule.registerComponents === 'function') {\r\n this.unifiedComponents = componentsModule.components || {};\r\n this.log('info', `[PRODUCTION] Unified components loaded: ${Object.keys(this.unifiedComponents).length} components`);\r\n return this.unifiedComponents;\r\n } else {\r\n throw new Error('registerComponents function not found in components module');\r\n }\r\n } catch (error) {\r\n this.log('warn', '[PRODUCTION] Failed to load unified components:', error.message);\r\n this.unifiedComponents = {};\r\n return {};\r\n }\r\n }\r\n \r\n /**\r\n * \uAC1C\uBC1C \uBAA8\uB4DC: \uAC1C\uBCC4 \uCEF4\uD3EC\uB10C\uD2B8 \uB85C\uB529\r\n */\r\n async _loadDevelopmentComponents() {\r\n const componentNames = this._getComponentNames();\r\n const components = {};\r\n \r\n this.log('info', `[DEVELOPMENT] Loading individual components: ${componentNames.join(', ')}`);\r\n \r\n for (const name of componentNames) {\r\n try {\r\n const component = await this.loadComponent(name);\r\n if (component) {\r\n components[name] = component;\r\n }\r\n } catch (loadError) {\r\n this.log('warn', `[DEVELOPMENT] Failed to load component ${name}:`, loadError.message);\r\n }\r\n }\r\n \r\n this.unifiedComponents = components;\r\n this.log('info', `[DEVELOPMENT] Individual components loaded: ${Object.keys(components).length} components`);\r\n return components;\r\n }\r\n \r\n /**\r\n * \uCEF4\uD3EC\uB10C\uD2B8 \uC774\uB984 \uBAA9\uB85D \uAC00\uC838\uC624\uAE30\r\n */\r\n _getComponentNames() {\r\n if (Array.isArray(this.config.componentNames) && this.config.componentNames.length > 0) {\r\n return [...this.config.componentNames];\r\n }\r\n \r\n // \uD3F4\uBC31: \uAE30\uC874 \uD558\uB4DC\uCF54\uB529 \uBAA9\uB85D\r\n return [\r\n 'Button', 'Modal', 'Card', 'Toast', 'Input', 'Tabs',\r\n 'Checkbox', 'Alert', 'DynamicInclude', 'HtmlInclude'\r\n ];\r\n }\r\n \r\n /**\r\n * \uBA54\uBAA8\uB9AC \uC815\uB9AC\r\n */\r\n dispose() {\r\n this.clearComponents();\r\n this.log('debug', 'ComponentLoader disposed');\r\n this.router = null;\r\n }\r\n}", "// ViewLogic Router - ES6 Module\r\nimport { I18nManager } from './plugins/I18nManager.js';\r\nimport { AuthManager } from './plugins/AuthManager.js';\r\nimport { CacheManager } from './plugins/CacheManager.js';\r\nimport { QueryManager } from './plugins/QueryManager.js';\r\nimport { RouteLoader } from './core/RouteLoader.js';\r\nimport { ErrorHandler } from './core/ErrorHandler.js';\r\nimport { ComponentLoader } from './core/ComponentLoader.js';\r\n\r\nexport class ViewLogicRouter {\r\n constructor(options = {}) {\r\n // \uBC84\uC804 \uC815\uBCF4\r\n this.version = options.version || '1.0.0';\r\n \r\n // \uAE30\uBCF8 \uD658\uACBD\uC124\uC815 \uCD5C\uC801\uD654\r\n this.config = this._buildConfig(options);\r\n \r\n this.currentHash = '';\r\n this.currentVueApp = null;\r\n this.previousVueApp = null; // \uC774\uC804 Vue \uC571 (\uC804\uD658 \uD6A8\uACFC\uB97C \uC704\uD574 \uBCF4\uAD00)\r\n this.componentLoader = null; // \uCEF4\uD3EC\uB10C\uD2B8 \uB85C\uB354 \uC778\uC2A4\uD134\uC2A4\r\n\r\n // LoadingManager\uAC00 \uC5C6\uC744 \uB54C\uB97C \uC704\uD55C \uAE30\uBCF8 \uC804\uD658 \uC0C1\uD0DC\r\n this.transitionInProgress = false;\r\n \r\n // \uCD08\uAE30\uD654 \uC900\uBE44 \uC0C1\uD0DC\r\n this.isReady = false;\r\n this.readyPromise = null;\r\n \r\n // \uC774\uBCA4\uD2B8 \uB9AC\uC2A4\uB108 \uBC14\uC778\uB529 \uCD5C\uC801\uD654\r\n this._boundHandleRouteChange = this.handleRouteChange.bind(this);\r\n \r\n // \uBAA8\uB4E0 \uCD08\uAE30\uD654\uB97C \uD55C\uBC88\uC5D0 \uCC98\uB9AC\r\n this.readyPromise = this.initialize();\r\n }\r\n\r\n /**\r\n * \uC124\uC815 \uBE4C\uB4DC (\uBD84\uB9AC\uD558\uC5EC \uAC00\uB3C5\uC131 \uD5A5\uC0C1)\r\n */\r\n _buildConfig(options) {\r\n const defaults = {\r\n basePath: '/src',\r\n mode: 'hash',\r\n cacheMode: 'memory',\r\n cacheTTL: 300000,\r\n maxCacheSize: 50,\r\n useLayout: true,\r\n defaultLayout: 'default',\r\n environment: 'development',\r\n routesPath: '/routes',\r\n enableErrorReporting: true,\r\n useComponents: true,\r\n componentNames: ['Button', 'Modal', 'Card', 'Toast', 'Input', 'Tabs', 'Checkbox', 'Alert', 'DynamicInclude', 'HtmlInclude'],\r\n useI18n: true,\r\n defaultLanguage: 'ko',\r\n logLevel: 'info',\r\n authEnabled: false,\r\n loginRoute: 'login',\r\n protectedRoutes: [],\r\n protectedPrefixes: [],\r\n publicRoutes: ['login', 'register', 'home'],\r\n checkAuthFunction: null,\r\n redirectAfterLogin: 'home',\r\n authCookieName: 'authToken',\r\n authFallbackCookieNames: ['accessToken', 'token', 'jwt'],\r\n authStorage: 'cookie',\r\n authCookieOptions: {},\r\n authSkipValidation: false,\r\n enableParameterValidation: true,\r\n maxParameterLength: 1000,\r\n maxParameterCount: 50,\r\n maxArraySize: 100,\r\n allowedKeyPattern: /^[a-zA-Z0-9_-]+$/,\r\n logSecurityWarnings: true\r\n };\r\n \r\n return { ...defaults, ...options };\r\n }\r\n\r\n\r\n /**\r\n * \uB85C\uAE45 \uB798\uD37C \uBA54\uC11C\uB4DC\r\n */\r\n log(level, ...args) {\r\n if (this.errorHandler) {\r\n this.errorHandler.log(level, 'Router', ...args);\r\n }\r\n }\r\n\r\n /**\r\n * \uD1B5\uD569 \uCD08\uAE30\uD654 - \uB9E4\uB2C8\uC800 \uC0DD\uC131 \u2192 \uBE44\uB3D9\uAE30 \uB85C\uB529 \u2192 \uB77C\uC6B0\uD130 \uC2DC\uC791\r\n */\r\n async initialize() {\r\n try {\r\n // 1. \uB9E4\uB2C8\uC800 \uCD08\uAE30\uD654 (\uB3D9\uAE30)\r\n // \uD56D\uC0C1 \uD544\uC694\uD55C \uB9E4\uB2C8\uC800\uB4E4\r\n this.cacheManager = new CacheManager(this, this.config);\r\n this.routeLoader = new RouteLoader(this, this.config);\r\n this.queryManager = new QueryManager(this, this.config);\r\n this.errorHandler = new ErrorHandler(this, this.config);\r\n \r\n // \uC870\uAC74\uBD80 \uB9E4\uB2C8\uC800\uB4E4\r\n if (this.config.useI18n) {\r\n this.i18nManager = new I18nManager(this, this.config);\r\n if (this.i18nManager.initPromise) {\r\n await this.i18nManager.initPromise;\r\n }\r\n }\r\n \r\n if (this.config.authEnabled) {\r\n this.authManager = new AuthManager(this, this.config);\r\n }\r\n \r\n if (this.config.useComponents) {\r\n this.componentLoader = new ComponentLoader(this, {\r\n ...this.config,\r\n basePath: this.config.basePath + '/components',\r\n cache: true,\r\n componentNames: this.config.componentNames\r\n });\r\n await this.componentLoader.loadAllComponents();\r\n }\r\n \r\n // 2. \uB77C\uC6B0\uD130 \uC2DC\uC791\r\n this.isReady = true;\r\n this.init();\r\n \r\n } catch (error) {\r\n this.log('error', 'Router initialization failed:', error);\r\n // \uC2E4\uD328\uD574\uB3C4 \uB77C\uC6B0\uD130\uB294 \uC2DC\uC791 (graceful degradation)\r\n this.isReady = true;\r\n this.init();\r\n }\r\n }\r\n\r\n /**\r\n * \uB77C\uC6B0\uD130\uAC00 \uC900\uBE44\uB420 \uB54C\uAE4C\uC9C0 \uB300\uAE30\r\n */\r\n async waitForReady() {\r\n if (this.isReady) return true;\r\n if (this.readyPromise) {\r\n await this.readyPromise;\r\n }\r\n return this.isReady;\r\n }\r\n\r\n\r\n init() {\r\n const isHashMode = this.config.mode === 'hash';\r\n \r\n // \uC774\uBCA4\uD2B8 \uB9AC\uC2A4\uB108 \uB4F1\uB85D (\uBA54\uBAA8\uB9AC \uCD5C\uC801\uD654)\r\n window.addEventListener(\r\n isHashMode ? 'hashchange' : 'popstate',\r\n this._boundHandleRouteChange\r\n );\r\n \r\n // DOM \uB85C\uB4DC \uCC98\uB9AC \uD1B5\uD569\r\n const initRoute = () => {\r\n if (isHashMode && !window.location.hash) {\r\n window.location.hash = '#/';\r\n } else if (!isHashMode && window.location.pathname === '/') {\r\n this.navigateTo('home');\r\n } else {\r\n this.handleRouteChange();\r\n }\r\n };\r\n \r\n if (document.readyState === 'loading') {\r\n document.addEventListener('DOMContentLoaded', initRoute);\r\n } else {\r\n // requestAnimationFrame\uC73C\uB85C \uC131\uB2A5 \uAC1C\uC120\r\n requestAnimationFrame(initRoute);\r\n }\r\n }\r\n\r\n handleRouteChange() {\r\n const { route, queryParams } = this._parseCurrentLocation();\r\n \r\n // Store current query parameters in QueryManager\r\n this.queryManager?.setCurrentQueryParams(queryParams);\r\n \r\n // \uBCC0\uACBD\uC0AC\uD56D\uC774 \uC788\uC744 \uB54C\uB9CC \uB85C\uB4DC (\uC131\uB2A5 \uCD5C\uC801\uD654)\r\n if (route !== this.currentHash || this.queryManager?.hasQueryParamsChanged(queryParams)) {\r\n this.currentHash = route;\r\n this.loadRoute(route);\r\n }\r\n }\r\n\r\n /**\r\n * \uD604\uC7AC \uC704\uCE58 \uD30C\uC2F1 (\uBD84\uB9AC\uD558\uC5EC \uAC00\uB3C5\uC131 \uD5A5\uC0C1)\r\n */\r\n _parseCurrentLocation() {\r\n if (this.config.mode === 'hash') {\r\n const hashPath = window.location.hash.slice(1) || '/';\r\n const [pathPart, queryPart] = hashPath.split('?');\r\n \r\n // \uACBD\uB85C \uD30C\uC2F1 \uCD5C\uC801\uD654\r\n let route = 'home';\r\n if (pathPart && pathPart !== '/') {\r\n route = pathPart.startsWith('/') ? pathPart.slice(1) : pathPart;\r\n }\r\n \r\n return {\r\n route: route || 'home',\r\n queryParams: this.queryManager?.parseQueryString(queryPart || window.location.search.slice(1)) || {}\r\n };\r\n } else {\r\n return {\r\n route: window.location.pathname.slice(1) || 'home',\r\n queryParams: this.queryManager?.parseQueryString(window.location.search.slice(1)) || {}\r\n };\r\n }\r\n }\r\n\r\n async loadRoute(routeName) {\r\n // \uC804\uD658\uC774 \uC9C4\uD589 \uC911\uC774\uBA74 \uBB34\uC2DC\r\n const inProgress = this.transitionInProgress;\r\n \r\n if (inProgress) {\r\n return;\r\n }\r\n\r\n try {\r\n this.transitionInProgress = true;\r\n \r\n // \uC778\uC99D \uCCB4\uD06C\r\n const authResult = this.authManager ? \r\n await this.authManager.checkAuthentication(routeName) :\r\n { allowed: true, reason: 'auth_disabled' };\r\n if (!authResult.allowed) {\r\n // \uC778\uC99D \uC2E4\uD328 \uC2DC \uB85C\uADF8\uC778 \uD398\uC774\uC9C0\uB85C \uB9AC\uB2E4\uC774\uB809\uD2B8\r\n if (this.authManager) {\r\n this.authManager.emitAuthEvent('auth_required', { \r\n originalRoute: routeName,\r\n loginRoute: this.config.loginRoute \r\n });\r\n const redirectUrl = routeName !== this.config.loginRoute ? \r\n `${this.config.loginRoute}?redirect=${encodeURIComponent(routeName)}` : \r\n this.config.loginRoute;\r\n this.navigateTo(redirectUrl);\r\n }\r\n return;\r\n }\r\n \r\n const appElement = document.getElementById('app');\r\n if (!appElement) {\r\n throw new Error('App element not found');\r\n }\r\n\r\n // Vue \uCEF4\uD3EC\uB10C\uD2B8 \uC0DD\uC131 (\uBC31\uADF8\uB77C\uC6B4\uB4DC\uC5D0\uC11C)\r\n const component = await this.routeLoader.createVueComponent(routeName);\r\n \r\n // \uC0C8\uB85C\uC6B4 \uD398\uC774\uC9C0\uB97C \uC624\uBC84\uB808\uC774\uB85C \uB80C\uB354\uB9C1\r\n await this.renderComponentWithTransition(component, routeName);\r\n \r\n // \uB85C\uB529 \uC644\uB8CC\r\n \r\n } catch (error) {\r\n this.log('error', `Route loading failed [${routeName}]:`, error.message);\r\n \r\n \r\n // \uC5D0\uB7EC \uD0C0\uC785\uC5D0 \uB530\uB978 \uCC98\uB9AC\r\n if (this.errorHandler) {\r\n await this.errorHandler.handleRouteError(routeName, error);\r\n } else {\r\n console.error('[Router] No error handler available');\r\n }\r\n } finally {\r\n // \uBAA8\uB4E0 \uCC98\uB9AC\uAC00 \uC644\uB8CC\uB41C \uD6C4 \uC804\uD658 \uC0C1\uD0DC \uB9AC\uC14B\r\n this.transitionInProgress = false;\r\n }\r\n }\r\n\r\n async renderComponentWithTransition(vueComponent, routeName) {\r\n const appElement = document.getElementById('app');\r\n if (!appElement) return;\r\n\r\n // \uC0C8\uB85C\uC6B4 \uD398\uC774\uC9C0 \uCEE8\uD14C\uC774\uB108 \uC0DD\uC131\r\n const newPageContainer = document.createElement('div');\r\n newPageContainer.className = 'page-container page-entered';\r\n newPageContainer.id = `page-${routeName}-${Date.now()}`;\r\n \r\n // \uAE30\uC874 \uCEE8\uD14C\uC774\uB108\uAC00 \uC788\uB2E4\uBA74 \uC989\uC2DC \uC228\uAE30\uAE30\r\n const existingContainers = appElement.querySelectorAll('.page-container');\r\n existingContainers.forEach(container => {\r\n container.classList.remove('page-entered');\r\n container.classList.add('page-exiting');\r\n });\r\n\r\n // \uC0C8 \uCEE8\uD14C\uC774\uB108\uB97C \uC571\uC5D0 \uCD94\uAC00\r\n appElement.appendChild(newPageContainer);\r\n\r\n // \uAC1C\uBC1C \uBAA8\uB4DC\uC5D0\uC11C\uB9CC \uC2A4\uD0C0\uC77C \uC801\uC6A9 (\uD504\uB85C\uB355\uC158 \uBAA8\uB4DC\uB294 \uBE4C\uB4DC\uB41C JS\uC5D0\uC11C \uC790\uB3D9 \uCC98\uB9AC)\r\n if (this.config.environment === 'development' && vueComponent._style) {\r\n this.applyStyle(vueComponent._style, routeName);\r\n }\r\n \r\n // \uC0C8\uB85C\uC6B4 Vue \uC571\uC744 \uC0C8 \uCEE8\uD14C\uC774\uB108\uC5D0 \uB9C8\uC6B4\uD2B8\r\n const { createApp } = Vue;\r\n const newVueApp = createApp(vueComponent);\r\n \r\n // Vue 3 \uC804\uC5ED \uC18D\uC131 \uC124\uC815\r\n newVueApp.config.globalProperties.$router = {\r\n navigateTo: (route, params) => this.navigateTo(route, params),\r\n getCurrentRoute: () => this.getCurrentRoute(),\r\n getQueryParams: () => this.queryManager?.getQueryParams() || {},\r\n getQueryParam: (key) => this.queryManager?.getQueryParam(key),\r\n setQueryParams: (params, replace) => this.queryManager?.setQueryParams(params, replace),\r\n removeQueryParams: (keys) => this.queryManager?.removeQueryParams(keys),\r\n currentRoute: this.currentHash,\r\n currentQuery: this.queryManager?.getQueryParams() || {}\r\n };\r\n\r\n // \uBAA8\uBC14\uC77C \uBA54\uB274 \uC804\uC5ED \uD568\uC218 \uCD94\uAC00\r\n\r\n newVueApp.mount(`#${newPageContainer.id}`);\r\n\r\n // requestAnimationFrame\uC73C\uB85C \uC131\uB2A5 \uAC1C\uC120\r\n requestAnimationFrame(() => {\r\n this.cleanupPreviousPages();\r\n this.transitionInProgress = false;\r\n });\r\n\r\n // \uC774\uC804 \uC571 \uC815\uB9AC \uC900\uBE44\r\n if (this.currentVueApp) {\r\n this.previousVueApp = this.currentVueApp;\r\n }\r\n \r\n this.currentVueApp = newVueApp;\r\n }\r\n\r\n cleanupPreviousPages() {\r\n const appElement = document.getElementById('app');\r\n if (!appElement) return;\r\n\r\n // \uBC30\uCE58 DOM \uC870\uC791\uC73C\uB85C \uC131\uB2A5 \uAC1C\uC120\r\n const fragment = document.createDocumentFragment();\r\n const exitingContainers = appElement.querySelectorAll('.page-container.page-exiting');\r\n \r\n // \uD55C\uBC88\uC5D0 \uC81C\uAC70\r\n exitingContainers.forEach(container => container.remove());\r\n\r\n // \uC774\uC804 Vue \uC571 \uC815\uB9AC\r\n if (this.previousVueApp) {\r\n try {\r\n this.previousVueApp.unmount();\r\n } catch (error) {\r\n // \uBB34\uC2DC (\uC774\uBBF8 \uC5B8\uB9C8\uC6B4\uD2B8\uB41C \uACBD\uC6B0)\r\n }\r\n this.previousVueApp = null;\r\n }\r\n\r\n // \uB85C\uB529 \uC5D8\uB9AC\uBA3C\uD2B8 \uC81C\uAC70\r\n \r\n appElement.querySelector('.loading')?.remove();\r\n }\r\n\r\n applyStyle(css, routeName) {\r\n // \uAE30\uC874 \uC2A4\uD0C0\uC77C \uC81C\uAC70\r\n const existing = document.querySelector(`style[data-route=\"${routeName}\"]`);\r\n if (existing) existing.remove();\r\n\r\n if (css) {\r\n const style = document.createElement('style');\r\n style.textContent = css;\r\n style.setAttribute('data-route', routeName);\r\n document.head.appendChild(style);\r\n }\r\n }\r\n\r\n\r\n navigateTo(routeName, params = null) {\r\n // If routeName is an object, treat it as {route, params}\r\n if (typeof routeName === 'object') {\r\n params = routeName.params || null;\r\n routeName = routeName.route;\r\n }\r\n \r\n // Clear current query params if navigating to a different route\r\n if (routeName !== this.currentHash && this.queryManager) {\r\n this.queryManager.clearQueryParams();\r\n }\r\n \r\n // Update URL with new route and params\r\n this.updateURL(routeName, params);\r\n }\r\n\r\n getCurrentRoute() {\r\n return this.currentHash;\r\n }\r\n\r\n\r\n updateURL(route, params = null) {\r\n const queryParams = params || this.queryManager?.getQueryParams() || {};\r\n const queryString = this.queryManager?.buildQueryString(queryParams) || '';\r\n \r\n // URL \uBE4C\uB4DC \uCD5C\uC801\uD654\r\n const buildURL = (route, queryString, isHash = true) => {\r\n const base = route === 'home' ? '/' : `/${route}`;\r\n const url = queryString ? `${base}?${queryString}` : base;\r\n return isHash ? `#${url}` : url;\r\n };\r\n \r\n if (this.config.mode === 'hash') {\r\n const newHash = buildURL(route, queryString);\r\n \r\n // \uB3D9\uC77C\uD55C URL\uC774\uBA74 \uC5C5\uB370\uC774\uD2B8\uD558\uC9C0 \uC54A\uC74C (\uC131\uB2A5 \uCD5C\uC801\uD654)\r\n if (window.location.hash !== newHash) {\r\n window.location.hash = newHash;\r\n }\r\n } else {\r\n const newPath = buildURL(route, queryString, false);\r\n const isSameRoute = window.location.pathname === (route === 'home' ? '/' : `/${route}`);\r\n \r\n if (isSameRoute) {\r\n window.history.replaceState({}, '', newPath);\r\n } else {\r\n window.history.pushState({}, '', newPath);\r\n }\r\n this.handleRouteChange();\r\n }\r\n }\r\n\r\n /**\r\n * \uB77C\uC6B0\uD130 \uC815\uB9AC (\uBA54\uBAA8\uB9AC \uB204\uC218 \uBC29\uC9C0)\r\n */\r\n destroy() {\r\n // \uC774\uBCA4\uD2B8 \uB9AC\uC2A4\uB108 \uC81C\uAC70\r\n window.removeEventListener(\r\n this.config.mode === 'hash' ? 'hashchange' : 'popstate',\r\n this._boundHandleRouteChange\r\n );\r\n \r\n // \uD604\uC7AC Vue \uC571 \uC5B8\uB9C8\uC6B4\uD2B8\r\n if (this.currentVueApp) {\r\n this.currentVueApp.unmount();\r\n this.currentVueApp = null;\r\n }\r\n \r\n // \uC774\uC804 Vue \uC571 \uC5B8\uB9C8\uC6B4\uD2B8\r\n if (this.previousVueApp) {\r\n this.previousVueApp.unmount();\r\n this.previousVueApp = null;\r\n }\r\n \r\n // \uB9E4\uB2C8\uC800 \uC815\uB9AC\r\n Object.values(this).forEach(manager => {\r\n if (manager && typeof manager.destroy === 'function') {\r\n manager.destroy();\r\n }\r\n });\r\n \r\n // \uCE90\uC2DC \uD074\uB9AC\uC5B4\r\n this.cacheManager?.clearAll();\r\n \r\n // DOM \uC815\uB9AC\r\n const appElement = document.getElementById('app');\r\n if (appElement) {\r\n appElement.innerHTML = '';\r\n }\r\n \r\n this.log('info', 'Router destroyed');\r\n }\r\n}\r\n// \uC804\uC5ED \uB77C\uC6B0\uD130\uB294 index.html\uC5D0\uC11C \uD658\uACBD\uC124\uC815\uACFC \uD568\uAED8 \uC0DD\uC131\uB428"],
|
|
5
|
+
"mappings": "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",
|
|
6
|
+
"names": ["isAuthenticated", "route", "queryString"]
|
|
7
|
+
}
|
|
@@ -0,0 +1,53 @@
|
|
|
1
|
+
/* ViewLogic v1.0.0 | (c) 2024 hopegiver | MIT License */
|
|
2
|
+
var d=class{constructor(e,t={}){this.config={enabled:t.useI18n!==void 0?t.useI18n:!0,defaultLanguage:t.defaultLanguage||"ko",fallbackLanguage:t.defaultLanguage||"ko",cacheKey:t.cacheKey||"viewlogic_lang",dataCacheKey:t.dataCacheKey||"viewlogic_i18n_data",cacheVersion:t.cacheVersion||"1.0.0",enableDataCache:t.enableDataCache!==!1,debug:t.debug||!1},this.router=e,this.messages=new Map,this.currentLanguage=this.config.defaultLanguage,this.isLoading=!1,this.loadPromises=new Map,this.listeners={languageChanged:[]},this.initPromise=this.init()}async init(){if(!this.config.enabled){this.log("info","I18n system disabled");return}if(this.loadLanguageFromCache(),this.config.debug&&(this.config.enableDataCache=!1,this.log("debug","Data cache disabled in debug mode")),this.messages.has(this.currentLanguage))this.log("debug","Language messages already loaded:",this.currentLanguage);else try{await this.loadMessages(this.currentLanguage)}catch(e){this.log("error","Failed to load initial language file:",e)}}loadLanguageFromCache(){try{let e=localStorage.getItem(this.config.cacheKey);e&&this.isValidLanguage(e)&&(this.currentLanguage=e,this.log("debug","Language loaded from cache:",e))}catch(e){this.log("warn","Failed to load language from cache:",e)}}isValidLanguage(e){return typeof e=="string"&&/^[a-z]{2}$/.test(e)}getCurrentLanguage(){return this.currentLanguage}async setLanguage(e){if(!this.isValidLanguage(e))return this.log("warn","Invalid language code:",e),!1;if(this.currentLanguage===e)return this.log("debug","Language already set to:",e),!0;let t=this.currentLanguage;this.currentLanguage=e;try{return await this.loadMessages(e),this.saveLanguageToCache(e),this.emit("languageChanged",{from:t,to:e,messages:this.messages.get(e)}),this.log("info","Language changed successfully",{from:t,to:e}),!0}catch(r){return this.currentLanguage=t,this.log("error","Failed to change language:",r),!1}}saveLanguageToCache(e){try{localStorage.setItem(this.config.cacheKey,e),this.log("debug","Language saved to cache:",e)}catch(t){this.log("warn","Failed to save language to cache:",t)}}async loadMessages(e){if(this.messages.has(e))return this.log("debug","Messages already loaded for:",e),this.messages.get(e);if(this.loadPromises.has(e))return this.log("debug","Messages loading in progress for:",e),await this.loadPromises.get(e);let t=this._loadMessagesFromFile(e);this.loadPromises.set(e,t);try{let r=await t;return this.messages.set(e,r),this.loadPromises.delete(e),this.log("debug","Messages loaded successfully for:",e),r}catch(r){throw this.loadPromises.delete(e),r}}async _loadMessagesFromFile(e){if(this.config.enableDataCache){let t=this.getDataFromCache(e);if(t)return this.log("debug","Messages loaded from cache:",e),t}try{let t=await fetch(`../i18n/${e}.json`);if(!t.ok)throw new Error(`HTTP error! status: ${t.status}`);let r=await t.json();return this.config.enableDataCache&&this.saveDataToCache(e,r),r}catch(t){if(this.log("error","Failed to load messages file for:",e,t),e!==this.config.fallbackLanguage)return this.log("info","Trying fallback language:",this.config.fallbackLanguage),await this._loadMessagesFromFile(this.config.fallbackLanguage);throw new Error(`Failed to load messages for language: ${e}`)}}getDataFromCache(e){try{let t=`${this.config.dataCacheKey}_${e}_${this.config.cacheVersion}`,r=localStorage.getItem(t);if(r){let{data:a,timestamp:o,version:i}=JSON.parse(r);if(i!==this.config.cacheVersion)return this.log("debug","Cache version mismatch, clearing:",e),localStorage.removeItem(t),null;let n=Date.now(),s=1440*60*1e3;return n-o>s?(this.log("debug","Cache expired, removing:",e),localStorage.removeItem(t),null):a}}catch(t){this.log("warn","Failed to read from cache:",t)}return null}saveDataToCache(e,t){try{let r=`${this.config.dataCacheKey}_${e}_${this.config.cacheVersion}`,a={data:t,timestamp:Date.now(),version:this.config.cacheVersion};localStorage.setItem(r,JSON.stringify(a)),this.log("debug","Data saved to cache:",e)}catch(r){this.log("warn","Failed to save to cache:",r)}}t(e,t={}){if(!this.config.enabled)return e;let r=this.messages.get(this.currentLanguage);if(!r)return this.log("warn","No messages loaded for current language:",this.currentLanguage),e;let a=this.getNestedValue(r,e);if(a===void 0){this.log("warn","Translation not found for key:",e);let o=this.messages.get(this.config.fallbackLanguage);if(o&&this.currentLanguage!==this.config.fallbackLanguage){let i=this.getNestedValue(o,e);if(i!==void 0)return this.interpolate(i,t)}return e}return this.interpolate(a,t)}getNestedValue(e,t){return t.split(".").reduce((r,a)=>r&&r[a]!==void 0?r[a]:void 0,e)}interpolate(e,t){return typeof e!="string"?e:e.replace(/\{(\w+)\}/g,(r,a)=>t.hasOwnProperty(a)?t[a]:r)}plural(e,t,r={}){let a=t===1?`${e}.singular`:`${e}.plural`;return this.t(a,{...r,count:t})}getAvailableLanguages(){return["ko","en"]}on(e,t){this.listeners[e]&&this.listeners[e].push(t)}off(e,t){if(this.listeners[e]){let r=this.listeners[e].indexOf(t);r>-1&&this.listeners[e].splice(r,1)}}emit(e,t){this.listeners[e]&&this.listeners[e].forEach(r=>{try{r(t)}catch(a){this.log("error","Error in event listener:",a)}})}getMessages(){return this.messages.get(this.currentLanguage)||{}}formatDate(e,t={}){let r=this.currentLanguage==="ko"?"ko-KR":"en-US";return new Intl.DateTimeFormat(r,t).format(new Date(e))}formatNumber(e,t={}){let r=this.currentLanguage==="ko"?"ko-KR":"en-US";return new Intl.NumberFormat(r,t).format(e)}log(e,...t){this.router?.errorHandler&&this.router.errorHandler.log(e,"I18nManager",...t)}isEnabled(){return this.config.enabled}async isReady(){if(!this.config.enabled)return!0;try{return await this.initPromise,!0}catch(e){return this.log("error","I18n initialization failed:",e),!1}}clearCache(){try{let t=Object.keys(localStorage).filter(r=>r.startsWith(this.config.dataCacheKey));t.forEach(r=>{localStorage.removeItem(r)}),this.log("debug","Cache cleared, removed",t.length,"items")}catch(e){this.log("warn","Failed to clear cache:",e)}}getCacheInfo(){let e={enabled:this.config.enableDataCache,version:this.config.cacheVersion,languages:{}};try{Object.keys(localStorage).filter(a=>a.startsWith(this.config.dataCacheKey)).forEach(a=>{let o=a.match(new RegExp(`${this.config.dataCacheKey}_(w+)_(.+)`));if(o){let[,i,n]=o,s=JSON.parse(localStorage.getItem(a));e.languages[i]={version:n,timestamp:s.timestamp,age:Date.now()-s.timestamp}}})}catch(t){this.log("warn","Failed to get cache info:",t)}return e}async initialize(){if(!this.config.enabled)return this.log("info","I18n system is disabled, skipping initialization"),!0;try{return await this.initPromise,this.log("info","I18n system fully initialized"),!0}catch(e){return this.log("error","Failed to initialize I18n system:",e),!1}}};var f=class{constructor(e,t={}){this.config={enabled:t.authEnabled||!1,loginRoute:t.loginRoute||"login",protectedRoutes:t.protectedRoutes||[],protectedPrefixes:t.protectedPrefixes||[],publicRoutes:t.publicRoutes||["login","register","home"],checkAuthFunction:t.checkAuthFunction||null,redirectAfterLogin:t.redirectAfterLogin||"home",authCookieName:t.authCookieName||"authToken",authFallbackCookieNames:t.authFallbackCookieNames||["accessToken","token","jwt"],authStorage:t.authStorage||"cookie",authCookieOptions:t.authCookieOptions||{},authSkipValidation:t.authSkipValidation||!1,debug:t.debug||!1},this.router=e,this.eventListeners=new Map,this.log("info","AuthManager initialized",{enabled:this.config.enabled})}log(e,...t){this.router?.errorHandler&&this.router.errorHandler.log(e,"AuthManager",...t)}async checkAuthentication(e){if(!this.config.enabled)return{allowed:!0,reason:"auth_disabled"};if(this.log("debug",`\u{1F510} Checking authentication for route: ${e}`),this.isPublicRoute(e))return{allowed:!0,reason:"public_route"};if(!this.isProtectedRoute(e))return{allowed:!0,reason:"not_protected"};if(typeof this.config.checkAuthFunction=="function")try{let a=await this.config.checkAuthFunction(e);return{allowed:a,reason:a?"custom_auth_success":"custom_auth_failed",routeName:e}}catch(a){return this.log("error","Custom auth function failed:",a),{allowed:!1,reason:"custom_auth_error",error:a}}let r=this.isUserAuthenticated();return{allowed:r,reason:r?"authenticated":"not_authenticated",routeName:e}}isUserAuthenticated(){this.log("debug","\u{1F50D} Checking user authentication status");let e=localStorage.getItem("authToken")||localStorage.getItem("accessToken");if(e)try{if(e.includes(".")){let a=JSON.parse(atob(e.split(".")[1]));if(a.exp&&Date.now()>=a.exp*1e3)return this.log("debug","localStorage token expired, removing..."),localStorage.removeItem("authToken"),localStorage.removeItem("accessToken"),!1}return this.log("debug","\u2705 Valid token found in localStorage"),!0}catch(a){this.log("warn","Invalid token in localStorage:",a)}if(sessionStorage.getItem("authToken")||sessionStorage.getItem("accessToken"))return this.log("debug","\u2705 Token found in sessionStorage"),!0;let r=this.getAuthCookie();if(r)try{if(r.includes(".")){let a=JSON.parse(atob(r.split(".")[1]));if(a.exp&&Date.now()>=a.exp*1e3)return this.log("debug","Cookie token expired, removing..."),this.removeAuthCookie(),!1}return this.log("debug","\u2705 Valid token found in cookies"),!0}catch(a){this.log("warn","Cookie token validation failed:",a)}return window.user||window.isAuthenticated?(this.log("debug","\u2705 Global authentication variable found"),!0):(this.log("debug","\u274C No valid authentication found"),!1)}isPublicRoute(e){return this.config.publicRoutes.includes(e)}isProtectedRoute(e){if(this.config.protectedRoutes.includes(e))return!0;for(let t of this.config.protectedPrefixes)if(e.startsWith(t))return!0;return!1}getAuthCookie(){let e=this.getCookieValue(this.config.authCookieName);if(e)return e;for(let t of this.config.authFallbackCookieNames){let r=this.getCookieValue(t);if(r)return this.log("debug",`Found auth token in fallback cookie: ${t}`),r}return null}getCookieValue(e){let r=`; ${document.cookie}`.split(`; ${e}=`);return r.length===2?decodeURIComponent(r.pop().split(";").shift()):null}removeAuthCookie(){[this.config.authCookieName,...this.config.authFallbackCookieNames].forEach(t=>{document.cookie=`${t}=; expires=Thu, 01 Jan 1970 00:00:00 UTC; path=/;`,document.cookie=`${t}=; expires=Thu, 01 Jan 1970 00:00:00 UTC; path=${window.location.pathname};`}),this.log("debug","Auth cookies removed")}getAccessToken(){let e=localStorage.getItem("authToken")||localStorage.getItem("accessToken");return e||(e=sessionStorage.getItem("authToken")||sessionStorage.getItem("accessToken"),e)||(e=this.getAuthCookie(),e)?e:null}setAccessToken(e,t={}){if(!e)return this.log("warn","Empty token provided"),!1;let{storage:r=this.config.authStorage,cookieOptions:a=this.config.authCookieOptions,skipValidation:o=this.config.authSkipValidation}=t;try{if(!o&&e.includes("."))try{let i=JSON.parse(atob(e.split(".")[1]));if(i.exp&&Date.now()>=i.exp*1e3)return this.log("warn","\u274C Token is expired"),!1;this.log("debug","\u2705 JWT token validated")}catch(i){this.log("warn","\u26A0\uFE0F JWT validation failed, but proceeding:",i.message)}switch(r){case"localStorage":localStorage.setItem("authToken",e),this.log("debug","Token saved to localStorage");break;case"sessionStorage":sessionStorage.setItem("authToken",e),this.log("debug","Token saved to sessionStorage");break;case"cookie":this.setAuthCookie(e,a);break;default:localStorage.setItem("authToken",e),this.log("debug","Token saved to localStorage (default)")}return this.emitAuthEvent("token_set",{storage:r,tokenLength:e.length,hasExpiration:e.includes(".")}),!0}catch(i){return this.log("Failed to set token:",i),!1}}setAuthCookie(e,t={}){let{cookieName:r=this.config.authCookieName,secure:a=window.location.protocol==="https:",sameSite:o="Strict",path:i="/",domain:n=null}=t,s=`${r}=${encodeURIComponent(e)}; path=${i}`;a&&(s+="; Secure"),o&&(s+=`; SameSite=${o}`),n&&(s+=`; Domain=${n}`);try{if(e.includes("."))try{let l=JSON.parse(atob(e.split(".")[1]));if(l.exp){let h=new Date(l.exp*1e3);s+=`; Expires=${h.toUTCString()}`}}catch{this.log("Could not extract expiration from JWT token")}}catch(l){this.log("Token processing error:",l)}document.cookie=s,this.log(`Auth cookie set: ${r}`)}removeAccessToken(e="all"){switch(e){case"localStorage":localStorage.removeItem("authToken"),localStorage.removeItem("accessToken");break;case"sessionStorage":sessionStorage.removeItem("authToken"),sessionStorage.removeItem("accessToken");break;case"cookie":this.removeAuthCookie();break;case"all":default:localStorage.removeItem("authToken"),localStorage.removeItem("accessToken"),sessionStorage.removeItem("authToken"),sessionStorage.removeItem("accessToken"),this.removeAuthCookie();break}this.emitAuthEvent("token_removed",{storage:e}),this.log(`Token removed from: ${e}`)}handleLoginSuccess(e=null){let t=e||this.config.redirectAfterLogin;return this.log(`\u{1F389} Login success, redirecting to: ${t}`),this.emitAuthEvent("login_success",{targetRoute:t}),this.router&&typeof this.router.navigateTo=="function"&&this.router.navigateTo(t),t}handleLogout(){return this.log("\u{1F44B} Logging out user"),this.removeAccessToken(),window.user&&(window.user=null),window.isAuthenticated&&(window.isAuthenticated=!1),this.emitAuthEvent("logout",{}),this.router&&typeof this.router.navigateTo=="function"&&this.router.navigateTo(this.config.loginRoute),this.config.loginRoute}emitAuthEvent(e,t){let r=new CustomEvent("router:auth",{detail:{type:e,timestamp:Date.now(),...t}});document.dispatchEvent(r),this.eventListeners.has(e)&&this.eventListeners.get(e).forEach(a=>{try{a(t)}catch(o){this.log("Event listener error:",o)}}),this.log(`\u{1F514} Auth event emitted: ${e}`,t)}on(e,t){this.eventListeners.has(e)||this.eventListeners.set(e,[]),this.eventListeners.get(e).push(t)}off(e,t){if(this.eventListeners.has(e)){let r=this.eventListeners.get(e),a=r.indexOf(t);a>-1&&r.splice(a,1)}}getAuthStats(){return{enabled:this.config.enabled,isAuthenticated:this.isUserAuthenticated(),hasToken:!!this.getAccessToken(),protectedRoutesCount:this.config.protectedRoutes.length,protectedPrefixesCount:this.config.protectedPrefixes.length,publicRoutesCount:this.config.publicRoutes.length,storage:this.config.authStorage,loginRoute:this.config.loginRoute}}destroy(){this.eventListeners.clear(),this.log("debug","AuthManager destroyed")}};var m=class{constructor(e,t={}){this.config={cacheMode:t.cacheMode||"memory",cacheTTL:t.cacheTTL||3e5,maxCacheSize:t.maxCacheSize||50,debug:t.debug||!1},this.router=e,this.cache=new Map,this.cacheTimestamps=new Map,this.lruOrder=[],this.log("info","CacheManager initialized with config:",this.config)}log(e,...t){this.router?.errorHandler&&this.router.errorHandler.log(e,"CacheManager",...t)}setCache(e,t){let r=Date.now();if(this.config.cacheMode==="lru"){if(this.cache.size>=this.config.maxCacheSize&&!this.cache.has(e)){let o=this.lruOrder.shift();o&&(this.cache.delete(o),this.cacheTimestamps.delete(o),this.log("debug",`\u{1F5D1}\uFE0F LRU evicted cache key: ${o}`))}let a=this.lruOrder.indexOf(e);a>-1&&this.lruOrder.splice(a,1),this.lruOrder.push(e)}this.cache.set(e,t),this.cacheTimestamps.set(e,r),this.log("debug",`\u{1F4BE} Cached: ${e} (size: ${this.cache.size})`)}getFromCache(e){let t=Date.now(),r=this.cacheTimestamps.get(e);if(r&&t-r>this.config.cacheTTL){if(this.cache.delete(e),this.cacheTimestamps.delete(e),this.config.cacheMode==="lru"){let o=this.lruOrder.indexOf(e);o>-1&&this.lruOrder.splice(o,1)}return this.log("debug",`\u23F0 Cache expired and removed: ${e}`),null}let a=this.cache.get(e);if(a&&this.config.cacheMode==="lru"){let o=this.lruOrder.indexOf(e);o>-1&&(this.lruOrder.splice(o,1),this.lruOrder.push(e))}return a?this.log("debug",`\u{1F3AF} Cache hit: ${e}`):this.log("debug",`\u274C Cache miss: ${e}`),a}hasCache(e){return this.cache.has(e)&&this.getFromCache(e)!==null}invalidateByPattern(e){let t=[];for(let r of this.cache.keys())(r.includes(e)||r.startsWith(e))&&t.push(r);return t.forEach(r=>{if(this.cache.delete(r),this.cacheTimestamps.delete(r),this.config.cacheMode==="lru"){let a=this.lruOrder.indexOf(r);a>-1&&this.lruOrder.splice(a,1)}}),this.log("debug",`\u{1F9F9} Invalidated ${t.length} cache entries matching: ${e}`),t.length}invalidateComponentCache(e){let t=[`component_${e}`,`script_${e}`,`template_${e}`,`style_${e}`,`layout_${e}`],r=0;return t.forEach(a=>{r+=this.invalidateByPattern(a)}),this.log(`\u{1F504} Invalidated component cache for route: ${e} (${r} entries)`),r}clearComponentCache(){let e=["component_","script_","template_","style_","layout_"],t=0;return e.forEach(r=>{t+=this.invalidateByPattern(r)}),this.log(`\u{1F9FD} Cleared all component caches (${t} entries)`),t}clearCache(){let e=this.cache.size;this.cache.clear(),this.cacheTimestamps.clear(),this.lruOrder=[],this.log(`\u{1F525} Cleared all cache (${e} entries)`)}cleanExpiredCache(){let e=Date.now(),t=[];for(let[r,a]of this.cacheTimestamps.entries())e-a>this.config.cacheTTL&&t.push(r);return t.forEach(r=>{if(this.cache.delete(r),this.cacheTimestamps.delete(r),this.config.cacheMode==="lru"){let a=this.lruOrder.indexOf(r);a>-1&&this.lruOrder.splice(a,1)}}),t.length>0&&this.log(`\u23F1\uFE0F Cleaned ${t.length} expired cache entries`),t.length}getCacheStats(){return{size:this.cache.size,maxSize:this.config.maxCacheSize,mode:this.config.cacheMode,ttl:this.config.cacheTTL,memoryUsage:this.getMemoryUsage(),hitRatio:this.getHitRatio(),categories:this.getCategorizedStats()}}getMemoryUsage(){let e=0;for(let[t,r]of this.cache.entries())e+=t.length*2,typeof r=="string"?e+=r.length*2:typeof r=="object"&&r!==null?e+=JSON.stringify(r).length*2:e+=8;return{bytes:e,kb:Math.round(e/1024*100)/100,mb:Math.round(e/(1024*1024)*100)/100}}getHitRatio(){let e=this.cache.size>0?Math.min(this.cache.size/this.config.maxCacheSize,1):0;return Math.round(e*100)}getCategorizedStats(){let e={components:0,scripts:0,templates:0,styles:0,layouts:0,others:0};for(let t of this.cache.keys())t.startsWith("component_")?e.components++:t.startsWith("script_")?e.scripts++:t.startsWith("template_")?e.templates++:t.startsWith("style_")?e.styles++:t.startsWith("layout_")?e.layouts++:e.others++;return e}getCacheKeys(){return Array.from(this.cache.keys())}getCacheKeysByPattern(e){return this.getCacheKeys().filter(t=>t.includes(e)||t.startsWith(e))}startAutoCleanup(e=6e4){this.cleanupInterval&&clearInterval(this.cleanupInterval),this.cleanupInterval=setInterval(()=>{this.cleanExpiredCache()},e),this.log(`\u{1F916} Auto cleanup started (interval: ${e}ms)`)}stopAutoCleanup(){this.cleanupInterval&&(clearInterval(this.cleanupInterval),this.cleanupInterval=null,this.log("debug","\u{1F6D1} Auto cleanup stopped"))}destroy(){this.stopAutoCleanup(),this.clearCache(),this.log("debug","CacheManager destroyed")}};var p=class{constructor(e,t={}){this.config={enableParameterValidation:t.enableParameterValidation!==!1,logSecurityWarnings:t.logSecurityWarnings!==!1,maxParameterLength:t.maxParameterLength||1e3,maxArraySize:t.maxArraySize||100,maxParameterCount:t.maxParameterCount||50,allowedKeyPattern:t.allowedKeyPattern||/^[a-zA-Z0-9_\-]+$/,debug:t.debug||!1},this.router=e,this.currentQueryParams={},this.log("info","QueryManager initialized with config:",this.config)}log(e,...t){this.router?.errorHandler&&this.router.errorHandler.log(e,"QueryManager",...t)}sanitizeParameter(e){if(typeof e!="string")return e;let t=e.replace(/<script\b[^<]*(?:(?!<\/script>)<[^<]*)*<\/script>/gi,"").replace(/<iframe\b[^<]*(?:(?!<\/iframe>)<[^<]*)*<\/iframe>/gi,"").replace(/<object\b[^<]*(?:(?!<\/object>)<[^<]*)*<\/object>/gi,"").replace(/<embed\b[^<]*(?:(?!<\/embed>)<[^<]*)*<\/embed>/gi,"").replace(/<link\b[^<]*>/gi,"").replace(/<meta\b[^<]*>/gi,"").replace(/javascript:/gi,"").replace(/vbscript:/gi,"").replace(/data:/gi,"").replace(/on\w+\s*=/gi,"").replace(/expression\s*\(/gi,"").replace(/url\s*\(/gi,""),r=[/(\b(union|select|insert|update|delete|drop|create|alter|exec|execute|sp_|xp_)\b)/gi,/(;|\||&|\*|%|<|>)/g,/(--|\/\*|\*\/)/g,/(\bor\b.*\b=\b|\band\b.*\b=\b)/gi,/('.*'|".*")/g,/(\\\w+)/g];for(let a of r)t=t.replace(a,"");return t=t.replace(/[<>'"&]{2,}/g,""),t.length>this.config.maxParameterLength&&(t=t.substring(0,this.config.maxParameterLength)),t.trim()}validateParameter(e,t){if(!this.config.enableParameterValidation)return!0;if(typeof e!="string"||e.length===0)return!1;if(!this.config.allowedKeyPattern.test(e))return this.config.logSecurityWarnings&&console.warn(`Invalid parameter key format: ${e}`),!1;if(e.length>50)return this.config.logSecurityWarnings&&console.warn(`Parameter key too long: ${e}`),!1;if(t!=null){if(typeof t=="string"){if(t.length>this.config.maxParameterLength)return this.config.logSecurityWarnings&&console.warn(`Parameter value too long for key: ${e}`),!1;let r=[/<script|<iframe|<object|<embed/gi,/javascript:|vbscript:|data:/gi,/union.*select|insert.*into|delete.*from/gi,/\.\.\//g,/[<>'"&]{3,}/g];for(let a of r)if(a.test(t))return this.config.logSecurityWarnings&&console.warn(`Dangerous pattern detected in parameter ${e}:`,t),!1}else if(Array.isArray(t)){if(t.length>this.config.maxArraySize)return this.config.logSecurityWarnings&&console.warn(`Parameter array too large for key: ${e}`),!1;for(let r of t)if(!this.validateParameter(`${e}[]`,r))return!1}}return!0}parseQueryString(e){let t={};if(!e)return t;let r=e.split("&");for(let o of r)try{let[i,n]=o.split("=");if(!i)continue;let s,l;try{s=decodeURIComponent(i),l=n?decodeURIComponent(n):""}catch{this.log("warn","Failed to decode URI component:",o);continue}if(!this.validateParameter(s,l)){this.log("warn",`Parameter rejected by security filter: ${s}`);continue}let h=this.sanitizeParameter(l);if(s.endsWith("[]")){let c=s.slice(0,-2);if(!this.validateParameter(c,[]))continue;t[c]||(t[c]=[]),t[c].length<this.config.maxArraySize?t[c].push(h):this.config.logSecurityWarnings&&console.warn(`Array parameter ${c} size limit exceeded`)}else t[s]=h}catch(i){this.log("error","Error parsing query parameter:",o,i)}let a=Object.keys(t).length;if(a>this.config.maxParameterCount){this.config.logSecurityWarnings&&console.warn(`Too many parameters (${a}). Limiting to first ${this.config.maxParameterCount}.`);let o={},i=0;for(let[n,s]of Object.entries(t)){if(i>=this.config.maxParameterCount)break;o[n]=s,i++}return o}return t}buildQueryString(e){if(!e||Object.keys(e).length===0)return"";let t=[];for(let[r,a]of Object.entries(e))if(Array.isArray(a))for(let o of a)t.push(`${encodeURIComponent(r)}[]=${encodeURIComponent(o)}`);else a!=null&&t.push(`${encodeURIComponent(r)}=${encodeURIComponent(a)}`);return t.join("&")}hasQueryParamsChanged(e){if(!this.currentQueryParams&&!e)return!1;if(!this.currentQueryParams||!e)return!0;let t=Object.keys(this.currentQueryParams),r=Object.keys(e);if(t.length!==r.length)return!0;for(let a of t)if(JSON.stringify(this.currentQueryParams[a])!==JSON.stringify(e[a]))return!0;return!1}getQueryParams(){return{...this.currentQueryParams}}getQueryParam(e){return this.currentQueryParams?this.currentQueryParams[e]:void 0}setQueryParams(e,t=!1){if(!e||typeof e!="object"){console.warn("Invalid parameters object provided to setQueryParams");return}let r=t?{}:{...this.currentQueryParams},a={};for(let[i,n]of Object.entries(e)){if(!this.validateParameter(i,n)){console.warn(`Parameter ${i} rejected by security filter`);continue}n!=null&&(Array.isArray(n)?a[i]=n.map(s=>this.sanitizeParameter(s)):a[i]=this.sanitizeParameter(n))}Object.assign(r,a);for(let[i,n]of Object.entries(r))(n==null||n==="")&&delete r[i];let o=Object.keys(r).length;o>this.config.maxParameterCount&&this.config.logSecurityWarnings&&console.warn(`Too many parameters after update (${o}). Some parameters may be dropped.`),this.currentQueryParams=r,this.updateURL()}removeQueryParams(e){if(!e)return;let t=Array.isArray(e)?e:[e];for(let r of t)delete this.currentQueryParams[r];this.updateURL()}clearQueryParams(){this.currentQueryParams={},this.updateURL()}setCurrentQueryParams(e){this.currentQueryParams=e||{}}updateURL(){if(this.router&&typeof this.router.updateURL=="function"){let e=this.router.currentHash||"home";this.router.updateURL(e,this.currentQueryParams)}}getStats(){return{currentParams:Object.keys(this.currentQueryParams).length,maxAllowed:this.config.maxParameterCount,validationEnabled:this.config.enableParameterValidation,currentQueryString:this.buildQueryString(this.currentQueryParams)}}destroy(){this.currentQueryParams={},this.router=null,this.log("debug","QueryManager destroyed")}};var y=class{constructor(e,t={}){this.config={basePath:t.basePath||"/src",routesPath:t.routesPath||"/routes",environment:t.environment||"development",useLayout:t.useLayout!==!1,defaultLayout:t.defaultLayout||"default",useComponents:t.useComponents!==!1,debug:t.debug||!1},this.router=e,this.log("debug","RouteLoader initialized with config:",this.config)}async loadScript(e){let t;try{if(this.config.environment==="production"){let r=`${this.config.routesPath}/${e}.js`;this.log("debug",`Loading production route: ${r}`),t=(await import(r)).default}else{let r=`${this.config.basePath}/logic/${e}.js`;this.log("debug",`Loading development route: ${r}`),t=(await import(r)).default}if(!t)throw new Error(`Route '${e}' not found - no default export`)}catch(r){throw r.message.includes("Failed to resolve")||r.message.includes("Failed to fetch")||r.message.includes("not found")||r.name==="TypeError"?new Error(`Route '${e}' not found - 404`):r}return t}async loadTemplate(e){try{let t=await fetch(`${this.config.basePath}/views/${e}.html`);if(!t.ok)throw new Error(`Template not found: ${t.status}`);let r=await t.text();return this.log("debug",`Template '${e}' loaded successfully`),r}catch(t){return this.log("warn",`Template '${e}' not found, using default:`,t.message),this.generateDefaultTemplate(e)}}async loadStyle(e){try{let t=await fetch(`${this.config.basePath}/styles/${e}.css`);if(!t.ok)throw new Error(`Style not found: ${t.status}`);let r=await t.text();return this.log("debug",`Style '${e}' loaded successfully`),r}catch(t){return this.log("debug",`Style '${e}' not found, no styles applied:`,t.message),""}}async loadLayout(e){try{let t=await fetch(`${this.config.basePath}/layouts/${e}.html`);if(!t.ok)throw new Error(`Layout not found: ${t.status}`);let r=await t.text();return this.log("debug",`Layout '${e}' loaded successfully`),r}catch(t){return this.log("debug",`Layout '${e}' not found, no layout applied:`,t.message),null}}mergeLayoutWithTemplate(e,t,r){let a;return t.includes("{{ content }}")?a=t.replace(/{{ content }}/s,r):t.includes('class="main-content"')?(this.log("debug","Using main-content replacement"),a=t.replace(/(<div class="container">).*?(<\/div>\s*<\/main>)/s,`$1${r}$2`)):(this.log("debug","Wrapping template with layout"),a=`${t}
|
|
3
|
+
${r}`),a}async createVueComponent(e){let t=`component_${e}`,r=this.router.cacheManager?.getFromCache(t);if(r)return r;let a=await this.loadScript(e),o=this.router,i=this.config.environment==="production",n,s="",l=null;i?n=a.template||this.generateDefaultTemplate(e):(n=await this.loadTemplate(e),s=await this.loadStyle(e),l=this.config.useLayout&&a.layout!==null?await this.loadLayout(a.layout||this.config.defaultLayout):null,l&&(n=this.mergeLayoutWithTemplate(e,l,n)));let h={...a,name:a.name||this.toPascalCase(e),template:n,components:this.config.useComponents&&o.componentLoader?await o.componentLoader.loadAllComponents():{},data(){return{...a.data?a.data():{},currentRoute:e,pageTitle:a.pageTitle||o.routeLoader.generatePageTitle(e),showHeader:a.showHeader!==!1,headerTitle:a.headerTitle||o.routeLoader.generatePageTitle(e),headerSubtitle:a.headerSubtitle,$query:o.queryManager?.getQueryParams()||{},$lang:o.i18nManager?.getCurrentLanguage()||o.config.i18nDefaultLanguage,$dataLoading:!1}},computed:{...a.computed||{},params(){return o.queryManager?.getQueryParams()||{}}},async mounted(){a.mounted&&await a.mounted.call(this),a.dataURL&&await this.$fetchData()},methods:{...a.methods,navigateTo:(c,u)=>o.navigateTo(c,u),getCurrentRoute:()=>o.getCurrentRoute(),getQueryParams:()=>o.queryManager?.getQueryParams()||{},getQueryParam:c=>o.queryManager?.getQueryParam(c),setQueryParams:(c,u)=>o.queryManager?.setQueryParams(c,u),removeQueryParams:c=>o.queryManager?.removeQueryParams(c),$t:(c,u)=>o.i18nManager?.t(c,u)||c,$i18n:()=>o.i18nManager||null,$isAuthenticated:()=>o.authManager?.isUserAuthenticated()||!1,$logout:()=>o.authManager?o.navigateTo(o.authManager.handleLogout()):null,$loginSuccess:c=>o.authManager?o.navigateTo(o.authManager.handleLoginSuccess(c)):null,$checkAuth:c=>o.authManager?o.authManager.checkAuthentication(c):Promise.resolve({allowed:!0,reason:"auth_disabled"}),$getToken:()=>o.authManager?.getAccessToken()||null,$setToken:(c,u)=>o.authManager?.setAccessToken(c,u)||!1,$removeToken:c=>o.authManager?.removeAccessToken(c)||null,$getAuthCookie:()=>o.authManager?.getAuthCookie()||null,$getCookie:c=>o.authManager?.getCookieValue(c)||null,async $fetchData(){if(a.dataURL){this.$dataLoading=!0;try{let c=await o.routeLoader.fetchComponentData(a.dataURL);o.errorHandler&&o.errorHandler.debug("RouteLoader",`Data fetched for ${e}:`,c),Object.assign(this,c),this.$emit("data-loaded",c)}catch(c){o.errorHandler&&o.errorHandler.warn("RouteLoader",`Failed to fetch data for ${e}:`,c),this.$emit("data-error",c)}finally{this.$dataLoading=!1}}}},_routeName:e};return!i&&s&&(h._style=s),this.router.cacheManager?.setCache(t,h),h}toPascalCase(e){return e.split(/[-_\s]+/).map(t=>t.charAt(0).toUpperCase()+t.slice(1).toLowerCase()).join("")}generateDefaultTemplate(e){return`<div class="route-${e}"><h1>Route: ${e}</h1></div>`}async fetchComponentData(e){try{let t=this.router.queryManager?.buildQueryString(this.router.queryManager?.getQueryParams())||"",r=t?`${e}?${t}`:e;this.log("debug",`Fetching data from: ${r}`);let a=await fetch(r,{method:"GET",headers:{"Content-Type":"application/json",Accept:"application/json"}});if(!a.ok)throw new Error(`HTTP error! status: ${a.status}`);let o=await a.json();if(typeof o!="object"||o===null)throw new Error("Invalid data format: expected object");return o}catch(t){throw this.log("error","Failed to fetch component data:",t),t}}invalidateCache(e){this.router.cacheManager&&this.router.cacheManager.invalidateComponentCache(e),this.log("debug",`Cache invalidated for route: ${e}`)}getStats(){return{environment:this.config.environment,basePath:this.config.basePath,routesPath:this.config.routesPath,useLayout:this.config.useLayout,useComponents:this.config.useComponents}}generatePageTitle(e){return this.toPascalCase(e).replace(/([A-Z])/g," $1").trim()}log(e,...t){this.router?.errorHandler&&this.router.errorHandler.log(e,"RouteLoader",...t)}destroy(){this.log("debug","RouteLoader destroyed"),this.router=null}};var b=class{constructor(e,t={}){this.config={enableErrorReporting:t.enableErrorReporting!==!1,debug:t.debug||!1,logLevel:t.logLevel||(t.debug?"debug":"info"),environment:t.environment||"development"},this.router=e,this.logLevels={error:0,warn:1,info:2,debug:3},this.log("info","ErrorHandler","ErrorHandler initialized with config:",this.config)}async handleRouteError(e,t){let r=500,a="\uD398\uC774\uC9C0\uB97C \uB85C\uB4DC\uD560 \uC218 \uC5C6\uC2B5\uB2C8\uB2E4.";this.debug("ErrorHandler","\uC5D0\uB7EC \uC0C1\uC138:",t.message,t.name),t.message.includes("not found")||t.message.includes("404")||t.message.includes("Failed to resolve")||t.message.includes("Failed to fetch")||t.name==="TypeError"&&t.message.includes("resolve")?(r=404,a=`'${e}' \uD398\uC774\uC9C0\uB97C \uCC3E\uC744 \uC218 \uC5C6\uC2B5\uB2C8\uB2E4.`):t.message.includes("network")&&!t.message.includes("not found")?(r=503,a="\uB124\uD2B8\uC6CC\uD06C \uC5F0\uACB0\uC744 \uD655\uC778\uD574 \uC8FC\uC138\uC694."):(t.message.includes("permission")||t.message.includes("403"))&&(r=403,a="\uD398\uC774\uC9C0\uC5D0 \uC811\uADFC\uD560 \uAD8C\uD55C\uC774 \uC5C6\uC2B5\uB2C8\uB2E4."),this.debug("ErrorHandler",`\uC5D0\uB7EC \uCF54\uB4DC \uACB0\uC815: ${r} (\uB77C\uC6B0\uD2B8: ${e})`),this.config.enableErrorReporting&&this.reportError(e,t,r);try{r===404?await this.load404Page():await this.loadErrorPage(r,a)}catch(o){this.error("ErrorHandler","\uC5D0\uB7EC \uD398\uC774\uC9C0 \uB85C\uB529 \uC2E4\uD328:",o),this.showFallbackErrorPage(r,a)}}async load404Page(){try{this.info("ErrorHandler","Loading 404 page...");let e=await this.createVueComponent("404");await this.renderComponentWithTransition(e,"404"),this.info("ErrorHandler","404 page loaded successfully")}catch(e){this.error("ErrorHandler","404 page loading failed:",e),this.showFallbackErrorPage("404","\uD398\uC774\uC9C0\uB97C \uCC3E\uC744 \uC218 \uC5C6\uC2B5\uB2C8\uB2E4.")}}async loadErrorPage(e,t){try{this.info("ErrorHandler",`Loading error page for ${e}...`);let r=await this.createErrorComponent(e,t);await this.renderComponentWithTransition(r,"error"),this.info("ErrorHandler",`Error page ${e} loaded successfully`)}catch(r){this.error("ErrorHandler",`Error page ${e} loading failed:`,r),this.showFallbackErrorPage(e,t)}}async createErrorComponent(e,t){try{let r=await this.createVueComponent("error");return{...r,data(){return{...r.data?r.data():{},errorCode:e,errorMessage:t,showRetry:!0,showGoHome:!0}}}}catch(r){throw this.error("ErrorHandler","Error component load failed:",r),new Error(`Cannot load error page: ${r.message}`)}}showFallbackErrorPage(e,t){let r=document.getElementById("app");if(!r)return;let a=`
|
|
4
|
+
<div class="fallback-error-page" style="
|
|
5
|
+
display: flex;
|
|
6
|
+
flex-direction: column;
|
|
7
|
+
align-items: center;
|
|
8
|
+
justify-content: center;
|
|
9
|
+
min-height: 100vh;
|
|
10
|
+
padding: 2rem;
|
|
11
|
+
text-align: center;
|
|
12
|
+
background: #f8f9fa;
|
|
13
|
+
font-family: -apple-system, BlinkMacSystemFont, 'Segoe UI', Roboto, sans-serif;
|
|
14
|
+
">
|
|
15
|
+
<div style="
|
|
16
|
+
background: white;
|
|
17
|
+
padding: 3rem;
|
|
18
|
+
border-radius: 12px;
|
|
19
|
+
box-shadow: 0 4px 20px rgba(0,0,0,0.1);
|
|
20
|
+
max-width: 500px;
|
|
21
|
+
">
|
|
22
|
+
<h1 style="
|
|
23
|
+
font-size: 4rem;
|
|
24
|
+
margin: 0;
|
|
25
|
+
color: #dc3545;
|
|
26
|
+
font-weight: 300;
|
|
27
|
+
">${e}</h1>
|
|
28
|
+
<h2 style="
|
|
29
|
+
margin: 1rem 0;
|
|
30
|
+
color: #495057;
|
|
31
|
+
font-weight: 400;
|
|
32
|
+
">${t}</h2>
|
|
33
|
+
<p style="
|
|
34
|
+
color: #6c757d;
|
|
35
|
+
margin-bottom: 2rem;
|
|
36
|
+
line-height: 1.5;
|
|
37
|
+
">\uC694\uCCAD\uD558\uC2E0 \uD398\uC774\uC9C0\uB97C \uCC3E\uC744 \uC218 \uC5C6\uC2B5\uB2C8\uB2E4.</p>
|
|
38
|
+
<button onclick="window.location.hash = '#/'" style="
|
|
39
|
+
background: #007bff;
|
|
40
|
+
color: white;
|
|
41
|
+
border: none;
|
|
42
|
+
padding: 12px 24px;
|
|
43
|
+
border-radius: 6px;
|
|
44
|
+
cursor: pointer;
|
|
45
|
+
font-size: 1rem;
|
|
46
|
+
transition: background 0.2s;
|
|
47
|
+
" onmouseover="this.style.background='#0056b3'" onmouseout="this.style.background='#007bff'">
|
|
48
|
+
\uD648\uC73C\uB85C \uB3CC\uC544\uAC00\uAE30
|
|
49
|
+
</button>
|
|
50
|
+
</div>
|
|
51
|
+
</div>
|
|
52
|
+
`;r.innerHTML=a,this.info("ErrorHandler",`Fallback error page displayed for ${e}`)}reportError(e,t,r){let a={route:e,errorCode:r,errorMessage:t.message,stack:t.stack,url:window.location.href,userAgent:navigator.userAgent,timestamp:new Date().toISOString(),routerConfig:{environment:this.router.config.environment,mode:this.router.config.mode}};this.error("ErrorHandler","\uB77C\uC6B0\uD130 \uC5D0\uB7EC \uB9AC\uD3EC\uD2B8:",a)}async createVueComponent(e){if(this.router.routeLoader)return await this.router.routeLoader.createVueComponent(e);throw new Error("RouteLoader not available")}async renderComponentWithTransition(e,t){if(this.router.renderComponentWithTransition)return await this.router.renderComponentWithTransition(e,t);throw new Error("Render function not available")}log(e,t,...r){(typeof e!="string"||!this.logLevels.hasOwnProperty(e))&&(r=[t,...r],t=e,e=this.config.debug?"debug":"info");let a=this.logLevels[this.config.logLevel]||this.logLevels.info,o=this.logLevels[e]||this.logLevels.info;if(o>a||this.config.environment==="production"&&o>this.logLevels.warn)return;let i=t?`[${t}]`:"[ViewLogic]",n=new Date().toISOString().substring(11,23);switch(e){case"error":console.error(`${n} ${i}`,...r);break;case"warn":console.warn(`${n} ${i}`,...r);break;case"info":console.info(`${n} ${i}`,...r);break;case"debug":console.log(`${n} ${i}`,...r);break;default:console.log(`${n} ${i}`,...r)}}error(e,...t){this.log("error",e,...t)}warn(e,...t){this.log("warn",e,...t)}info(e,...t){this.log("info",e,...t)}debug(e,...t){this.log("debug",e,...t)}destroy(){this.router=null,this.info("ErrorHandler","ErrorHandler destroyed")}};var w=class{constructor(e=null,t={}){this.config={basePath:t.basePath||"/src/components",debug:t.debug||!1,environment:t.environment||"development",...t},this.router=e,this.loadingPromises=new Map,this.unifiedComponents=null}log(e,...t){this.router?.errorHandler&&this.router.errorHandler.log(e,"ComponentLoader",...t)}async loadComponent(e){if(!e||typeof e!="string")throw new Error("Component name must be a non-empty string");if(this.loadingPromises.has(e))return this.loadingPromises.get(e);let t=this._loadComponentFromFile(e);this.loadingPromises.set(e,t);try{return await t}catch(r){throw r}finally{this.loadingPromises.delete(e)}}async _loadComponentFromFile(e){let t=`${this.config.basePath}/${e}.js`;try{let a=(await import(t)).default;if(!a)throw new Error(`Component '${e}' has no default export`);return a.name||(a.name=e),this.log("debug",`Component '${e}' loaded successfully`),a}catch(r){throw this.log("error",`Failed to load component '${e}':`,r),new Error(`Component '${e}' not found: ${r.message}`)}}clearComponents(){this.loadingPromises.clear(),this.unifiedComponents=null,this.log("debug","All components cleared")}async loadAllComponents(){return this.unifiedComponents?(this.log("debug","Using existing unified components"),this.unifiedComponents):this.config.environment==="production"?await this._loadProductionComponents():await this._loadDevelopmentComponents()}async _loadProductionComponents(){try{let e=`${this.config.routesPath}/_components.js`;this.log("info","[PRODUCTION] Loading unified components from:",e);let t=await import(e);if(typeof t.registerComponents=="function")return this.unifiedComponents=t.components||{},this.log("info",`[PRODUCTION] Unified components loaded: ${Object.keys(this.unifiedComponents).length} components`),this.unifiedComponents;throw new Error("registerComponents function not found in components module")}catch(e){return this.log("warn","[PRODUCTION] Failed to load unified components:",e.message),this.unifiedComponents={},{}}}async _loadDevelopmentComponents(){let e=this._getComponentNames(),t={};this.log("info",`[DEVELOPMENT] Loading individual components: ${e.join(", ")}`);for(let r of e)try{let a=await this.loadComponent(r);a&&(t[r]=a)}catch(a){this.log("warn",`[DEVELOPMENT] Failed to load component ${r}:`,a.message)}return this.unifiedComponents=t,this.log("info",`[DEVELOPMENT] Individual components loaded: ${Object.keys(t).length} components`),t}_getComponentNames(){return Array.isArray(this.config.componentNames)&&this.config.componentNames.length>0?[...this.config.componentNames]:["Button","Modal","Card","Toast","Input","Tabs","Checkbox","Alert","DynamicInclude","HtmlInclude"]}dispose(){this.clearComponents(),this.log("debug","ComponentLoader disposed"),this.router=null}};var C=class{constructor(e={}){this.version=e.version||"1.0.0",this.config=this._buildConfig(e),this.currentHash="",this.currentVueApp=null,this.previousVueApp=null,this.componentLoader=null,this.transitionInProgress=!1,this.isReady=!1,this.readyPromise=null,this._boundHandleRouteChange=this.handleRouteChange.bind(this),this.readyPromise=this.initialize()}_buildConfig(e){return{...{basePath:"/src",mode:"hash",cacheMode:"memory",cacheTTL:3e5,maxCacheSize:50,useLayout:!0,defaultLayout:"default",environment:"development",routesPath:"/routes",enableErrorReporting:!0,useComponents:!0,componentNames:["Button","Modal","Card","Toast","Input","Tabs","Checkbox","Alert","DynamicInclude","HtmlInclude"],useI18n:!0,defaultLanguage:"ko",logLevel:"info",authEnabled:!1,loginRoute:"login",protectedRoutes:[],protectedPrefixes:[],publicRoutes:["login","register","home"],checkAuthFunction:null,redirectAfterLogin:"home",authCookieName:"authToken",authFallbackCookieNames:["accessToken","token","jwt"],authStorage:"cookie",authCookieOptions:{},authSkipValidation:!1,enableParameterValidation:!0,maxParameterLength:1e3,maxParameterCount:50,maxArraySize:100,allowedKeyPattern:/^[a-zA-Z0-9_-]+$/,logSecurityWarnings:!0},...e}}log(e,...t){this.errorHandler&&this.errorHandler.log(e,"Router",...t)}async initialize(){try{this.cacheManager=new m(this,this.config),this.routeLoader=new y(this,this.config),this.queryManager=new p(this,this.config),this.errorHandler=new b(this,this.config),this.config.useI18n&&(this.i18nManager=new d(this,this.config),this.i18nManager.initPromise&&await this.i18nManager.initPromise),this.config.authEnabled&&(this.authManager=new f(this,this.config)),this.config.useComponents&&(this.componentLoader=new w(this,{...this.config,basePath:this.config.basePath+"/components",cache:!0,componentNames:this.config.componentNames}),await this.componentLoader.loadAllComponents()),this.isReady=!0,this.init()}catch(e){this.log("error","Router initialization failed:",e),this.isReady=!0,this.init()}}async waitForReady(){return this.isReady?!0:(this.readyPromise&&await this.readyPromise,this.isReady)}init(){let e=this.config.mode==="hash";window.addEventListener(e?"hashchange":"popstate",this._boundHandleRouteChange);let t=()=>{e&&!window.location.hash?window.location.hash="#/":!e&&window.location.pathname==="/"?this.navigateTo("home"):this.handleRouteChange()};document.readyState==="loading"?document.addEventListener("DOMContentLoaded",t):requestAnimationFrame(t)}handleRouteChange(){let{route:e,queryParams:t}=this._parseCurrentLocation();this.queryManager?.setCurrentQueryParams(t),(e!==this.currentHash||this.queryManager?.hasQueryParamsChanged(t))&&(this.currentHash=e,this.loadRoute(e))}_parseCurrentLocation(){if(this.config.mode==="hash"){let e=window.location.hash.slice(1)||"/",[t,r]=e.split("?"),a="home";return t&&t!=="/"&&(a=t.startsWith("/")?t.slice(1):t),{route:a||"home",queryParams:this.queryManager?.parseQueryString(r||window.location.search.slice(1))||{}}}else return{route:window.location.pathname.slice(1)||"home",queryParams:this.queryManager?.parseQueryString(window.location.search.slice(1))||{}}}async loadRoute(e){if(!this.transitionInProgress)try{if(this.transitionInProgress=!0,!(this.authManager?await this.authManager.checkAuthentication(e):{allowed:!0,reason:"auth_disabled"}).allowed){if(this.authManager){this.authManager.emitAuthEvent("auth_required",{originalRoute:e,loginRoute:this.config.loginRoute});let i=e!==this.config.loginRoute?`${this.config.loginRoute}?redirect=${encodeURIComponent(e)}`:this.config.loginRoute;this.navigateTo(i)}return}if(!document.getElementById("app"))throw new Error("App element not found");let o=await this.routeLoader.createVueComponent(e);await this.renderComponentWithTransition(o,e)}catch(r){this.log("error",`Route loading failed [${e}]:`,r.message),this.errorHandler?await this.errorHandler.handleRouteError(e,r):console.error("[Router] No error handler available")}finally{this.transitionInProgress=!1}}async renderComponentWithTransition(e,t){let r=document.getElementById("app");if(!r)return;let a=document.createElement("div");a.className="page-container page-entered",a.id=`page-${t}-${Date.now()}`,r.querySelectorAll(".page-container").forEach(s=>{s.classList.remove("page-entered"),s.classList.add("page-exiting")}),r.appendChild(a),this.config.environment==="development"&&e._style&&this.applyStyle(e._style,t);let{createApp:i}=Vue,n=i(e);n.config.globalProperties.$router={navigateTo:(s,l)=>this.navigateTo(s,l),getCurrentRoute:()=>this.getCurrentRoute(),getQueryParams:()=>this.queryManager?.getQueryParams()||{},getQueryParam:s=>this.queryManager?.getQueryParam(s),setQueryParams:(s,l)=>this.queryManager?.setQueryParams(s,l),removeQueryParams:s=>this.queryManager?.removeQueryParams(s),currentRoute:this.currentHash,currentQuery:this.queryManager?.getQueryParams()||{}},n.mount(`#${a.id}`),requestAnimationFrame(()=>{this.cleanupPreviousPages(),this.transitionInProgress=!1}),this.currentVueApp&&(this.previousVueApp=this.currentVueApp),this.currentVueApp=n}cleanupPreviousPages(){let e=document.getElementById("app");if(!e)return;let t=document.createDocumentFragment();if(e.querySelectorAll(".page-container.page-exiting").forEach(a=>a.remove()),this.previousVueApp){try{this.previousVueApp.unmount()}catch{}this.previousVueApp=null}e.querySelector(".loading")?.remove()}applyStyle(e,t){let r=document.querySelector(`style[data-route="${t}"]`);if(r&&r.remove(),e){let a=document.createElement("style");a.textContent=e,a.setAttribute("data-route",t),document.head.appendChild(a)}}navigateTo(e,t=null){typeof e=="object"&&(t=e.params||null,e=e.route),e!==this.currentHash&&this.queryManager&&this.queryManager.clearQueryParams(),this.updateURL(e,t)}getCurrentRoute(){return this.currentHash}updateURL(e,t=null){let r=t||this.queryManager?.getQueryParams()||{},a=this.queryManager?.buildQueryString(r)||"",o=(i,n,s=!0)=>{let l=i==="home"?"/":`/${i}`,h=n?`${l}?${n}`:l;return s?`#${h}`:h};if(this.config.mode==="hash"){let i=o(e,a);window.location.hash!==i&&(window.location.hash=i)}else{let i=o(e,a,!1);window.location.pathname===(e==="home"?"/":`/${e}`)?window.history.replaceState({},"",i):window.history.pushState({},"",i),this.handleRouteChange()}}destroy(){window.removeEventListener(this.config.mode==="hash"?"hashchange":"popstate",this._boundHandleRouteChange),this.currentVueApp&&(this.currentVueApp.unmount(),this.currentVueApp=null),this.previousVueApp&&(this.previousVueApp.unmount(),this.previousVueApp=null),Object.values(this).forEach(t=>{t&&typeof t.destroy=="function"&&t.destroy()}),this.cacheManager?.clearAll();let e=document.getElementById("app");e&&(e.innerHTML=""),this.log("info","Router destroyed")}};export{C as ViewLogicRouter};
|
|
53
|
+
//# sourceMappingURL=viewlogic-router.min.js.map
|