Skip to content

feat(#161): refactor string literals to typed enums #216

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Open
wants to merge 13 commits into
base: develop
Choose a base branch
from
Open
Show file tree
Hide file tree
Changes from 6 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
8 changes: 5 additions & 3 deletions .github/workflows/lint.yml
Original file line number Diff line number Diff line change
Expand Up @@ -17,9 +17,11 @@ jobs:
- name: Checkout Repository
uses: actions/checkout@v4

- name: Setup pnpm
uses: pnpm/action-setup@v4

- name: Setup Node.js
- uses: pnpm/action-setup@v4
- uses: actions/setup-node@v4
uses: actions/setup-node@v4
with:
node-version-file: '.nvmrc'
cache: pnpm
Expand All @@ -28,4 +30,4 @@ jobs:
run: pnpm install --frozen-lockfile --prefer-offline

- name: Run ESLint
- run: pnpm lint
run: pnpm lint
4 changes: 3 additions & 1 deletion .github/workflows/prettier.yml
Original file line number Diff line number Diff line change
Expand Up @@ -17,8 +17,10 @@ jobs:
- name: Checkout Repository
uses: actions/checkout@v4

- name: Setup pnpm
uses: pnpm/action-setup@v4

- name: Setup Node.js
- uses: pnpm/action-setup@v4
uses: actions/setup-node@v4
with:
node-version-file: '.nvmrc'
Expand Down
119 changes: 61 additions & 58 deletions chrome-extension/src/background/index.ts
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,21 @@ import 'webextension-polyfill';
import { v4 as uuidv4 } from 'uuid';

import { t } from '@extension/i18n';
import {
MessageType,
MessageAction,
CaptureState,
CaptureType,
RecordType,
RecordSource,
LogMethod,
InstallReason,
ContextType,
ContextMenuId,
ResponseStatus,
ImageFormat,
RequestProperty,
} from '@extension/shared';
import {
annotationsRedoStorage,
annotationsStorage,
Expand All @@ -23,7 +38,7 @@ chrome.tabs.onRemoved.addListener(async tabId => {

const captureTabId = await captureTabStorage.getCaptureTabId();
if (tabId === captureTabId) {
await captureStateStorage.setCaptureState('idle');
await captureStateStorage.setCaptureState(CaptureState.IDLE);
await captureTabStorage.setCaptureTabId(null);

annotationsStorage.setAnnotations([]);
Expand All @@ -33,7 +48,7 @@ chrome.tabs.onRemoved.addListener(async tabId => {
}
});

chrome.tabs.onUpdated.addListener(async (tabId, changeInfo) => {
chrome.tabs.onUpdated.addListener(async (tabId, changeInfo, tab) => {
// If tab finished loading (refreshed), remove it from pending reload tabs
if (changeInfo.status === 'complete') {
const pendingTabIds = await pendingReloadTabsStorage.getAll();
Expand All @@ -49,12 +64,12 @@ chrome.tabs.onUpdated.addListener(async (tabId, changeInfo) => {
captureTabStorage.getCaptureTabId(),
]);

if (!capturedTabId && state === 'unsaved') {
await captureStateStorage.setCaptureState('idle');
if (!capturedTabId && state === CaptureState.UNSAVED) {
await captureStateStorage.setCaptureState(CaptureState.IDLE);
}

if (tabId === capturedTabId) {
await captureStateStorage.setCaptureState('idle');
await captureStateStorage.setCaptureState(CaptureState.IDLE);
await captureTabStorage.setCaptureTabId(null);

annotationsStorage.setAnnotations([]);
Expand All @@ -66,71 +81,59 @@ chrome.tabs.onUpdated.addListener(async (tabId, changeInfo) => {
* NOTE: Do Not Use async/await in onMessage listeners
*/
chrome.runtime.onMessage.addListener((message, sender, sendResponse) => {
if (message.type === 'EXIT_CAPTURE') {
captureStateStorage.setCaptureState('idle');
if (message.type === MessageType.EXIT_CAPTURE) {
captureStateStorage.setCaptureState(CaptureState.IDLE);
captureTabStorage.setCaptureTabId(null);

annotationsStorage.setAnnotations([]);
annotationsRedoStorage.setAnnotations([]);
sendResponse({ status: 'success' });
sendResponse({ status: ResponseStatus.SUCCESS });
}

if (sender?.tab?.id) {
if (message.type === 'ADD_RECORD') {
if (message.type === MessageType.ADD_RECORD) {
// Merge fetch request data from content script
addOrMergeRecords(sender.tab.id, message.data);
sendResponse({ status: 'success' });
sendResponse({ status: ResponseStatus.SUCCESS });
}

if (message.type === 'GET_RECORDS') {
if (message.type === MessageType.GET_RECORDS) {
getRecords(sender.tab.id).then(records => sendResponse({ records }));
}
} else {
console.log('[Background] - Add Records: No sender id');
}

if (message.action === 'checkNativeCapture') {
if (message.action === MessageAction.CHECK_NATIVE_CAPTURE) {
sendResponse({ isAvailable: !!chrome.tabs?.captureVisibleTab });
}

if (message.action === 'captureVisibleTab') {
if (message.action === MessageAction.CAPTURE_VISIBLE_TAB) {
// Handle the async operation
chrome.tabs.captureVisibleTab(
null, // Current window
{ format: 'jpeg', quality: 100 },
dataUrl => {
if (chrome.runtime.lastError) {
console.error('Error capturing screenshot:', chrome.runtime.lastError);
sendResponse({ success: false, message: chrome.runtime.lastError.message });
} else {
sendResponse({ success: true, dataUrl });
}
},
);
chrome.tabs.captureVisibleTab({ format: ImageFormat.JPEG, quality: 100 }, dataUrl => {
if (chrome.runtime.lastError) {
console.error('Error capturing screenshot:', chrome.runtime.lastError);
sendResponse({ success: false, message: chrome.runtime.lastError.message });
} else {
sendResponse({ success: true, dataUrl });
}
});
}

return true; // Keep the connection open for async handling
});

chrome.runtime.onInstalled.addListener(async ({ reason }) => {
if (reason === 'install') {
/**
* Set unique identifier for the user
* to store reported bugs when no account
*/
if (reason === InstallReason.INSTALL) {
const userUuid = await userUUIDStorage.get();
if (!userUuid) await userUUIDStorage.update(uuidv4());

// Open a welcome page
// await chrome.tabs.create({ url: 'welcome.html' });
}

/**
* @todo
* find a better way to reload the tabs that are open when install/update happens.
* context: see issue: #24

*/
if (['install', 'update'].includes(reason)) {
if ([InstallReason.INSTALL, InstallReason.UPDATE].includes(reason as InstallReason)) {
chrome.tabs.query({}, tabs => {
tabs.forEach(tab => {
if (tab.id) {
Expand All @@ -142,43 +145,43 @@ chrome.runtime.onInstalled.addListener(async ({ reason }) => {

// Creates parent context menu item
chrome.contextMenus.create({
id: 'capture_parent',
id: ContextMenuId.CAPTURE_PARENT,
title: t('extensionName'),
contexts: ['all'],
contexts: [ContextType.ALL],
});

// Define the child options
const captureOptions = [
{ id: 'area', title: t('area') },
{ id: 'full-page', title: t('fullPage') },
{ id: 'viewport', title: t('viewport') },
{ id: CaptureType.AREA, title: t('area') },
{ id: CaptureType.FULL_PAGE, title: t('fullPage') },
{ id: CaptureType.VIEWPORT, title: t('viewport') },
];

captureOptions.forEach(({ id, title }) => {
chrome.contextMenus.create({
id,
parentId: 'capture_parent',
parentId: ContextMenuId.CAPTURE_PARENT,
title,
contexts: ['all'],
contexts: [ContextType.ALL],
});
});
});

chrome.contextMenus.onClicked.addListener(async (info, tab) => {
if (!tab?.id) return; //skip if tab is invalid

const type = info.menuItemId as 'area' | 'viewport' | 'full-page';
const type = info.menuItemId as CaptureType;

// Updates capture state and active tab
await captureStateStorage.setCaptureState('capturing');
await captureStateStorage.setCaptureState(CaptureState.CAPTURING);
await captureTabStorage.setCaptureTabId(tab.id);

// Sends message to contentScript to start capture
if (type) {
chrome.tabs.sendMessage(
tab.id,
{
action: 'START_SCREENSHOT',
action: MessageAction.START_SCREENSHOT,
payload: { type },
},
response => {
Expand All @@ -205,18 +208,18 @@ chrome.webRequest.onCompleted.addListener(
(request: chrome.webRequest.WebResponseCacheDetails) => {
const clonedRequest = structuredClone(request);
addOrMergeRecords(clonedRequest.tabId, {
recordType: 'network',
source: 'background',
recordType: RecordType.NETWORK,
source: RecordSource.BACKGROUND,
...clonedRequest,
});

if (clonedRequest.statusCode >= 400) {
addOrMergeRecords(clonedRequest.tabId, {
timestamp: Date.now(),
type: 'log',
recordType: 'console',
source: 'background',
method: 'error',
type: RecordType.CONSOLE,
recordType: RecordType.CONSOLE,
source: RecordSource.BACKGROUND,
method: LogMethod.ERROR,
args: [
`[${clonedRequest.type}] ${clonedRequest.method} ${clonedRequest.url} responded with status ${clonedRequest.statusCode}`,
clonedRequest,
Expand All @@ -236,24 +239,24 @@ chrome.webRequest.onCompleted.addListener(
chrome.webRequest.onBeforeRequest.addListener(
(request: chrome.webRequest.WebRequestBodyDetails) => {
addOrMergeRecords(request.tabId, {
recordType: 'network',
source: 'background',
recordType: RecordType.NETWORK,
source: RecordSource.BACKGROUND,
...structuredClone(request),
});
},
{ urls: ['<all_urls>'] },
['requestBody'],
[RequestProperty.REQUEST_BODY],
);

// Listener for onBeforeSendHeaders
chrome.webRequest.onBeforeSendHeaders.addListener(
(request: chrome.webRequest.WebRequestHeadersDetails) => {
addOrMergeRecords(request.tabId, {
recordType: 'network',
source: 'background',
recordType: RecordType.NETWORK,
source: RecordSource.BACKGROUND,
...structuredClone(request),
});
},
{ urls: ['<all_urls>'] },
['requestHeaders'],
[RequestProperty.REQUEST_HEADERS],
);
6 changes: 2 additions & 4 deletions chrome-extension/src/utils/manage-records.util.ts
Original file line number Diff line number Diff line change
@@ -1,14 +1,12 @@
import { v4 as uuidv4 } from 'uuid';

import { deepRedactSensitiveInfo } from '@extension/shared';
import { deepRedactSensitiveInfo, RecordType } from '@extension/shared';

const restricted = ['https://api.briehq.com']; // 'extend.iife', 'kbmbnelnoppneadncmmkfikbcgmilbao' Note: it blocks the logs
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I see some differences between current changes in develop branch.
Can you pull the latests changes from develop branch?

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

@naaa760,
I still see the issue with missing changes that are not matching the develop branch.

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

@naaa760,
can you please pull the latest changes from upstream develop branch?

const invalidRecord = (entity: string) => restricted.some(word => entity.includes(word));

const tabRecordsMap = new Map<number, Map<string, any>>();

export type RecordType = 'events' | 'network' | 'console' | 'cookies';

export interface Record {
recordType: RecordType;
url?: string;
Expand Down Expand Up @@ -50,7 +48,7 @@ export const addOrMergeRecords = async (tabId: number, record: Record | any): Pr
const uuid = uuidv4();

try {
if (record.recordType !== 'network') {
if (record.recordType !== RecordType.NETWORK) {
recordsMap.set(uuid, { uuid, ...deepRedactSensitiveInfo(record, tabUrl) });
return;
}
Expand Down
8 changes: 5 additions & 3 deletions package.json
Original file line number Diff line number Diff line change
Expand Up @@ -52,18 +52,19 @@
},
"dependencies": {
"html2canvas": "^1.4.1",
"i18n": "^0.15.1",
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Remove this.

Also,
it seems that you used to create your branch from main branch.
Please rebase it to match develop branch, since this is our development branch.

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

@naaa760,
what was the reason to add i18n package?

We have our own custom i18n package, see: packages/i18n

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

@naaa760,
we don't need i18n as of now.

"react": "19.1.0",
"react-dom": "19.1.0"
"react-dom": "19.1.0",
"uuid": "^11.1.0"
},
"devDependencies": {
"prettier-plugin-tailwindcss": "^0.6.12",
"@eslint/compat": "^1.2.5",
"@eslint/eslintrc": "^3.2.0",
"@eslint/js": "^9.20.0",
"@types/chrome": "0.0.304",
"@types/eslint-plugin-jsx-a11y": "^6.10.0",
"@types/eslint__eslintrc": "^2.1.2",
"@types/eslint__js": "^8.42.3",
"@types/eslint-plugin-jsx-a11y": "^6.10.0",
"@types/node": "^22.14.1",
"@types/react": "^19.0.8",
"@types/react-dom": "^19.0.3",
Expand Down Expand Up @@ -92,6 +93,7 @@
"postcss": "^8.5.2",
"postcss-load-config": "^6.0.1",
"prettier": "^3.3.3",
"prettier-plugin-tailwindcss": "^0.6.12",
"rimraf": "^6.0.1",
"run-script-os": "^1.1.6",
"tailwindcss": "^3.4.17",
Expand Down
3 changes: 0 additions & 3 deletions packages/shared/README.md
Original file line number Diff line number Diff line change
@@ -1,7 +1,4 @@
# Shared Package

This package contains code shared with other packages.
To use the code in the package, you need to add the following to the package.json file.

```json
{
Expand Down
11 changes: 11 additions & 0 deletions packages/shared/lib/constants/enums/capture-states.enum.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,11 @@
export enum CaptureState {
IDLE = 'idle',
CAPTURING = 'capturing',
UNSAVED = 'unsaved',
}

export enum CaptureType {
AREA = 'area',
FULL_PAGE = 'full-page',
VIEWPORT = 'viewport',
}
27 changes: 27 additions & 0 deletions packages/shared/lib/constants/enums/chrome-extension.enum.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,27 @@
export enum InstallReason {
INSTALL = 'install',
UPDATE = 'update',
}

export enum ContextType {
ALL = 'all',
}

export enum ContextMenuId {
CAPTURE_PARENT = 'capture_parent',
}

export enum ResponseStatus {
SUCCESS = 'success',
ERROR = 'error',
}

export enum ImageFormat {
JPEG = 'jpeg',
PNG = 'png',
}

export enum RequestProperty {
REQUEST_BODY = 'requestBody',
REQUEST_HEADERS = 'requestHeaders',
}
Loading