From 8bb5ef278b4e57245c5cf8560deb9c3a39509a24 Mon Sep 17 00:00:00 2001 From: "copilot-swe-agent[bot]" <198982749+Copilot@users.noreply.github.com> Date: Thu, 9 Apr 2026 00:27:09 +0000 Subject: [PATCH 1/7] Initial plan From dbe631d7c0a151e9472ab481d9b518916f401819 Mon Sep 17 00:00:00 2001 From: "copilot-swe-agent[bot]" <198982749+Copilot@users.noreply.github.com> Date: Thu, 9 Apr 2026 00:34:54 +0000 Subject: [PATCH 2/7] fix: merge remote settings before first sync upload Agent-Logs-Url: https://github.com/salarcode/SmartProxy/sessions/69f46906-6c9e-45c5-8d08-6a4715b56051 Co-authored-by: salarcode <1272095+salarcode@users.noreply.github.com> --- src/core/Core.ts | 29 +++++ src/core/SettingsOperation.ts | 201 +++++++++++++++++++++++++++++++++- 2 files changed, 228 insertions(+), 2 deletions(-) diff --git a/src/core/Core.ts b/src/core/Core.ts index 0fdc1576..926b02fe 100644 --- a/src/core/Core.ts +++ b/src/core/Core.ts @@ -366,7 +366,36 @@ export class Core { case CommandMessages.SettingsPageSaveOptions: { if (!message.options) return; + const syncWasEnabled = settingsLib.current.options?.syncSettings === true; + const previousOptions = settingsLib.current.options; settingsLib.current.options = message.options; + + if (!syncWasEnabled && message.options.syncSettings) { + settingsOperationLib.performInitialSyncMerge( + () => { + // update proxy rules + proxyEngineLib.updateBrowsersProxyConfig(); + + if (sendResponse) { + sendResponse({ + success: true, + // General options saved successfully. + message: api.i18n.getMessage('settingsSaveOptionsSuccess'), + }); + } + }, + (error: Error) => { + settingsLib.current.options = previousOptions; + if (sendResponse) { + sendResponse({ + success: false, + message: api.i18n.getMessage("settingsErrorFailedToSaveGeneral") + " " + error.message + }); + } + }); + return true; + } + settingsOperationLib.saveOptions(); settingsOperationLib.saveAllSync(); diff --git a/src/core/SettingsOperation.ts b/src/core/SettingsOperation.ts index 5cd6fa24..9810e556 100644 --- a/src/core/SettingsOperation.ts +++ b/src/core/SettingsOperation.ts @@ -19,7 +19,7 @@ import { PolyFill } from "../lib/PolyFill"; import { Debug } from "../lib/Debug"; import { Settings } from "./Settings"; import { Utils } from "../lib/Utils"; -import { GeneralOptions, ProxyServer, ProxyServerFromSubscription, ProxyServerSubscription, SettingsConfig, SmartProfile, UpdateInfo } from "./definitions"; +import { GeneralOptions, ProxyRule, ProxyRulesSubscription, ProxyServer, ProxyServerFromSubscription, ProxyServerSubscription, SettingsConfig, SmartProfile, UpdateInfo } from "./definitions"; import { ProxyEngine } from "./ProxyEngine"; import { ProxyRules } from "./ProxyRules"; import { SubscriptionUpdater } from "./SubscriptionUpdater"; @@ -166,6 +166,58 @@ export class SettingsOperation { Settings.updateActiveSettings(); } + public static performInitialSyncMerge(onSuccess?: Function, onError?: Function) { + me.readConfiguredSyncSettings( + (syncedSettings: SettingsConfig) => { + if (!syncedSettings?.options) { + me.saveAllSync(); + me.reloadSubscriptionsAfterSyncMerge(); + if (onSuccess) + onSuccess(); + return; + } + + const remoteSettings = Settings.getRestorableSettings(JSON.parse(JSON.stringify(syncedSettings))); + const remoteSettingsSyncable = JSON.stringify(me.getStrippedSyncableSettings(remoteSettings)); + const mergedSettings = me.mergeSettingsForInitialSync(remoteSettings, Settings.current); + const mergedSettingsSyncable = JSON.stringify(me.getStrippedSyncableSettings(mergedSettings)); + const mergeChangedSettings = remoteSettingsSyncable !== mergedSettingsSyncable; + + me.applySyncSettings(mergedSettings); + SettingsOperation.saveAllLocal(true); + + if (mergeChangedSettings) { + me.saveAllSync(); + } + + me.reloadSubscriptionsAfterSyncMerge(); + + if (onSuccess) + onSuccess(); + }, + (error: Error) => { + if (me.isMissingSyncDataError(error)) { + me.saveAllSync(); + me.reloadSubscriptionsAfterSyncMerge(); + if (onSuccess) + onSuccess(); + return; + } + + if (onError) + onError(error); + }); + } + public static mergeSettingsForInitialSync(baseSettings: SettingsConfig, incomingSettings: SettingsConfig): SettingsConfig { + let mergedSettings = Settings.getRestorableSettings(JSON.parse(JSON.stringify(baseSettings))); + + me.mergeProxyServers(mergedSettings, incomingSettings); + me.mergeProxyServerSubscriptions(mergedSettings, incomingSettings); + me.mergeSmartProfiles(mergedSettings, incomingSettings); + + Settings.ensureIntegrityOfSettings(mergedSettings); + return mergedSettings; + } /** In local options if sync is disabled for these particular options, don't update them from sync server */ private static revertSyncOptions(syncedConfig: SettingsConfig) { @@ -494,6 +546,151 @@ export class SettingsOperation { return String(rawData); } + private static readConfiguredSyncSettings(onSuccess: Function, onError?: Function) { + if (Settings.current.options.syncWebDavServerEnabled) { + me.readFromWebDavServer( + Settings.current.options.syncWebDavServerUrl, + Settings.current.options.syncWebDavBackupFilename, + Settings.current.options.syncWebDavServerUser, + Settings.current.options.syncWebDavServerPassword, + onSuccess, + onError); + return; + } + + polyFillLib.storageSyncGet( + null, + (data: any) => { + try { + onSuccess(utilsLib.decodeSyncData(data)); + } catch (e) { + if (onError) + onError(me.normalizeError(e)); + } + }, + (error: any) => { + if (onError) + onError(me.normalizeError(error)); + }); + } + private static reloadSubscriptionsAfterSyncMerge() { + subscriptionUpdaterLib.setServerSubscriptionsRefreshTimers(); + subscriptionUpdaterLib.reloadEmptyServerSubscriptions(); + subscriptionUpdaterLib.setRulesSubscriptionsRefreshTimers(); + subscriptionUpdaterLib.reloadEmptyRulesSubscriptions(); + subscriptionUpdaterLib.updateProxyServerSubscriptionsCountryCode(); + } + private static mergeProxyServers(targetSettings: SettingsConfig, sourceSettings: SettingsConfig) { + if (!sourceSettings?.proxyServers?.length) + return; + + targetSettings.proxyServers ||= []; + for (const proxyServer of sourceSettings.proxyServers) { + if (!proxyServer?.id) + continue; + + if (targetSettings.proxyServers.find(existing => existing.id === proxyServer.id)) + continue; + + let copyProxy = new ProxyServer(); + copyProxy.CopyFrom(proxyServer); + if (copyProxy.isValid()) + targetSettings.proxyServers.push(copyProxy); + } + } + private static mergeProxyServerSubscriptions(targetSettings: SettingsConfig, sourceSettings: SettingsConfig) { + if (!sourceSettings?.proxyServerSubscriptions?.length) + return; + + targetSettings.proxyServerSubscriptions ||= []; + for (const subscription of sourceSettings.proxyServerSubscriptions) { + if (!subscription) + continue; + + let existingSubscription = targetSettings.proxyServerSubscriptions.find(existing => + existing.name === subscription.name && + existing.url === subscription.url); + if (existingSubscription) + continue; + + let copySubscription = new ProxyServerSubscription(); + copySubscription.CopyFrom(subscription); + if (copySubscription.isValid()) + targetSettings.proxyServerSubscriptions.push(copySubscription); + } + } + private static mergeSmartProfiles(targetSettings: SettingsConfig, sourceSettings: SettingsConfig) { + if (!sourceSettings?.proxyProfiles?.length) + return; + + targetSettings.proxyProfiles ||= []; + for (const profile of sourceSettings.proxyProfiles) { + if (!profile) + continue; + + let existingProfile = targetSettings.proxyProfiles.find(existing => + existing.profileId === profile.profileId || + (existing.profileTypeConfig?.builtin && existing.profileType === profile.profileType) || + existing.profileName === profile.profileName); + + if (!existingProfile) { + let copyProfile = new SmartProfile(); + ProfileOperations.copySmartProfile(profile, copyProfile); + targetSettings.proxyProfiles.push(copyProfile); + continue; + } + + existingProfile.proxyRules ||= []; + for (const rule of profile.proxyRules || []) { + let copyRule = new ProxyRule(); + copyRule.CopyFrom(rule); + + if (!copyRule.isValid()) + continue; + + if (existingProfile.proxyRules.find(existingRule => me.areProxyRulesEquivalent(existingRule, copyRule))) + continue; + + existingProfile.proxyRules.push(copyRule); + } + + existingProfile.rulesSubscriptions ||= []; + for (const subscription of profile.rulesSubscriptions || []) { + let existingSubscription = existingProfile.rulesSubscriptions.find(existing => + existing.id === subscription.id || + (existing.name === subscription.name && existing.url === subscription.url)); + if (existingSubscription) + continue; + + let copySubscription = new ProxyRulesSubscription(); + copySubscription.CopyFrom(subscription); + if (copySubscription.isValid()) + existingProfile.rulesSubscriptions.push(copySubscription); + } + } + } + private static areProxyRulesEquivalent(firstRule: ProxyRule, secondRule: ProxyRule): boolean { + return +firstRule.ruleType === +secondRule.ruleType && + (firstRule.hostName || '') === (secondRule.hostName || '') && + (firstRule.ruleSearch || '') === (secondRule.ruleSearch || '') && + (firstRule.rulePattern || '') === (secondRule.rulePattern || '') && + (firstRule.ruleRegex || '') === (secondRule.ruleRegex || '') && + (firstRule.ruleExact || '') === (secondRule.ruleExact || '') && + (firstRule.whiteList || false) === (secondRule.whiteList || false) && + (firstRule.proxyServerId || firstRule.proxy?.id || '') === (secondRule.proxyServerId || secondRule.proxy?.id || ''); + } + private static isMissingSyncDataError(error: any): boolean { + const errorMessage = `${error?.message || error || ''}`.toLowerCase(); + return errorMessage.includes('404') || + errorMessage.includes('not found') || + errorMessage.includes('no such file'); + } + private static normalizeError(error: any): Error { + if (error instanceof Error) + return error; + + return new Error(`${error}`); + } public static saveAllLocal(forceSave: boolean = false) { if (!forceSave && Settings.current.options.syncSettings) @@ -1088,4 +1285,4 @@ export class SettingsOperation { } } -let me = SettingsOperation; \ No newline at end of file +let me = SettingsOperation; From 04deb3e2fc05e50614bcd87645eeee6b22b240f3 Mon Sep 17 00:00:00 2001 From: "copilot-swe-agent[bot]" <198982749+Copilot@users.noreply.github.com> Date: Thu, 9 Apr 2026 00:36:24 +0000 Subject: [PATCH 3/7] chore: address validation feedback Agent-Logs-Url: https://github.com/salarcode/SmartProxy/sessions/69f46906-6c9e-45c5-8d08-6a4715b56051 Co-authored-by: salarcode <1272095+salarcode@users.noreply.github.com> --- src/core/SettingsOperation.ts | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/core/SettingsOperation.ts b/src/core/SettingsOperation.ts index 9810e556..69c1bed7 100644 --- a/src/core/SettingsOperation.ts +++ b/src/core/SettingsOperation.ts @@ -169,7 +169,7 @@ export class SettingsOperation { public static performInitialSyncMerge(onSuccess?: Function, onError?: Function) { me.readConfiguredSyncSettings( (syncedSettings: SettingsConfig) => { - if (!syncedSettings?.options) { + if (!syncedSettings || !syncedSettings.options) { me.saveAllSync(); me.reloadSubscriptionsAfterSyncMerge(); if (onSuccess) From ed4a7546f21f61f7eaa206d9b500eb6c63d1ef51 Mon Sep 17 00:00:00 2001 From: "copilot-swe-agent[bot]" <198982749+Copilot@users.noreply.github.com> Date: Thu, 9 Apr 2026 00:37:51 +0000 Subject: [PATCH 4/7] refactor: tighten initial sync merge callbacks Agent-Logs-Url: https://github.com/salarcode/SmartProxy/sessions/69f46906-6c9e-45c5-8d08-6a4715b56051 Co-authored-by: salarcode <1272095+salarcode@users.noreply.github.com> --- src/core/Core.ts | 2 +- src/core/SettingsOperation.ts | 45 ++++++++++++++++++++++++----------- 2 files changed, 32 insertions(+), 15 deletions(-) diff --git a/src/core/Core.ts b/src/core/Core.ts index 926b02fe..5fba070c 100644 --- a/src/core/Core.ts +++ b/src/core/Core.ts @@ -366,7 +366,7 @@ export class Core { case CommandMessages.SettingsPageSaveOptions: { if (!message.options) return; - const syncWasEnabled = settingsLib.current.options?.syncSettings === true; + const syncWasEnabled = settingsLib.current.options?.syncSettings; const previousOptions = settingsLib.current.options; settingsLib.current.options = message.options; diff --git a/src/core/SettingsOperation.ts b/src/core/SettingsOperation.ts index 69c1bed7..f9609d11 100644 --- a/src/core/SettingsOperation.ts +++ b/src/core/SettingsOperation.ts @@ -166,7 +166,7 @@ export class SettingsOperation { Settings.updateActiveSettings(); } - public static performInitialSyncMerge(onSuccess?: Function, onError?: Function) { + public static performInitialSyncMerge(onSuccess?: () => void, onError?: (error: Error) => void) { me.readConfiguredSyncSettings( (syncedSettings: SettingsConfig) => { if (!syncedSettings || !syncedSettings.options) { @@ -208,12 +208,12 @@ export class SettingsOperation { onError(error); }); } - public static mergeSettingsForInitialSync(baseSettings: SettingsConfig, incomingSettings: SettingsConfig): SettingsConfig { - let mergedSettings = Settings.getRestorableSettings(JSON.parse(JSON.stringify(baseSettings))); + public static mergeSettingsForInitialSync(remoteSettings: SettingsConfig, localSettings: SettingsConfig): SettingsConfig { + let mergedSettings = Settings.getRestorableSettings(JSON.parse(JSON.stringify(remoteSettings))); - me.mergeProxyServers(mergedSettings, incomingSettings); - me.mergeProxyServerSubscriptions(mergedSettings, incomingSettings); - me.mergeSmartProfiles(mergedSettings, incomingSettings); + me.mergeProxyServers(mergedSettings, localSettings); + me.mergeProxyServerSubscriptions(mergedSettings, localSettings); + me.mergeSmartProfiles(mergedSettings, localSettings); Settings.ensureIntegrityOfSettings(mergedSettings); return mergedSettings; @@ -546,7 +546,7 @@ export class SettingsOperation { return String(rawData); } - private static readConfiguredSyncSettings(onSuccess: Function, onError?: Function) { + private static readConfiguredSyncSettings(onSuccess: (settings: SettingsConfig) => void, onError?: (error: Error) => void) { if (Settings.current.options.syncWebDavServerEnabled) { me.readFromWebDavServer( Settings.current.options.syncWebDavServerUrl, @@ -628,10 +628,7 @@ export class SettingsOperation { if (!profile) continue; - let existingProfile = targetSettings.proxyProfiles.find(existing => - existing.profileId === profile.profileId || - (existing.profileTypeConfig?.builtin && existing.profileType === profile.profileType) || - existing.profileName === profile.profileName); + let existingProfile = me.findMatchingProfileForMerge(targetSettings.proxyProfiles, profile); if (!existingProfile) { let copyProfile = new SmartProfile(); @@ -656,9 +653,7 @@ export class SettingsOperation { existingProfile.rulesSubscriptions ||= []; for (const subscription of profile.rulesSubscriptions || []) { - let existingSubscription = existingProfile.rulesSubscriptions.find(existing => - existing.id === subscription.id || - (existing.name === subscription.name && existing.url === subscription.url)); + let existingSubscription = me.findMatchingRulesSubscriptionForMerge(existingProfile.rulesSubscriptions, subscription); if (existingSubscription) continue; @@ -679,6 +674,28 @@ export class SettingsOperation { (firstRule.whiteList || false) === (secondRule.whiteList || false) && (firstRule.proxyServerId || firstRule.proxy?.id || '') === (secondRule.proxyServerId || secondRule.proxy?.id || ''); } + private static findMatchingProfileForMerge(profiles: SmartProfile[], profileToMerge: SmartProfile): SmartProfile { + let profileById = profiles.find(existing => existing.profileId === profileToMerge.profileId); + if (profileById) + return profileById; + + let builtinProfile = profiles.find(existing => + existing.profileTypeConfig?.builtin && + existing.profileType === profileToMerge.profileType); + if (builtinProfile) + return builtinProfile; + + return profiles.find(existing => existing.profileName === profileToMerge.profileName); + } + private static findMatchingRulesSubscriptionForMerge(subscriptions: ProxyRulesSubscription[], subscriptionToMerge: ProxyRulesSubscription): ProxyRulesSubscription { + let subscriptionById = subscriptions.find(existing => existing.id === subscriptionToMerge.id); + if (subscriptionById) + return subscriptionById; + + return subscriptions.find(existing => + existing.name === subscriptionToMerge.name && + existing.url === subscriptionToMerge.url); + } private static isMissingSyncDataError(error: any): boolean { const errorMessage = `${error?.message || error || ''}`.toLowerCase(); return errorMessage.includes('404') || From 4a88c4b1c31b6ed2e060291d1f938fbc5f59d6fe Mon Sep 17 00:00:00 2001 From: "copilot-swe-agent[bot]" <198982749+Copilot@users.noreply.github.com> Date: Thu, 9 Apr 2026 00:39:12 +0000 Subject: [PATCH 5/7] refactor: clarify sync merge comparisons Agent-Logs-Url: https://github.com/salarcode/SmartProxy/sessions/69f46906-6c9e-45c5-8d08-6a4715b56051 Co-authored-by: salarcode <1272095+salarcode@users.noreply.github.com> --- src/core/SettingsOperation.ts | 25 +++++++++++++++++-------- 1 file changed, 17 insertions(+), 8 deletions(-) diff --git a/src/core/SettingsOperation.ts b/src/core/SettingsOperation.ts index f9609d11..a19b4160 100644 --- a/src/core/SettingsOperation.ts +++ b/src/core/SettingsOperation.ts @@ -665,14 +665,23 @@ export class SettingsOperation { } } private static areProxyRulesEquivalent(firstRule: ProxyRule, secondRule: ProxyRule): boolean { - return +firstRule.ruleType === +secondRule.ruleType && - (firstRule.hostName || '') === (secondRule.hostName || '') && - (firstRule.ruleSearch || '') === (secondRule.ruleSearch || '') && - (firstRule.rulePattern || '') === (secondRule.rulePattern || '') && - (firstRule.ruleRegex || '') === (secondRule.ruleRegex || '') && - (firstRule.ruleExact || '') === (secondRule.ruleExact || '') && - (firstRule.whiteList || false) === (secondRule.whiteList || false) && - (firstRule.proxyServerId || firstRule.proxy?.id || '') === (secondRule.proxyServerId || secondRule.proxy?.id || ''); + const sameType = +firstRule.ruleType === +secondRule.ruleType; + const sameHostName = (firstRule.hostName || '') === (secondRule.hostName || ''); + const sameSearch = (firstRule.ruleSearch || '') === (secondRule.ruleSearch || ''); + const samePattern = (firstRule.rulePattern || '') === (secondRule.rulePattern || ''); + const sameRegex = (firstRule.ruleRegex || '') === (secondRule.ruleRegex || ''); + const sameExact = (firstRule.ruleExact || '') === (secondRule.ruleExact || ''); + const sameWhitelistMode = (firstRule.whiteList || false) === (secondRule.whiteList || false); + const sameProxyServer = (firstRule.proxyServerId || firstRule.proxy?.id || '') === (secondRule.proxyServerId || secondRule.proxy?.id || ''); + + return sameType && + sameHostName && + sameSearch && + samePattern && + sameRegex && + sameExact && + sameWhitelistMode && + sameProxyServer; } private static findMatchingProfileForMerge(profiles: SmartProfile[], profileToMerge: SmartProfile): SmartProfile { let profileById = profiles.find(existing => existing.profileId === profileToMerge.profileId); From 376a999f58dd3ff1b365bb10dec3dbfc3dc54996 Mon Sep 17 00:00:00 2001 From: "copilot-swe-agent[bot]" <198982749+Copilot@users.noreply.github.com> Date: Thu, 9 Apr 2026 00:40:31 +0000 Subject: [PATCH 6/7] refactor: tidy sync merge cloning and errors Agent-Logs-Url: https://github.com/salarcode/SmartProxy/sessions/69f46906-6c9e-45c5-8d08-6a4715b56051 Co-authored-by: salarcode <1272095+salarcode@users.noreply.github.com> --- src/core/SettingsOperation.ts | 20 ++++++++++++++++---- 1 file changed, 16 insertions(+), 4 deletions(-) diff --git a/src/core/SettingsOperation.ts b/src/core/SettingsOperation.ts index a19b4160..691e05cc 100644 --- a/src/core/SettingsOperation.ts +++ b/src/core/SettingsOperation.ts @@ -177,7 +177,7 @@ export class SettingsOperation { return; } - const remoteSettings = Settings.getRestorableSettings(JSON.parse(JSON.stringify(syncedSettings))); + const remoteSettings = Settings.getRestorableSettings(me.cloneSettingsConfig(syncedSettings)); const remoteSettingsSyncable = JSON.stringify(me.getStrippedSyncableSettings(remoteSettings)); const mergedSettings = me.mergeSettingsForInitialSync(remoteSettings, Settings.current); const mergedSettingsSyncable = JSON.stringify(me.getStrippedSyncableSettings(mergedSettings)); @@ -209,7 +209,7 @@ export class SettingsOperation { }); } public static mergeSettingsForInitialSync(remoteSettings: SettingsConfig, localSettings: SettingsConfig): SettingsConfig { - let mergedSettings = Settings.getRestorableSettings(JSON.parse(JSON.stringify(remoteSettings))); + let mergedSettings = remoteSettings; me.mergeProxyServers(mergedSettings, localSettings); me.mergeProxyServerSubscriptions(mergedSettings, localSettings); @@ -665,7 +665,7 @@ export class SettingsOperation { } } private static areProxyRulesEquivalent(firstRule: ProxyRule, secondRule: ProxyRule): boolean { - const sameType = +firstRule.ruleType === +secondRule.ruleType; + const sameType = Number(firstRule.ruleType) === Number(secondRule.ruleType); const sameHostName = (firstRule.hostName || '') === (secondRule.hostName || ''); const sameSearch = (firstRule.ruleSearch || '') === (secondRule.ruleSearch || ''); const samePattern = (firstRule.rulePattern || '') === (secondRule.rulePattern || ''); @@ -711,11 +711,23 @@ export class SettingsOperation { errorMessage.includes('not found') || errorMessage.includes('no such file'); } + private static cloneSettingsConfig(settings: SettingsConfig): SettingsConfig { + if (typeof structuredClone === 'function') + return structuredClone(settings); + + return JSON.parse(JSON.stringify(settings)); + } private static normalizeError(error: any): Error { if (error instanceof Error) return error; - return new Error(`${error}`); + if (typeof error === 'string') + return new Error(error); + + if (error && typeof error === 'object' && typeof error.message === 'string') + return new Error(error.message); + + return new Error('Unknown error'); } public static saveAllLocal(forceSave: boolean = false) { From 4966eb2b810c430d73f3b454fba011b5cafc18c9 Mon Sep 17 00:00:00 2001 From: Salar K <1272095+salarcode@users.noreply.github.com> Date: Tue, 14 Apr 2026 13:36:34 +1000 Subject: [PATCH 7/7] Addressing comments Change strict equality to loose equality for matching --- src/core/SettingsOperation.ts | 26 +++++++++++++++----------- 1 file changed, 15 insertions(+), 11 deletions(-) diff --git a/src/core/SettingsOperation.ts b/src/core/SettingsOperation.ts index 691e05cc..93105091 100644 --- a/src/core/SettingsOperation.ts +++ b/src/core/SettingsOperation.ts @@ -1,4 +1,4 @@ -/* +/* * This file is part of SmartProxy , * Copyright (C) 2025 Salar Khalilzadeh * @@ -684,26 +684,30 @@ export class SettingsOperation { sameProxyServer; } private static findMatchingProfileForMerge(profiles: SmartProfile[], profileToMerge: SmartProfile): SmartProfile { - let profileById = profiles.find(existing => existing.profileId === profileToMerge.profileId); - if (profileById) - return profileById; + if (profileToMerge.profileId) { + let profileById = profiles.find(existing => existing.profileId == profileToMerge.profileId); + if (profileById) + return profileById; + } let builtinProfile = profiles.find(existing => existing.profileTypeConfig?.builtin && - existing.profileType === profileToMerge.profileType); + existing.profileType == profileToMerge.profileType); if (builtinProfile) return builtinProfile; - return profiles.find(existing => existing.profileName === profileToMerge.profileName); + return profiles.find(existing => existing.profileName == profileToMerge.profileName); } private static findMatchingRulesSubscriptionForMerge(subscriptions: ProxyRulesSubscription[], subscriptionToMerge: ProxyRulesSubscription): ProxyRulesSubscription { - let subscriptionById = subscriptions.find(existing => existing.id === subscriptionToMerge.id); - if (subscriptionById) - return subscriptionById; + if (subscriptionToMerge.id) { + let subscriptionById = subscriptions.find(existing => existing.id == subscriptionToMerge.id); + if (subscriptionById) + return subscriptionById; + } return subscriptions.find(existing => - existing.name === subscriptionToMerge.name && - existing.url === subscriptionToMerge.url); + existing.name == subscriptionToMerge.name && + existing.url == subscriptionToMerge.url); } private static isMissingSyncDataError(error: any): boolean { const errorMessage = `${error?.message || error || ''}`.toLowerCase();