diff --git a/.forgejo/workflows/checkpr.yml b/.forgejo/workflows/checkpr.yml deleted file mode 100644 index 2f6dc9f..0000000 --- a/.forgejo/workflows/checkpr.yml +++ /dev/null @@ -1,34 +0,0 @@ - -on: - pull_request: - types: [opened, synchronize, reopened] - -jobs: - checkpr: - runs-on: fedora-41 - steps: - - name: Checkout - uses: actions/checkout@v4 - - - name: Setup Bun - uses: oven-sh/setup-bun@v2 - with: - bun-version-file: 'package.json' - - - name: Cache Dependencies - id: dependencies-cache - uses: actions/cache@v4 - with: - path: ~/.bun/install/cache - key: ${{ runner.os }}-bun-${{ hashFiles('**/bun.lockb') }} - restore-keys: | - ${{ runner.os }}-bun- - - - name: Install Dependencies - run: bun install - - - name: Validate types - run: bun typecheck - - - name: Build Dist - run: VITE_CODE_VERSION=$GITHUB_SHA bun dist diff --git a/.forgejo/workflows/depoly.yml b/.forgejo/workflows/depoly.yml index 0ad6d10..edba093 100644 --- a/.forgejo/workflows/depoly.yml +++ b/.forgejo/workflows/depoly.yml @@ -30,9 +30,6 @@ jobs: - name: Install Dependencies run: bun install - - name: Validate types - run: bun typecheck - - name: Build Dist (Staging) run: VITE_CODE_VERSION=$GITHUB_SHA bun dist -m staging if: env.GITHUB_REF_NAME == 'master' diff --git a/package.json b/package.json index 6222ecd..dd31430 100644 --- a/package.json +++ b/package.json @@ -9,8 +9,7 @@ "dev": "vite --host 0.0.0.0", "preview": "vite preview", "dist": "vite build", - "count-source-lines": "exec scripts/src-lc.sh", - "typecheck": "tsc --noEmit --skipLibCheck" + "count-source-lines": "exec scripts/src-lc.sh" }, "keywords": [], "author": "Rubicon", diff --git a/src/platform/polyfills.ts b/src/platform/polyfills.ts index 1af3341..032207a 100644 --- a/src/platform/polyfills.ts +++ b/src/platform/polyfills.ts @@ -15,24 +15,3 @@ if (typeof window.crypto.randomUUID === "undefined") { ) as `${string}-${string}-${string}-${string}-${string}`; }; } - - -if (typeof Promise.withResolvers === "undefined") { - // Chrome/Edge 119, Firefox 121, Safari/iOS 17.4 - - // Promise.withResolvers is generic and works with subclasses - the typescript built-in decl - // could not handle the subclassing case. - Promise.withResolvers = function (this: AnyPromiseConstructor) { - let resolve!: PromiseWithResolvers["resolve"], reject!: PromiseWithResolvers["reject"]; - // These variables are expected to be set after `new this()` - - const promise = new this((resolve0, reject0) => { - resolve = resolve0; - reject = reject0; - }) - - return { - promise, resolve, reject - } - } -} diff --git a/src/serviceworker/main.ts b/src/serviceworker/main.ts index 99305a9..71a4f37 100644 --- a/src/serviceworker/main.ts +++ b/src/serviceworker/main.ts @@ -4,27 +4,23 @@ 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 Record)["serviceWorker"] instanceof - ServiceWorker - ); + return !!(self as unknown as ServiceWorkerGlobalScope).registration; } -if (!isServiceWorker(self)) { +if (isServiceWorker(self)) { + cleanupOutdatedCaches(); + precacheAndRoute(self.__WB_MANIFEST, { + cleanURLs: false, + }); + + // auto update + self.skipWaiting(); + clientsClaim(); +} else { 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() {}, }; @@ -33,9 +29,6 @@ self.addEventListener("message", (event: MessageEvent) => { const payload = event.data; if (typeof payload !== "object") return; if (isJSONRPCCall(payload as Record)) { - dispatchCall( - Service, - event as MessageEvent> & { source: MessageEventSource }, - ); + dispatchCall(Service, event as MessageEvent>); } }); diff --git a/src/serviceworker/tsconfig.json b/src/serviceworker/tsconfig.json index 090edc2..bc88f57 100644 --- a/src/serviceworker/tsconfig.json +++ b/src/serviceworker/tsconfig.json @@ -1,7 +1,5 @@ { "compilerOptions": { - "lib": ["WebWorker", "ESNext"], + "lib": ["ESNext", "WebWorker"], }, - "extends": ["../../tsconfig.super.json"], - "include": ["./**/*.ts"], -} +} \ No newline at end of file diff --git a/src/serviceworker/workerrpc.ts b/src/serviceworker/workerrpc.ts index 7680716..84bb39f 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,9 +114,6 @@ 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); @@ -124,30 +121,28 @@ export class ResultDispatcher { } } - const { promise, resolve } = Promise.withResolvers(); + return new Promise((resolve) => { + let retried = 0; - let retried = 0; + 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}"`, + ); + } + }; - 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; + // start the loop + checkAndDispatch(); + }); } createTypedCall< @@ -164,16 +159,14 @@ export class ResultDispatcher { } } -type AnyService = Record unknown>; +type AnyService = Record unknown) | undefined> -export async function dispatchCall>( - service: S, - event: MessageEvent> & { source: MessageEventSource }, -) { +export async function dispatchCall< + S extends AnyService, +>(service: S, event: MessageEvent>) { 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", @@ -183,12 +176,10 @@ 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 feaab58..b92e528 100644 --- a/tsconfig.json +++ b/tsconfig.json @@ -1,11 +1,20 @@ { "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"], - "lib": ["ESNext", "DOM", "DOM.Iterable"] - }, - "include": ["./src/**/*.ts", "./src/**/*.tsx", "./*.ts", "./types/**.ts"], - "exclude": ["./src/serviceworker/**"], - "extends": ["./tsconfig.super.json"] + "noEmit": true, + "isolatedModules": true, + "resolveJsonModule": true, + "paths": { + "~platform/*": ["./src/platform/*"], + "~material/*": ["./src/material/*"] + } + } } diff --git a/tsconfig.super.json b/tsconfig.super.json deleted file mode 100644 index 9cf8e60..0000000 --- a/tsconfig.super.json +++ /dev/null @@ -1,17 +0,0 @@ -{ - "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/*"] - } - } -} diff --git a/types/lib.esnext.promise.d.ts b/types/lib.esnext.promise.d.ts deleted file mode 100644 index 5df9b56..0000000 --- a/types/lib.esnext.promise.d.ts +++ /dev/null @@ -1,26 +0,0 @@ -interface AnyPromiseWithResolvers { - promise: Instance; - resolve: (value: T | PromiseLike) => void; - reject: (reason?: any) => void; -} - -type AnyPromiseConstructor = new ( - executor: ( - resolve: PromiseWithResolvers["resolve"], - reject: PromiseWithResolvers["reject"], - ) => void, -) => Promise; - -interface PromiseConstructor { - /** - * Creates a new Promise and returns it in an object, along with its resolve and reject functions. - * @returns An object with the properties `promise`, `resolve`, and `reject`. - * - * ```ts - * const { promise, resolve, reject } = Promise.withResolvers(); - * ``` - */ - withResolvers>( - this: K, - ): AnyPromiseWithResolvers>; -}