@mint-soft/notikit-web
v0.2.0
Published
Notikit Web SDK — browser push via FCM (Firebase Cloud Messaging)
Readme
@mint-soft/notikit-web
Notikit Web SDK — 브라우저 푸시 (FCM / Firebase Cloud Messaging).
토큰은 FCM 등록 토큰입니다. 서버는 안드로이드·iOS 와 같은 경로로 발송하므로 웹 전용 전송 분기가 필요 없습니다.
설치
npm install @mint-soft/notikit-web firebasefirebase 는 peer dependency 입니다(선택). getToken 을 직접 넘기면 설치하지 않아도 됩니다.
1) 서비스워커 배치
public/notikit-sw.js 로 SDK 의 NOTIKIT_SERVICE_WORKER 문자열을 그대로 저장하세요.
import { NOTIKIT_SERVICE_WORKER } from "@mint-soft/notikit-web";
// 빌드 스크립트에서: fs.writeFileSync("public/notikit-sw.js", NOTIKIT_SERVICE_WORKER)워커는 설정을 자기 URL 쿼리에서만 읽습니다(워커에는 SDK 인스턴스가 없습니다).
register() 가 쿼리를 자동으로 붙이므로 경로만 맞추면 됩니다.
2) 등록
firebase 설정은 항상 필요합니다. 워커에는 앱의 Firebase 인스턴스가 없어서, 이 값으로
직접 초기화해야 백그라운드 메시지를 받습니다.
import { NotikitWeb } from "@mint-soft/notikit-web";
const notikit = new NotikitWeb({
baseUrl: "https://push.example.com",
apiKey: "nk_xxx",
vapidPublicKey: "B...", // Firebase 콘솔 > 클라우드 메시징 > 웹 푸시 인증서
userId: "user-123", // 고객 서비스의 유저 id (서버에는 user_id 로 전송)
firebase: {
apiKey: "AIza...",
projectId: "my-project",
messagingSenderId: "1234567890",
appId: "1:1234567890:web:abc",
},
// 워커가 불러올 compat SDK 버전. 설치한 firebase 와 메이저를 맞추세요.
firebaseSdkVersion: "12.0.0",
});
if (NotikitWeb.isSupported()) {
await notikit.register(); // 권한 요청 → FCM 토큰 → 서버 등록
}userId 는 고객 서비스의 유저 id 이며 서버에 user_id 로 보냅니다. 이전 이름 externalId(external_id)도
그대로 동작하지만 deprecated 입니다 — 둘 다 주면 userId 가 이깁니다. identify(userId, attributes?, name?) 도 같습니다.
이미 Firebase 를 초기화한 앱이라면 토큰 획득만 넘겨받게 할 수 있습니다 — SDK 가
initializeApp 을 또 부르면 앱이 쓰던 인스턴스와 어긋납니다. (firebase 설정은 그래도
워커용으로 함께 넘겨야 합니다.)
import { getMessaging, getToken } from "firebase/messaging";
const notikit = new NotikitWeb({
/* ...위와 동일... */
getToken: (reg) =>
getToken(getMessaging(myFirebaseApp), { vapidKey: "B...", serviceWorkerRegistration: reg }),
});3) 토큰 교체
FCM 은 토큰을 갱신합니다. 새 토큰으로 register() 를 다시 부르면 행이 하나 더 생겨
같은 사람에게 중복 발송됩니다. 교체는 전용 메서드를 쓰세요 — 서버가 기존 행을 제자리
갱신해 토픽 구독·클릭 이력이 보존됩니다.
웹에는 토큰 갱신 이벤트가 없습니다. 네이티브의 onNewToken/didReceiveRegistrationToken
에 해당하는 것이 모듈 API(v10~v12)에 없으므로, 앱이 직접 비교해야 합니다. 앱을 열 때
한 번 확인하는 정도면 충분합니다 — FCM 토큰은 수명이 깁니다.
const saved = localStorage.getItem("fcm_token");
const current = await getToken(getMessaging(app), { vapidKey, serviceWorkerRegistration: reg });
if (saved && current && saved !== current) {
await notikit.rotateToken(saved, current);
}
localStorage.setItem("fcm_token", current);서버가 옛 토큰을 찾지 못하거나 증명이 맞지 않아 교체하지 못하면(rotated: false), SDK 가 새 토큰을
현재 userId·identityHash 로 직접 등록합니다. 그것마저 실패하면 던지므로 저장한 토큰을
갱신하지 말고 다음에 다시 시도하세요(위 예제는 던지면 setItem 까지 가지 않습니다).
클릭 추적
워커가 notificationclick 에서 자동으로 보고합니다. 탭이 보이는 상태(포그라운드)에서 온 푸시도
onForegroundMessage 를 넘기지 않았다면 SDK 가 서비스워커 등록으로 같은 모양의 알림을 띄우므로
클릭은 같은 경로로 보고됩니다(무음 푸시는 띄우지 않습니다). 보고에 쓸 FCM 토큰은 등록 시점에
IndexedDB 에 저장된 값을 읽습니다 — 워커에서는 getToken 을 부를 수 없기 때문입니다.
수신(도달) 추적
워커가 push 이벤트에서 자동으로 보고합니다(POST /api/v1/messages/received).
앱 코드는 아무것도 하지 않아도 됩니다 — 워커만 최신 NOTIKIT_SERVICE_WORKER 로 배치하세요.
notificationclick 이 아니라 push 에 다는 이유: 무음(data-only) 푸시는 알림을 띄우지
않고, 사용자가 알림을 누르지 않는 경우가 대부분입니다. push 는 배달된 모든 메시지에
대해 한 번 뜨므로 "받았다"의 정의와 정확히 겹칩니다.
이 보고가 없으면 콘솔의 "도달" 칸은 계속 비어 있습니다 — 발송 성공(FCM 접수)은 기기가
꺼져 있어도 성공하므로 도달이 아닙니다. 같은 워커 인스턴스 안에서 같은 발송이 다시
배달되면 요청을 내보내지 않고, 서버도 (발송, 기기) 유니크로 한 번만 셉니다.
iOS Safari 는 홈화면에 추가한 PWA 에서만 웹 푸시가 동작합니다(16.4+).
라이선스
Apache-2.0
