Skip to main content

devtools_traits/
lib.rs

1/* This Source Code Form is subject to the terms of the Mozilla Public
2 * License, v. 2.0. If a copy of the MPL was not distributed with this
3 * file, You can obtain one at https://mozilla.org/MPL/2.0/. */
4
5//! This module contains shared types and messages for use by devtools/script.
6//! The traits are here instead of in script so that the devtools crate can be
7//! modified independently of the rest of Servo.
8//!
9//! Since these types can be sent through the IPC channel and use non
10//! self-describing serializers, the `flatten`, `skip*`, `tag` and `untagged`
11//! serde annotations are not supported. Types like `serde_json::Value` aren't
12//! supported either. For JSON serialization it is preferred to use a wrapper
13//! struct in the devtools crate instead.
14
15#![crate_name = "devtools_traits"]
16#![crate_type = "rlib"]
17#![deny(unsafe_code)]
18
19use core::fmt;
20use std::collections::HashMap;
21use std::fmt::Display;
22use std::net::TcpStream;
23use std::str::FromStr;
24use std::time::{Duration, SystemTime, UNIX_EPOCH};
25
26pub use embedder_traits::ConsoleLogLevel;
27use embedder_traits::Theme;
28use http::{HeaderMap, Method};
29use malloc_size_of_derive::MallocSizeOf;
30use net_traits::http_status::HttpStatus;
31use net_traits::request::Destination;
32use net_traits::{DebugVec, TlsSecurityInfo};
33use profile_traits::mem::ReportsChan;
34use serde::de::{Error, Visitor};
35use serde::{Deserialize, Serialize};
36use servo_base::cross_process_instant::CrossProcessInstant;
37use servo_base::generic_channel::GenericSender;
38use servo_base::id::{BrowsingContextId, PipelineId, WebViewId};
39use servo_url::ServoUrl;
40use uuid::Uuid;
41
42// Information would be attached to NewGlobal to be received and show in devtools.
43// Extend these fields if we need more information.
44#[derive(Clone, Debug, Deserialize, MallocSizeOf, Serialize)]
45pub struct DevtoolsPageInfo {
46    pub title: String,
47    pub url: ServoUrl,
48    pub is_top_level_global: bool,
49    pub is_service_worker: bool,
50}
51
52#[derive(Clone, Debug, Deserialize, MallocSizeOf, Serialize)]
53pub struct CSSError {
54    pub filename: String,
55    pub line: u32,
56    pub column: u32,
57    pub msg: String,
58}
59
60/// Messages to instruct the devtools server to update its known actors/state
61/// according to changes in the browser.
62#[derive(Debug)]
63pub enum DevtoolsControlMsg {
64    /// Messages from threads in the chrome process (resource/constellation/devtools)
65    FromChrome(ChromeToDevtoolsControlMsg),
66    /// Messages from script threads
67    FromScript(ScriptToDevtoolsControlMsg),
68    /// Sent when a devtools client thread terminates.
69    ClientExited,
70}
71
72/// Events that the devtools server must act upon.
73// FIXME: https://github.com/servo/servo/issues/34591
74#[expect(clippy::large_enum_variant)]
75#[derive(Debug)]
76pub enum ChromeToDevtoolsControlMsg {
77    /// A new client has connected to the server.
78    AddClient(TcpStream),
79    /// The browser is shutting down.
80    ServerExitMsg,
81    /// A network event occurred (request, reply, etc.). The actor with the
82    /// provided name should be notified.
83    NetworkEvent(String, NetworkEvent),
84    /// Perform a memory report.
85    CollectMemoryReport(ReportsChan),
86}
87
88/// The state of a page navigation.
89#[derive(Debug, Deserialize, Serialize)]
90pub enum NavigationState {
91    /// A browsing context is about to navigate to a given URL.
92    Start(ServoUrl),
93    /// A browsing context has completed navigating to the provided pipeline.
94    Stop(PipelineId, DevtoolsPageInfo),
95}
96
97#[derive(Debug, Deserialize, Serialize)]
98/// Events that the devtools server must act upon.
99pub enum ScriptToDevtoolsControlMsg {
100    /// A new global object was created, associated with a particular pipeline.
101    /// The means of communicating directly with it are provided.
102    NewGlobal(
103        (BrowsingContextId, PipelineId, Option<WorkerId>, WebViewId),
104        GenericSender<DevtoolScriptControlMsg>,
105        DevtoolsPageInfo,
106    ),
107    /// The given browsing context is performing a navigation.
108    Navigate(BrowsingContextId, NavigationState),
109    /// A particular page has invoked the console API.
110    ConsoleAPI(PipelineId, ConsoleMessage, Option<WorkerId>),
111    /// Request to clear the console for a given pipeline.
112    ClearConsole(PipelineId, Option<WorkerId>),
113    /// An animation frame with the given timestamp was processed in a script thread.
114    /// The actor with the provided name should be notified.
115    FramerateTick(String, f64),
116
117    /// Report a CSS parse error for the given pipeline
118    ReportCSSError(PipelineId, CSSError),
119
120    /// Report a page error for the given pipeline
121    ReportPageError(PipelineId, PageError),
122
123    /// Report a page title change
124    TitleChanged(PipelineId, String),
125
126    /// Get source information from script
127    CreateSourceActor(
128        GenericSender<DevtoolScriptControlMsg>,
129        PipelineId,
130        SourceInfo,
131    ),
132
133    UpdateSourceContent(PipelineId, String),
134
135    DomMutation(PipelineId, DomMutation),
136
137    /// The debugger is paused, sending frame information.
138    DebuggerPause(PipelineId, FrameOffset, PauseReason),
139
140    /// Get frame information from script
141    CreateFrameActor(GenericSender<String>, PipelineId, FrameInfo),
142
143    /// Get object information from script
144    CreateObjectActor(GenericSender<String>, DebuggerValue),
145
146    /// Get environment information from script
147    CreateEnvironmentActor(
148        GenericSender<String>,
149        EnvironmentInfo,
150        Option<String>,
151        Option<String>,
152    ),
153}
154
155#[derive(Clone, Debug, Deserialize, MallocSizeOf, Serialize)]
156pub enum DomMutation {
157    AttributeModified {
158        node: String,
159        attribute_name: String,
160        new_value: Option<String>,
161    },
162}
163
164#[derive(Clone, Debug, Deserialize, MallocSizeOf, Serialize)]
165#[serde(rename_all = "camelCase")]
166pub struct ObjectPreview {
167    pub kind: String,
168    pub size: Option<u32>,
169    pub entries: Option<Vec<(DebuggerValue, DebuggerValue)>>,
170    pub own_properties: Option<Vec<PropertyDescriptor>>,
171    pub own_properties_length: Option<u32>,
172    pub function: Option<FunctionPreview>,
173    pub array_length: Option<u32>,
174    pub items: Option<Vec<DebuggerValue>>,
175}
176
177#[derive(Clone, Debug, Deserialize, MallocSizeOf, Serialize)]
178#[serde(rename_all = "camelCase")]
179pub struct FunctionPreview {
180    pub name: Option<String>,
181    pub display_name: Option<String>,
182    pub parameter_names: Vec<String>,
183    pub is_async: Option<bool>,
184    pub is_generator: Option<bool>,
185}
186
187struct DebuggerNumberVisitor;
188
189impl Visitor<'_> for DebuggerNumberVisitor {
190    type Value = f64;
191
192    fn expecting(&self, formatter: &mut fmt::Formatter) -> fmt::Result {
193        formatter.write_str("a debugger value number")
194    }
195
196    fn visit_f64<E>(self, value: f64) -> Result<Self::Value, E> {
197        Ok(value)
198    }
199
200    fn visit_i64<E>(self, value: i64) -> Result<Self::Value, E> {
201        Ok(value as f64)
202    }
203
204    fn visit_u64<E>(self, value: u64) -> Result<Self::Value, E> {
205        Ok(value as f64)
206    }
207
208    fn visit_str<E>(self, value: &str) -> Result<Self::Value, E>
209    where
210        E: Error,
211    {
212        value.parse().map_err(E::custom)
213    }
214}
215
216fn deserialize_debugger_number<'de, D>(deserializer: D) -> Result<f64, D::Error>
217where
218    D: serde::Deserializer<'de>,
219{
220    // `DebuggerValue` is also sent over Servo IPC, not only through debugger.js.
221    if !deserializer.is_human_readable() {
222        return f64::deserialize(deserializer);
223    }
224
225    deserializer.deserialize_any(DebuggerNumberVisitor)
226}
227
228#[derive(Clone, Debug, Deserialize, MallocSizeOf, Serialize)]
229#[serde(rename_all_fields = "camelCase")]
230pub enum DebuggerValue {
231    VoidValue,
232    NullValue(bool),
233    BooleanValue(bool),
234    NumberValue(#[serde(deserialize_with = "deserialize_debugger_number")] f64),
235    StringValue(String),
236    ObjectValue {
237        actor: Option<String>,
238        class: String,
239        own_property_length: Option<u32>,
240        preview: Option<Box<ObjectPreview>>,
241    },
242}
243
244/// <https://searchfox.org/mozilla-central/source/devtools/server/actors/object/property-iterator.js#51>
245#[derive(Clone, Debug, Deserialize, MallocSizeOf, Serialize)]
246#[serde(rename_all = "camelCase")]
247pub struct PropertyDescriptor {
248    pub name: String,
249    pub value: DebuggerValue,
250    pub configurable: bool,
251    pub enumerable: bool,
252    pub writable: bool,
253    pub is_accessor: bool,
254}
255
256#[derive(Debug, Deserialize, Serialize)]
257#[serde(rename_all = "camelCase")]
258pub struct EvaluateJSReply {
259    pub value: DebuggerValue,
260    pub exception_message: Option<String>,
261    pub has_exception: bool,
262}
263
264#[derive(Debug, Deserialize, MallocSizeOf, Serialize)]
265pub struct AttrInfo {
266    pub namespace: String,
267    pub name: String,
268    pub value: String,
269}
270
271#[derive(Debug, Deserialize, MallocSizeOf, Serialize)]
272#[serde(rename_all = "camelCase")]
273pub struct NodeInfo {
274    pub unique_id: String,
275    pub host: Option<String>,
276    #[serde(rename = "baseURI")]
277    pub base_uri: String,
278    pub parent: String,
279    pub node_type: u16,
280    pub node_name: String,
281    pub node_value: Option<String>,
282    pub num_children: usize,
283    pub attrs: Vec<AttrInfo>,
284    pub is_top_level_document: bool,
285    pub shadow_root_mode: Option<ShadowRootMode>,
286    pub is_shadow_host: bool,
287    pub display: Option<String>,
288    /// Whether this node is currently displayed.
289    ///
290    /// For example, the node might have `display: none`.
291    pub is_displayed: bool,
292
293    /// The `DOCTYPE` name if this is a `DocumentType` node, `None` otherwise
294    pub doctype_name: Option<String>,
295
296    /// The `DOCTYPE` public identifier if this is a `DocumentType` node , `None` otherwise
297    pub doctype_public_identifier: Option<String>,
298
299    /// The `DOCTYPE` system identifier if this is a `DocumentType` node, `None` otherwise
300    pub doctype_system_identifier: Option<String>,
301
302    pub has_event_listeners: bool,
303}
304
305pub struct StartedTimelineMarker {
306    name: String,
307    start_time: CrossProcessInstant,
308    start_stack: Option<Vec<()>>,
309}
310
311#[derive(Debug, Deserialize, Serialize)]
312pub struct TimelineMarker {
313    pub name: String,
314    pub start_time: CrossProcessInstant,
315    pub start_stack: Option<Vec<()>>,
316    pub end_time: CrossProcessInstant,
317    pub end_stack: Option<Vec<()>>,
318}
319
320#[derive(Clone, Debug, Deserialize, Eq, Hash, MallocSizeOf, PartialEq, Serialize)]
321pub enum TimelineMarkerType {
322    Reflow,
323    DOMEvent,
324}
325
326#[derive(Debug, Deserialize, Serialize)]
327#[serde(rename_all = "camelCase")]
328pub struct NodeStyle {
329    pub name: String,
330    pub value: String,
331    pub priority: String,
332}
333
334#[derive(Clone, Debug, Deserialize, Serialize, MallocSizeOf, PartialEq, Eq, Hash)]
335#[serde(tag = "type", rename_all = "camelCase")]
336pub enum AncestorData {
337    Layer {
338        actor_id: Option<String>,
339        value: Option<String>,
340    },
341}
342
343#[derive(Clone, Debug, Deserialize, Serialize, MallocSizeOf, PartialEq, Eq, Hash)]
344#[serde(rename_all = "camelCase")]
345pub struct MatchedRule {
346    pub selector: String,
347    pub stylesheet_index: usize,
348    pub block_id: usize,
349    pub ancestor_data: Vec<AncestorData>,
350}
351
352/// The properties of a DOM node as computed by layout.
353#[derive(Debug, Deserialize, Serialize)]
354#[serde(rename_all = "kebab-case")]
355pub struct ComputedNodeLayout {
356    pub display: String,
357    pub position: String,
358    pub z_index: String,
359    pub box_sizing: String,
360
361    pub margin_top: String,
362    pub margin_right: String,
363    pub margin_bottom: String,
364    pub margin_left: String,
365
366    pub border_top_width: String,
367    pub border_right_width: String,
368    pub border_bottom_width: String,
369    pub border_left_width: String,
370
371    pub padding_top: String,
372    pub padding_right: String,
373    pub padding_bottom: String,
374    pub padding_left: String,
375
376    pub width: f32,
377    pub height: f32,
378}
379
380#[derive(Debug, Default, Deserialize, Serialize)]
381pub struct AutoMargins {
382    pub top: bool,
383    pub right: bool,
384    pub bottom: bool,
385    pub left: bool,
386}
387
388#[derive(Debug, Deserialize, Serialize)]
389pub enum GetHTMLType {
390    OuterHTML,
391    InnerHTML,
392}
393
394/// Messages to process in a particular script thread, as instructed by a devtools client.
395/// TODO: better error handling, e.g. if pipeline id lookup fails?
396#[derive(Debug, Deserialize, Serialize)]
397pub enum DevtoolScriptControlMsg {
398    /// Retrieve the details of the root node (ie. the document) for the given pipeline.
399    GetRootNode(PipelineId, GenericSender<Option<NodeInfo>>),
400    /// Retrieve the details of the document element for the given pipeline.
401    GetDocumentElement(PipelineId, GenericSender<Option<NodeInfo>>),
402    /// Retrieve the details of the child nodes of the given node in the given pipeline.
403    GetChildren(PipelineId, String, GenericSender<Option<Vec<NodeInfo>>>),
404    /// Retrieve the CSS style properties defined in the attribute tag for the given node.
405    GetAttributeStyle(PipelineId, String, GenericSender<Option<Vec<NodeStyle>>>),
406    /// Retrieve the CSS style properties defined in an stylesheet for the given selector.
407    GetStylesheetStyle(
408        PipelineId,
409        String,
410        MatchedRule,
411        GenericSender<Option<Vec<NodeStyle>>>,
412    ),
413    /// Retrieve the list of stylesheets for the given pipeline and node.
414    GetStyleSheets(PipelineId, GenericSender<Vec<StyleSheetInfo>>),
415    /// Retrieve the actual CSS text for the stylesheet with the given node ID and index.
416    GetStyleSheetText(PipelineId, i32, GenericSender<Option<String>>),
417    /// Retrieves the CSS selectors for the given node. A selector is comprised of the text
418    /// of the selector and the id of the stylesheet that contains it.
419    GetSelectors(PipelineId, String, GenericSender<Option<Vec<MatchedRule>>>),
420    /// Retrieve the computed CSS style properties for the given node.
421    GetComputedStyle(PipelineId, String, GenericSender<Option<Vec<NodeStyle>>>),
422    /// Get information about event listeners on a node.
423    GetEventListenerInfo(PipelineId, String, GenericSender<Vec<EventListenerInfo>>),
424    /// Retrieve the computed layout properties of the given node in the given pipeline.
425    GetLayout(
426        PipelineId,
427        String,
428        GenericSender<Option<(ComputedNodeLayout, AutoMargins)>>,
429    ),
430    /// Get a unique XPath selector for the node.
431    GetXPath(PipelineId, String, GenericSender<String>),
432    /// Get inner/outer HTML on a node.
433    GetInnerOrOuterHTML(
434        PipelineId,
435        String,
436        GenericSender<Option<String>>,
437        GetHTMLType,
438    ),
439    /// Update a given node's attributes with a list of modifications.
440    ModifyAttribute(PipelineId, String, Vec<AttrModification>),
441    /// Update a given node's style rules with a list of modifications.
442    ModifyRule(PipelineId, String, Vec<RuleModification>),
443    /// Request live console messages for a given pipeline (true if desired, false otherwise).
444    WantsLiveNotifications(PipelineId, bool),
445    /// Request live notifications for a given set of timeline events for a given pipeline.
446    SetTimelineMarkers(
447        PipelineId,
448        Vec<TimelineMarkerType>,
449        GenericSender<Option<TimelineMarker>>,
450    ),
451    /// Withdraw request for live timeline notifications for a given pipeline.
452    DropTimelineMarkers(PipelineId, Vec<TimelineMarkerType>),
453    /// Request a callback directed at the given actor name from the next animation frame
454    /// executed in the given pipeline.
455    RequestAnimationFrame(PipelineId, String),
456    /// Direct the WebView containing the given pipeline to load a new URL,
457    /// as if it was typed by the user.
458    NavigateTo(PipelineId, ServoUrl),
459    /// Direct the WebView containing the given pipeline to traverse history backward
460    /// up to one step.
461    GoBack(PipelineId),
462    /// Direct the WebView containing the given pipeline to traverse history forward
463    /// up to one step.
464    GoForward(PipelineId),
465    /// Direct the given pipeline to reload the current page.
466    Reload(PipelineId),
467    /// Gets the list of all allowed CSS rules and possible values.
468    GetCssDatabase(GenericSender<HashMap<String, CssDatabaseProperty>>),
469    /// Simulates a light or dark color scheme for the given pipeline
470    SimulateColorScheme(PipelineId, Theme),
471    /// Highlight the given DOM node
472    HighlightDomNode(PipelineId, Option<String>),
473
474    Eval(
475        String,
476        PipelineId,
477        Option<String>,
478        GenericSender<EvaluateJSReply>,
479    ),
480    GetPossibleBreakpoints(u32, GenericSender<Vec<RecommendedBreakpointLocation>>),
481    SetBreakpoint(u32, u32, u32),
482    ClearBreakpoint(u32, u32, u32),
483    Interrupt,
484    Resume(Option<String>, Option<String>),
485    ListFrames(PipelineId, u32, u32, GenericSender<Vec<String>>),
486    GetEnvironment(String, GenericSender<String>),
487    Blackbox(u32, BlackboxCoverage),
488    Unblackbox(u32, BlackboxCoverage),
489}
490
491#[derive(Debug, Deserialize, Serialize)]
492pub enum BlackboxCoverage {
493    Full,
494    Partial((u32, u32), (u32, u32)),
495}
496
497#[derive(Clone, Debug, Deserialize, Serialize, MallocSizeOf)]
498#[serde(rename_all = "camelCase")]
499pub struct AttrModification {
500    pub attribute_name: String,
501    pub new_value: Option<String>,
502}
503
504#[derive(Clone, Debug, Deserialize, Serialize)]
505#[serde(rename_all = "camelCase")]
506pub struct RuleModification {
507    #[serde(rename = "type")]
508    pub type_: String,
509    pub index: u32,
510    pub name: String,
511    pub value: String,
512    pub priority: String,
513}
514
515#[derive(Clone, Debug, Deserialize, Serialize, MallocSizeOf)]
516#[serde(rename_all = "camelCase")]
517pub struct StackFrame {
518    pub filename: String,
519    pub function_name: String,
520    pub column_number: u32,
521    pub line_number: u32,
522    // Not implemented in Servo
523    // source_id
524}
525
526pub fn get_time_stamp() -> u64 {
527    SystemTime::now()
528        .duration_since(UNIX_EPOCH)
529        .unwrap_or_default()
530        .as_millis() as u64
531}
532
533#[derive(Clone, Debug, Deserialize, Serialize, MallocSizeOf)]
534#[serde(rename_all = "camelCase")]
535pub struct ConsoleMessageFields {
536    pub level: ConsoleLogLevel,
537    pub filename: String,
538    pub line_number: u32,
539    pub column_number: u32,
540    pub time_stamp: u64,
541}
542
543#[derive(Clone, Debug, Deserialize, Serialize)]
544pub struct ConsoleMessage {
545    pub fields: ConsoleMessageFields,
546    pub arguments: Vec<DebuggerValue>,
547    pub stacktrace: Option<Vec<StackFrame>>,
548}
549
550#[derive(Clone, Debug, Deserialize, Serialize, MallocSizeOf)]
551#[serde(rename_all = "camelCase")]
552pub struct PageError {
553    pub error_message: String,
554    pub source_name: String,
555    pub line_number: u32,
556    pub column_number: u32,
557    pub time_stamp: u64,
558}
559
560#[derive(Debug, PartialEq, MallocSizeOf)]
561pub struct HttpRequest {
562    pub url: ServoUrl,
563    pub method: Method,
564    pub headers: HeaderMap,
565    pub body: Option<DebugVec>,
566    pub pipeline_id: PipelineId,
567    pub started_date_time: SystemTime,
568    pub time_stamp: i64,
569    pub connect_time: Duration,
570    pub send_time: Duration,
571    pub destination: Destination,
572    pub is_xhr: bool,
573    pub browsing_context_id: BrowsingContextId,
574}
575
576#[derive(Debug, PartialEq, MallocSizeOf)]
577pub struct HttpResponse {
578    #[ignore_malloc_size_of = "Http type"]
579    pub headers: Option<HeaderMap>,
580    pub status: HttpStatus,
581    pub body: Option<DebugVec>,
582    pub from_cache: bool,
583    pub pipeline_id: PipelineId,
584    pub browsing_context_id: BrowsingContextId,
585}
586
587#[derive(Debug, PartialEq)]
588pub struct SecurityInfoUpdate {
589    pub browsing_context_id: BrowsingContextId,
590    pub security_info: Option<TlsSecurityInfo>,
591}
592
593#[derive(Debug)]
594pub enum NetworkEvent {
595    HttpRequest(HttpRequest),
596    HttpRequestUpdate(HttpRequest),
597    HttpResponse(HttpResponse),
598    SecurityInfo(SecurityInfoUpdate),
599}
600
601impl NetworkEvent {
602    pub fn forward_to_devtools(&self) -> bool {
603        match self {
604            NetworkEvent::HttpRequest(http_request) => http_request.url.scheme() != "data",
605            NetworkEvent::HttpRequestUpdate(_) => true,
606            NetworkEvent::HttpResponse(_) => true,
607            NetworkEvent::SecurityInfo(_) => true,
608        }
609    }
610}
611
612impl TimelineMarker {
613    pub fn start(name: String) -> StartedTimelineMarker {
614        StartedTimelineMarker {
615            name,
616            start_time: CrossProcessInstant::now(),
617            start_stack: None,
618        }
619    }
620}
621
622impl StartedTimelineMarker {
623    pub fn end(self) -> TimelineMarker {
624        TimelineMarker {
625            name: self.name,
626            start_time: self.start_time,
627            start_stack: self.start_stack,
628            end_time: CrossProcessInstant::now(),
629            end_stack: None,
630        }
631    }
632}
633#[derive(Clone, Copy, Debug, Deserialize, Eq, Hash, MallocSizeOf, PartialEq, Serialize)]
634pub struct WorkerId(pub Uuid);
635impl Display for WorkerId {
636    fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
637        write!(f, "{}", self.0)
638    }
639}
640impl FromStr for WorkerId {
641    type Err = uuid::Error;
642
643    fn from_str(s: &str) -> Result<Self, Self::Err> {
644        Ok(Self(s.parse()?))
645    }
646}
647
648#[derive(Debug, Deserialize, Serialize, MallocSizeOf)]
649#[serde(rename_all = "camelCase")]
650pub struct CssDatabaseProperty {
651    pub is_inherited: bool,
652    pub values: Vec<String>,
653    pub supports: Vec<String>,
654    pub subproperties: Vec<String>,
655}
656
657#[derive(Debug, Deserialize, MallocSizeOf, Serialize)]
658pub enum ShadowRootMode {
659    Open,
660    Closed,
661}
662
663impl fmt::Display for ShadowRootMode {
664    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
665        match self {
666            Self::Open => write!(f, "open"),
667            Self::Closed => write!(f, "close"),
668        }
669    }
670}
671
672#[derive(Debug, Deserialize, Serialize)]
673pub struct SourceInfo {
674    pub url: ServoUrl,
675    pub introduction_type: String,
676    pub inline: bool,
677    pub worker_id: Option<WorkerId>,
678    pub content: Option<String>,
679    pub content_type: Option<String>,
680    pub spidermonkey_id: u32,
681}
682
683#[derive(Clone, Debug, Deserialize, Serialize)]
684#[serde(rename_all = "camelCase")]
685pub struct RecommendedBreakpointLocation {
686    pub script_id: u32,
687    pub offset: u32,
688    pub line_number: u32,
689    pub column_number: u32,
690    pub is_step_start: bool,
691}
692
693#[derive(Clone, Debug, Deserialize, MallocSizeOf, Serialize)]
694pub struct FrameInfo {
695    pub display_name: Option<String>,
696    pub on_stack: bool,
697    pub oldest: bool,
698    pub this_value: DebuggerValue,
699    pub terminated: bool,
700    pub type_: String,
701    pub url: String,
702}
703
704#[derive(Clone, Debug, Default, Deserialize, MallocSizeOf, Serialize)]
705pub struct EnvironmentInfo {
706    pub type_: Option<String>,
707    pub scope_kind: Option<String>,
708    pub function_display_name: Option<String>,
709    pub object: Option<DebuggerValue>,
710    pub binding_variables: Vec<PropertyDescriptor>,
711}
712
713#[derive(Clone, Debug, Deserialize, Serialize)]
714pub struct StyleSheetInfo {
715    pub href: Option<String>,
716    pub disabled: bool,
717    pub title: String,
718    pub style_sheet_index: i32,
719    pub system: bool,
720    pub rule_count: u32,
721}
722
723#[derive(Clone, Debug, Deserialize, Serialize)]
724pub struct EventListenerInfo {
725    pub event_type: String,
726    pub capturing: bool,
727}
728
729#[derive(Debug, Deserialize, Serialize)]
730#[serde(rename_all = "camelCase")]
731pub struct PauseReason {
732    #[serde(rename = "type")]
733    pub type_: String,
734    pub on_next: Option<bool>,
735}
736
737#[derive(Debug, Deserialize, Serialize)]
738pub struct FrameOffset {
739    pub actor: String,
740    pub column: u32,
741    pub line: u32,
742}