@tgwf/co2 0.11.3 → 0.12.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/.esbuild.esm.js +1 -1
- package/.esbuild.node.js +1 -1
- package/README.md +3 -3
- package/dist/cjs/1byte.js.map +2 -2
- package/dist/cjs/co2.js +67 -4
- package/dist/cjs/co2.js.map +2 -2
- package/dist/cjs/constants/index.js +23 -1
- package/dist/cjs/constants/index.js.map +2 -2
- package/dist/cjs/helpers/index.js +139 -1
- package/dist/cjs/helpers/index.js.map +2 -2
- package/dist/cjs/hosting-api.js +0 -4
- package/dist/cjs/hosting-api.js.map +2 -2
- package/dist/cjs/hosting-json.node.js +2 -1
- package/dist/cjs/hosting-json.node.js.map +2 -2
- package/dist/cjs/sustainable-web-design.js +67 -49
- package/dist/cjs/sustainable-web-design.js.map +2 -2
- package/dist/esm/co2.js +70 -4
- package/dist/esm/constants/index.js +23 -1
- package/dist/esm/helpers/index.js +144 -1
- package/dist/esm/hosting-api.js +0 -4
- package/dist/esm/sustainable-web-design.js +90 -41
- package/dist/iife/index.js +19 -3
- package/dist/iife/index.js.map +3 -3
- package/package.json +1 -1
- package/src/1byte.js +7 -0
- package/src/co2.js +157 -4
- package/src/constants/index.js +38 -1
- package/src/helpers/index.js +173 -1
- package/src/hosting-api.js +5 -4
- package/src/hosting-json.node.js +1 -0
- package/src/sustainable-web-design.js +113 -72
- package/dist/cjs/1byte.test.js +0 -27
- package/dist/cjs/1byte.test.js.map +0 -7
- package/dist/cjs/co2.test.js +0 -281
- package/dist/cjs/co2.test.js.map +0 -7
- package/dist/cjs/hosting-api.test.js +0 -47
- package/dist/cjs/hosting-api.test.js.map +0 -7
- package/dist/cjs/hosting-database.node.test.js +0 -36
- package/dist/cjs/hosting-database.node.test.js.map +0 -7
- package/dist/cjs/hosting-json.node.test.js +0 -43
- package/dist/cjs/hosting-json.node.test.js.map +0 -7
- package/dist/cjs/hosting.test.js +0 -74
- package/dist/cjs/hosting.test.js.map +0 -7
- package/dist/cjs/sustainable-web-design.test.js +0 -84
- package/dist/cjs/sustainable-web-design.test.js.map +0 -7
- package/dist/esm/1byte.test.js +0 -11
- package/dist/esm/co2.test.js +0 -265
- package/dist/esm/hosting-api.test.js +0 -31
- package/dist/esm/hosting-database.node.test.js +0 -20
- package/dist/esm/hosting-json.node.test.js +0 -27
- package/dist/esm/hosting.test.js +0 -58
- package/dist/esm/sustainable-web-design.test.js +0 -68
- package/src/readme.md +0 -66
package/src/constants/index.js
CHANGED
|
@@ -1,3 +1,40 @@
|
|
|
1
1
|
import fileSize from "./file-size.js";
|
|
2
|
+
import testConstants from "./test-constants.js";
|
|
2
3
|
|
|
3
|
-
|
|
4
|
+
// SUSTAINABLE WEB DESIGN CONSTANTS
|
|
5
|
+
// this refers to the estimated total energy use for the internet around 2000 TWh,
|
|
6
|
+
// divided by the total transfer it enables around 2500 exabytes
|
|
7
|
+
const KWH_PER_GB = 0.81;
|
|
8
|
+
|
|
9
|
+
// these constants outline how the energy is attributed to
|
|
10
|
+
// different parts of the system in the SWD model
|
|
11
|
+
const END_USER_DEVICE_ENERGY = 0.52;
|
|
12
|
+
const NETWORK_ENERGY = 0.14;
|
|
13
|
+
const DATACENTER_ENERGY = 0.15;
|
|
14
|
+
const PRODUCTION_ENERGY = 0.19;
|
|
15
|
+
|
|
16
|
+
// These carbon intensity figures https://ember-climate.org/data/data-explorer
|
|
17
|
+
// - Global carbon intensity for 2021
|
|
18
|
+
const GLOBAL_GRID_INTENSITY = 442;
|
|
19
|
+
const RENEWABLES_GRID_INTENSITY = 50;
|
|
20
|
+
|
|
21
|
+
// Taken from: https://gitlab.com/wholegrain/carbon-api-2-0/-/blob/master/includes/carbonapi.php
|
|
22
|
+
|
|
23
|
+
const FIRST_TIME_VIEWING_PERCENTAGE = 0.75;
|
|
24
|
+
const RETURNING_VISITOR_PERCENTAGE = 0.25;
|
|
25
|
+
const PERCENTAGE_OF_DATA_LOADED_ON_SUBSEQUENT_LOAD = 0.02;
|
|
26
|
+
|
|
27
|
+
export {
|
|
28
|
+
fileSize,
|
|
29
|
+
testConstants,
|
|
30
|
+
KWH_PER_GB,
|
|
31
|
+
END_USER_DEVICE_ENERGY,
|
|
32
|
+
NETWORK_ENERGY,
|
|
33
|
+
DATACENTER_ENERGY,
|
|
34
|
+
PRODUCTION_ENERGY,
|
|
35
|
+
GLOBAL_GRID_INTENSITY,
|
|
36
|
+
RENEWABLES_GRID_INTENSITY,
|
|
37
|
+
FIRST_TIME_VIEWING_PERCENTAGE,
|
|
38
|
+
RETURNING_VISITOR_PERCENTAGE,
|
|
39
|
+
PERCENTAGE_OF_DATA_LOADED_ON_SUBSEQUENT_LOAD,
|
|
40
|
+
};
|
package/src/helpers/index.js
CHANGED
|
@@ -1,3 +1,175 @@
|
|
|
1
|
+
import { averageIntensity } from "../index.js";
|
|
2
|
+
import {
|
|
3
|
+
GLOBAL_GRID_INTENSITY,
|
|
4
|
+
PERCENTAGE_OF_DATA_LOADED_ON_SUBSEQUENT_LOAD,
|
|
5
|
+
FIRST_TIME_VIEWING_PERCENTAGE,
|
|
6
|
+
RETURNING_VISITOR_PERCENTAGE,
|
|
7
|
+
} from "../constants/index.js";
|
|
1
8
|
const formatNumber = (num) => parseFloat(num.toFixed(2));
|
|
2
9
|
|
|
3
|
-
|
|
10
|
+
function parseOptions(options) {
|
|
11
|
+
// CHeck that it is an object
|
|
12
|
+
if (typeof options !== "object") {
|
|
13
|
+
throw new Error("Options must be an object");
|
|
14
|
+
}
|
|
15
|
+
|
|
16
|
+
const adjustments = {};
|
|
17
|
+
|
|
18
|
+
if (options?.gridIntensity) {
|
|
19
|
+
adjustments.gridIntensity = {};
|
|
20
|
+
const { device, dataCenter, network } = options.gridIntensity;
|
|
21
|
+
if (device) {
|
|
22
|
+
if (typeof device === "object") {
|
|
23
|
+
if (!averageIntensity.data[device.country?.toUpperCase()]) {
|
|
24
|
+
console.warn(
|
|
25
|
+
`"${device.country}" is not a valid country. Please use a valid 3 digit ISO 3166 country code. \nSee https://developers.thegreenwebfoundation.org/co2js/data/ for more information. \nFalling back to global average grid intensity.`
|
|
26
|
+
);
|
|
27
|
+
adjustments.gridIntensity["device"] = {
|
|
28
|
+
value: GLOBAL_GRID_INTENSITY,
|
|
29
|
+
};
|
|
30
|
+
}
|
|
31
|
+
adjustments.gridIntensity["device"] = {
|
|
32
|
+
country: device.country,
|
|
33
|
+
value: parseFloat(
|
|
34
|
+
averageIntensity.data[device.country?.toUpperCase()]
|
|
35
|
+
),
|
|
36
|
+
};
|
|
37
|
+
} else if (typeof device === "number") {
|
|
38
|
+
adjustments.gridIntensity["device"] = {
|
|
39
|
+
value: device,
|
|
40
|
+
};
|
|
41
|
+
} else {
|
|
42
|
+
adjustments.gridIntensity["device"] = {
|
|
43
|
+
value: GLOBAL_GRID_INTENSITY,
|
|
44
|
+
};
|
|
45
|
+
console.warn(
|
|
46
|
+
`The device grid intensity must be a number or an object. You passed in a ${typeof device}. \nFalling back to global average grid intensity.`
|
|
47
|
+
);
|
|
48
|
+
}
|
|
49
|
+
}
|
|
50
|
+
if (dataCenter) {
|
|
51
|
+
if (typeof dataCenter === "object") {
|
|
52
|
+
if (!averageIntensity.data[dataCenter.country?.toUpperCase()]) {
|
|
53
|
+
console.warn(
|
|
54
|
+
`"${dataCenter.country}" is not a valid country. Please use a valid 3 digit ISO 3166 country code. \nSee https://developers.thegreenwebfoundation.org/co2js/data/ for more information. \nFalling back to global average grid intensity.`
|
|
55
|
+
);
|
|
56
|
+
adjustments.gridIntensity["dataCenter"] = {
|
|
57
|
+
value: GLOBAL_GRID_INTENSITY,
|
|
58
|
+
};
|
|
59
|
+
}
|
|
60
|
+
adjustments.gridIntensity["dataCenter"] = {
|
|
61
|
+
country: dataCenter.country,
|
|
62
|
+
value: parseFloat(
|
|
63
|
+
averageIntensity.data[dataCenter.country?.toUpperCase()]
|
|
64
|
+
),
|
|
65
|
+
};
|
|
66
|
+
} else if (typeof dataCenter === "number") {
|
|
67
|
+
adjustments.gridIntensity["dataCenter"] = {
|
|
68
|
+
value: dataCenter,
|
|
69
|
+
};
|
|
70
|
+
} else {
|
|
71
|
+
adjustments.gridIntensity["dataCenter"] = {
|
|
72
|
+
value: GLOBAL_GRID_INTENSITY,
|
|
73
|
+
};
|
|
74
|
+
console.warn(
|
|
75
|
+
`The data center grid intensity must be a number or an object. You passed in a ${typeof dataCenter}. \nFalling back to global average grid intensity.`
|
|
76
|
+
);
|
|
77
|
+
}
|
|
78
|
+
}
|
|
79
|
+
if (network) {
|
|
80
|
+
if (typeof network === "object") {
|
|
81
|
+
if (!averageIntensity.data[network.country?.toUpperCase()]) {
|
|
82
|
+
console.warn(
|
|
83
|
+
`"${network.country}" is not a valid country. Please use a valid 3 digit ISO 3166 country code. \nSee https://developers.thegreenwebfoundation.org/co2js/data/ for more information. Falling back to global average grid intensity. \nFalling back to global average grid intensity.`
|
|
84
|
+
);
|
|
85
|
+
adjustments.gridIntensity["network"] = {
|
|
86
|
+
value: GLOBAL_GRID_INTENSITY,
|
|
87
|
+
};
|
|
88
|
+
}
|
|
89
|
+
adjustments.gridIntensity["network"] = {
|
|
90
|
+
country: network.country,
|
|
91
|
+
value: parseFloat(
|
|
92
|
+
averageIntensity.data[network.country?.toUpperCase()]
|
|
93
|
+
),
|
|
94
|
+
};
|
|
95
|
+
} else if (typeof network === "number") {
|
|
96
|
+
adjustments.gridIntensity["network"] = {
|
|
97
|
+
value: network,
|
|
98
|
+
};
|
|
99
|
+
} else {
|
|
100
|
+
adjustments.gridIntensity["network"] = {
|
|
101
|
+
value: GLOBAL_GRID_INTENSITY,
|
|
102
|
+
};
|
|
103
|
+
console.warn(
|
|
104
|
+
`The network grid intensity must be a number or an object. You passed in a ${typeof network}. \nFalling back to global average grid intensity.`
|
|
105
|
+
);
|
|
106
|
+
}
|
|
107
|
+
}
|
|
108
|
+
}
|
|
109
|
+
|
|
110
|
+
if (options?.dataReloadRatio) {
|
|
111
|
+
if (typeof options.dataReloadRatio === "number") {
|
|
112
|
+
if (options.dataReloadRatio >= 0 && options.dataReloadRatio <= 1) {
|
|
113
|
+
adjustments.dataReloadRatio = options.dataReloadRatio;
|
|
114
|
+
} else {
|
|
115
|
+
adjustments.dataReloadRatio =
|
|
116
|
+
PERCENTAGE_OF_DATA_LOADED_ON_SUBSEQUENT_LOAD;
|
|
117
|
+
console.warn(
|
|
118
|
+
`The dataReloadRatio option must be a number between 0 and 1. You passed in ${options.dataReloadRatio}. \nFalling back to default value.`
|
|
119
|
+
);
|
|
120
|
+
}
|
|
121
|
+
} else {
|
|
122
|
+
adjustments.dataReloadRatio =
|
|
123
|
+
PERCENTAGE_OF_DATA_LOADED_ON_SUBSEQUENT_LOAD;
|
|
124
|
+
console.warn(
|
|
125
|
+
`The dataReloadRatio option must be a number. You passed in a ${typeof options.dataReloadRatio}. \nFalling back to default value.`
|
|
126
|
+
);
|
|
127
|
+
}
|
|
128
|
+
}
|
|
129
|
+
|
|
130
|
+
if (options?.firstVisitPercentage) {
|
|
131
|
+
if (typeof options.firstVisitPercentage === "number") {
|
|
132
|
+
if (
|
|
133
|
+
options.firstVisitPercentage >= 0 &&
|
|
134
|
+
options.firstVisitPercentage <= 1
|
|
135
|
+
) {
|
|
136
|
+
adjustments.firstVisitPercentage = options.firstVisitPercentage;
|
|
137
|
+
} else {
|
|
138
|
+
adjustments.firstVisitPercentage = FIRST_TIME_VIEWING_PERCENTAGE;
|
|
139
|
+
console.warn(
|
|
140
|
+
`The firstVisitPercentage option must be a number between 0 and 1. You passed in ${options.firstVisitPercentage}. \nFalling back to default value.`
|
|
141
|
+
);
|
|
142
|
+
}
|
|
143
|
+
} else {
|
|
144
|
+
adjustments.firstVisitPercentage = FIRST_TIME_VIEWING_PERCENTAGE;
|
|
145
|
+
console.warn(
|
|
146
|
+
`The firstVisitPercentage option must be a number. You passed in a ${typeof options.firstVisitPercentage}. \nFalling back to default value.`
|
|
147
|
+
);
|
|
148
|
+
}
|
|
149
|
+
}
|
|
150
|
+
|
|
151
|
+
if (options?.returnVisitPercentage) {
|
|
152
|
+
if (typeof options.returnVisitPercentage === "number") {
|
|
153
|
+
if (
|
|
154
|
+
options.returnVisitPercentage >= 0 &&
|
|
155
|
+
options.returnVisitPercentage <= 1
|
|
156
|
+
) {
|
|
157
|
+
adjustments.returnVisitPercentage = options.returnVisitPercentage;
|
|
158
|
+
} else {
|
|
159
|
+
adjustments.returnVisitPercentage = RETURNING_VISITOR_PERCENTAGE;
|
|
160
|
+
console.warn(
|
|
161
|
+
`The returnVisitPercentage option must be a number between 0 and 1. You passed in ${options.returnVisitPercentage}. \nFalling back to default value.`
|
|
162
|
+
);
|
|
163
|
+
}
|
|
164
|
+
} else {
|
|
165
|
+
adjustments.returnVisitPercentage = RETURNING_VISITOR_PERCENTAGE;
|
|
166
|
+
console.warn(
|
|
167
|
+
`The returnVisitPercentage option must be a number. You passed in a ${typeof options.returnVisitPercentage}. \nFalling back to default value.`
|
|
168
|
+
);
|
|
169
|
+
}
|
|
170
|
+
}
|
|
171
|
+
|
|
172
|
+
return adjustments;
|
|
173
|
+
}
|
|
174
|
+
|
|
175
|
+
export { formatNumber, parseOptions };
|
package/src/hosting-api.js
CHANGED
|
@@ -30,10 +30,11 @@ async function checkDomainsAgainstAPI(domains) {
|
|
|
30
30
|
// sanity check API result. Is this the library or
|
|
31
31
|
// the actual API request that's the problem?
|
|
32
32
|
// Is nock mocking node-native fetch API calls properly?
|
|
33
|
-
|
|
34
|
-
log({
|
|
35
|
-
|
|
36
|
-
|
|
33
|
+
// Commented out the logs for now, as they cause an error to be thrown when using the library.
|
|
34
|
+
// log(`${apiPath}/${domainsString}`);
|
|
35
|
+
// log({ req });
|
|
36
|
+
// const textResult = await req.text();
|
|
37
|
+
// log({ textResult });
|
|
37
38
|
|
|
38
39
|
const allGreenCheckResults = await req.json();
|
|
39
40
|
|
package/src/hosting-json.node.js
CHANGED
|
@@ -6,36 +6,25 @@
|
|
|
6
6
|
* Updated calculations and figures from
|
|
7
7
|
* https://sustainablewebdesign.org/calculating-digital-emissions/
|
|
8
8
|
*
|
|
9
|
-
*
|
|
10
9
|
*/
|
|
11
10
|
import debugFactory from "debug";
|
|
12
11
|
const log = debugFactory("tgwf:sustainable-web-design");
|
|
13
12
|
|
|
14
|
-
import {
|
|
13
|
+
import {
|
|
14
|
+
fileSize,
|
|
15
|
+
KWH_PER_GB,
|
|
16
|
+
END_USER_DEVICE_ENERGY,
|
|
17
|
+
NETWORK_ENERGY,
|
|
18
|
+
DATACENTER_ENERGY,
|
|
19
|
+
PRODUCTION_ENERGY,
|
|
20
|
+
GLOBAL_GRID_INTENSITY,
|
|
21
|
+
RENEWABLES_GRID_INTENSITY,
|
|
22
|
+
FIRST_TIME_VIEWING_PERCENTAGE,
|
|
23
|
+
RETURNING_VISITOR_PERCENTAGE,
|
|
24
|
+
PERCENTAGE_OF_DATA_LOADED_ON_SUBSEQUENT_LOAD,
|
|
25
|
+
} from "./constants/index.js";
|
|
15
26
|
import { formatNumber } from "./helpers/index.js";
|
|
16
27
|
|
|
17
|
-
// this refers to the estimated total energy use for the internet around 2000 TWh,
|
|
18
|
-
// divided by the total transfer it enables around 2500 exabytes
|
|
19
|
-
const KWH_PER_GB = 0.81;
|
|
20
|
-
|
|
21
|
-
// these constants outline how the energy is attributed to
|
|
22
|
-
// different parts of the system in the SWD model
|
|
23
|
-
const END_USER_DEVICE_ENERGY = 0.52;
|
|
24
|
-
const NETWORK_ENERGY = 0.14;
|
|
25
|
-
const DATACENTER_ENERGY = 0.15;
|
|
26
|
-
const PRODUCTION_ENERGY = 0.19;
|
|
27
|
-
|
|
28
|
-
// These carbon intensity figures https://ember-climate.org/data/data-explorer
|
|
29
|
-
// - Global carbon intensity for 2021
|
|
30
|
-
const GLOBAL_INTENSITY = 442;
|
|
31
|
-
const RENEWABLES_INTENSITY = 50;
|
|
32
|
-
|
|
33
|
-
// Taken from: https://gitlab.com/wholegrain/carbon-api-2-0/-/blob/master/includes/carbonapi.php
|
|
34
|
-
|
|
35
|
-
const FIRST_TIME_VIEWING_PERCENTAGE = 0.75;
|
|
36
|
-
const RETURNING_VISITOR_PERCENTAGE = 0.25;
|
|
37
|
-
const PERCENTAGE_OF_DATA_LOADED_ON_SUBSEQUENT_LOAD = 0.02;
|
|
38
|
-
|
|
39
28
|
class SustainableWebDesign {
|
|
40
29
|
constructor(options) {
|
|
41
30
|
this.options = options;
|
|
@@ -65,24 +54,61 @@ class SustainableWebDesign {
|
|
|
65
54
|
* Accept an object keys by the different system components, and
|
|
66
55
|
* return an object with the co2 figures key by the each component
|
|
67
56
|
*
|
|
68
|
-
* @param {object}
|
|
57
|
+
* @param {object} energyByComponent - energy grouped by the four system components
|
|
69
58
|
* @param {number} [carbonIntensity] - carbon intensity to apply to the datacentre values
|
|
70
59
|
* @return {number} the total number in grams of CO2 equivalent emissions
|
|
71
60
|
*/
|
|
72
|
-
co2byComponent(
|
|
61
|
+
co2byComponent(
|
|
62
|
+
energyByComponent,
|
|
63
|
+
carbonIntensity = GLOBAL_GRID_INTENSITY,
|
|
64
|
+
options = {}
|
|
65
|
+
) {
|
|
66
|
+
let deviceCarbonIntensity = GLOBAL_GRID_INTENSITY;
|
|
67
|
+
let networkCarbonIntensity = GLOBAL_GRID_INTENSITY;
|
|
68
|
+
let dataCenterCarbonIntensity = GLOBAL_GRID_INTENSITY;
|
|
69
|
+
|
|
70
|
+
let globalEmissions = GLOBAL_GRID_INTENSITY;
|
|
71
|
+
|
|
72
|
+
if (options?.gridIntensity) {
|
|
73
|
+
const { device, network, dataCenter } = options.gridIntensity;
|
|
74
|
+
|
|
75
|
+
if (device?.value) {
|
|
76
|
+
deviceCarbonIntensity = device.value;
|
|
77
|
+
}
|
|
78
|
+
if (network?.value) {
|
|
79
|
+
networkCarbonIntensity = network.value;
|
|
80
|
+
}
|
|
81
|
+
// If the user has set a carbon intensity value for the datacentre, then that overrides everything and is used
|
|
82
|
+
if (dataCenter?.value) {
|
|
83
|
+
dataCenterCarbonIntensity = dataCenter.value;
|
|
84
|
+
}
|
|
85
|
+
}
|
|
86
|
+
|
|
87
|
+
// If the user passes in a TRUE value (green web host), then use the renewables intensity value
|
|
88
|
+
if (carbonIntensity === true) {
|
|
89
|
+
dataCenterCarbonIntensity = RENEWABLES_GRID_INTENSITY;
|
|
90
|
+
}
|
|
91
|
+
|
|
73
92
|
const returnCO2ByComponent = {};
|
|
74
|
-
for (const [key, value] of Object.entries(
|
|
93
|
+
for (const [key, value] of Object.entries(energyByComponent)) {
|
|
75
94
|
// we update the datacentre, as that's what we have information
|
|
76
95
|
// about.
|
|
77
96
|
if (key.startsWith("dataCenterEnergy")) {
|
|
78
|
-
returnCO2ByComponent[key] =
|
|
97
|
+
returnCO2ByComponent[key.replace("Energy", "CO2")] =
|
|
98
|
+
value * dataCenterCarbonIntensity;
|
|
99
|
+
} else if (key.startsWith("consumerDeviceEnergy")) {
|
|
100
|
+
returnCO2ByComponent[key.replace("Energy", "CO2")] =
|
|
101
|
+
value * deviceCarbonIntensity;
|
|
102
|
+
} else if (key.startsWith("networkEnergy")) {
|
|
103
|
+
returnCO2ByComponent[key.replace("Energy", "CO2")] =
|
|
104
|
+
value * networkCarbonIntensity;
|
|
79
105
|
} else {
|
|
80
|
-
//
|
|
81
|
-
|
|
82
|
-
|
|
83
|
-
returnCO2ByComponent[key] = value * GLOBAL_INTENSITY;
|
|
106
|
+
// Use the global intensity for the remaining segments
|
|
107
|
+
returnCO2ByComponent[key.replace("Energy", "CO2")] =
|
|
108
|
+
value * globalEmissions;
|
|
84
109
|
}
|
|
85
110
|
}
|
|
111
|
+
|
|
86
112
|
return returnCO2ByComponent;
|
|
87
113
|
}
|
|
88
114
|
|
|
@@ -96,38 +122,38 @@ class SustainableWebDesign {
|
|
|
96
122
|
* @param {number} `carbonIntensity` the carbon intensity for datacentre (average figures, not marginal ones)
|
|
97
123
|
* @return {number} the total number in grams of CO2 equivalent emissions
|
|
98
124
|
*/
|
|
99
|
-
perByte(
|
|
100
|
-
|
|
101
|
-
|
|
102
|
-
|
|
103
|
-
|
|
104
|
-
|
|
105
|
-
|
|
106
|
-
// if we have a boolean, we have a green result from the green web checker
|
|
107
|
-
// use the renewables intensity
|
|
108
|
-
if (carbonIntensity === true) {
|
|
109
|
-
carbonIntensity = RENEWABLES_INTENSITY;
|
|
110
|
-
}
|
|
125
|
+
perByte(
|
|
126
|
+
bytes,
|
|
127
|
+
carbonIntensity = false,
|
|
128
|
+
segmentResults = false,
|
|
129
|
+
options = {}
|
|
130
|
+
) {
|
|
131
|
+
const energyBycomponent = this.energyPerByteByComponent(bytes, options);
|
|
111
132
|
|
|
112
133
|
// otherwise when faced with non numeric values throw an error
|
|
113
|
-
if (typeof carbonIntensity !== "
|
|
134
|
+
if (typeof carbonIntensity !== "boolean") {
|
|
114
135
|
throw new Error(
|
|
115
|
-
`perByte expects a
|
|
136
|
+
`perByte expects a boolean for the carbon intensity value. Received: ${carbonIntensity}`
|
|
116
137
|
);
|
|
117
138
|
}
|
|
118
139
|
|
|
119
140
|
const co2ValuesbyComponent = this.co2byComponent(
|
|
120
141
|
energyBycomponent,
|
|
121
|
-
carbonIntensity
|
|
142
|
+
carbonIntensity,
|
|
143
|
+
options
|
|
122
144
|
);
|
|
123
145
|
|
|
124
146
|
// pull out our values…
|
|
125
147
|
const co2Values = Object.values(co2ValuesbyComponent);
|
|
126
|
-
|
|
127
|
-
// so we can return their sum
|
|
128
|
-
return co2Values.reduce(
|
|
148
|
+
const co2ValuesSum = co2Values.reduce(
|
|
129
149
|
(prevValue, currentValue) => prevValue + currentValue
|
|
130
150
|
);
|
|
151
|
+
|
|
152
|
+
if (segmentResults) {
|
|
153
|
+
return { ...co2ValuesbyComponent, total: co2ValuesSum };
|
|
154
|
+
}
|
|
155
|
+
|
|
156
|
+
return co2ValuesSum;
|
|
131
157
|
}
|
|
132
158
|
|
|
133
159
|
/**
|
|
@@ -138,38 +164,39 @@ class SustainableWebDesign {
|
|
|
138
164
|
* @param {number} `carbonIntensity` the carbon intensity for datacentre (average figures, not marginal ones)
|
|
139
165
|
* @return {number} the total number in grams of CO2 equivalent emissions
|
|
140
166
|
*/
|
|
141
|
-
perVisit(
|
|
142
|
-
|
|
143
|
-
|
|
144
|
-
|
|
145
|
-
|
|
146
|
-
|
|
147
|
-
|
|
148
|
-
// if we have a boolean, we have a green result from the green web checker
|
|
149
|
-
// use the renewables intensity
|
|
150
|
-
if (carbonIntensity === true) {
|
|
151
|
-
carbonIntensity = RENEWABLES_INTENSITY;
|
|
152
|
-
}
|
|
167
|
+
perVisit(
|
|
168
|
+
bytes,
|
|
169
|
+
carbonIntensity = false,
|
|
170
|
+
segmentResults = false,
|
|
171
|
+
options = {}
|
|
172
|
+
) {
|
|
173
|
+
const energyBycomponent = this.energyPerVisitByComponent(bytes, options);
|
|
153
174
|
|
|
154
|
-
|
|
155
|
-
|
|
175
|
+
if (typeof carbonIntensity !== "boolean") {
|
|
176
|
+
// otherwise when faced with non numeric values throw an error
|
|
156
177
|
throw new Error(
|
|
157
|
-
`perVisit expects a
|
|
178
|
+
`perVisit expects a boolean for the carbon intensity value. Received: ${carbonIntensity}`
|
|
158
179
|
);
|
|
159
180
|
}
|
|
160
181
|
|
|
161
182
|
const co2ValuesbyComponent = this.co2byComponent(
|
|
162
183
|
energyBycomponent,
|
|
163
|
-
carbonIntensity
|
|
184
|
+
carbonIntensity,
|
|
185
|
+
options
|
|
164
186
|
);
|
|
165
187
|
|
|
166
188
|
// pull out our values…
|
|
167
189
|
const co2Values = Object.values(co2ValuesbyComponent);
|
|
168
|
-
|
|
169
|
-
// so we can return their sum
|
|
170
|
-
return co2Values.reduce(
|
|
190
|
+
const co2ValuesSum = co2Values.reduce(
|
|
171
191
|
(prevValue, currentValue) => prevValue + currentValue
|
|
172
192
|
);
|
|
193
|
+
|
|
194
|
+
if (segmentResults) {
|
|
195
|
+
return { ...co2ValuesbyComponent, total: co2ValuesSum };
|
|
196
|
+
}
|
|
197
|
+
|
|
198
|
+
// so we can return their sum
|
|
199
|
+
return co2ValuesSum;
|
|
173
200
|
}
|
|
174
201
|
|
|
175
202
|
/**
|
|
@@ -207,10 +234,23 @@ class SustainableWebDesign {
|
|
|
207
234
|
*/
|
|
208
235
|
energyPerVisitByComponent(
|
|
209
236
|
bytes,
|
|
237
|
+
options = {},
|
|
210
238
|
firstView = FIRST_TIME_VIEWING_PERCENTAGE,
|
|
211
239
|
returnView = RETURNING_VISITOR_PERCENTAGE,
|
|
212
240
|
dataReloadRatio = PERCENTAGE_OF_DATA_LOADED_ON_SUBSEQUENT_LOAD
|
|
213
241
|
) {
|
|
242
|
+
if (options.dataReloadRatio) {
|
|
243
|
+
dataReloadRatio = options.dataReloadRatio;
|
|
244
|
+
}
|
|
245
|
+
|
|
246
|
+
if (options.firstVisitPercentage) {
|
|
247
|
+
firstView = options.firstVisitPercentage;
|
|
248
|
+
}
|
|
249
|
+
|
|
250
|
+
if (options.returnVisitPercentage) {
|
|
251
|
+
returnView = options.returnVisitPercentage;
|
|
252
|
+
}
|
|
253
|
+
|
|
214
254
|
const energyBycomponent = this.energyPerByteByComponent(bytes);
|
|
215
255
|
const cacheAdjustedSegmentEnergy = {};
|
|
216
256
|
|
|
@@ -264,9 +304,10 @@ class SustainableWebDesign {
|
|
|
264
304
|
return firstVisits + subsequentVisits;
|
|
265
305
|
}
|
|
266
306
|
|
|
267
|
-
|
|
268
|
-
|
|
269
|
-
|
|
307
|
+
emissionsPerVisitInGrams(
|
|
308
|
+
energyPerVisit,
|
|
309
|
+
carbonintensity = GLOBAL_GRID_INTENSITY
|
|
310
|
+
) {
|
|
270
311
|
return formatNumber(energyPerVisit * carbonintensity);
|
|
271
312
|
}
|
|
272
313
|
|
package/dist/cjs/1byte.test.js
DELETED
|
@@ -1,27 +0,0 @@
|
|
|
1
|
-
"use strict";
|
|
2
|
-
var __create = Object.create;
|
|
3
|
-
var __defProp = Object.defineProperty;
|
|
4
|
-
var __getOwnPropDesc = Object.getOwnPropertyDescriptor;
|
|
5
|
-
var __getOwnPropNames = Object.getOwnPropertyNames;
|
|
6
|
-
var __getProtoOf = Object.getPrototypeOf;
|
|
7
|
-
var __hasOwnProp = Object.prototype.hasOwnProperty;
|
|
8
|
-
var __copyProps = (to, from, except, desc) => {
|
|
9
|
-
if (from && typeof from === "object" || typeof from === "function") {
|
|
10
|
-
for (let key of __getOwnPropNames(from))
|
|
11
|
-
if (!__hasOwnProp.call(to, key) && key !== except)
|
|
12
|
-
__defProp(to, key, { get: () => from[key], enumerable: !(desc = __getOwnPropDesc(from, key)) || desc.enumerable });
|
|
13
|
-
}
|
|
14
|
-
return to;
|
|
15
|
-
};
|
|
16
|
-
var __toESM = (mod, isNodeMode, target) => (target = mod != null ? __create(__getProtoOf(mod)) : {}, __copyProps(isNodeMode || !mod || !mod.__esModule ? __defProp(target, "default", { value: mod, enumerable: true }) : target, mod));
|
|
17
|
-
var import_byte = __toESM(require("./1byte.js"));
|
|
18
|
-
describe("onebyte", () => {
|
|
19
|
-
describe("perByte", () => {
|
|
20
|
-
it("returns a simple average of the different networks", () => {
|
|
21
|
-
const expected_val = 488e-12 .toFixed(12);
|
|
22
|
-
const instance = new import_byte.default();
|
|
23
|
-
expect(instance.KWH_PER_BYTE_FOR_NETWORK.toFixed(12)).toBe(expected_val);
|
|
24
|
-
});
|
|
25
|
-
});
|
|
26
|
-
});
|
|
27
|
-
//# sourceMappingURL=1byte.test.js.map
|
|
@@ -1,7 +0,0 @@
|
|
|
1
|
-
{
|
|
2
|
-
"version": 3,
|
|
3
|
-
"sources": ["../../src/1byte.test.js"],
|
|
4
|
-
"sourcesContent": ["\"use strict\";\n\nimport OneByte from \"./1byte.js\";\n\ndescribe(\"onebyte\", () => {\n describe(\"perByte\", () => {\n it(\"returns a simple average of the different networks\", () => {\n // we limit this to 12 figures with toFixed(12), because\n // we have a recurring 333333 afterwards\n // 4.88e-10 is the same as 0.000000000488\n const expected_val = (0.000000000488).toFixed(12);\n const instance = new OneByte();\n\n expect(instance.KWH_PER_BYTE_FOR_NETWORK.toFixed(12)).toBe(expected_val);\n });\n });\n});\n"],
|
|
5
|
-
"mappings": ";;;;;;;;;;;;;;;;AAEA,kBAAoB;AAEpB,SAAS,WAAW,MAAM;AACxB,WAAS,WAAW,MAAM;AACxB,OAAG,sDAAsD,MAAM;AAI7D,YAAM,eAAgB,SAAgB,QAAQ,EAAE;AAChD,YAAM,WAAW,IAAI,oBAAQ;AAE7B,aAAO,SAAS,yBAAyB,QAAQ,EAAE,CAAC,EAAE,KAAK,YAAY;AAAA,IACzE,CAAC;AAAA,EACH,CAAC;AACH,CAAC;",
|
|
6
|
-
"names": []
|
|
7
|
-
}
|