← back to AbramsOS

lib/drive-fetcher.js

57 lines

// Google Drive fetcher. Walks the user's Drive for receipt-shaped files
// (PDFs, JPGs, PNGs whose name suggests "receipt", "invoice", "order").
// Returns metadata + file content stream; the caller persists.
//
// Uses the same OAuth client (refresh token shared with Gmail since it's the
// same Google account, drive.readonly scope was added to lib/google-oauth.js).

const { google } = require('googleapis');
const { clientFor } = require('./google-oauth');

const RECEIPT_NAME_QUERY = `(name contains 'receipt' or name contains 'invoice' or name contains 'order' or name contains 'confirmation')`;
const MIME_QUERY = `(mimeType = 'application/pdf' or mimeType contains 'image/')`;
const RECENT_QUERY = `modifiedTime > '${new Date(Date.now() - 90 * 24 * 60 * 60 * 1000).toISOString()}'`;

function driveClient(refreshToken) {
  return google.drive({ version: 'v3', auth: clientFor(refreshToken) });
}

async function listReceiptFiles(refreshToken, { max = 100 } = {}) {
  const drive = driveClient(refreshToken);
  const out = [];
  let pageToken;
  do {
    const resp = await drive.files.list({
      q: `${RECEIPT_NAME_QUERY} and ${MIME_QUERY} and ${RECENT_QUERY} and trashed = false`,
      fields: 'nextPageToken, files(id, name, mimeType, size, modifiedTime, webViewLink, webContentLink, md5Checksum)',
      pageSize: Math.min(100, max - out.length),
      pageToken,
      orderBy: 'modifiedTime desc',
    });
    for (const f of resp.data.files || []) out.push(f);
    pageToken = resp.data.nextPageToken;
  } while (pageToken && out.length < max);
  return out;
}

/**
 * Returns an async stream of bytes for a Drive file.
 * Caller handles writing to disk / hashing.
 */
async function downloadFile(refreshToken, fileId) {
  const drive = driveClient(refreshToken);
  const resp = await drive.files.get({ fileId, alt: 'media' }, { responseType: 'stream' });
  return resp.data;
}

async function fileMetadata(refreshToken, fileId) {
  const drive = driveClient(refreshToken);
  const resp = await drive.files.get({
    fileId,
    fields: 'id, name, mimeType, size, modifiedTime, webViewLink, md5Checksum',
  });
  return resp.data;
}

module.exports = { listReceiptFiles, downloadFile, fileMetadata };