diff --git a/server/cmd/api/api/events.go b/server/cmd/api/api/events.go index 27dfc50a..33e2b88d 100644 --- a/server/cmd/api/api/events.go +++ b/server/cmd/api/api/events.go @@ -122,6 +122,9 @@ func (s *ApiService) StreamTelemetryEvents(ctx context.Context, req oapi.StreamT } if result.Dropped > 0 { + // The client's next Last-Event-ID will skip this gap, so record it: + // a silent skip reads as a quiet stream rather than a lost one. + s.telemetrySession.RecordDropped(result.Dropped) continue } diff --git a/server/cmd/api/api/telemetry.go b/server/cmd/api/api/telemetry.go index a45ca3ba..27826453 100644 --- a/server/cmd/api/api/telemetry.go +++ b/server/cmd/api/api/telemetry.go @@ -52,7 +52,7 @@ func (s *ApiService) PutTelemetry(ctx context.Context, req oapi.PutTelemetryRequ s.telemetrySession.Stop() s.stopTelemetryState() } - return oapi.PutTelemetry200JSONResponse(oapi.TelemetryState{Config: disabledConfig(), Seq: int64(s.telemetrySession.Seq())}), nil + return oapi.PutTelemetry200JSONResponse(s.stoppedTelemetryResponse()), nil } // Commit the config first so the filter is live before the collector emits, @@ -102,7 +102,7 @@ func (s *ApiService) PatchTelemetry(ctx context.Context, req oapi.PatchTelemetry if allDisabled { s.telemetrySession.Stop() s.stopTelemetryState() - return oapi.PatchTelemetry200JSONResponse(oapi.TelemetryState{Config: disabledConfig(), Seq: int64(s.telemetrySession.Seq())}), nil + return oapi.PatchTelemetry200JSONResponse(s.stoppedTelemetryResponse()), nil } // Commit first so the filter is live before the collector emits, then @@ -199,8 +199,9 @@ func (s *ApiService) stopTelemetryState() { // buildTelemetryResponse constructs a TelemetryState response from the current configuration. func (s *ApiService) buildTelemetryResponse() oapi.TelemetryState { resp := oapi.TelemetryState{ - Config: telemetryConfigToOAPI(s.telemetrySession.Config()), - Seq: int64(s.telemetrySession.Seq()), + Config: telemetryConfigToOAPI(s.telemetrySession.Config()), + Seq: int64(s.telemetrySession.Seq()), + DroppedEvents: lo.ToPtr(int64(s.telemetrySession.DroppedEvents())), } if appliedAt := s.telemetrySession.AppliedAt(); !appliedAt.IsZero() { resp.AppliedAt = &appliedAt @@ -208,28 +209,59 @@ func (s *ApiService) buildTelemetryResponse() oapi.TelemetryState { return resp } -// categoryField pairs a category with its config field so the helpers can walk -// the configurable categories without enumerating them inline. +// stoppedTelemetryResponse reports the cleared configuration. Seq and the +// dropped count are process-scoped, so they survive a session ending. +func (s *ApiService) stoppedTelemetryResponse() oapi.TelemetryState { + return oapi.TelemetryState{ + Config: disabledConfig(), + Seq: int64(s.telemetrySession.Seq()), + DroppedEvents: lo.ToPtr(int64(s.telemetrySession.DroppedEvents())), + } +} + +// categoryField pairs a category with its enabled flag so the helpers can walk +// the configurable categories without enumerating them inline. The flag rather +// than the config, because control carries settings the others do not. type categoryField struct { category oapi.TelemetryEventCategory - config *oapi.BrowserTelemetryCategoryConfig + enabled *bool } func categoryFields(b *oapi.BrowserTelemetryCategoriesConfig) []categoryField { + flag := func(c *oapi.BrowserTelemetryCategoryConfig) *bool { + if c == nil { + return nil + } + return c.Enabled + } + var control *bool + if b.Control != nil { + control = b.Control.Enabled + } return []categoryField{ - {events.Console, b.Console}, - {events.Network, b.Network}, - {events.Page, b.Page}, - {events.Interaction, b.Interaction}, - {events.Control, b.Control}, - {events.Platform, b.Platform}, - {events.Connection, b.Connection}, - {events.System, b.System}, - {events.Screenshot, b.Screenshot}, - {events.Captcha, b.Captcha}, + {events.Console, flag(b.Console)}, + {events.Network, flag(b.Network)}, + {events.Page, flag(b.Page)}, + {events.Interaction, flag(b.Interaction)}, + {events.Control, control}, + {events.Platform, flag(b.Platform)}, + {events.Connection, flag(b.Connection)}, + {events.System, flag(b.System)}, + {events.Screenshot, flag(b.Screenshot)}, + {events.Captcha, flag(b.Captcha)}, } } +// excludedCdpMethodsFromOAPI reads the cdp_command exclusion list, which only +// the control category carries. +func excludedCdpMethodsFromOAPI(cfg *oapi.BrowserTelemetryConfig) []oapi.BrowserCdpCommandMethod { + if cfg == nil || cfg.Browser == nil || cfg.Browser.Control == nil || + cfg.Browser.Control.Cdp == nil || cfg.Browser.Control.Cdp.ExcludedMethods == nil { + return nil + } + return *cfg.Browser.Control.Cdp.ExcludedMethods +} + func categorySetOf(cats []oapi.TelemetryEventCategory) map[oapi.TelemetryEventCategory]bool { set := make(map[oapi.TelemetryEventCategory]bool, len(cats)) for _, c := range cats { @@ -262,14 +294,18 @@ func telemetryConfigFromOAPI(cfg *oapi.BrowserTelemetryConfig) (telemetry.Teleme cats := make([]oapi.TelemetryEventCategory, 0, len(events.UserCategories)) for _, f := range categoryFields(cfg.Browser) { - if f.config != nil && f.config.Enabled != nil && *f.config.Enabled { + if f.enabled != nil && *f.enabled { cats = append(cats, f.category) } } if len(cats) == 0 { return telemetry.TelemetryConfig{}, true, nil } - return telemetry.TelemetryConfig{Categories: cats, ExportOTLP: exportOTLP}, false, nil + return telemetry.TelemetryConfig{ + Categories: cats, + ExportOTLP: exportOTLP, + ExcludedCdpMethods: excludedCdpMethodsFromOAPI(cfg), + }, false, nil } // exportOTLPFromOAPI reads the OTLP export toggle from a config, defaulting to @@ -295,10 +331,10 @@ func mergeTelemetryConfig(current telemetry.TelemetryConfig, patch *oapi.Browser if patch.Browser != nil { for _, f := range categoryFields(patch.Browser) { - if f.config == nil || f.config.Enabled == nil { + if f.enabled == nil { continue // not mentioned in patch; keep current state } - if *f.config.Enabled { + if *f.enabled { active[f.category] = struct{}{} } else { delete(active, f.category) @@ -312,6 +348,13 @@ func mergeTelemetryConfig(current telemetry.TelemetryConfig, patch *oapi.Browser exportOTLP = *patch.Export.Otlp.Enabled } + // So do the cdp_command exclusions: an omitted list is unchanged, an empty + // one clears them. + excluded := current.ExcludedCdpMethods + if patched := excludedCdpMethodsFromOAPI(patch); patched != nil { + excluded = patched + } + if len(active) == 0 { return telemetry.TelemetryConfig{}, true } @@ -319,7 +362,7 @@ func mergeTelemetryConfig(current telemetry.TelemetryConfig, patch *oapi.Browser for c := range active { cats = append(cats, c) } - return telemetry.TelemetryConfig{Categories: cats, ExportOTLP: exportOTLP}, false + return telemetry.TelemetryConfig{Categories: cats, ExportOTLP: exportOTLP, ExcludedCdpMethods: excluded}, false } // disabledConfig returns a BrowserTelemetryConfig with every configurable category explicitly disabled. @@ -333,7 +376,7 @@ func disabledConfig() oapi.BrowserTelemetryConfig { Network: off(), Page: off(), Interaction: off(), - Control: off(), + Control: &oapi.BrowserTelemetryControlConfig{Enabled: lo.ToPtr(false)}, Platform: off(), Connection: off(), System: off(), @@ -359,13 +402,17 @@ func telemetryConfigToOAPI(cfg telemetry.TelemetryConfig) oapi.BrowserTelemetryC on := active[cat] return &oapi.BrowserTelemetryCategoryConfig{Enabled: &on} } + control := &oapi.BrowserTelemetryControlConfig{Enabled: lo.ToPtr(active[events.Control])} + if len(cfg.ExcludedCdpMethods) > 0 { + control.Cdp = &oapi.BrowserTelemetryCdpControlConfig{ExcludedMethods: &cfg.ExcludedCdpMethods} + } return oapi.BrowserTelemetryConfig{ Browser: &oapi.BrowserTelemetryCategoriesConfig{ Console: enabled(events.Console), Network: enabled(events.Network), Page: enabled(events.Page), Interaction: enabled(events.Interaction), - Control: enabled(events.Control), + Control: control, Platform: enabled(events.Platform), Connection: enabled(events.Connection), System: enabled(events.System), diff --git a/server/cmd/api/api/telemetry_test.go b/server/cmd/api/api/telemetry_test.go index ec69d07b..8db4243c 100644 --- a/server/cmd/api/api/telemetry_test.go +++ b/server/cmd/api/api/telemetry_test.go @@ -12,6 +12,7 @@ import ( oapi "github.com/kernel/kernel-images/server/lib/oapi" "github.com/kernel/kernel-images/server/lib/recorder" "github.com/kernel/kernel-images/server/lib/scaletozero" + "github.com/samber/lo" "github.com/stretchr/testify/assert" "github.com/stretchr/testify/require" ) @@ -28,7 +29,7 @@ func allCategoriesDisabled() *oapi.BrowserTelemetryCategoriesConfig { Network: off(), Page: off(), Interaction: off(), - Control: off(), + Control: &oapi.BrowserTelemetryControlConfig{Enabled: lo.ToPtr(false)}, Platform: off(), Connection: off(), System: off(), @@ -207,7 +208,7 @@ func TestTelemetryHandlersDriveMiddlewareToggle(t *testing.T) { _, err := svc.PutTelemetry(ctx, oapi.PutTelemetryRequestObject{ Body: &oapi.BrowserTelemetryConfig{ Browser: &oapi.BrowserTelemetryCategoriesConfig{ - Control: &oapi.BrowserTelemetryCategoryConfig{Enabled: &tr}, + Control: &oapi.BrowserTelemetryControlConfig{Enabled: &tr}, }, }, }) @@ -217,7 +218,7 @@ func TestTelemetryHandlersDriveMiddlewareToggle(t *testing.T) { _, err = svc.PatchTelemetry(ctx, oapi.PatchTelemetryRequestObject{ Body: &oapi.BrowserTelemetryConfig{ Browser: &oapi.BrowserTelemetryCategoriesConfig{ - Control: &oapi.BrowserTelemetryCategoryConfig{Enabled: &f}, + Control: &oapi.BrowserTelemetryControlConfig{Enabled: &f}, }, }, }) @@ -254,7 +255,7 @@ func TestTelemetryHandlersEnableMiddlewareForPlatformOnly(t *testing.T) { _, err = svc.PatchTelemetry(ctx, oapi.PatchTelemetryRequestObject{ Body: &oapi.BrowserTelemetryConfig{ Browser: &oapi.BrowserTelemetryCategoriesConfig{ - Control: &oapi.BrowserTelemetryCategoryConfig{Enabled: &f}, + Control: &oapi.BrowserTelemetryControlConfig{Enabled: &f}, }, }, }) @@ -293,6 +294,10 @@ func TestGetTelemetry(t *testing.T) { r200, ok := resp.(oapi.GetTelemetry200JSONResponse) require.True(t, ok) assert.Equal(t, started.Config, r200.Config) + // Optional in the schema so an older image's response still validates, + // but always set here: absent would mean "not reported", not zero. + require.NotNil(t, r200.DroppedEvents) + assert.Zero(t, *r200.DroppedEvents) }) } @@ -624,3 +629,78 @@ func (e *blockingStopExporter) Running() bool { defer e.mu.Unlock() return e.running } + +func TestCdpExcludedMethodsRoundTrip(t *testing.T) { + ctx := context.Background() + excluded := []oapi.BrowserCdpCommandMethod{"Input.dispatchMouseEvent", "Page.captureScreenshot"} + withExclusions := func() *oapi.BrowserTelemetryConfig { + return &oapi.BrowserTelemetryConfig{ + Browser: &oapi.BrowserTelemetryCategoriesConfig{ + Control: &oapi.BrowserTelemetryControlConfig{ + Enabled: lo.ToPtr(true), + Cdp: &oapi.BrowserTelemetryCdpControlConfig{ExcludedMethods: &excluded}, + }, + }, + } + } + + t.Run("put stores them and the session exposes them to the proxy", func(t *testing.T) { + svc := newTestService(t, newMockRecordManager()) + resp, err := svc.PutTelemetry(ctx, oapi.PutTelemetryRequestObject{Body: withExclusions()}) + require.NoError(t, err) + created := resp.(oapi.PutTelemetry201JSONResponse) + require.NotNil(t, created.Config.Browser.Control.Cdp) + assert.Equal(t, excluded, *created.Config.Browser.Control.Cdp.ExcludedMethods) + + // The proxy reads this set per command, so it has to reflect the config. + assert.Equal(t, map[string]struct{}{ + "Input.dispatchMouseEvent": {}, + "Page.captureScreenshot": {}, + }, svc.telemetrySession.ExcludedCdpMethods()) + }) + + t.Run("patch leaves an omitted list alone and an empty list clears it", func(t *testing.T) { + svc := newTestService(t, newMockRecordManager()) + _, err := svc.PutTelemetry(ctx, oapi.PutTelemetryRequestObject{Body: withExclusions()}) + require.NoError(t, err) + + // Category toggle only: the exclusions are not mentioned, so they stand. + _, err = svc.PatchTelemetry(ctx, oapi.PatchTelemetryRequestObject{Body: &oapi.BrowserTelemetryConfig{ + Browser: &oapi.BrowserTelemetryCategoriesConfig{ + System: &oapi.BrowserTelemetryCategoryConfig{Enabled: lo.ToPtr(true)}, + }, + }}) + require.NoError(t, err) + assert.Len(t, svc.telemetrySession.ExcludedCdpMethods(), 2) + + empty := []oapi.BrowserCdpCommandMethod{} + _, err = svc.PatchTelemetry(ctx, oapi.PatchTelemetryRequestObject{Body: &oapi.BrowserTelemetryConfig{ + Browser: &oapi.BrowserTelemetryCategoriesConfig{ + Control: &oapi.BrowserTelemetryControlConfig{ + Cdp: &oapi.BrowserTelemetryCdpControlConfig{ExcludedMethods: &empty}, + }, + }, + }}) + require.NoError(t, err) + assert.Empty(t, svc.telemetrySession.ExcludedCdpMethods()) + }) +} + +// dropped_events was added to TelemetryState after it shipped, so it stays +// optional: a response from an image that predates it must still decode, and +// an old client's control block must still be a valid request. +func TestTelemetryStateStaysCompatibleWithOlderImages(t *testing.T) { + var state oapi.TelemetryState + err := json.Unmarshal([]byte(`{"config":{},"seq":42}`), &state) + require.NoError(t, err) + assert.Nil(t, state.DroppedEvents, "absent means not reported, which is not zero") + assert.EqualValues(t, 42, state.Seq) + + // A client that predates control.cdp sends only enabled, and still parses. + var cfg oapi.BrowserTelemetryConfig + err = json.Unmarshal([]byte(`{"browser":{"control":{"enabled":true}}}`), &cfg) + require.NoError(t, err) + require.NotNil(t, cfg.Browser.Control) + assert.True(t, *cfg.Browser.Control.Enabled) + assert.Nil(t, cfg.Browser.Control.Cdp) +} diff --git a/server/cmd/api/main.go b/server/cmd/api/main.go index 3a4a1461..30155ede 100644 --- a/server/cmd/api/main.go +++ b/server/cmd/api/main.go @@ -108,8 +108,12 @@ func main() { } // Construct events pipeline + // Sized for the control stream's event rate rather than the operational + // signals it started with: browser-control CDP commands are one event per + // keystroke and two per click, so a form-filling session produces thousands + // where a session used to produce tens. eventStream, err := events.NewEventStream(events.EventStreamConfig{ - RingCapacity: 1024, + RingCapacity: 8192, }) if err != nil { slogger.Error("failed to create event stream", "err", err) @@ -321,8 +325,11 @@ func main() { rDevtools.Get("/json/", jsonTargetHandler) rDevtools.Get("/json/list", jsonTargetHandler) rDevtools.Get("/json/list/", jsonTargetHandler) + // Checked once per forwarded client frame, so it reads the session's + // lock-free view rather than taking the telemetry lock. + controlEnabled := func() bool { return telemetrySession.CategoryEnabled(events.Control) } rDevtools.Get("/*", func(w http.ResponseWriter, r *http.Request) { - devtoolsproxy.WebSocketProxyHandler(upstreamMgr, slogger, config.LogCDPMessages, stz, telemetrySession.Publish, wsRegistry).ServeHTTP(w, r) + devtoolsproxy.WebSocketProxyHandler(upstreamMgr, slogger, config.LogCDPMessages, stz, telemetrySession.Publish, controlEnabled, telemetrySession.ExcludedCdpMethods, wsRegistry).ServeHTTP(w, r) }) srvDevtools := &http.Server{ diff --git a/server/e2e/e2e_otlp_storage_test.go b/server/e2e/e2e_otlp_storage_test.go index 8610e07d..c4c66b3e 100644 --- a/server/e2e/e2e_otlp_storage_test.go +++ b/server/e2e/e2e_otlp_storage_test.go @@ -106,7 +106,7 @@ func enableControlExport(t *testing.T, ctx context.Context, client *instanceoapi tr := true resp, err := client.PutTelemetryWithResponse(ctx, instanceoapi.PutTelemetryJSONRequestBody{ Browser: &instanceoapi.BrowserTelemetryCategoriesConfig{ - Control: &instanceoapi.BrowserTelemetryCategoryConfig{Enabled: &tr}, + Control: &instanceoapi.BrowserTelemetryControlConfig{Enabled: &tr}, }, Export: &instanceoapi.BrowserTelemetryExportConfig{ Otlp: &instanceoapi.BrowserTelemetryOTLPExportConfig{Enabled: &tr}, diff --git a/server/lib/devtoolsproxy/cdpcommand.go b/server/lib/devtoolsproxy/cdpcommand.go new file mode 100644 index 00000000..fee22adc --- /dev/null +++ b/server/lib/devtoolsproxy/cdpcommand.go @@ -0,0 +1,83 @@ +package devtoolsproxy + +import ( + "encoding/json" + + "github.com/kernel/kernel-images/server/lib/events" + oapi "github.com/kernel/kernel-images/server/lib/oapi" +) + +// cdpCommandMethod is the first of two decodes: the method alone. With no +// Params field, encoding/json walks the arguments without copying them, so +// deciding that a large Runtime.callFunctionOn is not browser control costs a +// scan rather than a megabyte. It is a real decode rather than a scan for the +// method name, so an escaped name like "Input.\u0064ispatchMouseEvent" +// resolves to the method it actually names. +type cdpCommandMethod struct { + Method string `json:"method"` +} + +// cdpCommand is the JSON-RPC envelope of a client command, matching the shape +// the rest of the repo uses (cdpmonitor, cdpclient). Params stays raw so the +// per-method sanitizer decides what is worth decoding. Only a frame that +// already named a supported method is decoded this far. +type cdpCommand struct { + Method string `json:"method"` + SessionID string `json:"sessionId"` + Params json.RawMessage `json:"params"` +} + +func (c cdpCommand) sessionID() *string { + if c.SessionID == "" { + return nil + } + return &c.SessionID +} + +// cdpCommandEvent builds the cdp_command event for a client-to-upstream frame, +// or reports false when the frame is not a browser-control command or its +// method is excluded by telemetry configuration. ts is when the command +// reached Chromium, passed in so time spent queued for classification does not +// show up as event time. +// +// Every supported command gets one event. Subtypes like mouseMoved and keyUp +// are commands in their own right — a mouseMoved with buttons held is a drag +// path, a keyUp releases a modifier — so the stream is never coalesced down to +// what looks like the interesting phases. +func cdpCommandEvent(msg []byte, ts int64, excluded map[string]struct{}) (events.Event, bool) { + var probe cdpCommandMethod + if err := json.Unmarshal(msg, &probe); err != nil { + return events.Event{}, false + } + sanitize, ok := sanitizers[probe.Method] + if !ok { + return events.Event{}, false + } + // Excluding a method suppresses only its event; the raw command was + // forwarded to Chromium before this ran. + if _, skip := excluded[probe.Method]; skip { + return events.Event{}, false + } + + // Only now is the frame worth copying arguments out of. A browser-control + // command is small, so the second pass is cheap. + var cmd cdpCommand + if err := json.Unmarshal(msg, &cmd); err != nil { + return events.Event{}, false + } + data, err := sanitize(cmd) + if err != nil { + return events.Event{}, false + } + payload, err := json.Marshal(data) + if err != nil { + return events.Event{}, false + } + return events.Event{ + Ts: ts, + Type: "cdp_command", + Category: events.Control, + Source: oapi.BrowserEventSource{Kind: oapi.KernelApi}, + Data: payload, + }, true +} diff --git a/server/lib/devtoolsproxy/cdpcommand_test.go b/server/lib/devtoolsproxy/cdpcommand_test.go new file mode 100644 index 00000000..18ca6d68 --- /dev/null +++ b/server/lib/devtoolsproxy/cdpcommand_test.go @@ -0,0 +1,422 @@ +package devtoolsproxy + +import ( + "encoding/json" + "fmt" + "sort" + "strings" + "testing" + + "github.com/ghodss/yaml" + + serverpkg "github.com/kernel/kernel-images/server" + "github.com/kernel/kernel-images/server/lib/events" +) + +// bs is a single backslash, kept out of the fixtures below so an editing +// pass cannot silently strip the escape they are testing. +const bs = `\` + +// testForwardTs stands in for the time a command reached Chromium. +const testForwardTs int64 = 1_700_000_000_000_000 + +// payloadOf classifies a frame and returns its event payload as a plain map. +// Asserting on the wire shape rather than the generated union type is the +// point: the payload is what a reader sees. +func payloadOf(t *testing.T, frame string) map[string]any { + t.Helper() + ev, ok := cdpCommandEvent([]byte(frame), testForwardTs, nil) + if !ok { + t.Fatalf("frame produced no event: %s", frame) + } + if ev.Type != "cdp_command" { + t.Fatalf("type = %q, want cdp_command", ev.Type) + } + if ev.Category != events.Control { + t.Fatalf("category = %q, want control", ev.Category) + } + if ev.Ts != testForwardTs { + t.Fatalf("ts = %d, want the forward time %d", ev.Ts, testForwardTs) + } + var got map[string]any + if err := json.Unmarshal(ev.Data, &got); err != nil { + t.Fatalf("unmarshal data: %v", err) + } + return got +} + +func TestCdpCommandEventClassification(t *testing.T) { + tests := []struct { + name string + frame string + want map[string]any + }{ + { + name: "click keeps the arguments that describe it", + frame: `{"id":1,"sessionId":"S1","method":"Input.dispatchMouseEvent","params":{"type":"mousePressed","x":10.5,"y":20,"button":"left","clickCount":2,"modifiers":8,"buttons":1,"pointerType":"mouse"}}`, + want: map[string]any{ + "method": "Input.dispatchMouseEvent", "session_id": "S1", "event_type": "mousePressed", + "x": 10.5, "y": 20.0, "button": "left", "click_count": 2.0, + "modifiers": 8.0, "buttons": 1.0, "pointer_type": "mouse", + }, + }, + { + name: "mouseMoved with buttons held is a drag path, not a duplicate phase", + frame: `{"id":2,"method":"Input.dispatchMouseEvent","params":{"type":"mouseMoved","x":9,"y":9,"buttons":1}}`, + want: map[string]any{ + "method": "Input.dispatchMouseEvent", "event_type": "mouseMoved", + "x": 9.0, "y": 9.0, "buttons": 1.0, + }, + }, + { + name: "wheel keeps its deltas", + frame: `{"id":3,"method":"Input.dispatchMouseEvent","params":{"type":"mouseWheel","x":1,"y":2,"deltaX":0,"deltaY":-400}}`, + want: map[string]any{ + "method": "Input.dispatchMouseEvent", "event_type": "mouseWheel", + "x": 1.0, "y": 2.0, "delta_x": 0.0, "delta_y": -400.0, + }, + }, + { + name: "keyUp releases a held modifier", + frame: `{"id":4,"method":"Input.dispatchKeyEvent","params":{"type":"keyUp","key":"Shift"}}`, + want: map[string]any{"method": "Input.dispatchKeyEvent", "event_type": "keyUp", "named_key": "Shift"}, + }, + { + name: "char is the command that inserts the character", + frame: `{"id":5,"method":"Input.dispatchKeyEvent","params":{"type":"char","text":"a"}}`, + want: map[string]any{"method": "Input.dispatchKeyEvent", "event_type": "char", "text_length": 1.0}, + }, + { + name: "a typed key is counted, never named", + frame: `{"id":6,"method":"Input.dispatchKeyEvent","params":{"type":"keyDown","key":"é","text":"é","code":"KeyE"}}`, + want: map[string]any{"method": "Input.dispatchKeyEvent", "event_type": "keyDown", "text_length": 1.0}, + }, + { + name: "scroll gesture keeps its distance", + frame: `{"id":7,"method":"Input.synthesizeScrollGesture","params":{"x":1,"y":2,"xDistance":0,"yDistance":-500,"speed":800}}`, + want: map[string]any{ + "method": "Input.synthesizeScrollGesture", "x": 1.0, "y": 2.0, + "x_distance": 0.0, "y_distance": -500.0, "speed": 800.0, + }, + }, + { + name: "touch reports its point count and the primary point", + frame: `{"id":8,"method":"Input.dispatchTouchEvent","params":{"type":"touchStart","touchPoints":[{"x":100,"y":200},{"x":300,"y":400}]}}`, + want: map[string]any{ + "method": "Input.dispatchTouchEvent", "event_type": "touchStart", + "touch_point_count": 2.0, "x": 100.0, "y": 200.0, + }, + }, + { + name: "drag reports counts and mime categories, not contents", + frame: `{"id":9,"method":"Input.dispatchDragEvent","params":{"type":"drop","x":5,"y":6,"data":{"items":[{"mimeType":"text/plain","data":"secret"},{"mimeType":"image/png","data":"secret"}],"files":["/tmp/a.pdf"],"dragOperationsMask":1}}}`, + want: map[string]any{ + "method": "Input.dispatchDragEvent", "event_type": "drop", "x": 5.0, "y": 6.0, + "drag_item_count": 2.0, "drag_file_count": 1.0, + "drag_mime_categories": []any{"image", "text"}, "drag_operations_mask": 1.0, + }, + }, + { + name: "navigation reports the scheme, never the host or the path", + frame: `{"id":10,"method":"Page.navigate","params":{"url":"https://example.com/reset?token=abc","referrer":"https://mail.example.com/x","transitionType":"typed"}}`, + want: map[string]any{ + "method": "Page.navigate", "url_scheme": "https", + "transition_type": "typed", "referrer_present": true, + }, + }, + { + name: "dialog reports the decision", + frame: `{"id":11,"method":"Page.handleJavaScriptDialog","params":{"accept":true,"promptText":"hunter2"}}`, + want: map[string]any{"method": "Page.handleJavaScriptDialog", "accept": true, "prompt_text_length": 7.0}, + }, + { + name: "file selection reports the count, never the paths", + frame: `{"id":12,"method":"DOM.setFileInputFiles","params":{"files":["/tmp/a.pdf","/tmp/b.pdf"],"backendNodeId":7}}`, + want: map[string]any{"method": "DOM.setFileInputFiles", "file_count": 2.0, "backend_node_id": 7.0}, + }, + { + name: "screenshot reports its options and clip", + frame: `{"id":13,"method":"Page.captureScreenshot","params":{"format":"png","quality":80,"clip":{"x":0,"y":0,"width":800,"height":600,"scale":1}}}`, + want: map[string]any{ + "method": "Page.captureScreenshot", "format": "png", "quality": 80.0, + "clip_x": 0.0, "clip_y": 0.0, "clip_width": 800.0, "clip_height": 600.0, "clip_scale": 1.0, + }, + }, + { + name: "autofill reports which kind of value was filled", + frame: `{"id":14,"method":"Autofill.trigger","params":{"fieldId":3,"card":{"number":"4111111111111111","cvc":"123"}}}`, + want: map[string]any{"method": "Autofill.trigger", "field_id": 3.0, "mode": "card"}, + }, + { + name: "a command with no arguments reports its name", + frame: `{"id":15,"method":"Page.bringToFront"}`, + want: map[string]any{"method": "Page.bringToFront"}, + }, + { + name: "window bounds are flattened out of the bounds object", + frame: `{"id":16,"method":"Browser.setWindowBounds","params":{"windowId":1,"bounds":{"left":0,"top":0,"width":1280,"height":720,"windowState":"normal"}}}`, + want: map[string]any{ + "method": "Browser.setWindowBounds", "window_id": 1.0, "left": 0.0, "top": 0.0, + "width": 1280.0, "height": 720.0, "window_state": "normal", + }, + }, + {name: "library bookkeeping is not browser control", frame: `{"id":17,"method":"Runtime.callFunctionOn","params":{"functionDeclaration":"() => 1","objectId":"x"}}`}, + {name: "runtime evaluation is not browser control", frame: `{"id":18,"method":"Runtime.evaluate","params":{"expression":"1+1"}}`}, + {name: "configuration is not browser control", frame: `{"id":19,"method":"Emulation.setDeviceMetricsOverride","params":{"width":1920,"height":1080}}`}, + {name: "chrome ui commands stay out", frame: `{"id":20,"method":"Browser.executeBrowserCommand","params":{"commandId":"openTabSearch"}}`}, + {name: "command results carry no method", frame: `{"id":21,"result":{"nodeId":42}}`}, + {name: "upstream events are not commands", frame: `{"method":"Page.frameNavigated","params":{"frame":{"url":"https://example.com"}}}`}, + {name: "a nested method cannot spoof a control command", frame: `{"id":22,"method":"Runtime.callFunctionOn","params":{"method":"Input.dispatchMouseEvent","x":1}}`}, + {name: "malformed frames are dropped", frame: `{"id":23,"method":"Input.insertText","params":`}, + {name: "malformed params are dropped", frame: `{"id":24,"method":"Input.insertText","params":{"text":5}}`}, + {name: "an empty frame is dropped", frame: ``}, + } + + for _, tc := range tests { + t.Run(tc.name, func(t *testing.T) { + if tc.want == nil { + if ev, ok := cdpCommandEvent([]byte(tc.frame), testForwardTs, nil); ok { + t.Fatalf("frame produced an event, want none: %s", ev.Data) + } + return + } + got := payloadOf(t, tc.frame) + wantJSON, _ := json.Marshal(tc.want) + gotJSON, _ := json.Marshal(got) + if string(wantJSON) != string(gotJSON) { + t.Fatalf("payload mismatch:\n want %s\n got %s", wantJSON, gotJSON) + } + }) + } +} + +// An escaped method name is still that method. The classifier decodes the +// frame rather than scanning it for a literal, so "Input.dispatch..." +// cannot slip a command past the stream. +func TestCdpCommandEventDecodesEscapedMethodNames(t *testing.T) { + // The "d" arrives as a unicode escape. A byte scan for the literal method + // name misses this; a decode does not. + escaped := `{"id":1,"method":"Input.\u0064ispatchMouseEvent","params":{"type":"mousePressed","x":1,"y":2}}` + if !strings.Contains(escaped, bs+`u0064`) { + t.Fatal("the fixture lost its escape, so this test proves nothing") + } + got := payloadOf(t, escaped) + if got["method"] != "Input.dispatchMouseEvent" { + t.Fatalf("method = %v, want Input.dispatchMouseEvent", got["method"]) + } + if got["event_type"] != "mousePressed" { + t.Fatalf("event_type = %v, want mousePressed", got["event_type"]) + } +} + +// sensitiveParams stuffs a unique sentinel into every argument that must never +// reach an event, across every supported method at once. A sanitizer only +// decodes its own arguments, so the superset is safe to send to all of them and +// catches a sanitizer that passes one of these through. +const sensitiveParams = `{ + "text":"SENTINELtext", + "unmodifiedText":"SENTINELunmodified", + "key":"SENTINELkey", + "code":"SENTINELcode", + "keyIdentifier":"SENTINELkeyident", + "url":"https://SENTINELhost.example/SENTINELpath?token=SENTINELquery#SENTINELfragment", + "referrer":"https://SENTINELhost.example/SENTINELreferrer", + "scriptToEvaluateOnLoad":"SENTINELscript", + "headerTemplate":"SENTINELheader", + "footerTemplate":"SENTINELfooter", + "pageRanges":"SENTINELranges", + "promptText":"SENTINELprompt", + "interactionMarkerName":"SENTINELmarker", + "files":["/tmp/SENTINELfile.pdf"], + "proxyServer":"http://SENTINELproxy:8080", + "proxyBypassList":"SENTINELbypass", + "originsWithUniversalNetworkAccess":["https://SENTINELorigin"], + "card":{"number":"SENTINELcard","cvc":"SENTINELcvc"}, + "address":{"fields":[{"name":"SENTINELname","value":"SENTINELaddress"}]}, + "data":{"items":[{"mimeType":"text/SENTINELsubtype","data":"SENTINELdrag","baseURL":"https://SENTINELhost.example/SENTINELbase","title":"SENTINELtitle"}],"files":["/tmp/SENTINELdragfile"]}, + "bounds":{}, + "clip":{}, + "touchPoints":[{"x":1,"y":2}] +}` + +func TestSanitizersNeverEmitSensitiveValues(t *testing.T) { + for method := range sanitizers { + t.Run(method, func(t *testing.T) { + frame := fmt.Sprintf(`{"id":1,"sessionId":"S","method":%q,"params":%s}`, method, sensitiveParams) + ev, ok := cdpCommandEvent([]byte(frame), testForwardTs, nil) + if !ok { + t.Fatalf("supported method produced no event") + } + payload := string(ev.Data) + if strings.Contains(payload, "SENTINEL") { + t.Fatalf("payload leaked a sensitive value: %s", payload) + } + }) + } +} + +// The map key and the payload's method must agree, or a copy-paste between two +// similar sanitizers would silently mislabel a command. +func TestSanitizersReportTheMethodTheyAreKeyedBy(t *testing.T) { + for method := range sanitizers { + t.Run(method, func(t *testing.T) { + got := payloadOf(t, fmt.Sprintf(`{"id":1,"method":%q}`, method)) + if got["method"] != method { + t.Fatalf("payload method = %v, want %s", got["method"], method) + } + }) + } +} + +// The inventory is the spec's enum. A method added to one and not the other is +// either an event no schema describes or a schema nothing emits. +func TestSanitizersMatchTheSchemaMethodEnum(t *testing.T) { + want := specCommandMethods(t) + got := make([]string, 0, len(sanitizers)) + for method := range sanitizers { + got = append(got, method) + } + sort.Strings(got) + sort.Strings(want) + if strings.Join(got, ",") != strings.Join(want, ",") { + t.Fatalf("sanitizers and BrowserCdpCommandMethod disagree:\n sanitizers: %v\n schema: %v", got, want) + } +} + +func TestSessionIdIsReportedWhenAddressed(t *testing.T) { + got := payloadOf(t, `{"id":1,"sessionId":"ABC","method":"Page.reload","params":{"ignoreCache":true}}`) + if got["session_id"] != "ABC" { + t.Fatalf("session_id = %v, want ABC", got["session_id"]) + } + got = payloadOf(t, `{"id":2,"method":"Browser.close"}`) + if _, ok := got["session_id"]; ok { + t.Fatal("browser-level command reported a session_id") + } +} + +func FuzzCdpCommandEvent(f *testing.F) { + f.Add(`{"id":1,"method":"Input.dispatchMouseEvent","params":{"type":"mousePressed","x":1,"y":2}}`) + f.Add(`{"id":1,"method":"Input.insertText","params":{"text":"hunter2"}}`) + f.Add(`{"id":1,"method":"Page.navigate","params":{"url":"https://example.com/a?token=b"}}`) + f.Add(`{"id":1,"method":"Input.dispatchDragEvent","params":{"data":{"items":[{"mimeType":"x"}]}}}`) + f.Add(`{"id":1,"method":"Autofill.trigger","params":{"fieldId":1,"address":{}}}`) + f.Add(`{"id":1,"method":`) + f.Add("\x00\xff\xfe") + + f.Fuzz(func(t *testing.T, frame string) { + ev, ok := cdpCommandEvent([]byte(frame), testForwardTs, nil) + if !ok { + return + } + // Whatever the input, the output must be a payload naming a supported + // method: an event that cannot be discriminated is worse than none. + var payload struct { + Method string `json:"method"` + } + if err := json.Unmarshal(ev.Data, &payload); err != nil { + t.Fatalf("emitted unparseable payload %q for frame %q", ev.Data, frame) + } + if _, ok := sanitizers[payload.Method]; !ok { + t.Fatalf("emitted method %q that is not supported, for frame %q", payload.Method, frame) + } + }) +} + +func BenchmarkCdpCommandEventClick(b *testing.B) { + frame := []byte(`{"id":1,"method":"Input.dispatchMouseEvent","params":{"type":"mousePressed","x":1,"y":2,"button":"left","clickCount":1}}`) + b.ReportAllocs() + for b.Loop() { + cdpCommandEvent(frame, testForwardTs, nil) + } +} + +func BenchmarkCdpCommandEventUnsupported(b *testing.B) { + frame := []byte(`{"id":1,"method":"Runtime.callFunctionOn","params":{"functionDeclaration":"() => 1","objectId":"x"}}`) + b.ReportAllocs() + for b.Loop() { + cdpCommandEvent(frame, testForwardTs, nil) + } +} + +// specCommandMethods reads the BrowserCdpCommandMethod enum out of the +// embedded spec, so the test compares against the schema rather than a second +// copy of the list. +func specCommandMethods(t *testing.T) []string { + t.Helper() + raw, err := yaml.YAMLToJSON(serverpkg.OpenAPIYAML) + if err != nil { + t.Fatalf("convert spec: %v", err) + } + var spec struct { + Components struct { + Schemas struct { + BrowserCdpCommandMethod struct { + Enum []string `json:"enum"` + } `json:"BrowserCdpCommandMethod"` + } `json:"schemas"` + } `json:"components"` + } + if err := json.Unmarshal(raw, &spec); err != nil { + t.Fatalf("parse spec: %v", err) + } + methods := spec.Components.Schemas.BrowserCdpCommandMethod.Enum + if len(methods) == 0 { + t.Fatal("spec has no BrowserCdpCommandMethod enum") + } + return methods +} + +// Excluding a method suppresses only its event. The raw command reached +// Chromium before classification ran, so exclusion can never change what the +// browser was told to do. +func TestExcludedMethodsSuppressOnlyTheirOwnEvents(t *testing.T) { + click := `{"id":1,"method":"Input.dispatchMouseEvent","params":{"type":"mousePressed","x":1,"y":2}}` + nav := `{"id":2,"method":"Page.navigate","params":{"url":"https://example.com/"}}` + excluded := map[string]struct{}{"Input.dispatchMouseEvent": {}} + + if _, ok := cdpCommandEvent([]byte(click), testForwardTs, excluded); ok { + t.Fatal("excluded method produced an event") + } + if _, ok := cdpCommandEvent([]byte(nav), testForwardTs, excluded); !ok { + t.Fatal("a method that was not excluded produced no event") + } + if _, ok := cdpCommandEvent([]byte(click), testForwardTs, nil); !ok { + t.Fatal("no exclusions configured, but the command produced no event") + } +} + +// The scheme is the only part of a URL the control category carries. A reader +// who needs the destination opts into the page category, where navigation +// events report the URL itself. +func TestNavigationReportsSchemeOnly(t *testing.T) { + for _, tc := range []struct { + frame string + want string + }{ + {`{"id":1,"method":"Page.navigate","params":{"url":"https://internal.acme.example/admin?token=abc"}}`, "https"}, + {`{"id":2,"method":"Page.navigate","params":{"url":"data:text/html,

hi

"}}`, "data"}, + {`{"id":3,"method":"Target.createTarget","params":{"url":"about:blank"}}`, "about"}, + } { + got := payloadOf(t, tc.frame) + if got["url_scheme"] != tc.want { + t.Fatalf("url_scheme = %v, want %v", got["url_scheme"], tc.want) + } + if _, ok := got["url_host"]; ok { + t.Fatalf("payload carried a url_host: %v", got) + } + for key, value := range got { + if str, isStr := value.(string); isStr && strings.Contains(str, "acme") { + t.Fatalf("payload leaked the host in %s: %v", key, value) + } + } + } +} + +// A relative or unparseable URL has no scheme, and the event says so rather +// than inventing one. +func TestNavigationOmitsSchemeWhenThereIsNone(t *testing.T) { + got := payloadOf(t, `{"id":1,"method":"Page.navigate","params":{"url":"/relative/path"}}`) + if _, ok := got["url_scheme"]; ok { + t.Fatalf("relative URL reported a scheme: %v", got) + } +} diff --git a/server/lib/devtoolsproxy/cdpobserver.go b/server/lib/devtoolsproxy/cdpobserver.go new file mode 100644 index 00000000..0d0a5f45 --- /dev/null +++ b/server/lib/devtoolsproxy/cdpobserver.go @@ -0,0 +1,197 @@ +package devtoolsproxy + +import ( + "context" + "log/slog" + "sync/atomic" + "time" +) + +// ControlEnabledFunc reports whether control-category telemetry is currently +// captured. The proxy calls it once per forwarded client frame, so it must be +// cheap: telemetry.TelemetrySession.CategoryEnabled is lock-free for this. +type ControlEnabledFunc func() bool + +// ExcludedMethodsFunc returns the browser-control methods configured out of the +// cdp_command stream, or nil when none are. Consulted on the worker once the +// method is known, so an exclusion never costs the pump anything. +type ExcludedMethodsFunc func() map[string]struct{} + +const ( + // cdpObserverQueueDepth bounds how many forwarded frames may be waiting for + // classification. Deep enough to absorb a burst of input gestures, shallow + // enough that a stalled publisher cannot accumulate unbounded garbage. + cdpObserverQueueDepth = 256 + // cdpObserverMaxQueuedBytes bounds the memory frames awaiting classification + // can hold. A per-frame cap would be the obvious bound, but the pump cannot + // know a frame's method without parsing it, so a cap there rejects a large + // Runtime.callFunctionOn — which would never have produced an event — as + // though a command had been lost. Budgeting the queue as a whole bounds the + // same memory while leaving that judgement to the worker. + cdpObserverMaxQueuedBytes = 8 << 20 + // cdpObserverDrainWait bounds how long connection teardown waits for the + // worker to finish the queue. + cdpObserverDrainWait = time.Second +) + +// cdpObserver turns forwarded client frames into cdp_command events on its own +// goroutine. Observe runs on the pump, so it does only what is needed to decide +// the frame is not worth queuing; classification, sanitation and publication +// all happen on the worker, where they cannot delay CDP or kill the process. +type cdpObserver struct { + frames chan observedFrame + drained chan struct{} + publish EventPublisher + controlEnabled ControlEnabledFunc + excludedMethods ExcludedMethodsFunc + logger *slog.Logger + + // queuedBytes tracks what the queue is holding, so admission can be decided + // on bytes rather than frame count alone. + queuedBytes atomic.Int64 + droppedQueued atomic.Int64 + droppedPanicked atomic.Int64 +} + +// observedFrame is a client frame that reached Chromium, with the time the +// forward completed. The timestamp travels with the frame so queue latency +// does not show up as event time. +type observedFrame struct { + msg []byte + ts int64 +} + +// newCdpObserver starts the classification worker. It stops when ctx is done. +// A nil publish or controlEnabled disables observation entirely. +func newCdpObserver(ctx context.Context, publish EventPublisher, controlEnabled ControlEnabledFunc, excludedMethods ExcludedMethodsFunc, logger *slog.Logger) *cdpObserver { + if publish == nil || controlEnabled == nil { + return nil + } + if excludedMethods == nil { + excludedMethods = func() map[string]struct{} { return nil } + } + o := &cdpObserver{ + frames: make(chan observedFrame, cdpObserverQueueDepth), + drained: make(chan struct{}), + publish: publish, + controlEnabled: controlEnabled, + excludedMethods: excludedMethods, + logger: logger, + } + go o.run(ctx) + return o +} + +// Observe queues a forwarded client frame. It never blocks and never parses: +// a frame arrives here only after Chromium has already accepted it, and the +// pump is waiting on the return. +func (o *cdpObserver) Observe(msg []byte, ts int64) { + if o == nil || !o.controlEnabled() { + return + } + size := int64(len(msg)) + if o.queuedBytes.Add(size) > cdpObserverMaxQueuedBytes { + o.queuedBytes.Add(-size) + o.droppedQueued.Add(1) + return + } + select { + case o.frames <- observedFrame{msg: msg, ts: ts}: + default: + o.queuedBytes.Add(-size) + o.droppedQueued.Add(1) + } +} + +// Dropped reports how many forwarded frames the classifier never saw: queue +// saturation, classification panics, and anything still queued once the worker +// has stopped. Reported on cdp_disconnect so a reader sees the loss rather than +// only the VM's log. A saturated queue rejects whatever arrives next, which may +// be library traffic that would have produced nothing, so this is an upper +// bound on commands lost rather than a count. +func (o *cdpObserver) Dropped() int64 { + if o == nil { + return 0 + } + dropped := o.droppedQueued.Load() + o.droppedPanicked.Load() + // Pump calls onClose as soon as one direction fails, while the other may + // still be forwarding, so a frame can be queued after the final drain. Once + // the worker has stopped nothing will read it, which makes it as lost as one + // the queue turned away — and silently so, unless it is counted here. + select { + case <-o.drained: + dropped += int64(len(o.frames)) + default: + } + return dropped +} + +func (o *cdpObserver) run(ctx context.Context) { + defer close(o.drained) + for { + select { + case <-ctx.Done(): + o.drain() + o.logDrops() + return + case f := <-o.frames: + o.handle(f) + } + } +} + +// drain classifies what is already queued once the pump is done, so a client's +// last commands still produce events rather than dying with the connection. +// The queue is bounded, so this is too. +func (o *cdpObserver) drain() { + for { + select { + case f := <-o.frames: + o.handle(f) + default: + return + } + } +} + +// WaitDrained blocks until the worker has finished the queue. Bounded, so a +// wedged publisher delays connection teardown by at most timeout. +func (o *cdpObserver) WaitDrained(timeout time.Duration) { + if o == nil { + return + } + timer := time.NewTimer(timeout) + defer timer.Stop() + select { + case <-o.drained: + case <-timer.C: + } +} + +// handle classifies one frame. The recover is what keeps a malformed-input bug +// in a sanitizer, or a panicking publisher, from taking the VM down: the pump +// is a bare goroutine and so is this one. +func (o *cdpObserver) handle(f observedFrame) { + defer o.queuedBytes.Add(-int64(len(f.msg))) + defer func() { + if r := recover(); r != nil { + o.droppedPanicked.Add(1) + o.logger.Error("cdp command telemetry panicked", slog.Any("err", r)) + } + }() + ev, ok := cdpCommandEvent(f.msg, f.ts, o.excludedMethods()) + if !ok { + return + } + o.publish(ev) +} + +func (o *cdpObserver) logDrops() { + queued, panicked := o.droppedQueued.Load(), o.droppedPanicked.Load() + if queued+panicked == 0 { + return + } + o.logger.Warn("cdp command telemetry dropped frames", + slog.Int64("queue_full", queued), + slog.Int64("panicked", panicked)) +} diff --git a/server/lib/devtoolsproxy/cdpobserver_test.go b/server/lib/devtoolsproxy/cdpobserver_test.go new file mode 100644 index 00000000..ffa7a12f --- /dev/null +++ b/server/lib/devtoolsproxy/cdpobserver_test.go @@ -0,0 +1,248 @@ +package devtoolsproxy + +import ( + "context" + "strings" + "sync" + "sync/atomic" + "testing" + "time" + + "github.com/kernel/kernel-images/server/lib/events" +) + +const clickFrame = `{"id":1,"method":"Input.dispatchMouseEvent","params":{"type":"mousePressed","x":1,"y":2}}` + +// countingPublisher records how many events reached the bus. +type countingPublisher struct { + n atomic.Int64 +} + +func (c *countingPublisher) publish(ev events.Event) (events.Envelope, bool) { + c.n.Add(1) + return events.Envelope{Event: ev}, true +} + +func newTestObserver(t *testing.T, publish EventPublisher, enabled ControlEnabledFunc) *cdpObserver { + t.Helper() + ctx, cancel := context.WithCancel(context.Background()) + t.Cleanup(cancel) + o := newCdpObserver(ctx, publish, enabled, nil, silentLogger()) + if o == nil { + t.Fatal("observer was not created") + } + return o +} + +// The gate is what makes telemetry free when it is off: a frame observed with +// control disabled must not be retained, parsed or queued. +func TestObserverDoesNoWorkWhenControlIsDisabled(t *testing.T) { + pub := &countingPublisher{} + o := newTestObserver(t, pub.publish, func() bool { return false }) + + for range 100 { + o.Observe([]byte(clickFrame), testForwardTs) + } + if queued := len(o.frames); queued != 0 { + t.Fatalf("queued %d frames with control disabled, want 0", queued) + } + if got := pub.n.Load(); got != 0 { + t.Fatalf("published %d events with control disabled, want 0", got) + } + if got := o.Dropped(); got != 0 { + t.Fatalf("counted %d drops with control disabled, want 0: a frame nobody wanted is not a loss", got) + } +} + +func TestObserveAllocatesNothingWhenControlIsDisabled(t *testing.T) { + o := newTestObserver(t, (&countingPublisher{}).publish, func() bool { return false }) + frame := []byte(clickFrame) + allocs := testing.AllocsPerRun(1000, func() { o.Observe(frame, testForwardTs) }) + if allocs != 0 { + t.Fatalf("Observe allocated %v times per call with control disabled, want 0", allocs) + } +} + +// A panicking publisher is the failure the pump must survive: before this the +// panic unwound through the message transform and took the process with it. +func TestPanickingPublisherIsContainedAndCounted(t *testing.T) { + var published atomic.Int64 + panicking := func(ev events.Event) (events.Envelope, bool) { + published.Add(1) + panic("publisher exploded") + } + o := newTestObserver(t, panicking, controlOn) + + for range 5 { + o.Observe([]byte(clickFrame), testForwardTs) + } + waitFor(t, func() bool { return o.Dropped() == 5 }) + if got := published.Load(); got != 5 { + t.Fatalf("publisher called %d times, want 5: the worker must keep going after a panic", got) + } +} + +// Saturation is an acceptable loss, but only a counted one. +func TestQueueSaturationIsCounted(t *testing.T) { + blocked := make(chan struct{}) + var released sync.Once + t.Cleanup(func() { released.Do(func() { close(blocked) }) }) + + blocking := func(ev events.Event) (events.Envelope, bool) { + <-blocked + return events.Envelope{Event: ev}, true + } + o := newTestObserver(t, blocking, controlOn) + + // One frame occupies the worker, the queue absorbs cdpObserverQueueDepth + // more, and everything past that is dropped rather than blocking the pump. + const overshoot = 50 + for range cdpObserverQueueDepth + overshoot + 1 { + o.Observe([]byte(clickFrame), testForwardTs) + } + waitFor(t, func() bool { return o.Dropped() > 0 }) + if got := o.Dropped(); got > overshoot+1 { + t.Fatalf("dropped %d frames, want at most %d: the queue should absorb the rest", got, overshoot+1) + } +} + +// A big frame is admitted on its merits, not rejected for its size: the pump +// cannot tell a large paste from library traffic, and rejecting either as a +// lost command is wrong. Only the queue's byte budget turns one away. +func TestLargeFramesAreClassifiedRatherThanRejected(t *testing.T) { + pub := &countingPublisher{} + o := newTestObserver(t, pub.publish, controlOn) + + big := `{"id":1,"method":"Input.insertText","params":{"text":"` + + strings.Repeat("x", 256<<10) + `"}}` + o.Observe([]byte(big), testForwardTs) + waitFor(t, func() bool { return pub.n.Load() == 1 }) + + if got := o.Dropped(); got != 0 { + t.Fatalf("dropped = %d, want 0: the frame was classified, not lost", got) + } +} + +// Library traffic the classifier discards is not a loss, however large it is. +// Counting it would make telemetry_dropped read as lost commands. +func TestLargeLibraryTrafficIsNotCountedAsLoss(t *testing.T) { + pub := &countingPublisher{} + o := newTestObserver(t, pub.publish, controlOn) + + big := `{"id":1,"method":"Runtime.callFunctionOn","params":{"functionDeclaration":"` + + strings.Repeat("x", 256<<10) + `","objectId":"x"}}` + o.Observe([]byte(big), testForwardTs) + waitFor(t, func() bool { return o.queuedBytes.Load() == 0 }) + + if got := pub.n.Load(); got != 0 { + t.Fatalf("published %d events for library traffic, want 0", got) + } + if got := o.Dropped(); got != 0 { + t.Fatalf("dropped = %d, want 0: a frame that would never be an event is not a loss", got) + } +} + +// The byte budget is what bounds memory, since there is no per-frame cap. +func TestQueueByteBudgetTurnsAwayWhatItCannotHold(t *testing.T) { + blocked := make(chan struct{}) + var released sync.Once + t.Cleanup(func() { released.Do(func() { close(blocked) }) }) + + blocking := func(ev events.Event) (events.Envelope, bool) { + <-blocked + return events.Envelope{Event: ev}, true + } + o := newTestObserver(t, blocking, controlOn) + + // Each frame is a sixteenth of the budget, so the budget binds well before + // the queue depth does. + frame := []byte(`{"id":1,"method":"Input.insertText","params":{"text":"` + + strings.Repeat("x", cdpObserverMaxQueuedBytes/16) + `"}}`) + for range 32 { + o.Observe(frame, testForwardTs) + } + waitFor(t, func() bool { return o.Dropped() > 0 }) + if got := o.queuedBytes.Load(); got > cdpObserverMaxQueuedBytes { + t.Fatalf("queued %d bytes, over the %d budget", got, cdpObserverMaxQueuedBytes) + } +} + +// Teardown must not lose the commands a client sent last. +func TestObserverDrainsQueuedFramesOnShutdown(t *testing.T) { + pub := &countingPublisher{} + ctx, cancel := context.WithCancel(context.Background()) + o := newCdpObserver(ctx, pub.publish, controlOn, nil, silentLogger()) + + const sent = 20 + for range sent { + o.Observe([]byte(clickFrame), testForwardTs) + } + cancel() + o.WaitDrained(5 * time.Second) + + if got := pub.n.Load(); got != sent { + t.Fatalf("published %d events, want %d: queued commands must survive teardown", got, sent) + } +} + +func TestObserverAppliesMethodExclusions(t *testing.T) { + pub := &countingPublisher{} + ctx, cancel := context.WithCancel(context.Background()) + t.Cleanup(cancel) + excluded := func() map[string]struct{} { + return map[string]struct{}{"Input.dispatchMouseEvent": {}} + } + o := newCdpObserver(ctx, pub.publish, controlOn, excluded, silentLogger()) + + o.Observe([]byte(clickFrame), testForwardTs) + o.Observe([]byte(`{"id":2,"method":"Page.reload"}`), testForwardTs) + waitFor(t, func() bool { return pub.n.Load() == 1 }) + + // An excluded method is not a drop: nothing was lost, it was configured out. + if got := o.Dropped(); got != 0 { + t.Fatalf("dropped = %d, want 0", got) + } +} + +func waitFor(t *testing.T, cond func() bool) { + t.Helper() + deadline := time.Now().Add(5 * time.Second) + for time.Now().Before(deadline) { + if cond() { + return + } + time.Sleep(2 * time.Millisecond) + } + t.Fatal("condition not met within 5s") +} + +// Pump reports a disconnect as soon as one direction fails, while the other can +// still forward, so a frame can reach the queue after the worker has drained +// and stopped. Nothing will classify it, so it has to be counted rather than +// quietly left behind: telemetry_dropped is what tells a reader the tail of the +// session is incomplete. +func TestFramesQueuedAfterTeardownAreCountedAsLoss(t *testing.T) { + pub := &countingPublisher{} + ctx, cancel := context.WithCancel(context.Background()) + o := newCdpObserver(ctx, pub.publish, controlOn, nil, silentLogger()) + + o.Observe([]byte(clickFrame), testForwardTs) + cancel() + o.WaitDrained(5 * time.Second) + if got := pub.n.Load(); got != 1 { + t.Fatalf("published %d events before teardown, want 1", got) + } + if got := o.Dropped(); got != 0 { + t.Fatalf("dropped = %d before the late frame, want 0", got) + } + + // The straggler the other pump direction forwarded on its way out. + o.Observe([]byte(clickFrame), testForwardTs) + + if got := pub.n.Load(); got != 1 { + t.Fatalf("published %d events, want 1: the worker has stopped", got) + } + if got := o.Dropped(); got != 1 { + t.Fatalf("dropped = %d, want 1: a frame nothing will read is a loss", got) + } +} diff --git a/server/lib/devtoolsproxy/cdpparams.go b/server/lib/devtoolsproxy/cdpparams.go new file mode 100644 index 00000000..e7f52aec --- /dev/null +++ b/server/lib/devtoolsproxy/cdpparams.go @@ -0,0 +1,1031 @@ +package devtoolsproxy + +// Sanitizers for the browser-control CDP commands the proxy reports. Each +// supported method has a canonical input type mirroring its parameters at +// devtools-protocol@2d019e73, and produces a separate output type generated +// from the OpenAPI schema. The split is what keeps the two jobs apart: the +// input names what the client sent, the output names what is safe to publish. +// +// The rule for every field: an argument that can carry a secret — typed and +// composition text, URLs, referrers, scripts, templates, file paths, drag +// contents, autofill values — is replaced by a length, a count, a presence +// flag, an enum or a URL scheme. Everything else is reported as it +// arrived, because an event that omits the click count or the scroll distance +// cannot answer what the agent did. +// +// Fields a canonical input type does not name are not decoded and cannot +// reach an event, so a protocol addition is privacy-safe until someone +// deliberately adds it here. + +import ( + "encoding/json" + "net/url" + "sort" + "strings" + "unicode/utf8" + + oapi "github.com/kernel/kernel-images/server/lib/oapi" +) + +// sanitizer turns one command's raw params into its sanitized payload. +type sanitizer func(cmd cdpCommand) (oapi.BrowserCdpCommandEventData, error) + +// sanitizers is the supported-method inventory: a method is reported if and +// only if it has an entry here. +var sanitizers = map[string]sanitizer{ + "Input.dispatchMouseEvent": sanitizeInputDispatchMouseEvent, + "Input.dispatchKeyEvent": sanitizeInputDispatchKeyEvent, + "Input.insertText": sanitizeInputInsertText, + "Input.imeSetComposition": sanitizeInputImeSetComposition, + "Input.dispatchTouchEvent": sanitizeInputDispatchTouchEvent, + "Input.dispatchDragEvent": sanitizeInputDispatchDragEvent, + "Input.cancelDragging": sanitizeInputCancelDragging, + "Input.emulateTouchFromMouseEvent": sanitizeInputEmulateTouchFromMouseEvent, + "Input.synthesizePinchGesture": sanitizeInputSynthesizePinchGesture, + "Input.synthesizeScrollGesture": sanitizeInputSynthesizeScrollGesture, + "Input.synthesizeTapGesture": sanitizeInputSynthesizeTapGesture, + "DOM.setFileInputFiles": sanitizeDomSetFileInputFiles, + "DOM.focus": sanitizeDomFocus, + "DOM.scrollIntoViewIfNeeded": sanitizeDomScrollIntoViewIfNeeded, + "Page.bringToFront": sanitizePageBringToFront, + "Page.captureScreenshot": sanitizePageCaptureScreenshot, + "Page.captureSnapshot": sanitizePageCaptureSnapshot, + "Page.handleJavaScriptDialog": sanitizePageHandleJavaScriptDialog, + "Page.navigate": sanitizePageNavigate, + "Page.navigateToHistoryEntry": sanitizePageNavigateToHistoryEntry, + "Page.reload": sanitizePageReload, + "Page.printToPDF": sanitizePagePrintToPDF, + "Page.startScreencast": sanitizePageStartScreencast, + "Page.stopScreencast": sanitizePageStopScreencast, + "Page.stopLoading": sanitizePageStopLoading, + "Page.close": sanitizePageClose, + "Page.setWebLifecycleState": sanitizePageSetWebLifecycleState, + "Target.activateTarget": sanitizeTargetActivateTarget, + "Target.closeTarget": sanitizeTargetCloseTarget, + "Target.createTarget": sanitizeTargetCreateTarget, + "Target.createBrowserContext": sanitizeTargetCreateBrowserContext, + "Target.disposeBrowserContext": sanitizeTargetDisposeBrowserContext, + "Target.openDevTools": sanitizeTargetOpenDevTools, + "Browser.cancelDownload": sanitizeBrowserCancelDownload, + "Browser.close": sanitizeBrowserClose, + "Browser.setWindowBounds": sanitizeBrowserSetWindowBounds, + "Browser.setContentsSize": sanitizeBrowserSetContentsSize, + "Autofill.trigger": sanitizeAutofillTrigger, +} + +// namedKeys are the KeyboardEvent.key values worth reading back: keys that +// command the page rather than type into it. This is an allowlist rather than a +// "more than one character" rule because key for typed input can itself be +// multi-rune — a decomposed "é" is two runes and is the letter someone typed, +// so a length rule would publish it. +var namedKeys = lookup(` + Enter Tab Escape Backspace Delete Insert + Home End PageUp PageDown ArrowUp ArrowDown ArrowLeft ArrowRight + Shift Control Alt Meta CapsLock NumLock ScrollLock + ContextMenu Pause PrintScreen + F1 F2 F3 F4 F5 F6 F7 F8 F9 F10 F11 F12 +`) + +// mimeCategories are the top-level MIME types a drag payload may report. A +// subtype names the file ("application/vnd.acme.invoice-2024"), so only the +// category survives, and one outside this set reports as "other". +var mimeCategories = lookup(`text image audio video application font model multipart message`) + +// lookup builds a membership set from a whitespace-separated list, so the lists +// above read as lists. +func lookup(words string) map[string]struct{} { + out := make(map[string]struct{}) + for _, word := range strings.Fields(words) { + out[word] = struct{}{} + } + return out +} + +// decodeParams fills p from a command's params. Several control commands take +// no arguments, so an absent params object means "all defaults", not an error. +func decodeParams(raw json.RawMessage, p any) error { + if len(raw) == 0 || string(raw) == "null" { + return nil + } + return json.Unmarshal(raw, p) +} + +func runeLen(s *string) *int { + if s == nil { + return nil + } + n := utf8.RuneCountInString(*s) + return &n +} + +func present(s *string) *bool { + p := s != nil && *s != "" + return &p +} + +func count[T any](items []T) *int { + n := len(items) + return &n +} + +func boolPtr(b bool) *bool { return &b } + +// namedKey passes through only a key that commands the page. A key that +// produces a character is the character someone typed. +func namedKey(key *string) *string { + if key == nil { + return nil + } + if _, ok := namedKeys[*key]; !ok { + return nil + } + return key +} + +// urlScheme reduces a URL to its scheme. The host names the site the agent +// went to and the path and query can carry a reset token, so neither leaves +// the VM through the control category; the page category is where a reader +// opts in to navigation URLs. +func urlScheme(raw string) *string { + if raw == "" { + return nil + } + parsed, err := url.Parse(raw) + if err != nil || parsed.Scheme == "" { + return nil + } + scheme := parsed.Scheme + return &scheme +} + +// ---- Input ---- + +type inputDispatchMouseEventParams struct { + Type string `json:"type"` + X *float64 `json:"x"` + Y *float64 `json:"y"` + Modifiers *int `json:"modifiers"` + Button *string `json:"button"` + Buttons *int `json:"buttons"` + ClickCount *int `json:"clickCount"` + Force *float64 `json:"force"` + TangentialPressure *float64 `json:"tangentialPressure"` + TiltX *float64 `json:"tiltX"` + TiltY *float64 `json:"tiltY"` + Twist *int `json:"twist"` + DeltaX *float64 `json:"deltaX"` + DeltaY *float64 `json:"deltaY"` + PointerType *string `json:"pointerType"` +} + +func sanitizeInputDispatchMouseEvent(cmd cdpCommand) (oapi.BrowserCdpCommandEventData, error) { + var p inputDispatchMouseEventParams + var out oapi.BrowserCdpCommandEventData + if err := decodeParams(cmd.Params, &p); err != nil { + return out, err + } + return out, out.FromBrowserCdpInputDispatchMouseEventCommandData(oapi.BrowserCdpInputDispatchMouseEventCommandData{ + SessionId: cmd.sessionID(), + EventType: p.Type, + X: p.X, + Y: p.Y, + Modifiers: p.Modifiers, + Button: p.Button, + Buttons: p.Buttons, + ClickCount: p.ClickCount, + DeltaX: p.DeltaX, + DeltaY: p.DeltaY, + PointerType: p.PointerType, + Force: p.Force, + TangentialPressure: p.TangentialPressure, + TiltX: p.TiltX, + TiltY: p.TiltY, + Twist: p.Twist, + }) +} + +type inputDispatchKeyEventParams struct { + Type string `json:"type"` + Modifiers *int `json:"modifiers"` + Text *string `json:"text"` + Key *string `json:"key"` + Location *int `json:"location"` + AutoRepeat *bool `json:"autoRepeat"` + IsKeypad *bool `json:"isKeypad"` + IsSystemKey *bool `json:"isSystemKey"` + Commands []string `json:"commands"` +} + +func sanitizeInputDispatchKeyEvent(cmd cdpCommand) (oapi.BrowserCdpCommandEventData, error) { + var p inputDispatchKeyEventParams + var out oapi.BrowserCdpCommandEventData + if err := decodeParams(cmd.Params, &p); err != nil { + return out, err + } + data := oapi.BrowserCdpInputDispatchKeyEventCommandData{ + SessionId: cmd.sessionID(), + EventType: p.Type, + Modifiers: p.Modifiers, + TextLength: runeLen(p.Text), + NamedKey: namedKey(p.Key), + Location: p.Location, + AutoRepeat: p.AutoRepeat, + IsKeypad: p.IsKeypad, + IsSystemKey: p.IsSystemKey, + } + // code, keyIdentifier and the virtual key codes all name the character as + // surely as text does, so they are never decoded. + if p.Commands != nil { + data.CommandCount = count(p.Commands) + } + return out, out.FromBrowserCdpInputDispatchKeyEventCommandData(data) +} + +type inputInsertTextParams struct { + Text string `json:"text"` +} + +func sanitizeInputInsertText(cmd cdpCommand) (oapi.BrowserCdpCommandEventData, error) { + var p inputInsertTextParams + var out oapi.BrowserCdpCommandEventData + if err := decodeParams(cmd.Params, &p); err != nil { + return out, err + } + return out, out.FromBrowserCdpInputInsertTextCommandData(oapi.BrowserCdpInputInsertTextCommandData{ + SessionId: cmd.sessionID(), + TextLength: utf8.RuneCountInString(p.Text), + }) +} + +type inputImeSetCompositionParams struct { + Text string `json:"text"` + SelectionStart *int `json:"selectionStart"` + SelectionEnd *int `json:"selectionEnd"` + ReplacementStart *int `json:"replacementStart"` + ReplacementEnd *int `json:"replacementEnd"` +} + +func sanitizeInputImeSetComposition(cmd cdpCommand) (oapi.BrowserCdpCommandEventData, error) { + var p inputImeSetCompositionParams + var out oapi.BrowserCdpCommandEventData + if err := decodeParams(cmd.Params, &p); err != nil { + return out, err + } + return out, out.FromBrowserCdpInputImeSetCompositionCommandData(oapi.BrowserCdpInputImeSetCompositionCommandData{ + SessionId: cmd.sessionID(), + TextLength: utf8.RuneCountInString(p.Text), + SelectionStart: p.SelectionStart, + SelectionEnd: p.SelectionEnd, + ReplacementStart: p.ReplacementStart, + ReplacementEnd: p.ReplacementEnd, + }) +} + +type touchPoint struct { + X *float64 `json:"x"` + Y *float64 `json:"y"` +} + +type inputDispatchTouchEventParams struct { + Type string `json:"type"` + TouchPoints []touchPoint `json:"touchPoints"` + Modifiers *int `json:"modifiers"` +} + +func sanitizeInputDispatchTouchEvent(cmd cdpCommand) (oapi.BrowserCdpCommandEventData, error) { + var p inputDispatchTouchEventParams + var out oapi.BrowserCdpCommandEventData + if err := decodeParams(cmd.Params, &p); err != nil { + return out, err + } + data := oapi.BrowserCdpInputDispatchTouchEventCommandData{ + SessionId: cmd.sessionID(), + EventType: p.Type, + TouchPointCount: len(p.TouchPoints), + Modifiers: p.Modifiers, + } + // A touch dispatch carries its coordinates inside touchPoints rather than + // at the top level, so the primary point stands in for where it landed. + if len(p.TouchPoints) > 0 { + data.X = p.TouchPoints[0].X + data.Y = p.TouchPoints[0].Y + } + return out, out.FromBrowserCdpInputDispatchTouchEventCommandData(data) +} + +type dragDataItem struct { + MimeType string `json:"mimeType"` +} + +type dragData struct { + Items []dragDataItem `json:"items"` + Files []string `json:"files"` + DragOperationsMask *int `json:"dragOperationsMask"` +} + +type inputDispatchDragEventParams struct { + Type string `json:"type"` + X *float64 `json:"x"` + Y *float64 `json:"y"` + Modifiers *int `json:"modifiers"` + Data dragData `json:"data"` +} + +func sanitizeInputDispatchDragEvent(cmd cdpCommand) (oapi.BrowserCdpCommandEventData, error) { + var p inputDispatchDragEventParams + var out oapi.BrowserCdpCommandEventData + if err := decodeParams(cmd.Params, &p); err != nil { + return out, err + } + data := oapi.BrowserCdpInputDispatchDragEventCommandData{ + SessionId: cmd.sessionID(), + EventType: p.Type, + X: p.X, + Y: p.Y, + Modifiers: p.Modifiers, + DragItemCount: count(p.Data.Items), + DragFileCount: count(p.Data.Files), + DragOperationsMask: p.Data.DragOperationsMask, + } + if cats := mimeCategoriesOf(p.Data.Items); len(cats) > 0 { + data.DragMimeCategories = &cats + } + return out, out.FromBrowserCdpInputDispatchDragEventCommandData(data) +} + +// mimeCategoriesOf reduces drag item MIME types to their distinct top-level +// categories. The subtype names the file, so it does not survive. +func mimeCategoriesOf(items []dragDataItem) []string { + seen := make(map[string]struct{}, len(items)) + for _, item := range items { + category, _, _ := strings.Cut(item.MimeType, "/") + category = strings.ToLower(strings.TrimSpace(category)) + if _, ok := mimeCategories[category]; !ok { + category = "other" + } + seen[category] = struct{}{} + } + out := make([]string, 0, len(seen)) + for category := range seen { + out = append(out, category) + } + sort.Strings(out) + return out +} + +func sanitizeInputCancelDragging(cmd cdpCommand) (oapi.BrowserCdpCommandEventData, error) { + var out oapi.BrowserCdpCommandEventData + return out, out.FromBrowserCdpInputCancelDraggingCommandData(oapi.BrowserCdpInputCancelDraggingCommandData{ + SessionId: cmd.sessionID(), + }) +} + +type inputEmulateTouchFromMouseEventParams struct { + Type string `json:"type"` + X *float64 `json:"x"` + Y *float64 `json:"y"` + Button *string `json:"button"` + Modifiers *int `json:"modifiers"` + ClickCount *int `json:"clickCount"` + DeltaX *float64 `json:"deltaX"` + DeltaY *float64 `json:"deltaY"` +} + +func sanitizeInputEmulateTouchFromMouseEvent(cmd cdpCommand) (oapi.BrowserCdpCommandEventData, error) { + var p inputEmulateTouchFromMouseEventParams + var out oapi.BrowserCdpCommandEventData + if err := decodeParams(cmd.Params, &p); err != nil { + return out, err + } + return out, out.FromBrowserCdpInputEmulateTouchFromMouseEventCommandData(oapi.BrowserCdpInputEmulateTouchFromMouseEventCommandData{ + SessionId: cmd.sessionID(), + EventType: p.Type, + X: p.X, + Y: p.Y, + Button: p.Button, + Modifiers: p.Modifiers, + ClickCount: p.ClickCount, + DeltaX: p.DeltaX, + DeltaY: p.DeltaY, + }) +} + +type inputSynthesizePinchGestureParams struct { + X *float64 `json:"x"` + Y *float64 `json:"y"` + ScaleFactor *float64 `json:"scaleFactor"` + RelativeSpeed *int `json:"relativeSpeed"` + GestureSourceType *string `json:"gestureSourceType"` +} + +func sanitizeInputSynthesizePinchGesture(cmd cdpCommand) (oapi.BrowserCdpCommandEventData, error) { + var p inputSynthesizePinchGestureParams + var out oapi.BrowserCdpCommandEventData + if err := decodeParams(cmd.Params, &p); err != nil { + return out, err + } + return out, out.FromBrowserCdpInputSynthesizePinchGestureCommandData(oapi.BrowserCdpInputSynthesizePinchGestureCommandData{ + SessionId: cmd.sessionID(), + X: p.X, + Y: p.Y, + ScaleFactor: p.ScaleFactor, + RelativeSpeed: p.RelativeSpeed, + GestureSourceType: p.GestureSourceType, + }) +} + +type inputSynthesizeScrollGestureParams struct { + X *float64 `json:"x"` + Y *float64 `json:"y"` + XDistance *float64 `json:"xDistance"` + YDistance *float64 `json:"yDistance"` + XOverscroll *float64 `json:"xOverscroll"` + YOverscroll *float64 `json:"yOverscroll"` + PreventFling *bool `json:"preventFling"` + Speed *int `json:"speed"` + GestureSourceType *string `json:"gestureSourceType"` + RepeatCount *int `json:"repeatCount"` + RepeatDelayMs *int `json:"repeatDelayMs"` +} + +func sanitizeInputSynthesizeScrollGesture(cmd cdpCommand) (oapi.BrowserCdpCommandEventData, error) { + var p inputSynthesizeScrollGestureParams + var out oapi.BrowserCdpCommandEventData + if err := decodeParams(cmd.Params, &p); err != nil { + return out, err + } + // interactionMarkerName is a caller-supplied label, so it is not decoded. + return out, out.FromBrowserCdpInputSynthesizeScrollGestureCommandData(oapi.BrowserCdpInputSynthesizeScrollGestureCommandData{ + SessionId: cmd.sessionID(), + X: p.X, + Y: p.Y, + XDistance: p.XDistance, + YDistance: p.YDistance, + XOverscroll: p.XOverscroll, + YOverscroll: p.YOverscroll, + PreventFling: p.PreventFling, + Speed: p.Speed, + GestureSourceType: p.GestureSourceType, + RepeatCount: p.RepeatCount, + RepeatDelayMs: p.RepeatDelayMs, + }) +} + +type inputSynthesizeTapGestureParams struct { + X *float64 `json:"x"` + Y *float64 `json:"y"` + Duration *int `json:"duration"` + TapCount *int `json:"tapCount"` + GestureSourceType *string `json:"gestureSourceType"` +} + +func sanitizeInputSynthesizeTapGesture(cmd cdpCommand) (oapi.BrowserCdpCommandEventData, error) { + var p inputSynthesizeTapGestureParams + var out oapi.BrowserCdpCommandEventData + if err := decodeParams(cmd.Params, &p); err != nil { + return out, err + } + return out, out.FromBrowserCdpInputSynthesizeTapGestureCommandData(oapi.BrowserCdpInputSynthesizeTapGestureCommandData{ + SessionId: cmd.sessionID(), + X: p.X, + Y: p.Y, + Duration: p.Duration, + TapCount: p.TapCount, + GestureSourceType: p.GestureSourceType, + }) +} + +// ---- DOM ---- + +// domNodeRef is the three-way node reference DOM commands take. It is shared +// because it is one canonical argument group, not because the commands are. +type domNodeRef struct { + NodeId *int `json:"nodeId"` + BackendNodeId *int `json:"backendNodeId"` + ObjectId *string `json:"objectId"` +} + +type domSetFileInputFilesParams struct { + domNodeRef + Files []string `json:"files"` +} + +func sanitizeDomSetFileInputFiles(cmd cdpCommand) (oapi.BrowserCdpCommandEventData, error) { + var p domSetFileInputFilesParams + var out oapi.BrowserCdpCommandEventData + if err := decodeParams(cmd.Params, &p); err != nil { + return out, err + } + return out, out.FromBrowserCdpDomSetFileInputFilesCommandData(oapi.BrowserCdpDomSetFileInputFilesCommandData{ + SessionId: cmd.sessionID(), + FileCount: len(p.Files), + NodeId: p.NodeId, + BackendNodeId: p.BackendNodeId, + ObjectId: p.ObjectId, + }) +} + +func sanitizeDomFocus(cmd cdpCommand) (oapi.BrowserCdpCommandEventData, error) { + var p domNodeRef + var out oapi.BrowserCdpCommandEventData + if err := decodeParams(cmd.Params, &p); err != nil { + return out, err + } + return out, out.FromBrowserCdpDomFocusCommandData(oapi.BrowserCdpDomFocusCommandData{ + SessionId: cmd.sessionID(), + NodeId: p.NodeId, + BackendNodeId: p.BackendNodeId, + ObjectId: p.ObjectId, + }) +} + +type domScrollIntoViewIfNeededParams struct { + domNodeRef + Rect json.RawMessage `json:"rect"` +} + +func sanitizeDomScrollIntoViewIfNeeded(cmd cdpCommand) (oapi.BrowserCdpCommandEventData, error) { + var p domScrollIntoViewIfNeededParams + var out oapi.BrowserCdpCommandEventData + if err := decodeParams(cmd.Params, &p); err != nil { + return out, err + } + return out, out.FromBrowserCdpDomScrollIntoViewIfNeededCommandData(oapi.BrowserCdpDomScrollIntoViewIfNeededCommandData{ + SessionId: cmd.sessionID(), + NodeId: p.NodeId, + BackendNodeId: p.BackendNodeId, + ObjectId: p.ObjectId, + HasRect: boolPtr(len(p.Rect) > 0 && string(p.Rect) != "null"), + }) +} + +// ---- Page ---- + +func sanitizePageBringToFront(cmd cdpCommand) (oapi.BrowserCdpCommandEventData, error) { + var out oapi.BrowserCdpCommandEventData + return out, out.FromBrowserCdpPageBringToFrontCommandData(oapi.BrowserCdpPageBringToFrontCommandData{ + SessionId: cmd.sessionID(), + }) +} + +type viewport struct { + X *float64 `json:"x"` + Y *float64 `json:"y"` + Width *float64 `json:"width"` + Height *float64 `json:"height"` + Scale *float64 `json:"scale"` +} + +type pageCaptureScreenshotParams struct { + Format *string `json:"format"` + Quality *int `json:"quality"` + Clip *viewport `json:"clip"` + FromSurface *bool `json:"fromSurface"` + CaptureBeyondViewport *bool `json:"captureBeyondViewport"` + OptimizeForSpeed *bool `json:"optimizeForSpeed"` +} + +func sanitizePageCaptureScreenshot(cmd cdpCommand) (oapi.BrowserCdpCommandEventData, error) { + var p pageCaptureScreenshotParams + var out oapi.BrowserCdpCommandEventData + if err := decodeParams(cmd.Params, &p); err != nil { + return out, err + } + data := oapi.BrowserCdpPageCaptureScreenshotCommandData{ + SessionId: cmd.sessionID(), + Format: p.Format, + Quality: p.Quality, + FromSurface: p.FromSurface, + CaptureBeyondViewport: p.CaptureBeyondViewport, + OptimizeForSpeed: p.OptimizeForSpeed, + } + if p.Clip != nil { + data.ClipX, data.ClipY = p.Clip.X, p.Clip.Y + data.ClipWidth, data.ClipHeight, data.ClipScale = p.Clip.Width, p.Clip.Height, p.Clip.Scale + } + return out, out.FromBrowserCdpPageCaptureScreenshotCommandData(data) +} + +type pageCaptureSnapshotParams struct { + Format *string `json:"format"` +} + +func sanitizePageCaptureSnapshot(cmd cdpCommand) (oapi.BrowserCdpCommandEventData, error) { + var p pageCaptureSnapshotParams + var out oapi.BrowserCdpCommandEventData + if err := decodeParams(cmd.Params, &p); err != nil { + return out, err + } + return out, out.FromBrowserCdpPageCaptureSnapshotCommandData(oapi.BrowserCdpPageCaptureSnapshotCommandData{ + SessionId: cmd.sessionID(), + Format: p.Format, + }) +} + +type pageHandleJavaScriptDialogParams struct { + Accept bool `json:"accept"` + PromptText *string `json:"promptText"` +} + +func sanitizePageHandleJavaScriptDialog(cmd cdpCommand) (oapi.BrowserCdpCommandEventData, error) { + var p pageHandleJavaScriptDialogParams + var out oapi.BrowserCdpCommandEventData + if err := decodeParams(cmd.Params, &p); err != nil { + return out, err + } + return out, out.FromBrowserCdpPageHandleJavaScriptDialogCommandData(oapi.BrowserCdpPageHandleJavaScriptDialogCommandData{ + SessionId: cmd.sessionID(), + Accept: p.Accept, + PromptTextLength: runeLen(p.PromptText), + }) +} + +type pageNavigateParams struct { + Url string `json:"url"` + Referrer *string `json:"referrer"` + TransitionType *string `json:"transitionType"` + FrameId *string `json:"frameId"` + ReferrerPolicy *string `json:"referrerPolicy"` +} + +func sanitizePageNavigate(cmd cdpCommand) (oapi.BrowserCdpCommandEventData, error) { + var p pageNavigateParams + var out oapi.BrowserCdpCommandEventData + if err := decodeParams(cmd.Params, &p); err != nil { + return out, err + } + return out, out.FromBrowserCdpPageNavigateCommandData(oapi.BrowserCdpPageNavigateCommandData{ + SessionId: cmd.sessionID(), + UrlScheme: urlScheme(p.Url), + TransitionType: p.TransitionType, + ReferrerPresent: present(p.Referrer), + ReferrerPolicy: p.ReferrerPolicy, + FrameId: p.FrameId, + }) +} + +type pageNavigateToHistoryEntryParams struct { + EntryId int `json:"entryId"` +} + +func sanitizePageNavigateToHistoryEntry(cmd cdpCommand) (oapi.BrowserCdpCommandEventData, error) { + var p pageNavigateToHistoryEntryParams + var out oapi.BrowserCdpCommandEventData + if err := decodeParams(cmd.Params, &p); err != nil { + return out, err + } + return out, out.FromBrowserCdpPageNavigateToHistoryEntryCommandData(oapi.BrowserCdpPageNavigateToHistoryEntryCommandData{ + SessionId: cmd.sessionID(), + EntryId: p.EntryId, + }) +} + +type pageReloadParams struct { + IgnoreCache *bool `json:"ignoreCache"` + ScriptToEvaluateOnLoad *string `json:"scriptToEvaluateOnLoad"` + LoaderId *string `json:"loaderId"` +} + +func sanitizePageReload(cmd cdpCommand) (oapi.BrowserCdpCommandEventData, error) { + var p pageReloadParams + var out oapi.BrowserCdpCommandEventData + if err := decodeParams(cmd.Params, &p); err != nil { + return out, err + } + return out, out.FromBrowserCdpPageReloadCommandData(oapi.BrowserCdpPageReloadCommandData{ + SessionId: cmd.sessionID(), + IgnoreCache: p.IgnoreCache, + ScriptLength: runeLen(p.ScriptToEvaluateOnLoad), + LoaderId: p.LoaderId, + }) +} + +type pagePrintToPDFParams struct { + Landscape *bool `json:"landscape"` + DisplayHeaderFooter *bool `json:"displayHeaderFooter"` + PrintBackground *bool `json:"printBackground"` + Scale *float64 `json:"scale"` + PaperWidth *float64 `json:"paperWidth"` + PaperHeight *float64 `json:"paperHeight"` + PageRanges *string `json:"pageRanges"` + HeaderTemplate *string `json:"headerTemplate"` + FooterTemplate *string `json:"footerTemplate"` + PreferCSSPageSize *bool `json:"preferCSSPageSize"` + TransferMode *string `json:"transferMode"` +} + +func sanitizePagePrintToPDF(cmd cdpCommand) (oapi.BrowserCdpCommandEventData, error) { + var p pagePrintToPDFParams + var out oapi.BrowserCdpCommandEventData + if err := decodeParams(cmd.Params, &p); err != nil { + return out, err + } + return out, out.FromBrowserCdpPagePrintToPdfCommandData(oapi.BrowserCdpPagePrintToPdfCommandData{ + SessionId: cmd.sessionID(), + Landscape: p.Landscape, + Scale: p.Scale, + PaperWidth: p.PaperWidth, + PaperHeight: p.PaperHeight, + DisplayHeaderFooter: p.DisplayHeaderFooter, + PrintBackground: p.PrintBackground, + PreferCssPageSize: p.PreferCSSPageSize, + TransferMode: p.TransferMode, + PageRangesPresent: present(p.PageRanges), + HeaderTemplatePresent: present(p.HeaderTemplate), + FooterTemplatePresent: present(p.FooterTemplate), + }) +} + +type pageStartScreencastParams struct { + Format *string `json:"format"` + Quality *int `json:"quality"` + MaxWidth *int `json:"maxWidth"` + MaxHeight *int `json:"maxHeight"` + EveryNthFrame *int `json:"everyNthFrame"` +} + +func sanitizePageStartScreencast(cmd cdpCommand) (oapi.BrowserCdpCommandEventData, error) { + var p pageStartScreencastParams + var out oapi.BrowserCdpCommandEventData + if err := decodeParams(cmd.Params, &p); err != nil { + return out, err + } + return out, out.FromBrowserCdpPageStartScreencastCommandData(oapi.BrowserCdpPageStartScreencastCommandData{ + SessionId: cmd.sessionID(), + Format: p.Format, + Quality: p.Quality, + MaxWidth: p.MaxWidth, + MaxHeight: p.MaxHeight, + EveryNthFrame: p.EveryNthFrame, + }) +} + +func sanitizePageStopScreencast(cmd cdpCommand) (oapi.BrowserCdpCommandEventData, error) { + var out oapi.BrowserCdpCommandEventData + return out, out.FromBrowserCdpPageStopScreencastCommandData(oapi.BrowserCdpPageStopScreencastCommandData{ + SessionId: cmd.sessionID(), + }) +} + +func sanitizePageStopLoading(cmd cdpCommand) (oapi.BrowserCdpCommandEventData, error) { + var out oapi.BrowserCdpCommandEventData + return out, out.FromBrowserCdpPageStopLoadingCommandData(oapi.BrowserCdpPageStopLoadingCommandData{ + SessionId: cmd.sessionID(), + }) +} + +func sanitizePageClose(cmd cdpCommand) (oapi.BrowserCdpCommandEventData, error) { + var out oapi.BrowserCdpCommandEventData + return out, out.FromBrowserCdpPageCloseCommandData(oapi.BrowserCdpPageCloseCommandData{ + SessionId: cmd.sessionID(), + }) +} + +type pageSetWebLifecycleStateParams struct { + State string `json:"state"` +} + +func sanitizePageSetWebLifecycleState(cmd cdpCommand) (oapi.BrowserCdpCommandEventData, error) { + var p pageSetWebLifecycleStateParams + var out oapi.BrowserCdpCommandEventData + if err := decodeParams(cmd.Params, &p); err != nil { + return out, err + } + return out, out.FromBrowserCdpPageSetWebLifecycleStateCommandData(oapi.BrowserCdpPageSetWebLifecycleStateCommandData{ + SessionId: cmd.sessionID(), + State: p.State, + }) +} + +// ---- Target ---- + +type targetIdParams struct { + TargetId string `json:"targetId"` + PanelId string `json:"panelId"` +} + +func sanitizeTargetActivateTarget(cmd cdpCommand) (oapi.BrowserCdpCommandEventData, error) { + var p targetIdParams + var out oapi.BrowserCdpCommandEventData + if err := decodeParams(cmd.Params, &p); err != nil { + return out, err + } + return out, out.FromBrowserCdpTargetActivateTargetCommandData(oapi.BrowserCdpTargetActivateTargetCommandData{ + SessionId: cmd.sessionID(), + TargetId: p.TargetId, + }) +} + +func sanitizeTargetCloseTarget(cmd cdpCommand) (oapi.BrowserCdpCommandEventData, error) { + var p targetIdParams + var out oapi.BrowserCdpCommandEventData + if err := decodeParams(cmd.Params, &p); err != nil { + return out, err + } + return out, out.FromBrowserCdpTargetCloseTargetCommandData(oapi.BrowserCdpTargetCloseTargetCommandData{ + SessionId: cmd.sessionID(), + TargetId: p.TargetId, + }) +} + +func sanitizeTargetOpenDevTools(cmd cdpCommand) (oapi.BrowserCdpCommandEventData, error) { + var p targetIdParams + var out oapi.BrowserCdpCommandEventData + if err := decodeParams(cmd.Params, &p); err != nil { + return out, err + } + data := oapi.BrowserCdpTargetOpenDevToolsCommandData{ + SessionId: cmd.sessionID(), + TargetId: p.TargetId, + } + if p.PanelId != "" { + data.PanelId = &p.PanelId + } + return out, out.FromBrowserCdpTargetOpenDevToolsCommandData(data) +} + +type targetCreateTargetParams struct { + Url string `json:"url"` + Left *int `json:"left"` + Top *int `json:"top"` + Width *int `json:"width"` + Height *int `json:"height"` + WindowState *string `json:"windowState"` + BrowserContextId *string `json:"browserContextId"` + EnableBeginFrameControl *bool `json:"enableBeginFrameControl"` + NewWindow *bool `json:"newWindow"` + Background *bool `json:"background"` + ForTab *bool `json:"forTab"` + Hidden *bool `json:"hidden"` +} + +func sanitizeTargetCreateTarget(cmd cdpCommand) (oapi.BrowserCdpCommandEventData, error) { + var p targetCreateTargetParams + var out oapi.BrowserCdpCommandEventData + if err := decodeParams(cmd.Params, &p); err != nil { + return out, err + } + return out, out.FromBrowserCdpTargetCreateTargetCommandData(oapi.BrowserCdpTargetCreateTargetCommandData{ + SessionId: cmd.sessionID(), + UrlScheme: urlScheme(p.Url), + Left: p.Left, + Top: p.Top, + Width: p.Width, + Height: p.Height, + WindowState: p.WindowState, + BrowserContextId: p.BrowserContextId, + NewWindow: p.NewWindow, + Background: p.Background, + ForTab: p.ForTab, + Hidden: p.Hidden, + EnableBeginFrameControl: p.EnableBeginFrameControl, + }) +} + +type targetCreateBrowserContextParams struct { + DisposeOnDetach *bool `json:"disposeOnDetach"` + ProxyServer *string `json:"proxyServer"` + ProxyBypassList *string `json:"proxyBypassList"` + OriginsWithUniversalNetworkAccess []string `json:"originsWithUniversalNetworkAccess"` +} + +func sanitizeTargetCreateBrowserContext(cmd cdpCommand) (oapi.BrowserCdpCommandEventData, error) { + var p targetCreateBrowserContextParams + var out oapi.BrowserCdpCommandEventData + if err := decodeParams(cmd.Params, &p); err != nil { + return out, err + } + return out, out.FromBrowserCdpTargetCreateBrowserContextCommandData(oapi.BrowserCdpTargetCreateBrowserContextCommandData{ + SessionId: cmd.sessionID(), + DisposeOnDetach: p.DisposeOnDetach, + ProxyServerPresent: present(p.ProxyServer), + ProxyBypassListPresent: present(p.ProxyBypassList), + UniversalNetworkAccessOriginCount: count(p.OriginsWithUniversalNetworkAccess), + }) +} + +type browserContextIdParams struct { + BrowserContextId string `json:"browserContextId"` +} + +func sanitizeTargetDisposeBrowserContext(cmd cdpCommand) (oapi.BrowserCdpCommandEventData, error) { + var p browserContextIdParams + var out oapi.BrowserCdpCommandEventData + if err := decodeParams(cmd.Params, &p); err != nil { + return out, err + } + return out, out.FromBrowserCdpTargetDisposeBrowserContextCommandData(oapi.BrowserCdpTargetDisposeBrowserContextCommandData{ + SessionId: cmd.sessionID(), + BrowserContextId: p.BrowserContextId, + }) +} + +// ---- Browser ---- + +type browserCancelDownloadParams struct { + Guid string `json:"guid"` + BrowserContextId *string `json:"browserContextId"` +} + +func sanitizeBrowserCancelDownload(cmd cdpCommand) (oapi.BrowserCdpCommandEventData, error) { + var p browserCancelDownloadParams + var out oapi.BrowserCdpCommandEventData + if err := decodeParams(cmd.Params, &p); err != nil { + return out, err + } + return out, out.FromBrowserCdpBrowserCancelDownloadCommandData(oapi.BrowserCdpBrowserCancelDownloadCommandData{ + SessionId: cmd.sessionID(), + DownloadGuid: p.Guid, + BrowserContextId: p.BrowserContextId, + }) +} + +func sanitizeBrowserClose(cmd cdpCommand) (oapi.BrowserCdpCommandEventData, error) { + var out oapi.BrowserCdpCommandEventData + return out, out.FromBrowserCdpBrowserCloseCommandData(oapi.BrowserCdpBrowserCloseCommandData{ + SessionId: cmd.sessionID(), + }) +} + +type windowBounds struct { + Left *int `json:"left"` + Top *int `json:"top"` + Width *int `json:"width"` + Height *int `json:"height"` + WindowState *string `json:"windowState"` +} + +type browserSetWindowBoundsParams struct { + WindowId int `json:"windowId"` + Bounds windowBounds `json:"bounds"` +} + +func sanitizeBrowserSetWindowBounds(cmd cdpCommand) (oapi.BrowserCdpCommandEventData, error) { + var p browserSetWindowBoundsParams + var out oapi.BrowserCdpCommandEventData + if err := decodeParams(cmd.Params, &p); err != nil { + return out, err + } + return out, out.FromBrowserCdpBrowserSetWindowBoundsCommandData(oapi.BrowserCdpBrowserSetWindowBoundsCommandData{ + SessionId: cmd.sessionID(), + WindowId: p.WindowId, + Left: p.Bounds.Left, + Top: p.Bounds.Top, + Width: p.Bounds.Width, + Height: p.Bounds.Height, + WindowState: p.Bounds.WindowState, + }) +} + +type browserSetContentsSizeParams struct { + WindowId int `json:"windowId"` + Width *int `json:"width"` + Height *int `json:"height"` +} + +func sanitizeBrowserSetContentsSize(cmd cdpCommand) (oapi.BrowserCdpCommandEventData, error) { + var p browserSetContentsSizeParams + var out oapi.BrowserCdpCommandEventData + if err := decodeParams(cmd.Params, &p); err != nil { + return out, err + } + return out, out.FromBrowserCdpBrowserSetContentsSizeCommandData(oapi.BrowserCdpBrowserSetContentsSizeCommandData{ + SessionId: cmd.sessionID(), + WindowId: p.WindowId, + Width: p.Width, + Height: p.Height, + }) +} + +// ---- Autofill ---- + +type autofillTriggerParams struct { + FieldId int `json:"fieldId"` + FrameId *string `json:"frameId"` + Card json.RawMessage `json:"card"` + Address json.RawMessage `json:"address"` +} + +func sanitizeAutofillTrigger(cmd cdpCommand) (oapi.BrowserCdpCommandEventData, error) { + var p autofillTriggerParams + var out oapi.BrowserCdpCommandEventData + if err := decodeParams(cmd.Params, &p); err != nil { + return out, err + } + data := oapi.BrowserCdpAutofillTriggerCommandData{ + SessionId: cmd.sessionID(), + FieldId: p.FieldId, + FrameId: p.FrameId, + } + // The card number and the address lines are the whole payload, so only + // which of the two was filled survives. + switch { + case len(p.Card) > 0 && string(p.Card) != "null": + mode := "card" + data.Mode = &mode + case len(p.Address) > 0 && string(p.Address) != "null": + mode := "address" + data.Mode = &mode + } + return out, out.FromBrowserCdpAutofillTriggerCommandData(data) +} diff --git a/server/lib/devtoolsproxy/cdpproxy_test.go b/server/lib/devtoolsproxy/cdpproxy_test.go new file mode 100644 index 00000000..c4fc5f45 --- /dev/null +++ b/server/lib/devtoolsproxy/cdpproxy_test.go @@ -0,0 +1,300 @@ +package devtoolsproxy + +import ( + "context" + "encoding/json" + "net/http" + "net/http/httptest" + "net/url" + "strconv" + "strings" + "testing" + "time" + + "github.com/coder/websocket" + "github.com/kernel/kernel-images/server/lib/events" + oapi "github.com/kernel/kernel-images/server/lib/oapi" + "github.com/kernel/kernel-images/server/lib/scaletozero" +) + +// echoProxy stands up a proxy in front of an echoing upstream and returns a +// connected client. The upstream echoes every frame back, so a test that +// counted the upstream direction as commands would fail. +func echoProxy(t *testing.T, publish EventPublisher, controlEnabled ControlEnabledFunc) (*websocket.Conn, context.Context) { + t.Helper() + upstream := httptest.NewServer(http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) { + c, err := websocket.Accept(w, r, &websocket.AcceptOptions{OriginPatterns: []string{"*"}}) + if err != nil { + return + } + defer c.Close(websocket.StatusNormalClosure, "") + c.SetReadLimit(100 * 1024 * 1024) + for { + mt, msg, err := c.Read(r.Context()) + if err != nil { + return + } + if err := c.Write(r.Context(), mt, msg); err != nil { + return + } + } + })) + t.Cleanup(upstream.Close) + + u, _ := url.Parse(upstream.URL) + u.Scheme = "ws" + u.Path = "/devtools/browser/x" + + logger := silentLogger() + mgr := NewUpstreamManager("/dev/null", logger) + mgr.setCurrent(u.String()) + + proxy := httptest.NewServer(WebSocketProxyHandler( + mgr, logger, false, scaletozero.NewNoopController(), publish, controlEnabled, nil, nil)) + t.Cleanup(proxy.Close) + + pu, _ := url.Parse(proxy.URL) + pu.Scheme = "ws" + + ctx, cancel := context.WithTimeout(context.Background(), 20*time.Second) + t.Cleanup(cancel) + conn, _, err := websocket.Dial(ctx, pu.String(), nil) + if err != nil { + t.Fatalf("dial proxy failed: %v", err) + } + conn.SetReadLimit(100 * 1024 * 1024) + t.Cleanup(func() { conn.Close(websocket.StatusNormalClosure, "") }) + return conn, ctx +} + +// roundTrip writes each frame and reads the echo back, so the test only +// proceeds once the proxy has relayed in both directions. +func roundTrip(t *testing.T, conn *websocket.Conn, ctx context.Context, frames ...string) []string { + t.Helper() + echoes := make([]string, 0, len(frames)) + for i, frame := range frames { + if err := conn.Write(ctx, websocket.MessageText, []byte(frame)); err != nil { + t.Fatalf("write %d: %v", i, err) + } + _, echo, err := conn.Read(ctx) + if err != nil { + t.Fatalf("read %d: %v", i, err) + } + echoes = append(echoes, string(echo)) + } + return echoes +} + +func commandEvents(evs []events.Event) []events.Event { + out := make([]events.Event, 0, len(evs)) + for _, ev := range evs { + if ev.Type == "cdp_command" { + out = append(out, ev) + } + } + return out +} + +// waitForDisconnect blocks until the proxy has published cdp_disconnect, which +// happens after the observer has drained. Anything the upstream direction +// wrongly produced has been recorded by then. +func waitForDisconnect(t *testing.T, rp *recordingPublisher) events.Event { + t.Helper() + var found events.Event + if !waitForCondition(10*time.Second, func() bool { + for _, ev := range rp.snapshot() { + if ev.Type == "cdp_disconnect" { + found = ev + return true + } + } + return false + }) { + t.Fatal("proxy never published cdp_disconnect") + } + return found +} + +func TestProxyEmitsOneEventPerClientControlCommand(t *testing.T) { + rp := &recordingPublisher{} + conn, ctx := echoProxy(t, rp.publish, controlOn) + + roundTrip(t, conn, ctx, + `{"id":1,"method":"Runtime.callFunctionOn","params":{"functionDeclaration":"() => 1"}}`, + `{"id":2,"method":"Input.dispatchMouseEvent","params":{"type":"mouseMoved","x":9,"y":9}}`, + `{"id":3,"method":"Input.dispatchMouseEvent","params":{"type":"mousePressed","x":10,"y":20,"button":"left"}}`, + `{"id":4,"method":"Input.dispatchMouseEvent","params":{"type":"mouseReleased","x":10,"y":20,"button":"left"}}`, + ) + _ = conn.Close(websocket.StatusNormalClosure, "bye") + + disconnect := waitForDisconnect(t, rp) + commands := commandEvents(rp.snapshot()) + if len(commands) != 3 { + t.Fatalf("cdp_command count = %d, want 3 (the move and both click phases; nothing for Runtime.callFunctionOn or the echoes)", len(commands)) + } + + var data map[string]any + if err := json.Unmarshal(disconnect.Data, &data); err != nil { + t.Fatalf("unmarshal disconnect: %v", err) + } + if data["telemetry_dropped"] != 0.0 { + t.Fatalf("telemetry_dropped = %v, want 0", data["telemetry_dropped"]) + } + // Optional in the schema for compatibility, but this image always sets it, + // so a reader can tell "nothing lost" from "not reported". + if _, ok := data["telemetry_dropped"]; !ok { + t.Fatal("cdp_disconnect omitted telemetry_dropped") + } +} + +func TestProxyEmitsNothingWhenControlIsDisabled(t *testing.T) { + rp := &recordingPublisher{} + conn, ctx := echoProxy(t, rp.publish, func() bool { return false }) + + roundTrip(t, conn, ctx, + `{"id":1,"method":"Input.dispatchMouseEvent","params":{"type":"mousePressed","x":1,"y":2}}`, + `{"id":2,"method":"Page.navigate","params":{"url":"https://example.com/"}}`, + ) + _ = conn.Close(websocket.StatusNormalClosure, "bye") + + waitForDisconnect(t, rp) + if got := len(commandEvents(rp.snapshot())); got != 0 { + t.Fatalf("cdp_command count = %d with control disabled, want 0", got) + } +} + +// The failure that motivated moving classification off the pump: a publisher +// that never returns used to stall the message transform, and with it the +// browser. +// +// Only cdp_command misbehaves here. cdp_connect and cdp_disconnect are +// published once per connection from the request goroutine, which chi's +// Recoverer covers and which forwards nothing; the pump is the path under +// test. +func TestBlockedPublisherDoesNotStallForwarding(t *testing.T) { + release := make(chan struct{}) + defer close(release) + blocking := func(ev events.Event) (events.Envelope, bool) { + if ev.Type == "cdp_command" { + <-release + } + return events.Envelope{Event: ev}, true + } + conn, ctx := echoProxy(t, blocking, controlOn) + + // Far more commands than the queue holds, so the publisher is wedged and + // the queue is full well before the last one. Forwarding must not notice. + frames := make([]string, 0, cdpObserverQueueDepth*2) + for i := range cap(frames) { + frames = append(frames, `{"id":`+strconv.Itoa(i)+`,"method":"Input.dispatchMouseEvent","params":{"type":"mousePressed","x":1,"y":2}}`) + } + echoes := roundTrip(t, conn, ctx, frames...) + for i, echo := range echoes { + if echo != frames[i] { + t.Fatalf("frame %d came back changed:\n sent %s\n got %s", i, frames[i], echo) + } + } +} + +// A panicking publisher used to unwind through the pump goroutine, which no +// Recoverer covers, and take the process down with it. Forwarding must survive +// it, in both bytes and order. +func TestPanickingPublisherDoesNotBreakForwarding(t *testing.T) { + panicking := func(ev events.Event) (events.Envelope, bool) { + if ev.Type == "cdp_command" { + panic("publisher exploded") + } + return events.Envelope{Event: ev}, true + } + conn, ctx := echoProxy(t, panicking, controlOn) + + frames := []string{ + `{"id":1,"method":"Input.dispatchMouseEvent","params":{"type":"mousePressed","x":1,"y":2}}`, + `{"id":2,"method":"Page.navigate","params":{"url":"https://example.com/"}}`, + `{"id":3,"method":"Input.insertText","params":{"text":"still forwarding"}}`, + } + echoes := roundTrip(t, conn, ctx, frames...) + for i, echo := range echoes { + if echo != frames[i] { + t.Fatalf("frame %d came back changed:\n sent %s\n got %s", i, frames[i], echo) + } + } +} + +// Telemetry looks at frames; it must not change them. Whatever the client +// sends — malformed JSON, binary, invalid UTF-8, a large paste — the browser +// gets the same bytes in the same order. +func TestForwardingPreservesBytesAndOrderForAwkwardTraffic(t *testing.T) { + rp := &recordingPublisher{} + conn, ctx := echoProxy(t, rp.publish, controlOn) + + big := `{"id":9,"method":"Input.insertText","params":{"text":"` + + strings.Repeat("x", 256<<10) + `"}}` + frames := []string{ + `{"id":1,"method":"Input.dispatchMouseEvent","params":`, + `{"id":2,"method":"Input.insertText","params":{"text":"\ud800"}}`, + `{"id":3,"method":"Input.dispatchMouseEvent","params":{"type":"mousePressed","x":1,"y":2},"method":"Page.close"}`, + `{"id":4,"method":"Input.dispatchMouseEvent","params":{"type":"mousePressed","x":1,"y":2}}`, + big, + `{"id":5,"method":"Page.reload"}`, + } + echoes := roundTrip(t, conn, ctx, frames...) + for i, echo := range echoes { + if echo != frames[i] { + t.Fatalf("frame %d came back changed (len sent %d, len got %d)", i, len(frames[i]), len(echo)) + } + } + + _ = conn.Close(websocket.StatusNormalClosure, "bye") + disconnect := waitForDisconnect(t, rp) + + // Awkward traffic is classified or discarded, never counted as loss. + var data map[string]any + if err := json.Unmarshal(disconnect.Data, &data); err != nil { + t.Fatalf("unmarshal disconnect: %v", err) + } + if data["telemetry_dropped"] != 0.0 { + t.Fatalf("telemetry_dropped = %v, want 0", data["telemetry_dropped"]) + } +} + +// Binary frames are not CDP commands, so they are relayed and ignored. +func TestBinaryFramesAreForwardedAndNotClassified(t *testing.T) { + rp := &recordingPublisher{} + conn, ctx := echoProxy(t, rp.publish, controlOn) + + payload := []byte{0x00, 0xff, 0xfe, 0x7b, 0x22} + if err := conn.Write(ctx, websocket.MessageBinary, payload); err != nil { + t.Fatalf("write binary: %v", err) + } + mt, echo, err := conn.Read(ctx) + if err != nil { + t.Fatalf("read binary: %v", err) + } + if mt != websocket.MessageBinary || string(echo) != string(payload) { + t.Fatalf("binary frame came back as %v %q", mt, echo) + } + + _ = conn.Close(websocket.StatusNormalClosure, "bye") + waitForDisconnect(t, rp) + if got := len(commandEvents(rp.snapshot())); got != 0 { + t.Fatalf("cdp_command count = %d for binary traffic, want 0", got) + } +} + +// telemetry_dropped was added to cdp_disconnect after the event type shipped, +// so it stays optional: a payload from an image that predates it must still +// decode, and must be distinguishable from one reporting zero. +func TestDisconnectPayloadFromAnOlderImageStillDecodes(t *testing.T) { + old := `{"duration_ms":12.5,"message_count":3,"reason":"client_close"}` + var data oapi.BrowserCdpDisconnectEventData + if err := json.Unmarshal([]byte(old), &data); err != nil { + t.Fatalf("payload without telemetry_dropped failed to decode: %v", err) + } + if data.TelemetryDropped != nil { + t.Fatalf("telemetry_dropped = %v, want absent", *data.TelemetryDropped) + } + if data.MessageCount != 3 || data.Reason != oapi.ClientClose { + t.Fatalf("decoded the rest wrong: %+v", data) + } +} diff --git a/server/lib/devtoolsproxy/proxy.go b/server/lib/devtoolsproxy/proxy.go index df8b47eb..5521d81b 100644 --- a/server/lib/devtoolsproxy/proxy.go +++ b/server/lib/devtoolsproxy/proxy.go @@ -309,8 +309,10 @@ type EventPublisher func(ev events.Event) (events.Envelope, bool) // proxies them to the current upstream websocket URL. It expects only websocket requests. // If logCDPMessages is true, all CDP messages will be logged with their direction. // publish is invoked on accept (cdp_connect) and on teardown (cdp_disconnect); pass -// nil to disable emission. -func WebSocketProxyHandler(mgr *UpstreamManager, logger *slog.Logger, logCDPMessages bool, ctrl scaletozero.Controller, publish EventPublisher, reg *wsdrain.Registry) http.Handler { +// nil to disable emission. controlEnabled gates cdp_command classification and is +// checked once per forwarded client frame; pass nil to disable it. excludedMethods +// names the control methods configured out of the stream; nil reports them all. +func WebSocketProxyHandler(mgr *UpstreamManager, logger *slog.Logger, logCDPMessages bool, ctrl scaletozero.Controller, publish EventPublisher, controlEnabled ControlEnabledFunc, excludedMethods ExcludedMethodsFunc, reg *wsdrain.Registry) http.Handler { return http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) { // Counts every relayed message so cdp_disconnect can report message_count. var msgCount atomic.Int64 @@ -364,11 +366,11 @@ func WebSocketProxyHandler(mgr *UpstreamManager, logger *slog.Logger, logCDPMess switch { case errors.Is(err, context.Canceled), errors.Is(err, context.DeadlineExceeded), errors.Is(r.Context().Err(), context.Canceled), errors.Is(r.Context().Err(), context.DeadlineExceeded): clientConn.Close(websocket.StatusGoingAway, "request cancelled") - publishCdpDisconnect(publish, oapi.ContextCancelled, connectedAt, time.Now(), msgCount.Load()) + publishCdpDisconnect(publish, oapi.ContextCancelled, connectedAt, time.Now(), msgCount.Load(), 0) default: logger.Error("failed to connect to upstream", slog.String("err", err.Error())) clientConn.Close(websocket.StatusInternalError, "upstream unavailable") - publishCdpDisconnect(publish, oapi.UpstreamError, connectedAt, time.Now(), msgCount.Load()) + publishCdpDisconnect(publish, oapi.UpstreamError, connectedAt, time.Now(), msgCount.Load(), 0) } return } @@ -378,6 +380,20 @@ func WebSocketProxyHandler(mgr *UpstreamManager, logger *slog.Logger, logCDPMess pumpCtx, pumpCancel := context.WithCancel(r.Context()) + // Classification of client commands runs behind the pump, not inside it: + // a frame is observed only once Chromium has accepted it. + observer := newCdpObserver(pumpCtx, publish, controlEnabled, excludedMethods, logger) + var observe wsproxy.Observer + if observer != nil { + observe = func(direction string, mt websocket.MessageType, msg []byte, ts int64) { + // Client-to-upstream only: commands are what the caller drives the + // browser with, and upstream frames are events and command results. + if direction == "->" && mt == websocket.MessageText { + observer.Observe(msg, ts) + } + } + } + // Force clients off a stale upstream as soon as UpstreamManager // publishes a different DevTools URL. Closing upstreamConn (rather // than cancelling pumpCtx) makes the pump exit PumpExitUpstream so @@ -416,21 +432,35 @@ func WebSocketProxyHandler(mgr *UpstreamManager, logger *slog.Logger, logCDPMess pumpCancel() upstreamConn.Close(websocket.StatusNormalClosure, "") clientConn.Close(websocket.StatusNormalClosure, "") - reason := resolveDisconnectReason(cause, r.Context(), mgr, upstreamURL, restartConfirmWait, logger) - publishCdpDisconnect(publish, reason, connectedAt, disconnectedAt, msgCount.Load()) + reason := resolveDisconnectReason(cause, r.Context(), mgr, upstreamURL, getRestartConfirmWait(), logger) + // Let the worker finish the queue before the disconnect, so the + // client's last commands land ahead of it and telemetry_dropped + // is final. + observer.WaitDrained(cdpObserverDrainWait) + publishCdpDisconnect(publish, reason, connectedAt, disconnectedAt, msgCount.Load(), observer.Dropped()) }) } - wsproxy.Pump(pumpCtx, clientConn, upstreamConn, cleanup, logger, transform) + wsproxy.Pump(pumpCtx, clientConn, upstreamConn, cleanup, logger, transform, observe) }) } // restartConfirmWait is how long cleanup waits for a new upstream URL after // the upstream side of the pump dies before classifying the disconnect as // upstream_error vs upstream_changed. Sized for Chromium's typical cold -// restart (~5-8s on Unikraft Cloud) with headroom. var (not const) so tests -// can temporarily shrink it. -var restartConfirmWait = 10 * time.Second +// restart (~5-8s on Unikraft Cloud) with headroom. Atomic rather than a plain +// var because tests shrink it while other handlers are still reading it. +var restartConfirmWait atomic.Int64 + +func init() { setRestartConfirmWait(10 * time.Second) } + +func getRestartConfirmWait() time.Duration { + return time.Duration(restartConfirmWait.Load()) +} + +func setRestartConfirmWait(d time.Duration) { + restartConfirmWait.Store(int64(d)) +} // resolveDisconnectReason picks the cdp_disconnect reason from which side // caused the pump to exit. On upstream cause it polls mgr.Current() for up @@ -480,14 +510,19 @@ func publishCdpConnect(publish EventPublisher) { }) } -func publishCdpDisconnect(publish EventPublisher, reason oapi.BrowserCdpDisconnectEventDataReason, connectedAt, disconnectedAt time.Time, msgCount int64) { +func publishCdpDisconnect(publish EventPublisher, reason oapi.BrowserCdpDisconnectEventDataReason, connectedAt, disconnectedAt time.Time, msgCount, telemetryDropped int64) { if publish == nil { return } + // Optional in the schema so an event from an image that predates the field + // still validates, but always set here: absent means "not reported", which + // is not the same as zero. + dropped := int(telemetryDropped) data, _ := json.Marshal(oapi.BrowserCdpDisconnectEventData{ - DurationMs: float32(disconnectedAt.Sub(connectedAt).Microseconds()) / 1000.0, - MessageCount: int(msgCount), - Reason: reason, + DurationMs: float32(disconnectedAt.Sub(connectedAt).Microseconds()) / 1000.0, + MessageCount: int(msgCount), + TelemetryDropped: &dropped, + Reason: reason, }) publish(events.Event{ Ts: disconnectedAt.UnixMicro(), diff --git a/server/lib/devtoolsproxy/proxy_test.go b/server/lib/devtoolsproxy/proxy_test.go index 5956a555..eb2ee285 100644 --- a/server/lib/devtoolsproxy/proxy_test.go +++ b/server/lib/devtoolsproxy/proxy_test.go @@ -133,7 +133,7 @@ func TestWebSocketProxyHandler_ProxiesEcho(t *testing.T) { // seed current upstream to echo server including path/query (bypass tailing) mgr.setCurrent((&url.URL{Scheme: u.Scheme, Host: u.Host, Path: u.Path, RawQuery: u.RawQuery}).String()) - proxy := WebSocketProxyHandler(mgr, logger, false, scaletozero.NewNoopController(), nil, nil) + proxy := WebSocketProxyHandler(mgr, logger, false, scaletozero.NewNoopController(), nil, nil, nil, nil) proxySrv := httptest.NewServer(proxy) defer proxySrv.Close() @@ -191,7 +191,7 @@ func TestWebSocketProxyHandler_RegistryClosesClientWithGoingAway(t *testing.T) { mgr.setCurrent((&url.URL{Scheme: "ws", Host: u.Host, Path: "/echo"}).String()) reg := wsdrain.New() - proxySrv := httptest.NewServer(WebSocketProxyHandler(mgr, logger, false, scaletozero.NewNoopController(), nil, reg)) + proxySrv := httptest.NewServer(WebSocketProxyHandler(mgr, logger, false, scaletozero.NewNoopController(), nil, nil, nil, reg)) defer proxySrv.Close() pu, _ := url.Parse(proxySrv.URL) @@ -520,7 +520,7 @@ func TestWebSocketProxyHandler_EmitsConnectAndDisconnect(t *testing.T) { mgr.setCurrent(u.String()) rp := &recordingPublisher{} - proxySrv := httptest.NewServer(WebSocketProxyHandler(mgr, logger, false, scaletozero.NewNoopController(), rp.publish, nil)) + proxySrv := httptest.NewServer(WebSocketProxyHandler(mgr, logger, false, scaletozero.NewNoopController(), rp.publish, controlOn, nil, nil)) defer proxySrv.Close() pu, _ := url.Parse(proxySrv.URL) @@ -664,9 +664,9 @@ func TestResolveDisconnectReason(t *testing.T) { func TestWebSocketProxyHandler_EmitsUpstreamChangedOnMidStreamRestart(t *testing.T) { // Shorten the resolve wait so the test doesn't pay the production 10s. - prev := restartConfirmWait - restartConfirmWait = 1 * time.Second - defer func() { restartConfirmWait = prev }() + prev := getRestartConfirmWait() + setRestartConfirmWait(1 * time.Second) + defer setRestartConfirmWait(prev) // Upstream A: echoes once, then closes (simulates Chromium dying mid-session). upstreamA := httptest.NewServer(http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) { @@ -695,7 +695,7 @@ func TestWebSocketProxyHandler_EmitsUpstreamChangedOnMidStreamRestart(t *testing mgr.setCurrent(urlA.String()) rp := &recordingPublisher{} - proxySrv := httptest.NewServer(WebSocketProxyHandler(mgr, logger, false, scaletozero.NewNoopController(), rp.publish, nil)) + proxySrv := httptest.NewServer(WebSocketProxyHandler(mgr, logger, false, scaletozero.NewNoopController(), rp.publish, controlOn, nil, nil)) defer proxySrv.Close() pu, _ := url.Parse(proxySrv.URL) @@ -749,9 +749,9 @@ func TestWebSocketProxyHandler_EmitsUpstreamChangedOnMidStreamRestart(t *testing } func TestWebSocketProxyHandler_KicksClientOffStaleUpstreamOnURLChange(t *testing.T) { - prev := restartConfirmWait - restartConfirmWait = 500 * time.Millisecond - defer func() { restartConfirmWait = prev }() + prev := getRestartConfirmWait() + setRestartConfirmWait(500 * time.Millisecond) + defer setRestartConfirmWait(prev) // Upstream stays alive until the proxy closes it from the watcher path. upstreamSrv := httptest.NewServer(http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) { @@ -779,7 +779,7 @@ func TestWebSocketProxyHandler_KicksClientOffStaleUpstreamOnURLChange(t *testing mgr.setCurrent(urlA.String()) rp := &recordingPublisher{} - proxySrv := httptest.NewServer(WebSocketProxyHandler(mgr, logger, false, scaletozero.NewNoopController(), rp.publish, nil)) + proxySrv := httptest.NewServer(WebSocketProxyHandler(mgr, logger, false, scaletozero.NewNoopController(), rp.publish, controlOn, nil, nil)) defer proxySrv.Close() pu, _ := url.Parse(proxySrv.URL) @@ -831,7 +831,7 @@ func TestWebSocketProxyHandler_EmitsUpstreamErrorOnDialFailure(t *testing.T) { mgr.setCurrent(deadURL) rp := &recordingPublisher{} - proxySrv := httptest.NewServer(WebSocketProxyHandler(mgr, logger, false, scaletozero.NewNoopController(), rp.publish, nil)) + proxySrv := httptest.NewServer(WebSocketProxyHandler(mgr, logger, false, scaletozero.NewNoopController(), rp.publish, controlOn, nil, nil)) defer proxySrv.Close() pu, _ := url.Parse(proxySrv.URL) @@ -863,3 +863,6 @@ func TestWebSocketProxyHandler_EmitsUpstreamErrorOnDialFailure(t *testing.T) { t.Fatalf("disconnect reason = %q, want %q", disconnect.Reason, oapi.UpstreamError) } } + +// controlOn is the gate a proxy test needs to see cdp_command events at all. +func controlOn() bool { return true } diff --git a/server/lib/events/category_gen.go b/server/lib/events/category_gen.go index e7fa54b5..47df9d79 100644 --- a/server/lib/events/category_gen.go +++ b/server/lib/events/category_gen.go @@ -7,6 +7,7 @@ import oapi "github.com/kernel/kernel-images/server/lib/oapi" var categoryByType = map[string]oapi.TelemetryEventCategory{ "api_call": oapi.TelemetryEventCategory("control"), "captcha_solve_result": oapi.TelemetryEventCategory("captcha"), + "cdp_command": oapi.TelemetryEventCategory("control"), "cdp_connect": oapi.TelemetryEventCategory("connection"), "cdp_disconnect": oapi.TelemetryEventCategory("connection"), "console_error": oapi.TelemetryEventCategory("console"), diff --git a/server/lib/events/eventsstorage.go b/server/lib/events/eventsstorage.go index c14cf063..93ee3ddb 100644 --- a/server/lib/events/eventsstorage.go +++ b/server/lib/events/eventsstorage.go @@ -19,6 +19,7 @@ type Storage interface { // available event in the ring, not the current tail. Delivery is // at-least-once; consumers should dedupe by env.Seq. type StorageWriter struct { + es *EventStream reader *Reader storage Storage log *slog.Logger @@ -38,6 +39,7 @@ func NewStorageWriter(es *EventStream, storage Storage, log *slog.Logger) *Stora // rebuilt on demand does not replay the ring. func NewStorageWriterAfter(es *EventStream, storage Storage, log *slog.Logger, afterSeq uint64) *StorageWriter { return &StorageWriter{ + es: es, reader: es.NewReader(afterSeq), storage: storage, log: log, @@ -89,6 +91,7 @@ func (w *StorageWriter) Drain(ctx context.Context) error { func (w *StorageWriter) processResult(ctx context.Context, res ReadResult) error { if res.Dropped > 0 { + w.es.RecordDropped(res.Dropped) w.log.Warn("storage writer: dropped events", "count", res.Dropped) return nil } diff --git a/server/lib/events/eventstream.go b/server/lib/events/eventstream.go index 371061d4..73214b70 100644 --- a/server/lib/events/eventstream.go +++ b/server/lib/events/eventstream.go @@ -3,6 +3,7 @@ package events import ( "fmt" "sync" + "sync/atomic" ) // EventStream is the process-lifetime event bus. It owns the ring buffer and @@ -11,6 +12,10 @@ type EventStream struct { mu sync.Mutex seq uint64 ring *ringBuffer + // dropped counts envelopes a consumer missed because it fell behind the + // ring, summed across consumers and sessions. Loss is per-consumer, so this + // is a pressure signal rather than a count of distinct lost events. + dropped atomic.Uint64 } type EventStreamConfig struct { @@ -39,6 +44,19 @@ func (es *EventStream) Publish(env Envelope) Envelope { return env } +// RecordDropped notes that a consumer found a gap of n envelopes. Consumers +// report it rather than the ring detecting it, because only a consumer knows +// what it had already read. +func (es *EventStream) RecordDropped(n uint64) { + es.dropped.Add(n) +} + +// DroppedEvents returns the cumulative gap count across consumers, so a reader +// can tell a quiet stream from one it is falling behind. +func (es *EventStream) DroppedEvents() uint64 { + return es.dropped.Load() +} + // NewReader returns a Reader positioned after afterSeq. Pass 0 to start from // the oldest buffered event. func (es *EventStream) NewReader(afterSeq uint64) *Reader { diff --git a/server/lib/oapi/oapi.go b/server/lib/oapi/oapi.go index 2104712e..53344e1b 100644 --- a/server/lib/oapi/oapi.go +++ b/server/lib/oapi/oapi.go @@ -140,6 +140,237 @@ func (e BrowserCaptchaSolveResultEventDataStatus) Valid() bool { } } +// Defines values for BrowserCdpAutofillTriggerCommandDataMethod. +const ( + BrowserCdpAutofillTriggerCommandDataMethodAutofillTrigger BrowserCdpAutofillTriggerCommandDataMethod = "Autofill.trigger" +) + +// Valid indicates whether the value is a known member of the BrowserCdpAutofillTriggerCommandDataMethod enum. +func (e BrowserCdpAutofillTriggerCommandDataMethod) Valid() bool { + switch e { + case BrowserCdpAutofillTriggerCommandDataMethodAutofillTrigger: + return true + default: + return false + } +} + +// Defines values for BrowserCdpBrowserCancelDownloadCommandDataMethod. +const ( + BrowserCancelDownload BrowserCdpBrowserCancelDownloadCommandDataMethod = "Browser.cancelDownload" +) + +// Valid indicates whether the value is a known member of the BrowserCdpBrowserCancelDownloadCommandDataMethod enum. +func (e BrowserCdpBrowserCancelDownloadCommandDataMethod) Valid() bool { + switch e { + case BrowserCancelDownload: + return true + default: + return false + } +} + +// Defines values for BrowserCdpBrowserCloseCommandDataMethod. +const ( + BrowserClose BrowserCdpBrowserCloseCommandDataMethod = "Browser.close" +) + +// Valid indicates whether the value is a known member of the BrowserCdpBrowserCloseCommandDataMethod enum. +func (e BrowserCdpBrowserCloseCommandDataMethod) Valid() bool { + switch e { + case BrowserClose: + return true + default: + return false + } +} + +// Defines values for BrowserCdpBrowserSetContentsSizeCommandDataMethod. +const ( + BrowserSetContentsSize BrowserCdpBrowserSetContentsSizeCommandDataMethod = "Browser.setContentsSize" +) + +// Valid indicates whether the value is a known member of the BrowserCdpBrowserSetContentsSizeCommandDataMethod enum. +func (e BrowserCdpBrowserSetContentsSizeCommandDataMethod) Valid() bool { + switch e { + case BrowserSetContentsSize: + return true + default: + return false + } +} + +// Defines values for BrowserCdpBrowserSetWindowBoundsCommandDataMethod. +const ( + BrowserSetWindowBounds BrowserCdpBrowserSetWindowBoundsCommandDataMethod = "Browser.setWindowBounds" +) + +// Valid indicates whether the value is a known member of the BrowserCdpBrowserSetWindowBoundsCommandDataMethod enum. +func (e BrowserCdpBrowserSetWindowBoundsCommandDataMethod) Valid() bool { + switch e { + case BrowserSetWindowBounds: + return true + default: + return false + } +} + +// Defines values for BrowserCdpCommandEventCategory. +const ( + BrowserCdpCommandEventCategoryControl BrowserCdpCommandEventCategory = "control" +) + +// Valid indicates whether the value is a known member of the BrowserCdpCommandEventCategory enum. +func (e BrowserCdpCommandEventCategory) Valid() bool { + switch e { + case BrowserCdpCommandEventCategoryControl: + return true + default: + return false + } +} + +// Defines values for BrowserCdpCommandEventType. +const ( + CdpCommand BrowserCdpCommandEventType = "cdp_command" +) + +// Valid indicates whether the value is a known member of the BrowserCdpCommandEventType enum. +func (e BrowserCdpCommandEventType) Valid() bool { + switch e { + case CdpCommand: + return true + default: + return false + } +} + +// Defines values for BrowserCdpCommandMethod. +const ( + BrowserCdpCommandMethodAutofillTrigger BrowserCdpCommandMethod = "Autofill.trigger" + BrowserCdpCommandMethodBrowserCancelDownload BrowserCdpCommandMethod = "Browser.cancelDownload" + BrowserCdpCommandMethodBrowserClose BrowserCdpCommandMethod = "Browser.close" + BrowserCdpCommandMethodBrowserSetContentsSize BrowserCdpCommandMethod = "Browser.setContentsSize" + BrowserCdpCommandMethodBrowserSetWindowBounds BrowserCdpCommandMethod = "Browser.setWindowBounds" + BrowserCdpCommandMethodDOMFocus BrowserCdpCommandMethod = "DOM.focus" + BrowserCdpCommandMethodDOMScrollIntoViewIfNeeded BrowserCdpCommandMethod = "DOM.scrollIntoViewIfNeeded" + BrowserCdpCommandMethodDOMSetFileInputFiles BrowserCdpCommandMethod = "DOM.setFileInputFiles" + BrowserCdpCommandMethodInputCancelDragging BrowserCdpCommandMethod = "Input.cancelDragging" + BrowserCdpCommandMethodInputDispatchDragEvent BrowserCdpCommandMethod = "Input.dispatchDragEvent" + BrowserCdpCommandMethodInputDispatchKeyEvent BrowserCdpCommandMethod = "Input.dispatchKeyEvent" + BrowserCdpCommandMethodInputDispatchMouseEvent BrowserCdpCommandMethod = "Input.dispatchMouseEvent" + BrowserCdpCommandMethodInputDispatchTouchEvent BrowserCdpCommandMethod = "Input.dispatchTouchEvent" + BrowserCdpCommandMethodInputEmulateTouchFromMouseEvent BrowserCdpCommandMethod = "Input.emulateTouchFromMouseEvent" + BrowserCdpCommandMethodInputImeSetComposition BrowserCdpCommandMethod = "Input.imeSetComposition" + BrowserCdpCommandMethodInputInsertText BrowserCdpCommandMethod = "Input.insertText" + BrowserCdpCommandMethodInputSynthesizePinchGesture BrowserCdpCommandMethod = "Input.synthesizePinchGesture" + BrowserCdpCommandMethodInputSynthesizeScrollGesture BrowserCdpCommandMethod = "Input.synthesizeScrollGesture" + BrowserCdpCommandMethodInputSynthesizeTapGesture BrowserCdpCommandMethod = "Input.synthesizeTapGesture" + BrowserCdpCommandMethodPageBringToFront BrowserCdpCommandMethod = "Page.bringToFront" + BrowserCdpCommandMethodPageCaptureScreenshot BrowserCdpCommandMethod = "Page.captureScreenshot" + BrowserCdpCommandMethodPageCaptureSnapshot BrowserCdpCommandMethod = "Page.captureSnapshot" + BrowserCdpCommandMethodPageClose BrowserCdpCommandMethod = "Page.close" + BrowserCdpCommandMethodPageHandleJavaScriptDialog BrowserCdpCommandMethod = "Page.handleJavaScriptDialog" + BrowserCdpCommandMethodPageNavigate BrowserCdpCommandMethod = "Page.navigate" + BrowserCdpCommandMethodPageNavigateToHistoryEntry BrowserCdpCommandMethod = "Page.navigateToHistoryEntry" + BrowserCdpCommandMethodPagePrintToPDF BrowserCdpCommandMethod = "Page.printToPDF" + BrowserCdpCommandMethodPageReload BrowserCdpCommandMethod = "Page.reload" + BrowserCdpCommandMethodPageSetWebLifecycleState BrowserCdpCommandMethod = "Page.setWebLifecycleState" + BrowserCdpCommandMethodPageStartScreencast BrowserCdpCommandMethod = "Page.startScreencast" + BrowserCdpCommandMethodPageStopLoading BrowserCdpCommandMethod = "Page.stopLoading" + BrowserCdpCommandMethodPageStopScreencast BrowserCdpCommandMethod = "Page.stopScreencast" + BrowserCdpCommandMethodTargetActivateTarget BrowserCdpCommandMethod = "Target.activateTarget" + BrowserCdpCommandMethodTargetCloseTarget BrowserCdpCommandMethod = "Target.closeTarget" + BrowserCdpCommandMethodTargetCreateBrowserContext BrowserCdpCommandMethod = "Target.createBrowserContext" + BrowserCdpCommandMethodTargetCreateTarget BrowserCdpCommandMethod = "Target.createTarget" + BrowserCdpCommandMethodTargetDisposeBrowserContext BrowserCdpCommandMethod = "Target.disposeBrowserContext" + BrowserCdpCommandMethodTargetOpenDevTools BrowserCdpCommandMethod = "Target.openDevTools" +) + +// Valid indicates whether the value is a known member of the BrowserCdpCommandMethod enum. +func (e BrowserCdpCommandMethod) Valid() bool { + switch e { + case BrowserCdpCommandMethodAutofillTrigger: + return true + case BrowserCdpCommandMethodBrowserCancelDownload: + return true + case BrowserCdpCommandMethodBrowserClose: + return true + case BrowserCdpCommandMethodBrowserSetContentsSize: + return true + case BrowserCdpCommandMethodBrowserSetWindowBounds: + return true + case BrowserCdpCommandMethodDOMFocus: + return true + case BrowserCdpCommandMethodDOMScrollIntoViewIfNeeded: + return true + case BrowserCdpCommandMethodDOMSetFileInputFiles: + return true + case BrowserCdpCommandMethodInputCancelDragging: + return true + case BrowserCdpCommandMethodInputDispatchDragEvent: + return true + case BrowserCdpCommandMethodInputDispatchKeyEvent: + return true + case BrowserCdpCommandMethodInputDispatchMouseEvent: + return true + case BrowserCdpCommandMethodInputDispatchTouchEvent: + return true + case BrowserCdpCommandMethodInputEmulateTouchFromMouseEvent: + return true + case BrowserCdpCommandMethodInputImeSetComposition: + return true + case BrowserCdpCommandMethodInputInsertText: + return true + case BrowserCdpCommandMethodInputSynthesizePinchGesture: + return true + case BrowserCdpCommandMethodInputSynthesizeScrollGesture: + return true + case BrowserCdpCommandMethodInputSynthesizeTapGesture: + return true + case BrowserCdpCommandMethodPageBringToFront: + return true + case BrowserCdpCommandMethodPageCaptureScreenshot: + return true + case BrowserCdpCommandMethodPageCaptureSnapshot: + return true + case BrowserCdpCommandMethodPageClose: + return true + case BrowserCdpCommandMethodPageHandleJavaScriptDialog: + return true + case BrowserCdpCommandMethodPageNavigate: + return true + case BrowserCdpCommandMethodPageNavigateToHistoryEntry: + return true + case BrowserCdpCommandMethodPagePrintToPDF: + return true + case BrowserCdpCommandMethodPageReload: + return true + case BrowserCdpCommandMethodPageSetWebLifecycleState: + return true + case BrowserCdpCommandMethodPageStartScreencast: + return true + case BrowserCdpCommandMethodPageStopLoading: + return true + case BrowserCdpCommandMethodPageStopScreencast: + return true + case BrowserCdpCommandMethodTargetActivateTarget: + return true + case BrowserCdpCommandMethodTargetCloseTarget: + return true + case BrowserCdpCommandMethodTargetCreateBrowserContext: + return true + case BrowserCdpCommandMethodTargetCreateTarget: + return true + case BrowserCdpCommandMethodTargetDisposeBrowserContext: + return true + case BrowserCdpCommandMethodTargetOpenDevTools: + return true + default: + return false + } +} + // Defines values for BrowserCdpConnectEventCategory. const ( BrowserCdpConnectEventCategoryConnection BrowserCdpConnectEventCategory = "connection" @@ -224,1479 +455,3268 @@ func (e BrowserCdpDisconnectEventDataReason) Valid() bool { } } -// Defines values for BrowserConsoleErrorEventCategory. +// Defines values for BrowserCdpDomFocusCommandDataMethod. const ( - BrowserConsoleErrorEventCategoryConsole BrowserConsoleErrorEventCategory = "console" + DOMFocus BrowserCdpDomFocusCommandDataMethod = "DOM.focus" ) -// Valid indicates whether the value is a known member of the BrowserConsoleErrorEventCategory enum. -func (e BrowserConsoleErrorEventCategory) Valid() bool { +// Valid indicates whether the value is a known member of the BrowserCdpDomFocusCommandDataMethod enum. +func (e BrowserCdpDomFocusCommandDataMethod) Valid() bool { switch e { - case BrowserConsoleErrorEventCategoryConsole: + case DOMFocus: return true default: return false } } -// Defines values for BrowserConsoleErrorEventType. +// Defines values for BrowserCdpDomScrollIntoViewIfNeededCommandDataMethod. const ( - ConsoleError BrowserConsoleErrorEventType = "console_error" + DOMScrollIntoViewIfNeeded BrowserCdpDomScrollIntoViewIfNeededCommandDataMethod = "DOM.scrollIntoViewIfNeeded" ) -// Valid indicates whether the value is a known member of the BrowserConsoleErrorEventType enum. -func (e BrowserConsoleErrorEventType) Valid() bool { +// Valid indicates whether the value is a known member of the BrowserCdpDomScrollIntoViewIfNeededCommandDataMethod enum. +func (e BrowserCdpDomScrollIntoViewIfNeededCommandDataMethod) Valid() bool { switch e { - case ConsoleError: + case DOMScrollIntoViewIfNeeded: return true default: return false } } -// Defines values for BrowserConsoleLogEventCategory. +// Defines values for BrowserCdpDomSetFileInputFilesCommandDataMethod. const ( - BrowserConsoleLogEventCategoryConsole BrowserConsoleLogEventCategory = "console" + DOMSetFileInputFiles BrowserCdpDomSetFileInputFilesCommandDataMethod = "DOM.setFileInputFiles" ) -// Valid indicates whether the value is a known member of the BrowserConsoleLogEventCategory enum. -func (e BrowserConsoleLogEventCategory) Valid() bool { +// Valid indicates whether the value is a known member of the BrowserCdpDomSetFileInputFilesCommandDataMethod enum. +func (e BrowserCdpDomSetFileInputFilesCommandDataMethod) Valid() bool { switch e { - case BrowserConsoleLogEventCategoryConsole: + case DOMSetFileInputFiles: return true default: return false } } -// Defines values for BrowserConsoleLogEventType. +// Defines values for BrowserCdpInputCancelDraggingCommandDataMethod. const ( - ConsoleLog BrowserConsoleLogEventType = "console_log" + InputCancelDragging BrowserCdpInputCancelDraggingCommandDataMethod = "Input.cancelDragging" ) -// Valid indicates whether the value is a known member of the BrowserConsoleLogEventType enum. -func (e BrowserConsoleLogEventType) Valid() bool { +// Valid indicates whether the value is a known member of the BrowserCdpInputCancelDraggingCommandDataMethod enum. +func (e BrowserCdpInputCancelDraggingCommandDataMethod) Valid() bool { switch e { - case ConsoleLog: + case InputCancelDragging: return true default: return false } } -// Defines values for BrowserEventSourceKind. +// Defines values for BrowserCdpInputDispatchDragEventCommandDataMethod. const ( - Cdp BrowserEventSourceKind = "cdp" - Extension BrowserEventSourceKind = "extension" - KernelApi BrowserEventSourceKind = "kernel_api" - LocalProcess BrowserEventSourceKind = "local_process" + InputDispatchDragEvent BrowserCdpInputDispatchDragEventCommandDataMethod = "Input.dispatchDragEvent" ) -// Valid indicates whether the value is a known member of the BrowserEventSourceKind enum. -func (e BrowserEventSourceKind) Valid() bool { +// Valid indicates whether the value is a known member of the BrowserCdpInputDispatchDragEventCommandDataMethod enum. +func (e BrowserCdpInputDispatchDragEventCommandDataMethod) Valid() bool { switch e { - case Cdp: - return true - case Extension: - return true - case KernelApi: - return true - case LocalProcess: + case InputDispatchDragEvent: return true default: return false } } -// Defines values for BrowserInteractionClickEventCategory. +// Defines values for BrowserCdpInputDispatchKeyEventCommandDataMethod. const ( - BrowserInteractionClickEventCategoryInteraction BrowserInteractionClickEventCategory = "interaction" + InputDispatchKeyEvent BrowserCdpInputDispatchKeyEventCommandDataMethod = "Input.dispatchKeyEvent" ) -// Valid indicates whether the value is a known member of the BrowserInteractionClickEventCategory enum. -func (e BrowserInteractionClickEventCategory) Valid() bool { +// Valid indicates whether the value is a known member of the BrowserCdpInputDispatchKeyEventCommandDataMethod enum. +func (e BrowserCdpInputDispatchKeyEventCommandDataMethod) Valid() bool { switch e { - case BrowserInteractionClickEventCategoryInteraction: + case InputDispatchKeyEvent: return true default: return false } } -// Defines values for BrowserInteractionClickEventType. +// Defines values for BrowserCdpInputDispatchMouseEventCommandDataMethod. const ( - InteractionClick BrowserInteractionClickEventType = "interaction_click" + InputDispatchMouseEvent BrowserCdpInputDispatchMouseEventCommandDataMethod = "Input.dispatchMouseEvent" ) -// Valid indicates whether the value is a known member of the BrowserInteractionClickEventType enum. -func (e BrowserInteractionClickEventType) Valid() bool { +// Valid indicates whether the value is a known member of the BrowserCdpInputDispatchMouseEventCommandDataMethod enum. +func (e BrowserCdpInputDispatchMouseEventCommandDataMethod) Valid() bool { switch e { - case InteractionClick: + case InputDispatchMouseEvent: return true default: return false } } -// Defines values for BrowserInteractionKeyEventCategory. +// Defines values for BrowserCdpInputDispatchTouchEventCommandDataMethod. const ( - BrowserInteractionKeyEventCategoryInteraction BrowserInteractionKeyEventCategory = "interaction" + InputDispatchTouchEvent BrowserCdpInputDispatchTouchEventCommandDataMethod = "Input.dispatchTouchEvent" ) -// Valid indicates whether the value is a known member of the BrowserInteractionKeyEventCategory enum. -func (e BrowserInteractionKeyEventCategory) Valid() bool { +// Valid indicates whether the value is a known member of the BrowserCdpInputDispatchTouchEventCommandDataMethod enum. +func (e BrowserCdpInputDispatchTouchEventCommandDataMethod) Valid() bool { switch e { - case BrowserInteractionKeyEventCategoryInteraction: + case InputDispatchTouchEvent: return true default: return false } } -// Defines values for BrowserInteractionKeyEventType. +// Defines values for BrowserCdpInputEmulateTouchFromMouseEventCommandDataMethod. const ( - InteractionKey BrowserInteractionKeyEventType = "interaction_key" + InputEmulateTouchFromMouseEvent BrowserCdpInputEmulateTouchFromMouseEventCommandDataMethod = "Input.emulateTouchFromMouseEvent" ) -// Valid indicates whether the value is a known member of the BrowserInteractionKeyEventType enum. -func (e BrowserInteractionKeyEventType) Valid() bool { +// Valid indicates whether the value is a known member of the BrowserCdpInputEmulateTouchFromMouseEventCommandDataMethod enum. +func (e BrowserCdpInputEmulateTouchFromMouseEventCommandDataMethod) Valid() bool { switch e { - case InteractionKey: + case InputEmulateTouchFromMouseEvent: return true default: return false } } -// Defines values for BrowserInteractionScrollSettledEventCategory. +// Defines values for BrowserCdpInputImeSetCompositionCommandDataMethod. const ( - Interaction BrowserInteractionScrollSettledEventCategory = "interaction" + InputImeSetComposition BrowserCdpInputImeSetCompositionCommandDataMethod = "Input.imeSetComposition" ) -// Valid indicates whether the value is a known member of the BrowserInteractionScrollSettledEventCategory enum. -func (e BrowserInteractionScrollSettledEventCategory) Valid() bool { +// Valid indicates whether the value is a known member of the BrowserCdpInputImeSetCompositionCommandDataMethod enum. +func (e BrowserCdpInputImeSetCompositionCommandDataMethod) Valid() bool { switch e { - case Interaction: + case InputImeSetComposition: return true default: return false } } -// Defines values for BrowserInteractionScrollSettledEventType. +// Defines values for BrowserCdpInputInsertTextCommandDataMethod. const ( - InteractionScrollSettled BrowserInteractionScrollSettledEventType = "interaction_scroll_settled" + InputInsertText BrowserCdpInputInsertTextCommandDataMethod = "Input.insertText" ) -// Valid indicates whether the value is a known member of the BrowserInteractionScrollSettledEventType enum. -func (e BrowserInteractionScrollSettledEventType) Valid() bool { +// Valid indicates whether the value is a known member of the BrowserCdpInputInsertTextCommandDataMethod enum. +func (e BrowserCdpInputInsertTextCommandDataMethod) Valid() bool { switch e { - case InteractionScrollSettled: + case InputInsertText: return true default: return false } } -// Defines values for BrowserLiveViewConnectEventCategory. +// Defines values for BrowserCdpInputSynthesizePinchGestureCommandDataMethod. const ( - BrowserLiveViewConnectEventCategoryConnection BrowserLiveViewConnectEventCategory = "connection" + InputSynthesizePinchGesture BrowserCdpInputSynthesizePinchGestureCommandDataMethod = "Input.synthesizePinchGesture" ) -// Valid indicates whether the value is a known member of the BrowserLiveViewConnectEventCategory enum. -func (e BrowserLiveViewConnectEventCategory) Valid() bool { +// Valid indicates whether the value is a known member of the BrowserCdpInputSynthesizePinchGestureCommandDataMethod enum. +func (e BrowserCdpInputSynthesizePinchGestureCommandDataMethod) Valid() bool { switch e { - case BrowserLiveViewConnectEventCategoryConnection: + case InputSynthesizePinchGesture: return true default: return false } } -// Defines values for BrowserLiveViewConnectEventType. +// Defines values for BrowserCdpInputSynthesizeScrollGestureCommandDataMethod. const ( - LiveViewConnect BrowserLiveViewConnectEventType = "live_view_connect" + InputSynthesizeScrollGesture BrowserCdpInputSynthesizeScrollGestureCommandDataMethod = "Input.synthesizeScrollGesture" ) -// Valid indicates whether the value is a known member of the BrowserLiveViewConnectEventType enum. -func (e BrowserLiveViewConnectEventType) Valid() bool { +// Valid indicates whether the value is a known member of the BrowserCdpInputSynthesizeScrollGestureCommandDataMethod enum. +func (e BrowserCdpInputSynthesizeScrollGestureCommandDataMethod) Valid() bool { switch e { - case LiveViewConnect: + case InputSynthesizeScrollGesture: return true default: return false } } -// Defines values for BrowserLiveViewDisconnectEventCategory. +// Defines values for BrowserCdpInputSynthesizeTapGestureCommandDataMethod. const ( - BrowserLiveViewDisconnectEventCategoryConnection BrowserLiveViewDisconnectEventCategory = "connection" + InputSynthesizeTapGesture BrowserCdpInputSynthesizeTapGestureCommandDataMethod = "Input.synthesizeTapGesture" ) -// Valid indicates whether the value is a known member of the BrowserLiveViewDisconnectEventCategory enum. -func (e BrowserLiveViewDisconnectEventCategory) Valid() bool { +// Valid indicates whether the value is a known member of the BrowserCdpInputSynthesizeTapGestureCommandDataMethod enum. +func (e BrowserCdpInputSynthesizeTapGestureCommandDataMethod) Valid() bool { switch e { - case BrowserLiveViewDisconnectEventCategoryConnection: + case InputSynthesizeTapGesture: return true default: return false } } -// Defines values for BrowserLiveViewDisconnectEventType. +// Defines values for BrowserCdpPageBringToFrontCommandDataMethod. const ( - LiveViewDisconnect BrowserLiveViewDisconnectEventType = "live_view_disconnect" + PageBringToFront BrowserCdpPageBringToFrontCommandDataMethod = "Page.bringToFront" ) -// Valid indicates whether the value is a known member of the BrowserLiveViewDisconnectEventType enum. -func (e BrowserLiveViewDisconnectEventType) Valid() bool { +// Valid indicates whether the value is a known member of the BrowserCdpPageBringToFrontCommandDataMethod enum. +func (e BrowserCdpPageBringToFrontCommandDataMethod) Valid() bool { switch e { - case LiveViewDisconnect: + case PageBringToFront: return true default: return false } } -// Defines values for BrowserMonitorDisconnectedEventCategory. +// Defines values for BrowserCdpPageCaptureScreenshotCommandDataMethod. const ( - BrowserMonitorDisconnectedEventCategoryMonitor BrowserMonitorDisconnectedEventCategory = "monitor" + PageCaptureScreenshot BrowserCdpPageCaptureScreenshotCommandDataMethod = "Page.captureScreenshot" ) -// Valid indicates whether the value is a known member of the BrowserMonitorDisconnectedEventCategory enum. -func (e BrowserMonitorDisconnectedEventCategory) Valid() bool { +// Valid indicates whether the value is a known member of the BrowserCdpPageCaptureScreenshotCommandDataMethod enum. +func (e BrowserCdpPageCaptureScreenshotCommandDataMethod) Valid() bool { switch e { - case BrowserMonitorDisconnectedEventCategoryMonitor: + case PageCaptureScreenshot: return true default: return false } } -// Defines values for BrowserMonitorDisconnectedEventType. +// Defines values for BrowserCdpPageCaptureSnapshotCommandDataMethod. const ( - MonitorDisconnected BrowserMonitorDisconnectedEventType = "monitor_disconnected" + PageCaptureSnapshot BrowserCdpPageCaptureSnapshotCommandDataMethod = "Page.captureSnapshot" ) -// Valid indicates whether the value is a known member of the BrowserMonitorDisconnectedEventType enum. -func (e BrowserMonitorDisconnectedEventType) Valid() bool { +// Valid indicates whether the value is a known member of the BrowserCdpPageCaptureSnapshotCommandDataMethod enum. +func (e BrowserCdpPageCaptureSnapshotCommandDataMethod) Valid() bool { switch e { - case MonitorDisconnected: + case PageCaptureSnapshot: return true default: return false } } -// Defines values for BrowserMonitorDisconnectedEventDataReason. +// Defines values for BrowserCdpPageCloseCommandDataMethod. const ( - ChromeRestarted BrowserMonitorDisconnectedEventDataReason = "chrome_restarted" + PageClose BrowserCdpPageCloseCommandDataMethod = "Page.close" ) -// Valid indicates whether the value is a known member of the BrowserMonitorDisconnectedEventDataReason enum. -func (e BrowserMonitorDisconnectedEventDataReason) Valid() bool { +// Valid indicates whether the value is a known member of the BrowserCdpPageCloseCommandDataMethod enum. +func (e BrowserCdpPageCloseCommandDataMethod) Valid() bool { switch e { - case ChromeRestarted: + case PageClose: return true default: return false } } -// Defines values for BrowserMonitorInitFailedEventCategory. +// Defines values for BrowserCdpPageHandleJavaScriptDialogCommandDataMethod. const ( - BrowserMonitorInitFailedEventCategoryMonitor BrowserMonitorInitFailedEventCategory = "monitor" + PageHandleJavaScriptDialog BrowserCdpPageHandleJavaScriptDialogCommandDataMethod = "Page.handleJavaScriptDialog" ) -// Valid indicates whether the value is a known member of the BrowserMonitorInitFailedEventCategory enum. -func (e BrowserMonitorInitFailedEventCategory) Valid() bool { +// Valid indicates whether the value is a known member of the BrowserCdpPageHandleJavaScriptDialogCommandDataMethod enum. +func (e BrowserCdpPageHandleJavaScriptDialogCommandDataMethod) Valid() bool { switch e { - case BrowserMonitorInitFailedEventCategoryMonitor: + case PageHandleJavaScriptDialog: return true default: return false } } -// Defines values for BrowserMonitorInitFailedEventType. +// Defines values for BrowserCdpPageNavigateCommandDataMethod. const ( - MonitorInitFailed BrowserMonitorInitFailedEventType = "monitor_init_failed" + PageNavigate BrowserCdpPageNavigateCommandDataMethod = "Page.navigate" ) -// Valid indicates whether the value is a known member of the BrowserMonitorInitFailedEventType enum. -func (e BrowserMonitorInitFailedEventType) Valid() bool { +// Valid indicates whether the value is a known member of the BrowserCdpPageNavigateCommandDataMethod enum. +func (e BrowserCdpPageNavigateCommandDataMethod) Valid() bool { switch e { - case MonitorInitFailed: + case PageNavigate: return true default: return false } } -// Defines values for BrowserMonitorReconnectFailedEventCategory. +// Defines values for BrowserCdpPageNavigateToHistoryEntryCommandDataMethod. const ( - BrowserMonitorReconnectFailedEventCategoryMonitor BrowserMonitorReconnectFailedEventCategory = "monitor" + PageNavigateToHistoryEntry BrowserCdpPageNavigateToHistoryEntryCommandDataMethod = "Page.navigateToHistoryEntry" ) -// Valid indicates whether the value is a known member of the BrowserMonitorReconnectFailedEventCategory enum. -func (e BrowserMonitorReconnectFailedEventCategory) Valid() bool { +// Valid indicates whether the value is a known member of the BrowserCdpPageNavigateToHistoryEntryCommandDataMethod enum. +func (e BrowserCdpPageNavigateToHistoryEntryCommandDataMethod) Valid() bool { switch e { - case BrowserMonitorReconnectFailedEventCategoryMonitor: + case PageNavigateToHistoryEntry: return true default: return false } } -// Defines values for BrowserMonitorReconnectFailedEventType. +// Defines values for BrowserCdpPagePrintToPdfCommandDataMethod. const ( - MonitorReconnectFailed BrowserMonitorReconnectFailedEventType = "monitor_reconnect_failed" + PagePrintToPDF BrowserCdpPagePrintToPdfCommandDataMethod = "Page.printToPDF" ) -// Valid indicates whether the value is a known member of the BrowserMonitorReconnectFailedEventType enum. -func (e BrowserMonitorReconnectFailedEventType) Valid() bool { +// Valid indicates whether the value is a known member of the BrowserCdpPagePrintToPdfCommandDataMethod enum. +func (e BrowserCdpPagePrintToPdfCommandDataMethod) Valid() bool { switch e { - case MonitorReconnectFailed: + case PagePrintToPDF: return true default: return false } } -// Defines values for BrowserMonitorReconnectFailedEventDataReason. +// Defines values for BrowserCdpPageReloadCommandDataMethod. const ( - ReconnectExhausted BrowserMonitorReconnectFailedEventDataReason = "reconnect_exhausted" + PageReload BrowserCdpPageReloadCommandDataMethod = "Page.reload" ) -// Valid indicates whether the value is a known member of the BrowserMonitorReconnectFailedEventDataReason enum. -func (e BrowserMonitorReconnectFailedEventDataReason) Valid() bool { +// Valid indicates whether the value is a known member of the BrowserCdpPageReloadCommandDataMethod enum. +func (e BrowserCdpPageReloadCommandDataMethod) Valid() bool { switch e { - case ReconnectExhausted: + case PageReload: return true default: return false } } -// Defines values for BrowserMonitorReconnectedEventCategory. +// Defines values for BrowserCdpPageSetWebLifecycleStateCommandDataMethod. const ( - BrowserMonitorReconnectedEventCategoryMonitor BrowserMonitorReconnectedEventCategory = "monitor" + PageSetWebLifecycleState BrowserCdpPageSetWebLifecycleStateCommandDataMethod = "Page.setWebLifecycleState" ) -// Valid indicates whether the value is a known member of the BrowserMonitorReconnectedEventCategory enum. -func (e BrowserMonitorReconnectedEventCategory) Valid() bool { +// Valid indicates whether the value is a known member of the BrowserCdpPageSetWebLifecycleStateCommandDataMethod enum. +func (e BrowserCdpPageSetWebLifecycleStateCommandDataMethod) Valid() bool { switch e { - case BrowserMonitorReconnectedEventCategoryMonitor: + case PageSetWebLifecycleState: return true default: return false } } -// Defines values for BrowserMonitorReconnectedEventType. +// Defines values for BrowserCdpPageStartScreencastCommandDataMethod. const ( - MonitorReconnected BrowserMonitorReconnectedEventType = "monitor_reconnected" + PageStartScreencast BrowserCdpPageStartScreencastCommandDataMethod = "Page.startScreencast" ) -// Valid indicates whether the value is a known member of the BrowserMonitorReconnectedEventType enum. -func (e BrowserMonitorReconnectedEventType) Valid() bool { +// Valid indicates whether the value is a known member of the BrowserCdpPageStartScreencastCommandDataMethod enum. +func (e BrowserCdpPageStartScreencastCommandDataMethod) Valid() bool { switch e { - case MonitorReconnected: + case PageStartScreencast: return true default: return false } } -// Defines values for BrowserMonitorScreenshotEventCategory. +// Defines values for BrowserCdpPageStopLoadingCommandDataMethod. const ( - Screenshot BrowserMonitorScreenshotEventCategory = "screenshot" + PageStopLoading BrowserCdpPageStopLoadingCommandDataMethod = "Page.stopLoading" ) -// Valid indicates whether the value is a known member of the BrowserMonitorScreenshotEventCategory enum. -func (e BrowserMonitorScreenshotEventCategory) Valid() bool { +// Valid indicates whether the value is a known member of the BrowserCdpPageStopLoadingCommandDataMethod enum. +func (e BrowserCdpPageStopLoadingCommandDataMethod) Valid() bool { switch e { - case Screenshot: + case PageStopLoading: return true default: return false } } -// Defines values for BrowserMonitorScreenshotEventType. +// Defines values for BrowserCdpPageStopScreencastCommandDataMethod. const ( - MonitorScreenshot BrowserMonitorScreenshotEventType = "monitor_screenshot" + PageStopScreencast BrowserCdpPageStopScreencastCommandDataMethod = "Page.stopScreencast" ) -// Valid indicates whether the value is a known member of the BrowserMonitorScreenshotEventType enum. -func (e BrowserMonitorScreenshotEventType) Valid() bool { +// Valid indicates whether the value is a known member of the BrowserCdpPageStopScreencastCommandDataMethod enum. +func (e BrowserCdpPageStopScreencastCommandDataMethod) Valid() bool { switch e { - case MonitorScreenshot: + case PageStopScreencast: return true default: return false } } -// Defines values for BrowserNetworkIdleEventCategory. +// Defines values for BrowserCdpTargetActivateTargetCommandDataMethod. const ( - BrowserNetworkIdleEventCategoryNetwork BrowserNetworkIdleEventCategory = "network" + TargetActivateTarget BrowserCdpTargetActivateTargetCommandDataMethod = "Target.activateTarget" ) -// Valid indicates whether the value is a known member of the BrowserNetworkIdleEventCategory enum. -func (e BrowserNetworkIdleEventCategory) Valid() bool { +// Valid indicates whether the value is a known member of the BrowserCdpTargetActivateTargetCommandDataMethod enum. +func (e BrowserCdpTargetActivateTargetCommandDataMethod) Valid() bool { switch e { - case BrowserNetworkIdleEventCategoryNetwork: + case TargetActivateTarget: return true default: return false } } -// Defines values for BrowserNetworkIdleEventType. +// Defines values for BrowserCdpTargetCloseTargetCommandDataMethod. const ( - NetworkIdle BrowserNetworkIdleEventType = "network_idle" + TargetCloseTarget BrowserCdpTargetCloseTargetCommandDataMethod = "Target.closeTarget" ) -// Valid indicates whether the value is a known member of the BrowserNetworkIdleEventType enum. -func (e BrowserNetworkIdleEventType) Valid() bool { +// Valid indicates whether the value is a known member of the BrowserCdpTargetCloseTargetCommandDataMethod enum. +func (e BrowserCdpTargetCloseTargetCommandDataMethod) Valid() bool { switch e { - case NetworkIdle: + case TargetCloseTarget: return true default: return false } } -// Defines values for BrowserNetworkLoadingFailedEventCategory. +// Defines values for BrowserCdpTargetCreateBrowserContextCommandDataMethod. const ( - BrowserNetworkLoadingFailedEventCategoryNetwork BrowserNetworkLoadingFailedEventCategory = "network" + TargetCreateBrowserContext BrowserCdpTargetCreateBrowserContextCommandDataMethod = "Target.createBrowserContext" ) -// Valid indicates whether the value is a known member of the BrowserNetworkLoadingFailedEventCategory enum. -func (e BrowserNetworkLoadingFailedEventCategory) Valid() bool { +// Valid indicates whether the value is a known member of the BrowserCdpTargetCreateBrowserContextCommandDataMethod enum. +func (e BrowserCdpTargetCreateBrowserContextCommandDataMethod) Valid() bool { switch e { - case BrowserNetworkLoadingFailedEventCategoryNetwork: + case TargetCreateBrowserContext: return true default: return false } } -// Defines values for BrowserNetworkLoadingFailedEventType. +// Defines values for BrowserCdpTargetCreateTargetCommandDataMethod. const ( - NetworkLoadingFailed BrowserNetworkLoadingFailedEventType = "network_loading_failed" + TargetCreateTarget BrowserCdpTargetCreateTargetCommandDataMethod = "Target.createTarget" ) -// Valid indicates whether the value is a known member of the BrowserNetworkLoadingFailedEventType enum. -func (e BrowserNetworkLoadingFailedEventType) Valid() bool { +// Valid indicates whether the value is a known member of the BrowserCdpTargetCreateTargetCommandDataMethod enum. +func (e BrowserCdpTargetCreateTargetCommandDataMethod) Valid() bool { switch e { - case NetworkLoadingFailed: + case TargetCreateTarget: return true default: return false } } -// Defines values for BrowserNetworkRequestEventCategory. +// Defines values for BrowserCdpTargetDisposeBrowserContextCommandDataMethod. const ( - BrowserNetworkRequestEventCategoryNetwork BrowserNetworkRequestEventCategory = "network" + TargetDisposeBrowserContext BrowserCdpTargetDisposeBrowserContextCommandDataMethod = "Target.disposeBrowserContext" ) -// Valid indicates whether the value is a known member of the BrowserNetworkRequestEventCategory enum. -func (e BrowserNetworkRequestEventCategory) Valid() bool { +// Valid indicates whether the value is a known member of the BrowserCdpTargetDisposeBrowserContextCommandDataMethod enum. +func (e BrowserCdpTargetDisposeBrowserContextCommandDataMethod) Valid() bool { switch e { - case BrowserNetworkRequestEventCategoryNetwork: + case TargetDisposeBrowserContext: return true default: return false } } -// Defines values for BrowserNetworkRequestEventType. +// Defines values for BrowserCdpTargetOpenDevToolsCommandDataMethod. const ( - NetworkRequest BrowserNetworkRequestEventType = "network_request" + TargetOpenDevTools BrowserCdpTargetOpenDevToolsCommandDataMethod = "Target.openDevTools" ) -// Valid indicates whether the value is a known member of the BrowserNetworkRequestEventType enum. -func (e BrowserNetworkRequestEventType) Valid() bool { +// Valid indicates whether the value is a known member of the BrowserCdpTargetOpenDevToolsCommandDataMethod enum. +func (e BrowserCdpTargetOpenDevToolsCommandDataMethod) Valid() bool { switch e { - case NetworkRequest: + case TargetOpenDevTools: return true default: return false } } -// Defines values for BrowserNetworkResponseEventCategory. +// Defines values for BrowserConsoleErrorEventCategory. const ( - BrowserNetworkResponseEventCategoryNetwork BrowserNetworkResponseEventCategory = "network" + BrowserConsoleErrorEventCategoryConsole BrowserConsoleErrorEventCategory = "console" ) -// Valid indicates whether the value is a known member of the BrowserNetworkResponseEventCategory enum. -func (e BrowserNetworkResponseEventCategory) Valid() bool { +// Valid indicates whether the value is a known member of the BrowserConsoleErrorEventCategory enum. +func (e BrowserConsoleErrorEventCategory) Valid() bool { switch e { - case BrowserNetworkResponseEventCategoryNetwork: + case BrowserConsoleErrorEventCategoryConsole: return true default: return false } } -// Defines values for BrowserNetworkResponseEventType. +// Defines values for BrowserConsoleErrorEventType. const ( - NetworkResponse BrowserNetworkResponseEventType = "network_response" + ConsoleError BrowserConsoleErrorEventType = "console_error" ) -// Valid indicates whether the value is a known member of the BrowserNetworkResponseEventType enum. -func (e BrowserNetworkResponseEventType) Valid() bool { +// Valid indicates whether the value is a known member of the BrowserConsoleErrorEventType enum. +func (e BrowserConsoleErrorEventType) Valid() bool { switch e { - case NetworkResponse: + case ConsoleError: return true default: return false } } -// Defines values for BrowserPageCrashedEventCategory. +// Defines values for BrowserConsoleLogEventCategory. const ( - BrowserPageCrashedEventCategoryPage BrowserPageCrashedEventCategory = "page" + BrowserConsoleLogEventCategoryConsole BrowserConsoleLogEventCategory = "console" ) -// Valid indicates whether the value is a known member of the BrowserPageCrashedEventCategory enum. -func (e BrowserPageCrashedEventCategory) Valid() bool { +// Valid indicates whether the value is a known member of the BrowserConsoleLogEventCategory enum. +func (e BrowserConsoleLogEventCategory) Valid() bool { switch e { - case BrowserPageCrashedEventCategoryPage: + case BrowserConsoleLogEventCategoryConsole: return true default: return false } } -// Defines values for BrowserPageCrashedEventType. +// Defines values for BrowserConsoleLogEventType. const ( - PageCrashed BrowserPageCrashedEventType = "page_crashed" + ConsoleLog BrowserConsoleLogEventType = "console_log" ) -// Valid indicates whether the value is a known member of the BrowserPageCrashedEventType enum. -func (e BrowserPageCrashedEventType) Valid() bool { +// Valid indicates whether the value is a known member of the BrowserConsoleLogEventType enum. +func (e BrowserConsoleLogEventType) Valid() bool { switch e { - case PageCrashed: + case ConsoleLog: return true default: return false } } -// Defines values for BrowserPageDomContentLoadedEventCategory. +// Defines values for BrowserEventSourceKind. const ( - BrowserPageDomContentLoadedEventCategoryPage BrowserPageDomContentLoadedEventCategory = "page" + Cdp BrowserEventSourceKind = "cdp" + Extension BrowserEventSourceKind = "extension" + KernelApi BrowserEventSourceKind = "kernel_api" + LocalProcess BrowserEventSourceKind = "local_process" ) -// Valid indicates whether the value is a known member of the BrowserPageDomContentLoadedEventCategory enum. -func (e BrowserPageDomContentLoadedEventCategory) Valid() bool { +// Valid indicates whether the value is a known member of the BrowserEventSourceKind enum. +func (e BrowserEventSourceKind) Valid() bool { switch e { - case BrowserPageDomContentLoadedEventCategoryPage: + case Cdp: + return true + case Extension: + return true + case KernelApi: + return true + case LocalProcess: return true default: return false } } -// Defines values for BrowserPageDomContentLoadedEventType. +// Defines values for BrowserInteractionClickEventCategory. const ( - PageDomContentLoaded BrowserPageDomContentLoadedEventType = "page_dom_content_loaded" + BrowserInteractionClickEventCategoryInteraction BrowserInteractionClickEventCategory = "interaction" ) -// Valid indicates whether the value is a known member of the BrowserPageDomContentLoadedEventType enum. -func (e BrowserPageDomContentLoadedEventType) Valid() bool { +// Valid indicates whether the value is a known member of the BrowserInteractionClickEventCategory enum. +func (e BrowserInteractionClickEventCategory) Valid() bool { switch e { - case PageDomContentLoaded: + case BrowserInteractionClickEventCategoryInteraction: return true default: return false } } -// Defines values for BrowserPageLayoutSettledEventCategory. +// Defines values for BrowserInteractionClickEventType. const ( - BrowserPageLayoutSettledEventCategoryPage BrowserPageLayoutSettledEventCategory = "page" + InteractionClick BrowserInteractionClickEventType = "interaction_click" ) -// Valid indicates whether the value is a known member of the BrowserPageLayoutSettledEventCategory enum. -func (e BrowserPageLayoutSettledEventCategory) Valid() bool { +// Valid indicates whether the value is a known member of the BrowserInteractionClickEventType enum. +func (e BrowserInteractionClickEventType) Valid() bool { switch e { - case BrowserPageLayoutSettledEventCategoryPage: + case InteractionClick: return true default: return false } } -// Defines values for BrowserPageLayoutSettledEventType. +// Defines values for BrowserInteractionKeyEventCategory. const ( - PageLayoutSettled BrowserPageLayoutSettledEventType = "page_layout_settled" + BrowserInteractionKeyEventCategoryInteraction BrowserInteractionKeyEventCategory = "interaction" ) -// Valid indicates whether the value is a known member of the BrowserPageLayoutSettledEventType enum. -func (e BrowserPageLayoutSettledEventType) Valid() bool { +// Valid indicates whether the value is a known member of the BrowserInteractionKeyEventCategory enum. +func (e BrowserInteractionKeyEventCategory) Valid() bool { switch e { - case PageLayoutSettled: + case BrowserInteractionKeyEventCategoryInteraction: return true default: return false } } -// Defines values for BrowserPageLayoutShiftEventCategory. +// Defines values for BrowserInteractionKeyEventType. const ( - BrowserPageLayoutShiftEventCategoryPage BrowserPageLayoutShiftEventCategory = "page" + InteractionKey BrowserInteractionKeyEventType = "interaction_key" ) -// Valid indicates whether the value is a known member of the BrowserPageLayoutShiftEventCategory enum. -func (e BrowserPageLayoutShiftEventCategory) Valid() bool { +// Valid indicates whether the value is a known member of the BrowserInteractionKeyEventType enum. +func (e BrowserInteractionKeyEventType) Valid() bool { switch e { - case BrowserPageLayoutShiftEventCategoryPage: + case InteractionKey: return true default: return false } } -// Defines values for BrowserPageLayoutShiftEventType. +// Defines values for BrowserInteractionScrollSettledEventCategory. const ( - PageLayoutShift BrowserPageLayoutShiftEventType = "page_layout_shift" + BrowserInteractionScrollSettledEventCategoryInteraction BrowserInteractionScrollSettledEventCategory = "interaction" ) -// Valid indicates whether the value is a known member of the BrowserPageLayoutShiftEventType enum. -func (e BrowserPageLayoutShiftEventType) Valid() bool { +// Valid indicates whether the value is a known member of the BrowserInteractionScrollSettledEventCategory enum. +func (e BrowserInteractionScrollSettledEventCategory) Valid() bool { switch e { - case PageLayoutShift: + case BrowserInteractionScrollSettledEventCategoryInteraction: return true default: return false } } -// Defines values for BrowserPageLcpEventCategory. +// Defines values for BrowserInteractionScrollSettledEventType. const ( - BrowserPageLcpEventCategoryPage BrowserPageLcpEventCategory = "page" + InteractionScrollSettled BrowserInteractionScrollSettledEventType = "interaction_scroll_settled" ) -// Valid indicates whether the value is a known member of the BrowserPageLcpEventCategory enum. -func (e BrowserPageLcpEventCategory) Valid() bool { +// Valid indicates whether the value is a known member of the BrowserInteractionScrollSettledEventType enum. +func (e BrowserInteractionScrollSettledEventType) Valid() bool { switch e { - case BrowserPageLcpEventCategoryPage: + case InteractionScrollSettled: return true default: return false } } -// Defines values for BrowserPageLcpEventType. +// Defines values for BrowserLiveViewConnectEventCategory. const ( - PageLcp BrowserPageLcpEventType = "page_lcp" + BrowserLiveViewConnectEventCategoryConnection BrowserLiveViewConnectEventCategory = "connection" ) -// Valid indicates whether the value is a known member of the BrowserPageLcpEventType enum. -func (e BrowserPageLcpEventType) Valid() bool { +// Valid indicates whether the value is a known member of the BrowserLiveViewConnectEventCategory enum. +func (e BrowserLiveViewConnectEventCategory) Valid() bool { switch e { - case PageLcp: + case BrowserLiveViewConnectEventCategoryConnection: return true default: return false } } -// Defines values for BrowserPageLoadEventCategory. +// Defines values for BrowserLiveViewConnectEventType. const ( - BrowserPageLoadEventCategoryPage BrowserPageLoadEventCategory = "page" + LiveViewConnect BrowserLiveViewConnectEventType = "live_view_connect" ) -// Valid indicates whether the value is a known member of the BrowserPageLoadEventCategory enum. -func (e BrowserPageLoadEventCategory) Valid() bool { +// Valid indicates whether the value is a known member of the BrowserLiveViewConnectEventType enum. +func (e BrowserLiveViewConnectEventType) Valid() bool { switch e { - case BrowserPageLoadEventCategoryPage: + case LiveViewConnect: return true default: return false } } -// Defines values for BrowserPageLoadEventType. +// Defines values for BrowserLiveViewDisconnectEventCategory. const ( - PageLoad BrowserPageLoadEventType = "page_load" + BrowserLiveViewDisconnectEventCategoryConnection BrowserLiveViewDisconnectEventCategory = "connection" ) -// Valid indicates whether the value is a known member of the BrowserPageLoadEventType enum. -func (e BrowserPageLoadEventType) Valid() bool { +// Valid indicates whether the value is a known member of the BrowserLiveViewDisconnectEventCategory enum. +func (e BrowserLiveViewDisconnectEventCategory) Valid() bool { switch e { - case PageLoad: + case BrowserLiveViewDisconnectEventCategoryConnection: return true default: return false } } -// Defines values for BrowserPageNavigationEventCategory. +// Defines values for BrowserLiveViewDisconnectEventType. const ( - BrowserPageNavigationEventCategoryPage BrowserPageNavigationEventCategory = "page" + LiveViewDisconnect BrowserLiveViewDisconnectEventType = "live_view_disconnect" ) -// Valid indicates whether the value is a known member of the BrowserPageNavigationEventCategory enum. -func (e BrowserPageNavigationEventCategory) Valid() bool { +// Valid indicates whether the value is a known member of the BrowserLiveViewDisconnectEventType enum. +func (e BrowserLiveViewDisconnectEventType) Valid() bool { switch e { - case BrowserPageNavigationEventCategoryPage: + case LiveViewDisconnect: return true default: return false } } -// Defines values for BrowserPageNavigationEventType. +// Defines values for BrowserMonitorDisconnectedEventCategory. const ( - PageNavigation BrowserPageNavigationEventType = "page_navigation" + BrowserMonitorDisconnectedEventCategoryMonitor BrowserMonitorDisconnectedEventCategory = "monitor" ) -// Valid indicates whether the value is a known member of the BrowserPageNavigationEventType enum. -func (e BrowserPageNavigationEventType) Valid() bool { +// Valid indicates whether the value is a known member of the BrowserMonitorDisconnectedEventCategory enum. +func (e BrowserMonitorDisconnectedEventCategory) Valid() bool { switch e { - case PageNavigation: + case BrowserMonitorDisconnectedEventCategoryMonitor: return true default: return false } } -// Defines values for BrowserPageNavigationSettledEventCategory. +// Defines values for BrowserMonitorDisconnectedEventType. const ( - BrowserPageNavigationSettledEventCategoryPage BrowserPageNavigationSettledEventCategory = "page" + MonitorDisconnected BrowserMonitorDisconnectedEventType = "monitor_disconnected" ) -// Valid indicates whether the value is a known member of the BrowserPageNavigationSettledEventCategory enum. -func (e BrowserPageNavigationSettledEventCategory) Valid() bool { +// Valid indicates whether the value is a known member of the BrowserMonitorDisconnectedEventType enum. +func (e BrowserMonitorDisconnectedEventType) Valid() bool { switch e { - case BrowserPageNavigationSettledEventCategoryPage: + case MonitorDisconnected: return true default: return false } } -// Defines values for BrowserPageNavigationSettledEventType. +// Defines values for BrowserMonitorDisconnectedEventDataReason. const ( - PageNavigationSettled BrowserPageNavigationSettledEventType = "page_navigation_settled" + ChromeRestarted BrowserMonitorDisconnectedEventDataReason = "chrome_restarted" ) -// Valid indicates whether the value is a known member of the BrowserPageNavigationSettledEventType enum. -func (e BrowserPageNavigationSettledEventType) Valid() bool { +// Valid indicates whether the value is a known member of the BrowserMonitorDisconnectedEventDataReason enum. +func (e BrowserMonitorDisconnectedEventDataReason) Valid() bool { switch e { - case PageNavigationSettled: + case ChromeRestarted: return true default: return false } } -// Defines values for BrowserPageTabOpenedEventCategory. +// Defines values for BrowserMonitorInitFailedEventCategory. const ( - Page BrowserPageTabOpenedEventCategory = "page" + BrowserMonitorInitFailedEventCategoryMonitor BrowserMonitorInitFailedEventCategory = "monitor" ) -// Valid indicates whether the value is a known member of the BrowserPageTabOpenedEventCategory enum. -func (e BrowserPageTabOpenedEventCategory) Valid() bool { +// Valid indicates whether the value is a known member of the BrowserMonitorInitFailedEventCategory enum. +func (e BrowserMonitorInitFailedEventCategory) Valid() bool { switch e { - case Page: + case BrowserMonitorInitFailedEventCategoryMonitor: return true default: return false } } -// Defines values for BrowserPageTabOpenedEventType. +// Defines values for BrowserMonitorInitFailedEventType. const ( - PageTabOpened BrowserPageTabOpenedEventType = "page_tab_opened" + MonitorInitFailed BrowserMonitorInitFailedEventType = "monitor_init_failed" ) -// Valid indicates whether the value is a known member of the BrowserPageTabOpenedEventType enum. -func (e BrowserPageTabOpenedEventType) Valid() bool { +// Valid indicates whether the value is a known member of the BrowserMonitorInitFailedEventType enum. +func (e BrowserMonitorInitFailedEventType) Valid() bool { switch e { - case PageTabOpened: + case MonitorInitFailed: return true default: return false } } -// Defines values for BrowserPlatformApiCallEventCategory. +// Defines values for BrowserMonitorReconnectFailedEventCategory. const ( - Platform BrowserPlatformApiCallEventCategory = "platform" + BrowserMonitorReconnectFailedEventCategoryMonitor BrowserMonitorReconnectFailedEventCategory = "monitor" ) -// Valid indicates whether the value is a known member of the BrowserPlatformApiCallEventCategory enum. -func (e BrowserPlatformApiCallEventCategory) Valid() bool { +// Valid indicates whether the value is a known member of the BrowserMonitorReconnectFailedEventCategory enum. +func (e BrowserMonitorReconnectFailedEventCategory) Valid() bool { switch e { - case Platform: + case BrowserMonitorReconnectFailedEventCategoryMonitor: return true default: return false } } -// Defines values for BrowserPlatformApiCallEventType. +// Defines values for BrowserMonitorReconnectFailedEventType. const ( - PlatformApiCall BrowserPlatformApiCallEventType = "platform_api_call" + MonitorReconnectFailed BrowserMonitorReconnectFailedEventType = "monitor_reconnect_failed" ) -// Valid indicates whether the value is a known member of the BrowserPlatformApiCallEventType enum. -func (e BrowserPlatformApiCallEventType) Valid() bool { +// Valid indicates whether the value is a known member of the BrowserMonitorReconnectFailedEventType enum. +func (e BrowserMonitorReconnectFailedEventType) Valid() bool { switch e { - case PlatformApiCall: + case MonitorReconnectFailed: return true default: return false } } -// Defines values for BrowserServiceCrashedEventCategory. +// Defines values for BrowserMonitorReconnectFailedEventDataReason. const ( - BrowserServiceCrashedEventCategorySystem BrowserServiceCrashedEventCategory = "system" + ReconnectExhausted BrowserMonitorReconnectFailedEventDataReason = "reconnect_exhausted" ) -// Valid indicates whether the value is a known member of the BrowserServiceCrashedEventCategory enum. -func (e BrowserServiceCrashedEventCategory) Valid() bool { +// Valid indicates whether the value is a known member of the BrowserMonitorReconnectFailedEventDataReason enum. +func (e BrowserMonitorReconnectFailedEventDataReason) Valid() bool { switch e { - case BrowserServiceCrashedEventCategorySystem: + case ReconnectExhausted: return true default: return false } } -// Defines values for BrowserServiceCrashedEventType. +// Defines values for BrowserMonitorReconnectedEventCategory. const ( - ServiceCrashed BrowserServiceCrashedEventType = "service_crashed" + BrowserMonitorReconnectedEventCategoryMonitor BrowserMonitorReconnectedEventCategory = "monitor" ) -// Valid indicates whether the value is a known member of the BrowserServiceCrashedEventType enum. -func (e BrowserServiceCrashedEventType) Valid() bool { +// Valid indicates whether the value is a known member of the BrowserMonitorReconnectedEventCategory enum. +func (e BrowserMonitorReconnectedEventCategory) Valid() bool { switch e { - case ServiceCrashed: + case BrowserMonitorReconnectedEventCategoryMonitor: return true default: return false } } -// Defines values for BrowserServiceCrashedEventDataPhase. +// Defines values for BrowserMonitorReconnectedEventType. const ( - BrowserServiceCrashedEventDataPhaseGaveUp BrowserServiceCrashedEventDataPhase = "gave_up" - BrowserServiceCrashedEventDataPhaseRunning BrowserServiceCrashedEventDataPhase = "running" - BrowserServiceCrashedEventDataPhaseStartup BrowserServiceCrashedEventDataPhase = "startup" + MonitorReconnected BrowserMonitorReconnectedEventType = "monitor_reconnected" ) -// Valid indicates whether the value is a known member of the BrowserServiceCrashedEventDataPhase enum. -func (e BrowserServiceCrashedEventDataPhase) Valid() bool { +// Valid indicates whether the value is a known member of the BrowserMonitorReconnectedEventType enum. +func (e BrowserMonitorReconnectedEventType) Valid() bool { switch e { - case BrowserServiceCrashedEventDataPhaseGaveUp: - return true - case BrowserServiceCrashedEventDataPhaseRunning: - return true - case BrowserServiceCrashedEventDataPhaseStartup: + case MonitorReconnected: return true default: return false } } -// Defines values for BrowserSystemOomKillEventCategory. +// Defines values for BrowserMonitorScreenshotEventCategory. const ( - BrowserSystemOomKillEventCategorySystem BrowserSystemOomKillEventCategory = "system" + Screenshot BrowserMonitorScreenshotEventCategory = "screenshot" ) -// Valid indicates whether the value is a known member of the BrowserSystemOomKillEventCategory enum. -func (e BrowserSystemOomKillEventCategory) Valid() bool { +// Valid indicates whether the value is a known member of the BrowserMonitorScreenshotEventCategory enum. +func (e BrowserMonitorScreenshotEventCategory) Valid() bool { switch e { - case BrowserSystemOomKillEventCategorySystem: + case Screenshot: return true default: return false } } -// Defines values for BrowserSystemOomKillEventType. +// Defines values for BrowserMonitorScreenshotEventType. const ( - SystemOomKill BrowserSystemOomKillEventType = "system_oom_kill" + MonitorScreenshot BrowserMonitorScreenshotEventType = "monitor_screenshot" ) -// Valid indicates whether the value is a known member of the BrowserSystemOomKillEventType enum. -func (e BrowserSystemOomKillEventType) Valid() bool { +// Valid indicates whether the value is a known member of the BrowserMonitorScreenshotEventType enum. +func (e BrowserMonitorScreenshotEventType) Valid() bool { switch e { - case SystemOomKill: + case MonitorScreenshot: return true default: return false } } -// Defines values for BrowserSystemOomKillEventDataConstraint. +// Defines values for BrowserNetworkIdleEventCategory. const ( - Cpuset BrowserSystemOomKillEventDataConstraint = "cpuset" - Memcg BrowserSystemOomKillEventDataConstraint = "memcg" - MemoryPolicy BrowserSystemOomKillEventDataConstraint = "memory_policy" - None BrowserSystemOomKillEventDataConstraint = "none" + BrowserNetworkIdleEventCategoryNetwork BrowserNetworkIdleEventCategory = "network" ) -// Valid indicates whether the value is a known member of the BrowserSystemOomKillEventDataConstraint enum. -func (e BrowserSystemOomKillEventDataConstraint) Valid() bool { +// Valid indicates whether the value is a known member of the BrowserNetworkIdleEventCategory enum. +func (e BrowserNetworkIdleEventCategory) Valid() bool { switch e { - case Cpuset: - return true - case Memcg: - return true - case MemoryPolicy: - return true - case None: + case BrowserNetworkIdleEventCategoryNetwork: return true default: return false } } -// Defines values for BrowserTargetType. +// Defines values for BrowserNetworkIdleEventType. const ( - BrowserTargetTypeBackgroundPage BrowserTargetType = "background_page" - BrowserTargetTypeOther BrowserTargetType = "other" - BrowserTargetTypePage BrowserTargetType = "page" - BrowserTargetTypeServiceWorker BrowserTargetType = "service_worker" - BrowserTargetTypeSharedWorker BrowserTargetType = "shared_worker" + NetworkIdle BrowserNetworkIdleEventType = "network_idle" ) -// Valid indicates whether the value is a known member of the BrowserTargetType enum. -func (e BrowserTargetType) Valid() bool { +// Valid indicates whether the value is a known member of the BrowserNetworkIdleEventType enum. +func (e BrowserNetworkIdleEventType) Valid() bool { switch e { - case BrowserTargetTypeBackgroundPage: - return true - case BrowserTargetTypeOther: - return true - case BrowserTargetTypePage: - return true - case BrowserTargetTypeServiceWorker: - return true - case BrowserTargetTypeSharedWorker: + case NetworkIdle: return true default: return false } } -// Defines values for ChromiumConfigureErrorPhase. +// Defines values for BrowserNetworkLoadingFailedEventCategory. const ( - ConfigurePhase ChromiumConfigureErrorPhase = "configure_phase" - NavigatePhase ChromiumConfigureErrorPhase = "navigate_phase" + BrowserNetworkLoadingFailedEventCategoryNetwork BrowserNetworkLoadingFailedEventCategory = "network" ) -// Valid indicates whether the value is a known member of the ChromiumConfigureErrorPhase enum. -func (e ChromiumConfigureErrorPhase) Valid() bool { +// Valid indicates whether the value is a known member of the BrowserNetworkLoadingFailedEventCategory enum. +func (e BrowserNetworkLoadingFailedEventCategory) Valid() bool { switch e { - case ConfigurePhase: - return true - case NavigatePhase: + case BrowserNetworkLoadingFailedEventCategoryNetwork: return true default: return false } } -// Defines values for ChromiumConfigureErrorStep. +// Defines values for BrowserNetworkLoadingFailedEventType. const ( - ChromePolicies ChromiumConfigureErrorStep = "chrome_policies" - ChromiumFlags ChromiumConfigureErrorStep = "chromium_flags" - Display ChromiumConfigureErrorStep = "display" - Extensions ChromiumConfigureErrorStep = "extensions" - Profile ChromiumConfigureErrorStep = "profile" - StartChromium ChromiumConfigureErrorStep = "start_chromium" - StopChromium ChromiumConfigureErrorStep = "stop_chromium" + NetworkLoadingFailed BrowserNetworkLoadingFailedEventType = "network_loading_failed" ) -// Valid indicates whether the value is a known member of the ChromiumConfigureErrorStep enum. -func (e ChromiumConfigureErrorStep) Valid() bool { +// Valid indicates whether the value is a known member of the BrowserNetworkLoadingFailedEventType enum. +func (e BrowserNetworkLoadingFailedEventType) Valid() bool { switch e { - case ChromePolicies: - return true - case ChromiumFlags: - return true - case Display: - return true - case Extensions: - return true - case Profile: - return true - case StartChromium: - return true - case StopChromium: + case NetworkLoadingFailed: return true default: return false } } -// Defines values for ClickMouseRequestButton. +// Defines values for BrowserNetworkRequestEventCategory. const ( - ClickMouseRequestButtonBack ClickMouseRequestButton = "back" - ClickMouseRequestButtonForward ClickMouseRequestButton = "forward" - ClickMouseRequestButtonLeft ClickMouseRequestButton = "left" - ClickMouseRequestButtonMiddle ClickMouseRequestButton = "middle" - ClickMouseRequestButtonRight ClickMouseRequestButton = "right" + BrowserNetworkRequestEventCategoryNetwork BrowserNetworkRequestEventCategory = "network" ) -// Valid indicates whether the value is a known member of the ClickMouseRequestButton enum. -func (e ClickMouseRequestButton) Valid() bool { +// Valid indicates whether the value is a known member of the BrowserNetworkRequestEventCategory enum. +func (e BrowserNetworkRequestEventCategory) Valid() bool { switch e { - case ClickMouseRequestButtonBack: - return true - case ClickMouseRequestButtonForward: - return true - case ClickMouseRequestButtonLeft: - return true - case ClickMouseRequestButtonMiddle: - return true - case ClickMouseRequestButtonRight: + case BrowserNetworkRequestEventCategoryNetwork: return true default: return false } } -// Defines values for ClickMouseRequestClickType. +// Defines values for BrowserNetworkRequestEventType. const ( - Click ClickMouseRequestClickType = "click" - Down ClickMouseRequestClickType = "down" - Up ClickMouseRequestClickType = "up" + NetworkRequest BrowserNetworkRequestEventType = "network_request" ) -// Valid indicates whether the value is a known member of the ClickMouseRequestClickType enum. -func (e ClickMouseRequestClickType) Valid() bool { +// Valid indicates whether the value is a known member of the BrowserNetworkRequestEventType enum. +func (e BrowserNetworkRequestEventType) Valid() bool { switch e { - case Click: - return true - case Down: - return true - case Up: + case NetworkRequest: return true default: return false } } -// Defines values for ComputerActionType. +// Defines values for BrowserNetworkResponseEventCategory. const ( - ClickMouse ComputerActionType = "click_mouse" - DragMouse ComputerActionType = "drag_mouse" - MoveMouse ComputerActionType = "move_mouse" - PressKey ComputerActionType = "press_key" - Scroll ComputerActionType = "scroll" - SetCursor ComputerActionType = "set_cursor" - Sleep ComputerActionType = "sleep" - TypeText ComputerActionType = "type_text" + BrowserNetworkResponseEventCategoryNetwork BrowserNetworkResponseEventCategory = "network" ) -// Valid indicates whether the value is a known member of the ComputerActionType enum. -func (e ComputerActionType) Valid() bool { +// Valid indicates whether the value is a known member of the BrowserNetworkResponseEventCategory enum. +func (e BrowserNetworkResponseEventCategory) Valid() bool { switch e { - case ClickMouse: - return true - case DragMouse: - return true - case MoveMouse: - return true - case PressKey: - return true - case Scroll: - return true - case SetCursor: - return true - case Sleep: - return true - case TypeText: + case BrowserNetworkResponseEventCategoryNetwork: return true default: return false } } -// Defines values for DragMouseRequestButton. +// Defines values for BrowserNetworkResponseEventType. const ( - DragMouseRequestButtonLeft DragMouseRequestButton = "left" - DragMouseRequestButtonMiddle DragMouseRequestButton = "middle" - DragMouseRequestButtonRight DragMouseRequestButton = "right" + NetworkResponse BrowserNetworkResponseEventType = "network_response" ) -// Valid indicates whether the value is a known member of the DragMouseRequestButton enum. -func (e DragMouseRequestButton) Valid() bool { +// Valid indicates whether the value is a known member of the BrowserNetworkResponseEventType enum. +func (e BrowserNetworkResponseEventType) Valid() bool { switch e { - case DragMouseRequestButtonLeft: - return true - case DragMouseRequestButtonMiddle: - return true - case DragMouseRequestButtonRight: + case NetworkResponse: return true default: return false } } -// Defines values for FileSystemEventType. +// Defines values for BrowserPageCrashedEventCategory. const ( - CREATE FileSystemEventType = "CREATE" - DELETE FileSystemEventType = "DELETE" - RENAME FileSystemEventType = "RENAME" - WRITE FileSystemEventType = "WRITE" + BrowserPageCrashedEventCategoryPage BrowserPageCrashedEventCategory = "page" ) -// Valid indicates whether the value is a known member of the FileSystemEventType enum. -func (e FileSystemEventType) Valid() bool { +// Valid indicates whether the value is a known member of the BrowserPageCrashedEventCategory enum. +func (e BrowserPageCrashedEventCategory) Valid() bool { switch e { - case CREATE: - return true - case DELETE: - return true - case RENAME: - return true - case WRITE: + case BrowserPageCrashedEventCategoryPage: return true default: return false } } -// Defines values for PatchDisplayRequestRefreshRate. +// Defines values for BrowserPageCrashedEventType. const ( - N10 PatchDisplayRequestRefreshRate = 10 - N25 PatchDisplayRequestRefreshRate = 25 - N30 PatchDisplayRequestRefreshRate = 30 - N60 PatchDisplayRequestRefreshRate = 60 + PageCrashed BrowserPageCrashedEventType = "page_crashed" ) -// Valid indicates whether the value is a known member of the PatchDisplayRequestRefreshRate enum. -func (e PatchDisplayRequestRefreshRate) Valid() bool { - switch e { - case N10: - return true - case N25: - return true - case N30: - return true - case N60: +// Valid indicates whether the value is a known member of the BrowserPageCrashedEventType enum. +func (e BrowserPageCrashedEventType) Valid() bool { + switch e { + case PageCrashed: return true default: return false } } -// Defines values for ProcessKillRequestSignal. +// Defines values for BrowserPageDomContentLoadedEventCategory. const ( - HUP ProcessKillRequestSignal = "HUP" - INT ProcessKillRequestSignal = "INT" - KILL ProcessKillRequestSignal = "KILL" - TERM ProcessKillRequestSignal = "TERM" + BrowserPageDomContentLoadedEventCategoryPage BrowserPageDomContentLoadedEventCategory = "page" ) -// Valid indicates whether the value is a known member of the ProcessKillRequestSignal enum. -func (e ProcessKillRequestSignal) Valid() bool { +// Valid indicates whether the value is a known member of the BrowserPageDomContentLoadedEventCategory enum. +func (e BrowserPageDomContentLoadedEventCategory) Valid() bool { switch e { - case HUP: - return true - case INT: - return true - case KILL: - return true - case TERM: + case BrowserPageDomContentLoadedEventCategoryPage: return true default: return false } } -// Defines values for ProcessStatusState. +// Defines values for BrowserPageDomContentLoadedEventType. const ( - ProcessStatusStateExited ProcessStatusState = "exited" - ProcessStatusStateRunning ProcessStatusState = "running" + PageDomContentLoaded BrowserPageDomContentLoadedEventType = "page_dom_content_loaded" ) -// Valid indicates whether the value is a known member of the ProcessStatusState enum. -func (e ProcessStatusState) Valid() bool { +// Valid indicates whether the value is a known member of the BrowserPageDomContentLoadedEventType enum. +func (e BrowserPageDomContentLoadedEventType) Valid() bool { switch e { - case ProcessStatusStateExited: - return true - case ProcessStatusStateRunning: + case PageDomContentLoaded: return true default: return false } } -// Defines values for ProcessStreamEventEvent. +// Defines values for BrowserPageLayoutSettledEventCategory. const ( - Exit ProcessStreamEventEvent = "exit" + BrowserPageLayoutSettledEventCategoryPage BrowserPageLayoutSettledEventCategory = "page" ) -// Valid indicates whether the value is a known member of the ProcessStreamEventEvent enum. -func (e ProcessStreamEventEvent) Valid() bool { +// Valid indicates whether the value is a known member of the BrowserPageLayoutSettledEventCategory enum. +func (e BrowserPageLayoutSettledEventCategory) Valid() bool { switch e { - case Exit: + case BrowserPageLayoutSettledEventCategoryPage: return true default: return false } } -// Defines values for ProcessStreamEventStream. +// Defines values for BrowserPageLayoutSettledEventType. const ( - Stderr ProcessStreamEventStream = "stderr" - Stdout ProcessStreamEventStream = "stdout" + PageLayoutSettled BrowserPageLayoutSettledEventType = "page_layout_settled" ) -// Valid indicates whether the value is a known member of the ProcessStreamEventStream enum. -func (e ProcessStreamEventStream) Valid() bool { +// Valid indicates whether the value is a known member of the BrowserPageLayoutSettledEventType enum. +func (e BrowserPageLayoutSettledEventType) Valid() bool { switch e { - case Stderr: - return true - case Stdout: + case PageLayoutSettled: return true default: return false } } -// Defines values for PublishEventRequestCategory. +// Defines values for BrowserPageLayoutShiftEventCategory. const ( - PublishEventRequestCategoryCaptcha PublishEventRequestCategory = "captcha" - PublishEventRequestCategoryConnection PublishEventRequestCategory = "connection" - PublishEventRequestCategoryConsole PublishEventRequestCategory = "console" - PublishEventRequestCategoryControl PublishEventRequestCategory = "control" - PublishEventRequestCategoryInteraction PublishEventRequestCategory = "interaction" - PublishEventRequestCategoryMonitor PublishEventRequestCategory = "monitor" - PublishEventRequestCategoryNetwork PublishEventRequestCategory = "network" - PublishEventRequestCategoryPage PublishEventRequestCategory = "page" - PublishEventRequestCategoryPlatform PublishEventRequestCategory = "platform" - PublishEventRequestCategoryScreenshot PublishEventRequestCategory = "screenshot" - PublishEventRequestCategorySystem PublishEventRequestCategory = "system" + BrowserPageLayoutShiftEventCategoryPage BrowserPageLayoutShiftEventCategory = "page" ) -// Valid indicates whether the value is a known member of the PublishEventRequestCategory enum. -func (e PublishEventRequestCategory) Valid() bool { +// Valid indicates whether the value is a known member of the BrowserPageLayoutShiftEventCategory enum. +func (e BrowserPageLayoutShiftEventCategory) Valid() bool { switch e { - case PublishEventRequestCategoryCaptcha: - return true - case PublishEventRequestCategoryConnection: - return true - case PublishEventRequestCategoryConsole: - return true - case PublishEventRequestCategoryControl: - return true - case PublishEventRequestCategoryInteraction: - return true - case PublishEventRequestCategoryMonitor: - return true - case PublishEventRequestCategoryNetwork: - return true - case PublishEventRequestCategoryPage: - return true - case PublishEventRequestCategoryPlatform: - return true - case PublishEventRequestCategoryScreenshot: - return true - case PublishEventRequestCategorySystem: + case BrowserPageLayoutShiftEventCategoryPage: return true default: return false } } -// Defines values for TelemetryEventCategory. +// Defines values for BrowserPageLayoutShiftEventType. const ( - TelemetryEventCategoryCaptcha TelemetryEventCategory = "captcha" - TelemetryEventCategoryConnection TelemetryEventCategory = "connection" - TelemetryEventCategoryConsole TelemetryEventCategory = "console" - TelemetryEventCategoryControl TelemetryEventCategory = "control" - TelemetryEventCategoryInteraction TelemetryEventCategory = "interaction" - TelemetryEventCategoryMonitor TelemetryEventCategory = "monitor" - TelemetryEventCategoryNetwork TelemetryEventCategory = "network" - TelemetryEventCategoryPage TelemetryEventCategory = "page" - TelemetryEventCategoryPlatform TelemetryEventCategory = "platform" - TelemetryEventCategoryScreenshot TelemetryEventCategory = "screenshot" - TelemetryEventCategorySystem TelemetryEventCategory = "system" + PageLayoutShift BrowserPageLayoutShiftEventType = "page_layout_shift" ) -// Valid indicates whether the value is a known member of the TelemetryEventCategory enum. -func (e TelemetryEventCategory) Valid() bool { +// Valid indicates whether the value is a known member of the BrowserPageLayoutShiftEventType enum. +func (e BrowserPageLayoutShiftEventType) Valid() bool { switch e { - case TelemetryEventCategoryCaptcha: - return true - case TelemetryEventCategoryConnection: - return true - case TelemetryEventCategoryConsole: - return true - case TelemetryEventCategoryControl: - return true - case TelemetryEventCategoryInteraction: - return true - case TelemetryEventCategoryMonitor: - return true - case TelemetryEventCategoryNetwork: - return true - case TelemetryEventCategoryPage: - return true - case TelemetryEventCategoryPlatform: - return true - case TelemetryEventCategoryScreenshot: - return true - case TelemetryEventCategorySystem: + case PageLayoutShift: return true default: return false } } -// Defines values for DownloadDirZstdParamsCompressionLevel. +// Defines values for BrowserPageLcpEventCategory. const ( - Best DownloadDirZstdParamsCompressionLevel = "best" - Better DownloadDirZstdParamsCompressionLevel = "better" - Default DownloadDirZstdParamsCompressionLevel = "default" - Fastest DownloadDirZstdParamsCompressionLevel = "fastest" + BrowserPageLcpEventCategoryPage BrowserPageLcpEventCategory = "page" ) -// Valid indicates whether the value is a known member of the DownloadDirZstdParamsCompressionLevel enum. -func (e DownloadDirZstdParamsCompressionLevel) Valid() bool { +// Valid indicates whether the value is a known member of the BrowserPageLcpEventCategory enum. +func (e BrowserPageLcpEventCategory) Valid() bool { switch e { - case Best: - return true - case Better: - return true - case Default: - return true - case Fastest: + case BrowserPageLcpEventCategoryPage: return true default: return false } } -// Defines values for LogsStreamParamsSource. +// Defines values for BrowserPageLcpEventType. const ( - Path LogsStreamParamsSource = "path" - Supervisor LogsStreamParamsSource = "supervisor" + PageLcp BrowserPageLcpEventType = "page_lcp" ) -// Valid indicates whether the value is a known member of the LogsStreamParamsSource enum. -func (e LogsStreamParamsSource) Valid() bool { +// Valid indicates whether the value is a known member of the BrowserPageLcpEventType enum. +func (e BrowserPageLcpEventType) Valid() bool { switch e { - case Path: - return true - case Supervisor: + case PageLcp: return true default: return false } } -// Defines values for StreamTelemetryEventsParamsReplay. +// Defines values for BrowserPageLoadEventCategory. const ( - All StreamTelemetryEventsParamsReplay = "all" + BrowserPageLoadEventCategoryPage BrowserPageLoadEventCategory = "page" ) -// Valid indicates whether the value is a known member of the StreamTelemetryEventsParamsReplay enum. -func (e StreamTelemetryEventsParamsReplay) Valid() bool { +// Valid indicates whether the value is a known member of the BrowserPageLoadEventCategory enum. +func (e BrowserPageLoadEventCategory) Valid() bool { switch e { - case All: + case BrowserPageLoadEventCategoryPage: return true default: return false } } -// BatchComputerActionRequest A batch of computer actions to execute sequentially. -type BatchComputerActionRequest struct { - // Actions Ordered list of actions to execute. Execution stops on the first error. - Actions []ComputerAction `json:"actions"` -} +// Defines values for BrowserPageLoadEventType. +const ( + PageLoad BrowserPageLoadEventType = "page_load" +) -// BrowserApiCallEvent A call that drives the browser, handled by the kernel-images-api server: computer-control actions, Playwright code execution, screenshots and clipboard access. Calls that manage the VM instead emit `platform_api_call`. -type BrowserApiCallEvent struct { - Category BrowserApiCallEventCategory `json:"category"` +// Valid indicates whether the value is a known member of the BrowserPageLoadEventType enum. +func (e BrowserPageLoadEventType) Valid() bool { + switch e { + case PageLoad: + return true + default: + return false + } +} - // Data Per-call payload for `api_call` events. - Data *BrowserApiCallEventData `json:"data,omitempty"` +// Defines values for BrowserPageNavigationEventCategory. +const ( + BrowserPageNavigationEventCategoryPage BrowserPageNavigationEventCategory = "page" +) - // Source Provenance metadata identifying which producer emitted the event. - Source BrowserEventSource `json:"source"` +// Valid indicates whether the value is a known member of the BrowserPageNavigationEventCategory enum. +func (e BrowserPageNavigationEventCategory) Valid() bool { + switch e { + case BrowserPageNavigationEventCategoryPage: + return true + default: + return false + } +} - // Truncated True if the data field was truncated due to size limits. - Truncated *bool `json:"truncated,omitempty"` +// Defines values for BrowserPageNavigationEventType. +const ( + PageNavigation BrowserPageNavigationEventType = "page_navigation" +) - // Ts Event timestamp in Unix microseconds. - Ts int64 `json:"ts"` - Type BrowserApiCallEventType `json:"type"` +// Valid indicates whether the value is a known member of the BrowserPageNavigationEventType enum. +func (e BrowserPageNavigationEventType) Valid() bool { + switch e { + case PageNavigation: + return true + default: + return false + } } -// BrowserApiCallEventCategory defines model for BrowserApiCallEvent.Category. -type BrowserApiCallEventCategory string - -// BrowserApiCallEventType defines model for BrowserApiCallEvent.Type. -type BrowserApiCallEventType string +// Defines values for BrowserPageNavigationSettledEventCategory. +const ( + BrowserPageNavigationSettledEventCategoryPage BrowserPageNavigationSettledEventCategory = "page" +) -// BrowserApiCallEventData Per-call payload for `api_call` events. -type BrowserApiCallEventData struct { - // Code Source submitted to `executePlaywrightCode`, capped at 8192 bytes like every other captured string. A capped value is cut on a character boundary and ends in `...[truncated]`. Absent for every other operation. - Code *string `json:"code,omitempty"` +// Valid indicates whether the value is a known member of the BrowserPageNavigationSettledEventCategory enum. +func (e BrowserPageNavigationSettledEventCategory) Valid() bool { + switch e { + case BrowserPageNavigationSettledEventCategoryPage: + return true + default: + return false + } +} + +// Defines values for BrowserPageNavigationSettledEventType. +const ( + PageNavigationSettled BrowserPageNavigationSettledEventType = "page_navigation_settled" +) + +// Valid indicates whether the value is a known member of the BrowserPageNavigationSettledEventType enum. +func (e BrowserPageNavigationSettledEventType) Valid() bool { + switch e { + case PageNavigationSettled: + return true + default: + return false + } +} + +// Defines values for BrowserPageTabOpenedEventCategory. +const ( + Page BrowserPageTabOpenedEventCategory = "page" +) + +// Valid indicates whether the value is a known member of the BrowserPageTabOpenedEventCategory enum. +func (e BrowserPageTabOpenedEventCategory) Valid() bool { + switch e { + case Page: + return true + default: + return false + } +} + +// Defines values for BrowserPageTabOpenedEventType. +const ( + PageTabOpened BrowserPageTabOpenedEventType = "page_tab_opened" +) + +// Valid indicates whether the value is a known member of the BrowserPageTabOpenedEventType enum. +func (e BrowserPageTabOpenedEventType) Valid() bool { + switch e { + case PageTabOpened: + return true + default: + return false + } +} + +// Defines values for BrowserPlatformApiCallEventCategory. +const ( + Platform BrowserPlatformApiCallEventCategory = "platform" +) + +// Valid indicates whether the value is a known member of the BrowserPlatformApiCallEventCategory enum. +func (e BrowserPlatformApiCallEventCategory) Valid() bool { + switch e { + case Platform: + return true + default: + return false + } +} + +// Defines values for BrowserPlatformApiCallEventType. +const ( + PlatformApiCall BrowserPlatformApiCallEventType = "platform_api_call" +) + +// Valid indicates whether the value is a known member of the BrowserPlatformApiCallEventType enum. +func (e BrowserPlatformApiCallEventType) Valid() bool { + switch e { + case PlatformApiCall: + return true + default: + return false + } +} + +// Defines values for BrowserServiceCrashedEventCategory. +const ( + BrowserServiceCrashedEventCategorySystem BrowserServiceCrashedEventCategory = "system" +) + +// Valid indicates whether the value is a known member of the BrowserServiceCrashedEventCategory enum. +func (e BrowserServiceCrashedEventCategory) Valid() bool { + switch e { + case BrowserServiceCrashedEventCategorySystem: + return true + default: + return false + } +} + +// Defines values for BrowserServiceCrashedEventType. +const ( + ServiceCrashed BrowserServiceCrashedEventType = "service_crashed" +) + +// Valid indicates whether the value is a known member of the BrowserServiceCrashedEventType enum. +func (e BrowserServiceCrashedEventType) Valid() bool { + switch e { + case ServiceCrashed: + return true + default: + return false + } +} + +// Defines values for BrowserServiceCrashedEventDataPhase. +const ( + BrowserServiceCrashedEventDataPhaseGaveUp BrowserServiceCrashedEventDataPhase = "gave_up" + BrowserServiceCrashedEventDataPhaseRunning BrowserServiceCrashedEventDataPhase = "running" + BrowserServiceCrashedEventDataPhaseStartup BrowserServiceCrashedEventDataPhase = "startup" +) + +// Valid indicates whether the value is a known member of the BrowserServiceCrashedEventDataPhase enum. +func (e BrowserServiceCrashedEventDataPhase) Valid() bool { + switch e { + case BrowserServiceCrashedEventDataPhaseGaveUp: + return true + case BrowserServiceCrashedEventDataPhaseRunning: + return true + case BrowserServiceCrashedEventDataPhaseStartup: + return true + default: + return false + } +} + +// Defines values for BrowserSystemOomKillEventCategory. +const ( + BrowserSystemOomKillEventCategorySystem BrowserSystemOomKillEventCategory = "system" +) + +// Valid indicates whether the value is a known member of the BrowserSystemOomKillEventCategory enum. +func (e BrowserSystemOomKillEventCategory) Valid() bool { + switch e { + case BrowserSystemOomKillEventCategorySystem: + return true + default: + return false + } +} + +// Defines values for BrowserSystemOomKillEventType. +const ( + SystemOomKill BrowserSystemOomKillEventType = "system_oom_kill" +) + +// Valid indicates whether the value is a known member of the BrowserSystemOomKillEventType enum. +func (e BrowserSystemOomKillEventType) Valid() bool { + switch e { + case SystemOomKill: + return true + default: + return false + } +} + +// Defines values for BrowserSystemOomKillEventDataConstraint. +const ( + Cpuset BrowserSystemOomKillEventDataConstraint = "cpuset" + Memcg BrowserSystemOomKillEventDataConstraint = "memcg" + MemoryPolicy BrowserSystemOomKillEventDataConstraint = "memory_policy" + None BrowserSystemOomKillEventDataConstraint = "none" +) + +// Valid indicates whether the value is a known member of the BrowserSystemOomKillEventDataConstraint enum. +func (e BrowserSystemOomKillEventDataConstraint) Valid() bool { + switch e { + case Cpuset: + return true + case Memcg: + return true + case MemoryPolicy: + return true + case None: + return true + default: + return false + } +} + +// Defines values for BrowserTargetType. +const ( + BrowserTargetTypeBackgroundPage BrowserTargetType = "background_page" + BrowserTargetTypeOther BrowserTargetType = "other" + BrowserTargetTypePage BrowserTargetType = "page" + BrowserTargetTypeServiceWorker BrowserTargetType = "service_worker" + BrowserTargetTypeSharedWorker BrowserTargetType = "shared_worker" +) + +// Valid indicates whether the value is a known member of the BrowserTargetType enum. +func (e BrowserTargetType) Valid() bool { + switch e { + case BrowserTargetTypeBackgroundPage: + return true + case BrowserTargetTypeOther: + return true + case BrowserTargetTypePage: + return true + case BrowserTargetTypeServiceWorker: + return true + case BrowserTargetTypeSharedWorker: + return true + default: + return false + } +} + +// Defines values for ChromiumConfigureErrorPhase. +const ( + ConfigurePhase ChromiumConfigureErrorPhase = "configure_phase" + NavigatePhase ChromiumConfigureErrorPhase = "navigate_phase" +) + +// Valid indicates whether the value is a known member of the ChromiumConfigureErrorPhase enum. +func (e ChromiumConfigureErrorPhase) Valid() bool { + switch e { + case ConfigurePhase: + return true + case NavigatePhase: + return true + default: + return false + } +} + +// Defines values for ChromiumConfigureErrorStep. +const ( + ChromePolicies ChromiumConfigureErrorStep = "chrome_policies" + ChromiumFlags ChromiumConfigureErrorStep = "chromium_flags" + Display ChromiumConfigureErrorStep = "display" + Extensions ChromiumConfigureErrorStep = "extensions" + Profile ChromiumConfigureErrorStep = "profile" + StartChromium ChromiumConfigureErrorStep = "start_chromium" + StopChromium ChromiumConfigureErrorStep = "stop_chromium" +) + +// Valid indicates whether the value is a known member of the ChromiumConfigureErrorStep enum. +func (e ChromiumConfigureErrorStep) Valid() bool { + switch e { + case ChromePolicies: + return true + case ChromiumFlags: + return true + case Display: + return true + case Extensions: + return true + case Profile: + return true + case StartChromium: + return true + case StopChromium: + return true + default: + return false + } +} + +// Defines values for ClickMouseRequestButton. +const ( + ClickMouseRequestButtonBack ClickMouseRequestButton = "back" + ClickMouseRequestButtonForward ClickMouseRequestButton = "forward" + ClickMouseRequestButtonLeft ClickMouseRequestButton = "left" + ClickMouseRequestButtonMiddle ClickMouseRequestButton = "middle" + ClickMouseRequestButtonRight ClickMouseRequestButton = "right" +) + +// Valid indicates whether the value is a known member of the ClickMouseRequestButton enum. +func (e ClickMouseRequestButton) Valid() bool { + switch e { + case ClickMouseRequestButtonBack: + return true + case ClickMouseRequestButtonForward: + return true + case ClickMouseRequestButtonLeft: + return true + case ClickMouseRequestButtonMiddle: + return true + case ClickMouseRequestButtonRight: + return true + default: + return false + } +} + +// Defines values for ClickMouseRequestClickType. +const ( + Click ClickMouseRequestClickType = "click" + Down ClickMouseRequestClickType = "down" + Up ClickMouseRequestClickType = "up" +) + +// Valid indicates whether the value is a known member of the ClickMouseRequestClickType enum. +func (e ClickMouseRequestClickType) Valid() bool { + switch e { + case Click: + return true + case Down: + return true + case Up: + return true + default: + return false + } +} + +// Defines values for ComputerActionType. +const ( + ClickMouse ComputerActionType = "click_mouse" + DragMouse ComputerActionType = "drag_mouse" + MoveMouse ComputerActionType = "move_mouse" + PressKey ComputerActionType = "press_key" + Scroll ComputerActionType = "scroll" + SetCursor ComputerActionType = "set_cursor" + Sleep ComputerActionType = "sleep" + TypeText ComputerActionType = "type_text" +) + +// Valid indicates whether the value is a known member of the ComputerActionType enum. +func (e ComputerActionType) Valid() bool { + switch e { + case ClickMouse: + return true + case DragMouse: + return true + case MoveMouse: + return true + case PressKey: + return true + case Scroll: + return true + case SetCursor: + return true + case Sleep: + return true + case TypeText: + return true + default: + return false + } +} + +// Defines values for DragMouseRequestButton. +const ( + DragMouseRequestButtonLeft DragMouseRequestButton = "left" + DragMouseRequestButtonMiddle DragMouseRequestButton = "middle" + DragMouseRequestButtonRight DragMouseRequestButton = "right" +) + +// Valid indicates whether the value is a known member of the DragMouseRequestButton enum. +func (e DragMouseRequestButton) Valid() bool { + switch e { + case DragMouseRequestButtonLeft: + return true + case DragMouseRequestButtonMiddle: + return true + case DragMouseRequestButtonRight: + return true + default: + return false + } +} + +// Defines values for FileSystemEventType. +const ( + CREATE FileSystemEventType = "CREATE" + DELETE FileSystemEventType = "DELETE" + RENAME FileSystemEventType = "RENAME" + WRITE FileSystemEventType = "WRITE" +) + +// Valid indicates whether the value is a known member of the FileSystemEventType enum. +func (e FileSystemEventType) Valid() bool { + switch e { + case CREATE: + return true + case DELETE: + return true + case RENAME: + return true + case WRITE: + return true + default: + return false + } +} + +// Defines values for PatchDisplayRequestRefreshRate. +const ( + N10 PatchDisplayRequestRefreshRate = 10 + N25 PatchDisplayRequestRefreshRate = 25 + N30 PatchDisplayRequestRefreshRate = 30 + N60 PatchDisplayRequestRefreshRate = 60 +) + +// Valid indicates whether the value is a known member of the PatchDisplayRequestRefreshRate enum. +func (e PatchDisplayRequestRefreshRate) Valid() bool { + switch e { + case N10: + return true + case N25: + return true + case N30: + return true + case N60: + return true + default: + return false + } +} + +// Defines values for ProcessKillRequestSignal. +const ( + HUP ProcessKillRequestSignal = "HUP" + INT ProcessKillRequestSignal = "INT" + KILL ProcessKillRequestSignal = "KILL" + TERM ProcessKillRequestSignal = "TERM" +) + +// Valid indicates whether the value is a known member of the ProcessKillRequestSignal enum. +func (e ProcessKillRequestSignal) Valid() bool { + switch e { + case HUP: + return true + case INT: + return true + case KILL: + return true + case TERM: + return true + default: + return false + } +} + +// Defines values for ProcessStatusState. +const ( + ProcessStatusStateExited ProcessStatusState = "exited" + ProcessStatusStateRunning ProcessStatusState = "running" +) + +// Valid indicates whether the value is a known member of the ProcessStatusState enum. +func (e ProcessStatusState) Valid() bool { + switch e { + case ProcessStatusStateExited: + return true + case ProcessStatusStateRunning: + return true + default: + return false + } +} + +// Defines values for ProcessStreamEventEvent. +const ( + Exit ProcessStreamEventEvent = "exit" +) + +// Valid indicates whether the value is a known member of the ProcessStreamEventEvent enum. +func (e ProcessStreamEventEvent) Valid() bool { + switch e { + case Exit: + return true + default: + return false + } +} + +// Defines values for ProcessStreamEventStream. +const ( + Stderr ProcessStreamEventStream = "stderr" + Stdout ProcessStreamEventStream = "stdout" +) + +// Valid indicates whether the value is a known member of the ProcessStreamEventStream enum. +func (e ProcessStreamEventStream) Valid() bool { + switch e { + case Stderr: + return true + case Stdout: + return true + default: + return false + } +} + +// Defines values for PublishEventRequestCategory. +const ( + PublishEventRequestCategoryCaptcha PublishEventRequestCategory = "captcha" + PublishEventRequestCategoryConnection PublishEventRequestCategory = "connection" + PublishEventRequestCategoryConsole PublishEventRequestCategory = "console" + PublishEventRequestCategoryControl PublishEventRequestCategory = "control" + PublishEventRequestCategoryInteraction PublishEventRequestCategory = "interaction" + PublishEventRequestCategoryMonitor PublishEventRequestCategory = "monitor" + PublishEventRequestCategoryNetwork PublishEventRequestCategory = "network" + PublishEventRequestCategoryPage PublishEventRequestCategory = "page" + PublishEventRequestCategoryPlatform PublishEventRequestCategory = "platform" + PublishEventRequestCategoryScreenshot PublishEventRequestCategory = "screenshot" + PublishEventRequestCategorySystem PublishEventRequestCategory = "system" +) + +// Valid indicates whether the value is a known member of the PublishEventRequestCategory enum. +func (e PublishEventRequestCategory) Valid() bool { + switch e { + case PublishEventRequestCategoryCaptcha: + return true + case PublishEventRequestCategoryConnection: + return true + case PublishEventRequestCategoryConsole: + return true + case PublishEventRequestCategoryControl: + return true + case PublishEventRequestCategoryInteraction: + return true + case PublishEventRequestCategoryMonitor: + return true + case PublishEventRequestCategoryNetwork: + return true + case PublishEventRequestCategoryPage: + return true + case PublishEventRequestCategoryPlatform: + return true + case PublishEventRequestCategoryScreenshot: + return true + case PublishEventRequestCategorySystem: + return true + default: + return false + } +} + +// Defines values for TelemetryEventCategory. +const ( + TelemetryEventCategoryCaptcha TelemetryEventCategory = "captcha" + TelemetryEventCategoryConnection TelemetryEventCategory = "connection" + TelemetryEventCategoryConsole TelemetryEventCategory = "console" + TelemetryEventCategoryControl TelemetryEventCategory = "control" + TelemetryEventCategoryInteraction TelemetryEventCategory = "interaction" + TelemetryEventCategoryMonitor TelemetryEventCategory = "monitor" + TelemetryEventCategoryNetwork TelemetryEventCategory = "network" + TelemetryEventCategoryPage TelemetryEventCategory = "page" + TelemetryEventCategoryPlatform TelemetryEventCategory = "platform" + TelemetryEventCategoryScreenshot TelemetryEventCategory = "screenshot" + TelemetryEventCategorySystem TelemetryEventCategory = "system" +) + +// Valid indicates whether the value is a known member of the TelemetryEventCategory enum. +func (e TelemetryEventCategory) Valid() bool { + switch e { + case TelemetryEventCategoryCaptcha: + return true + case TelemetryEventCategoryConnection: + return true + case TelemetryEventCategoryConsole: + return true + case TelemetryEventCategoryControl: + return true + case TelemetryEventCategoryInteraction: + return true + case TelemetryEventCategoryMonitor: + return true + case TelemetryEventCategoryNetwork: + return true + case TelemetryEventCategoryPage: + return true + case TelemetryEventCategoryPlatform: + return true + case TelemetryEventCategoryScreenshot: + return true + case TelemetryEventCategorySystem: + return true + default: + return false + } +} + +// Defines values for DownloadDirZstdParamsCompressionLevel. +const ( + Best DownloadDirZstdParamsCompressionLevel = "best" + Better DownloadDirZstdParamsCompressionLevel = "better" + Default DownloadDirZstdParamsCompressionLevel = "default" + Fastest DownloadDirZstdParamsCompressionLevel = "fastest" +) + +// Valid indicates whether the value is a known member of the DownloadDirZstdParamsCompressionLevel enum. +func (e DownloadDirZstdParamsCompressionLevel) Valid() bool { + switch e { + case Best: + return true + case Better: + return true + case Default: + return true + case Fastest: + return true + default: + return false + } +} + +// Defines values for LogsStreamParamsSource. +const ( + Path LogsStreamParamsSource = "path" + Supervisor LogsStreamParamsSource = "supervisor" +) + +// Valid indicates whether the value is a known member of the LogsStreamParamsSource enum. +func (e LogsStreamParamsSource) Valid() bool { + switch e { + case Path: + return true + case Supervisor: + return true + default: + return false + } +} + +// Defines values for StreamTelemetryEventsParamsReplay. +const ( + All StreamTelemetryEventsParamsReplay = "all" +) + +// Valid indicates whether the value is a known member of the StreamTelemetryEventsParamsReplay enum. +func (e StreamTelemetryEventsParamsReplay) Valid() bool { + switch e { + case All: + return true + default: + return false + } +} + +// BatchComputerActionRequest A batch of computer actions to execute sequentially. +type BatchComputerActionRequest struct { + // Actions Ordered list of actions to execute. Execution stops on the first error. + Actions []ComputerAction `json:"actions"` +} + +// BrowserApiCallEvent A call that drives the browser, handled by the kernel-images-api server: computer-control actions, Playwright code execution, screenshots and clipboard access. Calls that manage the VM instead emit `platform_api_call`. +type BrowserApiCallEvent struct { + Category BrowserApiCallEventCategory `json:"category"` + + // Data Per-call payload for `api_call` events. + Data *BrowserApiCallEventData `json:"data,omitempty"` + + // Source Provenance metadata identifying which producer emitted the event. + Source BrowserEventSource `json:"source"` + + // Truncated True if the data field was truncated due to size limits. + Truncated *bool `json:"truncated,omitempty"` + + // Ts Event timestamp in Unix microseconds. + Ts int64 `json:"ts"` + Type BrowserApiCallEventType `json:"type"` +} + +// BrowserApiCallEventCategory defines model for BrowserApiCallEvent.Category. +type BrowserApiCallEventCategory string + +// BrowserApiCallEventType defines model for BrowserApiCallEvent.Type. +type BrowserApiCallEventType string + +// BrowserApiCallEventData Per-call payload for `api_call` events. +type BrowserApiCallEventData struct { + // Code Source submitted to `executePlaywrightCode`, capped at 8192 bytes like every other captured string. A capped value is cut on a character boundary and ends in `...[truncated]`. Absent for every other operation. + Code *string `json:"code,omitempty"` + + // DurationMs Wall-clock duration of the handler in milliseconds. + DurationMs float32 `json:"duration_ms"` + + // OperationId Matched route's operation, named as the server names its handler (e.g. `TakeScreenshot`, `ExecutePlaywrightCode`). + OperationId string `json:"operation_id"` + + // RequestId Per-request identifier from the kernel-images-api request middleware. + RequestId string `json:"request_id"` + + // Status HTTP response status code. + Status int `json:"status"` +} + +// BrowserCallStack CDP Runtime.StackTrace representing the JavaScript call stack at the time of an event. Fields use CDP naming conventions rather than snake_case to match the Chrome DevTools Protocol wire format. +type BrowserCallStack struct { + // CallFrames Ordered list of call frames, outermost first. + CallFrames []struct { + // ColumnNumber Zero-based column number within the line. + ColumnNumber int `json:"columnNumber"` + + // FunctionName JavaScript function name, or empty string for anonymous functions. + FunctionName string `json:"functionName"` + + // LineNumber Zero-based line number within the script. + LineNumber int `json:"lineNumber"` + + // ScriptId CDP script identifier. + ScriptId string `json:"scriptId"` + + // Url URL or name of the script file. + Url string `json:"url"` + } `json:"callFrames"` + + // Description Optional label for the stack trace (e.g. async cause). + Description *string `json:"description,omitempty"` + + // Parent Parent stack trace for async stacks. + Parent *BrowserCallStack `json:"parent,omitempty"` +} + +// BrowserCaptchaSolveResultEvent A captcha solve attempt reached a terminal outcome. +type BrowserCaptchaSolveResultEvent struct { + Category BrowserCaptchaSolveResultEventCategory `json:"category"` + + // Data Per-attempt payload for `captcha_solve_result` events. + Data *BrowserCaptchaSolveResultEventData `json:"data,omitempty"` + + // Source Provenance metadata identifying which producer emitted the event. + Source BrowserEventSource `json:"source"` + + // Truncated True if the data field was truncated due to size limits. + Truncated *bool `json:"truncated,omitempty"` + + // Ts Event timestamp in Unix microseconds. + Ts int64 `json:"ts"` + Type BrowserCaptchaSolveResultEventType `json:"type"` +} + +// BrowserCaptchaSolveResultEventCategory defines model for BrowserCaptchaSolveResultEvent.Category. +type BrowserCaptchaSolveResultEventCategory string + +// BrowserCaptchaSolveResultEventType defines model for BrowserCaptchaSolveResultEvent.Type. +type BrowserCaptchaSolveResultEventType string + +// BrowserCaptchaSolveResultEventData Per-attempt payload for `captcha_solve_result` events. +type BrowserCaptchaSolveResultEventData struct { + // CaptchaType Captcha vendor family. Producers normalize provider-specific task names into this set: enterprise variants of recaptcha collapse into their version bucket (v2 / v3), and anything not covered (e.g. DataDome, MtCaptcha, plain OCR) is reported as `other`. + CaptchaType BrowserCaptchaSolveResultEventDataCaptchaType `json:"captcha_type"` + + // DurationMs Wall-clock duration from solve start to terminal outcome. + DurationMs float32 `json:"duration_ms"` + + // ErrorCode Solver-specific error code on failure (e.g. `ERROR_CAPTCHA_UNSOLVABLE`). Absent on success. + ErrorCode *string `json:"error_code,omitempty"` + + // Status Terminal outcome. `success`: solver returned a usable solution. `failure`: solver returned an error (see `error_code`). `timeout`: solver did not return within the caller's wait budget. `abandoned`: caller cancelled or the page navigated away mid-solve. + Status BrowserCaptchaSolveResultEventDataStatus `json:"status"` + + // TaskId Solver-assigned identifier. Opaque, useful for support cross-references. + TaskId *string `json:"task_id,omitempty"` + + // WebsiteHost Host of the page where the captcha was solved. + WebsiteHost *string `json:"website_host,omitempty"` + + // WebsitePath Path of the page where the captcha was solved. Query string excluded. + WebsitePath *string `json:"website_path,omitempty"` +} + +// BrowserCaptchaSolveResultEventDataCaptchaType Captcha vendor family. Producers normalize provider-specific task names into this set: enterprise variants of recaptcha collapse into their version bucket (v2 / v3), and anything not covered (e.g. DataDome, MtCaptcha, plain OCR) is reported as `other`. +type BrowserCaptchaSolveResultEventDataCaptchaType string + +// BrowserCaptchaSolveResultEventDataStatus Terminal outcome. `success`: solver returned a usable solution. `failure`: solver returned an error (see `error_code`). `timeout`: solver did not return within the caller's wait budget. `abandoned`: caller cancelled or the page navigated away mid-solve. +type BrowserCaptchaSolveResultEventDataStatus string + +// BrowserCdpAutofillTriggerCommandData Sanitized `Autofill.trigger` arguments. Canonical input: devtools-protocol@2d019e73 `Autofill.trigger`. +type BrowserCdpAutofillTriggerCommandData struct { + // FieldId Opaque backend node identifier of the field that was autofilled. + FieldId int `json:"field_id"` + + // FrameId Opaque frame identifier. + FrameId *string `json:"frame_id,omitempty"` + Method BrowserCdpAutofillTriggerCommandDataMethod `json:"method"` + + // Mode What was filled: `card` or `address`. The values themselves are never captured. + Mode *string `json:"mode,omitempty"` + + // SessionId CDP session identifier the command was addressed to. Absent for browser-level commands. + SessionId *string `json:"session_id,omitempty"` +} + +// BrowserCdpAutofillTriggerCommandDataMethod defines model for BrowserCdpAutofillTriggerCommandData.Method. +type BrowserCdpAutofillTriggerCommandDataMethod string + +// BrowserCdpBrowserCancelDownloadCommandData Sanitized `Browser.cancelDownload` arguments. Canonical input: devtools-protocol@2d019e73 `Browser.cancelDownload`. +type BrowserCdpBrowserCancelDownloadCommandData struct { + // BrowserContextId Opaque browser context identifier. + BrowserContextId *string `json:"browser_context_id,omitempty"` + + // DownloadGuid Opaque identifier of the download that was cancelled. + DownloadGuid string `json:"download_guid"` + Method BrowserCdpBrowserCancelDownloadCommandDataMethod `json:"method"` + + // SessionId CDP session identifier the command was addressed to. Absent for browser-level commands. + SessionId *string `json:"session_id,omitempty"` +} + +// BrowserCdpBrowserCancelDownloadCommandDataMethod defines model for BrowserCdpBrowserCancelDownloadCommandData.Method. +type BrowserCdpBrowserCancelDownloadCommandDataMethod string + +// BrowserCdpBrowserCloseCommandData Sanitized `Browser.close` arguments. Canonical input: devtools-protocol@2d019e73 `Browser.close`. +type BrowserCdpBrowserCloseCommandData struct { + Method BrowserCdpBrowserCloseCommandDataMethod `json:"method"` + + // SessionId CDP session identifier the command was addressed to. Absent for browser-level commands. + SessionId *string `json:"session_id,omitempty"` +} + +// BrowserCdpBrowserCloseCommandDataMethod defines model for BrowserCdpBrowserCloseCommandData.Method. +type BrowserCdpBrowserCloseCommandDataMethod string + +// BrowserCdpBrowserSetContentsSizeCommandData Sanitized `Browser.setContentsSize` arguments. Canonical input: devtools-protocol@2d019e73 `Browser.setContentsSize`. +type BrowserCdpBrowserSetContentsSizeCommandData struct { + // Height Contents height in DIP. + Height *int `json:"height,omitempty"` + Method BrowserCdpBrowserSetContentsSizeCommandDataMethod `json:"method"` + + // SessionId CDP session identifier the command was addressed to. Absent for browser-level commands. + SessionId *string `json:"session_id,omitempty"` + + // Width Contents width in DIP. + Width *int `json:"width,omitempty"` + + // WindowId Browser window identifier. + WindowId int `json:"window_id"` +} + +// BrowserCdpBrowserSetContentsSizeCommandDataMethod defines model for BrowserCdpBrowserSetContentsSizeCommandData.Method. +type BrowserCdpBrowserSetContentsSizeCommandDataMethod string + +// BrowserCdpBrowserSetWindowBoundsCommandData Sanitized `Browser.setWindowBounds` arguments. Canonical input: devtools-protocol@2d019e73 `Browser.setWindowBounds`. +type BrowserCdpBrowserSetWindowBoundsCommandData struct { + // Height Window height in DIP. + Height *int `json:"height,omitempty"` + + // Left Window x position in screen coordinates. + Left *int `json:"left,omitempty"` + Method BrowserCdpBrowserSetWindowBoundsCommandDataMethod `json:"method"` + + // SessionId CDP session identifier the command was addressed to. Absent for browser-level commands. + SessionId *string `json:"session_id,omitempty"` + + // Top Window y position in screen coordinates. + Top *int `json:"top,omitempty"` + + // Width Window width in DIP. + Width *int `json:"width,omitempty"` + + // WindowId Browser window identifier. + WindowId int `json:"window_id"` + + // WindowState Window state requested (`normal`, `minimized`, `maximized`, `fullscreen`). + WindowState *string `json:"window_state,omitempty"` +} + +// BrowserCdpBrowserSetWindowBoundsCommandDataMethod defines model for BrowserCdpBrowserSetWindowBoundsCommandData.Method. +type BrowserCdpBrowserSetWindowBoundsCommandDataMethod string + +// BrowserCdpCommandEvent A browser-control command a client sent over the CDP WebSocket proxy: input gestures, navigation, dialog handling, file selection and screenshots. Configuration commands and the DOM/Runtime traffic a client library issues on the caller's behalf are not reported. +// One event per browser-control command that reached the browser. The command stream is not sampled, coalesced or reordered. An event is lost only when the method is excluded by telemetry configuration, when or when classification cannot keep up; those losses are counted in `cdp_disconnect.telemetry_dropped`. +type BrowserCdpCommandEvent struct { + Category BrowserCdpCommandEventCategory `json:"category"` + + // Data Per-command payload for `cdp_command` events, discriminated by `method`. Each variant carries only the arguments approved for that command: values that could hold a secret — typed and composition text, URLs, referrers, scripts, templates, file paths, drag contents and autofill values — are replaced by a length, a count, a presence flag, an enum or a URL scheme and host. + Data BrowserCdpCommandEventData `json:"data"` + + // Source Provenance metadata identifying which producer emitted the event. + Source BrowserEventSource `json:"source"` + + // Truncated True if the data field was truncated due to size limits. + Truncated *bool `json:"truncated,omitempty"` + + // Ts Event timestamp in Unix microseconds. + Ts int64 `json:"ts"` + Type BrowserCdpCommandEventType `json:"type"` +} + +// BrowserCdpCommandEventCategory defines model for BrowserCdpCommandEvent.Category. +type BrowserCdpCommandEventCategory string + +// BrowserCdpCommandEventType defines model for BrowserCdpCommandEvent.Type. +type BrowserCdpCommandEventType string + +// BrowserCdpCommandEventData Per-command payload for `cdp_command` events, discriminated by `method`. Each variant carries only the arguments approved for that command: values that could hold a secret — typed and composition text, URLs, referrers, scripts, templates, file paths, drag contents and autofill values — are replaced by a length, a count, a presence flag, an enum or a URL scheme and host. +type BrowserCdpCommandEventData struct { + union json.RawMessage +} + +// BrowserCdpCommandMethod A browser-control CDP method the proxy reports. The set covers the commands an agent drives the browser with; configuration, DOM and Runtime bookkeeping, and Chrome-specific UI commands are outside it. Canonical definitions: devtools-protocol@2d019e73. +type BrowserCdpCommandMethod string + +// BrowserCdpConnectEvent An external client (e.g. customer SDK, Playwright, Puppeteer) connected to the CDP WebSocket proxy on this VM. +type BrowserCdpConnectEvent struct { + Category BrowserCdpConnectEventCategory `json:"category"` + + // Source Provenance metadata identifying which producer emitted the event. + Source BrowserEventSource `json:"source"` + + // Truncated True if the data field was truncated due to size limits. + Truncated *bool `json:"truncated,omitempty"` + + // Ts Event timestamp in Unix microseconds. + Ts int64 `json:"ts"` + Type BrowserCdpConnectEventType `json:"type"` +} + +// BrowserCdpConnectEventCategory defines model for BrowserCdpConnectEvent.Category. +type BrowserCdpConnectEventCategory string + +// BrowserCdpConnectEventType defines model for BrowserCdpConnectEvent.Type. +type BrowserCdpConnectEventType string + +// BrowserCdpDisconnectEvent An external client disconnected from the CDP WebSocket proxy on this VM. Pair with the immediately preceding `cdp_connect` on the same stream. +type BrowserCdpDisconnectEvent struct { + Category BrowserCdpDisconnectEventCategory `json:"category"` + + // Data Per-disconnect payload for `cdp_disconnect` events. + Data *BrowserCdpDisconnectEventData `json:"data,omitempty"` + + // Source Provenance metadata identifying which producer emitted the event. + Source BrowserEventSource `json:"source"` + + // Truncated True if the data field was truncated due to size limits. + Truncated *bool `json:"truncated,omitempty"` + + // Ts Event timestamp in Unix microseconds. + Ts int64 `json:"ts"` + Type BrowserCdpDisconnectEventType `json:"type"` +} + +// BrowserCdpDisconnectEventCategory defines model for BrowserCdpDisconnectEvent.Category. +type BrowserCdpDisconnectEventCategory string + +// BrowserCdpDisconnectEventType defines model for BrowserCdpDisconnectEvent.Type. +type BrowserCdpDisconnectEventType string + +// BrowserCdpDisconnectEventData Per-disconnect payload for `cdp_disconnect` events. +type BrowserCdpDisconnectEventData struct { + // DurationMs Wall-clock duration of the connection in milliseconds. + DurationMs float32 `json:"duration_ms"` + + // MessageCount Number of CDP messages relayed across the connection in either direction. + MessageCount int `json:"message_count"` + + // Reason Why the connection ended. `client_close`: the client initiated the close. `upstream_changed`: Chromium restarted mid-session and the proxy tore down so the client could reconnect against the new upstream. `upstream_error`: upstream dial or message pump errored. `context_cancelled`: the request context was cancelled (typically server shutdown). + Reason BrowserCdpDisconnectEventDataReason `json:"reason"` + + // TelemetryDropped Number of forwarded client frames the classifier never saw, because it could not keep up or because classification failed. An upper bound on lost commands rather than a count: a saturated queue turns away whatever arrives next, which may be library traffic that would have produced no event. Telemetry loss only; every command was still relayed to the browser. Always present on events from images that report it; absent on events from an image predating the field, which is not the same as zero. + TelemetryDropped *int `json:"telemetry_dropped,omitempty"` +} + +// BrowserCdpDisconnectEventDataReason Why the connection ended. `client_close`: the client initiated the close. `upstream_changed`: Chromium restarted mid-session and the proxy tore down so the client could reconnect against the new upstream. `upstream_error`: upstream dial or message pump errored. `context_cancelled`: the request context was cancelled (typically server shutdown). +type BrowserCdpDisconnectEventDataReason string + +// BrowserCdpDomFocusCommandData Sanitized `DOM.focus` arguments. Canonical input: devtools-protocol@2d019e73 `DOM.focus`. +type BrowserCdpDomFocusCommandData struct { + // BackendNodeId Opaque backend DOM node identifier the command targeted. + BackendNodeId *int `json:"backend_node_id,omitempty"` + Method BrowserCdpDomFocusCommandDataMethod `json:"method"` + + // NodeId Opaque DOM node identifier the command targeted. + NodeId *int `json:"node_id,omitempty"` + + // ObjectId Opaque Runtime remote object identifier the command targeted. + ObjectId *string `json:"object_id,omitempty"` + + // SessionId CDP session identifier the command was addressed to. Absent for browser-level commands. + SessionId *string `json:"session_id,omitempty"` +} + +// BrowserCdpDomFocusCommandDataMethod defines model for BrowserCdpDomFocusCommandData.Method. +type BrowserCdpDomFocusCommandDataMethod string + +// BrowserCdpDomScrollIntoViewIfNeededCommandData Sanitized `DOM.scrollIntoViewIfNeeded` arguments. Canonical input: devtools-protocol@2d019e73 `DOM.scrollIntoViewIfNeeded`. +type BrowserCdpDomScrollIntoViewIfNeededCommandData struct { + // BackendNodeId Opaque backend DOM node identifier the command targeted. + BackendNodeId *int `json:"backend_node_id,omitempty"` + + // HasRect Whether the command constrained scrolling to a rect within the node. + HasRect *bool `json:"has_rect,omitempty"` + Method BrowserCdpDomScrollIntoViewIfNeededCommandDataMethod `json:"method"` + + // NodeId Opaque DOM node identifier the command targeted. + NodeId *int `json:"node_id,omitempty"` + + // ObjectId Opaque Runtime remote object identifier the command targeted. + ObjectId *string `json:"object_id,omitempty"` + + // SessionId CDP session identifier the command was addressed to. Absent for browser-level commands. + SessionId *string `json:"session_id,omitempty"` +} + +// BrowserCdpDomScrollIntoViewIfNeededCommandDataMethod defines model for BrowserCdpDomScrollIntoViewIfNeededCommandData.Method. +type BrowserCdpDomScrollIntoViewIfNeededCommandDataMethod string + +// BrowserCdpDomSetFileInputFilesCommandData Sanitized `DOM.setFileInputFiles` arguments. Canonical input: devtools-protocol@2d019e73 `DOM.setFileInputFiles`. +type BrowserCdpDomSetFileInputFilesCommandData struct { + // BackendNodeId Opaque backend DOM node identifier the command targeted. + BackendNodeId *int `json:"backend_node_id,omitempty"` + + // FileCount Number of files handed to the input. File paths are never captured. + FileCount int `json:"file_count"` + Method BrowserCdpDomSetFileInputFilesCommandDataMethod `json:"method"` + + // NodeId Opaque DOM node identifier the command targeted. + NodeId *int `json:"node_id,omitempty"` + + // ObjectId Opaque Runtime remote object identifier the command targeted. + ObjectId *string `json:"object_id,omitempty"` + + // SessionId CDP session identifier the command was addressed to. Absent for browser-level commands. + SessionId *string `json:"session_id,omitempty"` +} + +// BrowserCdpDomSetFileInputFilesCommandDataMethod defines model for BrowserCdpDomSetFileInputFilesCommandData.Method. +type BrowserCdpDomSetFileInputFilesCommandDataMethod string + +// BrowserCdpInputCancelDraggingCommandData Sanitized `Input.cancelDragging` arguments. Canonical input: devtools-protocol@2d019e73 `Input.cancelDragging`. +type BrowserCdpInputCancelDraggingCommandData struct { + Method BrowserCdpInputCancelDraggingCommandDataMethod `json:"method"` + + // SessionId CDP session identifier the command was addressed to. Absent for browser-level commands. + SessionId *string `json:"session_id,omitempty"` +} + +// BrowserCdpInputCancelDraggingCommandDataMethod defines model for BrowserCdpInputCancelDraggingCommandData.Method. +type BrowserCdpInputCancelDraggingCommandDataMethod string + +// BrowserCdpInputDispatchDragEventCommandData Sanitized `Input.dispatchDragEvent` arguments. Canonical input: devtools-protocol@2d019e73 `Input.dispatchDragEvent`. +type BrowserCdpInputDispatchDragEventCommandData struct { + // DragFileCount Number of files in the drag payload. File paths are never captured. + DragFileCount *int `json:"drag_file_count,omitempty"` + + // DragItemCount Number of items in the drag payload. Item contents are never captured. + DragItemCount *int `json:"drag_item_count,omitempty"` + + // DragMimeCategories Distinct top-level MIME categories of the drag items (e.g. `text`, `image`, `application`). Subtypes and contents are never captured. + DragMimeCategories *[]string `json:"drag_mime_categories,omitempty"` + + // DragOperationsMask Bit field of allowed drag operations (1=copy, 2=link, 16=move). + DragOperationsMask *int `json:"drag_operations_mask,omitempty"` + + // EventType Drag event phase: `dragEnter`, `dragOver`, `drop` or `dragCancel`. + EventType string `json:"event_type"` + Method BrowserCdpInputDispatchDragEventCommandDataMethod `json:"method"` + + // Modifiers Bit field of held modifier keys (1=Alt, 2=Ctrl, 4=Meta, 8=Shift). + Modifiers *int `json:"modifiers,omitempty"` + + // SessionId CDP session identifier the command was addressed to. Absent for browser-level commands. + SessionId *string `json:"session_id,omitempty"` + + // X Viewport x coordinate in CSS pixels. + X *float64 `json:"x,omitempty"` + + // Y Viewport y coordinate in CSS pixels. + Y *float64 `json:"y,omitempty"` +} + +// BrowserCdpInputDispatchDragEventCommandDataMethod defines model for BrowserCdpInputDispatchDragEventCommandData.Method. +type BrowserCdpInputDispatchDragEventCommandDataMethod string + +// BrowserCdpInputDispatchKeyEventCommandData Sanitized `Input.dispatchKeyEvent` arguments. Canonical input: devtools-protocol@2d019e73 `Input.dispatchKeyEvent`. +type BrowserCdpInputDispatchKeyEventCommandData struct { + // AutoRepeat Whether the event was generated by key repeat. + AutoRepeat *bool `json:"auto_repeat,omitempty"` + + // CommandCount Number of editing commands (e.g. `selectAll`) carried by the event. + CommandCount *int `json:"command_count,omitempty"` + + // EventType Key event phase: `keyDown`, `keyUp`, `rawKeyDown` or `char`. + EventType string `json:"event_type"` + + // IsKeypad Whether the key is on the numeric keypad. + IsKeypad *bool `json:"is_keypad,omitempty"` + + // IsSystemKey Whether the event is a system key event. + IsSystemKey *bool `json:"is_system_key,omitempty"` + + // Location Keyboard location (1=left, 2=right, 3=numpad). + Location *int `json:"location,omitempty"` + Method BrowserCdpInputDispatchKeyEventCommandDataMethod `json:"method"` + + // Modifiers Bit field of held modifier keys (1=Alt, 2=Ctrl, 4=Meta, 8=Shift). + Modifiers *int `json:"modifiers,omitempty"` + + // NamedKey Key that commands the page rather than typing into it (e.g. `Enter`, `Tab`, `ArrowDown`, `F5`). Keys that produce a character are never captured; those are counted by `text_length`. + NamedKey *string `json:"named_key,omitempty"` + + // SessionId CDP session identifier the command was addressed to. Absent for browser-level commands. + SessionId *string `json:"session_id,omitempty"` + + // TextLength Number of characters the command submitted. The text itself is never captured. + TextLength *int `json:"text_length,omitempty"` +} + +// BrowserCdpInputDispatchKeyEventCommandDataMethod defines model for BrowserCdpInputDispatchKeyEventCommandData.Method. +type BrowserCdpInputDispatchKeyEventCommandDataMethod string + +// BrowserCdpInputDispatchMouseEventCommandData Sanitized `Input.dispatchMouseEvent` arguments. Canonical input: devtools-protocol@2d019e73 `Input.dispatchMouseEvent`. +type BrowserCdpInputDispatchMouseEventCommandData struct { + // Button Button named by the command (`none`, `left`, `middle`, `right`, `back`, `forward`). + Button *string `json:"button,omitempty"` + + // Buttons Bit field of buttons held down. Non-zero on a `mouseMoved` means the move is a drag path. + Buttons *int `json:"buttons,omitempty"` + + // ClickCount Number of times the button was clicked (2 is a double click). + ClickCount *int `json:"click_count,omitempty"` + + // DeltaX Horizontal scroll delta, for `mouseWheel`. + DeltaX *float64 `json:"delta_x,omitempty"` + + // DeltaY Vertical scroll delta, for `mouseWheel`. + DeltaY *float64 `json:"delta_y,omitempty"` + + // EventType Mouse event phase: `mousePressed`, `mouseReleased`, `mouseMoved` or `mouseWheel`. + EventType string `json:"event_type"` + + // Force Normalized pressure, 0 to 1. + Force *float64 `json:"force,omitempty"` + Method BrowserCdpInputDispatchMouseEventCommandDataMethod `json:"method"` + + // Modifiers Bit field of held modifier keys (1=Alt, 2=Ctrl, 4=Meta, 8=Shift). + Modifiers *int `json:"modifiers,omitempty"` + + // PointerType Pointer that generated the event (`mouse` or `pen`). + PointerType *string `json:"pointer_type,omitempty"` + + // SessionId CDP session identifier the command was addressed to. Absent for browser-level commands. + SessionId *string `json:"session_id,omitempty"` + + // TangentialPressure Normalized tangential pressure, -1 to 1. + TangentialPressure *float64 `json:"tangential_pressure,omitempty"` + + // TiltX Pen tilt from the Y-Z plane, in degrees. + TiltX *float64 `json:"tilt_x,omitempty"` + + // TiltY Pen tilt from the X-Z plane, in degrees. + TiltY *float64 `json:"tilt_y,omitempty"` + + // Twist Pen clockwise rotation, in degrees. + Twist *int `json:"twist,omitempty"` + + // X Viewport x coordinate in CSS pixels. + X *float64 `json:"x,omitempty"` + + // Y Viewport y coordinate in CSS pixels. + Y *float64 `json:"y,omitempty"` +} + +// BrowserCdpInputDispatchMouseEventCommandDataMethod defines model for BrowserCdpInputDispatchMouseEventCommandData.Method. +type BrowserCdpInputDispatchMouseEventCommandDataMethod string + +// BrowserCdpInputDispatchTouchEventCommandData Sanitized `Input.dispatchTouchEvent` arguments. Canonical input: devtools-protocol@2d019e73 `Input.dispatchTouchEvent`. +type BrowserCdpInputDispatchTouchEventCommandData struct { + // EventType Touch event phase: `touchStart`, `touchEnd`, `touchMove` or `touchCancel`. + EventType string `json:"event_type"` + Method BrowserCdpInputDispatchTouchEventCommandDataMethod `json:"method"` + + // Modifiers Bit field of held modifier keys (1=Alt, 2=Ctrl, 4=Meta, 8=Shift). + Modifiers *int `json:"modifiers,omitempty"` + + // SessionId CDP session identifier the command was addressed to. Absent for browser-level commands. + SessionId *string `json:"session_id,omitempty"` + + // TouchPointCount Number of active touch points the command carried. + TouchPointCount int `json:"touch_point_count"` + + // X Viewport x coordinate of the first touch point. Touch coordinates live inside `touchPoints`, so this is the primary point rather than a command-level argument. + X *float64 `json:"x,omitempty"` + + // Y Viewport y coordinate of the first touch point. + Y *float64 `json:"y,omitempty"` +} + +// BrowserCdpInputDispatchTouchEventCommandDataMethod defines model for BrowserCdpInputDispatchTouchEventCommandData.Method. +type BrowserCdpInputDispatchTouchEventCommandDataMethod string + +// BrowserCdpInputEmulateTouchFromMouseEventCommandData Sanitized `Input.emulateTouchFromMouseEvent` arguments. Canonical input: devtools-protocol@2d019e73 `Input.emulateTouchFromMouseEvent`. +type BrowserCdpInputEmulateTouchFromMouseEventCommandData struct { + // Button Button named by the command. + Button *string `json:"button,omitempty"` + + // ClickCount Number of times the button was clicked. + ClickCount *int `json:"click_count,omitempty"` + + // DeltaX Horizontal scroll delta. + DeltaX *float64 `json:"delta_x,omitempty"` + + // DeltaY Vertical scroll delta. + DeltaY *float64 `json:"delta_y,omitempty"` + + // EventType Mouse event phase being emulated as touch. + EventType string `json:"event_type"` + Method BrowserCdpInputEmulateTouchFromMouseEventCommandDataMethod `json:"method"` + + // Modifiers Bit field of held modifier keys (1=Alt, 2=Ctrl, 4=Meta, 8=Shift). + Modifiers *int `json:"modifiers,omitempty"` + + // SessionId CDP session identifier the command was addressed to. Absent for browser-level commands. + SessionId *string `json:"session_id,omitempty"` + + // X Viewport x coordinate in CSS pixels. + X *float64 `json:"x,omitempty"` + + // Y Viewport y coordinate in CSS pixels. + Y *float64 `json:"y,omitempty"` +} + +// BrowserCdpInputEmulateTouchFromMouseEventCommandDataMethod defines model for BrowserCdpInputEmulateTouchFromMouseEventCommandData.Method. +type BrowserCdpInputEmulateTouchFromMouseEventCommandDataMethod string + +// BrowserCdpInputImeSetCompositionCommandData Sanitized `Input.imeSetComposition` arguments. Canonical input: devtools-protocol@2d019e73 `Input.imeSetComposition`. +type BrowserCdpInputImeSetCompositionCommandData struct { + Method BrowserCdpInputImeSetCompositionCommandDataMethod `json:"method"` + + // ReplacementEnd Replacement range end offset. + ReplacementEnd *int `json:"replacement_end,omitempty"` + + // ReplacementStart Replacement range start offset. + ReplacementStart *int `json:"replacement_start,omitempty"` + + // SelectionEnd Selection end offset within the composition. + SelectionEnd *int `json:"selection_end,omitempty"` + + // SelectionStart Selection start offset within the composition. + SelectionStart *int `json:"selection_start,omitempty"` + + // SessionId CDP session identifier the command was addressed to. Absent for browser-level commands. + SessionId *string `json:"session_id,omitempty"` + + // TextLength Number of characters in the composition. The text itself is never captured. + TextLength int `json:"text_length"` +} + +// BrowserCdpInputImeSetCompositionCommandDataMethod defines model for BrowserCdpInputImeSetCompositionCommandData.Method. +type BrowserCdpInputImeSetCompositionCommandDataMethod string + +// BrowserCdpInputInsertTextCommandData Sanitized `Input.insertText` arguments. Canonical input: devtools-protocol@2d019e73 `Input.insertText`. +type BrowserCdpInputInsertTextCommandData struct { + Method BrowserCdpInputInsertTextCommandDataMethod `json:"method"` + + // SessionId CDP session identifier the command was addressed to. Absent for browser-level commands. + SessionId *string `json:"session_id,omitempty"` + + // TextLength Number of characters inserted. The text itself is never captured. + TextLength int `json:"text_length"` +} + +// BrowserCdpInputInsertTextCommandDataMethod defines model for BrowserCdpInputInsertTextCommandData.Method. +type BrowserCdpInputInsertTextCommandDataMethod string + +// BrowserCdpInputSynthesizePinchGestureCommandData Sanitized `Input.synthesizePinchGesture` arguments. Canonical input: devtools-protocol@2d019e73 `Input.synthesizePinchGesture`. +type BrowserCdpInputSynthesizePinchGestureCommandData struct { + // GestureSourceType Input source the synthesized gesture emulates. + GestureSourceType *string `json:"gesture_source_type,omitempty"` + Method BrowserCdpInputSynthesizePinchGestureCommandDataMethod `json:"method"` + + // RelativeSpeed Relative pointer speed, in pixels per second. + RelativeSpeed *int `json:"relative_speed,omitempty"` + + // ScaleFactor Relative scale of the pinch (>1 zooms in). + ScaleFactor *float64 `json:"scale_factor,omitempty"` + + // SessionId CDP session identifier the command was addressed to. Absent for browser-level commands. + SessionId *string `json:"session_id,omitempty"` + + // X Viewport x coordinate in CSS pixels. + X *float64 `json:"x,omitempty"` + + // Y Viewport y coordinate in CSS pixels. + Y *float64 `json:"y,omitempty"` +} + +// BrowserCdpInputSynthesizePinchGestureCommandDataMethod defines model for BrowserCdpInputSynthesizePinchGestureCommandData.Method. +type BrowserCdpInputSynthesizePinchGestureCommandDataMethod string + +// BrowserCdpInputSynthesizeScrollGestureCommandData Sanitized `Input.synthesizeScrollGesture` arguments. Canonical input: devtools-protocol@2d019e73 `Input.synthesizeScrollGesture`. +type BrowserCdpInputSynthesizeScrollGestureCommandData struct { + // GestureSourceType Input source the synthesized gesture emulates. + GestureSourceType *string `json:"gesture_source_type,omitempty"` + Method BrowserCdpInputSynthesizeScrollGestureCommandDataMethod `json:"method"` + + // PreventFling Whether fling was suppressed. + PreventFling *bool `json:"prevent_fling,omitempty"` + + // RepeatCount Number of additional repeats of the scroll. + RepeatCount *int `json:"repeat_count,omitempty"` + + // RepeatDelayMs Delay between repeats, in milliseconds. + RepeatDelayMs *int `json:"repeat_delay_ms,omitempty"` + + // SessionId CDP session identifier the command was addressed to. Absent for browser-level commands. + SessionId *string `json:"session_id,omitempty"` + + // Speed Swipe speed in pixels per second. + Speed *int `json:"speed,omitempty"` + + // X Viewport x coordinate in CSS pixels. + X *float64 `json:"x,omitempty"` + + // XDistance Horizontal scroll distance in CSS pixels; positive scrolls left. + XDistance *float64 `json:"x_distance,omitempty"` + + // XOverscroll Additional horizontal distance scrolled past the end. + XOverscroll *float64 `json:"x_overscroll,omitempty"` + + // Y Viewport y coordinate in CSS pixels. + Y *float64 `json:"y,omitempty"` + + // YDistance Vertical scroll distance in CSS pixels; positive scrolls up. + YDistance *float64 `json:"y_distance,omitempty"` + + // YOverscroll Additional vertical distance scrolled past the end. + YOverscroll *float64 `json:"y_overscroll,omitempty"` +} + +// BrowserCdpInputSynthesizeScrollGestureCommandDataMethod defines model for BrowserCdpInputSynthesizeScrollGestureCommandData.Method. +type BrowserCdpInputSynthesizeScrollGestureCommandDataMethod string + +// BrowserCdpInputSynthesizeTapGestureCommandData Sanitized `Input.synthesizeTapGesture` arguments. Canonical input: devtools-protocol@2d019e73 `Input.synthesizeTapGesture`. +type BrowserCdpInputSynthesizeTapGestureCommandData struct { + // Duration Duration between touchdown and touchup, in milliseconds. + Duration *int `json:"duration,omitempty"` + + // GestureSourceType Input source the synthesized gesture emulates. + GestureSourceType *string `json:"gesture_source_type,omitempty"` + Method BrowserCdpInputSynthesizeTapGestureCommandDataMethod `json:"method"` + + // SessionId CDP session identifier the command was addressed to. Absent for browser-level commands. + SessionId *string `json:"session_id,omitempty"` + + // TapCount Number of times to tap (2 is a double tap). + TapCount *int `json:"tap_count,omitempty"` + + // X Viewport x coordinate in CSS pixels. + X *float64 `json:"x,omitempty"` + + // Y Viewport y coordinate in CSS pixels. + Y *float64 `json:"y,omitempty"` +} + +// BrowserCdpInputSynthesizeTapGestureCommandDataMethod defines model for BrowserCdpInputSynthesizeTapGestureCommandData.Method. +type BrowserCdpInputSynthesizeTapGestureCommandDataMethod string + +// BrowserCdpPageBringToFrontCommandData Sanitized `Page.bringToFront` arguments. Canonical input: devtools-protocol@2d019e73 `Page.bringToFront`. +type BrowserCdpPageBringToFrontCommandData struct { + Method BrowserCdpPageBringToFrontCommandDataMethod `json:"method"` + + // SessionId CDP session identifier the command was addressed to. Absent for browser-level commands. + SessionId *string `json:"session_id,omitempty"` +} + +// BrowserCdpPageBringToFrontCommandDataMethod defines model for BrowserCdpPageBringToFrontCommandData.Method. +type BrowserCdpPageBringToFrontCommandDataMethod string + +// BrowserCdpPageCaptureScreenshotCommandData Sanitized `Page.captureScreenshot` arguments. Canonical input: devtools-protocol@2d019e73 `Page.captureScreenshot`. +type BrowserCdpPageCaptureScreenshotCommandData struct { + // CaptureBeyondViewport Whether the capture extended past the viewport. + CaptureBeyondViewport *bool `json:"capture_beyond_viewport,omitempty"` + + // ClipHeight Clip region height in CSS pixels. + ClipHeight *float64 `json:"clip_height,omitempty"` + + // ClipScale Clip region page scale factor. + ClipScale *float64 `json:"clip_scale,omitempty"` + + // ClipWidth Clip region width in CSS pixels. + ClipWidth *float64 `json:"clip_width,omitempty"` + + // ClipX Clip region x offset in CSS pixels. + ClipX *float64 `json:"clip_x,omitempty"` + + // ClipY Clip region y offset in CSS pixels. + ClipY *float64 `json:"clip_y,omitempty"` + + // Format Image format requested (`jpeg`, `png` or `webp`). + Format *string `json:"format,omitempty"` + + // FromSurface Whether the capture was taken from the surface rather than the view. + FromSurface *bool `json:"from_surface,omitempty"` + Method BrowserCdpPageCaptureScreenshotCommandDataMethod `json:"method"` + + // OptimizeForSpeed Whether encoding favored speed over size. + OptimizeForSpeed *bool `json:"optimize_for_speed,omitempty"` + + // Quality Compression quality, 0 to 100, for lossy formats. + Quality *int `json:"quality,omitempty"` + + // SessionId CDP session identifier the command was addressed to. Absent for browser-level commands. + SessionId *string `json:"session_id,omitempty"` +} + +// BrowserCdpPageCaptureScreenshotCommandDataMethod defines model for BrowserCdpPageCaptureScreenshotCommandData.Method. +type BrowserCdpPageCaptureScreenshotCommandDataMethod string + +// BrowserCdpPageCaptureSnapshotCommandData Sanitized `Page.captureSnapshot` arguments. Canonical input: devtools-protocol@2d019e73 `Page.captureSnapshot`. +type BrowserCdpPageCaptureSnapshotCommandData struct { + // Format Snapshot format requested (`mhtml`). + Format *string `json:"format,omitempty"` + Method BrowserCdpPageCaptureSnapshotCommandDataMethod `json:"method"` + + // SessionId CDP session identifier the command was addressed to. Absent for browser-level commands. + SessionId *string `json:"session_id,omitempty"` +} + +// BrowserCdpPageCaptureSnapshotCommandDataMethod defines model for BrowserCdpPageCaptureSnapshotCommandData.Method. +type BrowserCdpPageCaptureSnapshotCommandDataMethod string + +// BrowserCdpPageCloseCommandData Sanitized `Page.close` arguments. Canonical input: devtools-protocol@2d019e73 `Page.close`. +type BrowserCdpPageCloseCommandData struct { + Method BrowserCdpPageCloseCommandDataMethod `json:"method"` + + // SessionId CDP session identifier the command was addressed to. Absent for browser-level commands. + SessionId *string `json:"session_id,omitempty"` +} + +// BrowserCdpPageCloseCommandDataMethod defines model for BrowserCdpPageCloseCommandData.Method. +type BrowserCdpPageCloseCommandDataMethod string + +// BrowserCdpPageHandleJavaScriptDialogCommandData Sanitized `Page.handleJavaScriptDialog` arguments. Canonical input: devtools-protocol@2d019e73 `Page.handleJavaScriptDialog`. +type BrowserCdpPageHandleJavaScriptDialogCommandData struct { + // Accept Whether the dialog was accepted or dismissed. + Accept bool `json:"accept"` + Method BrowserCdpPageHandleJavaScriptDialogCommandDataMethod `json:"method"` + + // PromptTextLength Number of characters entered into a prompt dialog. The text itself is never captured. + PromptTextLength *int `json:"prompt_text_length,omitempty"` + + // SessionId CDP session identifier the command was addressed to. Absent for browser-level commands. + SessionId *string `json:"session_id,omitempty"` +} + +// BrowserCdpPageHandleJavaScriptDialogCommandDataMethod defines model for BrowserCdpPageHandleJavaScriptDialogCommandData.Method. +type BrowserCdpPageHandleJavaScriptDialogCommandDataMethod string + +// BrowserCdpPageNavigateCommandData Sanitized `Page.navigate` arguments. Canonical input: devtools-protocol@2d019e73 `Page.navigate`. +type BrowserCdpPageNavigateCommandData struct { + // FrameId Opaque frame identifier. + FrameId *string `json:"frame_id,omitempty"` + Method BrowserCdpPageNavigateCommandDataMethod `json:"method"` + + // ReferrerPolicy Referrer policy named by the command. + ReferrerPolicy *string `json:"referrer_policy,omitempty"` + + // ReferrerPresent Whether the command carried a referrer. The referrer itself is never captured. + ReferrerPresent *bool `json:"referrer_present,omitempty"` + + // SessionId CDP session identifier the command was addressed to. Absent for browser-level commands. + SessionId *string `json:"session_id,omitempty"` + + // TransitionType Navigation reason reported by the caller (e.g. `link`, `typed`, `reload`). + TransitionType *string `json:"transition_type,omitempty"` + + // UrlScheme Scheme of the destination URL (e.g. `https`, `about`, `data`). The rest of the URL — host, path, query and fragment — is never captured. Enable the `page` category for navigation events that carry the URL itself. + UrlScheme *string `json:"url_scheme,omitempty"` +} + +// BrowserCdpPageNavigateCommandDataMethod defines model for BrowserCdpPageNavigateCommandData.Method. +type BrowserCdpPageNavigateCommandDataMethod string + +// BrowserCdpPageNavigateToHistoryEntryCommandData Sanitized `Page.navigateToHistoryEntry` arguments. Canonical input: devtools-protocol@2d019e73 `Page.navigateToHistoryEntry`. +type BrowserCdpPageNavigateToHistoryEntryCommandData struct { + // EntryId History entry the command navigated to. + EntryId int `json:"entry_id"` + Method BrowserCdpPageNavigateToHistoryEntryCommandDataMethod `json:"method"` + + // SessionId CDP session identifier the command was addressed to. Absent for browser-level commands. + SessionId *string `json:"session_id,omitempty"` +} + +// BrowserCdpPageNavigateToHistoryEntryCommandDataMethod defines model for BrowserCdpPageNavigateToHistoryEntryCommandData.Method. +type BrowserCdpPageNavigateToHistoryEntryCommandDataMethod string + +// BrowserCdpPagePrintToPdfCommandData Sanitized `Page.printToPDF` arguments. Canonical input: devtools-protocol@2d019e73 `Page.printToPDF`. +type BrowserCdpPagePrintToPdfCommandData struct { + // DisplayHeaderFooter Whether a header and footer were rendered. + DisplayHeaderFooter *bool `json:"display_header_footer,omitempty"` + + // FooterTemplatePresent Whether a footer template was supplied. The template itself is never captured. + FooterTemplatePresent *bool `json:"footer_template_present,omitempty"` + + // HeaderTemplatePresent Whether a header template was supplied. The template itself is never captured. + HeaderTemplatePresent *bool `json:"header_template_present,omitempty"` + + // Landscape Whether the page was laid out in landscape. + Landscape *bool `json:"landscape,omitempty"` + Method BrowserCdpPagePrintToPdfCommandDataMethod `json:"method"` + + // PageRangesPresent Whether a page range was supplied. + PageRangesPresent *bool `json:"page_ranges_present,omitempty"` + + // PaperHeight Paper height in inches. + PaperHeight *float64 `json:"paper_height,omitempty"` + + // PaperWidth Paper width in inches. + PaperWidth *float64 `json:"paper_width,omitempty"` + + // PreferCssPageSize Whether the CSS page size was preferred over the paper size. + PreferCssPageSize *bool `json:"prefer_css_page_size,omitempty"` + + // PrintBackground Whether background graphics were printed. + PrintBackground *bool `json:"print_background,omitempty"` + + // Scale Page render scale. + Scale *float64 `json:"scale,omitempty"` + + // SessionId CDP session identifier the command was addressed to. Absent for browser-level commands. + SessionId *string `json:"session_id,omitempty"` + + // TransferMode How the PDF was returned (`ReturnAsBase64` or `ReturnAsStream`). + TransferMode *string `json:"transfer_mode,omitempty"` +} + +// BrowserCdpPagePrintToPdfCommandDataMethod defines model for BrowserCdpPagePrintToPdfCommandData.Method. +type BrowserCdpPagePrintToPdfCommandDataMethod string + +// BrowserCdpPageReloadCommandData Sanitized `Page.reload` arguments. Canonical input: devtools-protocol@2d019e73 `Page.reload`. +type BrowserCdpPageReloadCommandData struct { + // IgnoreCache Whether the reload bypassed the cache. + IgnoreCache *bool `json:"ignore_cache,omitempty"` + + // LoaderId Opaque document loader identifier. + LoaderId *string `json:"loader_id,omitempty"` + Method BrowserCdpPageReloadCommandDataMethod `json:"method"` + + // ScriptLength Number of characters in the injected script, absent when none was supplied and 0 when an empty one was. The script itself is never captured. + ScriptLength *int `json:"script_length,omitempty"` + + // SessionId CDP session identifier the command was addressed to. Absent for browser-level commands. + SessionId *string `json:"session_id,omitempty"` +} + +// BrowserCdpPageReloadCommandDataMethod defines model for BrowserCdpPageReloadCommandData.Method. +type BrowserCdpPageReloadCommandDataMethod string + +// BrowserCdpPageSetWebLifecycleStateCommandData Sanitized `Page.setWebLifecycleState` arguments. Canonical input: devtools-protocol@2d019e73 `Page.setWebLifecycleState`. +type BrowserCdpPageSetWebLifecycleStateCommandData struct { + Method BrowserCdpPageSetWebLifecycleStateCommandDataMethod `json:"method"` + + // SessionId CDP session identifier the command was addressed to. Absent for browser-level commands. + SessionId *string `json:"session_id,omitempty"` + + // State Lifecycle state applied (`frozen` or `active`). + State string `json:"state"` +} + +// BrowserCdpPageSetWebLifecycleStateCommandDataMethod defines model for BrowserCdpPageSetWebLifecycleStateCommandData.Method. +type BrowserCdpPageSetWebLifecycleStateCommandDataMethod string + +// BrowserCdpPageStartScreencastCommandData Sanitized `Page.startScreencast` arguments. Canonical input: devtools-protocol@2d019e73 `Page.startScreencast`. +type BrowserCdpPageStartScreencastCommandData struct { + // EveryNthFrame Frame sampling interval. + EveryNthFrame *int `json:"every_nth_frame,omitempty"` + + // Format Frame format requested (`jpeg` or `png`). + Format *string `json:"format,omitempty"` + + // MaxHeight Maximum frame height in pixels. + MaxHeight *int `json:"max_height,omitempty"` + + // MaxWidth Maximum frame width in pixels. + MaxWidth *int `json:"max_width,omitempty"` + Method BrowserCdpPageStartScreencastCommandDataMethod `json:"method"` + + // Quality Compression quality, 0 to 100. + Quality *int `json:"quality,omitempty"` + + // SessionId CDP session identifier the command was addressed to. Absent for browser-level commands. + SessionId *string `json:"session_id,omitempty"` +} + +// BrowserCdpPageStartScreencastCommandDataMethod defines model for BrowserCdpPageStartScreencastCommandData.Method. +type BrowserCdpPageStartScreencastCommandDataMethod string + +// BrowserCdpPageStopLoadingCommandData Sanitized `Page.stopLoading` arguments. Canonical input: devtools-protocol@2d019e73 `Page.stopLoading`. +type BrowserCdpPageStopLoadingCommandData struct { + Method BrowserCdpPageStopLoadingCommandDataMethod `json:"method"` + + // SessionId CDP session identifier the command was addressed to. Absent for browser-level commands. + SessionId *string `json:"session_id,omitempty"` +} + +// BrowserCdpPageStopLoadingCommandDataMethod defines model for BrowserCdpPageStopLoadingCommandData.Method. +type BrowserCdpPageStopLoadingCommandDataMethod string + +// BrowserCdpPageStopScreencastCommandData Sanitized `Page.stopScreencast` arguments. Canonical input: devtools-protocol@2d019e73 `Page.stopScreencast`. +type BrowserCdpPageStopScreencastCommandData struct { + Method BrowserCdpPageStopScreencastCommandDataMethod `json:"method"` + + // SessionId CDP session identifier the command was addressed to. Absent for browser-level commands. + SessionId *string `json:"session_id,omitempty"` +} + +// BrowserCdpPageStopScreencastCommandDataMethod defines model for BrowserCdpPageStopScreencastCommandData.Method. +type BrowserCdpPageStopScreencastCommandDataMethod string + +// BrowserCdpTargetActivateTargetCommandData Sanitized `Target.activateTarget` arguments. Canonical input: devtools-protocol@2d019e73 `Target.activateTarget`. +type BrowserCdpTargetActivateTargetCommandData struct { + Method BrowserCdpTargetActivateTargetCommandDataMethod `json:"method"` + + // SessionId CDP session identifier the command was addressed to. Absent for browser-level commands. + SessionId *string `json:"session_id,omitempty"` + + // TargetId Opaque target identifier. + TargetId string `json:"target_id"` +} + +// BrowserCdpTargetActivateTargetCommandDataMethod defines model for BrowserCdpTargetActivateTargetCommandData.Method. +type BrowserCdpTargetActivateTargetCommandDataMethod string + +// BrowserCdpTargetCloseTargetCommandData Sanitized `Target.closeTarget` arguments. Canonical input: devtools-protocol@2d019e73 `Target.closeTarget`. +type BrowserCdpTargetCloseTargetCommandData struct { + Method BrowserCdpTargetCloseTargetCommandDataMethod `json:"method"` + + // SessionId CDP session identifier the command was addressed to. Absent for browser-level commands. + SessionId *string `json:"session_id,omitempty"` + + // TargetId Opaque target identifier. + TargetId string `json:"target_id"` +} + +// BrowserCdpTargetCloseTargetCommandDataMethod defines model for BrowserCdpTargetCloseTargetCommandData.Method. +type BrowserCdpTargetCloseTargetCommandDataMethod string + +// BrowserCdpTargetCreateBrowserContextCommandData Sanitized `Target.createBrowserContext` arguments. Canonical input: devtools-protocol@2d019e73 `Target.createBrowserContext`. +type BrowserCdpTargetCreateBrowserContextCommandData struct { + // DisposeOnDetach Whether the context is disposed when the debugging session detaches. + DisposeOnDetach *bool `json:"dispose_on_detach,omitempty"` + Method BrowserCdpTargetCreateBrowserContextCommandDataMethod `json:"method"` + + // ProxyBypassListPresent Whether a proxy bypass list was configured. + ProxyBypassListPresent *bool `json:"proxy_bypass_list_present,omitempty"` + + // ProxyServerPresent Whether a proxy was configured. The proxy address is never captured. + ProxyServerPresent *bool `json:"proxy_server_present,omitempty"` + + // SessionId CDP session identifier the command was addressed to. Absent for browser-level commands. + SessionId *string `json:"session_id,omitempty"` + + // UniversalNetworkAccessOriginCount Number of origins granted universal network access. The origins themselves are never captured. + UniversalNetworkAccessOriginCount *int `json:"universal_network_access_origin_count,omitempty"` +} + +// BrowserCdpTargetCreateBrowserContextCommandDataMethod defines model for BrowserCdpTargetCreateBrowserContextCommandData.Method. +type BrowserCdpTargetCreateBrowserContextCommandDataMethod string + +// BrowserCdpTargetCreateTargetCommandData Sanitized `Target.createTarget` arguments. Canonical input: devtools-protocol@2d019e73 `Target.createTarget`. +type BrowserCdpTargetCreateTargetCommandData struct { + // Background Whether the target was created in the background. + Background *bool `json:"background,omitempty"` + + // BrowserContextId Opaque browser context identifier. + BrowserContextId *string `json:"browser_context_id,omitempty"` + + // EnableBeginFrameControl Whether BeginFrame control was enabled (headless only). + EnableBeginFrameControl *bool `json:"enable_begin_frame_control,omitempty"` + + // ForTab Whether a tab target rather than a page target was created. + ForTab *bool `json:"for_tab,omitempty"` + + // Height Window height in DIP. + Height *int `json:"height,omitempty"` + + // Hidden Whether the target was created hidden. + Hidden *bool `json:"hidden,omitempty"` + + // Left Window x position in screen coordinates. + Left *int `json:"left,omitempty"` + Method BrowserCdpTargetCreateTargetCommandDataMethod `json:"method"` + + // NewWindow Whether a new window was requested. + NewWindow *bool `json:"new_window,omitempty"` + + // SessionId CDP session identifier the command was addressed to. Absent for browser-level commands. + SessionId *string `json:"session_id,omitempty"` + + // Top Window y position in screen coordinates. + Top *int `json:"top,omitempty"` + + // UrlScheme Scheme of the destination URL (e.g. `https`, `about`, `data`). The rest of the URL — host, path, query and fragment — is never captured. Enable the `page` category for navigation events that carry the URL itself. + UrlScheme *string `json:"url_scheme,omitempty"` + + // Width Window width in DIP. + Width *int `json:"width,omitempty"` + + // WindowState Window state requested (`normal`, `minimized`, `maximized`, `fullscreen`). + WindowState *string `json:"window_state,omitempty"` +} + +// BrowserCdpTargetCreateTargetCommandDataMethod defines model for BrowserCdpTargetCreateTargetCommandData.Method. +type BrowserCdpTargetCreateTargetCommandDataMethod string + +// BrowserCdpTargetDisposeBrowserContextCommandData Sanitized `Target.disposeBrowserContext` arguments. Canonical input: devtools-protocol@2d019e73 `Target.disposeBrowserContext`. +type BrowserCdpTargetDisposeBrowserContextCommandData struct { + // BrowserContextId Opaque browser context identifier. + BrowserContextId string `json:"browser_context_id"` + Method BrowserCdpTargetDisposeBrowserContextCommandDataMethod `json:"method"` + + // SessionId CDP session identifier the command was addressed to. Absent for browser-level commands. + SessionId *string `json:"session_id,omitempty"` +} + +// BrowserCdpTargetDisposeBrowserContextCommandDataMethod defines model for BrowserCdpTargetDisposeBrowserContextCommandData.Method. +type BrowserCdpTargetDisposeBrowserContextCommandDataMethod string + +// BrowserCdpTargetOpenDevToolsCommandData Sanitized `Target.openDevTools` arguments. Canonical input: devtools-protocol@2d019e73 `Target.openDevTools`. +type BrowserCdpTargetOpenDevToolsCommandData struct { + Method BrowserCdpTargetOpenDevToolsCommandDataMethod `json:"method"` + + // PanelId DevTools panel opened. + PanelId *string `json:"panel_id,omitempty"` + + // SessionId CDP session identifier the command was addressed to. Absent for browser-level commands. + SessionId *string `json:"session_id,omitempty"` + + // TargetId Opaque target identifier. + TargetId string `json:"target_id"` +} + +// BrowserCdpTargetOpenDevToolsCommandDataMethod defines model for BrowserCdpTargetOpenDevToolsCommandData.Method. +type BrowserCdpTargetOpenDevToolsCommandDataMethod string + +// BrowserConsoleErrorEvent A browser console error or uncaught JavaScript exception event. Emitted from two distinct CDP sources with different data shapes. Runtime.consoleAPICalled (console.error calls) produces level, text, args, and stack_trace. Runtime.exceptionThrown (uncaught exceptions) produces text, line, column, source_url, and stack_trace. Fields not applicable to the source are absent. +type BrowserConsoleErrorEvent struct { + Category BrowserConsoleErrorEventCategory `json:"category"` + Data *BrowserConsoleErrorEventData `json:"data,omitempty"` + + // Source Provenance metadata identifying which producer emitted the event. + Source BrowserEventSource `json:"source"` + + // Truncated True if the data field was truncated due to size limits. + Truncated *bool `json:"truncated,omitempty"` + + // Ts Event timestamp in Unix microseconds. + Ts int64 `json:"ts"` + Type BrowserConsoleErrorEventType `json:"type"` +} + +// BrowserConsoleErrorEventCategory defines model for BrowserConsoleErrorEvent.Category. +type BrowserConsoleErrorEventCategory string + +// BrowserConsoleErrorEventType defines model for BrowserConsoleErrorEvent.Type. +type BrowserConsoleErrorEventType string + +// BrowserConsoleErrorEventData defines model for BrowserConsoleErrorEventData. +type BrowserConsoleErrorEventData struct { + // Args All console arguments coerced to strings. Present only when sourced from Runtime.consoleAPICalled. + Args *[]string `json:"args,omitempty"` + + // Column Column number in the script where the exception was thrown. Present only when sourced from Runtime.exceptionThrown. + Column *int `json:"column,omitempty"` + + // FrameId CDP frame identifier within the target. + FrameId *string `json:"frame_id,omitempty"` + + // Level CDP console type value, always "error". Present only when sourced from Runtime.consoleAPICalled. + Level *string `json:"level,omitempty"` + + // Line Line number in the script where the exception was thrown. Present only when sourced from Runtime.exceptionThrown. + Line *int `json:"line,omitempty"` + + // LoaderId CDP document loader identifier, reset on each navigation. + LoaderId *string `json:"loader_id,omitempty"` + + // NavSeq Monotonically increasing navigation sequence number, incremented on each top-level navigation within the target. + NavSeq int64 `json:"nav_seq"` + + // SessionId CDP session identifier for the target connection. + SessionId string `json:"session_id"` + + // SourceUrl URL of the script file that threw the exception. Present only when sourced from Runtime.exceptionThrown. + SourceUrl *string `json:"source_url,omitempty"` + + // StackTrace CDP Runtime.StackTrace representing the JavaScript call stack at the time of an event. Fields use CDP naming conventions rather than snake_case to match the Chrome DevTools Protocol wire format. + StackTrace *BrowserCallStack `json:"stack_trace,omitempty"` + + // TargetId Browser target identifier (stable across navigations within a tab). + TargetId string `json:"target_id"` + + // TargetType CDP target type of the page that produced the event. + TargetType BrowserTargetType `json:"target_type"` + + // Text Human-readable error text, as the browser console would display it. For console.error() calls, the first argument coerced to a string. For uncaught exceptions, the prefix and error message, e.g. "Uncaught Error: boom" or "Uncaught (in promise) TypeError: x is not a function". + Text string `json:"text"` + + // Url URL relevant to this event; page URL for navigation and page events, request URL for network events. + Url *string `json:"url,omitempty"` +} + +// BrowserConsoleLogEvent A browser console log event (console.log, console.info, console.warn, etc.). +type BrowserConsoleLogEvent struct { + Category BrowserConsoleLogEventCategory `json:"category"` + Data *BrowserConsoleLogEventData `json:"data,omitempty"` + + // Source Provenance metadata identifying which producer emitted the event. + Source BrowserEventSource `json:"source"` + + // Truncated True if the data field was truncated due to size limits. + Truncated *bool `json:"truncated,omitempty"` + + // Ts Event timestamp in Unix microseconds. + Ts int64 `json:"ts"` + Type BrowserConsoleLogEventType `json:"type"` +} + +// BrowserConsoleLogEventCategory defines model for BrowserConsoleLogEvent.Category. +type BrowserConsoleLogEventCategory string + +// BrowserConsoleLogEventType defines model for BrowserConsoleLogEvent.Type. +type BrowserConsoleLogEventType string + +// BrowserConsoleLogEventData defines model for BrowserConsoleLogEventData. +type BrowserConsoleLogEventData struct { + // Args All console arguments coerced to strings. + Args *[]string `json:"args,omitempty"` + + // FrameId CDP frame identifier within the target. + FrameId *string `json:"frame_id,omitempty"` + + // Level CDP Runtime.consoleAPICalled type, passed through unfiltered from Chrome. `error` is routed to console_error events instead; all other CDP console types appear here. See CDP spec for the full enum. + Level string `json:"level"` + + // LoaderId CDP document loader identifier, reset on each navigation. + LoaderId *string `json:"loader_id,omitempty"` + + // NavSeq Monotonically increasing navigation sequence number, incremented on each top-level navigation within the target. + NavSeq int64 `json:"nav_seq"` + + // SessionId CDP session identifier for the target connection. + SessionId string `json:"session_id"` + + // StackTrace CDP Runtime.StackTrace representing the JavaScript call stack at the time of an event. Fields use CDP naming conventions rather than snake_case to match the Chrome DevTools Protocol wire format. + StackTrace *BrowserCallStack `json:"stack_trace,omitempty"` + + // TargetId Browser target identifier (stable across navigations within a tab). + TargetId string `json:"target_id"` + + // TargetType CDP target type of the page that produced the event. + TargetType BrowserTargetType `json:"target_type"` + + // Text First console argument coerced to string. + Text string `json:"text"` + + // Url URL relevant to this event; page URL for navigation and page events, request URL for network events. + Url *string `json:"url,omitempty"` +} + +// BrowserEventContext Browser event context stamped by the browser monitor onto all CDP-sourced events. Identifies the target, frame, and navigation epoch in which the event occurred. +type BrowserEventContext struct { + // FrameId CDP frame identifier within the target. + FrameId *string `json:"frame_id,omitempty"` + + // LoaderId CDP document loader identifier, reset on each navigation. + LoaderId *string `json:"loader_id,omitempty"` + + // NavSeq Monotonically increasing navigation sequence number, incremented on each top-level navigation within the target. + NavSeq int64 `json:"nav_seq"` + + // SessionId CDP session identifier for the target connection. + SessionId string `json:"session_id"` + + // TargetId Browser target identifier (stable across navigations within a tab). + TargetId string `json:"target_id"` + + // TargetType CDP target type of the page that produced the event. + TargetType BrowserTargetType `json:"target_type"` + + // Url URL relevant to this event; page URL for navigation and page events, request URL for network events. + Url *string `json:"url,omitempty"` +} + +// BrowserEventSource Provenance metadata identifying which producer emitted the event. +type BrowserEventSource struct { + // Event Producer-specific event name (e.g. `Runtime.consoleAPICalled` for CDP-sourced console events). + Event *string `json:"event,omitempty"` + + // Kind Event producer. `cdp`: Chrome DevTools Protocol events from the browser. `kernel_api`: Kernel API server (reserved for server-generated events). `extension`: injected Chrome extension. `local_process`: system process running alongside the browser. + Kind BrowserEventSourceKind `json:"kind"` + + // Metadata Producer-specific context (e.g. CDP target/session/frame IDs). + Metadata *map[string]string `json:"metadata,omitempty"` +} + +// BrowserEventSourceKind Event producer. `cdp`: Chrome DevTools Protocol events from the browser. `kernel_api`: Kernel API server (reserved for server-generated events). `extension`: injected Chrome extension. `local_process`: system process running alongside the browser. +type BrowserEventSourceKind string + +// BrowserHttpHeaders HTTP headers map forwarded as-is from CDP without normalization. Values are typically strings but may be any JSON type. +type BrowserHttpHeaders map[string]interface{} + +// BrowserInteractionClickEvent A browser user click event captured via injected page script. +type BrowserInteractionClickEvent struct { + Category BrowserInteractionClickEventCategory `json:"category"` + Data *BrowserInteractionClickEventData `json:"data,omitempty"` + + // Source Provenance metadata identifying which producer emitted the event. + Source BrowserEventSource `json:"source"` + + // Truncated True if the data field was truncated due to size limits. + Truncated *bool `json:"truncated,omitempty"` + + // Ts Event timestamp in Unix microseconds. + Ts int64 `json:"ts"` + Type BrowserInteractionClickEventType `json:"type"` +} + +// BrowserInteractionClickEventCategory defines model for BrowserInteractionClickEvent.Category. +type BrowserInteractionClickEventCategory string + +// BrowserInteractionClickEventType defines model for BrowserInteractionClickEvent.Type. +type BrowserInteractionClickEventType string + +// BrowserInteractionClickEventData defines model for BrowserInteractionClickEventData. +type BrowserInteractionClickEventData struct { + // FrameId CDP frame identifier within the target. + FrameId *string `json:"frame_id,omitempty"` + + // LoaderId CDP document loader identifier, reset on each navigation. + LoaderId *string `json:"loader_id,omitempty"` + + // NavSeq Monotonically increasing navigation sequence number, incremented on each top-level navigation within the target. + NavSeq int64 `json:"nav_seq"` + + // Selector CSS selector path to the clicked element. + Selector string `json:"selector"` + + // SessionId CDP session identifier for the target connection. + SessionId string `json:"session_id"` + + // Tag HTML tag name of the clicked element in uppercase (e.g. BUTTON, A, DIV). + Tag string `json:"tag"` + + // TargetId Browser target identifier (stable across navigations within a tab). + TargetId string `json:"target_id"` + + // TargetType CDP target type of the page that produced the event. + TargetType BrowserTargetType `json:"target_type"` + + // Text Visible text content of the clicked element, trimmed. + Text *string `json:"text,omitempty"` + + // Url URL relevant to this event; page URL for navigation and page events, request URL for network events. + Url *string `json:"url,omitempty"` + + // X Viewport x-coordinate of the click in CSS pixels. + X int `json:"x"` + + // Y Viewport y-coordinate of the click in CSS pixels. + Y int `json:"y"` +} + +// BrowserInteractionKeyEvent A browser keyboard event captured via injected page script. +type BrowserInteractionKeyEvent struct { + Category BrowserInteractionKeyEventCategory `json:"category"` + Data *BrowserInteractionKeyEventData `json:"data,omitempty"` + + // Source Provenance metadata identifying which producer emitted the event. + Source BrowserEventSource `json:"source"` + + // Truncated True if the data field was truncated due to size limits. + Truncated *bool `json:"truncated,omitempty"` - // DurationMs Wall-clock duration of the handler in milliseconds. - DurationMs float32 `json:"duration_ms"` + // Ts Event timestamp in Unix microseconds. + Ts int64 `json:"ts"` + Type BrowserInteractionKeyEventType `json:"type"` +} - // OperationId Matched route's operation, named as the server names its handler (e.g. `TakeScreenshot`, `ExecutePlaywrightCode`). - OperationId string `json:"operation_id"` +// BrowserInteractionKeyEventCategory defines model for BrowserInteractionKeyEvent.Category. +type BrowserInteractionKeyEventCategory string - // RequestId Per-request identifier from the kernel-images-api request middleware. - RequestId string `json:"request_id"` +// BrowserInteractionKeyEventType defines model for BrowserInteractionKeyEvent.Type. +type BrowserInteractionKeyEventType string - // Status HTTP response status code. - Status int `json:"status"` -} +// BrowserInteractionKeyEventData defines model for BrowserInteractionKeyEventData. +type BrowserInteractionKeyEventData struct { + // FrameId CDP frame identifier within the target. + FrameId *string `json:"frame_id,omitempty"` -// BrowserCallStack CDP Runtime.StackTrace representing the JavaScript call stack at the time of an event. Fields use CDP naming conventions rather than snake_case to match the Chrome DevTools Protocol wire format. -type BrowserCallStack struct { - // CallFrames Ordered list of call frames, outermost first. - CallFrames []struct { - // ColumnNumber Zero-based column number within the line. - ColumnNumber int `json:"columnNumber"` + // Key Key value from the KeyboardEvent (e.g. Enter, Backspace, a). + Key string `json:"key"` - // FunctionName JavaScript function name, or empty string for anonymous functions. - FunctionName string `json:"functionName"` + // LoaderId CDP document loader identifier, reset on each navigation. + LoaderId *string `json:"loader_id,omitempty"` - // LineNumber Zero-based line number within the script. - LineNumber int `json:"lineNumber"` + // NavSeq Monotonically increasing navigation sequence number, incremented on each top-level navigation within the target. + NavSeq int64 `json:"nav_seq"` - // ScriptId CDP script identifier. - ScriptId string `json:"scriptId"` + // Selector CSS selector path to the element that had focus when the key was pressed. + Selector string `json:"selector"` - // Url URL or name of the script file. - Url string `json:"url"` - } `json:"callFrames"` + // SessionId CDP session identifier for the target connection. + SessionId string `json:"session_id"` - // Description Optional label for the stack trace (e.g. async cause). - Description *string `json:"description,omitempty"` + // Tag HTML tag name of the focused element in uppercase (e.g. INPUT, TEXTAREA, DIV). + Tag string `json:"tag"` - // Parent Parent stack trace for async stacks. - Parent *BrowserCallStack `json:"parent,omitempty"` -} + // TargetId Browser target identifier (stable across navigations within a tab). + TargetId string `json:"target_id"` -// BrowserCaptchaSolveResultEvent A captcha solve attempt reached a terminal outcome. -type BrowserCaptchaSolveResultEvent struct { - Category BrowserCaptchaSolveResultEventCategory `json:"category"` + // TargetType CDP target type of the page that produced the event. + TargetType BrowserTargetType `json:"target_type"` - // Data Per-attempt payload for `captcha_solve_result` events. - Data *BrowserCaptchaSolveResultEventData `json:"data,omitempty"` + // Url URL relevant to this event; page URL for navigation and page events, request URL for network events. + Url *string `json:"url,omitempty"` +} + +// BrowserInteractionScrollSettledEvent A browser scroll settled event emitted after scroll position stops changing, captured via injected page script. +type BrowserInteractionScrollSettledEvent struct { + Category BrowserInteractionScrollSettledEventCategory `json:"category"` + Data *BrowserInteractionScrollSettledEventData `json:"data,omitempty"` // Source Provenance metadata identifying which producer emitted the event. Source BrowserEventSource `json:"source"` @@ -1705,49 +3725,61 @@ type BrowserCaptchaSolveResultEvent struct { Truncated *bool `json:"truncated,omitempty"` // Ts Event timestamp in Unix microseconds. - Ts int64 `json:"ts"` - Type BrowserCaptchaSolveResultEventType `json:"type"` + Ts int64 `json:"ts"` + Type BrowserInteractionScrollSettledEventType `json:"type"` } -// BrowserCaptchaSolveResultEventCategory defines model for BrowserCaptchaSolveResultEvent.Category. -type BrowserCaptchaSolveResultEventCategory string +// BrowserInteractionScrollSettledEventCategory defines model for BrowserInteractionScrollSettledEvent.Category. +type BrowserInteractionScrollSettledEventCategory string -// BrowserCaptchaSolveResultEventType defines model for BrowserCaptchaSolveResultEvent.Type. -type BrowserCaptchaSolveResultEventType string +// BrowserInteractionScrollSettledEventType defines model for BrowserInteractionScrollSettledEvent.Type. +type BrowserInteractionScrollSettledEventType string -// BrowserCaptchaSolveResultEventData Per-attempt payload for `captcha_solve_result` events. -type BrowserCaptchaSolveResultEventData struct { - // CaptchaType Captcha vendor family. Producers normalize provider-specific task names into this set: enterprise variants of recaptcha collapse into their version bucket (v2 / v3), and anything not covered (e.g. DataDome, MtCaptcha, plain OCR) is reported as `other`. - CaptchaType BrowserCaptchaSolveResultEventDataCaptchaType `json:"captcha_type"` +// BrowserInteractionScrollSettledEventData defines model for BrowserInteractionScrollSettledEventData. +type BrowserInteractionScrollSettledEventData struct { + // FrameId CDP frame identifier within the target. + FrameId *string `json:"frame_id,omitempty"` - // DurationMs Wall-clock duration from solve start to terminal outcome. - DurationMs float32 `json:"duration_ms"` + // FromX Scroll x-position at the start of the scroll gesture in CSS pixels. + FromX int `json:"from_x"` - // ErrorCode Solver-specific error code on failure (e.g. `ERROR_CAPTCHA_UNSOLVABLE`). Absent on success. - ErrorCode *string `json:"error_code,omitempty"` + // FromY Scroll y-position at the start of the scroll gesture in CSS pixels. + FromY int `json:"from_y"` - // Status Terminal outcome. `success`: solver returned a usable solution. `failure`: solver returned an error (see `error_code`). `timeout`: solver did not return within the caller's wait budget. `abandoned`: caller cancelled or the page navigated away mid-solve. - Status BrowserCaptchaSolveResultEventDataStatus `json:"status"` + // LoaderId CDP document loader identifier, reset on each navigation. + LoaderId *string `json:"loader_id,omitempty"` - // TaskId Solver-assigned identifier. Opaque, useful for support cross-references. - TaskId *string `json:"task_id,omitempty"` + // NavSeq Monotonically increasing navigation sequence number, incremented on each top-level navigation within the target. + NavSeq int64 `json:"nav_seq"` - // WebsiteHost Host of the page where the captcha was solved. - WebsiteHost *string `json:"website_host,omitempty"` + // SessionId CDP session identifier for the target connection. + SessionId string `json:"session_id"` - // WebsitePath Path of the page where the captcha was solved. Query string excluded. - WebsitePath *string `json:"website_path,omitempty"` -} + // TargetId Browser target identifier (stable across navigations within a tab). + TargetId string `json:"target_id"` -// BrowserCaptchaSolveResultEventDataCaptchaType Captcha vendor family. Producers normalize provider-specific task names into this set: enterprise variants of recaptcha collapse into their version bucket (v2 / v3), and anything not covered (e.g. DataDome, MtCaptcha, plain OCR) is reported as `other`. -type BrowserCaptchaSolveResultEventDataCaptchaType string + // TargetSelector CSS selector path to the scrolled element. + TargetSelector string `json:"target_selector"` -// BrowserCaptchaSolveResultEventDataStatus Terminal outcome. `success`: solver returned a usable solution. `failure`: solver returned an error (see `error_code`). `timeout`: solver did not return within the caller's wait budget. `abandoned`: caller cancelled or the page navigated away mid-solve. -type BrowserCaptchaSolveResultEventDataStatus string + // TargetType CDP target type of the page that produced the event. + TargetType BrowserTargetType `json:"target_type"` -// BrowserCdpConnectEvent An external client (e.g. customer SDK, Playwright, Puppeteer) connected to the CDP WebSocket proxy on this VM. -type BrowserCdpConnectEvent struct { - Category BrowserCdpConnectEventCategory `json:"category"` + // ToX Final scroll x-position after the gesture settled in CSS pixels. + ToX int `json:"to_x"` + + // ToY Final scroll y-position after the gesture settled in CSS pixels. + ToY int `json:"to_y"` + + // Url URL relevant to this event; page URL for navigation and page events, request URL for network events. + Url *string `json:"url,omitempty"` +} + +// BrowserLiveViewConnectEvent A live view client connected to the headful browser's WebRTC server (Neko). Headful only; not emitted for headless images. +type BrowserLiveViewConnectEvent struct { + Category BrowserLiveViewConnectEventCategory `json:"category"` + + // Data Per-session payload for `live_view_connect` events. + Data *BrowserLiveViewConnectEventData `json:"data,omitempty"` // Source Provenance metadata identifying which producer emitted the event. Source BrowserEventSource `json:"source"` @@ -1756,22 +3788,28 @@ type BrowserCdpConnectEvent struct { Truncated *bool `json:"truncated,omitempty"` // Ts Event timestamp in Unix microseconds. - Ts int64 `json:"ts"` - Type BrowserCdpConnectEventType `json:"type"` + Ts int64 `json:"ts"` + Type BrowserLiveViewConnectEventType `json:"type"` } -// BrowserCdpConnectEventCategory defines model for BrowserCdpConnectEvent.Category. -type BrowserCdpConnectEventCategory string +// BrowserLiveViewConnectEventCategory defines model for BrowserLiveViewConnectEvent.Category. +type BrowserLiveViewConnectEventCategory string -// BrowserCdpConnectEventType defines model for BrowserCdpConnectEvent.Type. -type BrowserCdpConnectEventType string +// BrowserLiveViewConnectEventType defines model for BrowserLiveViewConnectEvent.Type. +type BrowserLiveViewConnectEventType string -// BrowserCdpDisconnectEvent An external client disconnected from the CDP WebSocket proxy on this VM. Pair with the immediately preceding `cdp_connect` on the same stream. -type BrowserCdpDisconnectEvent struct { - Category BrowserCdpDisconnectEventCategory `json:"category"` +// BrowserLiveViewConnectEventData Per-session payload for `live_view_connect` events. +type BrowserLiveViewConnectEventData struct { + // SessionId Live view session identifier. Stable across reconnects, so a transient network blip can emit two events with the same `session_id`. + SessionId string `json:"session_id"` +} - // Data Per-disconnect payload for `cdp_disconnect` events. - Data *BrowserCdpDisconnectEventData `json:"data,omitempty"` +// BrowserLiveViewDisconnectEvent A live view client disconnected from the headful browser's WebRTC server (Neko). Pair with `live_view_connect` by `session_id`. +type BrowserLiveViewDisconnectEvent struct { + Category BrowserLiveViewDisconnectEventCategory `json:"category"` + + // Data Per-session payload for `live_view_disconnect` events. + Data *BrowserLiveViewDisconnectEventData `json:"data,omitempty"` // Source Provenance metadata identifying which producer emitted the event. Source BrowserEventSource `json:"source"` @@ -1780,35 +3818,29 @@ type BrowserCdpDisconnectEvent struct { Truncated *bool `json:"truncated,omitempty"` // Ts Event timestamp in Unix microseconds. - Ts int64 `json:"ts"` - Type BrowserCdpDisconnectEventType `json:"type"` + Ts int64 `json:"ts"` + Type BrowserLiveViewDisconnectEventType `json:"type"` } -// BrowserCdpDisconnectEventCategory defines model for BrowserCdpDisconnectEvent.Category. -type BrowserCdpDisconnectEventCategory string +// BrowserLiveViewDisconnectEventCategory defines model for BrowserLiveViewDisconnectEvent.Category. +type BrowserLiveViewDisconnectEventCategory string -// BrowserCdpDisconnectEventType defines model for BrowserCdpDisconnectEvent.Type. -type BrowserCdpDisconnectEventType string +// BrowserLiveViewDisconnectEventType defines model for BrowserLiveViewDisconnectEvent.Type. +type BrowserLiveViewDisconnectEventType string -// BrowserCdpDisconnectEventData Per-disconnect payload for `cdp_disconnect` events. -type BrowserCdpDisconnectEventData struct { +// BrowserLiveViewDisconnectEventData Per-session payload for `live_view_disconnect` events. +type BrowserLiveViewDisconnectEventData struct { // DurationMs Wall-clock duration of the connection in milliseconds. DurationMs float32 `json:"duration_ms"` - // MessageCount Number of CDP messages relayed across the connection in either direction. - MessageCount int `json:"message_count"` - - // Reason Why the connection ended. `client_close`: the client initiated the close. `upstream_changed`: Chromium restarted mid-session and the proxy tore down so the client could reconnect against the new upstream. `upstream_error`: upstream dial or message pump errored. `context_cancelled`: the request context was cancelled (typically server shutdown). - Reason BrowserCdpDisconnectEventDataReason `json:"reason"` + // SessionId Live view session identifier; matches the corresponding `live_view_connect` event. + SessionId string `json:"session_id"` } -// BrowserCdpDisconnectEventDataReason Why the connection ended. `client_close`: the client initiated the close. `upstream_changed`: Chromium restarted mid-session and the proxy tore down so the client could reconnect against the new upstream. `upstream_error`: upstream dial or message pump errored. `context_cancelled`: the request context was cancelled (typically server shutdown). -type BrowserCdpDisconnectEventDataReason string - -// BrowserConsoleErrorEvent A browser console error or uncaught JavaScript exception event. Emitted from two distinct CDP sources with different data shapes. Runtime.consoleAPICalled (console.error calls) produces level, text, args, and stack_trace. Runtime.exceptionThrown (uncaught exceptions) produces text, line, column, source_url, and stack_trace. Fields not applicable to the source are absent. -type BrowserConsoleErrorEvent struct { - Category BrowserConsoleErrorEventCategory `json:"category"` - Data *BrowserConsoleErrorEventData `json:"data,omitempty"` +// BrowserMonitorDisconnectedEvent The CDP connection to Chrome was lost. Telemetry events may be dropped until monitor_reconnected arrives. Treat any in-progress computed state (network_idle, page_layout_settled) as unreliable until then. +type BrowserMonitorDisconnectedEvent struct { + Category BrowserMonitorDisconnectedEventCategory `json:"category"` + Data *BrowserMonitorDisconnectedEventData `json:"data,omitempty"` // Source Provenance metadata identifying which producer emitted the event. Source BrowserEventSource `json:"source"` @@ -1817,65 +3849,57 @@ type BrowserConsoleErrorEvent struct { Truncated *bool `json:"truncated,omitempty"` // Ts Event timestamp in Unix microseconds. - Ts int64 `json:"ts"` - Type BrowserConsoleErrorEventType `json:"type"` + Ts int64 `json:"ts"` + Type BrowserMonitorDisconnectedEventType `json:"type"` } -// BrowserConsoleErrorEventCategory defines model for BrowserConsoleErrorEvent.Category. -type BrowserConsoleErrorEventCategory string - -// BrowserConsoleErrorEventType defines model for BrowserConsoleErrorEvent.Type. -type BrowserConsoleErrorEventType string - -// BrowserConsoleErrorEventData defines model for BrowserConsoleErrorEventData. -type BrowserConsoleErrorEventData struct { - // Args All console arguments coerced to strings. Present only when sourced from Runtime.consoleAPICalled. - Args *[]string `json:"args,omitempty"` - - // Column Column number in the script where the exception was thrown. Present only when sourced from Runtime.exceptionThrown. - Column *int `json:"column,omitempty"` - - // FrameId CDP frame identifier within the target. - FrameId *string `json:"frame_id,omitempty"` - - // Level CDP console type value, always "error". Present only when sourced from Runtime.consoleAPICalled. - Level *string `json:"level,omitempty"` +// BrowserMonitorDisconnectedEventCategory defines model for BrowserMonitorDisconnectedEvent.Category. +type BrowserMonitorDisconnectedEventCategory string - // Line Line number in the script where the exception was thrown. Present only when sourced from Runtime.exceptionThrown. - Line *int `json:"line,omitempty"` +// BrowserMonitorDisconnectedEventType defines model for BrowserMonitorDisconnectedEvent.Type. +type BrowserMonitorDisconnectedEventType string - // LoaderId CDP document loader identifier, reset on each navigation. - LoaderId *string `json:"loader_id,omitempty"` +// BrowserMonitorDisconnectedEventData defines model for BrowserMonitorDisconnectedEventData. +type BrowserMonitorDisconnectedEventData struct { + // Reason Reason for the disconnection. chrome_restarted: Chrome process restarted. + Reason BrowserMonitorDisconnectedEventDataReason `json:"reason"` +} - // NavSeq Monotonically increasing navigation sequence number, incremented on each top-level navigation within the target. - NavSeq int64 `json:"nav_seq"` +// BrowserMonitorDisconnectedEventDataReason Reason for the disconnection. chrome_restarted: Chrome process restarted. +type BrowserMonitorDisconnectedEventDataReason string - // SessionId CDP session identifier for the target connection. - SessionId string `json:"session_id"` +// BrowserMonitorInitFailedEvent The CDP session could not be initialized. +type BrowserMonitorInitFailedEvent struct { + Category BrowserMonitorInitFailedEventCategory `json:"category"` + Data *BrowserMonitorInitFailedEventData `json:"data,omitempty"` - // SourceUrl URL of the script file that threw the exception. Present only when sourced from Runtime.exceptionThrown. - SourceUrl *string `json:"source_url,omitempty"` + // Source Provenance metadata identifying which producer emitted the event. + Source BrowserEventSource `json:"source"` - // StackTrace CDP Runtime.StackTrace representing the JavaScript call stack at the time of an event. Fields use CDP naming conventions rather than snake_case to match the Chrome DevTools Protocol wire format. - StackTrace *BrowserCallStack `json:"stack_trace,omitempty"` + // Truncated True if the data field was truncated due to size limits. + Truncated *bool `json:"truncated,omitempty"` - // TargetId Browser target identifier (stable across navigations within a tab). - TargetId string `json:"target_id"` + // Ts Event timestamp in Unix microseconds. + Ts int64 `json:"ts"` + Type BrowserMonitorInitFailedEventType `json:"type"` +} - // TargetType CDP target type of the page that produced the event. - TargetType BrowserTargetType `json:"target_type"` +// BrowserMonitorInitFailedEventCategory defines model for BrowserMonitorInitFailedEvent.Category. +type BrowserMonitorInitFailedEventCategory string - // Text Human-readable error text, as the browser console would display it. For console.error() calls, the first argument coerced to a string. For uncaught exceptions, the prefix and error message, e.g. "Uncaught Error: boom" or "Uncaught (in promise) TypeError: x is not a function". - Text string `json:"text"` +// BrowserMonitorInitFailedEventType defines model for BrowserMonitorInitFailedEvent.Type. +type BrowserMonitorInitFailedEventType string - // Url URL relevant to this event; page URL for navigation and page events, request URL for network events. - Url *string `json:"url,omitempty"` +// BrowserMonitorInitFailedEventData defines model for BrowserMonitorInitFailedEventData. +type BrowserMonitorInitFailedEventData struct { + // Step The CDP method or initialization step that failed (e.g. Target.setAutoAttach). + Step string `json:"step"` } -// BrowserConsoleLogEvent A browser console log event (console.log, console.info, console.warn, etc.). -type BrowserConsoleLogEvent struct { - Category BrowserConsoleLogEventCategory `json:"category"` - Data *BrowserConsoleLogEventData `json:"data,omitempty"` +// BrowserMonitorReconnectFailedEvent The CDP connection to Chrome could not be re-established after exhausting all reconnection attempts. No further telemetry events will arrive on this session. +type BrowserMonitorReconnectFailedEvent struct { + Category BrowserMonitorReconnectFailedEventCategory `json:"category"` + Data *BrowserMonitorReconnectFailedEventData `json:"data,omitempty"` // Source Provenance metadata identifying which producer emitted the event. Source BrowserEventSource `json:"source"` @@ -1884,98 +3908,109 @@ type BrowserConsoleLogEvent struct { Truncated *bool `json:"truncated,omitempty"` // Ts Event timestamp in Unix microseconds. - Ts int64 `json:"ts"` - Type BrowserConsoleLogEventType `json:"type"` + Ts int64 `json:"ts"` + Type BrowserMonitorReconnectFailedEventType `json:"type"` } -// BrowserConsoleLogEventCategory defines model for BrowserConsoleLogEvent.Category. -type BrowserConsoleLogEventCategory string - -// BrowserConsoleLogEventType defines model for BrowserConsoleLogEvent.Type. -type BrowserConsoleLogEventType string - -// BrowserConsoleLogEventData defines model for BrowserConsoleLogEventData. -type BrowserConsoleLogEventData struct { - // Args All console arguments coerced to strings. - Args *[]string `json:"args,omitempty"` +// BrowserMonitorReconnectFailedEventCategory defines model for BrowserMonitorReconnectFailedEvent.Category. +type BrowserMonitorReconnectFailedEventCategory string - // FrameId CDP frame identifier within the target. - FrameId *string `json:"frame_id,omitempty"` +// BrowserMonitorReconnectFailedEventType defines model for BrowserMonitorReconnectFailedEvent.Type. +type BrowserMonitorReconnectFailedEventType string - // Level CDP Runtime.consoleAPICalled type, passed through unfiltered from Chrome. `error` is routed to console_error events instead; all other CDP console types appear here. See CDP spec for the full enum. - Level string `json:"level"` +// BrowserMonitorReconnectFailedEventData defines model for BrowserMonitorReconnectFailedEventData. +type BrowserMonitorReconnectFailedEventData struct { + // Reason Reason for the reconnection failure. reconnect_exhausted: all retry attempts were used up without successfully restoring the CDP connection. + Reason BrowserMonitorReconnectFailedEventDataReason `json:"reason"` +} - // LoaderId CDP document loader identifier, reset on each navigation. - LoaderId *string `json:"loader_id,omitempty"` +// BrowserMonitorReconnectFailedEventDataReason Reason for the reconnection failure. reconnect_exhausted: all retry attempts were used up without successfully restoring the CDP connection. +type BrowserMonitorReconnectFailedEventDataReason string - // NavSeq Monotonically increasing navigation sequence number, incremented on each top-level navigation within the target. - NavSeq int64 `json:"nav_seq"` +// BrowserMonitorReconnectedEvent The CDP connection to Chrome was successfully re-established after a disconnection. Events emitted during the gap are lost. Computed state is reset, so navigation and network tracking restart fresh from this point. +type BrowserMonitorReconnectedEvent struct { + Category BrowserMonitorReconnectedEventCategory `json:"category"` + Data *BrowserMonitorReconnectedEventData `json:"data,omitempty"` - // SessionId CDP session identifier for the target connection. - SessionId string `json:"session_id"` + // Source Provenance metadata identifying which producer emitted the event. + Source BrowserEventSource `json:"source"` - // StackTrace CDP Runtime.StackTrace representing the JavaScript call stack at the time of an event. Fields use CDP naming conventions rather than snake_case to match the Chrome DevTools Protocol wire format. - StackTrace *BrowserCallStack `json:"stack_trace,omitempty"` + // Truncated True if the data field was truncated due to size limits. + Truncated *bool `json:"truncated,omitempty"` - // TargetId Browser target identifier (stable across navigations within a tab). - TargetId string `json:"target_id"` + // Ts Event timestamp in Unix microseconds. + Ts int64 `json:"ts"` + Type BrowserMonitorReconnectedEventType `json:"type"` +} - // TargetType CDP target type of the page that produced the event. - TargetType BrowserTargetType `json:"target_type"` +// BrowserMonitorReconnectedEventCategory defines model for BrowserMonitorReconnectedEvent.Category. +type BrowserMonitorReconnectedEventCategory string - // Text First console argument coerced to string. - Text string `json:"text"` +// BrowserMonitorReconnectedEventType defines model for BrowserMonitorReconnectedEvent.Type. +type BrowserMonitorReconnectedEventType string - // Url URL relevant to this event; page URL for navigation and page events, request URL for network events. - Url *string `json:"url,omitempty"` +// BrowserMonitorReconnectedEventData defines model for BrowserMonitorReconnectedEventData. +type BrowserMonitorReconnectedEventData struct { + // ReconnectDurationMs Wall-clock time in milliseconds taken to reconnect after the disconnection. + ReconnectDurationMs int64 `json:"reconnect_duration_ms"` } -// BrowserEventContext Browser event context stamped by the browser monitor onto all CDP-sourced events. Identifies the target, frame, and navigation epoch in which the event occurred. -type BrowserEventContext struct { - // FrameId CDP frame identifier within the target. - FrameId *string `json:"frame_id,omitempty"` +// BrowserMonitorScreenshotEvent A periodic screenshot of the browser viewport. +type BrowserMonitorScreenshotEvent struct { + Category BrowserMonitorScreenshotEventCategory `json:"category"` + Data *BrowserMonitorScreenshotEventData `json:"data,omitempty"` - // LoaderId CDP document loader identifier, reset on each navigation. - LoaderId *string `json:"loader_id,omitempty"` + // Source Provenance metadata identifying which producer emitted the event. + Source BrowserEventSource `json:"source"` - // NavSeq Monotonically increasing navigation sequence number, incremented on each top-level navigation within the target. - NavSeq int64 `json:"nav_seq"` + // Truncated True if the data field was truncated due to size limits. + Truncated *bool `json:"truncated,omitempty"` - // SessionId CDP session identifier for the target connection. - SessionId string `json:"session_id"` + // Ts Event timestamp in Unix microseconds. + Ts int64 `json:"ts"` + Type BrowserMonitorScreenshotEventType `json:"type"` +} - // TargetId Browser target identifier (stable across navigations within a tab). - TargetId string `json:"target_id"` +// BrowserMonitorScreenshotEventCategory defines model for BrowserMonitorScreenshotEvent.Category. +type BrowserMonitorScreenshotEventCategory string - // TargetType CDP target type of the page that produced the event. - TargetType BrowserTargetType `json:"target_type"` +// BrowserMonitorScreenshotEventType defines model for BrowserMonitorScreenshotEvent.Type. +type BrowserMonitorScreenshotEventType string - // Url URL relevant to this event; page URL for navigation and page events, request URL for network events. - Url *string `json:"url,omitempty"` +// BrowserMonitorScreenshotEventData defines model for BrowserMonitorScreenshotEventData. +type BrowserMonitorScreenshotEventData struct { + // Png Base64-encoded PNG screenshot of the browser viewport. + Png []byte `json:"png"` } -// BrowserEventSource Provenance metadata identifying which producer emitted the event. -type BrowserEventSource struct { - // Event Producer-specific event name (e.g. `Runtime.consoleAPICalled` for CDP-sourced console events). - Event *string `json:"event,omitempty"` +// BrowserNetworkIdleEvent A browser network idle event emitted after a 500ms quiet period with no in-flight HTTP requests. +type BrowserNetworkIdleEvent struct { + Category BrowserNetworkIdleEventCategory `json:"category"` - // Kind Event producer. `cdp`: Chrome DevTools Protocol events from the browser. `kernel_api`: Kernel API server (reserved for server-generated events). `extension`: injected Chrome extension. `local_process`: system process running alongside the browser. - Kind BrowserEventSourceKind `json:"kind"` + // Data Browser event context stamped by the browser monitor onto all CDP-sourced events. Identifies the target, frame, and navigation epoch in which the event occurred. + Data *BrowserEventContext `json:"data,omitempty"` - // Metadata Producer-specific context (e.g. CDP target/session/frame IDs). - Metadata *map[string]string `json:"metadata,omitempty"` + // Source Provenance metadata identifying which producer emitted the event. + Source BrowserEventSource `json:"source"` + + // Truncated True if the data field was truncated due to size limits. + Truncated *bool `json:"truncated,omitempty"` + + // Ts Event timestamp in Unix microseconds. + Ts int64 `json:"ts"` + Type BrowserNetworkIdleEventType `json:"type"` } -// BrowserEventSourceKind Event producer. `cdp`: Chrome DevTools Protocol events from the browser. `kernel_api`: Kernel API server (reserved for server-generated events). `extension`: injected Chrome extension. `local_process`: system process running alongside the browser. -type BrowserEventSourceKind string +// BrowserNetworkIdleEventCategory defines model for BrowserNetworkIdleEvent.Category. +type BrowserNetworkIdleEventCategory string -// BrowserHttpHeaders HTTP headers map forwarded as-is from CDP without normalization. Values are typically strings but may be any JSON type. -type BrowserHttpHeaders map[string]interface{} +// BrowserNetworkIdleEventType defines model for BrowserNetworkIdleEvent.Type. +type BrowserNetworkIdleEventType string -// BrowserInteractionClickEvent A browser user click event captured via injected page script. -type BrowserInteractionClickEvent struct { - Category BrowserInteractionClickEventCategory `json:"category"` - Data *BrowserInteractionClickEventData `json:"data,omitempty"` +// BrowserNetworkLoadingFailedEvent A browser network loading failed event. If the request was already in flight when CDP attached (no prior `network_request` was emitted for it), `url`, `frame_id`, `loader_id`, and `resource_type` are absent; `BrowserEventContext` is partially populated in that case. +type BrowserNetworkLoadingFailedEvent struct { + Category BrowserNetworkLoadingFailedEventCategory `json:"category"` + Data *BrowserNetworkLoadingFailedEventData `json:"data,omitempty"` // Source Provenance metadata identifying which producer emitted the event. Source BrowserEventSource `json:"source"` @@ -1984,18 +4019,24 @@ type BrowserInteractionClickEvent struct { Truncated *bool `json:"truncated,omitempty"` // Ts Event timestamp in Unix microseconds. - Ts int64 `json:"ts"` - Type BrowserInteractionClickEventType `json:"type"` + Ts int64 `json:"ts"` + Type BrowserNetworkLoadingFailedEventType `json:"type"` } -// BrowserInteractionClickEventCategory defines model for BrowserInteractionClickEvent.Category. -type BrowserInteractionClickEventCategory string +// BrowserNetworkLoadingFailedEventCategory defines model for BrowserNetworkLoadingFailedEvent.Category. +type BrowserNetworkLoadingFailedEventCategory string -// BrowserInteractionClickEventType defines model for BrowserInteractionClickEvent.Type. -type BrowserInteractionClickEventType string +// BrowserNetworkLoadingFailedEventType defines model for BrowserNetworkLoadingFailedEvent.Type. +type BrowserNetworkLoadingFailedEventType string + +// BrowserNetworkLoadingFailedEventData defines model for BrowserNetworkLoadingFailedEventData. +type BrowserNetworkLoadingFailedEventData struct { + // Canceled True if the request was canceled by the browser or page script. + Canceled bool `json:"canceled"` + + // ErrorText Network error description (e.g. net::ERR_CONNECTION_REFUSED). + ErrorText string `json:"error_text"` -// BrowserInteractionClickEventData defines model for BrowserInteractionClickEventData. -type BrowserInteractionClickEventData struct { // FrameId CDP frame identifier within the target. FrameId *string `json:"frame_id,omitempty"` @@ -2005,38 +4046,29 @@ type BrowserInteractionClickEventData struct { // NavSeq Monotonically increasing navigation sequence number, incremented on each top-level navigation within the target. NavSeq int64 `json:"nav_seq"` - // Selector CSS selector path to the clicked element. - Selector string `json:"selector"` + // RequestId CDP request identifier matching the originating network_request event. + RequestId string `json:"request_id"` + + // ResourceType CDP Network.ResourceType for the request, passed through as-is from Chrome. Known values include Document, Fetch, XHR, Script, Stylesheet, Image, Media, Font, TextTrack, EventSource, WebSocket, Manifest, Prefetch, Other, and more. + ResourceType *string `json:"resource_type,omitempty"` // SessionId CDP session identifier for the target connection. SessionId string `json:"session_id"` - // Tag HTML tag name of the clicked element in uppercase (e.g. BUTTON, A, DIV). - Tag string `json:"tag"` - // TargetId Browser target identifier (stable across navigations within a tab). TargetId string `json:"target_id"` // TargetType CDP target type of the page that produced the event. TargetType BrowserTargetType `json:"target_type"` - // Text Visible text content of the clicked element, trimmed. - Text *string `json:"text,omitempty"` - // Url URL relevant to this event; page URL for navigation and page events, request URL for network events. Url *string `json:"url,omitempty"` - - // X Viewport x-coordinate of the click in CSS pixels. - X int `json:"x"` - - // Y Viewport y-coordinate of the click in CSS pixels. - Y int `json:"y"` } -// BrowserInteractionKeyEvent A browser keyboard event captured via injected page script. -type BrowserInteractionKeyEvent struct { - Category BrowserInteractionKeyEventCategory `json:"category"` - Data *BrowserInteractionKeyEventData `json:"data,omitempty"` +// BrowserNetworkRequestEvent A browser network request sent event. +type BrowserNetworkRequestEvent struct { + Category BrowserNetworkRequestEventCategory `json:"category"` + Data *BrowserNetworkRequestEventData `json:"data,omitempty"` // Source Provenance metadata identifying which producer emitted the event. Source BrowserEventSource `json:"source"` @@ -2046,38 +4078,56 @@ type BrowserInteractionKeyEvent struct { // Ts Event timestamp in Unix microseconds. Ts int64 `json:"ts"` - Type BrowserInteractionKeyEventType `json:"type"` + Type BrowserNetworkRequestEventType `json:"type"` } -// BrowserInteractionKeyEventCategory defines model for BrowserInteractionKeyEvent.Category. -type BrowserInteractionKeyEventCategory string +// BrowserNetworkRequestEventCategory defines model for BrowserNetworkRequestEvent.Category. +type BrowserNetworkRequestEventCategory string -// BrowserInteractionKeyEventType defines model for BrowserInteractionKeyEvent.Type. -type BrowserInteractionKeyEventType string +// BrowserNetworkRequestEventType defines model for BrowserNetworkRequestEvent.Type. +type BrowserNetworkRequestEventType string + +// BrowserNetworkRequestEventData defines model for BrowserNetworkRequestEventData. +type BrowserNetworkRequestEventData struct { + // DocumentUrl URL of the document that initiated the request. + DocumentUrl string `json:"document_url"` -// BrowserInteractionKeyEventData defines model for BrowserInteractionKeyEventData. -type BrowserInteractionKeyEventData struct { // FrameId CDP frame identifier within the target. FrameId *string `json:"frame_id,omitempty"` - // Key Key value from the KeyboardEvent (e.g. Enter, Backspace, a). - Key string `json:"key"` + // Headers Request headers. + Headers BrowserHttpHeaders `json:"headers"` + + // InitiatorType CDP Initiator.type indicating what caused the request, passed through as-is from Chrome. Known values include script, parser, preload, and other. + InitiatorType string `json:"initiator_type"` + + // IsRedirect True if this request is the result of a redirect. + IsRedirect *bool `json:"is_redirect,omitempty"` // LoaderId CDP document loader identifier, reset on each navigation. LoaderId *string `json:"loader_id,omitempty"` + // Method HTTP method as sent on the wire (e.g. GET, POST). + Method string `json:"method"` + // NavSeq Monotonically increasing navigation sequence number, incremented on each top-level navigation within the target. NavSeq int64 `json:"nav_seq"` - // Selector CSS selector path to the element that had focus when the key was pressed. - Selector string `json:"selector"` + // PostData Request body for POST/PUT requests, if available. + PostData *string `json:"post_data,omitempty"` + + // RedirectUrl Original URL before the redirect, present when is_redirect is true. + RedirectUrl *string `json:"redirect_url,omitempty"` + + // RequestId CDP request identifier, unique within the session. + RequestId string `json:"request_id"` + + // ResourceType CDP Network.ResourceType for the request, passed through as-is from Chrome. Known values include Document, Fetch, XHR, Script, Stylesheet, Image, Media, Font, TextTrack, EventSource, WebSocket, Manifest, Prefetch, Other, and more. + ResourceType *string `json:"resource_type,omitempty"` // SessionId CDP session identifier for the target connection. SessionId string `json:"session_id"` - // Tag HTML tag name of the focused element in uppercase (e.g. INPUT, TEXTAREA, DIV). - Tag string `json:"tag"` - // TargetId Browser target identifier (stable across navigations within a tab). TargetId string `json:"target_id"` @@ -2088,10 +4138,10 @@ type BrowserInteractionKeyEventData struct { Url *string `json:"url,omitempty"` } -// BrowserInteractionScrollSettledEvent A browser scroll settled event emitted after scroll position stops changing, captured via injected page script. -type BrowserInteractionScrollSettledEvent struct { - Category BrowserInteractionScrollSettledEventCategory `json:"category"` - Data *BrowserInteractionScrollSettledEventData `json:"data,omitempty"` +// BrowserNetworkResponseEvent A browser network response received event. Fired after the response body is fully received, not when headers arrive. +type BrowserNetworkResponseEvent struct { + Category BrowserNetworkResponseEventCategory `json:"category"` + Data *BrowserNetworkResponseEventData `json:"data,omitempty"` // Source Provenance metadata identifying which producer emitted the event. Source BrowserEventSource `json:"source"` @@ -2100,61 +4150,68 @@ type BrowserInteractionScrollSettledEvent struct { Truncated *bool `json:"truncated,omitempty"` // Ts Event timestamp in Unix microseconds. - Ts int64 `json:"ts"` - Type BrowserInteractionScrollSettledEventType `json:"type"` + Ts int64 `json:"ts"` + Type BrowserNetworkResponseEventType `json:"type"` } -// BrowserInteractionScrollSettledEventCategory defines model for BrowserInteractionScrollSettledEvent.Category. -type BrowserInteractionScrollSettledEventCategory string +// BrowserNetworkResponseEventCategory defines model for BrowserNetworkResponseEvent.Category. +type BrowserNetworkResponseEventCategory string -// BrowserInteractionScrollSettledEventType defines model for BrowserInteractionScrollSettledEvent.Type. -type BrowserInteractionScrollSettledEventType string +// BrowserNetworkResponseEventType defines model for BrowserNetworkResponseEvent.Type. +type BrowserNetworkResponseEventType string + +// BrowserNetworkResponseEventData defines model for BrowserNetworkResponseEventData. +type BrowserNetworkResponseEventData struct { + // Body Truncated response body, present only for text MIME types. + Body *string `json:"body,omitempty"` -// BrowserInteractionScrollSettledEventData defines model for BrowserInteractionScrollSettledEventData. -type BrowserInteractionScrollSettledEventData struct { // FrameId CDP frame identifier within the target. FrameId *string `json:"frame_id,omitempty"` - // FromX Scroll x-position at the start of the scroll gesture in CSS pixels. - FromX int `json:"from_x"` - - // FromY Scroll y-position at the start of the scroll gesture in CSS pixels. - FromY int `json:"from_y"` + // Headers Response headers. + Headers BrowserHttpHeaders `json:"headers"` // LoaderId CDP document loader identifier, reset on each navigation. LoaderId *string `json:"loader_id,omitempty"` + // Method HTTP method of the original request. + Method string `json:"method"` + + // MimeType MIME type of the response (e.g. text/html, application/json). + MimeType *string `json:"mime_type,omitempty"` + // NavSeq Monotonically increasing navigation sequence number, incremented on each top-level navigation within the target. NavSeq int64 `json:"nav_seq"` + // RequestId CDP request identifier matching the originating network_request event. + RequestId string `json:"request_id"` + + // ResourceType CDP Network.ResourceType for the request, passed through as-is from Chrome. Known values include Document, Fetch, XHR, Script, Stylesheet, Image, Media, Font, TextTrack, EventSource, WebSocket, Manifest, Prefetch, Other, and more. + ResourceType *string `json:"resource_type,omitempty"` + // SessionId CDP session identifier for the target connection. SessionId string `json:"session_id"` + // Status HTTP response status code. + Status int `json:"status"` + + // StatusText HTTP response status text (e.g. OK, Not Found). + StatusText *string `json:"status_text,omitempty"` + // TargetId Browser target identifier (stable across navigations within a tab). TargetId string `json:"target_id"` - // TargetSelector CSS selector path to the scrolled element. - TargetSelector string `json:"target_selector"` - // TargetType CDP target type of the page that produced the event. TargetType BrowserTargetType `json:"target_type"` - // ToX Final scroll x-position after the gesture settled in CSS pixels. - ToX int `json:"to_x"` - - // ToY Final scroll y-position after the gesture settled in CSS pixels. - ToY int `json:"to_y"` - // Url URL relevant to this event; page URL for navigation and page events, request URL for network events. Url *string `json:"url,omitempty"` } -// BrowserLiveViewConnectEvent A live view client connected to the headful browser's WebRTC server (Neko). Headful only; not emitted for headless images. -type BrowserLiveViewConnectEvent struct { - Category BrowserLiveViewConnectEventCategory `json:"category"` - - // Data Per-session payload for `live_view_connect` events. - Data *BrowserLiveViewConnectEventData `json:"data,omitempty"` +// BrowserPageCrashedEvent A page's renderer process crashed (an "Aw, Snap!" failure) while the browser process itself stayed alive. Reported on the crashed page's session, with the session and target ids on `source.metadata`. Captured only while the `page` category is enabled. +type BrowserPageCrashedEvent struct { + Category BrowserPageCrashedEventCategory `json:"category"` + Data *BrowserPageCrashedEventData `json:"data,omitempty"` // Source Provenance metadata identifying which producer emitted the event. Source BrowserEventSource `json:"source"` @@ -2163,28 +4220,32 @@ type BrowserLiveViewConnectEvent struct { Truncated *bool `json:"truncated,omitempty"` // Ts Event timestamp in Unix microseconds. - Ts int64 `json:"ts"` - Type BrowserLiveViewConnectEventType `json:"type"` + Ts int64 `json:"ts"` + Type BrowserPageCrashedEventType `json:"type"` } -// BrowserLiveViewConnectEventCategory defines model for BrowserLiveViewConnectEvent.Category. -type BrowserLiveViewConnectEventCategory string +// BrowserPageCrashedEventCategory defines model for BrowserPageCrashedEvent.Category. +type BrowserPageCrashedEventCategory string -// BrowserLiveViewConnectEventType defines model for BrowserLiveViewConnectEvent.Type. -type BrowserLiveViewConnectEventType string +// BrowserPageCrashedEventType defines model for BrowserPageCrashedEvent.Type. +type BrowserPageCrashedEventType string -// BrowserLiveViewConnectEventData Per-session payload for `live_view_connect` events. -type BrowserLiveViewConnectEventData struct { - // SessionId Live view session identifier. Stable across reconnects, so a transient network blip can emit two events with the same `session_id`. - SessionId string `json:"session_id"` -} +// BrowserPageCrashedEventData defines model for BrowserPageCrashedEventData. +type BrowserPageCrashedEventData struct { + // TargetId CDP target identifier of the crashed page. + TargetId string `json:"target_id"` -// BrowserLiveViewDisconnectEvent A live view client disconnected from the headful browser's WebRTC server (Neko). Pair with `live_view_connect` by `session_id`. -type BrowserLiveViewDisconnectEvent struct { - Category BrowserLiveViewDisconnectEventCategory `json:"category"` + // TargetType CDP target type of the page that produced the event. + TargetType BrowserTargetType `json:"target_type"` - // Data Per-session payload for `live_view_disconnect` events. - Data *BrowserLiveViewDisconnectEventData `json:"data,omitempty"` + // Url URL the page was on when its renderer process crashed. + Url string `json:"url"` +} + +// BrowserPageDomContentLoadedEvent A browser DOMContentLoaded event (CDP Page.domContentEventFired). +type BrowserPageDomContentLoadedEvent struct { + Category BrowserPageDomContentLoadedEventCategory `json:"category"` + Data *BrowserPageDomContentLoadedEventData `json:"data,omitempty"` // Source Provenance metadata identifying which producer emitted the event. Source BrowserEventSource `json:"source"` @@ -2193,60 +4254,49 @@ type BrowserLiveViewDisconnectEvent struct { Truncated *bool `json:"truncated,omitempty"` // Ts Event timestamp in Unix microseconds. - Ts int64 `json:"ts"` - Type BrowserLiveViewDisconnectEventType `json:"type"` + Ts int64 `json:"ts"` + Type BrowserPageDomContentLoadedEventType `json:"type"` } -// BrowserLiveViewDisconnectEventCategory defines model for BrowserLiveViewDisconnectEvent.Category. -type BrowserLiveViewDisconnectEventCategory string - -// BrowserLiveViewDisconnectEventType defines model for BrowserLiveViewDisconnectEvent.Type. -type BrowserLiveViewDisconnectEventType string +// BrowserPageDomContentLoadedEventCategory defines model for BrowserPageDomContentLoadedEvent.Category. +type BrowserPageDomContentLoadedEventCategory string -// BrowserLiveViewDisconnectEventData Per-session payload for `live_view_disconnect` events. -type BrowserLiveViewDisconnectEventData struct { - // DurationMs Wall-clock duration of the connection in milliseconds. - DurationMs float32 `json:"duration_ms"` +// BrowserPageDomContentLoadedEventType defines model for BrowserPageDomContentLoadedEvent.Type. +type BrowserPageDomContentLoadedEventType string - // SessionId Live view session identifier; matches the corresponding `live_view_connect` event. - SessionId string `json:"session_id"` -} +// BrowserPageDomContentLoadedEventData defines model for BrowserPageDomContentLoadedEventData. +type BrowserPageDomContentLoadedEventData struct { + // CdpTimestamp Chrome monotonic clock value in seconds at which DOMContentLoaded fired, relative to browser process start (not Unix epoch). Use `ts` for wall-clock time. + CdpTimestamp float32 `json:"cdp_timestamp"` -// BrowserMonitorDisconnectedEvent The CDP connection to Chrome was lost. Telemetry events may be dropped until monitor_reconnected arrives. Treat any in-progress computed state (network_idle, page_layout_settled) as unreliable until then. -type BrowserMonitorDisconnectedEvent struct { - Category BrowserMonitorDisconnectedEventCategory `json:"category"` - Data *BrowserMonitorDisconnectedEventData `json:"data,omitempty"` + // FrameId CDP frame identifier within the target. + FrameId *string `json:"frame_id,omitempty"` - // Source Provenance metadata identifying which producer emitted the event. - Source BrowserEventSource `json:"source"` + // LoaderId CDP document loader identifier, reset on each navigation. + LoaderId *string `json:"loader_id,omitempty"` - // Truncated True if the data field was truncated due to size limits. - Truncated *bool `json:"truncated,omitempty"` + // NavSeq Monotonically increasing navigation sequence number, incremented on each top-level navigation within the target. + NavSeq int64 `json:"nav_seq"` - // Ts Event timestamp in Unix microseconds. - Ts int64 `json:"ts"` - Type BrowserMonitorDisconnectedEventType `json:"type"` -} + // SessionId CDP session identifier for the target connection. + SessionId string `json:"session_id"` -// BrowserMonitorDisconnectedEventCategory defines model for BrowserMonitorDisconnectedEvent.Category. -type BrowserMonitorDisconnectedEventCategory string + // TargetId Browser target identifier (stable across navigations within a tab). + TargetId string `json:"target_id"` -// BrowserMonitorDisconnectedEventType defines model for BrowserMonitorDisconnectedEvent.Type. -type BrowserMonitorDisconnectedEventType string + // TargetType CDP target type of the page that produced the event. + TargetType BrowserTargetType `json:"target_type"` -// BrowserMonitorDisconnectedEventData defines model for BrowserMonitorDisconnectedEventData. -type BrowserMonitorDisconnectedEventData struct { - // Reason Reason for the disconnection. chrome_restarted: Chrome process restarted. - Reason BrowserMonitorDisconnectedEventDataReason `json:"reason"` + // Url URL relevant to this event; page URL for navigation and page events, request URL for network events. + Url *string `json:"url,omitempty"` } -// BrowserMonitorDisconnectedEventDataReason Reason for the disconnection. chrome_restarted: Chrome process restarted. -type BrowserMonitorDisconnectedEventDataReason string +// BrowserPageLayoutSettledEvent A browser layout settled event emitted 1 second after page load with no intervening layout shifts, indicating visual stability. Each layout shift resets the 1-second timer. +type BrowserPageLayoutSettledEvent struct { + Category BrowserPageLayoutSettledEventCategory `json:"category"` -// BrowserMonitorInitFailedEvent The CDP session could not be initialized. -type BrowserMonitorInitFailedEvent struct { - Category BrowserMonitorInitFailedEventCategory `json:"category"` - Data *BrowserMonitorInitFailedEventData `json:"data,omitempty"` + // Data Browser event context stamped by the browser monitor onto all CDP-sourced events. Identifies the target, frame, and navigation epoch in which the event occurred. + Data *BrowserEventContext `json:"data,omitempty"` // Source Provenance metadata identifying which producer emitted the event. Source BrowserEventSource `json:"source"` @@ -2256,25 +4306,19 @@ type BrowserMonitorInitFailedEvent struct { // Ts Event timestamp in Unix microseconds. Ts int64 `json:"ts"` - Type BrowserMonitorInitFailedEventType `json:"type"` + Type BrowserPageLayoutSettledEventType `json:"type"` } -// BrowserMonitorInitFailedEventCategory defines model for BrowserMonitorInitFailedEvent.Category. -type BrowserMonitorInitFailedEventCategory string - -// BrowserMonitorInitFailedEventType defines model for BrowserMonitorInitFailedEvent.Type. -type BrowserMonitorInitFailedEventType string +// BrowserPageLayoutSettledEventCategory defines model for BrowserPageLayoutSettledEvent.Category. +type BrowserPageLayoutSettledEventCategory string -// BrowserMonitorInitFailedEventData defines model for BrowserMonitorInitFailedEventData. -type BrowserMonitorInitFailedEventData struct { - // Step The CDP method or initialization step that failed (e.g. Target.setAutoAttach). - Step string `json:"step"` -} +// BrowserPageLayoutSettledEventType defines model for BrowserPageLayoutSettledEvent.Type. +type BrowserPageLayoutSettledEventType string -// BrowserMonitorReconnectFailedEvent The CDP connection to Chrome could not be re-established after exhausting all reconnection attempts. No further telemetry events will arrive on this session. -type BrowserMonitorReconnectFailedEvent struct { - Category BrowserMonitorReconnectFailedEventCategory `json:"category"` - Data *BrowserMonitorReconnectFailedEventData `json:"data,omitempty"` +// BrowserPageLayoutShiftEvent A browser cumulative layout shift (CLS) event from the Performance Timeline API. +type BrowserPageLayoutShiftEvent struct { + Category BrowserPageLayoutShiftEventCategory `json:"category"` + Data *BrowserPageLayoutShiftEventData `json:"data,omitempty"` // Source Provenance metadata identifying which producer emitted the event. Source BrowserEventSource `json:"source"` @@ -2283,29 +4327,62 @@ type BrowserMonitorReconnectFailedEvent struct { Truncated *bool `json:"truncated,omitempty"` // Ts Event timestamp in Unix microseconds. - Ts int64 `json:"ts"` - Type BrowserMonitorReconnectFailedEventType `json:"type"` + Ts int64 `json:"ts"` + Type BrowserPageLayoutShiftEventType `json:"type"` } -// BrowserMonitorReconnectFailedEventCategory defines model for BrowserMonitorReconnectFailedEvent.Category. -type BrowserMonitorReconnectFailedEventCategory string +// BrowserPageLayoutShiftEventCategory defines model for BrowserPageLayoutShiftEvent.Category. +type BrowserPageLayoutShiftEventCategory string -// BrowserMonitorReconnectFailedEventType defines model for BrowserMonitorReconnectFailedEvent.Type. -type BrowserMonitorReconnectFailedEventType string +// BrowserPageLayoutShiftEventType defines model for BrowserPageLayoutShiftEvent.Type. +type BrowserPageLayoutShiftEventType string + +// BrowserPageLayoutShiftEventData defines model for BrowserPageLayoutShiftEventData. +type BrowserPageLayoutShiftEventData struct { + // Duration Duration of the layout shift entry in milliseconds (always 0 for layout shifts per spec). + Duration float32 `json:"duration"` + + // FrameId CDP frame identifier within the target. + FrameId *string `json:"frame_id,omitempty"` + + // LayoutShiftDetails PerformanceLayoutShift attributes from the Performance Timeline entry. + LayoutShiftDetails *struct { + // HadRecentInput True if the layout shift was preceded by user input within 500ms, excluding it from CLS. + HadRecentInput *bool `json:"had_recent_input,omitempty"` + + // Value Layout shift score for this entry (contribution to CLS). + Value *float32 `json:"value,omitempty"` + } `json:"layout_shift_details,omitempty"` + + // LoaderId CDP document loader identifier, reset on each navigation. + LoaderId *string `json:"loader_id,omitempty"` + + // NavSeq Monotonically increasing navigation sequence number, incremented on each top-level navigation within the target. + NavSeq int64 `json:"nav_seq"` + + // SessionId CDP session identifier for the target connection. + SessionId string `json:"session_id"` + + // SourceFrameId CDP frame identifier of the frame where the layout shift occurred. + SourceFrameId string `json:"source_frame_id"` + + // TargetId Browser target identifier (stable across navigations within a tab). + TargetId string `json:"target_id"` + + // TargetType CDP target type of the page that produced the event. + TargetType BrowserTargetType `json:"target_type"` + + // Time Performance Timeline timestamp of the layout shift in milliseconds. + Time float32 `json:"time"` -// BrowserMonitorReconnectFailedEventData defines model for BrowserMonitorReconnectFailedEventData. -type BrowserMonitorReconnectFailedEventData struct { - // Reason Reason for the reconnection failure. reconnect_exhausted: all retry attempts were used up without successfully restoring the CDP connection. - Reason BrowserMonitorReconnectFailedEventDataReason `json:"reason"` + // Url URL relevant to this event; page URL for navigation and page events, request URL for network events. + Url *string `json:"url,omitempty"` } -// BrowserMonitorReconnectFailedEventDataReason Reason for the reconnection failure. reconnect_exhausted: all retry attempts were used up without successfully restoring the CDP connection. -type BrowserMonitorReconnectFailedEventDataReason string - -// BrowserMonitorReconnectedEvent The CDP connection to Chrome was successfully re-established after a disconnection. Events emitted during the gap are lost. Computed state is reset, so navigation and network tracking restart fresh from this point. -type BrowserMonitorReconnectedEvent struct { - Category BrowserMonitorReconnectedEventCategory `json:"category"` - Data *BrowserMonitorReconnectedEventData `json:"data,omitempty"` +// BrowserPageLcpEvent A browser Largest Contentful Paint (LCP) event from the Performance Timeline API. +type BrowserPageLcpEvent struct { + Category BrowserPageLcpEventCategory `json:"category"` + Data *BrowserPageLcpEventData `json:"data,omitempty"` // Source Provenance metadata identifying which producer emitted the event. Source BrowserEventSource `json:"source"` @@ -2314,78 +4391,71 @@ type BrowserMonitorReconnectedEvent struct { Truncated *bool `json:"truncated,omitempty"` // Ts Event timestamp in Unix microseconds. - Ts int64 `json:"ts"` - Type BrowserMonitorReconnectedEventType `json:"type"` + Ts int64 `json:"ts"` + Type BrowserPageLcpEventType `json:"type"` } -// BrowserMonitorReconnectedEventCategory defines model for BrowserMonitorReconnectedEvent.Category. -type BrowserMonitorReconnectedEventCategory string +// BrowserPageLcpEventCategory defines model for BrowserPageLcpEvent.Category. +type BrowserPageLcpEventCategory string -// BrowserMonitorReconnectedEventType defines model for BrowserMonitorReconnectedEvent.Type. -type BrowserMonitorReconnectedEventType string +// BrowserPageLcpEventType defines model for BrowserPageLcpEvent.Type. +type BrowserPageLcpEventType string -// BrowserMonitorReconnectedEventData defines model for BrowserMonitorReconnectedEventData. -type BrowserMonitorReconnectedEventData struct { - // ReconnectDurationMs Wall-clock time in milliseconds taken to reconnect after the disconnection. - ReconnectDurationMs int64 `json:"reconnect_duration_ms"` -} +// BrowserPageLcpEventData defines model for BrowserPageLcpEventData. +type BrowserPageLcpEventData struct { + // FrameId CDP frame identifier within the target. + FrameId *string `json:"frame_id,omitempty"` -// BrowserMonitorScreenshotEvent A periodic screenshot of the browser viewport. -type BrowserMonitorScreenshotEvent struct { - Category BrowserMonitorScreenshotEventCategory `json:"category"` - Data *BrowserMonitorScreenshotEventData `json:"data,omitempty"` + // LcpDetails LargestContentfulPaint attributes from the Performance Timeline entry. + LcpDetails *struct { + // ElementId id attribute of the LCP element, if present. + ElementId *string `json:"element_id,omitempty"` - // Source Provenance metadata identifying which producer emitted the event. - Source BrowserEventSource `json:"source"` + // LoadTime Load time of the LCP element in milliseconds. + LoadTime *float32 `json:"load_time,omitempty"` - // Truncated True if the data field was truncated due to size limits. - Truncated *bool `json:"truncated,omitempty"` + // NodeId CDP DOM node identifier of the LCP element. + NodeId *int `json:"node_id,omitempty"` - // Ts Event timestamp in Unix microseconds. - Ts int64 `json:"ts"` - Type BrowserMonitorScreenshotEventType `json:"type"` -} + // RenderTime Render time of the LCP element in milliseconds; 0 for cross-origin images without Timing-Allow-Origin. + RenderTime *float32 `json:"render_time,omitempty"` -// BrowserMonitorScreenshotEventCategory defines model for BrowserMonitorScreenshotEvent.Category. -type BrowserMonitorScreenshotEventCategory string + // Size Visible area of the LCP element in pixels squared. + Size *float32 `json:"size,omitempty"` -// BrowserMonitorScreenshotEventType defines model for BrowserMonitorScreenshotEvent.Type. -type BrowserMonitorScreenshotEventType string + // Url URL of the LCP element for image or video elements. + Url *string `json:"url,omitempty"` + } `json:"lcp_details,omitempty"` -// BrowserMonitorScreenshotEventData defines model for BrowserMonitorScreenshotEventData. -type BrowserMonitorScreenshotEventData struct { - // Png Base64-encoded PNG screenshot of the browser viewport. - Png []byte `json:"png"` -} + // LoaderId CDP document loader identifier, reset on each navigation. + LoaderId *string `json:"loader_id,omitempty"` -// BrowserNetworkIdleEvent A browser network idle event emitted after a 500ms quiet period with no in-flight HTTP requests. -type BrowserNetworkIdleEvent struct { - Category BrowserNetworkIdleEventCategory `json:"category"` + // NavSeq Monotonically increasing navigation sequence number, incremented on each top-level navigation within the target. + NavSeq int64 `json:"nav_seq"` - // Data Browser event context stamped by the browser monitor onto all CDP-sourced events. Identifies the target, frame, and navigation epoch in which the event occurred. - Data *BrowserEventContext `json:"data,omitempty"` + // SessionId CDP session identifier for the target connection. + SessionId string `json:"session_id"` - // Source Provenance metadata identifying which producer emitted the event. - Source BrowserEventSource `json:"source"` + // SourceFrameId CDP frame identifier of the frame where the LCP element was rendered. + SourceFrameId string `json:"source_frame_id"` - // Truncated True if the data field was truncated due to size limits. - Truncated *bool `json:"truncated,omitempty"` + // TargetId Browser target identifier (stable across navigations within a tab). + TargetId string `json:"target_id"` - // Ts Event timestamp in Unix microseconds. - Ts int64 `json:"ts"` - Type BrowserNetworkIdleEventType `json:"type"` -} + // TargetType CDP target type of the page that produced the event. + TargetType BrowserTargetType `json:"target_type"` -// BrowserNetworkIdleEventCategory defines model for BrowserNetworkIdleEvent.Category. -type BrowserNetworkIdleEventCategory string + // Time Performance Timeline timestamp of the LCP entry in milliseconds. + Time float32 `json:"time"` -// BrowserNetworkIdleEventType defines model for BrowserNetworkIdleEvent.Type. -type BrowserNetworkIdleEventType string + // Url URL relevant to this event; page URL for navigation and page events, request URL for network events. + Url *string `json:"url,omitempty"` +} -// BrowserNetworkLoadingFailedEvent A browser network loading failed event. If the request was already in flight when CDP attached (no prior `network_request` was emitted for it), `url`, `frame_id`, `loader_id`, and `resource_type` are absent; `BrowserEventContext` is partially populated in that case. -type BrowserNetworkLoadingFailedEvent struct { - Category BrowserNetworkLoadingFailedEventCategory `json:"category"` - Data *BrowserNetworkLoadingFailedEventData `json:"data,omitempty"` +// BrowserPageLoadEvent A browser page load event (CDP Page.loadEventFired). +type BrowserPageLoadEvent struct { + Category BrowserPageLoadEventCategory `json:"category"` + Data *BrowserPageLoadEventData `json:"data,omitempty"` // Source Provenance metadata identifying which producer emitted the event. Source BrowserEventSource `json:"source"` @@ -2394,23 +4464,20 @@ type BrowserNetworkLoadingFailedEvent struct { Truncated *bool `json:"truncated,omitempty"` // Ts Event timestamp in Unix microseconds. - Ts int64 `json:"ts"` - Type BrowserNetworkLoadingFailedEventType `json:"type"` + Ts int64 `json:"ts"` + Type BrowserPageLoadEventType `json:"type"` } -// BrowserNetworkLoadingFailedEventCategory defines model for BrowserNetworkLoadingFailedEvent.Category. -type BrowserNetworkLoadingFailedEventCategory string - -// BrowserNetworkLoadingFailedEventType defines model for BrowserNetworkLoadingFailedEvent.Type. -type BrowserNetworkLoadingFailedEventType string +// BrowserPageLoadEventCategory defines model for BrowserPageLoadEvent.Category. +type BrowserPageLoadEventCategory string -// BrowserNetworkLoadingFailedEventData defines model for BrowserNetworkLoadingFailedEventData. -type BrowserNetworkLoadingFailedEventData struct { - // Canceled True if the request was canceled by the browser or page script. - Canceled bool `json:"canceled"` +// BrowserPageLoadEventType defines model for BrowserPageLoadEvent.Type. +type BrowserPageLoadEventType string - // ErrorText Network error description (e.g. net::ERR_CONNECTION_REFUSED). - ErrorText string `json:"error_text"` +// BrowserPageLoadEventData defines model for BrowserPageLoadEventData. +type BrowserPageLoadEventData struct { + // CdpTimestamp Chrome monotonic clock value in seconds at which the load event fired, relative to browser process start (not Unix epoch). Use `ts` for wall-clock time. + CdpTimestamp float32 `json:"cdp_timestamp"` // FrameId CDP frame identifier within the target. FrameId *string `json:"frame_id,omitempty"` @@ -2421,12 +4488,6 @@ type BrowserNetworkLoadingFailedEventData struct { // NavSeq Monotonically increasing navigation sequence number, incremented on each top-level navigation within the target. NavSeq int64 `json:"nav_seq"` - // RequestId CDP request identifier matching the originating network_request event. - RequestId string `json:"request_id"` - - // ResourceType CDP Network.ResourceType for the request, passed through as-is from Chrome. Known values include Document, Fetch, XHR, Script, Stylesheet, Image, Media, Font, TextTrack, EventSource, WebSocket, Manifest, Prefetch, Other, and more. - ResourceType *string `json:"resource_type,omitempty"` - // SessionId CDP session identifier for the target connection. SessionId string `json:"session_id"` @@ -2440,10 +4501,10 @@ type BrowserNetworkLoadingFailedEventData struct { Url *string `json:"url,omitempty"` } -// BrowserNetworkRequestEvent A browser network request sent event. -type BrowserNetworkRequestEvent struct { - Category BrowserNetworkRequestEventCategory `json:"category"` - Data *BrowserNetworkRequestEventData `json:"data,omitempty"` +// BrowserPageNavigationEvent A browser page navigation started event (CDP Page.frameNavigated). Carries nav context fields inline but not nav_seq, as this event resets the navigation epoch. +type BrowserPageNavigationEvent struct { + Category BrowserPageNavigationEventCategory `json:"category"` + Data *BrowserPageNavigationEventData `json:"data,omitempty"` // Source Provenance metadata identifying which producer emitted the event. Source BrowserEventSource `json:"source"` @@ -2453,70 +4514,109 @@ type BrowserNetworkRequestEvent struct { // Ts Event timestamp in Unix microseconds. Ts int64 `json:"ts"` - Type BrowserNetworkRequestEventType `json:"type"` + Type BrowserPageNavigationEventType `json:"type"` } -// BrowserNetworkRequestEventCategory defines model for BrowserNetworkRequestEvent.Category. -type BrowserNetworkRequestEventCategory string +// BrowserPageNavigationEventCategory defines model for BrowserPageNavigationEvent.Category. +type BrowserPageNavigationEventCategory string -// BrowserNetworkRequestEventType defines model for BrowserNetworkRequestEvent.Type. -type BrowserNetworkRequestEventType string +// BrowserPageNavigationEventType defines model for BrowserPageNavigationEvent.Type. +type BrowserPageNavigationEventType string -// BrowserNetworkRequestEventData defines model for BrowserNetworkRequestEventData. -type BrowserNetworkRequestEventData struct { - // DocumentUrl URL of the document that initiated the request. - DocumentUrl string `json:"document_url"` +// BrowserPageNavigationEventData defines model for BrowserPageNavigationEventData. +type BrowserPageNavigationEventData struct { + // FrameId CDP frame identifier of the navigated frame. + FrameId string `json:"frame_id"` - // FrameId CDP frame identifier within the target. - FrameId *string `json:"frame_id,omitempty"` + // LoaderId New CDP document loader identifier assigned for this navigation. + LoaderId string `json:"loader_id"` - // Headers Request headers. - Headers BrowserHttpHeaders `json:"headers"` + // ParentFrameId Parent frame identifier for subframe navigations; absent for top-level navigations. + ParentFrameId *string `json:"parent_frame_id,omitempty"` - // InitiatorType CDP Initiator.type indicating what caused the request, passed through as-is from Chrome. Known values include script, parser, preload, and other. - InitiatorType string `json:"initiator_type"` + // SessionId CDP session identifier. + SessionId string `json:"session_id"` - // IsRedirect True if this request is the result of a redirect. - IsRedirect *bool `json:"is_redirect,omitempty"` + // TargetId Browser target identifier. + TargetId string `json:"target_id"` - // LoaderId CDP document loader identifier, reset on each navigation. - LoaderId *string `json:"loader_id,omitempty"` + // TargetType CDP target type of the page that produced the event. + TargetType BrowserTargetType `json:"target_type"` - // Method HTTP method as sent on the wire (e.g. GET, POST). - Method string `json:"method"` + // Url URL navigated to. + Url string `json:"url"` +} - // NavSeq Monotonically increasing navigation sequence number, incremented on each top-level navigation within the target. - NavSeq int64 `json:"nav_seq"` +// BrowserPageNavigationSettledEvent Emitted when page_dom_content_loaded and page_layout_settled have both fired for the same navigation, indicating the page is loaded and visually stable. Independent of network_idle; a single pending request does not block it. +type BrowserPageNavigationSettledEvent struct { + Category BrowserPageNavigationSettledEventCategory `json:"category"` - // PostData Request body for POST/PUT requests, if available. - PostData *string `json:"post_data,omitempty"` + // Data Browser event context stamped by the browser monitor onto all CDP-sourced events. Identifies the target, frame, and navigation epoch in which the event occurred. + Data *BrowserEventContext `json:"data,omitempty"` - // RedirectUrl Original URL before the redirect, present when is_redirect is true. - RedirectUrl *string `json:"redirect_url,omitempty"` + // Source Provenance metadata identifying which producer emitted the event. + Source BrowserEventSource `json:"source"` - // RequestId CDP request identifier, unique within the session. - RequestId string `json:"request_id"` + // Truncated True if the data field was truncated due to size limits. + Truncated *bool `json:"truncated,omitempty"` - // ResourceType CDP Network.ResourceType for the request, passed through as-is from Chrome. Known values include Document, Fetch, XHR, Script, Stylesheet, Image, Media, Font, TextTrack, EventSource, WebSocket, Manifest, Prefetch, Other, and more. - ResourceType *string `json:"resource_type,omitempty"` + // Ts Event timestamp in Unix microseconds. + Ts int64 `json:"ts"` + Type BrowserPageNavigationSettledEventType `json:"type"` +} - // SessionId CDP session identifier for the target connection. - SessionId string `json:"session_id"` +// BrowserPageNavigationSettledEventCategory defines model for BrowserPageNavigationSettledEvent.Category. +type BrowserPageNavigationSettledEventCategory string - // TargetId Browser target identifier (stable across navigations within a tab). +// BrowserPageNavigationSettledEventType defines model for BrowserPageNavigationSettledEvent.Type. +type BrowserPageNavigationSettledEventType string + +// BrowserPageTabOpenedEvent A new browser tab or target was opened (CDP Target.attachedToTarget for page targets). Fires before a CDP session is attached to the new target, so `session_id`, `frame_id`, `loader_id`, and `nav_seq` are absent; this event does not compose `BrowserEventContext`. Consumers reading context fields generically should treat it as a special case. +type BrowserPageTabOpenedEvent struct { + Category BrowserPageTabOpenedEventCategory `json:"category"` + Data *BrowserPageTabOpenedEventData `json:"data,omitempty"` + + // Source Provenance metadata identifying which producer emitted the event. + Source BrowserEventSource `json:"source"` + + // Truncated True if the data field was truncated due to size limits. + Truncated *bool `json:"truncated,omitempty"` + + // Ts Event timestamp in Unix microseconds. + Ts int64 `json:"ts"` + Type BrowserPageTabOpenedEventType `json:"type"` +} + +// BrowserPageTabOpenedEventCategory defines model for BrowserPageTabOpenedEvent.Category. +type BrowserPageTabOpenedEventCategory string + +// BrowserPageTabOpenedEventType defines model for BrowserPageTabOpenedEvent.Type. +type BrowserPageTabOpenedEventType string + +// BrowserPageTabOpenedEventData defines model for BrowserPageTabOpenedEventData. +type BrowserPageTabOpenedEventData struct { + // OpenerId Target identifier of the tab that opened this one, if any. + OpenerId *string `json:"opener_id,omitempty"` + + // TargetId CDP target identifier for the newly opened tab. TargetId string `json:"target_id"` // TargetType CDP target type of the page that produced the event. TargetType BrowserTargetType `json:"target_type"` - // Url URL relevant to this event; page URL for navigation and page events, request URL for network events. - Url *string `json:"url,omitempty"` + // Title Initial page title of the new tab. + Title *string `json:"title,omitempty"` + + // Url Initial URL of the new tab. + Url string `json:"url"` } -// BrowserNetworkResponseEvent A browser network response received event. Fired after the response body is fully received, not when headers arrive. -type BrowserNetworkResponseEvent struct { - Category BrowserNetworkResponseEventCategory `json:"category"` - Data *BrowserNetworkResponseEventData `json:"data,omitempty"` +// BrowserPlatformApiCallEvent A call that manages the browser VM rather than driving the browser, handled by the kernel-images-api server: recording lifecycle, filesystem and process management, telemetry and browser configuration. These are mostly platform-induced (e.g. profile save, replay capture) rather than agent actions. +type BrowserPlatformApiCallEvent struct { + Category BrowserPlatformApiCallEventCategory `json:"category"` + + // Data Per-call payload for `platform_api_call` events. Metadata only: a platform call carries no submitted content, so there is no `code` field as there is on `api_call`. + Data *BrowserPlatformApiCallEventData `json:"data,omitempty"` // Source Provenance metadata identifying which producer emitted the event. Source BrowserEventSource `json:"source"` @@ -2526,67 +4626,75 @@ type BrowserNetworkResponseEvent struct { // Ts Event timestamp in Unix microseconds. Ts int64 `json:"ts"` - Type BrowserNetworkResponseEventType `json:"type"` + Type BrowserPlatformApiCallEventType `json:"type"` } -// BrowserNetworkResponseEventCategory defines model for BrowserNetworkResponseEvent.Category. -type BrowserNetworkResponseEventCategory string - -// BrowserNetworkResponseEventType defines model for BrowserNetworkResponseEvent.Type. -type BrowserNetworkResponseEventType string +// BrowserPlatformApiCallEventCategory defines model for BrowserPlatformApiCallEvent.Category. +type BrowserPlatformApiCallEventCategory string -// BrowserNetworkResponseEventData defines model for BrowserNetworkResponseEventData. -type BrowserNetworkResponseEventData struct { - // Body Truncated response body, present only for text MIME types. - Body *string `json:"body,omitempty"` +// BrowserPlatformApiCallEventType defines model for BrowserPlatformApiCallEvent.Type. +type BrowserPlatformApiCallEventType string - // FrameId CDP frame identifier within the target. - FrameId *string `json:"frame_id,omitempty"` +// BrowserPlatformApiCallEventData Per-call payload for `platform_api_call` events. Metadata only: a platform call carries no submitted content, so there is no `code` field as there is on `api_call`. +type BrowserPlatformApiCallEventData struct { + // DurationMs Wall-clock duration of the handler in milliseconds. + DurationMs float32 `json:"duration_ms"` - // Headers Response headers. - Headers BrowserHttpHeaders `json:"headers"` + // OperationId Matched route's operation, named as the server names its handler (e.g. `ProcessExec`, `StartRecording`). + OperationId string `json:"operation_id"` - // LoaderId CDP document loader identifier, reset on each navigation. - LoaderId *string `json:"loader_id,omitempty"` + // RequestId Per-request identifier from the kernel-images-api request middleware. + RequestId string `json:"request_id"` - // Method HTTP method of the original request. - Method string `json:"method"` + // Status HTTP response status code. + Status int `json:"status"` +} - // MimeType MIME type of the response (e.g. text/html, application/json). - MimeType *string `json:"mime_type,omitempty"` +// BrowserServiceCrashedEvent A managed service exited unexpectedly. Intentional stops (e.g. operator-initiated shutdown) do not produce this event — only unexpected exits and terminal restart-give-up transitions do. +type BrowserServiceCrashedEvent struct { + Category BrowserServiceCrashedEventCategory `json:"category"` - // NavSeq Monotonically increasing navigation sequence number, incremented on each top-level navigation within the target. - NavSeq int64 `json:"nav_seq"` + // Data Per-crash payload for `service_crashed` events. Exit code and signal are not exposed by the underlying process manager on this channel, so only the service identity, the lifecycle phase the crash occurred in, and (when available) the PID are reported. + Data *BrowserServiceCrashedEventData `json:"data,omitempty"` - // RequestId CDP request identifier matching the originating network_request event. - RequestId string `json:"request_id"` + // Source Provenance metadata identifying which producer emitted the event. + Source BrowserEventSource `json:"source"` - // ResourceType CDP Network.ResourceType for the request, passed through as-is from Chrome. Known values include Document, Fetch, XHR, Script, Stylesheet, Image, Media, Font, TextTrack, EventSource, WebSocket, Manifest, Prefetch, Other, and more. - ResourceType *string `json:"resource_type,omitempty"` + // Truncated True if the data field was truncated due to size limits. + Truncated *bool `json:"truncated,omitempty"` - // SessionId CDP session identifier for the target connection. - SessionId string `json:"session_id"` + // Ts Event timestamp in Unix microseconds. + Ts int64 `json:"ts"` + Type BrowserServiceCrashedEventType `json:"type"` +} - // Status HTTP response status code. - Status int `json:"status"` +// BrowserServiceCrashedEventCategory defines model for BrowserServiceCrashedEvent.Category. +type BrowserServiceCrashedEventCategory string - // StatusText HTTP response status text (e.g. OK, Not Found). - StatusText *string `json:"status_text,omitempty"` +// BrowserServiceCrashedEventType defines model for BrowserServiceCrashedEvent.Type. +type BrowserServiceCrashedEventType string - // TargetId Browser target identifier (stable across navigations within a tab). - TargetId string `json:"target_id"` +// BrowserServiceCrashedEventData Per-crash payload for `service_crashed` events. Exit code and signal are not exposed by the underlying process manager on this channel, so only the service identity, the lifecycle phase the crash occurred in, and (when available) the PID are reported. +type BrowserServiceCrashedEventData struct { + // Phase Lifecycle phase the crash occurred in. `startup` means the process died before it ever reached a healthy running state. `running` means a previously healthy process died unexpectedly. `gave_up` means the process manager exhausted its restart attempts and stopped trying; no further `service_crashed` events will fire for this service until something restarts it. + Phase BrowserServiceCrashedEventDataPhase `json:"phase"` - // TargetType CDP target type of the page that produced the event. - TargetType BrowserTargetType `json:"target_type"` + // Pid PID of the crashed process. Absent when the process manager gave up after exhausting restart attempts and is no longer tracking a live PID. + Pid *int `json:"pid,omitempty"` - // Url URL relevant to this event; page URL for navigation and page events, request URL for network events. - Url *string `json:"url,omitempty"` + // ServiceName Program name of the crashed service (e.g. `chromium`, `mutter`, `kernel-images-api`). + ServiceName string `json:"service_name"` } -// BrowserPageCrashedEvent A page's renderer process crashed (an "Aw, Snap!" failure) while the browser process itself stayed alive. Reported on the crashed page's session, with the session and target ids on `source.metadata`. Captured only while the `page` category is enabled. -type BrowserPageCrashedEvent struct { - Category BrowserPageCrashedEventCategory `json:"category"` - Data *BrowserPageCrashedEventData `json:"data,omitempty"` +// BrowserServiceCrashedEventDataPhase Lifecycle phase the crash occurred in. `startup` means the process died before it ever reached a healthy running state. `running` means a previously healthy process died unexpectedly. `gave_up` means the process manager exhausted its restart attempts and stopped trying; no further `service_crashed` events will fire for this service until something restarts it. +type BrowserServiceCrashedEventDataPhase string + +// BrowserSystemOomKillEvent The Linux kernel OOM-killer terminated a process inside the VM. Sourced from `/dev/kmsg`. Fires for any process killed by the kernel due to memory exhaustion, including Chrome renderer subprocesses that are not supervised. +type BrowserSystemOomKillEvent struct { + Category BrowserSystemOomKillEventCategory `json:"category"` + + // Data Per-kill payload for `system_oom_kill` events. + Data *BrowserSystemOomKillEventData `json:"data,omitempty"` // Source Provenance metadata identifying which producer emitted the event. Source BrowserEventSource `json:"source"` @@ -2595,1561 +4703,2265 @@ type BrowserPageCrashedEvent struct { Truncated *bool `json:"truncated,omitempty"` // Ts Event timestamp in Unix microseconds. - Ts int64 `json:"ts"` - Type BrowserPageCrashedEventType `json:"type"` + Ts int64 `json:"ts"` + Type BrowserSystemOomKillEventType `json:"type"` } -// BrowserPageCrashedEventCategory defines model for BrowserPageCrashedEvent.Category. -type BrowserPageCrashedEventCategory string +// BrowserSystemOomKillEventCategory defines model for BrowserSystemOomKillEvent.Category. +type BrowserSystemOomKillEventCategory string -// BrowserPageCrashedEventType defines model for BrowserPageCrashedEvent.Type. -type BrowserPageCrashedEventType string +// BrowserSystemOomKillEventType defines model for BrowserSystemOomKillEvent.Type. +type BrowserSystemOomKillEventType string -// BrowserPageCrashedEventData defines model for BrowserPageCrashedEventData. -type BrowserPageCrashedEventData struct { - // TargetId CDP target identifier of the crashed page. - TargetId string `json:"target_id"` +// BrowserSystemOomKillEventData Per-kill payload for `system_oom_kill` events. +type BrowserSystemOomKillEventData struct { + // Constraint Why the kernel decided to OOM-kill. `none` means global memory exhaustion; `memcg` means a cgroup memory limit was hit; `cpuset` / `memory_policy` are NUMA/policy-driven kills. Absent on kernels older than 5.0 which did not emit the structured `oom-kill:` line. + Constraint *BrowserSystemOomKillEventDataConstraint `json:"constraint,omitempty"` - // TargetType CDP target type of the page that produced the event. - TargetType BrowserTargetType `json:"target_type"` + // MemFreeKb Free system memory in KiB at the time of the kill, derived from the `free:N` field in the kernel's Mem-Info dump. Assumes a 4 KiB page size. Does not include reclaimable caches, so a small value with a large `mem_total_kb` may still mean the system was not under hard pressure. Absent if the kernel did not emit a parseable Mem-Info section. + MemFreeKb *int `json:"mem_free_kb,omitempty"` - // Url URL the page was on when its renderer process crashed. - Url string `json:"url"` + // MemTotalKb Total system memory in KiB at the time of the kill, derived from the `N pages RAM` line in the kernel's Mem-Info dump. Assumes a 4 KiB page size. Absent if the kernel did not emit a parseable Mem-Info section. + MemTotalKb *int `json:"mem_total_kb,omitempty"` + + // Pid PID of the killed process. + Pid int `json:"pid"` + + // ProcessName Comm of the killed process as reported by the kernel (max 15 chars, truncated by the kernel). + ProcessName string `json:"process_name"` + + // RssKb Resident set size of the killed process in KiB (sum of anon-rss, file-rss, and shmem-rss). This is the physical memory the process was using at the time of the kill. + RssKb int `json:"rss_kb"` + + // TopTasks Top processes by resident-set-size at the moment of the kill, sorted descending. Sourced from the kernel's `Tasks state` table. Empty if the kernel did not emit the table. Capped at 5 entries to bound payload size. + TopTasks *[]BrowserSystemOomKillTask `json:"top_tasks,omitempty"` + + // TriggerPid PID of the triggering process. Absent if the kernel did not emit the standard `CPU: N PID: N Comm:` header line. + TriggerPid *int `json:"trigger_pid,omitempty"` + + // TriggerProcessName Comm of the process whose allocation request caused the kernel to invoke the OOM-killer. Often the same as `process_name` (the kernel killed the requester) but can differ when the kernel chose a different victim. Max 15 chars, truncated by the kernel. + TriggerProcessName *string `json:"trigger_process_name,omitempty"` } -// BrowserPageDomContentLoadedEvent A browser DOMContentLoaded event (CDP Page.domContentEventFired). -type BrowserPageDomContentLoadedEvent struct { - Category BrowserPageDomContentLoadedEventCategory `json:"category"` - Data *BrowserPageDomContentLoadedEventData `json:"data,omitempty"` +// BrowserSystemOomKillEventDataConstraint Why the kernel decided to OOM-kill. `none` means global memory exhaustion; `memcg` means a cgroup memory limit was hit; `cpuset` / `memory_policy` are NUMA/policy-driven kills. Absent on kernels older than 5.0 which did not emit the structured `oom-kill:` line. +type BrowserSystemOomKillEventDataConstraint string - // Source Provenance metadata identifying which producer emitted the event. - Source BrowserEventSource `json:"source"` +// BrowserSystemOomKillTask A single process entry from the kernel's `Tasks state` dump. +type BrowserSystemOomKillTask struct { + // Name Comm of the process (max 15 chars, truncated by the kernel). + Name string `json:"name"` - // Truncated True if the data field was truncated due to size limits. - Truncated *bool `json:"truncated,omitempty"` + // Pid PID of the process. + Pid int `json:"pid"` - // Ts Event timestamp in Unix microseconds. - Ts int64 `json:"ts"` - Type BrowserPageDomContentLoadedEventType `json:"type"` + // RssKb Resident set size in KiB at the moment of the kill. + RssKb int `json:"rss_kb"` } -// BrowserPageDomContentLoadedEventCategory defines model for BrowserPageDomContentLoadedEvent.Category. -type BrowserPageDomContentLoadedEventCategory string +// BrowserTargetType CDP target type of the page that produced the event. +type BrowserTargetType string -// BrowserPageDomContentLoadedEventType defines model for BrowserPageDomContentLoadedEvent.Type. -type BrowserPageDomContentLoadedEventType string +// BrowserTelemetryCategoriesConfig Per-category telemetry capture settings for browser events. +type BrowserTelemetryCategoriesConfig struct { + // Captcha Captcha solve attempt outcomes. + Captcha *BrowserTelemetryCategoryConfig `json:"captcha,omitempty"` -// BrowserPageDomContentLoadedEventData defines model for BrowserPageDomContentLoadedEventData. -type BrowserPageDomContentLoadedEventData struct { - // CdpTimestamp Chrome monotonic clock value in seconds at which DOMContentLoaded fired, relative to browser process start (not Unix epoch). Use `ts` for wall-clock time. - CdpTimestamp float32 `json:"cdp_timestamp"` + // Connection Client attach/detach lifecycle for the CDP proxy and live view. + Connection *BrowserTelemetryCategoryConfig `json:"connection,omitempty"` - // FrameId CDP frame identifier within the target. - FrameId *string `json:"frame_id,omitempty"` + // Console Console output (log, warn, error) and uncaught exceptions. + Console *BrowserTelemetryCategoryConfig `json:"console,omitempty"` - // LoaderId CDP document loader identifier, reset on each navigation. - LoaderId *string `json:"loader_id,omitempty"` + // Control Agent-driven actions against the browser — computer-control calls, Playwright code execution, screenshots, clipboard access, and browser-control commands sent over the CDP proxy. + Control *BrowserTelemetryControlConfig `json:"control,omitempty"` - // NavSeq Monotonically increasing navigation sequence number, incremented on each top-level navigation within the target. - NavSeq int64 `json:"nav_seq"` + // Interaction User interaction events (clicks, keydowns, scroll). + Interaction *BrowserTelemetryCategoryConfig `json:"interaction,omitempty"` - // SessionId CDP session identifier for the target connection. - SessionId string `json:"session_id"` + // Network HTTP request/response metadata. + Network *BrowserTelemetryCategoryConfig `json:"network,omitempty"` - // TargetId Browser target identifier (stable across navigations within a tab). - TargetId string `json:"target_id"` + // Page Page lifecycle events (navigation, load, layout shifts, LCP). + Page *BrowserTelemetryCategoryConfig `json:"page,omitempty"` - // TargetType CDP target type of the page that produced the event. - TargetType BrowserTargetType `json:"target_type"` + // Platform Calls that manage the VM rather than drive the browser (recording, filesystem, process, telemetry and browser configuration). Mostly platform-induced; off by default and opt-in. + Platform *BrowserTelemetryCategoryConfig `json:"platform,omitempty"` - // Url URL relevant to this event; page URL for navigation and page events, request URL for network events. - Url *string `json:"url,omitempty"` + // Screenshot Periodic base64-encoded viewport screenshots. High volume; off by default and opt-in. + Screenshot *BrowserTelemetryCategoryConfig `json:"screenshot,omitempty"` + + // System Browser VM health, such as out-of-memory kills and managed-service crashes. + System *BrowserTelemetryCategoryConfig `json:"system,omitempty"` +} + +// BrowserTelemetryCategoryConfig Configuration for a single telemetry category. +type BrowserTelemetryCategoryConfig struct { + // Enabled Whether this category is captured. In PUT requests selection is opt-in: omitting this field (or the whole category) leaves the category off, so a PUT captures exactly the categories set to true. In PATCH requests, omitting this field (or sending an empty object `{}`) is a no-op; the category retains its current state. To enable or disable a category via PATCH, you must send an explicit `true` or `false`. + Enabled *bool `json:"enabled,omitempty"` +} + +// BrowserTelemetryCdpControlConfig Settings for the `cdp_command` events the DevTools proxy reports. +type BrowserTelemetryCdpControlConfig struct { + // ExcludedMethods Methods to leave out of the `cdp_command` stream. Omit the list (or send an empty one) to report every supported method. Exclusion is a telemetry setting only: an excluded command is still relayed to the browser unchanged, it simply produces no event. Use it to drop the highest-volume methods — `Input.dispatchMouseEvent` during a humanized cursor path, or `Page.captureScreenshot` under a screencast — without turning the whole category off. + ExcludedMethods *[]BrowserCdpCommandMethod `json:"excluded_methods,omitempty"` +} + +// BrowserTelemetryConfig Telemetry configuration for a browser. Selection is opt-in. Omit the browser key (or send an empty object) to capture the default set: lightweight operational signals (control, connection, system, captcha). Within `browser`, only the categories you set enabled: true are captured; anything omitted is off. The CDP categories (console, network, page, interaction), `screenshot` and `platform` are off by default and must be opted into. A `browser` config with nothing enabled clears the telemetry configuration. The `monitor` category (CDP collector health) is not configurable here; it flows automatically whenever a CDP category is captured. +type BrowserTelemetryConfig struct { + // Browser Per-category telemetry capture settings for browser events. + Browser *BrowserTelemetryCategoriesConfig `json:"browser,omitempty"` + + // Export Forwarding of captured telemetry to an external destination. Independent of what is captured: export is off unless explicitly enabled here, even when an export destination is configured. In a PUT (full replace) an omitted export block resets export to off, the same as omitted categories turn off; in a PATCH an omitted field leaves the current setting unchanged. + Export *BrowserTelemetryExportConfig `json:"export,omitempty"` +} + +// BrowserTelemetryControlConfig Configuration for the control category. Same `enabled` semantics as any other category, plus settings for the browser-control commands the CDP proxy reports. +type BrowserTelemetryControlConfig struct { + // Cdp Settings for the `cdp_command` events the DevTools proxy reports. + Cdp *BrowserTelemetryCdpControlConfig `json:"cdp,omitempty"` + + // Enabled Whether this category is captured. In PUT requests selection is opt-in: omitting this field (or the whole category) leaves the category off, so a PUT captures exactly the categories set to true. In PATCH requests, omitting this field (or sending an empty object `{}`) is a no-op; the category retains its current state. To enable or disable a category via PATCH, you must send an explicit `true` or `false`. + Enabled *bool `json:"enabled,omitempty"` +} + +// BrowserTelemetryExportConfig Forwarding of captured telemetry to an external destination. Independent of what is captured: export is off unless explicitly enabled here, even when an export destination is configured. In a PUT (full replace) an omitted export block resets export to off, the same as omitted categories turn off; in a PATCH an omitted field leaves the current setting unchanged. +type BrowserTelemetryExportConfig struct { + // Otlp OTLP/HTTP export settings. + Otlp *BrowserTelemetryOTLPExportConfig `json:"otlp,omitempty"` +} + +// BrowserTelemetryOTLPExportConfig OTLP/HTTP export settings. +type BrowserTelemetryOTLPExportConfig struct { + // Enabled Whether captured telemetry is forwarded to the configured OTLP destination. Off by default. Has no effect (export stays inactive) when no export destination is configured. + Enabled *bool `json:"enabled,omitempty"` } -// BrowserPageLayoutSettledEvent A browser layout settled event emitted 1 second after page load with no intervening layout shifts, indicating visual stability. Each layout shift resets the 1-second timer. -type BrowserPageLayoutSettledEvent struct { - Category BrowserPageLayoutSettledEventCategory `json:"category"` +// ChromiumConfigureError Failure from batched chromium configure — includes which phase failed. +type ChromiumConfigureError struct { + Message string `json:"message"` - // Data Browser event context stamped by the browser monitor onto all CDP-sourced events. Identifies the target, frame, and navigation epoch in which the event occurred. - Data *BrowserEventContext `json:"data,omitempty"` + // Phase configure_phase maps to restart/filesystem/policy/extension/profile/display work; navigate_phase is retained for compatibility. + Phase ChromiumConfigureErrorPhase `json:"phase"` - // Source Provenance metadata identifying which producer emitted the event. - Source BrowserEventSource `json:"source"` + // Step Optional configure step that failed. + Step *ChromiumConfigureErrorStep `json:"step,omitempty"` +} - // Truncated True if the data field was truncated due to size limits. - Truncated *bool `json:"truncated,omitempty"` +// ChromiumConfigureErrorPhase configure_phase maps to restart/filesystem/policy/extension/profile/display work; navigate_phase is retained for compatibility. +type ChromiumConfigureErrorPhase string - // Ts Event timestamp in Unix microseconds. - Ts int64 `json:"ts"` - Type BrowserPageLayoutSettledEventType `json:"type"` -} +// ChromiumConfigureErrorStep Optional configure step that failed. +type ChromiumConfigureErrorStep string -// BrowserPageLayoutSettledEventCategory defines model for BrowserPageLayoutSettledEvent.Category. -type BrowserPageLayoutSettledEventCategory string +// ClickMouseRequest defines model for ClickMouseRequest. +type ClickMouseRequest struct { + // Button Mouse button to interact with + Button *ClickMouseRequestButton `json:"button,omitempty"` -// BrowserPageLayoutSettledEventType defines model for BrowserPageLayoutSettledEvent.Type. -type BrowserPageLayoutSettledEventType string + // ClickType Type of click action + ClickType *ClickMouseRequestClickType `json:"click_type,omitempty"` -// BrowserPageLayoutShiftEvent A browser cumulative layout shift (CLS) event from the Performance Timeline API. -type BrowserPageLayoutShiftEvent struct { - Category BrowserPageLayoutShiftEventCategory `json:"category"` - Data *BrowserPageLayoutShiftEventData `json:"data,omitempty"` + // HoldKeys Modifier keys to hold during the click + HoldKeys *[]string `json:"hold_keys,omitempty"` - // Source Provenance metadata identifying which producer emitted the event. - Source BrowserEventSource `json:"source"` + // NumClicks Number of times to repeat the click + NumClicks *int `json:"num_clicks,omitempty"` - // Truncated True if the data field was truncated due to size limits. - Truncated *bool `json:"truncated,omitempty"` + // X X coordinate of the click position + X int `json:"x"` - // Ts Event timestamp in Unix microseconds. - Ts int64 `json:"ts"` - Type BrowserPageLayoutShiftEventType `json:"type"` + // Y Y coordinate of the click position + Y int `json:"y"` } -// BrowserPageLayoutShiftEventCategory defines model for BrowserPageLayoutShiftEvent.Category. -type BrowserPageLayoutShiftEventCategory string +// ClickMouseRequestButton Mouse button to interact with +type ClickMouseRequestButton string -// BrowserPageLayoutShiftEventType defines model for BrowserPageLayoutShiftEvent.Type. -type BrowserPageLayoutShiftEventType string +// ClickMouseRequestClickType Type of click action +type ClickMouseRequestClickType string -// BrowserPageLayoutShiftEventData defines model for BrowserPageLayoutShiftEventData. -type BrowserPageLayoutShiftEventData struct { - // Duration Duration of the layout shift entry in milliseconds (always 0 for layout shifts per spec). - Duration float32 `json:"duration"` +// ClipboardContent defines model for ClipboardContent. +type ClipboardContent struct { + // Text Current clipboard text content + Text string `json:"text"` +} - // FrameId CDP frame identifier within the target. - FrameId *string `json:"frame_id,omitempty"` +// ComputerAction A single computer action to execute as part of a batch. The `type` field selects which +// action to perform, and the corresponding field contains the action parameters. +// Exactly one action field matching the type must be provided. +type ComputerAction struct { + ClickMouse *ClickMouseRequest `json:"click_mouse,omitempty"` + DragMouse *DragMouseRequest `json:"drag_mouse,omitempty"` + MoveMouse *MoveMouseRequest `json:"move_mouse,omitempty"` + PressKey *PressKeyRequest `json:"press_key,omitempty"` + Scroll *ScrollRequest `json:"scroll,omitempty"` + SetCursor *SetCursorRequest `json:"set_cursor,omitempty"` - // LayoutShiftDetails PerformanceLayoutShift attributes from the Performance Timeline entry. - LayoutShiftDetails *struct { - // HadRecentInput True if the layout shift was preceded by user input within 500ms, excluding it from CLS. - HadRecentInput *bool `json:"had_recent_input,omitempty"` + // Sleep Pause execution for a specified duration. + Sleep *SleepAction `json:"sleep,omitempty"` - // Value Layout shift score for this entry (contribution to CLS). - Value *float32 `json:"value,omitempty"` - } `json:"layout_shift_details,omitempty"` + // Type The type of action to perform. + Type ComputerActionType `json:"type"` + TypeText *TypeTextRequest `json:"type_text,omitempty"` +} - // LoaderId CDP document loader identifier, reset on each navigation. - LoaderId *string `json:"loader_id,omitempty"` +// ComputerActionType The type of action to perform. +type ComputerActionType string - // NavSeq Monotonically increasing navigation sequence number, incremented on each top-level navigation within the target. - NavSeq int64 `json:"nav_seq"` +// CreateDirectoryRequest defines model for CreateDirectoryRequest. +type CreateDirectoryRequest struct { + // Mode Optional directory mode (octal string, e.g. 755). Defaults to 755. + Mode *string `json:"mode,omitempty"` - // SessionId CDP session identifier for the target connection. - SessionId string `json:"session_id"` + // Path Absolute directory path to create. + Path string `json:"path"` +} - // SourceFrameId CDP frame identifier of the frame where the layout shift occurred. - SourceFrameId string `json:"source_frame_id"` +// DeletePathRequest defines model for DeletePathRequest. +type DeletePathRequest struct { + // Path Absolute path to delete. + Path string `json:"path"` +} - // TargetId Browser target identifier (stable across navigations within a tab). - TargetId string `json:"target_id"` +// DeleteRecordingRequest defines model for DeleteRecordingRequest. +type DeleteRecordingRequest struct { + // Id Identifier of the recording session to delete, as passed to /recording/start. Alphanumeric or hyphen. When omitted, the default recording session is deleted. + Id *string `json:"id,omitempty"` +} - // TargetType CDP target type of the page that produced the event. - TargetType BrowserTargetType `json:"target_type"` +// DisplayConfig defines model for DisplayConfig. +type DisplayConfig struct { + // Height Current display height in pixels + Height *int `json:"height,omitempty"` - // Time Performance Timeline timestamp of the layout shift in milliseconds. - Time float32 `json:"time"` + // RefreshRate Current display refresh rate in Hz (may be null if not detectable) + RefreshRate *int `json:"refresh_rate,omitempty"` - // Url URL relevant to this event; page URL for navigation and page events, request URL for network events. - Url *string `json:"url,omitempty"` + // Width Current display width in pixels + Width *int `json:"width,omitempty"` } -// BrowserPageLcpEvent A browser Largest Contentful Paint (LCP) event from the Performance Timeline API. -type BrowserPageLcpEvent struct { - Category BrowserPageLcpEventCategory `json:"category"` - Data *BrowserPageLcpEventData `json:"data,omitempty"` +// DragMouseRequest defines model for DragMouseRequest. +type DragMouseRequest struct { + // Button Mouse button to drag with + Button *DragMouseRequestButton `json:"button,omitempty"` - // Source Provenance metadata identifying which producer emitted the event. - Source BrowserEventSource `json:"source"` + // Delay Delay in milliseconds between button down and starting to move along the path. + Delay *int `json:"delay,omitempty"` - // Truncated True if the data field was truncated due to size limits. - Truncated *bool `json:"truncated,omitempty"` + // DurationMs Target total duration in milliseconds for the entire drag movement when smooth=true. Omit for automatic timing based on total path length. + DurationMs *int `json:"duration_ms,omitempty"` - // Ts Event timestamp in Unix microseconds. - Ts int64 `json:"ts"` - Type BrowserPageLcpEventType `json:"type"` -} + // HoldKeys Modifier keys to hold during the drag + HoldKeys *[]string `json:"hold_keys,omitempty"` -// BrowserPageLcpEventCategory defines model for BrowserPageLcpEvent.Category. -type BrowserPageLcpEventCategory string + // Path Ordered list of [x, y] coordinate pairs to move through while dragging. Must contain at least 2 points. + Path [][]int `json:"path"` -// BrowserPageLcpEventType defines model for BrowserPageLcpEvent.Type. -type BrowserPageLcpEventType string + // Smooth Use human-like Bezier curves between path waypoints instead of linear interpolation. When true, steps_per_segment and step_delay_ms are ignored. + Smooth *bool `json:"smooth,omitempty"` -// BrowserPageLcpEventData defines model for BrowserPageLcpEventData. -type BrowserPageLcpEventData struct { - // FrameId CDP frame identifier within the target. - FrameId *string `json:"frame_id,omitempty"` + // StepDelayMs Delay in milliseconds between relative steps while dragging. Ignored when smooth=true. + StepDelayMs *int `json:"step_delay_ms,omitempty"` - // LcpDetails LargestContentfulPaint attributes from the Performance Timeline entry. - LcpDetails *struct { - // ElementId id attribute of the LCP element, if present. - ElementId *string `json:"element_id,omitempty"` + // StepsPerSegment Number of relative move steps per segment in the path. Ignored when smooth=true. Minimum 1. + StepsPerSegment *int `json:"steps_per_segment,omitempty"` +} - // LoadTime Load time of the LCP element in milliseconds. - LoadTime *float32 `json:"load_time,omitempty"` +// DragMouseRequestButton Mouse button to drag with +type DragMouseRequestButton string - // NodeId CDP DOM node identifier of the LCP element. - NodeId *int `json:"node_id,omitempty"` +// Error defines model for Error. +type Error struct { + Message string `json:"message"` +} - // RenderTime Render time of the LCP element in milliseconds; 0 for cross-origin images without Timing-Allow-Origin. - RenderTime *float32 `json:"render_time,omitempty"` +// ExecutePlaywrightRequest Request to execute Playwright code +type ExecutePlaywrightRequest struct { + // Code TypeScript/JavaScript code to execute. The code has access to 'page', 'context', and 'browser' variables. + // Example: "await page.goto('https://example.com'); return await page.title();" + Code string `json:"code"` - // Size Visible area of the LCP element in pixels squared. - Size *float32 `json:"size,omitempty"` + // TimeoutSec Maximum execution time in seconds. Default is 60. + TimeoutSec *int `json:"timeout_sec,omitempty"` +} - // Url URL of the LCP element for image or video elements. - Url *string `json:"url,omitempty"` - } `json:"lcp_details,omitempty"` +// ExecutePlaywrightResult Result of Playwright code execution +type ExecutePlaywrightResult struct { + // Error Error message if execution failed + Error *string `json:"error,omitempty"` - // LoaderId CDP document loader identifier, reset on each navigation. - LoaderId *string `json:"loader_id,omitempty"` + // Result The value returned by the code (if any) + Result interface{} `json:"result,omitempty"` - // NavSeq Monotonically increasing navigation sequence number, incremented on each top-level navigation within the target. - NavSeq int64 `json:"nav_seq"` + // Stderr Standard error from the execution + Stderr *string `json:"stderr,omitempty"` - // SessionId CDP session identifier for the target connection. - SessionId string `json:"session_id"` + // Stdout Standard output from the execution + Stdout *string `json:"stdout,omitempty"` - // SourceFrameId CDP frame identifier of the frame where the LCP element was rendered. - SourceFrameId string `json:"source_frame_id"` + // Success Whether the code executed successfully + Success bool `json:"success"` +} - // TargetId Browser target identifier (stable across navigations within a tab). - TargetId string `json:"target_id"` +// FileInfo defines model for FileInfo. +type FileInfo struct { + // IsDir Whether the path is a directory. + IsDir bool `json:"is_dir"` - // TargetType CDP target type of the page that produced the event. - TargetType BrowserTargetType `json:"target_type"` + // ModTime Last modification time. + ModTime time.Time `json:"mod_time"` - // Time Performance Timeline timestamp of the LCP entry in milliseconds. - Time float32 `json:"time"` + // Mode File mode bits (e.g., "drwxr-xr-x" or "-rw-r--r--"). + Mode string `json:"mode"` - // Url URL relevant to this event; page URL for navigation and page events, request URL for network events. - Url *string `json:"url,omitempty"` + // Name Base name of the file or directory. + Name string `json:"name"` + + // Path Absolute path. + Path string `json:"path"` + + // SizeBytes Size in bytes. 0 for directories. + SizeBytes int `json:"size_bytes"` } -// BrowserPageLoadEvent A browser page load event (CDP Page.loadEventFired). -type BrowserPageLoadEvent struct { - Category BrowserPageLoadEventCategory `json:"category"` - Data *BrowserPageLoadEventData `json:"data,omitempty"` +// FileSystemEvent Filesystem change event. +type FileSystemEvent struct { + // IsDir Whether the affected path is a directory. + IsDir *bool `json:"is_dir,omitempty"` - // Source Provenance metadata identifying which producer emitted the event. - Source BrowserEventSource `json:"source"` + // Name Base name of the file or directory affected. + Name *string `json:"name,omitempty"` - // Truncated True if the data field was truncated due to size limits. - Truncated *bool `json:"truncated,omitempty"` + // Path Absolute path of the file or directory. + Path string `json:"path"` - // Ts Event timestamp in Unix microseconds. - Ts int64 `json:"ts"` - Type BrowserPageLoadEventType `json:"type"` + // Type Event type. + Type FileSystemEventType `json:"type"` } -// BrowserPageLoadEventCategory defines model for BrowserPageLoadEvent.Category. -type BrowserPageLoadEventCategory string +// FileSystemEventType Event type. +type FileSystemEventType string -// BrowserPageLoadEventType defines model for BrowserPageLoadEvent.Type. -type BrowserPageLoadEventType string +// KnownBrowserTelemetryEvent Discriminated union of browser telemetry events emitted by the Kernel image. This is a structural taxonomy: any event on the telemetry stream whose `data` conforms to one of the variants below (selected by `type`) is a `KnownBrowserTelemetryEvent`, regardless of who published it. Caller-published events via POST /telemetry/events are not constrained to this union; see `TelemetryEvent` for the wire shape. Validation of caller payloads against this taxonomy is the consumer's responsibility. +type KnownBrowserTelemetryEvent struct { + union json.RawMessage +} -// BrowserPageLoadEventData defines model for BrowserPageLoadEventData. -type BrowserPageLoadEventData struct { - // CdpTimestamp Chrome monotonic clock value in seconds at which the load event fired, relative to browser process start (not Unix epoch). Use `ts` for wall-clock time. - CdpTimestamp float32 `json:"cdp_timestamp"` +// ListFiles Array of file or directory information entries. +type ListFiles = []FileInfo - // FrameId CDP frame identifier within the target. - FrameId *string `json:"frame_id,omitempty"` +// LogEvent A log entry from the application. +type LogEvent struct { + // Message Log message text. + Message string `json:"message"` - // LoaderId CDP document loader identifier, reset on each navigation. - LoaderId *string `json:"loader_id,omitempty"` + // Timestamp Time the log entry was produced. + Timestamp time.Time `json:"timestamp"` +} - // NavSeq Monotonically increasing navigation sequence number, incremented on each top-level navigation within the target. - NavSeq int64 `json:"nav_seq"` +// MarkRecordingRequest defines model for MarkRecordingRequest. +type MarkRecordingRequest struct { + // Id Identifier of the recording session to mark, as passed to /recording/start. Alphanumeric or hyphen. When omitted, the marker is added to the default recording session. + Id *string `json:"id,omitempty"` - // SessionId CDP session identifier for the target connection. - SessionId string `json:"session_id"` + // Name Name of the marker, used as the MP4 chapter title. + Name string `json:"name"` +} - // TargetId Browser target identifier (stable across navigations within a tab). - TargetId string `json:"target_id"` +// MarkRecordingResult defines model for MarkRecordingResult. +type MarkRecordingResult struct { + // Name Name of the recorded marker. + Name string `json:"name"` - // TargetType CDP target type of the page that produced the event. - TargetType BrowserTargetType `json:"target_type"` + // OffsetMs Provisional offset of the marker from the recording start, in milliseconds, measured against the start time at mark time. The authoritative offset is the chapter start written at finalize. + OffsetMs int64 `json:"offset_ms"` +} - // Url URL relevant to this event; page URL for navigation and page events, request URL for network events. - Url *string `json:"url,omitempty"` +// MousePositionResponse defines model for MousePositionResponse. +type MousePositionResponse struct { + // X X coordinate of the cursor + X int `json:"x"` + + // Y Y coordinate of the cursor + Y int `json:"y"` } -// BrowserPageNavigationEvent A browser page navigation started event (CDP Page.frameNavigated). Carries nav context fields inline but not nav_seq, as this event resets the navigation epoch. -type BrowserPageNavigationEvent struct { - Category BrowserPageNavigationEventCategory `json:"category"` - Data *BrowserPageNavigationEventData `json:"data,omitempty"` +// MoveMouseRequest defines model for MoveMouseRequest. +type MoveMouseRequest struct { + // DurationMs Target total duration in milliseconds for the mouse movement when smooth=true. Omit for automatic timing based on distance. + DurationMs *int `json:"duration_ms,omitempty"` - // Source Provenance metadata identifying which producer emitted the event. - Source BrowserEventSource `json:"source"` + // HoldKeys Modifier keys to hold during the move + HoldKeys *[]string `json:"hold_keys,omitempty"` - // Truncated True if the data field was truncated due to size limits. - Truncated *bool `json:"truncated,omitempty"` + // Smooth Use human-like Bezier curve path instead of instant mouse movement. + Smooth *bool `json:"smooth,omitempty"` - // Ts Event timestamp in Unix microseconds. - Ts int64 `json:"ts"` - Type BrowserPageNavigationEventType `json:"type"` -} + // X X coordinate to move the cursor to + X int `json:"x"` -// BrowserPageNavigationEventCategory defines model for BrowserPageNavigationEvent.Category. -type BrowserPageNavigationEventCategory string + // Y Y coordinate to move the cursor to + Y int `json:"y"` +} -// BrowserPageNavigationEventType defines model for BrowserPageNavigationEvent.Type. -type BrowserPageNavigationEventType string +// MovePathRequest defines model for MovePathRequest. +type MovePathRequest struct { + // DestPath Absolute destination path. + DestPath string `json:"dest_path"` -// BrowserPageNavigationEventData defines model for BrowserPageNavigationEventData. -type BrowserPageNavigationEventData struct { - // FrameId CDP frame identifier of the navigated frame. - FrameId string `json:"frame_id"` + // SrcPath Absolute source path. + SrcPath string `json:"src_path"` +} - // LoaderId New CDP document loader identifier assigned for this navigation. - LoaderId string `json:"loader_id"` +// OkResponse Generic OK response. +type OkResponse struct { + // Ok Indicates success. + Ok bool `json:"ok"` +} - // ParentFrameId Parent frame identifier for subframe navigations; absent for top-level navigations. - ParentFrameId *string `json:"parent_frame_id,omitempty"` +// PatchDisplayRequest defines model for PatchDisplayRequest. +type PatchDisplayRequest struct { + // Height Display height in pixels + Height *int `json:"height,omitempty"` - // SessionId CDP session identifier. - SessionId string `json:"session_id"` + // RefreshRate Display refresh rate in Hz. If omitted, uses the highest available rate for the resolution. + RefreshRate *PatchDisplayRequestRefreshRate `json:"refresh_rate,omitempty"` - // TargetId Browser target identifier. - TargetId string `json:"target_id"` + // RequireIdle If true, refuse to resize when live view or recording/replay is active. + RequireIdle *bool `json:"require_idle,omitempty"` - // TargetType CDP target type of the page that produced the event. - TargetType BrowserTargetType `json:"target_type"` + // RestartChromium If true, restart Chromium after resolution change to ensure it adapts to new size. Default is false for headful, true for headless. + RestartChromium *bool `json:"restart_chromium,omitempty"` - // Url URL navigated to. - Url string `json:"url"` + // Width Display width in pixels + Width *int `json:"width,omitempty"` } -// BrowserPageNavigationSettledEvent Emitted when page_dom_content_loaded and page_layout_settled have both fired for the same navigation, indicating the page is loaded and visually stable. Independent of network_idle; a single pending request does not block it. -type BrowserPageNavigationSettledEvent struct { - Category BrowserPageNavigationSettledEventCategory `json:"category"` - - // Data Browser event context stamped by the browser monitor onto all CDP-sourced events. Identifies the target, frame, and navigation epoch in which the event occurred. - Data *BrowserEventContext `json:"data,omitempty"` +// PatchDisplayRequestRefreshRate Display refresh rate in Hz. If omitted, uses the highest available rate for the resolution. +type PatchDisplayRequestRefreshRate int - // Source Provenance metadata identifying which producer emitted the event. - Source BrowserEventSource `json:"source"` +// PressKeyRequest defines model for PressKeyRequest. +type PressKeyRequest struct { + // Duration Duration to hold the keys down in milliseconds. If omitted or 0, keys are tapped. + Duration *int `json:"duration,omitempty"` - // Truncated True if the data field was truncated due to size limits. - Truncated *bool `json:"truncated,omitempty"` + // HoldKeys Optional modifier keys to hold during the key press sequence. + HoldKeys *[]string `json:"hold_keys,omitempty"` - // Ts Event timestamp in Unix microseconds. - Ts int64 `json:"ts"` - Type BrowserPageNavigationSettledEventType `json:"type"` + // Keys List of key symbols to press. Each item should be a key symbol supported by xdotool + // (see X11 keysym definitions). Examples include "Return", "Shift", "Ctrl", "Alt", "F5". + // Items in this list could also be combinations, e.g. "Ctrl+t" or "Ctrl+Shift+Tab". + Keys []string `json:"keys"` } -// BrowserPageNavigationSettledEventCategory defines model for BrowserPageNavigationSettledEvent.Category. -type BrowserPageNavigationSettledEventCategory string +// ProcessExecRequest Request to execute a command synchronously. +type ProcessExecRequest struct { + // Args Command arguments. + Args *[]string `json:"args,omitempty"` -// BrowserPageNavigationSettledEventType defines model for BrowserPageNavigationSettledEvent.Type. -type BrowserPageNavigationSettledEventType string + // AsRoot Run the process with root privileges. + AsRoot *bool `json:"as_root,omitempty"` -// BrowserPageTabOpenedEvent A new browser tab or target was opened (CDP Target.attachedToTarget for page targets). Fires before a CDP session is attached to the new target, so `session_id`, `frame_id`, `loader_id`, and `nav_seq` are absent; this event does not compose `BrowserEventContext`. Consumers reading context fields generically should treat it as a special case. -type BrowserPageTabOpenedEvent struct { - Category BrowserPageTabOpenedEventCategory `json:"category"` - Data *BrowserPageTabOpenedEventData `json:"data,omitempty"` + // AsUser Run the process as this user. + AsUser *string `json:"as_user,omitempty"` - // Source Provenance metadata identifying which producer emitted the event. - Source BrowserEventSource `json:"source"` + // Command Executable or shell command to run. + Command string `json:"command"` - // Truncated True if the data field was truncated due to size limits. - Truncated *bool `json:"truncated,omitempty"` + // Cwd Working directory (absolute path) to run the command in. + Cwd *string `json:"cwd,omitempty"` - // Ts Event timestamp in Unix microseconds. - Ts int64 `json:"ts"` - Type BrowserPageTabOpenedEventType `json:"type"` + // Env Environment variables to set for the process. + Env *map[string]string `json:"env,omitempty"` + + // TimeoutSec Maximum execution time in seconds. + TimeoutSec *int `json:"timeout_sec,omitempty"` } -// BrowserPageTabOpenedEventCategory defines model for BrowserPageTabOpenedEvent.Category. -type BrowserPageTabOpenedEventCategory string +// ProcessExecResult Result of a synchronous command execution. +type ProcessExecResult struct { + // DurationMs Execution duration in milliseconds. + DurationMs *int `json:"duration_ms,omitempty"` -// BrowserPageTabOpenedEventType defines model for BrowserPageTabOpenedEvent.Type. -type BrowserPageTabOpenedEventType string + // ExitCode Process exit code. + ExitCode *int `json:"exit_code,omitempty"` -// BrowserPageTabOpenedEventData defines model for BrowserPageTabOpenedEventData. -type BrowserPageTabOpenedEventData struct { - // OpenerId Target identifier of the tab that opened this one, if any. - OpenerId *string `json:"opener_id,omitempty"` + // StderrB64 Base64-encoded stderr buffer. + StderrB64 *string `json:"stderr_b64,omitempty"` - // TargetId CDP target identifier for the newly opened tab. - TargetId string `json:"target_id"` + // StdoutB64 Base64-encoded stdout buffer. + StdoutB64 *string `json:"stdout_b64,omitempty"` +} - // TargetType CDP target type of the page that produced the event. - TargetType BrowserTargetType `json:"target_type"` +// ProcessKillRequest Signal to send to the process. +type ProcessKillRequest struct { + // Signal Signal to send. + Signal ProcessKillRequestSignal `json:"signal"` +} - // Title Initial page title of the new tab. - Title *string `json:"title,omitempty"` +// ProcessKillRequestSignal Signal to send. +type ProcessKillRequestSignal string - // Url Initial URL of the new tab. - Url string `json:"url"` -} +// ProcessResizeRequest Resize a PTY-backed process. +type ProcessResizeRequest struct { + // Cols New terminal columns. + Cols int `json:"cols"` -// BrowserPlatformApiCallEvent A call that manages the browser VM rather than driving the browser, handled by the kernel-images-api server: recording lifecycle, filesystem and process management, telemetry and browser configuration. These are mostly platform-induced (e.g. profile save, replay capture) rather than agent actions. -type BrowserPlatformApiCallEvent struct { - Category BrowserPlatformApiCallEventCategory `json:"category"` + // Rows New terminal rows. + Rows int `json:"rows"` +} - // Data Per-call payload for `platform_api_call` events. Metadata only: a platform call carries no submitted content, so there is no `code` field as there is on `api_call`. - Data *BrowserPlatformApiCallEventData `json:"data,omitempty"` +// ProcessSpawnRequest defines model for ProcessSpawnRequest. +type ProcessSpawnRequest struct { + // AllocateTty Allocate a pseudo-terminal (PTY) for the process to enable interactive shells. + AllocateTty *bool `json:"allocate_tty,omitempty"` - // Source Provenance metadata identifying which producer emitted the event. - Source BrowserEventSource `json:"source"` + // Args Command arguments. + Args *[]string `json:"args,omitempty"` - // Truncated True if the data field was truncated due to size limits. - Truncated *bool `json:"truncated,omitempty"` + // AsRoot Run the process with root privileges. + AsRoot *bool `json:"as_root,omitempty"` - // Ts Event timestamp in Unix microseconds. - Ts int64 `json:"ts"` - Type BrowserPlatformApiCallEventType `json:"type"` -} + // AsUser Run the process as this user. + AsUser *string `json:"as_user,omitempty"` -// BrowserPlatformApiCallEventCategory defines model for BrowserPlatformApiCallEvent.Category. -type BrowserPlatformApiCallEventCategory string + // Cols Initial terminal columns when allocate_tty is true. + Cols *int `json:"cols,omitempty"` -// BrowserPlatformApiCallEventType defines model for BrowserPlatformApiCallEvent.Type. -type BrowserPlatformApiCallEventType string + // Command Executable or shell command to run. + Command string `json:"command"` -// BrowserPlatformApiCallEventData Per-call payload for `platform_api_call` events. Metadata only: a platform call carries no submitted content, so there is no `code` field as there is on `api_call`. -type BrowserPlatformApiCallEventData struct { - // DurationMs Wall-clock duration of the handler in milliseconds. - DurationMs float32 `json:"duration_ms"` + // Cwd Working directory (absolute path) to run the command in. + Cwd *string `json:"cwd,omitempty"` - // OperationId Matched route's operation, named as the server names its handler (e.g. `ProcessExec`, `StartRecording`). - OperationId string `json:"operation_id"` + // Env Environment variables to set for the process. + Env *map[string]string `json:"env,omitempty"` - // RequestId Per-request identifier from the kernel-images-api request middleware. - RequestId string `json:"request_id"` + // Rows Initial terminal rows when allocate_tty is true. + Rows *int `json:"rows,omitempty"` - // Status HTTP response status code. - Status int `json:"status"` + // TimeoutSec Maximum execution time in seconds. + TimeoutSec *int `json:"timeout_sec,omitempty"` } -// BrowserServiceCrashedEvent A managed service exited unexpectedly. Intentional stops (e.g. operator-initiated shutdown) do not produce this event — only unexpected exits and terminal restart-give-up transitions do. -type BrowserServiceCrashedEvent struct { - Category BrowserServiceCrashedEventCategory `json:"category"` +// ProcessSpawnResult Information about a spawned process. +type ProcessSpawnResult struct { + // Pid OS process ID. + Pid *int `json:"pid,omitempty"` - // Data Per-crash payload for `service_crashed` events. Exit code and signal are not exposed by the underlying process manager on this channel, so only the service identity, the lifecycle phase the crash occurred in, and (when available) the PID are reported. - Data *BrowserServiceCrashedEventData `json:"data,omitempty"` + // ProcessId Server-assigned identifier for the process. + ProcessId *openapi_types.UUID `json:"process_id,omitempty"` - // Source Provenance metadata identifying which producer emitted the event. - Source BrowserEventSource `json:"source"` + // StartedAt Timestamp when the process started. + StartedAt *time.Time `json:"started_at,omitempty"` +} - // Truncated True if the data field was truncated due to size limits. - Truncated *bool `json:"truncated,omitempty"` +// ProcessStatus Current status of a process. +type ProcessStatus struct { + // CpuPct Estimated CPU usage percentage. + CpuPct *float32 `json:"cpu_pct,omitempty"` - // Ts Event timestamp in Unix microseconds. - Ts int64 `json:"ts"` - Type BrowserServiceCrashedEventType `json:"type"` -} + // ExitCode Exit code if the process has exited. + ExitCode *int `json:"exit_code,omitempty"` -// BrowserServiceCrashedEventCategory defines model for BrowserServiceCrashedEvent.Category. -type BrowserServiceCrashedEventCategory string + // MemBytes Estimated resident memory usage in bytes. + MemBytes *int `json:"mem_bytes,omitempty"` -// BrowserServiceCrashedEventType defines model for BrowserServiceCrashedEvent.Type. -type BrowserServiceCrashedEventType string + // State Process state. + State *ProcessStatusState `json:"state,omitempty"` +} -// BrowserServiceCrashedEventData Per-crash payload for `service_crashed` events. Exit code and signal are not exposed by the underlying process manager on this channel, so only the service identity, the lifecycle phase the crash occurred in, and (when available) the PID are reported. -type BrowserServiceCrashedEventData struct { - // Phase Lifecycle phase the crash occurred in. `startup` means the process died before it ever reached a healthy running state. `running` means a previously healthy process died unexpectedly. `gave_up` means the process manager exhausted its restart attempts and stopped trying; no further `service_crashed` events will fire for this service until something restarts it. - Phase BrowserServiceCrashedEventDataPhase `json:"phase"` +// ProcessStatusState Process state. +type ProcessStatusState string - // Pid PID of the crashed process. Absent when the process manager gave up after exhausting restart attempts and is no longer tracking a live PID. - Pid *int `json:"pid,omitempty"` +// ProcessStdinRequest Data to write to the process standard input. +type ProcessStdinRequest struct { + // DataB64 Base64-encoded data to write. + DataB64 string `json:"data_b64"` +} - // ServiceName Program name of the crashed service (e.g. `chromium`, `mutter`, `kernel-images-api`). - ServiceName string `json:"service_name"` +// ProcessStdinResult Result of writing to stdin. +type ProcessStdinResult struct { + // WrittenBytes Number of bytes written. + WrittenBytes *int `json:"written_bytes,omitempty"` } -// BrowserServiceCrashedEventDataPhase Lifecycle phase the crash occurred in. `startup` means the process died before it ever reached a healthy running state. `running` means a previously healthy process died unexpectedly. `gave_up` means the process manager exhausted its restart attempts and stopped trying; no further `service_crashed` events will fire for this service until something restarts it. -type BrowserServiceCrashedEventDataPhase string +// ProcessStreamEvent SSE payload representing process output or lifecycle events. +type ProcessStreamEvent struct { + // DataB64 Base64-encoded data from the process stream. + DataB64 *string `json:"data_b64,omitempty"` -// BrowserSystemOomKillEvent The Linux kernel OOM-killer terminated a process inside the VM. Sourced from `/dev/kmsg`. Fires for any process killed by the kernel due to memory exhaustion, including Chrome renderer subprocesses that are not supervised. -type BrowserSystemOomKillEvent struct { - Category BrowserSystemOomKillEventCategory `json:"category"` + // Event Lifecycle event type. + Event *ProcessStreamEventEvent `json:"event,omitempty"` - // Data Per-kill payload for `system_oom_kill` events. - Data *BrowserSystemOomKillEventData `json:"data,omitempty"` + // ExitCode Exit code when the event is "exit". + ExitCode *int `json:"exit_code,omitempty"` - // Source Provenance metadata identifying which producer emitted the event. - Source BrowserEventSource `json:"source"` + // Stream Source stream of the data chunk. + Stream *ProcessStreamEventStream `json:"stream,omitempty"` +} - // Truncated True if the data field was truncated due to size limits. - Truncated *bool `json:"truncated,omitempty"` +// ProcessStreamEventEvent Lifecycle event type. +type ProcessStreamEventEvent string - // Ts Event timestamp in Unix microseconds. - Ts int64 `json:"ts"` - Type BrowserSystemOomKillEventType `json:"type"` -} +// ProcessStreamEventStream Source stream of the data chunk. +type ProcessStreamEventStream string -// BrowserSystemOomKillEventCategory defines model for BrowserSystemOomKillEvent.Category. -type BrowserSystemOomKillEventCategory string +// PublishEventRequest Request body for publishing an event into the telemetry stream. +type PublishEventRequest struct { + // Category Event category. Optional and advisory: for a known event `type` the server assigns the category authoritatively and ignores this field. It is only used for unknown custom types, where it is required. + Category *PublishEventRequestCategory `json:"category,omitempty"` -// BrowserSystemOomKillEventType defines model for BrowserSystemOomKillEvent.Type. -type BrowserSystemOomKillEventType string + // Data Telemetry event payload. + Data interface{} `json:"data,omitempty"` -// BrowserSystemOomKillEventData Per-kill payload for `system_oom_kill` events. -type BrowserSystemOomKillEventData struct { - // Constraint Why the kernel decided to OOM-kill. `none` means global memory exhaustion; `memcg` means a cgroup memory limit was hit; `cpuset` / `memory_policy` are NUMA/policy-driven kills. Absent on kernels older than 5.0 which did not emit the structured `oom-kill:` line. - Constraint *BrowserSystemOomKillEventDataConstraint `json:"constraint,omitempty"` + // Source Provenance metadata identifying which producer emitted the event. + Source *BrowserEventSource `json:"source,omitempty"` - // MemFreeKb Free system memory in KiB at the time of the kill, derived from the `free:N` field in the kernel's Mem-Info dump. Assumes a 4 KiB page size. Does not include reclaimable caches, so a small value with a large `mem_total_kb` may still mean the system was not under hard pressure. Absent if the kernel did not emit a parseable Mem-Info section. - MemFreeKb *int `json:"mem_free_kb,omitempty"` + // Type Event type identifier. + Type string `json:"type"` +} - // MemTotalKb Total system memory in KiB at the time of the kill, derived from the `N pages RAM` line in the kernel's Mem-Info dump. Assumes a 4 KiB page size. Absent if the kernel did not emit a parseable Mem-Info section. - MemTotalKb *int `json:"mem_total_kb,omitempty"` +// PublishEventRequestCategory Event category. Optional and advisory: for a known event `type` the server assigns the category authoritatively and ignores this field. It is only used for unknown custom types, where it is required. +type PublishEventRequestCategory string - // Pid PID of the killed process. - Pid int `json:"pid"` +// RecorderInfo defines model for RecorderInfo. +type RecorderInfo struct { + // FinishedAt Timestamp when recording finished + FinishedAt *time.Time `json:"finished_at,omitempty"` + Id string `json:"id"` + IsRecording bool `json:"isRecording"` - // ProcessName Comm of the killed process as reported by the kernel (max 15 chars, truncated by the kernel). - ProcessName string `json:"process_name"` + // StartedAt Timestamp when recording started + StartedAt *time.Time `json:"started_at,omitempty"` +} - // RssKb Resident set size of the killed process in KiB (sum of anon-rss, file-rss, and shmem-rss). This is the physical memory the process was using at the time of the kill. - RssKb int `json:"rss_kb"` +// ScreenshotRegion defines model for ScreenshotRegion. +type ScreenshotRegion struct { + // Height Height of the region in pixels + Height int `json:"height"` - // TopTasks Top processes by resident-set-size at the moment of the kill, sorted descending. Sourced from the kernel's `Tasks state` table. Empty if the kernel did not emit the table. Capped at 5 entries to bound payload size. - TopTasks *[]BrowserSystemOomKillTask `json:"top_tasks,omitempty"` + // Width Width of the region in pixels + Width int `json:"width"` - // TriggerPid PID of the triggering process. Absent if the kernel did not emit the standard `CPU: N PID: N Comm:` header line. - TriggerPid *int `json:"trigger_pid,omitempty"` + // X X coordinate of the region's top-left corner + X int `json:"x"` - // TriggerProcessName Comm of the process whose allocation request caused the kernel to invoke the OOM-killer. Often the same as `process_name` (the kernel killed the requester) but can differ when the kernel chose a different victim. Max 15 chars, truncated by the kernel. - TriggerProcessName *string `json:"trigger_process_name,omitempty"` + // Y Y coordinate of the region's top-left corner + Y int `json:"y"` } -// BrowserSystemOomKillEventDataConstraint Why the kernel decided to OOM-kill. `none` means global memory exhaustion; `memcg` means a cgroup memory limit was hit; `cpuset` / `memory_policy` are NUMA/policy-driven kills. Absent on kernels older than 5.0 which did not emit the structured `oom-kill:` line. -type BrowserSystemOomKillEventDataConstraint string +// ScreenshotRequest defines model for ScreenshotRequest. +type ScreenshotRequest struct { + Region *ScreenshotRegion `json:"region,omitempty"` +} -// BrowserSystemOomKillTask A single process entry from the kernel's `Tasks state` dump. -type BrowserSystemOomKillTask struct { - // Name Comm of the process (max 15 chars, truncated by the kernel). - Name string `json:"name"` +// ScrollRequest defines model for ScrollRequest. +type ScrollRequest struct { + // DeltaX Horizontal scroll amount. Positive scrolls right, negative scrolls left. + DeltaX *int `json:"delta_x,omitempty"` - // Pid PID of the process. - Pid int `json:"pid"` + // DeltaY Vertical scroll amount. Positive scrolls down, negative scrolls up. + DeltaY *int `json:"delta_y,omitempty"` - // RssKb Resident set size in KiB at the moment of the kill. - RssKb int `json:"rss_kb"` + // HoldKeys Modifier keys to hold during the scroll + HoldKeys *[]string `json:"hold_keys,omitempty"` + + // X X coordinate at which to perform the scroll + X int `json:"x"` + + // Y Y coordinate at which to perform the scroll + Y int `json:"y"` } -// BrowserTargetType CDP target type of the page that produced the event. -type BrowserTargetType string +// SetCursorRequest defines model for SetCursorRequest. +type SetCursorRequest struct { + // Hidden Whether the cursor should be hidden + Hidden bool `json:"hidden"` +} -// BrowserTelemetryCategoriesConfig Per-category telemetry capture settings for browser events. -type BrowserTelemetryCategoriesConfig struct { - // Captcha Captcha solve attempt outcomes. - Captcha *BrowserTelemetryCategoryConfig `json:"captcha,omitempty"` +// SetFilePermissionsRequest defines model for SetFilePermissionsRequest. +type SetFilePermissionsRequest struct { + // Group New group name or GID. + Group *string `json:"group,omitempty"` - // Connection Client attach/detach lifecycle for the CDP proxy and live view. - Connection *BrowserTelemetryCategoryConfig `json:"connection,omitempty"` + // Mode File mode bits (octal string, e.g. 644). + Mode string `json:"mode"` - // Console Console output (log, warn, error) and uncaught exceptions. - Console *BrowserTelemetryCategoryConfig `json:"console,omitempty"` + // Owner New owner username or UID. + Owner *string `json:"owner,omitempty"` - // Control Agent-driven actions against the browser — computer-control calls, Playwright code execution, screenshots and clipboard access. - Control *BrowserTelemetryCategoryConfig `json:"control,omitempty"` + // Path Absolute path whose permissions are to be changed. + Path string `json:"path"` +} - // Interaction User interaction events (clicks, keydowns, scroll). - Interaction *BrowserTelemetryCategoryConfig `json:"interaction,omitempty"` +// SleepAction Pause execution for a specified duration. +type SleepAction struct { + // DurationMs Duration to sleep in milliseconds. + DurationMs int `json:"duration_ms"` +} - // Network HTTP request/response metadata. - Network *BrowserTelemetryCategoryConfig `json:"network,omitempty"` +// StartFsWatchRequest defines model for StartFsWatchRequest. +type StartFsWatchRequest struct { + // Path Directory to watch. + Path string `json:"path"` - // Page Page lifecycle events (navigation, load, layout shifts, LCP). - Page *BrowserTelemetryCategoryConfig `json:"page,omitempty"` + // Recursive Whether to watch recursively. + Recursive *bool `json:"recursive,omitempty"` +} - // Platform Calls that manage the VM rather than drive the browser (recording, filesystem, process, telemetry and browser configuration). Mostly platform-induced; off by default and opt-in. - Platform *BrowserTelemetryCategoryConfig `json:"platform,omitempty"` +// StartRecordingRequest defines model for StartRecordingRequest. +type StartRecordingRequest struct { + // Framerate Recording framerate in fps (overrides server default) + Framerate *int `json:"framerate,omitempty"` - // Screenshot Periodic base64-encoded viewport screenshots. High volume; off by default and opt-in. - Screenshot *BrowserTelemetryCategoryConfig `json:"screenshot,omitempty"` + // Id Optional identifier for this recording session, used to target it from the other /recording endpoints (stop, mark, download, delete) and allowing multiple concurrent recordings. Alphanumeric or hyphen. When omitted, the default recording session is started. + Id *string `json:"id,omitempty"` - // System Browser VM health, such as out-of-memory kills and managed-service crashes. - System *BrowserTelemetryCategoryConfig `json:"system,omitempty"` -} + // MaxDurationInSeconds Maximum recording duration in seconds (overrides server default) + MaxDurationInSeconds *int `json:"maxDurationInSeconds,omitempty"` -// BrowserTelemetryCategoryConfig Configuration for a single telemetry category. -type BrowserTelemetryCategoryConfig struct { - // Enabled Whether this category is captured. In PUT requests selection is opt-in: omitting this field (or the whole category) leaves the category off, so a PUT captures exactly the categories set to true. In PATCH requests, omitting this field (or sending an empty object `{}`) is a no-op; the category retains its current state. To enable or disable a category via PATCH, you must send an explicit `true` or `false`. - Enabled *bool `json:"enabled,omitempty"` + // MaxFileSizeInMB Maximum file size in MB (overrides server default) + MaxFileSizeInMB *int `json:"maxFileSizeInMB,omitempty"` + + // RecordAudio Capture audio alongside video. Requires the server to have an audio source and PulseAudio socket configured (the image sets both by default). When false the recording is video-only. + RecordAudio *bool `json:"recordAudio,omitempty"` } -// BrowserTelemetryConfig Telemetry configuration for a browser. Selection is opt-in. Omit the browser key (or send an empty object) to capture the default set: lightweight operational signals (control, connection, system, captcha). Within `browser`, only the categories you set enabled: true are captured; anything omitted is off. The CDP categories (console, network, page, interaction), `screenshot` and `platform` are off by default and must be opted into. A `browser` config with nothing enabled clears the telemetry configuration. The `monitor` category (CDP collector health) is not configurable here; it flows automatically whenever a CDP category is captured. -type BrowserTelemetryConfig struct { - // Browser Per-category telemetry capture settings for browser events. - Browser *BrowserTelemetryCategoriesConfig `json:"browser,omitempty"` +// StopRecordingRequest defines model for StopRecordingRequest. +type StopRecordingRequest struct { + // ForceStop Immediately stop without graceful shutdown. This may result in a corrupted video file. + ForceStop *bool `json:"forceStop,omitempty"` - // Export Forwarding of captured telemetry to an external destination. Independent of what is captured: export is off unless explicitly enabled here, even when an export destination is configured. In a PUT (full replace) an omitted export block resets export to off, the same as omitted categories turn off; in a PATCH an omitted field leaves the current setting unchanged. - Export *BrowserTelemetryExportConfig `json:"export,omitempty"` + // Id Identifier of the recording session to stop, as passed to /recording/start. Alphanumeric or hyphen. When omitted, the default recording session is stopped. + Id *string `json:"id,omitempty"` } -// BrowserTelemetryExportConfig Forwarding of captured telemetry to an external destination. Independent of what is captured: export is off unless explicitly enabled here, even when an export destination is configured. In a PUT (full replace) an omitted export block resets export to off, the same as omitted categories turn off; in a PATCH an omitted field leaves the current setting unchanged. -type BrowserTelemetryExportConfig struct { - // Otlp OTLP/HTTP export settings. - Otlp *BrowserTelemetryOTLPExportConfig `json:"otlp,omitempty"` -} +// TelemetryEnvelope The envelope assigned to a successfully published event. +type TelemetryEnvelope struct { + // Event A telemetry event. The wire-level event shape accepted by the publish endpoint and emitted on the SSE stream. Arbitrary `type` strings and `data` payloads are admitted. For browser events emitted by the Kernel image, `data` conforms to the per-type schema documented in the `Browser*Event` / `Browser*EventData` definitions, selected by `type`. + Event TelemetryEvent `json:"event"` -// BrowserTelemetryOTLPExportConfig OTLP/HTTP export settings. -type BrowserTelemetryOTLPExportConfig struct { - // Enabled Whether captured telemetry is forwarded to the configured OTLP destination. Off by default. Has no effect (export stays inactive) when no export destination is configured. - Enabled *bool `json:"enabled,omitempty"` + // Seq Process-monotonic sequence number assigned across the lifetime of the server. Use with Last-Event-ID to resume the SSE stream from this point. + Seq int64 `json:"seq"` } -// ChromiumConfigureError Failure from batched chromium configure — includes which phase failed. -type ChromiumConfigureError struct { - Message string `json:"message"` +// TelemetryEvent A telemetry event. The wire-level event shape accepted by the publish endpoint and emitted on the SSE stream. Arbitrary `type` strings and `data` payloads are admitted. For browser events emitted by the Kernel image, `data` conforms to the per-type schema documented in the `Browser*Event` / `Browser*EventData` definitions, selected by `type`. +type TelemetryEvent struct { + // Category Event category. + Category *TelemetryEventCategory `json:"category,omitempty"` - // Phase configure_phase maps to restart/filesystem/policy/extension/profile/display work; navigate_phase is retained for compatibility. - Phase ChromiumConfigureErrorPhase `json:"phase"` + // Data Arbitrary JSON payload. For browser events listed in `KnownBrowserTelemetryEvent`, the payload conforms to the corresponding `Browser*EventData` schema. + Data interface{} `json:"data,omitempty"` - // Step Optional configure step that failed. - Step *ChromiumConfigureErrorStep `json:"step,omitempty"` -} + // Source Provenance metadata identifying which producer emitted the event. + Source *BrowserEventSource `json:"source,omitempty"` -// ChromiumConfigureErrorPhase configure_phase maps to restart/filesystem/policy/extension/profile/display work; navigate_phase is retained for compatibility. -type ChromiumConfigureErrorPhase string + // Truncated Set by the server when the data field was truncated to fit the size limit. + Truncated *bool `json:"truncated,omitempty"` -// ChromiumConfigureErrorStep Optional configure step that failed. -type ChromiumConfigureErrorStep string + // Ts Unix timestamp in microseconds. Defaults to the current time when omitted. + Ts *int64 `json:"ts,omitempty"` -// ClickMouseRequest defines model for ClickMouseRequest. -type ClickMouseRequest struct { - // Button Mouse button to interact with - Button *ClickMouseRequestButton `json:"button,omitempty"` + // Type Event type identifier. + Type string `json:"type"` +} - // ClickType Type of click action - ClickType *ClickMouseRequestClickType `json:"click_type,omitempty"` +// TelemetryEventCategory Event category. +type TelemetryEventCategory string - // HoldKeys Modifier keys to hold during the click - HoldKeys *[]string `json:"hold_keys,omitempty"` +// TelemetryState Current telemetry configuration. +type TelemetryState struct { + // AppliedAt Wall-clock time at which the current configuration was applied. Omitted when telemetry is not configured. + AppliedAt *time.Time `json:"applied_at,omitempty"` - // NumClicks Number of times to repeat the click - NumClicks *int `json:"num_clicks,omitempty"` + // Config Telemetry configuration for a browser. Selection is opt-in. Omit the browser key (or send an empty object) to capture the default set: lightweight operational signals (control, connection, system, captcha). Within `browser`, only the categories you set enabled: true are captured; anything omitted is off. The CDP categories (console, network, page, interaction), `screenshot` and `platform` are off by default and must be opted into. A `browser` config with nothing enabled clears the telemetry configuration. The `monitor` category (CDP collector health) is not configurable here; it flows automatically whenever a CDP category is captured. + Config BrowserTelemetryConfig `json:"config"` - // X X coordinate of the click position - X int `json:"x"` + // DroppedEvents Cumulative number of buffered events a consumer missed because it fell behind the ring, summed across consumers and configuration changes. A rising count means the stream is being produced faster than it is being read; a steady one means nothing has been lost. Always present on images that report it; absent on an image predating the field, which is not the same as zero. + DroppedEvents *int64 `json:"dropped_events,omitempty"` - // Y Y coordinate of the click position - Y int `json:"y"` + // Seq Process-monotonic sequence number of the last published event. Does not reset across configuration changes. + Seq int64 `json:"seq"` } -// ClickMouseRequestButton Mouse button to interact with -type ClickMouseRequestButton string +// TypeTextRequest defines model for TypeTextRequest. +type TypeTextRequest struct { + // Delay Delay in milliseconds between keystrokes. Ignored when smooth is true. + Delay *int `json:"delay,omitempty"` -// ClickMouseRequestClickType Type of click action -type ClickMouseRequestClickType string + // Smooth Use human-like variable keystroke timing instead of a fixed delay. + // Defaults to true (same as moveMouse/dragMouse). Set to false for + // xdotool typing with an optional fixed delay between keys (delay=0 is instant). + // When true, text is typed in word-sized chunks with variable intra-word delays + // and natural inter-word pauses. The delay field is ignored when smooth is true. + Smooth *bool `json:"smooth,omitempty"` -// ClipboardContent defines model for ClipboardContent. -type ClipboardContent struct { - // Text Current clipboard text content + // Text Text to type on the host computer Text string `json:"text"` + + // TypoChance Per-character typo injection rate; mistakes are corrected with backspace. + // Default 0. Only applies when smooth is true (silently ignored when + // smooth is false). + TypoChance *float32 `json:"typo_chance,omitempty"` } -// ComputerAction A single computer action to execute as part of a batch. The `type` field selects which -// action to perform, and the corresponding field contains the action parameters. -// Exactly one action field matching the type must be provided. -type ComputerAction struct { - ClickMouse *ClickMouseRequest `json:"click_mouse,omitempty"` - DragMouse *DragMouseRequest `json:"drag_mouse,omitempty"` - MoveMouse *MoveMouseRequest `json:"move_mouse,omitempty"` - PressKey *PressKeyRequest `json:"press_key,omitempty"` - Scroll *ScrollRequest `json:"scroll,omitempty"` - SetCursor *SetCursorRequest `json:"set_cursor,omitempty"` +// WriteClipboardRequest defines model for WriteClipboardRequest. +type WriteClipboardRequest struct { + // Text Text to write to the system clipboard + Text string `json:"text"` +} - // Sleep Pause execution for a specified duration. - Sleep *SleepAction `json:"sleep,omitempty"` +// BadRequestError defines model for BadRequestError. +type BadRequestError = Error - // Type The type of action to perform. - Type ComputerActionType `json:"type"` - TypeText *TypeTextRequest `json:"type_text,omitempty"` -} +// ConflictError defines model for ConflictError. +type ConflictError = Error -// ComputerActionType The type of action to perform. -type ComputerActionType string +// InternalError defines model for InternalError. +type InternalError = Error -// CreateDirectoryRequest defines model for CreateDirectoryRequest. -type CreateDirectoryRequest struct { - // Mode Optional directory mode (octal string, e.g. 755). Defaults to 755. - Mode *string `json:"mode,omitempty"` +// NotFoundError defines model for NotFoundError. +type NotFoundError = Error - // Path Absolute directory path to create. - Path string `json:"path"` +// PatchChromiumFlagsJSONBody defines parameters for PatchChromiumFlags. +type PatchChromiumFlagsJSONBody struct { + // Flags Chromium flags to merge (e.g., ["--kiosk", "--disable-gpu"]) + Flags []string `json:"flags"` } -// DeletePathRequest defines model for DeletePathRequest. -type DeletePathRequest struct { - // Path Absolute path to delete. - Path string `json:"path"` -} +// PatchChromiumPoliciesJSONBody defines parameters for PatchChromiumPolicies. +type PatchChromiumPoliciesJSONBody map[string]interface{} -// DeleteRecordingRequest defines model for DeleteRecordingRequest. -type DeleteRecordingRequest struct { - // Id Identifier of the recording session to delete, as passed to /recording/start. Alphanumeric or hyphen. When omitted, the default recording session is deleted. - Id *string `json:"id,omitempty"` +// UploadExtensionsAndRestartMultipartBody defines parameters for UploadExtensionsAndRestart. +type UploadExtensionsAndRestartMultipartBody struct { + // Extensions List of extensions to upload and activate + Extensions []struct { + // Name Folder name to place the extension under /home/kernel/extensions/ + Name string `json:"name"` + + // ZipFile Zip archive containing an unpacked Chromium extension (must include manifest.json) + ZipFile openapi_types.File `json:"zip_file"` + } `json:"extensions"` } -// DisplayConfig defines model for DisplayConfig. -type DisplayConfig struct { - // Height Current display height in pixels - Height *int `json:"height,omitempty"` +// ChromiumConfigureMultipartBody defines parameters for ChromiumConfigure. +type ChromiumConfigureMultipartBody struct { + // ChromePolicies UTF-8 JSON policy override map — same semantics as PATCH /chromium/policies. + ChromePolicies *string `json:"chrome_policies,omitempty"` - // RefreshRate Current display refresh rate in Hz (may be null if not detectable) - RefreshRate *int `json:"refresh_rate,omitempty"` + // ChromiumFlags UTF-8 JSON object `{"flags":["--kiosk"]}` — same semantics as PATCH /chromium/flags. + ChromiumFlags *string `json:"chromium_flags,omitempty"` - // Width Current display width in pixels - Width *int `json:"width,omitempty"` -} + // Display UTF-8 JSON object matching `#/components/schemas/PatchDisplayRequest` (width/height/etc.). When combined with restart-triggering fields, the resize is applied while Chromium is stopped and Chromium is started once at the end. + Display *string `json:"display,omitempty"` -// DragMouseRequest defines model for DragMouseRequest. -type DragMouseRequest struct { - // Button Mouse button to drag with - Button *DragMouseRequestButton `json:"button,omitempty"` + // Extensions Extension zips paired with consecutive extensions.name fields (same as upload-extensions-and-restart). + Extensions *[]struct { + Name string `json:"name"` + ZipFile openapi_types.File `json:"zip_file"` + } `json:"extensions,omitempty"` - // Delay Delay in milliseconds between button down and starting to move along the path. - Delay *int `json:"delay,omitempty"` + // ProfileArchive tar.zst archive containing the desired `/home/kernel/user-data` profile contents. Prefer archives whose root entries are the profile files/directories themselves (for example `Default/Preferences`). Use `strip_components` only when uploading an archive that includes leading wrapper directories. + ProfileArchive *openapi_types.File `json:"profile_archive,omitempty"` - // DurationMs Target total duration in milliseconds for the entire drag movement when smooth=true. Omit for automatic timing based on total path length. - DurationMs *int `json:"duration_ms,omitempty"` + // StartUrl URL text to navigate after configure. Bare hosts are normalized to https://, length is capped at 2048 bytes, and Chrome decides which schemes are navigable. + StartUrl *string `json:"start_url,omitempty"` - // HoldKeys Modifier keys to hold during the drag - HoldKeys *[]string `json:"hold_keys,omitempty"` + // StripComponents Optional number of leading path components to strip from profile_archive entries (non-negative integer as text). + StripComponents *string `json:"strip_components,omitempty"` +} - // Path Ordered list of [x, y] coordinate pairs to move through while dragging. Must contain at least 2 points. - Path [][]int `json:"path"` +// DownloadDirZipParams defines parameters for DownloadDirZip. +type DownloadDirZipParams struct { + // Path Absolute directory path to archive and download. + Path string `form:"path" json:"path"` +} - // Smooth Use human-like Bezier curves between path waypoints instead of linear interpolation. When true, steps_per_segment and step_delay_ms are ignored. - Smooth *bool `json:"smooth,omitempty"` +// DownloadDirZstdParams defines parameters for DownloadDirZstd. +type DownloadDirZstdParams struct { + // Path Absolute directory path to archive and download. + Path string `form:"path" json:"path"` - // StepDelayMs Delay in milliseconds between relative steps while dragging. Ignored when smooth=true. - StepDelayMs *int `json:"step_delay_ms,omitempty"` + // CompressionLevel Compression level. Higher levels produce smaller archives but take longer. + // - fastest: ~zstd level 1, maximum speed (~300-500 MB/s) + // - default: ~zstd level 3, balanced speed/ratio (~150 MB/s) + // - better: ~zstd level 7, better ratio (~50-80 MB/s) + // - best: ~zstd level 11, best ratio (~20-40 MB/s) + CompressionLevel *DownloadDirZstdParamsCompressionLevel `form:"compression_level,omitempty" json:"compression_level,omitempty"` +} - // StepsPerSegment Number of relative move steps per segment in the path. Ignored when smooth=true. Minimum 1. - StepsPerSegment *int `json:"steps_per_segment,omitempty"` +// DownloadDirZstdParamsCompressionLevel defines parameters for DownloadDirZstd. +type DownloadDirZstdParamsCompressionLevel string + +// FileInfoParams defines parameters for FileInfo. +type FileInfoParams struct { + // Path Absolute path of the file or directory. + Path string `form:"path" json:"path"` +} + +// ListFilesParams defines parameters for ListFiles. +type ListFilesParams struct { + // Path Absolute directory path. + Path string `form:"path" json:"path"` } -// DragMouseRequestButton Mouse button to drag with -type DragMouseRequestButton string - -// Error defines model for Error. -type Error struct { - Message string `json:"message"` +// ReadFileParams defines parameters for ReadFile. +type ReadFileParams struct { + // Path Absolute file path to read. + Path string `form:"path" json:"path"` } -// ExecutePlaywrightRequest Request to execute Playwright code -type ExecutePlaywrightRequest struct { - // Code TypeScript/JavaScript code to execute. The code has access to 'page', 'context', and 'browser' variables. - // Example: "await page.goto('https://example.com'); return await page.title();" - Code string `json:"code"` +// UploadFilesMultipartBody defines parameters for UploadFiles. +type UploadFilesMultipartBody struct { + Files []struct { + // DestPath Absolute destination path to write the file. + DestPath string `json:"dest_path"` + File openapi_types.File `json:"file"` + } `json:"files"` +} - // TimeoutSec Maximum execution time in seconds. Default is 60. - TimeoutSec *int `json:"timeout_sec,omitempty"` +// UploadZipMultipartBody defines parameters for UploadZip. +type UploadZipMultipartBody struct { + // DestPath Absolute destination directory to extract the archive to. + DestPath string `json:"dest_path"` + ZipFile openapi_types.File `json:"zip_file"` } -// ExecutePlaywrightResult Result of Playwright code execution -type ExecutePlaywrightResult struct { - // Error Error message if execution failed - Error *string `json:"error,omitempty"` +// UploadZstdMultipartBody defines parameters for UploadZstd. +type UploadZstdMultipartBody struct { + // Archive The tar.zst archive file. + Archive openapi_types.File `json:"archive"` - // Result The value returned by the code (if any) - Result interface{} `json:"result,omitempty"` + // DestPath Absolute destination directory to extract the archive to. + DestPath string `json:"dest_path"` - // Stderr Standard error from the execution - Stderr *string `json:"stderr,omitempty"` + // StripComponents Number of leading path components to strip during extraction (like tar --strip-components). + StripComponents *int `json:"strip_components,omitempty"` +} - // Stdout Standard output from the execution - Stdout *string `json:"stdout,omitempty"` +// WriteFileParams defines parameters for WriteFile. +type WriteFileParams struct { + // Path Destination absolute file path. + Path string `form:"path" json:"path"` - // Success Whether the code executed successfully - Success bool `json:"success"` + // Mode Optional file mode (octal string, e.g. 644). Defaults to 644. + Mode *string `form:"mode,omitempty" json:"mode,omitempty"` } -// FileInfo defines model for FileInfo. -type FileInfo struct { - // IsDir Whether the path is a directory. - IsDir bool `json:"is_dir"` +// LogsStreamParams defines parameters for LogsStream. +type LogsStreamParams struct { + Source LogsStreamParamsSource `form:"source" json:"source"` + Follow *bool `form:"follow,omitempty" json:"follow,omitempty"` - // ModTime Last modification time. - ModTime time.Time `json:"mod_time"` + // Path only required if source is path + Path *string `form:"path,omitempty" json:"path,omitempty"` - // Mode File mode bits (e.g., "drwxr-xr-x" or "-rw-r--r--"). - Mode string `json:"mode"` + // SupervisorProcess only required if source is supervisor + SupervisorProcess *string `form:"supervisor_process,omitempty" json:"supervisor_process,omitempty"` +} - // Name Base name of the file or directory. - Name string `json:"name"` +// LogsStreamParamsSource defines parameters for LogsStream. +type LogsStreamParamsSource string - // Path Absolute path. - Path string `json:"path"` +// DownloadRecordingParams defines parameters for DownloadRecording. +type DownloadRecordingParams struct { + // Id Identifier of the recording session to download, as passed to /recording/start. When omitted, the default recording session is downloaded. + Id *string `form:"id,omitempty" json:"id,omitempty"` +} - // SizeBytes Size in bytes. 0 for directories. - SizeBytes int `json:"size_bytes"` +// StreamTelemetryEventsParams defines parameters for StreamTelemetryEvents. +type StreamTelemetryEventsParams struct { + // Replay Pass `all` to start from the oldest retained event. Ring buffer caps at 1024; older events are evicted and surface as a first `id` greater than 1. + Replay *StreamTelemetryEventsParamsReplay `form:"replay,omitempty" json:"replay,omitempty"` + + // LastEventID Resume after this sequence number. Omit or send 0 to start from the current position. Sequence numbers are process-monotonic, so any previous value resumes correctly from that point. Takes precedence over `replay` when both are present, so SSE auto-reconnect resumes cleanly instead of re-replaying history. + LastEventID *string `json:"Last-Event-ID,omitempty"` } -// FileSystemEvent Filesystem change event. -type FileSystemEvent struct { - // IsDir Whether the affected path is a directory. - IsDir *bool `json:"is_dir,omitempty"` +// StreamTelemetryEventsParamsReplay defines parameters for StreamTelemetryEvents. +type StreamTelemetryEventsParamsReplay string - // Name Base name of the file or directory affected. - Name *string `json:"name,omitempty"` +// PatchChromiumFlagsJSONRequestBody defines body for PatchChromiumFlags for application/json ContentType. +type PatchChromiumFlagsJSONRequestBody PatchChromiumFlagsJSONBody - // Path Absolute path of the file or directory. - Path string `json:"path"` +// PatchChromiumPoliciesJSONRequestBody defines body for PatchChromiumPolicies for application/json ContentType. +type PatchChromiumPoliciesJSONRequestBody PatchChromiumPoliciesJSONBody - // Type Event type. - Type FileSystemEventType `json:"type"` -} +// UploadExtensionsAndRestartMultipartRequestBody defines body for UploadExtensionsAndRestart for multipart/form-data ContentType. +type UploadExtensionsAndRestartMultipartRequestBody UploadExtensionsAndRestartMultipartBody -// FileSystemEventType Event type. -type FileSystemEventType string +// BatchComputerActionJSONRequestBody defines body for BatchComputerAction for application/json ContentType. +type BatchComputerActionJSONRequestBody = BatchComputerActionRequest -// KnownBrowserTelemetryEvent Discriminated union of browser telemetry events emitted by the Kernel image. This is a structural taxonomy: any event on the telemetry stream whose `data` conforms to one of the variants below (selected by `type`) is a `KnownBrowserTelemetryEvent`, regardless of who published it. Caller-published events via POST /telemetry/events are not constrained to this union; see `TelemetryEvent` for the wire shape. Validation of caller payloads against this taxonomy is the consumer's responsibility. -type KnownBrowserTelemetryEvent struct { - union json.RawMessage -} +// ClickMouseJSONRequestBody defines body for ClickMouse for application/json ContentType. +type ClickMouseJSONRequestBody = ClickMouseRequest -// ListFiles Array of file or directory information entries. -type ListFiles = []FileInfo +// WriteClipboardJSONRequestBody defines body for WriteClipboard for application/json ContentType. +type WriteClipboardJSONRequestBody = WriteClipboardRequest -// LogEvent A log entry from the application. -type LogEvent struct { - // Message Log message text. - Message string `json:"message"` +// SetCursorJSONRequestBody defines body for SetCursor for application/json ContentType. +type SetCursorJSONRequestBody = SetCursorRequest - // Timestamp Time the log entry was produced. - Timestamp time.Time `json:"timestamp"` -} +// DragMouseJSONRequestBody defines body for DragMouse for application/json ContentType. +type DragMouseJSONRequestBody = DragMouseRequest -// MarkRecordingRequest defines model for MarkRecordingRequest. -type MarkRecordingRequest struct { - // Id Identifier of the recording session to mark, as passed to /recording/start. Alphanumeric or hyphen. When omitted, the marker is added to the default recording session. - Id *string `json:"id,omitempty"` +// MoveMouseJSONRequestBody defines body for MoveMouse for application/json ContentType. +type MoveMouseJSONRequestBody = MoveMouseRequest - // Name Name of the marker, used as the MP4 chapter title. - Name string `json:"name"` -} +// PressKeyJSONRequestBody defines body for PressKey for application/json ContentType. +type PressKeyJSONRequestBody = PressKeyRequest -// MarkRecordingResult defines model for MarkRecordingResult. -type MarkRecordingResult struct { - // Name Name of the recorded marker. - Name string `json:"name"` +// TakeScreenshotJSONRequestBody defines body for TakeScreenshot for application/json ContentType. +type TakeScreenshotJSONRequestBody = ScreenshotRequest - // OffsetMs Provisional offset of the marker from the recording start, in milliseconds, measured against the start time at mark time. The authoritative offset is the chapter start written at finalize. - OffsetMs int64 `json:"offset_ms"` -} +// ScrollJSONRequestBody defines body for Scroll for application/json ContentType. +type ScrollJSONRequestBody = ScrollRequest -// MousePositionResponse defines model for MousePositionResponse. -type MousePositionResponse struct { - // X X coordinate of the cursor - X int `json:"x"` +// TypeTextJSONRequestBody defines body for TypeText for application/json ContentType. +type TypeTextJSONRequestBody = TypeTextRequest - // Y Y coordinate of the cursor - Y int `json:"y"` -} +// ChromiumConfigureMultipartRequestBody defines body for ChromiumConfigure for multipart/form-data ContentType. +type ChromiumConfigureMultipartRequestBody ChromiumConfigureMultipartBody -// MoveMouseRequest defines model for MoveMouseRequest. -type MoveMouseRequest struct { - // DurationMs Target total duration in milliseconds for the mouse movement when smooth=true. Omit for automatic timing based on distance. - DurationMs *int `json:"duration_ms,omitempty"` +// PatchDisplayJSONRequestBody defines body for PatchDisplay for application/json ContentType. +type PatchDisplayJSONRequestBody = PatchDisplayRequest - // HoldKeys Modifier keys to hold during the move - HoldKeys *[]string `json:"hold_keys,omitempty"` +// CreateDirectoryJSONRequestBody defines body for CreateDirectory for application/json ContentType. +type CreateDirectoryJSONRequestBody = CreateDirectoryRequest - // Smooth Use human-like Bezier curve path instead of instant mouse movement. - Smooth *bool `json:"smooth,omitempty"` +// DeleteDirectoryJSONRequestBody defines body for DeleteDirectory for application/json ContentType. +type DeleteDirectoryJSONRequestBody = DeletePathRequest - // X X coordinate to move the cursor to - X int `json:"x"` +// DeleteFileJSONRequestBody defines body for DeleteFile for application/json ContentType. +type DeleteFileJSONRequestBody = DeletePathRequest - // Y Y coordinate to move the cursor to - Y int `json:"y"` -} +// MovePathJSONRequestBody defines body for MovePath for application/json ContentType. +type MovePathJSONRequestBody = MovePathRequest -// MovePathRequest defines model for MovePathRequest. -type MovePathRequest struct { - // DestPath Absolute destination path. - DestPath string `json:"dest_path"` +// SetFilePermissionsJSONRequestBody defines body for SetFilePermissions for application/json ContentType. +type SetFilePermissionsJSONRequestBody = SetFilePermissionsRequest - // SrcPath Absolute source path. - SrcPath string `json:"src_path"` -} +// UploadFilesMultipartRequestBody defines body for UploadFiles for multipart/form-data ContentType. +type UploadFilesMultipartRequestBody UploadFilesMultipartBody -// OkResponse Generic OK response. -type OkResponse struct { - // Ok Indicates success. - Ok bool `json:"ok"` -} +// UploadZipMultipartRequestBody defines body for UploadZip for multipart/form-data ContentType. +type UploadZipMultipartRequestBody UploadZipMultipartBody -// PatchDisplayRequest defines model for PatchDisplayRequest. -type PatchDisplayRequest struct { - // Height Display height in pixels - Height *int `json:"height,omitempty"` +// UploadZstdMultipartRequestBody defines body for UploadZstd for multipart/form-data ContentType. +type UploadZstdMultipartRequestBody UploadZstdMultipartBody - // RefreshRate Display refresh rate in Hz. If omitted, uses the highest available rate for the resolution. - RefreshRate *PatchDisplayRequestRefreshRate `json:"refresh_rate,omitempty"` +// StartFsWatchJSONRequestBody defines body for StartFsWatch for application/json ContentType. +type StartFsWatchJSONRequestBody = StartFsWatchRequest - // RequireIdle If true, refuse to resize when live view or recording/replay is active. - RequireIdle *bool `json:"require_idle,omitempty"` +// ExecutePlaywrightCodeJSONRequestBody defines body for ExecutePlaywrightCode for application/json ContentType. +type ExecutePlaywrightCodeJSONRequestBody = ExecutePlaywrightRequest - // RestartChromium If true, restart Chromium after resolution change to ensure it adapts to new size. Default is false for headful, true for headless. - RestartChromium *bool `json:"restart_chromium,omitempty"` +// ProcessExecJSONRequestBody defines body for ProcessExec for application/json ContentType. +type ProcessExecJSONRequestBody = ProcessExecRequest - // Width Display width in pixels - Width *int `json:"width,omitempty"` -} +// ProcessSpawnJSONRequestBody defines body for ProcessSpawn for application/json ContentType. +type ProcessSpawnJSONRequestBody = ProcessSpawnRequest -// PatchDisplayRequestRefreshRate Display refresh rate in Hz. If omitted, uses the highest available rate for the resolution. -type PatchDisplayRequestRefreshRate int +// ProcessKillJSONRequestBody defines body for ProcessKill for application/json ContentType. +type ProcessKillJSONRequestBody = ProcessKillRequest -// PressKeyRequest defines model for PressKeyRequest. -type PressKeyRequest struct { - // Duration Duration to hold the keys down in milliseconds. If omitted or 0, keys are tapped. - Duration *int `json:"duration,omitempty"` +// ProcessResizeJSONRequestBody defines body for ProcessResize for application/json ContentType. +type ProcessResizeJSONRequestBody = ProcessResizeRequest - // HoldKeys Optional modifier keys to hold during the key press sequence. - HoldKeys *[]string `json:"hold_keys,omitempty"` +// ProcessStdinJSONRequestBody defines body for ProcessStdin for application/json ContentType. +type ProcessStdinJSONRequestBody = ProcessStdinRequest - // Keys List of key symbols to press. Each item should be a key symbol supported by xdotool - // (see X11 keysym definitions). Examples include "Return", "Shift", "Ctrl", "Alt", "F5". - // Items in this list could also be combinations, e.g. "Ctrl+t" or "Ctrl+Shift+Tab". - Keys []string `json:"keys"` -} +// DeleteRecordingJSONRequestBody defines body for DeleteRecording for application/json ContentType. +type DeleteRecordingJSONRequestBody = DeleteRecordingRequest -// ProcessExecRequest Request to execute a command synchronously. -type ProcessExecRequest struct { - // Args Command arguments. - Args *[]string `json:"args,omitempty"` +// MarkRecordingJSONRequestBody defines body for MarkRecording for application/json ContentType. +type MarkRecordingJSONRequestBody = MarkRecordingRequest - // AsRoot Run the process with root privileges. - AsRoot *bool `json:"as_root,omitempty"` +// StartRecordingJSONRequestBody defines body for StartRecording for application/json ContentType. +type StartRecordingJSONRequestBody = StartRecordingRequest - // AsUser Run the process as this user. - AsUser *string `json:"as_user,omitempty"` +// StopRecordingJSONRequestBody defines body for StopRecording for application/json ContentType. +type StopRecordingJSONRequestBody = StopRecordingRequest - // Command Executable or shell command to run. - Command string `json:"command"` +// PatchTelemetryJSONRequestBody defines body for PatchTelemetry for application/json ContentType. +type PatchTelemetryJSONRequestBody = BrowserTelemetryConfig - // Cwd Working directory (absolute path) to run the command in. - Cwd *string `json:"cwd,omitempty"` +// PutTelemetryJSONRequestBody defines body for PutTelemetry for application/json ContentType. +type PutTelemetryJSONRequestBody = BrowserTelemetryConfig - // Env Environment variables to set for the process. - Env *map[string]string `json:"env,omitempty"` +// PublishTelemetryEventJSONRequestBody defines body for PublishTelemetryEvent for application/json ContentType. +type PublishTelemetryEventJSONRequestBody = PublishEventRequest - // TimeoutSec Maximum execution time in seconds. - TimeoutSec *int `json:"timeout_sec,omitempty"` +// AsBrowserCdpInputDispatchMouseEventCommandData returns the union data inside the BrowserCdpCommandEventData as a BrowserCdpInputDispatchMouseEventCommandData +func (t BrowserCdpCommandEventData) AsBrowserCdpInputDispatchMouseEventCommandData() (BrowserCdpInputDispatchMouseEventCommandData, error) { + var body BrowserCdpInputDispatchMouseEventCommandData + err := json.Unmarshal(t.union, &body) + return body, err } -// ProcessExecResult Result of a synchronous command execution. -type ProcessExecResult struct { - // DurationMs Execution duration in milliseconds. - DurationMs *int `json:"duration_ms,omitempty"` - - // ExitCode Process exit code. - ExitCode *int `json:"exit_code,omitempty"` +// FromBrowserCdpInputDispatchMouseEventCommandData overwrites any union data inside the BrowserCdpCommandEventData as the provided BrowserCdpInputDispatchMouseEventCommandData +func (t *BrowserCdpCommandEventData) FromBrowserCdpInputDispatchMouseEventCommandData(v BrowserCdpInputDispatchMouseEventCommandData) error { + v.Method = "Input.dispatchMouseEvent" + b, err := json.Marshal(v) + t.union = b + return err +} - // StderrB64 Base64-encoded stderr buffer. - StderrB64 *string `json:"stderr_b64,omitempty"` +// MergeBrowserCdpInputDispatchMouseEventCommandData performs a merge with any union data inside the BrowserCdpCommandEventData, using the provided BrowserCdpInputDispatchMouseEventCommandData +func (t *BrowserCdpCommandEventData) MergeBrowserCdpInputDispatchMouseEventCommandData(v BrowserCdpInputDispatchMouseEventCommandData) error { + v.Method = "Input.dispatchMouseEvent" + b, err := json.Marshal(v) + if err != nil { + return err + } - // StdoutB64 Base64-encoded stdout buffer. - StdoutB64 *string `json:"stdout_b64,omitempty"` + merged, err := runtime.JSONMerge(t.union, b) + t.union = merged + return err } -// ProcessKillRequest Signal to send to the process. -type ProcessKillRequest struct { - // Signal Signal to send. - Signal ProcessKillRequestSignal `json:"signal"` +// AsBrowserCdpInputDispatchKeyEventCommandData returns the union data inside the BrowserCdpCommandEventData as a BrowserCdpInputDispatchKeyEventCommandData +func (t BrowserCdpCommandEventData) AsBrowserCdpInputDispatchKeyEventCommandData() (BrowserCdpInputDispatchKeyEventCommandData, error) { + var body BrowserCdpInputDispatchKeyEventCommandData + err := json.Unmarshal(t.union, &body) + return body, err } -// ProcessKillRequestSignal Signal to send. -type ProcessKillRequestSignal string +// FromBrowserCdpInputDispatchKeyEventCommandData overwrites any union data inside the BrowserCdpCommandEventData as the provided BrowserCdpInputDispatchKeyEventCommandData +func (t *BrowserCdpCommandEventData) FromBrowserCdpInputDispatchKeyEventCommandData(v BrowserCdpInputDispatchKeyEventCommandData) error { + v.Method = "Input.dispatchKeyEvent" + b, err := json.Marshal(v) + t.union = b + return err +} -// ProcessResizeRequest Resize a PTY-backed process. -type ProcessResizeRequest struct { - // Cols New terminal columns. - Cols int `json:"cols"` +// MergeBrowserCdpInputDispatchKeyEventCommandData performs a merge with any union data inside the BrowserCdpCommandEventData, using the provided BrowserCdpInputDispatchKeyEventCommandData +func (t *BrowserCdpCommandEventData) MergeBrowserCdpInputDispatchKeyEventCommandData(v BrowserCdpInputDispatchKeyEventCommandData) error { + v.Method = "Input.dispatchKeyEvent" + b, err := json.Marshal(v) + if err != nil { + return err + } - // Rows New terminal rows. - Rows int `json:"rows"` + merged, err := runtime.JSONMerge(t.union, b) + t.union = merged + return err } -// ProcessSpawnRequest defines model for ProcessSpawnRequest. -type ProcessSpawnRequest struct { - // AllocateTty Allocate a pseudo-terminal (PTY) for the process to enable interactive shells. - AllocateTty *bool `json:"allocate_tty,omitempty"` - - // Args Command arguments. - Args *[]string `json:"args,omitempty"` +// AsBrowserCdpInputInsertTextCommandData returns the union data inside the BrowserCdpCommandEventData as a BrowserCdpInputInsertTextCommandData +func (t BrowserCdpCommandEventData) AsBrowserCdpInputInsertTextCommandData() (BrowserCdpInputInsertTextCommandData, error) { + var body BrowserCdpInputInsertTextCommandData + err := json.Unmarshal(t.union, &body) + return body, err +} - // AsRoot Run the process with root privileges. - AsRoot *bool `json:"as_root,omitempty"` +// FromBrowserCdpInputInsertTextCommandData overwrites any union data inside the BrowserCdpCommandEventData as the provided BrowserCdpInputInsertTextCommandData +func (t *BrowserCdpCommandEventData) FromBrowserCdpInputInsertTextCommandData(v BrowserCdpInputInsertTextCommandData) error { + v.Method = "Input.insertText" + b, err := json.Marshal(v) + t.union = b + return err +} - // AsUser Run the process as this user. - AsUser *string `json:"as_user,omitempty"` +// MergeBrowserCdpInputInsertTextCommandData performs a merge with any union data inside the BrowserCdpCommandEventData, using the provided BrowserCdpInputInsertTextCommandData +func (t *BrowserCdpCommandEventData) MergeBrowserCdpInputInsertTextCommandData(v BrowserCdpInputInsertTextCommandData) error { + v.Method = "Input.insertText" + b, err := json.Marshal(v) + if err != nil { + return err + } - // Cols Initial terminal columns when allocate_tty is true. - Cols *int `json:"cols,omitempty"` + merged, err := runtime.JSONMerge(t.union, b) + t.union = merged + return err +} - // Command Executable or shell command to run. - Command string `json:"command"` +// AsBrowserCdpInputImeSetCompositionCommandData returns the union data inside the BrowserCdpCommandEventData as a BrowserCdpInputImeSetCompositionCommandData +func (t BrowserCdpCommandEventData) AsBrowserCdpInputImeSetCompositionCommandData() (BrowserCdpInputImeSetCompositionCommandData, error) { + var body BrowserCdpInputImeSetCompositionCommandData + err := json.Unmarshal(t.union, &body) + return body, err +} - // Cwd Working directory (absolute path) to run the command in. - Cwd *string `json:"cwd,omitempty"` +// FromBrowserCdpInputImeSetCompositionCommandData overwrites any union data inside the BrowserCdpCommandEventData as the provided BrowserCdpInputImeSetCompositionCommandData +func (t *BrowserCdpCommandEventData) FromBrowserCdpInputImeSetCompositionCommandData(v BrowserCdpInputImeSetCompositionCommandData) error { + v.Method = "Input.imeSetComposition" + b, err := json.Marshal(v) + t.union = b + return err +} - // Env Environment variables to set for the process. - Env *map[string]string `json:"env,omitempty"` +// MergeBrowserCdpInputImeSetCompositionCommandData performs a merge with any union data inside the BrowserCdpCommandEventData, using the provided BrowserCdpInputImeSetCompositionCommandData +func (t *BrowserCdpCommandEventData) MergeBrowserCdpInputImeSetCompositionCommandData(v BrowserCdpInputImeSetCompositionCommandData) error { + v.Method = "Input.imeSetComposition" + b, err := json.Marshal(v) + if err != nil { + return err + } - // Rows Initial terminal rows when allocate_tty is true. - Rows *int `json:"rows,omitempty"` + merged, err := runtime.JSONMerge(t.union, b) + t.union = merged + return err +} - // TimeoutSec Maximum execution time in seconds. - TimeoutSec *int `json:"timeout_sec,omitempty"` +// AsBrowserCdpInputDispatchTouchEventCommandData returns the union data inside the BrowserCdpCommandEventData as a BrowserCdpInputDispatchTouchEventCommandData +func (t BrowserCdpCommandEventData) AsBrowserCdpInputDispatchTouchEventCommandData() (BrowserCdpInputDispatchTouchEventCommandData, error) { + var body BrowserCdpInputDispatchTouchEventCommandData + err := json.Unmarshal(t.union, &body) + return body, err } -// ProcessSpawnResult Information about a spawned process. -type ProcessSpawnResult struct { - // Pid OS process ID. - Pid *int `json:"pid,omitempty"` +// FromBrowserCdpInputDispatchTouchEventCommandData overwrites any union data inside the BrowserCdpCommandEventData as the provided BrowserCdpInputDispatchTouchEventCommandData +func (t *BrowserCdpCommandEventData) FromBrowserCdpInputDispatchTouchEventCommandData(v BrowserCdpInputDispatchTouchEventCommandData) error { + v.Method = "Input.dispatchTouchEvent" + b, err := json.Marshal(v) + t.union = b + return err +} - // ProcessId Server-assigned identifier for the process. - ProcessId *openapi_types.UUID `json:"process_id,omitempty"` +// MergeBrowserCdpInputDispatchTouchEventCommandData performs a merge with any union data inside the BrowserCdpCommandEventData, using the provided BrowserCdpInputDispatchTouchEventCommandData +func (t *BrowserCdpCommandEventData) MergeBrowserCdpInputDispatchTouchEventCommandData(v BrowserCdpInputDispatchTouchEventCommandData) error { + v.Method = "Input.dispatchTouchEvent" + b, err := json.Marshal(v) + if err != nil { + return err + } - // StartedAt Timestamp when the process started. - StartedAt *time.Time `json:"started_at,omitempty"` + merged, err := runtime.JSONMerge(t.union, b) + t.union = merged + return err } -// ProcessStatus Current status of a process. -type ProcessStatus struct { - // CpuPct Estimated CPU usage percentage. - CpuPct *float32 `json:"cpu_pct,omitempty"` +// AsBrowserCdpInputDispatchDragEventCommandData returns the union data inside the BrowserCdpCommandEventData as a BrowserCdpInputDispatchDragEventCommandData +func (t BrowserCdpCommandEventData) AsBrowserCdpInputDispatchDragEventCommandData() (BrowserCdpInputDispatchDragEventCommandData, error) { + var body BrowserCdpInputDispatchDragEventCommandData + err := json.Unmarshal(t.union, &body) + return body, err +} - // ExitCode Exit code if the process has exited. - ExitCode *int `json:"exit_code,omitempty"` +// FromBrowserCdpInputDispatchDragEventCommandData overwrites any union data inside the BrowserCdpCommandEventData as the provided BrowserCdpInputDispatchDragEventCommandData +func (t *BrowserCdpCommandEventData) FromBrowserCdpInputDispatchDragEventCommandData(v BrowserCdpInputDispatchDragEventCommandData) error { + v.Method = "Input.dispatchDragEvent" + b, err := json.Marshal(v) + t.union = b + return err +} - // MemBytes Estimated resident memory usage in bytes. - MemBytes *int `json:"mem_bytes,omitempty"` +// MergeBrowserCdpInputDispatchDragEventCommandData performs a merge with any union data inside the BrowserCdpCommandEventData, using the provided BrowserCdpInputDispatchDragEventCommandData +func (t *BrowserCdpCommandEventData) MergeBrowserCdpInputDispatchDragEventCommandData(v BrowserCdpInputDispatchDragEventCommandData) error { + v.Method = "Input.dispatchDragEvent" + b, err := json.Marshal(v) + if err != nil { + return err + } - // State Process state. - State *ProcessStatusState `json:"state,omitempty"` + merged, err := runtime.JSONMerge(t.union, b) + t.union = merged + return err } -// ProcessStatusState Process state. -type ProcessStatusState string - -// ProcessStdinRequest Data to write to the process standard input. -type ProcessStdinRequest struct { - // DataB64 Base64-encoded data to write. - DataB64 string `json:"data_b64"` +// AsBrowserCdpInputCancelDraggingCommandData returns the union data inside the BrowserCdpCommandEventData as a BrowserCdpInputCancelDraggingCommandData +func (t BrowserCdpCommandEventData) AsBrowserCdpInputCancelDraggingCommandData() (BrowserCdpInputCancelDraggingCommandData, error) { + var body BrowserCdpInputCancelDraggingCommandData + err := json.Unmarshal(t.union, &body) + return body, err } -// ProcessStdinResult Result of writing to stdin. -type ProcessStdinResult struct { - // WrittenBytes Number of bytes written. - WrittenBytes *int `json:"written_bytes,omitempty"` +// FromBrowserCdpInputCancelDraggingCommandData overwrites any union data inside the BrowserCdpCommandEventData as the provided BrowserCdpInputCancelDraggingCommandData +func (t *BrowserCdpCommandEventData) FromBrowserCdpInputCancelDraggingCommandData(v BrowserCdpInputCancelDraggingCommandData) error { + v.Method = "Input.cancelDragging" + b, err := json.Marshal(v) + t.union = b + return err } -// ProcessStreamEvent SSE payload representing process output or lifecycle events. -type ProcessStreamEvent struct { - // DataB64 Base64-encoded data from the process stream. - DataB64 *string `json:"data_b64,omitempty"` +// MergeBrowserCdpInputCancelDraggingCommandData performs a merge with any union data inside the BrowserCdpCommandEventData, using the provided BrowserCdpInputCancelDraggingCommandData +func (t *BrowserCdpCommandEventData) MergeBrowserCdpInputCancelDraggingCommandData(v BrowserCdpInputCancelDraggingCommandData) error { + v.Method = "Input.cancelDragging" + b, err := json.Marshal(v) + if err != nil { + return err + } - // Event Lifecycle event type. - Event *ProcessStreamEventEvent `json:"event,omitempty"` + merged, err := runtime.JSONMerge(t.union, b) + t.union = merged + return err +} - // ExitCode Exit code when the event is "exit". - ExitCode *int `json:"exit_code,omitempty"` +// AsBrowserCdpInputEmulateTouchFromMouseEventCommandData returns the union data inside the BrowserCdpCommandEventData as a BrowserCdpInputEmulateTouchFromMouseEventCommandData +func (t BrowserCdpCommandEventData) AsBrowserCdpInputEmulateTouchFromMouseEventCommandData() (BrowserCdpInputEmulateTouchFromMouseEventCommandData, error) { + var body BrowserCdpInputEmulateTouchFromMouseEventCommandData + err := json.Unmarshal(t.union, &body) + return body, err +} - // Stream Source stream of the data chunk. - Stream *ProcessStreamEventStream `json:"stream,omitempty"` +// FromBrowserCdpInputEmulateTouchFromMouseEventCommandData overwrites any union data inside the BrowserCdpCommandEventData as the provided BrowserCdpInputEmulateTouchFromMouseEventCommandData +func (t *BrowserCdpCommandEventData) FromBrowserCdpInputEmulateTouchFromMouseEventCommandData(v BrowserCdpInputEmulateTouchFromMouseEventCommandData) error { + v.Method = "Input.emulateTouchFromMouseEvent" + b, err := json.Marshal(v) + t.union = b + return err } -// ProcessStreamEventEvent Lifecycle event type. -type ProcessStreamEventEvent string +// MergeBrowserCdpInputEmulateTouchFromMouseEventCommandData performs a merge with any union data inside the BrowserCdpCommandEventData, using the provided BrowserCdpInputEmulateTouchFromMouseEventCommandData +func (t *BrowserCdpCommandEventData) MergeBrowserCdpInputEmulateTouchFromMouseEventCommandData(v BrowserCdpInputEmulateTouchFromMouseEventCommandData) error { + v.Method = "Input.emulateTouchFromMouseEvent" + b, err := json.Marshal(v) + if err != nil { + return err + } -// ProcessStreamEventStream Source stream of the data chunk. -type ProcessStreamEventStream string + merged, err := runtime.JSONMerge(t.union, b) + t.union = merged + return err +} -// PublishEventRequest Request body for publishing an event into the telemetry stream. -type PublishEventRequest struct { - // Category Event category. Optional and advisory: for a known event `type` the server assigns the category authoritatively and ignores this field. It is only used for unknown custom types, where it is required. - Category *PublishEventRequestCategory `json:"category,omitempty"` +// AsBrowserCdpInputSynthesizePinchGestureCommandData returns the union data inside the BrowserCdpCommandEventData as a BrowserCdpInputSynthesizePinchGestureCommandData +func (t BrowserCdpCommandEventData) AsBrowserCdpInputSynthesizePinchGestureCommandData() (BrowserCdpInputSynthesizePinchGestureCommandData, error) { + var body BrowserCdpInputSynthesizePinchGestureCommandData + err := json.Unmarshal(t.union, &body) + return body, err +} - // Data Telemetry event payload. - Data interface{} `json:"data,omitempty"` +// FromBrowserCdpInputSynthesizePinchGestureCommandData overwrites any union data inside the BrowserCdpCommandEventData as the provided BrowserCdpInputSynthesizePinchGestureCommandData +func (t *BrowserCdpCommandEventData) FromBrowserCdpInputSynthesizePinchGestureCommandData(v BrowserCdpInputSynthesizePinchGestureCommandData) error { + v.Method = "Input.synthesizePinchGesture" + b, err := json.Marshal(v) + t.union = b + return err +} - // Source Provenance metadata identifying which producer emitted the event. - Source *BrowserEventSource `json:"source,omitempty"` +// MergeBrowserCdpInputSynthesizePinchGestureCommandData performs a merge with any union data inside the BrowserCdpCommandEventData, using the provided BrowserCdpInputSynthesizePinchGestureCommandData +func (t *BrowserCdpCommandEventData) MergeBrowserCdpInputSynthesizePinchGestureCommandData(v BrowserCdpInputSynthesizePinchGestureCommandData) error { + v.Method = "Input.synthesizePinchGesture" + b, err := json.Marshal(v) + if err != nil { + return err + } - // Type Event type identifier. - Type string `json:"type"` + merged, err := runtime.JSONMerge(t.union, b) + t.union = merged + return err +} + +// AsBrowserCdpInputSynthesizeScrollGestureCommandData returns the union data inside the BrowserCdpCommandEventData as a BrowserCdpInputSynthesizeScrollGestureCommandData +func (t BrowserCdpCommandEventData) AsBrowserCdpInputSynthesizeScrollGestureCommandData() (BrowserCdpInputSynthesizeScrollGestureCommandData, error) { + var body BrowserCdpInputSynthesizeScrollGestureCommandData + err := json.Unmarshal(t.union, &body) + return body, err } -// PublishEventRequestCategory Event category. Optional and advisory: for a known event `type` the server assigns the category authoritatively and ignores this field. It is only used for unknown custom types, where it is required. -type PublishEventRequestCategory string +// FromBrowserCdpInputSynthesizeScrollGestureCommandData overwrites any union data inside the BrowserCdpCommandEventData as the provided BrowserCdpInputSynthesizeScrollGestureCommandData +func (t *BrowserCdpCommandEventData) FromBrowserCdpInputSynthesizeScrollGestureCommandData(v BrowserCdpInputSynthesizeScrollGestureCommandData) error { + v.Method = "Input.synthesizeScrollGesture" + b, err := json.Marshal(v) + t.union = b + return err +} -// RecorderInfo defines model for RecorderInfo. -type RecorderInfo struct { - // FinishedAt Timestamp when recording finished - FinishedAt *time.Time `json:"finished_at,omitempty"` - Id string `json:"id"` - IsRecording bool `json:"isRecording"` +// MergeBrowserCdpInputSynthesizeScrollGestureCommandData performs a merge with any union data inside the BrowserCdpCommandEventData, using the provided BrowserCdpInputSynthesizeScrollGestureCommandData +func (t *BrowserCdpCommandEventData) MergeBrowserCdpInputSynthesizeScrollGestureCommandData(v BrowserCdpInputSynthesizeScrollGestureCommandData) error { + v.Method = "Input.synthesizeScrollGesture" + b, err := json.Marshal(v) + if err != nil { + return err + } - // StartedAt Timestamp when recording started - StartedAt *time.Time `json:"started_at,omitempty"` + merged, err := runtime.JSONMerge(t.union, b) + t.union = merged + return err } -// ScreenshotRegion defines model for ScreenshotRegion. -type ScreenshotRegion struct { - // Height Height of the region in pixels - Height int `json:"height"` +// AsBrowserCdpInputSynthesizeTapGestureCommandData returns the union data inside the BrowserCdpCommandEventData as a BrowserCdpInputSynthesizeTapGestureCommandData +func (t BrowserCdpCommandEventData) AsBrowserCdpInputSynthesizeTapGestureCommandData() (BrowserCdpInputSynthesizeTapGestureCommandData, error) { + var body BrowserCdpInputSynthesizeTapGestureCommandData + err := json.Unmarshal(t.union, &body) + return body, err +} - // Width Width of the region in pixels - Width int `json:"width"` +// FromBrowserCdpInputSynthesizeTapGestureCommandData overwrites any union data inside the BrowserCdpCommandEventData as the provided BrowserCdpInputSynthesizeTapGestureCommandData +func (t *BrowserCdpCommandEventData) FromBrowserCdpInputSynthesizeTapGestureCommandData(v BrowserCdpInputSynthesizeTapGestureCommandData) error { + v.Method = "Input.synthesizeTapGesture" + b, err := json.Marshal(v) + t.union = b + return err +} - // X X coordinate of the region's top-left corner - X int `json:"x"` +// MergeBrowserCdpInputSynthesizeTapGestureCommandData performs a merge with any union data inside the BrowserCdpCommandEventData, using the provided BrowserCdpInputSynthesizeTapGestureCommandData +func (t *BrowserCdpCommandEventData) MergeBrowserCdpInputSynthesizeTapGestureCommandData(v BrowserCdpInputSynthesizeTapGestureCommandData) error { + v.Method = "Input.synthesizeTapGesture" + b, err := json.Marshal(v) + if err != nil { + return err + } - // Y Y coordinate of the region's top-left corner - Y int `json:"y"` + merged, err := runtime.JSONMerge(t.union, b) + t.union = merged + return err } -// ScreenshotRequest defines model for ScreenshotRequest. -type ScreenshotRequest struct { - Region *ScreenshotRegion `json:"region,omitempty"` +// AsBrowserCdpDomSetFileInputFilesCommandData returns the union data inside the BrowserCdpCommandEventData as a BrowserCdpDomSetFileInputFilesCommandData +func (t BrowserCdpCommandEventData) AsBrowserCdpDomSetFileInputFilesCommandData() (BrowserCdpDomSetFileInputFilesCommandData, error) { + var body BrowserCdpDomSetFileInputFilesCommandData + err := json.Unmarshal(t.union, &body) + return body, err } -// ScrollRequest defines model for ScrollRequest. -type ScrollRequest struct { - // DeltaX Horizontal scroll amount. Positive scrolls right, negative scrolls left. - DeltaX *int `json:"delta_x,omitempty"` - - // DeltaY Vertical scroll amount. Positive scrolls down, negative scrolls up. - DeltaY *int `json:"delta_y,omitempty"` - - // HoldKeys Modifier keys to hold during the scroll - HoldKeys *[]string `json:"hold_keys,omitempty"` +// FromBrowserCdpDomSetFileInputFilesCommandData overwrites any union data inside the BrowserCdpCommandEventData as the provided BrowserCdpDomSetFileInputFilesCommandData +func (t *BrowserCdpCommandEventData) FromBrowserCdpDomSetFileInputFilesCommandData(v BrowserCdpDomSetFileInputFilesCommandData) error { + v.Method = "DOM.setFileInputFiles" + b, err := json.Marshal(v) + t.union = b + return err +} - // X X coordinate at which to perform the scroll - X int `json:"x"` +// MergeBrowserCdpDomSetFileInputFilesCommandData performs a merge with any union data inside the BrowserCdpCommandEventData, using the provided BrowserCdpDomSetFileInputFilesCommandData +func (t *BrowserCdpCommandEventData) MergeBrowserCdpDomSetFileInputFilesCommandData(v BrowserCdpDomSetFileInputFilesCommandData) error { + v.Method = "DOM.setFileInputFiles" + b, err := json.Marshal(v) + if err != nil { + return err + } - // Y Y coordinate at which to perform the scroll - Y int `json:"y"` + merged, err := runtime.JSONMerge(t.union, b) + t.union = merged + return err } -// SetCursorRequest defines model for SetCursorRequest. -type SetCursorRequest struct { - // Hidden Whether the cursor should be hidden - Hidden bool `json:"hidden"` +// AsBrowserCdpDomFocusCommandData returns the union data inside the BrowserCdpCommandEventData as a BrowserCdpDomFocusCommandData +func (t BrowserCdpCommandEventData) AsBrowserCdpDomFocusCommandData() (BrowserCdpDomFocusCommandData, error) { + var body BrowserCdpDomFocusCommandData + err := json.Unmarshal(t.union, &body) + return body, err } -// SetFilePermissionsRequest defines model for SetFilePermissionsRequest. -type SetFilePermissionsRequest struct { - // Group New group name or GID. - Group *string `json:"group,omitempty"` +// FromBrowserCdpDomFocusCommandData overwrites any union data inside the BrowserCdpCommandEventData as the provided BrowserCdpDomFocusCommandData +func (t *BrowserCdpCommandEventData) FromBrowserCdpDomFocusCommandData(v BrowserCdpDomFocusCommandData) error { + v.Method = "DOM.focus" + b, err := json.Marshal(v) + t.union = b + return err +} - // Mode File mode bits (octal string, e.g. 644). - Mode string `json:"mode"` +// MergeBrowserCdpDomFocusCommandData performs a merge with any union data inside the BrowserCdpCommandEventData, using the provided BrowserCdpDomFocusCommandData +func (t *BrowserCdpCommandEventData) MergeBrowserCdpDomFocusCommandData(v BrowserCdpDomFocusCommandData) error { + v.Method = "DOM.focus" + b, err := json.Marshal(v) + if err != nil { + return err + } - // Owner New owner username or UID. - Owner *string `json:"owner,omitempty"` + merged, err := runtime.JSONMerge(t.union, b) + t.union = merged + return err +} - // Path Absolute path whose permissions are to be changed. - Path string `json:"path"` +// AsBrowserCdpDomScrollIntoViewIfNeededCommandData returns the union data inside the BrowserCdpCommandEventData as a BrowserCdpDomScrollIntoViewIfNeededCommandData +func (t BrowserCdpCommandEventData) AsBrowserCdpDomScrollIntoViewIfNeededCommandData() (BrowserCdpDomScrollIntoViewIfNeededCommandData, error) { + var body BrowserCdpDomScrollIntoViewIfNeededCommandData + err := json.Unmarshal(t.union, &body) + return body, err } -// SleepAction Pause execution for a specified duration. -type SleepAction struct { - // DurationMs Duration to sleep in milliseconds. - DurationMs int `json:"duration_ms"` +// FromBrowserCdpDomScrollIntoViewIfNeededCommandData overwrites any union data inside the BrowserCdpCommandEventData as the provided BrowserCdpDomScrollIntoViewIfNeededCommandData +func (t *BrowserCdpCommandEventData) FromBrowserCdpDomScrollIntoViewIfNeededCommandData(v BrowserCdpDomScrollIntoViewIfNeededCommandData) error { + v.Method = "DOM.scrollIntoViewIfNeeded" + b, err := json.Marshal(v) + t.union = b + return err } -// StartFsWatchRequest defines model for StartFsWatchRequest. -type StartFsWatchRequest struct { - // Path Directory to watch. - Path string `json:"path"` +// MergeBrowserCdpDomScrollIntoViewIfNeededCommandData performs a merge with any union data inside the BrowserCdpCommandEventData, using the provided BrowserCdpDomScrollIntoViewIfNeededCommandData +func (t *BrowserCdpCommandEventData) MergeBrowserCdpDomScrollIntoViewIfNeededCommandData(v BrowserCdpDomScrollIntoViewIfNeededCommandData) error { + v.Method = "DOM.scrollIntoViewIfNeeded" + b, err := json.Marshal(v) + if err != nil { + return err + } - // Recursive Whether to watch recursively. - Recursive *bool `json:"recursive,omitempty"` + merged, err := runtime.JSONMerge(t.union, b) + t.union = merged + return err } -// StartRecordingRequest defines model for StartRecordingRequest. -type StartRecordingRequest struct { - // Framerate Recording framerate in fps (overrides server default) - Framerate *int `json:"framerate,omitempty"` - - // Id Optional identifier for this recording session, used to target it from the other /recording endpoints (stop, mark, download, delete) and allowing multiple concurrent recordings. Alphanumeric or hyphen. When omitted, the default recording session is started. - Id *string `json:"id,omitempty"` +// AsBrowserCdpPageBringToFrontCommandData returns the union data inside the BrowserCdpCommandEventData as a BrowserCdpPageBringToFrontCommandData +func (t BrowserCdpCommandEventData) AsBrowserCdpPageBringToFrontCommandData() (BrowserCdpPageBringToFrontCommandData, error) { + var body BrowserCdpPageBringToFrontCommandData + err := json.Unmarshal(t.union, &body) + return body, err +} - // MaxDurationInSeconds Maximum recording duration in seconds (overrides server default) - MaxDurationInSeconds *int `json:"maxDurationInSeconds,omitempty"` +// FromBrowserCdpPageBringToFrontCommandData overwrites any union data inside the BrowserCdpCommandEventData as the provided BrowserCdpPageBringToFrontCommandData +func (t *BrowserCdpCommandEventData) FromBrowserCdpPageBringToFrontCommandData(v BrowserCdpPageBringToFrontCommandData) error { + v.Method = "Page.bringToFront" + b, err := json.Marshal(v) + t.union = b + return err +} - // MaxFileSizeInMB Maximum file size in MB (overrides server default) - MaxFileSizeInMB *int `json:"maxFileSizeInMB,omitempty"` +// MergeBrowserCdpPageBringToFrontCommandData performs a merge with any union data inside the BrowserCdpCommandEventData, using the provided BrowserCdpPageBringToFrontCommandData +func (t *BrowserCdpCommandEventData) MergeBrowserCdpPageBringToFrontCommandData(v BrowserCdpPageBringToFrontCommandData) error { + v.Method = "Page.bringToFront" + b, err := json.Marshal(v) + if err != nil { + return err + } - // RecordAudio Capture audio alongside video. Requires the server to have an audio source and PulseAudio socket configured (the image sets both by default). When false the recording is video-only. - RecordAudio *bool `json:"recordAudio,omitempty"` + merged, err := runtime.JSONMerge(t.union, b) + t.union = merged + return err } -// StopRecordingRequest defines model for StopRecordingRequest. -type StopRecordingRequest struct { - // ForceStop Immediately stop without graceful shutdown. This may result in a corrupted video file. - ForceStop *bool `json:"forceStop,omitempty"` +// AsBrowserCdpPageCaptureScreenshotCommandData returns the union data inside the BrowserCdpCommandEventData as a BrowserCdpPageCaptureScreenshotCommandData +func (t BrowserCdpCommandEventData) AsBrowserCdpPageCaptureScreenshotCommandData() (BrowserCdpPageCaptureScreenshotCommandData, error) { + var body BrowserCdpPageCaptureScreenshotCommandData + err := json.Unmarshal(t.union, &body) + return body, err +} - // Id Identifier of the recording session to stop, as passed to /recording/start. Alphanumeric or hyphen. When omitted, the default recording session is stopped. - Id *string `json:"id,omitempty"` +// FromBrowserCdpPageCaptureScreenshotCommandData overwrites any union data inside the BrowserCdpCommandEventData as the provided BrowserCdpPageCaptureScreenshotCommandData +func (t *BrowserCdpCommandEventData) FromBrowserCdpPageCaptureScreenshotCommandData(v BrowserCdpPageCaptureScreenshotCommandData) error { + v.Method = "Page.captureScreenshot" + b, err := json.Marshal(v) + t.union = b + return err } -// TelemetryEnvelope The envelope assigned to a successfully published event. -type TelemetryEnvelope struct { - // Event A telemetry event. The wire-level event shape accepted by the publish endpoint and emitted on the SSE stream. Arbitrary `type` strings and `data` payloads are admitted. For browser events emitted by the Kernel image, `data` conforms to the per-type schema documented in the `Browser*Event` / `Browser*EventData` definitions, selected by `type`. - Event TelemetryEvent `json:"event"` +// MergeBrowserCdpPageCaptureScreenshotCommandData performs a merge with any union data inside the BrowserCdpCommandEventData, using the provided BrowserCdpPageCaptureScreenshotCommandData +func (t *BrowserCdpCommandEventData) MergeBrowserCdpPageCaptureScreenshotCommandData(v BrowserCdpPageCaptureScreenshotCommandData) error { + v.Method = "Page.captureScreenshot" + b, err := json.Marshal(v) + if err != nil { + return err + } - // Seq Process-monotonic sequence number assigned across the lifetime of the server. Use with Last-Event-ID to resume the SSE stream from this point. - Seq int64 `json:"seq"` + merged, err := runtime.JSONMerge(t.union, b) + t.union = merged + return err } -// TelemetryEvent A telemetry event. The wire-level event shape accepted by the publish endpoint and emitted on the SSE stream. Arbitrary `type` strings and `data` payloads are admitted. For browser events emitted by the Kernel image, `data` conforms to the per-type schema documented in the `Browser*Event` / `Browser*EventData` definitions, selected by `type`. -type TelemetryEvent struct { - // Category Event category. - Category *TelemetryEventCategory `json:"category,omitempty"` +// AsBrowserCdpPageCaptureSnapshotCommandData returns the union data inside the BrowserCdpCommandEventData as a BrowserCdpPageCaptureSnapshotCommandData +func (t BrowserCdpCommandEventData) AsBrowserCdpPageCaptureSnapshotCommandData() (BrowserCdpPageCaptureSnapshotCommandData, error) { + var body BrowserCdpPageCaptureSnapshotCommandData + err := json.Unmarshal(t.union, &body) + return body, err +} - // Data Arbitrary JSON payload. For browser events listed in `KnownBrowserTelemetryEvent`, the payload conforms to the corresponding `Browser*EventData` schema. - Data interface{} `json:"data,omitempty"` +// FromBrowserCdpPageCaptureSnapshotCommandData overwrites any union data inside the BrowserCdpCommandEventData as the provided BrowserCdpPageCaptureSnapshotCommandData +func (t *BrowserCdpCommandEventData) FromBrowserCdpPageCaptureSnapshotCommandData(v BrowserCdpPageCaptureSnapshotCommandData) error { + v.Method = "Page.captureSnapshot" + b, err := json.Marshal(v) + t.union = b + return err +} - // Source Provenance metadata identifying which producer emitted the event. - Source *BrowserEventSource `json:"source,omitempty"` +// MergeBrowserCdpPageCaptureSnapshotCommandData performs a merge with any union data inside the BrowserCdpCommandEventData, using the provided BrowserCdpPageCaptureSnapshotCommandData +func (t *BrowserCdpCommandEventData) MergeBrowserCdpPageCaptureSnapshotCommandData(v BrowserCdpPageCaptureSnapshotCommandData) error { + v.Method = "Page.captureSnapshot" + b, err := json.Marshal(v) + if err != nil { + return err + } - // Truncated Set by the server when the data field was truncated to fit the size limit. - Truncated *bool `json:"truncated,omitempty"` + merged, err := runtime.JSONMerge(t.union, b) + t.union = merged + return err +} - // Ts Unix timestamp in microseconds. Defaults to the current time when omitted. - Ts *int64 `json:"ts,omitempty"` +// AsBrowserCdpPageHandleJavaScriptDialogCommandData returns the union data inside the BrowserCdpCommandEventData as a BrowserCdpPageHandleJavaScriptDialogCommandData +func (t BrowserCdpCommandEventData) AsBrowserCdpPageHandleJavaScriptDialogCommandData() (BrowserCdpPageHandleJavaScriptDialogCommandData, error) { + var body BrowserCdpPageHandleJavaScriptDialogCommandData + err := json.Unmarshal(t.union, &body) + return body, err +} - // Type Event type identifier. - Type string `json:"type"` +// FromBrowserCdpPageHandleJavaScriptDialogCommandData overwrites any union data inside the BrowserCdpCommandEventData as the provided BrowserCdpPageHandleJavaScriptDialogCommandData +func (t *BrowserCdpCommandEventData) FromBrowserCdpPageHandleJavaScriptDialogCommandData(v BrowserCdpPageHandleJavaScriptDialogCommandData) error { + v.Method = "Page.handleJavaScriptDialog" + b, err := json.Marshal(v) + t.union = b + return err } -// TelemetryEventCategory Event category. -type TelemetryEventCategory string +// MergeBrowserCdpPageHandleJavaScriptDialogCommandData performs a merge with any union data inside the BrowserCdpCommandEventData, using the provided BrowserCdpPageHandleJavaScriptDialogCommandData +func (t *BrowserCdpCommandEventData) MergeBrowserCdpPageHandleJavaScriptDialogCommandData(v BrowserCdpPageHandleJavaScriptDialogCommandData) error { + v.Method = "Page.handleJavaScriptDialog" + b, err := json.Marshal(v) + if err != nil { + return err + } -// TelemetryState Current telemetry configuration. -type TelemetryState struct { - // AppliedAt Wall-clock time at which the current configuration was applied. Omitted when telemetry is not configured. - AppliedAt *time.Time `json:"applied_at,omitempty"` + merged, err := runtime.JSONMerge(t.union, b) + t.union = merged + return err +} - // Config Telemetry configuration for a browser. Selection is opt-in. Omit the browser key (or send an empty object) to capture the default set: lightweight operational signals (control, connection, system, captcha). Within `browser`, only the categories you set enabled: true are captured; anything omitted is off. The CDP categories (console, network, page, interaction), `screenshot` and `platform` are off by default and must be opted into. A `browser` config with nothing enabled clears the telemetry configuration. The `monitor` category (CDP collector health) is not configurable here; it flows automatically whenever a CDP category is captured. - Config BrowserTelemetryConfig `json:"config"` +// AsBrowserCdpPageNavigateCommandData returns the union data inside the BrowserCdpCommandEventData as a BrowserCdpPageNavigateCommandData +func (t BrowserCdpCommandEventData) AsBrowserCdpPageNavigateCommandData() (BrowserCdpPageNavigateCommandData, error) { + var body BrowserCdpPageNavigateCommandData + err := json.Unmarshal(t.union, &body) + return body, err +} - // Seq Process-monotonic sequence number of the last published event. Does not reset across configuration changes. - Seq int64 `json:"seq"` +// FromBrowserCdpPageNavigateCommandData overwrites any union data inside the BrowserCdpCommandEventData as the provided BrowserCdpPageNavigateCommandData +func (t *BrowserCdpCommandEventData) FromBrowserCdpPageNavigateCommandData(v BrowserCdpPageNavigateCommandData) error { + v.Method = "Page.navigate" + b, err := json.Marshal(v) + t.union = b + return err } -// TypeTextRequest defines model for TypeTextRequest. -type TypeTextRequest struct { - // Delay Delay in milliseconds between keystrokes. Ignored when smooth is true. - Delay *int `json:"delay,omitempty"` +// MergeBrowserCdpPageNavigateCommandData performs a merge with any union data inside the BrowserCdpCommandEventData, using the provided BrowserCdpPageNavigateCommandData +func (t *BrowserCdpCommandEventData) MergeBrowserCdpPageNavigateCommandData(v BrowserCdpPageNavigateCommandData) error { + v.Method = "Page.navigate" + b, err := json.Marshal(v) + if err != nil { + return err + } - // Smooth Use human-like variable keystroke timing instead of a fixed delay. - // Defaults to true (same as moveMouse/dragMouse). Set to false for - // xdotool typing with an optional fixed delay between keys (delay=0 is instant). - // When true, text is typed in word-sized chunks with variable intra-word delays - // and natural inter-word pauses. The delay field is ignored when smooth is true. - Smooth *bool `json:"smooth,omitempty"` + merged, err := runtime.JSONMerge(t.union, b) + t.union = merged + return err +} + +// AsBrowserCdpPageNavigateToHistoryEntryCommandData returns the union data inside the BrowserCdpCommandEventData as a BrowserCdpPageNavigateToHistoryEntryCommandData +func (t BrowserCdpCommandEventData) AsBrowserCdpPageNavigateToHistoryEntryCommandData() (BrowserCdpPageNavigateToHistoryEntryCommandData, error) { + var body BrowserCdpPageNavigateToHistoryEntryCommandData + err := json.Unmarshal(t.union, &body) + return body, err +} - // Text Text to type on the host computer - Text string `json:"text"` +// FromBrowserCdpPageNavigateToHistoryEntryCommandData overwrites any union data inside the BrowserCdpCommandEventData as the provided BrowserCdpPageNavigateToHistoryEntryCommandData +func (t *BrowserCdpCommandEventData) FromBrowserCdpPageNavigateToHistoryEntryCommandData(v BrowserCdpPageNavigateToHistoryEntryCommandData) error { + v.Method = "Page.navigateToHistoryEntry" + b, err := json.Marshal(v) + t.union = b + return err +} - // TypoChance Per-character typo injection rate; mistakes are corrected with backspace. - // Default 0. Only applies when smooth is true (silently ignored when - // smooth is false). - TypoChance *float32 `json:"typo_chance,omitempty"` +// MergeBrowserCdpPageNavigateToHistoryEntryCommandData performs a merge with any union data inside the BrowserCdpCommandEventData, using the provided BrowserCdpPageNavigateToHistoryEntryCommandData +func (t *BrowserCdpCommandEventData) MergeBrowserCdpPageNavigateToHistoryEntryCommandData(v BrowserCdpPageNavigateToHistoryEntryCommandData) error { + v.Method = "Page.navigateToHistoryEntry" + b, err := json.Marshal(v) + if err != nil { + return err + } + + merged, err := runtime.JSONMerge(t.union, b) + t.union = merged + return err } -// WriteClipboardRequest defines model for WriteClipboardRequest. -type WriteClipboardRequest struct { - // Text Text to write to the system clipboard - Text string `json:"text"` +// AsBrowserCdpPageReloadCommandData returns the union data inside the BrowserCdpCommandEventData as a BrowserCdpPageReloadCommandData +func (t BrowserCdpCommandEventData) AsBrowserCdpPageReloadCommandData() (BrowserCdpPageReloadCommandData, error) { + var body BrowserCdpPageReloadCommandData + err := json.Unmarshal(t.union, &body) + return body, err } -// BadRequestError defines model for BadRequestError. -type BadRequestError = Error +// FromBrowserCdpPageReloadCommandData overwrites any union data inside the BrowserCdpCommandEventData as the provided BrowserCdpPageReloadCommandData +func (t *BrowserCdpCommandEventData) FromBrowserCdpPageReloadCommandData(v BrowserCdpPageReloadCommandData) error { + v.Method = "Page.reload" + b, err := json.Marshal(v) + t.union = b + return err +} -// ConflictError defines model for ConflictError. -type ConflictError = Error +// MergeBrowserCdpPageReloadCommandData performs a merge with any union data inside the BrowserCdpCommandEventData, using the provided BrowserCdpPageReloadCommandData +func (t *BrowserCdpCommandEventData) MergeBrowserCdpPageReloadCommandData(v BrowserCdpPageReloadCommandData) error { + v.Method = "Page.reload" + b, err := json.Marshal(v) + if err != nil { + return err + } -// InternalError defines model for InternalError. -type InternalError = Error + merged, err := runtime.JSONMerge(t.union, b) + t.union = merged + return err +} -// NotFoundError defines model for NotFoundError. -type NotFoundError = Error +// AsBrowserCdpPagePrintToPdfCommandData returns the union data inside the BrowserCdpCommandEventData as a BrowserCdpPagePrintToPdfCommandData +func (t BrowserCdpCommandEventData) AsBrowserCdpPagePrintToPdfCommandData() (BrowserCdpPagePrintToPdfCommandData, error) { + var body BrowserCdpPagePrintToPdfCommandData + err := json.Unmarshal(t.union, &body) + return body, err +} -// PatchChromiumFlagsJSONBody defines parameters for PatchChromiumFlags. -type PatchChromiumFlagsJSONBody struct { - // Flags Chromium flags to merge (e.g., ["--kiosk", "--disable-gpu"]) - Flags []string `json:"flags"` +// FromBrowserCdpPagePrintToPdfCommandData overwrites any union data inside the BrowserCdpCommandEventData as the provided BrowserCdpPagePrintToPdfCommandData +func (t *BrowserCdpCommandEventData) FromBrowserCdpPagePrintToPdfCommandData(v BrowserCdpPagePrintToPdfCommandData) error { + v.Method = "Page.printToPDF" + b, err := json.Marshal(v) + t.union = b + return err } -// PatchChromiumPoliciesJSONBody defines parameters for PatchChromiumPolicies. -type PatchChromiumPoliciesJSONBody map[string]interface{} +// MergeBrowserCdpPagePrintToPdfCommandData performs a merge with any union data inside the BrowserCdpCommandEventData, using the provided BrowserCdpPagePrintToPdfCommandData +func (t *BrowserCdpCommandEventData) MergeBrowserCdpPagePrintToPdfCommandData(v BrowserCdpPagePrintToPdfCommandData) error { + v.Method = "Page.printToPDF" + b, err := json.Marshal(v) + if err != nil { + return err + } -// UploadExtensionsAndRestartMultipartBody defines parameters for UploadExtensionsAndRestart. -type UploadExtensionsAndRestartMultipartBody struct { - // Extensions List of extensions to upload and activate - Extensions []struct { - // Name Folder name to place the extension under /home/kernel/extensions/ - Name string `json:"name"` + merged, err := runtime.JSONMerge(t.union, b) + t.union = merged + return err +} - // ZipFile Zip archive containing an unpacked Chromium extension (must include manifest.json) - ZipFile openapi_types.File `json:"zip_file"` - } `json:"extensions"` +// AsBrowserCdpPageStartScreencastCommandData returns the union data inside the BrowserCdpCommandEventData as a BrowserCdpPageStartScreencastCommandData +func (t BrowserCdpCommandEventData) AsBrowserCdpPageStartScreencastCommandData() (BrowserCdpPageStartScreencastCommandData, error) { + var body BrowserCdpPageStartScreencastCommandData + err := json.Unmarshal(t.union, &body) + return body, err } -// ChromiumConfigureMultipartBody defines parameters for ChromiumConfigure. -type ChromiumConfigureMultipartBody struct { - // ChromePolicies UTF-8 JSON policy override map — same semantics as PATCH /chromium/policies. - ChromePolicies *string `json:"chrome_policies,omitempty"` +// FromBrowserCdpPageStartScreencastCommandData overwrites any union data inside the BrowserCdpCommandEventData as the provided BrowserCdpPageStartScreencastCommandData +func (t *BrowserCdpCommandEventData) FromBrowserCdpPageStartScreencastCommandData(v BrowserCdpPageStartScreencastCommandData) error { + v.Method = "Page.startScreencast" + b, err := json.Marshal(v) + t.union = b + return err +} - // ChromiumFlags UTF-8 JSON object `{"flags":["--kiosk"]}` — same semantics as PATCH /chromium/flags. - ChromiumFlags *string `json:"chromium_flags,omitempty"` +// MergeBrowserCdpPageStartScreencastCommandData performs a merge with any union data inside the BrowserCdpCommandEventData, using the provided BrowserCdpPageStartScreencastCommandData +func (t *BrowserCdpCommandEventData) MergeBrowserCdpPageStartScreencastCommandData(v BrowserCdpPageStartScreencastCommandData) error { + v.Method = "Page.startScreencast" + b, err := json.Marshal(v) + if err != nil { + return err + } - // Display UTF-8 JSON object matching `#/components/schemas/PatchDisplayRequest` (width/height/etc.). When combined with restart-triggering fields, the resize is applied while Chromium is stopped and Chromium is started once at the end. - Display *string `json:"display,omitempty"` + merged, err := runtime.JSONMerge(t.union, b) + t.union = merged + return err +} - // Extensions Extension zips paired with consecutive extensions.name fields (same as upload-extensions-and-restart). - Extensions *[]struct { - Name string `json:"name"` - ZipFile openapi_types.File `json:"zip_file"` - } `json:"extensions,omitempty"` +// AsBrowserCdpPageStopScreencastCommandData returns the union data inside the BrowserCdpCommandEventData as a BrowserCdpPageStopScreencastCommandData +func (t BrowserCdpCommandEventData) AsBrowserCdpPageStopScreencastCommandData() (BrowserCdpPageStopScreencastCommandData, error) { + var body BrowserCdpPageStopScreencastCommandData + err := json.Unmarshal(t.union, &body) + return body, err +} - // ProfileArchive tar.zst archive containing the desired `/home/kernel/user-data` profile contents. Prefer archives whose root entries are the profile files/directories themselves (for example `Default/Preferences`). Use `strip_components` only when uploading an archive that includes leading wrapper directories. - ProfileArchive *openapi_types.File `json:"profile_archive,omitempty"` +// FromBrowserCdpPageStopScreencastCommandData overwrites any union data inside the BrowserCdpCommandEventData as the provided BrowserCdpPageStopScreencastCommandData +func (t *BrowserCdpCommandEventData) FromBrowserCdpPageStopScreencastCommandData(v BrowserCdpPageStopScreencastCommandData) error { + v.Method = "Page.stopScreencast" + b, err := json.Marshal(v) + t.union = b + return err +} - // StartUrl URL text to navigate after configure. Bare hosts are normalized to https://, length is capped at 2048 bytes, and Chrome decides which schemes are navigable. - StartUrl *string `json:"start_url,omitempty"` +// MergeBrowserCdpPageStopScreencastCommandData performs a merge with any union data inside the BrowserCdpCommandEventData, using the provided BrowserCdpPageStopScreencastCommandData +func (t *BrowserCdpCommandEventData) MergeBrowserCdpPageStopScreencastCommandData(v BrowserCdpPageStopScreencastCommandData) error { + v.Method = "Page.stopScreencast" + b, err := json.Marshal(v) + if err != nil { + return err + } - // StripComponents Optional number of leading path components to strip from profile_archive entries (non-negative integer as text). - StripComponents *string `json:"strip_components,omitempty"` + merged, err := runtime.JSONMerge(t.union, b) + t.union = merged + return err } -// DownloadDirZipParams defines parameters for DownloadDirZip. -type DownloadDirZipParams struct { - // Path Absolute directory path to archive and download. - Path string `form:"path" json:"path"` +// AsBrowserCdpPageStopLoadingCommandData returns the union data inside the BrowserCdpCommandEventData as a BrowserCdpPageStopLoadingCommandData +func (t BrowserCdpCommandEventData) AsBrowserCdpPageStopLoadingCommandData() (BrowserCdpPageStopLoadingCommandData, error) { + var body BrowserCdpPageStopLoadingCommandData + err := json.Unmarshal(t.union, &body) + return body, err } -// DownloadDirZstdParams defines parameters for DownloadDirZstd. -type DownloadDirZstdParams struct { - // Path Absolute directory path to archive and download. - Path string `form:"path" json:"path"` - - // CompressionLevel Compression level. Higher levels produce smaller archives but take longer. - // - fastest: ~zstd level 1, maximum speed (~300-500 MB/s) - // - default: ~zstd level 3, balanced speed/ratio (~150 MB/s) - // - better: ~zstd level 7, better ratio (~50-80 MB/s) - // - best: ~zstd level 11, best ratio (~20-40 MB/s) - CompressionLevel *DownloadDirZstdParamsCompressionLevel `form:"compression_level,omitempty" json:"compression_level,omitempty"` +// FromBrowserCdpPageStopLoadingCommandData overwrites any union data inside the BrowserCdpCommandEventData as the provided BrowserCdpPageStopLoadingCommandData +func (t *BrowserCdpCommandEventData) FromBrowserCdpPageStopLoadingCommandData(v BrowserCdpPageStopLoadingCommandData) error { + v.Method = "Page.stopLoading" + b, err := json.Marshal(v) + t.union = b + return err } -// DownloadDirZstdParamsCompressionLevel defines parameters for DownloadDirZstd. -type DownloadDirZstdParamsCompressionLevel string +// MergeBrowserCdpPageStopLoadingCommandData performs a merge with any union data inside the BrowserCdpCommandEventData, using the provided BrowserCdpPageStopLoadingCommandData +func (t *BrowserCdpCommandEventData) MergeBrowserCdpPageStopLoadingCommandData(v BrowserCdpPageStopLoadingCommandData) error { + v.Method = "Page.stopLoading" + b, err := json.Marshal(v) + if err != nil { + return err + } -// FileInfoParams defines parameters for FileInfo. -type FileInfoParams struct { - // Path Absolute path of the file or directory. - Path string `form:"path" json:"path"` + merged, err := runtime.JSONMerge(t.union, b) + t.union = merged + return err } -// ListFilesParams defines parameters for ListFiles. -type ListFilesParams struct { - // Path Absolute directory path. - Path string `form:"path" json:"path"` +// AsBrowserCdpPageCloseCommandData returns the union data inside the BrowserCdpCommandEventData as a BrowserCdpPageCloseCommandData +func (t BrowserCdpCommandEventData) AsBrowserCdpPageCloseCommandData() (BrowserCdpPageCloseCommandData, error) { + var body BrowserCdpPageCloseCommandData + err := json.Unmarshal(t.union, &body) + return body, err } -// ReadFileParams defines parameters for ReadFile. -type ReadFileParams struct { - // Path Absolute file path to read. - Path string `form:"path" json:"path"` +// FromBrowserCdpPageCloseCommandData overwrites any union data inside the BrowserCdpCommandEventData as the provided BrowserCdpPageCloseCommandData +func (t *BrowserCdpCommandEventData) FromBrowserCdpPageCloseCommandData(v BrowserCdpPageCloseCommandData) error { + v.Method = "Page.close" + b, err := json.Marshal(v) + t.union = b + return err } -// UploadFilesMultipartBody defines parameters for UploadFiles. -type UploadFilesMultipartBody struct { - Files []struct { - // DestPath Absolute destination path to write the file. - DestPath string `json:"dest_path"` - File openapi_types.File `json:"file"` - } `json:"files"` +// MergeBrowserCdpPageCloseCommandData performs a merge with any union data inside the BrowserCdpCommandEventData, using the provided BrowserCdpPageCloseCommandData +func (t *BrowserCdpCommandEventData) MergeBrowserCdpPageCloseCommandData(v BrowserCdpPageCloseCommandData) error { + v.Method = "Page.close" + b, err := json.Marshal(v) + if err != nil { + return err + } + + merged, err := runtime.JSONMerge(t.union, b) + t.union = merged + return err } -// UploadZipMultipartBody defines parameters for UploadZip. -type UploadZipMultipartBody struct { - // DestPath Absolute destination directory to extract the archive to. - DestPath string `json:"dest_path"` - ZipFile openapi_types.File `json:"zip_file"` +// AsBrowserCdpPageSetWebLifecycleStateCommandData returns the union data inside the BrowserCdpCommandEventData as a BrowserCdpPageSetWebLifecycleStateCommandData +func (t BrowserCdpCommandEventData) AsBrowserCdpPageSetWebLifecycleStateCommandData() (BrowserCdpPageSetWebLifecycleStateCommandData, error) { + var body BrowserCdpPageSetWebLifecycleStateCommandData + err := json.Unmarshal(t.union, &body) + return body, err } -// UploadZstdMultipartBody defines parameters for UploadZstd. -type UploadZstdMultipartBody struct { - // Archive The tar.zst archive file. - Archive openapi_types.File `json:"archive"` +// FromBrowserCdpPageSetWebLifecycleStateCommandData overwrites any union data inside the BrowserCdpCommandEventData as the provided BrowserCdpPageSetWebLifecycleStateCommandData +func (t *BrowserCdpCommandEventData) FromBrowserCdpPageSetWebLifecycleStateCommandData(v BrowserCdpPageSetWebLifecycleStateCommandData) error { + v.Method = "Page.setWebLifecycleState" + b, err := json.Marshal(v) + t.union = b + return err +} - // DestPath Absolute destination directory to extract the archive to. - DestPath string `json:"dest_path"` +// MergeBrowserCdpPageSetWebLifecycleStateCommandData performs a merge with any union data inside the BrowserCdpCommandEventData, using the provided BrowserCdpPageSetWebLifecycleStateCommandData +func (t *BrowserCdpCommandEventData) MergeBrowserCdpPageSetWebLifecycleStateCommandData(v BrowserCdpPageSetWebLifecycleStateCommandData) error { + v.Method = "Page.setWebLifecycleState" + b, err := json.Marshal(v) + if err != nil { + return err + } - // StripComponents Number of leading path components to strip during extraction (like tar --strip-components). - StripComponents *int `json:"strip_components,omitempty"` + merged, err := runtime.JSONMerge(t.union, b) + t.union = merged + return err } -// WriteFileParams defines parameters for WriteFile. -type WriteFileParams struct { - // Path Destination absolute file path. - Path string `form:"path" json:"path"` +// AsBrowserCdpTargetActivateTargetCommandData returns the union data inside the BrowserCdpCommandEventData as a BrowserCdpTargetActivateTargetCommandData +func (t BrowserCdpCommandEventData) AsBrowserCdpTargetActivateTargetCommandData() (BrowserCdpTargetActivateTargetCommandData, error) { + var body BrowserCdpTargetActivateTargetCommandData + err := json.Unmarshal(t.union, &body) + return body, err +} - // Mode Optional file mode (octal string, e.g. 644). Defaults to 644. - Mode *string `form:"mode,omitempty" json:"mode,omitempty"` +// FromBrowserCdpTargetActivateTargetCommandData overwrites any union data inside the BrowserCdpCommandEventData as the provided BrowserCdpTargetActivateTargetCommandData +func (t *BrowserCdpCommandEventData) FromBrowserCdpTargetActivateTargetCommandData(v BrowserCdpTargetActivateTargetCommandData) error { + v.Method = "Target.activateTarget" + b, err := json.Marshal(v) + t.union = b + return err } -// LogsStreamParams defines parameters for LogsStream. -type LogsStreamParams struct { - Source LogsStreamParamsSource `form:"source" json:"source"` - Follow *bool `form:"follow,omitempty" json:"follow,omitempty"` +// MergeBrowserCdpTargetActivateTargetCommandData performs a merge with any union data inside the BrowserCdpCommandEventData, using the provided BrowserCdpTargetActivateTargetCommandData +func (t *BrowserCdpCommandEventData) MergeBrowserCdpTargetActivateTargetCommandData(v BrowserCdpTargetActivateTargetCommandData) error { + v.Method = "Target.activateTarget" + b, err := json.Marshal(v) + if err != nil { + return err + } - // Path only required if source is path - Path *string `form:"path,omitempty" json:"path,omitempty"` + merged, err := runtime.JSONMerge(t.union, b) + t.union = merged + return err +} - // SupervisorProcess only required if source is supervisor - SupervisorProcess *string `form:"supervisor_process,omitempty" json:"supervisor_process,omitempty"` +// AsBrowserCdpTargetCloseTargetCommandData returns the union data inside the BrowserCdpCommandEventData as a BrowserCdpTargetCloseTargetCommandData +func (t BrowserCdpCommandEventData) AsBrowserCdpTargetCloseTargetCommandData() (BrowserCdpTargetCloseTargetCommandData, error) { + var body BrowserCdpTargetCloseTargetCommandData + err := json.Unmarshal(t.union, &body) + return body, err } -// LogsStreamParamsSource defines parameters for LogsStream. -type LogsStreamParamsSource string +// FromBrowserCdpTargetCloseTargetCommandData overwrites any union data inside the BrowserCdpCommandEventData as the provided BrowserCdpTargetCloseTargetCommandData +func (t *BrowserCdpCommandEventData) FromBrowserCdpTargetCloseTargetCommandData(v BrowserCdpTargetCloseTargetCommandData) error { + v.Method = "Target.closeTarget" + b, err := json.Marshal(v) + t.union = b + return err +} -// DownloadRecordingParams defines parameters for DownloadRecording. -type DownloadRecordingParams struct { - // Id Identifier of the recording session to download, as passed to /recording/start. When omitted, the default recording session is downloaded. - Id *string `form:"id,omitempty" json:"id,omitempty"` +// MergeBrowserCdpTargetCloseTargetCommandData performs a merge with any union data inside the BrowserCdpCommandEventData, using the provided BrowserCdpTargetCloseTargetCommandData +func (t *BrowserCdpCommandEventData) MergeBrowserCdpTargetCloseTargetCommandData(v BrowserCdpTargetCloseTargetCommandData) error { + v.Method = "Target.closeTarget" + b, err := json.Marshal(v) + if err != nil { + return err + } + + merged, err := runtime.JSONMerge(t.union, b) + t.union = merged + return err } -// StreamTelemetryEventsParams defines parameters for StreamTelemetryEvents. -type StreamTelemetryEventsParams struct { - // Replay Pass `all` to start from the oldest retained event. Ring buffer caps at 1024; older events are evicted and surface as a first `id` greater than 1. - Replay *StreamTelemetryEventsParamsReplay `form:"replay,omitempty" json:"replay,omitempty"` +// AsBrowserCdpTargetCreateTargetCommandData returns the union data inside the BrowserCdpCommandEventData as a BrowserCdpTargetCreateTargetCommandData +func (t BrowserCdpCommandEventData) AsBrowserCdpTargetCreateTargetCommandData() (BrowserCdpTargetCreateTargetCommandData, error) { + var body BrowserCdpTargetCreateTargetCommandData + err := json.Unmarshal(t.union, &body) + return body, err +} - // LastEventID Resume after this sequence number. Omit or send 0 to start from the current position. Sequence numbers are process-monotonic, so any previous value resumes correctly from that point. Takes precedence over `replay` when both are present, so SSE auto-reconnect resumes cleanly instead of re-replaying history. - LastEventID *string `json:"Last-Event-ID,omitempty"` +// FromBrowserCdpTargetCreateTargetCommandData overwrites any union data inside the BrowserCdpCommandEventData as the provided BrowserCdpTargetCreateTargetCommandData +func (t *BrowserCdpCommandEventData) FromBrowserCdpTargetCreateTargetCommandData(v BrowserCdpTargetCreateTargetCommandData) error { + v.Method = "Target.createTarget" + b, err := json.Marshal(v) + t.union = b + return err } -// StreamTelemetryEventsParamsReplay defines parameters for StreamTelemetryEvents. -type StreamTelemetryEventsParamsReplay string +// MergeBrowserCdpTargetCreateTargetCommandData performs a merge with any union data inside the BrowserCdpCommandEventData, using the provided BrowserCdpTargetCreateTargetCommandData +func (t *BrowserCdpCommandEventData) MergeBrowserCdpTargetCreateTargetCommandData(v BrowserCdpTargetCreateTargetCommandData) error { + v.Method = "Target.createTarget" + b, err := json.Marshal(v) + if err != nil { + return err + } -// PatchChromiumFlagsJSONRequestBody defines body for PatchChromiumFlags for application/json ContentType. -type PatchChromiumFlagsJSONRequestBody PatchChromiumFlagsJSONBody + merged, err := runtime.JSONMerge(t.union, b) + t.union = merged + return err +} -// PatchChromiumPoliciesJSONRequestBody defines body for PatchChromiumPolicies for application/json ContentType. -type PatchChromiumPoliciesJSONRequestBody PatchChromiumPoliciesJSONBody +// AsBrowserCdpTargetCreateBrowserContextCommandData returns the union data inside the BrowserCdpCommandEventData as a BrowserCdpTargetCreateBrowserContextCommandData +func (t BrowserCdpCommandEventData) AsBrowserCdpTargetCreateBrowserContextCommandData() (BrowserCdpTargetCreateBrowserContextCommandData, error) { + var body BrowserCdpTargetCreateBrowserContextCommandData + err := json.Unmarshal(t.union, &body) + return body, err +} -// UploadExtensionsAndRestartMultipartRequestBody defines body for UploadExtensionsAndRestart for multipart/form-data ContentType. -type UploadExtensionsAndRestartMultipartRequestBody UploadExtensionsAndRestartMultipartBody +// FromBrowserCdpTargetCreateBrowserContextCommandData overwrites any union data inside the BrowserCdpCommandEventData as the provided BrowserCdpTargetCreateBrowserContextCommandData +func (t *BrowserCdpCommandEventData) FromBrowserCdpTargetCreateBrowserContextCommandData(v BrowserCdpTargetCreateBrowserContextCommandData) error { + v.Method = "Target.createBrowserContext" + b, err := json.Marshal(v) + t.union = b + return err +} -// BatchComputerActionJSONRequestBody defines body for BatchComputerAction for application/json ContentType. -type BatchComputerActionJSONRequestBody = BatchComputerActionRequest +// MergeBrowserCdpTargetCreateBrowserContextCommandData performs a merge with any union data inside the BrowserCdpCommandEventData, using the provided BrowserCdpTargetCreateBrowserContextCommandData +func (t *BrowserCdpCommandEventData) MergeBrowserCdpTargetCreateBrowserContextCommandData(v BrowserCdpTargetCreateBrowserContextCommandData) error { + v.Method = "Target.createBrowserContext" + b, err := json.Marshal(v) + if err != nil { + return err + } -// ClickMouseJSONRequestBody defines body for ClickMouse for application/json ContentType. -type ClickMouseJSONRequestBody = ClickMouseRequest + merged, err := runtime.JSONMerge(t.union, b) + t.union = merged + return err +} -// WriteClipboardJSONRequestBody defines body for WriteClipboard for application/json ContentType. -type WriteClipboardJSONRequestBody = WriteClipboardRequest +// AsBrowserCdpTargetDisposeBrowserContextCommandData returns the union data inside the BrowserCdpCommandEventData as a BrowserCdpTargetDisposeBrowserContextCommandData +func (t BrowserCdpCommandEventData) AsBrowserCdpTargetDisposeBrowserContextCommandData() (BrowserCdpTargetDisposeBrowserContextCommandData, error) { + var body BrowserCdpTargetDisposeBrowserContextCommandData + err := json.Unmarshal(t.union, &body) + return body, err +} -// SetCursorJSONRequestBody defines body for SetCursor for application/json ContentType. -type SetCursorJSONRequestBody = SetCursorRequest +// FromBrowserCdpTargetDisposeBrowserContextCommandData overwrites any union data inside the BrowserCdpCommandEventData as the provided BrowserCdpTargetDisposeBrowserContextCommandData +func (t *BrowserCdpCommandEventData) FromBrowserCdpTargetDisposeBrowserContextCommandData(v BrowserCdpTargetDisposeBrowserContextCommandData) error { + v.Method = "Target.disposeBrowserContext" + b, err := json.Marshal(v) + t.union = b + return err +} -// DragMouseJSONRequestBody defines body for DragMouse for application/json ContentType. -type DragMouseJSONRequestBody = DragMouseRequest +// MergeBrowserCdpTargetDisposeBrowserContextCommandData performs a merge with any union data inside the BrowserCdpCommandEventData, using the provided BrowserCdpTargetDisposeBrowserContextCommandData +func (t *BrowserCdpCommandEventData) MergeBrowserCdpTargetDisposeBrowserContextCommandData(v BrowserCdpTargetDisposeBrowserContextCommandData) error { + v.Method = "Target.disposeBrowserContext" + b, err := json.Marshal(v) + if err != nil { + return err + } -// MoveMouseJSONRequestBody defines body for MoveMouse for application/json ContentType. -type MoveMouseJSONRequestBody = MoveMouseRequest + merged, err := runtime.JSONMerge(t.union, b) + t.union = merged + return err +} -// PressKeyJSONRequestBody defines body for PressKey for application/json ContentType. -type PressKeyJSONRequestBody = PressKeyRequest +// AsBrowserCdpTargetOpenDevToolsCommandData returns the union data inside the BrowserCdpCommandEventData as a BrowserCdpTargetOpenDevToolsCommandData +func (t BrowserCdpCommandEventData) AsBrowserCdpTargetOpenDevToolsCommandData() (BrowserCdpTargetOpenDevToolsCommandData, error) { + var body BrowserCdpTargetOpenDevToolsCommandData + err := json.Unmarshal(t.union, &body) + return body, err +} -// TakeScreenshotJSONRequestBody defines body for TakeScreenshot for application/json ContentType. -type TakeScreenshotJSONRequestBody = ScreenshotRequest +// FromBrowserCdpTargetOpenDevToolsCommandData overwrites any union data inside the BrowserCdpCommandEventData as the provided BrowserCdpTargetOpenDevToolsCommandData +func (t *BrowserCdpCommandEventData) FromBrowserCdpTargetOpenDevToolsCommandData(v BrowserCdpTargetOpenDevToolsCommandData) error { + v.Method = "Target.openDevTools" + b, err := json.Marshal(v) + t.union = b + return err +} -// ScrollJSONRequestBody defines body for Scroll for application/json ContentType. -type ScrollJSONRequestBody = ScrollRequest +// MergeBrowserCdpTargetOpenDevToolsCommandData performs a merge with any union data inside the BrowserCdpCommandEventData, using the provided BrowserCdpTargetOpenDevToolsCommandData +func (t *BrowserCdpCommandEventData) MergeBrowserCdpTargetOpenDevToolsCommandData(v BrowserCdpTargetOpenDevToolsCommandData) error { + v.Method = "Target.openDevTools" + b, err := json.Marshal(v) + if err != nil { + return err + } -// TypeTextJSONRequestBody defines body for TypeText for application/json ContentType. -type TypeTextJSONRequestBody = TypeTextRequest + merged, err := runtime.JSONMerge(t.union, b) + t.union = merged + return err +} -// ChromiumConfigureMultipartRequestBody defines body for ChromiumConfigure for multipart/form-data ContentType. -type ChromiumConfigureMultipartRequestBody ChromiumConfigureMultipartBody +// AsBrowserCdpBrowserCancelDownloadCommandData returns the union data inside the BrowserCdpCommandEventData as a BrowserCdpBrowserCancelDownloadCommandData +func (t BrowserCdpCommandEventData) AsBrowserCdpBrowserCancelDownloadCommandData() (BrowserCdpBrowserCancelDownloadCommandData, error) { + var body BrowserCdpBrowserCancelDownloadCommandData + err := json.Unmarshal(t.union, &body) + return body, err +} -// PatchDisplayJSONRequestBody defines body for PatchDisplay for application/json ContentType. -type PatchDisplayJSONRequestBody = PatchDisplayRequest +// FromBrowserCdpBrowserCancelDownloadCommandData overwrites any union data inside the BrowserCdpCommandEventData as the provided BrowserCdpBrowserCancelDownloadCommandData +func (t *BrowserCdpCommandEventData) FromBrowserCdpBrowserCancelDownloadCommandData(v BrowserCdpBrowserCancelDownloadCommandData) error { + v.Method = "Browser.cancelDownload" + b, err := json.Marshal(v) + t.union = b + return err +} -// CreateDirectoryJSONRequestBody defines body for CreateDirectory for application/json ContentType. -type CreateDirectoryJSONRequestBody = CreateDirectoryRequest +// MergeBrowserCdpBrowserCancelDownloadCommandData performs a merge with any union data inside the BrowserCdpCommandEventData, using the provided BrowserCdpBrowserCancelDownloadCommandData +func (t *BrowserCdpCommandEventData) MergeBrowserCdpBrowserCancelDownloadCommandData(v BrowserCdpBrowserCancelDownloadCommandData) error { + v.Method = "Browser.cancelDownload" + b, err := json.Marshal(v) + if err != nil { + return err + } -// DeleteDirectoryJSONRequestBody defines body for DeleteDirectory for application/json ContentType. -type DeleteDirectoryJSONRequestBody = DeletePathRequest + merged, err := runtime.JSONMerge(t.union, b) + t.union = merged + return err +} -// DeleteFileJSONRequestBody defines body for DeleteFile for application/json ContentType. -type DeleteFileJSONRequestBody = DeletePathRequest +// AsBrowserCdpBrowserCloseCommandData returns the union data inside the BrowserCdpCommandEventData as a BrowserCdpBrowserCloseCommandData +func (t BrowserCdpCommandEventData) AsBrowserCdpBrowserCloseCommandData() (BrowserCdpBrowserCloseCommandData, error) { + var body BrowserCdpBrowserCloseCommandData + err := json.Unmarshal(t.union, &body) + return body, err +} -// MovePathJSONRequestBody defines body for MovePath for application/json ContentType. -type MovePathJSONRequestBody = MovePathRequest +// FromBrowserCdpBrowserCloseCommandData overwrites any union data inside the BrowserCdpCommandEventData as the provided BrowserCdpBrowserCloseCommandData +func (t *BrowserCdpCommandEventData) FromBrowserCdpBrowserCloseCommandData(v BrowserCdpBrowserCloseCommandData) error { + v.Method = "Browser.close" + b, err := json.Marshal(v) + t.union = b + return err +} -// SetFilePermissionsJSONRequestBody defines body for SetFilePermissions for application/json ContentType. -type SetFilePermissionsJSONRequestBody = SetFilePermissionsRequest +// MergeBrowserCdpBrowserCloseCommandData performs a merge with any union data inside the BrowserCdpCommandEventData, using the provided BrowserCdpBrowserCloseCommandData +func (t *BrowserCdpCommandEventData) MergeBrowserCdpBrowserCloseCommandData(v BrowserCdpBrowserCloseCommandData) error { + v.Method = "Browser.close" + b, err := json.Marshal(v) + if err != nil { + return err + } -// UploadFilesMultipartRequestBody defines body for UploadFiles for multipart/form-data ContentType. -type UploadFilesMultipartRequestBody UploadFilesMultipartBody + merged, err := runtime.JSONMerge(t.union, b) + t.union = merged + return err +} -// UploadZipMultipartRequestBody defines body for UploadZip for multipart/form-data ContentType. -type UploadZipMultipartRequestBody UploadZipMultipartBody +// AsBrowserCdpBrowserSetWindowBoundsCommandData returns the union data inside the BrowserCdpCommandEventData as a BrowserCdpBrowserSetWindowBoundsCommandData +func (t BrowserCdpCommandEventData) AsBrowserCdpBrowserSetWindowBoundsCommandData() (BrowserCdpBrowserSetWindowBoundsCommandData, error) { + var body BrowserCdpBrowserSetWindowBoundsCommandData + err := json.Unmarshal(t.union, &body) + return body, err +} -// UploadZstdMultipartRequestBody defines body for UploadZstd for multipart/form-data ContentType. -type UploadZstdMultipartRequestBody UploadZstdMultipartBody +// FromBrowserCdpBrowserSetWindowBoundsCommandData overwrites any union data inside the BrowserCdpCommandEventData as the provided BrowserCdpBrowserSetWindowBoundsCommandData +func (t *BrowserCdpCommandEventData) FromBrowserCdpBrowserSetWindowBoundsCommandData(v BrowserCdpBrowserSetWindowBoundsCommandData) error { + v.Method = "Browser.setWindowBounds" + b, err := json.Marshal(v) + t.union = b + return err +} -// StartFsWatchJSONRequestBody defines body for StartFsWatch for application/json ContentType. -type StartFsWatchJSONRequestBody = StartFsWatchRequest +// MergeBrowserCdpBrowserSetWindowBoundsCommandData performs a merge with any union data inside the BrowserCdpCommandEventData, using the provided BrowserCdpBrowserSetWindowBoundsCommandData +func (t *BrowserCdpCommandEventData) MergeBrowserCdpBrowserSetWindowBoundsCommandData(v BrowserCdpBrowserSetWindowBoundsCommandData) error { + v.Method = "Browser.setWindowBounds" + b, err := json.Marshal(v) + if err != nil { + return err + } -// ExecutePlaywrightCodeJSONRequestBody defines body for ExecutePlaywrightCode for application/json ContentType. -type ExecutePlaywrightCodeJSONRequestBody = ExecutePlaywrightRequest + merged, err := runtime.JSONMerge(t.union, b) + t.union = merged + return err +} -// ProcessExecJSONRequestBody defines body for ProcessExec for application/json ContentType. -type ProcessExecJSONRequestBody = ProcessExecRequest +// AsBrowserCdpBrowserSetContentsSizeCommandData returns the union data inside the BrowserCdpCommandEventData as a BrowserCdpBrowserSetContentsSizeCommandData +func (t BrowserCdpCommandEventData) AsBrowserCdpBrowserSetContentsSizeCommandData() (BrowserCdpBrowserSetContentsSizeCommandData, error) { + var body BrowserCdpBrowserSetContentsSizeCommandData + err := json.Unmarshal(t.union, &body) + return body, err +} -// ProcessSpawnJSONRequestBody defines body for ProcessSpawn for application/json ContentType. -type ProcessSpawnJSONRequestBody = ProcessSpawnRequest +// FromBrowserCdpBrowserSetContentsSizeCommandData overwrites any union data inside the BrowserCdpCommandEventData as the provided BrowserCdpBrowserSetContentsSizeCommandData +func (t *BrowserCdpCommandEventData) FromBrowserCdpBrowserSetContentsSizeCommandData(v BrowserCdpBrowserSetContentsSizeCommandData) error { + v.Method = "Browser.setContentsSize" + b, err := json.Marshal(v) + t.union = b + return err +} -// ProcessKillJSONRequestBody defines body for ProcessKill for application/json ContentType. -type ProcessKillJSONRequestBody = ProcessKillRequest +// MergeBrowserCdpBrowserSetContentsSizeCommandData performs a merge with any union data inside the BrowserCdpCommandEventData, using the provided BrowserCdpBrowserSetContentsSizeCommandData +func (t *BrowserCdpCommandEventData) MergeBrowserCdpBrowserSetContentsSizeCommandData(v BrowserCdpBrowserSetContentsSizeCommandData) error { + v.Method = "Browser.setContentsSize" + b, err := json.Marshal(v) + if err != nil { + return err + } -// ProcessResizeJSONRequestBody defines body for ProcessResize for application/json ContentType. -type ProcessResizeJSONRequestBody = ProcessResizeRequest + merged, err := runtime.JSONMerge(t.union, b) + t.union = merged + return err +} -// ProcessStdinJSONRequestBody defines body for ProcessStdin for application/json ContentType. -type ProcessStdinJSONRequestBody = ProcessStdinRequest +// AsBrowserCdpAutofillTriggerCommandData returns the union data inside the BrowserCdpCommandEventData as a BrowserCdpAutofillTriggerCommandData +func (t BrowserCdpCommandEventData) AsBrowserCdpAutofillTriggerCommandData() (BrowserCdpAutofillTriggerCommandData, error) { + var body BrowserCdpAutofillTriggerCommandData + err := json.Unmarshal(t.union, &body) + return body, err +} -// DeleteRecordingJSONRequestBody defines body for DeleteRecording for application/json ContentType. -type DeleteRecordingJSONRequestBody = DeleteRecordingRequest +// FromBrowserCdpAutofillTriggerCommandData overwrites any union data inside the BrowserCdpCommandEventData as the provided BrowserCdpAutofillTriggerCommandData +func (t *BrowserCdpCommandEventData) FromBrowserCdpAutofillTriggerCommandData(v BrowserCdpAutofillTriggerCommandData) error { + v.Method = "Autofill.trigger" + b, err := json.Marshal(v) + t.union = b + return err +} -// MarkRecordingJSONRequestBody defines body for MarkRecording for application/json ContentType. -type MarkRecordingJSONRequestBody = MarkRecordingRequest +// MergeBrowserCdpAutofillTriggerCommandData performs a merge with any union data inside the BrowserCdpCommandEventData, using the provided BrowserCdpAutofillTriggerCommandData +func (t *BrowserCdpCommandEventData) MergeBrowserCdpAutofillTriggerCommandData(v BrowserCdpAutofillTriggerCommandData) error { + v.Method = "Autofill.trigger" + b, err := json.Marshal(v) + if err != nil { + return err + } -// StartRecordingJSONRequestBody defines body for StartRecording for application/json ContentType. -type StartRecordingJSONRequestBody = StartRecordingRequest + merged, err := runtime.JSONMerge(t.union, b) + t.union = merged + return err +} -// StopRecordingJSONRequestBody defines body for StopRecording for application/json ContentType. -type StopRecordingJSONRequestBody = StopRecordingRequest +func (t BrowserCdpCommandEventData) Discriminator() (string, error) { + var discriminator struct { + Discriminator string `json:"method"` + } + err := json.Unmarshal(t.union, &discriminator) + return discriminator.Discriminator, err +} -// PatchTelemetryJSONRequestBody defines body for PatchTelemetry for application/json ContentType. -type PatchTelemetryJSONRequestBody = BrowserTelemetryConfig +func (t BrowserCdpCommandEventData) ValueByDiscriminator() (interface{}, error) { + discriminator, err := t.Discriminator() + if err != nil { + return nil, err + } + switch discriminator { + case "Autofill.trigger": + return t.AsBrowserCdpAutofillTriggerCommandData() + case "Browser.cancelDownload": + return t.AsBrowserCdpBrowserCancelDownloadCommandData() + case "Browser.close": + return t.AsBrowserCdpBrowserCloseCommandData() + case "Browser.setContentsSize": + return t.AsBrowserCdpBrowserSetContentsSizeCommandData() + case "Browser.setWindowBounds": + return t.AsBrowserCdpBrowserSetWindowBoundsCommandData() + case "DOM.focus": + return t.AsBrowserCdpDomFocusCommandData() + case "DOM.scrollIntoViewIfNeeded": + return t.AsBrowserCdpDomScrollIntoViewIfNeededCommandData() + case "DOM.setFileInputFiles": + return t.AsBrowserCdpDomSetFileInputFilesCommandData() + case "Input.cancelDragging": + return t.AsBrowserCdpInputCancelDraggingCommandData() + case "Input.dispatchDragEvent": + return t.AsBrowserCdpInputDispatchDragEventCommandData() + case "Input.dispatchKeyEvent": + return t.AsBrowserCdpInputDispatchKeyEventCommandData() + case "Input.dispatchMouseEvent": + return t.AsBrowserCdpInputDispatchMouseEventCommandData() + case "Input.dispatchTouchEvent": + return t.AsBrowserCdpInputDispatchTouchEventCommandData() + case "Input.emulateTouchFromMouseEvent": + return t.AsBrowserCdpInputEmulateTouchFromMouseEventCommandData() + case "Input.imeSetComposition": + return t.AsBrowserCdpInputImeSetCompositionCommandData() + case "Input.insertText": + return t.AsBrowserCdpInputInsertTextCommandData() + case "Input.synthesizePinchGesture": + return t.AsBrowserCdpInputSynthesizePinchGestureCommandData() + case "Input.synthesizeScrollGesture": + return t.AsBrowserCdpInputSynthesizeScrollGestureCommandData() + case "Input.synthesizeTapGesture": + return t.AsBrowserCdpInputSynthesizeTapGestureCommandData() + case "Page.bringToFront": + return t.AsBrowserCdpPageBringToFrontCommandData() + case "Page.captureScreenshot": + return t.AsBrowserCdpPageCaptureScreenshotCommandData() + case "Page.captureSnapshot": + return t.AsBrowserCdpPageCaptureSnapshotCommandData() + case "Page.close": + return t.AsBrowserCdpPageCloseCommandData() + case "Page.handleJavaScriptDialog": + return t.AsBrowserCdpPageHandleJavaScriptDialogCommandData() + case "Page.navigate": + return t.AsBrowserCdpPageNavigateCommandData() + case "Page.navigateToHistoryEntry": + return t.AsBrowserCdpPageNavigateToHistoryEntryCommandData() + case "Page.printToPDF": + return t.AsBrowserCdpPagePrintToPdfCommandData() + case "Page.reload": + return t.AsBrowserCdpPageReloadCommandData() + case "Page.setWebLifecycleState": + return t.AsBrowserCdpPageSetWebLifecycleStateCommandData() + case "Page.startScreencast": + return t.AsBrowserCdpPageStartScreencastCommandData() + case "Page.stopLoading": + return t.AsBrowserCdpPageStopLoadingCommandData() + case "Page.stopScreencast": + return t.AsBrowserCdpPageStopScreencastCommandData() + case "Target.activateTarget": + return t.AsBrowserCdpTargetActivateTargetCommandData() + case "Target.closeTarget": + return t.AsBrowserCdpTargetCloseTargetCommandData() + case "Target.createBrowserContext": + return t.AsBrowserCdpTargetCreateBrowserContextCommandData() + case "Target.createTarget": + return t.AsBrowserCdpTargetCreateTargetCommandData() + case "Target.disposeBrowserContext": + return t.AsBrowserCdpTargetDisposeBrowserContextCommandData() + case "Target.openDevTools": + return t.AsBrowserCdpTargetOpenDevToolsCommandData() + default: + return nil, errors.New("unknown discriminator value: " + discriminator) + } +} -// PutTelemetryJSONRequestBody defines body for PutTelemetry for application/json ContentType. -type PutTelemetryJSONRequestBody = BrowserTelemetryConfig +func (t BrowserCdpCommandEventData) MarshalJSON() ([]byte, error) { + b, err := t.union.MarshalJSON() + return b, err +} -// PublishTelemetryEventJSONRequestBody defines body for PublishTelemetryEvent for application/json ContentType. -type PublishTelemetryEventJSONRequestBody = PublishEventRequest +func (t *BrowserCdpCommandEventData) UnmarshalJSON(b []byte) error { + err := t.union.UnmarshalJSON(b) + return err +} // AsBrowserConsoleLogEvent returns the union data inside the KnownBrowserTelemetryEvent as a BrowserConsoleLogEvent func (t KnownBrowserTelemetryEvent) AsBrowserConsoleLogEvent() (BrowserConsoleLogEvent, error) { @@ -4851,6 +7663,34 @@ func (t *KnownBrowserTelemetryEvent) MergeBrowserPlatformApiCallEvent(v BrowserP return err } +// AsBrowserCdpCommandEvent returns the union data inside the KnownBrowserTelemetryEvent as a BrowserCdpCommandEvent +func (t KnownBrowserTelemetryEvent) AsBrowserCdpCommandEvent() (BrowserCdpCommandEvent, error) { + var body BrowserCdpCommandEvent + err := json.Unmarshal(t.union, &body) + return body, err +} + +// FromBrowserCdpCommandEvent overwrites any union data inside the KnownBrowserTelemetryEvent as the provided BrowserCdpCommandEvent +func (t *KnownBrowserTelemetryEvent) FromBrowserCdpCommandEvent(v BrowserCdpCommandEvent) error { + v.Type = "cdp_command" + b, err := json.Marshal(v) + t.union = b + return err +} + +// MergeBrowserCdpCommandEvent performs a merge with any union data inside the KnownBrowserTelemetryEvent, using the provided BrowserCdpCommandEvent +func (t *KnownBrowserTelemetryEvent) MergeBrowserCdpCommandEvent(v BrowserCdpCommandEvent) error { + v.Type = "cdp_command" + b, err := json.Marshal(v) + if err != nil { + return err + } + + merged, err := runtime.JSONMerge(t.union, b) + t.union = merged + return err +} + // AsBrowserCdpConnectEvent returns the union data inside the KnownBrowserTelemetryEvent as a BrowserCdpConnectEvent func (t KnownBrowserTelemetryEvent) AsBrowserCdpConnectEvent() (BrowserCdpConnectEvent, error) { var body BrowserCdpConnectEvent @@ -5065,6 +7905,8 @@ func (t KnownBrowserTelemetryEvent) ValueByDiscriminator() (interface{}, error) return t.AsBrowserApiCallEvent() case "captcha_solve_result": return t.AsBrowserCaptchaSolveResultEvent() + case "cdp_command": + return t.AsBrowserCdpCommandEvent() case "cdp_connect": return t.AsBrowserCdpConnectEvent() case "cdp_disconnect": @@ -19369,392 +22211,503 @@ func (sh *strictHandler) StreamTelemetryEvents(w http.ResponseWriter, r *http.Re // Base64 encoded, gzipped, json marshaled Swagger object var swaggerSpec = []string{ - "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", + "j1EDLD/gP3/+ewAAAP//8YBscHOXAgA=", } // GetSwagger returns the content of the embedded swagger specification file diff --git a/server/lib/telemetry/telemetry.go b/server/lib/telemetry/telemetry.go index de41f880..c155ed71 100644 --- a/server/lib/telemetry/telemetry.go +++ b/server/lib/telemetry/telemetry.go @@ -1,7 +1,9 @@ package telemetry import ( + "sort" "sync" + "sync/atomic" "time" "github.com/kernel/kernel-images/server/lib/events" @@ -18,6 +20,10 @@ type TelemetryConfig struct { // ExportOTLP forwards captured events to the configured OTLP endpoint. // Off by default and independent of what is captured. ExportOTLP bool + // ExcludedCdpMethods leaves the named browser-control methods out of the + // cdp_command stream. Empty reports every supported method. Telemetry only: + // an excluded command still reaches the browser. + ExcludedCdpMethods []oapi.BrowserCdpCommandMethod } // TelemetrySession manages a telemetry session against a shared EventStream. @@ -36,6 +42,15 @@ type TelemetrySession struct { categories map[oapi.TelemetryEventCategory]struct{} exportOTLP bool appliedAt time.Time + excludedCdp map[string]struct{} + // active mirrors "a session is running with these categories" for callers + // on a hot path, who must decide whether to do any work at all before they + // reach Publish and its mutex. nil means no session. Written under mu; + // the pointed-to set is never mutated after it is stored. + active atomic.Pointer[map[oapi.TelemetryEventCategory]struct{}] + // excludedCdpActive mirrors excludedCdp for the same reason. Never nil once + // stored, and the pointed-to set is never mutated after it is stored. + excludedCdpActive atomic.Pointer[map[string]struct{}] } func NewTelemetrySession(es *events.EventStream) *TelemetrySession { @@ -45,6 +60,19 @@ func NewTelemetrySession(es *events.EventStream) *TelemetrySession { return &TelemetrySession{es: es, categories: categorySet(nil)} } +// setActiveLocked republishes the lock-free view of the session state. +// Requires s.mu to be held. +func (s *TelemetrySession) setActiveLocked() { + if s.id == "" { + s.active.Store(nil) + return + } + cats := s.categories + s.active.Store(&cats) + excluded := s.excludedCdp + s.excludedCdpActive.Store(&excluded) +} + // categorySet builds the active filter set from the configured categories. An // empty config falls back to the default set. Monitor is included whenever any // CDP category is present, since collector-health rides along with CDP data. @@ -62,6 +90,19 @@ func categorySet(cats []oapi.TelemetryEventCategory) map[oapi.TelemetryEventCate return set } +// excludedSet builds the cdp_command exclusion set. nil when nothing is +// excluded, which is the common case and the cheapest lookup. +func excludedSet(methods []oapi.BrowserCdpCommandMethod) map[string]struct{} { + if len(methods) == 0 { + return nil + } + set := make(map[string]struct{}, len(methods)) + for _, m := range methods { + set[string(m)] = struct{}{} + } + return set +} + // Start begins a new telemetry session with the given ID and config. Sequence // numbers are process-monotonic and do not reset between sessions; a // Last-Event-ID from any previous session is valid for resuming the SSE stream. @@ -73,6 +114,8 @@ func (s *TelemetrySession) Start(telemetrySessionID string, cfg TelemetryConfig) s.appliedAt = time.Now() s.categories = categorySet(cfg.Categories) s.exportOTLP = cfg.ExportOTLP + s.excludedCdp = excludedSet(cfg.ExcludedCdpMethods) + s.setActiveLocked() } // publishLocked stamps telemetry_session_id into ev.Source.Metadata and forwards to the bus. @@ -117,6 +160,16 @@ func (s *TelemetrySession) ID() string { return s.id } +// RecordDropped notes that a consumer found a gap of n envelopes in the stream. +func (s *TelemetrySession) RecordDropped(n uint64) { + s.es.RecordDropped(n) +} + +// DroppedEvents returns the cumulative gap count across consumers. +func (s *TelemetrySession) DroppedEvents() uint64 { + return s.es.DroppedEvents() +} + // Seq returns the sequence number of the last published event. func (s *TelemetrySession) Seq() uint64 { return s.es.Seq() @@ -138,7 +191,12 @@ func (s *TelemetrySession) Config() TelemetryConfig { for c := range s.categories { cats = append(cats, c) } - return TelemetryConfig{Categories: cats, ExportOTLP: s.exportOTLP} + excluded := make([]oapi.BrowserCdpCommandMethod, 0, len(s.excludedCdp)) + for m := range s.excludedCdp { + excluded = append(excluded, oapi.BrowserCdpCommandMethod(m)) + } + sort.Slice(excluded, func(i, j int) bool { return excluded[i] < excluded[j] }) + return TelemetryConfig{Categories: cats, ExportOTLP: s.exportOTLP, ExcludedCdpMethods: excluded} } // AppliedAt returns when the current configuration was applied, or the zero @@ -155,25 +213,36 @@ func (s *TelemetrySession) UpdateConfig(cfg TelemetryConfig) { defer s.mu.Unlock() s.categories = categorySet(cfg.Categories) s.exportOTLP = cfg.ExportOTLP + s.excludedCdp = excludedSet(cfg.ExcludedCdpMethods) + s.setActiveLocked() } // CategoryEnabled reports whether events in category c are currently captured. -// It returns false when no session is active. +// It returns false when no session is active. Lock-free, so a caller on the +// CDP forwarding path can check it per frame; Publish re-checks under mu. func (s *TelemetrySession) CategoryEnabled(c oapi.TelemetryEventCategory) bool { - s.mu.Lock() - defer s.mu.Unlock() - if s.id == "" { + cats := s.active.Load() + if cats == nil { return false } - _, ok := s.categories[c] + _, ok := (*cats)[c] return ok } +// ExcludedCdpMethods returns the methods left out of the cdp_command stream. +// Lock-free for the same reason CategoryEnabled is; the returned set is +// read-only and may be nil. +func (s *TelemetrySession) ExcludedCdpMethods() map[string]struct{} { + excluded := s.excludedCdpActive.Load() + if excluded == nil { + return nil + } + return *excluded +} + // Active reports whether a telemetry session is currently running. func (s *TelemetrySession) Active() bool { - s.mu.Lock() - defer s.mu.Unlock() - return s.id != "" + return s.active.Load() != nil } // Stop ends the current telemetry session. The ring buffer is left intact so @@ -186,4 +255,5 @@ func (s *TelemetrySession) Stop() { // The session is over, so export is off; keep Config() authoritative for the // desired export state after a clear. s.exportOTLP = false + s.setActiveLocked() } diff --git a/server/lib/wsproxy/wsproxy.go b/server/lib/wsproxy/wsproxy.go index 8a7e5940..65ad81f4 100644 --- a/server/lib/wsproxy/wsproxy.go +++ b/server/lib/wsproxy/wsproxy.go @@ -5,6 +5,7 @@ import ( "log/slog" "net/http" "sync" + "time" "github.com/coder/websocket" "github.com/kernel/kernel-images/server/lib/wsdrain" @@ -22,6 +23,13 @@ type Conn interface { // It returns the (possibly modified) message bytes to forward. type MessageTransform func(direction string, mt websocket.MessageType, msg []byte) []byte +// Observer is called after a message has been successfully written to the +// other side, with ts set to the time that write completed (Unix +// microseconds). It runs on the pump goroutine, so anything it does delays the +// next message: hand work to a worker rather than doing it here. msg is not +// retained by the pump after the call, so an observer may take ownership. +type Observer func(direction string, mt websocket.MessageType, msg []byte, ts int64) + // ProxyOptions configures the proxy accept/dial behavior and optional message // transformation. Zero values are valid and use sensible defaults. type ProxyOptions struct { @@ -29,6 +37,7 @@ type ProxyOptions struct { DialOptions *websocket.DialOptions Logger *slog.Logger Transform MessageTransform + Observe Observer // Registry, when set, tracks the accepted client connection so it is // closed with a Going Away frame on server shutdown. Registry *wsdrain.Registry @@ -54,8 +63,10 @@ const ( // Pump bidirectionally copies messages between client and upstream until // either side errors or ctx is cancelled, then calls onClose with the cause. // If transform is non-nil it is called for every message; the returned bytes -// are forwarded to the other side. -func Pump(ctx context.Context, client, upstream Conn, onClose func(cause PumpExitCause), logger *slog.Logger, transform MessageTransform) { +// are forwarded to the other side. If observe is non-nil it is called for +// every message that was forwarded successfully, so a message whose write +// failed is never observed. +func Pump(ctx context.Context, client, upstream Conn, onClose func(cause PumpExitCause), logger *slog.Logger, transform MessageTransform, observe Observer) { causeChan := make(chan PumpExitCause, 2) go func() { @@ -74,6 +85,9 @@ func Pump(ctx context.Context, client, upstream Conn, onClose func(cause PumpExi causeChan <- PumpExitUpstream return } + if observe != nil { + observe("->", mt, msg, time.Now().UnixMicro()) + } } }() @@ -93,6 +107,9 @@ func Pump(ctx context.Context, client, upstream Conn, onClose func(cause PumpExi causeChan <- PumpExitClient return } + if observe != nil { + observe("<-", mt, msg, time.Now().UnixMicro()) + } } }() @@ -146,5 +163,5 @@ func Proxy(w http.ResponseWriter, r *http.Request, upstreamURL string, opts Prox }) } - Pump(r.Context(), clientConn, upstreamConn, cleanup, logger, opts.Transform) + Pump(r.Context(), clientConn, upstreamConn, cleanup, logger, opts.Transform, opts.Observe) } diff --git a/server/lib/wsproxy/wsproxy_test.go b/server/lib/wsproxy/wsproxy_test.go new file mode 100644 index 00000000..f6ed2edf --- /dev/null +++ b/server/lib/wsproxy/wsproxy_test.go @@ -0,0 +1,139 @@ +package wsproxy + +import ( + "context" + "errors" + "io" + "log/slog" + "sync" + "testing" + "time" + + "github.com/coder/websocket" +) + +// fakeConn plays back a fixed script of reads and records what was written. +type fakeConn struct { + mu sync.Mutex + reads [][]byte + readErr error + written [][]byte + writeErr error + // idle, when set, parks Read once the script is exhausted instead of + // returning EOF, so one side does not end the pump before the other side + // has worked through its script. + idle chan struct{} +} + +func (c *fakeConn) Read(ctx context.Context) (websocket.MessageType, []byte, error) { + c.mu.Lock() + defer c.mu.Unlock() + if len(c.reads) == 0 { + idle, err := c.idle, c.readErr + c.mu.Unlock() + defer c.mu.Lock() + if idle != nil { + select { + case <-idle: + case <-ctx.Done(): + } + } + if err != nil { + return 0, nil, err + } + return 0, nil, io.EOF + } + msg := c.reads[0] + c.reads = c.reads[1:] + return websocket.MessageText, msg, nil +} + +func (c *fakeConn) Write(ctx context.Context, typ websocket.MessageType, p []byte) error { + c.mu.Lock() + defer c.mu.Unlock() + if c.writeErr != nil { + return c.writeErr + } + c.written = append(c.written, append([]byte(nil), p...)) + return nil +} + +func (c *fakeConn) Close(websocket.StatusCode, string) error { return nil } + +func (c *fakeConn) writes() [][]byte { + c.mu.Lock() + defer c.mu.Unlock() + out := make([][]byte, len(c.written)) + copy(out, c.written) + return out +} + +func silent() *slog.Logger { + return slog.New(slog.NewTextHandler(io.Discard, nil)) +} + +// An observer must never see a message the other side did not accept, or a +// reader would conclude the browser was told something it never was. +func TestPumpDoesNotObserveMessagesWhoseWriteFailed(t *testing.T) { + idle := make(chan struct{}) + defer close(idle) + client := &fakeConn{reads: [][]byte{[]byte("a"), []byte("b")}, idle: idle} + upstream := &fakeConn{writeErr: errors.New("upstream gone"), idle: idle} + + var observed [][]byte + var mu sync.Mutex + observe := func(direction string, mt websocket.MessageType, msg []byte, ts int64) { + mu.Lock() + defer mu.Unlock() + observed = append(observed, msg) + } + + ctx, cancel := context.WithTimeout(context.Background(), 5*time.Second) + defer cancel() + Pump(ctx, client, upstream, func(PumpExitCause) {}, silent(), nil, observe) + + mu.Lock() + defer mu.Unlock() + if len(observed) != 0 { + t.Fatalf("observed %d messages whose write failed, want 0", len(observed)) + } +} + +// Observation runs after the forward, so the bytes an observer sees are the +// bytes the other side got, in the order it got them. +func TestPumpObservesForwardedMessagesInOrder(t *testing.T) { + idle := make(chan struct{}) + defer close(idle) + frames := [][]byte{[]byte("one"), []byte("two"), []byte("three")} + client := &fakeConn{reads: frames} + upstream := &fakeConn{idle: idle} + + var observed []string + var mu sync.Mutex + observe := func(direction string, mt websocket.MessageType, msg []byte, ts int64) { + if direction != "->" { + return + } + mu.Lock() + defer mu.Unlock() + observed = append(observed, string(msg)) + } + + ctx, cancel := context.WithTimeout(context.Background(), 5*time.Second) + defer cancel() + Pump(ctx, client, upstream, func(PumpExitCause) {}, silent(), nil, observe) + + mu.Lock() + defer mu.Unlock() + if got := len(observed); got != len(frames) { + t.Fatalf("observed %d messages, want %d", got, len(frames)) + } + for i, want := range []string{"one", "two", "three"} { + if observed[i] != want { + t.Fatalf("observed[%d] = %q, want %q", i, observed[i], want) + } + } + if got := len(upstream.writes()); got != len(frames) { + t.Fatalf("forwarded %d messages, want %d", got, len(frames)) + } +} diff --git a/server/openapi.yaml b/server/openapi.yaml index 20dfdef9..d38946dc 100644 --- a/server/openapi.yaml +++ b/server/openapi.yaml @@ -1723,8 +1723,8 @@ components: $ref: "#/components/schemas/BrowserTelemetryCategoryConfig" description: HTTP request/response metadata. control: - $ref: "#/components/schemas/BrowserTelemetryCategoryConfig" - description: Agent-driven actions against the browser — computer-control calls, Playwright code execution, screenshots and clipboard access. + $ref: "#/components/schemas/BrowserTelemetryControlConfig" + description: Agent-driven actions against the browser — computer-control calls, Playwright code execution, screenshots, clipboard access, and browser-control commands sent over the CDP proxy. platform: $ref: "#/components/schemas/BrowserTelemetryCategoryConfig" description: Calls that manage the VM rather than drive the browser (recording, filesystem, process, telemetry and browser configuration). Mostly platform-induced; off by default and opt-in. @@ -1755,6 +1755,42 @@ components: category retains its current state. To enable or disable a category via PATCH, you must send an explicit `true` or `false`. additionalProperties: false + BrowserTelemetryControlConfig: + type: object + description: > + Configuration for the control category. Same `enabled` semantics as any + other category, plus settings for the browser-control commands the CDP + proxy reports. + properties: + enabled: + type: boolean + description: > + Whether this category is captured. In PUT requests selection is opt-in: + omitting this field (or the whole category) leaves the category off, so + a PUT captures exactly the categories set to true. In PATCH requests, + omitting this field (or sending an empty object `{}`) is a no-op; the + category retains its current state. To enable or disable a category via + PATCH, you must send an explicit `true` or `false`. + cdp: + $ref: "#/components/schemas/BrowserTelemetryCdpControlConfig" + additionalProperties: false + BrowserTelemetryCdpControlConfig: + type: object + description: Settings for the `cdp_command` events the DevTools proxy reports. + properties: + excluded_methods: + type: array + description: > + Methods to leave out of the `cdp_command` stream. Omit the list (or + send an empty one) to report every supported method. Exclusion is a + telemetry setting only: an excluded command is still relayed to the + browser unchanged, it simply produces no event. Use it to drop the + highest-volume methods — `Input.dispatchMouseEvent` during a + humanized cursor path, or `Page.captureScreenshot` under a + screencast — without turning the whole category off. + items: + $ref: "#/components/schemas/BrowserCdpCommandMethod" + additionalProperties: false BrowserCallStack: type: object description: > @@ -2827,157 +2863,1653 @@ components: truncated: type: boolean description: True if the data field was truncated due to size limits. - BrowserCdpConnectEvent: + BrowserCdpCommandMethod: + type: string + description: > + A browser-control CDP method the proxy reports. The set covers the + commands an agent drives the browser with; configuration, DOM and + Runtime bookkeeping, and Chrome-specific UI commands are outside it. + Canonical definitions: devtools-protocol@2d019e73. + enum: + - Input.dispatchMouseEvent + - Input.dispatchKeyEvent + - Input.insertText + - Input.imeSetComposition + - Input.dispatchTouchEvent + - Input.dispatchDragEvent + - Input.cancelDragging + - Input.emulateTouchFromMouseEvent + - Input.synthesizePinchGesture + - Input.synthesizeScrollGesture + - Input.synthesizeTapGesture + - DOM.setFileInputFiles + - DOM.focus + - DOM.scrollIntoViewIfNeeded + - Page.bringToFront + - Page.captureScreenshot + - Page.captureSnapshot + - Page.handleJavaScriptDialog + - Page.navigate + - Page.navigateToHistoryEntry + - Page.reload + - Page.printToPDF + - Page.startScreencast + - Page.stopScreencast + - Page.stopLoading + - Page.close + - Page.setWebLifecycleState + - Target.activateTarget + - Target.closeTarget + - Target.createTarget + - Target.createBrowserContext + - Target.disposeBrowserContext + - Target.openDevTools + - Browser.cancelDownload + - Browser.close + - Browser.setWindowBounds + - Browser.setContentsSize + - Autofill.trigger + BrowserCdpInputDispatchMouseEventCommandData: type: object - description: An external client (e.g. customer SDK, Playwright, Puppeteer) connected to the CDP WebSocket proxy on this VM. - required: [ts, type, category, source] + description: > + Sanitized `Input.dispatchMouseEvent` arguments. Canonical input: + devtools-protocol@2d019e73 `Input.dispatchMouseEvent`. + additionalProperties: false + required: [method, event_type] properties: - ts: + method: + type: string + const: Input.dispatchMouseEvent + session_id: + type: string + description: > + CDP session identifier the command was addressed to. Absent for + browser-level commands. + event_type: + type: string + description: > + Mouse event phase: `mousePressed`, `mouseReleased`, `mouseMoved` + or `mouseWheel`. + x: + type: number + format: double + description: > + Viewport x coordinate in CSS pixels. + y: + type: number + format: double + description: > + Viewport y coordinate in CSS pixels. + modifiers: type: integer - format: int64 - description: Event timestamp in Unix microseconds. - type: + description: > + Bit field of held modifier keys (1=Alt, 2=Ctrl, 4=Meta, + 8=Shift). + button: type: string - const: cdp_connect - category: + description: > + Button named by the command (`none`, `left`, `middle`, `right`, + `back`, `forward`). + buttons: + type: integer + description: > + Bit field of buttons held down. Non-zero on a `mouseMoved` means + the move is a drag path. + click_count: + type: integer + description: > + Number of times the button was clicked (2 is a double click). + delta_x: + type: number + format: double + description: > + Horizontal scroll delta, for `mouseWheel`. + delta_y: + type: number + format: double + description: > + Vertical scroll delta, for `mouseWheel`. + pointer_type: type: string - const: connection - source: - $ref: "#/components/schemas/BrowserEventSource" - truncated: - type: boolean - description: True if the data field was truncated due to size limits. - BrowserCdpDisconnectEventData: + description: > + Pointer that generated the event (`mouse` or `pen`). + force: + type: number + format: double + description: > + Normalized pressure, 0 to 1. + tangential_pressure: + type: number + format: double + description: > + Normalized tangential pressure, -1 to 1. + tilt_x: + type: number + format: double + description: > + Pen tilt from the Y-Z plane, in degrees. + tilt_y: + type: number + format: double + description: > + Pen tilt from the X-Z plane, in degrees. + twist: + type: integer + description: > + Pen clockwise rotation, in degrees. + BrowserCdpInputDispatchKeyEventCommandData: type: object - description: Per-disconnect payload for `cdp_disconnect` events. + description: > + Sanitized `Input.dispatchKeyEvent` arguments. Canonical input: + devtools-protocol@2d019e73 `Input.dispatchKeyEvent`. additionalProperties: false - required: [duration_ms, message_count, reason] + required: [method, event_type] properties: - duration_ms: - type: number - description: Wall-clock duration of the connection in milliseconds. - message_count: + method: + type: string + const: Input.dispatchKeyEvent + session_id: + type: string + description: > + CDP session identifier the command was addressed to. Absent for + browser-level commands. + event_type: + type: string + description: > + Key event phase: `keyDown`, `keyUp`, `rawKeyDown` or `char`. + modifiers: type: integer - description: Number of CDP messages relayed across the connection in either direction. - reason: + description: > + Bit field of held modifier keys (1=Alt, 2=Ctrl, 4=Meta, + 8=Shift). + text_length: + type: integer + description: > + Number of characters the command submitted. The text itself is + never captured. + named_key: type: string description: > - Why the connection ended. `client_close`: the client initiated the close. - `upstream_changed`: Chromium restarted mid-session and the proxy tore down - so the client could reconnect against the new upstream. `upstream_error`: - upstream dial or message pump errored. `context_cancelled`: the request - context was cancelled (typically server shutdown). - enum: - - client_close - - upstream_changed - - upstream_error - - context_cancelled - BrowserCdpDisconnectEvent: + Key that commands the page rather than typing into it (e.g. + `Enter`, `Tab`, `ArrowDown`, `F5`). Keys that produce a + character are never captured; those are counted by + `text_length`. + location: + type: integer + description: > + Keyboard location (1=left, 2=right, 3=numpad). + auto_repeat: + type: boolean + description: > + Whether the event was generated by key repeat. + is_keypad: + type: boolean + description: > + Whether the key is on the numeric keypad. + is_system_key: + type: boolean + description: > + Whether the event is a system key event. + command_count: + type: integer + description: > + Number of editing commands (e.g. `selectAll`) carried by the + event. + BrowserCdpInputInsertTextCommandData: type: object - description: An external client disconnected from the CDP WebSocket proxy on this VM. Pair with the immediately preceding `cdp_connect` on the same stream. - required: [ts, type, category, source] + description: > + Sanitized `Input.insertText` arguments. Canonical input: + devtools-protocol@2d019e73 `Input.insertText`. + additionalProperties: false + required: [method, text_length] properties: - ts: - type: integer - format: int64 - description: Event timestamp in Unix microseconds. - type: + method: type: string - const: cdp_disconnect - category: + const: Input.insertText + session_id: type: string - const: connection - source: - $ref: "#/components/schemas/BrowserEventSource" - data: - $ref: "#/components/schemas/BrowserCdpDisconnectEventData" - truncated: - type: boolean - description: True if the data field was truncated due to size limits. - BrowserLiveViewConnectEventData: + description: > + CDP session identifier the command was addressed to. Absent for + browser-level commands. + text_length: + type: integer + description: > + Number of characters inserted. The text itself is never + captured. + BrowserCdpInputImeSetCompositionCommandData: type: object - description: Per-session payload for `live_view_connect` events. + description: > + Sanitized `Input.imeSetComposition` arguments. Canonical input: + devtools-protocol@2d019e73 `Input.imeSetComposition`. additionalProperties: false - required: [session_id] + required: [method, text_length] properties: + method: + type: string + const: Input.imeSetComposition session_id: type: string - description: Live view session identifier. Stable across reconnects, so a transient network blip can emit two events with the same `session_id`. - BrowserLiveViewConnectEvent: + description: > + CDP session identifier the command was addressed to. Absent for + browser-level commands. + text_length: + type: integer + description: > + Number of characters in the composition. The text itself is + never captured. + selection_start: + type: integer + description: > + Selection start offset within the composition. + selection_end: + type: integer + description: > + Selection end offset within the composition. + replacement_start: + type: integer + description: > + Replacement range start offset. + replacement_end: + type: integer + description: > + Replacement range end offset. + BrowserCdpInputDispatchTouchEventCommandData: type: object - description: A live view client connected to the headful browser's WebRTC server (Neko). Headful only; not emitted for headless images. - required: [ts, type, category, source] + description: > + Sanitized `Input.dispatchTouchEvent` arguments. Canonical input: + devtools-protocol@2d019e73 `Input.dispatchTouchEvent`. + additionalProperties: false + required: [method, event_type, touch_point_count] properties: - ts: - type: integer - format: int64 - description: Event timestamp in Unix microseconds. - type: + method: type: string - const: live_view_connect - category: + const: Input.dispatchTouchEvent + session_id: type: string - const: connection - source: - $ref: "#/components/schemas/BrowserEventSource" - data: - $ref: "#/components/schemas/BrowserLiveViewConnectEventData" - truncated: - type: boolean - description: True if the data field was truncated due to size limits. - BrowserLiveViewDisconnectEventData: + description: > + CDP session identifier the command was addressed to. Absent for + browser-level commands. + event_type: + type: string + description: > + Touch event phase: `touchStart`, `touchEnd`, `touchMove` or + `touchCancel`. + touch_point_count: + type: integer + description: > + Number of active touch points the command carried. + x: + type: number + format: double + description: > + Viewport x coordinate of the first touch point. Touch + coordinates live inside `touchPoints`, so this is the primary + point rather than a command-level argument. + y: + type: number + format: double + description: > + Viewport y coordinate of the first touch point. + modifiers: + type: integer + description: > + Bit field of held modifier keys (1=Alt, 2=Ctrl, 4=Meta, + 8=Shift). + BrowserCdpInputDispatchDragEventCommandData: type: object - description: Per-session payload for `live_view_disconnect` events. + description: > + Sanitized `Input.dispatchDragEvent` arguments. Canonical input: + devtools-protocol@2d019e73 `Input.dispatchDragEvent`. additionalProperties: false - required: [session_id, duration_ms] + required: [method, event_type] properties: + method: + type: string + const: Input.dispatchDragEvent session_id: type: string - description: Live view session identifier; matches the corresponding `live_view_connect` event. - duration_ms: + description: > + CDP session identifier the command was addressed to. Absent for + browser-level commands. + event_type: + type: string + description: > + Drag event phase: `dragEnter`, `dragOver`, `drop` or + `dragCancel`. + x: type: number - description: Wall-clock duration of the connection in milliseconds. - BrowserLiveViewDisconnectEvent: + format: double + description: > + Viewport x coordinate in CSS pixels. + y: + type: number + format: double + description: > + Viewport y coordinate in CSS pixels. + modifiers: + type: integer + description: > + Bit field of held modifier keys (1=Alt, 2=Ctrl, 4=Meta, + 8=Shift). + drag_item_count: + type: integer + description: > + Number of items in the drag payload. Item contents are never + captured. + drag_file_count: + type: integer + description: > + Number of files in the drag payload. File paths are never + captured. + drag_mime_categories: + type: array + items: + type: string + description: > + Distinct top-level MIME categories of the drag items (e.g. + `text`, `image`, `application`). Subtypes and contents are never + captured. + drag_operations_mask: + type: integer + description: > + Bit field of allowed drag operations (1=copy, 2=link, 16=move). + BrowserCdpInputCancelDraggingCommandData: type: object - description: A live view client disconnected from the headful browser's WebRTC server (Neko). Pair with `live_view_connect` by `session_id`. - required: [ts, type, category, source] + description: > + Sanitized `Input.cancelDragging` arguments. Canonical input: + devtools-protocol@2d019e73 `Input.cancelDragging`. + additionalProperties: false + required: [method] properties: - ts: - type: integer - format: int64 - description: Event timestamp in Unix microseconds. - type: + method: type: string - const: live_view_disconnect - category: + const: Input.cancelDragging + session_id: type: string - const: connection - source: - $ref: "#/components/schemas/BrowserEventSource" - data: - $ref: "#/components/schemas/BrowserLiveViewDisconnectEventData" - truncated: - type: boolean - description: True if the data field was truncated due to size limits. - BrowserCaptchaSolveResultEventData: + description: > + CDP session identifier the command was addressed to. Absent for + browser-level commands. + BrowserCdpInputEmulateTouchFromMouseEventCommandData: type: object - description: Per-attempt payload for `captcha_solve_result` events. + description: > + Sanitized `Input.emulateTouchFromMouseEvent` arguments. Canonical + input: devtools-protocol@2d019e73 + `Input.emulateTouchFromMouseEvent`. additionalProperties: false - required: [captcha_type, status, duration_ms] + required: [method, event_type] properties: - captcha_type: + method: + type: string + const: Input.emulateTouchFromMouseEvent + session_id: type: string description: > - Captcha vendor family. Producers normalize provider-specific task - names into this set: enterprise variants of recaptcha collapse into - their version bucket (v2 / v3), and anything not covered (e.g. - DataDome, MtCaptcha, plain OCR) is reported as `other`. - enum: - - hcaptcha - - recaptcha_v2 - - recaptcha_v3 - - turnstile - - geetest + CDP session identifier the command was addressed to. Absent for + browser-level commands. + event_type: + type: string + description: > + Mouse event phase being emulated as touch. + x: + type: number + format: double + description: > + Viewport x coordinate in CSS pixels. + y: + type: number + format: double + description: > + Viewport y coordinate in CSS pixels. + button: + type: string + description: > + Button named by the command. + modifiers: + type: integer + description: > + Bit field of held modifier keys (1=Alt, 2=Ctrl, 4=Meta, + 8=Shift). + click_count: + type: integer + description: > + Number of times the button was clicked. + delta_x: + type: number + format: double + description: > + Horizontal scroll delta. + delta_y: + type: number + format: double + description: > + Vertical scroll delta. + BrowserCdpInputSynthesizePinchGestureCommandData: + type: object + description: > + Sanitized `Input.synthesizePinchGesture` arguments. Canonical input: + devtools-protocol@2d019e73 `Input.synthesizePinchGesture`. + additionalProperties: false + required: [method] + properties: + method: + type: string + const: Input.synthesizePinchGesture + session_id: + type: string + description: > + CDP session identifier the command was addressed to. Absent for + browser-level commands. + x: + type: number + format: double + description: > + Viewport x coordinate in CSS pixels. + y: + type: number + format: double + description: > + Viewport y coordinate in CSS pixels. + scale_factor: + type: number + format: double + description: > + Relative scale of the pinch (>1 zooms in). + relative_speed: + type: integer + description: > + Relative pointer speed, in pixels per second. + gesture_source_type: + type: string + description: > + Input source the synthesized gesture emulates. + BrowserCdpInputSynthesizeScrollGestureCommandData: + type: object + description: > + Sanitized `Input.synthesizeScrollGesture` arguments. Canonical + input: devtools-protocol@2d019e73 `Input.synthesizeScrollGesture`. + additionalProperties: false + required: [method] + properties: + method: + type: string + const: Input.synthesizeScrollGesture + session_id: + type: string + description: > + CDP session identifier the command was addressed to. Absent for + browser-level commands. + x: + type: number + format: double + description: > + Viewport x coordinate in CSS pixels. + y: + type: number + format: double + description: > + Viewport y coordinate in CSS pixels. + x_distance: + type: number + format: double + description: > + Horizontal scroll distance in CSS pixels; positive scrolls left. + y_distance: + type: number + format: double + description: > + Vertical scroll distance in CSS pixels; positive scrolls up. + x_overscroll: + type: number + format: double + description: > + Additional horizontal distance scrolled past the end. + y_overscroll: + type: number + format: double + description: > + Additional vertical distance scrolled past the end. + prevent_fling: + type: boolean + description: > + Whether fling was suppressed. + speed: + type: integer + description: > + Swipe speed in pixels per second. + gesture_source_type: + type: string + description: > + Input source the synthesized gesture emulates. + repeat_count: + type: integer + description: > + Number of additional repeats of the scroll. + repeat_delay_ms: + type: integer + description: > + Delay between repeats, in milliseconds. + BrowserCdpInputSynthesizeTapGestureCommandData: + type: object + description: > + Sanitized `Input.synthesizeTapGesture` arguments. Canonical input: + devtools-protocol@2d019e73 `Input.synthesizeTapGesture`. + additionalProperties: false + required: [method] + properties: + method: + type: string + const: Input.synthesizeTapGesture + session_id: + type: string + description: > + CDP session identifier the command was addressed to. Absent for + browser-level commands. + x: + type: number + format: double + description: > + Viewport x coordinate in CSS pixels. + y: + type: number + format: double + description: > + Viewport y coordinate in CSS pixels. + duration: + type: integer + description: > + Duration between touchdown and touchup, in milliseconds. + tap_count: + type: integer + description: > + Number of times to tap (2 is a double tap). + gesture_source_type: + type: string + description: > + Input source the synthesized gesture emulates. + BrowserCdpDomSetFileInputFilesCommandData: + type: object + description: > + Sanitized `DOM.setFileInputFiles` arguments. Canonical input: + devtools-protocol@2d019e73 `DOM.setFileInputFiles`. + additionalProperties: false + required: [method, file_count] + properties: + method: + type: string + const: DOM.setFileInputFiles + session_id: + type: string + description: > + CDP session identifier the command was addressed to. Absent for + browser-level commands. + file_count: + type: integer + description: > + Number of files handed to the input. File paths are never + captured. + node_id: + type: integer + description: > + Opaque DOM node identifier the command targeted. + backend_node_id: + type: integer + description: > + Opaque backend DOM node identifier the command targeted. + object_id: + type: string + description: > + Opaque Runtime remote object identifier the command targeted. + BrowserCdpDomFocusCommandData: + type: object + description: > + Sanitized `DOM.focus` arguments. Canonical input: + devtools-protocol@2d019e73 `DOM.focus`. + additionalProperties: false + required: [method] + properties: + method: + type: string + const: DOM.focus + session_id: + type: string + description: > + CDP session identifier the command was addressed to. Absent for + browser-level commands. + node_id: + type: integer + description: > + Opaque DOM node identifier the command targeted. + backend_node_id: + type: integer + description: > + Opaque backend DOM node identifier the command targeted. + object_id: + type: string + description: > + Opaque Runtime remote object identifier the command targeted. + BrowserCdpDomScrollIntoViewIfNeededCommandData: + type: object + description: > + Sanitized `DOM.scrollIntoViewIfNeeded` arguments. Canonical input: + devtools-protocol@2d019e73 `DOM.scrollIntoViewIfNeeded`. + additionalProperties: false + required: [method] + properties: + method: + type: string + const: DOM.scrollIntoViewIfNeeded + session_id: + type: string + description: > + CDP session identifier the command was addressed to. Absent for + browser-level commands. + node_id: + type: integer + description: > + Opaque DOM node identifier the command targeted. + backend_node_id: + type: integer + description: > + Opaque backend DOM node identifier the command targeted. + object_id: + type: string + description: > + Opaque Runtime remote object identifier the command targeted. + has_rect: + type: boolean + description: > + Whether the command constrained scrolling to a rect within the + node. + BrowserCdpPageBringToFrontCommandData: + type: object + description: > + Sanitized `Page.bringToFront` arguments. Canonical input: + devtools-protocol@2d019e73 `Page.bringToFront`. + additionalProperties: false + required: [method] + properties: + method: + type: string + const: Page.bringToFront + session_id: + type: string + description: > + CDP session identifier the command was addressed to. Absent for + browser-level commands. + BrowserCdpPageCaptureScreenshotCommandData: + type: object + description: > + Sanitized `Page.captureScreenshot` arguments. Canonical input: + devtools-protocol@2d019e73 `Page.captureScreenshot`. + additionalProperties: false + required: [method] + properties: + method: + type: string + const: Page.captureScreenshot + session_id: + type: string + description: > + CDP session identifier the command was addressed to. Absent for + browser-level commands. + format: + type: string + description: > + Image format requested (`jpeg`, `png` or `webp`). + quality: + type: integer + description: > + Compression quality, 0 to 100, for lossy formats. + from_surface: + type: boolean + description: > + Whether the capture was taken from the surface rather than the + view. + capture_beyond_viewport: + type: boolean + description: > + Whether the capture extended past the viewport. + optimize_for_speed: + type: boolean + description: > + Whether encoding favored speed over size. + clip_x: + type: number + format: double + description: > + Clip region x offset in CSS pixels. + clip_y: + type: number + format: double + description: > + Clip region y offset in CSS pixels. + clip_width: + type: number + format: double + description: > + Clip region width in CSS pixels. + clip_height: + type: number + format: double + description: > + Clip region height in CSS pixels. + clip_scale: + type: number + format: double + description: > + Clip region page scale factor. + BrowserCdpPageCaptureSnapshotCommandData: + type: object + description: > + Sanitized `Page.captureSnapshot` arguments. Canonical input: + devtools-protocol@2d019e73 `Page.captureSnapshot`. + additionalProperties: false + required: [method] + properties: + method: + type: string + const: Page.captureSnapshot + session_id: + type: string + description: > + CDP session identifier the command was addressed to. Absent for + browser-level commands. + format: + type: string + description: > + Snapshot format requested (`mhtml`). + BrowserCdpPageHandleJavaScriptDialogCommandData: + type: object + description: > + Sanitized `Page.handleJavaScriptDialog` arguments. Canonical input: + devtools-protocol@2d019e73 `Page.handleJavaScriptDialog`. + additionalProperties: false + required: [method, accept] + properties: + method: + type: string + const: Page.handleJavaScriptDialog + session_id: + type: string + description: > + CDP session identifier the command was addressed to. Absent for + browser-level commands. + accept: + type: boolean + description: > + Whether the dialog was accepted or dismissed. + prompt_text_length: + type: integer + description: > + Number of characters entered into a prompt dialog. The text + itself is never captured. + BrowserCdpPageNavigateCommandData: + type: object + description: > + Sanitized `Page.navigate` arguments. Canonical input: + devtools-protocol@2d019e73 `Page.navigate`. + additionalProperties: false + required: [method] + properties: + method: + type: string + const: Page.navigate + session_id: + type: string + description: > + CDP session identifier the command was addressed to. Absent for + browser-level commands. + url_scheme: + type: string + description: > + Scheme of the destination URL (e.g. `https`, `about`, `data`). + The rest of the URL — host, path, query and fragment — is never + captured. Enable the `page` category for navigation events that + carry the URL itself. + transition_type: + type: string + description: > + Navigation reason reported by the caller (e.g. `link`, `typed`, + `reload`). + referrer_present: + type: boolean + description: > + Whether the command carried a referrer. The referrer itself is + never captured. + referrer_policy: + type: string + description: > + Referrer policy named by the command. + frame_id: + type: string + description: > + Opaque frame identifier. + BrowserCdpPageNavigateToHistoryEntryCommandData: + type: object + description: > + Sanitized `Page.navigateToHistoryEntry` arguments. Canonical input: + devtools-protocol@2d019e73 `Page.navigateToHistoryEntry`. + additionalProperties: false + required: [method, entry_id] + properties: + method: + type: string + const: Page.navigateToHistoryEntry + session_id: + type: string + description: > + CDP session identifier the command was addressed to. Absent for + browser-level commands. + entry_id: + type: integer + description: > + History entry the command navigated to. + BrowserCdpPageReloadCommandData: + type: object + description: > + Sanitized `Page.reload` arguments. Canonical input: + devtools-protocol@2d019e73 `Page.reload`. + additionalProperties: false + required: [method] + properties: + method: + type: string + const: Page.reload + session_id: + type: string + description: > + CDP session identifier the command was addressed to. Absent for + browser-level commands. + ignore_cache: + type: boolean + description: > + Whether the reload bypassed the cache. + script_length: + type: integer + description: > + Number of characters in the injected script, absent when none was + supplied and 0 when an empty one was. The script itself is never + captured. + loader_id: + type: string + description: > + Opaque document loader identifier. + BrowserCdpPagePrintToPdfCommandData: + type: object + description: > + Sanitized `Page.printToPDF` arguments. Canonical input: + devtools-protocol@2d019e73 `Page.printToPDF`. + additionalProperties: false + required: [method] + properties: + method: + type: string + const: Page.printToPDF + session_id: + type: string + description: > + CDP session identifier the command was addressed to. Absent for + browser-level commands. + landscape: + type: boolean + description: > + Whether the page was laid out in landscape. + scale: + type: number + format: double + description: > + Page render scale. + paper_width: + type: number + format: double + description: > + Paper width in inches. + paper_height: + type: number + format: double + description: > + Paper height in inches. + display_header_footer: + type: boolean + description: > + Whether a header and footer were rendered. + print_background: + type: boolean + description: > + Whether background graphics were printed. + prefer_css_page_size: + type: boolean + description: > + Whether the CSS page size was preferred over the paper size. + transfer_mode: + type: string + description: > + How the PDF was returned (`ReturnAsBase64` or `ReturnAsStream`). + page_ranges_present: + type: boolean + description: > + Whether a page range was supplied. + header_template_present: + type: boolean + description: > + Whether a header template was supplied. The template itself is + never captured. + footer_template_present: + type: boolean + description: > + Whether a footer template was supplied. The template itself is + never captured. + BrowserCdpPageStartScreencastCommandData: + type: object + description: > + Sanitized `Page.startScreencast` arguments. Canonical input: + devtools-protocol@2d019e73 `Page.startScreencast`. + additionalProperties: false + required: [method] + properties: + method: + type: string + const: Page.startScreencast + session_id: + type: string + description: > + CDP session identifier the command was addressed to. Absent for + browser-level commands. + format: + type: string + description: > + Frame format requested (`jpeg` or `png`). + quality: + type: integer + description: > + Compression quality, 0 to 100. + max_width: + type: integer + description: > + Maximum frame width in pixels. + max_height: + type: integer + description: > + Maximum frame height in pixels. + every_nth_frame: + type: integer + description: > + Frame sampling interval. + BrowserCdpPageStopScreencastCommandData: + type: object + description: > + Sanitized `Page.stopScreencast` arguments. Canonical input: + devtools-protocol@2d019e73 `Page.stopScreencast`. + additionalProperties: false + required: [method] + properties: + method: + type: string + const: Page.stopScreencast + session_id: + type: string + description: > + CDP session identifier the command was addressed to. Absent for + browser-level commands. + BrowserCdpPageStopLoadingCommandData: + type: object + description: > + Sanitized `Page.stopLoading` arguments. Canonical input: + devtools-protocol@2d019e73 `Page.stopLoading`. + additionalProperties: false + required: [method] + properties: + method: + type: string + const: Page.stopLoading + session_id: + type: string + description: > + CDP session identifier the command was addressed to. Absent for + browser-level commands. + BrowserCdpPageCloseCommandData: + type: object + description: > + Sanitized `Page.close` arguments. Canonical input: + devtools-protocol@2d019e73 `Page.close`. + additionalProperties: false + required: [method] + properties: + method: + type: string + const: Page.close + session_id: + type: string + description: > + CDP session identifier the command was addressed to. Absent for + browser-level commands. + BrowserCdpPageSetWebLifecycleStateCommandData: + type: object + description: > + Sanitized `Page.setWebLifecycleState` arguments. Canonical input: + devtools-protocol@2d019e73 `Page.setWebLifecycleState`. + additionalProperties: false + required: [method, state] + properties: + method: + type: string + const: Page.setWebLifecycleState + session_id: + type: string + description: > + CDP session identifier the command was addressed to. Absent for + browser-level commands. + state: + type: string + description: > + Lifecycle state applied (`frozen` or `active`). + BrowserCdpTargetActivateTargetCommandData: + type: object + description: > + Sanitized `Target.activateTarget` arguments. Canonical input: + devtools-protocol@2d019e73 `Target.activateTarget`. + additionalProperties: false + required: [method, target_id] + properties: + method: + type: string + const: Target.activateTarget + session_id: + type: string + description: > + CDP session identifier the command was addressed to. Absent for + browser-level commands. + target_id: + type: string + description: > + Opaque target identifier. + BrowserCdpTargetCloseTargetCommandData: + type: object + description: > + Sanitized `Target.closeTarget` arguments. Canonical input: + devtools-protocol@2d019e73 `Target.closeTarget`. + additionalProperties: false + required: [method, target_id] + properties: + method: + type: string + const: Target.closeTarget + session_id: + type: string + description: > + CDP session identifier the command was addressed to. Absent for + browser-level commands. + target_id: + type: string + description: > + Opaque target identifier. + BrowserCdpTargetCreateTargetCommandData: + type: object + description: > + Sanitized `Target.createTarget` arguments. Canonical input: + devtools-protocol@2d019e73 `Target.createTarget`. + additionalProperties: false + required: [method] + properties: + method: + type: string + const: Target.createTarget + session_id: + type: string + description: > + CDP session identifier the command was addressed to. Absent for + browser-level commands. + url_scheme: + type: string + description: > + Scheme of the destination URL (e.g. `https`, `about`, `data`). + The rest of the URL — host, path, query and fragment — is never + captured. Enable the `page` category for navigation events that + carry the URL itself. + left: + type: integer + description: > + Window x position in screen coordinates. + top: + type: integer + description: > + Window y position in screen coordinates. + width: + type: integer + description: > + Window width in DIP. + height: + type: integer + description: > + Window height in DIP. + window_state: + type: string + description: > + Window state requested (`normal`, `minimized`, `maximized`, + `fullscreen`). + browser_context_id: + type: string + description: > + Opaque browser context identifier. + new_window: + type: boolean + description: > + Whether a new window was requested. + background: + type: boolean + description: > + Whether the target was created in the background. + for_tab: + type: boolean + description: > + Whether a tab target rather than a page target was created. + hidden: + type: boolean + description: > + Whether the target was created hidden. + enable_begin_frame_control: + type: boolean + description: > + Whether BeginFrame control was enabled (headless only). + BrowserCdpTargetCreateBrowserContextCommandData: + type: object + description: > + Sanitized `Target.createBrowserContext` arguments. Canonical input: + devtools-protocol@2d019e73 `Target.createBrowserContext`. + additionalProperties: false + required: [method] + properties: + method: + type: string + const: Target.createBrowserContext + session_id: + type: string + description: > + CDP session identifier the command was addressed to. Absent for + browser-level commands. + dispose_on_detach: + type: boolean + description: > + Whether the context is disposed when the debugging session + detaches. + proxy_server_present: + type: boolean + description: > + Whether a proxy was configured. The proxy address is never + captured. + proxy_bypass_list_present: + type: boolean + description: > + Whether a proxy bypass list was configured. + universal_network_access_origin_count: + type: integer + description: > + Number of origins granted universal network access. The origins + themselves are never captured. + BrowserCdpTargetDisposeBrowserContextCommandData: + type: object + description: > + Sanitized `Target.disposeBrowserContext` arguments. Canonical input: + devtools-protocol@2d019e73 `Target.disposeBrowserContext`. + additionalProperties: false + required: [method, browser_context_id] + properties: + method: + type: string + const: Target.disposeBrowserContext + session_id: + type: string + description: > + CDP session identifier the command was addressed to. Absent for + browser-level commands. + browser_context_id: + type: string + description: > + Opaque browser context identifier. + BrowserCdpTargetOpenDevToolsCommandData: + type: object + description: > + Sanitized `Target.openDevTools` arguments. Canonical input: + devtools-protocol@2d019e73 `Target.openDevTools`. + additionalProperties: false + required: [method, target_id] + properties: + method: + type: string + const: Target.openDevTools + session_id: + type: string + description: > + CDP session identifier the command was addressed to. Absent for + browser-level commands. + target_id: + type: string + description: > + Opaque target identifier. + panel_id: + type: string + description: > + DevTools panel opened. + BrowserCdpBrowserCancelDownloadCommandData: + type: object + description: > + Sanitized `Browser.cancelDownload` arguments. Canonical input: + devtools-protocol@2d019e73 `Browser.cancelDownload`. + additionalProperties: false + required: [method, download_guid] + properties: + method: + type: string + const: Browser.cancelDownload + session_id: + type: string + description: > + CDP session identifier the command was addressed to. Absent for + browser-level commands. + download_guid: + type: string + description: > + Opaque identifier of the download that was cancelled. + browser_context_id: + type: string + description: > + Opaque browser context identifier. + BrowserCdpBrowserCloseCommandData: + type: object + description: > + Sanitized `Browser.close` arguments. Canonical input: + devtools-protocol@2d019e73 `Browser.close`. + additionalProperties: false + required: [method] + properties: + method: + type: string + const: Browser.close + session_id: + type: string + description: > + CDP session identifier the command was addressed to. Absent for + browser-level commands. + BrowserCdpBrowserSetWindowBoundsCommandData: + type: object + description: > + Sanitized `Browser.setWindowBounds` arguments. Canonical input: + devtools-protocol@2d019e73 `Browser.setWindowBounds`. + additionalProperties: false + required: [method, window_id] + properties: + method: + type: string + const: Browser.setWindowBounds + session_id: + type: string + description: > + CDP session identifier the command was addressed to. Absent for + browser-level commands. + window_id: + type: integer + description: > + Browser window identifier. + left: + type: integer + description: > + Window x position in screen coordinates. + top: + type: integer + description: > + Window y position in screen coordinates. + width: + type: integer + description: > + Window width in DIP. + height: + type: integer + description: > + Window height in DIP. + window_state: + type: string + description: > + Window state requested (`normal`, `minimized`, `maximized`, + `fullscreen`). + BrowserCdpBrowserSetContentsSizeCommandData: + type: object + description: > + Sanitized `Browser.setContentsSize` arguments. Canonical input: + devtools-protocol@2d019e73 `Browser.setContentsSize`. + additionalProperties: false + required: [method, window_id] + properties: + method: + type: string + const: Browser.setContentsSize + session_id: + type: string + description: > + CDP session identifier the command was addressed to. Absent for + browser-level commands. + window_id: + type: integer + description: > + Browser window identifier. + width: + type: integer + description: > + Contents width in DIP. + height: + type: integer + description: > + Contents height in DIP. + BrowserCdpAutofillTriggerCommandData: + type: object + description: > + Sanitized `Autofill.trigger` arguments. Canonical input: + devtools-protocol@2d019e73 `Autofill.trigger`. + additionalProperties: false + required: [method, field_id] + properties: + method: + type: string + const: Autofill.trigger + session_id: + type: string + description: > + CDP session identifier the command was addressed to. Absent for + browser-level commands. + field_id: + type: integer + description: > + Opaque backend node identifier of the field that was autofilled. + frame_id: + type: string + description: > + Opaque frame identifier. + mode: + type: string + description: > + What was filled: `card` or `address`. The values themselves are + never captured. + BrowserCdpCommandEventData: + description: > + Per-command payload for `cdp_command` events, discriminated by + `method`. Each variant carries only the arguments approved for that + command: values that could hold a secret — typed and composition + text, URLs, referrers, scripts, templates, file paths, drag contents + and autofill values — are replaced by a length, a count, a presence + flag, an enum or a URL scheme and host. + oneOf: + - $ref: "#/components/schemas/BrowserCdpInputDispatchMouseEventCommandData" + - $ref: "#/components/schemas/BrowserCdpInputDispatchKeyEventCommandData" + - $ref: "#/components/schemas/BrowserCdpInputInsertTextCommandData" + - $ref: "#/components/schemas/BrowserCdpInputImeSetCompositionCommandData" + - $ref: "#/components/schemas/BrowserCdpInputDispatchTouchEventCommandData" + - $ref: "#/components/schemas/BrowserCdpInputDispatchDragEventCommandData" + - $ref: "#/components/schemas/BrowserCdpInputCancelDraggingCommandData" + - $ref: "#/components/schemas/BrowserCdpInputEmulateTouchFromMouseEventCommandData" + - $ref: "#/components/schemas/BrowserCdpInputSynthesizePinchGestureCommandData" + - $ref: "#/components/schemas/BrowserCdpInputSynthesizeScrollGestureCommandData" + - $ref: "#/components/schemas/BrowserCdpInputSynthesizeTapGestureCommandData" + - $ref: "#/components/schemas/BrowserCdpDomSetFileInputFilesCommandData" + - $ref: "#/components/schemas/BrowserCdpDomFocusCommandData" + - $ref: "#/components/schemas/BrowserCdpDomScrollIntoViewIfNeededCommandData" + - $ref: "#/components/schemas/BrowserCdpPageBringToFrontCommandData" + - $ref: "#/components/schemas/BrowserCdpPageCaptureScreenshotCommandData" + - $ref: "#/components/schemas/BrowserCdpPageCaptureSnapshotCommandData" + - $ref: "#/components/schemas/BrowserCdpPageHandleJavaScriptDialogCommandData" + - $ref: "#/components/schemas/BrowserCdpPageNavigateCommandData" + - $ref: "#/components/schemas/BrowserCdpPageNavigateToHistoryEntryCommandData" + - $ref: "#/components/schemas/BrowserCdpPageReloadCommandData" + - $ref: "#/components/schemas/BrowserCdpPagePrintToPdfCommandData" + - $ref: "#/components/schemas/BrowserCdpPageStartScreencastCommandData" + - $ref: "#/components/schemas/BrowserCdpPageStopScreencastCommandData" + - $ref: "#/components/schemas/BrowserCdpPageStopLoadingCommandData" + - $ref: "#/components/schemas/BrowserCdpPageCloseCommandData" + - $ref: "#/components/schemas/BrowserCdpPageSetWebLifecycleStateCommandData" + - $ref: "#/components/schemas/BrowserCdpTargetActivateTargetCommandData" + - $ref: "#/components/schemas/BrowserCdpTargetCloseTargetCommandData" + - $ref: "#/components/schemas/BrowserCdpTargetCreateTargetCommandData" + - $ref: "#/components/schemas/BrowserCdpTargetCreateBrowserContextCommandData" + - $ref: "#/components/schemas/BrowserCdpTargetDisposeBrowserContextCommandData" + - $ref: "#/components/schemas/BrowserCdpTargetOpenDevToolsCommandData" + - $ref: "#/components/schemas/BrowserCdpBrowserCancelDownloadCommandData" + - $ref: "#/components/schemas/BrowserCdpBrowserCloseCommandData" + - $ref: "#/components/schemas/BrowserCdpBrowserSetWindowBoundsCommandData" + - $ref: "#/components/schemas/BrowserCdpBrowserSetContentsSizeCommandData" + - $ref: "#/components/schemas/BrowserCdpAutofillTriggerCommandData" + discriminator: + propertyName: method + mapping: + Input.dispatchMouseEvent: "#/components/schemas/BrowserCdpInputDispatchMouseEventCommandData" + Input.dispatchKeyEvent: "#/components/schemas/BrowserCdpInputDispatchKeyEventCommandData" + Input.insertText: "#/components/schemas/BrowserCdpInputInsertTextCommandData" + Input.imeSetComposition: "#/components/schemas/BrowserCdpInputImeSetCompositionCommandData" + Input.dispatchTouchEvent: "#/components/schemas/BrowserCdpInputDispatchTouchEventCommandData" + Input.dispatchDragEvent: "#/components/schemas/BrowserCdpInputDispatchDragEventCommandData" + Input.cancelDragging: "#/components/schemas/BrowserCdpInputCancelDraggingCommandData" + Input.emulateTouchFromMouseEvent: "#/components/schemas/BrowserCdpInputEmulateTouchFromMouseEventCommandData" + Input.synthesizePinchGesture: "#/components/schemas/BrowserCdpInputSynthesizePinchGestureCommandData" + Input.synthesizeScrollGesture: "#/components/schemas/BrowserCdpInputSynthesizeScrollGestureCommandData" + Input.synthesizeTapGesture: "#/components/schemas/BrowserCdpInputSynthesizeTapGestureCommandData" + DOM.setFileInputFiles: "#/components/schemas/BrowserCdpDomSetFileInputFilesCommandData" + DOM.focus: "#/components/schemas/BrowserCdpDomFocusCommandData" + DOM.scrollIntoViewIfNeeded: "#/components/schemas/BrowserCdpDomScrollIntoViewIfNeededCommandData" + Page.bringToFront: "#/components/schemas/BrowserCdpPageBringToFrontCommandData" + Page.captureScreenshot: "#/components/schemas/BrowserCdpPageCaptureScreenshotCommandData" + Page.captureSnapshot: "#/components/schemas/BrowserCdpPageCaptureSnapshotCommandData" + Page.handleJavaScriptDialog: "#/components/schemas/BrowserCdpPageHandleJavaScriptDialogCommandData" + Page.navigate: "#/components/schemas/BrowserCdpPageNavigateCommandData" + Page.navigateToHistoryEntry: "#/components/schemas/BrowserCdpPageNavigateToHistoryEntryCommandData" + Page.reload: "#/components/schemas/BrowserCdpPageReloadCommandData" + Page.printToPDF: "#/components/schemas/BrowserCdpPagePrintToPdfCommandData" + Page.startScreencast: "#/components/schemas/BrowserCdpPageStartScreencastCommandData" + Page.stopScreencast: "#/components/schemas/BrowserCdpPageStopScreencastCommandData" + Page.stopLoading: "#/components/schemas/BrowserCdpPageStopLoadingCommandData" + Page.close: "#/components/schemas/BrowserCdpPageCloseCommandData" + Page.setWebLifecycleState: "#/components/schemas/BrowserCdpPageSetWebLifecycleStateCommandData" + Target.activateTarget: "#/components/schemas/BrowserCdpTargetActivateTargetCommandData" + Target.closeTarget: "#/components/schemas/BrowserCdpTargetCloseTargetCommandData" + Target.createTarget: "#/components/schemas/BrowserCdpTargetCreateTargetCommandData" + Target.createBrowserContext: "#/components/schemas/BrowserCdpTargetCreateBrowserContextCommandData" + Target.disposeBrowserContext: "#/components/schemas/BrowserCdpTargetDisposeBrowserContextCommandData" + Target.openDevTools: "#/components/schemas/BrowserCdpTargetOpenDevToolsCommandData" + Browser.cancelDownload: "#/components/schemas/BrowserCdpBrowserCancelDownloadCommandData" + Browser.close: "#/components/schemas/BrowserCdpBrowserCloseCommandData" + Browser.setWindowBounds: "#/components/schemas/BrowserCdpBrowserSetWindowBoundsCommandData" + Browser.setContentsSize: "#/components/schemas/BrowserCdpBrowserSetContentsSizeCommandData" + Autofill.trigger: "#/components/schemas/BrowserCdpAutofillTriggerCommandData" + BrowserCdpCommandEvent: + type: object + description: > + A browser-control command a client sent over the CDP WebSocket proxy: + input gestures, navigation, dialog handling, file selection and + screenshots. Configuration commands and the DOM/Runtime traffic a client + library issues on the caller's behalf are not reported. + + One event per browser-control command that reached the browser. The + command stream is not sampled, coalesced or reordered. An event is lost + only when the method is excluded by telemetry configuration, when + or when classification cannot keep up; those losses are counted in + `cdp_disconnect.telemetry_dropped`. + required: [ts, type, category, source, data] + properties: + ts: + type: integer + format: int64 + description: Event timestamp in Unix microseconds. + type: + type: string + const: cdp_command + category: + type: string + const: control + source: + $ref: "#/components/schemas/BrowserEventSource" + data: + $ref: "#/components/schemas/BrowserCdpCommandEventData" + truncated: + type: boolean + description: True if the data field was truncated due to size limits. + BrowserCdpConnectEvent: + type: object + description: An external client (e.g. customer SDK, Playwright, Puppeteer) connected to the CDP WebSocket proxy on this VM. + required: [ts, type, category, source] + properties: + ts: + type: integer + format: int64 + description: Event timestamp in Unix microseconds. + type: + type: string + const: cdp_connect + category: + type: string + const: connection + source: + $ref: "#/components/schemas/BrowserEventSource" + truncated: + type: boolean + description: True if the data field was truncated due to size limits. + BrowserCdpDisconnectEventData: + type: object + description: Per-disconnect payload for `cdp_disconnect` events. + additionalProperties: false + required: [duration_ms, message_count, reason] + properties: + duration_ms: + type: number + description: Wall-clock duration of the connection in milliseconds. + message_count: + type: integer + description: Number of CDP messages relayed across the connection in either direction. + telemetry_dropped: + type: integer + description: > + Number of forwarded client frames the classifier never saw, + because it could not keep up or because classification failed. + An upper bound on lost commands rather than a count: a saturated + queue turns away whatever arrives next, which may be library + traffic that would have produced no event. Telemetry loss only; + every command was still relayed to the browser. Always present on + events from images that report it; absent on events from an image + predating the field, which is not the same as zero. + reason: + type: string + description: > + Why the connection ended. `client_close`: the client initiated the close. + `upstream_changed`: Chromium restarted mid-session and the proxy tore down + so the client could reconnect against the new upstream. `upstream_error`: + upstream dial or message pump errored. `context_cancelled`: the request + context was cancelled (typically server shutdown). + enum: + - client_close + - upstream_changed + - upstream_error + - context_cancelled + BrowserCdpDisconnectEvent: + type: object + description: An external client disconnected from the CDP WebSocket proxy on this VM. Pair with the immediately preceding `cdp_connect` on the same stream. + required: [ts, type, category, source] + properties: + ts: + type: integer + format: int64 + description: Event timestamp in Unix microseconds. + type: + type: string + const: cdp_disconnect + category: + type: string + const: connection + source: + $ref: "#/components/schemas/BrowserEventSource" + data: + $ref: "#/components/schemas/BrowserCdpDisconnectEventData" + truncated: + type: boolean + description: True if the data field was truncated due to size limits. + BrowserLiveViewConnectEventData: + type: object + description: Per-session payload for `live_view_connect` events. + additionalProperties: false + required: [session_id] + properties: + session_id: + type: string + description: Live view session identifier. Stable across reconnects, so a transient network blip can emit two events with the same `session_id`. + BrowserLiveViewConnectEvent: + type: object + description: A live view client connected to the headful browser's WebRTC server (Neko). Headful only; not emitted for headless images. + required: [ts, type, category, source] + properties: + ts: + type: integer + format: int64 + description: Event timestamp in Unix microseconds. + type: + type: string + const: live_view_connect + category: + type: string + const: connection + source: + $ref: "#/components/schemas/BrowserEventSource" + data: + $ref: "#/components/schemas/BrowserLiveViewConnectEventData" + truncated: + type: boolean + description: True if the data field was truncated due to size limits. + BrowserLiveViewDisconnectEventData: + type: object + description: Per-session payload for `live_view_disconnect` events. + additionalProperties: false + required: [session_id, duration_ms] + properties: + session_id: + type: string + description: Live view session identifier; matches the corresponding `live_view_connect` event. + duration_ms: + type: number + description: Wall-clock duration of the connection in milliseconds. + BrowserLiveViewDisconnectEvent: + type: object + description: A live view client disconnected from the headful browser's WebRTC server (Neko). Pair with `live_view_connect` by `session_id`. + required: [ts, type, category, source] + properties: + ts: + type: integer + format: int64 + description: Event timestamp in Unix microseconds. + type: + type: string + const: live_view_disconnect + category: + type: string + const: connection + source: + $ref: "#/components/schemas/BrowserEventSource" + data: + $ref: "#/components/schemas/BrowserLiveViewDisconnectEventData" + truncated: + type: boolean + description: True if the data field was truncated due to size limits. + BrowserCaptchaSolveResultEventData: + type: object + description: Per-attempt payload for `captcha_solve_result` events. + additionalProperties: false + required: [captcha_type, status, duration_ms] + properties: + captcha_type: + type: string + description: > + Captcha vendor family. Producers normalize provider-specific task + names into this set: enterprise variants of recaptcha collapse into + their version bucket (v2 / v3), and anything not covered (e.g. + DataDome, MtCaptcha, plain OCR) is reported as `other`. + enum: + - hcaptcha + - recaptcha_v2 + - recaptcha_v3 + - turnstile + - geetest - other status: type: string @@ -3225,6 +4757,7 @@ components: - $ref: "#/components/schemas/BrowserMonitorInitFailedEvent" - $ref: "#/components/schemas/BrowserApiCallEvent" - $ref: "#/components/schemas/BrowserPlatformApiCallEvent" + - $ref: "#/components/schemas/BrowserCdpCommandEvent" - $ref: "#/components/schemas/BrowserCdpConnectEvent" - $ref: "#/components/schemas/BrowserCdpDisconnectEvent" - $ref: "#/components/schemas/BrowserLiveViewConnectEvent" @@ -3260,6 +4793,7 @@ components: monitor_init_failed: "#/components/schemas/BrowserMonitorInitFailedEvent" api_call: "#/components/schemas/BrowserApiCallEvent" platform_api_call: "#/components/schemas/BrowserPlatformApiCallEvent" + cdp_command: "#/components/schemas/BrowserCdpCommandEvent" cdp_connect: "#/components/schemas/BrowserCdpConnectEvent" cdp_disconnect: "#/components/schemas/BrowserCdpDisconnectEvent" live_view_connect: "#/components/schemas/BrowserLiveViewConnectEvent" @@ -3283,6 +4817,17 @@ components: Process-monotonic sequence number of the last published event. Does not reset across configuration changes. minimum: 0 + dropped_events: + type: integer + format: int64 + description: >- + Cumulative number of buffered events a consumer missed because it + fell behind the ring, summed across consumers and configuration + changes. A rising count means the stream is being produced faster + than it is being read; a steady one means nothing has been lost. + Always present on images that report it; absent on an image + predating the field, which is not the same as zero. + minimum: 0 applied_at: type: string format: date-time