import browser from "webextension-polyfill"; import { SYNCABLE_PLUGIN_SETTING_DEFAULTS } from "@/plugins/syncablePluginDefaults"; import { getDefaultSettingsState } from "@/seqta/utils/defaultSettings"; import { isKeyIncludedInCloudUploadPayload, migrateLegacyToPluginSettings, } from "@/seqta/utils/cloudSettingsSync"; /** Legacy top-level keys — never backfill; use `migrateLegacyToPluginSettings` instead. */ const LEGACY_STORAGE_KEYS = [ "animatedbk", "bksliderinput", "assessmentsAverage", "lettergrade", "notificationCollector", ] as const; /** * Keys where `undefined` in storage is intentional and must not be replaced by a * default (differs from the value we would write). */ const OPTIONAL_UNSET_MEANS_DEFAULT_KEYS = [ "timeFormat", "selectedFont", "privacyStatementShown", "privacyStatementLastUpdated", "bsCloudAutoSyncAnnouncementShown", "themeOfTheMonthDismissedMonth", "themeOfTheMonthLastSeenId", "justupdated", "devMode", "hideSensitiveContent", "mockNotices", "devGhReleaseVersionOverride", "lastSeenNightlyPublishedAt", "originalDarkMode", "profile_picture_revision", ] as const; let defaultsEnsured = false; /** * Flat default map in upload shape (plugin-format only; no legacy keys). */ export function getSyncableStorageDefaults(): Record { const flat: Record = { ...getDefaultSettingsState(), }; for (const key of LEGACY_STORAGE_KEYS) { delete flat[key]; } for (const key of OPTIONAL_UNSET_MEANS_DEFAULT_KEYS) { delete flat[key]; } for (const [pluginId, settings] of Object.entries( SYNCABLE_PLUGIN_SETTING_DEFAULTS, )) { flat[`plugin.${pluginId}.settings`] = settings; } return flat; } function mergePluginSettingsDefaults( defaults: Record, fromLegacy: unknown, ): Record { if (!fromLegacy || typeof fromLegacy !== "object" || Array.isArray(fromLegacy)) { return defaults; } return { ...defaults, ...(fromLegacy as Record) }; } /** * Writes any missing cloud-syncable keys locally for consistent diffing. * Never overwrites existing values. Missing plugin settings respect legacy keys. */ export async function ensureSyncableStorageDefaults(): Promise { if (defaultsEnsured) return; const existing = await browser.storage.local.get(); const migratedFromExisting = migrateLegacyToPluginSettings({ ...existing, }); const defaults = getSyncableStorageDefaults(); const patch: Record = {}; for (const [key, value] of Object.entries(defaults)) { if (!isKeyIncludedInCloudUploadPayload(key)) continue; if (Object.prototype.hasOwnProperty.call(existing, key)) continue; if (key.startsWith("plugin.") && key.endsWith(".settings")) { patch[key] = mergePluginSettingsDefaults( value as Record, migratedFromExisting[key], ); continue; } patch[key] = value; } if (Object.keys(patch).length > 0) { await browser.storage.local.set(patch); } defaultsEnsured = true; }