tokentracker-cli 0.24.0 → 0.24.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 (37) hide show
  1. package/dashboard/dist/assets/{Card-C22jvaH-.js → Card-B3zit51o.js} +1 -1
  2. package/dashboard/dist/assets/{DashboardPage-Dv_4x35m.js → DashboardPage-p0PukR6H.js} +1 -1
  3. package/dashboard/dist/assets/{DevicePage-BjhiTjFW.js → DevicePage-cYRFC4jD.js} +1 -1
  4. package/dashboard/dist/assets/{FadeIn-CHxDANbJ.js → FadeIn-BeLgcj1F.js} +1 -1
  5. package/dashboard/dist/assets/{HeaderGithubStar-CIfUeDxZ.js → HeaderGithubStar-DJJ-z5Wo.js} +1 -1
  6. package/dashboard/dist/assets/{IpCheckPage-DIa0AzUn.js → IpCheckPage-CxswyJC6.js} +1 -1
  7. package/dashboard/dist/assets/{LandingPage-sh7tcPKd.js → LandingPage-Bc1ahbkE.js} +1 -1
  8. package/dashboard/dist/assets/{LeaderboardPage-Dg6zcGG1.js → LeaderboardPage-khmZdEvK.js} +1 -1
  9. package/dashboard/dist/assets/{LeaderboardProfilePage-BOJJ-T57.js → LeaderboardProfilePage-NdMct8UA.js} +1 -1
  10. package/dashboard/dist/assets/{LimitsPage-CdMhF5lF.js → LimitsPage-Dc-Rgfn2.js} +1 -1
  11. package/dashboard/dist/assets/{LoginPage-BbJO2VUw.js → LoginPage-nhgDDL4s.js} +1 -1
  12. package/dashboard/dist/assets/{PopoverPopup-Csxg6Urf.js → PopoverPopup-D7c8Tufb.js} +1 -1
  13. package/dashboard/dist/assets/{ProviderIcon-BdfV-wMB.js → ProviderIcon-B79ytQj1.js} +1 -1
  14. package/dashboard/dist/assets/{SettingsPage-B0UsE-Cz.js → SettingsPage-Dv5A3ADR.js} +1 -1
  15. package/dashboard/dist/assets/{SkillsPage-CpV5GRRc.js → SkillsPage-CJdMytgb.js} +1 -1
  16. package/dashboard/dist/assets/{WidgetsPage-DdQEZR9N.js → WidgetsPage-PteVAvZa.js} +1 -1
  17. package/dashboard/dist/assets/{WrappedPage-DKYCqqJa.js → WrappedPage-r7rchUJS.js} +1 -1
  18. package/dashboard/dist/assets/check-CQ9GtDMA.js +1 -0
  19. package/dashboard/dist/assets/{chevron-down-Dh0EAuAs.js → chevron-down-CNvz7vRS.js} +1 -1
  20. package/dashboard/dist/assets/{download-B-u2224w.js → download-HiydOOCL.js} +1 -1
  21. package/dashboard/dist/assets/{info-Bax52N3e.js → info-CWqFjI4Z.js} +1 -1
  22. package/dashboard/dist/assets/leaderboard-columns-BWyNquUf.js +1 -0
  23. package/dashboard/dist/assets/{main-uaLO1Ae7.js → main-C1bPtjN7.js} +15 -15
  24. package/dashboard/dist/assets/{use-limits-display-prefs-BVawA_Rp.js → use-limits-display-prefs-CTnU4ZMo.js} +1 -1
  25. package/dashboard/dist/assets/{use-native-settings-DHtj5DnD.js → use-native-settings-DkTJDNZG.js} +1 -1
  26. package/dashboard/dist/assets/{use-reduced-motion-8tbVQBYw.js → use-reduced-motion-DJE4Frme.js} +1 -1
  27. package/dashboard/dist/assets/{use-usage-limits-SwQjCSa8.js → use-usage-limits-OjbraegI.js} +1 -1
  28. package/dashboard/dist/assets/{useCurrency-Bc8I7sE1.js → useCurrency-DJA7tRVi.js} +1 -1
  29. package/dashboard/dist/index.html +1 -1
  30. package/dashboard/dist/share.html +1 -1
  31. package/package.json +1 -1
  32. package/src/cli.js +1 -2
  33. package/src/commands/serve.js +2 -57
  34. package/src/lib/local-api.js +4 -37
  35. package/src/lib/pricing/seed-snapshot.json +1 -1
  36. package/dashboard/dist/assets/check-CO0YnJo0.js +0 -1
  37. package/dashboard/dist/assets/leaderboard-columns-CmMWLqut.js +0 -1
@@ -1 +1 @@
1
- import{r as a}from"./main-uaLO1Ae7.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-C1bPtjN7.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{C as a,a7 as x,r as n,aH as g,aI as m,aJ as b,aK as u,aL as f,aF as h}from"./main-uaLO1Ae7.js";import{C as y}from"./Card-C22jvaH-.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{C as a,a7 as x,r as n,aH as g,aI as m,aJ as b,aK as u,aL as f,aF as h}from"./main-C1bPtjN7.js";import{C as y}from"./Card-B3zit51o.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{aM as t,aN as o,r,aO as s}from"./main-uaLO1Ae7.js";function u(){!t.current&&o();const[e]=r.useState(s.current);return e}export{u};
1
+ import{aM as t,aN as o,r,aO as s}from"./main-C1bPtjN7.js";function u(){!t.current&&o();const[e]=r.useState(s.current);return e}export{u};
@@ -1 +1 @@
1
- import{r,al as l}from"./main-uaLO1Ae7.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,al as l}from"./main-C1bPtjN7.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 +1 @@
1
- import{r as e,aA as t,aB as r,I as c}from"./main-uaLO1Ae7.js";const a=Object.freeze({currency:c,rate:1,symbol:"$",rates:{...r},rateSource:"default",rateFetchedAt:null,setCurrency:()=>{}});function u(){return e.useContext(t)??a}export{u};
1
+ import{r as e,aA as t,aB as r,I as c}from"./main-C1bPtjN7.js";const a=Object.freeze({currency:c,rate:1,symbol:"$",rates:{...r},rateSource:"default",rateFetchedAt:null,setCurrency:()=>{}});function u(){return e.useContext(t)??a}export{u};
@@ -210,7 +210,7 @@
210
210
  ]
211
211
  }
212
212
  </script>
213
- <script type="module" crossorigin src="/assets/main-uaLO1Ae7.js"></script>
213
+ <script type="module" crossorigin src="/assets/main-C1bPtjN7.js"></script>
214
214
  <link rel="stylesheet" crossorigin href="/assets/main-JP_EYeq-.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-uaLO1Ae7.js"></script>
54
+ <script type="module" crossorigin src="/assets/main-C1bPtjN7.js"></script>
55
55
  <link rel="stylesheet" crossorigin href="/assets/main-JP_EYeq-.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.24.0",
3
+ "version": "0.24.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, Roo Code, Zed Agent, Goose)",
5
5
  "main": "src/cli.js",
6
6
  "bin": {
package/src/cli.js CHANGED
@@ -63,7 +63,7 @@ function printHelp() {
63
63
  "",
64
64
  "Usage:",
65
65
  " npx tokentracker Open local dashboard",
66
- " npx tokentracker [--debug] serve [--port 7680] [--allowed-hosts <host[,host...]>] [--no-open] [--no-sync]",
66
+ " npx tokentracker [--debug] serve [--port 7680] [--no-open] [--no-sync]",
67
67
  " npx tokentracker [--debug] init [--yes] [--dry-run] [--no-open] [--link-code <code>]",
68
68
  " npx tokentracker [--debug] sync [--auto] [--drain] [--from-openclaw]",
69
69
  " npx tokentracker [--debug] status [--probe-keychain] [--probe-keychain-details]",
@@ -82,7 +82,6 @@ function printHelp() {
82
82
  " - OpenClaw hook auto-links when OpenClaw is installed (requires gateway restart).",
83
83
  " - auto sync waits for a device token.",
84
84
  " - optional: --dashboard-url for hosted landing.",
85
- " - serve: --allowed-hosts marks extra hostnames as local-dashboard auth proxy origins (for tunnels/previews).",
86
85
  " - sync parses ~/.codex/sessions/**/rollout-*.jsonl and ~/.code/sessions/**/rollout-*.jsonl, then uploads token deltas.",
87
86
  " - --from-openclaw marks sync runs triggered by OpenClaw hooks.",
88
87
  " - --debug shows original backend errors.",
@@ -87,7 +87,7 @@ async function cmdServe(argv) {
87
87
  }
88
88
 
89
89
  // 3. Create handler
90
- const handleApi = createLocalApiHandler({ queuePath, allowedHosts: opts.allowedHosts });
90
+ const handleApi = createLocalApiHandler({ queuePath });
91
91
 
92
92
  const server = http.createServer(async (req, res) => {
93
93
  try {
@@ -104,11 +104,6 @@ async function cmdServe(argv) {
104
104
  }
105
105
 
106
106
  // API routes
107
- if (url.pathname === "/api/dashboard-config") {
108
- serveDashboardConfig(res, { allowedHosts: opts.allowedHosts });
109
- return;
110
- }
111
-
112
107
  if (
113
108
  url.pathname.startsWith("/functions/")
114
109
  || url.pathname.startsWith("/api/")
@@ -229,66 +224,19 @@ function resolveDashboardDir() {
229
224
  return null;
230
225
  }
231
226
 
232
- function splitHostList(value) {
233
- if (Array.isArray(value)) return value.flatMap(splitHostList);
234
- if (typeof value !== "string") return [];
235
- return value.split(",").map((entry) => entry.trim()).filter(Boolean);
236
- }
237
-
238
- function normalizeAllowedHost(value) {
239
- if (typeof value !== "string") return null;
240
- const raw = value.trim();
241
- if (!raw || raw.includes("*") || /\s/.test(raw)) return null;
242
- try {
243
- const withScheme = /^[a-z][a-z0-9+.-]*:\/\//i.test(raw) ? raw : `http://${raw}`;
244
- const url = new URL(withScheme);
245
- if (!url.hostname || url.username || url.password) return null;
246
- return url.hostname.toLowerCase();
247
- } catch (_e) {
248
- return null;
249
- }
250
- }
251
-
252
- function normalizeAllowedHosts(values) {
253
- const out = [];
254
- const seen = new Set();
255
- for (const item of splitHostList(values)) {
256
- const host = normalizeAllowedHost(item);
257
- if (!host || seen.has(host)) continue;
258
- seen.add(host);
259
- out.push(host);
260
- }
261
- return out;
262
- }
263
-
264
- function serveDashboardConfig(res, { allowedHosts } = {}) {
265
- const body = Buffer.from(JSON.stringify({ allowedHosts: normalizeAllowedHosts(allowedHosts) }), "utf8");
266
- res.writeHead(200, {
267
- "Content-Type": "application/json; charset=utf-8",
268
- "Content-Length": body.length,
269
- "Cache-Control": "no-store",
270
- });
271
- res.end(body);
272
- }
273
-
274
227
  function parseArgs(argv) {
275
- const opts = { port: DEFAULT_PORT, open: true, sync: true, allowedHosts: [] };
228
+ const opts = { port: DEFAULT_PORT, open: true, sync: true };
276
229
  for (let i = 0; i < argv.length; i++) {
277
230
  const arg = argv[i];
278
231
  if (arg === "--port" && i + 1 < argv.length) {
279
232
  const n = parseInt(argv[++i], 10);
280
233
  if (Number.isFinite(n) && n > 0 && n < 65536) opts.port = n;
281
- } else if (arg === "--allowed-hosts" && i + 1 < argv.length && !argv[i + 1].startsWith("-")) {
282
- opts.allowedHosts.push(...normalizeAllowedHosts(argv[++i]));
283
- } else if (arg.startsWith("--allowed-hosts=")) {
284
- opts.allowedHosts.push(...normalizeAllowedHosts(arg.slice("--allowed-hosts=".length)));
285
234
  } else if (arg === "--no-open") {
286
235
  opts.open = false;
287
236
  } else if (arg === "--no-sync") {
288
237
  opts.sync = false;
289
238
  }
290
239
  }
291
- opts.allowedHosts = normalizeAllowedHosts(opts.allowedHosts);
292
240
  return opts;
293
241
  }
294
242
 
@@ -298,7 +246,4 @@ module.exports = {
298
246
  NPM_PACKAGE_NAME,
299
247
  LOCAL_BIND_HOST,
300
248
  getLocalServerUrl,
301
- parseArgs,
302
- normalizeAllowedHosts,
303
- serveDashboardConfig,
304
249
  };
@@ -457,45 +457,13 @@ function isLoopbackHostname(hostname) {
457
457
  return hostname === "127.0.0.1" || hostname === "localhost" || hostname === "::1" || hostname === "[::1]";
458
458
  }
459
459
 
460
- function normalizeAllowedHost(value) {
461
- if (typeof value !== "string") return null;
462
- const raw = value.trim();
463
- if (!raw || raw.includes("*") || /\s/.test(raw)) return null;
464
- try {
465
- const withScheme = /^[a-z][a-z0-9+.-]*:\/\//i.test(raw) ? raw : `http://${raw}`;
466
- const url = new URL(withScheme);
467
- if (!url.hostname || url.username || url.password) return null;
468
- return url.hostname.toLowerCase();
469
- } catch (_e) {
470
- return null;
471
- }
472
- }
473
-
474
- function normalizeAllowedHosts(values) {
475
- const raw = Array.isArray(values) ? values : [values];
476
- const out = [];
477
- const seen = new Set();
478
- for (const item of raw) {
479
- const host = normalizeAllowedHost(item);
480
- if (!host || seen.has(host)) continue;
481
- seen.add(host);
482
- out.push(host);
483
- }
484
- return out;
485
- }
486
-
487
- function hasAllowedLoopbackOrigin(headers = {}, allowedHosts = []) {
488
- const allowed = new Set(normalizeAllowedHosts(allowedHosts));
460
+ function hasAllowedLoopbackOrigin(headers = {}) {
489
461
  const candidates = [headers.origin, headers.referer];
490
462
  for (const raw of candidates) {
491
463
  if (raw == null || raw === "") continue;
492
464
  try {
493
465
  const url = new URL(String(raw));
494
- if (!["http:", "https:"].includes(url.protocol)) return false;
495
- const host = url.hostname.toLowerCase();
496
- if (url.protocol === "http:" && isLoopbackHostname(host)) continue;
497
- if (allowed.has(host)) continue;
498
- return false;
466
+ if (url.protocol !== "http:" || !isLoopbackHostname(url.hostname)) return false;
499
467
  } catch (_e) {
500
468
  return false;
501
469
  }
@@ -689,9 +657,8 @@ const IP_CHECK_TARGET = "https://ip.net.coffee";
689
657
  // Main handler factory
690
658
  // ---------------------------------------------------------------------------
691
659
 
692
- function createLocalApiHandler({ queuePath, allowedHosts = [] } = {}) {
660
+ function createLocalApiHandler({ queuePath }) {
693
661
  const qp = queuePath || resolveQueuePath();
694
- const allowedLocalOriginHosts = normalizeAllowedHosts(allowedHosts);
695
662
 
696
663
  // Server-side cookie relay: captures auth cookies from InsForge cloud responses
697
664
  // so that both browser and WKWebView share the same login session via the proxy.
@@ -863,7 +830,7 @@ function createLocalApiHandler({ queuePath, allowedHosts = [] } = {}) {
863
830
  ? headerToken.trim()
864
831
  : cookieToken || "";
865
832
  if (!token || token !== localAuthToken) return false;
866
- return hasAllowedLoopbackOrigin(req?.headers || {}, allowedLocalOriginHosts);
833
+ return hasAllowedLoopbackOrigin(req?.headers || {});
867
834
  }
868
835
 
869
836
  return async function handleLocalApi(req, res, url) {