tokentracker-cli 0.18.0 → 0.18.1

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 (29) hide show
  1. package/dashboard/dist/assets/{Card-DaQruAEZ.js → Card-8ZPdKuRR.js} +1 -1
  2. package/dashboard/dist/assets/{DashboardPage-B1ZCjfgB.js → DashboardPage-OVP6u_7i.js} +1 -1
  3. package/dashboard/dist/assets/{FadeIn-BYn5mp_C.js → FadeIn-BxnaPv7O.js} +1 -1
  4. package/dashboard/dist/assets/{HeaderGithubStar-DnKHfm5F.js → HeaderGithubStar-8z6DrTLD.js} +1 -1
  5. package/dashboard/dist/assets/{IpCheckPage-BtYkItYr.js → IpCheckPage-yagKgpi7.js} +1 -1
  6. package/dashboard/dist/assets/{LandingPage-C4Ukq_ho.js → LandingPage-Ca72J5F0.js} +1 -1
  7. package/dashboard/dist/assets/{LeaderboardPage-yWE-j66g.js → LeaderboardPage-CSmW4lBz.js} +1 -1
  8. package/dashboard/dist/assets/{LeaderboardProfilePage-C3UVE-YJ.js → LeaderboardProfilePage-BOihURRE.js} +1 -1
  9. package/dashboard/dist/assets/{LimitsPage-DH2yQZwk.js → LimitsPage-Bq4zB2w9.js} +1 -1
  10. package/dashboard/dist/assets/{LoginPage-BbEBnz58.js → LoginPage-CoB1ZkE6.js} +1 -1
  11. package/dashboard/dist/assets/{PopoverPopup-B6sNFXGZ.js → PopoverPopup-D7d5-v70.js} +1 -1
  12. package/dashboard/dist/assets/{ProviderIcon-CDVWc_TN.js → ProviderIcon-DzvUcjPu.js} +1 -1
  13. package/dashboard/dist/assets/{SettingsPage-CJ2KJuU5.js → SettingsPage-BeyW1iTj.js} +1 -1
  14. package/dashboard/dist/assets/{SkillsPage-BQHojjxy.js → SkillsPage-B6auz1NO.js} +1 -1
  15. package/dashboard/dist/assets/{WidgetsPage-DuUOC5LD.js → WidgetsPage-C9t8qw0F.js} +1 -1
  16. package/dashboard/dist/assets/{chevron-down-CkMLZDuK.js → chevron-down-C8RgL-uJ.js} +1 -1
  17. package/dashboard/dist/assets/{download-BjbAqWCN.js → download-C90EEqc8.js} +1 -1
  18. package/dashboard/dist/assets/{leaderboard-columns-m4UzCZhg.js → leaderboard-columns-BgqTAms5.js} +1 -1
  19. package/dashboard/dist/assets/{main-Dgiw16jZ.js → main-DJcfmlDf.js} +2 -2
  20. package/dashboard/dist/assets/{use-limits-display-prefs-DvnaGeUj.js → use-limits-display-prefs-BUBBOUIF.js} +1 -1
  21. package/dashboard/dist/assets/{use-native-settings-BPjPcvON.js → use-native-settings-CFUEzyoi.js} +1 -1
  22. package/dashboard/dist/assets/{use-reduced-motion-D1akEyuH.js → use-reduced-motion-NZDZrVKK.js} +1 -1
  23. package/dashboard/dist/assets/{use-usage-limits-BmK4zEAz.js → use-usage-limits-CoOOhZrW.js} +1 -1
  24. package/dashboard/dist/index.html +1 -1
  25. package/dashboard/dist/share.html +1 -1
  26. package/package.json +1 -1
  27. package/src/commands/serve.js +5 -1
  28. package/src/lib/local-api.js +84 -0
  29. package/src/lib/pricing/seed-snapshot.json +1 -1
@@ -1 +1 @@
1
- import{r as a}from"./main-Dgiw16jZ.js";const d=["claude","codex","cursor","gemini","kimi","kiro","copilot","antigravity"],S={claude:"Claude",codex:"Codex",cursor:"Cursor",gemini:"Gemini",kimi:"Kimi",kiro:"Kiro",copilot:"GitHub Copilot",antigravity:"Antigravity"},v={claude:"/brand-logos/claude-code.svg",codex:"/brand-logos/codex.svg",cursor:"/brand-logos/cursor.svg",gemini:"/brand-logos/gemini.svg",kimi:"/brand-logos/kimi.svg",kiro:"/brand-logos/kiro.svg",copilot:"/brand-logos/copilot.svg",antigravity:"/brand-logos/antigravity.svg"},l="tt.limits.providerOrder",g="tt.limits.providerVisibility";function w(){if(typeof window>"u")return[...d];try{const i=window.localStorage.getItem(l);if(!i)return[...d];const s=JSON.parse(i);if(!Array.isArray(s))return[...d];const r=s.filter(c=>d.includes(c));for(const c of d)r.includes(c)||r.push(c);return r}catch{return[...d]}}function y(){const i=Object.fromEntries(d.map(s=>[s,!0]));if(typeof window>"u")return i;try{const s=window.localStorage.getItem(g);if(!s)return i;const r=JSON.parse(s);if(!r||typeof r!="object")return i;const c={...i};for(const u of d)typeof r[u]=="boolean"&&(c[u]=r[u]);return c}catch{return i}}function C(){const[i,s]=a.useState(w),[r,c]=a.useState(y);a.useEffect(()=>{if(!(typeof window>"u"))try{window.localStorage.setItem(l,JSON.stringify(i))}catch{}},[i]),a.useEffect(()=>{if(!(typeof window>"u"))try{window.localStorage.setItem(g,JSON.stringify(r))}catch{}},[r]),a.useEffect(()=>{if(typeof window>"u")return;const o=t=>{t.key===l&&s(w()),t.key===g&&c(y())};return window.addEventListener("storage",o),()=>window.removeEventListener("storage",o)},[]);const u=a.useCallback(o=>{c(t=>({...t,[o]:!t[o]}))},[]),b=a.useCallback(o=>{s(t=>{const e=t.indexOf(o);if(e<=0)return t;const n=[...t];return[n[e-1],n[e]]=[n[e],n[e-1]],n})},[]),p=a.useCallback(o=>{s(t=>{const e=t.indexOf(o);if(e<0||e>=t.length-1)return t;const n=[...t];return[n[e],n[e+1]]=[n[e+1],n[e]],n})},[]),O=a.useCallback((o,t)=>{o!==t&&s(e=>{const n=e.indexOf(o),m=e.indexOf(t);if(n<0||m<0)return e;const f=[...e],[I]=f.splice(n,1);return f.splice(m,0,I),f})},[]),k=a.useCallback(()=>{s([...d]),c(Object.fromEntries(d.map(o=>[o,!0])))},[]),x=a.useMemo(()=>i.filter(o=>r[o]!==!1),[i,r]);return{order:i,visibility:r,visibleOrdered:x,toggle:u,moveUp:b,moveDown:p,moveToward:O,reset:k}}export{v as L,S as a,C as u};
1
+ import{r as a}from"./main-DJcfmlDf.js";const d=["claude","codex","cursor","gemini","kimi","kiro","copilot","antigravity"],S={claude:"Claude",codex:"Codex",cursor:"Cursor",gemini:"Gemini",kimi:"Kimi",kiro:"Kiro",copilot:"GitHub Copilot",antigravity:"Antigravity"},v={claude:"/brand-logos/claude-code.svg",codex:"/brand-logos/codex.svg",cursor:"/brand-logos/cursor.svg",gemini:"/brand-logos/gemini.svg",kimi:"/brand-logos/kimi.svg",kiro:"/brand-logos/kiro.svg",copilot:"/brand-logos/copilot.svg",antigravity:"/brand-logos/antigravity.svg"},l="tt.limits.providerOrder",g="tt.limits.providerVisibility";function w(){if(typeof window>"u")return[...d];try{const i=window.localStorage.getItem(l);if(!i)return[...d];const s=JSON.parse(i);if(!Array.isArray(s))return[...d];const r=s.filter(c=>d.includes(c));for(const c of d)r.includes(c)||r.push(c);return r}catch{return[...d]}}function y(){const i=Object.fromEntries(d.map(s=>[s,!0]));if(typeof window>"u")return i;try{const s=window.localStorage.getItem(g);if(!s)return i;const r=JSON.parse(s);if(!r||typeof r!="object")return i;const c={...i};for(const u of d)typeof r[u]=="boolean"&&(c[u]=r[u]);return c}catch{return i}}function C(){const[i,s]=a.useState(w),[r,c]=a.useState(y);a.useEffect(()=>{if(!(typeof window>"u"))try{window.localStorage.setItem(l,JSON.stringify(i))}catch{}},[i]),a.useEffect(()=>{if(!(typeof window>"u"))try{window.localStorage.setItem(g,JSON.stringify(r))}catch{}},[r]),a.useEffect(()=>{if(typeof window>"u")return;const o=t=>{t.key===l&&s(w()),t.key===g&&c(y())};return window.addEventListener("storage",o),()=>window.removeEventListener("storage",o)},[]);const u=a.useCallback(o=>{c(t=>({...t,[o]:!t[o]}))},[]),b=a.useCallback(o=>{s(t=>{const e=t.indexOf(o);if(e<=0)return t;const n=[...t];return[n[e-1],n[e]]=[n[e],n[e-1]],n})},[]),p=a.useCallback(o=>{s(t=>{const e=t.indexOf(o);if(e<0||e>=t.length-1)return t;const n=[...t];return[n[e],n[e+1]]=[n[e+1],n[e]],n})},[]),O=a.useCallback((o,t)=>{o!==t&&s(e=>{const n=e.indexOf(o),m=e.indexOf(t);if(n<0||m<0)return e;const f=[...e],[I]=f.splice(n,1);return f.splice(m,0,I),f})},[]),k=a.useCallback(()=>{s([...d]),c(Object.fromEntries(d.map(o=>[o,!0])))},[]),x=a.useMemo(()=>i.filter(o=>r[o]!==!1),[i,r]);return{order:i,visibility:r,visibleOrdered:x,toggle:u,moveUp:b,moveDown:p,moveToward:O,reset:k}}export{v as L,S as a,C as u};
@@ -1 +1 @@
1
- import{D as a,a5 as x,r as n,aB as g,aC as m,aD as b,aE as u,aF as f,az as h}from"./main-Dgiw16jZ.js";import{C as y}from"./Card-DaQruAEZ.js";function p({checked:s,onChange:t,disabled:e,ariaLabel:i}){return a.jsx("button",{type:"button",role:"switch","aria-checked":s,"aria-label":i,onClick:t,disabled:e,className:x("relative inline-flex h-5 w-9 shrink-0 items-center rounded-full transition-colors focus:outline-none focus-visible:ring-2 focus-visible:ring-oai-brand-500 disabled:opacity-50 disabled:cursor-not-allowed",s?"bg-oai-brand-500":"bg-oai-gray-300 dark:bg-oai-gray-700"),children:a.jsx("span",{className:x("inline-block h-3.5 w-3.5 rounded-full bg-white transition-transform",s?"translate-x-[18px]":"translate-x-[3px]")})})}function j({label:s,hint:t,control:e}){return a.jsxs("div",{className:"flex items-center justify-between gap-4 py-3",children:[a.jsxs("div",{className:"min-w-0 flex-1",children:[a.jsx("div",{className:"text-sm text-oai-gray-900 dark:text-oai-gray-200",children:s}),t?a.jsx("div",{className:"mt-0.5 text-xs text-oai-gray-500 dark:text-oai-gray-400",children:t}):null]}),a.jsx("div",{className:"shrink-0",children:e})]})}function N({title:s,subtitle:t,action:e,children:i}){return a.jsxs(y,{children:[a.jsxs("div",{className:"mb-3 flex items-start justify-between gap-4",children:[a.jsxs("div",{className:"min-w-0 flex-1",children:[a.jsx("h2",{className:"text-sm font-medium text-oai-gray-500 dark:text-oai-gray-300 uppercase tracking-wide",children:s}),t?a.jsx("p",{className:"mt-1 truncate text-xs text-oai-gray-500 dark:text-oai-gray-400",children:t}):null]}),e?a.jsx("div",{className:"shrink-0",children:e}):null]}),a.jsx("div",{className:"-mb-3 divide-y divide-oai-gray-200/60 dark:divide-oai-gray-800/60",children:i})]})}function w({options:s,value:t,onChange:e}){return a.jsx("div",{className:"inline-flex items-center rounded-lg border border-oai-gray-200 bg-oai-gray-50 p-0.5 dark:border-oai-gray-800 dark:bg-oai-gray-900",children:s.map(({value:i,label:d,Icon:l})=>{const r=t===i;return a.jsxs("button",{type:"button",onClick:()=>e(i),"aria-pressed":r,className:x("inline-flex items-center gap-1.5 rounded-md px-3 py-1.5 text-xs font-medium transition-colors",r?"bg-white text-oai-black shadow-sm dark:bg-oai-gray-800 dark:text-white":"text-oai-gray-500 hover:text-oai-black dark:text-oai-gray-400 dark:hover:text-white"),children:[l?a.jsx(l,{className:"h-3.5 w-3.5","aria-hidden":!0}):null,a.jsx("span",{children:d})]},i)})})}function S(){const[s,t]=n.useState(null),e=g()&&m();n.useEffect(()=>{if(!e)return;const r=b(o=>t(o));return u(),r},[e]);const i=n.useCallback((r,o)=>{e&&(t(c=>c&&{...c,[r]:o}),f(r,o))},[e]),d=n.useCallback(r=>{e&&h(r)},[e]),l=n.useCallback(()=>{e&&u()},[e]);return{available:e,settings:s,setSetting:i,runAction:d,refresh:l}}export{N as S,p as T,j as a,w as b,S as u};
1
+ import{D as a,a5 as x,r as n,aB as g,aC as m,aD as b,aE as u,aF as f,az as h}from"./main-DJcfmlDf.js";import{C as y}from"./Card-8ZPdKuRR.js";function p({checked:s,onChange:t,disabled:e,ariaLabel:i}){return a.jsx("button",{type:"button",role:"switch","aria-checked":s,"aria-label":i,onClick:t,disabled:e,className:x("relative inline-flex h-5 w-9 shrink-0 items-center rounded-full transition-colors focus:outline-none focus-visible:ring-2 focus-visible:ring-oai-brand-500 disabled:opacity-50 disabled:cursor-not-allowed",s?"bg-oai-brand-500":"bg-oai-gray-300 dark:bg-oai-gray-700"),children:a.jsx("span",{className:x("inline-block h-3.5 w-3.5 rounded-full bg-white transition-transform",s?"translate-x-[18px]":"translate-x-[3px]")})})}function j({label:s,hint:t,control:e}){return a.jsxs("div",{className:"flex items-center justify-between gap-4 py-3",children:[a.jsxs("div",{className:"min-w-0 flex-1",children:[a.jsx("div",{className:"text-sm text-oai-gray-900 dark:text-oai-gray-200",children:s}),t?a.jsx("div",{className:"mt-0.5 text-xs text-oai-gray-500 dark:text-oai-gray-400",children:t}):null]}),a.jsx("div",{className:"shrink-0",children:e})]})}function N({title:s,subtitle:t,action:e,children:i}){return a.jsxs(y,{children:[a.jsxs("div",{className:"mb-3 flex items-start justify-between gap-4",children:[a.jsxs("div",{className:"min-w-0 flex-1",children:[a.jsx("h2",{className:"text-sm font-medium text-oai-gray-500 dark:text-oai-gray-300 uppercase tracking-wide",children:s}),t?a.jsx("p",{className:"mt-1 truncate text-xs text-oai-gray-500 dark:text-oai-gray-400",children:t}):null]}),e?a.jsx("div",{className:"shrink-0",children:e}):null]}),a.jsx("div",{className:"-mb-3 divide-y divide-oai-gray-200/60 dark:divide-oai-gray-800/60",children:i})]})}function w({options:s,value:t,onChange:e}){return a.jsx("div",{className:"inline-flex items-center rounded-lg border border-oai-gray-200 bg-oai-gray-50 p-0.5 dark:border-oai-gray-800 dark:bg-oai-gray-900",children:s.map(({value:i,label:d,Icon:l})=>{const r=t===i;return a.jsxs("button",{type:"button",onClick:()=>e(i),"aria-pressed":r,className:x("inline-flex items-center gap-1.5 rounded-md px-3 py-1.5 text-xs font-medium transition-colors",r?"bg-white text-oai-black shadow-sm dark:bg-oai-gray-800 dark:text-white":"text-oai-gray-500 hover:text-oai-black dark:text-oai-gray-400 dark:hover:text-white"),children:[l?a.jsx(l,{className:"h-3.5 w-3.5","aria-hidden":!0}):null,a.jsx("span",{children:d})]},i)})})}function S(){const[s,t]=n.useState(null),e=g()&&m();n.useEffect(()=>{if(!e)return;const r=b(o=>t(o));return u(),r},[e]);const i=n.useCallback((r,o)=>{e&&(t(c=>c&&{...c,[r]:o}),f(r,o))},[e]),d=n.useCallback(r=>{e&&h(r)},[e]),l=n.useCallback(()=>{e&&u()},[e]);return{available:e,settings:s,setSetting:i,runAction:d,refresh:l}}export{N as S,p as T,j as a,w as b,S as u};
@@ -1 +1 @@
1
- import{aG as t,aH as o,r,aI as s}from"./main-Dgiw16jZ.js";function u(){!t.current&&o();const[e]=r.useState(s.current);return e}export{u};
1
+ import{aG as t,aH as o,r,aI as s}from"./main-DJcfmlDf.js";function u(){!t.current&&o();const[e]=r.useState(s.current);return e}export{u};
@@ -1 +1 @@
1
- import{r,aj as l}from"./main-Dgiw16jZ.js";function y(i){const[o,a]=r.useState(null),[u,s]=r.useState(null),[c,f]=r.useState(!0),n=!!i?.initialRefresh,g=r.useCallback(async()=>{try{const e=await l({refresh:!0});a(e&&typeof e=="object"?e:null),s(null)}catch(e){s(e?.message||String(e))}},[]);return r.useEffect(()=>{let e=!1;return(async()=>{try{const t=await l(n?{refresh:!0}:{});if(e)return;a(t&&typeof t=="object"?t:null),s(null)}catch(t){if(e)return;s(t?.message||String(t))}finally{e||f(!1)}})(),()=>{e=!0}},[n]),{data:o,error:u,isLoading:c,refresh:g}}export{y as u};
1
+ import{r,aj as l}from"./main-DJcfmlDf.js";function y(i){const[o,a]=r.useState(null),[u,s]=r.useState(null),[c,f]=r.useState(!0),n=!!i?.initialRefresh,g=r.useCallback(async()=>{try{const e=await l({refresh:!0});a(e&&typeof e=="object"?e:null),s(null)}catch(e){s(e?.message||String(e))}},[]);return r.useEffect(()=>{let e=!1;return(async()=>{try{const t=await l(n?{refresh:!0}:{});if(e)return;a(t&&typeof t=="object"?t:null),s(null)}catch(t){if(e)return;s(t?.message||String(t))}finally{e||f(!1)}})(),()=>{e=!0}},[n]),{data:o,error:u,isLoading:c,refresh:g}}export{y as u};
@@ -210,7 +210,7 @@
210
210
  ]
211
211
  }
212
212
  </script>
213
- <script type="module" crossorigin src="/assets/main-Dgiw16jZ.js"></script>
213
+ <script type="module" crossorigin src="/assets/main-DJcfmlDf.js"></script>
214
214
  <link rel="stylesheet" crossorigin href="/assets/main-CITVpx5B.css">
215
215
  </head>
216
216
  <body>
@@ -51,7 +51,7 @@
51
51
  "description": "Shareable Token Tracker dashboard snapshot."
52
52
  }
53
53
  </script>
54
- <script type="module" crossorigin src="/assets/main-Dgiw16jZ.js"></script>
54
+ <script type="module" crossorigin src="/assets/main-DJcfmlDf.js"></script>
55
55
  <link rel="stylesheet" crossorigin href="/assets/main-CITVpx5B.css">
56
56
  </head>
57
57
  <body>
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "tokentracker-cli",
3
- "version": "0.18.0",
3
+ "version": "0.18.1",
4
4
  "description": "Token usage tracker for AI agent CLIs (Claude Code, Codex, Cursor, Gemini, Kiro, OpenCode, OpenClaw, Every Code, Hermes, GitHub Copilot, Kimi Code, CodeBuddy, Grok Build, oh-my-pi, pi, Craft Agents, Kilo CLI, Kilo Code)",
5
5
  "main": "src/cli.js",
6
6
  "bin": {
@@ -116,7 +116,11 @@ async function cmdServe(argv) {
116
116
  }
117
117
 
118
118
  // API routes
119
- if (url.pathname.startsWith("/functions/") || url.pathname.startsWith("/api/")) {
119
+ if (
120
+ url.pathname.startsWith("/functions/")
121
+ || url.pathname.startsWith("/api/")
122
+ || url.pathname.startsWith("/proxy/")
123
+ ) {
120
124
  const handled = await handleApi(req, res, url);
121
125
  if (handled) return;
122
126
  }
@@ -634,6 +634,30 @@ function json(res, data, status) {
634
634
  res.end(JSON.stringify(data));
635
635
  }
636
636
 
637
+ // ---------------------------------------------------------------------------
638
+ // IP check proxy (issue #81): ip.net.coffee/claude/ sets X-Frame-Options:
639
+ // SAMEORIGIN so the dashboard iframe is blocked. We reverse-proxy through
640
+ // /proxy/ipcheck/* so requests stay same-origin to 127.0.0.1, then strip the
641
+ // embedding-hostile headers and rewrite root-relative URLs in HTML so the
642
+ // page's own /api/* and /claude/* fetches route back through us.
643
+ // ---------------------------------------------------------------------------
644
+
645
+ const IP_CHECK_PROXY_PREFIX = "/proxy/ipcheck";
646
+ const IP_CHECK_TARGET = "https://ip.net.coffee";
647
+
648
+ function rewriteIpCheckHtml(html) {
649
+ const prefix = IP_CHECK_PROXY_PREFIX;
650
+ return html
651
+ .replace(
652
+ /(\s(?:href|src|action)\s*=\s*["'])\/(?!\/|proxy\/ipcheck\/)/g,
653
+ `$1${prefix}/`,
654
+ )
655
+ .replace(
656
+ /(fetch\s*\(\s*["'`])\/(?!\/|proxy\/ipcheck\/)/g,
657
+ `$1${prefix}/`,
658
+ );
659
+ }
660
+
637
661
  // ---------------------------------------------------------------------------
638
662
  // Main handler factory
639
663
  // ---------------------------------------------------------------------------
@@ -872,6 +896,66 @@ function createLocalApiHandler({ queuePath }) {
872
896
  return true;
873
897
  }
874
898
 
899
+ // --- ip-check proxy: reverse-proxy ip.net.coffee/claude/ (issue #81) ---
900
+ if (p.startsWith(`${IP_CHECK_PROXY_PREFIX}/`) || p === IP_CHECK_PROXY_PREFIX) {
901
+ const targetPath = p === IP_CHECK_PROXY_PREFIX
902
+ ? "/"
903
+ : p.slice(IP_CHECK_PROXY_PREFIX.length) || "/";
904
+ const targetUrl = `${IP_CHECK_TARGET}${targetPath}${url.search || ""}`;
905
+ try {
906
+ const proxyHeaders = {};
907
+ for (const [key, value] of Object.entries(req.headers)) {
908
+ const lk = key.toLowerCase();
909
+ if (["host", "connection", "referer", "origin"].includes(lk)) continue;
910
+ proxyHeaders[key] = value;
911
+ }
912
+ proxyHeaders["host"] = "ip.net.coffee";
913
+ proxyHeaders["referer"] = `${IP_CHECK_TARGET}${targetPath}`;
914
+
915
+ const method = String(req.method || "GET").toUpperCase();
916
+ let body;
917
+ if (method !== "GET" && method !== "HEAD") {
918
+ const chunks = [];
919
+ for await (const chunk of req) chunks.push(chunk);
920
+ if (chunks.length > 0) body = Buffer.concat(chunks);
921
+ }
922
+
923
+ const proxyRes = await fetch(targetUrl, {
924
+ method,
925
+ headers: proxyHeaders,
926
+ body,
927
+ redirect: "manual",
928
+ });
929
+
930
+ const stripped = new Set([
931
+ "transfer-encoding",
932
+ "connection",
933
+ "content-length",
934
+ "content-encoding",
935
+ "x-frame-options",
936
+ "content-security-policy",
937
+ "cross-origin-opener-policy",
938
+ "cross-origin-embedder-policy",
939
+ "cross-origin-resource-policy",
940
+ ]);
941
+ const responseHeaders = [...proxyRes.headers.entries()].filter(
942
+ ([k]) => !stripped.has(k.toLowerCase()),
943
+ );
944
+
945
+ const contentType = proxyRes.headers.get("content-type") || "";
946
+ let resBody = Buffer.from(await proxyRes.arrayBuffer());
947
+ if (contentType.toLowerCase().includes("text/html")) {
948
+ resBody = Buffer.from(rewriteIpCheckHtml(resBody.toString("utf8")), "utf8");
949
+ }
950
+
951
+ res.writeHead(proxyRes.status, Object.fromEntries(responseHeaders));
952
+ res.end(resBody);
953
+ } catch (e) {
954
+ json(res, { error: `IP check proxy error: ${e?.message || e}` }, 502);
955
+ }
956
+ return true;
957
+ }
958
+
875
959
  // --- local-sync (POST) ---
876
960
  if (p === "/functions/tokentracker-local-sync") {
877
961
  if (String(req.method || "GET").toUpperCase() !== "POST") {