chrome-ai-bridge 1.0.2 → 1.0.4
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/build/node_modules/chrome-devtools-frontend/front_end/core/common/Base64.js +20 -2
- package/build/node_modules/chrome-devtools-frontend/front_end/core/common/Gzip.js +11 -0
- package/build/node_modules/chrome-devtools-frontend/front_end/core/common/Object.js +6 -1
- package/build/node_modules/chrome-devtools-frontend/front_end/core/common/ParsedURL.js +3 -0
- package/build/node_modules/chrome-devtools-frontend/front_end/core/common/ResourceType.js +6 -0
- package/build/node_modules/chrome-devtools-frontend/front_end/core/common/Settings.js +18 -8
- package/build/node_modules/chrome-devtools-frontend/front_end/core/host/InspectorFrontendHostStub.js +3 -3
- package/build/node_modules/chrome-devtools-frontend/front_end/core/host/ResourceLoader.js +1 -1
- package/build/node_modules/chrome-devtools-frontend/front_end/core/host/UserMetrics.js +17 -1
- package/build/node_modules/chrome-devtools-frontend/front_end/core/platform/ArrayUtilities.js +10 -0
- package/build/node_modules/chrome-devtools-frontend/front_end/core/platform/StringUtilities.js +63 -12
- package/build/node_modules/chrome-devtools-frontend/front_end/core/protocol_client/CDPConnection.js +1 -0
- package/build/node_modules/chrome-devtools-frontend/front_end/core/protocol_client/InspectorBackend.js +4 -1
- package/build/node_modules/chrome-devtools-frontend/front_end/core/sdk/CSSMatchedStyles.js +44 -9
- package/build/node_modules/chrome-devtools-frontend/front_end/core/sdk/CSSMetadata.js +6 -6
- package/build/node_modules/chrome-devtools-frontend/front_end/core/sdk/CSSModel.js +1 -1
- package/build/node_modules/chrome-devtools-frontend/front_end/core/sdk/DOMModel.js +169 -12
- package/build/node_modules/chrome-devtools-frontend/front_end/core/sdk/DebuggerModel.js +2 -1
- package/build/node_modules/chrome-devtools-frontend/front_end/core/sdk/IsolateManager.js +6 -0
- package/build/node_modules/chrome-devtools-frontend/front_end/core/sdk/NetworkManager.js +18 -4
- package/build/node_modules/chrome-devtools-frontend/front_end/core/sdk/NetworkRequest.js +7 -21
- package/build/node_modules/chrome-devtools-frontend/front_end/core/sdk/OverlayModel.js +17 -5
- package/build/node_modules/chrome-devtools-frontend/front_end/core/sdk/RehydratingConnection.js +5 -1
- package/build/node_modules/chrome-devtools-frontend/front_end/core/sdk/ResourceTreeModel.js +8 -5
- package/build/node_modules/chrome-devtools-frontend/front_end/core/sdk/SourceMap.js +14 -2
- package/build/node_modules/chrome-devtools-frontend/front_end/core/sdk/SourceMapManager.js +1 -1
- package/build/node_modules/chrome-devtools-frontend/front_end/core/sdk/SourceMapScopesInfo.js +11 -4
- package/build/node_modules/chrome-devtools-frontend/front_end/core/sdk/Target.js +3 -1
- package/build/node_modules/chrome-devtools-frontend/front_end/generated/ARIAProperties.js +1 -1
- package/build/node_modules/chrome-devtools-frontend/front_end/generated/Deprecation.js +1 -16
- package/build/node_modules/chrome-devtools-frontend/front_end/generated/InspectorBackendCommands.js +35 -14
- package/build/node_modules/chrome-devtools-frontend/front_end/generated/SupportedCSSProperties.js +197 -101
- package/build/node_modules/chrome-devtools-frontend/front_end/models/ai_assistance/data_formatters/NetworkRequestFormatter.js +2 -1
- package/build/node_modules/chrome-devtools-frontend/front_end/models/ai_assistance/data_formatters/PerformanceInsightFormatter.js +10 -16
- package/build/node_modules/chrome-devtools-frontend/front_end/models/ai_assistance/data_formatters/PerformanceTraceFormatter.js +97 -26
- package/build/node_modules/chrome-devtools-frontend/front_end/models/ai_assistance/performance/AICallTree.js +35 -0
- package/build/node_modules/chrome-devtools-frontend/front_end/models/bindings/CompilerScriptMapping.js +5 -3
- package/build/node_modules/chrome-devtools-frontend/front_end/models/bindings/DebuggerWorkspaceBinding.js +7 -3
- package/build/node_modules/chrome-devtools-frontend/front_end/models/emulation/DeviceModeModel.js +1 -1
- package/build/node_modules/chrome-devtools-frontend/front_end/models/emulation/EmulatedDevices.js +14 -0
- package/build/node_modules/chrome-devtools-frontend/front_end/models/formatter/FormatterWorkerPool.js +8 -5
- package/build/node_modules/chrome-devtools-frontend/front_end/models/stack_trace/StackTraceImpl.js +70 -1
- package/build/node_modules/chrome-devtools-frontend/front_end/models/stack_trace/StackTraceModel.js +82 -30
- package/build/node_modules/chrome-devtools-frontend/front_end/models/trace/EventsSerializer.js +7 -2
- package/build/node_modules/chrome-devtools-frontend/front_end/models/trace/LanternComputationData.js +2 -2
- package/build/node_modules/chrome-devtools-frontend/front_end/models/trace/Processor.js +18 -19
- package/build/node_modules/chrome-devtools-frontend/front_end/models/trace/Styles.js +12 -4
- package/build/node_modules/chrome-devtools-frontend/front_end/models/trace/extras/Initiators.js +46 -0
- package/build/node_modules/chrome-devtools-frontend/front_end/models/trace/extras/TraceTree.js +4 -3
- package/build/node_modules/chrome-devtools-frontend/front_end/models/trace/extras/extras.js +1 -0
- package/build/node_modules/chrome-devtools-frontend/front_end/models/trace/handlers/LargestImagePaintHandler.js +2 -2
- package/build/node_modules/chrome-devtools-frontend/front_end/models/trace/handlers/LayoutShiftsHandler.js +1 -1
- package/build/node_modules/chrome-devtools-frontend/front_end/models/trace/handlers/MetaHandler.js +6 -0
- package/build/node_modules/chrome-devtools-frontend/front_end/models/trace/handlers/NetworkRequestsHandler.js +10 -1
- package/build/node_modules/chrome-devtools-frontend/front_end/models/trace/handlers/PageLoadMetricsHandler.js +44 -27
- package/build/node_modules/chrome-devtools-frontend/front_end/models/trace/helpers/Timing.js +9 -2
- package/build/node_modules/chrome-devtools-frontend/front_end/models/trace/insights/Common.js +1 -6
- package/build/node_modules/chrome-devtools-frontend/front_end/models/trace/insights/LCPBreakdown.js +2 -2
- package/build/node_modules/chrome-devtools-frontend/front_end/models/trace/insights/LCPDiscovery.js +2 -4
- package/build/node_modules/chrome-devtools-frontend/front_end/models/trace/insights/NetworkDependencyTree.js +3 -2
- package/build/node_modules/chrome-devtools-frontend/front_end/models/trace/insights/RenderBlocking.js +1 -1
- package/build/node_modules/chrome-devtools-frontend/front_end/models/trace/types/TraceEvents.js +30 -11
- package/build/node_modules/chrome-devtools-frontend/front_end/third_party/source-map-scopes-codec/package/src/decode/decode.js +28 -13
- package/build/node_modules/chrome-devtools-frontend/front_end/third_party/source-map-scopes-codec/package/src/encode/encoder.js +1 -1
- package/build/node_modules/chrome-devtools-frontend/front_end/third_party/source-map-scopes-codec/package/src/scopes.js +4 -0
- package/build/src/tools/chatgpt-web.js +102 -64
- package/build/src/tools/gemini-web.js +43 -16
- package/build/src/tools/pages.js +0 -1
- package/package.json +1 -1
|
@@ -8,8 +8,8 @@ import { bytes, millis } from './UnitFormatters.js';
|
|
|
8
8
|
/**
|
|
9
9
|
* For a given frame ID and navigation ID, returns the LCP Event and the LCP Request, if the resource was an image.
|
|
10
10
|
*/
|
|
11
|
-
function getLCPData(parsedTrace, frameId,
|
|
12
|
-
const navMetrics = parsedTrace.data.PageLoadMetrics.metricScoresByFrameId.get(frameId)?.get(
|
|
11
|
+
function getLCPData(parsedTrace, frameId, navigation) {
|
|
12
|
+
const navMetrics = parsedTrace.data.PageLoadMetrics.metricScoresByFrameId.get(frameId)?.get(navigation);
|
|
13
13
|
if (!navMetrics) {
|
|
14
14
|
return null;
|
|
15
15
|
}
|
|
@@ -18,12 +18,14 @@ function getLCPData(parsedTrace, frameId, navigationId) {
|
|
|
18
18
|
return null;
|
|
19
19
|
}
|
|
20
20
|
const lcpEvent = metric?.event;
|
|
21
|
-
if (!lcpEvent || !Trace.Types.Events.
|
|
21
|
+
if (!lcpEvent || !Trace.Types.Events.isAnyLargestContentfulPaintCandidate(lcpEvent)) {
|
|
22
22
|
return null;
|
|
23
23
|
}
|
|
24
|
+
const navigationId = navigation.args.data?.navigationId;
|
|
24
25
|
return {
|
|
25
26
|
lcpEvent,
|
|
26
|
-
lcpRequest: parsedTrace.data.LargestImagePaint.lcpRequestByNavigationId.get(navigationId)
|
|
27
|
+
lcpRequest: navigationId ? parsedTrace.data.LargestImagePaint.lcpRequestByNavigationId.get(navigationId) :
|
|
28
|
+
undefined,
|
|
27
29
|
metricScore: metric,
|
|
28
30
|
};
|
|
29
31
|
}
|
|
@@ -68,14 +70,14 @@ export class PerformanceInsightFormatter {
|
|
|
68
70
|
* Information about LCP which we pass to the LLM for all insights that relate to LCP.
|
|
69
71
|
*/
|
|
70
72
|
#lcpMetricSharedContext() {
|
|
71
|
-
if (!this.#insight.
|
|
73
|
+
if (!this.#insight.navigation) {
|
|
72
74
|
// No navigation ID = no LCP.
|
|
73
75
|
return '';
|
|
74
76
|
}
|
|
75
|
-
if (!this.#insight.frameId || !this.#insight.
|
|
77
|
+
if (!this.#insight.frameId || !this.#insight.navigation) {
|
|
76
78
|
return '';
|
|
77
79
|
}
|
|
78
|
-
const data = getLCPData(this.#parsedTrace, this.#insight.frameId, this.#insight.
|
|
80
|
+
const data = getLCPData(this.#parsedTrace, this.#insight.frameId, this.#insight.navigation);
|
|
79
81
|
if (!data) {
|
|
80
82
|
return '';
|
|
81
83
|
}
|
|
@@ -97,12 +99,6 @@ export class PerformanceInsightFormatter {
|
|
|
97
99
|
return parts.join('\n');
|
|
98
100
|
}
|
|
99
101
|
insightIsSupported() {
|
|
100
|
-
// Although our types don't show it, Insights can end up as Errors if there
|
|
101
|
-
// is an issue in the processing stage. In this case we should gracefully
|
|
102
|
-
// ignore this error.
|
|
103
|
-
if (this.#insight instanceof Error) {
|
|
104
|
-
return false;
|
|
105
|
-
}
|
|
106
102
|
return this.#description().length > 0;
|
|
107
103
|
}
|
|
108
104
|
getSuggestions() {
|
|
@@ -179,7 +175,7 @@ export class PerformanceInsightFormatter {
|
|
|
179
175
|
{ title: 'How can I reduce the amount of legacy JavaScript on my page?' },
|
|
180
176
|
];
|
|
181
177
|
default:
|
|
182
|
-
throw new Error(
|
|
178
|
+
throw new Error(`Unknown insight key '${this.#insight.insightKey}'`);
|
|
183
179
|
}
|
|
184
180
|
}
|
|
185
181
|
/**
|
|
@@ -228,8 +224,6 @@ export class PerformanceInsightFormatter {
|
|
|
228
224
|
potentialRootCauses.push(animationInfoOutput.map(l => ' '.repeat(4) + l).join('\n'));
|
|
229
225
|
});
|
|
230
226
|
rootCauses.unsizedImages.forEach(img => {
|
|
231
|
-
// TODO(b/413284569): if we store a nice human readable name for this
|
|
232
|
-
// image in the trace metadata, we can do something much nicer here.
|
|
233
227
|
const url = img.paintImageEvent.args.data.url;
|
|
234
228
|
const nodeName = img.paintImageEvent.args.data.nodeName;
|
|
235
229
|
const extraText = url ? `url: ${this.#formatUrl(url)}` : `id: ${img.backendNodeId}`;
|
|
@@ -1,6 +1,7 @@
|
|
|
1
1
|
// Copyright 2025 The Chromium Authors
|
|
2
2
|
// Use of this source code is governed by a BSD-style license that can be
|
|
3
3
|
// found in the LICENSE file.
|
|
4
|
+
import * as Annotations from '../../annotations/annotations.js';
|
|
4
5
|
import * as CrUXManager from '../../crux-manager/crux-manager.js';
|
|
5
6
|
import * as Trace from '../../trace/trace.js';
|
|
6
7
|
import { AIQueries } from '../performance/AIQueries.js';
|
|
@@ -12,6 +13,8 @@ export class PerformanceTraceFormatter {
|
|
|
12
13
|
#parsedTrace;
|
|
13
14
|
#insightSet;
|
|
14
15
|
#eventsSerializer;
|
|
16
|
+
#formattedFunctionCodes = new Set();
|
|
17
|
+
resolveFunctionCode;
|
|
15
18
|
constructor(focus) {
|
|
16
19
|
this.#focus = focus;
|
|
17
20
|
this.#parsedTrace = focus.parsedTrace;
|
|
@@ -101,19 +104,19 @@ export class PerformanceTraceFormatter {
|
|
|
101
104
|
parts.push('\n# Available insight sets\n');
|
|
102
105
|
parts.push('The following is a list of insight sets. An insight set covers a specific part of the trace, split by navigations. The insights within each insight set are specific to that part of the trace. Be sure to consider the insight set id and bounds when calling functions. If no specific insight set or navigation is mentioned, assume the user is referring to the first one.');
|
|
103
106
|
for (const insightSet of parsedTrace.insights?.values() ?? []) {
|
|
104
|
-
const lcp =
|
|
105
|
-
const cls =
|
|
106
|
-
const inp =
|
|
107
|
+
const lcp = Trace.Insights.Common.getLCP(insightSet);
|
|
108
|
+
const cls = Trace.Insights.Common.getCLS(insightSet);
|
|
109
|
+
const inp = Trace.Insights.Common.getINP(insightSet);
|
|
107
110
|
parts.push(`\n## insight set id: ${insightSet.id}\n`);
|
|
108
111
|
parts.push(`URL: ${insightSet.url}`);
|
|
109
112
|
parts.push(`Bounds: ${this.serializeBounds(insightSet.bounds)}`);
|
|
110
113
|
if (lcp || cls || inp) {
|
|
111
114
|
parts.push('Metrics (lab / observed):');
|
|
112
115
|
if (lcp) {
|
|
113
|
-
const nodeId = insightSet
|
|
116
|
+
const nodeId = insightSet.model.LCPBreakdown?.lcpEvent?.args.data?.nodeId;
|
|
114
117
|
const nodeIdText = nodeId !== undefined ? `, nodeId: ${nodeId}` : '';
|
|
115
118
|
parts.push(` - LCP: ${Math.round(lcp.value / 1000)} ms, event: ${this.serializeEvent(lcp.event)}${nodeIdText}`);
|
|
116
|
-
const subparts = insightSet
|
|
119
|
+
const subparts = insightSet.model.LCPBreakdown?.subparts;
|
|
117
120
|
if (subparts) {
|
|
118
121
|
const serializeSubpart = (subpart) => {
|
|
119
122
|
return `${micros(subpart.range)}, bounds: ${this.serializeBounds(subpart)}`;
|
|
@@ -135,6 +138,13 @@ export class PerformanceTraceFormatter {
|
|
|
135
138
|
if (cls) {
|
|
136
139
|
const eventText = cls.worstClusterEvent ? `, event: ${this.serializeEvent(cls.worstClusterEvent)}` : '';
|
|
137
140
|
parts.push(` - CLS: ${cls.value.toFixed(2)}${eventText}`);
|
|
141
|
+
if (Annotations.AnnotationRepository.annotationsEnabled()) {
|
|
142
|
+
const worstClusterEvent = cls.worstClusterEvent;
|
|
143
|
+
const layoutShiftData = worstClusterEvent?.worstShiftEvent?.args?.data;
|
|
144
|
+
if (layoutShiftData?.impacted_nodes && layoutShiftData.impacted_nodes?.length > 0) {
|
|
145
|
+
Annotations.AnnotationRepository.instance().addElementsAnnotation('This element is impacted by a layout shift', layoutShiftData.impacted_nodes[0].node_id.toString());
|
|
146
|
+
}
|
|
147
|
+
}
|
|
138
148
|
}
|
|
139
149
|
}
|
|
140
150
|
else {
|
|
@@ -178,7 +188,7 @@ export class PerformanceTraceFormatter {
|
|
|
178
188
|
}
|
|
179
189
|
return parts.join('\n');
|
|
180
190
|
}
|
|
181
|
-
#formatFactByInsightSet(options) {
|
|
191
|
+
async #formatFactByInsightSet(options) {
|
|
182
192
|
const { insights, title, description, empty, cb } = options;
|
|
183
193
|
const lines = [`# ${title}\n`];
|
|
184
194
|
if (description) {
|
|
@@ -190,7 +200,7 @@ export class PerformanceTraceFormatter {
|
|
|
190
200
|
if (multipleInsightSets) {
|
|
191
201
|
lines.push(`## insight set id: ${insightSet.id}\n`);
|
|
192
202
|
}
|
|
193
|
-
lines.push((cb(insightSet) ?? empty) + '\n');
|
|
203
|
+
lines.push((await cb(insightSet) ?? empty) + '\n');
|
|
194
204
|
}
|
|
195
205
|
}
|
|
196
206
|
else {
|
|
@@ -204,18 +214,18 @@ export class PerformanceTraceFormatter {
|
|
|
204
214
|
insights: parsedTrace.insights,
|
|
205
215
|
title: 'Critical network requests',
|
|
206
216
|
empty: 'none',
|
|
207
|
-
cb: insightSet => {
|
|
217
|
+
cb: async (insightSet) => {
|
|
208
218
|
const criticalRequests = [];
|
|
209
219
|
const walkRequest = (node) => {
|
|
210
220
|
criticalRequests.push(node.request);
|
|
211
221
|
node.children.forEach(walkRequest);
|
|
212
222
|
};
|
|
213
|
-
insightSet.model.NetworkDependencyTree
|
|
223
|
+
insightSet.model.NetworkDependencyTree?.rootNodes.forEach(walkRequest);
|
|
214
224
|
return criticalRequests.length ? this.formatNetworkRequests(criticalRequests, { verbose: false }) : null;
|
|
215
225
|
},
|
|
216
226
|
});
|
|
217
227
|
}
|
|
218
|
-
#serializeBottomUpRootNode(rootNode, limit) {
|
|
228
|
+
async #serializeBottomUpRootNode(rootNode, limit) {
|
|
219
229
|
// Sorted by selfTime.
|
|
220
230
|
// No nodes less than 1 ms.
|
|
221
231
|
// Limit.
|
|
@@ -223,15 +233,20 @@ export class PerformanceTraceFormatter {
|
|
|
223
233
|
.filter(n => n.totalTime >= 1)
|
|
224
234
|
.sort((a, b) => b.selfTime - a.selfTime)
|
|
225
235
|
.slice(0, limit);
|
|
236
|
+
const callFrames = [];
|
|
226
237
|
function nodeToText(node) {
|
|
227
238
|
const event = node.event;
|
|
228
239
|
let frame;
|
|
229
240
|
if (Trace.Types.Events.isProfileCall(event)) {
|
|
230
241
|
frame = event.callFrame;
|
|
242
|
+
if (node.selfTime >= 100 && callFrames.length < 3) {
|
|
243
|
+
callFrames.push(frame);
|
|
244
|
+
}
|
|
231
245
|
}
|
|
232
246
|
else {
|
|
233
247
|
frame = Trace.Helpers.Trace.getStackTraceTopCallFrameInEventPayload(event);
|
|
234
248
|
}
|
|
249
|
+
// TODO(crbug.com/452333154): this is not source mapped.
|
|
235
250
|
let source = Trace.Name.forEntry(event);
|
|
236
251
|
if (frame?.url) {
|
|
237
252
|
source += ` (url: ${frame.url}`;
|
|
@@ -245,7 +260,8 @@ export class PerformanceTraceFormatter {
|
|
|
245
260
|
}
|
|
246
261
|
return `- self: ${millis(node.selfTime)}, total: ${millis(node.totalTime)}, source: ${source}`;
|
|
247
262
|
}
|
|
248
|
-
return topNodes.map(node => nodeToText.call(this, node)).join('\n')
|
|
263
|
+
return topNodes.map(node => nodeToText.call(this, node)).join('\n') +
|
|
264
|
+
await this.#serializeRelevantFunctions(callFrames);
|
|
249
265
|
}
|
|
250
266
|
#getSerializeBottomUpRootNodeFormat(limit) {
|
|
251
267
|
return `This is the bottom-up summary for the entire trace. Only the top ${limit} activities (sorted by self time) are shown. An activity is all the aggregated time spent on the same type of work. For example, it can be all the time spent in a specific JavaScript function, or all the time spent in a specific browser rendering stage (like layout, v8 compile, parsing html). "Self time" represents the aggregated time spent directly in an activity, across all occurrences. "Total time" represents the aggregated time spent in an activity or any of its children.`;
|
|
@@ -258,9 +274,9 @@ export class PerformanceTraceFormatter {
|
|
|
258
274
|
title: 'Main thread bottom-up summary',
|
|
259
275
|
description: this.#getSerializeBottomUpRootNodeFormat(limit),
|
|
260
276
|
empty: 'no activity',
|
|
261
|
-
cb: insightSet => {
|
|
277
|
+
cb: async (insightSet) => {
|
|
262
278
|
const rootNode = AIQueries.mainThreadActivityBottomUpSingleNavigation(insightSet.navigation?.args.data?.navigationId, insightSet.bounds, parsedTrace);
|
|
263
|
-
return rootNode ? this.#serializeBottomUpRootNode(rootNode, limit) : null;
|
|
279
|
+
return rootNode ? await this.#serializeBottomUpRootNode(rootNode, limit) : null;
|
|
264
280
|
},
|
|
265
281
|
});
|
|
266
282
|
}
|
|
@@ -283,7 +299,7 @@ export class PerformanceTraceFormatter {
|
|
|
283
299
|
insights: parsedTrace.insights,
|
|
284
300
|
title: '3rd party summary',
|
|
285
301
|
empty: 'no 3rd parties',
|
|
286
|
-
cb: insightSet => {
|
|
302
|
+
cb: async (insightSet) => {
|
|
287
303
|
const thirdPartySummaries = Trace.Extras.ThirdParties.summarizeByThirdParty(parsedTrace.data, insightSet.bounds);
|
|
288
304
|
return thirdPartySummaries.length ? this.#formatThirdPartyEntitySummaries(thirdPartySummaries) : null;
|
|
289
305
|
},
|
|
@@ -295,7 +311,7 @@ export class PerformanceTraceFormatter {
|
|
|
295
311
|
insights: parsedTrace.insights,
|
|
296
312
|
title: 'Longest tasks',
|
|
297
313
|
empty: 'none',
|
|
298
|
-
cb: insightSet => {
|
|
314
|
+
cb: async (insightSet) => {
|
|
299
315
|
const longestTaskTrees = AIQueries.longestTasks(insightSet.navigation?.args.data?.navigationId, insightSet.bounds, parsedTrace, 3);
|
|
300
316
|
if (!longestTaskTrees?.length) {
|
|
301
317
|
return null;
|
|
@@ -342,7 +358,7 @@ export class PerformanceTraceFormatter {
|
|
|
342
358
|
}
|
|
343
359
|
return results.join('\n');
|
|
344
360
|
}
|
|
345
|
-
formatMainThreadTrackSummary(bounds) {
|
|
361
|
+
async formatMainThreadTrackSummary(bounds) {
|
|
346
362
|
if (!this.#parsedTrace.insights) {
|
|
347
363
|
return 'No main thread activity found';
|
|
348
364
|
}
|
|
@@ -351,14 +367,14 @@ export class PerformanceTraceFormatter {
|
|
|
351
367
|
const topDownTree = AIQueries.mainThreadActivityTopDown(insightSet?.navigation?.args.data?.navigationId, bounds, this.#parsedTrace);
|
|
352
368
|
if (topDownTree) {
|
|
353
369
|
results.push('# Top-down main thread summary');
|
|
354
|
-
results.push(this.formatCallTree(topDownTree, 2 /* headerLevel */));
|
|
370
|
+
results.push(await this.formatCallTree(topDownTree, 2 /* headerLevel */));
|
|
355
371
|
}
|
|
356
372
|
const bottomUpRootNode = AIQueries.mainThreadActivityBottomUp(bounds, this.#parsedTrace);
|
|
357
373
|
if (bottomUpRootNode) {
|
|
358
374
|
results.push('# Bottom-up main thread summary');
|
|
359
375
|
const limit = 20;
|
|
360
376
|
results.push(this.#getSerializeBottomUpRootNodeFormat(limit));
|
|
361
|
-
results.push(this.#serializeBottomUpRootNode(bottomUpRootNode, limit));
|
|
377
|
+
results.push(await this.#serializeBottomUpRootNode(bottomUpRootNode, limit));
|
|
362
378
|
}
|
|
363
379
|
const thirdPartySummaries = Trace.Extras.ThirdParties.summarizeByThirdParty(this.#parsedTrace.data, bounds);
|
|
364
380
|
if (thirdPartySummaries.length) {
|
|
@@ -390,8 +406,19 @@ export class PerformanceTraceFormatter {
|
|
|
390
406
|
}
|
|
391
407
|
return results.join('\n\n');
|
|
392
408
|
}
|
|
393
|
-
formatCallTree(tree, headerLevel = 1) {
|
|
394
|
-
|
|
409
|
+
async formatCallTree(tree, headerLevel = 1) {
|
|
410
|
+
let result = `${tree.serialize(headerLevel)}\n\nIMPORTANT: Never show eventKey to the user.\n`;
|
|
411
|
+
const relevantCallFrames = [];
|
|
412
|
+
if (tree.selectedNode && Trace.Types.Events.isProfileCall(tree.selectedNode.event)) {
|
|
413
|
+
relevantCallFrames.push(tree.selectedNode.event.callFrame);
|
|
414
|
+
}
|
|
415
|
+
const topCallFrameByTotalTime = tree.topCallFrameByTotalTime();
|
|
416
|
+
if (topCallFrameByTotalTime) {
|
|
417
|
+
relevantCallFrames.push(topCallFrameByTotalTime);
|
|
418
|
+
}
|
|
419
|
+
relevantCallFrames.push(...tree.topCallFramesBySelfTime(3));
|
|
420
|
+
result += await this.#serializeRelevantFunctions(relevantCallFrames);
|
|
421
|
+
return result;
|
|
395
422
|
}
|
|
396
423
|
formatNetworkRequests(requests, options) {
|
|
397
424
|
if (requests.length === 0) {
|
|
@@ -424,7 +451,7 @@ export class PerformanceTraceFormatter {
|
|
|
424
451
|
const initiators = [];
|
|
425
452
|
let cur = request;
|
|
426
453
|
while (cur) {
|
|
427
|
-
const initiator =
|
|
454
|
+
const initiator = Trace.Extras.Initiators.getNetworkInitiator(parsedTrace.data, cur);
|
|
428
455
|
if (initiator) {
|
|
429
456
|
// Should never happen, but if it did that would be an infinite loop.
|
|
430
457
|
if (initiators.includes(initiator)) {
|
|
@@ -445,7 +472,7 @@ export class PerformanceTraceFormatter {
|
|
|
445
472
|
* talk to jacktfranklin@.
|
|
446
473
|
*/
|
|
447
474
|
#networkRequestVerbosely(request, options) {
|
|
448
|
-
const { url, statusCode, initialPriority, priority, fromServiceWorker, mimeType, responseHeaders, syntheticData, protocol } = request.args.data;
|
|
475
|
+
const { url, requestId, statusCode, initialPriority, priority, fromServiceWorker, mimeType, responseHeaders, syntheticData, protocol } = request.args.data;
|
|
449
476
|
const parsedTrace = this.#parsedTrace;
|
|
450
477
|
const titlePrefix = `## ${options?.customTitle ?? 'Network request'}`;
|
|
451
478
|
// Note: unlike other agents, we do have the ability to include
|
|
@@ -464,7 +491,7 @@ export class PerformanceTraceFormatter {
|
|
|
464
491
|
const mainThreadProcessingDuration = startTimesForLifecycle.processingCompletedAt - startTimesForLifecycle.downloadCompletedAt;
|
|
465
492
|
const downloadTime = syntheticData.finishTime - syntheticData.downloadStart;
|
|
466
493
|
const renderBlocking = Trace.Helpers.Network.isSyntheticNetworkRequestEventRenderBlocking(request);
|
|
467
|
-
const initiator =
|
|
494
|
+
const initiator = Trace.Extras.Initiators.getNetworkInitiator(parsedTrace.data, request);
|
|
468
495
|
const priorityLines = [];
|
|
469
496
|
if (initialPriority === priority) {
|
|
470
497
|
priorityLines.push(`Priority: ${priority}`);
|
|
@@ -483,7 +510,7 @@ export class PerformanceTraceFormatter {
|
|
|
483
510
|
const initiatorUrls = initiators.map(initiator => initiator.args.data.url);
|
|
484
511
|
const eventKey = this.#eventsSerializer.keyForEvent(request);
|
|
485
512
|
const eventKeyLine = eventKey ? `eventKey: ${eventKey}\n` : '';
|
|
486
|
-
return `${titlePrefix}: ${url}
|
|
513
|
+
return `${titlePrefix}: ${url}${Annotations.AnnotationRepository.annotationsEnabled() ? `\nrequestId: ${requestId}` : ''}
|
|
487
514
|
${eventKeyLine}Timings:
|
|
488
515
|
- Queued at: ${micros(startTimesForLifecycle.queuedAt)}
|
|
489
516
|
- Request sent at: ${micros(startTimesForLifecycle.requestSentAt)}
|
|
@@ -648,17 +675,61 @@ The order of headers corresponds to an internal fixed list. If a header is not p
|
|
|
648
675
|
];
|
|
649
676
|
return parts.join(';');
|
|
650
677
|
}
|
|
678
|
+
resolveFunctionCodeAtLocation(url, line, column) {
|
|
679
|
+
if (!this.resolveFunctionCode) {
|
|
680
|
+
throw new Error('missing resolveFunctionCode');
|
|
681
|
+
}
|
|
682
|
+
return this.resolveFunctionCode(url, line, column);
|
|
683
|
+
}
|
|
651
684
|
formatFunctionCode(code) {
|
|
685
|
+
return this.#getFormattedFunctionCodeExplainer() + '\n\n' + this.#formatFunctionCode(code);
|
|
686
|
+
}
|
|
687
|
+
#getFormattedFunctionCodeExplainer() {
|
|
688
|
+
return 'The following are markdown block(s) of code that ran in the page, each representing a separate function. <FUNCTION_START> and <FUNCTION_END> marks the exact function declaration, and everything outside that is provided for additional context. Comments at the end of each line indicate the runtime performance cost of that code. Do not show the user the function markers or the additional context.';
|
|
689
|
+
}
|
|
690
|
+
#functionCodeToKey(code) {
|
|
691
|
+
return code.functionBounds.uiSourceCode.url() + ':' + code.functionBounds.range.toString();
|
|
692
|
+
}
|
|
693
|
+
#hasFormattedFunctionCode(code) {
|
|
694
|
+
return this.#formattedFunctionCodes.has(this.#functionCodeToKey(code));
|
|
695
|
+
}
|
|
696
|
+
#formatFunctionCode(code) {
|
|
697
|
+
this.#formattedFunctionCodes.add(this.#functionCodeToKey(code));
|
|
652
698
|
const { startLine, startColumn } = code.range;
|
|
653
699
|
const { startLine: contextStartLine, startColumn: contextStartColumn, endLine: contextEndLine, endColumn: contextEndColumn } = code.rangeWithContext;
|
|
654
|
-
const name = code.functionBounds.name;
|
|
700
|
+
const name = code.functionBounds.name || '(anonymous)';
|
|
655
701
|
const url = code.functionBounds.uiSourceCode.url();
|
|
656
702
|
const parts = [];
|
|
657
703
|
parts.push(`${name} @ ${url}:${startLine}:${startColumn}. With added context, chunk is from ${contextStartLine}:${contextStartColumn} to ${contextEndLine}:${contextEndColumn}`);
|
|
658
|
-
parts.push('\nThe following is a markdown block of JavaScript. <FUNCTION_START> and <FUNCTION_END> marks the exact function declaration, and everything outside that is provided for additional context. Comments at the end of each line indicate the runtime performance cost of that code. Do not show the user the function markers or the additional context.\n');
|
|
659
704
|
parts.push('```');
|
|
660
705
|
parts.push(code.codeWithContext);
|
|
661
706
|
parts.push('```');
|
|
662
707
|
return parts.join('\n');
|
|
663
708
|
}
|
|
709
|
+
/**
|
|
710
|
+
* Appends the code of each call frame's function, but only if the function was not
|
|
711
|
+
* serialized previously.
|
|
712
|
+
*/
|
|
713
|
+
async #serializeRelevantFunctions(callFrames) {
|
|
714
|
+
const resolveFunctionCode = this.resolveFunctionCode;
|
|
715
|
+
if (!resolveFunctionCode) {
|
|
716
|
+
return '';
|
|
717
|
+
}
|
|
718
|
+
const functionCodeStrings = [];
|
|
719
|
+
const functionCodes = await Promise.all(callFrames.map(frame => resolveFunctionCode(frame.url, frame.lineNumber, frame.columnNumber)));
|
|
720
|
+
for (const code of functionCodes) {
|
|
721
|
+
if (code && !this.#hasFormattedFunctionCode(code)) {
|
|
722
|
+
functionCodeStrings.push(this.#formatFunctionCode(code));
|
|
723
|
+
}
|
|
724
|
+
}
|
|
725
|
+
if (!functionCodeStrings.length) {
|
|
726
|
+
return '';
|
|
727
|
+
}
|
|
728
|
+
return '\n' + [
|
|
729
|
+
this.#getFormattedFunctionCodeExplainer(),
|
|
730
|
+
functionCodeStrings.length > 1 ? `Here are ${functionCodeStrings.length} relevant functions:` :
|
|
731
|
+
`Here is a relevant function:`,
|
|
732
|
+
...functionCodeStrings,
|
|
733
|
+
].join('\n\n');
|
|
734
|
+
}
|
|
664
735
|
}
|
|
@@ -319,6 +319,41 @@ export class AICallTree {
|
|
|
319
319
|
}
|
|
320
320
|
return line;
|
|
321
321
|
}
|
|
322
|
+
topCallFramesBySelfTime(limit) {
|
|
323
|
+
const functionNodesByCallFrame = new Map();
|
|
324
|
+
this.breadthFirstWalk(this.rootNode.children().values(), node => {
|
|
325
|
+
if (Trace.Types.Events.isProfileCall(node.event)) {
|
|
326
|
+
const callFrame = node.event.callFrame;
|
|
327
|
+
const callFrameKey = `${callFrame.scriptId}:${callFrame.lineNumber}:${callFrame.columnNumber}`;
|
|
328
|
+
const array = functionNodesByCallFrame.get(callFrameKey) ?? [];
|
|
329
|
+
array.push(node);
|
|
330
|
+
functionNodesByCallFrame.set(callFrameKey, array);
|
|
331
|
+
}
|
|
332
|
+
});
|
|
333
|
+
return [...functionNodesByCallFrame.values()]
|
|
334
|
+
.map(nodes => {
|
|
335
|
+
return {
|
|
336
|
+
callFrame: nodes[0].event.callFrame,
|
|
337
|
+
selfTime: nodes.reduce((total, cur) => total + cur.selfTime, 0),
|
|
338
|
+
};
|
|
339
|
+
})
|
|
340
|
+
.sort((a, b) => b.selfTime - a.selfTime)
|
|
341
|
+
.slice(0, limit)
|
|
342
|
+
.map(({ callFrame }) => callFrame);
|
|
343
|
+
}
|
|
344
|
+
topCallFrameByTotalTime() {
|
|
345
|
+
let topChild = null;
|
|
346
|
+
let topProfileCallEvent = null;
|
|
347
|
+
for (const child of this.rootNode.children().values()) {
|
|
348
|
+
if (Trace.Types.Events.isProfileCall(child.event)) {
|
|
349
|
+
if (!topChild || child.totalTime > topChild.totalTime) {
|
|
350
|
+
topChild = child;
|
|
351
|
+
topProfileCallEvent = child.event;
|
|
352
|
+
}
|
|
353
|
+
}
|
|
354
|
+
}
|
|
355
|
+
return topProfileCallEvent?.callFrame ?? null;
|
|
356
|
+
}
|
|
322
357
|
// Only used for debugging.
|
|
323
358
|
logDebug() {
|
|
324
359
|
const str = this.serialize();
|
|
@@ -229,6 +229,7 @@ export class CompilerScriptMapping {
|
|
|
229
229
|
if (!sourceMap) {
|
|
230
230
|
return null;
|
|
231
231
|
}
|
|
232
|
+
await sourceMap.waitForScopeInfo();
|
|
232
233
|
const { lineNumber, columnNumber } = script.rawLocationToRelativeLocation(rawLocation);
|
|
233
234
|
const { url, scope } = sourceMap.findOriginalFunctionScope({ line: lineNumber, column: columnNumber }) ?? {};
|
|
234
235
|
if (!scope || !url) {
|
|
@@ -254,21 +255,22 @@ export class CompilerScriptMapping {
|
|
|
254
255
|
const range = new TextUtils.TextRange.TextRange(scope.start.line, scope.start.column, scope.end.line, scope.end.column);
|
|
255
256
|
return new Workspace.UISourceCode.UIFunctionBounds(uiSourceCode, range, name);
|
|
256
257
|
}
|
|
257
|
-
translateRawFramesStep(rawFrames, translatedFrames) {
|
|
258
|
+
async translateRawFramesStep(rawFrames, translatedFrames) {
|
|
258
259
|
const frame = rawFrames[0];
|
|
259
260
|
if (StackTraceImpl.Trie.isBuiltinFrame(frame)) {
|
|
260
261
|
return false;
|
|
261
262
|
}
|
|
262
|
-
const sourceMapWithScopeInfoForFrame = (rawFrame) => {
|
|
263
|
+
const sourceMapWithScopeInfoForFrame = async (rawFrame) => {
|
|
263
264
|
const script = this.#debuggerModel.scriptForId(rawFrame.scriptId ?? '');
|
|
264
265
|
if (!script || this.#stubUISourceCodes.has(script)) {
|
|
265
266
|
// Use fallback while source map is being loaded.
|
|
266
267
|
return null;
|
|
267
268
|
}
|
|
268
269
|
const sourceMap = script.sourceMap();
|
|
270
|
+
await sourceMap?.waitForScopeInfo();
|
|
269
271
|
return sourceMap?.hasScopeInfo() ? { sourceMap, script } : null;
|
|
270
272
|
};
|
|
271
|
-
const sourceMapAndScript = sourceMapWithScopeInfoForFrame(frame);
|
|
273
|
+
const sourceMapAndScript = await sourceMapWithScopeInfoForFrame(frame);
|
|
272
274
|
if (!sourceMapAndScript) {
|
|
273
275
|
return false;
|
|
274
276
|
}
|
|
@@ -141,6 +141,10 @@ export class DebuggerWorkspaceBinding {
|
|
|
141
141
|
const model = target.model(StackTraceImpl.StackTraceModel.StackTraceModel);
|
|
142
142
|
return await model.createFromProtocolRuntime(stackTrace, this.#translateRawFrames.bind(this));
|
|
143
143
|
}
|
|
144
|
+
async createStackTraceFromDebuggerPaused(pausedDetails, target) {
|
|
145
|
+
const model = target.model(StackTraceImpl.StackTraceModel.StackTraceModel);
|
|
146
|
+
return await model.createFromDebuggerPaused(pausedDetails, this.#translateRawFrames.bind(this));
|
|
147
|
+
}
|
|
144
148
|
async createLiveLocation(rawLocation, updateDelegate, locationPool) {
|
|
145
149
|
const modelData = this.#debuggerModelToData.get(rawLocation.debuggerModel);
|
|
146
150
|
if (!modelData) {
|
|
@@ -382,7 +386,7 @@ export class DebuggerWorkspaceBinding {
|
|
|
382
386
|
}
|
|
383
387
|
const modelData = this.#debuggerModelToData.get(target.model(SDK.DebuggerModel.DebuggerModel));
|
|
384
388
|
if (modelData) {
|
|
385
|
-
modelData.translateRawFramesStep(rawFrames, translatedFrames);
|
|
389
|
+
await modelData.translateRawFramesStep(rawFrames, translatedFrames);
|
|
386
390
|
return;
|
|
387
391
|
}
|
|
388
392
|
const frame = rawFrames.shift();
|
|
@@ -473,8 +477,8 @@ class ModelData {
|
|
|
473
477
|
scope = scope || await this.#resourceMapping.functionBoundsAtRawLocation(rawLocation);
|
|
474
478
|
return scope;
|
|
475
479
|
}
|
|
476
|
-
translateRawFramesStep(rawFrames, translatedFrames) {
|
|
477
|
-
if (!this.compilerMapping.translateRawFramesStep(rawFrames, translatedFrames)) {
|
|
480
|
+
async translateRawFramesStep(rawFrames, translatedFrames) {
|
|
481
|
+
if (!await this.compilerMapping.translateRawFramesStep(rawFrames, translatedFrames)) {
|
|
478
482
|
this.#defaultTranslateRawFramesStep(rawFrames, translatedFrames);
|
|
479
483
|
}
|
|
480
484
|
}
|
package/build/node_modules/chrome-devtools-frontend/front_end/models/emulation/DeviceModeModel.js
CHANGED
|
@@ -107,7 +107,7 @@ export class DeviceModeModel extends Common.ObjectWrapper.ObjectWrapper {
|
|
|
107
107
|
this.#preferredSize = new Geometry.Size(1, 1);
|
|
108
108
|
this.#initialized = false;
|
|
109
109
|
this.#appliedDeviceSize = new Geometry.Size(1, 1);
|
|
110
|
-
this.#appliedDeviceScaleFactor =
|
|
110
|
+
this.#appliedDeviceScaleFactor = globalThis.devicePixelRatio;
|
|
111
111
|
this.#appliedUserAgentType = "Desktop" /* UA.DESKTOP */;
|
|
112
112
|
this.#scaleSetting = Common.Settings.Settings.instance().createSetting('emulation.device-scale', 1);
|
|
113
113
|
// We've used to allow zero before.
|
package/build/node_modules/chrome-devtools-frontend/front_end/models/emulation/EmulatedDevices.js
CHANGED
|
@@ -550,6 +550,7 @@ const emulatedDevices = [
|
|
|
550
550
|
},
|
|
551
551
|
'capabilities': ['touch', 'mobile'],
|
|
552
552
|
'user-agent': 'Mozilla/5.0 (iPhone; CPU iPhone OS 18_5 like Mac OS X) AppleWebKit/605.1.15 (KHTML, like Gecko) Version/18.5 Mobile/15E148 Safari/604.1',
|
|
553
|
+
'user-agent-metadata': { 'platform': 'iOS', 'platformVersion': '18.5', 'architecture': '', 'model': 'iPhone', 'mobile': true },
|
|
553
554
|
'type': 'phone',
|
|
554
555
|
},
|
|
555
556
|
{
|
|
@@ -569,6 +570,7 @@ const emulatedDevices = [
|
|
|
569
570
|
},
|
|
570
571
|
'capabilities': ['touch', 'mobile'],
|
|
571
572
|
'user-agent': 'Mozilla/5.0 (iPhone; CPU iPhone OS 18_5 like Mac OS X) AppleWebKit/605.1.15 (KHTML, like Gecko) Version/18.5 Mobile/15E148 Safari/604.1',
|
|
573
|
+
'user-agent-metadata': { 'platform': 'iOS', 'platformVersion': '18.5', 'architecture': '', 'model': 'iPhone', 'mobile': true },
|
|
572
574
|
'type': 'phone',
|
|
573
575
|
},
|
|
574
576
|
{
|
|
@@ -588,6 +590,7 @@ const emulatedDevices = [
|
|
|
588
590
|
},
|
|
589
591
|
'capabilities': ['touch', 'mobile'],
|
|
590
592
|
'user-agent': 'Mozilla/5.0 (iPhone; CPU iPhone OS 18_5 like Mac OS X) AppleWebKit/605.1.15 (KHTML, like Gecko) Version/18.5 Mobile/15E148 Safari/604.1',
|
|
593
|
+
'user-agent-metadata': { 'platform': 'iOS', 'platformVersion': '18.5', 'architecture': '', 'model': 'iPhone', 'mobile': true },
|
|
591
594
|
'type': 'phone',
|
|
592
595
|
},
|
|
593
596
|
{
|
|
@@ -607,6 +610,7 @@ const emulatedDevices = [
|
|
|
607
610
|
},
|
|
608
611
|
'capabilities': ['touch', 'mobile'],
|
|
609
612
|
'user-agent': 'Mozilla/5.0 (iPhone; CPU iPhone OS 18_5 like Mac OS X) AppleWebKit/605.1.15 (KHTML, like Gecko) Version/18.5 Mobile/15E148 Safari/604.1',
|
|
613
|
+
'user-agent-metadata': { 'platform': 'iOS', 'platformVersion': '18.5', 'architecture': '', 'model': 'iPhone', 'mobile': true },
|
|
610
614
|
'type': 'phone',
|
|
611
615
|
},
|
|
612
616
|
{
|
|
@@ -706,6 +710,7 @@ const emulatedDevices = [
|
|
|
706
710
|
},
|
|
707
711
|
'capabilities': ['touch', 'mobile'],
|
|
708
712
|
'user-agent': 'Mozilla/5.0 (iPad; CPU OS 18_5 like Mac OS X) AppleWebKit/605.1.15 (KHTML, like Gecko) Version/18.5 Mobile/15E148 Safari/604.1',
|
|
713
|
+
'user-agent-metadata': { 'platform': 'iOS', 'platformVersion': '18.5', 'architecture': '', 'model': 'iPad', 'mobile': true },
|
|
709
714
|
'type': 'tablet',
|
|
710
715
|
},
|
|
711
716
|
{
|
|
@@ -725,6 +730,7 @@ const emulatedDevices = [
|
|
|
725
730
|
},
|
|
726
731
|
'capabilities': ['touch', 'mobile'],
|
|
727
732
|
'user-agent': 'Mozilla/5.0 (Macintosh; Intel Mac OS X 10_15_7) AppleWebKit/605.1.15 (KHTML, like Gecko) Version/18.5 Safari/605.1.15',
|
|
733
|
+
'user-agent-metadata': { 'platform': 'iOS', 'platformVersion': '18.5', 'architecture': '', 'model': 'iPad', 'mobile': true },
|
|
728
734
|
'type': 'tablet',
|
|
729
735
|
},
|
|
730
736
|
{
|
|
@@ -744,6 +750,7 @@ const emulatedDevices = [
|
|
|
744
750
|
},
|
|
745
751
|
'capabilities': ['touch', 'mobile'],
|
|
746
752
|
'user-agent': 'Mozilla/5.0 (Macintosh; Intel Mac OS X 10_15_7) AppleWebKit/605.1.15 (KHTML, like Gecko) Version/18.5 Safari/605.1.15',
|
|
753
|
+
'user-agent-metadata': { 'platform': 'iOS', 'platformVersion': '18.5', 'architecture': '', 'model': 'iPad', 'mobile': true },
|
|
747
754
|
'type': 'tablet',
|
|
748
755
|
},
|
|
749
756
|
{
|
|
@@ -982,6 +989,7 @@ const emulatedDevices = [
|
|
|
982
989
|
},
|
|
983
990
|
'capabilities': ['touch', 'mobile'],
|
|
984
991
|
'user-agent': 'Mozilla/5.0 (iPhone; CPU iPhone OS 7_1_2 like Mac OS X) AppleWebKit/537.51.2 (KHTML, like Gecko) Version/7.0 Mobile/11D257 Safari/9537.53',
|
|
992
|
+
'user-agent-metadata': { 'platform': 'iOS', 'platformVersion': '7.1.2', 'architecture': '', 'model': 'iPhone', 'mobile': true },
|
|
985
993
|
'type': 'phone',
|
|
986
994
|
},
|
|
987
995
|
{
|
|
@@ -1009,6 +1017,7 @@ const emulatedDevices = [
|
|
|
1009
1017
|
},
|
|
1010
1018
|
'capabilities': ['touch', 'mobile'],
|
|
1011
1019
|
'user-agent': 'Mozilla/5.0 (iPhone; CPU iPhone OS 10_3_1 like Mac OS X) AppleWebKit/603.1.30 (KHTML, like Gecko) Version/10.0 Mobile/14E304 Safari/602.1',
|
|
1020
|
+
'user-agent-metadata': { 'platform': 'iOS', 'platformVersion': '10.3.1', 'architecture': '', 'model': 'iPhone', 'mobile': true },
|
|
1012
1021
|
'type': 'phone',
|
|
1013
1022
|
},
|
|
1014
1023
|
{
|
|
@@ -1036,6 +1045,7 @@ const emulatedDevices = [
|
|
|
1036
1045
|
},
|
|
1037
1046
|
'capabilities': ['touch', 'mobile'],
|
|
1038
1047
|
'user-agent': 'Mozilla/5.0 (iPhone; CPU iPhone OS 13_2_3 like Mac OS X) AppleWebKit/605.1.15 (KHTML, like Gecko) Version/13.0.3 Mobile/15E148 Safari/604.1',
|
|
1048
|
+
'user-agent-metadata': { 'platform': 'iOS', 'platformVersion': '13.2.3', 'architecture': '', 'model': 'iPhone', 'mobile': true },
|
|
1039
1049
|
'type': 'phone',
|
|
1040
1050
|
},
|
|
1041
1051
|
{
|
|
@@ -1063,6 +1073,7 @@ const emulatedDevices = [
|
|
|
1063
1073
|
},
|
|
1064
1074
|
'capabilities': ['touch', 'mobile'],
|
|
1065
1075
|
'user-agent': 'Mozilla/5.0 (iPhone; CPU iPhone OS 13_2_3 like Mac OS X) AppleWebKit/605.1.15 (KHTML, like Gecko) Version/13.0.3 Mobile/15E148 Safari/604.1',
|
|
1076
|
+
'user-agent-metadata': { 'platform': 'iOS', 'platformVersion': '13.2.3', 'architecture': '', 'model': 'iPhone', 'mobile': true },
|
|
1066
1077
|
'type': 'phone',
|
|
1067
1078
|
},
|
|
1068
1079
|
{
|
|
@@ -1076,6 +1087,7 @@ const emulatedDevices = [
|
|
|
1076
1087
|
},
|
|
1077
1088
|
'capabilities': ['touch', 'mobile'],
|
|
1078
1089
|
'user-agent': 'Mozilla/5.0 (iPhone; CPU iPhone OS 13_2_3 like Mac OS X) AppleWebKit/605.1.15 (KHTML, like Gecko) Version/13.0.3 Mobile/15E148 Safari/604.1',
|
|
1090
|
+
'user-agent-metadata': { 'platform': 'iOS', 'platformVersion': '13.2.3', 'architecture': '', 'model': 'iPhone', 'mobile': true },
|
|
1079
1091
|
'type': 'phone',
|
|
1080
1092
|
},
|
|
1081
1093
|
{
|
|
@@ -1499,6 +1511,7 @@ const emulatedDevices = [
|
|
|
1499
1511
|
},
|
|
1500
1512
|
'capabilities': ['touch', 'mobile'],
|
|
1501
1513
|
'user-agent': 'Mozilla/5.0 (iPad; CPU OS 11_0 like Mac OS X) AppleWebKit/604.1.34 (KHTML, like Gecko) Version/11.0 Mobile/15A5341f Safari/604.1',
|
|
1514
|
+
'user-agent-metadata': { 'platform': 'iOS', 'platformVersion': '11.0', 'architecture': '', 'model': 'iPad', 'mobile': true },
|
|
1502
1515
|
'type': 'tablet',
|
|
1503
1516
|
},
|
|
1504
1517
|
{
|
|
@@ -1512,6 +1525,7 @@ const emulatedDevices = [
|
|
|
1512
1525
|
},
|
|
1513
1526
|
'capabilities': ['touch', 'mobile'],
|
|
1514
1527
|
'user-agent': 'Mozilla/5.0 (iPad; CPU OS 11_0 like Mac OS X) AppleWebKit/604.1.34 (KHTML, like Gecko) Version/11.0 Mobile/15A5341f Safari/604.1',
|
|
1528
|
+
'user-agent-metadata': { 'platform': 'iOS', 'platformVersion': '11.0', 'architecture': '', 'model': 'iPad', 'mobile': true },
|
|
1515
1529
|
'type': 'tablet',
|
|
1516
1530
|
},
|
|
1517
1531
|
{
|
|
@@ -6,13 +6,16 @@ let formatterWorkerPoolInstance;
|
|
|
6
6
|
export class FormatterWorkerPool {
|
|
7
7
|
taskQueue;
|
|
8
8
|
workerTasks;
|
|
9
|
-
|
|
9
|
+
entrypointURL;
|
|
10
|
+
constructor(entrypointURL) {
|
|
10
11
|
this.taskQueue = [];
|
|
11
12
|
this.workerTasks = new Map();
|
|
13
|
+
this.entrypointURL =
|
|
14
|
+
entrypointURL ?? import.meta.resolve('../../entrypoints/formatter_worker/formatter_worker-entrypoint.js');
|
|
12
15
|
}
|
|
13
|
-
static instance() {
|
|
14
|
-
if (!formatterWorkerPoolInstance) {
|
|
15
|
-
formatterWorkerPoolInstance = new FormatterWorkerPool();
|
|
16
|
+
static instance(opts) {
|
|
17
|
+
if (!formatterWorkerPoolInstance || opts?.forceNew) {
|
|
18
|
+
formatterWorkerPoolInstance = new FormatterWorkerPool(opts?.entrypointURL);
|
|
16
19
|
}
|
|
17
20
|
return formatterWorkerPoolInstance;
|
|
18
21
|
}
|
|
@@ -31,7 +34,7 @@ export class FormatterWorkerPool {
|
|
|
31
34
|
formatterWorkerPoolInstance = undefined;
|
|
32
35
|
}
|
|
33
36
|
createWorker() {
|
|
34
|
-
const worker = Platform.HostRuntime.HOST_RUNTIME.createWorker(
|
|
37
|
+
const worker = Platform.HostRuntime.HOST_RUNTIME.createWorker(this.entrypointURL);
|
|
35
38
|
worker.onmessage = this.onWorkerMessage.bind(this, worker);
|
|
36
39
|
worker.onerror = this.onWorkerError.bind(this, worker);
|
|
37
40
|
return worker;
|