@tgwf/co2 0.14.4 → 0.16.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/CHANGELOG.md +41 -2
- package/CONTRIBUTING.md +46 -0
- package/README.md +4 -0
- package/dist/cjs/1byte.js +1 -0
- package/dist/cjs/1byte.js.map +2 -2
- package/dist/cjs/co2.js +38 -104
- package/dist/cjs/co2.js.map +2 -2
- package/dist/cjs/constants/file-size.js +1 -0
- package/dist/cjs/constants/file-size.js.map +2 -2
- package/dist/cjs/constants/index.js +28 -0
- package/dist/cjs/constants/index.js.map +2 -2
- package/dist/cjs/data/average-intensities.min.js +1 -1
- package/dist/cjs/data/average-intensities.min.js.map +2 -2
- package/dist/cjs/helpers/index.js +89 -13
- package/dist/cjs/helpers/index.js.map +2 -2
- package/dist/cjs/hosting-api.js +21 -10
- package/dist/cjs/hosting-api.js.map +2 -2
- package/dist/cjs/hosting-json.js +57 -0
- package/dist/cjs/hosting-json.js.map +7 -0
- package/dist/cjs/hosting-json.node.js +1 -30
- package/dist/cjs/hosting-json.node.js.map +2 -2
- package/dist/cjs/hosting-node.js +26 -17
- package/dist/cjs/hosting-node.js.map +2 -2
- package/dist/cjs/hosting.js +2 -2
- package/dist/cjs/hosting.js.map +2 -2
- package/dist/cjs/{sustainable-web-design.js → sustainable-web-design-v3.js} +41 -8
- package/dist/cjs/sustainable-web-design-v3.js.map +7 -0
- package/dist/cjs/sustainable-web-design-v4.js +218 -0
- package/dist/cjs/sustainable-web-design-v4.js.map +7 -0
- package/dist/esm/1byte.js +1 -0
- package/dist/esm/co2.js +74 -113
- package/dist/esm/constants/file-size.js +1 -0
- package/dist/esm/constants/index.js +28 -0
- package/dist/esm/data/average-intensities.min.js +1 -1
- package/dist/esm/helpers/index.js +95 -16
- package/dist/esm/hosting-api.js +18 -10
- package/dist/esm/hosting-json.js +65 -0
- package/dist/esm/hosting.js +2 -2
- package/dist/esm/{sustainable-web-design.js → sustainable-web-design-v3.js} +36 -5
- package/dist/esm/sustainable-web-design-v4.js +212 -0
- package/package.json +1 -2
- package/dist/cjs/sustainable-web-design.js.map +0 -7
package/dist/esm/hosting.js
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
"use strict";
|
|
2
2
|
import hostingAPI from "./hosting-api.js";
|
|
3
|
-
function check(domain,
|
|
4
|
-
return hostingAPI.check(domain,
|
|
3
|
+
function check(domain, optionsOrAgentId) {
|
|
4
|
+
return hostingAPI.check(domain, optionsOrAgentId);
|
|
5
5
|
}
|
|
6
6
|
var hosting_default = {
|
|
7
7
|
check
|
|
@@ -31,10 +31,12 @@ import {
|
|
|
31
31
|
RETURNING_VISITOR_PERCENTAGE,
|
|
32
32
|
PERCENTAGE_OF_DATA_LOADED_ON_SUBSEQUENT_LOAD
|
|
33
33
|
} from "./constants/index.js";
|
|
34
|
-
import { formatNumber } from "./helpers/index.js";
|
|
34
|
+
import { formatNumber, outputRating } from "./helpers/index.js";
|
|
35
35
|
class SustainableWebDesign {
|
|
36
36
|
constructor(options) {
|
|
37
|
+
this.allowRatings = true;
|
|
37
38
|
this.options = options;
|
|
39
|
+
this.version = 3;
|
|
38
40
|
}
|
|
39
41
|
energyPerByteByComponent(bytes) {
|
|
40
42
|
const transferedBytesToGb = bytes / fileSize.GIGABYTE;
|
|
@@ -80,7 +82,7 @@ class SustainableWebDesign {
|
|
|
80
82
|
}
|
|
81
83
|
return returnCO2ByComponent;
|
|
82
84
|
}
|
|
83
|
-
perByte(bytes, carbonIntensity = false, segmentResults = false, options = {}) {
|
|
85
|
+
perByte(bytes, carbonIntensity = false, segmentResults = false, ratingResults = false, options = {}) {
|
|
84
86
|
if (bytes < 1) {
|
|
85
87
|
bytes = 0;
|
|
86
88
|
}
|
|
@@ -91,12 +93,25 @@ class SustainableWebDesign {
|
|
|
91
93
|
const co2ValuesbyComponent = this.co2byComponent(energyBycomponent, carbonIntensity, options);
|
|
92
94
|
const co2Values = Object.values(co2ValuesbyComponent);
|
|
93
95
|
const co2ValuesSum = co2Values.reduce((prevValue, currentValue) => prevValue + currentValue);
|
|
96
|
+
let rating = null;
|
|
97
|
+
if (ratingResults) {
|
|
98
|
+
rating = this.ratingScale(co2ValuesSum);
|
|
99
|
+
}
|
|
94
100
|
if (segmentResults) {
|
|
101
|
+
if (ratingResults) {
|
|
102
|
+
return __spreadProps(__spreadValues({}, co2ValuesbyComponent), {
|
|
103
|
+
total: co2ValuesSum,
|
|
104
|
+
rating
|
|
105
|
+
});
|
|
106
|
+
}
|
|
95
107
|
return __spreadProps(__spreadValues({}, co2ValuesbyComponent), { total: co2ValuesSum });
|
|
96
108
|
}
|
|
109
|
+
if (ratingResults) {
|
|
110
|
+
return { total: co2ValuesSum, rating };
|
|
111
|
+
}
|
|
97
112
|
return co2ValuesSum;
|
|
98
113
|
}
|
|
99
|
-
perVisit(bytes, carbonIntensity = false, segmentResults = false, options = {}) {
|
|
114
|
+
perVisit(bytes, carbonIntensity = false, segmentResults = false, ratingResults = false, options = {}) {
|
|
100
115
|
const energyBycomponent = this.energyPerVisitByComponent(bytes, options);
|
|
101
116
|
if (typeof carbonIntensity !== "boolean") {
|
|
102
117
|
throw new Error(`perVisit expects a boolean for the carbon intensity value. Received: ${carbonIntensity}`);
|
|
@@ -104,9 +119,22 @@ class SustainableWebDesign {
|
|
|
104
119
|
const co2ValuesbyComponent = this.co2byComponent(energyBycomponent, carbonIntensity, options);
|
|
105
120
|
const co2Values = Object.values(co2ValuesbyComponent);
|
|
106
121
|
const co2ValuesSum = co2Values.reduce((prevValue, currentValue) => prevValue + currentValue);
|
|
122
|
+
let rating = null;
|
|
123
|
+
if (ratingResults) {
|
|
124
|
+
rating = this.ratingScale(co2ValuesSum);
|
|
125
|
+
}
|
|
107
126
|
if (segmentResults) {
|
|
127
|
+
if (ratingResults) {
|
|
128
|
+
return __spreadProps(__spreadValues({}, co2ValuesbyComponent), {
|
|
129
|
+
total: co2ValuesSum,
|
|
130
|
+
rating
|
|
131
|
+
});
|
|
132
|
+
}
|
|
108
133
|
return __spreadProps(__spreadValues({}, co2ValuesbyComponent), { total: co2ValuesSum });
|
|
109
134
|
}
|
|
135
|
+
if (ratingResults) {
|
|
136
|
+
return { total: co2ValuesSum, rating };
|
|
137
|
+
}
|
|
110
138
|
return co2ValuesSum;
|
|
111
139
|
}
|
|
112
140
|
energyPerByte(bytes) {
|
|
@@ -166,9 +194,12 @@ class SustainableWebDesign {
|
|
|
166
194
|
productionEnergy: formatNumber(annualEnergy * PRODUCTION_ENERGY)
|
|
167
195
|
};
|
|
168
196
|
}
|
|
197
|
+
ratingScale(co2e) {
|
|
198
|
+
return outputRating(co2e, this.version);
|
|
199
|
+
}
|
|
169
200
|
}
|
|
170
|
-
var
|
|
201
|
+
var sustainable_web_design_v3_default = SustainableWebDesign;
|
|
171
202
|
export {
|
|
172
203
|
SustainableWebDesign,
|
|
173
|
-
|
|
204
|
+
sustainable_web_design_v3_default as default
|
|
174
205
|
};
|
|
@@ -0,0 +1,212 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
var __defProp = Object.defineProperty;
|
|
3
|
+
var __defProps = Object.defineProperties;
|
|
4
|
+
var __getOwnPropDescs = Object.getOwnPropertyDescriptors;
|
|
5
|
+
var __getOwnPropSymbols = Object.getOwnPropertySymbols;
|
|
6
|
+
var __hasOwnProp = Object.prototype.hasOwnProperty;
|
|
7
|
+
var __propIsEnum = Object.prototype.propertyIsEnumerable;
|
|
8
|
+
var __defNormalProp = (obj, key, value) => key in obj ? __defProp(obj, key, { enumerable: true, configurable: true, writable: true, value }) : obj[key] = value;
|
|
9
|
+
var __spreadValues = (a, b) => {
|
|
10
|
+
for (var prop in b || (b = {}))
|
|
11
|
+
if (__hasOwnProp.call(b, prop))
|
|
12
|
+
__defNormalProp(a, prop, b[prop]);
|
|
13
|
+
if (__getOwnPropSymbols)
|
|
14
|
+
for (var prop of __getOwnPropSymbols(b)) {
|
|
15
|
+
if (__propIsEnum.call(b, prop))
|
|
16
|
+
__defNormalProp(a, prop, b[prop]);
|
|
17
|
+
}
|
|
18
|
+
return a;
|
|
19
|
+
};
|
|
20
|
+
var __spreadProps = (a, b) => __defProps(a, __getOwnPropDescs(b));
|
|
21
|
+
import { fileSize, SWDV4 } from "./constants/index.js";
|
|
22
|
+
import { outputRating } from "./helpers/index.js";
|
|
23
|
+
const {
|
|
24
|
+
OPERATIONAL_KWH_PER_GB_DATACENTER,
|
|
25
|
+
OPERATIONAL_KWH_PER_GB_NETWORK,
|
|
26
|
+
OPERATIONAL_KWH_PER_GB_DEVICE,
|
|
27
|
+
EMBODIED_KWH_PER_GB_DATACENTER,
|
|
28
|
+
EMBODIED_KWH_PER_GB_NETWORK,
|
|
29
|
+
EMBODIED_KWH_PER_GB_DEVICE,
|
|
30
|
+
GLOBAL_GRID_INTENSITY
|
|
31
|
+
} = SWDV4;
|
|
32
|
+
function outputSegments(operationalEmissions, embodiedEmissions) {
|
|
33
|
+
const totalOperationalCO2e = operationalEmissions.dataCenter + operationalEmissions.network + operationalEmissions.device;
|
|
34
|
+
const totalEmbodiedCO2e = embodiedEmissions.dataCenter + embodiedEmissions.network + embodiedEmissions.device;
|
|
35
|
+
const dataCenterCO2e = operationalEmissions.dataCenter + embodiedEmissions.dataCenter;
|
|
36
|
+
const networkCO2e = operationalEmissions.network + embodiedEmissions.network;
|
|
37
|
+
const consumerDeviceCO2e = operationalEmissions.device + embodiedEmissions.device;
|
|
38
|
+
return {
|
|
39
|
+
dataCenterOperationalCO2e: operationalEmissions.dataCenter,
|
|
40
|
+
networkOperationalCO2e: operationalEmissions.network,
|
|
41
|
+
consumerDeviceOperationalCO2e: operationalEmissions.device,
|
|
42
|
+
dataCenterEmbodiedCO2e: embodiedEmissions.dataCenter,
|
|
43
|
+
networkEmbodiedCO2e: embodiedEmissions.network,
|
|
44
|
+
consumerDeviceEmbodiedCO2e: embodiedEmissions.device,
|
|
45
|
+
totalEmbodiedCO2e,
|
|
46
|
+
totalOperationalCO2e,
|
|
47
|
+
dataCenterCO2e,
|
|
48
|
+
networkCO2e,
|
|
49
|
+
consumerDeviceCO2e
|
|
50
|
+
};
|
|
51
|
+
}
|
|
52
|
+
function getGreenHostingFactor(green, options) {
|
|
53
|
+
if (green) {
|
|
54
|
+
return 1;
|
|
55
|
+
} else if ((options == null ? void 0 : options.greenHostingFactor) || (options == null ? void 0 : options.greenHostingFactor) === 0) {
|
|
56
|
+
return options.greenHostingFactor;
|
|
57
|
+
}
|
|
58
|
+
return 0;
|
|
59
|
+
}
|
|
60
|
+
class SustainableWebDesign {
|
|
61
|
+
constructor(options) {
|
|
62
|
+
this.allowRatings = true;
|
|
63
|
+
this.options = options;
|
|
64
|
+
this.version = 4;
|
|
65
|
+
}
|
|
66
|
+
operationalEnergyPerSegment(bytes) {
|
|
67
|
+
const transferedBytesToGb = bytes / fileSize.GIGABYTE;
|
|
68
|
+
const dataCenter = transferedBytesToGb * OPERATIONAL_KWH_PER_GB_DATACENTER;
|
|
69
|
+
const network = transferedBytesToGb * OPERATIONAL_KWH_PER_GB_NETWORK;
|
|
70
|
+
const device = transferedBytesToGb * OPERATIONAL_KWH_PER_GB_DEVICE;
|
|
71
|
+
return {
|
|
72
|
+
dataCenter,
|
|
73
|
+
network,
|
|
74
|
+
device
|
|
75
|
+
};
|
|
76
|
+
}
|
|
77
|
+
operationalEmissions(bytes, options = {}) {
|
|
78
|
+
const { dataCenter, network, device } = this.operationalEnergyPerSegment(bytes);
|
|
79
|
+
let dataCenterGridIntensity = GLOBAL_GRID_INTENSITY;
|
|
80
|
+
let networkGridIntensity = GLOBAL_GRID_INTENSITY;
|
|
81
|
+
let deviceGridIntensity = GLOBAL_GRID_INTENSITY;
|
|
82
|
+
if (options == null ? void 0 : options.gridIntensity) {
|
|
83
|
+
const { device: device2, network: network2, dataCenter: dataCenter2 } = options.gridIntensity;
|
|
84
|
+
if ((device2 == null ? void 0 : device2.value) || (device2 == null ? void 0 : device2.value) === 0) {
|
|
85
|
+
deviceGridIntensity = device2.value;
|
|
86
|
+
}
|
|
87
|
+
if ((network2 == null ? void 0 : network2.value) || (network2 == null ? void 0 : network2.value) === 0) {
|
|
88
|
+
networkGridIntensity = network2.value;
|
|
89
|
+
}
|
|
90
|
+
if ((dataCenter2 == null ? void 0 : dataCenter2.value) || (dataCenter2 == null ? void 0 : dataCenter2.value) === 0) {
|
|
91
|
+
dataCenterGridIntensity = dataCenter2.value;
|
|
92
|
+
}
|
|
93
|
+
}
|
|
94
|
+
const dataCenterEmissions = dataCenter * dataCenterGridIntensity;
|
|
95
|
+
const networkEmissions = network * networkGridIntensity;
|
|
96
|
+
const deviceEmissions = device * deviceGridIntensity;
|
|
97
|
+
return {
|
|
98
|
+
dataCenter: dataCenterEmissions,
|
|
99
|
+
network: networkEmissions,
|
|
100
|
+
device: deviceEmissions
|
|
101
|
+
};
|
|
102
|
+
}
|
|
103
|
+
embodiedEnergyPerSegment(bytes) {
|
|
104
|
+
const transferedBytesToGb = bytes / fileSize.GIGABYTE;
|
|
105
|
+
const dataCenter = transferedBytesToGb * EMBODIED_KWH_PER_GB_DATACENTER;
|
|
106
|
+
const network = transferedBytesToGb * EMBODIED_KWH_PER_GB_NETWORK;
|
|
107
|
+
const device = transferedBytesToGb * EMBODIED_KWH_PER_GB_DEVICE;
|
|
108
|
+
return {
|
|
109
|
+
dataCenter,
|
|
110
|
+
network,
|
|
111
|
+
device
|
|
112
|
+
};
|
|
113
|
+
}
|
|
114
|
+
embodiedEmissions(bytes) {
|
|
115
|
+
const { dataCenter, network, device } = this.embodiedEnergyPerSegment(bytes);
|
|
116
|
+
const dataCenterGridIntensity = GLOBAL_GRID_INTENSITY;
|
|
117
|
+
const networkGridIntensity = GLOBAL_GRID_INTENSITY;
|
|
118
|
+
const deviceGridIntensity = GLOBAL_GRID_INTENSITY;
|
|
119
|
+
const dataCenterEmissions = dataCenter * dataCenterGridIntensity;
|
|
120
|
+
const networkEmissions = network * networkGridIntensity;
|
|
121
|
+
const deviceEmissions = device * deviceGridIntensity;
|
|
122
|
+
return {
|
|
123
|
+
dataCenter: dataCenterEmissions,
|
|
124
|
+
network: networkEmissions,
|
|
125
|
+
device: deviceEmissions
|
|
126
|
+
};
|
|
127
|
+
}
|
|
128
|
+
perByte(bytes, green = false, segmented = false, ratingResults = false, options = {}) {
|
|
129
|
+
if (bytes < 1) {
|
|
130
|
+
return 0;
|
|
131
|
+
}
|
|
132
|
+
const operationalEmissions = this.operationalEmissions(bytes, options);
|
|
133
|
+
const embodiedEmissions = this.embodiedEmissions(bytes);
|
|
134
|
+
const greenHostingFactor = getGreenHostingFactor(green, options);
|
|
135
|
+
const totalEmissions = {
|
|
136
|
+
dataCenter: operationalEmissions.dataCenter * (1 - greenHostingFactor) + embodiedEmissions.dataCenter,
|
|
137
|
+
network: operationalEmissions.network + embodiedEmissions.network,
|
|
138
|
+
device: operationalEmissions.device + embodiedEmissions.device
|
|
139
|
+
};
|
|
140
|
+
const total = totalEmissions.dataCenter + totalEmissions.network + totalEmissions.device;
|
|
141
|
+
let rating = null;
|
|
142
|
+
if (ratingResults) {
|
|
143
|
+
rating = this.ratingScale(total);
|
|
144
|
+
}
|
|
145
|
+
if (segmented) {
|
|
146
|
+
const segments = __spreadValues({}, outputSegments(operationalEmissions, embodiedEmissions));
|
|
147
|
+
if (ratingResults) {
|
|
148
|
+
return __spreadProps(__spreadValues({}, segments), {
|
|
149
|
+
total,
|
|
150
|
+
rating
|
|
151
|
+
});
|
|
152
|
+
}
|
|
153
|
+
return __spreadProps(__spreadValues({}, segments), { total });
|
|
154
|
+
}
|
|
155
|
+
if (ratingResults) {
|
|
156
|
+
return { total, rating };
|
|
157
|
+
}
|
|
158
|
+
return total;
|
|
159
|
+
}
|
|
160
|
+
perVisit(bytes, green = false, segmented = false, ratingResults = false, options = {}) {
|
|
161
|
+
let firstViewRatio = 1;
|
|
162
|
+
let returnViewRatio = 0;
|
|
163
|
+
let dataReloadRatio = 0;
|
|
164
|
+
const greenHostingFactor = getGreenHostingFactor(green, options);
|
|
165
|
+
const operationalEmissions = this.operationalEmissions(bytes, options);
|
|
166
|
+
const embodiedEmissions = this.embodiedEmissions(bytes);
|
|
167
|
+
if (bytes < 1) {
|
|
168
|
+
return 0;
|
|
169
|
+
}
|
|
170
|
+
if (options.firstVisitPercentage || options.firstVisitPercentage === 0) {
|
|
171
|
+
firstViewRatio = options.firstVisitPercentage;
|
|
172
|
+
}
|
|
173
|
+
if (options.returnVisitPercentage || options.returnVisitPercentage === 0) {
|
|
174
|
+
returnViewRatio = options.returnVisitPercentage;
|
|
175
|
+
}
|
|
176
|
+
if (options.dataReloadRatio || options.dataReloadRatio === 0) {
|
|
177
|
+
dataReloadRatio = options.dataReloadRatio;
|
|
178
|
+
}
|
|
179
|
+
const firstVisitEmissions = operationalEmissions.dataCenter * (1 - greenHostingFactor) + embodiedEmissions.dataCenter + operationalEmissions.network + embodiedEmissions.network + operationalEmissions.device + embodiedEmissions.device;
|
|
180
|
+
const returnVisitEmissions = (operationalEmissions.dataCenter * (1 - greenHostingFactor) + embodiedEmissions.dataCenter + operationalEmissions.network + embodiedEmissions.network + operationalEmissions.device + embodiedEmissions.device) * (1 - dataReloadRatio);
|
|
181
|
+
const total = firstVisitEmissions * firstViewRatio + returnVisitEmissions * returnViewRatio;
|
|
182
|
+
let rating = null;
|
|
183
|
+
if (ratingResults) {
|
|
184
|
+
rating = this.ratingScale(total);
|
|
185
|
+
}
|
|
186
|
+
if (segmented) {
|
|
187
|
+
const segments = __spreadProps(__spreadValues({}, outputSegments(operationalEmissions, embodiedEmissions)), {
|
|
188
|
+
firstVisitCO2e: firstVisitEmissions,
|
|
189
|
+
returnVisitCO2e: returnVisitEmissions
|
|
190
|
+
});
|
|
191
|
+
if (ratingResults) {
|
|
192
|
+
return __spreadProps(__spreadValues({}, segments), {
|
|
193
|
+
total,
|
|
194
|
+
rating
|
|
195
|
+
});
|
|
196
|
+
}
|
|
197
|
+
return __spreadProps(__spreadValues({}, segments), { total });
|
|
198
|
+
}
|
|
199
|
+
if (ratingResults) {
|
|
200
|
+
return { total, rating };
|
|
201
|
+
}
|
|
202
|
+
return total;
|
|
203
|
+
}
|
|
204
|
+
ratingScale(co2e) {
|
|
205
|
+
return outputRating(co2e, this.version);
|
|
206
|
+
}
|
|
207
|
+
}
|
|
208
|
+
var sustainable_web_design_v4_default = SustainableWebDesign;
|
|
209
|
+
export {
|
|
210
|
+
SustainableWebDesign,
|
|
211
|
+
sustainable_web_design_v4_default as default
|
|
212
|
+
};
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@tgwf/co2",
|
|
3
|
-
"version": "0.
|
|
3
|
+
"version": "0.16.0",
|
|
4
4
|
"description": "Work out the co2 of your digital services",
|
|
5
5
|
"main": "dist/cjs/index-node.js",
|
|
6
6
|
"module": "dist/esm/index.js",
|
|
@@ -56,7 +56,6 @@
|
|
|
56
56
|
"jest": "^28.1.0",
|
|
57
57
|
"nock": "^13.2.4",
|
|
58
58
|
"np": "^8.0.4",
|
|
59
|
-
"pagexray": "^4.4.2",
|
|
60
59
|
"prettier": "^2.6.2"
|
|
61
60
|
},
|
|
62
61
|
"jest": {
|
|
@@ -1,7 +0,0 @@
|
|
|
1
|
-
{
|
|
2
|
-
"version": 3,
|
|
3
|
-
"sources": ["../../src/sustainable-web-design.js"],
|
|
4
|
-
"sourcesContent": ["\"use strict\";\n\n/**\n * Sustainable Web Design\n *\n * Updated calculations and figures from\n * https://sustainablewebdesign.org/calculating-digital-emissions/\n *\n */\n\nimport {\n fileSize,\n KWH_PER_GB,\n END_USER_DEVICE_ENERGY,\n NETWORK_ENERGY,\n DATACENTER_ENERGY,\n PRODUCTION_ENERGY,\n GLOBAL_GRID_INTENSITY,\n RENEWABLES_GRID_INTENSITY,\n FIRST_TIME_VIEWING_PERCENTAGE,\n RETURNING_VISITOR_PERCENTAGE,\n PERCENTAGE_OF_DATA_LOADED_ON_SUBSEQUENT_LOAD,\n} from \"./constants/index.js\";\nimport { formatNumber } from \"./helpers/index.js\";\n\nclass SustainableWebDesign {\n constructor(options) {\n this.options = options;\n }\n\n /**\n * Accept a figure for bytes transferred and return an object representing\n * the share of the total enrgy use of the entire system, broken down\n * by each corresponding system component\n *\n * @param {number} bytes - the data transferred in bytes\n * @return {object} Object containing the energy in kilowatt hours, keyed by system component\n */\n energyPerByteByComponent(bytes) {\n const transferedBytesToGb = bytes / fileSize.GIGABYTE;\n const energyUsage = transferedBytesToGb * KWH_PER_GB;\n\n // return the total energy, with breakdown by component\n return {\n consumerDeviceEnergy: energyUsage * END_USER_DEVICE_ENERGY,\n networkEnergy: energyUsage * NETWORK_ENERGY,\n productionEnergy: energyUsage * PRODUCTION_ENERGY,\n dataCenterEnergy: energyUsage * DATACENTER_ENERGY,\n };\n }\n /**\n * Accept an object keys by the different system components, and\n * return an object with the co2 figures key by the each component\n *\n * @param {object} energyByComponent - energy grouped by the four system components\n * @param {number} [carbonIntensity] - carbon intensity to apply to the datacentre values\n * @return {number} the total number in grams of CO2 equivalent emissions\n */\n co2byComponent(\n energyByComponent,\n carbonIntensity = GLOBAL_GRID_INTENSITY,\n options = {}\n ) {\n let deviceCarbonIntensity = GLOBAL_GRID_INTENSITY;\n let networkCarbonIntensity = GLOBAL_GRID_INTENSITY;\n let dataCenterCarbonIntensity = GLOBAL_GRID_INTENSITY;\n\n let globalEmissions = GLOBAL_GRID_INTENSITY;\n\n if (options?.gridIntensity) {\n const { device, network, dataCenter } = options.gridIntensity;\n\n if (device?.value || device?.value === 0) {\n deviceCarbonIntensity = device.value;\n }\n if (network?.value || network?.value === 0) {\n networkCarbonIntensity = network.value;\n }\n // If the user has set a carbon intensity value for the datacentre, then that overrides everything and is used\n if (dataCenter?.value || dataCenter?.value === 0) {\n dataCenterCarbonIntensity = dataCenter.value;\n }\n }\n\n // If the user passes in a TRUE value (green web host), then use the renewables intensity value\n if (carbonIntensity === true) {\n dataCenterCarbonIntensity = RENEWABLES_GRID_INTENSITY;\n }\n\n const returnCO2ByComponent = {};\n for (const [key, value] of Object.entries(energyByComponent)) {\n // we update the datacentre, as that's what we have information\n // about.\n if (key.startsWith(\"dataCenterEnergy\")) {\n returnCO2ByComponent[key.replace(\"Energy\", \"CO2\")] =\n value * dataCenterCarbonIntensity;\n } else if (key.startsWith(\"consumerDeviceEnergy\")) {\n returnCO2ByComponent[key.replace(\"Energy\", \"CO2\")] =\n value * deviceCarbonIntensity;\n } else if (key.startsWith(\"networkEnergy\")) {\n returnCO2ByComponent[key.replace(\"Energy\", \"CO2\")] =\n value * networkCarbonIntensity;\n } else {\n // Use the global intensity for the remaining segments\n returnCO2ByComponent[key.replace(\"Energy\", \"CO2\")] =\n value * globalEmissions;\n }\n }\n\n return returnCO2ByComponent;\n }\n\n /**\n * Accept a figure for bytes transferred and return a single figure for CO2\n * emissions. Where information exists about the origin data is being\n * fetched from, a different carbon intensity figure\n * is applied for the data centre share of the carbon intensity.\n *\n * @param {number} bytes - the data transferred in bytes\n * @param {boolean} carbonIntensity - a boolean indicating whether the data center is green or not\n * @param {boolean} segmentResults - a boolean indicating whether to return the results broken down by component\n * @param {object} options - an object containing the grid intensity and first/return visitor values\n * @return {number|object} the total number in grams of CO2 equivalent emissions, or an object containing the breakdown by component\n */\n perByte(\n bytes,\n carbonIntensity = false,\n segmentResults = false,\n options = {}\n ) {\n if (bytes < 1) {\n bytes = 0;\n }\n\n const energyBycomponent = this.energyPerByteByComponent(bytes, options);\n\n // otherwise when faced with non numeric values throw an error\n if (typeof carbonIntensity !== \"boolean\") {\n throw new Error(\n `perByte expects a boolean for the carbon intensity value. Received: ${carbonIntensity}`\n );\n }\n\n const co2ValuesbyComponent = this.co2byComponent(\n energyBycomponent,\n carbonIntensity,\n options\n );\n\n // pull out our values\u2026\n const co2Values = Object.values(co2ValuesbyComponent);\n const co2ValuesSum = co2Values.reduce(\n (prevValue, currentValue) => prevValue + currentValue\n );\n\n if (segmentResults) {\n return { ...co2ValuesbyComponent, total: co2ValuesSum };\n }\n\n return co2ValuesSum;\n }\n\n /**\n * Accept a figure for bytes transferred and return a single figure for CO2\n * emissions. This method applies caching assumptions from the original Sustainable Web Design model.\n *\n * @param {number} bytes - the data transferred in bytes\n * @param {boolean} carbonIntensity - a boolean indicating whether the data center is green or not\n * @param {boolean} segmentResults - a boolean indicating whether to return the results broken down by component\n * @param {object} options - an object containing the grid intensity and first/return visitor values\n * @return {number|object} the total number in grams of CO2 equivalent emissions, or an object containing the breakdown by component\n */\n perVisit(\n bytes,\n carbonIntensity = false,\n segmentResults = false,\n options = {}\n ) {\n const energyBycomponent = this.energyPerVisitByComponent(bytes, options);\n\n if (typeof carbonIntensity !== \"boolean\") {\n // otherwise when faced with non numeric values throw an error\n throw new Error(\n `perVisit expects a boolean for the carbon intensity value. Received: ${carbonIntensity}`\n );\n }\n\n const co2ValuesbyComponent = this.co2byComponent(\n energyBycomponent,\n carbonIntensity,\n options\n );\n\n // pull out our values\u2026\n const co2Values = Object.values(co2ValuesbyComponent);\n const co2ValuesSum = co2Values.reduce(\n (prevValue, currentValue) => prevValue + currentValue\n );\n\n if (segmentResults) {\n return { ...co2ValuesbyComponent, total: co2ValuesSum };\n }\n\n // so we can return their sum\n return co2ValuesSum;\n }\n\n /**\n * Accept a figure for bytes transferred and return the number of kilowatt hours used\n * by the total system for this data transfer\n *\n * @param {number} bytes\n * @return {number} the number of kilowatt hours used\n */\n energyPerByte(bytes) {\n const energyByComponent = this.energyPerByteByComponent(bytes);\n\n // pull out our values\u2026\n const energyValues = Object.values(energyByComponent);\n\n // so we can return their sum\n return energyValues.reduce(\n (prevValue, currentValue) => prevValue + currentValue\n );\n }\n\n /**\n * Accept a figure for bytes transferred, and return an object containing figures\n * per system component, with the caching assumptions applied. This tries to account\n * for webpages being loaded from a cache by browsers, so if you had a thousand page views,\n * and tried to work out the energy per visit, the numbers would reflect the reduced amounts\n * of transfer.\n *\n * @param {number} bytes - the data transferred in bytes for loading a webpage\n * @param {number} firstView - what percentage of visits are loading this page for the first time\n * @param {number} returnView - what percentage of visits are loading this page for subsequent times\n * @param {number} dataReloadRatio - what percentage of a page is reloaded on each subsequent page view\n *\n * @return {object} Object containing the energy in kilowatt hours, keyed by system component\n */\n energyPerVisitByComponent(\n bytes,\n options = {},\n firstView = FIRST_TIME_VIEWING_PERCENTAGE,\n returnView = RETURNING_VISITOR_PERCENTAGE,\n dataReloadRatio = PERCENTAGE_OF_DATA_LOADED_ON_SUBSEQUENT_LOAD\n ) {\n if (options.dataReloadRatio || options.dataReloadRatio === 0) {\n dataReloadRatio = options.dataReloadRatio;\n }\n\n if (options.firstVisitPercentage || options.firstVisitPercentage === 0) {\n firstView = options.firstVisitPercentage;\n }\n\n if (options.returnVisitPercentage || options.returnVisitPercentage === 0) {\n returnView = options.returnVisitPercentage;\n }\n\n const energyBycomponent = this.energyPerByteByComponent(bytes);\n const cacheAdjustedSegmentEnergy = {};\n\n const energyValues = Object.values(energyBycomponent);\n\n // for this, we want\n for (const [key, value] of Object.entries(energyBycomponent)) {\n // represent the first load\n cacheAdjustedSegmentEnergy[`${key} - first`] = value * firstView;\n\n // then represent the subsequent load\n cacheAdjustedSegmentEnergy[`${key} - subsequent`] =\n value * returnView * dataReloadRatio;\n }\n\n return cacheAdjustedSegmentEnergy;\n }\n\n /**\n * Accept a figure for bytes, and return the total figure for energy per visit\n * using the default caching assumptions for loading a single website\n *\n * @param {number} bytes\n * @return {number} the total energy use for the visit, after applying the caching assumptions\n */\n energyPerVisit(bytes) {\n // fetch the values using the default caching assumptions\n // const energyValues = Object.values(this.energyPerVisitByComponent(bytes));\n\n let firstVisits = 0;\n let subsequentVisits = 0;\n\n const energyBycomponent = Object.entries(\n this.energyPerVisitByComponent(bytes)\n );\n\n for (const [key, val] of energyBycomponent) {\n if (key.indexOf(\"first\") > 0) {\n firstVisits += val;\n }\n }\n\n for (const [key, val] of energyBycomponent) {\n if (key.indexOf(\"subsequent\") > 0) {\n subsequentVisits += val;\n }\n }\n\n return firstVisits + subsequentVisits;\n }\n\n emissionsPerVisitInGrams(\n energyPerVisit,\n carbonintensity = GLOBAL_GRID_INTENSITY\n ) {\n return formatNumber(energyPerVisit * carbonintensity);\n }\n\n annualEnergyInKwh(energyPerVisit, monthlyVisitors = 1000) {\n return energyPerVisit * monthlyVisitors * 12;\n }\n\n annualEmissionsInGrams(co2grams, monthlyVisitors = 1000) {\n return co2grams * monthlyVisitors * 12;\n }\n\n annualSegmentEnergy(annualEnergy) {\n return {\n consumerDeviceEnergy: formatNumber(annualEnergy * END_USER_DEVICE_ENERGY),\n networkEnergy: formatNumber(annualEnergy * NETWORK_ENERGY),\n dataCenterEnergy: formatNumber(annualEnergy * DATACENTER_ENERGY),\n productionEnergy: formatNumber(annualEnergy * PRODUCTION_ENERGY),\n };\n }\n}\n\nexport { SustainableWebDesign };\nexport default SustainableWebDesign;\n"],
|
|
5
|
-
"mappings": "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",
|
|
6
|
-
"names": []
|
|
7
|
-
}
|