{"record":{"id":"d3d7806f9c88aa31","repo":"jlcodes99/cockpit-tools","slug":"traeautocheckin-d3d780","errorCode":null,"errorMessage":"[TraeAutoCheckin] 保存自动签到日志失败:","messagePattern":"\\[TraeAutoCheckin\\] 保存自动签到日志失败:","errorType":"console","errorClass":null,"httpStatus":null,"severity":"warning","filePath":"src/services/traeAutoCheckinService.ts","lineNumber":205,"sourceCode":"  } catch {\n    return [];\n  }\n}\n\nexport function saveTraeAutoCheckinLogs(logs: TraeAutoCheckinLogRecord[]): void {\n  if (typeof window === 'undefined') {\n    return;\n  }\n  try {\n    const now = Date.now();\n    const validLogs = logs.filter((log) => {\n      const logTime = new Date(log.timestamp.replace(' ', 'T')).getTime();\n      return !isNaN(logTime) && now - logTime <= THIRTY_DAYS_MS;\n    });\n    localStorage.setItem(LOGS_KEY, JSON.stringify(validLogs));\n    window.dispatchEvent(new Event(TRAE_AUTO_CHECKIN_LOGS_CHANGED_EVENT));\n  } catch (err) {\n    console.warn('[TraeAutoCheckin] 保存自动签到日志失败:', err);\n  }\n}\n\nexport function addTraeAutoCheckinLog(record: TraeAutoCheckinLogRecord): void {\n  const currentLogs = getTraeAutoCheckinLogs();\n  const existingIndex = currentLogs.findIndex((l) => l.date === record.date);\n\n  if (existingIndex < 0) {\n    saveTraeAutoCheckinLogs([record, ...currentLogs]);\n    return;\n  }\n\n  const existing = currentLogs[existingIndex];\n  if (!existing) {\n    saveTraeAutoCheckinLogs([record, ...currentLogs]);\n    return;\n  }\n","sourceCodeStart":187,"sourceCodeEnd":223,"githubUrl":"https://github.com/jlcodes99/cockpit-tools/blob/1ed8b77992d62ca81fabf744deb0839ad361d5bf/src/services/traeAutoCheckinService.ts#L187-L223","documentation":"saveTraeAutoCheckinLogs persists the Trae auto-checkin log array to localStorage under LOGS_KEY and notifies listeners via a window event. It wraps all persistence in try/catch and logs a warning instead of throwing, because saving checkin history is non-critical and a quota or storage failure should not break the checkin flow.","triggerScenarios":"localStorage.setItem throws when the serialized log JSON exceeds the ~5MB browser quota, when storage is disabled (private mode, denied permission), or when JSON.stringify produces an unexpected failure while filtering logs to the last 30 days.","commonSituations":"Long-running installs accumulating many accounts/logs until quota is hit; Safari private browsing where setItem always throws; enterprise browsers with localStorage disabled by policy.","solutions":["Trim stored logs more aggressively (fewer than 30 days or cap count) before writing","Clear other localStorage keys or call clearTraeAutoCheckinLogs to free quota","Check that localStorage is accessible (try a test write) and warn users in private-mode contexts","Accept the warning: the app intentionally continues without persisted logs"],"exampleFix":"// before\nlocalStorage.setItem(LOGS_KEY, JSON.stringify(validLogs));\n// after\nconst trimmed = validLogs.slice(-500);\ntry {\n  localStorage.setItem(LOGS_KEY, JSON.stringify(trimmed));\n} catch (err) {\n  console.warn('[TraeAutoCheckin] 保存自动签到日志失败:', err);\n}","handlingStrategy":"try-catch","validationCode":"function canWriteLocalStorage(): boolean {\n  try { localStorage.setItem('__probe__', '1'); localStorage.removeItem('__probe__'); return true; }\n  catch { return false; }\n}","typeGuard":null,"tryCatchPattern":"try {\n  localStorage.setItem(LOGS_KEY, JSON.stringify(validLogs.slice(-500)));\n} catch (err) {\n  if (err instanceof DOMException && err.name === 'QuotaExceededError') trimAndRetry();\n  else console.warn('[TraeAutoCheckin] 保存自动签到日志失败:', err);\n}","preventionTips":["Cap stored log count/date range before serializing","Probe storage availability at app startup","Periodically prune legacy keys to keep quota headroom","Treat logs as disposable; never let log persistence break checkin flow"],"tags":["localstorage","quota","persistence"],"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"}