import type express from 'express'; import {BetaAnalyticsDataClient} from '@google-analytics/data'; import {getFirestore} from 'firebase-admin/firestore'; // Replace with your credentials const CLIENT_EMAIL = process.env.GOOGLE_SERVICE_ACCOUNT_EMAIL as string; const PRIVATE_KEY = (process.env.GOOGLE_GA_PRIVATE_KEY || '') .split(String.raw`\n`) .join('\n'); const client = new BetaAnalyticsDataClient({ credentials: { // eslint-disable-next-line @typescript-eslint/naming-convention client_email: CLIENT_EMAIL, // eslint-disable-next-line @typescript-eslint/naming-convention private_key: PRIVATE_KEY, }, }); import type {LogContext} from '@rocicorp/logger'; export async function populateMetrics( _request: express.Request, response: express.Response, _lc: LogContext, ) { try { const daysAgo = parseInt(_request.query.duration as string) || 30; const REFLECT_CLI_PROPERTY_ID = '407999956'; const REFLECT_NET_WEB_PROPERTY_ID = '373998424'; const REFLECT_HELLO_NET_PROPERTY_ID = '405748009'; const [ analyticsCliActiveUsersData, analyticsCliActiveEventsData, analyticsCliEventsData, analyticsReflectNetActiveUsersData, analyticsHelloReflectNetActiveUsersData, npmStats, appMetrics, ] = await Promise.all([ await fetchGoogleAnalyticsData( daysAgo, REFLECT_CLI_PROPERTY_ID, [{name: 'date'}], [{name: 'activeUsers'}], ), await fetchGoogleAnalyticsData( daysAgo, REFLECT_CLI_PROPERTY_ID, [{name: 'date'}], [{name: 'eventCount'}], ), await fetchGoogleAnalyticsData( daysAgo, REFLECT_CLI_PROPERTY_ID, [{name: 'eventName'}, {name: 'date'}], [{name: 'eventCount'}], ), await fetchGoogleAnalyticsData( daysAgo, REFLECT_NET_WEB_PROPERTY_ID, [{name: 'date'}], [{name: 'activeUsers'}], ), await fetchGoogleAnalyticsData( daysAgo, REFLECT_HELLO_NET_PROPERTY_ID, [{name: 'date'}], [{name: 'activeUsers'}], ), await fetchNpmStats(daysAgo), await fetchFirebaseData(), ]).catch(error => { throw new Error(error); }); const chartData = { analyticsCliActiveUsersData, analyticsCliActiveEventsData, analyticsCliEventsData, analyticsReflectNetActiveUsersData, analyticsHelloReflectNetActiveUsersData, npmStats, appMetrics, }; response.json(chartData); } catch (error) { console.error(error); response.status(500).send('Error fetching data'); } } async function fetchNpmStats(daysAgo: number) { const dateDaysAgo = new Date(); dateDaysAgo.setDate(dateDaysAgo.getDate() - daysAgo); const startDate = dateDaysAgo.toISOString().slice(0, 10); // Format: YYYY-MM-DD const todayDate = new Date().toISOString().slice(0, 10); // Format: YYYY-MM-DD //write function that calls this endpoint and returns the json const url = `https://api.npmjs.org/downloads/range/${startDate}:${todayDate}/@rocicorp/reflect`; const response = await fetch(url); if (!response.ok) { throw new Error(`HTTP error! Status: ${response.status}`); } return await response.json(); } async function fetchGoogleAnalyticsData( daysAgo: number, propertyId: string, dimensions: {name: string}[], metrics: {name: string}[], ) { const dateDaysAgo = new Date(); dateDaysAgo.setDate(dateDaysAgo.getDate() - daysAgo); const startDate = dateDaysAgo.toISOString().slice(0, 10); // Format: YYYY-MM-DD const request = { property: `properties/${propertyId}`, dateRanges: [ { startDate, endDate: 'today', }, ], dimensions, metrics, }; const [response] = await client.runReport(request); return response; } async function fetchFirebaseData() { const firestore = getFirestore(); //current years metrics const dt = new Date(); const year = dt.getFullYear(); const month = (dt.getMonth() + 1).toString().padStart(2, '0'); const q = await firestore .collectionGroup('metrics') .where('yearMonth', '==', Number(year + month)) .where('appID', '==', null) .get(); const {docs} = q; const data = []; for (const doc of docs) { data.push(doc.data()); } const q2 = await firestore.collectionGroup('teams').get(); const teamsData = []; const teamDocs = q2.docs; for (const doc of teamDocs) { const data = doc.data(); const {id} = doc; teamsData.push({id, data}); } return {teamsData, data}; }