@elastic/synthetics 1.0.0-beta.24 → 1.0.0-beta.27

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 (131) hide show
  1. package/README.md +2 -2
  2. package/dist/cli.js +51 -6
  3. package/dist/cli.js.map +1 -1
  4. package/dist/common_types.d.ts +62 -14
  5. package/dist/common_types.d.ts.map +1 -1
  6. package/dist/core/gatherer.d.ts +2 -2
  7. package/dist/core/gatherer.d.ts.map +1 -1
  8. package/dist/core/gatherer.js +16 -7
  9. package/dist/core/gatherer.js.map +1 -1
  10. package/dist/core/index.d.ts +4 -0
  11. package/dist/core/index.d.ts.map +1 -1
  12. package/dist/core/index.js +15 -1
  13. package/dist/core/index.js.map +1 -1
  14. package/dist/core/runner.d.ts +10 -58
  15. package/dist/core/runner.d.ts.map +1 -1
  16. package/dist/core/runner.js +89 -50
  17. package/dist/core/runner.js.map +1 -1
  18. package/dist/dsl/journey.d.ts +3 -0
  19. package/dist/dsl/journey.d.ts.map +1 -1
  20. package/dist/dsl/journey.js +15 -0
  21. package/dist/dsl/journey.js.map +1 -1
  22. package/dist/{reporters/reporter.d.ts → dsl/locations.d.ts} +12 -8
  23. package/dist/dsl/locations.d.ts.map +1 -0
  24. package/dist/dsl/locations.js +41 -0
  25. package/dist/dsl/locations.js.map +1 -0
  26. package/dist/dsl/monitor.d.ts +65 -0
  27. package/dist/dsl/monitor.d.ts.map +1 -0
  28. package/dist/dsl/monitor.js +63 -0
  29. package/dist/dsl/monitor.js.map +1 -0
  30. package/dist/generator/index.d.ts +20 -0
  31. package/dist/generator/index.d.ts.map +1 -0
  32. package/dist/generator/index.js +158 -0
  33. package/dist/generator/index.js.map +1 -0
  34. package/{src/reporters/reporter.ts → dist/generator/utils.d.ts} +4 -11
  35. package/dist/generator/utils.d.ts.map +1 -0
  36. package/dist/generator/utils.js +57 -0
  37. package/dist/generator/utils.js.map +1 -0
  38. package/dist/helpers.d.ts +12 -6
  39. package/dist/helpers.d.ts.map +1 -1
  40. package/dist/helpers.js +33 -43
  41. package/dist/helpers.js.map +1 -1
  42. package/dist/index.d.ts +2 -7
  43. package/dist/index.d.ts.map +1 -1
  44. package/dist/index.js +4 -3
  45. package/dist/index.js.map +1 -1
  46. package/dist/loader.js +4 -4
  47. package/dist/loader.js.map +1 -1
  48. package/dist/options.d.ts +7 -0
  49. package/dist/options.d.ts.map +1 -1
  50. package/dist/options.js +66 -12
  51. package/dist/options.js.map +1 -1
  52. package/dist/plugins/network.d.ts +17 -30
  53. package/dist/plugins/network.d.ts.map +1 -1
  54. package/dist/plugins/network.js +179 -245
  55. package/dist/plugins/network.js.map +1 -1
  56. package/dist/plugins/performance.d.ts +1 -16
  57. package/dist/plugins/performance.d.ts.map +1 -1
  58. package/dist/plugins/performance.js.map +1 -1
  59. package/dist/plugins/plugin-manager.d.ts +2 -2
  60. package/dist/plugins/plugin-manager.d.ts.map +1 -1
  61. package/dist/plugins/plugin-manager.js +2 -2
  62. package/dist/plugins/plugin-manager.js.map +1 -1
  63. package/dist/push/bundler.d.ts +34 -0
  64. package/dist/push/bundler.d.ts.map +1 -0
  65. package/dist/push/bundler.js +119 -0
  66. package/dist/push/bundler.js.map +1 -0
  67. package/dist/{reporters/reporter.js → push/index.d.ts} +4 -3
  68. package/dist/push/index.d.ts.map +1 -0
  69. package/dist/push/index.js +58 -0
  70. package/dist/push/index.js.map +1 -0
  71. package/dist/push/monitor.d.ts +32 -0
  72. package/dist/push/monitor.d.ts.map +1 -0
  73. package/dist/push/monitor.js +62 -0
  74. package/dist/push/monitor.js.map +1 -0
  75. package/dist/push/plugin.d.ts +33 -0
  76. package/dist/push/plugin.d.ts.map +1 -0
  77. package/dist/push/plugin.js +123 -0
  78. package/dist/push/plugin.js.map +1 -0
  79. package/dist/push/request.d.ts +43 -0
  80. package/dist/push/request.d.ts.map +1 -0
  81. package/dist/push/request.js +89 -0
  82. package/dist/push/request.js.map +1 -0
  83. package/dist/reporters/base.d.ts +14 -6
  84. package/dist/reporters/base.d.ts.map +1 -1
  85. package/dist/reporters/base.js +45 -47
  86. package/dist/reporters/base.js.map +1 -1
  87. package/dist/reporters/index.d.ts +18 -8
  88. package/dist/reporters/index.d.ts.map +1 -1
  89. package/dist/reporters/index.js.map +1 -1
  90. package/dist/reporters/json.d.ts +7 -4
  91. package/dist/reporters/json.d.ts.map +1 -1
  92. package/dist/reporters/json.js +119 -137
  93. package/dist/reporters/json.js.map +1 -1
  94. package/dist/reporters/junit.d.ts +7 -1
  95. package/dist/reporters/junit.d.ts.map +1 -1
  96. package/dist/reporters/junit.js +91 -86
  97. package/dist/reporters/junit.js.map +1 -1
  98. package/dist/tsconfig.tsbuildinfo +1 -1
  99. package/package.json +14 -8
  100. package/src/cli.ts +81 -11
  101. package/src/common_types.ts +72 -14
  102. package/src/core/gatherer.ts +20 -12
  103. package/src/core/index.ts +15 -0
  104. package/src/core/runner.ts +87 -114
  105. package/src/dsl/journey.ts +18 -0
  106. package/src/dsl/locations.ts +38 -0
  107. package/src/dsl/monitor.ts +87 -0
  108. package/src/generator/index.ts +201 -0
  109. package/src/generator/utils.ts +54 -0
  110. package/src/helpers.ts +36 -52
  111. package/src/index.ts +9 -1
  112. package/src/loader.ts +4 -4
  113. package/src/options.ts +72 -15
  114. package/src/plugins/network.ts +218 -294
  115. package/src/plugins/performance.ts +1 -17
  116. package/src/plugins/plugin-manager.ts +2 -2
  117. package/src/push/bundler.ts +99 -0
  118. package/src/push/index.ts +63 -0
  119. package/src/push/monitor.ts +68 -0
  120. package/src/push/plugin.ts +113 -0
  121. package/src/push/request.ts +116 -0
  122. package/src/reporters/base.ts +57 -56
  123. package/src/reporters/index.ts +26 -3
  124. package/src/reporters/json.ts +154 -162
  125. package/src/reporters/junit.ts +98 -93
  126. package/templates/journeys/example.journey.ts +18 -0
  127. package/templates/synthetics.config.ts +26 -0
  128. package/CHANGELOG.md +0 -348
  129. package/NOTICE.txt +0 -250
  130. package/dist/reporters/reporter.d.ts.map +0 -1
  131. package/dist/reporters/reporter.js.map +0 -1
package/dist/options.js CHANGED
@@ -27,7 +27,7 @@ var __importDefault = (this && this.__importDefault) || function (mod) {
27
27
  return (mod && mod.__esModule) ? mod : { "default": mod };
28
28
  };
29
29
  Object.defineProperty(exports, "__esModule", { value: true });
30
- exports.normalizeOptions = void 0;
30
+ exports.parseThrottling = exports.normalizeOptions = void 0;
31
31
  const deepmerge_1 = __importDefault(require("deepmerge"));
32
32
  const config_1 = require("./config");
33
33
  const helpers_1 = require("./helpers");
@@ -86,23 +86,77 @@ function normalizeOptions(cliArgs) {
86
86
  const config = cliArgs.config || !cliArgs.inline
87
87
  ? (0, config_1.readConfig)(options.environment, cliArgs.config)
88
88
  : {};
89
+ /**
90
+ * Order of preference for options that are used while running are
91
+ * 1. Local options configured via Runner API
92
+ * 2. CLI flags
93
+ * 3. Configuration file
94
+ */
89
95
  options.params = Object.freeze((0, deepmerge_1.default)(config.params, cliArgs.params || {}));
90
96
  /**
91
- * Favor playwright options passed via cli to inline playwright options
97
+ * Merge playwright options from CLI and Synthetics config
98
+ * and prefer individual options over other option
92
99
  */
93
- options.playwrightOptions = deepmerge_1.default.all([
94
- config.playwrightOptions || {},
95
- cliArgs.playwrightOptions || {},
96
- {
97
- headless: cliArgs.headless,
98
- chromiumSandbox: cliArgs.sandbox,
99
- ignoreHTTPSErrors: cliArgs.ignoreHttpsErrors,
100
- },
101
- ]);
100
+ const playwrightOpts = (0, deepmerge_1.default)(config.playwrightOptions, cliArgs.playwrightOptions || {});
101
+ options.playwrightOptions = {
102
+ ...playwrightOpts,
103
+ headless: cliArgs.headless,
104
+ chromiumSandbox: cliArgs.sandbox ?? playwrightOpts?.chromiumSandbox,
105
+ ignoreHTTPSErrors: cliArgs.ignoreHttpsErrors ?? playwrightOpts?.ignoreHTTPSErrors,
106
+ };
107
+ /**
108
+ * Get the default monitor config from synthetics.config.ts file
109
+ */
110
+ const monitor = config.monitor;
102
111
  if (cliArgs.throttling) {
103
- options.networkConditions = (0, helpers_1.parseNetworkConditions)(cliArgs.throttling);
112
+ const throttleConfig = deepmerge_1.default.all([
113
+ helpers_1.DEFAULT_THROTTLING_OPTIONS,
114
+ monitor?.throttling || {},
115
+ cliArgs.throttling,
116
+ ]);
117
+ options.throttling = throttleConfig;
118
+ options.networkConditions = (0, helpers_1.getNetworkConditions)(throttleConfig);
104
119
  }
120
+ else {
121
+ /**
122
+ * Do not apply throttling when `--no-throttling` flag is passed
123
+ */
124
+ options.throttling = {};
125
+ }
126
+ options.schedule = cliArgs.schedule ?? monitor?.schedule;
127
+ options.locations = cliArgs.locations ?? monitor?.locations;
105
128
  return options;
106
129
  }
107
130
  exports.normalizeOptions = normalizeOptions;
131
+ /**
132
+ * Parses the throttling CLI settings and also
133
+ * adapts to the format to keep the backwards compatability
134
+ * - Accepts old format `<5d/3u/20l>`
135
+ * - Processess new format otherwise `{download: 5, upload: 3, latency: 20}`
136
+ */
137
+ function parseThrottling(value, prev) {
138
+ const THROTTLING_REGEX = /([0-9]{1,}u)|([0-9]{1,}d)|([0-9]{1,}l)/gm;
139
+ if (THROTTLING_REGEX.test(value)) {
140
+ const throttling = {};
141
+ const conditions = value.split('/');
142
+ conditions.forEach(condition => {
143
+ const setting = condition.slice(0, condition.length - 1);
144
+ const token = condition.slice(-1);
145
+ switch (token) {
146
+ case 'd':
147
+ throttling.download = Number(setting);
148
+ break;
149
+ case 'u':
150
+ throttling.upload = Number(setting);
151
+ break;
152
+ case 'l':
153
+ throttling.latency = Number(setting);
154
+ break;
155
+ }
156
+ });
157
+ return throttling;
158
+ }
159
+ return JSON.parse(value || prev);
160
+ }
161
+ exports.parseThrottling = parseThrottling;
108
162
  //# sourceMappingURL=options.js.map
@@ -1 +1 @@
1
- {"version":3,"file":"options.js","sourceRoot":"","sources":["../src/options.ts"],"names":[],"mappings":";AAAA;;;;;;;;;;;;;;;;;;;;;;;GAuBG;;;;;;AAEH,0DAA8B;AAC9B,qCAAsC;AACtC,uCAAmD;AAGnD;;;GAGG;AACH,MAAM,SAAS,GAAG,YAAY,CAAC;AAC/B,IAAI,OAAO,CAAC,GAAG,CAAC,KAAK,IAAI,OAAO,CAAC,GAAG,CAAC,KAAK,CAAC,QAAQ,CAAC,SAAS,CAAC,EAAE;IAC9D,OAAO,CAAC,GAAG,CAAC,KAAK,GAAG,GAAG,CAAC;CACzB;AAED,SAAgB,gBAAgB,CAAC,OAAgB;IAC/C,MAAM,OAAO,GAAe;QAC1B,GAAG,OAAO;QACV,WAAW,EAAE,OAAO,CAAC,GAAG,CAAC,UAAU,CAAC,IAAI,aAAa;KACtD,CAAC;IACF;;;OAGG;IACH,IAAI,OAAO,CAAC,UAAU,EAAE;QACtB,OAAO,CAAC,QAAQ,GAAG,OAAO,CAAC,QAAQ,IAAI,MAAM,CAAC;QAC9C,OAAO,CAAC,QAAQ,GAAG,IAAI,CAAC;QACxB,OAAO,CAAC,OAAO,GAAG,IAAI,CAAC;QACvB,OAAO,CAAC,KAAK,GAAG,IAAI,CAAC;QACrB,OAAO,CAAC,aAAa,GAAG,IAAI,CAAC;KAC9B;IAED,IAAI,OAAO,CAAC,UAAU,EAAE;QACtB,MAAM,qBAAqB,GAAG;YAC5B,OAAO;YACP,SAAS;YACT,YAAY;YACZ,SAAS;YACT,UAAU;SACX,CAAC;QACF;;;;;;WAMG;QACH,KAAK,MAAM,IAAI,IAAI,OAAO,CAAC,UAAU,EAAE;YACrC,IAAI,qBAAqB,CAAC,QAAQ,CAAC,IAAI,CAAC,EAAE;gBACxC,OAAO,CAAC,IAAI,CAAC,GAAG,IAAI,CAAC;aACtB;iBAAM;gBACL,OAAO,CAAC,IAAI,CACV,uBAAuB,IAAI,yCAAyC,qBAAqB,CAAC,IAAI,CAC5F,IAAI,CACL,EAAE,CACJ,CAAC;aACH;SACF;KACF;IAED;;;OAGG;IACH,MAAM,MAAM,GACV,OAAO,CAAC,MAAM,IAAI,CAAC,OAAO,CAAC,MAAM;QAC/B,CAAC,CAAC,IAAA,mBAAU,EAAC,OAAO,CAAC,WAAW,EAAE,OAAO,CAAC,MAAM,CAAC;QACjD,CAAC,CAAC,EAAE,CAAC;IAET,OAAO,CAAC,MAAM,GAAG,MAAM,CAAC,MAAM,CAAC,IAAA,mBAAK,EAAC,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,MAAM,IAAI,EAAE,CAAC,CAAC,CAAC;IAE3E;;OAEG;IACH,OAAO,CAAC,iBAAiB,GAAG,mBAAK,CAAC,GAAG,CAAC;QACpC,MAAM,CAAC,iBAAiB,IAAI,EAAE;QAC9B,OAAO,CAAC,iBAAiB,IAAI,EAAE;QAC/B;YACE,QAAQ,EAAE,OAAO,CAAC,QAAQ;YAC1B,eAAe,EAAE,OAAO,CAAC,OAAO;YAChC,iBAAiB,EAAE,OAAO,CAAC,iBAAiB;SAC7C;KACF,CAAC,CAAC;IAEH,IAAI,OAAO,CAAC,UAAU,EAAE;QACtB,OAAO,CAAC,iBAAiB,GAAG,IAAA,gCAAsB,EAChD,OAAO,CAAC,UAAoB,CAC7B,CAAC;KACH;IAED,OAAO,OAAO,CAAC;AACjB,CAAC;AA5ED,4CA4EC"}
1
+ {"version":3,"file":"options.js","sourceRoot":"","sources":["../src/options.ts"],"names":[],"mappings":";AAAA;;;;;;;;;;;;;;;;;;;;;;;GAuBG;;;;;;AAEH,0DAA8B;AAC9B,qCAAsC;AACtC,uCAA6E;AAG7E;;;GAGG;AACH,MAAM,SAAS,GAAG,YAAY,CAAC;AAC/B,IAAI,OAAO,CAAC,GAAG,CAAC,KAAK,IAAI,OAAO,CAAC,GAAG,CAAC,KAAK,CAAC,QAAQ,CAAC,SAAS,CAAC,EAAE;IAC9D,OAAO,CAAC,GAAG,CAAC,KAAK,GAAG,GAAG,CAAC;CACzB;AAED,SAAgB,gBAAgB,CAAC,OAAgB;IAC/C,MAAM,OAAO,GAAe;QAC1B,GAAG,OAAO;QACV,WAAW,EAAE,OAAO,CAAC,GAAG,CAAC,UAAU,CAAC,IAAI,aAAa;KACtD,CAAC;IACF;;;OAGG;IACH,IAAI,OAAO,CAAC,UAAU,EAAE;QACtB,OAAO,CAAC,QAAQ,GAAG,OAAO,CAAC,QAAQ,IAAI,MAAM,CAAC;QAC9C,OAAO,CAAC,QAAQ,GAAG,IAAI,CAAC;QACxB,OAAO,CAAC,OAAO,GAAG,IAAI,CAAC;QACvB,OAAO,CAAC,KAAK,GAAG,IAAI,CAAC;QACrB,OAAO,CAAC,aAAa,GAAG,IAAI,CAAC;KAC9B;IAED,IAAI,OAAO,CAAC,UAAU,EAAE;QACtB,MAAM,qBAAqB,GAAG;YAC5B,OAAO;YACP,SAAS;YACT,YAAY;YACZ,SAAS;YACT,UAAU;SACX,CAAC;QACF;;;;;;WAMG;QACH,KAAK,MAAM,IAAI,IAAI,OAAO,CAAC,UAAU,EAAE;YACrC,IAAI,qBAAqB,CAAC,QAAQ,CAAC,IAAI,CAAC,EAAE;gBACxC,OAAO,CAAC,IAAI,CAAC,GAAG,IAAI,CAAC;aACtB;iBAAM;gBACL,OAAO,CAAC,IAAI,CACV,uBAAuB,IAAI,yCAAyC,qBAAqB,CAAC,IAAI,CAC5F,IAAI,CACL,EAAE,CACJ,CAAC;aACH;SACF;KACF;IAED;;;OAGG;IACH,MAAM,MAAM,GACV,OAAO,CAAC,MAAM,IAAI,CAAC,OAAO,CAAC,MAAM;QAC/B,CAAC,CAAC,IAAA,mBAAU,EAAC,OAAO,CAAC,WAAW,EAAE,OAAO,CAAC,MAAM,CAAC;QACjD,CAAC,CAAC,EAAE,CAAC;IAET;;;;;OAKG;IACH,OAAO,CAAC,MAAM,GAAG,MAAM,CAAC,MAAM,CAAC,IAAA,mBAAK,EAAC,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,MAAM,IAAI,EAAE,CAAC,CAAC,CAAC;IAE3E;;;OAGG;IACH,MAAM,cAAc,GAAG,IAAA,mBAAK,EAC1B,MAAM,CAAC,iBAAiB,EACxB,OAAO,CAAC,iBAAiB,IAAI,EAAE,CAChC,CAAC;IACF,OAAO,CAAC,iBAAiB,GAAG;QAC1B,GAAG,cAAc;QACjB,QAAQ,EAAE,OAAO,CAAC,QAAQ;QAC1B,eAAe,EAAE,OAAO,CAAC,OAAO,IAAI,cAAc,EAAE,eAAe;QACnE,iBAAiB,EACf,OAAO,CAAC,iBAAiB,IAAI,cAAc,EAAE,iBAAiB;KACjE,CAAC;IAEF;;OAEG;IACH,MAAM,OAAO,GAAG,MAAM,CAAC,OAAO,CAAC;IAC/B,IAAI,OAAO,CAAC,UAAU,EAAE;QACtB,MAAM,cAAc,GAAG,mBAAK,CAAC,GAAG,CAAC;YAC/B,oCAA0B;YAC1B,OAAO,EAAE,UAAU,IAAI,EAAE;YACzB,OAAO,CAAC,UAA+B;SACxC,CAAC,CAAC;QACH,OAAO,CAAC,UAAU,GAAG,cAAc,CAAC;QACpC,OAAO,CAAC,iBAAiB,GAAG,IAAA,8BAAoB,EAAC,cAAc,CAAC,CAAC;KAClE;SAAM;QACL;;WAEG;QACH,OAAO,CAAC,UAAU,GAAG,EAAE,CAAC;KACzB;IAED,OAAO,CAAC,QAAQ,GAAG,OAAO,CAAC,QAAQ,IAAI,OAAO,EAAE,QAAQ,CAAC;IACzD,OAAO,CAAC,SAAS,GAAG,OAAO,CAAC,SAAS,IAAI,OAAO,EAAE,SAAS,CAAC;IAE5D,OAAO,OAAO,CAAC;AACjB,CAAC;AArGD,4CAqGC;AAED;;;;;GAKG;AACH,SAAgB,eAAe,CAAC,KAAa,EAAE,IAAa;IAC1D,MAAM,gBAAgB,GAAG,0CAA0C,CAAC;IACpE,IAAI,gBAAgB,CAAC,IAAI,CAAC,KAAK,CAAC,EAAE;QAChC,MAAM,UAAU,GAAsB,EAAE,CAAC;QACzC,MAAM,UAAU,GAAG,KAAK,CAAC,KAAK,CAAC,GAAG,CAAC,CAAC;QAEpC,UAAU,CAAC,OAAO,CAAC,SAAS,CAAC,EAAE;YAC7B,MAAM,OAAO,GAAG,SAAS,CAAC,KAAK,CAAC,CAAC,EAAE,SAAS,CAAC,MAAM,GAAG,CAAC,CAAC,CAAC;YACzD,MAAM,KAAK,GAAG,SAAS,CAAC,KAAK,CAAC,CAAC,CAAC,CAAC,CAAC;YAClC,QAAQ,KAAK,EAAE;gBACb,KAAK,GAAG;oBACN,UAAU,CAAC,QAAQ,GAAG,MAAM,CAAC,OAAO,CAAC,CAAC;oBACtC,MAAM;gBACR,KAAK,GAAG;oBACN,UAAU,CAAC,MAAM,GAAG,MAAM,CAAC,OAAO,CAAC,CAAC;oBACpC,MAAM;gBACR,KAAK,GAAG;oBACN,UAAU,CAAC,OAAO,GAAG,MAAM,CAAC,OAAO,CAAC,CAAC;oBACrC,MAAM;aACT;QACH,CAAC,CAAC,CAAC;QACH,OAAO,UAAU,CAAC;KACnB;IACD,OAAO,IAAI,CAAC,KAAK,CAAC,KAAK,IAAI,IAAI,CAAC,CAAC;AACnC,CAAC;AAxBD,0CAwBC"}
@@ -22,45 +22,32 @@
22
22
  * THE SOFTWARE.
23
23
  *
24
24
  */
25
- import { Protocol } from 'playwright-core/types/protocol';
26
25
  import { NetworkInfo, Driver } from '../common_types';
27
26
  import { Step } from '../dsl';
27
+ /**
28
+ * Used as a key in each Network Request to identify the
29
+ * associated request across distinct lifecycle events
30
+ */
31
+ export declare const NETWORK_ENTRY_SUMBOL: unique symbol;
28
32
  export declare class NetworkManager {
29
33
  private driver;
30
34
  private _browser;
31
- private _InflightRequestMap;
35
+ private _barrierPromises;
32
36
  results: Array<NetworkInfo>;
33
37
  _currentStep: Partial<Step>;
34
38
  constructor(driver: Driver);
35
- start(): Promise<void>;
36
- _findNetworkRecord(requestId: string): NetworkInfo;
37
- _onRequestWillBeSent(event: Protocol.Network.requestWillBeSentPayload): void;
38
- _onRequestWillBeSentExtraInfo(event: Protocol.Network.requestWillBeSentExtraInfoPayload): void;
39
- _onDataReceived(event: Protocol.Network.dataReceivedPayload): void;
40
- _onResponseReceived(event: Protocol.Network.responseReceivedPayload): void;
41
- _onLoadingFinished(event: Protocol.Network.loadingFinishedPayload): void;
42
- _onLoadingFailed(event: Protocol.Network.loadingFailedPayload): void;
43
- _requestCompleted(requestId: string, endTime: number, encodedDataLength?: number): void;
44
39
  /**
45
- * Account for missing response received event and also adjust the
46
- * response received event based on when first byte event was recorded
40
+ * Adds a protection barrier aganist all asynchronous extract operations from
41
+ * request/response object that are happening during page lifecycle, If the
42
+ * page is closed during the extraction, the barrier enforces those operations
43
+ * to not result in exception
47
44
  */
48
- stop(): NetworkInfo[];
45
+ private _addBarrier;
46
+ start(): Promise<void>;
47
+ private _findNetworkEntry;
48
+ private _onRequest;
49
+ private _onResponse;
50
+ private _onRequestCompleted;
51
+ stop(): Promise<NetworkInfo[]>;
49
52
  }
50
- /**
51
- * The timing calculations are based on the chrome devtools frontend
52
- * https://github.com/ChromeDevTools/devtools-frontend/blob/7f5478d8ceb7586f23f4073ab5c2085dac1ec26a/front_end/network/RequestTimingView.js#L98-L193
53
- */
54
- export declare function calculateTimings(record: NetworkInfo): {
55
- blocked: number;
56
- queueing: number;
57
- dns: number;
58
- ssl: number;
59
- proxy: number;
60
- connect: number;
61
- send: number;
62
- wait: number;
63
- receive: number;
64
- total: number;
65
- };
66
53
  //# sourceMappingURL=network.d.ts.map
@@ -1 +1 @@
1
- {"version":3,"file":"network.d.ts","sourceRoot":"","sources":["../../src/plugins/network.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;;;;;;;;;GAuBG;AAEH,OAAO,EAAE,QAAQ,EAAE,MAAM,gCAAgC,CAAC;AAC1D,OAAO,EAAE,WAAW,EAAe,MAAM,EAAE,MAAM,iBAAiB,CAAC;AACnE,OAAO,EAAE,IAAI,EAAE,MAAM,QAAQ,CAAC;AAG9B,qBAAa,cAAc;IAMb,OAAO,CAAC,MAAM;IAL1B,OAAO,CAAC,QAAQ,CAAc;IAC9B,OAAO,CAAC,mBAAmB,CAAkC;IAC7D,OAAO,EAAE,KAAK,CAAC,WAAW,CAAC,CAAM;IACjC,YAAY,EAAE,OAAO,CAAC,IAAI,CAAC,CAAQ;gBAEf,MAAM,EAAE,MAAM;IAE5B,KAAK;IAuBX,kBAAkB,CAAC,SAAS,EAAE,MAAM;IAIpC,oBAAoB,CAAC,KAAK,EAAE,QAAQ,CAAC,OAAO,CAAC,wBAAwB;IA+ErE,6BAA6B,CAC3B,KAAK,EAAE,QAAQ,CAAC,OAAO,CAAC,iCAAiC;IAiB3D,eAAe,CAAC,KAAK,EAAE,QAAQ,CAAC,OAAO,CAAC,mBAAmB;IAU3D,mBAAmB,CAAC,KAAK,EAAE,QAAQ,CAAC,OAAO,CAAC,uBAAuB;IAiCnE,kBAAkB,CAAC,KAAK,EAAE,QAAQ,CAAC,OAAO,CAAC,sBAAsB;IAKjE,gBAAgB,CAAC,KAAK,EAAE,QAAQ,CAAC,OAAO,CAAC,oBAAoB;IAK7D,iBAAiB,CACf,SAAS,EAAE,MAAM,EACjB,OAAO,EAAE,MAAM,EACf,iBAAiB,CAAC,EAAE,MAAM;IAsB5B;;;OAGG;IAEH,IAAI;CAGL;AAoBD;;;GAGG;AACH,wBAAgB,gBAAgB,CAAC,MAAM,EAAE,WAAW;;;;;;;;;;;EA6GnD"}
1
+ {"version":3,"file":"network.d.ts","sourceRoot":"","sources":["../../src/plugins/network.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;;;;;;;;;GAuBG;AAGH,OAAO,EAAE,WAAW,EAAe,MAAM,EAAE,MAAM,iBAAiB,CAAC;AACnE,OAAO,EAAE,IAAI,EAAE,MAAM,QAAQ,CAAC;AAY9B;;;GAGG;AACH,eAAO,MAAM,oBAAoB,eAA6B,CAAC;AAM/D,qBAAa,cAAc;IAMb,OAAO,CAAC,MAAM;IAL1B,OAAO,CAAC,QAAQ,CAAc;IAC9B,OAAO,CAAC,gBAAgB,CAA4B;IACpD,OAAO,EAAE,KAAK,CAAC,WAAW,CAAC,CAAM;IACjC,YAAY,EAAE,OAAO,CAAC,IAAI,CAAC,CAAQ;gBAEf,MAAM,EAAE,MAAM;IAElC;;;;;OAKG;IACH,OAAO,CAAC,WAAW;IAeb,KAAK;IAeX,OAAO,CAAC,iBAAiB;IAMzB,OAAO,CAAC,UAAU;YAgDJ,WAAW;YAgDX,mBAAmB;IAoG3B,IAAI;CAUX"}
@@ -24,300 +24,234 @@
24
24
  *
25
25
  */
26
26
  Object.defineProperty(exports, "__esModule", { value: true });
27
- exports.calculateTimings = exports.NetworkManager = void 0;
27
+ exports.NetworkManager = exports.NETWORK_ENTRY_SUMBOL = void 0;
28
28
  const helpers_1 = require("../helpers");
29
+ /**
30
+ * Kibana UI expects the requestStartTime and loadEndTime to be baseline
31
+ * in seconds as they have the logic to convert it to milliseconds before
32
+ * using for offset calculation
33
+ */
34
+ function epochTimeInSeconds() {
35
+ return (0, helpers_1.getTimestamp)() / 1e6;
36
+ }
37
+ /**
38
+ * Used as a key in each Network Request to identify the
39
+ * associated request across distinct lifecycle events
40
+ */
41
+ exports.NETWORK_ENTRY_SUMBOL = Symbol.for('NetworkEntry');
29
42
  class NetworkManager {
30
43
  constructor(driver) {
31
44
  this.driver = driver;
32
- this._InflightRequestMap = new Map();
45
+ this._barrierPromises = new Set();
33
46
  this.results = [];
34
47
  this._currentStep = null;
35
48
  }
49
+ /**
50
+ * Adds a protection barrier aganist all asynchronous extract operations from
51
+ * request/response object that are happening during page lifecycle, If the
52
+ * page is closed during the extraction, the barrier enforces those operations
53
+ * to not result in exception
54
+ */
55
+ _addBarrier(page, promise) {
56
+ if (!page)
57
+ return;
58
+ const race = Promise.race([
59
+ new Promise(resolve => page.on('close', () => {
60
+ this._barrierPromises.delete(race);
61
+ resolve();
62
+ })),
63
+ promise,
64
+ ]);
65
+ this._barrierPromises.add(race);
66
+ race.then(() => this._barrierPromises.delete(race));
67
+ }
36
68
  async start() {
37
- const { client } = this.driver;
69
+ const { client, context } = this.driver;
38
70
  const { product } = await client.send('Browser.getVersion');
39
71
  const [name, version] = product.split('/');
40
72
  this._browser = { name, version };
41
73
  await client.send('Network.enable');
42
74
  /**
43
- * Listen for all network events
75
+ * Listen for all network events from PW context
44
76
  */
45
- client.on('Network.requestWillBeSent', this._onRequestWillBeSent.bind(this));
46
- client.on('Network.requestWillBeSentExtraInfo', this._onRequestWillBeSentExtraInfo.bind(this));
47
- client.on('Network.dataReceived', this._onDataReceived.bind(this));
48
- client.on('Network.responseReceived', this._onResponseReceived.bind(this));
49
- client.on('Network.loadingFinished', this._onLoadingFinished.bind(this));
50
- client.on('Network.loadingFailed', this._onLoadingFailed.bind(this));
77
+ context.on('request', this._onRequest.bind(this));
78
+ context.on('response', this._onResponse.bind(this));
79
+ context.on('requestfinished', this._onRequestCompleted.bind(this));
80
+ context.on('requestfailed', this._onRequestCompleted.bind(this));
51
81
  }
52
- _findNetworkRecord(requestId) {
53
- return this._InflightRequestMap.get(requestId);
82
+ _findNetworkEntry(request) {
83
+ return request[exports.NETWORK_ENTRY_SUMBOL];
54
84
  }
55
- _onRequestWillBeSent(event) {
56
- const { url, method, postData, headers } = event.request;
85
+ _onRequest(request) {
86
+ const url = request.url();
57
87
  /**
58
88
  * Data URI should not show up as network requests
59
89
  */
60
90
  if (url.startsWith('data:')) {
61
91
  return;
62
92
  }
63
- const { requestId, timestamp, type, loaderId } = event;
64
- const isNavigationRequest = requestId == loaderId && type === 'Document';
65
- const record = this._findNetworkRecord(requestId);
66
- /**
67
- * On redirects, another `requestWillBeSent` event will be fired for the
68
- * same requestId. We calculate the timings for the redirect request using
69
- * the `redirectedResponse` from the redirected request.
70
- */
71
- if (record) {
72
- if (event.redirectResponse) {
73
- record.response.redirectURL = url;
74
- const response = event.redirectResponse;
75
- const data = Object.assign(event, {
76
- type: event.type,
77
- response,
78
- encodedDataLength: response.encodedDataLength,
79
- hasExtraInfo: false,
80
- });
81
- this._onResponseReceived(data);
82
- this._onLoadingFinished(data);
83
- }
84
- else {
85
- /**
86
- * Edge case, we handle it to proceed with next navigation
87
- */
88
- this._onLoadingFailed(Object.assign(event, {
89
- type: event.type,
90
- errorText: 'redirectResponse data is not available',
91
- }));
92
- }
93
- const redirectedRecord = this._findNetworkRecord(requestId);
94
- /**
95
- * Rewrite the map with new redirect id to not reset
96
- * the redirect request with original request
97
- */
98
- this._InflightRequestMap.delete(requestId);
99
- this._InflightRequestMap.set(`redirect:${timestamp}:${requestId}`, redirectedRecord);
100
- }
101
- this._InflightRequestMap.set(requestId, {
93
+ const timestamp = (0, helpers_1.getTimestamp)();
94
+ const networkEntry = {
102
95
  browser: this._browser,
103
96
  step: this._currentStep,
104
- timestamp: (0, helpers_1.getTimestamp)(),
97
+ timestamp,
105
98
  url,
106
- type,
99
+ type: request.resourceType(),
107
100
  request: {
108
101
  url,
109
- method,
110
- headers,
111
- bytes: postData?.length || 0,
102
+ method: request.method(),
103
+ headers: {},
104
+ body: {
105
+ bytes: request.postDataBuffer()?.length || 0,
106
+ },
112
107
  },
113
108
  response: {
114
109
  status: -1,
115
- mimeType: 'x-unknown',
116
110
  headers: {},
117
- timing: null,
111
+ mimeType: 'x-unknown',
112
+ redirectURL: '',
118
113
  },
119
- isNavigationRequest,
120
- requestSentTime: timestamp,
121
- responseReceivedTime: -1,
114
+ isNavigationRequest: request.isNavigationRequest(),
115
+ requestSentTime: epochTimeInSeconds(),
122
116
  loadEndTime: -1,
117
+ responseReceivedTime: -1,
123
118
  resourceSize: 0,
124
119
  transferSize: 0,
125
120
  timings: null,
126
- });
121
+ };
122
+ if (request.redirectedFrom()) {
123
+ const fromEntry = this._findNetworkEntry(request.redirectedFrom());
124
+ if (fromEntry)
125
+ fromEntry.response.redirectURL = request.url();
126
+ }
127
+ request[exports.NETWORK_ENTRY_SUMBOL] = networkEntry;
128
+ this.results.push(networkEntry);
127
129
  }
128
- _onRequestWillBeSentExtraInfo(event) {
129
- const { requestId, headers } = event;
130
- const record = this._findNetworkRecord(requestId);
131
- if (!record) {
130
+ async _onResponse(response) {
131
+ const request = response.request();
132
+ const networkEntry = this._findNetworkEntry(request);
133
+ if (!networkEntry)
132
134
  return;
133
- }
134
- /**
135
- * Enhance request headers with additional information
136
- */
137
- record.request.headers = {
138
- ...record.request.headers,
139
- ...headers,
135
+ networkEntry.responseReceivedTime = epochTimeInSeconds();
136
+ networkEntry.response = {
137
+ url: response.url(),
138
+ status: response.status(),
139
+ statusText: response.statusText(),
140
+ headers: {},
141
+ mimeType: 'x-unknown',
142
+ redirectURL: networkEntry.response.redirectURL,
140
143
  };
141
- record.request.referrer = record.request.headers?.Referer;
144
+ const page = request.frame().page();
145
+ this._addBarrier(page, request.allHeaders().then(reqHeaders => {
146
+ networkEntry.request.headers = reqHeaders;
147
+ networkEntry.request.referrer = reqHeaders?.referer;
148
+ }));
149
+ this._addBarrier(page, response.serverAddr().then(server => {
150
+ networkEntry.response.remoteIPAddress = server?.ipAddress;
151
+ networkEntry.response.remotePort = server?.port;
152
+ }));
153
+ this._addBarrier(page, response.securityDetails().then(details => {
154
+ if (details)
155
+ networkEntry.response.securityDetails = details;
156
+ }));
157
+ this._addBarrier(page, response.allHeaders().then(resHeaders => {
158
+ networkEntry.response.headers = resHeaders;
159
+ const contentType = resHeaders['content-type'];
160
+ if (contentType)
161
+ networkEntry.response.mimeType = contentType.split(';')[0];
162
+ }));
142
163
  }
143
- _onDataReceived(event) {
144
- const { requestId, dataLength, encodedDataLength } = event;
145
- const record = this._findNetworkRecord(requestId);
146
- if (!record) {
164
+ async _onRequestCompleted(request) {
165
+ const networkEntry = this._findNetworkEntry(request);
166
+ if (!networkEntry)
147
167
  return;
148
- }
149
- record.resourceSize += dataLength;
150
- if (encodedDataLength >= 0)
151
- record.transferSize += encodedDataLength;
152
- }
153
- _onResponseReceived(event) {
154
- const { requestId, response, timestamp } = event;
155
- const record = this._findNetworkRecord(requestId);
156
- if (!record) {
168
+ networkEntry.loadEndTime = epochTimeInSeconds();
169
+ const timing = request.timing();
170
+ const { loadEndTime, requestSentTime } = networkEntry;
171
+ networkEntry.timings = {
172
+ blocked: -1,
173
+ dns: -1,
174
+ ssl: -1,
175
+ connect: -1,
176
+ send: -1,
177
+ wait: -1,
178
+ receive: -1,
179
+ total: -1,
180
+ };
181
+ const firstPositive = (numbers) => {
182
+ for (let i = 0; i < numbers.length; ++i) {
183
+ if (numbers[i] > 0) {
184
+ return numbers[i];
185
+ }
186
+ }
187
+ return null;
188
+ };
189
+ const roundMilliSecs = (value) => {
190
+ return Math.floor(value * 1000) / 1000;
191
+ };
192
+ if (timing.startTime === 0) {
193
+ // Convert to milliseconds before round off
194
+ const total = roundMilliSecs((loadEndTime - requestSentTime) * 1000);
195
+ networkEntry.timings.total = total;
157
196
  return;
158
197
  }
159
- record.responseReceivedTime = timestamp;
160
- record.transferSize = response.encodedDataLength;
161
- record.response = {
162
- url: response.url,
163
- status: response.status,
164
- protocol: response.protocol,
165
- statusText: response.statusText,
166
- headers: response.headers,
167
- mimeType: response.mimeType,
168
- remoteIPAddress: response.remoteIPAddress,
169
- remotePort: response.remotePort,
170
- fromServiceWorker: response.fromServiceWorker,
171
- redirectURL: record.response.redirectURL,
172
- timing: response.timing,
198
+ const blocked = roundMilliSecs(firstPositive([
199
+ timing.domainLookupStart,
200
+ timing.connectStart,
201
+ timing.requestStart,
202
+ ])) || -1;
203
+ const dns = timing.domainLookupEnd !== -1
204
+ ? roundMilliSecs(timing.domainLookupEnd - timing.domainLookupStart)
205
+ : -1;
206
+ const connect = timing.connectEnd !== -1
207
+ ? roundMilliSecs(timing.connectEnd - timing.connectStart)
208
+ : -1;
209
+ const ssl = timing.secureConnectionStart !== -1
210
+ ? roundMilliSecs(timing.connectEnd - timing.secureConnectionStart)
211
+ : -1;
212
+ const wait = timing.responseStart !== -1
213
+ ? roundMilliSecs(timing.responseStart - timing.requestStart)
214
+ : -1;
215
+ const receive = timing.responseEnd !== -1
216
+ ? roundMilliSecs(timing.responseEnd - timing.responseStart)
217
+ : -1;
218
+ const total = [blocked, dns, connect, wait, receive].reduce((pre, cur) => (cur > 0 ? cur + pre : pre), 0);
219
+ networkEntry.timings = {
220
+ blocked,
221
+ dns,
222
+ connect,
223
+ ssl,
224
+ wait,
225
+ send: 0,
226
+ receive,
227
+ total,
173
228
  };
174
- if (response.securityDetails) {
175
- record.response.securityDetails = {
176
- protocol: response.securityDetails.protocol,
177
- subjectName: response.securityDetails.subjectName,
178
- issuer: response.securityDetails.issuer,
179
- validFrom: response.securityDetails.validFrom,
180
- validTo: response.securityDetails.validTo,
229
+ const page = request.frame().page();
230
+ // For aborted/failed requests sizes will not be present
231
+ this._addBarrier(page, request.sizes().then(sizes => {
232
+ networkEntry.request.bytes =
233
+ sizes.requestHeadersSize + sizes.requestBodySize;
234
+ networkEntry.request.body = {
235
+ bytes: sizes.requestBodySize,
181
236
  };
182
- }
183
- }
184
- _onLoadingFinished(event) {
185
- const { requestId, timestamp, encodedDataLength } = event;
186
- this._requestCompleted(requestId, timestamp, encodedDataLength);
187
- }
188
- _onLoadingFailed(event) {
189
- const { requestId, timestamp } = event;
190
- this._requestCompleted(requestId, timestamp);
191
- }
192
- _requestCompleted(requestId, endTime, encodedDataLength) {
193
- const record = this._findNetworkRecord(requestId);
194
- if (!record) {
195
- return;
196
- }
197
- if (encodedDataLength >= 0) {
198
- record.transferSize = encodedDataLength;
199
- record.response.body = {
200
- bytes: encodedDataLength,
237
+ networkEntry.response.bytes =
238
+ sizes.responseHeadersSize + sizes.responseBodySize;
239
+ networkEntry.response.body = {
240
+ bytes: sizes.responseBodySize,
201
241
  };
202
- }
203
- record.loadEndTime = endTime;
204
- record.timings = calculateTimings(record);
205
- this.results.push(record);
206
- /**
207
- * When there is DNS failure, browsers keeps retrying requests which
208
- * might result in incorrect timings so we get remove them to measure only once
209
- */
210
- this._InflightRequestMap.delete(requestId);
242
+ networkEntry.transferSize = sizes.responseBodySize;
243
+ }));
211
244
  }
212
- /**
213
- * Account for missing response received event and also adjust the
214
- * response received event based on when first byte event was recorded
215
- */
216
- stop() {
245
+ async stop() {
246
+ await Promise.all(this._barrierPromises);
247
+ const context = this.driver.context;
248
+ context.off('request', this._onRequest.bind(this));
249
+ context.off('response', this._onResponse.bind(this));
250
+ context.off('requestfinished', this._onRequestCompleted.bind(this));
251
+ context.off('requestfailed', this._onRequestCompleted.bind(this));
252
+ this._barrierPromises.clear();
217
253
  return this.results;
218
254
  }
219
255
  }
220
256
  exports.NetworkManager = NetworkManager;
221
- function getResponseReceivedTime(timing, responseReceivedTime) {
222
- if (timing == null) {
223
- return responseReceivedTime;
224
- }
225
- const startTime = timing.requestTime;
226
- const headersReceivedTime = startTime + timing.receiveHeadersEnd / 1000;
227
- if (responseReceivedTime < 0 || responseReceivedTime > headersReceivedTime) {
228
- responseReceivedTime = headersReceivedTime;
229
- }
230
- if (startTime > responseReceivedTime) {
231
- responseReceivedTime = startTime;
232
- }
233
- return responseReceivedTime;
234
- }
235
- /**
236
- * The timing calculations are based on the chrome devtools frontend
237
- * https://github.com/ChromeDevTools/devtools-frontend/blob/7f5478d8ceb7586f23f4073ab5c2085dac1ec26a/front_end/network/RequestTimingView.js#L98-L193
238
- */
239
- function calculateTimings(record) {
240
- const result = {
241
- blocked: -1,
242
- queueing: -1,
243
- proxy: -1,
244
- dns: -1,
245
- ssl: -1,
246
- connect: -1,
247
- send: -1,
248
- wait: -1,
249
- receive: -1,
250
- total: -1,
251
- };
252
- const toMilliseconds = (time) => (time === -1 ? -1 : time * 1000);
253
- const calculateDiffInMs = (name, start, end) => {
254
- if (start < Number.MAX_VALUE && start <= end) {
255
- result[name] = toMilliseconds(end - start);
256
- }
257
- };
258
- const firstPositive = (numbers) => {
259
- for (let i = 0; i < numbers.length; ++i) {
260
- if (numbers[i] > 0) {
261
- return numbers[i];
262
- }
263
- }
264
- return null;
265
- };
266
- /**
267
- * requestTime is baseline in seconds, rest of the timing data are ticks in milliseconds
268
- * from the requestTime, so we calculate the offset from that
269
- */
270
- const addOffsetRange = (name, start, end) => {
271
- if (start >= 0 && end >= 0) {
272
- calculateDiffInMs(name, startTime + start / 1000, startTime + end / 1000);
273
- }
274
- };
275
- const { requestSentTime, loadEndTime, responseReceivedTime, response } = record;
276
- const timing = response.timing;
277
- const actResRcvdTime = getResponseReceivedTime(timing, responseReceivedTime);
278
- const issueTime = requestSentTime;
279
- const startTime = timing == null ? -1 : timing.requestTime;
280
- const endTime = firstPositive([loadEndTime, actResRcvdTime]) || startTime;
281
- if (timing == null) {
282
- const start = issueTime !== -1 ? issueTime : startTime !== -1 ? startTime : 0;
283
- const middle = actResRcvdTime === -1 ? Number.MAX_VALUE : actResRcvdTime;
284
- const end = endTime === -1 ? Number.MAX_VALUE : endTime;
285
- calculateDiffInMs('total', start, end);
286
- calculateDiffInMs('blocked', start, middle);
287
- calculateDiffInMs('receive', middle, end);
288
- // Check if the request is blocked/stalled for the whole timeframe and
289
- // calculate timings appropriately for that request
290
- if (!isFinite(result['blocked'])) {
291
- result['blocked'] = result['total'];
292
- }
293
- return result;
294
- }
295
- calculateDiffInMs('total', issueTime < startTime ? issueTime : startTime, endTime);
296
- if (issueTime < startTime) {
297
- calculateDiffInMs('queueing', issueTime, startTime);
298
- }
299
- const responseReceived = toMilliseconds(actResRcvdTime - startTime);
300
- if (response.fromServiceWorker) {
301
- addOffsetRange('blocked', 0, timing.workerStart);
302
- addOffsetRange('wait', timing.sendEnd, responseReceived);
303
- }
304
- else if (!timing.pushStart) {
305
- const blockingEnd = firstPositive([
306
- timing.dnsStart,
307
- timing.connectStart,
308
- timing.sendStart,
309
- responseReceived,
310
- ]) || 0;
311
- addOffsetRange('blocked', 0, blockingEnd);
312
- addOffsetRange('proxy', timing.proxyStart, timing.proxyEnd);
313
- addOffsetRange('dns', timing.dnsStart, timing.dnsEnd);
314
- addOffsetRange('connect', timing.connectStart, timing.connectEnd);
315
- addOffsetRange('ssl', timing.sslStart, timing.sslEnd);
316
- addOffsetRange('send', timing.sendStart, timing.sendEnd);
317
- addOffsetRange('wait', Math.max(timing.sendEnd, timing.connectEnd, timing.dnsEnd, timing.proxyEnd, blockingEnd), responseReceived);
318
- }
319
- calculateDiffInMs('receive', actResRcvdTime, endTime);
320
- return result;
321
- }
322
- exports.calculateTimings = calculateTimings;
323
257
  //# sourceMappingURL=network.js.map