har-replay
npx skills add https://github.com/lightdash/lightdash --skill har-replay
Agent 安装分布
Skill 文档
HAR Replay
Replay a HAR file as a mock Lightdash backend so the frontend renders with exact production data. No database, warehouse, or authentication needed.
The user must provide a path to a .har file. If not provided as $ARGUMENTS, ask for it.
Step 1: Analyze the HAR file
Run a Python script to extract key information from the HAR:
import json, sys, re
from collections import Counter
from urllib.parse import urlparse
har_path = "$HAR_FILE_PATH"
with open(har_path) as f:
har = json.load(f)
entries = har['log']['entries']
# Extract the page URL from the HAR pages section
page_path = None
pages = har['log'].get('pages', [])
for p in pages:
title = p.get('title', '')
parsed = urlparse(title)
if parsed.path and parsed.path != '/':
page_path = parsed.path
break
# Fallback: extract from referer headers
if not page_path:
for e in entries:
for h in e['request']['headers']:
if h['name'].lower() == 'referer':
parsed = urlparse(h['value'])
if parsed.path and parsed.path != '/':
page_path = parsed.path
break
if page_path:
break
# Find the origin (first API call)
origin = None
for e in entries:
url = urlparse(e['request']['url'])
if url.path.startswith('/api/'):
origin = f"{url.scheme}://{url.netloc}"
break
# Filter to origin entries only
api_entries = [e for e in entries if origin and origin in e['request']['url']]
# Find dashboard URL if present
dashboard_uuid = None
for e in api_entries:
path = urlparse(e['request']['url']).path
m = re.search(r'/dashboards/([0-9a-f-]{36})', path)
if m:
dashboard_uuid = m.group(1)
break
# Find project UUID
project_uuid = None
for e in api_entries:
path = urlparse(e['request']['url']).path
m = re.search(r'/projects/([0-9a-f-]{36})', path)
if m:
project_uuid = m.group(1)
break
# Count request types
methods = Counter()
api_paths = Counter()
has_base64 = False
post_endpoints_needing_body_match = []
for e in api_entries:
method = e['request']['method']
path = urlparse(e['request']['url']).path
methods[method] += 1
normalized = re.sub(r'[0-9a-f]{8}-[0-9a-f]{4}-[0-9a-f]{4}-[0-9a-f]{4}-[0-9a-f]{12}', '{uuid}', path)
api_paths[f'{method} {normalized}'] += 1
if e['response']['content'].get('encoding') == 'base64':
has_base64 = True
# Find POST endpoints with multiple entries (need body-based matching)
for key, count in api_paths.items():
if key.startswith('POST') and count > 1:
post_endpoints_needing_body_match.append((key, count))
print(f"Page path: {page_path}")
print(f"Origin: {origin}")
print(f"Total API entries: {len(api_entries)}")
print(f"Project UUID: {project_uuid}")
print(f"Dashboard UUID: {dashboard_uuid}")
print(f"Has base64 content: {has_base64}")
print(f"Methods: {dict(methods)}")
print(f"POST endpoints needing body match: {post_endpoints_needing_body_match}")
print()
print("API paths:")
for p, c in sorted(api_paths.items()):
print(f" {p}: {c}")
Report the findings to the user:
- Page path extracted from the HAR (this is the URL the user was viewing when the HAR was captured)
- Origin domain
- Number of API entries
- Notable POST endpoints that need body-based matching (e.g.,
dashboard-chartwith multiple chart tiles)
Step 2: Write a tailored replay server
Based on the analysis, write a replay server to scripts/har-replay-server.ts. The server must handle these concerns:
Core structure
import http from 'node:http';
import fs from 'node:fs';
import path from 'node:path';
Use only Node.js built-in modules. Run with npx tsx scripts/har-replay-server.ts <har-path>.
HAR parsing rules
- Filter by origin: Only index entries matching the detected origin domain
- Base64 decoding: Check
entry.response.content.encoding === 'base64'and decode withBuffer.from(text, 'base64').toString('utf-8') - Skip pending poll responses: For
GET /api/v2/projects/{uuid}/query/{uuid}endpoints, parse the response body and skip entries whereresults.status === 'pending'â only keep the finalreadyresponse - Normalize 304s to 200: Serve
304responses as200(they have full body in HAR) - Strip transport headers: Remove
:pseudo-headers,transfer-encoding,content-encoding,content-lengthfrom response headers
Request matching strategy
- GET requests: Match by exact
"METHOD /path?query". Fall back to path without query string. - POST
dashboard-chart: These all hit the same URL but carry differentchartUuidin the request body. Index bychartUuidfrom the HAR request body, and match incoming requests by parsing their body. - POST
dashboard-sql-chart: Same pattern but withsavedSqlUuid. If there’s only one, exact path match works. - Other POST requests (e.g.,
availableFilters): Usually unique paths, exact match works. - Any POST endpoint the analysis identified as having multiple entries to the same path: Must use body-based matching on a distinguishing field.
Server behavior
- Listen on port 3001
- Log every request with method, path, and whether it matched
- Return
{"status":"error","error":{"message":"HAR replay: no matching entry"}}for 404s - On startup, print the number of indexed responses and the dashboard URL to navigate to
Step 3: Start the replay server and frontend
- Kill any existing processes on port 3001
- Start the replay server in the background:
npx tsx scripts/har-replay-server.ts <har-path> - Start the Vite frontend dev server pointing at the replay server:
PORT=3001 pnpm -F frontend dev - Wait for both to be ready, then verify with:
curl -s http://localhost:3001/api/v1/health
Step 4: Provide the URL
Once both servers are confirmed running, tell the user the URL to open in their browser. Construct it from the page path extracted in Step 1:
http://localhost:<vite-port><page-path>
For example, if the HAR was captured on /projects/abc-123/dashboards/def-456/view, the URL would be http://localhost:3002/projects/abc-123/dashboards/def-456/view.
Note: Vite may pick a port other than 3000 since 3001 is in use. Check the Vite startup output for the actual port.
Step 5: Debug any rendering errors
If the user reports errors:
- Check the replay server logs for 404s (missing HAR entries)
- Check for response format issues (base64 encoding, unexpected MIME types)
- Fix the replay server script and restart
Notes
- The replay server is disposable â it’s tailored to the specific HAR file and can be deleted after use
- HAR files may contain session cookies and sensitive data â do not commit them
- The frontend will 404 on any navigation away from the captured pages
- To re-capture: Chrome DevTools > Network tab > right-click > “Save all as HAR with content”