@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.
Files changed (53) hide show
  1. package/.esbuild.esm.js +1 -1
  2. package/.esbuild.node.js +1 -1
  3. package/README.md +3 -3
  4. package/dist/cjs/1byte.js.map +2 -2
  5. package/dist/cjs/co2.js +67 -4
  6. package/dist/cjs/co2.js.map +2 -2
  7. package/dist/cjs/constants/index.js +23 -1
  8. package/dist/cjs/constants/index.js.map +2 -2
  9. package/dist/cjs/helpers/index.js +139 -1
  10. package/dist/cjs/helpers/index.js.map +2 -2
  11. package/dist/cjs/hosting-api.js +0 -4
  12. package/dist/cjs/hosting-api.js.map +2 -2
  13. package/dist/cjs/hosting-json.node.js +2 -1
  14. package/dist/cjs/hosting-json.node.js.map +2 -2
  15. package/dist/cjs/sustainable-web-design.js +67 -49
  16. package/dist/cjs/sustainable-web-design.js.map +2 -2
  17. package/dist/esm/co2.js +70 -4
  18. package/dist/esm/constants/index.js +23 -1
  19. package/dist/esm/helpers/index.js +144 -1
  20. package/dist/esm/hosting-api.js +0 -4
  21. package/dist/esm/sustainable-web-design.js +90 -41
  22. package/dist/iife/index.js +19 -3
  23. package/dist/iife/index.js.map +3 -3
  24. package/package.json +1 -1
  25. package/src/1byte.js +7 -0
  26. package/src/co2.js +157 -4
  27. package/src/constants/index.js +38 -1
  28. package/src/helpers/index.js +173 -1
  29. package/src/hosting-api.js +5 -4
  30. package/src/hosting-json.node.js +1 -0
  31. package/src/sustainable-web-design.js +113 -72
  32. package/dist/cjs/1byte.test.js +0 -27
  33. package/dist/cjs/1byte.test.js.map +0 -7
  34. package/dist/cjs/co2.test.js +0 -281
  35. package/dist/cjs/co2.test.js.map +0 -7
  36. package/dist/cjs/hosting-api.test.js +0 -47
  37. package/dist/cjs/hosting-api.test.js.map +0 -7
  38. package/dist/cjs/hosting-database.node.test.js +0 -36
  39. package/dist/cjs/hosting-database.node.test.js.map +0 -7
  40. package/dist/cjs/hosting-json.node.test.js +0 -43
  41. package/dist/cjs/hosting-json.node.test.js.map +0 -7
  42. package/dist/cjs/hosting.test.js +0 -74
  43. package/dist/cjs/hosting.test.js.map +0 -7
  44. package/dist/cjs/sustainable-web-design.test.js +0 -84
  45. package/dist/cjs/sustainable-web-design.test.js.map +0 -7
  46. package/dist/esm/1byte.test.js +0 -11
  47. package/dist/esm/co2.test.js +0 -265
  48. package/dist/esm/hosting-api.test.js +0 -31
  49. package/dist/esm/hosting-database.node.test.js +0 -20
  50. package/dist/esm/hosting-json.node.test.js +0 -27
  51. package/dist/esm/hosting.test.js +0 -58
  52. package/dist/esm/sustainable-web-design.test.js +0 -68
  53. package/src/readme.md +0 -66
@@ -1,84 +0,0 @@
1
- var __create = Object.create;
2
- var __defProp = Object.defineProperty;
3
- var __getOwnPropDesc = Object.getOwnPropertyDescriptor;
4
- var __getOwnPropNames = Object.getOwnPropertyNames;
5
- var __getProtoOf = Object.getPrototypeOf;
6
- var __hasOwnProp = Object.prototype.hasOwnProperty;
7
- var __copyProps = (to, from, except, desc) => {
8
- if (from && typeof from === "object" || typeof from === "function") {
9
- for (let key of __getOwnPropNames(from))
10
- if (!__hasOwnProp.call(to, key) && key !== except)
11
- __defProp(to, key, { get: () => from[key], enumerable: !(desc = __getOwnPropDesc(from, key)) || desc.enumerable });
12
- }
13
- return to;
14
- };
15
- 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));
16
- var import_sustainable_web_design = __toESM(require("./sustainable-web-design.js"));
17
- describe("sustainable web design model", () => {
18
- const swd = new import_sustainable_web_design.default();
19
- const averageWebsiteInBytes = 22577152e-1;
20
- describe("energyPerByteByComponent", () => {
21
- it("should return a object with numbers for each system component", () => {
22
- const groupedEnergy = swd.energyPerByteByComponent(averageWebsiteInBytes);
23
- expect(groupedEnergy.consumerDeviceEnergy).toBeCloseTo(95095e-8, 8);
24
- expect(groupedEnergy.networkEnergy).toBeCloseTo(25602e-8, 7);
25
- expect(groupedEnergy.dataCenterEnergy).toBeCloseTo(27431e-8, 8);
26
- expect(groupedEnergy.productionEnergy).toBeCloseTo(3475e-7, 7);
27
- });
28
- });
29
- describe("energyPerByte", () => {
30
- it("should return a number in kilowatt hours for the given data transfer in bytes", () => {
31
- const energyForTransfer = swd.energyPerByte(averageWebsiteInBytes);
32
- expect(energyForTransfer).toBeCloseTo(182874e-8, 7);
33
- });
34
- });
35
- describe("perByte", () => {
36
- it("should return a single number for CO2 emissions", () => {
37
- expect(typeof swd.perByte(22577152e-1)).toBe("number");
38
- });
39
- });
40
- describe("perVisit", () => {
41
- it("should return a single number for CO2 emissions", () => {
42
- expect(typeof swd.perVisit(22577152e-1)).toBe("number");
43
- });
44
- });
45
- describe("energyPerVisit", () => {
46
- it("should return a number", () => {
47
- expect(typeof swd.energyPerVisit(averageWebsiteInBytes)).toBe("number");
48
- });
49
- it("should calculate the correct energy", () => {
50
- expect(swd.energyPerVisit(averageWebsiteInBytes)).toBe(0.0013807057305600004);
51
- });
52
- });
53
- describe("emissionsPerVisitInGrams", () => {
54
- it("should calculate the correct co2 per visit", () => {
55
- const energy = swd.energyPerVisit(averageWebsiteInBytes);
56
- expect(swd.emissionsPerVisitInGrams(energy)).toEqual(0.61);
57
- });
58
- it("should accept a dynamic KwH value", () => {
59
- const energy = swd.energyPerVisit(averageWebsiteInBytes);
60
- expect(swd.emissionsPerVisitInGrams(energy, 245)).toEqual(0.34);
61
- });
62
- });
63
- describe("annualEnergyInKwh", () => {
64
- it("should calculate the correct energy in kWh", () => {
65
- expect(swd.annualEnergyInKwh(averageWebsiteInBytes)).toBe(27092582400);
66
- });
67
- });
68
- describe("annualEmissionsInGrams", () => {
69
- it("should calculate the corrent energy in grams", () => {
70
- expect(swd.annualEmissionsInGrams(averageWebsiteInBytes)).toBe(27092582400);
71
- });
72
- });
73
- describe("annualSegmentEnergy", () => {
74
- it("should return the correct values", () => {
75
- expect(swd.annualSegmentEnergy(averageWebsiteInBytes)).toEqual({
76
- consumerDeviceEnergy: 11740119e-1,
77
- dataCenterEnergy: 338657.28,
78
- networkEnergy: 316080.13,
79
- productionEnergy: 428965.89
80
- });
81
- });
82
- });
83
- });
84
- //# sourceMappingURL=sustainable-web-design.test.js.map
@@ -1,7 +0,0 @@
1
- {
2
- "version": 3,
3
- "sources": ["../../src/sustainable-web-design.test.js"],
4
- "sourcesContent": ["import SustainableWebDesign from \"./sustainable-web-design.js\";\n\ndescribe(\"sustainable web design model\", () => {\n const swd = new SustainableWebDesign();\n const averageWebsiteInBytes = 2257715.2;\n\n describe(\"energyPerByteByComponent\", () => {\n it(\"should return a object with numbers for each system component\", () => {\n // Compare these with the carbon intensity tab C7-C10.\n // https://docs.google.com/spreadsheets/d/1eFlHhSBus_HqmoXqX237eAYr0PREUhTr6YBxznQC4jI/edit#gid=0\n\n // These numbers should match the spreadsheet\n const groupedEnergy = swd.energyPerByteByComponent(averageWebsiteInBytes);\n expect(groupedEnergy.consumerDeviceEnergy).toBeCloseTo(0.00095095, 8);\n expect(groupedEnergy.networkEnergy).toBeCloseTo(0.00025602, 7);\n expect(groupedEnergy.dataCenterEnergy).toBeCloseTo(0.00027431, 8);\n expect(groupedEnergy.productionEnergy).toBeCloseTo(0.0003475, 7);\n });\n });\n\n describe(\"energyPerByte\", () => {\n it(\"should return a number in kilowatt hours for the given data transfer in bytes\", () => {\n const energyForTransfer = swd.energyPerByte(averageWebsiteInBytes);\n expect(energyForTransfer).toBeCloseTo(0.00182874, 7);\n });\n });\n\n describe(\"perByte\", () => {\n it(\"should return a single number for CO2 emissions\", () => {\n expect(typeof swd.perByte(2257715.2)).toBe(\"number\");\n });\n });\n\n describe(\"perVisit\", () => {\n it(\"should return a single number for CO2 emissions\", () => {\n expect(typeof swd.perVisit(2257715.2)).toBe(\"number\");\n });\n });\n\n describe(\"energyPerVisit\", () => {\n it(\"should return a number\", () => {\n expect(typeof swd.energyPerVisit(averageWebsiteInBytes)).toBe(\"number\");\n });\n\n it(\"should calculate the correct energy\", () => {\n expect(swd.energyPerVisit(averageWebsiteInBytes)).toBe(\n 0.0013807057305600004\n );\n });\n });\n\n describe(\"emissionsPerVisitInGrams\", () => {\n it(\"should calculate the correct co2 per visit\", () => {\n const energy = swd.energyPerVisit(averageWebsiteInBytes);\n expect(swd.emissionsPerVisitInGrams(energy)).toEqual(0.61);\n });\n\n it(\"should accept a dynamic KwH value\", () => {\n const energy = swd.energyPerVisit(averageWebsiteInBytes);\n expect(swd.emissionsPerVisitInGrams(energy, 245)).toEqual(0.34);\n });\n });\n\n describe(\"annualEnergyInKwh\", () => {\n it(\"should calculate the correct energy in kWh\", () => {\n expect(swd.annualEnergyInKwh(averageWebsiteInBytes)).toBe(27092582400);\n });\n });\n\n describe(\"annualEmissionsInGrams\", () => {\n it(\"should calculate the corrent energy in grams\", () => {\n expect(swd.annualEmissionsInGrams(averageWebsiteInBytes)).toBe(\n 27092582400\n );\n });\n });\n\n describe(\"annualSegmentEnergy\", () => {\n it(\"should return the correct values\", () => {\n expect(swd.annualSegmentEnergy(averageWebsiteInBytes)).toEqual({\n consumerDeviceEnergy: 1174011.9,\n dataCenterEnergy: 338657.28,\n networkEnergy: 316080.13,\n productionEnergy: 428965.89,\n });\n });\n });\n});\n"],
5
- "mappings": ";;;;;;;;;;;;;;;AAAA,oCAAiC;AAEjC,SAAS,gCAAgC,MAAM;AAC7C,QAAM,MAAM,IAAI,sCAAqB;AACrC,QAAM,wBAAwB;AAE9B,WAAS,4BAA4B,MAAM;AACzC,OAAG,iEAAiE,MAAM;AAKxE,YAAM,gBAAgB,IAAI,yBAAyB,qBAAqB;AACxE,aAAO,cAAc,oBAAoB,EAAE,YAAY,UAAY,CAAC;AACpE,aAAO,cAAc,aAAa,EAAE,YAAY,UAAY,CAAC;AAC7D,aAAO,cAAc,gBAAgB,EAAE,YAAY,UAAY,CAAC;AAChE,aAAO,cAAc,gBAAgB,EAAE,YAAY,SAAW,CAAC;AAAA,IACjE,CAAC;AAAA,EACH,CAAC;AAED,WAAS,iBAAiB,MAAM;AAC9B,OAAG,iFAAiF,MAAM;AACxF,YAAM,oBAAoB,IAAI,cAAc,qBAAqB;AACjE,aAAO,iBAAiB,EAAE,YAAY,WAAY,CAAC;AAAA,IACrD,CAAC;AAAA,EACH,CAAC;AAED,WAAS,WAAW,MAAM;AACxB,OAAG,mDAAmD,MAAM;AAC1D,aAAO,OAAO,IAAI,QAAQ,WAAS,CAAC,EAAE,KAAK,QAAQ;AAAA,IACrD,CAAC;AAAA,EACH,CAAC;AAED,WAAS,YAAY,MAAM;AACzB,OAAG,mDAAmD,MAAM;AAC1D,aAAO,OAAO,IAAI,SAAS,WAAS,CAAC,EAAE,KAAK,QAAQ;AAAA,IACtD,CAAC;AAAA,EACH,CAAC;AAED,WAAS,kBAAkB,MAAM;AAC/B,OAAG,0BAA0B,MAAM;AACjC,aAAO,OAAO,IAAI,eAAe,qBAAqB,CAAC,EAAE,KAAK,QAAQ;AAAA,IACxE,CAAC;AAED,OAAG,uCAAuC,MAAM;AAC9C,aAAO,IAAI,eAAe,qBAAqB,CAAC,EAAE,KAChD,qBACF;AAAA,IACF,CAAC;AAAA,EACH,CAAC;AAED,WAAS,4BAA4B,MAAM;AACzC,OAAG,8CAA8C,MAAM;AACrD,YAAM,SAAS,IAAI,eAAe,qBAAqB;AACvD,aAAO,IAAI,yBAAyB,MAAM,CAAC,EAAE,QAAQ,IAAI;AAAA,IAC3D,CAAC;AAED,OAAG,qCAAqC,MAAM;AAC5C,YAAM,SAAS,IAAI,eAAe,qBAAqB;AACvD,aAAO,IAAI,yBAAyB,QAAQ,GAAG,CAAC,EAAE,QAAQ,IAAI;AAAA,IAChE,CAAC;AAAA,EACH,CAAC;AAED,WAAS,qBAAqB,MAAM;AAClC,OAAG,8CAA8C,MAAM;AACrD,aAAO,IAAI,kBAAkB,qBAAqB,CAAC,EAAE,KAAK,WAAW;AAAA,IACvE,CAAC;AAAA,EACH,CAAC;AAED,WAAS,0BAA0B,MAAM;AACvC,OAAG,gDAAgD,MAAM;AACvD,aAAO,IAAI,uBAAuB,qBAAqB,CAAC,EAAE,KACxD,WACF;AAAA,IACF,CAAC;AAAA,EACH,CAAC;AAED,WAAS,uBAAuB,MAAM;AACpC,OAAG,oCAAoC,MAAM;AAC3C,aAAO,IAAI,oBAAoB,qBAAqB,CAAC,EAAE,QAAQ;AAAA,QAC7D,sBAAsB;AAAA,QACtB,kBAAkB;AAAA,QAClB,eAAe;AAAA,QACf,kBAAkB;AAAA,MACpB,CAAC;AAAA,IACH,CAAC;AAAA,EACH,CAAC;AACH,CAAC;",
6
- "names": []
7
- }
@@ -1,11 +0,0 @@
1
- "use strict";
2
- import OneByte from "./1byte.js";
3
- describe("onebyte", () => {
4
- describe("perByte", () => {
5
- it("returns a simple average of the different networks", () => {
6
- const expected_val = 488e-12 .toFixed(12);
7
- const instance = new OneByte();
8
- expect(instance.KWH_PER_BYTE_FOR_NETWORK.toFixed(12)).toBe(expected_val);
9
- });
10
- });
11
- });
@@ -1,265 +0,0 @@
1
- "use strict";
2
- import fs from "fs";
3
- import path from "path";
4
- import pagexray from "pagexray";
5
- import CO2 from "./co2.js";
6
- import { averageIntensity, marginalIntensity } from "./index.js";
7
- describe("co2", () => {
8
- let har, co2;
9
- describe("1 byte model", () => {
10
- const TGWF_GREY_VALUE = 0.20497;
11
- const TGWF_GREEN_VALUE = 0.54704;
12
- const TGWF_MIXED_VALUE = 0.16718;
13
- const MILLION = 1e6;
14
- const MILLION_GREY = 0.29081;
15
- const MILLION_GREEN = 0.23196;
16
- beforeEach(() => {
17
- co2 = new CO2({ model: "1byte" });
18
- har = JSON.parse(fs.readFileSync(path.resolve(__dirname, "../data/fixtures/tgwf.har"), "utf8"));
19
- });
20
- describe("perByte", () => {
21
- it("returns a CO2 number for data transfer using 'grey' power", () => {
22
- expect(co2.perByte(MILLION).toPrecision(5)).toBe(MILLION_GREY.toPrecision(5));
23
- });
24
- it("returns a lower CO2 number for data transfer from domains using entirely 'green' power", () => {
25
- expect(co2.perByte(MILLION).toPrecision(5)).toBe(MILLION_GREY.toPrecision(5));
26
- expect(co2.perByte(MILLION, true).toPrecision(5)).toBe(MILLION_GREEN.toPrecision(5));
27
- });
28
- });
29
- describe("perPage", () => {
30
- it("returns CO2 for total transfer for page", () => {
31
- const pages = pagexray.convert(har);
32
- const pageXrayRun = pages[0];
33
- expect(co2.perPage(pageXrayRun).toPrecision(5)).toBe(TGWF_GREY_VALUE.toPrecision(5));
34
- });
35
- it("returns lower CO2 for page served from green site", () => {
36
- const pages = pagexray.convert(har);
37
- const pageXrayRun = pages[0];
38
- let green = [
39
- "www.thegreenwebfoundation.org",
40
- "fonts.googleapis.com",
41
- "ajax.googleapis.com",
42
- "assets.digitalclimatestrike.net",
43
- "cdnjs.cloudflare.com",
44
- "graphite.thegreenwebfoundation.org",
45
- "analytics.thegreenwebfoundation.org",
46
- "fonts.gstatic.com",
47
- "api.thegreenwebfoundation.org"
48
- ];
49
- expect(co2.perPage(pageXrayRun, green)).toBeLessThan(TGWF_GREY_VALUE);
50
- });
51
- it("returns a lower CO2 number where *some* domains use green power", () => {
52
- const pages = pagexray.convert(har);
53
- const pageXrayRun = pages[0];
54
- let green = [
55
- "www.thegreenwebfoundation.org",
56
- "fonts.googleapis.com",
57
- "ajax.googleapis.com",
58
- "assets.digitalclimatestrike.net",
59
- "cdnjs.cloudflare.com",
60
- "graphite.thegreenwebfoundation.org",
61
- "analytics.thegreenwebfoundation.org",
62
- "fonts.gstatic.com",
63
- "api.thegreenwebfoundation.org"
64
- ];
65
- expect(co2.perPage(pageXrayRun, green).toPrecision(5)).toBe(TGWF_MIXED_VALUE.toPrecision(5));
66
- });
67
- });
68
- describe("perDomain", () => {
69
- it("shows object listing Co2 for each domain", () => {
70
- const pages = pagexray.convert(har);
71
- const pageXrayRun = pages[0];
72
- const res = co2.perDomain(pageXrayRun);
73
- const domains = [
74
- "thegreenwebfoundation.org",
75
- "www.thegreenwebfoundation.org",
76
- "maxcdn.bootstrapcdn.com",
77
- "fonts.googleapis.com",
78
- "ajax.googleapis.com",
79
- "assets.digitalclimatestrike.net",
80
- "cdnjs.cloudflare.com",
81
- "graphite.thegreenwebfoundation.org",
82
- "analytics.thegreenwebfoundation.org",
83
- "fonts.gstatic.com",
84
- "api.thegreenwebfoundation.org"
85
- ];
86
- for (let obj of res) {
87
- expect(domains.indexOf(obj.domain)).toBeGreaterThan(-1);
88
- expect(typeof obj.co2).toBe("number");
89
- }
90
- });
91
- it("shows lower Co2 for green domains", () => {
92
- const pages = pagexray.convert(har);
93
- const pageXrayRun = pages[0];
94
- const greenDomains = [
95
- "www.thegreenwebfoundation.org",
96
- "fonts.googleapis.com",
97
- "ajax.googleapis.com",
98
- "assets.digitalclimatestrike.net",
99
- "cdnjs.cloudflare.com",
100
- "graphite.thegreenwebfoundation.org",
101
- "analytics.thegreenwebfoundation.org",
102
- "fonts.gstatic.com",
103
- "api.thegreenwebfoundation.org"
104
- ];
105
- const res = co2.perDomain(pageXrayRun);
106
- const resWithGreen = co2.perDomain(pageXrayRun, greenDomains);
107
- for (let obj of res) {
108
- expect(typeof obj.co2).toBe("number");
109
- }
110
- for (let obj of greenDomains) {
111
- let index = 0;
112
- expect(resWithGreen[index].co2).toBeLessThan(res[index].co2);
113
- index++;
114
- }
115
- });
116
- });
117
- });
118
- describe("Sustainable Web Design model as simple option", () => {
119
- const MILLION = 1e6;
120
- const MILLION_GREY = 0.35802;
121
- const MILLION_GREEN = 0.31039;
122
- const MILLION_PERVISIT_GREY = 0.27031;
123
- const MILLION_PERVISIT_GREEN = 0.23435;
124
- const TGWF_GREY_VALUE = 0.25234;
125
- const TGWF_GREEN_VALUE = 0.54704;
126
- const TGWF_MIXED_VALUE = 0.22175;
127
- beforeEach(() => {
128
- co2 = new CO2();
129
- har = JSON.parse(fs.readFileSync(path.resolve(__dirname, "../data/fixtures/tgwf.har"), "utf8"));
130
- });
131
- describe("perByte", () => {
132
- it("returns a CO2 number for data transfer", () => {
133
- co2.perByte(MILLION);
134
- expect(co2.perByte(MILLION).toPrecision(5)).toBe(MILLION_GREY.toPrecision(5));
135
- });
136
- it("returns a lower CO2 number for data transfer from domains using entirely 'green' power", () => {
137
- expect(co2.perByte(MILLION, false).toPrecision(5)).toBe(MILLION_GREY.toPrecision(5));
138
- expect(co2.perByte(MILLION, true).toPrecision(5)).toBe(MILLION_GREEN.toPrecision(5));
139
- });
140
- });
141
- describe("perVisit", () => {
142
- it("returns a CO2 number for data transfer per visit with caching assumptions from the Sustainable Web Design model", () => {
143
- co2.perVisit(MILLION);
144
- expect(co2.perVisit(MILLION).toPrecision(5)).toBe(MILLION_PERVISIT_GREY.toPrecision(5));
145
- });
146
- it("returns a lower CO2 number for data transfer from domains using entirely 'green' power", () => {
147
- expect(co2.perVisit(MILLION, false).toPrecision(5)).toBe(MILLION_PERVISIT_GREY.toPrecision(5));
148
- expect(co2.perVisit(MILLION, true).toPrecision(5)).toBe(MILLION_PERVISIT_GREEN.toPrecision(5));
149
- });
150
- });
151
- describe("perPage", () => {
152
- it("returns CO2 for total transfer for page", () => {
153
- const pages = pagexray.convert(har);
154
- const pageXrayRun = pages[0];
155
- expect(co2.perPage(pageXrayRun).toPrecision(5)).toBe(TGWF_GREY_VALUE.toPrecision(5));
156
- });
157
- it("returns lower CO2 for page served from green site", () => {
158
- const pages = pagexray.convert(har);
159
- const pageXrayRun = pages[0];
160
- let green = [
161
- "www.thegreenwebfoundation.org",
162
- "fonts.googleapis.com",
163
- "ajax.googleapis.com",
164
- "assets.digitalclimatestrike.net",
165
- "cdnjs.cloudflare.com",
166
- "graphite.thegreenwebfoundation.org",
167
- "analytics.thegreenwebfoundation.org",
168
- "fonts.gstatic.com",
169
- "api.thegreenwebfoundation.org"
170
- ];
171
- expect(co2.perPage(pageXrayRun, green)).toBeLessThan(TGWF_GREY_VALUE);
172
- });
173
- it("returns a lower CO2 number where *some* domains use green power", () => {
174
- const pages = pagexray.convert(har);
175
- const pageXrayRun = pages[0];
176
- let green = [
177
- "www.thegreenwebfoundation.org",
178
- "fonts.googleapis.com",
179
- "ajax.googleapis.com",
180
- "assets.digitalclimatestrike.net",
181
- "cdnjs.cloudflare.com",
182
- "graphite.thegreenwebfoundation.org",
183
- "analytics.thegreenwebfoundation.org",
184
- "fonts.gstatic.com",
185
- "api.thegreenwebfoundation.org"
186
- ];
187
- expect(co2.perPage(pageXrayRun, green).toPrecision(5)).toBe(TGWF_MIXED_VALUE.toPrecision(5));
188
- });
189
- });
190
- describe("perDomain", () => {
191
- it("shows object listing Co2 for each domain", () => {
192
- const pages = pagexray.convert(har);
193
- const pageXrayRun = pages[0];
194
- const res = co2.perDomain(pageXrayRun);
195
- const domains = [
196
- "thegreenwebfoundation.org",
197
- "www.thegreenwebfoundation.org",
198
- "maxcdn.bootstrapcdn.com",
199
- "fonts.googleapis.com",
200
- "ajax.googleapis.com",
201
- "assets.digitalclimatestrike.net",
202
- "cdnjs.cloudflare.com",
203
- "graphite.thegreenwebfoundation.org",
204
- "analytics.thegreenwebfoundation.org",
205
- "fonts.gstatic.com",
206
- "api.thegreenwebfoundation.org"
207
- ];
208
- for (let obj of res) {
209
- expect(domains.indexOf(obj.domain)).toBeGreaterThan(-1);
210
- expect(typeof obj.co2).toBe("number");
211
- }
212
- });
213
- it("shows lower Co2 for green domains", () => {
214
- const pages = pagexray.convert(har);
215
- const pageXrayRun = pages[0];
216
- const greenDomains = [
217
- "www.thegreenwebfoundation.org",
218
- "fonts.googleapis.com",
219
- "ajax.googleapis.com",
220
- "assets.digitalclimatestrike.net",
221
- "cdnjs.cloudflare.com",
222
- "graphite.thegreenwebfoundation.org",
223
- "analytics.thegreenwebfoundation.org",
224
- "fonts.gstatic.com",
225
- "api.thegreenwebfoundation.org"
226
- ];
227
- const res = co2.perDomain(pageXrayRun);
228
- const resWithGreen = co2.perDomain(pageXrayRun, greenDomains);
229
- for (let obj of res) {
230
- expect(typeof obj.co2).toBe("number");
231
- }
232
- for (let obj of greenDomains) {
233
- let index = 0;
234
- expect(resWithGreen[index].co2).toBeLessThan(res[index].co2);
235
- index++;
236
- }
237
- });
238
- });
239
- });
240
- describe("Error checking", () => {
241
- it("throws an error if model is not valid", () => {
242
- expect(() => co2 = new CO2({ model: "1direction" })).toThrowError(`"1direction" is not a valid model. Please use "1byte" for the OneByte model, and "swd" for the Sustainable Web Design model.
243
- See https://developers.thegreenwebfoundation.org/co2js/models/ to learn more about the models available in CO2.js.`);
244
- });
245
- it("throws an error if perVisit method is not supported by model", () => {
246
- expect(() => {
247
- co2 = new CO2({ model: "1byte" });
248
- co2.perVisit(10);
249
- }).toThrowError(`The perVisit() method is not supported in the model you are using. Try using perByte() instead.
250
- See https://developers.thegreenwebfoundation.org/co2js/methods/ to learn more about the methods available in CO2.js.`);
251
- });
252
- });
253
- describe("Importing grid intensity", () => {
254
- describe("average intensity", () => {
255
- it("imports average intensity data", () => {
256
- expect(averageIntensity).toHaveProperty("type", "average");
257
- });
258
- });
259
- describe("marginal intensity", () => {
260
- it("imports average intensity data", () => {
261
- expect(marginalIntensity).toHaveProperty("type", "marginal");
262
- });
263
- });
264
- });
265
- });
@@ -1,31 +0,0 @@
1
- "use strict";
2
- import hosting from "./hosting-node.js";
3
- import nock from "nock";
4
- describe("hostingAPI", () => {
5
- describe("checking a single domain with #check", () => {
6
- it.skip("using the API", async () => {
7
- const scope = nock("https://api.thegreenwebfoundation.org/").get("/greencheck/google.com").reply(200, {
8
- url: "google.com",
9
- green: true
10
- });
11
- const res = await hosting.check("google.com");
12
- expect(res).toEqual(true);
13
- });
14
- });
15
- describe("implicitly checking multiple domains with #check", () => {
16
- it.skip("using the API", async () => {
17
- const scope = nock("https://api.thegreenwebfoundation.org/").get("/v2/greencheckmulti/[%22google.com%22,%22kochindustries.com%22]").reply(200, {
18
- "google.com": {
19
- url: "google.com",
20
- green: true
21
- },
22
- "kochindustries.com": {
23
- url: "kochindustries.com",
24
- green: null
25
- }
26
- });
27
- const res = await hosting.check(["google.com", "kochindustries.com"]);
28
- expect(res).toContain("google.com");
29
- });
30
- });
31
- });
@@ -1,20 +0,0 @@
1
- "use strict";
2
- import path from "path";
3
- import debugFactory from "debug";
4
- const log = debugFactory("tgwf:url2green:test");
5
- import { hosting } from "@tgwf/url2green";
6
- const dbPath = path.resolve(__dirname, "..", "data", "fixtures", "url2green.test.db");
7
- describe("hostingDatabase", () => {
8
- describe("checking a single domain with #check", () => {
9
- test("tries to use a local database if available", async () => {
10
- const res = await hosting.check("google.com", dbPath);
11
- expect(res).toEqual(true);
12
- });
13
- });
14
- describe("implicitly checking multiple domains with #check", () => {
15
- test("tries to use a local database if available", async () => {
16
- const res = await hosting.check(["google.com", "kochindustries.com"], dbPath);
17
- expect(res).toContain("google.com");
18
- });
19
- });
20
- });
@@ -1,27 +0,0 @@
1
- "use strict";
2
- import hosting from "./hosting-json.node.js";
3
- import path from "path";
4
- describe("hostingJSON", () => {
5
- const jsonPath = path.resolve(__dirname, "..", "data", "fixtures", "url2green.test.json");
6
- const jsonPathGz = path.resolve(__dirname, "..", "data", "fixtures", "url2green.test.json.gz");
7
- describe("checking a single domain with #check", () => {
8
- test("against the list of domains as JSON", async () => {
9
- const db = await hosting.loadJSON(jsonPath);
10
- const res = await hosting.check("google.com", db);
11
- expect(res).toEqual(true);
12
- });
13
- test("against the list of domains as JSON loaded from a gzipped JSON", async () => {
14
- const db = await hosting.loadJSON(jsonPathGz);
15
- const res = await hosting.check("google.com", db);
16
- expect(res).toEqual(true);
17
- });
18
- });
19
- describe("implicitly checking multiple domains with #check", () => {
20
- test("against the list of domains as JSON", async () => {
21
- const db = await hosting.loadJSON(jsonPath);
22
- const domains = ["google.com", "kochindustries.com"];
23
- const res = await hosting.check(domains, db);
24
- expect(res).toContain("google.com");
25
- });
26
- });
27
- });
@@ -1,58 +0,0 @@
1
- "use strict";
2
- import fs from "fs";
3
- import path from "path";
4
- import pagexray from "pagexray";
5
- import hosting from "./hosting-node.js";
6
- const jsonPath = path.resolve(__dirname, "..", "data", "fixtures", "url2green.test.json");
7
- describe("hosting", () => {
8
- let har;
9
- beforeEach(() => {
10
- har = JSON.parse(fs.readFileSync(path.resolve(__dirname, "../data/fixtures/tgwf.har"), "utf8"));
11
- });
12
- describe("checking all domains on a page object with #checkPage", () => {
13
- it("returns a list of green domains, when passed a page object", async () => {
14
- const pages = pagexray.convert(har);
15
- const pageXrayRun = pages[0];
16
- const db = await hosting.loadJSON(jsonPath);
17
- const greenDomains = await hosting.checkPage(pageXrayRun, db);
18
- expect(greenDomains).toHaveLength(11);
19
- const expectedGreendomains = [
20
- "maxcdn.bootstrapcdn.com",
21
- "thegreenwebfoundation.org",
22
- "www.thegreenwebfoundation.org",
23
- "fonts.googleapis.com",
24
- "ajax.googleapis.com",
25
- "assets.digitalclimatestrike.net",
26
- "cdnjs.cloudflare.com",
27
- "graphite.thegreenwebfoundation.org",
28
- "analytics.thegreenwebfoundation.org",
29
- "fonts.gstatic.com",
30
- "api.thegreenwebfoundation.org"
31
- ];
32
- greenDomains.forEach((dom) => {
33
- expect(expectedGreendomains).toContain(dom);
34
- });
35
- });
36
- });
37
- describe("checking a single domain with #check", () => {
38
- it("use the API instead", async () => {
39
- const db = await hosting.loadJSON(jsonPath);
40
- const res = await hosting.check("google.com", db);
41
- expect(res).toEqual(true);
42
- });
43
- });
44
- describe("implicitly checking multiple domains with #check", () => {
45
- it("Use the API", async () => {
46
- const db = await hosting.loadJSON(jsonPath);
47
- const res = await hosting.check(["google.com", "kochindustries.com"], db);
48
- expect(res).toContain("google.com");
49
- });
50
- });
51
- describe("explicitly checking multiple domains with #checkMulti", () => {
52
- it("use the API", async () => {
53
- const db = await hosting.loadJSON(jsonPath);
54
- const res = await hosting.check(["google.com", "kochindustries.com"], db);
55
- expect(res).toContain("google.com");
56
- });
57
- });
58
- });
@@ -1,68 +0,0 @@
1
- import SustainableWebDesign from "./sustainable-web-design.js";
2
- describe("sustainable web design model", () => {
3
- const swd = new SustainableWebDesign();
4
- const averageWebsiteInBytes = 22577152e-1;
5
- describe("energyPerByteByComponent", () => {
6
- it("should return a object with numbers for each system component", () => {
7
- const groupedEnergy = swd.energyPerByteByComponent(averageWebsiteInBytes);
8
- expect(groupedEnergy.consumerDeviceEnergy).toBeCloseTo(95095e-8, 8);
9
- expect(groupedEnergy.networkEnergy).toBeCloseTo(25602e-8, 7);
10
- expect(groupedEnergy.dataCenterEnergy).toBeCloseTo(27431e-8, 8);
11
- expect(groupedEnergy.productionEnergy).toBeCloseTo(3475e-7, 7);
12
- });
13
- });
14
- describe("energyPerByte", () => {
15
- it("should return a number in kilowatt hours for the given data transfer in bytes", () => {
16
- const energyForTransfer = swd.energyPerByte(averageWebsiteInBytes);
17
- expect(energyForTransfer).toBeCloseTo(182874e-8, 7);
18
- });
19
- });
20
- describe("perByte", () => {
21
- it("should return a single number for CO2 emissions", () => {
22
- expect(typeof swd.perByte(22577152e-1)).toBe("number");
23
- });
24
- });
25
- describe("perVisit", () => {
26
- it("should return a single number for CO2 emissions", () => {
27
- expect(typeof swd.perVisit(22577152e-1)).toBe("number");
28
- });
29
- });
30
- describe("energyPerVisit", () => {
31
- it("should return a number", () => {
32
- expect(typeof swd.energyPerVisit(averageWebsiteInBytes)).toBe("number");
33
- });
34
- it("should calculate the correct energy", () => {
35
- expect(swd.energyPerVisit(averageWebsiteInBytes)).toBe(0.0013807057305600004);
36
- });
37
- });
38
- describe("emissionsPerVisitInGrams", () => {
39
- it("should calculate the correct co2 per visit", () => {
40
- const energy = swd.energyPerVisit(averageWebsiteInBytes);
41
- expect(swd.emissionsPerVisitInGrams(energy)).toEqual(0.61);
42
- });
43
- it("should accept a dynamic KwH value", () => {
44
- const energy = swd.energyPerVisit(averageWebsiteInBytes);
45
- expect(swd.emissionsPerVisitInGrams(energy, 245)).toEqual(0.34);
46
- });
47
- });
48
- describe("annualEnergyInKwh", () => {
49
- it("should calculate the correct energy in kWh", () => {
50
- expect(swd.annualEnergyInKwh(averageWebsiteInBytes)).toBe(27092582400);
51
- });
52
- });
53
- describe("annualEmissionsInGrams", () => {
54
- it("should calculate the corrent energy in grams", () => {
55
- expect(swd.annualEmissionsInGrams(averageWebsiteInBytes)).toBe(27092582400);
56
- });
57
- });
58
- describe("annualSegmentEnergy", () => {
59
- it("should return the correct values", () => {
60
- expect(swd.annualSegmentEnergy(averageWebsiteInBytes)).toEqual({
61
- consumerDeviceEnergy: 11740119e-1,
62
- dataCenterEnergy: 338657.28,
63
- networkEnergy: 316080.13,
64
- productionEnergy: 428965.89
65
- });
66
- });
67
- });
68
- });
package/src/readme.md DELETED
@@ -1,66 +0,0 @@
1
- # How to use the different models in CO2.js
2
-
3
- CO2js offers two models for understanding the environmental impact of compute - the 1byte model (`1byte.js`), and the Sustainable Web Design model (`swd.js`)
4
-
5
- ### The 1byte model
6
-
7
- The default model in use is the 1byte model as used by the Shift Project, as introduced in their report on CO2 emissions from digital infrastructure, [Lean ICT: for a sober digital][soberDigital].
8
-
9
- This returns a number for the estimated CO2 emissions for the corresponding number of bytes sent over the wire, and has been used for video streaming, file downloads and websites.
10
-
11
- ```js
12
- // assume you have imported or required the CO2 class from 1byte.js
13
- // for your runtime - either a browser, nodejs, etc.
14
-
15
- const bytesSent = (1024 * 1024 * 1024)
16
- const co2Emission = new CO2();
17
- const estimatedCO2 = co2Emission.perByte(bytesSent)
18
- ```
19
-
20
-
21
- ### The Sustainable Web Design model
22
-
23
- As of version 0.9, CO2.js also provides the [Sustainable Web Design model][swd] for calculating emissions from digital services. As the name suggests, this has been designed for helping understand the environmental impact of websites. Further details are available on the [Sustainable Web Design website explaining the model](https://sustainablewebdesign.org/calculating-digital-emissions/), but for convenience, a short summary is below.
24
-
25
- #### How the SWD works
26
-
27
- This model uses data transfer as an proxy indicator for total resource usage, and uses this number to extrapolate energy usage numbers for your application as a fraction of the energy used by the total system comprised of:
28
-
29
- 1. the use-phase energy of datacentres serving content
30
- 2. the use-phase energy network transfering the data
31
- 3. the use-phase energy of user device an user is accessing content on
32
- 4. the total embodied energy used to create all of the above
33
-
34
- ![swd model](../images/swd-energy-usage.png)
35
-
36
- It then converts these energy figures to carbon emissions, based on the carbon intensity of electricity from the [Ember annual global electricity review][Ember-annual-global-electricity-review].
37
-
38
- The carbon intensity of electricity figures for the swd model include the the full lifecycle emissions including upstream methane, supply-chain and manufacturing emissions, and include all gases, converted into CO2 equivalent over a 100 year timescale.
39
-
40
- This follows the approach used by the IPCC 5th Assessment Report Annex 3 (2014), for the carbon intensity of electricity.
41
-
42
- [Ember's methodology notes][ember-methodology] detail where the rest of this data comes from in more detail, as well as any further assumptions made.
43
-
44
-
45
- [ember-methodology]: https://ember-climate.org/app/uploads/2022/03/GER22-Methodology.pdf
46
-
47
- [Ember-annual-global-electricity-review]: https://ember-climate.org/insights/research/european-electricity-review-2022/
48
-
49
-
50
-
51
-
52
- ### Sample usage
53
-
54
- ```js
55
- // assume you have imported or required the CO2 class from swd.js
56
- // for your runtime - either a browser, nodejs, etc.
57
-
58
- // assume a 1 megabyte webpage
59
- const bytesSent = (1024 * 1024 * 1024)
60
-
61
- const co2Emission = new CO2();
62
- const estimatedCO2ForTransfer = co2Emission.emissionsPerVisitInGrams(bytesSent)
63
- ```
64
-
65
- [soberDigital]: https://theshiftproject.org/en/lean-ict-2/
66
- [swd]: https://sustainablewebdesign.org/calculating-digital-emissions