From 53f4d97c26287f7aa7f019f22301b375e4f4435c Mon Sep 17 00:00:00 2001 From: axuj Date: Wed, 17 Jul 2024 23:11:27 +0800 Subject: [PATCH] =?UTF-8?q?=E2=9C=A8=20feat:=20background=20error=20handli?= =?UTF-8?q?ng?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- package.json | 1 + pnpm-lock.yaml | 139 ++++++++++++++++++++++++++++++++- src/createBackgroundHandler.ts | 9 ++- src/createWebextRpcCaller.ts | 18 ++--- src/types.ts | 18 +++-- src/utils/createRpcCaller.ts | 6 +- src/utils/handleCall.ts | 9 ++- src/utils/util.ts | 16 +++- 8 files changed, 187 insertions(+), 29 deletions(-) diff --git a/package.json b/package.json index 8abf915..5b8dc71 100644 --- a/package.json +++ b/package.json @@ -53,6 +53,7 @@ "webextension-polyfill": "^0.12.0" }, "devDependencies": { + "@swc/core": "^1.6.13", "@types/webextension-polyfill": "^0.10.7", "@vitest/coverage-v8": "^2.0.3", "tsup": "^8.1.1", diff --git a/pnpm-lock.yaml b/pnpm-lock.yaml index ce27325..670676f 100644 --- a/pnpm-lock.yaml +++ b/pnpm-lock.yaml @@ -12,6 +12,9 @@ importers: specifier: ^0.12.0 version: 0.12.0 devDependencies: + '@swc/core': + specifier: ^1.6.13 + version: 1.6.13 '@types/webextension-polyfill': specifier: ^0.10.7 version: 0.10.7 @@ -20,7 +23,7 @@ importers: version: 2.0.3(vitest@2.0.3(@types/node@20.14.11)) tsup: specifier: ^8.1.1 - version: 8.1.1(postcss@8.4.39)(tsx@4.16.2)(typescript@5.5.3)(yaml@2.4.5) + version: 8.1.1(@swc/core@1.6.13)(postcss@8.4.39)(tsx@4.16.2)(typescript@5.5.3)(yaml@2.4.5) tsx: specifier: ^4.16.2 version: 4.16.2 @@ -473,6 +476,85 @@ packages: cpu: [x64] os: [win32] + '@swc/core-darwin-arm64@1.6.13': + resolution: {integrity: sha512-SOF4buAis72K22BGJ3N8y88mLNfxLNprTuJUpzikyMGrvkuBFNcxYtMhmomO0XHsgLDzOJ+hWzcgjRNzjMsUcQ==} + engines: {node: '>=10'} + cpu: [arm64] + os: [darwin] + + '@swc/core-darwin-x64@1.6.13': + resolution: {integrity: sha512-AW8akFSC+tmPE6YQQvK9S2A1B8pjnXEINg+gGgw0KRUUXunvu1/OEOeC5L2Co1wAwhD7bhnaefi06Qi9AiwOag==} + engines: {node: '>=10'} + cpu: [x64] + os: [darwin] + + '@swc/core-linux-arm-gnueabihf@1.6.13': + resolution: {integrity: sha512-f4gxxvDXVUm2HLYXRd311mSrmbpQF2MZ4Ja6XCQz1hWAxXdhRl1gpnZ+LH/xIfGSwQChrtLLVrkxdYUCVuIjFg==} + engines: {node: '>=10'} + cpu: [arm] + os: [linux] + + '@swc/core-linux-arm64-gnu@1.6.13': + resolution: {integrity: sha512-Nf/eoW2CbG8s+9JoLtjl9FByBXyQ5cjdBsA4efO7Zw4p+YSuXDgc8HRPC+E2+ns0praDpKNZtLvDtmF2lL+2Gg==} + engines: {node: '>=10'} + cpu: [arm64] + os: [linux] + libc: [glibc] + + '@swc/core-linux-arm64-musl@1.6.13': + resolution: {integrity: sha512-2OysYSYtdw79prJYuKIiux/Gj0iaGEbpS2QZWCIY4X9sGoETJ5iMg+lY+YCrIxdkkNYd7OhIbXdYFyGs/w5LDg==} + engines: {node: '>=10'} + cpu: [arm64] + os: [linux] + libc: [musl] + + '@swc/core-linux-x64-gnu@1.6.13': + resolution: {integrity: sha512-PkR4CZYJNk5hcd2+tMWBpnisnmYsUzazI1O5X7VkIGFcGePTqJ/bWlfUIVVExWxvAI33PQFzLbzmN5scyIUyGQ==} + engines: {node: '>=10'} + cpu: [x64] + os: [linux] + libc: [glibc] + + '@swc/core-linux-x64-musl@1.6.13': + resolution: {integrity: sha512-OdsY7wryTxCKwGQcwW9jwWg3cxaHBkTTHi91+5nm7hFPpmZMz1HivJrWAMwVE7iXFw+M4l6ugB/wCvpYrUAAjA==} + engines: {node: '>=10'} + cpu: [x64] + os: [linux] + libc: [musl] + + '@swc/core-win32-arm64-msvc@1.6.13': + resolution: {integrity: sha512-ap6uNmYjwk9M/+bFEuWRNl3hq4VqgQ/Lk+ID/F5WGqczNr0L7vEf+pOsRAn0F6EV+o/nyb3ePt8rLhE/wjHpPg==} + engines: {node: '>=10'} + cpu: [arm64] + os: [win32] + + '@swc/core-win32-ia32-msvc@1.6.13': + resolution: {integrity: sha512-IJ8KH4yIUHTnS/U1jwQmtbfQals7zWPG0a9hbEfIr4zI0yKzjd83lmtS09lm2Q24QBWOCFGEEbuZxR4tIlvfzA==} + engines: {node: '>=10'} + cpu: [ia32] + os: [win32] + + '@swc/core-win32-x64-msvc@1.6.13': + resolution: {integrity: sha512-f6/sx6LMuEnbuxtiSL/EkR0Y6qUHFw1XVrh6rwzKXptTipUdOY+nXpKoh+1UsBm/r7H0/5DtOdrn3q5ZHbFZjQ==} + engines: {node: '>=10'} + cpu: [x64] + os: [win32] + + '@swc/core@1.6.13': + resolution: {integrity: sha512-eailUYex6fkfaQTev4Oa3mwn0/e3mQU4H8y1WPuImYQESOQDtVrowwUGDSc19evpBbHpKtwM+hw8nLlhIsF+Tw==} + engines: {node: '>=10'} + peerDependencies: + '@swc/helpers': '*' + peerDependenciesMeta: + '@swc/helpers': + optional: true + + '@swc/counter@0.1.3': + resolution: {integrity: sha512-e2BR4lsJkkRlKZ/qCHPw9ZaSxc0MVUd7gtbtaB7aMvHeJVYe8sOB8DBZkP2DtISHGSku9sCK6T6cnY0CtXrOCQ==} + + '@swc/types@0.1.9': + resolution: {integrity: sha512-qKnCno++jzcJ4lM4NTfYifm1EFSCeIfKiAHAfkENZAV5Kl9PjJIyd2yeeVv6c/2CckuLyv2NmRC5pv6pm2WQBg==} + '@types/estree@1.0.5': resolution: {integrity: sha512-/kYRxGDLWzHOB7q+wtSUQlFrtcdUccpfy+X+9iMBpHK8QLLhx2wIPYuS5DYtR9Wa/YlZAbIovy7qVdB1Aq6Lyw==} @@ -1450,6 +1532,58 @@ snapshots: '@rollup/rollup-win32-x64-msvc@4.18.1': optional: true + '@swc/core-darwin-arm64@1.6.13': + optional: true + + '@swc/core-darwin-x64@1.6.13': + optional: true + + '@swc/core-linux-arm-gnueabihf@1.6.13': + optional: true + + '@swc/core-linux-arm64-gnu@1.6.13': + optional: true + + '@swc/core-linux-arm64-musl@1.6.13': + optional: true + + '@swc/core-linux-x64-gnu@1.6.13': + optional: true + + '@swc/core-linux-x64-musl@1.6.13': + optional: true + + '@swc/core-win32-arm64-msvc@1.6.13': + optional: true + + '@swc/core-win32-ia32-msvc@1.6.13': + optional: true + + '@swc/core-win32-x64-msvc@1.6.13': + optional: true + + '@swc/core@1.6.13': + dependencies: + '@swc/counter': 0.1.3 + '@swc/types': 0.1.9 + optionalDependencies: + '@swc/core-darwin-arm64': 1.6.13 + '@swc/core-darwin-x64': 1.6.13 + '@swc/core-linux-arm-gnueabihf': 1.6.13 + '@swc/core-linux-arm64-gnu': 1.6.13 + '@swc/core-linux-arm64-musl': 1.6.13 + '@swc/core-linux-x64-gnu': 1.6.13 + '@swc/core-linux-x64-musl': 1.6.13 + '@swc/core-win32-arm64-msvc': 1.6.13 + '@swc/core-win32-ia32-msvc': 1.6.13 + '@swc/core-win32-x64-msvc': 1.6.13 + + '@swc/counter@0.1.3': {} + + '@swc/types@0.1.9': + dependencies: + '@swc/counter': 0.1.3 + '@types/estree@1.0.5': {} '@types/fs-extra@11.0.4': @@ -2072,7 +2206,7 @@ snapshots: ts-interface-checker@0.1.13: {} - tsup@8.1.1(postcss@8.4.39)(tsx@4.16.2)(typescript@5.5.3)(yaml@2.4.5): + tsup@8.1.1(@swc/core@1.6.13)(postcss@8.4.39)(tsx@4.16.2)(typescript@5.5.3)(yaml@2.4.5): dependencies: bundle-require: 5.0.0(esbuild@0.23.0) cac: 6.7.14 @@ -2090,6 +2224,7 @@ snapshots: sucrase: 3.35.0 tree-kill: 1.2.2 optionalDependencies: + '@swc/core': 1.6.13 postcss: 8.4.39 typescript: 5.5.3 transitivePeerDependencies: diff --git a/src/createBackgroundHandler.ts b/src/createBackgroundHandler.ts index 7892281..3352b70 100644 --- a/src/createBackgroundHandler.ts +++ b/src/createBackgroundHandler.ts @@ -1,8 +1,8 @@ import Browser from 'webextension-polyfill' import { C2BMessage, RouterRecord } from './types' -import { toError } from './utils/util' import { handleCall } from './utils/handleCall' import { DEFAULT_PORT_NAME } from './port_name' +import { toErrorMessage } from './utils' export function createBackgroundHandler( router: RouterRecord, @@ -15,8 +15,9 @@ export function createBackgroundHandler( port.onMessage.addListener(async (message: C2BMessage) => { const { calls, args } = message - function throwError(error: Error) { - port.postMessage({ error: error.message }) + function throwError(error: unknown) { + const error_message = toErrorMessage(error) + port.postMessage({ error: error_message }) throw error } try { @@ -26,7 +27,7 @@ export function createBackgroundHandler( port.postMessage(message) }) } catch (error) { - throwError(toError(error)) + throwError(error) } finally { port.disconnect() } diff --git a/src/createWebextRpcCaller.ts b/src/createWebextRpcCaller.ts index 84fe66b..1eed4d2 100644 --- a/src/createWebextRpcCaller.ts +++ b/src/createWebextRpcCaller.ts @@ -1,18 +1,13 @@ import Browser from 'webextension-polyfill' import { ExposedPromise } from './utils' -import type { - B2CMessage, - C2BMessage, - PromisifiedRouter, - RouterRecord, -} from './types' +import type { B2CMessage, RpcRouter, RouterRecord } from './types' import { MessageStream } from './utils' import { createRpcCaller } from './utils/createRpcCaller' import { DEFAULT_PORT_NAME } from './port_name' export const createWebextRpcCaller = ( port_name: string = DEFAULT_PORT_NAME -): PromisifiedRouter => { +): RpcRouter => { return createRpcCaller((calls, args) => { const port = Browser.runtime.connect({ name: port_name, @@ -21,8 +16,13 @@ export const createWebextRpcCaller = ( const exposedPromise = new ExposedPromise() let messageStream: MessageStream | null = null port.onMessage.addListener((message: B2CMessage) => { - if (message.error != undefined) { - throw new Error(message.error) + if (message.error) { + const error = new Error(message.error.message) + error.stack = + '[webext-rpc background function error]' + message.error.stack + error.name = message.error.name + exposedPromise.reject(error) + return } // stream diff --git a/src/types.ts b/src/types.ts index e8d666e..4720298 100644 --- a/src/types.ts +++ b/src/types.ts @@ -16,8 +16,14 @@ interface NonStreamMessage extends BaseMessage { isStream: false } -interface ErrorMessage { - error: string +export interface ErrorSerializable { + message: string + stack?: string + name: string +} + +export interface ErrorMessage { + error: ErrorSerializable } export type B2CMessage = ErrorMessage | StreamMessage | NonStreamMessage @@ -27,7 +33,7 @@ export interface C2BMessage { args: any[] } -export type Promisify = T extends (...args: infer A) => infer R +export type RpcFunction = T extends (...args: infer A) => infer R ? ( ...args: A ) => R extends Promise @@ -37,8 +43,8 @@ export type Promisify = T extends (...args: infer A) => infer R : Promise : Promise -export type PromisifiedRouter = { +export type RpcRouter = { [K in keyof T]: T[K] extends (...args: any) => any - ? Promisify - : PromisifiedRouter + ? RpcFunction + : RpcRouter } diff --git a/src/utils/createRpcCaller.ts b/src/utils/createRpcCaller.ts index 31b5897..5bcbdef 100644 --- a/src/utils/createRpcCaller.ts +++ b/src/utils/createRpcCaller.ts @@ -1,8 +1,8 @@ -import { PromisifiedRouter, RouterRecord } from '../types' +import { RpcRouter, RouterRecord } from '../types' export function createRpcCaller( callbacks: (calls: string[], args: any[]) => Promise -): PromisifiedRouter { +): RpcRouter { const createProxyObject = (calls: string[] = []): any => { const handler: ProxyHandler = { get(_thisArg, prop, receiver) { @@ -15,5 +15,5 @@ export function createRpcCaller( return new Proxy(() => {}, handler) } - return createProxyObject() as PromisifiedRouter + return createProxyObject() as RpcRouter } diff --git a/src/utils/handleCall.ts b/src/utils/handleCall.ts index 9c918d5..1ddc08c 100644 --- a/src/utils/handleCall.ts +++ b/src/utils/handleCall.ts @@ -40,8 +40,13 @@ export async function handleCall( sendMessage({ isStream: false, value }) return } - sendMessage({ error: 'Unsupported generator type' }) - throw new Error('Unsupported generator type') + const error = { + message: 'Unsupported type of generator', + stack: new Error().stack, + name: 'UnsupportedType', + } + sendMessage({ error }) + throw error } //Other diff --git a/src/utils/util.ts b/src/utils/util.ts index 439f32e..e88a681 100644 --- a/src/utils/util.ts +++ b/src/utils/util.ts @@ -1,6 +1,16 @@ -export function toError(error: unknown) { +import { ErrorSerializable } from '../types' + +export function toErrorMessage(error: unknown): ErrorSerializable { if (error instanceof Error) { - return error + return { + message: error.message, + stack: error.stack, + name: error.name, + } + } + return { + message: String(error), + stack: '', + name: 'UnknownError', } - return new Error(String(error)) }