/** * 环境数据层:环境/配置的读写,数据存于 chrome.storage.session(解锁后明文)。 * 首次建口令由 crypto-store.setupVault 完成;加密回写由 background 监听完成。 */ (function (root, factory) { if (typeof module === "object" && module.exports) { module.exports = factory({ getStorage: () => (typeof chrome !== "undefined" ? chrome.storage.session : null), getLocalStorage: () => (typeof chrome !== "undefined" ? chrome.storage.local : null), }); } else { const api = factory({ getStorage: () => chrome.storage.session, getLocalStorage: () => chrome.storage.local, }); root.EnvStore = api; } })(typeof globalThis !== "undefined" ? globalThis : this, function ({ getStorage, getLocalStorage }) { const ENV_KEY = "environments"; const ACTIVE_ENV_KEY = "activeEnvId"; function genId() { return "env_" + Date.now().toString(36) + Math.random().toString(36).slice(2, 8); } function genCfgId() { return Date.now().toString(36) + Math.random().toString(36).slice(2, 8); } function storage() { const s = getStorage(); if (!s) throw new Error("chrome.storage.session 不可用"); return s; } async function loadEnvironments() { const data = await storage().get([ENV_KEY, ACTIVE_ENV_KEY]); const environments = data[ENV_KEY] || []; const activeEnvId = data[ACTIVE_ENV_KEY] || environments[0]?.id || null; return { environments, activeEnvId }; } async function saveEnvironments(environments, activeEnvId) { const patch = { [ENV_KEY]: environments }; if (activeEnvId !== undefined) patch[ACTIVE_ENV_KEY] = activeEnvId; await storage().set(patch); } async function getActiveEnv() { const { environments, activeEnvId } = await loadEnvironments(); return environments.find((e) => e.id === activeEnvId) || environments[0] || null; } async function setActiveEnv(envId) { await storage().set({ [ACTIVE_ENV_KEY]: envId }); } const MAX_ENVIRONMENTS = 5; async function createEnvironment(name) { const { environments } = await loadEnvironments(); if (environments.length >= MAX_ENVIRONMENTS) { throw new Error(`最多 ${MAX_ENVIRONMENTS} 个环境`); } const env = { id: genId(), name, configs: [] }; environments.push(env); await saveEnvironments(environments, env.id); return env; } async function renameEnvironment(envId, newName) { const { environments } = await loadEnvironments(); const env = environments.find((e) => e.id === envId); if (env) { env.name = newName; await saveEnvironments(environments); } return env; } async function deleteEnvironment(envId) { const { environments, activeEnvId } = await loadEnvironments(); if (environments.length <= 1) { throw new Error("至少保留一个环境"); } const idx = environments.findIndex((e) => e.id === envId); if (idx === -1) return; environments.splice(idx, 1); const newActive = activeEnvId === envId ? environments[0].id : activeEnvId; await saveEnvironments(environments, newActive); // 失败计数存于 local(非敏感),删除环境时一并清理 const local = getLocalStorage(); if (local) { const attemptsData = await local.get("loginAttempts"); const attempts = attemptsData.loginAttempts || {}; Object.keys(attempts).forEach((k) => { if (k.startsWith(envId + "::")) delete attempts[k]; }); await local.set({ loginAttempts: attempts }); } } async function loadConfigs() { const env = await getActiveEnv(); return env?.configs || []; } async function saveConfigs(configs) { const { environments, activeEnvId } = await loadEnvironments(); const env = environments.find((e) => e.id === activeEnvId); if (!env) throw new Error("未找到当前环境"); env.configs = configs; await saveEnvironments(environments); } async function loadAllConfigs() { const { environments } = await loadEnvironments(); const all = []; environments.forEach((env) => { (env.configs || []).forEach((cfg) => { all.push({ ...cfg, envId: env.id, envName: env.name }); }); }); return all; } return { ENV_KEY, ACTIVE_ENV_KEY, MAX_ENVIRONMENTS, loadEnvironments, saveEnvironments, getActiveEnv, setActiveEnv, createEnvironment, renameEnvironment, deleteEnvironment, loadConfigs, saveConfigs, loadAllConfigs, genId, genCfgId, }; });