Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
28 changes: 25 additions & 3 deletions src/extension/react/components/DetailPanel.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -15,6 +15,8 @@ function DetailPanel({ selectedRow, onClose, direction = 'right' }: Props) {
const { theme } = useDevtronContext();
if (!selectedRow) return null;

const { serviceWorkerVersionId, serviceWorkerScope } = selectedRow.serviceWorkerDetails || {};

const timestamp = formatTimestamp(selectedRow.timestamp);

const isBottomDocked = direction === 'bottom';
Expand Down Expand Up @@ -43,7 +45,7 @@ function DetailPanel({ selectedRow, onClose, direction = 'right' }: Props) {
<div className="flex items-center gap-x-1">
<span className="font-medium"> Channel: </span>
{selectedRow.channel && (
<span className="block max-w-72 break-all rounded bg-gray-200 px-1 py-0.5 dark:bg-charcoal-500">
<span className="block max-w-96 break-all rounded bg-gray-200 px-1 py-0.5 dark:bg-charcoal-500">
{selectedRow.channel}
</span>
)}
Expand All @@ -64,12 +66,32 @@ function DetailPanel({ selectedRow, onClose, direction = 'right' }: Props) {
{/* Method */}
{selectedRow.method && (
<div className="flex w-fit items-center gap-x-1">
<span className="font-medium">Method: </span>
<span className="block max-w-72 break-all rounded bg-gray-200 px-1 py-0.5 dark:bg-charcoal-500">
<span className="text-nowrap font-medium">Method: </span>
<span className="block max-w-96 break-all rounded bg-gray-200 px-1 py-0.5 dark:bg-charcoal-500">
{selectedRow.method}
</span>
</div>
)}

{/* Service Worker Scope */}
{serviceWorkerScope && (
<div className="flex w-fit items-center gap-x-1">
<span className="text-nowrap font-medium">SW Scope: </span>
<span className="block max-w-96 break-all rounded bg-gray-200 px-1 py-0.5 dark:bg-charcoal-500">
{serviceWorkerScope}
</span>
</div>
)}

{/* Service Worker Version ID */}
{serviceWorkerVersionId && (
<div className="flex w-fit items-center gap-x-1">
<span className="text-nowrap font-medium">SW Version ID: </span>
<span className="block max-w-96 break-all rounded bg-gray-200 px-1 py-0.5 dark:bg-charcoal-500">
{serviceWorkerVersionId}
</span>
</div>
)}
</div>

{/* Args */}
Expand Down
11 changes: 10 additions & 1 deletion src/extension/react/components/DirectionBadge.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -30,12 +30,21 @@ export default function DirectionBadge({ direction }: Props) {
case 'service-worker-to-main':
return {
colorClass:
'dark:bg-dark-orange dark:text-light-orange bg-yellow-100 text-yellow-800 border-yellow-300 dark:border-light-orange',
'dark:bg-dark-yellow dark:text-light-yellow bg-yellow-100 text-yellow-800 border-yellow-300 dark:border-light-yellow',
Icon: ArrowRight,
labelLeft: 'SW',
labelRight: 'Main',
tooltip: 'Service Worker to Main',
};
case 'main-to-service-worker':
return {
colorClass:
'dark:bg-dark-orange dark:text-light-orange bg-orange-100 text-orange-800 border-orange-300 dark:border-light-orange',
Icon: ArrowRight,
labelLeft: 'Main',
labelRight: 'SW',
tooltip: 'Main to Service Worker',
};
case 'renderer':
return {
colorClass:
Expand Down
11 changes: 11 additions & 0 deletions src/extension/react/test_data/test_data.ts
Original file line number Diff line number Diff line change
Expand Up @@ -92,4 +92,15 @@ export const events: IpcEventDataIndexed[] = [
},
],
},
{
serialNumber: 129,
direction: 'main-to-service-worker',
channel: 'sw-check-2',
args: ['Hello from main to service worker!'],
timestamp: 1749114387250,
serviceWorkerDetails: {
serviceWorkerScope: 'chrome-extension://floigfkhicjhinimocdoblflbmefpjeg/',
serviceWorkerVersionId: 32,
},
},
];
94 changes: 83 additions & 11 deletions src/index.ts
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
import { app, session } from 'electron';
import path from 'node:path';
import { createRequire } from 'node:module';
import type { Direction, IpcEventData } from './types/shared';
import type { Direction, IpcEventData, ServiceWorkerDetails } from './types/shared';

let isInstalled = false;
let isInstalledToDefaultSession = false;
Expand All @@ -13,23 +13,25 @@ function trackIpcEvent(
direction: Direction,
channel: string,
args: any[],
serviceWorker: Electron.ServiceWorkerMain,
devtronSW: Electron.ServiceWorkerMain,
serviceWorkerDetails?: ServiceWorkerDetails,
) {
const eventData: IpcEventData = {
direction,
channel,
args,
timestamp: Date.now(),
serviceWorkerDetails,
};

if (serviceWorker === null) {
if (devtronSW === null) {
console.error('The service-worker for Devtron is not registered yet. Cannot track IPC event.');
return;
}
serviceWorker.send('devtron-render-event', eventData);
devtronSW.send('devtron-render-event', eventData);
}

function registerIpcListeners(ses: Electron.Session, serviceWorker: Electron.ServiceWorkerMain) {
function registerIpcListeners(ses: Electron.Session, devtronSW: Electron.ServiceWorkerMain) {
ses.on(
// @ts-expect-error: '-ipc-message' is an internal event
'-ipc-message',
Expand All @@ -38,9 +40,9 @@ function registerIpcListeners(ses: Electron.Session, serviceWorker: Electron.Ser
channel: string,
args: any[],
) => {
if (event.type === 'frame') trackIpcEvent('renderer-to-main', channel, args, serviceWorker);
if (event.type === 'frame') trackIpcEvent('renderer-to-main', channel, args, devtronSW);
else if (event.type === 'service-worker')
trackIpcEvent('service-worker-to-main', channel, args, serviceWorker);
trackIpcEvent('service-worker-to-main', channel, args, devtronSW);
},
);

Expand All @@ -52,9 +54,9 @@ function registerIpcListeners(ses: Electron.Session, serviceWorker: Electron.Ser
channel: string,
args: any[],
) => {
if (event.type === 'frame') trackIpcEvent('renderer-to-main', channel, args, serviceWorker);
if (event.type === 'frame') trackIpcEvent('renderer-to-main', channel, args, devtronSW);
else if (event.type === 'service-worker')
trackIpcEvent('service-worker-to-main', channel, args, serviceWorker);
trackIpcEvent('service-worker-to-main', channel, args, devtronSW);
},
);
ses.on(
Expand All @@ -65,18 +67,87 @@ function registerIpcListeners(ses: Electron.Session, serviceWorker: Electron.Ser
channel: string,
args: any[],
) => {
if (event.type === 'frame') trackIpcEvent('renderer-to-main', channel, args, serviceWorker);
if (event.type === 'frame') trackIpcEvent('renderer-to-main', channel, args, devtronSW);
else if (event.type === 'service-worker')
trackIpcEvent('service-worker-to-main', channel, args, serviceWorker);
trackIpcEvent('service-worker-to-main', channel, args, devtronSW);
},
);
}

/**
* Registers a listener for the service worker's send method to track IPC events
* sent from the main process to the service worker.
*/
function registerServiceWorkerSendListener(
ses: Electron.Session,
devtronSW: Electron.ServiceWorkerMain,
): void {
const isInstalledSet = new Set<number>(); // stores version IDs of patched service workers

// register listener for existing service workers
const allRunning = ses.serviceWorkers.getAllRunning();
for (const vid in allRunning) {
const swInfo = allRunning[vid];

const sw = ses.serviceWorkers.getWorkerFromVersionID(Number(vid));

if (typeof sw === 'undefined' || sw.scope === devtronSW.scope) continue;
isInstalledSet.add(swInfo.versionId);

const originalSend = sw.send;
sw.send = function (...args) {
trackIpcEvent(
'main-to-service-worker',
args[0], // channel
args.slice(1), // args
devtronSW,
{
serviceWorkerScope: sw.scope,
serviceWorkerVersionId: sw.versionId,
},
);
return originalSend.apply(this, args);
};
}

// register listener for new service workers
ses.serviceWorkers.on('running-status-changed', (details) => {
if (details.runningStatus === 'running' || details.runningStatus === 'starting') {
const sw = ses.serviceWorkers.getWorkerFromVersionID(details.versionId);

if (
typeof sw === 'undefined' ||
sw.scope === devtronSW.scope ||
isInstalledSet.has(sw.versionId)
)
return;

isInstalledSet.add(details.versionId);

const originalSend = sw.send;
sw.send = function (...args) {
trackIpcEvent(
'main-to-service-worker',
args[0], // channel
args.slice(1), // args
devtronSW,
{
serviceWorkerScope: sw.scope,
serviceWorkerVersionId: sw.versionId,
},
);
return originalSend.apply(this, args);
};
}
});
}

async function startServiceWorker(ses: Electron.Session, extension: Electron.Extension) {
try {
const sw = await ses.serviceWorkers.startWorkerForScope(extension.url);
sw.startTask();
registerIpcListeners(ses, sw);
registerServiceWorkerSendListener(ses, sw);
} catch (error) {
console.warn(`Failed to start Devtron service-worker (${error}), trying again...`);
/**
Expand All @@ -93,6 +164,7 @@ async function startServiceWorker(ses: Electron.Session, extension: Electron.Ext
const sw = await ses.serviceWorkers.startWorkerForScope(extension.url);
sw.startTask();
registerIpcListeners(ses, sw);
registerServiceWorkerSendListener(ses, sw);
ses.serviceWorkers.removeListener('registration-completed', handleDetails);
console.log(`Devtron service-worker started successfully`);
}
Expand Down
10 changes: 10 additions & 0 deletions src/types/shared.ts
Original file line number Diff line number Diff line change
Expand Up @@ -4,20 +4,30 @@ export type Direction =
| 'renderer-to-main'
| 'main-to-renderer'
| 'service-worker-to-main'
| 'main-to-service-worker'
| 'renderer';

export type ServiceWorkerDetails = {
serviceWorkerVersionId: number;
serviceWorkerScope: string;
};

export interface IpcEventData {
direction: Direction;
channel: string;
args: any[];
timestamp: number;
method?: string;
serviceWorkerDetails?: ServiceWorkerDetails;
}

/* ------------------------------------------------------ */

/* ---------------------- EXTENSION --------------------- */
export interface IpcEventDataIndexed extends IpcEventData {
serialNumber: number;
}

export type MessagePanel =
| { type: typeof MSG_TYPE.PONG }
| { type: typeof MSG_TYPE.PING }
Expand Down
4 changes: 3 additions & 1 deletion tailwind.config.js
Original file line number Diff line number Diff line change
Expand Up @@ -19,11 +19,13 @@ export default {
'charcoal-700': '#171717',
'charcoal-800': '#111113',

'light-orange': '#ffa057',
'light-yellow': '#ffc53d',
'light-orange': '#ff8a30 ',
'light-blue': '#70b8ff',
'light-green': '#3ddb8f',
'light-purple': '#c96cff',

'dark-yellow': '#362b00',
'dark-orange': '#331e10',
'dark-blue': '#0d2849',
'dark-green': '#132d23',
Expand Down