All files / src/cron expireDataExports.js

100% Statements 21/21
87.5% Branches 7/8
100% Functions 1/1
100% Lines 20/20

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              1x 1x 1x         1x     5x           5x 1x         5x 5x 503x 503x   2x 2x 2x   1x       1x   1x             5x 1x       1x  
/**
 * Expire data exports cron — runs daily at 04:00 UTC.
 *
 * Deletes R2 objects for expired exports and marks them as expired
 * in Firestore.
 */
 
const { db } = require('../utils/firebase');
const r2 = require('../utils/r2');
const log = require('../utils/log');
 
// Cap per-tick reads to keep Spark-tier quota bounded. Daily cron;
// any backlog beyond CRON_LIMIT processes on the next day's tick.
// Pattern matches subscriptions.js / expireBans.js cron caps.
const CRON_LIMIT = 500;
 
async function expireDataExports() {
  const expiredSnap = await db
    .collection('users')
    .where('dataExportStatus', '==', 'ready')
    .where('dataExportExpiresAt', '>', 0)
    .limit(CRON_LIMIT)
    .get();
  if (expiredSnap.size === CRON_LIMIT) {
    log.warn('cron', 'expireDataExports: hit CRON_LIMIT — possible truncation', {
      limit: CRON_LIMIT,
    });
  }
 
  let expired = 0;
  for (const doc of expiredSnap.docs) {
    const data = doc.data();
    if (data.dataExportExpiresAt > Date.now()) continue; // Not yet expired
 
    try {
      Eif (data.dataExportR2Key) {
        await r2.deleteObjects([data.dataExportR2Key]);
      }
      await db.doc(`users/${doc.id}`).update({
        dataExportStatus: 'expired',
        dataExportR2Key: null,
      });
      expired++;
    } catch (err) {
      log.error('cron', 'Failed to expire data export', {
        uniqueId: doc.id,
        error: err.message,
      });
    }
  }
 
  if (expired > 0) {
    log.info('cron', `Expired ${expired} data exports`);
  }
}
 
module.exports = expireDataExports;