demo-platform/extension/background.js
scot 9b09f14916 v0.1.0-alpha: interactive demo platform core
- Fastify API: demos/steps CRUD, content-addressed assets, scoped API keys
  (read/author/publish/admin, draft-only default per D4)
- Player: image + sandboxed DOM steps, hotspots, tooltips, keyboard nav,
  privacy-first beacons (no IP storage, viewer tokens only — R7)
- Editor: React SPA — demo list, drag-to-draw hotspots, annotations, publish
- MCP server: Streamable HTTP, scope-filtered tools, untrusted-data wrapping
  on viewer-supplied content (R8); platform never calls a model
- Capture extension (MV3): screenshot-flow recording, hotspots pre-placed
  from real clicks
- Docker: single app image + postgres, Traefik-ready (expose only)

E2E verified: capture->author->publish->play->beacon->lead->analytics + full
MCP tool surface with scope filtering.
2026-07-18 05:17:45 +00:00

25 lines
1.1 KiB
JavaScript

// Screenshot-flow capture: on each click in the recorded tab, grab a screenshot
// plus the click position, building image Steps with pre-placed hotspots.
let recording = { active: false, tabId: null, steps: [] };
chrome.runtime.onMessage.addListener((msg, sender, sendResponse) => {
if (msg.type === "start") {
recording = { active: true, tabId: msg.tabId, steps: [] };
chrome.scripting.executeScript({ target: { tabId: msg.tabId }, files: ["content.js"] });
sendResponse({ ok: true });
} else if (msg.type === "click" && recording.active && sender.tab?.id === recording.tabId) {
chrome.tabs.captureVisibleTab({ format: "png" }, (dataUrl) => {
recording.steps.push({ dataUrl, xPct: msg.xPct, yPct: msg.yPct });
sendResponse({ ok: true });
});
return true; // async
} else if (msg.type === "status") {
sendResponse({ active: recording.active, count: recording.steps.length });
} else if (msg.type === "stop") {
recording.active = false;
sendResponse({ steps: recording.steps });
} else if (msg.type === "discard") {
recording = { active: false, tabId: null, steps: [] };
sendResponse({ ok: true });
}
});