Skip to content

Commit

Permalink
Merge branch 'main' into e2e-isolate
Browse files Browse the repository at this point in the history
  • Loading branch information
sidvishnoi authored Jan 31, 2025
2 parents e19d49e + 2c076a7 commit da412e5
Show file tree
Hide file tree
Showing 15 changed files with 281 additions and 53 deletions.
6 changes: 6 additions & 0 deletions src/_locales/en/messages.json
Original file line number Diff line number Diff line change
Expand Up @@ -260,5 +260,11 @@
},
"postInstall_action_submit": {
"message": "Connect your wallet"
},
"postInstall_text_wallet_connected_1": {
"message": "You've already connected your wallet."
},
"postInstall_text_wallet_connected_2": {
"message": "Access the extension from the browser toolbar."
}
}
22 changes: 18 additions & 4 deletions src/background/container.ts
Original file line number Diff line number Diff line change
Expand Up @@ -15,7 +15,7 @@ import {
TabEvents,
TabState,
WindowState,
SendToPopup,
SendToPort,
EventsService,
Heartbeat,
Deduplicator,
Expand All @@ -29,8 +29,12 @@ import {
type Translation,
} from '@/shared/helpers';
import {
MessageManager,
type BackgroundToAppMessagesMap,
type BackgroundToPopupMessagesMap,
type BackgroundToContentMessage,
MessageManager,
BACKGROUND_TO_POPUP_CONNECTION_NAME,
BACKGROUND_TO_APP_CONNECTION_NAME,
} from '@/shared/messages';

export interface Cradle {
Expand All @@ -46,7 +50,8 @@ export interface Cradle {
walletService: WalletService;
monetizationService: MonetizationService;
message: MessageManager<BackgroundToContentMessage>;
sendToPopup: SendToPopup;
sendToPopup: SendToPort<BackgroundToPopupMessagesMap>;
sendToApp: SendToPort<BackgroundToAppMessagesMap>;
tabEvents: TabEvents;
background: Background;
t: Translation;
Expand Down Expand Up @@ -101,7 +106,16 @@ export const configureContainer = () => {
})),
message: asClass(MessageManager<BackgroundToContentMessage>).singleton(),
tabEvents: asClass(TabEvents).singleton(),
sendToPopup: asClass(SendToPopup).singleton(),
sendToPopup: asClass(SendToPort)
.singleton()
.inject(() => ({
connectionName: BACKGROUND_TO_POPUP_CONNECTION_NAME,
})),
sendToApp: asClass(SendToPort)
.singleton()
.inject(() => ({
connectionName: BACKGROUND_TO_APP_CONNECTION_NAME,
})),
background: asClass(Background)
.singleton()
.inject(() => ({
Expand Down
28 changes: 26 additions & 2 deletions src/background/services/background.ts
Original file line number Diff line number Diff line change
Expand Up @@ -14,6 +14,7 @@ import { getTab } from '@/background/utils';
import { PERMISSION_HOSTS } from '@/shared/defines';
import { APP_URL } from '@/background/constants';
import type { Cradle } from '@/background/container';
import type { AppStore } from '@/shared/types';

type AlarmCallback = Parameters<Browser['alarms']['onAlarm']['addListener']>[0];
const ALARM_RESET_OUT_OF_FUNDS = 'reset-out-of-funds';
Expand All @@ -27,6 +28,7 @@ export class Background {
private tabEvents: Cradle['tabEvents'];
private windowState: Cradle['windowState'];
private sendToPopup: Cradle['sendToPopup'];
private sendToApp: Cradle['sendToApp'];
private events: Cradle['events'];
private heartbeat: Cradle['heartbeat'];

Expand All @@ -39,6 +41,7 @@ export class Background {
tabEvents,
windowState,
sendToPopup,
sendToApp,
events,
heartbeat,
}: Cradle) {
Expand All @@ -48,6 +51,7 @@ export class Background {
monetizationService,
storage,
sendToPopup,
sendToApp,
tabEvents,
windowState,
logger,
Expand All @@ -67,6 +71,7 @@ export class Background {
this.bindTabHandlers();
this.bindWindowHandlers();
this.sendToPopup.start();
this.sendToApp.start();
await KeyAutoAddService.registerContentScripts({ browser: this.browser });
}

Expand Down Expand Up @@ -128,6 +133,19 @@ export class Background {
this.browser.alarms.onAlarm.addListener(resetOutOfFundsState);
}

async getAppData(): Promise<AppStore> {
const { connected, publicKey } = await this.storage.get([
'connected',
'publicKey',
]);

return {
connected,
publicKey,
transientState: this.storage.getPopupTransientState(),
};
}

bindWindowHandlers() {
this.browser.windows.onCreated.addListener(
this.windowState.onWindowCreated,
Expand All @@ -143,7 +161,7 @@ export class Background {
windowTypes: ['normal'],
});
const popupWasOpen = popupOpen;
popupOpen = this.sendToPopup.isPopupOpen;
popupOpen = this.sendToPopup.isPortOpen;
if (popupWasOpen || popupOpen) {
// This is intentionally called after windows.getAll, to add a little
// delay for popup port to open
Expand Down Expand Up @@ -189,7 +207,7 @@ export class Background {
try {
switch (message.action) {
// region Popup
case 'GET_CONTEXT_DATA':
case 'GET_DATA_POPUP':
return success(
await this.monetizationService.getPopupData(
await this.windowState.getCurrentTab(),
Expand Down Expand Up @@ -286,6 +304,11 @@ export class Background {

// endregion

// region App
case 'GET_DATA_APP':
return success(await this.getAppData());
// endregion

default:
return;
}
Expand Down Expand Up @@ -330,6 +353,7 @@ export class Background {

this.events.on('storage.popup_transient_state_update', (state) => {
this.sendToPopup.send('SET_TRANSIENT_STATE', state);
this.sendToApp.send('SET_TRANSIENT_STATE', state);
});

this.events.on('request_popup_close', () => {
Expand Down
2 changes: 1 addition & 1 deletion src/background/services/index.ts
Original file line number Diff line number Diff line change
Expand Up @@ -7,7 +7,7 @@ export { Background } from './background';
export { TabEvents } from './tabEvents';
export { TabState } from './tabState';
export { WindowState } from './windowState';
export { SendToPopup } from './sendToPopup';
export { SendToPort } from './sendToPort';
export { EventsService } from './events';
export { Deduplicator } from './deduplicator';
export { Heartbeat } from './heartbeat';
Original file line number Diff line number Diff line change
@@ -1,24 +1,23 @@
import type { Runtime } from 'webextension-polyfill';
import {
BACKGROUND_TO_POPUP_CONNECTION_NAME as CONNECTION_NAME,
type BackgroundToPopupMessage,
type BackgroundToPopupMessagesMap,
} from '@/shared/messages';
import type { Cradle } from '@/background/container';
import type { BackgroundToPortMessagesMap } from '@/shared/messages';

export class SendToPopup {
export class SendToPort<Message extends BackgroundToPortMessagesMap> {
private browser: Cradle['browser'];

private isConnected = false;
private port: Runtime.Port;
private isConnected = false;
private connectionName: string;

constructor({ browser }: Cradle) {
Object.assign(this, { browser });
constructor({
browser,
connectionName,
}: Cradle & { connectionName: string }) {
Object.assign(this, { browser, connectionName });
}

start() {
this.browser.runtime.onConnect.addListener((port) => {
if (port.name !== CONNECTION_NAME) return;
if (port.name !== this.connectionName) return;
if (port.error) {
return;
}
Expand All @@ -30,18 +29,16 @@ export class SendToPopup {
});
}

get isPopupOpen() {
get isPortOpen() {
return this.isConnected;
}

async send<T extends keyof BackgroundToPopupMessagesMap>(
type: T,
data: BackgroundToPopupMessagesMap[T],
) {
async send<K extends keyof Message>(type: K, data: Message[K]) {
if (!this.isConnected) {
return;
}
const message = { type, data } as BackgroundToPopupMessage;

const message = { type, data };
this.port.postMessage(message);
}
}
7 changes: 6 additions & 1 deletion src/pages/app/App.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,7 @@ import {
BrowserContextProvider,
TranslationContextProvider,
} from '@/pages/shared/lib/context';
import { MessageContextProvider, WaitForStateLoad } from '@/app/lib/context';
import browser from 'webextension-polyfill';
import {
createHashRouter,
Expand All @@ -28,7 +29,11 @@ export const App = () => {
return (
<BrowserContextProvider browser={browser}>
<TranslationContextProvider>
<RouterProvider router={router} />
<MessageContextProvider>
<WaitForStateLoad>
<RouterProvider router={router} />
</WaitForStateLoad>
</MessageContextProvider>
</TranslationContextProvider>
</BrowserContextProvider>
);
Expand Down
69 changes: 69 additions & 0 deletions src/pages/app/lib/context.tsx
Original file line number Diff line number Diff line change
@@ -1 +1,70 @@
import React from 'react';
import {
type BackgroundToAppMessage,
BACKGROUND_TO_APP_CONNECTION_NAME as CONNECTION_NAME,
MessageManager,
type AppToBackgroundMessage,
} from '@/shared/messages';
import { useBrowser } from '@/pages/shared/lib/context';
import { dispatch } from './store';

export { useBrowser, useTranslation } from '@/pages/shared/lib/context';

export function WaitForStateLoad({ children }: React.PropsWithChildren) {
const message = useMessage();
const [isLoading, setIsLoading] = React.useState(true);

React.useEffect(() => {
async function get() {
const response = await message.send('GET_DATA_APP');

if (response.success) {
dispatch({ type: 'SET_DATA_APP', data: response.payload });
setIsLoading(false);
}
}

get();
}, [message]);

if (isLoading) {
return <>Loading</>;
}

return <>{children}</>;
}

const MessageContext = React.createContext<
MessageManager<AppToBackgroundMessage>
>({} as MessageManager<AppToBackgroundMessage>);

export const useMessage = () => React.useContext(MessageContext);

export const MessageContextProvider = ({
children,
}: React.PropsWithChildren) => {
const browser = useBrowser();
const message = new MessageManager<AppToBackgroundMessage>({ browser });

React.useEffect(() => {
const port = browser.runtime.connect({ name: CONNECTION_NAME });
port.onMessage.addListener((message: BackgroundToAppMessage) => {
switch (message.type) {
case 'SET_TRANSIENT_STATE':
return dispatch(message);
}
});
port.onDisconnect.addListener(() => {
// nothing to do
});
return () => {
port.disconnect();
};
}, [browser]);

return (
<MessageContext.Provider value={message}>
{children}
</MessageContext.Provider>
);
};
35 changes: 35 additions & 0 deletions src/pages/app/lib/store.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,35 @@
import type {
AppStore,
DeepNonNullable,
PopupTransientState,
} from '@/shared/types';
import { proxy, useSnapshot } from 'valtio';

export type AppState = Required<DeepNonNullable<AppStore>>;

export const store = proxy<AppState>({
transientState: {} as PopupTransientState,
} as AppState);

// easier access to the store via this hook
export const useAppState = () => useSnapshot(store);

export const dispatch = async ({ type, data }: Actions) => {
switch (type) {
case 'SET_DATA_APP':
for (const key of Object.keys(data) as Array<keyof AppState>) {
// @ts-expect-error we know TypeScript
store[key] = data[key];
}
break;
case 'SET_TRANSIENT_STATE':
store.transientState = data;
break;
default:
throw new Error('Unknown action');
}
};

type Actions =
| { type: 'SET_TRANSIENT_STATE'; data: PopupTransientState }
| { type: 'SET_DATA_APP'; data: Pick<Storage, 'connected' | 'publicKey'> };
Loading

0 comments on commit da412e5

Please sign in to comment.