v0.12.6 FCM updates

This commit is contained in:
2026-03-23 13:11:47 -04:00
parent 10e3df25f9
commit a0183458eb
4 changed files with 47 additions and 58 deletions

View File

@@ -1,6 +1,6 @@
{ {
"name": "rosterchirp-backend", "name": "rosterchirp-backend",
"version": "0.12.5", "version": "0.12.6",
"description": "RosterChirp backend server", "description": "RosterChirp backend server",
"main": "src/index.js", "main": "src/index.js",
"scripts": { "scripts": {

View File

@@ -13,7 +13,7 @@
# ───────────────────────────────────────────────────────────── # ─────────────────────────────────────────────────────────────
set -euo pipefail set -euo pipefail
VERSION="${1:-0.12.5}" VERSION="${1:-0.12.6}"
ACTION="${2:-}" ACTION="${2:-}"
REGISTRY="${REGISTRY:-}" REGISTRY="${REGISTRY:-}"
IMAGE_NAME="rosterchirp" IMAGE_NAME="rosterchirp"

View File

@@ -1,6 +1,6 @@
{ {
"name": "rosterchirp-frontend", "name": "rosterchirp-frontend",
"version": "0.12.5", "version": "0.12.6",
"private": true, "private": true,
"scripts": { "scripts": {
"dev": "vite", "dev": "vite",

View File

@@ -1,35 +1,25 @@
// ── Firebase Messaging (background push for Android PWA) ────────────────────── // ── Firebase Messaging (background push for Android PWA) ──────────────────────
// Dynamically fetch Firebase config from backend to ensure consistency // Config must be hardcoded here — the SW is woken by push events before any
// async fetch can resolve, so Firebase must be initialised synchronously.
importScripts('https://www.gstatic.com/firebasejs/10.14.1/firebase-app-compat.js'); importScripts('https://www.gstatic.com/firebasejs/10.14.1/firebase-app-compat.js');
importScripts('https://www.gstatic.com/firebasejs/10.14.1/firebase-messaging-compat.js'); importScripts('https://www.gstatic.com/firebasejs/10.14.1/firebase-messaging-compat.js');
let FIREBASE_CONFIG = null; const FIREBASE_CONFIG = {
let VAPID_KEY = null; apiKey: "AIzaSyDx191unzXFT4WA1OvkdbrIY_c57kgruAU",
authDomain: "rosterchirp-push.firebaseapp.com",
projectId: "rosterchirp-push",
storageBucket: "rosterchirp-push.firebasestorage.app",
messagingSenderId: "126479377334",
appId: "1:126479377334:web:280abdd135cf7e0c50d717"
};
// Fetch Firebase config and initialise messaging // Initialise Firebase synchronously so the push listener is ready immediately
let messaging = null; let messaging = null;
let firebaseConfigPromise = fetch('/api/push/firebase-config') if (FIREBASE_CONFIG.apiKey !== '__FIREBASE_API_KEY__') {
.then(res => res.json()) firebase.initializeApp(FIREBASE_CONFIG);
.then(config => { messaging = firebase.messaging();
FIREBASE_CONFIG = { console.log('[SW] Firebase initialised');
apiKey: config.apiKey, }
authDomain: config.authDomain || `${config.projectId}.firebaseapp.com`,
projectId: config.projectId,
storageBucket: config.storageBucket || `${config.projectId}.firebasestorage.app`,
messagingSenderId: config.messagingSenderId,
appId: config.appId
};
VAPID_KEY = config.vapidKey;
if (FIREBASE_CONFIG.apiKey) {
firebase.initializeApp(FIREBASE_CONFIG);
messaging = firebase.messaging();
console.log('[SW] Firebase initialized with dynamic config');
}
})
.catch(err => {
console.warn('[SW] Failed to fetch Firebase config:', err);
});
// ── Cache ───────────────────────────────────────────────────────────────────── // ── Cache ─────────────────────────────────────────────────────────────────────
const CACHE_NAME = 'rosterchirp-v1'; const CACHE_NAME = 'rosterchirp-v1';
@@ -81,49 +71,48 @@ function showRosterChirpNotification(data) {
} }
// ── FCM background messages ─────────────────────────────────────────────────── // ── FCM background messages ───────────────────────────────────────────────────
// Wait for Firebase config to be loaded before setting up message handler if (messaging) {
firebaseConfigPromise.then(() => { messaging.onBackgroundMessage((payload) => {
if (messaging) { console.log('[SW] onBackgroundMessage received, data:', JSON.stringify(payload.data));
messaging.onBackgroundMessage((payload) => { return showRosterChirpNotification(payload.data || {});
console.log('[SW] onBackgroundMessage received, data:', JSON.stringify(payload.data)); });
return showRosterChirpNotification(payload.data || {}); } else {
}); console.warn('[SW] Firebase messaging not initialised — push notifications disabled');
} else { }
console.warn('[SW] Firebase messaging not initialised — push notifications disabled');
}
});
// ── Raw push event (fallback for Android) ───────────────────────────────────── // ── Raw push event (fallback for Android) ─────────────────────────────────────
// Android Chrome sometimes doesn't properly trigger Firebase's onBackgroundMessage // Only runs when Firebase messaging is NOT yet initialised (e.g. push arrives
// This fallback ensures notifications are displayed even if Firebase SDK fails // before firebaseConfigPromise resolves). If Firebase IS ready it already has
// its own push listener registered and will call onBackgroundMessage — running
// this handler too would show the notification twice.
self.addEventListener('push', (event) => { self.addEventListener('push', (event) => {
console.log('[SW] push event received, hasData:', !!event.data, 'text:', event.data?.text?.()?.slice(0, 120)); console.log('[SW] push event received, hasData:', !!event.data, 'messaging ready:', !!messaging);
// Try to handle the push event directly as a fallback // Firebase compat SDK handles it via onBackgroundMessage — skip to avoid double notification.
if (event.data) { if (messaging) return;
if (!event.data) return;
event.waitUntil((async () => {
try { try {
const data = event.data.json(); const data = event.data.json();
console.log('[SW] Push data parsed:', JSON.stringify(data)); console.log('[SW] Push fallback — data parsed:', JSON.stringify(data));
// If this is a Firebase message with data payload, show notification
if (data.data || (data.title && data.body)) { if (data.data || (data.title && data.body)) {
const notificationData = data.data || data; await showRosterChirpNotification(data.data || data);
return showRosterChirpNotification(notificationData);
} }
} catch (e) { } catch (e) {
console.warn('[SW] Failed to parse push data:', e); console.warn('[SW] Push fallback — failed to parse push data:', e);
// Try to show a basic notification with the raw text
const text = event.data.text(); const text = event.data.text();
if (text) { if (text) {
return self.registration.showNotification('RosterChirp', { await self.registration.showNotification('RosterChirp', {
body: text.slice(0, 100), body: text.slice(0, 100),
icon: '/icons/icon-192.png', icon: '/icons/icon-192.png',
badge: '/icons/icon-192-maskable.png', badge: '/icons/icon-192-maskable.png',
tag: 'rosterchirp-fallback', tag: 'rosterchirp-fallback',
}); });
} }
} }
} })());
}); });
// ── Notification click ──────────────────────────────────────────────────────── // ── Notification click ────────────────────────────────────────────────────────