{"record":{"id":"27e63c6b29188704","repo":"jlcodes99/cockpit-tools","slug":"workbuddyautocheckin-27e63c","errorCode":null,"errorMessage":"[WorkbuddyAutoCheckin] 本地缓存保存失败:","messagePattern":"\\[WorkbuddyAutoCheckin\\] 本地缓存保存失败:","errorType":"console","errorClass":null,"httpStatus":null,"severity":"warning","filePath":"src/services/workbuddyAutoCheckinService.ts","lineNumber":63,"sourceCode":"\nlet cachedConfig: WorkbuddyAutoCheckinConfig | null = null;\n\nfunction isValidTime(time: unknown): time is string {\n  return typeof time === 'string' && /^([01]\\d|2[0-3]):[0-5]\\d$/.test(time);\n}\n\nfunction cacheConfigLocally(config: WorkbuddyAutoCheckinConfig, emitChange = false): void {\n  cachedConfig = config;\n  if (typeof window === 'undefined') {\n    return;\n  }\n  try {\n    localStorage.setItem(CONFIG_KEY, JSON.stringify(config));\n    if (emitChange) {\n      window.dispatchEvent(new Event(WORKBUDDY_AUTO_CHECKIN_CONFIG_CHANGED_EVENT));\n    }\n  } catch (err) {\n    console.warn('[WorkbuddyAutoCheckin] 本地缓存保存失败:', err);\n  }\n}\n\nexport async function getWorkbuddyAutoCheckinConfigAsync(): Promise<WorkbuddyAutoCheckinConfig> {\n  try {\n    const config = await invoke<WorkbuddyAutoCheckinConfig>('get_workbuddy_auto_checkin_config');\n    cacheConfigLocally(config);\n    return config;\n  } catch (err) {\n    console.warn('[WorkbuddyAutoCheckin] 从 Rust 端获取配置失败，使用本地缓存或默认值:', err);\n    return getWorkbuddyAutoCheckinConfig();\n  }\n}\n\nexport function getWorkbuddyAutoCheckinConfig(): WorkbuddyAutoCheckinConfig {\n  if (cachedConfig) {\n    return cachedConfig;\n  }","sourceCodeStart":45,"sourceCodeEnd":81,"githubUrl":"https://github.com/jlcodes99/cockpit-tools/blob/1ed8b77992d62ca81fabf744deb0839ad361d5bf/src/services/workbuddyAutoCheckinService.ts#L45-L81","documentation":"cacheConfigLocally writes the Workbuddy auto-checkin config JSON to localStorage (CONFIG_KEY) as a mirror of the Rust-side config, optionally emitting a change event. A quota or disabled-storage error is caught and warned so the authoritative Rust config still wins.","triggerScenarios":"localStorage.setItem throws because the serialized config exceeds quota, storage is disabled/private-mode, or a JSON.stringify circular-structure error occurs on a malformed config object.","commonSituations":"localStorage nearly full from other keys; app opened in private browsing; config accidentally containing non-serializable values after a schema change.","solutions":["Free localStorage quota (remove legacy/cached keys)","Validate/normalize the config object before stringify","Treat localStorage as a cache only — fall back to the Rust config (the code already does)","Warn users in private-mode contexts that config caching is unavailable"],"exampleFix":"// before\nlocalStorage.setItem(CONFIG_KEY, JSON.stringify(config));\n// after\ntry {\n  localStorage.setItem(CONFIG_KEY, JSON.stringify(config));\n} catch (err) {\n  console.warn('[WorkbuddyAutoCheckin] 本地缓存保存失败，使用默认配置', err);\n}","handlingStrategy":"fallback","validationCode":"function isSerializable(value: unknown): boolean {\n  try { JSON.stringify(value); return true; } catch { return false; }\n}\nif (!isSerializable(config)) normalizeConfig(config);","typeGuard":null,"tryCatchPattern":"try {\n  localStorage.setItem(CONFIG_KEY, JSON.stringify(config));\n} catch (err) {\n  console.warn('[WorkbuddyAutoCheckin] 本地缓存保存失败:', err);\n  // fall through: Rust-side config remains authoritative\n}","preventionTips":["Always treat localStorage config as a cache, Rust side as source of truth","Validate config shape before caching","Free quota by pruning legacy cache keys","Fall back to defaults/cache when the write fails"],"tags":["localstorage","cache","quota"],"backgroundTag":"localstorage-quota-exceeded","analyzedSha":"1ed8b77992d62ca81fabf744deb0839ad361d5bf","analyzedAt":"2026-09-05T09:51:41.178Z","contentChangedAt":"2026-09-05T09:51:41.178Z","schemaVersion":2},"datasetVersion":"2026-09-12T12:17:11.808Z"}