diff --git a/app/_components/BubbleDiv.tsx b/app/_components/BubbleDiv.tsx index c8d6dd4..5414e00 100644 --- a/app/_components/BubbleDiv.tsx +++ b/app/_components/BubbleDiv.tsx @@ -40,7 +40,8 @@ const BubbleDiv = ({
{children || ( <> - 현재 775명 참여중이에요! + 현재 775명{" "} + 참여중이에요! )}
diff --git a/app/hobby-select/_components/ScreenHobbySelect.tsx b/app/hobby-select/_components/ScreenHobbySelect.tsx index 7b3b292..9df13e8 100644 --- a/app/hobby-select/_components/ScreenHobbySelect.tsx +++ b/app/hobby-select/_components/ScreenHobbySelect.tsx @@ -18,7 +18,7 @@ const ALL_HOBBIES = Object.values(HOBBIES).flat() as string[]; const ScreenHobbySelect = () => { const router = useRouter(); const { profile, updateProfile } = useProfile(); - + // 취미 이름으로 카테고리를 찾는 헬퍼 함수 const findCategoryByHobbyName = (name: string): HobbyCategory => { const found = (Object.keys(HOBBIES) as HobbyCategory[]).find((cat) => @@ -88,10 +88,12 @@ const ScreenHobbySelect = () => { const getHobbiesByCategory = (category: HobbyCategory) => { const predefined = HOBBIES[category]; // 사용자가 이 카테고리에 추가했던 모든 커스텀 취미 추출 - const customInCategory = addedCustomHobbies.filter(h => h.category === category); + const customInCategory = addedCustomHobbies.filter( + (h) => h.category === category, + ); return { predefined, - customInCategory + customInCategory, }; }; @@ -115,7 +117,7 @@ const ScreenHobbySelect = () => {
{filteredHobbies.length > 0 ? ( filteredHobbies.map((hobby) => { - const isSelected = selected.some(h => h.name === hobby); + const isSelected = selected.some((h) => h.name === hobby); return ( {
) : ( (Object.keys(HOBBIES) as HobbyCategory[]).map((category) => { - const { predefined, customInCategory } = getHobbiesByCategory(category); + const { predefined, customInCategory } = + getHobbiesByCategory(category); return (

{category}

@@ -145,7 +148,7 @@ const ScreenHobbySelect = () => { toggleHobby(hobby)} - selected={selected.some(h => h.name === hobby)} + selected={selected.some((h) => h.name === hobby)} > {hobby} @@ -155,7 +158,7 @@ const ScreenHobbySelect = () => { toggleHobby(hobby.name, category)} - selected={selected.some(h => h.name === hobby.name)} + selected={selected.some((h) => h.name === hobby.name)} > {hobby.name} diff --git a/app/layout.tsx b/app/layout.tsx index 701fbeb..b4bf06b 100644 --- a/app/layout.tsx +++ b/app/layout.tsx @@ -3,9 +3,10 @@ import localFont from "next/font/local"; import "./globals.css"; import Blur from "@/components/common/Blur"; import { QueryProvider } from "@/providers/query-provider"; +import { ServiceStatusProvider } from "@/providers/service-status-provider"; import { ProfileProvider } from "@/providers/profile-provider"; -// import { ServiceStatusProvider } from "@/providers/service-status-provider"; -// import { getInitialMaintenanceStatus } from "@/lib/status"; +import { getInitialMaintenanceStatus } from "@/lib/status"; +import FcmInitializer from "@/components/common/FcmInitializer"; const pretendard = localFont({ src: "./fonts/PretendardVariable.woff2", @@ -56,7 +57,7 @@ export default async function RootLayout({ }: Readonly<{ children: React.ReactNode; }>) { - // const initialMaintenanceMode = await getInitialMaintenanceStatus(); + const initialMaintenanceMode = await getInitialMaintenanceStatus(); return ( @@ -64,16 +65,17 @@ export default async function RootLayout({ className={`${pretendard.className} flex justify-center bg-white antialiased`} > - - {/* */} -
- - {children} -
- {/*
*/} -
+ + +
+ + + {children} +
+
+
diff --git a/app/login/_components/LoginForm.tsx b/app/login/_components/LoginForm.tsx index 244501a..8207dff 100644 --- a/app/login/_components/LoginForm.tsx +++ b/app/login/_components/LoginForm.tsx @@ -68,9 +68,7 @@ export const LoginForm = () => {
- - 아직 계정이 없으신가요?! - + 아직 계정이 없으신가요?! { + // 세션 당 1회만 실행 (페이지 이동마다 중복 등록 방지) + if (sessionStorage.getItem(FCM_REGISTERED_KEY)) return; + + const registerFcmToken = async () => { + try { + // 알림 권한 요청 + const permission = await Notification.requestPermission(); + if (permission !== "granted") { + console.log("[FCM] 알림 권한 거부됨. 토큰 등록 skip."); + return; + } + + // Firebase에서 FCM 토큰 발급 + const token = await registerServiceWorkerAndGetToken(); + if (!token) { + console.warn("[FCM] 토큰 발급 실패."); + return; + } + + // 백엔드에 FCM 토큰 등록 + await api.post("/api/fcm/token", { token }); + + // 세션 플래그 저장 (재등록 방지) + sessionStorage.setItem(FCM_REGISTERED_KEY, "true"); + console.log("[FCM] 토큰 등록 완료."); + } catch (error) { + console.error("[FCM] 토큰 등록 중 오류:", error); + } + }; + + registerFcmToken(); + }, []); + + return null; +} diff --git a/lib/axios.ts b/lib/axios.ts index b89d044..75820fe 100644 --- a/lib/axios.ts +++ b/lib/axios.ts @@ -32,6 +32,7 @@ api.interceptors.response.use( return api(originalRequest); } catch (reissueError) { // 재발급 실패 → 로그인 페이지로 리다이렉트 + alert("로그인 세션이 만료되었습니다. 다시 로그인해주세요."); window.location.href = "/login"; return Promise.reject(reissueError); } diff --git a/lib/constants/nicknames.ts b/lib/constants/nicknames.ts index e4ff646..0daaf2a 100644 --- a/lib/constants/nicknames.ts +++ b/lib/constants/nicknames.ts @@ -1,23 +1,108 @@ export const NICKNAME_MODIFIERS = [ // 리듬/움직임 - "노래하는", "춤추는", "뛰어노는", "구르는", "빙글도는", "날아가는", "흐느적이는", "뒹구는", "달리는", "흔들리는", + "노래하는", + "춤추는", + "뛰어노는", + "구르는", + "빙글도는", + "날아가는", + "흐느적이는", + "뒹구는", + "달리는", + "흔들리는", // 감정/표정 - "웃는", "반짝이는", "두근대는", "깔깔대는", "놀라는", "감탄하는", "감동한", "행복한", "수줍은", "즐거운", + "웃는", + "반짝이는", + "두근대는", + "깔깔대는", + "놀라는", + "감탄하는", + "감동한", + "행복한", + "수줍은", + "즐거운", // 상태/분위기 - "반짝반짝한", "포근한", "시원한", "따뜻한", "향기나는", "알록달록한", "몽글몽글한", "부드러운", "촉촉한", + "반짝반짝한", + "포근한", + "시원한", + "따뜻한", + "향기나는", + "알록달록한", + "몽글몽글한", + "부드러운", + "촉촉한", // 행동 스타일 - "장난치는", "휘파람 부는", "손흔드는", "인사하는", "하품하는", "손뻗는", "끄덕이는", "기지개 켜는", "숨바꼭질하는", + "장난치는", + "휘파람 부는", + "손흔드는", + "인사하는", + "하품하는", + "손뻗는", + "끄덕이는", + "기지개 켜는", + "숨바꼭질하는", // 캐릭터 감성 - "멋부린", "잠에서 깬", "바람 타는", "구경하는", "편지 쓰는", "노을 보는", "초콜릿 든", "선물 고르는" + "멋부린", + "잠에서 깬", + "바람 타는", + "구경하는", + "편지 쓰는", + "노을 보는", + "초콜릿 든", + "선물 고르는", ]; export const NICKNAME_NOUNS = [ // 동물 - "나무늘보", "햄스터", "다람쥐", "고슴도치", "기린", "오리", "판다", "앵무새", "물개", "코알라", "돌고래", "코끼리", "라마", "고래", "아기곰", + "나무늘보", + "햄스터", + "다람쥐", + "고슴도치", + "기린", + "오리", + "판다", + "앵무새", + "물개", + "코알라", + "돌고래", + "코끼리", + "라마", + "고래", + "아기곰", // 식물/꽃 - "데이지", "민들레", "코스모스", "라벤더", "동백꽃", "연꽃", "수국", "벚꽃잎", "클로버", "벚꽃", "해바라기", + "데이지", + "민들레", + "코스모스", + "라벤더", + "동백꽃", + "연꽃", + "수국", + "벚꽃잎", + "클로버", + "벚꽃", + "해바라기", // 자연/사물 - "파도", "구름", "별똥별", "바람", "노을", "햇살", "모래성", "무지개", "달빛", "눈송이", + "파도", + "구름", + "별똥별", + "바람", + "노을", + "햇살", + "모래성", + "무지개", + "달빛", + "눈송이", // 캐릭터형 단어 - "화가", "작가", "바리스타", "제빵사", "소방관", "탐험가", "마술사", "사진작가", "연기자", "시인", "조향사", "고고학자" + "화가", + "작가", + "바리스타", + "제빵사", + "소방관", + "탐험가", + "마술사", + "사진작가", + "연기자", + "시인", + "조향사", + "고고학자", ]; diff --git a/lib/firebase.ts b/lib/firebase.ts new file mode 100644 index 0000000..a4f86a5 --- /dev/null +++ b/lib/firebase.ts @@ -0,0 +1,69 @@ +"use client"; + +import { initializeApp, getApps } from "firebase/app"; +import { getAnalytics } from "firebase/analytics"; +import { getMessaging, getToken, onMessage } from "firebase/messaging"; + +export const firebaseConfig = { + apiKey: process.env.NEXT_PUBLIC_FIREBASE_API_KEY, + authDomain: process.env.NEXT_PUBLIC_FIREBASE_AUTH_DOMAIN, + projectId: process.env.NEXT_PUBLIC_FIREBASE_PROJECT_ID, + storageBucket: process.env.NEXT_PUBLIC_FIREBASE_STORAGE_BUCKET, + messagingSenderId: process.env.NEXT_PUBLIC_FIREBASE_MESSAGING_SENDER_ID, + appId: process.env.NEXT_PUBLIC_FIREBASE_APP_ID, + measurementId: process.env.NEXT_PUBLIC_FIREBASE_MEASUREMENT_ID, +}; + +// Initialize Firebase (중복 초기화 방지) +const app = + getApps().length === 0 ? initializeApp(firebaseConfig) : getApps()[0]; + +// Analytics (브라우저에서만 실행) +let analytics; +if (typeof window !== "undefined") { + analytics = getAnalytics(app); +} + +// 서비스 워커 등록 및 FCM 토큰 가져오기 +export async function registerServiceWorkerAndGetToken() { + if (typeof window === "undefined" || !("serviceWorker" in navigator)) { + return null; + } + + try { + // 서비스 워커 등록 + const registration = await navigator.serviceWorker.register( + "/firebase-messaging-sw.js", + ); + + // 서비스 워커에 Firebase Config 전달 + registration.active?.postMessage({ + type: "INIT_FIREBASE", + config: firebaseConfig, + }); + + // Messaging 인스턴스 가져오기 + const messaging = getMessaging(app); + + // FCM 토큰 요청 + const token = await getToken(messaging, { + vapidKey: process.env.NEXT_PUBLIC_FIREBASE_VAPID_KEY, + serviceWorkerRegistration: registration, + }); + + console.log("FCM Token:", token); + + // 포그라운드 메시지 수신 리스너 + onMessage(messaging, (payload) => { + console.log("[Foreground] 메시지 수신:", payload); + // 여기에 포그라운드 알림 UI 처리 + }); + + return token; + } catch (error) { + console.error("서비스 워커 등록 실패:", error); + return null; + } +} + +export { app, analytics }; diff --git a/lib/server-api.ts b/lib/server-api.ts index db13347..8dc888d 100644 --- a/lib/server-api.ts +++ b/lib/server-api.ts @@ -66,6 +66,7 @@ serverClient.interceptors.response.use( return serverClient(originalRequest); } catch { // 재발급 실패 → 로그인 페이지로 + alert("로그인 세션이 만료되었습니다. 다시 로그인해주세요."); redirect("/login"); } } diff --git a/lib/utils/nickname.ts b/lib/utils/nickname.ts index 99c37bd..500bffe 100644 --- a/lib/utils/nickname.ts +++ b/lib/utils/nickname.ts @@ -4,7 +4,9 @@ import { NICKNAME_MODIFIERS, NICKNAME_NOUNS } from "../constants/nicknames"; * 랜덤한 닉네임을 생성합니다 (수식어 + 명사) */ export const generateRandomNickname = () => { - const modifier = NICKNAME_MODIFIERS[Math.floor(Math.random() * NICKNAME_MODIFIERS.length)]; - const noun = NICKNAME_NOUNS[Math.floor(Math.random() * NICKNAME_NOUNS.length)]; + const modifier = + NICKNAME_MODIFIERS[Math.floor(Math.random() * NICKNAME_MODIFIERS.length)]; + const noun = + NICKNAME_NOUNS[Math.floor(Math.random() * NICKNAME_NOUNS.length)]; return `${modifier} ${noun}`; }; diff --git a/package.json b/package.json index 88c87dd..abe87c6 100644 --- a/package.json +++ b/package.json @@ -19,6 +19,7 @@ "axios": "^1.13.4", "class-variance-authority": "^0.7.1", "clsx": "^2.1.1", + "firebase": "^12.8.0", "heic2any": "^0.0.4", "lucide-react": "^0.562.0", "next": "16.1.3", diff --git a/pnpm-lock.yaml b/pnpm-lock.yaml index a60b115..c44ab97 100644 --- a/pnpm-lock.yaml +++ b/pnpm-lock.yaml @@ -26,6 +26,9 @@ importers: clsx: specifier: ^2.1.1 version: 2.1.1 + firebase: + specifier: ^12.8.0 + version: 12.8.0 heic2any: specifier: ^0.0.4 version: 0.0.4 @@ -211,6 +214,225 @@ packages: resolution: {integrity: sha512-43/qtrDUokr7LJqoF2c3+RInu/t4zfrpYdoSDfYyhg52rwLV6TnOvdG4fXm7IkSB3wErkcmJS9iEhjVtOSEjjA==} engines: {node: ^18.18.0 || ^20.9.0 || >=21.1.0} + '@firebase/ai@2.7.0': + resolution: {integrity: sha512-PwpCz+TtAMWICM7uQNO0mkSPpUKwrMV4NSwHkbVKDvPKoaQmSlO96vIz+Suw2Ao1EaUUsxYb5LGImHWt/fSnRQ==} + engines: {node: '>=20.0.0'} + peerDependencies: + '@firebase/app': 0.x + '@firebase/app-types': 0.x + + '@firebase/analytics-compat@0.2.25': + resolution: {integrity: sha512-fdzoaG0BEKbqksRDhmf4JoyZf16Wosrl0Y7tbZtJyVDOOwziE0vrFjmZuTdviL0yhak+Nco6rMsUUbkbD+qb6Q==} + peerDependencies: + '@firebase/app-compat': 0.x + + '@firebase/analytics-types@0.8.3': + resolution: {integrity: sha512-VrIp/d8iq2g501qO46uGz3hjbDb8xzYMrbu8Tp0ovzIzrvJZ2fvmj649gTjge/b7cCCcjT0H37g1gVtlNhnkbg==} + + '@firebase/analytics@0.10.19': + resolution: {integrity: sha512-3wU676fh60gaiVYQEEXsbGS4HbF2XsiBphyvvqDbtC1U4/dO4coshbYktcCHq+HFaGIK07iHOh4pME0hEq1fcg==} + peerDependencies: + '@firebase/app': 0.x + + '@firebase/app-check-compat@0.4.0': + resolution: {integrity: sha512-UfK2Q8RJNjYM/8MFORltZRG9lJj11k0nW84rrffiKvcJxLf1jf6IEjCIkCamykHE73C6BwqhVfhIBs69GXQV0g==} + engines: {node: '>=20.0.0'} + peerDependencies: + '@firebase/app-compat': 0.x + + '@firebase/app-check-interop-types@0.3.3': + resolution: {integrity: sha512-gAlxfPLT2j8bTI/qfe3ahl2I2YcBQ8cFIBdhAQA4I2f3TndcO+22YizyGYuttLHPQEpWkhmpFW60VCFEPg4g5A==} + + '@firebase/app-check-types@0.5.3': + resolution: {integrity: sha512-hyl5rKSj0QmwPdsAxrI5x1otDlByQ7bvNvVt8G/XPO2CSwE++rmSVf3VEhaeOR4J8ZFaF0Z0NDSmLejPweZ3ng==} + + '@firebase/app-check@0.11.0': + resolution: {integrity: sha512-XAvALQayUMBJo58U/rxW02IhsesaxxfWVmVkauZvGEz3vOAjMEQnzFlyblqkc2iAaO82uJ2ZVyZv9XzPfxjJ6w==} + engines: {node: '>=20.0.0'} + peerDependencies: + '@firebase/app': 0.x + + '@firebase/app-compat@0.5.7': + resolution: {integrity: sha512-MO+jfap8IBZQ+K8L2QCiHObyMgpYHrxo4Hc7iJgfb9hjGRW/z1y6LWVdT9wBBK+VJ7cRP2DjAiWQP+thu53hHA==} + engines: {node: '>=20.0.0'} + + '@firebase/app-types@0.9.3': + resolution: {integrity: sha512-kRVpIl4vVGJ4baogMDINbyrIOtOxqhkZQg4jTq3l8Lw6WSk0xfpEYzezFu+Kl4ve4fbPl79dvwRtaFqAC/ucCw==} + + '@firebase/app@0.14.7': + resolution: {integrity: sha512-o3ZfnOx0AWBD5n/36p2zPoB0rDDxQP8H/A60zDLvvfRLtW8b3LfCyV97GKpJaAVV1JMMl/BC89EDzMyzxFZxTw==} + engines: {node: '>=20.0.0'} + + '@firebase/auth-compat@0.6.2': + resolution: {integrity: sha512-8UhCzF6pav9bw/eXA8Zy1QAKssPRYEYXaWagie1ewLTwHkXv6bKp/j6/IwzSYQP67sy/BMFXIFaCCsoXzFLr7A==} + engines: {node: '>=20.0.0'} + peerDependencies: + '@firebase/app-compat': 0.x + + '@firebase/auth-interop-types@0.2.4': + resolution: {integrity: sha512-JPgcXKCuO+CWqGDnigBtvo09HeBs5u/Ktc2GaFj2m01hLarbxthLNm7Fk8iOP1aqAtXV+fnnGj7U28xmk7IwVA==} + + '@firebase/auth-types@0.13.0': + resolution: {integrity: sha512-S/PuIjni0AQRLF+l9ck0YpsMOdE8GO2KU6ubmBB7P+7TJUCQDa3R1dlgYm9UzGbbePMZsp0xzB93f2b/CgxMOg==} + peerDependencies: + '@firebase/app-types': 0.x + '@firebase/util': 1.x + + '@firebase/auth@1.12.0': + resolution: {integrity: sha512-zkvLpsrxynWHk07qGrUDfCSqKf4AvfZGEqJ7mVCtYGjNNDbGE71k0Yn84rg8QEZu4hQw1BC0qDEHzpNVBcSVmA==} + engines: {node: '>=20.0.0'} + peerDependencies: + '@firebase/app': 0.x + '@react-native-async-storage/async-storage': ^2.2.0 + peerDependenciesMeta: + '@react-native-async-storage/async-storage': + optional: true + + '@firebase/component@0.7.0': + resolution: {integrity: sha512-wR9En2A+WESUHexjmRHkqtaVH94WLNKt6rmeqZhSLBybg4Wyf0Umk04SZsS6sBq4102ZsDBFwoqMqJYj2IoDSg==} + engines: {node: '>=20.0.0'} + + '@firebase/data-connect@0.3.12': + resolution: {integrity: sha512-baPddcoNLj/+vYo+HSJidJUdr5W4OkhT109c5qhR8T1dJoZcyJpkv/dFpYlw/VJ3dV66vI8GHQFrmAZw/xUS4g==} + peerDependencies: + '@firebase/app': 0.x + + '@firebase/database-compat@2.1.0': + resolution: {integrity: sha512-8nYc43RqxScsePVd1qe1xxvWNf0OBnbwHxmXJ7MHSuuTVYFO3eLyLW3PiCKJ9fHnmIz4p4LbieXwz+qtr9PZDg==} + engines: {node: '>=20.0.0'} + + '@firebase/database-types@1.0.16': + resolution: {integrity: sha512-xkQLQfU5De7+SPhEGAXFBnDryUWhhlFXelEg2YeZOQMCdoe7dL64DDAd77SQsR+6uoXIZY5MB4y/inCs4GTfcw==} + + '@firebase/database@1.1.0': + resolution: {integrity: sha512-gM6MJFae3pTyNLoc9VcJNuaUDej0ctdjn3cVtILo3D5lpp0dmUHHLFN/pUKe7ImyeB1KAvRlEYxvIHNF04Filg==} + engines: {node: '>=20.0.0'} + + '@firebase/firestore-compat@0.4.4': + resolution: {integrity: sha512-JvxxIgi+D5v9BecjLA1YomdyF7LA6CXhJuVK10b4GtRrB3m2O2hT1jJWbKYZYHUAjTaajkvnos+4U5VNxqkI2w==} + engines: {node: '>=20.0.0'} + peerDependencies: + '@firebase/app-compat': 0.x + + '@firebase/firestore-types@3.0.3': + resolution: {integrity: sha512-hD2jGdiWRxB/eZWF89xcK9gF8wvENDJkzpVFb4aGkzfEaKxVRD1kjz1t1Wj8VZEp2LCB53Yx1zD8mrhQu87R6Q==} + peerDependencies: + '@firebase/app-types': 0.x + '@firebase/util': 1.x + + '@firebase/firestore@4.10.0': + resolution: {integrity: sha512-fgF6EbpoagGWh5Vwfu/7/jYgBFwUCwTlPNVF/aSjHcoEDRXpRsIqVfAFTp1LD+dWAUcAKEK3h+osk8spMJXtxA==} + engines: {node: '>=20.0.0'} + peerDependencies: + '@firebase/app': 0.x + + '@firebase/functions-compat@0.4.1': + resolution: {integrity: sha512-AxxUBXKuPrWaVNQ8o1cG1GaCAtXT8a0eaTDfqgS5VsRYLAR0ALcfqDLwo/QyijZj1w8Qf8n3Qrfy/+Im245hOQ==} + engines: {node: '>=20.0.0'} + peerDependencies: + '@firebase/app-compat': 0.x + + '@firebase/functions-types@0.6.3': + resolution: {integrity: sha512-EZoDKQLUHFKNx6VLipQwrSMh01A1SaL3Wg6Hpi//x6/fJ6Ee4hrAeswK99I5Ht8roiniKHw4iO0B1Oxj5I4plg==} + + '@firebase/functions@0.13.1': + resolution: {integrity: sha512-sUeWSb0rw5T+6wuV2o9XNmh9yHxjFI9zVGFnjFi+n7drTEWpl7ZTz1nROgGrSu472r+LAaj+2YaSicD4R8wfbw==} + engines: {node: '>=20.0.0'} + peerDependencies: + '@firebase/app': 0.x + + '@firebase/installations-compat@0.2.19': + resolution: {integrity: sha512-khfzIY3EI5LePePo7vT19/VEIH1E3iYsHknI/6ek9T8QCozAZshWT9CjlwOzZrKvTHMeNcbpo/VSOSIWDSjWdQ==} + peerDependencies: + '@firebase/app-compat': 0.x + + '@firebase/installations-types@0.5.3': + resolution: {integrity: sha512-2FJI7gkLqIE0iYsNQ1P751lO3hER+Umykel+TkLwHj6plzWVxqvfclPUZhcKFVQObqloEBTmpi2Ozn7EkCABAA==} + peerDependencies: + '@firebase/app-types': 0.x + + '@firebase/installations@0.6.19': + resolution: {integrity: sha512-nGDmiwKLI1lerhwfwSHvMR9RZuIH5/8E3kgUWnVRqqL7kGVSktjLTWEMva7oh5yxQ3zXfIlIwJwMcaM5bK5j8Q==} + peerDependencies: + '@firebase/app': 0.x + + '@firebase/logger@0.5.0': + resolution: {integrity: sha512-cGskaAvkrnh42b3BA3doDWeBmuHFO/Mx5A83rbRDYakPjO9bJtRL3dX7javzc2Rr/JHZf4HlterTW2lUkfeN4g==} + engines: {node: '>=20.0.0'} + + '@firebase/messaging-compat@0.2.23': + resolution: {integrity: sha512-SN857v/kBUvlQ9X/UjAqBoQ2FEaL1ZozpnmL1ByTe57iXkmnVVFm9KqAsTfmf+OEwWI4kJJe9NObtN/w22lUgg==} + peerDependencies: + '@firebase/app-compat': 0.x + + '@firebase/messaging-interop-types@0.2.3': + resolution: {integrity: sha512-xfzFaJpzcmtDjycpDeCUj0Ge10ATFi/VHVIvEEjDNc3hodVBQADZ7BWQU7CuFpjSHE+eLuBI13z5F/9xOoGX8Q==} + + '@firebase/messaging@0.12.23': + resolution: {integrity: sha512-cfuzv47XxqW4HH/OcR5rM+AlQd1xL/VhuaeW/wzMW1LFrsFcTn0GND/hak1vkQc2th8UisBcrkVcQAnOnKwYxg==} + peerDependencies: + '@firebase/app': 0.x + + '@firebase/performance-compat@0.2.22': + resolution: {integrity: sha512-xLKxaSAl/FVi10wDX/CHIYEUP13jXUjinL+UaNXT9ByIvxII5Ne5150mx6IgM8G6Q3V+sPiw9C8/kygkyHUVxg==} + peerDependencies: + '@firebase/app-compat': 0.x + + '@firebase/performance-types@0.2.3': + resolution: {integrity: sha512-IgkyTz6QZVPAq8GSkLYJvwSLr3LS9+V6vNPQr0x4YozZJiLF5jYixj0amDtATf1X0EtYHqoPO48a9ija8GocxQ==} + + '@firebase/performance@0.7.9': + resolution: {integrity: sha512-UzybENl1EdM2I1sjYm74xGt/0JzRnU/0VmfMAKo2LSpHJzaj77FCLZXmYQ4oOuE+Pxtt8Wy2BVJEENiZkaZAzQ==} + peerDependencies: + '@firebase/app': 0.x + + '@firebase/remote-config-compat@0.2.21': + resolution: {integrity: sha512-9+lm0eUycxbu8GO25JfJe4s6R2xlDqlVt0CR6CvN9E6B4AFArEV4qfLoDVRgIEB7nHKwvH2nYRocPWfmjRQTnw==} + peerDependencies: + '@firebase/app-compat': 0.x + + '@firebase/remote-config-types@0.5.0': + resolution: {integrity: sha512-vI3bqLoF14L/GchtgayMiFpZJF+Ao3uR8WCde0XpYNkSokDpAKca2DxvcfeZv7lZUqkUwQPL2wD83d3vQ4vvrg==} + + '@firebase/remote-config@0.8.0': + resolution: {integrity: sha512-sJz7C2VACeE257Z/3kY9Ap2WXbFsgsDLfaGfZmmToKAK39ipXxFan+vzB9CSbF6mP7bzjyzEnqPcMXhAnYE6fQ==} + peerDependencies: + '@firebase/app': 0.x + + '@firebase/storage-compat@0.4.0': + resolution: {integrity: sha512-vDzhgGczr1OfcOy285YAPur5pWDEvD67w4thyeCUh6Ys0izN9fNYtA1MJERmNBfqjqu0lg0FM5GLbw0Il21M+g==} + engines: {node: '>=20.0.0'} + peerDependencies: + '@firebase/app-compat': 0.x + + '@firebase/storage-types@0.8.3': + resolution: {integrity: sha512-+Muk7g9uwngTpd8xn9OdF/D48uiQ7I1Fae7ULsWPuKoCH3HU7bfFPhxtJYzyhjdniowhuDpQcfPmuNRAqZEfvg==} + peerDependencies: + '@firebase/app-types': 0.x + '@firebase/util': 1.x + + '@firebase/storage@0.14.0': + resolution: {integrity: sha512-xWWbb15o6/pWEw8H01UQ1dC5U3rf8QTAzOChYyCpafV6Xki7KVp3Yaw2nSklUwHEziSWE9KoZJS7iYeyqWnYFA==} + engines: {node: '>=20.0.0'} + peerDependencies: + '@firebase/app': 0.x + + '@firebase/util@1.13.0': + resolution: {integrity: sha512-0AZUyYUfpMNcztR5l09izHwXkZpghLgCUaAGjtMwXnCg3bj4ml5VgiwqOMOxJ+Nw4qN/zJAaOQBcJ7KGkWStqQ==} + engines: {node: '>=20.0.0'} + + '@firebase/webchannel-wrapper@1.0.5': + resolution: {integrity: sha512-+uGNN7rkfn41HLO0vekTFhTxk61eKa8mTpRGLO0QSqlQdKvIoGAvLp3ppdVIWbTGYJWM6Kp0iN+PjMIOcnVqTw==} + + '@grpc/grpc-js@1.9.15': + resolution: {integrity: sha512-nqE7Hc0AzI+euzUwDAy0aY5hCp10r734gMGRdU+qOPX0XSceI2ULrcXB5U2xSc5VkWwalCj4M7GzCAygZl2KoQ==} + engines: {node: ^8.13.0 || >=10.10.0} + + '@grpc/proto-loader@0.7.15': + resolution: {integrity: sha512-tMXdRCfYVixjuFK+Hk0Q1s38gV9zDiDJfWL3h1rv4Qc39oILCu1TRTDt7+fGUI8K4G1Fj125Hx/ru3azECWTyQ==} + engines: {node: '>=6'} + hasBin: true + '@humanfs/core@0.19.1': resolution: {integrity: sha512-5DyQ4+1JEUzejeK1JGICcideyfUbGixgS9jNgex5nqkW+cY7WZhxBigmieN5Qnw9ZosSNVC9KQKyb+GUaGyKUA==} engines: {node: '>=18.18.0'} @@ -453,6 +675,36 @@ packages: resolution: {integrity: sha512-nn5ozdjYQpUCZlWGuxcJY/KpxkWQs4DcbMCmKojjyrYDEAGy4Ce19NN4v5MduafTwJlbKc99UA8YhSVqq9yPZA==} engines: {node: '>=12.4.0'} + '@protobufjs/aspromise@1.1.2': + resolution: {integrity: sha512-j+gKExEuLmKwvz3OgROXtrJ2UG2x8Ch2YZUxahh+s1F2HZ+wAceUNLkvy6zKCPVRkU++ZWQrdxsUeQXmcg4uoQ==} + + '@protobufjs/base64@1.1.2': + resolution: {integrity: sha512-AZkcAA5vnN/v4PDqKyMR5lx7hZttPDgClv83E//FMNhR2TMcLUhfRUBHCmSl0oi9zMgDDqRUJkSxO3wm85+XLg==} + + '@protobufjs/codegen@2.0.4': + resolution: {integrity: sha512-YyFaikqM5sH0ziFZCN3xDC7zeGaB/d0IUb9CATugHWbd1FRFwWwt4ld4OYMPWu5a3Xe01mGAULCdqhMlPl29Jg==} + + '@protobufjs/eventemitter@1.1.0': + resolution: {integrity: sha512-j9ednRT81vYJ9OfVuXG6ERSTdEL1xVsNgqpkxMsbIabzSo3goCjDIveeGv5d03om39ML71RdmrGNjG5SReBP/Q==} + + '@protobufjs/fetch@1.1.0': + resolution: {integrity: sha512-lljVXpqXebpsijW71PZaCYeIcE5on1w5DlQy5WH6GLbFryLUrBD4932W/E2BSpfRJWseIL4v/KPgBFxDOIdKpQ==} + + '@protobufjs/float@1.0.2': + resolution: {integrity: sha512-Ddb+kVXlXst9d+R9PfTIxh1EdNkgoRe5tOX6t01f1lYWOvJnSPDBlG241QLzcyPdoNTsblLUdujGSE4RzrTZGQ==} + + '@protobufjs/inquire@1.1.0': + resolution: {integrity: sha512-kdSefcPdruJiFMVSbn801t4vFK7KB/5gd2fYvrxhuJYg8ILrmn9SKSX2tZdV6V+ksulWqS7aXjBcRXl3wHoD9Q==} + + '@protobufjs/path@1.1.2': + resolution: {integrity: sha512-6JOcJ5Tm08dOHAbdR3GrvP+yUUfkjG5ePsHYczMFLq3ZmMkAD98cDgcT2iA1lJ9NVwFd4tH/iSSoe44YWkltEA==} + + '@protobufjs/pool@1.1.0': + resolution: {integrity: sha512-0kELaGSIDBKvcgS4zkjz1PeddatrjYcmMWOlAuAPwAeccUrPHdUqo/J6LiymHHEiJT5NrF1UVwxY14f+fy4WQw==} + + '@protobufjs/utf8@1.1.0': + resolution: {integrity: sha512-Vvn3zZrhQZkkBE8LSuW3em98c0FwgO4nxzv6OdSxPKJIEKY2bGbHn+mhGIPerzI4twdxaP8/0+06HBpwf345Lw==} + '@radix-ui/primitive@1.1.3': resolution: {integrity: sha512-JTF99U/6XIjCBo0wqkU5sK10glYe27MRRsfwoiq5zzOEZLHU3A3KCMa5X/azekYRCJ0HlwI0crAXS/5dEHTzDg==} @@ -929,6 +1181,10 @@ packages: resolution: {integrity: sha512-g6LhBsl+GBPRWGWsBtutpzBYuIIdBkLEvad5C/va/74Db018+5TZiyA26cZJAr3Rft5lprVqOIPxf5Vid6tqAw==} engines: {node: '>=18'} + ansi-regex@5.0.1: + resolution: {integrity: sha512-quJQXlTSUGL2LH9SUXo8VwsY4soanhgo6LNSm84E1LBcE8s3O0wpdiRzyR9z/ZZJMlMWv37qOOb9pdJlMUEKFQ==} + engines: {node: '>=8'} + ansi-regex@6.2.2: resolution: {integrity: sha512-Bq3SmSpyFHaWjPk8If9yc6svM8c56dB5BAtW4Qbw5jHTwwXXcTLoRMkpDJp6VL0XzlWaCHTXrkFURMYmD0sLqg==} engines: {node: '>=12'} @@ -1071,6 +1327,10 @@ packages: client-only@0.0.1: resolution: {integrity: sha512-IV3Ou0jSMzZrd3pZ48nLkT9DA7Ag1pnPzaiQhpW7c3RbcqqzvzzVu+L8gfqMp/8IM2MQtSiqaCxrrcfu8I8rMA==} + cliui@8.0.1: + resolution: {integrity: sha512-BSeNnyus75C4//NQ9gQt1/csTXyo/8Sb+afLAkzAptFuMsod9HFokGNudZpi/oQV73hnVK+sR+5PVRMd+Dr7YQ==} + engines: {node: '>=12'} + clsx@2.1.1: resolution: {integrity: sha512-eYm0QWBtUrBWZWG0d386OGAw16Z995PiOVo2B7bjWSbHedGl5e0ZWaq65kOGgUSNesEIDkB9ISbTg/JK9dhCZA==} engines: {node: '>=6'} @@ -1174,6 +1434,9 @@ packages: emoji-regex@10.6.0: resolution: {integrity: sha512-toUI84YS5YmxW219erniWD0CIVOo46xGKColeNQRgOzDorgBi1v4D71/OFzgD9GO2UGKIv1C3Sp8DAn0+j5w7A==} + emoji-regex@8.0.0: + resolution: {integrity: sha512-MSjYzcWNOA0ewAHpz0MxpYFvwg6yjy1NG3xteoqz644VCo/RPgnr1/GGt+ic3iJTzQ8Eu3TdM14SawnVUmGE6A==} + emoji-regex@9.2.2: resolution: {integrity: sha512-L18DaJsXSUk2+42pv8mLs5jJT2hqFkFE4j21wOmgbUqsZ2hL72NsUU785g9RXgo3s0ZNgVl42TiHp3ZtOv/Vyg==} @@ -1360,6 +1623,10 @@ packages: fastq@1.20.1: resolution: {integrity: sha512-GGToxJ/w1x32s/D2EKND7kTil4n8OVk/9mycTc4VDza13lOvpUZTGX3mFSCtV9ksdGBVzvsyAVLM6mHFThxXxw==} + faye-websocket@0.11.4: + resolution: {integrity: sha512-CzbClwlXAuiRQAlUyfqPgvPoNKTckTPGfwZV4ZdAhVcP2lh9KUxJg2b5GkE7XbjKQ3YJnQ9z6D9ntLAlB+tP8g==} + engines: {node: '>=0.8.0'} + fdir@6.5.0: resolution: {integrity: sha512-tIbYtZbucOs0BRGqPJkshJUYdL+SDH7dVM8gjy+ERp3WAUjLEFJE+02kanyHtwjWOnwrKYBiwAmM0p4kLJAnXg==} engines: {node: '>=12.0.0'} @@ -1381,6 +1648,9 @@ packages: resolution: {integrity: sha512-78/PXT1wlLLDgTzDs7sjq9hzz0vXD+zn+7wypEe4fXQxCmdmqfGsEPQxmiCSQI3ajFV91bVSsvNtrJRiW6nGng==} engines: {node: '>=10'} + firebase@12.8.0: + resolution: {integrity: sha512-S1tCIR3ENecee0tY2cfTHfMkXqkitHfbsvqpCtvsT0Zi9vDB7A4CodAjHfHCjVvu/XtGy1LHLjOasVcF10rCVw==} + flat-cache@4.0.1: resolution: {integrity: sha512-f7ccFPK3SXFHpx15UIGyRJ/FJQctuKZ0zVuN3frBo4HnK3cay9VEW0R6yPYFHC0AgqhukPzKjq22t5DmAyqGyw==} engines: {node: '>=16'} @@ -1423,6 +1693,10 @@ packages: resolution: {integrity: sha512-3hN7NaskYvMDLQY55gnW3NQ+mesEAepTqlg+VEbj7zzqEMBVNhzcGYYeqFo/TlYz6eQiFcp1HcsCZO+nGgS8zg==} engines: {node: '>=6.9.0'} + get-caller-file@2.0.5: + resolution: {integrity: sha512-DyFP3BM/3YHTQOCUL/w0OZHR0lpKeGrxotcHWcqNEdnltqFwXVfhEBQ94eIo34AfQpo0rGki4cyIiftY06h2Fg==} + engines: {node: 6.* || 8.* || >= 10.*} + get-east-asian-width@1.4.0: resolution: {integrity: sha512-QZjmEOC+IT1uk6Rx0sX22V6uHWVwbdbxf1faPqJ1QhLdGgsRGCZoyaQBm/piRdJy/D2um6hM1UP7ZEeQ4EkP+Q==} engines: {node: '>=18'} @@ -1509,11 +1783,17 @@ packages: hermes-parser@0.25.1: resolution: {integrity: sha512-6pEjquH3rqaI6cYAXYPcz9MS4rY6R4ngRgrgfDshRptUZIc3lw0MCIJIGDj9++mfySOuPTHB4nrSW99BCvOPIA==} + http-parser-js@0.5.10: + resolution: {integrity: sha512-Pysuw9XpUq5dVc/2SMHpuTY01RFl8fttgcyunjL7eEMhGM3cI4eOmiCycJDVCo/7O7ClfQD3SaI6ftDzqOXYMA==} + husky@9.1.7: resolution: {integrity: sha512-5gs5ytaNjBrh5Ow3zrvdUUY+0VxIuWVL4i9irt6friV+BqdCfmV11CQTWMiBYWHbXhco+J1kHfTOUkePhCDvMA==} engines: {node: '>=18'} hasBin: true + idb@7.1.1: + resolution: {integrity: sha512-gchesWBzyvGHRO9W8tzUWFDycow5gwjvFKfyV9FF32Y7F50yZMp7mP+T2mJIWFx49zicqyC4uefHM17o6xKIVQ==} + ignore@5.3.2: resolution: {integrity: sha512-hsBTNUqQTDwkWtcdYI2i06Y/nUBEsNEDJKjWdigLvegy8kDuJAS8uRlpkkcQpyEXL0Z/pjDy5HBmMjRCJ2gq+g==} engines: {node: '>= 4'} @@ -1577,6 +1857,10 @@ packages: resolution: {integrity: sha512-1pC6N8qWJbWoPtEjgcL2xyhQOP491EQjeUo3qTKcmV8YSDDJrOepfG8pcC7h/QgnQHYSv0mJ3Z/ZWxmatVrysg==} engines: {node: '>= 0.4'} + is-fullwidth-code-point@3.0.0: + resolution: {integrity: sha512-zymm5+u+sCsSWyD9qNaejV3DFvhCKclKdizYaJUuHA83RLjb7nSuGnddCHGv0hk+KY7BMAlsWeK4Ueg6EV6XQg==} + engines: {node: '>=8'} + is-fullwidth-code-point@5.1.0: resolution: {integrity: sha512-5XHYaSyiqADb4RnZ1Bdad6cPp8Toise4TzEjcOYDHZkTCbKgiUl7WTUCpNWHuxmDt91wnsZBc9xinNzopv3JMQ==} engines: {node: '>=18'} @@ -1786,6 +2070,9 @@ packages: resolution: {integrity: sha512-iPZK6eYjbxRu3uB4/WZ3EsEIMJFMqAoopl3R+zuq0UjcAm/MO6KCweDgPfP3elTztoKP3KtnVHxTn2NHBSDVUw==} engines: {node: '>=10'} + lodash.camelcase@4.3.0: + resolution: {integrity: sha512-TwuEnCnxbc3rAvhf/LbG7tJUDzhqXyFnv3dtzLOPgCG/hODL7WFnsbwktkD7yUV0RrreP/l1PALq/YSg6VvjlA==} + lodash.merge@4.6.2: resolution: {integrity: sha512-0KpjqXRVvrYyCsX1swR/XTK0va6VQkQM6MNo7PqW77ByjAhoARA8EfrP1N4+KlKj8YS0ZUCtRT/YUuhyYDujIQ==} @@ -1793,6 +2080,9 @@ packages: resolution: {integrity: sha512-9ie8ItPR6tjY5uYJh8K/Zrv/RMZ5VOlOWvtZdEHYSTFKZfIBPQa9tOAEeAWhd+AnIneLJ22w5fjOYtoutpWq5w==} engines: {node: '>=18'} + long@5.3.2: + resolution: {integrity: sha512-mNAgZ1GmyNhD7AuqnTG3/VQ26o760+ZYBPKjPvugO8+nLbYfX6TVpJPseBvopbdY+qpZ/lKUnmEc1LeZYS3QAA==} + loose-envify@1.4.0: resolution: {integrity: sha512-lyuxPGr/Wfhrlem2CL/UcnUc1zcqKAImBDzukY7Y5F/yQiNdko6+fRLevlw1HgMySw7f611UIY408EtxRSoK3Q==} hasBin: true @@ -2048,6 +2338,10 @@ packages: prop-types@15.8.1: resolution: {integrity: sha512-oj87CgZICdulUohogVAR7AjlC0327U4el4L6eAvOqCeudMDVU0NThNaV+b9Df4dXgSP1gXMTnPdhfe/2qDH5cg==} + protobufjs@7.5.4: + resolution: {integrity: sha512-CvexbZtbov6jW2eXAvLukXjXUW1TzFaivC46BpWc/3BpcCysb5Vffu+B3XHMm8lVEuy2Mm4XGex8hBSg1yapPg==} + engines: {node: '>=12.0.0'} + proxy-from-env@1.1.0: resolution: {integrity: sha512-D+zkORCbA9f1tdWRK0RaCR3GPv50cMxcrz4X8k5LTSUD1Dkw47mKJEZQNunItRTkWwgtaUSo1RVFRIG9ZXiFYg==} @@ -2108,6 +2402,10 @@ packages: resolution: {integrity: sha512-dYqgNSZbDwkaJ2ceRd9ojCGjBq+mOm9LmtXnAnEGyHhN/5R7iDW2TRw3h+o/jCFxus3P2LfWIIiwowAjANm7IA==} engines: {node: '>= 0.4'} + require-directory@2.1.1: + resolution: {integrity: sha512-fGxEI7+wsG9xrvdjsrlmL22OMTTiHRwAMroiEeMgq8gzoLC/PQr7RsRDSTLUg/bZAZtF+TVIkHc6/4RIKrui+Q==} + engines: {node: '>=0.10.0'} + resolve-from@4.0.0: resolution: {integrity: sha512-pb/MYmXstAkysRFx8piNI1tGFNQIFA3vkE3Gq4EuA1dF6gHp/+vgZqsCGJapvy8N3Q+4o7FwvquPJcnZ7RYy4g==} engines: {node: '>=4'} @@ -2142,6 +2440,9 @@ packages: resolution: {integrity: sha512-AURm5f0jYEOydBj7VQlVvDrjeFgthDdEF5H1dP+6mNpoXOMo1quQqJ4wvJDyRZ9+pO3kGWoOdmV08cSv2aJV6Q==} engines: {node: '>=0.4'} + safe-buffer@5.2.1: + resolution: {integrity: sha512-rp3So07KcdmmKbGvgaNxQSJr7bGVSVk5S9Eq1F+ppbRo70+YeaDxkw5Dd8NPN+GD6bjnYm2VuPuCXmpuYvmCXQ==} + safe-push-apply@1.0.0: resolution: {integrity: sha512-iKE9w/Z7xCzUMIZqdBsp6pEQvwuEebH4vdpjcDWnyzaI6yl6O9FHvVpmGelvEHNsoY6wGblkxR6Zty/h00WiSA==} engines: {node: '>= 0.4'} @@ -2225,6 +2526,10 @@ packages: resolution: {integrity: sha512-aqD2Q0144Z+/RqG52NeHEkZauTAUWJO8c6yTftGJKO3Tja5tUgIfmIl6kExvhtxSDP7fXB6DvzkfMpCd/F3G+Q==} engines: {node: '>=0.6.19'} + string-width@4.2.3: + resolution: {integrity: sha512-wKyQRQpjJ0sIp62ErSZdGsjMJWsap5oRNihHhu6G7JVO/9jIB6UyevL+tXuOqrng8j/cxKTWyWUwvSTriiZz/g==} + engines: {node: '>=8'} + string-width@7.2.0: resolution: {integrity: sha512-tsaTIkKW9b4N+AEj+SVA+WhJzV7/zMhcSu78mLKWSk7cXMOSHsBKFWUs0fWwq8QyK3MgJBQRX6Gbi4kYbdvGkQ==} engines: {node: '>=18'} @@ -2256,6 +2561,10 @@ packages: resolution: {integrity: sha512-UXSH262CSZY1tfu3G3Secr6uGLCFVPMhIqHjlgCUtCCcgihYc/xKs9djMTMUOb2j1mVSeU8EU6NWc/iQKU6Gfg==} engines: {node: '>= 0.4'} + strip-ansi@6.0.1: + resolution: {integrity: sha512-Y38VPSHcqkFrCpFnQ9vuSXmquuv5oXOKpGeT6aGrr3o3Gc9AlVa6JBfUSOCnbxGGZF+/0ooI7KrPuUSztUdU5A==} + engines: {node: '>=8'} + strip-ansi@7.1.2: resolution: {integrity: sha512-gmBGslpoQJtgnMAvOVqGZpEz9dyoKTCzy2nfz/n8aIFhN/jCE/rCmcxabB6jOOHV+0WNnylOxaxBQPSvcWklhA==} engines: {node: '>=12'} @@ -2399,6 +2708,17 @@ packages: react: ^16.8 || ^17.0 || ^18.0 || ^19.0.0 || ^19.0.0-rc react-dom: ^16.8 || ^17.0 || ^18.0 || ^19.0.0 || ^19.0.0-rc + web-vitals@4.2.4: + resolution: {integrity: sha512-r4DIlprAGwJ7YM11VZp4R884m0Vmgr6EAKe3P+kO0PPj3Unqyvv59rczf6UiGcb9Z8QxZVcqKNwv/g0WNdWwsw==} + + websocket-driver@0.7.4: + resolution: {integrity: sha512-b17KeDIQVjvb0ssuSDF2cYXSg2iztliJ4B9WdsuB6J952qCPKmnVq4DyW5motImXHDC1cBT/1UezrJVsKw5zjg==} + engines: {node: '>=0.8.0'} + + websocket-extensions@0.1.4: + resolution: {integrity: sha512-OqedPIGOfsDlo31UNwYbCFMSaO9m9G/0faIHj5/dZFDMFqPTcx6UwqyOy3COEaEOg/9VsGIpdqn62W5KhoKSpg==} + engines: {node: '>=0.8.0'} + which-boxed-primitive@1.1.1: resolution: {integrity: sha512-TbX3mj8n0odCBFVlY8AxkqcHASw3L60jIuF8jFP78az3C2YhmGvqbHBpAjTRH2/xqYunrJ9g1jSyjCjpoWzIAA==} engines: {node: '>= 0.4'} @@ -2424,10 +2744,18 @@ packages: resolution: {integrity: sha512-BN22B5eaMMI9UMtjrGd5g5eCYPpCPDUy0FJXbYsaT5zYxjFOckS53SQDE3pWkVoWpHXVb3BrYcEN4Twa55B5cA==} engines: {node: '>=0.10.0'} + wrap-ansi@7.0.0: + resolution: {integrity: sha512-YVGIj2kamLSTxw6NsZjoBxfSwsn0ycdesmc4p+Q21c5zPuZ1pl+NfxVdxPtdHvmNVOQ6XSYG4AUtyt/Fi7D16Q==} + engines: {node: '>=10'} + wrap-ansi@9.0.2: resolution: {integrity: sha512-42AtmgqjV+X1VpdOfyTGOYRi0/zsoLqtXQckTmqTeybT+BDIbM/Guxo7x3pE2vtpr1ok6xRqM9OpBe+Jyoqyww==} engines: {node: '>=18'} + y18n@5.0.8: + resolution: {integrity: sha512-0pfFzegeDWJHJIAmTLRP2DwHjdF5s7jo9tuztdQxAhINCdvS+3nGINqPd00AphqJR/0LhANUS6/+7SCb98YOfA==} + engines: {node: '>=10'} + yallist@3.1.1: resolution: {integrity: sha512-a4UGQaWPH59mOXUYnAG2ewncQS4i4F43Tv3JoAM+s2VDAmS9NsK8GpDMLrCHPksFT7h3K6TOoUNn2pb7RoXx4g==} @@ -2436,6 +2764,14 @@ packages: engines: {node: '>= 14.6'} hasBin: true + yargs-parser@21.1.1: + resolution: {integrity: sha512-tVpsJW7DdjecAiFpbIB1e3qxIQsE6NoPc5/eTdrbbIC4h0LVsWhnoa3g+m2HclBIujHzsxZ4VJVA+GUuc2/LBw==} + engines: {node: '>=12'} + + yargs@17.7.2: + resolution: {integrity: sha512-7dSzzRQ++CKnNI/krKnYRV7JKKPUXMEh61soaHKg9mrWEhzFWhFnxPxGl+69cD1Ou63C13NUPCnmIcrvqCuM6w==} + engines: {node: '>=12'} + yocto-queue@0.1.0: resolution: {integrity: sha512-rVksvsnNCdJ/ohGc6xgPwyN8eheCxsiLM8mxuE/t/mOVqJewPuO1miLpTHQiRgTKCLexL4MeAFVagts7HmNZ2Q==} engines: {node: '>=10'} @@ -2615,6 +2951,336 @@ snapshots: '@eslint/core': 0.17.0 levn: 0.4.1 + '@firebase/ai@2.7.0(@firebase/app-types@0.9.3)(@firebase/app@0.14.7)': + dependencies: + '@firebase/app': 0.14.7 + '@firebase/app-check-interop-types': 0.3.3 + '@firebase/app-types': 0.9.3 + '@firebase/component': 0.7.0 + '@firebase/logger': 0.5.0 + '@firebase/util': 1.13.0 + tslib: 2.8.1 + + '@firebase/analytics-compat@0.2.25(@firebase/app-compat@0.5.7)(@firebase/app@0.14.7)': + dependencies: + '@firebase/analytics': 0.10.19(@firebase/app@0.14.7) + '@firebase/analytics-types': 0.8.3 + '@firebase/app-compat': 0.5.7 + '@firebase/component': 0.7.0 + '@firebase/util': 1.13.0 + tslib: 2.8.1 + transitivePeerDependencies: + - '@firebase/app' + + '@firebase/analytics-types@0.8.3': {} + + '@firebase/analytics@0.10.19(@firebase/app@0.14.7)': + dependencies: + '@firebase/app': 0.14.7 + '@firebase/component': 0.7.0 + '@firebase/installations': 0.6.19(@firebase/app@0.14.7) + '@firebase/logger': 0.5.0 + '@firebase/util': 1.13.0 + tslib: 2.8.1 + + '@firebase/app-check-compat@0.4.0(@firebase/app-compat@0.5.7)(@firebase/app@0.14.7)': + dependencies: + '@firebase/app-check': 0.11.0(@firebase/app@0.14.7) + '@firebase/app-check-types': 0.5.3 + '@firebase/app-compat': 0.5.7 + '@firebase/component': 0.7.0 + '@firebase/logger': 0.5.0 + '@firebase/util': 1.13.0 + tslib: 2.8.1 + transitivePeerDependencies: + - '@firebase/app' + + '@firebase/app-check-interop-types@0.3.3': {} + + '@firebase/app-check-types@0.5.3': {} + + '@firebase/app-check@0.11.0(@firebase/app@0.14.7)': + dependencies: + '@firebase/app': 0.14.7 + '@firebase/component': 0.7.0 + '@firebase/logger': 0.5.0 + '@firebase/util': 1.13.0 + tslib: 2.8.1 + + '@firebase/app-compat@0.5.7': + dependencies: + '@firebase/app': 0.14.7 + '@firebase/component': 0.7.0 + '@firebase/logger': 0.5.0 + '@firebase/util': 1.13.0 + tslib: 2.8.1 + + '@firebase/app-types@0.9.3': {} + + '@firebase/app@0.14.7': + dependencies: + '@firebase/component': 0.7.0 + '@firebase/logger': 0.5.0 + '@firebase/util': 1.13.0 + idb: 7.1.1 + tslib: 2.8.1 + + '@firebase/auth-compat@0.6.2(@firebase/app-compat@0.5.7)(@firebase/app-types@0.9.3)(@firebase/app@0.14.7)': + dependencies: + '@firebase/app-compat': 0.5.7 + '@firebase/auth': 1.12.0(@firebase/app@0.14.7) + '@firebase/auth-types': 0.13.0(@firebase/app-types@0.9.3)(@firebase/util@1.13.0) + '@firebase/component': 0.7.0 + '@firebase/util': 1.13.0 + tslib: 2.8.1 + transitivePeerDependencies: + - '@firebase/app' + - '@firebase/app-types' + - '@react-native-async-storage/async-storage' + + '@firebase/auth-interop-types@0.2.4': {} + + '@firebase/auth-types@0.13.0(@firebase/app-types@0.9.3)(@firebase/util@1.13.0)': + dependencies: + '@firebase/app-types': 0.9.3 + '@firebase/util': 1.13.0 + + '@firebase/auth@1.12.0(@firebase/app@0.14.7)': + dependencies: + '@firebase/app': 0.14.7 + '@firebase/component': 0.7.0 + '@firebase/logger': 0.5.0 + '@firebase/util': 1.13.0 + tslib: 2.8.1 + + '@firebase/component@0.7.0': + dependencies: + '@firebase/util': 1.13.0 + tslib: 2.8.1 + + '@firebase/data-connect@0.3.12(@firebase/app@0.14.7)': + dependencies: + '@firebase/app': 0.14.7 + '@firebase/auth-interop-types': 0.2.4 + '@firebase/component': 0.7.0 + '@firebase/logger': 0.5.0 + '@firebase/util': 1.13.0 + tslib: 2.8.1 + + '@firebase/database-compat@2.1.0': + dependencies: + '@firebase/component': 0.7.0 + '@firebase/database': 1.1.0 + '@firebase/database-types': 1.0.16 + '@firebase/logger': 0.5.0 + '@firebase/util': 1.13.0 + tslib: 2.8.1 + + '@firebase/database-types@1.0.16': + dependencies: + '@firebase/app-types': 0.9.3 + '@firebase/util': 1.13.0 + + '@firebase/database@1.1.0': + dependencies: + '@firebase/app-check-interop-types': 0.3.3 + '@firebase/auth-interop-types': 0.2.4 + '@firebase/component': 0.7.0 + '@firebase/logger': 0.5.0 + '@firebase/util': 1.13.0 + faye-websocket: 0.11.4 + tslib: 2.8.1 + + '@firebase/firestore-compat@0.4.4(@firebase/app-compat@0.5.7)(@firebase/app-types@0.9.3)(@firebase/app@0.14.7)': + dependencies: + '@firebase/app-compat': 0.5.7 + '@firebase/component': 0.7.0 + '@firebase/firestore': 4.10.0(@firebase/app@0.14.7) + '@firebase/firestore-types': 3.0.3(@firebase/app-types@0.9.3)(@firebase/util@1.13.0) + '@firebase/util': 1.13.0 + tslib: 2.8.1 + transitivePeerDependencies: + - '@firebase/app' + - '@firebase/app-types' + + '@firebase/firestore-types@3.0.3(@firebase/app-types@0.9.3)(@firebase/util@1.13.0)': + dependencies: + '@firebase/app-types': 0.9.3 + '@firebase/util': 1.13.0 + + '@firebase/firestore@4.10.0(@firebase/app@0.14.7)': + dependencies: + '@firebase/app': 0.14.7 + '@firebase/component': 0.7.0 + '@firebase/logger': 0.5.0 + '@firebase/util': 1.13.0 + '@firebase/webchannel-wrapper': 1.0.5 + '@grpc/grpc-js': 1.9.15 + '@grpc/proto-loader': 0.7.15 + tslib: 2.8.1 + + '@firebase/functions-compat@0.4.1(@firebase/app-compat@0.5.7)(@firebase/app@0.14.7)': + dependencies: + '@firebase/app-compat': 0.5.7 + '@firebase/component': 0.7.0 + '@firebase/functions': 0.13.1(@firebase/app@0.14.7) + '@firebase/functions-types': 0.6.3 + '@firebase/util': 1.13.0 + tslib: 2.8.1 + transitivePeerDependencies: + - '@firebase/app' + + '@firebase/functions-types@0.6.3': {} + + '@firebase/functions@0.13.1(@firebase/app@0.14.7)': + dependencies: + '@firebase/app': 0.14.7 + '@firebase/app-check-interop-types': 0.3.3 + '@firebase/auth-interop-types': 0.2.4 + '@firebase/component': 0.7.0 + '@firebase/messaging-interop-types': 0.2.3 + '@firebase/util': 1.13.0 + tslib: 2.8.1 + + '@firebase/installations-compat@0.2.19(@firebase/app-compat@0.5.7)(@firebase/app-types@0.9.3)(@firebase/app@0.14.7)': + dependencies: + '@firebase/app-compat': 0.5.7 + '@firebase/component': 0.7.0 + '@firebase/installations': 0.6.19(@firebase/app@0.14.7) + '@firebase/installations-types': 0.5.3(@firebase/app-types@0.9.3) + '@firebase/util': 1.13.0 + tslib: 2.8.1 + transitivePeerDependencies: + - '@firebase/app' + - '@firebase/app-types' + + '@firebase/installations-types@0.5.3(@firebase/app-types@0.9.3)': + dependencies: + '@firebase/app-types': 0.9.3 + + '@firebase/installations@0.6.19(@firebase/app@0.14.7)': + dependencies: + '@firebase/app': 0.14.7 + '@firebase/component': 0.7.0 + '@firebase/util': 1.13.0 + idb: 7.1.1 + tslib: 2.8.1 + + '@firebase/logger@0.5.0': + dependencies: + tslib: 2.8.1 + + '@firebase/messaging-compat@0.2.23(@firebase/app-compat@0.5.7)(@firebase/app@0.14.7)': + dependencies: + '@firebase/app-compat': 0.5.7 + '@firebase/component': 0.7.0 + '@firebase/messaging': 0.12.23(@firebase/app@0.14.7) + '@firebase/util': 1.13.0 + tslib: 2.8.1 + transitivePeerDependencies: + - '@firebase/app' + + '@firebase/messaging-interop-types@0.2.3': {} + + '@firebase/messaging@0.12.23(@firebase/app@0.14.7)': + dependencies: + '@firebase/app': 0.14.7 + '@firebase/component': 0.7.0 + '@firebase/installations': 0.6.19(@firebase/app@0.14.7) + '@firebase/messaging-interop-types': 0.2.3 + '@firebase/util': 1.13.0 + idb: 7.1.1 + tslib: 2.8.1 + + '@firebase/performance-compat@0.2.22(@firebase/app-compat@0.5.7)(@firebase/app@0.14.7)': + dependencies: + '@firebase/app-compat': 0.5.7 + '@firebase/component': 0.7.0 + '@firebase/logger': 0.5.0 + '@firebase/performance': 0.7.9(@firebase/app@0.14.7) + '@firebase/performance-types': 0.2.3 + '@firebase/util': 1.13.0 + tslib: 2.8.1 + transitivePeerDependencies: + - '@firebase/app' + + '@firebase/performance-types@0.2.3': {} + + '@firebase/performance@0.7.9(@firebase/app@0.14.7)': + dependencies: + '@firebase/app': 0.14.7 + '@firebase/component': 0.7.0 + '@firebase/installations': 0.6.19(@firebase/app@0.14.7) + '@firebase/logger': 0.5.0 + '@firebase/util': 1.13.0 + tslib: 2.8.1 + web-vitals: 4.2.4 + + '@firebase/remote-config-compat@0.2.21(@firebase/app-compat@0.5.7)(@firebase/app@0.14.7)': + dependencies: + '@firebase/app-compat': 0.5.7 + '@firebase/component': 0.7.0 + '@firebase/logger': 0.5.0 + '@firebase/remote-config': 0.8.0(@firebase/app@0.14.7) + '@firebase/remote-config-types': 0.5.0 + '@firebase/util': 1.13.0 + tslib: 2.8.1 + transitivePeerDependencies: + - '@firebase/app' + + '@firebase/remote-config-types@0.5.0': {} + + '@firebase/remote-config@0.8.0(@firebase/app@0.14.7)': + dependencies: + '@firebase/app': 0.14.7 + '@firebase/component': 0.7.0 + '@firebase/installations': 0.6.19(@firebase/app@0.14.7) + '@firebase/logger': 0.5.0 + '@firebase/util': 1.13.0 + tslib: 2.8.1 + + '@firebase/storage-compat@0.4.0(@firebase/app-compat@0.5.7)(@firebase/app-types@0.9.3)(@firebase/app@0.14.7)': + dependencies: + '@firebase/app-compat': 0.5.7 + '@firebase/component': 0.7.0 + '@firebase/storage': 0.14.0(@firebase/app@0.14.7) + '@firebase/storage-types': 0.8.3(@firebase/app-types@0.9.3)(@firebase/util@1.13.0) + '@firebase/util': 1.13.0 + tslib: 2.8.1 + transitivePeerDependencies: + - '@firebase/app' + - '@firebase/app-types' + + '@firebase/storage-types@0.8.3(@firebase/app-types@0.9.3)(@firebase/util@1.13.0)': + dependencies: + '@firebase/app-types': 0.9.3 + '@firebase/util': 1.13.0 + + '@firebase/storage@0.14.0(@firebase/app@0.14.7)': + dependencies: + '@firebase/app': 0.14.7 + '@firebase/component': 0.7.0 + '@firebase/util': 1.13.0 + tslib: 2.8.1 + + '@firebase/util@1.13.0': + dependencies: + tslib: 2.8.1 + + '@firebase/webchannel-wrapper@1.0.5': {} + + '@grpc/grpc-js@1.9.15': + dependencies: + '@grpc/proto-loader': 0.7.15 + '@types/node': 20.19.30 + + '@grpc/proto-loader@0.7.15': + dependencies: + lodash.camelcase: 4.3.0 + long: 5.3.2 + protobufjs: 7.5.4 + yargs: 17.7.2 + '@humanfs/core@0.19.1': {} '@humanfs/node@0.16.7': @@ -2793,6 +3459,29 @@ snapshots: '@nolyfill/is-core-module@1.0.39': {} + '@protobufjs/aspromise@1.1.2': {} + + '@protobufjs/base64@1.1.2': {} + + '@protobufjs/codegen@2.0.4': {} + + '@protobufjs/eventemitter@1.1.0': {} + + '@protobufjs/fetch@1.1.0': + dependencies: + '@protobufjs/aspromise': 1.1.2 + '@protobufjs/inquire': 1.1.0 + + '@protobufjs/float@1.0.2': {} + + '@protobufjs/inquire@1.1.0': {} + + '@protobufjs/path@1.1.2': {} + + '@protobufjs/pool@1.1.0': {} + + '@protobufjs/utf8@1.1.0': {} + '@radix-ui/primitive@1.1.3': {} '@radix-ui/react-compose-refs@1.1.2(@types/react@19.2.10)(react@19.2.3)': @@ -3216,6 +3905,8 @@ snapshots: dependencies: environment: 1.1.0 + ansi-regex@5.0.1: {} + ansi-regex@6.2.2: {} ansi-styles@4.3.0: @@ -3391,6 +4082,12 @@ snapshots: client-only@0.0.1: {} + cliui@8.0.1: + dependencies: + string-width: 4.2.3 + strip-ansi: 6.0.1 + wrap-ansi: 7.0.0 + clsx@2.1.1: {} color-convert@2.0.1: @@ -3481,6 +4178,8 @@ snapshots: emoji-regex@10.6.0: {} + emoji-regex@8.0.0: {} + emoji-regex@9.2.2: {} enhanced-resolve@5.18.4: @@ -3818,6 +4517,10 @@ snapshots: dependencies: reusify: 1.1.0 + faye-websocket@0.11.4: + dependencies: + websocket-driver: 0.7.4 + fdir@6.5.0(picomatch@4.0.3): optionalDependencies: picomatch: 4.0.3 @@ -3835,6 +4538,39 @@ snapshots: locate-path: 6.0.0 path-exists: 4.0.0 + firebase@12.8.0: + dependencies: + '@firebase/ai': 2.7.0(@firebase/app-types@0.9.3)(@firebase/app@0.14.7) + '@firebase/analytics': 0.10.19(@firebase/app@0.14.7) + '@firebase/analytics-compat': 0.2.25(@firebase/app-compat@0.5.7)(@firebase/app@0.14.7) + '@firebase/app': 0.14.7 + '@firebase/app-check': 0.11.0(@firebase/app@0.14.7) + '@firebase/app-check-compat': 0.4.0(@firebase/app-compat@0.5.7)(@firebase/app@0.14.7) + '@firebase/app-compat': 0.5.7 + '@firebase/app-types': 0.9.3 + '@firebase/auth': 1.12.0(@firebase/app@0.14.7) + '@firebase/auth-compat': 0.6.2(@firebase/app-compat@0.5.7)(@firebase/app-types@0.9.3)(@firebase/app@0.14.7) + '@firebase/data-connect': 0.3.12(@firebase/app@0.14.7) + '@firebase/database': 1.1.0 + '@firebase/database-compat': 2.1.0 + '@firebase/firestore': 4.10.0(@firebase/app@0.14.7) + '@firebase/firestore-compat': 0.4.4(@firebase/app-compat@0.5.7)(@firebase/app-types@0.9.3)(@firebase/app@0.14.7) + '@firebase/functions': 0.13.1(@firebase/app@0.14.7) + '@firebase/functions-compat': 0.4.1(@firebase/app-compat@0.5.7)(@firebase/app@0.14.7) + '@firebase/installations': 0.6.19(@firebase/app@0.14.7) + '@firebase/installations-compat': 0.2.19(@firebase/app-compat@0.5.7)(@firebase/app-types@0.9.3)(@firebase/app@0.14.7) + '@firebase/messaging': 0.12.23(@firebase/app@0.14.7) + '@firebase/messaging-compat': 0.2.23(@firebase/app-compat@0.5.7)(@firebase/app@0.14.7) + '@firebase/performance': 0.7.9(@firebase/app@0.14.7) + '@firebase/performance-compat': 0.2.22(@firebase/app-compat@0.5.7)(@firebase/app@0.14.7) + '@firebase/remote-config': 0.8.0(@firebase/app@0.14.7) + '@firebase/remote-config-compat': 0.2.21(@firebase/app-compat@0.5.7)(@firebase/app@0.14.7) + '@firebase/storage': 0.14.0(@firebase/app@0.14.7) + '@firebase/storage-compat': 0.4.0(@firebase/app-compat@0.5.7)(@firebase/app-types@0.9.3)(@firebase/app@0.14.7) + '@firebase/util': 1.13.0 + transitivePeerDependencies: + - '@react-native-async-storage/async-storage' + flat-cache@4.0.1: dependencies: flatted: 3.3.3 @@ -3873,6 +4609,8 @@ snapshots: gensync@1.0.0-beta.2: {} + get-caller-file@2.0.5: {} + get-east-asian-width@1.4.0: {} get-intrinsic@1.3.0: @@ -3956,8 +4694,12 @@ snapshots: dependencies: hermes-estree: 0.25.1 + http-parser-js@0.5.10: {} + husky@9.1.7: {} + idb@7.1.1: {} + ignore@5.3.2: {} ignore@7.0.5: {} @@ -4025,6 +4767,8 @@ snapshots: dependencies: call-bound: 1.0.4 + is-fullwidth-code-point@3.0.0: {} + is-fullwidth-code-point@5.1.0: dependencies: get-east-asian-width: 1.4.0 @@ -4220,6 +4964,8 @@ snapshots: dependencies: p-locate: 5.0.0 + lodash.camelcase@4.3.0: {} + lodash.merge@4.6.2: {} log-update@6.1.0: @@ -4230,6 +4976,8 @@ snapshots: strip-ansi: 7.1.2 wrap-ansi: 9.0.2 + long@5.3.2: {} + loose-envify@1.4.0: dependencies: js-tokens: 4.0.0 @@ -4425,6 +5173,21 @@ snapshots: object-assign: 4.1.1 react-is: 16.13.1 + protobufjs@7.5.4: + dependencies: + '@protobufjs/aspromise': 1.1.2 + '@protobufjs/base64': 1.1.2 + '@protobufjs/codegen': 2.0.4 + '@protobufjs/eventemitter': 1.1.0 + '@protobufjs/fetch': 1.1.0 + '@protobufjs/float': 1.0.2 + '@protobufjs/inquire': 1.1.0 + '@protobufjs/path': 1.1.2 + '@protobufjs/pool': 1.1.0 + '@protobufjs/utf8': 1.1.0 + '@types/node': 20.19.30 + long: 5.3.2 + proxy-from-env@1.1.0: {} punycode@2.3.1: {} @@ -4487,6 +5250,8 @@ snapshots: gopd: 1.2.0 set-function-name: 2.0.2 + require-directory@2.1.1: {} + resolve-from@4.0.0: {} resolve-pkg-maps@1.0.0: {} @@ -4524,6 +5289,8 @@ snapshots: has-symbols: 1.1.0 isarray: 2.0.5 + safe-buffer@5.2.1: {} + safe-push-apply@1.0.0: dependencies: es-errors: 1.3.0 @@ -4647,6 +5414,12 @@ snapshots: string-argv@0.3.2: {} + string-width@4.2.3: + dependencies: + emoji-regex: 8.0.0 + is-fullwidth-code-point: 3.0.0 + strip-ansi: 6.0.1 + string-width@7.2.0: dependencies: emoji-regex: 10.6.0 @@ -4708,6 +5481,10 @@ snapshots: define-properties: 1.2.1 es-object-atoms: 1.1.1 + strip-ansi@6.0.1: + dependencies: + ansi-regex: 5.0.1 + strip-ansi@7.1.2: dependencies: ansi-regex: 6.2.2 @@ -4876,6 +5653,16 @@ snapshots: - '@types/react' - '@types/react-dom' + web-vitals@4.2.4: {} + + websocket-driver@0.7.4: + dependencies: + http-parser-js: 0.5.10 + safe-buffer: 5.2.1 + websocket-extensions: 0.1.4 + + websocket-extensions@0.1.4: {} + which-boxed-primitive@1.1.1: dependencies: is-bigint: 1.1.0 @@ -4923,16 +5710,36 @@ snapshots: word-wrap@1.2.5: {} + wrap-ansi@7.0.0: + dependencies: + ansi-styles: 4.3.0 + string-width: 4.2.3 + strip-ansi: 6.0.1 + wrap-ansi@9.0.2: dependencies: ansi-styles: 6.2.3 string-width: 7.2.0 strip-ansi: 7.1.2 + y18n@5.0.8: {} + yallist@3.1.1: {} yaml@2.8.2: {} + yargs-parser@21.1.1: {} + + yargs@17.7.2: + dependencies: + cliui: 8.0.1 + escalade: 3.2.0 + get-caller-file: 2.0.5 + require-directory: 2.1.1 + string-width: 4.2.3 + y18n: 5.0.8 + yargs-parser: 21.1.1 + yocto-queue@0.1.0: {} zod-validation-error@4.0.2(zod@4.3.6): diff --git a/public/firebase-messaging-sw.js b/public/firebase-messaging-sw.js new file mode 100644 index 0000000..b7c5e14 --- /dev/null +++ b/public/firebase-messaging-sw.js @@ -0,0 +1,38 @@ +// public/firebase-messaging-sw.js + +importScripts( + "https://www.gstatic.com/firebasejs/9.23.0/firebase-app-compat.js", +); +importScripts( + "https://www.gstatic.com/firebasejs/9.23.0/firebase-messaging-compat.js", +); + +let messaging = null; + +// 메인 앱에서 Firebase Config를 받아서 초기화 +self.addEventListener("message", (event) => { + if (event.data && event.data.type === "INIT_FIREBASE") { + const firebaseConfig = event.data.config; + + if (!firebase.apps.length) { + firebase.initializeApp(firebaseConfig); + messaging = firebase.messaging(); + + // 백그라운드 알림 처리 + messaging.onBackgroundMessage((payload) => { + console.log("[Service Worker] 백그라운드 메시지 수신:", payload); + + const notificationTitle = payload.notification?.title || "새 알림"; + const notificationOptions = { + body: payload.notification?.body || "", + icon: payload.notification?.icon || "/logo/logo.svg", + }; + + self.registration.showNotification( + notificationTitle, + notificationOptions, + ); + }); + } + } +}); diff --git a/tsconfig.json b/tsconfig.json index 3a13f90..5d4792b 100644 --- a/tsconfig.json +++ b/tsconfig.json @@ -29,6 +29,6 @@ ".next/types/**/*.ts", ".next/dev/types/**/*.ts", "**/*.mts" - ], +, "public/firebase-messaging-sw.js" ], "exclude": ["node_modules"] }