From b2223bcbb8d47ac0a3318fe27c4067be974fcda5 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=E4=BA=8E=E5=B0=8F=E4=B8=98?= Date: Mon, 15 Jun 2026 18:24:18 +0800 Subject: [PATCH 1/2] fix(pwa): skip private network hosts in SW to restore Chrome PNA prompt The generateSW-mode Service Worker was intercepting fetch requests to private/local IPs (e.g. 192.168.x.x), which prevented Chrome from showing its Private Network Access permission dialog. Switch to injectManifest with a custom SW that imports isPrivateOrLocalHost (ipaddr.js) to let those requests fall through to the page context. Co-Authored-By: Claude Opus 4.6 (1M context) --- package.json | 5 +++++ src/sw.ts | 40 ++++++++++++++++++++++++++++++++++++++++ tsconfig.json | 2 +- vite.config.ts | 24 ++++-------------------- 4 files changed, 50 insertions(+), 21 deletions(-) create mode 100644 src/sw.ts diff --git a/package.json b/package.json index 014cfae..35b87cc 100644 --- a/package.json +++ b/package.json @@ -126,6 +126,11 @@ "vite-plugin-pwa": "^1.3.0", "vite-plugin-singlefile": "^2.3.3", "vitest": "^4.1.7", + "workbox-cacheable-response": "^7.4.1", + "workbox-expiration": "^7.4.1", + "workbox-precaching": "^7.4.1", + "workbox-routing": "^7.4.1", + "workbox-strategies": "^7.4.1", "workbox-window": "^7.4.1", "@base-ui/react": "^1.5.0", "@dnd-kit/core": "^6.3.1", diff --git a/src/sw.ts b/src/sw.ts new file mode 100644 index 0000000..9fbcea9 --- /dev/null +++ b/src/sw.ts @@ -0,0 +1,40 @@ +/// +import { cleanupOutdatedCaches, precacheAndRoute } from "workbox-precaching" +import { registerRoute } from "workbox-routing" +import { NetworkFirst } from "workbox-strategies" +import { ExpirationPlugin } from "workbox-expiration" +import { CacheableResponsePlugin } from "workbox-cacheable-response" +import { isPrivateOrLocalHost } from "@/lib/openapi/url-guard" + +declare const self: ServiceWorkerGlobalScope & { + __WB_MANIFEST: Array<{ url: string; revision: string | null }> +} + +cleanupOutdatedCaches() +precacheAndRoute(self.__WB_MANIFEST) + +// Only cache cross-origin *public* specs. Same-origin specs may be +// cookie/session-authenticated, and Authorization-bearing requests are +// excluded outright. Private/local network hosts are skipped so the fetch +// falls through to the page context, where Chrome can show the Private +// Network Access permission prompt. +registerRoute( + ({ request, url, sameOrigin }) => { + if (sameOrigin || request.headers.has("authorization")) return false + if (isPrivateOrLocalHost(url.hostname)) return false + return /(?:^|\/)(?:spec|openapi|swagger|asyncapi)[^/]*\.(json|ya?ml)$/i.test(url.pathname) + }, + new NetworkFirst({ + cacheName: "api-specs", + plugins: [ + new ExpirationPlugin({ maxEntries: 20, maxAgeSeconds: 7 * 24 * 60 * 60 }), + new CacheableResponsePlugin({ statuses: [200] }), + ], + }), +) + +self.addEventListener("message", (event) => { + if (event.data?.type === "SKIP_WAITING") { + self.skipWaiting() + } +}) diff --git a/tsconfig.json b/tsconfig.json index 474935d..afababf 100644 --- a/tsconfig.json +++ b/tsconfig.json @@ -23,5 +23,5 @@ } }, "include": ["src", "cli/src"], - "exclude": ["src/components/animate-ui/**"] + "exclude": ["src/components/animate-ui/**", "src/sw.ts"] } diff --git a/vite.config.ts b/vite.config.ts index 4354761..6d983f4 100644 --- a/vite.config.ts +++ b/vite.config.ts @@ -59,29 +59,13 @@ export default defineConfig(({ mode }) => { tailwindcss(), cspPlugin(), VitePWA({ + strategies: "injectManifest", + srcDir: "src", + filename: "sw.ts", registerType: "prompt", - workbox: { + injectManifest: { maximumFileSizeToCacheInBytes: 5 * 1024 * 1024, globPatterns: ["**/*.{js,css,html,svg}"], - runtimeCaching: [ - { - // Only cache cross-origin *public* specs. Same-origin specs may be - // cookie/session-authenticated (the Cookie header isn't visible to JS, - // so we can't filter on it), and Authorization-bearing requests are - // excluded outright. Caching a protected doc could expose it to a later, - // unauthenticated reader on a shared machine. Only cache 200s. - urlPattern: ({ request, url, sameOrigin }: { request: Request; url: URL; sameOrigin: boolean }) => - !sameOrigin - && !request.headers.has("authorization") - && /(?:^|\/)(?:spec|openapi|swagger|asyncapi)[^/]*\.(json|ya?ml)$/i.test(url.pathname), - handler: "NetworkFirst", - options: { - cacheName: "api-specs", - expiration: { maxEntries: 20, maxAgeSeconds: 7 * 24 * 60 * 60 }, - cacheableResponse: { statuses: [200] }, - }, - }, - ], }, manifest: { name: "Apilot", From f866065de910144af39459811823f9f06de16881 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=E4=BA=8E=E5=B0=8F=E4=B8=98?= Date: Mon, 15 Jun 2026 18:27:01 +0800 Subject: [PATCH 2/2] fix(deps): update lockfile for workbox packages Co-Authored-By: Claude Opus 4.6 (1M context) --- pnpm-lock.yaml | 53 ++++++++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 53 insertions(+) diff --git a/pnpm-lock.yaml b/pnpm-lock.yaml index 1e6e93d..fb98761 100644 --- a/pnpm-lock.yaml +++ b/pnpm-lock.yaml @@ -299,6 +299,21 @@ importers: vitest: specifier: ^4.1.7 version: 4.1.7(@types/node@25.9.1)(@vitest/coverage-v8@4.1.7)(msw@2.14.6(@types/node@25.9.1)(typescript@6.0.3))(vite@8.0.14(@types/node@25.9.1)(esbuild@0.28.0)(jiti@2.7.0)(terser@5.48.0)(tsx@4.22.3)(yaml@2.9.0)) + workbox-cacheable-response: + specifier: ^7.4.1 + version: 7.4.1 + workbox-expiration: + specifier: ^7.4.1 + version: 7.4.1 + workbox-precaching: + specifier: ^7.4.1 + version: 7.4.1 + workbox-routing: + specifier: ^7.4.1 + version: 7.4.1 + workbox-strategies: + specifier: ^7.4.1 + version: 7.4.1 workbox-window: specifier: ^7.4.1 version: 7.4.1 @@ -5662,6 +5677,9 @@ packages: workbox-cacheable-response@7.4.0: resolution: {integrity: sha512-0Fb8795zg/x23ISFkAc7lbWes6vbw34DGFIMw31cwuHPgDEC/5EYm6m/ZkylLX0EnEbbOyOCLjKgFS/Z5g0HeQ==} + workbox-cacheable-response@7.4.1: + resolution: {integrity: sha512-8xaFoJdDc2OjrlbbL3gEeBO1WKcMwRqwLRupgqahYXu75yXajPLuwrbXMrIGZuWYXrQwk0xDjOxZ/ujCy/oJYw==} + workbox-core@7.4.0: resolution: {integrity: sha512-6BMfd8tYEnN4baG4emG9U0hdXM4gGuDU3ectXuVHnj71vwxTFI7WOpQJC4siTOlVtGqCUtj0ZQNsrvi6kZZTAQ==} @@ -5671,6 +5689,9 @@ packages: workbox-expiration@7.4.0: resolution: {integrity: sha512-V50p4BxYhtA80eOvulu8xVfPBgZbkxJ1Jr8UUn0rvqjGhLDqKNtfrDfjJKnLz2U8fO2xGQJTx/SKXNTzHOjnHw==} + workbox-expiration@7.4.1: + resolution: {integrity: sha512-lRKUF7b+OGbeXkQk1s6MHXOa3d7Xxf7Of31W6c6hCfipfIyrtdWZ89stq21AHZMaoG7VNFoHply4Ox+rU31TWg==} + workbox-google-analytics@7.4.0: resolution: {integrity: sha512-MVPXQslRF6YHkzGoFw1A4GIB8GrKym/A5+jYDUSL+AeJw4ytQGrozYdiZqUW1TPQHW8isBCBtyFJergUXyNoWQ==} @@ -5680,6 +5701,9 @@ packages: workbox-precaching@7.4.0: resolution: {integrity: sha512-VQs37T6jDqf1rTxUJZXRl3yjZMf5JX/vDPhmx2CPgDDKXATzEoqyRqhYnRoxl6Kr0rqaQlp32i9rtG5zTzIlNg==} + workbox-precaching@7.4.1: + resolution: {integrity: sha512-cdr/9qByww7yzEp7zg/qI4ukUrrNjQLgN+ONQRpjy/VqGQXwkgHwr00KksGJK8v0VifwDXBb8a4cWNZH71jn3Q==} + workbox-range-requests@7.4.0: resolution: {integrity: sha512-3Vq854ZNuP6Y0KZOQWLaLC9FfM7ZaE+iuQl4VhADXybwzr4z/sMmnLgTeUZLq5PaDlcJBxYXQ3U91V7dwAIfvw==} @@ -5689,9 +5713,15 @@ packages: workbox-routing@7.4.0: resolution: {integrity: sha512-C/ooj5uBWYAhAqwmU8HYQJdOjjDKBp9MzTQ+otpMmd+q0eF59K+NuXUek34wbL0RFrIXe/KKT+tUWcZcBqxbHQ==} + workbox-routing@7.4.1: + resolution: {integrity: sha512-yubJGErZOusuidAenaL5ypfhQOa7urxP/f8E0ws7FPb4039RiWXUWBAyUkmUoOL/BcQGen3h0J8872d51IYxtA==} + workbox-strategies@7.4.0: resolution: {integrity: sha512-T4hVqIi5A4mHi92+5EppMX3cLaVywDp8nsyUgJhOZxcfSV/eQofcOA6/EMo5rnTNmNTpw0rUgjAI6LaVullPpg==} + workbox-strategies@7.4.1: + resolution: {integrity: sha512-GZxpaw9NbmOelj7667uZ2kpk5BFpOGbO4X0qjwh5ls8XQ8C+Lha5LQchTiUzsTFSS+NlUpftYAyOVXvQUrcqOQ==} + workbox-streams@7.4.0: resolution: {integrity: sha512-QHPBQrey7hQbnTs5GrEVoWz7RhHJXnPT+12qqWM378orDMo5VMJLCkCM1cnCk+8Eq92lccx/VgRZ7WAzZWbSLg==} @@ -11672,6 +11702,10 @@ snapshots: dependencies: workbox-core: 7.4.0 + workbox-cacheable-response@7.4.1: + dependencies: + workbox-core: 7.4.1 + workbox-core@7.4.0: {} workbox-core@7.4.1: {} @@ -11681,6 +11715,11 @@ snapshots: idb: 7.1.1 workbox-core: 7.4.0 + workbox-expiration@7.4.1: + dependencies: + idb: 7.1.1 + workbox-core: 7.4.1 + workbox-google-analytics@7.4.0: dependencies: workbox-background-sync: 7.4.0 @@ -11698,6 +11737,12 @@ snapshots: workbox-routing: 7.4.0 workbox-strategies: 7.4.0 + workbox-precaching@7.4.1: + dependencies: + workbox-core: 7.4.1 + workbox-routing: 7.4.1 + workbox-strategies: 7.4.1 + workbox-range-requests@7.4.0: dependencies: workbox-core: 7.4.0 @@ -11715,10 +11760,18 @@ snapshots: dependencies: workbox-core: 7.4.0 + workbox-routing@7.4.1: + dependencies: + workbox-core: 7.4.1 + workbox-strategies@7.4.0: dependencies: workbox-core: 7.4.0 + workbox-strategies@7.4.1: + dependencies: + workbox-core: 7.4.1 + workbox-streams@7.4.0: dependencies: workbox-core: 7.4.0