@paulirish/trace_engine 0.0.49 → 0.0.51

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 (225) hide show
  1. package/.tmp/tsbuildinfo/tsconfig.tsbuildinfo +1 -1
  2. package/core/platform/Constructor.d.ts +2 -2
  3. package/core/platform/Constructor.js.map +1 -1
  4. package/core/platform/StringUtilities.d.ts +2 -5
  5. package/core/platform/StringUtilities.js +0 -3
  6. package/core/platform/StringUtilities.js.map +1 -1
  7. package/core/platform/TypescriptUtilities.d.ts +1 -1
  8. package/core/platform/TypescriptUtilities.js +1 -1
  9. package/core/platform/TypescriptUtilities.js.map +1 -1
  10. package/core/platform/devtools_entrypoint-bundle-typescript-tsconfig.json +2 -2
  11. package/core/platform/platform-tsconfig.json +2 -3
  12. package/core/platform/platform.d.ts +1 -2
  13. package/core/platform/platform.js +1 -2
  14. package/core/platform/platform.js.map +1 -1
  15. package/generated/protocol.d.ts +156 -31
  16. package/locales/af.json +63 -3
  17. package/locales/am.json +63 -3
  18. package/locales/ar.json +63 -3
  19. package/locales/as.json +63 -3
  20. package/locales/az.json +63 -3
  21. package/locales/be.json +64 -4
  22. package/locales/bg.json +62 -2
  23. package/locales/bn.json +63 -3
  24. package/locales/bs.json +63 -3
  25. package/locales/ca.json +62 -2
  26. package/locales/cs.json +62 -2
  27. package/locales/cy.json +63 -3
  28. package/locales/da.json +63 -3
  29. package/locales/de.json +63 -3
  30. package/locales/el.json +62 -2
  31. package/locales/en-GB.json +63 -3
  32. package/locales/en-US.json +55 -22
  33. package/locales/en-XL.json +55 -22
  34. package/locales/es-419.json +63 -3
  35. package/locales/es.json +64 -4
  36. package/locales/et.json +64 -4
  37. package/locales/eu.json +79 -19
  38. package/locales/fa.json +62 -2
  39. package/locales/fi.json +63 -3
  40. package/locales/fil.json +63 -3
  41. package/locales/fr-CA.json +63 -3
  42. package/locales/fr.json +63 -3
  43. package/locales/gl.json +62 -2
  44. package/locales/gu.json +63 -3
  45. package/locales/he.json +63 -3
  46. package/locales/hi.json +62 -2
  47. package/locales/hr.json +63 -3
  48. package/locales/hu.json +62 -2
  49. package/locales/hy.json +63 -3
  50. package/locales/id.json +62 -2
  51. package/locales/is.json +64 -4
  52. package/locales/it.json +64 -4
  53. package/locales/ja.json +63 -3
  54. package/locales/ka.json +63 -3
  55. package/locales/kk.json +62 -2
  56. package/locales/km.json +62 -2
  57. package/locales/kn.json +63 -3
  58. package/locales/ko.json +63 -3
  59. package/locales/ky.json +63 -3
  60. package/locales/lo.json +63 -3
  61. package/locales/lt.json +62 -2
  62. package/locales/lv.json +62 -2
  63. package/locales/mk.json +62 -2
  64. package/locales/ml.json +63 -3
  65. package/locales/mn.json +63 -3
  66. package/locales/mr.json +64 -4
  67. package/locales/ms.json +63 -3
  68. package/locales/my.json +63 -3
  69. package/locales/ne.json +64 -4
  70. package/locales/nl.json +63 -3
  71. package/locales/no.json +62 -2
  72. package/locales/or.json +63 -3
  73. package/locales/pa.json +62 -2
  74. package/locales/pl.json +62 -2
  75. package/locales/pt-PT.json +62 -2
  76. package/locales/pt.json +63 -3
  77. package/locales/ro.json +63 -3
  78. package/locales/ru.json +63 -3
  79. package/locales/si.json +63 -3
  80. package/locales/sk.json +63 -3
  81. package/locales/sl.json +62 -2
  82. package/locales/sq.json +63 -3
  83. package/locales/sr-Latn.json +62 -2
  84. package/locales/sr.json +62 -2
  85. package/locales/sv.json +62 -2
  86. package/locales/sw.json +63 -3
  87. package/locales/ta.json +66 -6
  88. package/locales/te.json +63 -3
  89. package/locales/th.json +63 -3
  90. package/locales/tr.json +63 -3
  91. package/locales/uk.json +63 -3
  92. package/locales/ur.json +64 -4
  93. package/locales/uz.json +62 -2
  94. package/locales/vi.json +62 -2
  95. package/locales/zh-HK.json +63 -3
  96. package/locales/zh-TW.json +63 -3
  97. package/locales/zh.json +62 -2
  98. package/locales/zu.json +63 -3
  99. package/models/cpu_profile/CPUProfileDataModel.d.ts +8 -0
  100. package/models/cpu_profile/CPUProfileDataModel.js.map +1 -1
  101. package/models/cpu_profile/cpu_profile-tsconfig.json +2 -2
  102. package/models/cpu_profile/devtools_entrypoint-bundle-typescript-tsconfig.json +2 -2
  103. package/models/trace/Processor.d.ts +1 -1
  104. package/models/trace/Processor.js +94 -74
  105. package/models/trace/Processor.js.map +1 -1
  106. package/models/trace/TracingManager.js.map +1 -1
  107. package/models/trace/bundle-tsconfig.json +1 -1
  108. package/models/trace/devtools_entrypoint-bundle-typescript-tsconfig.json +20 -2
  109. package/models/trace/extras/ScriptDuplication.d.ts +11 -15
  110. package/models/trace/extras/ScriptDuplication.js +59 -77
  111. package/models/trace/extras/ScriptDuplication.js.map +1 -1
  112. package/models/trace/extras/ThirdParties.d.ts +6 -13
  113. package/models/trace/extras/ThirdParties.js +69 -133
  114. package/models/trace/extras/ThirdParties.js.map +1 -1
  115. package/models/trace/extras/TraceTree.d.ts +15 -3
  116. package/models/trace/extras/TraceTree.js +36 -8
  117. package/models/trace/extras/TraceTree.js.map +1 -1
  118. package/models/trace/extras/devtools_entrypoint-bundle-typescript-tsconfig.json +2 -2
  119. package/models/trace/extras/extras-tsconfig.json +2 -2
  120. package/models/trace/extras/extras.d.ts +881 -787
  121. package/models/trace/extras/extras.js +881 -787
  122. package/models/trace/handlers/AsyncJSCallsHandler.js +36 -4
  123. package/models/trace/handlers/AsyncJSCallsHandler.js.map +1 -1
  124. package/models/trace/handlers/InvalidationsHandler.js +1 -0
  125. package/models/trace/handlers/InvalidationsHandler.js.map +1 -1
  126. package/models/trace/handlers/ModelHandlers.d.ts +0 -1
  127. package/models/trace/handlers/ModelHandlers.js +0 -1
  128. package/models/trace/handlers/ModelHandlers.js.map +1 -1
  129. package/models/trace/handlers/NetworkRequestsHandler.js +1 -1
  130. package/models/trace/handlers/NetworkRequestsHandler.js.map +1 -1
  131. package/models/trace/handlers/RendererHandler.d.ts +1 -1
  132. package/models/trace/handlers/RendererHandler.js +2 -2
  133. package/models/trace/handlers/RendererHandler.js.map +1 -1
  134. package/models/trace/handlers/ScreenshotsHandler.js +3 -1
  135. package/models/trace/handlers/ScreenshotsHandler.js.map +1 -1
  136. package/models/trace/handlers/ScriptsHandler.d.ts +12 -0
  137. package/models/trace/handlers/ScriptsHandler.js +93 -1
  138. package/models/trace/handlers/ScriptsHandler.js.map +1 -1
  139. package/models/trace/handlers/devtools_entrypoint-bundle-typescript-tsconfig.json +2 -2
  140. package/models/trace/handlers/handlers-tsconfig.json +2 -3
  141. package/models/trace/helpers/Network.d.ts +5 -0
  142. package/models/trace/helpers/Network.js +17 -0
  143. package/models/trace/helpers/Network.js.map +1 -1
  144. package/models/trace/helpers/SamplesIntegrator.js +19 -23
  145. package/models/trace/helpers/SamplesIntegrator.js.map +1 -1
  146. package/models/trace/helpers/SyntheticEvents.d.ts +0 -1
  147. package/models/trace/helpers/SyntheticEvents.js +0 -4
  148. package/models/trace/helpers/SyntheticEvents.js.map +1 -1
  149. package/models/trace/helpers/Trace.d.ts +2 -1
  150. package/models/trace/helpers/Trace.js +101 -1
  151. package/models/trace/helpers/Trace.js.map +1 -1
  152. package/models/trace/helpers/TreeHelpers.d.ts +2 -5
  153. package/models/trace/helpers/TreeHelpers.js +0 -4
  154. package/models/trace/helpers/TreeHelpers.js.map +1 -1
  155. package/models/trace/helpers/devtools_entrypoint-bundle-typescript-tsconfig.json +2 -2
  156. package/models/trace/helpers/helpers-tsconfig.json +2 -2
  157. package/models/trace/insights/{UseCache.d.ts → Cache.d.ts} +2 -2
  158. package/models/trace/insights/{UseCache.js → Cache.js} +11 -5
  159. package/models/trace/insights/Cache.js.map +1 -0
  160. package/models/trace/insights/Common.d.ts +21 -2
  161. package/models/trace/insights/Common.js +86 -2
  162. package/models/trace/insights/Common.js.map +1 -1
  163. package/models/trace/insights/DocumentLatency.js +2 -8
  164. package/models/trace/insights/DocumentLatency.js.map +1 -1
  165. package/models/trace/insights/DuplicatedJavaScript.d.ts +7 -4
  166. package/models/trace/insights/DuplicatedJavaScript.js +25 -5
  167. package/models/trace/insights/DuplicatedJavaScript.js.map +1 -1
  168. package/models/trace/insights/ForcedReflow.d.ts +5 -1
  169. package/models/trace/insights/ForcedReflow.js +6 -2
  170. package/models/trace/insights/ForcedReflow.js.map +1 -1
  171. package/models/trace/insights/InteractionToNextPaint.d.ts +1 -0
  172. package/models/trace/insights/InteractionToNextPaint.js +3 -0
  173. package/models/trace/insights/InteractionToNextPaint.js.map +1 -1
  174. package/models/trace/insights/LegacyJavaScript.d.ts +32 -0
  175. package/models/trace/insights/LegacyJavaScript.js +77 -0
  176. package/models/trace/insights/LegacyJavaScript.js.map +1 -0
  177. package/models/trace/insights/Models.d.ts +3 -1
  178. package/models/trace/insights/Models.js +3 -1
  179. package/models/trace/insights/Models.js.map +1 -1
  180. package/models/trace/insights/ModernHTTP.d.ts +51 -0
  181. package/models/trace/insights/ModernHTTP.js +187 -0
  182. package/models/trace/insights/ModernHTTP.js.map +1 -0
  183. package/models/trace/insights/NetworkDependencyTree.js +1 -1
  184. package/models/trace/insights/NetworkDependencyTree.js.map +1 -1
  185. package/models/trace/insights/ThirdParties.d.ts +1 -5
  186. package/models/trace/insights/ThirdParties.js +8 -21
  187. package/models/trace/insights/ThirdParties.js.map +1 -1
  188. package/models/trace/insights/devtools_entrypoint-bundle-typescript-tsconfig.json +2 -2
  189. package/models/trace/insights/insights-tsconfig.json +8 -3
  190. package/models/trace/insights/types.d.ts +1 -0
  191. package/models/trace/insights/types.js.map +1 -1
  192. package/models/trace/lantern/core/core-tsconfig.json +2 -2
  193. package/models/trace/lantern/core/devtools_entrypoint-bundle-typescript-tsconfig.json +2 -2
  194. package/models/trace/lantern/devtools_entrypoint-bundle-typescript-tsconfig.json +2 -2
  195. package/models/trace/lantern/graph/devtools_entrypoint-bundle-typescript-tsconfig.json +2 -2
  196. package/models/trace/lantern/graph/graph-tsconfig.json +2 -2
  197. package/models/trace/lantern/lantern-tsconfig.json +2 -2
  198. package/models/trace/lantern/metrics/Metric.d.ts +4 -4
  199. package/models/trace/lantern/metrics/Metric.js +4 -6
  200. package/models/trace/lantern/metrics/Metric.js.map +1 -1
  201. package/models/trace/lantern/metrics/devtools_entrypoint-bundle-typescript-tsconfig.json +2 -2
  202. package/models/trace/lantern/metrics/metrics-tsconfig.json +2 -2
  203. package/models/trace/lantern/simulation/devtools_entrypoint-bundle-typescript-tsconfig.json +2 -2
  204. package/models/trace/lantern/simulation/simulation-tsconfig.json +2 -2
  205. package/models/trace/lantern/types/devtools_entrypoint-bundle-typescript-tsconfig.json +2 -2
  206. package/models/trace/lantern/types/types-tsconfig.json +2 -2
  207. package/models/trace/trace-tsconfig.json +2 -2
  208. package/models/trace/types/Configuration.d.ts +2 -0
  209. package/models/trace/types/Configuration.js.map +1 -1
  210. package/models/trace/types/TraceEvents.d.ts +28 -50
  211. package/models/trace/types/TraceEvents.js +8 -23
  212. package/models/trace/types/TraceEvents.js.map +1 -1
  213. package/models/trace/types/devtools_entrypoint-bundle-typescript-tsconfig.json +2 -2
  214. package/models/trace/types/types-tsconfig.json +2 -2
  215. package/package.json +3 -2
  216. package/test/test-trace-engine.mjs +19 -17
  217. package/third_party/legacy-javascript/legacy-javascript.d.ts +1 -0
  218. package/third_party/legacy-javascript/legacy-javascript.js +1 -0
  219. package/core/platform/ServerTiming.d.ts +0 -31
  220. package/core/platform/ServerTiming.js +0 -212
  221. package/core/platform/ServerTiming.js.map +0 -1
  222. package/models/trace/handlers/ServerTimingsHandler.d.ts +0 -9
  223. package/models/trace/handlers/ServerTimingsHandler.js +0 -106
  224. package/models/trace/handlers/ServerTimingsHandler.js.map +0 -1
  225. package/models/trace/insights/UseCache.js.map +0 -1
@@ -18,6 +18,7 @@
18
18
  "noImplicitOverride": true,
19
19
  "noImplicitReturns": true,
20
20
  "noUnusedLocals": false,
21
+ "noUnusedParameters": true,
21
22
  "outDir": ".",
22
23
  "rootDir": "../../../../../../../front_end/models/trace/types",
23
24
  "skipLibCheck": true,
@@ -36,8 +37,7 @@
36
37
  "../../../../../../../front_end/models/trace/types/TraceEvents.ts",
37
38
  "../../../../../../../front_end/legacy/legacy-defs.d.ts",
38
39
  "../../../../../../../front_end/global_typings/global_defs.d.ts",
39
- "../../../../../../../node_modules/@types/filesystem/index.d.ts",
40
- "../../../../../../../node_modules/@types/wicg-task-scheduling/index.d.ts"
40
+ "../../../../../../../node_modules/@types/filesystem/index.d.ts"
41
41
  ],
42
42
  "references": [
43
43
  {
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@paulirish/trace_engine",
3
- "version": "0.0.49",
3
+ "version": "0.0.51",
4
4
  "description": "",
5
5
  "main": "models/trace/trace.js",
6
6
  "scripts": {
@@ -13,7 +13,8 @@
13
13
  "author": "",
14
14
  "license": "BSD-3-Clause",
15
15
  "dependencies": {
16
- "third-party-web": "latest"
16
+ "third-party-web": "latest",
17
+ "legacy-javascript": "latest"
17
18
  },
18
19
  "devDependencies": {
19
20
  "typescript": "5.6.2",
@@ -81,7 +81,9 @@ test('insights look ok', t => {
81
81
  'DuplicatedJavaScript',
82
82
  'SlowCSSSelector',
83
83
  'ForcedReflow',
84
- 'UseCache',
84
+ 'Cache',
85
+ 'ModernHTTP',
86
+ 'LegacyJavaScript',
85
87
  ]);
86
88
  for (const [insightName, insightItem] of Object.entries(insightSet.model)) {
87
89
  const msg = insightItem instanceof Error ?
@@ -91,24 +93,24 @@ test('insights look ok', t => {
91
93
  assert.ok(typeof insightItem === 'object', `insightName ${insightName} is not an object`);
92
94
  }
93
95
 
94
- const entityNames = Array.from(insightSet.model.ThirdParties.summaryByEntity.keys()).map(e => e.name);
95
- const values = Array.from(insightSet.model.ThirdParties.summaryByEntity.values());
96
- const simplified = Object.fromEntries(values.map((v, i) => [entityNames[i], v]));
96
+ const entityNames = insightSet.model.ThirdParties.summaries.map(s => s.entity.name);
97
+ const values = insightSet.model.ThirdParties.summaries.values();
98
+ const simplified = Object.fromEntries(values.map((v, i) => [entityNames[i], {transferSize: v.transferSize, mainThreadTime: v.mainThreadTime}]));
97
99
 
98
100
  const expected = {
99
- ahfhijdlegdabablpippeagghigmibma: { transferSize: 0, mainThreadTime: 2189 },
100
- 'paulirish.com': { transferSize: 142142, mainThreadTime: 8995 },
101
- cjpalhdlnbpafiamejdnhcphjbkeiagm: { transferSize: 0, mainThreadTime: 2607 },
102
- jinjaccalgkegednnccohejagnlnfdag: { transferSize: 0, mainThreadTime: 841 },
103
- noondiphcddnnabmjcihcjfbhfklnnep: { transferSize: 0, mainThreadTime: 1811 },
104
- 'Google Tag Manager': { transferSize: 0, mainThreadTime: 124 },
105
- Disqus: { transferSize: 1550, mainThreadTime: 413 },
106
- 'Google Analytics': { transferSize: 0, mainThreadTime: 117 },
107
- bknnlbamapndemiekhkcnmdclnkijlhb: { transferSize: 0, mainThreadTime: 387 },
108
- kljjfejkagofbgklifblndjelgabcmig: { transferSize: 0, mainThreadTime: 149 },
109
- nffaoalbilbmmfgbnbgppjihopabppdk: { transferSize: 0, mainThreadTime: 812 },
110
- obadmbiiipafnncogfkdfionggeckfia: { transferSize: 0, mainThreadTime: 1477 },
111
- 'Google Fonts': { transferSize: 74145, mainThreadTime: 0 }
101
+ ahfhijdlegdabablpippeagghigmibma: { transferSize: 0, mainThreadTime: 3.953000009059906 },
102
+ 'paulirish.com': { transferSize: 142142, mainThreadTime: 17.631999850273132 },
103
+ cjpalhdlnbpafiamejdnhcphjbkeiagm: { transferSize: 0, mainThreadTime: 4.081999972462654 },
104
+ jinjaccalgkegednnccohejagnlnfdag: { transferSize: 0, mainThreadTime: 1.2049999833106995 },
105
+ noondiphcddnnabmjcihcjfbhfklnnep: { transferSize: 0, mainThreadTime: 2.2430000007152557 },
106
+ 'Google Tag Manager': { transferSize: 0, mainThreadTime: 0.2629999965429306 },
107
+ 'Google Fonts': { transferSize: 74145, mainThreadTime: 0 },
108
+ Disqus: { transferSize: 1550, mainThreadTime: 0.4229999780654907 },
109
+ 'Google Analytics': { transferSize: 0, mainThreadTime: 0.2199999839067459 },
110
+ bknnlbamapndemiekhkcnmdclnkijlhb: { transferSize: 0, mainThreadTime: 0.601999968290329 },
111
+ kljjfejkagofbgklifblndjelgabcmig: { transferSize: 0, mainThreadTime: 0.27699998021125793 },
112
+ nffaoalbilbmmfgbnbgppjihopabppdk: { transferSize: 0, mainThreadTime: 1.246999979019165 },
113
+ obadmbiiipafnncogfkdfionggeckfia: { transferSize: 0, mainThreadTime: 1.696999967098236 },
112
114
  };
113
115
  assert.deepStrictEqual(simplified, expected);
114
116
  });
@@ -0,0 +1 @@
1
+ import * as LegacyJavaScript from 'legacy-javascript'; export {LegacyJavaScript};
@@ -0,0 +1 @@
1
+ import * as LegacyJavaScript from 'legacy-javascript'; export {LegacyJavaScript};
@@ -1,31 +0,0 @@
1
- export interface NameValue {
2
- name: string;
3
- value: string;
4
- }
5
- export interface ServerTimingParsingWarningMessage {
6
- deprecratedSyntax: () => string;
7
- duplicateParameter: (parameter: string) => string;
8
- noValueFoundForParameter: (parameter: string) => string;
9
- unrecognizedParameter: (parameter: string) => string;
10
- extraneousTrailingCharacters: () => string;
11
- unableToParseValue: (parameter: string, value: string) => string;
12
- }
13
- export declare class ServerTiming {
14
- metric: string;
15
- value: number;
16
- description: string | null;
17
- start: number | null;
18
- constructor(metric: string, value: number, description: string | null, start: number | null);
19
- static parseHeaders(headers: NameValue[], warningMessages?: ServerTimingParsingWarningMessage): ServerTiming[] | null;
20
- /**
21
- * TODO(crbug.com/1011811): Instead of using !Object<string, *> we should have a proper type
22
- * with #name, desc and dur properties.
23
- */
24
- static createFromHeaderValue(valueString: string, warningMessages?: ServerTimingParsingWarningMessage): Array<{
25
- [x: string]: any;
26
- }>;
27
- static getParserForParameter(paramName: string, warningMessages: ServerTimingParsingWarningMessage): ((arg0: {
28
- [x: string]: any;
29
- }, arg1: string | null) => void) | null;
30
- static showWarning(msg: string): void;
31
- }
@@ -1,212 +0,0 @@
1
- // Copyright 2024 The Chromium Authors. All rights reserved.
2
- // Use of this source code is governed by a BSD-style license that can be
3
- // found in the LICENSE file.
4
- import { compare } from './StringUtilities.js';
5
- const defaultWarningMessages = {
6
- deprecratedSyntax() {
7
- return 'Deprecated syntax found. Please use: <name>;dur=<duration>;desc=<description>';
8
- },
9
- duplicateParameter(parameter) {
10
- return `Duplicate parameter "${parameter}" ignored.`;
11
- },
12
- noValueFoundForParameter(parameter) {
13
- return `No value found for parameter "${parameter}".`;
14
- },
15
- unrecognizedParameter(parameter) {
16
- return `Unrecognized parameter "${parameter}".`;
17
- },
18
- extraneousTrailingCharacters() {
19
- return 'Extraneous trailing characters.';
20
- },
21
- unableToParseValue(parameter, value) {
22
- return `Unable to parse "${parameter}" value "${value}".`;
23
- },
24
- };
25
- export class ServerTiming {
26
- metric;
27
- value;
28
- description;
29
- start;
30
- constructor(metric, value, description, start) {
31
- this.metric = metric;
32
- this.value = value;
33
- this.description = description;
34
- this.start = start;
35
- }
36
- static parseHeaders(headers, warningMessages = defaultWarningMessages) {
37
- const rawServerTimingHeaders = headers.filter(item => item.name.toLowerCase() === 'server-timing');
38
- if (!rawServerTimingHeaders.length) {
39
- return null;
40
- }
41
- const serverTimings = rawServerTimingHeaders.reduce((memo, header) => {
42
- const timing = this.createFromHeaderValue(header.value, warningMessages);
43
- memo.push(...timing.map(function (entry) {
44
- return new ServerTiming(entry.name, entry.hasOwnProperty('dur') ? entry.dur : null, entry.hasOwnProperty('desc') ? entry.desc : '', entry.hasOwnProperty('start') ? entry.start : null);
45
- }));
46
- return memo;
47
- }, []);
48
- serverTimings.sort((a, b) => compare(a.metric.toLowerCase(), b.metric.toLowerCase()));
49
- return serverTimings;
50
- }
51
- /**
52
- * TODO(crbug.com/1011811): Instead of using !Object<string, *> we should have a proper type
53
- * with #name, desc and dur properties.
54
- */
55
- static createFromHeaderValue(valueString, warningMessages = defaultWarningMessages) {
56
- function trimLeadingWhiteSpace() {
57
- valueString = valueString.replace(/^\s*/, '');
58
- }
59
- function consumeDelimiter(char) {
60
- console.assert(char.length === 1);
61
- trimLeadingWhiteSpace();
62
- if (valueString.charAt(0) !== char) {
63
- return false;
64
- }
65
- valueString = valueString.substring(1);
66
- return true;
67
- }
68
- function consumeToken() {
69
- // https://tools.ietf.org/html/rfc7230#appendix-B
70
- const result = /^(?:\s*)([\w!#$%&'*+\-.^`|~]+)(?:\s*)(.*)/.exec(valueString);
71
- if (!result) {
72
- return null;
73
- }
74
- valueString = result[2];
75
- return result[1];
76
- }
77
- function consumeTokenOrQuotedString() {
78
- trimLeadingWhiteSpace();
79
- if (valueString.charAt(0) === '"') {
80
- return consumeQuotedString();
81
- }
82
- return consumeToken();
83
- }
84
- function consumeQuotedString() {
85
- console.assert(valueString.charAt(0) === '"');
86
- valueString = valueString.substring(1); // remove leading DQUOTE
87
- let value = '';
88
- while (valueString.length) {
89
- // split into two parts:
90
- // -everything before the first " or \
91
- // -everything else
92
- const result = /^([^"\\]*)(.*)/.exec(valueString);
93
- if (!result) {
94
- return null; // not a valid quoted-string
95
- }
96
- value += result[1];
97
- if (result[2].charAt(0) === '"') {
98
- // we have found our closing "
99
- valueString = result[2].substring(1); // strip off everything after the closing "
100
- return value; // we are done here
101
- }
102
- console.assert(result[2].charAt(0) === '\\');
103
- // special rules for \ found in quoted-string (https://tools.ietf.org/html/rfc7230#section-3.2.6)
104
- value += result[2].charAt(1); // grab the character AFTER the \ (if there was one)
105
- valueString = result[2].substring(2); // strip off \ and next character
106
- }
107
- return null; // not a valid quoted-string
108
- }
109
- function consumeExtraneous() {
110
- const result = /([,;].*)/.exec(valueString);
111
- if (result) {
112
- valueString = result[1];
113
- }
114
- }
115
- const result = [];
116
- let name;
117
- while ((name = consumeToken()) !== null) {
118
- const entry = { name };
119
- if (valueString.charAt(0) === '=') {
120
- this.showWarning(warningMessages['deprecratedSyntax']());
121
- }
122
- while (consumeDelimiter(';')) {
123
- let paramName;
124
- if ((paramName = consumeToken()) === null) {
125
- continue;
126
- }
127
- paramName = paramName.toLowerCase();
128
- const parseParameter = this.getParserForParameter(paramName, warningMessages);
129
- let paramValue = null;
130
- if (consumeDelimiter('=')) {
131
- // always parse the value, even if we don't recognize the parameter #name
132
- paramValue = consumeTokenOrQuotedString();
133
- consumeExtraneous();
134
- }
135
- if (parseParameter) {
136
- // paramName is valid
137
- if (entry.hasOwnProperty(paramName)) {
138
- this.showWarning(warningMessages['duplicateParameter'](paramName));
139
- continue;
140
- }
141
- if (paramValue === null) {
142
- this.showWarning(warningMessages['noValueFoundForParameter'](paramName));
143
- }
144
- parseParameter.call(this, entry, paramValue);
145
- }
146
- else {
147
- // paramName is not valid
148
- this.showWarning(warningMessages['unrecognizedParameter'](paramName));
149
- }
150
- }
151
- result.push(entry);
152
- if (!consumeDelimiter(',')) {
153
- break;
154
- }
155
- }
156
- if (valueString.length) {
157
- this.showWarning(warningMessages['extraneousTrailingCharacters']());
158
- }
159
- return result;
160
- }
161
- static getParserForParameter(paramName, warningMessages) {
162
- switch (paramName) {
163
- case 'dur': {
164
- function durParser(entry,
165
- // TODO(crbug.com/1172300) Ignored during the jsdoc to ts migration
166
- // eslint-disable-next-line @typescript-eslint/no-explicit-any
167
- paramValue) {
168
- entry.dur = 0;
169
- if (paramValue !== null) {
170
- const duration = parseFloat(paramValue);
171
- if (isNaN(duration)) {
172
- ServerTiming.showWarning(warningMessages['unableToParseValue'](paramName, paramValue));
173
- return;
174
- }
175
- entry.dur = duration;
176
- }
177
- }
178
- return durParser;
179
- }
180
- case 'start': {
181
- function startParser(entry,
182
- // TODO(crbug.com/1172300) Ignored during the jsdoc to ts migration
183
- // eslint-disable-next-line @typescript-eslint/no-explicit-any
184
- paramValue) {
185
- entry.start = null;
186
- if (paramValue !== null) {
187
- const start = parseFloat(paramValue);
188
- if (isNaN(start)) {
189
- ServerTiming.showWarning(warningMessages['unableToParseValue'](paramName, paramValue));
190
- return;
191
- }
192
- entry.start = start;
193
- }
194
- }
195
- return startParser;
196
- }
197
- case 'desc': {
198
- function descParser(entry, paramValue) {
199
- entry.desc = paramValue || '';
200
- }
201
- return descParser;
202
- }
203
- default: {
204
- return null;
205
- }
206
- }
207
- }
208
- static showWarning(msg) {
209
- console.warn(`ServerTiming: ${msg}`);
210
- }
211
- }
212
- //# sourceMappingURL=ServerTiming.js.map
@@ -1 +0,0 @@
1
- {"version":3,"file":"ServerTiming.js","sourceRoot":"","sources":["../../../../../../front_end/core/platform/ServerTiming.ts"],"names":[],"mappings":"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","sourcesContent":["// Copyright 2024 The Chromium Authors. All rights reserved.\n// Use of this source code is governed by a BSD-style license that can be\n// found in the LICENSE file.\n\nimport {compare} from './StringUtilities.js';\n\nexport interface NameValue {\n name: string;\n value: string;\n}\nconst defaultWarningMessages: ServerTimingParsingWarningMessage = {\n deprecratedSyntax() {\n return 'Deprecated syntax found. Please use: <name>;dur=<duration>;desc=<description>';\n },\n duplicateParameter(parameter) {\n return `Duplicate parameter \"${parameter}\" ignored.`;\n },\n noValueFoundForParameter(parameter) {\n return `No value found for parameter \"${parameter}\".`;\n },\n unrecognizedParameter(parameter) {\n return `Unrecognized parameter \"${parameter}\".`;\n },\n extraneousTrailingCharacters() {\n return 'Extraneous trailing characters.';\n },\n unableToParseValue(parameter, value) {\n return `Unable to parse \"${parameter}\" value \"${value}\".`;\n },\n};\n\nexport interface ServerTimingParsingWarningMessage {\n deprecratedSyntax: () => string;\n duplicateParameter: (parameter: string) => string;\n noValueFoundForParameter: (parameter: string) => string;\n unrecognizedParameter: (parameter: string) => string;\n extraneousTrailingCharacters: () => string;\n unableToParseValue: (parameter: string, value: string) => string;\n}\n\nexport class ServerTiming {\n metric: string;\n value: number;\n description: string|null;\n start: number|null;\n\n constructor(metric: string, value: number, description: string|null, start: number|null) {\n this.metric = metric;\n this.value = value;\n this.description = description;\n this.start = start;\n }\n\n static parseHeaders(\n headers: NameValue[],\n warningMessages: ServerTimingParsingWarningMessage = defaultWarningMessages): ServerTiming[]|null {\n const rawServerTimingHeaders = headers.filter(item => item.name.toLowerCase() === 'server-timing');\n if (!rawServerTimingHeaders.length) {\n return null;\n }\n\n const serverTimings = rawServerTimingHeaders.reduce((memo, header) => {\n const timing = this.createFromHeaderValue(header.value, warningMessages);\n memo.push(...timing.map(function(entry) {\n return new ServerTiming(\n entry.name, entry.hasOwnProperty('dur') ? entry.dur : null, entry.hasOwnProperty('desc') ? entry.desc : '',\n entry.hasOwnProperty('start') ? entry.start : null);\n }));\n return memo;\n }, ([] as ServerTiming[]));\n serverTimings.sort((a, b) => compare(a.metric.toLowerCase(), b.metric.toLowerCase()));\n return serverTimings;\n }\n\n /**\n * TODO(crbug.com/1011811): Instead of using !Object<string, *> we should have a proper type\n * with #name, desc and dur properties.\n */\n static createFromHeaderValue(\n valueString: string, warningMessages: ServerTimingParsingWarningMessage = defaultWarningMessages): Array<{\n // TODO(crbug.com/1172300) Ignored during the jsdoc to ts migration\n // eslint-disable-next-line @typescript-eslint/no-explicit-any\n [x: string]: any,\n }> {\n function trimLeadingWhiteSpace(): void {\n valueString = valueString.replace(/^\\s*/, '');\n }\n function consumeDelimiter(char: string): boolean {\n console.assert(char.length === 1);\n trimLeadingWhiteSpace();\n if (valueString.charAt(0) !== char) {\n return false;\n }\n\n valueString = valueString.substring(1);\n return true;\n }\n function consumeToken(): string|null {\n // https://tools.ietf.org/html/rfc7230#appendix-B\n const result = /^(?:\\s*)([\\w!#$%&'*+\\-.^`|~]+)(?:\\s*)(.*)/.exec(valueString);\n if (!result) {\n return null;\n }\n\n valueString = result[2];\n return result[1];\n }\n function consumeTokenOrQuotedString(): string|null {\n trimLeadingWhiteSpace();\n if (valueString.charAt(0) === '\"') {\n return consumeQuotedString();\n }\n\n return consumeToken();\n }\n function consumeQuotedString(): string|null {\n console.assert(valueString.charAt(0) === '\"');\n valueString = valueString.substring(1); // remove leading DQUOTE\n\n let value = '';\n while (valueString.length) {\n // split into two parts:\n // -everything before the first \" or \\\n // -everything else\n const result = /^([^\"\\\\]*)(.*)/.exec(valueString);\n if (!result) {\n return null; // not a valid quoted-string\n }\n value += result[1];\n if (result[2].charAt(0) === '\"') {\n // we have found our closing \"\n valueString = result[2].substring(1); // strip off everything after the closing \"\n return value; // we are done here\n }\n\n console.assert(result[2].charAt(0) === '\\\\');\n // special rules for \\ found in quoted-string (https://tools.ietf.org/html/rfc7230#section-3.2.6)\n value += result[2].charAt(1); // grab the character AFTER the \\ (if there was one)\n valueString = result[2].substring(2); // strip off \\ and next character\n }\n\n return null; // not a valid quoted-string\n }\n function consumeExtraneous(): void {\n const result = /([,;].*)/.exec(valueString);\n if (result) {\n valueString = result[1];\n }\n }\n\n const result = [];\n let name;\n while ((name = consumeToken()) !== null) {\n const entry = {name};\n\n if (valueString.charAt(0) === '=') {\n this.showWarning(warningMessages['deprecratedSyntax']());\n }\n\n while (consumeDelimiter(';')) {\n let paramName;\n if ((paramName = consumeToken()) === null) {\n continue;\n }\n\n paramName = paramName.toLowerCase();\n const parseParameter = this.getParserForParameter(paramName, warningMessages);\n let paramValue: (string|null)|null = null;\n if (consumeDelimiter('=')) {\n // always parse the value, even if we don't recognize the parameter #name\n paramValue = consumeTokenOrQuotedString();\n consumeExtraneous();\n }\n\n if (parseParameter) {\n // paramName is valid\n if (entry.hasOwnProperty(paramName)) {\n this.showWarning(warningMessages['duplicateParameter'](paramName));\n continue;\n }\n\n if (paramValue === null) {\n this.showWarning(warningMessages['noValueFoundForParameter'](paramName));\n }\n\n parseParameter.call(this, entry, paramValue);\n } else {\n // paramName is not valid\n this.showWarning(warningMessages['unrecognizedParameter'](paramName));\n }\n }\n\n result.push(entry);\n if (!consumeDelimiter(',')) {\n break;\n }\n }\n\n if (valueString.length) {\n this.showWarning(warningMessages['extraneousTrailingCharacters']());\n }\n return result;\n }\n\n static getParserForParameter(paramName: string, warningMessages: ServerTimingParsingWarningMessage):\n ((arg0: {\n // TODO(crbug.com/1172300) Ignored during the jsdoc to ts migration\n // eslint-disable-next-line @typescript-eslint/no-explicit-any\n [x: string]: any,\n },\n arg1: string|null) => void)|null {\n switch (paramName) {\n case 'dur': {\n function durParser(\n entry: {\n // TODO(crbug.com/1172300) Ignored during the jsdoc to ts migration\n // eslint-disable-next-line @typescript-eslint/no-explicit-any\n [x: string]: any,\n },\n // TODO(crbug.com/1172300) Ignored during the jsdoc to ts migration\n // eslint-disable-next-line @typescript-eslint/no-explicit-any\n paramValue: any): void {\n entry.dur = 0;\n if (paramValue !== null) {\n const duration = parseFloat(paramValue);\n if (isNaN(duration)) {\n ServerTiming.showWarning(warningMessages['unableToParseValue'](paramName, paramValue));\n return;\n }\n entry.dur = duration;\n }\n }\n return durParser;\n }\n case 'start': {\n function startParser(\n entry: {\n // TODO(crbug.com/1172300) Ignored during the jsdoc to ts migration\n // eslint-disable-next-line @typescript-eslint/no-explicit-any\n [x: string]: any,\n },\n // TODO(crbug.com/1172300) Ignored during the jsdoc to ts migration\n // eslint-disable-next-line @typescript-eslint/no-explicit-any\n paramValue: any): void {\n entry.start = null;\n if (paramValue !== null) {\n const start = parseFloat(paramValue);\n if (isNaN(start)) {\n ServerTiming.showWarning(warningMessages['unableToParseValue'](paramName, paramValue));\n return;\n }\n entry.start = start;\n }\n }\n return startParser;\n }\n case 'desc': {\n function descParser(\n entry: {\n // TODO(crbug.com/1172300) Ignored during the jsdoc to ts migration\n // eslint-disable-next-line @typescript-eslint/no-explicit-any\n [x: string]: any,\n },\n paramValue: string|null): void {\n entry.desc = paramValue || '';\n }\n return descParser;\n }\n\n default: {\n return null;\n }\n }\n }\n\n static showWarning(msg: string): void {\n console.warn(`ServerTiming: ${msg}`);\n }\n}\n"]}
@@ -1,9 +0,0 @@
1
- import * as Types from '../types/types.js';
2
- import type { HandlerName } from './types.js';
3
- export declare function reset(): void;
4
- export declare function handleEvent(_event: Types.Events.Event): void;
5
- export declare function finalize(): Promise<void>;
6
- export declare function data(): {
7
- serverTimings: Types.Events.SyntheticServerTiming[];
8
- };
9
- export declare function deps(): HandlerName[];
@@ -1,106 +0,0 @@
1
- // Copyright 2024 The Chromium Authors. All rights reserved.
2
- // Use of this source code is governed by a BSD-style license that can be
3
- // found in the LICENSE file.
4
- import * as Platform from '../../../core/platform/platform.js';
5
- import * as Helpers from '../helpers/helpers.js';
6
- import * as Types from '../types/types.js';
7
- import { data as networkData } from './NetworkRequestsHandler.js';
8
- const serverTimings = [];
9
- export function reset() {
10
- serverTimings.length = 0;
11
- }
12
- export function handleEvent(_event) {
13
- // Implementation not needed because data is sourced from NetworkRequestsHandler
14
- }
15
- export async function finalize() {
16
- extractServerTimings();
17
- Helpers.Trace.sortTraceEventsInPlace(serverTimings);
18
- }
19
- const RESPONSE_START_METRIC_NAME = 'response-start';
20
- const RESPONSE_END_METRIC_NAME = 'response-end';
21
- /**
22
- * Creates synthetic trace events based on server timings in the
23
- * `Server-Timing` response header. A non-standard `start` param is
24
- * expected on each metric that contains the start time of the timing
25
- * based on the server clock.
26
- *
27
- * In order to estimate the offset between the server and client clocks,
28
- * we look for the non-standard `response-start` and `response-end`
29
- * metrics in the response header, which contain the start and end
30
- * timestamps of the network request processing in the server. We
31
- * compare these with the times the request was sent and received in the
32
- * client to estimate the offset between the client and the server
33
- * clocks.
34
- *
35
- * With this offset estimation at hand, we can map timestamps from the
36
- * server clock to the tracing clock and locate the timings in the
37
- * performance timeline.
38
- */
39
- function extractServerTimings() {
40
- for (const networkEvent of networkData().byTime) {
41
- let timingsInRequest = null;
42
- for (const header of networkEvent.args.data.responseHeaders) {
43
- const headerName = header.name.toLocaleLowerCase();
44
- // Some popular hosting providers like vercel or render get rid of
45
- // Server-Timing headers added by users, so as a workaround we
46
- // also support server timing headers with the `-test` suffix
47
- // while this feature is experimental, to enable easier trials.
48
- if (headerName === 'server-timing' || headerName === 'server-timing-test') {
49
- header.name = 'server-timing';
50
- timingsInRequest = Platform.ServerTiming.ServerTiming.parseHeaders([header]);
51
- continue;
52
- }
53
- }
54
- const serverStart = timingsInRequest?.find(timing => timing.metric === RESPONSE_START_METRIC_NAME)?.start;
55
- const serverEnd = timingsInRequest?.find(timing => timing.metric === RESPONSE_END_METRIC_NAME)?.start;
56
- if (!serverStart || !serverEnd || !timingsInRequest) {
57
- continue;
58
- }
59
- const serverStartInMicro = serverStart * 1_000;
60
- const serverEndInMicro = serverEnd * 1_000;
61
- serverTimings.push(...createSyntheticServerTiming(networkEvent, serverStartInMicro, serverEndInMicro, timingsInRequest));
62
- }
63
- }
64
- function createSyntheticServerTiming(request, serverStart, serverEnd, timingsInRequest) {
65
- const clientStart = request.args.data.syntheticData.sendStartTime;
66
- const clientEndTime = request.args.data.syntheticData.sendStartTime + request.args.data.syntheticData.waiting;
67
- const offset = Types.Timing.Micro((serverStart - clientStart + serverEnd - clientEndTime) / 2);
68
- const convertedServerTimings = [];
69
- for (const timing of timingsInRequest) {
70
- if (timing.metric === RESPONSE_START_METRIC_NAME || timing.metric === RESPONSE_END_METRIC_NAME) {
71
- continue;
72
- }
73
- if (timing.start === null) {
74
- continue;
75
- }
76
- const convertedTimestamp = Helpers.Timing.milliToMicro(Types.Timing.Milli(timing.start)) - offset;
77
- const parsedUrl = new URL(request.args.data.url);
78
- const origin = parsedUrl.origin;
79
- const serverTiming = Helpers.SyntheticEvents.SyntheticEventsManager.registerServerTiming({
80
- rawSourceEvent: request.rawSourceEvent,
81
- name: timing.metric,
82
- ph: "X" /* Types.Events.Phase.COMPLETE */,
83
- pid: Types.Events.ProcessID(0),
84
- tid: Types.Events.ThreadID(0),
85
- ts: Types.Timing.Micro(convertedTimestamp),
86
- dur: Helpers.Timing.milliToMicro(Types.Timing.Milli(timing.value)),
87
- cat: 'devtools.server-timing',
88
- args: { data: { desc: timing.description || undefined, origin } },
89
- });
90
- if (!request.args.data.syntheticServerTimings) {
91
- request.args.data.syntheticServerTimings = [];
92
- }
93
- request.args.data.syntheticServerTimings.push(serverTiming);
94
- convertedServerTimings.push(serverTiming);
95
- }
96
- return convertedServerTimings;
97
- }
98
- export function data() {
99
- return {
100
- serverTimings,
101
- };
102
- }
103
- export function deps() {
104
- return ['NetworkRequests'];
105
- }
106
- //# sourceMappingURL=ServerTimingsHandler.js.map
@@ -1 +0,0 @@
1
- {"version":3,"file":"ServerTimingsHandler.js","sourceRoot":"","sources":["../../../../../../../front_end/models/trace/handlers/ServerTimingsHandler.ts"],"names":[],"mappings":"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","sourcesContent":["// Copyright 2024 The Chromium Authors. All rights reserved.\n// Use of this source code is governed by a BSD-style license that can be\n// found in the LICENSE file.\n\nimport * as Platform from '../../../core/platform/platform.js';\nimport * as Helpers from '../helpers/helpers.js';\nimport * as Types from '../types/types.js';\n\nimport {data as networkData} from './NetworkRequestsHandler.js';\nimport type {HandlerName} from './types.js';\n\nconst serverTimings: Types.Events.SyntheticServerTiming[] = [];\n\nexport function reset(): void {\n serverTimings.length = 0;\n}\n\nexport function handleEvent(_event: Types.Events.Event): void {\n // Implementation not needed because data is sourced from NetworkRequestsHandler\n}\n\nexport async function finalize(): Promise<void> {\n extractServerTimings();\n Helpers.Trace.sortTraceEventsInPlace(serverTimings);\n}\n\nconst RESPONSE_START_METRIC_NAME = 'response-start';\nconst RESPONSE_END_METRIC_NAME = 'response-end';\n\n/**\n * Creates synthetic trace events based on server timings in the\n * `Server-Timing` response header. A non-standard `start` param is\n * expected on each metric that contains the start time of the timing\n * based on the server clock.\n *\n * In order to estimate the offset between the server and client clocks,\n * we look for the non-standard `response-start` and `response-end`\n * metrics in the response header, which contain the start and end\n * timestamps of the network request processing in the server. We\n * compare these with the times the request was sent and received in the\n * client to estimate the offset between the client and the server\n * clocks.\n *\n * With this offset estimation at hand, we can map timestamps from the\n * server clock to the tracing clock and locate the timings in the\n * performance timeline.\n */\nfunction extractServerTimings(): void {\n for (const networkEvent of networkData().byTime) {\n let timingsInRequest: Platform.ServerTiming.ServerTiming[]|null = null;\n for (const header of networkEvent.args.data.responseHeaders) {\n const headerName = header.name.toLocaleLowerCase();\n // Some popular hosting providers like vercel or render get rid of\n // Server-Timing headers added by users, so as a workaround we\n // also support server timing headers with the `-test` suffix\n // while this feature is experimental, to enable easier trials.\n if (headerName === 'server-timing' || headerName === 'server-timing-test') {\n header.name = 'server-timing';\n timingsInRequest = Platform.ServerTiming.ServerTiming.parseHeaders([header]);\n continue;\n }\n }\n const serverStart = timingsInRequest?.find(timing => timing.metric === RESPONSE_START_METRIC_NAME)?.start;\n const serverEnd = timingsInRequest?.find(timing => timing.metric === RESPONSE_END_METRIC_NAME)?.start;\n if (!serverStart || !serverEnd || !timingsInRequest) {\n continue;\n }\n\n const serverStartInMicro = serverStart * 1_000;\n const serverEndInMicro = serverEnd * 1_000;\n serverTimings.push(\n ...createSyntheticServerTiming(networkEvent, serverStartInMicro, serverEndInMicro, timingsInRequest));\n }\n}\nfunction createSyntheticServerTiming(\n request: Types.Events.SyntheticNetworkRequest, serverStart: number, serverEnd: number,\n timingsInRequest: Platform.ServerTiming.ServerTiming[]): Types.Events.SyntheticServerTiming[] {\n const clientStart = request.args.data.syntheticData.sendStartTime;\n const clientEndTime = request.args.data.syntheticData.sendStartTime + request.args.data.syntheticData.waiting;\n const offset = Types.Timing.Micro((serverStart - clientStart + serverEnd - clientEndTime) / 2);\n const convertedServerTimings: Types.Events.SyntheticServerTiming[] = [];\n for (const timing of timingsInRequest) {\n if (timing.metric === RESPONSE_START_METRIC_NAME || timing.metric === RESPONSE_END_METRIC_NAME) {\n continue;\n }\n if (timing.start === null) {\n continue;\n }\n const convertedTimestamp = Helpers.Timing.milliToMicro(Types.Timing.Milli(timing.start)) - offset;\n const parsedUrl = new URL(request.args.data.url);\n const origin = parsedUrl.origin;\n\n const serverTiming = Helpers.SyntheticEvents.SyntheticEventsManager.registerServerTiming({\n rawSourceEvent: request.rawSourceEvent,\n name: timing.metric,\n ph: Types.Events.Phase.COMPLETE,\n pid: Types.Events.ProcessID(0),\n tid: Types.Events.ThreadID(0),\n ts: Types.Timing.Micro(convertedTimestamp),\n dur: Helpers.Timing.milliToMicro(Types.Timing.Milli(timing.value)),\n cat: 'devtools.server-timing',\n args: {data: {desc: timing.description || undefined, origin}},\n });\n\n if (!request.args.data.syntheticServerTimings) {\n request.args.data.syntheticServerTimings = [];\n }\n request.args.data.syntheticServerTimings.push(serverTiming);\n convertedServerTimings.push(serverTiming);\n }\n return convertedServerTimings;\n}\n\nexport function data(): {serverTimings: Types.Events.SyntheticServerTiming[]} {\n return {\n serverTimings,\n };\n}\n\nexport function deps(): HandlerName[] {\n return ['NetworkRequests'];\n}\n"]}
@@ -1 +0,0 @@
1
- {"version":3,"file":"UseCache.js","sourceRoot":"","sources":["../../../../../../../front_end/models/trace/insights/UseCache.ts"],"names":[],"mappings":"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","sourcesContent":["// Copyright 2025 The Chromium Authors. All rights reserved.\n// Use of this source code is governed by a BSD-style license that can be\n// found in the LICENSE file.\n\nimport * as i18n from '../../../core/i18n/i18n.js';\nimport * as Protocol from '../../../generated/protocol.js';\nimport type * as Handlers from '../handlers/handlers.js';\nimport * as Helpers from '../helpers/helpers.js';\nimport type * as Types from '../types/types.js';\n\nimport {metricSavingsForWastedBytes} from './Common.js';\nimport {linearInterpolation} from './Statistics.js';\nimport {\n InsightCategory,\n type InsightModel,\n type InsightSetContext,\n type PartialInsightModel,\n} from './types.js';\n\nexport const UIStrings = {\n /**\n * @description Title of an insight that provides information and suggestions of resources that could improve their caching.\n */\n title: 'Use efficient cache lifetimes',\n /**\n * @description Text to tell the user about how caching can help improve performance.\n */\n description:\n 'A long cache lifetime can speed up repeat visits to your page. [Learn more](https://web.dev/uses-long-cache-ttl/).',\n /**\n * @description Column for a font loaded by the page to render text.\n */\n requestColumn: 'Request',\n /**\n * @description Column for a resource cache's Time To Live.\n */\n cacheTTL: 'Cache TTL',\n /**\n * @description Text describing that there were no requests found that need caching.\n */\n noRequestsToCache: 'No requests with inefficient cache policies',\n /**\n * @description Table row value representing the remaining items not shown in the table due to size constraints. This row will always represent at least 2 items.\n * @example {5} PH1\n */\n others: '{PH1} others',\n} as const;\n\nconst str_ = i18n.i18n.registerUIStrings('models/trace/insights/UseCache.ts', UIStrings);\nexport const i18nString = i18n.i18n.getLocalizedString.bind(undefined, str_);\n\nexport type UseCacheInsightModel = InsightModel<typeof UIStrings, {\n requests: Array<{\n request: Types.Events.SyntheticNetworkRequest,\n ttl: number,\n wastedBytes: number,\n }>,\n totalWastedBytes: number,\n}>;\n\n// Threshold for cache hits.\nconst IGNORE_THRESHOLD_IN_PERCENT = 0.925;\n\nfunction finalize(partialModel: PartialInsightModel<UseCacheInsightModel>): UseCacheInsightModel {\n return {\n insightKey: 'UseCache',\n strings: UIStrings,\n title: i18nString(UIStrings.title),\n description: i18nString(UIStrings.description),\n category: InsightCategory.ALL,\n state: partialModel.requests.length > 0 ? 'fail' : 'pass',\n ...partialModel,\n };\n}\n\n/**\n * Determines if a request is \"cacheable\".\n * A request is \"cacheable\" if it is of the appropriate protocol and resource type\n * (see Helpers.Network.NON_NETWORK_SCHEMES and Helpers.Network.STATIC_RESOURCE_TYPE)\n * and has the appropriate statusCodes.\n */\nexport function isCacheable(request: Types.Events.SyntheticNetworkRequest): boolean {\n // Caching doesn't make sense for requests not loaded over the network.\n if (Helpers.Network.NON_NETWORK_SCHEMES.includes(request.args.data.protocol)) {\n return false;\n }\n return Boolean(\n Helpers.Network.CACHEABLE_STATUS_CODES.has(request.args.data.statusCode) &&\n Helpers.Network.STATIC_RESOURCE_TYPES.has(request.args.data.resourceType || Protocol.Network.ResourceType.Other));\n}\n\n/**\n * Returns max-age if defined, otherwise expires header if defined, and null if not.\n */\nexport function computeCacheLifetimeInSeconds(\n headers: Array<{name: string, value: string}>, cacheControl: Helpers.Network.CacheControl|null): number|null {\n if (cacheControl?.['max-age'] !== undefined) {\n return cacheControl['max-age'];\n }\n\n const expiresHeaders = headers.find(h => h.name === 'expires')?.value ?? null;\n if (expiresHeaders) {\n const expires = new Date(expiresHeaders).getTime();\n // Treat expires values as having already expired.\n if (!expires) {\n return 0;\n }\n return Math.ceil((expires - Date.now()) / 1000);\n }\n return null;\n}\n\n/**\n * Computes the percent likelihood that a return visit will be within the cache lifetime, based on\n * Chrome UMA stats see the note below.\n * See https://github.com/GoogleChrome/lighthouse/blob/aba818f733552189de35121907cb5625a74af640/core/audits/byte-efficiency/uses-long-cache-ttl.js\n * TODO: This Chrome UMA stat is outdated. Using this is fine for now, but update in follow-up.\n */\nfunction getCacheHitProbability(maxAgeInSeconds: number): number {\n // This array contains the hand wavy distribution of the age of a resource in hours at the time of\n // cache hit at 0th, 10th, 20th, 30th, etc percentiles. This is used to compute `wastedMs` since there\n // are clearly diminishing returns to cache duration i.e. 6 months is not 2x better than 3 months.\n // Based on UMA stats for HttpCache.StaleEntry.Validated.Age, see https://www.desmos.com/calculator/7v0qh1nzvh\n // Example: a max-age of 12 hours already covers ~50% of cases, doubling to 24 hours covers ~10% more.\n const RESOURCE_AGE_IN_HOURS_DECILES = [0, 0.2, 1, 3, 8, 12, 24, 48, 72, 168, 8760, Infinity];\n\n const maxAgeInHours = maxAgeInSeconds / 3600;\n const upperDecileIndex = RESOURCE_AGE_IN_HOURS_DECILES.findIndex(decile => decile >= maxAgeInHours);\n\n // Clip the likelihood between 0 and 1\n if (upperDecileIndex === RESOURCE_AGE_IN_HOURS_DECILES.length - 1) {\n return 1;\n }\n if (upperDecileIndex === 0) {\n return 0;\n }\n\n // Use the two closest decile points as control points\n const upperDecileValue = RESOURCE_AGE_IN_HOURS_DECILES[upperDecileIndex];\n const lowerDecileValue = RESOURCE_AGE_IN_HOURS_DECILES[upperDecileIndex - 1];\n const upperDecile = upperDecileIndex / 10;\n const lowerDecile = (upperDecileIndex - 1) / 10;\n\n // Approximate the real likelihood with linear interpolation\n return linearInterpolation(lowerDecileValue, lowerDecile, upperDecileValue, upperDecile, maxAgeInHours);\n}\n\nexport function getCombinedHeaders(responseHeaders: Array<{name: string, value: string}>): Map<string, string> {\n const headers = new Map<string, string>();\n for (const header of responseHeaders) {\n const name = header.name.toLowerCase();\n if (headers.get(name)) {\n headers.set(name, `${headers.get(name)}, ${header.value}`);\n } else {\n headers.set(name, header.value);\n }\n }\n return headers;\n}\n\n/**\n * Returns whether a request contains headers that disable caching.\n * Disabled caching is checked on the 'cache-control' and 'pragma' headers.\n */\nexport function cachingDisabled(\n headers: Map<string, string>|null, parsedCacheControl: Helpers.Network.CacheControl|null): boolean {\n const cacheControl = headers?.get('cache-control') ?? null;\n const pragma = headers?.get('pragma') ?? null;\n\n // The HTTP/1.0 Pragma header can disable caching if cache-control is not set, see https://tools.ietf.org/html/rfc7234#section-5.4\n if (!cacheControl && pragma?.includes('no-cache')) {\n return true;\n }\n\n // If we have any of these, the user intentionally doesn't want to cache.\n if (parsedCacheControl &&\n (parsedCacheControl['must-revalidate'] || parsedCacheControl['no-cache'] || parsedCacheControl['no-store'] ||\n parsedCacheControl['private'])) {\n return true;\n }\n\n return false;\n}\n\nexport interface CacheableRequest {\n request: Types.Events.SyntheticNetworkRequest;\n ttl: number;\n wastedBytes: number;\n}\n\nexport function generateInsight(\n parsedTrace: Handlers.Types.ParsedTrace, context: InsightSetContext): UseCacheInsightModel {\n const results: CacheableRequest[] = [];\n const allRequests = parsedTrace.NetworkRequests.byTime;\n let totalWastedBytes = 0;\n const wastedBytesByRequestId = new Map<string, number>();\n for (const req of allRequests) {\n if (!isCacheable(req)) {\n continue;\n }\n\n const headers = getCombinedHeaders(req.args.data.responseHeaders);\n const cacheControl = headers.get('cache-control') ?? null;\n const parsedDirectives = Helpers.Network.parseCacheControl(cacheControl);\n\n // Skip requests that are deliberately avoiding caching.\n if (cachingDisabled(headers, parsedDirectives)) {\n continue;\n }\n\n let ttl = computeCacheLifetimeInSeconds(req.args.data.responseHeaders, parsedDirectives);\n // Ignore if a non-positive number.\n if (ttl !== null && (!Number.isFinite(ttl) || ttl <= 0)) {\n continue;\n }\n ttl = ttl || 0;\n\n // If cache lifetime is high enough, let's skip.\n const cacheHitProbability = getCacheHitProbability(ttl);\n if (cacheHitProbability > IGNORE_THRESHOLD_IN_PERCENT) {\n continue;\n }\n\n const transferSize = req.args.data.encodedDataLength || 0;\n const wastedBytes = (1 - cacheHitProbability) * transferSize;\n\n wastedBytesByRequestId.set(req.args.data.requestId, wastedBytes);\n totalWastedBytes += wastedBytes;\n\n results.push({request: req, ttl, wastedBytes});\n }\n\n // Sort by transfer size.\n results.sort((a, b) => {\n return b.request.args.data.decodedBodyLength - a.request.args.data.decodedBodyLength || a.ttl - b.ttl;\n });\n\n return finalize({\n relatedEvents: results.map(r => r.request),\n requests: results,\n metricSavings: metricSavingsForWastedBytes(wastedBytesByRequestId, context),\n totalWastedBytes,\n });\n}\n"]}