diff --git a/package-lock.json b/package-lock.json index 08984b7..dd1775d 100644 --- a/package-lock.json +++ b/package-lock.json @@ -102,7 +102,6 @@ "integrity": "sha512-e7jT4DxYvIDLk1ZHmU/m/mB19rex9sv0c2ftBtjSBv+kVM/902eh0fINUzD7UwLLNR+jU585GxUJ8/EBfAM5fw==", "dev": true, "license": "MIT", - "peer": true, "dependencies": { "@babel/code-frame": "^7.27.1", "@babel/generator": "^7.28.5", @@ -1876,7 +1875,6 @@ "integrity": "sha512-GNWcUTRBgIRJD5zj+Tq0fKOJ5XZajIiBroOF0yvj2bSU1WvNdYS/dn9UxwsujGW4JX06dnHyjV2y9rRaybH0iQ==", "dev": true, "license": "MIT", - "peer": true, "dependencies": { "undici-types": "~7.16.0" } @@ -2361,7 +2359,6 @@ "resolved": "https://registry.npmjs.org/@vueuse/core/-/core-14.1.0.tgz", "integrity": "sha512-rgBinKs07hAYyPF834mDTigH7BtPqvZ3Pryuzt1SD/lg5wEcWqvwzXXYGEDb2/cP0Sj5zSvHl3WkmMELr5kfWw==", "license": "MIT", - "peer": true, "dependencies": { "@types/web-bluetooth": "^0.0.21", "@vueuse/metadata": "14.1.0", @@ -2400,7 +2397,6 @@ "resolved": "https://registry.npmjs.org/acorn/-/acorn-8.15.0.tgz", "integrity": "sha512-NZyJarBfL7nWwIq+FDL6Zp/yHEhePMNnnJ0y3qfieCrmNvYct8uvtiV41UvlSe6apAfk0fY1FbWx+NwfmpvtTg==", "license": "MIT", - "peer": true, "bin": { "acorn": "bin/acorn" }, @@ -2606,7 +2602,6 @@ } ], "license": "MIT", - "peer": true, "dependencies": { "baseline-browser-mapping": "^2.9.0", "caniuse-lite": "^1.0.30001759", @@ -4120,7 +4115,6 @@ "integrity": "sha512-w8GmOxZfBmKknvdXU1sdM9NHcoQejwF/4mNgj2JuEEdRaHwwF12K7e9eXn1nLZ07ad+du76mkVsyeb2rKGllsA==", "dev": true, "license": "MIT", - "peer": true, "dependencies": { "@types/estree": "1.0.8" }, @@ -4977,7 +4971,6 @@ "integrity": "sha512-jl1vZzPDinLr9eUt3J/t7V6FgNEw9QjvBPdysz9KfQDD41fQrC2Y4vKQdiaUpFT4bXlb1RHhLpp8wtm6M5TgSw==", "devOptional": true, "license": "Apache-2.0", - "peer": true, "bin": { "tsc": "bin/tsc", "tsserver": "bin/tsserver" @@ -5298,7 +5291,6 @@ "integrity": "sha512-tI2l/nFHC5rLh7+5+o7QjKjSR04ivXDF4jcgV0f/bTQ+OJiITy5S6gaynVsEM+7RqzufMnVbIon6Sr5x1SDYaQ==", "dev": true, "license": "MIT", - "peer": true, "dependencies": { "esbuild": "^0.25.0", "fdir": "^6.5.0", @@ -5374,7 +5366,6 @@ "integrity": "sha512-n1RxDp8UJm6N0IbJLQo+yzLZ2sQCDyl1o0LeugbPWf8+8Fttp29GghsQBjYJVmWq3gBFfe9Hs1spR44vovn2wA==", "dev": true, "license": "MIT", - "peer": true, "dependencies": { "@vitest/expect": "4.0.15", "@vitest/mocker": "4.0.15", @@ -5469,7 +5460,6 @@ "resolved": "https://registry.npmjs.org/vue/-/vue-3.5.25.tgz", "integrity": "sha512-YLVdgv2K13WJ6n+kD5owehKtEXwdwXuj2TTyJMsO7pSeKw2bfRNZGjhB7YzrpbMYj5b5QsUebHpOqR3R3ziy/g==", "license": "MIT", - "peer": true, "dependencies": { "@vue/compiler-dom": "3.5.25", "@vue/compiler-sfc": "3.5.25", diff --git a/src/services/profile.ts b/src/services/profile.ts index d1f5e62..f057b4b 100644 --- a/src/services/profile.ts +++ b/src/services/profile.ts @@ -1,4 +1,5 @@ import { Host, PacScript, SimpleProxyServer } from "@/adapters"; +import { deepClone } from "./utils"; export type ProxyAuthInfo = { username: string; @@ -103,7 +104,9 @@ export function onProfileUpdate(callback: (p: ProfilesStorage) => void) { } async function overwriteProfiles(profiles: ProfilesStorage) { - await Host.set(keyProfileStorage, profiles); + // Deep clone to remove any Proxy objects before saving + const clonedProfiles = deepClone(profiles); + await Host.set(keyProfileStorage, clonedProfiles); onProfileUpdateListeners.map((cb) => cb(profiles)); } @@ -115,14 +118,16 @@ async function overwriteProfiles(profiles: ProfilesStorage) { */ export async function saveProfile(profile: ProxyProfile) { const data = await listProfiles(); - data[profile.profileID] = profile; + // Deep clone the profile to remove any Proxy objects before saving + data[profile.profileID] = deepClone(profile); await overwriteProfiles(data); } export async function saveManyProfiles(profiles: ProxyProfile[]) { let data = await listProfiles(); profiles.forEach((p) => { - data[p.profileID] = p; + // Deep clone each profile to remove any Proxy objects before saving + data[p.profileID] = deepClone(p); }); await overwriteProfiles(data); } diff --git a/src/services/proxy/index.ts b/src/services/proxy/index.ts index ae4e6a7..9da5c75 100644 --- a/src/services/proxy/index.ts +++ b/src/services/proxy/index.ts @@ -9,6 +9,7 @@ import { import { ProxySettingResultDetails } from "@/adapters"; import { ProfileConverter } from "./profile2config"; import { ProfileAuthProvider } from "./auth"; +import { deepClone } from "../utils"; export type ProxySetting = { activeProfile?: ProxyProfile; @@ -56,7 +57,8 @@ export async function setProxy(val: ProxyProfile) { break; } - await Host.set(keyActiveProfile, val); + // Deep clone to remove any Proxy objects before saving + await Host.set(keyActiveProfile, deepClone(val)); } /** diff --git a/src/services/utils.ts b/src/services/utils.ts new file mode 100644 index 0000000..fbe4b8c --- /dev/null +++ b/src/services/utils.ts @@ -0,0 +1,8 @@ +/** + * Deep clone an object to remove all Proxy objects (e.g., from Vue reactivity). + * This is necessary because chrome.storage and browser.storage use structured clone + * which cannot clone Proxy objects. + */ +export function deepClone(obj: T): T { + return JSON.parse(JSON.stringify(obj)); +}