v0.12.25 FCM bug fixes
This commit is contained in:
@@ -1,6 +1,6 @@
|
|||||||
{
|
{
|
||||||
"name": "rosterchirp-backend",
|
"name": "rosterchirp-backend",
|
||||||
"version": "0.12.24",
|
"version": "0.12.25",
|
||||||
"description": "RosterChirp backend server",
|
"description": "RosterChirp backend server",
|
||||||
"main": "src/index.js",
|
"main": "src/index.js",
|
||||||
"scripts": {
|
"scripts": {
|
||||||
|
|||||||
@@ -97,7 +97,7 @@ router.get('/firebase-config', (req, res) => {
|
|||||||
const appId = process.env.FIREBASE_APP_ID;
|
const appId = process.env.FIREBASE_APP_ID;
|
||||||
const vapidKey = process.env.FIREBASE_VAPID_KEY;
|
const vapidKey = process.env.FIREBASE_VAPID_KEY;
|
||||||
|
|
||||||
if (!apiKey || !projectId || !messagingSenderId || !appId) {
|
if (!apiKey || !projectId || !messagingSenderId || !appId || !vapidKey) {
|
||||||
return res.status(503).json({ error: 'FCM not configured' });
|
return res.status(503).json({ error: 'FCM not configured' });
|
||||||
}
|
}
|
||||||
res.json({ apiKey, projectId, messagingSenderId, appId, vapidKey });
|
res.json({ apiKey, projectId, messagingSenderId, appId, vapidKey });
|
||||||
@@ -220,7 +220,7 @@ router.get('/debug', authMiddleware, async (req, res) => {
|
|||||||
WHERE ps.fcm_token IS NOT NULL
|
WHERE ps.fcm_token IS NOT NULL
|
||||||
ORDER BY u.name, ps.device
|
ORDER BY u.name, ps.device
|
||||||
`);
|
`);
|
||||||
const fcmConfigured = !!(process.env.FIREBASE_API_KEY && process.env.FIREBASE_SERVICE_ACCOUNT);
|
const fcmConfigured = !!(process.env.FIREBASE_API_KEY && process.env.FIREBASE_SERVICE_ACCOUNT && process.env.FIREBASE_VAPID_KEY);
|
||||||
const firebaseAdminReady = !!getMessaging();
|
const firebaseAdminReady = !!getMessaging();
|
||||||
res.json({ subscriptions: subs, fcmConfigured, firebaseAdminReady });
|
res.json({ subscriptions: subs, fcmConfigured, firebaseAdminReady });
|
||||||
} catch (e) { res.status(500).json({ error: e.message }); }
|
} catch (e) { res.status(500).json({ error: e.message }); }
|
||||||
|
|||||||
2
build.sh
2
build.sh
@@ -13,7 +13,7 @@
|
|||||||
# ─────────────────────────────────────────────────────────────
|
# ─────────────────────────────────────────────────────────────
|
||||||
set -euo pipefail
|
set -euo pipefail
|
||||||
|
|
||||||
VERSION="${1:-0.12.24}"
|
VERSION="${1:-0.12.25}"
|
||||||
ACTION="${2:-}"
|
ACTION="${2:-}"
|
||||||
REGISTRY="${REGISTRY:-}"
|
REGISTRY="${REGISTRY:-}"
|
||||||
IMAGE_NAME="rosterchirp"
|
IMAGE_NAME="rosterchirp"
|
||||||
|
|||||||
@@ -1,6 +1,6 @@
|
|||||||
{
|
{
|
||||||
"name": "rosterchirp-frontend",
|
"name": "rosterchirp-frontend",
|
||||||
"version": "0.12.24",
|
"version": "0.12.25",
|
||||||
"private": true,
|
"private": true,
|
||||||
"scripts": {
|
"scripts": {
|
||||||
"dev": "vite",
|
"dev": "vite",
|
||||||
|
|||||||
@@ -211,7 +211,8 @@ function PushDebugTab() {
|
|||||||
const [testing, setTesting] = useState(false);
|
const [testing, setTesting] = useState(false);
|
||||||
|
|
||||||
const permission = (typeof Notification !== 'undefined') ? Notification.permission : 'unsupported';
|
const permission = (typeof Notification !== 'undefined') ? Notification.permission : 'unsupported';
|
||||||
const cachedToken = localStorage.getItem('rc_fcm_token');
|
const [cachedToken, setCachedToken] = useState(localStorage.getItem('rc_fcm_token'));
|
||||||
|
const [lastError, setLastError] = useState(localStorage.getItem('rc_fcm_error'));
|
||||||
|
|
||||||
const load = async () => {
|
const load = async () => {
|
||||||
setLoading(true);
|
setLoading(true);
|
||||||
@@ -245,9 +246,21 @@ function PushDebugTab() {
|
|||||||
|
|
||||||
const clearToken = () => {
|
const clearToken = () => {
|
||||||
localStorage.removeItem('rc_fcm_token');
|
localStorage.removeItem('rc_fcm_token');
|
||||||
|
localStorage.removeItem('rc_fcm_error');
|
||||||
|
setCachedToken(null);
|
||||||
|
setLastError(null);
|
||||||
toast('Cached token cleared — reload to re-register with server', 'info');
|
toast('Cached token cleared — reload to re-register with server', 'info');
|
||||||
};
|
};
|
||||||
|
|
||||||
|
const reregister = () => {
|
||||||
|
localStorage.removeItem('rc_fcm_token');
|
||||||
|
localStorage.removeItem('rc_fcm_error');
|
||||||
|
setCachedToken(null);
|
||||||
|
setLastError(null);
|
||||||
|
window.dispatchEvent(new CustomEvent('rosterchirp:push-init'));
|
||||||
|
toast('Re-registering push subscription…', 'info');
|
||||||
|
};
|
||||||
|
|
||||||
const box = { background: 'var(--surface-variant)', border: '1px solid var(--border)', borderRadius: 'var(--radius)', padding: '12px 14px', marginBottom: 14 };
|
const box = { background: 'var(--surface-variant)', border: '1px solid var(--border)', borderRadius: 'var(--radius)', padding: '12px 14px', marginBottom: 14 };
|
||||||
const sectionLabel = { fontSize: 11, fontWeight: 600, color: 'var(--text-tertiary)', textTransform: 'uppercase', letterSpacing: '0.5px', marginBottom: 8 };
|
const sectionLabel = { fontSize: 11, fontWeight: 600, color: 'var(--text-tertiary)', textTransform: 'uppercase', letterSpacing: '0.5px', marginBottom: 8 };
|
||||||
|
|
||||||
@@ -263,8 +276,12 @@ function PushDebugTab() {
|
|||||||
<DebugRow label="Cached FCM token" value={cachedToken ? cachedToken.slice(0, 36) + '…' : 'None'} ok={!!cachedToken} bad={!cachedToken} />
|
<DebugRow label="Cached FCM token" value={cachedToken ? cachedToken.slice(0, 36) + '…' : 'None'} ok={!!cachedToken} bad={!cachedToken} />
|
||||||
{debugData && <DebugRow label="FCM env vars" value={debugData.fcmConfigured ? 'Present' : 'Missing'} ok={debugData.fcmConfigured} bad={!debugData.fcmConfigured} />}
|
{debugData && <DebugRow label="FCM env vars" value={debugData.fcmConfigured ? 'Present' : 'Missing'} ok={debugData.fcmConfigured} bad={!debugData.fcmConfigured} />}
|
||||||
{debugData && <DebugRow label="Firebase Admin" value={debugData.firebaseAdminReady ? 'Ready' : 'Not ready'} ok={debugData.firebaseAdminReady} bad={!debugData.firebaseAdminReady} />}
|
{debugData && <DebugRow label="Firebase Admin" value={debugData.firebaseAdminReady ? 'Ready' : 'Not ready'} ok={debugData.firebaseAdminReady} bad={!debugData.firebaseAdminReady} />}
|
||||||
|
{lastError && <DebugRow label="Last reg. error" value={lastError} bad={true} />}
|
||||||
|
</div>
|
||||||
|
<div style={{ display: 'flex', gap: 8, flexWrap: 'wrap' }}>
|
||||||
|
<button className="btn btn-sm btn-primary" onClick={reregister}>Re-register</button>
|
||||||
|
<button className="btn btn-sm btn-secondary" onClick={clearToken}>Clear cached token</button>
|
||||||
</div>
|
</div>
|
||||||
<button className="btn btn-sm btn-secondary" onClick={clearToken}>Clear cached token</button>
|
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
{/* Test push */}
|
{/* Test push */}
|
||||||
|
|||||||
@@ -132,12 +132,22 @@ export default function Chat() {
|
|||||||
// deliver. Passing serviceWorkerRegistration directly to getToken() is enough
|
// deliver. Passing serviceWorkerRegistration directly to getToken() is enough
|
||||||
// for Firebase to return the existing valid token without needing a refresh.
|
// for Firebase to return the existing valid token without needing a refresh.
|
||||||
console.log('[Push] Requesting FCM token...');
|
console.log('[Push] Requesting FCM token...');
|
||||||
const fcmToken = await getToken(firebaseMessaging, {
|
let fcmToken;
|
||||||
vapidKey,
|
try {
|
||||||
serviceWorkerRegistration: reg,
|
fcmToken = await getToken(firebaseMessaging, {
|
||||||
});
|
vapidKey,
|
||||||
|
serviceWorkerRegistration: reg,
|
||||||
|
});
|
||||||
|
} catch (tokenErr) {
|
||||||
|
const msg = tokenErr.message || 'getToken() threw an error';
|
||||||
|
console.warn('[Push] getToken() threw:', msg);
|
||||||
|
localStorage.setItem('rc_fcm_error', msg);
|
||||||
|
return;
|
||||||
|
}
|
||||||
if (!fcmToken) {
|
if (!fcmToken) {
|
||||||
console.warn('[Push] getToken() returned null — notification permission may not be granted at OS level, or VAPID key is wrong');
|
const msg = 'getToken() returned null — check VAPID key and OS notification permission';
|
||||||
|
console.warn('[Push]', msg);
|
||||||
|
localStorage.setItem('rc_fcm_error', msg);
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
console.log('[Push] FCM token obtained:', fcmToken.slice(0, 30) + '...');
|
console.log('[Push] FCM token obtained:', fcmToken.slice(0, 30) + '...');
|
||||||
@@ -147,6 +157,7 @@ export default function Chat() {
|
|||||||
const cachedToken = localStorage.getItem('rc_fcm_token');
|
const cachedToken = localStorage.getItem('rc_fcm_token');
|
||||||
if (cachedToken === fcmToken) {
|
if (cachedToken === fcmToken) {
|
||||||
console.log('[Push] Token unchanged — skipping subscribe');
|
console.log('[Push] Token unchanged — skipping subscribe');
|
||||||
|
localStorage.removeItem('rc_fcm_error');
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -158,13 +169,17 @@ export default function Chat() {
|
|||||||
});
|
});
|
||||||
if (!subRes.ok) {
|
if (!subRes.ok) {
|
||||||
const err = await subRes.json().catch(() => ({}));
|
const err = await subRes.json().catch(() => ({}));
|
||||||
console.warn('[Push] Subscribe failed:', err.error || subRes.status);
|
const msg = `Subscribe failed: ${err.error || subRes.status}`;
|
||||||
|
console.warn('[Push]', msg);
|
||||||
|
localStorage.setItem('rc_fcm_error', msg);
|
||||||
} else {
|
} else {
|
||||||
localStorage.setItem('rc_fcm_token', fcmToken);
|
localStorage.setItem('rc_fcm_token', fcmToken);
|
||||||
|
localStorage.removeItem('rc_fcm_error');
|
||||||
console.log('[Push] FCM subscription registered successfully');
|
console.log('[Push] FCM subscription registered successfully');
|
||||||
}
|
}
|
||||||
} catch (e) {
|
} catch (e) {
|
||||||
console.warn('[Push] FCM subscription failed:', e.message);
|
console.warn('[Push] FCM subscription failed:', e.message);
|
||||||
|
localStorage.setItem('rc_fcm_error', e.message);
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|||||||
Reference in New Issue
Block a user