From f20b5da8e4c7c340c156e5fd788fcda6b789dd6c Mon Sep 17 00:00:00 2001 From: thislight Date: Wed, 4 Dec 2024 23:42:16 +0800 Subject: [PATCH] serviceworker: fix type errors --- src/serviceworker/main.ts | 31 ++++++++++------- src/serviceworker/tsconfig.json | 6 ++-- src/serviceworker/workerrpc.ts | 61 +++++++++++++++++++-------------- tsconfig.json | 19 +++------- tsconfig.super.json | 17 +++++++++ 5 files changed, 80 insertions(+), 54 deletions(-) create mode 100644 tsconfig.super.json diff --git a/src/serviceworker/main.ts b/src/serviceworker/main.ts index 71a4f37..99305a9 100644 --- a/src/serviceworker/main.ts +++ b/src/serviceworker/main.ts @@ -4,23 +4,27 @@ import { dispatchCall, isJSONRPCCall, type Call } from "./workerrpc"; function isServiceWorker( self: WorkerGlobalScope, + // @ts-ignore: workaround for workbox logger.d.ts decl ): self is ServiceWorkerGlobalScope { - return !!(self as unknown as ServiceWorkerGlobalScope).registration; + return ( + (self as unknown as Record)["serviceWorker"] instanceof + ServiceWorker + ); } -if (isServiceWorker(self)) { - cleanupOutdatedCaches(); - precacheAndRoute(self.__WB_MANIFEST, { - cleanURLs: false, - }); - - // auto update - self.skipWaiting(); - clientsClaim(); -} else { +if (!isServiceWorker(self)) { throw new TypeError("This entry point must be run in a service worker"); } +cleanupOutdatedCaches(); +precacheAndRoute(self.__WB_MANIFEST, { + cleanURLs: false, +}); + +// auto update +self.skipWaiting(); +clientsClaim(); + export const Service = { ping() {}, }; @@ -29,6 +33,9 @@ self.addEventListener("message", (event: MessageEvent) => { const payload = event.data; if (typeof payload !== "object") return; if (isJSONRPCCall(payload as Record)) { - dispatchCall(Service, event as MessageEvent>); + dispatchCall( + Service, + event as MessageEvent> & { source: MessageEventSource }, + ); } }); diff --git a/src/serviceworker/tsconfig.json b/src/serviceworker/tsconfig.json index bc88f57..090edc2 100644 --- a/src/serviceworker/tsconfig.json +++ b/src/serviceworker/tsconfig.json @@ -1,5 +1,7 @@ { "compilerOptions": { - "lib": ["ESNext", "WebWorker"], + "lib": ["WebWorker", "ESNext"], }, -} \ No newline at end of file + "extends": ["../../tsconfig.super.json"], + "include": ["./**/*.ts"], +} diff --git a/src/serviceworker/workerrpc.ts b/src/serviceworker/workerrpc.ts index 84bb39f..7680716 100644 --- a/src/serviceworker/workerrpc.ts +++ b/src/serviceworker/workerrpc.ts @@ -46,7 +46,7 @@ export type Result = JSONRPC & { id: string | number } & ( export function isJSONRPCResult( object: Record, ): object is Result { - return object["jsonrpc"] === "2.0" && object["id"] && !object["method"]; + return !!(object["jsonrpc"] === "2.0" && object["id"] && !object["method"]); } export function isJSONRPCCall( @@ -114,6 +114,9 @@ export class ResultDispatcher { { const callback = this.map.get(id); if (!callback) return; + // Now the callback is not undefined + + // Fast path if (typeof callback !== "boolean") { callback(message); this.map.delete(id); @@ -121,28 +124,30 @@ export class ResultDispatcher { } } - return new Promise((resolve) => { - let retried = 0; + const { promise, resolve } = Promise.withResolvers(); - const checkAndDispatch = () => { - const callback = this.map.get(id); - if (typeof callback !== "boolean") { - callback(message); - this.map.delete(id); - resolve(); - return; - } - setTimeout(checkAndDispatch, 0); - if (++retried > 3) { - console.warn( - `retried ${retried} time(s) but the callback is still disappeared, id is "${id}"`, - ); - } - }; + let retried = 0; - // start the loop - checkAndDispatch(); - }); + const checkAndDispatch = () => { + const callback = this.map.get(id); + if (typeof callback !== "boolean") { + callback!(message); // the nullability is already checked before + this.map.delete(id); + resolve(undefined); + return; + } + setTimeout(checkAndDispatch, 0); + if (++retried > 3) { + console.warn( + `retried ${retried} time(s) but the callback is still disappeared, id is "${id}"`, + ); + } + }; + + // start the loop + checkAndDispatch(); + + return promise; } createTypedCall< @@ -159,14 +164,16 @@ export class ResultDispatcher { } } -type AnyService = Record unknown) | undefined> +type AnyService = Record unknown>; -export async function dispatchCall< - S extends AnyService, ->(service: S, event: MessageEvent>) { +export async function dispatchCall>( + service: S, + event: MessageEvent> & { source: MessageEventSource }, +) { try { const fn = service[event.data.method]; if (!fn) { + console.warn("requested unknown method", event.data.method, event.data); if (event.data.id) return event.source.postMessage({ jsonrpc: "2.0", @@ -176,10 +183,12 @@ export async function dispatchCall< message: "Method not found", }, } as Result); + + return; } try { - const result = await fn(...event.data.params as unknown[]); + const result = await fn(...(event.data.params as unknown[])); if (!event.data.id) return; diff --git a/tsconfig.json b/tsconfig.json index b92e528..feaab58 100644 --- a/tsconfig.json +++ b/tsconfig.json @@ -1,20 +1,11 @@ { "compilerOptions": { - "strict": true, - "target": "ESNext", - "module": "esnext", - "moduleResolution": "node", - "allowSyntheticDefaultImports": true, - "esModuleInterop": true, "jsx": "preserve", "jsxImportSource": "solid-js", "types": ["vite/client", "vite-plugin-pwa/solid"], - "noEmit": true, - "isolatedModules": true, - "resolveJsonModule": true, - "paths": { - "~platform/*": ["./src/platform/*"], - "~material/*": ["./src/material/*"] - } - } + "lib": ["ESNext", "DOM", "DOM.Iterable"] + }, + "include": ["./src/**/*.ts", "./src/**/*.tsx", "./*.ts", "./types/**.ts"], + "exclude": ["./src/serviceworker/**"], + "extends": ["./tsconfig.super.json"] } diff --git a/tsconfig.super.json b/tsconfig.super.json new file mode 100644 index 0000000..9cf8e60 --- /dev/null +++ b/tsconfig.super.json @@ -0,0 +1,17 @@ +{ + "compilerOptions": { + "strict": true, + "target": "ESNext", + "module": "esnext", + "moduleResolution": "node", + "allowSyntheticDefaultImports": true, + "esModuleInterop": true, + "noEmit": true, + "isolatedModules": true, + "resolveJsonModule": true, + "paths": { + "~platform/*": ["./src/platform/*"], + "~material/*": ["./src/material/*"] + } + } +}