chrome-devtools-frontend 1.0.1515796 → 1.0.1516909

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 (163) hide show
  1. package/docs/contributing/infrastructure.md +131 -82
  2. package/front_end/Tests.js +3 -29
  3. package/front_end/core/common/Progress.ts +73 -55
  4. package/front_end/core/host/GdpClient.ts +1 -1
  5. package/front_end/core/host/UserMetrics.ts +5 -2
  6. package/front_end/core/protocol_client/InspectorBackend.ts +2 -0
  7. package/front_end/core/root/Runtime.ts +0 -1
  8. package/front_end/core/sdk/CSSMatchedStyles.ts +12 -10
  9. package/front_end/core/sdk/CSSModel.ts +1 -31
  10. package/front_end/core/sdk/CSSPropertyParserMatchers.ts +27 -7
  11. package/front_end/core/sdk/DebuggerModel.ts +1 -31
  12. package/front_end/core/sdk/EnhancedTracesParser.ts +81 -50
  13. package/front_end/core/sdk/NetworkManager.ts +1 -31
  14. package/front_end/core/sdk/NetworkRequest.ts +1 -31
  15. package/front_end/core/sdk/RehydratingConnection.snapshot.txt +1003 -0
  16. package/front_end/core/sdk/RehydratingConnection.ts +13 -18
  17. package/front_end/core/sdk/RehydratingObject.ts +8 -31
  18. package/front_end/core/sdk/RemoteObject.ts +1 -31
  19. package/front_end/core/sdk/ResourceTreeModel.ts +1 -31
  20. package/front_end/core/sdk/RuntimeModel.ts +1 -31
  21. package/front_end/core/sdk/ServiceWorkerManager.ts +1 -31
  22. package/front_end/core/sdk/SourceMap.ts +1 -31
  23. package/front_end/core/sdk/TraceObject.ts +8 -3
  24. package/front_end/entrypoints/main/MainImpl.ts +1 -3
  25. package/front_end/models/ai_assistance/AiHistoryStorage.ts +1 -3
  26. package/front_end/models/ai_assistance/ConversationHandler.ts +4 -6
  27. package/front_end/models/ai_assistance/agents/AiAgent.ts +4 -1
  28. package/front_end/models/ai_assistance/agents/PerformanceAgent.ts +110 -76
  29. package/front_end/models/ai_assistance/agents/PerformanceAnnotationsAgent.ts +2 -2
  30. package/front_end/models/ai_assistance/agents/StylingAgent.ts +2 -2
  31. package/front_end/models/ai_assistance/data_formatters/PerformanceInsightFormatter.snapshot.txt +178 -85
  32. package/front_end/models/ai_assistance/data_formatters/PerformanceInsightFormatter.ts +308 -218
  33. package/front_end/models/ai_assistance/data_formatters/PerformanceTraceFormatter.snapshot.txt +100 -100
  34. package/front_end/models/ai_assistance/data_formatters/UnitFormatters.ts +10 -1
  35. package/front_end/models/ai_assistance/performance/AIContext.ts +19 -21
  36. package/front_end/models/ai_code_completion/AiCodeCompletion.ts +24 -8
  37. package/front_end/models/badges/UserBadges.ts +38 -3
  38. package/front_end/models/bindings/ContentProviderBasedProject.ts +6 -4
  39. package/front_end/models/breakpoints/BreakpointManager.ts +3 -3
  40. package/front_end/models/formatter/FormatterWorkerPool.ts +3 -3
  41. package/front_end/models/har/Writer.ts +11 -11
  42. package/front_end/models/persistence/FileSystemWorkspaceBinding.ts +3 -3
  43. package/front_end/models/persistence/IsolatedFileSystem.ts +4 -4
  44. package/front_end/models/persistence/IsolatedFileSystemManager.ts +7 -7
  45. package/front_end/models/persistence/PersistenceImpl.ts +8 -8
  46. package/front_end/models/persistence/PlatformFileSystem.ts +1 -1
  47. package/front_end/models/trace/ModelImpl.ts +2 -16
  48. package/front_end/models/trace/Processor.ts +15 -9
  49. package/front_end/models/trace/handlers/AuctionWorkletsHandler.ts +4 -4
  50. package/front_end/models/trace/handlers/FramesHandler.ts +2 -2
  51. package/front_end/models/trace/handlers/LayoutShiftsHandler.ts +7 -10
  52. package/front_end/models/trace/handlers/MetaHandler.ts +11 -9
  53. package/front_end/models/trace/handlers/ScreenshotsHandler.ts +1 -1
  54. package/front_end/models/trace/handlers/ScriptsHandler.ts +5 -5
  55. package/front_end/models/trace/handlers/UserInteractionsHandler.ts +2 -14
  56. package/front_end/models/trace/handlers/UserTimingsHandler.ts +3 -4
  57. package/front_end/models/trace/insights/CLSCulprits.ts +1 -1
  58. package/front_end/models/trace/insights/DocumentLatency.ts +3 -4
  59. package/front_end/models/trace/insights/DuplicatedJavaScript.ts +1 -1
  60. package/front_end/models/trace/insights/INPBreakdown.ts +1 -1
  61. package/front_end/models/trace/insights/ImageDelivery.ts +1 -1
  62. package/front_end/models/trace/insights/LCPBreakdown.ts +1 -1
  63. package/front_end/models/trace/insights/LCPDiscovery.ts +1 -1
  64. package/front_end/models/trace/insights/ModernHTTP.ts +1 -1
  65. package/front_end/models/trace/insights/NetworkDependencyTree.ts +1 -1
  66. package/front_end/models/trace/insights/RenderBlocking.ts +1 -1
  67. package/front_end/models/trace/insights/types.ts +2 -0
  68. package/front_end/models/trace/types/TraceEvents.ts +41 -64
  69. package/front_end/models/trace_source_maps_resolver/trace_source_maps_resolver.ts +1 -1
  70. package/front_end/panels/ai_assistance/AiAssistancePanel.ts +21 -99
  71. package/front_end/panels/application/ServiceWorkersView.ts +0 -1
  72. package/front_end/panels/browser_debugger/CategorizedBreakpointsSidebarPane.ts +2 -3
  73. package/front_end/panels/common/BadgeNotification.ts +46 -10
  74. package/front_end/panels/common/GdpSignUpDialog.ts +6 -3
  75. package/front_end/panels/console/ConsoleView.ts +23 -28
  76. package/front_end/panels/console/ConsoleViewport.ts +2 -2
  77. package/front_end/panels/console/consoleView.css +11 -1
  78. package/front_end/panels/coverage/CoverageView.ts +2 -2
  79. package/front_end/panels/elements/ComputedStyleWidget.ts +1 -2
  80. package/front_end/panels/elements/ElementsTreeOutline.ts +2 -2
  81. package/front_end/panels/elements/LayoutPane.ts +1 -1
  82. package/front_end/panels/elements/StyleEditorWidget.ts +8 -19
  83. package/front_end/panels/elements/StylePropertyTreeElement.ts +39 -25
  84. package/front_end/panels/elements/StylesSidebarPane.ts +2 -2
  85. package/front_end/panels/elements/stylePropertiesTreeOutline.css +4 -3
  86. package/front_end/panels/layer_viewer/Layers3DView.ts +2 -2
  87. package/front_end/panels/layers/LayerTreeModel.ts +3 -3
  88. package/front_end/panels/mobile_throttling/ThrottlingSettingsTab.ts +4 -4
  89. package/front_end/panels/network/NetworkLogView.ts +6 -2
  90. package/front_end/panels/network/NetworkLogViewColumns.ts +3 -3
  91. package/front_end/panels/network/NetworkSearchScope.ts +6 -6
  92. package/front_end/panels/search/SearchResultsPane.ts +32 -47
  93. package/front_end/panels/search/SearchView.ts +58 -80
  94. package/front_end/panels/settings/components/SyncSection.ts +7 -2
  95. package/front_end/panels/sources/OutlineQuickOpen.ts +3 -1
  96. package/front_end/panels/sources/SourcesSearchScope.ts +4 -4
  97. package/front_end/panels/sources/TabbedEditorContainer.ts +5 -5
  98. package/front_end/panels/timeline/TimelineFlameChartDataProvider.ts +10 -5
  99. package/front_end/panels/timeline/TimelineFlameChartView.ts +18 -15
  100. package/front_end/panels/timeline/TimelinePanel.ts +41 -22
  101. package/front_end/panels/timeline/TimelineUIUtils.ts +13 -8
  102. package/front_end/panels/timeline/TracingLayerTree.ts +4 -5
  103. package/front_end/panels/timeline/components/ExportTraceOptions.ts +37 -22
  104. package/front_end/panels/timeline/components/insights/BaseInsightComponent.ts +17 -7
  105. package/front_end/third_party/axe-core/README.chromium +1 -0
  106. package/front_end/third_party/codemirror/README.chromium +1 -0
  107. package/front_end/third_party/codemirror.next/README.chromium +1 -0
  108. package/front_end/third_party/csp_evaluator/README.chromium +1 -0
  109. package/front_end/third_party/diff/README.chromium +1 -0
  110. package/front_end/third_party/i18n/README.chromium +1 -0
  111. package/front_end/third_party/intl-messageformat/README.chromium +1 -0
  112. package/front_end/third_party/json5/README.chromium +1 -0
  113. package/front_end/third_party/legacy-javascript/README.chromium +1 -0
  114. package/front_end/third_party/lighthouse/README.chromium +1 -0
  115. package/front_end/third_party/lit/README.chromium +1 -0
  116. package/front_end/third_party/marked/README.chromium +1 -0
  117. package/front_end/third_party/puppeteer/README.chromium +2 -2
  118. package/front_end/third_party/puppeteer/package/lib/cjs/puppeteer/bidi/core/Realm.d.ts +2 -2
  119. package/front_end/third_party/puppeteer/package/lib/cjs/puppeteer/cdp/Accessibility.js +0 -20
  120. package/front_end/third_party/puppeteer/package/lib/cjs/puppeteer/cdp/Accessibility.js.map +1 -1
  121. package/front_end/third_party/puppeteer/package/lib/cjs/puppeteer/generated/version.d.ts +1 -1
  122. package/front_end/third_party/puppeteer/package/lib/cjs/puppeteer/generated/version.js +1 -1
  123. package/front_end/third_party/puppeteer/package/lib/cjs/puppeteer/injected/injected.d.ts +1 -1
  124. package/front_end/third_party/puppeteer/package/lib/cjs/puppeteer/revisions.d.ts +1 -1
  125. package/front_end/third_party/puppeteer/package/lib/cjs/puppeteer/revisions.js +1 -1
  126. package/front_end/third_party/puppeteer/package/lib/cjs/puppeteer/revisions.js.map +1 -1
  127. package/front_end/third_party/puppeteer/package/lib/cjs/puppeteer/util/Mutex.d.ts +2 -2
  128. package/front_end/third_party/puppeteer/package/lib/es5-iife/puppeteer-core-browser.js +2 -23
  129. package/front_end/third_party/puppeteer/package/lib/esm/puppeteer/cdp/Accessibility.js +0 -20
  130. package/front_end/third_party/puppeteer/package/lib/esm/puppeteer/cdp/Accessibility.js.map +1 -1
  131. package/front_end/third_party/puppeteer/package/lib/esm/puppeteer/generated/version.d.ts +1 -1
  132. package/front_end/third_party/puppeteer/package/lib/esm/puppeteer/generated/version.js +1 -1
  133. package/front_end/third_party/puppeteer/package/lib/esm/puppeteer/revisions.d.ts +1 -1
  134. package/front_end/third_party/puppeteer/package/lib/esm/puppeteer/revisions.js +1 -1
  135. package/front_end/third_party/puppeteer/package/lib/esm/puppeteer/revisions.js.map +1 -1
  136. package/front_end/third_party/puppeteer/package/package.json +1 -1
  137. package/front_end/third_party/puppeteer/package/src/cdp/Accessibility.ts +1 -21
  138. package/front_end/third_party/puppeteer/package/src/generated/version.ts +1 -1
  139. package/front_end/third_party/puppeteer/package/src/revisions.ts +1 -1
  140. package/front_end/third_party/puppeteer-replay/README.chromium +1 -0
  141. package/front_end/third_party/third-party-web/README.chromium +1 -0
  142. package/front_end/third_party/vscode.web-custom-data/README.chromium +1 -0
  143. package/front_end/third_party/wasmparser/README.chromium +1 -0
  144. package/front_end/third_party/web-vitals/README.chromium +1 -0
  145. package/front_end/ui/components/text_editor/config.ts +30 -1
  146. package/front_end/ui/components/tooltips/Tooltip.ts +18 -4
  147. package/front_end/ui/legacy/ContextMenu.ts +2 -2
  148. package/front_end/ui/legacy/GlassPane.ts +7 -3
  149. package/front_end/ui/legacy/ProgressIndicator.ts +29 -16
  150. package/front_end/ui/legacy/TabbedPane.ts +2 -2
  151. package/front_end/ui/legacy/Treeoutline.ts +10 -5
  152. package/front_end/ui/legacy/UIUtils.ts +42 -10
  153. package/front_end/ui/legacy/components/color_picker/Spectrum.ts +14 -14
  154. package/front_end/ui/legacy/components/data_grid/DataGrid.ts +6 -6
  155. package/front_end/ui/legacy/components/perf_ui/FlameChart.ts +3 -29
  156. package/front_end/ui/legacy/components/source_frame/SourceFrame.ts +14 -14
  157. package/front_end/ui/visual_logging/KnownContextValues.ts +7 -0
  158. package/inspector_overlay/highlight_common.ts +1 -27
  159. package/inspector_overlay/highlight_grid_common.ts +1 -27
  160. package/inspector_overlay/tool_highlight.ts +1 -27
  161. package/inspector_overlay/tool_persistent.ts +1 -27
  162. package/inspector_overlay/tool_source_order.ts +1 -27
  163. package/package.json +1 -1
@@ -159,8 +159,10 @@ export class AiCodeCompletion extends Common.ObjectWrapper.ObjectWrapper<EventTy
159
159
  }
160
160
 
161
161
  #debouncedRequestAidaSuggestion = Common.Debouncer.debounce(
162
- (prefix: string, suffix: string, cursor: number, inferenceLanguage?: Host.AidaClient.AidaInferenceLanguage) => {
163
- void this.#requestAidaSuggestion(this.#buildRequest(prefix, suffix, inferenceLanguage), cursor);
162
+ (prefix: string, suffix: string, cursorPositionAtRequest: number,
163
+ inferenceLanguage?: Host.AidaClient.AidaInferenceLanguage) => {
164
+ void this.#requestAidaSuggestion(
165
+ this.#buildRequest(prefix, suffix, inferenceLanguage), cursorPositionAtRequest);
164
166
  },
165
167
  AIDA_REQUEST_DEBOUNCE_TIMEOUT_MS);
166
168
 
@@ -288,12 +290,15 @@ export class AiCodeCompletion extends Common.ObjectWrapper.ObjectWrapper<EventTy
288
290
  };
289
291
  }
290
292
 
291
- async #requestAidaSuggestion(request: Host.AidaClient.CompletionRequest, cursor: number): Promise<void> {
293
+ async #requestAidaSuggestion(request: Host.AidaClient.CompletionRequest, cursorPositionAtRequest: number):
294
+ Promise<void> {
292
295
  const startTime = performance.now();
293
296
  this.dispatchEventToListeners(Events.REQUEST_TRIGGERED, {});
297
+ // Registering AiCodeCompletionRequestTriggered metric even if the request is served from cache
298
+ Host.userMetrics.actionTaken(Host.UserMetrics.Action.AiCodeCompletionRequestTriggered);
294
299
 
295
300
  try {
296
- const sampleResponse = await this.#generateSampleForRequest(request, cursor);
301
+ const sampleResponse = await this.#generateSampleForRequest(request, cursorPositionAtRequest);
297
302
  if (!sampleResponse) {
298
303
  this.dispatchEventToListeners(Events.RESPONSE_RECEIVED, {});
299
304
  return;
@@ -308,12 +313,19 @@ export class AiCodeCompletion extends Common.ObjectWrapper.ObjectWrapper<EventTy
308
313
  } = sampleResponse;
309
314
  const remainingDelay = Math.max(DELAY_BEFORE_SHOWING_RESPONSE_MS - (performance.now() - startTime), 0);
310
315
  this.#renderingTimeout = window.setTimeout(() => {
316
+ const currentCursorPosition = this.#editor.editor.state.selection.main.head;
317
+ if (currentCursorPosition !== cursorPositionAtRequest) {
318
+ this.dispatchEventToListeners(Events.RESPONSE_RECEIVED, {});
319
+ return;
320
+ }
311
321
  this.#editor.dispatch({
312
322
  effects: TextEditor.Config.setAiAutoCompleteSuggestion.of({
313
323
  text: suggestionText,
314
- from: cursor,
324
+ from: cursorPositionAtRequest,
315
325
  rpcGlobalId,
316
326
  sampleId,
327
+ startTime,
328
+ onImpression: this.#registerUserImpression.bind(this),
317
329
  })
318
330
  });
319
331
 
@@ -326,12 +338,13 @@ export class AiCodeCompletion extends Common.ObjectWrapper.ObjectWrapper<EventTy
326
338
  this.#registerUserImpression(rpcGlobalId, sampleId, latency);
327
339
  }
328
340
 
329
- debugLog('Suggestion dispatched to the editor', suggestionText, 'at cursor position', cursor);
341
+ debugLog('Suggestion dispatched to the editor', suggestionText, 'at cursor position', cursorPositionAtRequest);
330
342
  this.dispatchEventToListeners(Events.RESPONSE_RECEIVED, {citations});
331
343
  }, remainingDelay);
332
344
  } catch (e) {
333
345
  debugLog('Error while fetching code completion suggestions from AIDA', e);
334
346
  this.dispatchEventToListeners(Events.RESPONSE_RECEIVED, {});
347
+ Host.userMetrics.actionTaken(Host.UserMetrics.Action.AiCodeCompletionError);
335
348
  }
336
349
  }
337
350
 
@@ -418,6 +431,7 @@ export class AiCodeCompletion extends Common.ObjectWrapper.ObjectWrapper<EventTy
418
431
  },
419
432
  });
420
433
  debugLog('Registered user impression with latency {seconds:', seconds, ', nanos:', nanos, '}');
434
+ Host.userMetrics.actionTaken(Host.UserMetrics.Action.AiCodeCompletionSuggestionDisplayed);
421
435
  }
422
436
 
423
437
  registerUserAcceptance(rpcGlobalId: Host.AidaClient.RpcGlobalId, sampleId: number): void {
@@ -433,11 +447,13 @@ export class AiCodeCompletion extends Common.ObjectWrapper.ObjectWrapper<EventTy
433
447
  },
434
448
  });
435
449
  debugLog('Registered user acceptance');
450
+ Host.userMetrics.actionTaken(Host.UserMetrics.Action.AiCodeCompletionSuggestionAccepted);
436
451
  }
437
452
 
438
453
  onTextChanged(
439
- prefix: string, suffix: string, cursor: number, inferenceLanguage?: Host.AidaClient.AidaInferenceLanguage): void {
440
- this.#debouncedRequestAidaSuggestion(prefix, suffix, cursor, inferenceLanguage);
454
+ prefix: string, suffix: string, cursorPositionAtRequest: number,
455
+ inferenceLanguage?: Host.AidaClient.AidaInferenceLanguage): void {
456
+ this.#debouncedRequestAidaSuggestion(prefix, suffix, cursorPositionAtRequest, inferenceLanguage);
441
457
  }
442
458
 
443
459
  remove(): void {
@@ -22,6 +22,9 @@ export interface EventTypes {
22
22
  [Events.BADGE_TRIGGERED]: Badge;
23
23
  }
24
24
 
25
+ const SNOOZE_TIME_MS = 24 * 60 * 60 * 1000; // 24 hours
26
+ const MAX_SNOOZE_COUNT = 3;
27
+
25
28
  let userBadgesInstance: UserBadges|undefined = undefined;
26
29
  export class UserBadges extends Common.ObjectWrapper.ObjectWrapper<EventTypes> {
27
30
  readonly #badgeActionEventTarget = new Common.ObjectWrapper.ObjectWrapper<BadgeActionEvents>();
@@ -29,6 +32,10 @@ export class UserBadges extends Common.ObjectWrapper.ObjectWrapper<EventTypes> {
29
32
  #receiveBadgesSetting: Common.Settings.Setting<Boolean>;
30
33
  #allBadges: Badge[];
31
34
 
35
+ #starterBadgeSnoozeCount: Common.Settings.Setting<number>;
36
+ #starterBadgeLastSnoozedTimestamp: Common.Settings.Setting<number>;
37
+ #starterBadgeDismissed: Common.Settings.Setting<boolean>;
38
+
32
39
  static readonly BADGE_REGISTRY: BadgeClass[] = [
33
40
  StarterBadge,
34
41
  SpeedsterBadge,
@@ -43,6 +50,13 @@ export class UserBadges extends Common.ObjectWrapper.ObjectWrapper<EventTypes> {
43
50
  this.#receiveBadgesSetting = Common.Settings.Settings.instance().moduleSetting('receive-gdp-badges');
44
51
  this.#receiveBadgesSetting.addChangeListener(this.#reconcileBadges, this);
45
52
 
53
+ this.#starterBadgeSnoozeCount = Common.Settings.Settings.instance().createSetting(
54
+ 'starter-badge-snooze-count', 0, Common.Settings.SettingStorageType.SYNCED);
55
+ this.#starterBadgeLastSnoozedTimestamp = Common.Settings.Settings.instance().createSetting(
56
+ 'starter-badge-last-snoozed-timestamp', 0, Common.Settings.SettingStorageType.SYNCED);
57
+ this.#starterBadgeDismissed = Common.Settings.Settings.instance().createSetting(
58
+ 'starter-badge-dismissed', false, Common.Settings.SettingStorageType.SYNCED);
59
+
46
60
  this.#allBadges = UserBadges.BADGE_REGISTRY.map(badgeCtor => new badgeCtor({
47
61
  onTriggerBadge: this.#onTriggerBadge.bind(this),
48
62
  badgeActionEventTarget: this.#badgeActionEventTarget,
@@ -60,6 +74,15 @@ export class UserBadges extends Common.ObjectWrapper.ObjectWrapper<EventTypes> {
60
74
  return await this.#reconcileBadges();
61
75
  }
62
76
 
77
+ snoozeStarterBadge(): void {
78
+ this.#starterBadgeSnoozeCount.set(this.#starterBadgeSnoozeCount.get() + 1);
79
+ this.#starterBadgeLastSnoozedTimestamp.set(Date.now());
80
+ }
81
+
82
+ dismissStarterBadge(): void {
83
+ this.#starterBadgeDismissed.set(true);
84
+ }
85
+
63
86
  recordAction(action: BadgeAction): void {
64
87
  // `Common.ObjectWrapper.ObjectWrapper` does not allow passing unions to
65
88
  // the `dispatchEventToListeners` and `action` in this case is a union.
@@ -79,7 +102,8 @@ export class UserBadges extends Common.ObjectWrapper.ObjectWrapper<EventTypes> {
79
102
  const gdpProfile = await Host.GdpClient.GdpClient.instance().getProfile();
80
103
  const receiveBadgesSettingEnabled = Boolean(this.#receiveBadgesSetting.get());
81
104
  // If there is a GDP profile and the user has enabled receiving badges, we award the starter badge as well.
82
- if (gdpProfile && receiveBadgesSettingEnabled) {
105
+ if (gdpProfile && receiveBadgesSettingEnabled && !this.#isStarterBadgeDismissed() &&
106
+ !this.#isStarterBadgeSnoozed()) {
83
107
  shouldAwardBadge = true;
84
108
  }
85
109
  }
@@ -101,7 +125,17 @@ export class UserBadges extends Common.ObjectWrapper.ObjectWrapper<EventTypes> {
101
125
  });
102
126
  }
103
127
 
104
- // TODO(ergunsh): Implement starter badge dismissal, snooze count & timestamp checks.
128
+ #isStarterBadgeDismissed(): boolean {
129
+ return this.#starterBadgeDismissed.get();
130
+ }
131
+
132
+ #isStarterBadgeSnoozed(): boolean {
133
+ const snoozeCount = this.#starterBadgeSnoozeCount.get();
134
+ const lastSnoozed = this.#starterBadgeLastSnoozedTimestamp.get();
135
+ const snoozedRecently = (Date.now() - lastSnoozed) < SNOOZE_TIME_MS;
136
+ return snoozeCount >= MAX_SNOOZE_COUNT || snoozedRecently;
137
+ }
138
+
105
139
  async #reconcileBadges(): Promise<void> {
106
140
  const syncInfo = await new Promise<Host.InspectorFrontendHostAPI.SyncInformation>(
107
141
  resolve => Host.InspectorFrontendHost.InspectorFrontendHostInstance.getSyncInformation(resolve));
@@ -148,7 +182,8 @@ export class UserBadges extends Common.ObjectWrapper.ObjectWrapper<EventTypes> {
148
182
  continue;
149
183
  }
150
184
 
151
- const shouldActivateStarterBadge = badge.isStarterBadge && isEligibleToCreateProfile;
185
+ const shouldActivateStarterBadge = badge.isStarterBadge && isEligibleToCreateProfile &&
186
+ !this.#isStarterBadgeDismissed() && !this.#isStarterBadgeSnoozed();
152
187
  const shouldActivateActivityBasedBadge =
153
188
  !badge.isStarterBadge && Boolean(gdpProfile) && receiveBadgesSettingEnabled;
154
189
  if (shouldActivateStarterBadge || shouldActivateActivityBasedBadge) {
@@ -126,9 +126,9 @@ export class ContentProviderBasedProject extends Workspace.Workspace.ProjectStor
126
126
  progress: Common.Progress.Progress):
127
127
  Promise<Map<Workspace.UISourceCode.UISourceCode, TextUtils.ContentProvider.SearchMatch[]|null>> {
128
128
  const result = new Map();
129
- progress.setTotalWork(filesMatchingFileQuery.length);
129
+ progress.totalWork = filesMatchingFileQuery.length;
130
130
  await Promise.all(filesMatchingFileQuery.map(searchInContent.bind(this)));
131
- progress.done();
131
+ progress.done = true;
132
132
  return result;
133
133
 
134
134
  async function searchInContent(
@@ -148,12 +148,14 @@ export class ContentProviderBasedProject extends Workspace.Workspace.ProjectStor
148
148
  if (allMatchesFound) {
149
149
  result.set(uiSourceCode, matches);
150
150
  }
151
- progress.incrementWorked(1);
151
+ ++progress.worked;
152
152
  }
153
153
  }
154
154
 
155
155
  override indexContent(progress: Common.Progress.Progress): void {
156
- queueMicrotask(progress.done.bind(progress));
156
+ queueMicrotask(() => {
157
+ progress.done = true;
158
+ });
157
159
  }
158
160
 
159
161
  addUISourceCodeWithProvider(
@@ -272,7 +272,7 @@ export class BreakpointManager extends Common.ObjectWrapper.ObjectWrapper<EventT
272
272
  if (!BreakpointManager.isValidPositionInScript(lineNumber, columnNumber, script)) {
273
273
  continue;
274
274
  }
275
- this.innerSetBreakpoint(
275
+ this.#setBreakpoint(
276
276
  uiSourceCode, lineNumber, columnNumber, breakpoint.condition, breakpoint.enabled, breakpoint.isLogpoint,
277
277
  BreakpointOrigin.OTHER);
278
278
  }
@@ -316,7 +316,7 @@ export class BreakpointManager extends Common.ObjectWrapper.ObjectWrapper<EventT
316
316
  const normalizedLocation = await this.debuggerWorkspaceBinding.normalizeUILocation(uiLocation);
317
317
  const breakpointLocation = BreakpointManager.breakpointLocationFromUiLocation(normalizedLocation);
318
318
 
319
- const breakpoint = this.innerSetBreakpoint(
319
+ const breakpoint = this.#setBreakpoint(
320
320
  normalizedLocation.uiSourceCode, breakpointLocation.lineNumber, breakpointLocation.columnNumber, condition,
321
321
  enabled, isLogpoint, origin);
322
322
 
@@ -333,7 +333,7 @@ export class BreakpointManager extends Common.ObjectWrapper.ObjectWrapper<EventT
333
333
  return primaryBreakpoint;
334
334
  }
335
335
 
336
- private innerSetBreakpoint(
336
+ #setBreakpoint(
337
337
  uiSourceCode: Workspace.UISourceCode.UISourceCode, lineNumber: number, columnNumber: number|undefined,
338
338
  condition: UserCondition, enabled: boolean, isLogpoint: boolean, origin: BreakpointOrigin): Breakpoint {
339
339
  const url = BreakpointManager.getScriptForInlineUiSourceCode(uiSourceCode)?.sourceURL ?? uiSourceCode.url();
@@ -7,8 +7,6 @@ import * as FormatterActions from '../../entrypoints/formatter_worker/FormatterA
7
7
 
8
8
  export {DefinitionKind, type ScopeTreeNode} from '../../entrypoints/formatter_worker/FormatterActions.js';
9
9
 
10
- const MAX_WORKERS = Math.max(2, navigator.hardwareConcurrency - 1);
11
-
12
10
  let formatterWorkerPoolInstance: FormatterWorkerPool;
13
11
 
14
12
  export class FormatterWorkerPool {
@@ -37,12 +35,14 @@ export class FormatterWorkerPool {
37
35
  }
38
36
 
39
37
  private processNextTask(): void {
38
+ const maxWorkers = Math.max(2, navigator.hardwareConcurrency - 1);
39
+
40
40
  if (!this.taskQueue.length) {
41
41
  return;
42
42
  }
43
43
 
44
44
  let freeWorker = [...this.workerTasks.keys()].find(worker => !this.workerTasks.get(worker));
45
- if (!freeWorker && this.workerTasks.size < MAX_WORKERS) {
45
+ if (!freeWorker && this.workerTasks.size < maxWorkers) {
46
46
  freeWorker = this.createWorker();
47
47
  }
48
48
  if (!freeWorker) {
@@ -59,7 +59,7 @@ export class Writer {
59
59
  const compositeProgress = new Common.Progress.CompositeProgress(progress);
60
60
 
61
61
  const content = await Writer.harStringForRequests(requests, options, compositeProgress);
62
- if (progress.isCanceled()) {
62
+ if (progress.canceled) {
63
63
  return;
64
64
  }
65
65
  await Writer.writeToStream(stream, compositeProgress, content);
@@ -69,8 +69,8 @@ export class Writer {
69
69
  requests: SDK.NetworkRequest.NetworkRequest[], options: BuildOptions,
70
70
  compositeProgress: Common.Progress.CompositeProgress): Promise<string> {
71
71
  const progress = compositeProgress.createSubProgress();
72
- progress.setTitle(i18nString(UIStrings.collectingContent));
73
- progress.setTotalWork(requests.length);
72
+ progress.title = i18nString(UIStrings.collectingContent);
73
+ progress.totalWork = requests.length;
74
74
 
75
75
  // Sort by issueTime because this is recorded as startedDateTime in HAR logs.
76
76
  requests.sort((reqA, reqB) => reqA.issueTime() - reqB.issueTime());
@@ -82,9 +82,9 @@ export class Writer {
82
82
  }
83
83
 
84
84
  await Promise.all(promises);
85
- progress.done();
85
+ progress.done = true;
86
86
 
87
- if (progress.isCanceled()) {
87
+ if (progress.canceled) {
88
88
  return '';
89
89
  }
90
90
  return JSON.stringify({log: harLog}, null, jsonIndent);
@@ -106,7 +106,7 @@ export class Writer {
106
106
  }
107
107
 
108
108
  function contentLoaded(entry: EntryDTO, contentDataOrError: TextUtils.ContentData.ContentDataOrError): void {
109
- progress.incrementWorked();
109
+ ++progress.worked;
110
110
  const contentData = TextUtils.ContentData.ContentData.asDeferredContent(contentDataOrError);
111
111
  let encoded: true|boolean = contentData.isEncoded;
112
112
  if (contentData.content !== null) {
@@ -127,14 +127,14 @@ export class Writer {
127
127
  stream: Common.StringOutputStream.OutputStream, compositeProgress: Common.Progress.CompositeProgress,
128
128
  fileContent: string): Promise<void> {
129
129
  const progress = compositeProgress.createSubProgress();
130
- progress.setTitle(i18nString(UIStrings.writingFile));
131
- progress.setTotalWork(fileContent.length);
132
- for (let i = 0; i < fileContent.length && !progress.isCanceled(); i += chunkSize) {
130
+ progress.title = i18nString(UIStrings.writingFile);
131
+ progress.totalWork = fileContent.length;
132
+ for (let i = 0; i < fileContent.length && !progress.canceled; i += chunkSize) {
133
133
  const chunk = fileContent.substr(i, chunkSize);
134
134
  await stream.write(chunk);
135
- progress.incrementWorked(chunk.length);
135
+ progress.worked += chunk.length;
136
136
  }
137
- progress.done();
137
+ progress.done = true;
138
138
  }
139
139
  }
140
140
 
@@ -276,14 +276,14 @@ export class FileSystem extends Workspace.Workspace.ProjectStore {
276
276
  if (!queriesToRun.length) {
277
277
  queriesToRun.push('');
278
278
  }
279
- progress.setTotalWork(queriesToRun.length);
279
+ progress.totalWork = queriesToRun.length;
280
280
 
281
281
  for (const query of queriesToRun) {
282
282
  const files = await this.#fileSystem.searchInPath(searchConfig.isRegex() ? '' : query, progress);
283
283
  files.sort(Platform.StringUtilities.naturalOrderComparator);
284
284
  workingFileSet = Platform.ArrayUtilities.intersectOrdered(
285
285
  workingFileSet, files, Platform.StringUtilities.naturalOrderComparator);
286
- progress.incrementWorked(1);
286
+ ++progress.worked;
287
287
  }
288
288
 
289
289
  const result = new Map();
@@ -294,7 +294,7 @@ export class FileSystem extends Workspace.Workspace.ProjectStore {
294
294
  }
295
295
  }
296
296
 
297
- progress.done();
297
+ progress.done = true;
298
298
  return result;
299
299
  }
300
300
 
@@ -184,7 +184,7 @@ export class IsolatedFileSystem extends PlatformFileSystem {
184
184
  let activePath = '';
185
185
  for (const path of paths) {
186
186
  activePath = activePath + '/' + path;
187
- dirEntry = await this.innerCreateFolderIfNeeded(activePath);
187
+ dirEntry = await this.#createFolderIfNeeded(activePath);
188
188
  if (!dirEntry) {
189
189
  return null;
190
190
  }
@@ -192,7 +192,7 @@ export class IsolatedFileSystem extends PlatformFileSystem {
192
192
  return dirEntry;
193
193
  }
194
194
 
195
- private innerCreateFolderIfNeeded(path: string): Promise<DirectoryEntry|null> {
195
+ #createFolderIfNeeded(path: string): Promise<DirectoryEntry|null> {
196
196
  return new Promise(resolve => {
197
197
  this.domFileSystem.root.getDirectory(path, {create: true}, dirEntry => resolve(dirEntry), error => {
198
198
  this.domFileSystem.root.getFile(
@@ -517,13 +517,13 @@ export class IsolatedFileSystem extends PlatformFileSystem {
517
517
 
518
518
  function innerCallback(files: Platform.DevToolsPath.RawPathString[]): void {
519
519
  resolve(files.map(path => Common.ParsedURL.ParsedURL.rawPathToUrlString(path)));
520
- progress.incrementWorked(1);
520
+ ++progress.worked;
521
521
  }
522
522
  });
523
523
  }
524
524
 
525
525
  override indexContent(progress: Common.Progress.Progress): void {
526
- progress.setTotalWork(1);
526
+ progress.totalWork = 1;
527
527
  const requestId = this.manager.registerProgress(progress);
528
528
  Host.InspectorFrontendHost.InspectorFrontendHostInstance.indexPath(
529
529
  requestId, this.#embedderPath, JSON.stringify(this.excludedEmbedderFolders));
@@ -123,7 +123,7 @@ export class IsolatedFileSystemManager extends Common.ObjectWrapper.ObjectWrappe
123
123
  const fileSystems = event.data;
124
124
  const promises = [];
125
125
  for (let i = 0; i < fileSystems.length; ++i) {
126
- promises.push(this.innerAddFileSystem(fileSystems[i], false));
126
+ promises.push(this.#addFileSystem(fileSystems[i], false));
127
127
  }
128
128
  void Promise.all(promises).then(onFileSystemsAdded);
129
129
  }
@@ -154,7 +154,7 @@ export class IsolatedFileSystemManager extends Common.ObjectWrapper.ObjectWrappe
154
154
  return this.fileSystemsLoadedPromise;
155
155
  }
156
156
 
157
- private innerAddFileSystem(fileSystem: Host.InspectorFrontendHostAPI.DevToolsFileSystem, dispatchEvent: boolean):
157
+ #addFileSystem(fileSystem: Host.InspectorFrontendHostAPI.DevToolsFileSystem, dispatchEvent: boolean):
158
158
  Promise<IsolatedFileSystem|null> {
159
159
  const embedderPath = fileSystem.fileSystemPath;
160
160
  const fileSystemURL = Common.ParsedURL.ParsedURL.rawPathToUrlString(fileSystem.fileSystemPath);
@@ -196,7 +196,7 @@ export class IsolatedFileSystemManager extends Common.ObjectWrapper.ObjectWrappe
196
196
  this.fileSystemRequestResolve.call(null, null);
197
197
  this.fileSystemRequestResolve = null;
198
198
  } else if (fileSystem) {
199
- void this.innerAddFileSystem(fileSystem, true).then(fileSystem => {
199
+ void this.#addFileSystem(fileSystem, true).then(fileSystem => {
200
200
  if (this.fileSystemRequestResolve) {
201
201
  this.fileSystemRequestResolve.call(null, fileSystem);
202
202
  this.fileSystemRequestResolve = null;
@@ -287,7 +287,7 @@ export class IsolatedFileSystemManager extends Common.ObjectWrapper.ObjectWrappe
287
287
  if (!progress) {
288
288
  return;
289
289
  }
290
- progress.setTotalWork(totalWork);
290
+ progress.totalWork = totalWork;
291
291
  }
292
292
 
293
293
  private onIndexingWorked(
@@ -297,8 +297,8 @@ export class IsolatedFileSystemManager extends Common.ObjectWrapper.ObjectWrappe
297
297
  if (!progress) {
298
298
  return;
299
299
  }
300
- progress.incrementWorked(worked);
301
- if (progress.isCanceled()) {
300
+ progress.worked += worked;
301
+ if (progress.canceled) {
302
302
  Host.InspectorFrontendHost.InspectorFrontendHostInstance.stopIndexing(requestId);
303
303
  this.onIndexingDone(event);
304
304
  }
@@ -311,7 +311,7 @@ export class IsolatedFileSystemManager extends Common.ObjectWrapper.ObjectWrappe
311
311
  if (!progress) {
312
312
  return;
313
313
  }
314
- progress.done();
314
+ progress.done = true;
315
315
  this.progresses.delete(requestId);
316
316
  }
317
317
 
@@ -64,19 +64,19 @@ export class PersistenceImpl extends Common.ObjectWrapper.ObjectWrapper<EventTyp
64
64
  }
65
65
 
66
66
  async addBinding(binding: PersistenceBinding): Promise<void> {
67
- await this.innerAddBinding(binding);
67
+ await this.#addBinding(binding);
68
68
  }
69
69
 
70
70
  async addBindingForTest(binding: PersistenceBinding): Promise<void> {
71
- await this.innerAddBinding(binding);
71
+ await this.#addBinding(binding);
72
72
  }
73
73
 
74
74
  async removeBinding(binding: PersistenceBinding): Promise<void> {
75
- await this.innerRemoveBinding(binding);
75
+ await this.#removeBinding(binding);
76
76
  }
77
77
 
78
78
  async removeBindingForTest(binding: PersistenceBinding): Promise<void> {
79
- await this.innerRemoveBinding(binding);
79
+ await this.#removeBinding(binding);
80
80
  }
81
81
 
82
82
  #setupBindings(networkUISourceCode: Workspace.UISourceCode.UISourceCode): Promise<void> {
@@ -86,7 +86,7 @@ export class PersistenceImpl extends Common.ObjectWrapper.ObjectWrapper<EventTyp
86
86
  return this.#mapping.computeNetworkStatus(networkUISourceCode);
87
87
  }
88
88
 
89
- private async innerAddBinding(binding: PersistenceBinding): Promise<void> {
89
+ async #addBinding(binding: PersistenceBinding): Promise<void> {
90
90
  bindings.set(binding.network, binding);
91
91
  bindings.set(binding.fileSystem, binding);
92
92
 
@@ -119,7 +119,7 @@ export class PersistenceImpl extends Common.ObjectWrapper.ObjectWrapper<EventTyp
119
119
  this.dispatchEventToListeners(Events.BindingCreated, binding);
120
120
  }
121
121
 
122
- private async innerRemoveBinding(binding: PersistenceBinding): Promise<void> {
122
+ async #removeBinding(binding: PersistenceBinding): Promise<void> {
123
123
  if (bindings.get(binding.network) !== binding) {
124
124
  return;
125
125
  }
@@ -150,12 +150,12 @@ export class PersistenceImpl extends Common.ObjectWrapper.ObjectWrapper<EventTyp
150
150
  private onStatusAdded(status: AutomappingStatus): Promise<void> {
151
151
  const binding = new PersistenceBinding(status.network, status.fileSystem);
152
152
  statusBindings.set(status, binding);
153
- return this.innerAddBinding(binding);
153
+ return this.#addBinding(binding);
154
154
  }
155
155
 
156
156
  private async onStatusRemoved(status: AutomappingStatus): Promise<void> {
157
157
  const binding = statusBindings.get(status) as PersistenceBinding;
158
- await this.innerRemoveBinding(binding);
158
+ await this.#removeBinding(binding);
159
159
  }
160
160
 
161
161
  private onWorkingCopyChanged(event: Common.EventTarget.EventTargetEvent<Workspace.UISourceCode.UISourceCode>): void {
@@ -148,7 +148,7 @@ export class PlatformFileSystem extends Common.ObjectWrapper.ObjectWrapper<Event
148
148
 
149
149
  indexContent(progress: Common.Progress.Progress): void {
150
150
  queueMicrotask(() => {
151
- progress.done();
151
+ progress.done = true;
152
152
  });
153
153
  }
154
154
 
@@ -14,12 +14,6 @@ import * as Types from './types/types.js';
14
14
  // processors. Currently there is only one implemented, but you will see
15
15
  // references to "processors" plural because it can easily be extended in the future.
16
16
 
17
- export interface ParseConfig {
18
- metadata?: Types.File.MetaData;
19
- isFreshRecording?: boolean;
20
- resolveSourceMap?: Types.Configuration.ParseOptions['resolveSourceMap'];
21
- }
22
-
23
17
  /**
24
18
  * The Model is responsible for parsing arrays of raw trace events and storing the
25
19
  * resulting data. It can store multiple traces at once, and can return the data for
@@ -87,10 +81,8 @@ export class Model extends EventTarget {
87
81
  * });
88
82
  * void this.traceModel.parse(events);
89
83
  **/
90
- async parse(traceEvents: readonly Types.Events.Event[], config?: ParseConfig): Promise<void> {
84
+ async parse(traceEvents: readonly Types.Events.Event[], config?: Types.Configuration.ParseOptions): Promise<void> {
91
85
  const metadata = config?.metadata || {};
92
- const isFreshRecording = config?.isFreshRecording || false;
93
- const isCPUProfile = metadata?.dataOrigin === Types.File.DataOrigin.CPU_PROFILE;
94
86
  // During parsing, periodically update any listeners on each processors'
95
87
  // progress (if they have any updates).
96
88
  const onTraceUpdate = (event: Event): void => {
@@ -106,13 +98,7 @@ export class Model extends EventTarget {
106
98
  try {
107
99
  // Wait for all outstanding promises before finishing the async execution,
108
100
  // but perform all tasks in parallel.
109
- const parseConfig: Types.Configuration.ParseOptions = {
110
- isFreshRecording,
111
- isCPUProfile,
112
- metadata,
113
- resolveSourceMap: config?.resolveSourceMap,
114
- };
115
- await this.#processor.parse(traceEvents, parseConfig);
101
+ await this.#processor.parse(traceEvents, config ?? {});
116
102
  if (!this.#processor.data) {
117
103
  throw new Error('processor did not parse trace');
118
104
  }
@@ -152,6 +152,10 @@ export class TraceProcessor extends EventTarget {
152
152
  throw new Error(`Trace processor can't start parsing when not idle. Current state: ${this.#status}`);
153
153
  }
154
154
 
155
+ if (typeof options.isCPUProfile === 'undefined' && options.metadata) {
156
+ options.isCPUProfile = options.metadata.dataOrigin === Types.File.DataOrigin.CPU_PROFILE;
157
+ }
158
+
155
159
  options.logger?.start('total');
156
160
  try {
157
161
  this.#status = Status.PARSING;
@@ -424,9 +428,9 @@ export class TraceProcessor extends EventTarget {
424
428
  insightSet.model = newModel;
425
429
  }
426
430
 
427
- #computeInsightSet(
428
- data: Handlers.Types.HandlerData, context: Insights.Types.InsightSetContext,
429
- options: Types.Configuration.ParseOptions): void {
431
+ #computeInsightSet(data: Handlers.Types.HandlerData, context: Insights.Types.InsightSetContext): void {
432
+ const logger = context.options.logger;
433
+
430
434
  let id, urlString, navigation;
431
435
  if (context.navigation) {
432
436
  id = context.navigationId;
@@ -442,8 +446,8 @@ export class TraceProcessor extends EventTarget {
442
446
  for (const [name, insight] of Object.entries(TraceProcessor.getInsightRunners())) {
443
447
  let model: Insights.Types.InsightModel|Error;
444
448
  try {
445
- options.logger?.start(`insights:${name}`);
446
- model = insight.generateInsight(data, context, options.insightTimeFormatters);
449
+ logger?.start(`insights:${name}`);
450
+ model = insight.generateInsight(data, context);
447
451
  model.frameId = context.frameId;
448
452
  const navId = context.navigation?.args.data?.navigationId;
449
453
  if (navId) {
@@ -456,7 +460,7 @@ export class TraceProcessor extends EventTarget {
456
460
  } catch (err) {
457
461
  model = err;
458
462
  } finally {
459
- options.logger?.end(`insights:${name}`);
463
+ logger?.end(`insights:${name}`);
460
464
  }
461
465
  Object.assign(insightSetModel, {[name]: model});
462
466
  }
@@ -503,7 +507,7 @@ export class TraceProcessor extends EventTarget {
503
507
  this.#insights = new Map();
504
508
  }
505
509
  this.#insights.set(insightSet.id, insightSet);
506
- this.sortInsightSet(insightSet, options.metadata ?? null);
510
+ this.sortInsightSet(insightSet, context.options.metadata ?? null);
507
511
  }
508
512
 
509
513
  /**
@@ -543,11 +547,12 @@ export class TraceProcessor extends EventTarget {
543
547
  data.Meta.traceBounds;
544
548
 
545
549
  const context: Insights.Types.InsightSetContext = {
550
+ options,
546
551
  bounds,
547
552
  frameId: data.Meta.mainFrameId,
548
553
  // No navigation or lantern context applies to this initial/no-navigation period.
549
554
  };
550
- this.#computeInsightSet(data, context, options);
555
+ this.#computeInsightSet(data, context);
551
556
  }
552
557
 
553
558
  /**
@@ -593,13 +598,14 @@ export class TraceProcessor extends EventTarget {
593
598
  }
594
599
 
595
600
  const context: Insights.Types.InsightSetContext = {
601
+ options,
596
602
  bounds,
597
603
  frameId,
598
604
  navigation,
599
605
  navigationId,
600
606
  lantern,
601
607
  };
602
- this.#computeInsightSet(data, context, options);
608
+ this.#computeInsightSet(data, context);
603
609
  }
604
610
  }
605
611
 
@@ -93,9 +93,9 @@ function workletType(input: string): Types.Events.AuctionWorkletType {
93
93
  * create everything other than the `args` field, as those are identical
94
94
  * regardless of the type of event.
95
95
  */
96
- function makeSyntheticEventBase(event: Types.Events.AuctionWorkletDoneWithProcess|
97
- Types.Events.AuctionWorkletRunningInProcess):
98
- Omit<Types.Events.SyntheticAuctionWorklet, 'args'> {
96
+ function makeSyntheticEventBase(
97
+ event: Types.Events.AuctionWorkletDoneWithProcess|
98
+ Types.Events.AuctionWorkletRunningInProcess): Omit<Types.Events.SyntheticAuctionWorklet, 'args'> {
99
99
  return Helpers.SyntheticEvents.SyntheticEventsManager
100
100
  .registerSyntheticEvent<Omit<Types.Events.SyntheticAuctionWorklet, 'args'>>({
101
101
  rawSourceEvent: event,
@@ -178,6 +178,6 @@ export interface AuctionWorkletsData {
178
178
 
179
179
  export function data(): AuctionWorkletsData {
180
180
  return {
181
- worklets: new Map(createdSyntheticEvents),
181
+ worklets: createdSyntheticEvents,
182
182
  };
183
183
  }
@@ -95,8 +95,8 @@ export interface FramesData {
95
95
 
96
96
  export function data(): FramesData {
97
97
  return {
98
- frames: model ? Array.from(model.frames()) : [],
99
- framesById: model ? {...model.framesById()} : {},
98
+ frames: model?.frames() ?? [],
99
+ framesById: model?.framesById() ?? {},
100
100
  };
101
101
  }
102
102