@cartanova/qgrid-cli 2.10.8 → 2.10.9

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.
@@ -1 +1 @@
1
- import{r as e}from"./rolldown-runtime-Dw2cE7zH.js";import{y as t}from"./vendor-tanstack-DJRQAbrY.js";import{i as n,r}from"./vendor-react-DH4kUfK2.js";import{n as i,o as a}from"./services.generated-BsieU37H.js";import{f as o,o as s}from"./index-DmCLKefs.js";import{t as c}from"./use-update-token-mutation-DAq0F8p-.js";import{n as l,t as u}from"./use-oauth-login-flow-D1jlq9ha.js";import{t as d}from"./plus-B62CuqT8.js";var f=e(n(),1),p=r();function m(){let[e,t]=(0,f.useState)(!1),[n,r]=(0,f.useState)(``),i=u(),a=()=>{t(!1),r(``),i.reset()},c=async e=>{await i.submitCode(e)&&a()};return(0,p.jsxs)(p.Fragment,{children:[(0,p.jsxs)(`button`,{type:`button`,className:`px-3.5 py-1.5 text-[12px] font-medium rounded-lg bg-sienna-500 text-white hover:bg-sienna-600 disabled:opacity-50 transition-all duration-150 active:scale-[0.97] flex items-center gap-1.5 shadow-sm`,onClick:()=>t(!0),children:[(0,p.jsx)(d,{className:`size-3.5`}),`Add Token`]}),e&&(0,p.jsxs)(`div`,{className:`fixed inset-0 z-50 flex items-start justify-center pt-[15vh]`,children:[(0,p.jsx)(`div`,{className:`absolute inset-0 bg-sand-900/8 backdrop-blur-sm`,onClick:a,onKeyDown:()=>{}}),(0,p.jsxs)(`div`,{className:`relative panel shadow-xl w-full max-w-md mx-4`,children:[(0,p.jsx)(`div`,{className:`px-5 py-4 border-b border-sand-100/50`,children:(0,p.jsx)(`h2`,{className:`text-base font-medium text-sand-900`,children:`Add Token`})}),(0,p.jsxs)(`div`,{className:`px-5 py-4 space-y-4`,children:[(0,p.jsxs)(`div`,{children:[(0,p.jsx)(`label`,{htmlFor:`token-name`,className:`text-[10px] uppercase tracking-wider text-sand-500 font-medium`,children:`Name *`}),(0,p.jsx)(s,{value:n,onChange:e=>r(e.target.value),placeholder:`e.g. your-token-name`,className:`mt-1 w-full border border-sand-200 rounded-md px-3 py-2 text-sm text-sand-900 bg-white placeholder:text-sand-300 focus:outline-none focus:border-sienna-300`})]}),i.codeEntryProvider?(0,p.jsx)(l,{provider:i.codeEntryProvider,isPending:i.completeMutation.isPending,isError:i.completeMutation.isError,onSubmit:e=>void c(e),onRestart:i.reset}):(0,p.jsxs)(`div`,{className:`space-y-2`,children:[(0,p.jsx)(`button`,{type:`button`,className:`w-full py-2.5 text-sm font-medium rounded-md bg-sand-900 text-white hover:bg-sand-800 disabled:opacity-50 transition-colors duration-150 flex items-center justify-center gap-2`,disabled:!n.trim()||i.loadingProvider!==null,onClick:()=>void i.start(`openai`,n),children:i.loadingProvider===`openai`?(0,p.jsxs)(`span`,{className:`flex items-center gap-1.5`,children:[(0,p.jsx)(`span`,{className:`w-3.5 h-3.5 border-2 border-white border-t-transparent rounded-full animate-spin`}),`Waiting for login...`]}):(0,p.jsxs)(p.Fragment,{children:[(0,p.jsx)(o,{className:`size-4`}),`Login with OpenAI`]})}),(0,p.jsxs)(`div`,{className:`flex items-center gap-3`,children:[(0,p.jsx)(`div`,{className:`flex-1 h-px bg-sand-200`}),(0,p.jsx)(`span`,{className:`text-[10px] text-sand-400 uppercase`,children:`or`}),(0,p.jsx)(`div`,{className:`flex-1 h-px bg-sand-200`})]}),(0,p.jsx)(`button`,{type:`button`,className:`w-full py-2.5 text-sm font-medium rounded-md border border-sand-300 text-sand-700 hover:bg-sand-100 disabled:opacity-50 transition-colors duration-150 flex items-center justify-center gap-2`,disabled:!n.trim()||i.loadingProvider!==null,onClick:()=>void i.start(`anthropic`,n),children:i.loadingProvider===`anthropic`?(0,p.jsxs)(`span`,{className:`flex items-center gap-1.5`,children:[(0,p.jsx)(`span`,{className:`w-3.5 h-3.5 border-2 border-sand-400 border-t-transparent rounded-full animate-spin`}),`Waiting for login...`]}):(0,p.jsxs)(p.Fragment,{children:[(0,p.jsx)(o,{className:`size-4`}),`Login with Claude`]})})]})]}),(0,p.jsx)(`div`,{className:`px-5 py-3 border-t border-sand-100/50 flex items-center justify-end gap-2`,children:(0,p.jsx)(`button`,{type:`button`,className:`px-3 py-1 text-xs font-medium rounded-md border border-sand-200 text-sand-600 hover:bg-sand-100 transition-colors duration-150`,onClick:a,children:`Cancel`})})]})]})]})}var h=e=>(0,p.jsx)(`svg`,{viewBox:`0 0 24 24`,width:`1.2em`,height:`1.2em`,...e,children:(0,p.jsx)(`path`,{fill:`none`,stroke:`currentColor`,strokeLinecap:`round`,strokeLinejoin:`round`,strokeWidth:2,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-.497zM15 5l4 4`})}),g=e=>(0,p.jsx)(`svg`,{viewBox:`0 0 24 24`,width:`1.2em`,height:`1.2em`,...e,children:(0,p.jsx)(`path`,{fill:`none`,stroke:`currentColor`,strokeLinecap:`round`,strokeLinejoin:`round`,strokeWidth:2,d:`M10 11v6m4-6v6m5-11v14a2 2 0 0 1-2 2H7a2 2 0 0 1-2-2V6M3 6h18M8 6V4a2 2 0 0 1 2-2h4a2 2 0 0 1 2 2v2`})});function _(e){if(!e||typeof e!=`object`)return`—`;if(`authSource`in e&&e.authSource===`system-keychain`)return`System Keychain`;let t=`accessToken`in e?e.accessToken:void 0;return typeof t!=`string`||!t?`—`:t.length<=12?t:`${t.slice(0,8)}...${t.slice(-4)}`}function v(e){let t=e.credentials;return`expiresAt`in t&&typeof t.expiresAt==`number`?t.expiresAt:`accessTokenExpiresAt`in t&&typeof t.accessTokenExpiresAt==`number`?t.accessTokenExpiresAt:null}function y(e){if(!e)return{text:``,color:``};let t=e-Date.now();if(t<=0)return{text:`expired`,color:`text-red-500`};let n=Math.floor(t/36e5),r=Math.floor(t%36e5/6e4),i=n>0?`${n}h ${r}m`:`${r}m`;return t<36e5?{text:i,color:`text-amber-500`}:{text:i,color:`text-sand-400`}}function b({data:e,isLoading:n}){let[r,a]=(0,f.useState)(null),[o,l]=(0,f.useState)(null),[u,d]=(0,f.useState)(``),m=t(),b=i.useRemoveTokenMutation(),x=c(),S=i.useToggleTokenMutation(),C=()=>Promise.all([m.invalidateQueries({queryKey:[`Token`]}),m.invalidateQueries({queryKey:[`Qgrid`]})]),w=async e=>{await S.mutateAsync({id:e.id}),await C()},T=async()=>{r&&(await b.mutateAsync({id:r.id}),await C(),a(null))},E=e=>{l(e),d(e.name??``)},D=async()=>{o&&(await x.mutateAsync({id:o.id,name:u.trim()}),await C(),l(null))};if(n)return(0,p.jsx)(`div`,{className:`space-y-2`,children:Array.from({length:3}).map((e,t)=>(0,p.jsx)(`div`,{className:`h-12 bg-sand-100 rounded-md animate-pulse`},`skeleton-${t}`))});let O=e??[];return O.length===0?(0,p.jsxs)(`div`,{className:`text-sand-400 text-center py-16 text-sm`,children:[`No tokens registered. Click `,(0,p.jsx)(`strong`,{className:`text-sand-600`,children:`Add Token`}),` to get started.`]}):(0,p.jsxs)(p.Fragment,{children:[(0,p.jsx)(`div`,{className:`panel overflow-hidden`,children:(0,p.jsx)(`div`,{className:`overflow-x-auto`,children:(0,p.jsxs)(`table`,{className:`w-full min-w-[640px] text-[13px]`,children:[(0,p.jsx)(`thead`,{children:(0,p.jsxs)(`tr`,{className:`panel-header`,children:[(0,p.jsx)(`th`,{className:`text-left px-5 py-2.5 text-[10px] uppercase tracking-wider text-sand-400 font-medium`,children:`Provider`}),(0,p.jsx)(`th`,{className:`text-left px-5 py-2.5 text-[10px] uppercase tracking-wider text-sand-400 font-medium`,children:`Name`}),(0,p.jsx)(`th`,{className:`text-left px-5 py-2.5 text-[10px] uppercase tracking-wider text-sand-400 font-medium`,children:`Token`}),(0,p.jsx)(`th`,{className:`text-left px-5 py-2.5 text-[10px] uppercase tracking-wider text-sand-400 font-medium`,children:`Status`}),(0,p.jsx)(`th`,{className:`text-left px-5 py-2.5 text-[10px] uppercase tracking-wider text-sand-400 font-medium`,children:`Expires`}),(0,p.jsx)(`th`,{className:`w-20 px-3 py-2.5`})]})}),(0,p.jsx)(`tbody`,{className:`divide-y divide-sand-100/80`,children:O.map(e=>{let t=y(v(e));return(0,p.jsxs)(`tr`,{className:`transition-colors duration-150 hover:bg-sand-100/60 ${e.active?``:`opacity-50`}`,children:[(0,p.jsx)(`td`,{className:`px-5 py-3`,children:(0,p.jsx)(`span`,{className:`text-xs font-medium text-sand-500 uppercase`,children:e.provider})}),(0,p.jsx)(`td`,{className:`px-5 py-3`,children:e.name?(0,p.jsx)(`span`,{className:`text-sm text-sand-700`,children:e.name}):(0,p.jsx)(`span`,{className:`text-[11px] text-sand-400`,children:`—`})}),(0,p.jsx)(`td`,{className:`px-5 py-3`,children:(0,p.jsx)(`code`,{className:`text-[13px] font-mono text-sand-800`,children:_(e.credentials)})}),(0,p.jsx)(`td`,{className:`px-5 py-3`,children:(0,p.jsx)(`button`,{type:`button`,className:`relative inline-flex h-5 w-9 items-center rounded-full transition-colors duration-200 ${e.active?`bg-sage-400`:`bg-sand-300`}`,onClick:()=>w(e),disabled:S.isPending||!e.active&&e.reauth_required,title:!e.active&&e.reauth_required?`재로그인이 필요한 토큰입니다`:void 0,children:(0,p.jsx)(`span`,{className:`inline-block h-3.5 w-3.5 rounded-full bg-white transition-transform duration-200 ${e.active?`translate-x-4.5`:`translate-x-0.5`}`})})}),(0,p.jsx)(`td`,{className:`px-5 py-3`,children:t.text&&(0,p.jsx)(`span`,{className:`text-xs ${t.color}`,children:t.text})}),(0,p.jsx)(`td`,{className:`px-3 py-3`,children:(0,p.jsxs)(`div`,{className:`flex items-center gap-1`,children:[(0,p.jsx)(`button`,{type:`button`,className:`p-1 rounded text-sand-400 hover:text-sienna-500 transition-colors duration-150`,onClick:()=>E(e),children:(0,p.jsx)(h,{className:`size-4`})}),(0,p.jsx)(`button`,{type:`button`,className:`p-1 rounded text-sand-400 hover:text-red-500 transition-colors duration-150`,onClick:()=>a(e),children:(0,p.jsx)(g,{className:`size-4`})})]})})]},e.id)})})]})})}),o&&(0,p.jsxs)(`div`,{className:`fixed inset-0 z-50 flex items-start justify-center pt-[15vh]`,children:[(0,p.jsx)(`div`,{className:`absolute inset-0 bg-sand-900/8 backdrop-blur-sm`,onClick:()=>l(null),onKeyDown:()=>{}}),(0,p.jsxs)(`div`,{className:`relative panel shadow-xl w-full max-w-sm mx-4`,children:[(0,p.jsx)(`div`,{className:`px-5 py-4 border-b border-sand-100/60`,children:(0,p.jsx)(`h3`,{className:`text-base font-medium text-sand-900`,children:`Edit Token`})}),(0,p.jsx)(`div`,{className:`px-5 py-4 space-y-3`,children:(0,p.jsxs)(`div`,{children:[(0,p.jsx)(`label`,{htmlFor:`token-name`,className:`text-[10px] uppercase tracking-wider text-sand-500 font-medium`,children:`Name`}),(0,p.jsx)(s,{value:u,onChange:e=>d(e.target.value),placeholder:`e.g. prod, dev, team-a`,className:`mt-1 w-full border border-sand-200 rounded-md px-3 py-2 text-sm text-sand-900 bg-white placeholder:text-sand-300 focus:outline-none focus:border-sienna-300`})]})}),(0,p.jsxs)(`div`,{className:`px-5 py-3 border-t border-sand-100/60 flex items-center justify-end gap-2`,children:[(0,p.jsx)(`button`,{type:`button`,className:`px-3 py-1 text-xs font-medium rounded-md border border-sand-200 text-sand-600 hover:bg-sand-100 transition-colors duration-150`,onClick:()=>l(null),children:`Cancel`}),(0,p.jsx)(`button`,{type:`button`,className:`px-3 py-1 text-xs font-medium rounded-md bg-sienna-400 text-white hover:bg-sienna-500 disabled:opacity-50 transition-colors duration-150`,disabled:x.isPending,onClick:D,children:x.isPending?`Saving...`:`Save`})]})]})]}),r&&(0,p.jsxs)(`div`,{className:`fixed inset-0 z-50 flex items-start justify-center pt-[15vh]`,children:[(0,p.jsx)(`div`,{className:`absolute inset-0 bg-sand-900/8 backdrop-blur-sm`,onClick:()=>a(null),onKeyDown:()=>{}}),(0,p.jsxs)(`div`,{className:`relative panel shadow-xl w-full max-w-sm mx-4`,children:[(0,p.jsxs)(`div`,{className:`px-5 py-4`,children:[(0,p.jsx)(`h3`,{className:`text-base font-medium text-sand-900`,children:`Remove Token`}),(0,p.jsxs)(`p`,{className:`text-sm text-sand-700 mt-2`,children:[`Are you sure you want to remove`,` `,(0,p.jsx)(`code`,{className:`text-[13px] font-mono text-sand-800`,children:_(r.credentials)}),r.name&&(0,p.jsxs)(`span`,{className:`text-sand-500`,children:[` (`,r.name,`)`]}),`?`]})]}),(0,p.jsxs)(`div`,{className:`px-5 py-3 border-t border-sand-100/60 flex items-center justify-end gap-2`,children:[(0,p.jsx)(`button`,{type:`button`,className:`px-3 py-1 text-xs font-medium rounded-md border border-sand-200 text-sand-600 hover:bg-sand-100 transition-colors duration-150`,onClick:()=>a(null),children:`Cancel`}),(0,p.jsx)(`button`,{type:`button`,className:`px-3 py-1 text-xs font-medium rounded-md bg-red-500 text-white hover:bg-red-600 disabled:opacity-50 transition-colors duration-150`,disabled:b.isPending,onClick:T,children:b.isPending?`Removing...`:`Remove`})]})]})]})]})}function x(){let{data:e,isLoading:t}=a.useTokens(`A`);return(0,p.jsxs)(`div`,{className:`max-w-6xl mx-auto space-y-4`,children:[(0,p.jsx)(`div`,{className:`flex items-center justify-end`,children:(0,p.jsx)(m,{})}),(0,p.jsx)(b,{data:e?.rows,isLoading:t})]})}export{x as component};
1
+ import{r as e}from"./rolldown-runtime-Dw2cE7zH.js";import{y as t}from"./vendor-tanstack-DJRQAbrY.js";import{i as n,r}from"./vendor-react-DH4kUfK2.js";import{n as i,o as a}from"./services.generated-BsieU37H.js";import{f as o,o as s}from"./index-CrXKu_J8.js";import{t as c}from"./use-update-token-mutation-DAq0F8p-.js";import{n as l,t as u}from"./use-oauth-login-flow-D0UaR9_e.js";import{t as d}from"./plus-B62CuqT8.js";var f=e(n(),1),p=r();function m(){let[e,t]=(0,f.useState)(!1),[n,r]=(0,f.useState)(``),i=u(),a=()=>{t(!1),r(``),i.reset()},c=async e=>{await i.submitCode(e)&&a()};return(0,p.jsxs)(p.Fragment,{children:[(0,p.jsxs)(`button`,{type:`button`,className:`px-3.5 py-1.5 text-[12px] font-medium rounded-lg bg-sienna-500 text-white hover:bg-sienna-600 disabled:opacity-50 transition-all duration-150 active:scale-[0.97] flex items-center gap-1.5 shadow-sm`,onClick:()=>t(!0),children:[(0,p.jsx)(d,{className:`size-3.5`}),`Add Token`]}),e&&(0,p.jsxs)(`div`,{className:`fixed inset-0 z-50 flex items-start justify-center pt-[15vh]`,children:[(0,p.jsx)(`div`,{className:`absolute inset-0 bg-sand-900/8 backdrop-blur-sm`,onClick:a,onKeyDown:()=>{}}),(0,p.jsxs)(`div`,{className:`relative panel shadow-xl w-full max-w-md mx-4`,children:[(0,p.jsx)(`div`,{className:`px-5 py-4 border-b border-sand-100/50`,children:(0,p.jsx)(`h2`,{className:`text-base font-medium text-sand-900`,children:`Add Token`})}),(0,p.jsxs)(`div`,{className:`px-5 py-4 space-y-4`,children:[(0,p.jsxs)(`div`,{children:[(0,p.jsx)(`label`,{htmlFor:`token-name`,className:`text-[10px] uppercase tracking-wider text-sand-500 font-medium`,children:`Name *`}),(0,p.jsx)(s,{value:n,onChange:e=>r(e.target.value),placeholder:`e.g. your-token-name`,className:`mt-1 w-full border border-sand-200 rounded-md px-3 py-2 text-sm text-sand-900 bg-white placeholder:text-sand-300 focus:outline-none focus:border-sienna-300`})]}),i.codeEntryProvider?(0,p.jsx)(l,{provider:i.codeEntryProvider,isPending:i.completeMutation.isPending,isError:i.completeMutation.isError,onSubmit:e=>void c(e),onRestart:i.reset}):(0,p.jsxs)(`div`,{className:`space-y-2`,children:[(0,p.jsx)(`button`,{type:`button`,className:`w-full py-2.5 text-sm font-medium rounded-md bg-sand-900 text-white hover:bg-sand-800 disabled:opacity-50 transition-colors duration-150 flex items-center justify-center gap-2`,disabled:!n.trim()||i.loadingProvider!==null,onClick:()=>void i.start(`openai`,n),children:i.loadingProvider===`openai`?(0,p.jsxs)(`span`,{className:`flex items-center gap-1.5`,children:[(0,p.jsx)(`span`,{className:`w-3.5 h-3.5 border-2 border-white border-t-transparent rounded-full animate-spin`}),`Waiting for login...`]}):(0,p.jsxs)(p.Fragment,{children:[(0,p.jsx)(o,{className:`size-4`}),`Login with OpenAI`]})}),(0,p.jsxs)(`div`,{className:`flex items-center gap-3`,children:[(0,p.jsx)(`div`,{className:`flex-1 h-px bg-sand-200`}),(0,p.jsx)(`span`,{className:`text-[10px] text-sand-400 uppercase`,children:`or`}),(0,p.jsx)(`div`,{className:`flex-1 h-px bg-sand-200`})]}),(0,p.jsx)(`button`,{type:`button`,className:`w-full py-2.5 text-sm font-medium rounded-md border border-sand-300 text-sand-700 hover:bg-sand-100 disabled:opacity-50 transition-colors duration-150 flex items-center justify-center gap-2`,disabled:!n.trim()||i.loadingProvider!==null,onClick:()=>void i.start(`anthropic`,n),children:i.loadingProvider===`anthropic`?(0,p.jsxs)(`span`,{className:`flex items-center gap-1.5`,children:[(0,p.jsx)(`span`,{className:`w-3.5 h-3.5 border-2 border-sand-400 border-t-transparent rounded-full animate-spin`}),`Waiting for login...`]}):(0,p.jsxs)(p.Fragment,{children:[(0,p.jsx)(o,{className:`size-4`}),`Login with Claude`]})})]})]}),(0,p.jsx)(`div`,{className:`px-5 py-3 border-t border-sand-100/50 flex items-center justify-end gap-2`,children:(0,p.jsx)(`button`,{type:`button`,className:`px-3 py-1 text-xs font-medium rounded-md border border-sand-200 text-sand-600 hover:bg-sand-100 transition-colors duration-150`,onClick:a,children:`Cancel`})})]})]})]})}var h=e=>(0,p.jsx)(`svg`,{viewBox:`0 0 24 24`,width:`1.2em`,height:`1.2em`,...e,children:(0,p.jsx)(`path`,{fill:`none`,stroke:`currentColor`,strokeLinecap:`round`,strokeLinejoin:`round`,strokeWidth:2,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-.497zM15 5l4 4`})}),g=e=>(0,p.jsx)(`svg`,{viewBox:`0 0 24 24`,width:`1.2em`,height:`1.2em`,...e,children:(0,p.jsx)(`path`,{fill:`none`,stroke:`currentColor`,strokeLinecap:`round`,strokeLinejoin:`round`,strokeWidth:2,d:`M10 11v6m4-6v6m5-11v14a2 2 0 0 1-2 2H7a2 2 0 0 1-2-2V6M3 6h18M8 6V4a2 2 0 0 1 2-2h4a2 2 0 0 1 2 2v2`})});function _(e){if(!e||typeof e!=`object`)return`—`;if(`authSource`in e&&e.authSource===`system-keychain`)return`System Keychain`;let t=`accessToken`in e?e.accessToken:void 0;return typeof t!=`string`||!t?`—`:t.length<=12?t:`${t.slice(0,8)}...${t.slice(-4)}`}function v(e){let t=e.credentials;return`expiresAt`in t&&typeof t.expiresAt==`number`?t.expiresAt:`accessTokenExpiresAt`in t&&typeof t.accessTokenExpiresAt==`number`?t.accessTokenExpiresAt:null}function y(e){if(!e)return{text:``,color:``};let t=e-Date.now();if(t<=0)return{text:`expired`,color:`text-red-500`};let n=Math.floor(t/36e5),r=Math.floor(t%36e5/6e4),i=n>0?`${n}h ${r}m`:`${r}m`;return t<36e5?{text:i,color:`text-amber-500`}:{text:i,color:`text-sand-400`}}function b({data:e,isLoading:n}){let[r,a]=(0,f.useState)(null),[o,l]=(0,f.useState)(null),[u,d]=(0,f.useState)(``),m=t(),b=i.useRemoveTokenMutation(),x=c(),S=i.useToggleTokenMutation(),C=()=>Promise.all([m.invalidateQueries({queryKey:[`Token`]}),m.invalidateQueries({queryKey:[`Qgrid`]})]),w=async e=>{await S.mutateAsync({id:e.id}),await C()},T=async()=>{r&&(await b.mutateAsync({id:r.id}),await C(),a(null))},E=e=>{l(e),d(e.name??``)},D=async()=>{o&&(await x.mutateAsync({id:o.id,name:u.trim()}),await C(),l(null))};if(n)return(0,p.jsx)(`div`,{className:`space-y-2`,children:Array.from({length:3}).map((e,t)=>(0,p.jsx)(`div`,{className:`h-12 bg-sand-100 rounded-md animate-pulse`},`skeleton-${t}`))});let O=e??[];return O.length===0?(0,p.jsxs)(`div`,{className:`text-sand-400 text-center py-16 text-sm`,children:[`No tokens registered. Click `,(0,p.jsx)(`strong`,{className:`text-sand-600`,children:`Add Token`}),` to get started.`]}):(0,p.jsxs)(p.Fragment,{children:[(0,p.jsx)(`div`,{className:`panel overflow-hidden`,children:(0,p.jsx)(`div`,{className:`overflow-x-auto`,children:(0,p.jsxs)(`table`,{className:`w-full min-w-[640px] text-[13px]`,children:[(0,p.jsx)(`thead`,{children:(0,p.jsxs)(`tr`,{className:`panel-header`,children:[(0,p.jsx)(`th`,{className:`text-left px-5 py-2.5 text-[10px] uppercase tracking-wider text-sand-400 font-medium`,children:`Provider`}),(0,p.jsx)(`th`,{className:`text-left px-5 py-2.5 text-[10px] uppercase tracking-wider text-sand-400 font-medium`,children:`Name`}),(0,p.jsx)(`th`,{className:`text-left px-5 py-2.5 text-[10px] uppercase tracking-wider text-sand-400 font-medium`,children:`Token`}),(0,p.jsx)(`th`,{className:`text-left px-5 py-2.5 text-[10px] uppercase tracking-wider text-sand-400 font-medium`,children:`Status`}),(0,p.jsx)(`th`,{className:`text-left px-5 py-2.5 text-[10px] uppercase tracking-wider text-sand-400 font-medium`,children:`Expires`}),(0,p.jsx)(`th`,{className:`w-20 px-3 py-2.5`})]})}),(0,p.jsx)(`tbody`,{className:`divide-y divide-sand-100/80`,children:O.map(e=>{let t=y(v(e));return(0,p.jsxs)(`tr`,{className:`transition-colors duration-150 hover:bg-sand-100/60 ${e.active?``:`opacity-50`}`,children:[(0,p.jsx)(`td`,{className:`px-5 py-3`,children:(0,p.jsx)(`span`,{className:`text-xs font-medium text-sand-500 uppercase`,children:e.provider})}),(0,p.jsx)(`td`,{className:`px-5 py-3`,children:e.name?(0,p.jsx)(`span`,{className:`text-sm text-sand-700`,children:e.name}):(0,p.jsx)(`span`,{className:`text-[11px] text-sand-400`,children:`—`})}),(0,p.jsx)(`td`,{className:`px-5 py-3`,children:(0,p.jsx)(`code`,{className:`text-[13px] font-mono text-sand-800`,children:_(e.credentials)})}),(0,p.jsx)(`td`,{className:`px-5 py-3`,children:(0,p.jsx)(`button`,{type:`button`,className:`relative inline-flex h-5 w-9 items-center rounded-full transition-colors duration-200 ${e.active?`bg-sage-400`:`bg-sand-300`}`,onClick:()=>w(e),disabled:S.isPending||!e.active&&e.reauth_required,title:!e.active&&e.reauth_required?`재로그인이 필요한 토큰입니다`:void 0,children:(0,p.jsx)(`span`,{className:`inline-block h-3.5 w-3.5 rounded-full bg-white transition-transform duration-200 ${e.active?`translate-x-4.5`:`translate-x-0.5`}`})})}),(0,p.jsx)(`td`,{className:`px-5 py-3`,children:t.text&&(0,p.jsx)(`span`,{className:`text-xs ${t.color}`,children:t.text})}),(0,p.jsx)(`td`,{className:`px-3 py-3`,children:(0,p.jsxs)(`div`,{className:`flex items-center gap-1`,children:[(0,p.jsx)(`button`,{type:`button`,className:`p-1 rounded text-sand-400 hover:text-sienna-500 transition-colors duration-150`,onClick:()=>E(e),children:(0,p.jsx)(h,{className:`size-4`})}),(0,p.jsx)(`button`,{type:`button`,className:`p-1 rounded text-sand-400 hover:text-red-500 transition-colors duration-150`,onClick:()=>a(e),children:(0,p.jsx)(g,{className:`size-4`})})]})})]},e.id)})})]})})}),o&&(0,p.jsxs)(`div`,{className:`fixed inset-0 z-50 flex items-start justify-center pt-[15vh]`,children:[(0,p.jsx)(`div`,{className:`absolute inset-0 bg-sand-900/8 backdrop-blur-sm`,onClick:()=>l(null),onKeyDown:()=>{}}),(0,p.jsxs)(`div`,{className:`relative panel shadow-xl w-full max-w-sm mx-4`,children:[(0,p.jsx)(`div`,{className:`px-5 py-4 border-b border-sand-100/60`,children:(0,p.jsx)(`h3`,{className:`text-base font-medium text-sand-900`,children:`Edit Token`})}),(0,p.jsx)(`div`,{className:`px-5 py-4 space-y-3`,children:(0,p.jsxs)(`div`,{children:[(0,p.jsx)(`label`,{htmlFor:`token-name`,className:`text-[10px] uppercase tracking-wider text-sand-500 font-medium`,children:`Name`}),(0,p.jsx)(s,{value:u,onChange:e=>d(e.target.value),placeholder:`e.g. prod, dev, team-a`,className:`mt-1 w-full border border-sand-200 rounded-md px-3 py-2 text-sm text-sand-900 bg-white placeholder:text-sand-300 focus:outline-none focus:border-sienna-300`})]})}),(0,p.jsxs)(`div`,{className:`px-5 py-3 border-t border-sand-100/60 flex items-center justify-end gap-2`,children:[(0,p.jsx)(`button`,{type:`button`,className:`px-3 py-1 text-xs font-medium rounded-md border border-sand-200 text-sand-600 hover:bg-sand-100 transition-colors duration-150`,onClick:()=>l(null),children:`Cancel`}),(0,p.jsx)(`button`,{type:`button`,className:`px-3 py-1 text-xs font-medium rounded-md bg-sienna-400 text-white hover:bg-sienna-500 disabled:opacity-50 transition-colors duration-150`,disabled:x.isPending,onClick:D,children:x.isPending?`Saving...`:`Save`})]})]})]}),r&&(0,p.jsxs)(`div`,{className:`fixed inset-0 z-50 flex items-start justify-center pt-[15vh]`,children:[(0,p.jsx)(`div`,{className:`absolute inset-0 bg-sand-900/8 backdrop-blur-sm`,onClick:()=>a(null),onKeyDown:()=>{}}),(0,p.jsxs)(`div`,{className:`relative panel shadow-xl w-full max-w-sm mx-4`,children:[(0,p.jsxs)(`div`,{className:`px-5 py-4`,children:[(0,p.jsx)(`h3`,{className:`text-base font-medium text-sand-900`,children:`Remove Token`}),(0,p.jsxs)(`p`,{className:`text-sm text-sand-700 mt-2`,children:[`Are you sure you want to remove`,` `,(0,p.jsx)(`code`,{className:`text-[13px] font-mono text-sand-800`,children:_(r.credentials)}),r.name&&(0,p.jsxs)(`span`,{className:`text-sand-500`,children:[` (`,r.name,`)`]}),`?`]})]}),(0,p.jsxs)(`div`,{className:`px-5 py-3 border-t border-sand-100/60 flex items-center justify-end gap-2`,children:[(0,p.jsx)(`button`,{type:`button`,className:`px-3 py-1 text-xs font-medium rounded-md border border-sand-200 text-sand-600 hover:bg-sand-100 transition-colors duration-150`,onClick:()=>a(null),children:`Cancel`}),(0,p.jsx)(`button`,{type:`button`,className:`px-3 py-1 text-xs font-medium rounded-md bg-red-500 text-white hover:bg-red-600 disabled:opacity-50 transition-colors duration-150`,disabled:b.isPending,onClick:T,children:b.isPending?`Removing...`:`Remove`})]})]})]})]})}function x(){let{data:e,isLoading:t}=a.useTokens(`A`);return(0,p.jsxs)(`div`,{className:`max-w-6xl mx-auto space-y-4`,children:[(0,p.jsx)(`div`,{className:`flex items-center justify-end`,children:(0,p.jsx)(m,{})}),(0,p.jsx)(b,{data:e?.rows,isLoading:t})]})}export{x as component};
@@ -1 +1 @@
1
- import{r as e}from"./rolldown-runtime-Dw2cE7zH.js";import{y as t}from"./vendor-tanstack-DJRQAbrY.js";import{i as n,r}from"./vendor-react-DH4kUfK2.js";import{n as i,o as a}from"./services.generated-BsieU37H.js";import{o}from"./index-DmCLKefs.js";var s=e(n(),1),c=r();function l({provider:e,isPending:t,isError:n,onSubmit:r,onRestart:i}){let[a,l]=(0,s.useState)(``),u=e===`openai`;return(0,c.jsxs)(`div`,{className:`space-y-2`,children:[(0,c.jsx)(`p`,{className:`text-[12px] text-sand-600 leading-relaxed`,children:u?`새 탭에서 OpenAI 로그인을 완료한 뒤 연결 실패 화면이 나타나면, 주소창의 전체 URL을 아래에 붙여넣으세요.`:`새 탭에서 Claude 로그인을 완료하면 코드가 표시됩니다. 코드 전체를 아래에 붙여넣으세요.`}),(0,c.jsx)(o,{value:a,onChange:e=>l(e.target.value),placeholder:u?`http://localhost:1455/auth/callback?code=...&state=...`:`code#state`,className:`w-full border border-sand-200 rounded-md px-3 py-2 text-sm font-mono text-sand-900 bg-white placeholder:text-sand-300 focus:outline-none focus:border-sienna-300`}),n&&(0,c.jsx)(`p`,{className:`text-[11px] text-red-500`,children:`인증 결과 확인에 실패했습니다 — 전체 값을 다시 붙여넣거나 로그인을 다시 시작하세요.`}),(0,c.jsx)(`button`,{type:`button`,className:`w-full py-2.5 text-sm font-medium rounded-md bg-sand-900 text-white hover:bg-sand-800 disabled:opacity-50 transition-colors duration-150 flex items-center justify-center gap-2`,disabled:!a.trim()||t,onClick:()=>r(a),children:t?(0,c.jsxs)(`span`,{className:`flex items-center gap-1.5`,children:[(0,c.jsx)(`span`,{className:`w-3.5 h-3.5 border-2 border-white border-t-transparent rounded-full animate-spin`}),`Verifying...`]}):`Complete login`}),(0,c.jsx)(`button`,{type:`button`,className:`w-full py-1.5 text-[12px] text-sand-500 hover:text-sand-700 transition-colors duration-150`,onClick:()=>{l(``),i()},children:`처음부터 다시 시작`})]})}var u=3e3,d=3e5;async function f(e,t){let{rows:n}=await a.getTokens(`A`,{num:0,queryMode:`list`});return new Set(n.filter(n=>n.provider===e&&n.name===t).map(e=>e.id))}function p(){let[e,n]=(0,s.useState)(null),[r,a]=(0,s.useState)(null),o=t(),c=i.useOauthStartMutation(),l=i.useOauthStartOpenAIMutation(),p=i.useOauthCompleteMutation(),m=(0,s.useRef)({}),h=(0,s.useRef)(0),g=()=>{h.current+=1,m.current.interval!==void 0&&clearInterval(m.current.interval),m.current.timeout!==void 0&&clearTimeout(m.current.timeout),m.current={}};(0,s.useEffect)(()=>g,[]);let _=()=>Promise.all([o.invalidateQueries({queryKey:[`Token`]}),o.invalidateQueries({queryKey:[`Qgrid`]})]);return{loadingProvider:e,codeEntryProvider:r,start:async(e,t)=>{let r=t.trim();if(!r)return;g();let i=h.current,o=window.open(`about:blank`,`_blank`);n(e);try{if(e===`openai`){let t=await f(e,r);if(i!==h.current){o?.close();return}let{authUrl:s,mode:c}=await l.mutateAsync({name:r});if(i!==h.current){o?.close();return}if(o?o.location.href=s:window.open(s,`_blank`),c===`code`){a(e),n(null);return}m.current.interval=window.setInterval(()=>{f(e,r).then(e=>{i===h.current&&[...e].some(e=>!t.has(e))&&(g(),n(null),_())}).catch(()=>{})},u),m.current.timeout=window.setTimeout(()=>{i===h.current&&(g(),n(null))},d);return}let{authUrl:t,mode:s}=await c.mutateAsync({name:r});if(i!==h.current){o?.close();return}s===`code`?(o?o.location.href=t:window.open(t,`_blank`),a(e),n(null)):(o?.close(),window.location.href=t)}catch(e){if(o?.close(),i!==h.current)return;console.error(`OAuth start failed:`,e),n(null)}},submitCode:async e=>{let t=e.trim();if(!t)return!1;try{await p.mutateAsync({pastedCode:t})}catch(e){return console.error(`OAuth complete failed:`,e),!1}return await _(),!0},reset:()=>{g(),n(null),a(null),p.reset()},completeMutation:p}}export{l as n,p as t};
1
+ import{r as e}from"./rolldown-runtime-Dw2cE7zH.js";import{y as t}from"./vendor-tanstack-DJRQAbrY.js";import{i as n,r}from"./vendor-react-DH4kUfK2.js";import{n as i,o as a}from"./services.generated-BsieU37H.js";import{o}from"./index-CrXKu_J8.js";var s=e(n(),1),c=r();function l({provider:e,isPending:t,isError:n,onSubmit:r,onRestart:i}){let[a,l]=(0,s.useState)(``),u=e===`openai`;return(0,c.jsxs)(`div`,{className:`space-y-2`,children:[(0,c.jsx)(`p`,{className:`text-[12px] text-sand-600 leading-relaxed`,children:u?`새 탭에서 OpenAI 로그인을 완료한 뒤 연결 실패 화면이 나타나면, 주소창의 전체 URL을 아래에 붙여넣으세요.`:`새 탭에서 Claude 로그인을 완료하면 코드가 표시됩니다. 코드 전체를 아래에 붙여넣으세요.`}),(0,c.jsx)(o,{value:a,onChange:e=>l(e.target.value),placeholder:u?`http://localhost:1455/auth/callback?code=...&state=...`:`code#state`,className:`w-full border border-sand-200 rounded-md px-3 py-2 text-sm font-mono text-sand-900 bg-white placeholder:text-sand-300 focus:outline-none focus:border-sienna-300`}),n&&(0,c.jsx)(`p`,{className:`text-[11px] text-red-500`,children:`인증 결과 확인에 실패했습니다 — 전체 값을 다시 붙여넣거나 로그인을 다시 시작하세요.`}),(0,c.jsx)(`button`,{type:`button`,className:`w-full py-2.5 text-sm font-medium rounded-md bg-sand-900 text-white hover:bg-sand-800 disabled:opacity-50 transition-colors duration-150 flex items-center justify-center gap-2`,disabled:!a.trim()||t,onClick:()=>r(a),children:t?(0,c.jsxs)(`span`,{className:`flex items-center gap-1.5`,children:[(0,c.jsx)(`span`,{className:`w-3.5 h-3.5 border-2 border-white border-t-transparent rounded-full animate-spin`}),`Verifying...`]}):`Complete login`}),(0,c.jsx)(`button`,{type:`button`,className:`w-full py-1.5 text-[12px] text-sand-500 hover:text-sand-700 transition-colors duration-150`,onClick:()=>{l(``),i()},children:`처음부터 다시 시작`})]})}var u=3e3,d=3e5;async function f(e,t){let{rows:n}=await a.getTokens(`A`,{num:0,queryMode:`list`});return new Set(n.filter(n=>n.provider===e&&n.name===t).map(e=>e.id))}function p(){let[e,n]=(0,s.useState)(null),[r,a]=(0,s.useState)(null),o=t(),c=i.useOauthStartMutation(),l=i.useOauthStartOpenAIMutation(),p=i.useOauthCompleteMutation(),m=(0,s.useRef)({}),h=(0,s.useRef)(0),g=()=>{h.current+=1,m.current.interval!==void 0&&clearInterval(m.current.interval),m.current.timeout!==void 0&&clearTimeout(m.current.timeout),m.current={}};(0,s.useEffect)(()=>g,[]);let _=()=>Promise.all([o.invalidateQueries({queryKey:[`Token`]}),o.invalidateQueries({queryKey:[`Qgrid`]})]);return{loadingProvider:e,codeEntryProvider:r,start:async(e,t)=>{let r=t.trim();if(!r)return;g();let i=h.current,o=window.open(`about:blank`,`_blank`);n(e);try{if(e===`openai`){let t=await f(e,r);if(i!==h.current){o?.close();return}let{authUrl:s,mode:c}=await l.mutateAsync({name:r});if(i!==h.current){o?.close();return}if(o?o.location.href=s:window.open(s,`_blank`),c===`code`){a(e),n(null);return}m.current.interval=window.setInterval(()=>{f(e,r).then(e=>{i===h.current&&[...e].some(e=>!t.has(e))&&(g(),n(null),_())}).catch(()=>{})},u),m.current.timeout=window.setTimeout(()=>{i===h.current&&(g(),n(null))},d);return}let{authUrl:t,mode:s}=await c.mutateAsync({name:r});if(i!==h.current){o?.close();return}s===`code`?(o?o.location.href=t:window.open(t,`_blank`),a(e),n(null)):(o?.close(),window.location.href=t)}catch(e){if(o?.close(),i!==h.current)return;console.error(`OAuth start failed:`,e),n(null)}},submitCode:async e=>{let t=e.trim();if(!t)return!1;try{await p.mutateAsync({pastedCode:t})}catch(e){return console.error(`OAuth complete failed:`,e),!1}return await _(),!0},reset:()=>{g(),n(null),a(null),p.reset()},completeMutation:p}}export{l as n,p as t};
@@ -5,7 +5,7 @@
5
5
  <link rel="icon" type="image/svg+xml" href="/sonamu.svg" />
6
6
  <meta name="viewport" content="width=device-width, initial-scale=1.0" />
7
7
  <title>Qgrid</title>
8
- <script type="module" crossorigin src="/assets/index-DmCLKefs.js"></script>
8
+ <script type="module" crossorigin src="/assets/index-CrXKu_J8.js"></script>
9
9
  <link rel="modulepreload" crossorigin href="/assets/rolldown-runtime-Dw2cE7zH.js">
10
10
  <link rel="modulepreload" crossorigin href="/assets/preload-helper-ca-nBW7U.js">
11
11
  <link rel="modulepreload" crossorigin href="/assets/vendor-react-DH4kUfK2.js">
@@ -46874,7 +46874,7 @@ function ChatWidget() {
46874
46874
  }
46875
46875
  //#endregion
46876
46876
  //#region src/components/Sidebar.tsx
46877
- var qgridVersion = "2.10.8";
46877
+ var qgridVersion = "2.10.9";
46878
46878
  function Sidebar({ className }) {
46879
46879
  const pathname = useRouterState({ select: (s) => s.location.pathname });
46880
46880
  return /* @__PURE__ */ (0, import_jsx_runtime.jsxs)("aside", {
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@cartanova/qgrid-cli",
3
- "version": "2.10.8",
3
+ "version": "2.10.9",
4
4
  "repository": {
5
5
  "type": "git",
6
6
  "url": "https://github.com/cartanova-ai/qgrid"
@@ -167,7 +167,7 @@ Payload responsibilities:
167
167
  - Preserve and resend `runContext` for tool-call follow-ups.
168
168
  - Let the server infer single-turn completion versus an open tool-call run. Logging-disabled tool calls still use the SDK's local pending-call correlation and continue without a request-log id.
169
169
  - Derive/store/resend opaque OpenAI affinity coordinates by `sessionKey`.
170
- - Keep language-model prompts text-only. Ignore image parts with an unsupported warning; this adapter does not support general vision.
170
+ - For `openai/` language models, send user-message image/file parts as image input: the current turn goes in qgrid `input` (text + image data/HTTP URLs) and earlier user turns as history `input_image`. The same JSON-transport size guard applies. Drop assistant image parts, and all image parts for `anthropic/` models (the Claude Code path is text-only), and report each drop as an AI SDK `unsupported` warning (`feature: "image input"`) in `warnings`, not only on the console.
171
171
  - The separate image provider converts `generateImage` prompt references to qgrid `input` and rejects oversized inline reference images before transport. Callers should compress/resize large reference photos, preferably to WebP/JPEG.
172
172
 
173
173
  Tools and `jsonSchema` can be used together as of qgrid 2.5.4. On OpenAI the
@@ -235,7 +235,7 @@ Key decisions:
235
235
  - It is non-stream only. Codex returns completed base64 image payloads, not useful image deltas.
236
236
  - Image turns send full input directly and retain no provider conversation state. This prevents base64 payloads from entering reusable state.
237
237
  - qgrid performs preflight capability/model gates. Raw `imageGeneration: true` requires an image; `"auto"` allows normal text replies but still rejects attempted image generation without a completed image. Public `generateImage` requires one direct Images output per provider call; AI SDK batches requests for `n` outputs.
238
- - Raw returned images are inline base64 content parts. The image SDK maps them to AI SDK `image`/`images` and takes references through standard `prompt: { text, images }`, with JSON data URL size guarding and HTTPS reference URL support. The language SDK ignores image parts with a warning and does not implement general vision.
238
+ - Raw returned images are inline base64 content parts. The image SDK maps them to AI SDK `image`/`images` and takes references through standard `prompt: { text, images }`, with JSON data URL size guarding and HTTPS reference URL support. The language SDK forwards user-message images to `openai/` models as image input (image→text) and drops other image parts with an AI SDK `unsupported` warning.
239
239
  - Raw/server `imageGenerationOptions` supports quality, size, and background. The public image SDK uses flat `QgridImageProviderOptions` and standard top-level `size`. The subscription backend can ignore size and quality hints. Put desired ratios in the prompt, report observed output settings, and never silently resize. Reported image usage is priced at public token rates; without it, use the requested quality/size table with a default-size price for auto/custom hints. Preserve observed settings separately from pricing assumptions. No background-removal fallback is allowed.
240
240
  - qgrid does not manage generated or reference images as durable assets through a `generated_images` table or object-storage layer. Current request logs can still contain inline image data URLs for inspection and synthetic `image_generation` tool-call steps; reference input images live in the first synthetic step's `tool_args.inputImages`.
241
241
  - Image cost is stored separately in `request_logs.image_cost_usd`; `request_logs.cost_usd` remains the Codex driver model token cost. Image costs use reported image usage at public token rates, or per-image quality/size estimates when usage is absent. Auto/custom sizes fall back to the 1536x1024 price; omitted quality uses medium. Rows and totals display combined costs as dollar amounts without Cost labels, without Known/Estimated labels or pricing disclaimers. Existing stored null costs are not backfilled; `totalCost.unknownImageCostCount` remains for API compatibility.
@@ -48,8 +48,9 @@ availability or identical limits on qgrid's ChatGPT-subscription route.
48
48
  ### GPT-6 Astra, Sol, Luna, and GPT-6.1 Sol
49
49
 
50
50
  `openai/gpt-6-astra` uses the existing text generation, streaming and structured-output paths.
51
- The model supports image input, but qgrid's language-model SDK adapter does not support general
52
- vision: it ignores image parts with a warning. Image generation/editing references belong to
51
+ The model supports image input. The language-model SDK adapter forwards user-message image parts
52
+ as `input_image` (image→text); assistant image parts are dropped with an `unsupported` warning.
53
+ Image generation/editing references belong to
53
54
  `generateImage({ model: qgrid.image(...), prompt: { text, images } })`; dashboard chat uses its
54
55
  own raw/server image inputs.
55
56
  Standard API-equivalent prices per million tokens are input $10, cached input $1, cache write
@@ -202,9 +202,9 @@ Generated SSE handlers missing a newly added event field:
202
202
 
203
203
  - Either removed key makes `generateText` and `streamText` fail before transport. Use `generateImage` with `qgrid.image()` and flat `QgridImageProviderOptions` for image output.
204
204
 
205
- `qgrid language models do not support image input`:
205
+ `unsupported` warning with `feature: "image input"`:
206
206
 
207
- - General vision remains unsupported by the language adapter; it ignores image parts with this warning. Reference-image editing belongs in `generateImage`'s `prompt: { text, images }`.
207
+ - The language adapter dropped image parts: all of them on `anthropic/` models, and assistant-message images on any model. User-message images on `openai/` models are sent as image input. Reference-image editing belongs in `generateImage`'s `prompt: { text, images }`.
208
208
 
209
209
  `image generation is not supported on the Anthropic route`:
210
210
 
@@ -216,7 +216,7 @@ Generated SSE handlers missing a newly added event field:
216
216
 
217
217
  `reference image input is too large for JSON transport`:
218
218
 
219
- - AI SDK reference-image guard. The client passed a base64 image data URL large enough to likely exceed qgrid's JSON request body transport. Compress or resize the image before calling `generateImage`, preferably as WebP/JPEG.
219
+ - AI SDK reference-image guard. The client passed a base64 image data URL large enough to likely exceed qgrid's JSON request body transport. Compress or resize the image before calling `generateImage` or an `openai/` language model with image input, preferably as WebP/JPEG.
220
220
 
221
221
  `qgrid query transport failed: response headers timed out`:
222
222