Skip to content

Commit

Permalink
Refactor popup ready msging
Browse files Browse the repository at this point in the history
  • Loading branch information
JasonMHasperhoven committed Aug 27, 2024
1 parent 7e7355b commit 6829bf6
Show file tree
Hide file tree
Showing 3 changed files with 18 additions and 55 deletions.
11 changes: 3 additions & 8 deletions apps/extension/src/hooks/popup-ready.ts
Original file line number Diff line number Diff line change
@@ -1,24 +1,19 @@
import { useEffect, useRef } from 'react';
import { PopupResponse, PopupType, Ready } from '../message/popup';
import { useSearchParams } from 'react-router-dom';

type IsReady = boolean | undefined;

// signals that react is ready (mounted) to service worker
export const usePopupReady = (isReady: IsReady = undefined) => {
const sentMessagesRef = useRef(new Set());
const searchParams = new URLSearchParams(window.location.search);
const [searchParams] = useSearchParams();
const popupId = searchParams.get('popupId');

useEffect(() => {
if (popupId && (isReady === undefined || isReady) && !sentMessagesRef.current.has(popupId)) {
sentMessagesRef.current.add(popupId);

void chrome.runtime.sendMessage({
type: PopupType.Ready,
data: {
popupId,
},
} as PopupResponse<Ready>);
void chrome.runtime.sendMessage(popupId);
}
}, [popupId, isReady]);
};
26 changes: 3 additions & 23 deletions apps/extension/src/message/popup.ts
Original file line number Diff line number Diff line change
Expand Up @@ -11,10 +11,9 @@ import { OriginRecord } from '../storage/types';
export enum PopupType {
TxApproval = 'TxApproval',
OriginApproval = 'OriginApproval',
Ready = 'PopupReady',
}

export type PopupMessage = TxApproval | OriginApproval | Ready;
export type PopupMessage = TxApproval | OriginApproval;
export type PopupRequest<T extends PopupMessage = PopupMessage> = InternalRequest<T>;
export type PopupResponse<T extends PopupMessage = PopupMessage> = InternalResponse<T>;

Expand All @@ -35,14 +34,6 @@ export type TxApproval = InternalMessage<
}
>;

export type Ready = InternalMessage<
PopupType.Ready,
null,
{
popupId: string;
}
>;

export const isPopupRequest = (req: unknown): req is PopupRequest =>
req != null &&
typeof req === 'object' &&
Expand All @@ -51,19 +42,8 @@ export const isPopupRequest = (req: unknown): req is PopupRequest =>
typeof req.type === 'string' &&
req.type in PopupType;

export const isPopupResponse = (res: unknown): res is PopupResponse =>
res != null &&
typeof res === 'object' &&
('data' in res || 'error' in res) &&
'type' in res &&
typeof res.type === 'string' &&
res.type in PopupType;

export const isOriginApprovalRequest = (req: unknown): req is InternalRequest<OriginApproval> =>
isPopupRequest(req) && req.type === PopupType.OriginApproval;
isPopupRequest(req) && req.type === PopupType.OriginApproval && 'origin' in req.request;

export const isTxApprovalRequest = (req: unknown): req is InternalRequest<TxApproval> =>
isPopupRequest(req) && req.type === PopupType.TxApproval;

export const isPopupReadyResponse = (res: unknown): res is InternalResponse<Ready> =>
isPopupResponse(res) && res.type === PopupType.Ready;
isPopupRequest(req) && req.type === PopupType.TxApproval && 'authorizeRequest' in req.request;
36 changes: 12 additions & 24 deletions apps/extension/src/popup.ts
Original file line number Diff line number Diff line change
@@ -1,11 +1,5 @@
import { sessionExtStorage } from './storage/session';
import {
isPopupReadyResponse,
PopupMessage,
PopupRequest,
PopupResponse,
PopupType,
} from './message/popup';
import { PopupMessage, PopupRequest, PopupType } from './message/popup';
import { PopupPath } from './routes/popup/paths';
import type { InternalRequest, InternalResponse } from '@penumbra-zone/types/internal-msg/shared';
import { Code, ConnectError } from '@connectrpc/connect';
Expand Down Expand Up @@ -82,16 +76,16 @@ const throwIfNeedsLogin = async () => {
};

const spawnPopup = async (pop: PopupType, popupId: string) => {
const popUrl = new URL(chrome.runtime.getURL(`popup.html?popupId=${popupId}`));
const popUrl = new URL(chrome.runtime.getURL('popup.html'));

await throwIfNeedsLogin();

switch (pop) {
case PopupType.OriginApproval:
popUrl.hash = PopupPath.ORIGIN_APPROVAL;
popUrl.hash = `${PopupPath.ORIGIN_APPROVAL}?popupId=${popupId}`;
return spawnDetachedPopup(popUrl.href);
case PopupType.TxApproval:
popUrl.hash = PopupPath.TRANSACTION_APPROVAL;
popUrl.hash = `${PopupPath.TRANSACTION_APPROVAL}?popupId=${popupId}`;
return spawnDetachedPopup(popUrl.href);
default:
throw Error('Unknown popup type');
Expand All @@ -100,23 +94,17 @@ const spawnPopup = async (pop: PopupType, popupId: string) => {

const POPUP_READY_TIMEOUT = 60 * 1000;

const popupReady = async (popupId: string): Promise<void> => {
return new Promise((resolve, reject): void => {
setTimeout(() => {
reject(new Error('Popup ready timed out'));
}, POPUP_READY_TIMEOUT);
const popupReady = (popupId: string): Promise<void> =>
new Promise((resolve, reject) => {
AbortSignal.timeout(POPUP_READY_TIMEOUT).onabort = reject;

const handlePopupReady = (res: PopupResponse): void => {
if (!isPopupReadyResponse(res)) {
return;
}

if ('data' in res && res.data.popupId === popupId) {
chrome.runtime.onMessage.removeListener(handlePopupReady);
const idListen = (msg: unknown, _: chrome.runtime.MessageSender, respond: () => void) => {
if (msg === popupId) {
resolve();
chrome.runtime.onMessage.removeListener(idListen);
respond();
}
};

chrome.runtime.onMessage.addListener(handlePopupReady);
chrome.runtime.onMessage.addListener(idListen);
});
};

0 comments on commit 6829bf6

Please sign in to comment.