@ipv9/tokentracker-cli 0.39.35 → 0.39.37

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (39) hide show
  1. package/dashboard/dist/assets/{ActivityHeatmap-rUm9bSZ9.js → ActivityHeatmap-DPZ_Aj6E.js} +1 -1
  2. package/dashboard/dist/assets/{Card-YWr91b5b.js → Card-DKmo-v8a.js} +1 -1
  3. package/dashboard/dist/assets/{DashboardPage-DdJOVJuw.js → DashboardPage-C9Q5HCDh.js} +1 -1
  4. package/dashboard/dist/assets/{DevicePage-CQMG1bh8.js → DevicePage-DhQFtROo.js} +1 -1
  5. package/dashboard/dist/assets/{DialogTitle-BM0Hz4Pq.js → DialogTitle-DduJCLiL.js} +1 -1
  6. package/dashboard/dist/assets/{FadeIn-D8xysY3i.js → FadeIn-Cf30rPTW.js} +1 -1
  7. package/dashboard/dist/assets/{InsforgeUserHeaderControls-CsAafXyj.js → InsforgeUserHeaderControls-CDqYVWBQ.js} +1 -1
  8. package/dashboard/dist/assets/{IpCheckPage-Bbg9erkT.js → IpCheckPage-D3CL8XP0.js} +1 -1
  9. package/dashboard/dist/assets/{LandingPage-BCMsWOwJ.js → LandingPage-9345o0vr.js} +1 -1
  10. package/dashboard/dist/assets/{LeaderboardAvatar-CkQa4EX2.js → LeaderboardAvatar-DNORVh3n.js} +1 -1
  11. package/dashboard/dist/assets/{LeaderboardPage-CyDX3tDL.js → LeaderboardPage-DBsdCCzY.js} +3 -3
  12. package/dashboard/dist/assets/{LeaderboardProfileModal-CMctMA-p.js → LeaderboardProfileModal-BuYdBVh_.js} +2 -2
  13. package/dashboard/dist/assets/{LeaderboardProfilePage-DTZ_6dBt.js → LeaderboardProfilePage-D4Fe1LOk.js} +1 -1
  14. package/dashboard/dist/assets/{LimitsPage-V7939U8b.js → LimitsPage-BqST7DxD.js} +2 -2
  15. package/dashboard/dist/assets/{LocalOnlyNotice-dODOM3SB.js → LocalOnlyNotice-CqHzPooT.js} +1 -1
  16. package/dashboard/dist/assets/{LoginPage-CE5GBEI2.js → LoginPage-BmcybmeK.js} +1 -1
  17. package/dashboard/dist/assets/{PopoverPopup-CRzMMFsC.js → PopoverPopup-CDL7kqy5.js} +1 -1
  18. package/dashboard/dist/assets/{Select-m6edgfye.js → Select-BkzhG41t.js} +1 -1
  19. package/dashboard/dist/assets/{SelectItemText-DIoTPvZM.js → SelectItemText-BmRzs9ud.js} +1 -1
  20. package/dashboard/dist/assets/SettingsPage-gXQl_o6s.js +1 -0
  21. package/dashboard/dist/assets/{SkillsPage-BSi26dZo.js → SkillsPage-BRXYEsKm.js} +1 -1
  22. package/dashboard/dist/assets/{WidgetsPage-CTl7OtvF.js → WidgetsPage-CLHLz2UW.js} +1 -1
  23. package/dashboard/dist/assets/{WrappedPage-BXwhD9aq.js → WrappedPage-p4ZFwQjO.js} +1 -1
  24. package/dashboard/dist/assets/{arrow-up-right-DxdoYoxg.js → arrow-up-right-BJzUcPig.js} +1 -1
  25. package/dashboard/dist/assets/{download-BZkwGDg8.js → download-CsXweDLj.js} +1 -1
  26. package/dashboard/dist/assets/{info-DRaQWOpM.js → info-CuLr7ZIa.js} +1 -1
  27. package/dashboard/dist/assets/{main-CuaPRwHu.js → main-CPGI-smk.js} +12 -11
  28. package/dashboard/dist/assets/{use-limits-display-prefs-5cj2WfP-.js → use-limits-display-prefs-DOB09__q.js} +1 -1
  29. package/dashboard/dist/assets/{use-native-settings-BfydbPtC.js → use-native-settings-JSylS2xS.js} +1 -1
  30. package/dashboard/dist/assets/{use-spring-BxDSGjR_.js → use-spring-qjUEvMQX.js} +1 -1
  31. package/dashboard/dist/assets/{use-usage-limits-D_5PMCyF.js → use-usage-limits-B0bzPxNR.js} +1 -1
  32. package/dashboard/dist/assets/{useCurrency-DQhzQX2k.js → useCurrency-BRorShq7.js} +1 -1
  33. package/dashboard/dist/assets/{useOpenInteractionType--grUNSll.js → useOpenInteractionType-DPP-6ZsL.js} +2 -2
  34. package/dashboard/dist/index.html +1 -1
  35. package/dashboard/dist/share.html +1 -1
  36. package/package.json +1 -1
  37. package/src/lib/pricing/seed-snapshot.json +1 -1
  38. package/src/lib/usage-limits.js +101 -17
  39. package/dashboard/dist/assets/SettingsPage-DObaSleW.js +0 -1
@@ -29,6 +29,8 @@ const DEFAULT_PROVIDER_TIMEOUT_MS = 15_000;
29
29
  const ANTIGRAVITY_LIMITS_CACHE_FILE = "usage-limits-cache.json";
30
30
  const ANTIGRAVITY_LIMITS_CACHE_MAX_AGE_MS = 7 * 24 * 60 * 60 * 1000;
31
31
  const ANTIGRAVITY_LIMITS_CACHE_UNKNOWN_RESET_TTL_MS = 12 * 60 * 60 * 1000;
32
+ const CLAUDE_LIMITS_CACHE_MAX_AGE_MS = 24 * 60 * 60 * 1000;
33
+ const CLAUDE_USAGE_RATE_LIMITED = "CLAUDE_USAGE_RATE_LIMITED";
32
34
 
33
35
  function clampPercent(value) {
34
36
  if (value === null || value === undefined || value === "") return null;
@@ -119,9 +121,12 @@ async function fetchClaudeUsageLimits(accessToken, { fetchImpl = fetch, maxAttem
119
121
  }
120
122
  if (!res.ok) {
121
123
  if (res.status === 429) {
122
- throw new Error(
124
+ const error = new Error(
123
125
  "Claude API rate limited (429) — wait ~1 minute and refresh.",
124
126
  );
127
+ error.code = CLAUDE_USAGE_RATE_LIMITED;
128
+ error.transient = true;
129
+ throw error;
125
130
  }
126
131
  throw new Error(`Claude API returned ${res.status}`);
127
132
  }
@@ -135,6 +140,13 @@ async function fetchClaudeUsageLimits(accessToken, { fetchImpl = fetch, maxAttem
135
140
  }
136
141
  }
137
142
 
143
+ function isClaudeTransientUsageError(error) {
144
+ if (!error) return false;
145
+ if (error.code === CLAUDE_USAGE_RATE_LIMITED || error.transient === true) return true;
146
+ const message = String(error.message || "");
147
+ return /rate limited|timed out/i.test(message);
148
+ }
149
+
138
150
  // Classify a wham window by `limit_window_seconds` rather than its slot name.
139
151
  // 18000s = 5h session window. 604800s = 7d weekly window. Free-tier accounts only get a
140
152
  // weekly window, often delivered in the `primary_window` slot — naive position-based
@@ -1324,11 +1336,34 @@ function detectAntigravityProcess({ commandRunner } = {}) {
1324
1336
  return { configured: false };
1325
1337
  }
1326
1338
 
1327
- function resolveAntigravityLimitsCachePath({ home } = {}) {
1339
+ function resolveUsageLimitsCachePath({ home } = {}) {
1328
1340
  return path.join(home || os.homedir(), ".tokentracker", "tracker", ANTIGRAVITY_LIMITS_CACHE_FILE);
1329
1341
  }
1330
1342
 
1343
+ function readUsageLimitsCacheFile({ home } = {}) {
1344
+ try {
1345
+ return JSON.parse(fs.readFileSync(resolveUsageLimitsCachePath({ home }), "utf8"));
1346
+ } catch (_error) {
1347
+ return {};
1348
+ }
1349
+ }
1350
+
1351
+ function writeUsageLimitsCacheFile(update, { home } = {}) {
1352
+ const cachePath = resolveUsageLimitsCachePath({ home });
1353
+ try {
1354
+ const current = readUsageLimitsCacheFile({ home });
1355
+ fs.mkdirSync(path.dirname(cachePath), { recursive: true });
1356
+ const tmpPath = `${cachePath}.${process.pid}.tmp`;
1357
+ fs.writeFileSync(tmpPath, JSON.stringify({ ...current, ...update }, null, 2), { encoding: "utf8", mode: 0o600 });
1358
+ fs.renameSync(tmpPath, cachePath);
1359
+ } catch (_error) {}
1360
+ }
1361
+
1331
1362
  function parseTimeMs(value) {
1363
+ if (typeof value === "number") {
1364
+ if (!Number.isFinite(value) || value <= 0) return null;
1365
+ return value < 1_000_000_000_000 ? value * 1000 : value;
1366
+ }
1332
1367
  if (typeof value !== "string" || !value) return null;
1333
1368
  const ts = Date.parse(value);
1334
1369
  return Number.isFinite(ts) && ts > 0 ? ts : null;
@@ -1367,18 +1402,12 @@ function normalizeAntigravityCachedLimits(raw, { nowMs = Date.now() } = {}) {
1367
1402
  }
1368
1403
 
1369
1404
  function readAntigravityLimitsCache({ home, nowMs = Date.now() } = {}) {
1370
- const cachePath = resolveAntigravityLimitsCachePath({ home });
1371
- try {
1372
- const parsed = JSON.parse(fs.readFileSync(cachePath, "utf8"));
1373
- return normalizeAntigravityCachedLimits(parsed?.antigravity, { nowMs });
1374
- } catch (_error) {
1375
- return null;
1376
- }
1405
+ const parsed = readUsageLimitsCacheFile({ home });
1406
+ return normalizeAntigravityCachedLimits(parsed?.antigravity, { nowMs });
1377
1407
  }
1378
1408
 
1379
1409
  function writeAntigravityLimitsCache(limits, { home, nowMs = Date.now() } = {}) {
1380
1410
  if (!limits?.configured || limits.error || !hasAntigravityWindow(limits)) return;
1381
- const cachePath = resolveAntigravityLimitsCachePath({ home });
1382
1411
  const payload = {
1383
1412
  antigravity: {
1384
1413
  account_email: limits.account_email || null,
@@ -1389,12 +1418,62 @@ function writeAntigravityLimitsCache(limits, { home, nowMs = Date.now() } = {})
1389
1418
  cached_at: new Date(nowMs).toISOString(),
1390
1419
  },
1391
1420
  };
1392
- try {
1393
- fs.mkdirSync(path.dirname(cachePath), { recursive: true });
1394
- const tmpPath = `${cachePath}.${process.pid}.tmp`;
1395
- fs.writeFileSync(tmpPath, JSON.stringify(payload, null, 2), { encoding: "utf8", mode: 0o600 });
1396
- fs.renameSync(tmpPath, cachePath);
1397
- } catch (_error) {}
1421
+ writeUsageLimitsCacheFile(payload, { home });
1422
+ }
1423
+
1424
+ function hasClaudeWindow(limits) {
1425
+ return Boolean(limits?.five_hour || limits?.seven_day || limits?.seven_day_opus);
1426
+ }
1427
+
1428
+ function isClaudeCacheWindowUsable(window, { cachedAtMs, nowMs } = {}) {
1429
+ if (!window || typeof window !== "object") return false;
1430
+ const resetAtMs = parseTimeMs(window.resets_at);
1431
+ if (resetAtMs !== null) return resetAtMs > nowMs;
1432
+ return Number.isFinite(cachedAtMs)
1433
+ && nowMs - cachedAtMs <= CLAUDE_LIMITS_CACHE_MAX_AGE_MS;
1434
+ }
1435
+
1436
+ function normalizeClaudeCachedLimits(raw, { nowMs = Date.now() } = {}) {
1437
+ const cachedAtMs = parseTimeMs(raw?.cached_at);
1438
+ if (!Number.isFinite(cachedAtMs)) return null;
1439
+ if (cachedAtMs > nowMs + 60_000) return null;
1440
+ if (nowMs - cachedAtMs > CLAUDE_LIMITS_CACHE_MAX_AGE_MS) return null;
1441
+
1442
+ const cached = {
1443
+ configured: true,
1444
+ error: null,
1445
+ five_hour: isClaudeCacheWindowUsable(raw?.five_hour, { cachedAtMs, nowMs }) ? raw.five_hour : null,
1446
+ seven_day: isClaudeCacheWindowUsable(raw?.seven_day, { cachedAtMs, nowMs }) ? raw.seven_day : null,
1447
+ seven_day_opus: isClaudeCacheWindowUsable(raw?.seven_day_opus, { cachedAtMs, nowMs }) ? raw.seven_day_opus : null,
1448
+ extra_usage: raw?.extra_usage || null,
1449
+ cached: true,
1450
+ cached_at: raw.cached_at,
1451
+ stale_reason: typeof raw?.stale_reason === "string" ? raw.stale_reason : null,
1452
+ };
1453
+ return hasClaudeWindow(cached) ? cached : null;
1454
+ }
1455
+
1456
+ function readClaudeLimitsCache({ home, nowMs = Date.now(), staleReason = null } = {}) {
1457
+ const parsed = readUsageLimitsCacheFile({ home });
1458
+ const cached = normalizeClaudeCachedLimits(parsed?.claude, { nowMs });
1459
+ if (!cached) return null;
1460
+ return {
1461
+ ...cached,
1462
+ stale_reason: typeof staleReason === "string" && staleReason ? staleReason : cached.stale_reason,
1463
+ };
1464
+ }
1465
+
1466
+ function writeClaudeLimitsCache(limits, { home, nowMs = Date.now() } = {}) {
1467
+ if (!limits?.configured || limits.error || !hasClaudeWindow(limits)) return;
1468
+ writeUsageLimitsCacheFile({
1469
+ claude: {
1470
+ five_hour: limits.five_hour || null,
1471
+ seven_day: limits.seven_day || null,
1472
+ seven_day_opus: limits.seven_day_opus || null,
1473
+ extra_usage: limits.extra_usage || null,
1474
+ cached_at: new Date(nowMs).toISOString(),
1475
+ },
1476
+ }, { home });
1398
1477
  }
1399
1478
 
1400
1479
  function resolveLsofBinary({ commandRunner } = {}) {
@@ -1860,7 +1939,11 @@ async function getUsageLimits({
1860
1939
  if (!claudeToken) {
1861
1940
  claude = { configured: false };
1862
1941
  } else if (!claudeResult || claudeResult.status === "rejected") {
1863
- claude = { configured: true, error: claudeResult?.reason?.message || "Unknown error" };
1942
+ const reason = claudeResult?.reason;
1943
+ const cached = isClaudeTransientUsageError(reason)
1944
+ ? readClaudeLimitsCache({ home, nowMs, staleReason: reason?.message })
1945
+ : null;
1946
+ claude = cached || { configured: true, error: reason?.message || "Unknown error" };
1864
1947
  } else {
1865
1948
  claude = {
1866
1949
  configured: true,
@@ -1870,6 +1953,7 @@ async function getUsageLimits({
1870
1953
  seven_day_opus: claudeResult.value.seven_day_opus,
1871
1954
  extra_usage: claudeResult.value.extra_usage,
1872
1955
  };
1956
+ writeClaudeLimitsCache(claude, { home, nowMs });
1873
1957
  }
1874
1958
 
1875
1959
  let codex;
@@ -1 +0,0 @@
1
- import{c as y,r as l,ah as Q,ab as q,aE as L,j as n,m as A,O as v,A as s,T as X,ao as ee,at as te,au as ne,av as O,aF as ae,aG as ie,as as se,a7 as oe,R as re,N as le,H as ce,W as ue,aH as de,aI as ge,aJ as he,aK as pe,E as me,aL as be,aM as fe,aN as xe,aO as ye,aP as ve,aQ as je,aR as ke,a8 as Ne}from"./main-CuaPRwHu.js";import{a as Se,b as E,u as we,L as G}from"./use-limits-display-prefs-5cj2WfP-.js";import{S as j,T as k,a as b,b as _,u as P}from"./use-native-settings-BfydbPtC.js";import{C as Ce}from"./useOpenInteractionType--grUNSll.js";import{u as Le}from"./useCurrency-DQhzQX2k.js";import{S as D}from"./Select-m6edgfye.js";import{I as Ee}from"./info-DRaQWOpM.js";import{D as Ge}from"./download-BZkwGDg8.js";import"./Card-YWr91b5b.js";import"./SelectItemText-DIoTPvZM.js";const Ie=[["path",{d:"M22 12h-2.48a2 2 0 0 0-1.93 1.46l-2.35 8.36a.25.25 0 0 1-.48 0L9.24 2.18a.25.25 0 0 0-.48 0l-2.35 8.36A2 2 0 0 1 4.49 12H2",key:"169zse"}]],Ae=y("activity",Ie);const Oe=[["rect",{width:"14",height:"14",x:"8",y:"8",rx:"2",ry:"2",key:"17jyea"}],["path",{d:"M4 16c-1.1 0-2-.9-2-2V4c0-1.1.9-2 2-2h10c1.1 0 2 .9 2 2",key:"zix9uf"}]],_e=y("copy",Oe);const Pe=[["circle",{cx:"9",cy:"12",r:"1",key:"1vctgf"}],["circle",{cx:"9",cy:"5",r:"1",key:"hp0tcf"}],["circle",{cx:"9",cy:"19",r:"1",key:"fkjjf6"}],["circle",{cx:"15",cy:"12",r:"1",key:"1tmaij"}],["circle",{cx:"15",cy:"5",r:"1",key:"19l28e"}],["circle",{cx:"15",cy:"19",r:"1",key:"f4zoj3"}]],De=y("grip-vertical",Pe);const Te=[["path",{d:"m5 8 6 6",key:"1wu5hv"}],["path",{d:"m4 14 6-6 2-3",key:"1k1g8d"}],["path",{d:"M2 5h12",key:"or177f"}],["path",{d:"M7 2h1",key:"1t2jsx"}],["path",{d:"m22 22-5-10-5 10",key:"don7ne"}],["path",{d:"M14 18h6",key:"1m8k6r"}]],Me=y("languages",Te);const Ue=[["path",{d:"m16 17 5-5-5-5",key:"1bji2h"}],["path",{d:"M21 12H9",key:"dn1m92"}],["path",{d:"M9 21H5a2 2 0 0 1-2-2V5a2 2 0 0 1 2-2h4",key:"1uf3rs"}]],Re=y("log-out",Ue);const Fe=[["path",{d:"M21.174 6.812a1 1 0 0 0-3.986-3.987L3.842 16.174a2 2 0 0 0-.5.83l-1.321 4.352a.5.5 0 0 0 .623.622l4.353-1.32a2 2 0 0 0 .83-.497z",key:"1a8usu"}],["path",{d:"m15 5 4 4",key:"1mk7zo"}]],He=y("pencil",Fe),$e=e=>!e.isLayoutDirty&&e.willUpdate(!1);function I(){const e=new Set,t=new WeakMap,a=()=>e.forEach($e);return{add:i=>{e.add(i),t.set(i,i.addEventListener("willUpdate",a))},remove:i=>{e.delete(i);const o=t.get(i);o&&(o(),t.delete(i)),a()},dirty:a}}const Be=l.createContext(null);function ze(){const e=l.useRef(!1);return Q(()=>(e.current=!0,()=>{e.current=!1}),[]),e}function Ve(){const e=ze(),[t,a]=l.useState(0),i=l.useCallback(()=>{e.current&&a(t+1)},[t]);return[l.useCallback(()=>q.postRender(i),[i]),t]}const T=e=>e===!0,We=e=>T(e===!0)||e==="id",Ze=({children:e,id:t,inherit:a=!0})=>{const i=l.useContext(L),o=l.useContext(Be),[r,c]=Ve(),u=l.useRef(null),g=i.id||o;u.current===null&&(We(a)&&g&&(t=t?g+"-"+t:g),u.current={id:t,group:T(a)&&i.group||I()});const h=l.useMemo(()=>({...u.current,forceRender:r}),[c]);return n.jsx(L.Provider,{value:h,children:e})},Ke=new Set(["cursor","kiro","copilot","kimi"]);function Ye({checked:e,onChange:t,ariaLabel:a}){return n.jsx("button",{type:"button",role:"switch","aria-checked":e,"aria-label":a,onClick:t,className:v("relative inline-flex h-5 w-9 shrink-0 items-center rounded-full transition-colors focus-visible:outline-none focus-visible:ring-2 focus-visible:ring-oai-brand-500",e?"bg-oai-brand-500":"bg-oai-gray-300 dark:bg-oai-gray-700"),children:n.jsx("span",{className:v("inline-block h-3.5 w-3.5 rounded-full bg-white transition-transform",e?"translate-x-[18px]":"translate-x-[3px]")})})}function Je({prefs:e}){const{order:t,visibility:a,toggle:i,moveToward:o}=e,[r,c]=l.useState(null),[u,g]=l.useState(null),h=d=>p=>{c(d),p.dataTransfer.effectAllowed="move",p.dataTransfer.setData("text/plain",d)},m=d=>p=>{p.preventDefault(),p.dataTransfer.dropEffect="move",r&&r!==d&&u!==d&&(g(d),o(r,d))},f=()=>{c(null),g(null)},x=d=>{d.preventDefault(),c(null),g(null)};return n.jsx(Ze,{children:n.jsx("div",{className:"flex flex-col",children:t.map(d=>{const p=a[d]!==!1,N=r===d;return n.jsxs(A.div,{layout:!0,transition:{duration:.28,ease:[.22,1,.36,1]},draggable:!0,onDragStart:h(d),onDragOver:m(d),onDragEnd:f,onDrop:x,className:v("flex items-center gap-3 py-2 rounded-md","hover:bg-oai-gray-100/60 dark:hover:bg-oai-gray-800/60",N&&"opacity-40"),style:{cursor:N?"grabbing":"grab"},children:[n.jsx(De,{className:"h-4 w-4 shrink-0 text-oai-gray-400 dark:text-oai-gray-500",strokeWidth:1.75,"aria-hidden":!0}),n.jsx("img",{src:Se[d],alt:"",width:18,height:18,className:v("h-[18px] w-[18px] shrink-0 pointer-events-none",Ke.has(d)&&"dark:invert"),draggable:!1}),n.jsx("span",{className:"flex-1 text-sm text-oai-gray-900 dark:text-oai-gray-200 select-none",children:E[d]}),n.jsx("div",{onMouseDown:S=>S.stopPropagation(),draggable:!1,children:n.jsx(Ye,{checked:p,onChange:()=>i(d),ariaLabel:`${s("limits.settings.toggle_visible")}: ${E[d]}`})})]},d)})})})}function Qe(e){if(!e||typeof e!="object")return"";const t=e.user_metadata&&typeof e.user_metadata=="object"?e.user_metadata:{},a=e.profile&&typeof e.profile=="object"?e.profile:{},i=t.full_name||t.name||a.name||t.user_name||t.preferred_username;return typeof i=="string"&&i.trim()?i.trim():typeof e.email=="string"&&e.email.includes("@")?e.email.split("@")[0].trim()||e.email.trim():typeof e.email=="string"?e.email.trim():""}function qe(e){return!e||typeof e!="object"?"":typeof e.email=="string"?e.email.trim():""}function Xe(e){const t=typeof e=="string"?e.trim():"";if(!t)return null;const a=t.match(/^@?([A-Za-z0-9][A-Za-z0-9-]{0,38})$/),i=t.match(/^https:\/\/github\.com\/([A-Za-z0-9][A-Za-z0-9-]{0,38})\/?$/i),o=a?.[1]||i?.[1];return o?`https://github.com/${o}`:null}function w(e,t){console.warn(`[tokentracker] settings ${e}:`,t)}function et(e,t,a){const[i,o]=l.useState(()=>ee()),r=t&&a&&se(),c=l.useCallback(async()=>{const u=!i;if(te(u),o(u),!!u)try{await ne(()=>e())}catch(g){w("cloud sync",g)}},[i,e]);return{cloudSyncOn:i,handleCloudSyncToggle:c,showLocalCloudSync:r}}function tt(e){const[t,a]=l.useState(!1),[i,o]=l.useState(!1),[r,c]=l.useState(!1),[u,g]=l.useState(!1),[h,m]=l.useState(null),[f,x]=l.useState(!1),[d,p]=l.useState(""),[N,S]=l.useState(!1),[F,C]=l.useState(""),[H,$]=l.useState(""),[B,z]=l.useState(!1),[V,W]=l.useState(null),Z=l.useMemo(()=>Qe(e),[e]),K=l.useMemo(()=>qe(e),[e]),Y=l.useMemo(()=>typeof e?.id=="string"?e.id.trim():"",[e]),J=l.useMemo(()=>({setAnonymousOn:o,setCustomDisplayName:m,setGithubUrl:C,setProfileLoading:c,setPublicProfileOn:a,setShowGithubOn:S}),[]);return{anonymousOn:i,customDisplayName:h,displayName:Z,editingGithub:B,editingName:f,email:K,githubError:V,githubInput:H,githubUrl:F,loadSetters:J,nameInput:d,profileLoading:r,profileSaving:u,publicProfileOn:t,setAnonymousOn:o,setCustomDisplayName:m,setEditingGithub:z,setEditingName:x,setGithubError:W,setGithubInput:$,setGithubUrl:C,setNameInput:p,setProfileLoading:c,setProfileSaving:g,setPublicProfileOn:a,setShowGithubOn:S,showGithubOn:N,userId:Y}}function nt(e,t,a){l.useEffect(()=>{if(!t)return;let i=!0;return a.setProfileLoading(!0),(async()=>{try{const o=await O({getAccessToken:e});if(!i||!o)return;const r=await ae({accessToken:o});if(!i)return;a.setPublicProfileOn(!!r?.enabled),a.setAnonymousOn(!!r?.anonymous),r?.display_name&&a.setCustomDisplayName(r.display_name),a.setShowGithubOn(!!r?.show_github_url),a.setGithubUrl(r?.github_url||"")}catch(o){w("load public profile",o)}finally{i&&a.setProfileLoading(!1)}})(),()=>{i=!1}},[e,t,a])}function at(e,t){return l.useCallback(async(a,{label:i,onError:o,onSuccess:r}={})=>{if(t.profileSaving)return!1;t.setProfileSaving(!0);try{const c=await O({getAccessToken:e});if(!c)return!1;const u=await ie({accessToken:c,...a});return r?.(u),!0}catch(c){return o?o(c):w(i||"mutate profile",c),!1}finally{t.setProfileSaving(!1)}},[e,t])}function it(e,t){return{anonymousOn:e.anonymousOn,customDisplayName:e.customDisplayName,displayName:e.displayName,editingName:e.editingName,handleAnonymousToggle:t.handleAnonymousToggle,handleSaveName:t.handleSaveName,nameInput:e.nameInput,profileLoading:e.profileLoading,profileSaving:e.profileSaving,setEditingName:e.setEditingName,setNameInput:e.setNameInput,startEditingName:t.startEditingName}}function st(e,t){return{editingGithub:e.editingGithub,githubError:e.githubError,githubInput:e.githubInput,githubUrl:e.githubUrl,handleSaveGithub:t.handleSaveGithub,handleShowGithubToggle:t.handleShowGithubToggle,profileLoading:e.profileLoading,profileSaving:e.profileSaving,setEditingGithub:e.setEditingGithub,setGithubError:e.setGithubError,setGithubInput:e.setGithubInput,showGithubOn:e.showGithubOn,startEditingGithub:t.startEditingGithub}}function ot(e,t){const a=l.useCallback(async()=>{const o=!e.publicProfileOn;await t({enabled:o},{label:"toggle public profile",onSuccess:()=>e.setPublicProfileOn(o)})},[t,e]);return{handleAnonymousToggle:l.useCallback(async()=>{const o=!e.anonymousOn;await t({anonymous:o},{label:"toggle anonymous",onSuccess:()=>e.setAnonymousOn(o)})},[t,e]),handlePublicProfileToggle:a}}function rt(e,t,a){const i=l.useCallback(async()=>{const r=e.nameInput.trim().slice(0,50);r&&await t({display_name:r},{label:"save display name",onSuccess:()=>{e.setCustomDisplayName(r),e.setEditingName(!1),a?.()}})},[t,e,a]),o=l.useCallback(()=>{e.setNameInput(e.customDisplayName||e.displayName),e.setEditingName(!0)},[e]);return{handleSaveName:i,startEditingName:o}}function lt(e,t){const a=l.useCallback(async()=>{if(!e.showGithubOn&&!e.githubUrl){e.setEditingGithub(!0),e.setGithubInput(""),e.setGithubError(null);return}const r=!e.showGithubOn;await t({show_github_url:r},{label:"toggle GitHub profile",onSuccess:()=>e.setShowGithubOn(r)})},[t,e]),i=l.useCallback(async()=>{const r=Xe(e.githubInput);if(e.githubInput.trim()&&!r){e.setGithubError(s("settings.account.githubUrlInvalid"));return}e.setGithubError(null),await t({github_url:r,show_github_url:!!r},{label:"save GitHub profile",onError:c=>e.setGithubError(c?.message||s("settings.account.githubUrlInvalid")),onSuccess:c=>{e.setGithubUrl(c?.github_url||r||""),e.setShowGithubOn(!!r),e.setEditingGithub(!1)}})},[t,e]),o=l.useCallback(()=>{e.setGithubInput(e.githubUrl),e.setGithubError(null),e.setEditingGithub(!0)},[e]);return{handleSaveGithub:i,handleShowGithubToggle:a,startEditingGithub:o}}function ct(){const e=X(),t=tt(e.user),a=et(e.getAccessToken,e.enabled,e.signedIn);nt(e.getAccessToken,e.signedIn,t.loadSetters);const i=at(e.getAccessToken,t),o=ot(t,i),r=rt(t,i,e.refreshDisplayName),c=lt(t,i);return{...e,...a,email:t.email,handlePublicProfileToggle:o.handlePublicProfileToggle,userId:t.userId,name:it(t,{...o,...r}),github:st(t,c),profileLoading:t.profileLoading,profileSaving:t.profileSaving,publicProfileOn:t.publicProfileOn}}function M({disabled:e,onCancel:t,onSave:a,saveLabel:i=s("settings.account.save")}){return n.jsxs(n.Fragment,{children:[n.jsx("button",{type:"button",onClick:a,disabled:e,className:"rounded-md bg-oai-brand-500 px-3 py-1.5 text-xs font-medium text-white transition-colors hover:bg-oai-brand-600 disabled:opacity-50",children:i}),n.jsx("button",{type:"button",onClick:t,className:"rounded-md px-2 py-1.5 text-xs text-oai-gray-500 transition-colors hover:text-oai-gray-700 dark:hover:text-oai-gray-300",children:s("settings.account.cancel")})]})}function ut({nameInput:e,setEditingName:t,setNameInput:a,profileSaving:i,handleSaveName:o}){return n.jsxs("div",{className:"mt-2 flex items-center gap-2",children:[n.jsx("input",{type:"text",value:e,onChange:r=>a(r.target.value),onKeyDown:r=>{r.key==="Enter"&&o(),r.key==="Escape"&&t(!1)},maxLength:50,autoFocus:!0,className:"flex-1 rounded-md border border-oai-gray-300 bg-transparent px-2.5 py-1.5 text-sm text-oai-black outline-none focus:border-oai-brand-500 focus:ring-1 focus:ring-inset focus:ring-oai-brand-500 dark:border-oai-gray-700 dark:text-white",placeholder:s("settings.account.displayName")}),n.jsx(M,{disabled:i||!e.trim(),onCancel:()=>t(!1),onSave:o,saveLabel:i?s("settings.account.saving"):void 0})]})}function dt({githubError:e,githubInput:t,handleSaveGithub:a,profileSaving:i,setEditingGithub:o,setGithubError:r,setGithubInput:c}){return n.jsxs("div",{className:"mt-2",children:[n.jsxs("div",{className:"flex items-center gap-2",children:[n.jsx("input",{type:"text",value:t,onChange:u=>{c(u.target.value),e&&r(null)},onKeyDown:u=>{u.key==="Enter"&&a(),u.key==="Escape"&&(o(!1),r(null))},maxLength:100,autoFocus:!0,className:"flex-1 rounded-md border border-oai-gray-300 bg-transparent px-2.5 py-1.5 text-sm text-oai-black outline-none focus:border-oai-brand-500 focus:ring-1 focus:ring-inset focus:ring-oai-brand-500 dark:border-oai-gray-700 dark:text-white",placeholder:s("settings.account.githubUrlPlaceholder")}),n.jsx(M,{disabled:i,onCancel:()=>{o(!1),r(null)},onSave:a,saveLabel:i?s("settings.account.saving"):void 0})]}),e?n.jsx("div",{className:"mt-1.5 text-xs text-red-600 dark:text-red-400",children:e}):null]})}function U({disabled:e=!1,label:t,onClick:a,title:i}){return n.jsxs("button",{type:"button",onClick:a,disabled:e,title:i,className:"inline-flex h-8 shrink-0 items-center gap-1.5 rounded-md border border-oai-gray-200 px-3 text-xs font-medium text-oai-gray-700 transition-colors hover:bg-oai-gray-100 disabled:cursor-not-allowed disabled:opacity-40 dark:border-oai-gray-800 dark:text-oai-gray-300 dark:hover:bg-oai-gray-800",children:[n.jsx(He,{className:"h-3.5 w-3.5","aria-hidden":!0}),t]})}function R({actions:e,editing:t,editor:a,hint:i,label:o}){return n.jsx("div",{className:"py-3",children:n.jsxs("div",{className:"flex items-start justify-between gap-4",children:[n.jsxs("div",{className:"min-w-0 flex-1",children:[n.jsx("div",{className:"text-sm text-oai-gray-900 dark:text-oai-gray-200",children:o}),t?a:n.jsx("div",{className:"mt-0.5 truncate text-xs text-oai-gray-500 dark:text-oai-gray-400",children:i})]}),t?null:e]})})}function gt({name:e}){const t=e.anonymousOn?s("settings.account.displayNameDisabledWhileAnon"):void 0;return n.jsxs("div",{className:"flex shrink-0 items-center gap-2",children:[n.jsx(U,{disabled:e.anonymousOn,label:s("settings.account.edit"),onClick:e.startEditingName,title:t}),n.jsx(k,{checked:!e.anonymousOn,onChange:e.handleAnonymousToggle,disabled:e.profileLoading||e.profileSaving,ariaLabel:s("settings.account.displayName")})]})}function ht({name:e}){const{anonymousOn:t,customDisplayName:a,displayName:i,editingName:o,handleAnonymousToggle:r,handleSaveName:c,nameInput:u,profileLoading:g,profileSaving:h,setEditingName:m,setNameInput:f,startEditingName:x}=e,d=t?s("settings.account.displayNameAnonymousHint"):a||i;return n.jsx(R,{label:s("settings.account.displayName"),editing:o,hint:d,editor:n.jsx(ut,{nameInput:u,setEditingName:m,setNameInput:f,profileSaving:h,handleSaveName:c}),actions:n.jsx(gt,{name:e})})}function pt({github:e}){const{editingGithub:t,githubError:a,githubInput:i,githubUrl:o,handleSaveGithub:r,handleShowGithubToggle:c,profileLoading:u,profileSaving:g,setEditingGithub:h,setGithubError:m,setGithubInput:f,showGithubOn:x,startEditingGithub:d}=e;return n.jsx(R,{label:s("settings.account.githubUrl"),editing:t,hint:o||s("settings.account.githubUrlHint"),editor:n.jsx(dt,{githubError:a,githubInput:i,handleSaveGithub:r,profileSaving:g,setEditingGithub:h,setGithubError:m,setGithubInput:f}),actions:n.jsxs("div",{className:"flex shrink-0 items-center gap-2",children:[n.jsx(U,{label:s("settings.account.edit"),onClick:d}),n.jsx(k,{checked:x,onChange:c,disabled:u||g,ariaLabel:s("settings.account.githubUrl")})]})})}function mt(){const{openLoginModal:e}=oe();return n.jsx(j,{title:s("settings.section.account"),children:n.jsxs("div",{className:"flex items-center justify-between gap-4 py-3",children:[n.jsx("p",{className:"text-sm text-oai-gray-500 dark:text-oai-gray-400",children:s("settings.account.signedOutHint")}),n.jsx("button",{type:"button",onClick:e,className:"inline-flex h-8 shrink-0 items-center justify-center rounded-md bg-oai-gray-900 px-4 text-xs font-medium text-white transition-colors hover:bg-oai-gray-800 dark:bg-white dark:text-oai-gray-900 dark:hover:bg-oai-gray-100",children:s("settings.account.signIn")})]})})}function bt({name:e,github:t}){return n.jsxs(n.Fragment,{children:[n.jsx(ht,{name:e}),n.jsx(pt,{github:t})]})}function ft(){const e=ct();return e.enabled?e.signedIn?n.jsxs(j,{title:s("settings.section.account"),subtitle:e.email||e.name.customDisplayName||e.name.displayName,action:n.jsx(yt,{onSignOut:e.signOut}),children:[n.jsx(xt,{userId:e.userId}),n.jsx(vt,{settings:e}),n.jsx(jt,{checked:e.publicProfileOn,disabled:e.profileLoading||e.profileSaving,onChange:e.handlePublicProfileToggle}),n.jsx(kt,{visible:e.publicProfileOn,name:e.name,github:e.github})]}):n.jsx(mt,{}):null}function xt({userId:e}){const[t,a]=re.useState(!1);if(!e)return null;const i=async()=>{try{if(typeof navigator>"u"||!navigator.clipboard?.writeText)return;await navigator.clipboard.writeText(e),a(!0),globalThis.setTimeout(()=>a(!1),1200)}catch{a(!1)}};return n.jsxs("div",{className:"flex items-center justify-between gap-4 py-3",children:[n.jsxs("div",{className:"min-w-0 flex-1",children:[n.jsx("div",{className:"text-sm text-oai-gray-900 dark:text-oai-gray-200",children:s("settings.account.userId")}),n.jsx("div",{className:"mt-0.5 truncate font-mono text-xs text-oai-gray-500 dark:text-oai-gray-400",children:e})]}),n.jsxs("button",{type:"button",onClick:i,className:"inline-flex h-8 shrink-0 items-center gap-1.5 rounded-md border border-oai-gray-200 px-3 text-xs font-medium text-oai-gray-700 transition-colors hover:bg-oai-gray-100 dark:border-oai-gray-800 dark:text-oai-gray-300 dark:hover:bg-oai-gray-800","aria-label":s("settings.account.copyUserId"),children:[t?n.jsx(Ce,{className:"h-3.5 w-3.5","aria-hidden":!0}):n.jsx(_e,{className:"h-3.5 w-3.5","aria-hidden":!0}),t?s("settings.account.copied"):s("settings.account.copy")]})]})}function yt({onSignOut:e}){return n.jsxs("button",{type:"button",onClick:()=>e(),className:"inline-flex h-7 items-center gap-1.5 text-xs font-medium text-oai-gray-500 transition-colors hover:text-oai-gray-700 dark:hover:text-oai-gray-300",children:[n.jsx(Re,{className:"h-3.5 w-3.5","aria-hidden":!0}),s("settings.account.signOut")]})}function vt({settings:e}){return e.showLocalCloudSync?n.jsx(b,{label:s("settings.account.cloudSync"),hint:s("settings.account.cloudSyncHint"),control:n.jsx(k,{checked:e.cloudSyncOn,onChange:e.handleCloudSyncToggle,ariaLabel:s("settings.account.cloudSync")})}):null}function jt({checked:e,disabled:t,onChange:a}){return n.jsx(b,{label:s("settings.account.publicProfile"),hint:s("settings.account.publicProfileHint"),control:n.jsx(k,{checked:e,onChange:a,disabled:t,ariaLabel:s("settings.account.publicProfile")})})}function kt({visible:e,name:t,github:a}){return n.jsx(le,{initial:!1,children:e?n.jsx(A.div,{initial:{height:0,opacity:0},animate:{height:"auto",opacity:1},exit:{height:0,opacity:0},transition:{height:{duration:.28,ease:[.22,1,.36,1]},opacity:{duration:.2,ease:[.22,1,.36,1]}},style:{overflow:"hidden"},className:"divide-y divide-oai-gray-200/60 dark:divide-oai-gray-800/60",children:n.jsx(bt,{name:t,github:a})},"public-profile-fields"):null})}function Nt(){return[{value:"light",label:s("settings.appearance.theme.light"),Icon:de},{value:"dark",label:s("settings.appearance.theme.dark"),Icon:ge},{value:"system",label:s("settings.appearance.theme.system"),Icon:he}]}function St(){return[{value:be,label:s("settings.appearance.language.system")},{value:fe,label:s("settings.appearance.language.english")},{value:xe,label:s("settings.appearance.language.chinese")},{value:ye,label:s("settings.appearance.language.traditional_chinese")},{value:ve,label:s("settings.appearance.language.japanese")},{value:je,label:s("settings.appearance.language.korean")}]}function wt(e){if(!e)return null;try{const t=new Date(e);return Number.isNaN(t.getTime())?null:t.toLocaleString()}catch{return null}}function Ct(e,t){const a=s(`settings.appearance.currency.rate_source.${e}`),i=wt(t),o=i?s("settings.appearance.currency.rate_updated",{when:i}):s("settings.appearance.currency.rate_never");return`${a} · ${o}`}function Lt({locale:e,setLocale:t}){const a=St();return n.jsx(D,{value:e,onValueChange:t,options:a,ariaLabel:s("settings.appearance.language.label"),className:"px-2.5 py-1.5 text-xs font-medium",leadingIcon:n.jsx(Me,{className:"h-3.5 w-3.5 text-oai-gray-500 dark:text-oai-gray-400","aria-hidden":!0})})}function Et({currency:e,setCurrency:t}){const a=pe().map(i=>({value:i.code,label:s(i.labelKey)}));return n.jsx(D,{value:e,onValueChange:t,options:a,ariaLabel:s("settings.appearance.currency.label"),className:"px-3 py-1.5 text-xs font-medium"})}function Gt({currency:e,rate:t,rateSource:a,rateFetchedAt:i}){if(e===me)return n.jsx(n.Fragment,{children:s("settings.appearance.currency.hint")});const o=Ct(a,i);return n.jsxs("span",{className:"inline-flex items-center gap-1.5",children:[n.jsx("span",{children:`1 USD = ${t.toFixed(4)} ${e}`}),n.jsx("span",{role:"img","aria-label":o,title:o,className:"inline-flex h-4 w-4 cursor-help items-center justify-center text-oai-gray-400 hover:text-oai-gray-600 dark:text-oai-gray-500 dark:hover:text-oai-gray-300",children:n.jsx(Ee,{className:"h-3.5 w-3.5","aria-hidden":!0})})]})}function It(){const{theme:e,setTheme:t}=ce(),{locale:a,setLocale:i}=ue(),{currency:o,rate:r,rateSource:c,rateFetchedAt:u,setCurrency:g}=Le();return n.jsxs(j,{title:s("settings.section.appearance"),children:[n.jsx(b,{label:s("settings.appearance.theme.label"),hint:s("settings.appearance.theme.hint"),control:n.jsx(_,{options:Nt(),value:e,onChange:t})}),n.jsx(b,{label:s("settings.appearance.language.label"),hint:s("settings.appearance.language.hint"),control:n.jsx(Lt,{locale:a,setLocale:i})}),n.jsx(b,{label:s("settings.appearance.currency.label"),hint:n.jsx(Gt,{currency:o,rate:r,rateSource:c,rateFetchedAt:u}),control:n.jsx(Et,{currency:o,setCurrency:g})})]})}function At(){const{available:e,settings:t,setSetting:a,runAction:i}=P();if(!e)return null;const o=!!t?.launchAtLogin,r=t?.launchAtLoginSupported!==!1,c=t?.updateStatus||null,u=!!t?.updateBusy,g=!!t?.isSyncing;return n.jsxs(j,{title:s("settings.section.menubar"),children:[r?n.jsx(b,{label:s("settings.menubar.launchAtLogin"),hint:s("settings.menubar.launchAtLoginHint"),control:n.jsx(k,{checked:o,onChange:()=>a("launchAtLogin",!o),ariaLabel:s("settings.menubar.launchAtLogin")})}):null,n.jsx(b,{label:s("settings.menubar.syncNow"),hint:s("settings.menubar.syncNowHint"),control:n.jsxs("button",{type:"button",onClick:()=>i("syncNow"),disabled:g,className:"inline-flex h-8 items-center gap-1.5 rounded-md border border-oai-gray-200 px-3 text-xs font-medium text-oai-gray-700 transition-colors hover:bg-oai-gray-100 disabled:cursor-not-allowed disabled:opacity-50 dark:border-oai-gray-800 dark:text-oai-gray-300 dark:hover:bg-oai-gray-800",children:[n.jsx(ke,{className:v("h-3.5 w-3.5",g&&"animate-spin"),"aria-hidden":!0}),g?s("settings.menubar.syncing"):s("settings.menubar.syncNow")]})}),n.jsx(b,{label:s("settings.menubar.updates"),hint:c||void 0,control:n.jsxs("button",{type:"button",onClick:()=>i("checkForUpdates"),disabled:u,className:"inline-flex h-8 items-center gap-1.5 rounded-md border border-oai-gray-200 px-3 text-xs font-medium text-oai-gray-700 transition-colors hover:bg-oai-gray-100 disabled:cursor-not-allowed disabled:opacity-50 dark:border-oai-gray-800 dark:text-oai-gray-300 dark:hover:bg-oai-gray-800",children:[n.jsx(Ge,{className:"h-3.5 w-3.5","aria-hidden":!0}),s("settings.menubar.checkUpdates")]})})]})}function Ot(){const{available:e,settings:t,runAction:a}=P(),i=e&&t?.version;return n.jsxs("div",{className:"mt-6 flex flex-wrap items-center justify-center gap-2 text-xs text-oai-gray-500 dark:text-oai-gray-500",children:[i?n.jsxs(n.Fragment,{children:[n.jsxs("span",{children:["TokenTrackerBar v",t.version]}),n.jsx("span",{"aria-hidden":!0,children:"·"}),n.jsx("button",{type:"button",onClick:()=>a("openAbout"),className:"underline-offset-2 transition-colors hover:text-oai-gray-700 hover:underline dark:hover:text-oai-gray-300",children:"GitHub"}),n.jsx("span",{"aria-hidden":!0,children:"·"})]}):null,n.jsxs("a",{href:Ne,target:"_blank",rel:"noopener noreferrer",className:"inline-flex items-center gap-1.5 underline-offset-2 transition-colors hover:text-oai-gray-700 hover:underline dark:hover:text-oai-gray-300",children:[n.jsx(Ae,{className:"h-3.5 w-3.5","aria-hidden":!0}),s("settings.footer.statusPage")]})]})}function _t({prefs:e}){return n.jsx(_,{options:[{value:G.USED,label:s("limits.settings.display_mode_used")},{value:G.REMAINING,label:s("limits.settings.display_mode_remaining")}],value:e.displayMode,onChange:e.setDisplayMode})}function zt(){const e=we();return n.jsx("div",{className:"flex flex-1 flex-col font-oai text-oai-black antialiased dark:text-oai-white",children:n.jsx("main",{className:"flex-1 pb-12 pt-8 sm:pb-16 sm:pt-10",children:n.jsxs("div",{className:"mx-auto max-w-3xl px-4 sm:px-6",children:[n.jsxs("div",{className:"mb-8",children:[n.jsx("h1",{className:"text-3xl font-semibold tracking-tight text-oai-black dark:text-white sm:text-4xl",children:s("settings.page.title")}),n.jsx("p",{className:"mt-2 text-sm text-oai-gray-500 dark:text-oai-gray-400",children:s("settings.page.subtitle")})]}),n.jsxs("div",{className:"space-y-4",children:[n.jsx(It,{}),n.jsx(At,{}),n.jsx(ft,{}),n.jsx(j,{title:s("settings.section.limits"),action:n.jsx(_t,{prefs:e}),children:n.jsx(Je,{prefs:e})})]}),n.jsx(Ot,{})]})})})}export{zt as SettingsPage};