Reference
Log Entry Structure
Every captured event, regardless of transport type, is stored as a UnifiedLogEntry:
typescript
interface UnifiedLogEntry {
id: string // Unique UUID-like identifier
type: 'http' | 'websocket' | 'sse'
// Timing
startTime: number // Unix timestamp at request start (ms)
endTime: number | null // Unix timestamp at completion
duration: number | null // endTime - startTime, milliseconds
// Request identity
url: string
method: string // HTTP verb, or WebSocket/SSE event type
// HTTP-specific (null for WebSocket / SSE)
http: {
status: number | null // e.g. 200, 404, 500
statusText: string | null // e.g. "OK", "Not Found"
protocol: string | null // e.g. "HTTP/1.1", "HTTP/2"
} | null
// WebSocket-specific (null for HTTP / SSE)
websocket: {
readyState: number // 0 CONNECTING | 1 OPEN | 2 CLOSING | 3 CLOSED
eventType: 'connection' | 'open' | 'message' | 'error' | 'close'
direction: 'incoming' | 'outgoing' | null
code: number | null // Close code (1000 = normal, 1001 = going away, …)
reason: string | null
wasClean: boolean | null
} | null
// SSE-specific (null for HTTP / WebSocket)
sse: {
readyState: number // 0 CONNECTING | 1 OPEN | 2 CLOSED
eventType: string | null // Named event type, or null for default "message"
lastEventId: string | null
} | null
// Headers
requestHeaders: Record<string, string> // Sanitized request headers
responseHeaders: Record<string, string> // Sanitized response headers
// Bodies
request: {
body: any | null // Parsed body (object, string, FormData, etc.)
bodyRaw: string | null // Raw serialized body string
bodySize: number | null // Size in bytes
bodyType: string | null // MIME type derived from Content-Type
}
response: {
body: any | null
bodyRaw: string | null
bodySize: number | null
bodyType: string | null
}
// Errors
error: {
occurred: boolean
message: string | null
name: string | null // e.g. "TypeError", "NetworkError"
stack: string | null
}
// Metadata
metadata: {
clientType: 'fetch' | 'xhr' | 'websocket' | 'eventsource'
redirected: boolean
retryCount: number
timestamp: string // ISO 8601 timestamp at log creation
}
// Vue Router route path at the moment the request was initiated.
// Populated only when `enrichWithRoute: true` is set in plugin options.
route?: string
}Statistics
getStats() returns a NetworkStats object:
typescript
interface NetworkStats {
totalRequests: number
totalErrors: number
averageDuration: number // Mean response time in ms
totalDataSent: number // Total request body bytes
totalDataReceived: number // Total response body bytes
requestsByMethod: Record<string, number> // { GET: 42, POST: 17, … }
requestsByStatus: Record<string, number> // { '200': 55, '404': 3, '500': 1, … }
slowestRequests: UnifiedLogEntry[] // Top 10 by duration (descending)
largestRequests: UnifiedLogEntry[] // Top 10 by total body size (descending)
sseEventCount: number // Total SSE events captured
}getStatsSummary() returns the same data as a formatted multi-line string, useful for logging to the console.
Architecture
vue-network-dashboard/
├── src/
│ ├── core/
│ │ ├── NetworkDashboard.ts # Orchestrator — interceptors, mock registry, breakpoints, lifecycle
│ │ ├── formatters.ts # HTTPFormatter, WebSocketFormatter, SSEFormatter
│ │ ├── openApiParser.ts # Parses OpenAPI 3.x / Swagger 2.x JSON → MockRule[]
│ │ └── types.ts # UnifiedLogEntry, MockRule, BreakpointRule, NetworkStats, …
│ ├── interceptors/
│ │ ├── fetchInterceptor.ts # Patches window.fetch (pending state + mock support)
│ │ ├── xhrInterceptor.ts # Patches XMLHttpRequest prototype (WeakMap + mock support)
│ │ ├── websocketInterceptor.ts # Replaces window.WebSocket
│ │ └── sseInterceptor.ts # Replaces window.EventSource
│ ├── store/
│ │ └── logStore.ts # Vue reactive storage — addLog, updateLog, HAR/JSON/CSV export
│ ├── plugins/
│ │ └── vuePlugin.ts # Vue 3 plugin + useNetworkDashboard composable + mock API
│ ├── adapters/
│ │ ├── sentry.ts # createSentryAdapter — breadcrumbs + Sentry events
│ │ └── opentelemetry.ts # createOpenTelemetryAdapter — OTel spans per request
│ ├── utils/
│ │ ├── sanitizer.ts # Header redaction, field removal, PII masking
│ │ ├── helpers.ts # generateId, formatBytes, getContentType
│ │ └── sizeCalculator.ts # calculateSize, getDataType, safeStringify
│ ├── view/
│ │ ├── components/
│ │ │ ├── NetworkDebugger.vue # Main draggable panel (logs / stats / timeline / mocks tabs)
│ │ │ ├── LogEntry.vue # Single row — pending state, mocked badge, diff select
│ │ │ ├── FilterBar.vue # Type tabs, URL, body, method, status, duration filters
│ │ │ ├── StatsPanel.vue # Live statistics with distribution bars
│ │ │ ├── MockPanel.vue # Mock rule editor — groups, conditions, transform, OpenAPI import
│ │ │ ├── BreakpointPanel.vue # Breakpoint rules + paused-request cards with editable fields
│ │ │ ├── ReplayModal.vue # Edit & Replay modal — URL, method, headers, body
│ │ │ ├── SessionComparePanel.vue # HAR diff view — two sessions side by side
│ │ │ ├── NetworkTimeline.vue # Waterfall bar chart
│ │ │ └── DiffPanel.vue # LCS-based header and body diff between two log entries
│ │ ├── composables/
│ │ │ ├── useLogFilter.ts # Reactive filter state (url, body, method, status, …)
│ │ │ └── useHotkey.ts # Keyboard shortcut binding helper
│ │ └── styles/
│ │ ├── variables.scss # Design tokens (colours, spacing, typography)
│ │ └── debugger.scss # All component styles
│ ├── devtools.ts # setupDevtools() — Vue DevTools inspector + timeline layer
│ ├── nuxt.ts # Nuxt 3 module (defineNuxtModule)
│ └── runtime/
│ └── nuxt-plugin.ts # Nuxt client plugin — registered automatically by nuxt.ts
└── demo/ # Demo app (Vite + Vue 3)The plugin has no runtime dependencies besides Vue 3. It relies only on standard browser APIs (window.fetch, XMLHttpRequest, WebSocket, EventSource).
License
MIT