Use synchronous listener registration

This commit is contained in:
Eduard Bardají Puig
2024-08-27 15:32:30 +02:00
parent ef8cd1000b
commit 407a9f031d
5 changed files with 116 additions and 77 deletions

64
package-lock.json generated
View File

@@ -11,7 +11,7 @@
"@aryzing/superqs": "0.0.6",
"@ledgerhq/hw-transport-webusb": "^6.27.13",
"@phosphor-icons/react": "^2.0.10",
"@playwright/test": "1.45.2",
"@playwright/test": "1.46.1",
"@react-spring/web": "^9.6.1",
"@sats-connect/core": "0.2.1",
"@scure/btc-signer": "1.2.1",
@@ -101,7 +101,7 @@
"eslint-plugin-import": "^2.26.0",
"eslint-plugin-jsx-a11y": "^6.6.1",
"eslint-plugin-no-inline-styles": "^1.0.5",
"eslint-plugin-playwright": "^1.6.0",
"eslint-plugin-playwright": "^1.6.2",
"eslint-plugin-prettier": "^4.2.1",
"eslint-plugin-react": "^7.31.8",
"eslint-plugin-react-hooks": "^4.6.0",
@@ -1394,12 +1394,12 @@
}
},
"node_modules/@playwright/test": {
"version": "1.45.2",
"resolved": "https://registry.npmjs.org/@playwright/test/-/test-1.45.2.tgz",
"integrity": "sha512-JxG9eq92ET75EbVi3s+4sYbcG7q72ECeZNbdBlaMkGcNbiDQ4cAi8U2QP5oKkOx+1gpaiL1LDStmzCaEM1Z6fQ==",
"version": "1.46.1",
"resolved": "https://registry.npmjs.org/@playwright/test/-/test-1.46.1.tgz",
"integrity": "sha512-Fq6SwLujA/DOIvNC2EL/SojJnkKf/rAwJ//APpJJHRyMi1PdKrY3Az+4XNQ51N4RTbItbIByQ0jgd1tayq1aeA==",
"license": "Apache-2.0",
"dependencies": {
"playwright": "1.45.2"
"playwright": "1.46.1"
},
"bin": {
"playwright": "cli.js"
@@ -6514,10 +6514,14 @@
}
},
"node_modules/eslint-plugin-playwright": {
"version": "1.6.0",
"resolved": "https://registry.npmjs.org/eslint-plugin-playwright/-/eslint-plugin-playwright-1.6.0.tgz",
"integrity": "sha512-tI1E/EDbHT4Fx5KvukUG3RTIT0gk44gvTP8bNwxLCFsUXVM98ZJG5zWU6Om5JOzH9FrmN4AhMu/UKyEsu0ZoDA==",
"version": "1.6.2",
"resolved": "https://registry.npmjs.org/eslint-plugin-playwright/-/eslint-plugin-playwright-1.6.2.tgz",
"integrity": "sha512-mraN4Em3b5jLt01q7qWPyLg0Q5v3KAWfJSlEWwldyUXoa7DSPrBR4k6B6LROLqipsG8ndkwWMdjl1Ffdh15tag==",
"dev": true,
"license": "MIT",
"workspaces": [
"examples"
],
"dependencies": {
"globals": "^13.23.0"
},
@@ -10632,12 +10636,12 @@
}
},
"node_modules/playwright": {
"version": "1.45.2",
"resolved": "https://registry.npmjs.org/playwright/-/playwright-1.45.2.tgz",
"integrity": "sha512-ReywF2t/0teRvNBpfIgh5e4wnrI/8Su8ssdo5XsQKpjxJj+jspm00jSoz9BTg91TT0c9HRjXO7LBNVrgYj9X0g==",
"version": "1.46.1",
"resolved": "https://registry.npmjs.org/playwright/-/playwright-1.46.1.tgz",
"integrity": "sha512-oPcr1yqoXLCkgKtD5eNUPLiN40rYEM39odNpIb6VE6S7/15gJmA1NzVv6zJYusV0e7tzvkU/utBFNa/Kpxmwng==",
"license": "Apache-2.0",
"dependencies": {
"playwright-core": "1.45.2"
"playwright-core": "1.46.1"
},
"bin": {
"playwright": "cli.js"
@@ -10650,9 +10654,9 @@
}
},
"node_modules/playwright-core": {
"version": "1.45.2",
"resolved": "https://registry.npmjs.org/playwright-core/-/playwright-core-1.45.2.tgz",
"integrity": "sha512-ha175tAWb0dTK0X4orvBIqi3jGEt701SMxMhyujxNrgd8K0Uy5wMSwwcQHtyB4om7INUkfndx02XnQ2p6dvLDw==",
"version": "1.46.1",
"resolved": "https://registry.npmjs.org/playwright-core/-/playwright-core-1.46.1.tgz",
"integrity": "sha512-h9LqIQaAv+CYvWzsZ+h3RsrqCStkBHlgo6/TJlFst3cOTlLghBQlJwPOZKQJTKNaD3QIB7aAVQ+gfWbN3NXB7A==",
"license": "Apache-2.0",
"bin": {
"playwright-core": "cli.js"
@@ -15053,11 +15057,11 @@
"requires": {}
},
"@playwright/test": {
"version": "1.45.2",
"resolved": "https://registry.npmjs.org/@playwright/test/-/test-1.45.2.tgz",
"integrity": "sha512-JxG9eq92ET75EbVi3s+4sYbcG7q72ECeZNbdBlaMkGcNbiDQ4cAi8U2QP5oKkOx+1gpaiL1LDStmzCaEM1Z6fQ==",
"version": "1.46.1",
"resolved": "https://registry.npmjs.org/@playwright/test/-/test-1.46.1.tgz",
"integrity": "sha512-Fq6SwLujA/DOIvNC2EL/SojJnkKf/rAwJ//APpJJHRyMi1PdKrY3Az+4XNQ51N4RTbItbIByQ0jgd1tayq1aeA==",
"requires": {
"playwright": "1.45.2"
"playwright": "1.46.1"
}
},
"@pmmmwh/react-refresh-webpack-plugin": {
@@ -19140,9 +19144,9 @@
}
},
"eslint-plugin-playwright": {
"version": "1.6.0",
"resolved": "https://registry.npmjs.org/eslint-plugin-playwright/-/eslint-plugin-playwright-1.6.0.tgz",
"integrity": "sha512-tI1E/EDbHT4Fx5KvukUG3RTIT0gk44gvTP8bNwxLCFsUXVM98ZJG5zWU6Om5JOzH9FrmN4AhMu/UKyEsu0ZoDA==",
"version": "1.6.2",
"resolved": "https://registry.npmjs.org/eslint-plugin-playwright/-/eslint-plugin-playwright-1.6.2.tgz",
"integrity": "sha512-mraN4Em3b5jLt01q7qWPyLg0Q5v3KAWfJSlEWwldyUXoa7DSPrBR4k6B6LROLqipsG8ndkwWMdjl1Ffdh15tag==",
"dev": true,
"requires": {
"globals": "^13.23.0"
@@ -22038,12 +22042,12 @@
}
},
"playwright": {
"version": "1.45.2",
"resolved": "https://registry.npmjs.org/playwright/-/playwright-1.45.2.tgz",
"integrity": "sha512-ReywF2t/0teRvNBpfIgh5e4wnrI/8Su8ssdo5XsQKpjxJj+jspm00jSoz9BTg91TT0c9HRjXO7LBNVrgYj9X0g==",
"version": "1.46.1",
"resolved": "https://registry.npmjs.org/playwright/-/playwright-1.46.1.tgz",
"integrity": "sha512-oPcr1yqoXLCkgKtD5eNUPLiN40rYEM39odNpIb6VE6S7/15gJmA1NzVv6zJYusV0e7tzvkU/utBFNa/Kpxmwng==",
"requires": {
"fsevents": "2.3.2",
"playwright-core": "1.45.2"
"playwright-core": "1.46.1"
},
"dependencies": {
"fsevents": {
@@ -22055,9 +22059,9 @@
}
},
"playwright-core": {
"version": "1.45.2",
"resolved": "https://registry.npmjs.org/playwright-core/-/playwright-core-1.45.2.tgz",
"integrity": "sha512-ha175tAWb0dTK0X4orvBIqi3jGEt701SMxMhyujxNrgd8K0Uy5wMSwwcQHtyB4om7INUkfndx02XnQ2p6dvLDw=="
"version": "1.46.1",
"resolved": "https://registry.npmjs.org/playwright-core/-/playwright-core-1.46.1.tgz",
"integrity": "sha512-h9LqIQaAv+CYvWzsZ+h3RsrqCStkBHlgo6/TJlFst3cOTlLghBQlJwPOZKQJTKNaD3QIB7aAVQ+gfWbN3NXB7A=="
},
"postcss": {
"version": "8.4.39",

View File

@@ -40,7 +40,7 @@
"@aryzing/superqs": "0.0.6",
"@ledgerhq/hw-transport-webusb": "^6.27.13",
"@phosphor-icons/react": "^2.0.10",
"@playwright/test": "1.45.2",
"@playwright/test": "1.46.1",
"@react-spring/web": "^9.6.1",
"@sats-connect/core": "0.2.1",
"@scure/btc-signer": "1.2.1",
@@ -130,7 +130,7 @@
"eslint-plugin-import": "^2.26.0",
"eslint-plugin-jsx-a11y": "^6.6.1",
"eslint-plugin-no-inline-styles": "^1.0.5",
"eslint-plugin-playwright": "^1.6.0",
"eslint-plugin-playwright": "^1.6.2",
"eslint-plugin-prettier": "^4.2.1",
"eslint-plugin-react": "^7.31.8",
"eslint-plugin-react-hooks": "^4.6.0",

View File

@@ -18,10 +18,10 @@ export default defineConfig({
forbidOnly: !!process.env.CI,
/* Retry on CI only */
retries: process.env.CI ? 1 : 0,
/* Opt to only 2 tests parallel on CI.
Note that you may want to change the non-ci amount to a lower number depending on
the specs of your computer or if the number of tests increases over time.
*/
/* Opt to only 2 tests parallel on CI. Note that you may want to change the
* non-ci amount to a lower number depending on the specs of your computer or
* if the number of tests increases over time.
*/
workers: process.env.CI ? 2 : 5,
/* Reporter to use. See https://playwright.dev/docs/test-reporters */
reporter: process.env.CI ? 'blob' : 'html',

View File

@@ -7,49 +7,84 @@ import { initPermissionsStore, permissionsStoreMutex } from '@components/permiss
import { rpcRequestMessageSchema } from '@sats-connect/core';
import * as v from 'valibot';
async function init() {
const [error] = await permissionsStoreMutex.runExclusive(initPermissionsStore);
if (error) {
// eslint-disable-next-line no-console
console.error('Failed to load permissions store:', error);
}
// Listen for connection to the content-script - port for two-way communication
chrome.runtime.onConnect.addListener((port) => {
if (port.name !== CONTENT_SCRIPT_PORT) return;
port.onMessage.addListener((message, messagingPort) => {
const parseResult = v.safeParse(rpcRequestMessageSchema, message);
if (!parseResult.success) {
// Assume it's a legacy message when parsing fails.
handleLegacyExternalMethodFormat(message, messagingPort);
return;
}
handleRPCRequest(parseResult.output, port);
});
});
chrome.runtime.onMessage.addListener((message, sender, sendResponse) => {
void internalBackgroundMessageHandler(message, sender, sendResponse);
// Listener fn must return `true` to indicate the response will be async
return true;
});
chrome.runtime.onInstalled.addListener((details) => {
if (details.reason === 'install') {
chrome.tabs.create({ url: chrome.runtime.getURL('options.html#/landing') });
let hasInitializationFinished = false;
permissionsStoreMutex
.runExclusive(initPermissionsStore)
.catch(([error]) => {
if (error) {
// eslint-disable-next-line no-console
console.error('Failed to load permissions store:', error);
}
})
// Even if the store initialization fails, the initialization is considered to
// have finished. This allows the app to continue running after a failure
// since many of the app's features are not dependent on the permissions
// store.
.finally(() => {
hasInitializationFinished = true;
});
if (process.env.WALLET_LABEL) {
chrome.action.setBadgeText({ text: process.env.WALLET_LABEL });
} else if (process.env.NODE_ENV === 'development') {
chrome.action.setBadgeText({ text: 'DEV' });
}
// All event handlers that could potentially lead to the permissions store
// being accessed should wait for the store to be initialized before
// proceeding.
async function waitForStoreInitialization() {
if (hasInitializationFinished) return;
await new Promise((resolve) => {
const interval = setInterval(() => {
if (hasInitializationFinished) {
clearInterval(interval);
resolve(undefined);
}
}, 10);
});
}
await init().catch((e) => {
// eslint-disable-next-line no-console
console.error('Failed to initialize background script:', e);
// Listen for connection to the content-script - port for two-way communication
chrome.runtime.onConnect.addListener((port) => {
if (port.name !== CONTENT_SCRIPT_PORT) return;
async function onMessageListener(message: any, messagingPort: chrome.runtime.Port) {
await waitForStoreInitialization();
const parseResult = v.safeParse(rpcRequestMessageSchema, message);
if (!parseResult.success) {
// Assume it's a legacy message when parsing fails.
handleLegacyExternalMethodFormat(message, messagingPort);
return;
}
handleRPCRequest(parseResult.output, port);
}
port.onMessage.addListener((message, messagingPort) => {
onMessageListener(message, messagingPort).catch((error) => {
// eslint-disable-next-line no-console
console.error('Failed to handle message:', error);
});
});
});
chrome.runtime.onMessage.addListener((message, sender, sendResponse) => {
void internalBackgroundMessageHandler(message, sender, sendResponse);
// Listener fn must return `true` to indicate the response will be async
return true;
});
async function onInstalledListener(details: chrome.runtime.InstalledDetails) {
await waitForStoreInitialization();
if (details.reason === 'install') {
chrome.tabs.create({ url: chrome.runtime.getURL('options.html#/landing') });
}
}
chrome.runtime.onInstalled.addListener((details) => {
onInstalledListener(details).catch((error) => {
// eslint-disable-next-line no-console
console.error('Failed to handle onInstalled event:', error);
});
});
if (process.env.WALLET_LABEL) {
chrome.action.setBadgeText({ text: process.env.WALLET_LABEL });
} else if (process.env.NODE_ENV === 'development') {
chrome.action.setBadgeText({ text: 'DEV' });
}

View File

@@ -32,7 +32,7 @@ export const test = baseTest.extend<{
// Xverse opens the landing page on install. Wait for it to load and
// use it as the main page by closing the default page.
// we give it 5 secs to start up
const MAX_STARTUP_TIME = 5000;
const MAX_STARTUP_TIME = 5_000;
const startTime = Date.now();
while (context.pages().length === 1) {
if (Date.now() - startTime > MAX_STARTUP_TIME) {