Press n or j to go to the next uncovered block, b, p or k for the previous block.
| 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 | 12x 12x 6x 4x 1x 1x 4x 3x 3x 3x 8x 6x 6x 4x 2x 3x 4x 2x 1x 1x 12x | /**
* Shared FCM (Firebase Cloud Messaging) utilities.
*
* Extracted from rooms.js, conversations.js, and reports.js to eliminate duplication.
*/
const { messaging, db, FieldValue } = require('./firebase');
const log = require('./log');
/**
* Send a data-only FCM message to multiple tokens via Firebase Admin SDK.
* All values are stringified (FCM data messages require string values).
* Returns a list of invalid tokens that should be cleaned up.
*/
async function sendFcmToTokens(tokens, data) {
if (!tokens || tokens.length === 0) return [];
if (process.env.NODE_ENV === 'local') {
log.info('fcm', `[FCM-LOCAL] Would send to ${tokens.length} tokens: ${data?.title}`);
return [];
}
const stringData = Object.fromEntries(Object.entries(data).map(([k, v]) => [k, String(v)]));
const result = await messaging.sendEachForMulticast({
tokens,
data: stringData,
});
const invalidTokens = [];
result.responses.forEach((resp, i) => {
if (resp.error) {
const code = resp.error.code;
if (
code === 'messaging/invalid-registration-token' ||
code === 'messaging/registration-token-not-registered' ||
code === 'messaging/sender-id-mismatch' ||
code === 'messaging/invalid-argument'
) {
invalidTokens.push(tokens[i]);
} else {
log.warn('fcm', `FCM send failed for token index ${i}`, {
code,
message: resp.error.message,
});
}
}
});
return invalidTokens;
}
/**
* Remove invalid FCM tokens from a user's doc using arrayRemove.
*/
async function cleanupInvalidTokens(invalidTokens, userId) {
if (!invalidTokens || invalidTokens.length === 0 || !userId) return;
if (process.env.NODE_ENV === 'local') return;
try {
await db.doc(`users/${userId}`).update({
fcmTokens: FieldValue.arrayRemove(...invalidTokens),
});
} catch (err) {
log.error('fcm', 'Failed to clean invalid tokens', { userId, error: err.message });
}
}
module.exports = { sendFcmToTokens, cleanupInvalidTokens };
|