UNPKG

@pierrad/web-carbon-analyzer

Version:

A tool to measure the carbon footprint of websites using CO2.js

189 lines 8.08 kB
"use strict"; var __createBinding = (this && this.__createBinding) || (Object.create ? (function(o, m, k, k2) { if (k2 === undefined) k2 = k; var desc = Object.getOwnPropertyDescriptor(m, k); if (!desc || ("get" in desc ? !m.__esModule : desc.writable || desc.configurable)) { desc = { enumerable: true, get: function() { return m[k]; } }; } Object.defineProperty(o, k2, desc); }) : (function(o, m, k, k2) { if (k2 === undefined) k2 = k; o[k2] = m[k]; })); var __setModuleDefault = (this && this.__setModuleDefault) || (Object.create ? (function(o, v) { Object.defineProperty(o, "default", { enumerable: true, value: v }); }) : function(o, v) { o["default"] = v; }); var __importStar = (this && this.__importStar) || (function () { var ownKeys = function(o) { ownKeys = Object.getOwnPropertyNames || function (o) { var ar = []; for (var k in o) if (Object.prototype.hasOwnProperty.call(o, k)) ar[ar.length] = k; return ar; }; return ownKeys(o); }; return function (mod) { if (mod && mod.__esModule) return mod; var result = {}; if (mod != null) for (var k = ownKeys(mod), i = 0; i < k.length; i++) if (k[i] !== "default") __createBinding(result, mod, k[i]); __setModuleDefault(result, mod); return result; }; })(); var __importDefault = (this && this.__importDefault) || function (mod) { return (mod && mod.__esModule) ? mod : { "default": mod }; }; Object.defineProperty(exports, "__esModule", { value: true }); /** * CO2 Calculator module * Calculates carbon emissions using CO2.js */ const CO2 = __importStar(require("@tgwf/co2")); const logger_1 = __importDefault(require("../utils/logger")); const default_1 = __importDefault(require("../config/default")); class CO2Calculator { constructor(customConfig = {}) { this.config = { ...default_1.default.co2, ...customConfig }; // Initialize CO2.js with the configured model this.co2 = new CO2.co2({ model: this.config.model, }); // Initialize green hosting checker if enabled if (this.config.includeGreenHostingCheck) { this.greenHostingCheck = CO2.hosting; } else { this.greenHostingCheck = null; } } /** * Calculate carbon emissions for a set of resources * @param {ResourcesData} resourcesData - Processed resources data from NetworkInterceptor * @returns {EmissionsData} - Carbon emissions data */ async calculateEmissions(resourcesData) { logger_1.default.info('Calculating carbon emissions'); if (!resourcesData || !resourcesData.allResources) { throw new Error('Invalid resources data'); } // Start with the calculation summary structure const result = { totalEmissions: 0, byType: {}, byDomain: {}, byGreenHosting: { green: { size: 0, emissions: 0, count: 0 }, nonGreen: { size: 0, emissions: 0, count: 0 }, unknown: { size: 0, emissions: 0, count: 0 } }, perResource: [], comparisons: {} }; // Initialize emissions by type Object.keys(resourcesData.sizeByType).forEach(type => { result.byType[type] = { size: resourcesData.sizeByType[type], emissions: 0, count: resourcesData.resourcesByType[type].length }; }); // Process each domain for (const [domain, domainData] of Object.entries(resourcesData.domains)) { // Check if the domain is green-hosted let isGreen = false; if (this.config.includeGreenHostingCheck && this.greenHostingCheck) { try { isGreen = await this.greenHostingCheck.check(domain); logger_1.default.debug(`Domain ${domain} is ${isGreen ? 'green' : 'non-green'} hosted`); } catch (error) { logger_1.default.debug(`Could not determine green hosting status for ${domain}: ${error.message}`); isGreen = null; // Unknown status } } // Calculate emissions for this domain const emissions = this.co2.perByte(domainData.size, isGreen === true); // Add to domain results result.byDomain[domain] = { size: domainData.size, emissions, count: domainData.count, isGreen }; // Add to green hosting breakdown if (isGreen === true) { result.byGreenHosting.green.size += domainData.size; result.byGreenHosting.green.emissions += emissions; result.byGreenHosting.green.count += domainData.count; } else if (isGreen === false) { result.byGreenHosting.nonGreen.size += domainData.size; result.byGreenHosting.nonGreen.emissions += emissions; result.byGreenHosting.nonGreen.count += domainData.count; } else { result.byGreenHosting.unknown.size += domainData.size; result.byGreenHosting.unknown.emissions += emissions; result.byGreenHosting.unknown.count += domainData.count; } // Update total emissions result.totalEmissions += emissions; } // Process individual resources for (const resource of resourcesData.allResources) { let domain = ''; try { domain = new URL(resource.url).hostname; } catch (error) { logger_1.default.debug(`Could not parse URL ${resource.url}: ${error.message}`); } const isGreen = result.byDomain[domain]?.isGreen; const resourceType = resource.resourceType; const size = resource.size.compressed || 0; // Calculate emissions for this resource const emissions = this.co2.perByte(size, isGreen === true); // Add to per-resource results result.perResource.push({ url: resource.url, type: resourceType, size, domain, isGreen, emissions }); // Add to type breakdown if (result.byType[resourceType]) { result.byType[resourceType].emissions += emissions; } } // Generate comparison metrics result.comparisons = this.generateComparisons(result.totalEmissions); logger_1.default.info(`Total calculated emissions: ${result.totalEmissions.toFixed(6)} gCO2e`); return result; } /** * Generate human-readable comparisons for the emissions * @param {number} emissions - Total emissions in gCO2e * @returns {Comparisons} - Comparison metrics */ generateComparisons(emissions) { // Conversion factors for comparisons // Note: These are approximate values and should be updated with more accurate data const comparisons = { // Tree seconds: how many seconds a mature tree takes to absorb this CO2 treeSeconds: emissions / 0.0035, // Assuming a tree absorbs ~0.0035g CO2 per second // Car distance: equivalent distance driven in a passenger car carMeters: emissions * 3.75, // ~3.75 meters per gram of CO2 // Smartphone charging: number of full smartphone charges smartphoneCharges: emissions / 7, // ~7g CO2 per full smartphone charge // Boiling water: cups of water boiled in an electric kettle waterBoiledML: emissions * 32, // ~32ml of water per gram of CO2 }; return comparisons; } } exports.default = CO2Calculator; //# sourceMappingURL=co2-calculator.js.map