// 네이버 지도 JS SDK 동적 로더 (싱글턴) // 키는 네이버 클라우드 플랫폼(Maps)에서 발급. .env 의 VITE_NAVER_MAP_CLIENT_ID 로 주입. let loadPromise: Promise | null = null // 인증 실패(잘못된 키/미등록 도메인) 콜백. 네이버 SDK 가 전역 navermap_authFailure 를 호출. const authFailureHandlers: Array<() => void> = [] export function onNaverAuthFailure(cb: () => void): void { authFailureHandlers.push(cb) } export function loadNaverMaps(): Promise { if (typeof window !== 'undefined' && window.naver?.maps) { return Promise.resolve(window.naver) } if (loadPromise) { return loadPromise } const clientId = import.meta.env.VITE_NAVER_MAP_CLIENT_ID // 신규 키는 ncpKeyId, 구형 키는 ncpClientId. 필요 시 env 로 전환. const authParam = import.meta.env.VITE_NAVER_MAP_AUTH_PARAM || 'ncpKeyId' // 네이버 SDK 는 인증 실패 시 이 전역 함수를 호출한다. ;(window as unknown as { navermap_authFailure?: () => void }).navermap_authFailure = () => { authFailureHandlers.forEach((h) => h()) } loadPromise = new Promise((resolve, reject) => { if (!clientId) { reject(new Error('VITE_NAVER_MAP_CLIENT_ID 가 설정되지 않았습니다.')) return } const script = document.createElement('script') script.src = `https://openapi.map.naver.com/openapi/v3/maps.js?${authParam}=${clientId}` script.async = true script.onload = () => resolve(window.naver) script.onerror = () => reject(new Error('네이버 지도 SDK 를 불러오지 못했습니다.')) document.head.appendChild(script) }) return loadPromise }