UNPKG

@tastekim/chat-cli

Version:

๐Ÿ’ฌConnect with developers worldwide through an interactive terminal chat experience while you code!๐Ÿ’ป

165 lines โ€ข 5.67 kB
import https from 'https'; export class LocationDetector { /** * ์‚ฌ์šฉ์ž์˜ ์ง€์—ญ ์ •๋ณด๋ฅผ ๊ฐ์ง€ํ•ฉ๋‹ˆ๋‹ค. * IP ๊ธฐ๋ฐ˜ ๊ฐ์ง€๋ฅผ ์šฐ์„  ์‹œ๋„ํ•˜๊ณ , ์‹คํŒจ ์‹œ ๋กœ์ผ€์ผ ๊ธฐ๋ฐ˜์œผ๋กœ fallbackํ•ฉ๋‹ˆ๋‹ค. */ static async detectLocation() { try { // 1์ฐจ: IP ๊ธฐ๋ฐ˜ ๊ฐ์ง€ (๋” ์ •ํ™•) const ipLocation = await this.getLocationFromIP(); return { country: ipLocation.country, countryCode: ipLocation.country_code, source: 'ip' }; } catch (error) { // 2์ฐจ: ๋กœ์ผ€์ผ ๊ธฐ๋ฐ˜ ๊ฐ์ง€ (์˜คํ”„๋ผ์ธ ๊ฐ€๋Šฅ) return this.getLocationFromLocale(); } } /** * IP ๊ธฐ๋ฐ˜์œผ๋กœ ์ง€์—ญ ์ •๋ณด๋ฅผ ๊ฐ€์ ธ์˜ต๋‹ˆ๋‹ค. */ static async getLocationFromIP() { return new Promise((resolve, reject) => { const request = https.get('https://ipapi.co/json/', { timeout: this.TIMEOUT_MS, headers: { 'User-Agent': 'chat-cli-location-detector' } }, (response) => { let data = ''; response.on('data', (chunk) => { data += chunk; }); response.on('end', () => { try { const locationData = JSON.parse(data); if (locationData.country_code && locationData.country_name) { resolve({ country: locationData.country_name, country_code: locationData.country_code }); } else { reject(new Error('Invalid response format')); } } catch (error) { reject(new Error('Failed to parse location response')); } }); }); request.on('error', (error) => { reject(error); }); request.on('timeout', () => { request.destroy(); reject(new Error('Request timeout')); }); }); } /** * ์‹œ์Šคํ…œ ๋กœ์ผ€์ผ ๊ธฐ๋ฐ˜์œผ๋กœ ์ง€์—ญ ์ •๋ณด๋ฅผ ๊ฐ€์ ธ์˜ต๋‹ˆ๋‹ค. */ static getLocationFromLocale() { try { // Intl API๋ฅผ ์‚ฌ์šฉํ•œ ๋กœ์ผ€์ผ ๊ฐ์ง€ const locale = Intl.DateTimeFormat().resolvedOptions().locale; const intlLocale = new Intl.Locale(locale); if (intlLocale.region) { return { country: this.getCountryNameFromCode(intlLocale.region), countryCode: intlLocale.region, source: 'locale' }; } } catch (error) { // Intl API ์‹คํŒจ ์‹œ ํ™˜๊ฒฝ๋ณ€์ˆ˜ ์‚ฌ์šฉ } // ํ™˜๊ฒฝ๋ณ€์ˆ˜์—์„œ ๋กœ์ผ€์ผ ์ถ”์ถœ const envLocale = process.env.LANG || process.env.LC_ALL || 'en_US.UTF-8'; const countryCode = envLocale.split('_')[1]?.split('.')[0] || 'US'; return { country: this.getCountryNameFromCode(countryCode), countryCode, source: 'locale' }; } /** * ๊ตญ๊ฐ€ ์ฝ”๋“œ๋ฅผ ๊ตญ๊ฐ€๋ช…์œผ๋กœ ๋ณ€ํ™˜ํ•ฉ๋‹ˆ๋‹ค. */ static getCountryNameFromCode(countryCode) { const countryMap = { 'US': 'United States', 'KR': 'South Korea', 'JP': 'Japan', 'CN': 'China', 'GB': 'United Kingdom', 'DE': 'Germany', 'FR': 'France', 'CA': 'Canada', 'AU': 'Australia', 'IN': 'India', 'BR': 'Brazil', 'RU': 'Russia', 'IT': 'Italy', 'ES': 'Spain', 'NL': 'Netherlands', 'SE': 'Sweden', 'NO': 'Norway', 'DK': 'Denmark', 'FI': 'Finland', 'PL': 'Poland', 'CZ': 'Czech Republic', 'AT': 'Austria', 'CH': 'Switzerland', 'BE': 'Belgium', 'PT': 'Portugal', 'IE': 'Ireland', 'IL': 'Israel', 'TR': 'Turkey', 'ZA': 'South Africa', 'EG': 'Egypt', 'NG': 'Nigeria', 'KE': 'Kenya', 'MA': 'Morocco', 'TH': 'Thailand', 'VN': 'Vietnam', 'SG': 'Singapore', 'MY': 'Malaysia', 'ID': 'Indonesia', 'PH': 'Philippines', 'TW': 'Taiwan', 'HK': 'Hong Kong', 'MX': 'Mexico', 'AR': 'Argentina', 'CL': 'Chile', 'CO': 'Colombia', 'PE': 'Peru', 'VE': 'Venezuela' }; return countryMap[countryCode.toUpperCase()] || countryCode; } /** * ๊ตญ๊ฐ€ ์ฝ”๋“œ๋ฅผ ์ด๋ชจ์ง€ ํ”Œ๋ž˜๊ทธ๋กœ ๋ณ€ํ™˜ํ•ฉ๋‹ˆ๋‹ค. */ static getCountryFlag(countryCode) { if (!countryCode || countryCode.length !== 2) return '๐ŸŒ'; const codePoints = countryCode.toUpperCase().split('').map(char => 127397 + char.charCodeAt(0)); return String.fromCodePoint(...codePoints); } /** * ์ง€์—ญ ์ •๋ณด๋ฅผ ์ฝ๊ธฐ ์‰ฌ์šด ํ˜•ํƒœ๋กœ ํฌ๋งทํ•ฉ๋‹ˆ๋‹ค. */ static formatLocation(locationInfo) { const flag = this.getCountryFlag(locationInfo.countryCode); return `${flag}${locationInfo.countryCode}`; } } LocationDetector.TIMEOUT_MS = 3000; //# sourceMappingURL=location-detector.js.map