Skip to content

Commit 029174c

Browse files
committed
review: fix lcp capture
1 parent 916f275 commit 029174c

4 files changed

Lines changed: 55 additions & 39 deletions

File tree

server/lib/cdpmonitor/computed.go

Lines changed: 8 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -78,15 +78,19 @@ func (s *computedState) navSnapshot() (json.RawMessage, map[string]string) {
7878
}
7979

8080
// navDataWith merges extra fields into the current nav payload.
81+
// Nav context fields (session_id, target_id, etc.) always take precedence over
82+
// caller-supplied extra so a page-controlled payload cannot forge nav identity.
8183
func (s *computedState) navDataWith(extra map[string]any) json.RawMessage {
82-
base := make(map[string]any)
84+
result := make(map[string]any)
85+
maps.Copy(result, extra)
8386
if s != nil {
8487
d, _ := s.navSnapshot()
88+
base := make(map[string]any)
8589
_ = json.Unmarshal(d, &base)
90+
maps.Copy(result, base)
8691
}
87-
maps.Copy(base, extra)
88-
result, _ := json.Marshal(base)
89-
return result
92+
out, _ := json.Marshal(result)
93+
return out
9094
}
9195

9296
func stopTimer(t *time.Timer) {

server/lib/cdpmonitor/domains.go

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -45,7 +45,7 @@ func (m *Monitor) enableDomains(ctx context.Context, sessionID string, targetTyp
4545
}
4646

4747
if _, err := m.send(ctx, "PerformanceTimeline.enable", map[string]any{
48-
"eventTypes": []string{timelineEventLayoutShift},
48+
"eventTypes": []string{timelineEventLayoutShift, timelineEventLCP},
4949
}, sessionID); err != nil && ctx.Err() == nil {
5050
m.log.Warn("cdpmonitor: failed to enable PerformanceTimeline", "session", sessionID, "err", err)
5151
}

server/lib/cdpmonitor/handlers.go

Lines changed: 41 additions & 32 deletions
Original file line numberDiff line numberDiff line change
@@ -208,41 +208,50 @@ func (m *Monitor) handleBindingCalled(p cdpRuntimeBindingCalledParams, sessionID
208208
m.publishEvent(header.Type, events.CategoryInteraction, events.Source{Kind: events.KindCDP}, "Runtime.bindingCalled", cs.navDataWith(payloadMap), sessionID)
209209
}
210210

211-
// handleTimelineEvent processes PerformanceTimeline layout-shift events.
211+
// handleTimelineEvent processes PerformanceTimeline layout-shift and LCP events.
212212
func (m *Monitor) handleTimelineEvent(p cdpPerformanceTimelineEventAddedParams, sessionID string) {
213-
if p.Event.Type != timelineEventLayoutShift {
214-
return
215-
}
216-
// source_frame_id is the frame where the shift occurred; distinct from nav
217-
// context's frame_id (the top-level navigated frame).
218-
ev := map[string]any{
219-
"source_frame_id": p.Event.FrameID,
220-
"time": p.Event.Time,
221-
"duration": p.Event.Duration,
222-
}
223-
var shift cdpLayoutShiftDetails
224-
if p.Event.LayoutShiftDetails != nil && json.Unmarshal(p.Event.LayoutShiftDetails, &shift) == nil {
225-
ev["layout_shift_details"] = map[string]any{
226-
"score": shift.Score,
227-
"had_recent_input": shift.HadRecentInput,
213+
switch p.Event.Type {
214+
case timelineEventLayoutShift:
215+
// source_frame_id is the frame where the shift occurred; distinct from nav
216+
// context's frame_id (the top-level navigated frame).
217+
ev := map[string]any{
218+
"source_frame_id": p.Event.FrameID,
219+
"time": p.Event.Time,
220+
"duration": p.Event.Duration,
228221
}
229-
}
230-
var lcp cdpLcpDetails
231-
if p.Event.LcpDetails != nil && json.Unmarshal(p.Event.LcpDetails, &lcp) == nil {
232-
ev["lcp_details"] = map[string]any{
233-
"render_time": lcp.RenderTime,
234-
"load_time": lcp.LoadTime,
235-
"size": lcp.Size,
236-
"element_id": lcp.ElementID,
237-
"url": lcp.URL,
238-
"node_id": lcp.NodeID,
222+
var shift cdpLayoutShiftDetails
223+
if p.Event.LayoutShiftDetails != nil && json.Unmarshal(p.Event.LayoutShiftDetails, &shift) == nil {
224+
ev["layout_shift_details"] = map[string]any{
225+
"score": shift.Score,
226+
"had_recent_input": shift.HadRecentInput,
227+
}
239228
}
240-
}
241-
cs := m.computedFor(sessionID)
242-
data := cs.navDataWith(ev)
243-
m.publishEvent(EventLayoutShift, events.CategoryPage, events.Source{Kind: events.KindCDP}, "PerformanceTimeline.timelineEventAdded", data, sessionID)
244-
if cs != nil {
245-
cs.onLayoutShift()
229+
cs := m.computedFor(sessionID)
230+
data := cs.navDataWith(ev)
231+
m.publishEvent(EventLayoutShift, events.CategoryPage, events.Source{Kind: events.KindCDP}, "PerformanceTimeline.timelineEventAdded", data, sessionID)
232+
if cs != nil {
233+
cs.onLayoutShift()
234+
}
235+
236+
case timelineEventLCP:
237+
ev := map[string]any{
238+
"source_frame_id": p.Event.FrameID,
239+
"time": p.Event.Time,
240+
}
241+
var lcp cdpLcpDetails
242+
if p.Event.LcpDetails != nil && json.Unmarshal(p.Event.LcpDetails, &lcp) == nil {
243+
ev["lcp_details"] = map[string]any{
244+
"render_time": lcp.RenderTime,
245+
"load_time": lcp.LoadTime,
246+
"size": lcp.Size,
247+
"element_id": lcp.ElementID,
248+
"url": lcp.URL,
249+
"node_id": lcp.NodeID,
250+
}
251+
}
252+
cs := m.computedFor(sessionID)
253+
data := cs.navDataWith(ev)
254+
m.publishEvent(EventLCP, events.CategoryPage, events.Source{Kind: events.KindCDP}, "PerformanceTimeline.timelineEventAdded", data, sessionID)
246255
}
247256
}
248257

server/lib/cdpmonitor/types.go

Lines changed: 5 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -25,6 +25,7 @@ const (
2525
EventDOMContentLoaded = "page_dom_content_loaded" // Page.domContentEventFired
2626
EventPageLoad = "page_load" // Page.loadEventFired
2727
EventLayoutShift = "page_layout_shift" // PerformanceTimeline event of type "layout-shift"
28+
EventLCP = "page_lcp" // PerformanceTimeline event of type "largest-contentful-paint"
2829
EventTabOpened = "page_tab_opened" // Target.attachedToTarget for type=page
2930
)
3031

@@ -62,8 +63,10 @@ const (
6263
MetadataKeyTargetType = "target_type"
6364
)
6465

65-
// CDP PerformanceTimeline event type for layout shifts.
66-
const timelineEventLayoutShift = "layout-shift"
66+
const (
67+
timelineEventLayoutShift = "layout-shift"
68+
timelineEventLCP = "largest-contentful-paint"
69+
)
6770

6871
// CDP target type for browser pages (as opposed to workers, iframes, etc.).
6972
const targetTypePage = "page"

0 commit comments

Comments
 (0)