Skip to content

Commit 155a07c

Browse files
committed
Send raw DOM element data for server-side processing
1 parent 9746914 commit 155a07c

File tree

5 files changed

+78
-9
lines changed

5 files changed

+78
-9
lines changed

.changeset/phase-2-raw-element.md

Lines changed: 11 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,11 @@
1+
---
2+
'@mcp-pointer/chrome-extension': patch
3+
---
4+
5+
Send raw DOM element data for server-side processing
6+
7+
- Add extractRawPointedDOMElement() to collect minimal raw DOM data
8+
- Send outerHTML, boundingClientRect, url, timestamp, computedStyles
9+
- Include React Fiber when present on element
10+
- Use DOM_ELEMENT_POINTED message type
11+
- Move data processing responsibility to server

packages/chrome-extension/src/background.ts

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -37,7 +37,7 @@ ConfigStorageService.onChange((newConfig: ExtensionConfig) => {
3737
// Listen for messages from content script
3838
chrome.runtime.onMessage
3939
.addListener((request: any, _sender: any, sendResponse: (response: any) => void) => {
40-
if (request.type === 'ELEMENT_SELECTED' && request.data) {
40+
if (request.type === 'DOM_ELEMENT_POINTED' && request.data) {
4141
// Send element with current port and status callback
4242
elementSender.sendElement(
4343
request.data,

packages/chrome-extension/src/services/element-pointer-service.ts

Lines changed: 4 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -1,9 +1,9 @@
1-
import { TargetedElement } from '@mcp-pointer/shared/types';
1+
import { RawPointedDOMElement } from '@mcp-pointer/shared/types';
22
import logger from '../utils/logger';
33
import TriggerMouseService from './trigger-mouse-service';
44
import TriggerKeyService from './trigger-key-service';
55
import OverlayManagerService, { OverlayType } from './overlay-manager-service';
6-
import { adaptTargetToElement } from '../utils/element';
6+
import { extractRawPointedDOMElement } from '../utils/element';
77

88
const POINTING_CLASS = 'mcp-pointer--is-pointing';
99

@@ -111,8 +111,8 @@ export default class ElementPointerService {
111111

112112
// Send directly to background script (isolated world has chrome.runtime access)
113113
chrome.runtime.sendMessage({
114-
type: 'ELEMENT_SELECTED',
115-
data: adaptTargetToElement(target) as TargetedElement,
114+
type: 'DOM_ELEMENT_POINTED',
115+
data: extractRawPointedDOMElement(target) as RawPointedDOMElement,
116116
}, (response: any) => {
117117
if (chrome.runtime.lastError) {
118118
logger.error('❌ Error sending to background:', chrome.runtime.lastError);

packages/chrome-extension/src/services/element-sender-service.ts

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,6 @@
11
import ReconnectingWebSocket from 'reconnecting-websocket';
22
import {
3-
TargetedElement, PointerMessage, PointerMessageType, ConnectionStatus,
3+
RawPointedDOMElement, PointerMessage, PointerMessageType, ConnectionStatus,
44
} from '@mcp-pointer/shared/types';
55
import logger from '../utils/logger';
66

@@ -26,7 +26,7 @@ export class ElementSenderService {
2626
private readonly MAX_RETRIES = 10; // Maximum connection retry attempts
2727

2828
async sendElement(
29-
element: TargetedElement,
29+
element: RawPointedDOMElement,
3030
port: number,
3131
statusCallback?: StatusCallback,
3232
): Promise<void> {
@@ -45,7 +45,7 @@ export class ElementSenderService {
4545
statusCallback?.(ConnectionStatus.SENDING);
4646

4747
const message: PointerMessage = {
48-
type: PointerMessageType.ELEMENT_SELECTED,
48+
type: PointerMessageType.DOM_ELEMENT_POINTED,
4949
data: element,
5050
timestamp: Date.now(),
5151
};

packages/chrome-extension/src/utils/element.ts

Lines changed: 59 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -2,7 +2,7 @@
22
/* eslint-disable no-underscore-dangle */
33

44
import {
5-
ComponentInfo, CSSProperties, ElementPosition, TargetedElement,
5+
ComponentInfo, CSSProperties, ElementPosition, TargetedElement, RawPointedDOMElement,
66
} from '@mcp-pointer/shared/types';
77
import logger from './logger';
88

@@ -212,3 +212,61 @@ export function adaptTargetToElement(element: HTMLElement): TargetedElement {
212212
url: window.location.href,
213213
};
214214
}
215+
216+
/**
217+
* Extract raw React Fiber from an element (if present)
218+
*/
219+
export function getRawReactFiber(element: HTMLElement): any | undefined {
220+
try {
221+
const fiberKey = Object.keys(element).find((key) => key.startsWith('__reactFiber$')
222+
|| key.startsWith('__reactInternalInstance$'));
223+
224+
if (fiberKey) {
225+
return (element as any)[fiberKey];
226+
}
227+
228+
return undefined;
229+
} catch (error) {
230+
logger.error('🚨 Error extracting raw Fiber:', error);
231+
return undefined;
232+
}
233+
}
234+
235+
/**
236+
* Get all computed styles as a plain object (Record)
237+
* CSSStyleDeclaration doesn't serialize properly with JSON.stringify,
238+
* so we convert it to a plain object
239+
*/
240+
export function getAllComputedStyles(element: HTMLElement): Record<string, string> {
241+
const computedStyle = window.getComputedStyle(element);
242+
const styles: Record<string, string> = {};
243+
244+
// Convert CSSStyleDeclaration to plain object
245+
for (let i = 0; i < computedStyle.length; i += 1) {
246+
const property = computedStyle[i];
247+
styles[property] = computedStyle.getPropertyValue(property);
248+
}
249+
250+
return styles;
251+
}
252+
253+
/**
254+
* Extract minimal raw DOM element data for server-side processing
255+
*/
256+
export function extractRawPointedDOMElement(element: HTMLElement): RawPointedDOMElement {
257+
const raw: RawPointedDOMElement = {
258+
outerHTML: element.outerHTML,
259+
url: window.location.href,
260+
timestamp: Date.now(),
261+
boundingClientRect: element.getBoundingClientRect(),
262+
computedStyles: getAllComputedStyles(element),
263+
};
264+
265+
// Add React Fiber if present
266+
const reactFiber = getRawReactFiber(element);
267+
if (reactFiber) {
268+
raw.reactFiber = reactFiber;
269+
}
270+
271+
return raw;
272+
}

0 commit comments

Comments
 (0)