@soba-so/react 0.0.9 → 0.0.10

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.
package/dist/index.mjs CHANGED
@@ -1,8 +1,8 @@
1
1
  "use client"
2
- var ye=class extends Error{status;constructor(t,n){super(t),this.name="ConnectError",this.status=n}},de=class{session;baseUrl;doFetch;constructor(t){this.session=t.session,this.baseUrl=(t.baseUrl??"").replace(/\/+$/,""),this.doFetch=t.fetchImpl??fetch.bind(globalThis)}context(){return this.request("GET","/v1/connect")}async machines(){return(await this.request("GET","/v1/machines")).machines}lookup(t){return this.request("GET",`/v1/device/lookup?code=${encodeURIComponent(t)}`)}approve(t){return this.request("POST","/v1/device/approve",{user_code:t})}deny(t){return this.request("POST","/v1/device/deny",{user_code:t})}plans(){return this.request("GET","/v1/plans")}selectPlan(t){return this.request("POST","/v1/plans/select",{plan:t})}checkoutPlan(t,n){return this.request("POST","/v1/plans/checkout",{plan:t,...n?.successUrl?{success_url:n.successUrl}:{},...n?.cancelUrl?{cancel_url:n.cancelUrl}:{}})}leavePlan(){return this.request("DELETE","/v1/plans/select")}approveRuntime(t,n){return this.request("POST","/v1/runtimes/approve",{machine_id:t,runtime_id:n})}async request(t,n,o){let s=await this.doFetch(`${this.baseUrl}${n}`,{method:t,headers:{authorization:`Bearer ${this.session}`,...o?{"content-type":"application/json"}:{}},...o?{body:JSON.stringify(o)}:{}}),r={};try{r=await s.json()}catch{}if(!s.ok){let m=typeof r.error=="string"?r.error:`Request failed (${s.status})`;throw new ye(m,s.status)}return r}};function Ee(e){return e.authenticated===!0?{tone:"ok",text:"signed in"}:e.authenticated===!1?{tone:"warn",text:e.auth_hint??"signed out on that machine"}:{tone:"unknown",text:"could not tell"}}function _e(e){return e.state==="busy"?{tone:"busy",text:`serving ${e.active} of ${e.capacity}`}:e.state==="online"?{tone:"ok",text:"connected"}:{tone:"off",text:"asleep or offline"}}import{jsx as O,jsxs as se}from"react/jsx-runtime";function G({machines:e,onApproveRuntime:t}){return e.length?O("div",{children:e.map(n=>{let o=_e(n);return se("div",{className:"sc-machine",children:[se("div",{className:"sc-row-between",children:[se("div",{className:"sc-row",children:[O("span",{className:`sc-dot sc-dot-${o.tone}`,"aria-hidden":"true"}),O("strong",{children:n.label??"This machine"})]}),O("span",{className:"sc-note",children:o.text})]}),O("p",{className:"sc-note",children:[n.platform,n.arch,n.version&&`worker ${n.version}`,n.always_on&&"always on"].filter(Boolean).join(" \xB7 ")}),se("ul",{className:"sc-runtimes",children:[n.runtimes.map(s=>{let r=Ee(s);return s.quarantined?se("li",{className:"sc-row-between",children:[O("span",{children:s.display_name}),t?O("button",{type:"button",className:"sc-btn",onClick:()=>t(n.id,s.id),children:"New here. Let it serve"}):O("span",{className:"sc-tone-warn",children:"new, not serving yet"})]},s.id):se("li",{className:"sc-row-between",children:[O("span",{children:s.display_name}),O("span",{className:`sc-tone-${r.tone}`,children:r.text})]},s.id)}),!n.runtimes.length&&O("li",{className:"sc-note",children:"No runtime advertised. Install Claude Code, Codex or Ollama on that machine."})]})]},n.id)})}):O("p",{className:"sc-note",children:"Nothing connected yet."})}import{useCallback as ve,useEffect as W,useId as St,useMemo as me,useRef as Pt,useState as L}from"react";import{jsx as z,jsxs as xt}from"react/jsx-runtime";function Me({className:e}){return xt("svg",{viewBox:"0 0 24 24","aria-hidden":"true",focusable:"false",className:e,children:[z("path",{d:"M18.125 7.039A8.6 8.6 0 1 0 18.125 16.961A6 6 0 0 1 18.125 7.039Z",fill:"currentColor"}),z("path",{d:"M19.925 7.039A8.6 8.6 0 0 1 19.925 16.961A6 6 0 0 0 19.925 7.039Z",fill:"currentColor"})]})}function Xe({className:e}){return z("svg",{viewBox:"0 0 24 24","aria-hidden":"true",focusable:"false",className:e,children:z("path",{fill:"currentColor",d:"M17.3041 3.541h-3.6718l6.696 16.918H24Zm-10.6082 0L0 20.459h3.7442l1.3693-3.5527h7.0052l1.3693 3.5528h3.7442L10.5363 3.5409Zm-.3712 10.2232 2.2914-5.9456 2.2914 5.9456Z"})})}function Qe({className:e}){return z("svg",{viewBox:"0 0 24 24","aria-hidden":"true",focusable:"false",className:e,children:z("path",{fill:"currentColor",d:"M22.2819 9.8211a5.9847 5.9847 0 0 0-.5157-4.9108 6.0462 6.0462 0 0 0-6.5098-2.9A6.0651 6.0651 0 0 0 4.9807 4.1818a5.9847 5.9847 0 0 0-3.9977 2.9 6.0462 6.0462 0 0 0 .7427 7.0966 5.98 5.98 0 0 0 .511 4.9107 6.051 6.051 0 0 0 6.5146 2.9001A5.9847 5.9847 0 0 0 13.2599 24a6.0557 6.0557 0 0 0 5.7718-4.2058 5.9894 5.9894 0 0 0 3.9977-2.9001 6.0557 6.0557 0 0 0-.7475-7.0729zm-9.022 12.6081a4.4755 4.4755 0 0 1-2.8764-1.0408l.1419-.0804 4.7783-2.7582a.7948.7948 0 0 0 .3927-.6813v-6.7369l2.02 1.1686a.071.071 0 0 1 .038.052v5.5826a4.504 4.504 0 0 1-4.4945 4.4944zm-9.6607-4.1254a4.4708 4.4708 0 0 1-.5346-3.0137l.142.0852 4.783 2.7582a.7712.7712 0 0 0 .7806 0l5.8428-3.3685v2.3324a.0804.0804 0 0 1-.0332.0615L9.74 19.9502a4.4992 4.4992 0 0 1-6.1408-1.6464zM2.3408 7.8956a4.485 4.485 0 0 1 2.3655-1.9728V11.6a.7664.7664 0 0 0 .3879.6765l5.8144 3.3543-2.0201 1.1685a.0757.0757 0 0 1-.071 0l-4.8303-2.7865A4.504 4.504 0 0 1 2.3408 7.872zm16.5963 3.8558L13.1038 8.364 15.1192 7.2a.0757.0757 0 0 1 .071 0l4.8303 2.7913a4.4944 4.4944 0 0 1-.6765 8.1042v-5.6772a.79.79 0 0 0-.407-.667zm2.0107-3.0231l-.142-.0852-4.7735-2.7818a.7759.7759 0 0 0-.7854 0L9.409 9.2297V6.8974a.0662.0662 0 0 1 .0284-.0615l4.8303-2.7866a4.4992 4.4992 0 0 1 6.6802 4.66zM8.3065 12.863l-2.02-1.1638a.0804.0804 0 0 1-.038-.0567V6.0742a4.4992 4.4992 0 0 1 7.3757-3.4537l-.142.0805L8.704 5.459a.7948.7948 0 0 0-.3927.6813zm1.0976-2.3654l2.602-1.4998 2.6069 1.4998v2.9994l-2.5974 1.4997-2.6067-1.4997Z"})})}function et({className:e}){return z("svg",{viewBox:"0 0 24 24","aria-hidden":"true",focusable:"false",className:e,children:z("path",{d:"M4 5h16v11H4zM9 20h6M12 16v4",fill:"none",stroke:"currentColor",strokeWidth:"2",strokeLinecap:"round",strokeLinejoin:"round"})})}var tt={claude:Xe,chatgpt:Qe,local:et};var pe=[{id:"claude",label:"Continue with Claude",title:"The Claude plan you already pay for",cost:"Nothing beyond the plan",prerequisite:"Claude Code installed, and signed in",hint:"Install it from claude.ai/code, then run `claude` once and sign in.",expects:["claude-code"]},{id:"chatgpt",label:"Continue with ChatGPT",title:"The ChatGPT plan you already pay for",cost:"Nothing beyond the plan",prerequisite:"Codex installed, and signed in",hint:"Install Codex, then run `codex` once and sign in.",expects:["codex"]},{id:"local",label:"Use a model on this machine",title:"A model on your own machine",cost:"Free. You bought the hardware",prerequisite:"Ollama running, with a model pulled",hint:"Install Ollama, then `ollama pull` a model before pairing.",expects:["ollama","openai-api"]}];var nt="soba.connect.choice",Nt=180*24*60*60*1e3;function kt(e){let t=2166136261;for(let n=0;n<e.length;n++)t^=e.charCodeAt(n),t=Math.imul(t,16777619);return(t>>>0).toString(36)}function Re(e,t){return e?t?`${nt}.${e}.${kt(t)}`:`${nt}.${e}`:null}function Te(e){if(!e||typeof localStorage>"u")return null;try{let t=localStorage.getItem(e);if(!t)return null;let n=JSON.parse(t);if(Date.now()-Date.parse(n.at)>Nt)return null;let o=pe.find(s=>s.id===n.choice);return o?o.id:null}catch{return null}}function Ie(e,t){if(!(!e||typeof localStorage>"u"))try{localStorage.setItem(e,JSON.stringify({choice:t,at:new Date().toISOString()}))}catch{}}function Ae(e,t){if(!e)return{kind:"unasked"};if(!t)return{kind:"bare"};let n=t.runtimes??[];if(n.length===0)return{kind:"bare"};let o=n.find(s=>e.expects.includes(s.id));return o?o.quarantined?{kind:"held",runtime:o}:o.authenticated===!1?{kind:"signed-out",runtime:o}:o.authenticated===null||o.authenticated===void 0?{kind:"unsure",runtime:o}:{kind:"matched",runtime:o}:{kind:"missing",found:n}}function Oe(e){return e.kind!=="bare"&&e.kind!=="missing"}function Le(e){return e.kind==="matched"||e.kind==="signed-out"||e.kind==="unsure"||e.kind==="held"}import{Fragment as ot,jsx as c,jsxs as b}from"react/jsx-runtime";var st=2e3,Et=1e4,_t=15e3,Mt=9e4;function Rt(e){let t=Math.max(0,Math.round(e/1e3));return`${Math.floor(t/60)}:${String(t%60).padStart(2,"0")}`}function $e({client:e,initialCode:t,onConnected:n,showStatus:o=!0,initialContext:s=null,initialMachines:r,onClose:m,headingId:h,theme:u}){let v=!!s&&r!==void 0,[d,a]=L(v?t?"code":o&&(r?.length??0)>0?"manage":"choose":"loading"),[f,R]=L(s),[w,T]=L(r??[]),[x,I]=L(null),[N,Y]=L(t??""),[g,B]=L(null),[j,U]=L(null),[V,q]=L(!1),[H,ke]=L(0),[K,ae]=L(()=>Date.now()),[ie,fe]=L(null),[X,Se]=L(null),Q=St(),ee=h??Q,te=Pt(null);W(()=>{if(!e||v)return;let i=!0;return Promise.all([e.context(),e.machines()]).then(([C,P])=>{i&&(R(C),T(P),t?a("code"):o&&P.length>0?a("manage"):a("choose"))}).catch(C=>{i&&(U(C.message),a("choose"))}),()=>{i=!1}},[e,t,o,v]),W(()=>{r&&T(r)},[r]),W(()=>{if(!e||d!=="manage")return;let i=!0,C=setInterval(async()=>{try{let P=await e.machines();i&&T(P)}catch{}},Et);return()=>{i=!1,clearInterval(C)}},[d,e]),W(()=>{if(!e||d!=="waiting")return;let i=!0,C=setInterval(async()=>{try{let P=await e.machines();if(!i)return;T(P);let ne=te.current;if(!ne)return;let l=P.filter(A=>!ne.has(A.id)),k=l.find(A=>A.state!=="offline")??l[0];k&&(Se(k.id),a("connected"),n?.(P))}catch{}},st);return()=>{i=!1,clearInterval(C)}},[d,e,n]);let ce=ve(async()=>{if(e){U(null),q(!0);try{let i=await e.lookup(N);B(i),a("confirm")}catch(i){U(i.message)}finally{q(!1)}}},[e,N]),ge=ve(async()=>{if(e){U(null),q(!0);try{try{te.current=new Set((await e.machines()).map(i=>i.id))}catch{te.current=new Set(w.map(i=>i.id))}await e.approve(N),a("waiting"),ke(Date.now())}catch(i){U(i.message)}finally{q(!1)}}},[e,N,w]),be=ve(async()=>{if(e){q(!0);try{await e.deny(N),a("denied")}catch(i){U(i.message)}finally{q(!1)}}},[e,N]),le=me(()=>f?.connect_url??null,[f]),D=me(()=>Re(f?.publishable_key??null),[f?.publishable_key]);W(()=>fe(Te(D)),[D]);let S=me(()=>w.find(i=>i.id===X),[w,X]),p=me(()=>Ae(x,S),[x,S]);W(()=>{if(!e||d!=="connected"||Oe(p))return;let i=Date.now()+_t,C=setInterval(async()=>{if(Date.now()>i)return clearInterval(C);try{T(await e.machines())}catch{}},st);return()=>clearInterval(C)},[e,d,p]),W(()=>{d!=="connected"||!x||Le(p)&&Ie(D,x.id)},[d,x,p,D]);let E=me(()=>{if(!g)return null;if(g.approved||g.denied)return"answered";let i=g.expires_at?Date.parse(g.expires_at):Number.NaN;return Number.isFinite(i)&&i<=K?"expired":"live"},[g,K]);function F({verdict:i,choice:C}){if(i.kind==="unasked"||i.kind==="matched")return null;if(i.kind==="signed-out")return b("p",{className:"sc-note sc-tone-warn",children:[i.runtime.display_name," is on that machine but"," ",i.runtime.auth_hint??"signed out",". ",C?.hint]});if(i.kind==="unsure")return b("p",{className:"sc-note",children:[i.runtime.display_name," is there. We could not tell whether it is signed in \u2014 the first run will say for certain."]});if(i.kind==="held")return b("p",{className:"sc-note sc-tone-warn",children:[i.runtime.display_name," appeared after pairing, so it is waiting for you to let it serve."]});if(i.kind==="missing"){let P=i.found.map(ne=>ne.display_name).join(", ");return b("p",{className:"sc-note sc-tone-warn",children:["That machine is not advertising ",C?.prerequisite.split(",")[0]??"what you picked",". It has ",P,", and runs will go there instead. ",C?.hint]})}return c("p",{className:"sc-note sc-tone-warn",children:"No runtime advertised yet. Install Claude Code, Codex or Ollama on that machine and it will appear here."})}W(()=>{if(!(d==="confirm"&&E==="live"||d==="waiting"))return;let C=setInterval(()=>ae(Date.now()),1e3);return()=>clearInterval(C)},[d,E]);let ue=ve(async(i,C)=>{if(e)try{await e.approveRuntime(i,C),T(await e.machines())}catch(P){U(P.message)}},[e]);return d==="loading"?c("div",{className:"soba-connect",...u?{"data-theme":u}:{},children:c("div",{className:"sc-card",children:c("p",{className:"sc-note",children:"Loading\u2026"})})}):b("div",{className:"soba-connect",...u?{"data-theme":u}:{},children:[m&&c("button",{type:"button",className:"sc-modal-close",onClick:m,"aria-label":"Close",children:"\xD7"}),d==="manage"&&b("div",{className:"sc-card",children:[c("h2",{className:"sc-title",children:"Your compute"}),b("p",{className:"sc-sub",children:[f?.app.name??"This app"," runs on these machines, while they are awake."]}),c(G,{machines:w,onApproveRuntime:ue}),j&&c("p",{className:"sc-error",children:j}),c("button",{type:"button",className:"sc-btn",style:{marginTop:16},onClick:()=>a("choose"),children:"Connect another machine"})]}),d==="choose"&&b("div",{className:"sc-card",children:[c("span",{className:"sc-mark","aria-hidden":"true",children:c(Me,{})}),c("h2",{className:"sc-h",id:ee,children:"Connect your AI"}),c("p",{className:"sc-p",children:"Use access you already have. Nothing here is charged to you."}),c("div",{className:"sc-opts",children:pe.map(i=>{let C=tt[i.id];return b("button",{type:"button",className:"sc-opt","aria-pressed":x?.id===i.id,onClick:()=>I(i),children:[C&&c(C,{className:"sc-opt-mark"}),c("span",{className:"sc-opt-label",children:i.label}),ie===i.id&&c("span",{className:"sc-opt-last",children:"last used"})]},i.id)})}),x&&b("div",{className:"sc-stack",style:{marginTop:16},children:[c("p",{className:"sc-note",children:x.hint}),le?b(ot,{children:[c("p",{className:"sc-label",children:"Install Soba Connect on the machine you want to use"}),c("a",{className:"sc-btn sc-btn-primary",href:"https://soba.so/soba-connect",target:"_blank",rel:"noreferrer noopener",children:"Get Soba Connect"}),c("p",{className:"sc-label",children:"Then paste this link into it"}),c("code",{className:"sc-code",children:le}),c("p",{className:"sc-note",children:"It will show you a short code. Nothing is pasted back: the credential is written straight to that machine."}),c("button",{type:"button",className:"sc-btn",onClick:()=>a("code"),children:"I have a code"})]}):c("p",{className:"sc-error",children:"This app has no publishable key yet, so there is nothing to pair against."})]})]}),d==="code"&&b("div",{className:"sc-card",children:[c("h2",{className:"sc-title",children:"Enter the code from that machine"}),c("p",{className:"sc-sub",children:"Eight characters, shown by Soba Connect once you paste the link."}),b("form",{className:"sc-stack",onSubmit:i=>{i.preventDefault(),ce()},children:[c("input",{className:"sc-input",value:N,onChange:i=>Y(i.target.value),placeholder:"ACDE-F234",autoComplete:"off",autoFocus:!0,"aria-label":"Pairing code"}),j&&c("p",{className:"sc-error",children:j}),c("button",{type:"submit",className:"sc-btn sc-btn-primary",disabled:V||N.length<8,children:V?"Checking\u2026":"Continue"})]})]}),d==="confirm"&&g&&b("div",{className:"sc-card",children:[c("h2",{className:"sc-title",children:"Attach this machine to your account?"}),b("p",{className:"sc-sub",children:["Once you approve, ",f?.app.name??"this app"," may send your runs to it. It can never see the account or the keys on it."]}),b("ul",{className:"sc-facts",children:[c(he,{k:"Code",v:g.user_code}),c(he,{k:"Machine",v:g.hostname??"not stated"}),c(he,{k:"System",v:[g.platform,g.arch].filter(Boolean).join(" / ")||"not stated"}),c(he,{k:"Asked by",v:g.client??"not stated"}),g.labels.length>0&&c(he,{k:"Labels",v:g.labels.join(", ")})]}),c("p",{className:"sc-note",style:{marginTop:12},children:"Every line above is what that machine said about itself. If none of it looks like a computer of yours, say no."}),E==="expired"&&c("p",{className:"sc-error",children:"That code has expired. Ask the machine for a new one \u2014 it prints a fresh code each time it starts."}),E==="answered"&&c("p",{className:"sc-error",children:"That code has already been answered. If it was not you, deny the next one."}),j&&c("p",{className:"sc-error",children:j}),b("div",{className:"sc-row",style:{marginTop:16},children:[c("button",{type:"button",className:"sc-btn sc-btn-primary",onClick:()=>void ge(),disabled:V||E!=="live",children:"Approve"}),c("button",{type:"button",className:"sc-btn",onClick:()=>void be(),disabled:V||E==="answered",children:"No, deny it"}),c("button",{type:"button",className:"sc-btn sc-btn-quiet",onClick:()=>a("code"),disabled:V,children:"Back"})]}),E==="live"&&g.expires_at&&b("p",{className:"sc-note",style:{marginTop:10},children:["This code expires in ",Rt(Date.parse(g.expires_at)-K),"."]})]}),d==="waiting"&&b("div",{className:"sc-card",children:[c("h2",{className:"sc-title",id:ee,children:"Approved. Waiting for it to connect\u2026"}),c("p",{className:"sc-sub",children:"The worker is starting on that machine. This page will change on its own the moment it arrives."}),c("p",{className:"sc-note",children:"If nothing happens, look at Soba Connect on that machine: it says what it is doing."}),H>0&&K-H>Mt&&b("div",{className:"sc-stack",style:{marginTop:14},children:[c("p",{className:"sc-note sc-tone-warn",children:"Still nothing. Soba Connect may not be running on that machine, or it may not have finished starting. This keeps watching either way."}),c("button",{type:"button",className:"sc-btn",onClick:()=>a("choose"),children:"Start over"})]})]}),d==="connected"&&b("div",{className:"sc-card",children:[c("h2",{className:"sc-title",id:ee,children:"Connected"}),b("p",{className:"sc-sub",children:[f?.app.name??"This app"," will use this machine from now on, while it is awake."]}),c(F,{verdict:p,choice:x}),o&&b(ot,{children:[c(G,{machines:w,onApproveRuntime:ue}),c("button",{type:"button",className:"sc-btn",style:{marginTop:16},onClick:()=>a("manage"),children:"Done"})]})]}),d==="denied"&&b("div",{className:"sc-card",children:[c("h2",{className:"sc-title",id:ee,children:"Declined"}),c("p",{className:"sc-sub",children:"That machine was not attached to your account, and the terminal has been told so."}),c("button",{type:"button",className:"sc-btn",style:{marginTop:16},onClick:()=>a("choose"),children:"Back to the start"})]})]})}function he({k:e,v:t}){return b("li",{className:"sc-fact",children:[c("span",{className:"sc-fact-key",children:e}),c("span",{children:t})]})}import{useEffect as Tt,useRef as qe}from"react";var Ce=0,Ue=null;function rt(){if(typeof document>"u")return()=>{};Ce===0&&(Ue=document.body.style.overflow,document.body.style.overflow="hidden"),Ce+=1;let e=!1;return()=>{e||(e=!0,Ce-=1,Ce===0&&(document.body.style.overflow=Ue??"",Ue=null))}}import{jsx as at}from"react/jsx-runtime";function Be({open:e,onClose:t,labelledBy:n,theme:o,children:s}){let r=qe(null),m=qe(null),h=qe(null);return Tt(()=>{let u=r.current;if(u){if(!e){u.open&&u.close();return}return u.open||u.showModal(),document.activeElement===u&&m.current?.focus(),rt()}},[e]),at("dialog",{ref:r,className:"soba-connect sc-modal","aria-labelledby":n,...o?{"data-theme":o}:{},onCancel:u=>{u.preventDefault(),t()},onPointerDown:u=>{h.current=u.target},onClick:u=>{u.target===u.currentTarget&&h.current===u.currentTarget&&t()},children:at("div",{className:"sc-modal-sheet",ref:m,tabIndex:-1,children:s})})}import{createContext as It,useContext as At}from"react";var De=It(null);function _(){let e=At(De);if(!e)throw new Error("useSoba() must be used inside a <SobaProvider>.");return e}import{jsx as oe}from"react/jsx-runtime";function Ot({className:e}){let{compute:t}=_(),n=e?`soba-connect ${e}`:"soba-connect";return t.loading&&!t.machines.length?oe("div",{className:n,children:oe("p",{className:"sc-note",children:"Loading\u2026"})}):t.error&&!t.machines.length?oe("div",{className:n,children:oe("p",{className:"sc-error",children:t.error.message})}):oe("div",{className:n,children:oe(G,{machines:t.machines})})}import{useEffect as $t,useRef as dt,useState as Ut}from"react";import{useId as Lt}from"react";import{createContext as it,useContext as ct}from"react";var Fe=it(null);function lt(){return ct(Fe)}var je=it({context:null,machines:void 0,theme:"light"});function ut(){return ct(je)}import{jsx as re,jsxs as Ve}from"react/jsx-runtime";function He({open:e,onOpenChange:t,initialCode:n,onConnected:o,showStatus:s}){let{error:r}=_(),m=lt(),h=ut(),u=()=>t(!1),v=Lt();return Ve(Be,{open:e,onClose:u,labelledBy:v,theme:h.theme,children:[r?Ve("div",{className:"sc-card",children:[re("h2",{className:"sc-title",id:v,children:"Could not start"}),re("p",{className:"sc-error",children:r.message})]}):!m&&!h.context?Ve("div",{className:"sc-card",children:[re("h2",{className:"sc-title",id:v,children:"One moment"}),re("p",{className:"sc-note",children:"Getting your compute\u2026"})]}):re($e,{client:m,onClose:u,headingId:v,theme:h.theme,initialContext:h.context,...h.machines!==void 0?{initialMachines:h.machines}:{},...n?{initialCode:n}:{},...o?{onConnected:o}:{},...s===void 0?{}:{showStatus:s}}),re("p",{className:"sc-modal-foot",children:"Secured by Soba"})]})}import{Fragment as pt,jsx as Ge,jsxs as mt}from"react/jsx-runtime";function ze({children:e,variant:t,className:n,initialCode:o,onConnected:s,defaultOpen:r,open:m,onOpenChange:h,showConnected:u=!0}){let{compute:v}=_(),[d,a]=Ut(r??!!o),f=dt(null),R=m!==void 0,w=R?m:d,T=B=>{R||a(B),h?.(B)},x=dt(w);$t(()=>{x.current&&!w&&f.current?.focus(),x.current=w},[w]);let I=v.machines.find(B=>B.state!=="offline")??v.machines[0],N=I?.runtimes?.find(B=>!B.quarantined)??I?.runtimes?.[0],Y=u&&I!==void 0,g=I?.state==="online"?"ok":I?.state==="busy"?"busy":"off";return mt(pt,{children:[Ge("button",{ref:f,type:"button",className:["sc-btn",Y?"sc-btn-connected":t==="outline"?"":"sc-btn-primary",n].filter(Boolean).join(" "),onClick:()=>T(!0),children:e??(Y?mt(pt,{children:[Ge("i",{className:`sc-dot sc-dot-${g}`,"aria-hidden":"true"}),N?.display_name??"Connected",I?.label?` \xB7 ${I.label}`:""]}):"Connect compute")}),Ge(He,{open:w,onOpenChange:T,...o?{initialCode:o}:{},...s?{onConnected:s}:{}})]})}import{jsx as We,jsxs as Bt}from"react/jsx-runtime";function qt({initialCode:e,onConnected:t,className:n,showStatus:o=!0}){let{compute:s}=_(),r=s.machines.length>0;return Bt("div",{className:n?`soba-connect ${n}`:"soba-connect",children:[o&&We(G,{machines:s.machines}),We("div",{style:{marginTop:o&&r?14:0},children:We(ze,{variant:o&&r?"outline":"primary",...e?{initialCode:e}:{},...t?{onConnected:t}:{}})})]})}var Dt=new Set(["delta","thinking","status","done","error"]);function we(e){let t;try{t=JSON.parse(e)}catch{return null}if(!t||typeof t!="object")return null;let n=t,o=n.type==="event"?n.event:n;if(!o||typeof o!="object")return null;let s=o;if(typeof s.type!="string"||!Dt.has(s.type))return null;let r={type:s.type};return typeof s.text=="string"&&(r.text=s.text),typeof s.message=="string"&&(r.message=s.message),typeof s.tool=="string"&&(r.tool=s.tool),typeof s.tier=="string"&&(r.tier=s.tier),s.usage&&typeof s.usage=="object"&&(r.usage=s.usage),r}async function*Ke(e){let t=e.body;if(!t)throw new Error("That run response had no body to stream.");let n=(e.headers.get("content-type")??"").includes("ndjson"),o=t.getReader(),s=new TextDecoder,r="",m=[];try{for(;;){let u=await o.read();if(u.done)break;for(r+=s.decode(u.value,{stream:!0});;){let v=r.indexOf(`
3
- `);if(v===-1)break;let d=ft(r.slice(0,v));if(r=r.slice(v+1),n){let a=d.trim()?we(d):null;a&&(yield a);continue}if(d===""){let a=m.join(`
4
- `);if(m=[],a==="[DONE]")return;let f=a?we(a):null;f&&(yield f);continue}ht(d,m)}}!n&&r&&ht(ft(r),m);let h=n?r.trim():m.join(`
5
- `);if(h&&h!=="[DONE]"){let u=we(h);u&&(yield u)}}finally{o.cancel().catch(()=>{})}}function ht(e,t){if(!e||e.startsWith(":"))return;let n=e.indexOf(":");if(n===-1||e.slice(0,n)!=="data")return;let o=e.slice(n+1);t.push(o.startsWith(" ")?o.slice(1):o)}function ft(e){return e.endsWith("\r")?e.slice(0,-1):e}async function Ft(e){let t="";for await(let n of e)if(n.type==="delta"&&n.text&&(t+=n.text),n.type==="error")throw new Error(n.message??"The run ended with an error.");return t}import{useState as gt}from"react";import{jsx as bt,jsxs as Vt}from"react/jsx-runtime";function jt({plan:e,successUrl:t,cancelUrl:n,label:o,className:s}){let{plan:r}=_(),[m,h]=gt(!1),[u,v]=gt(null);async function d(){h(!0),v(null);try{let a=await r.checkout(e.id,{...t?{successUrl:t}:{},...n?{cancelUrl:n}:{}});window.location.assign(a)}catch(a){v(a.message),h(!1)}}return Vt("div",{className:s?`soba-connect ${s}`:"soba-connect",children:[bt("button",{type:"button",className:"sc-btn sc-btn-primary",disabled:m,onClick:()=>void d(),children:m?"Opening\u2026":o??`Subscribe \u2014 $${e.price.toLocaleString()}/${e.interval}`}),u&&bt("p",{className:"sc-error",children:u})]})}import{useState as yt}from"react";import{Fragment as Wt,jsx as y,jsxs as M}from"react/jsx-runtime";var Ht={"user-hardware":"your own machine","user-subscription":"your own AI subscription","open-weights":"open models we host",frontier:"frontier models"},Gt=new Set(["user-hardware","user-subscription"]);function xe(e){return e?`soba-connect ${e}`:"soba-connect"}function zt({onSelect:e,successUrl:t,cancelUrl:n,showCompute:o=!0,className:s}){let{plan:r}=_(),[m,h]=yt(null),[u,v]=yt(null);if(r.error)return y("div",{className:xe(s),children:y("div",{className:"sc-card",children:y("p",{className:"sc-error",children:r.error.message})})});if(r.loading)return y("div",{className:xe(s),children:y("div",{className:"sc-card",children:y("p",{className:"sc-note",children:"Loading plans\u2026"})})});if(r.plans.length===0)return y("div",{className:xe(s),children:y("div",{className:"sc-card",children:y("p",{className:"sc-note",children:"This app has no plans yet."})})});async function d(a){h(a.id),v(null);try{if(a.selectable)await r.select(a.id);else if(e)e(a);else{let f=await r.checkout(a.id,{...t?{successUrl:t}:{},...n?{cancelUrl:n}:{}});window.location.assign(f);return}}catch(f){v(f.message)}finally{h(null)}}return M("div",{className:xe(s),children:[y("div",{className:"sc-plans",children:r.plans.map(a=>{let f=r.current?.plan_id===a.id;return M("div",{className:f?"sc-plan sc-plan-current":"sc-plan",children:[M("div",{className:"sc-row-between",children:[y("span",{className:"sc-title",children:a.name}),f&&y("span",{className:"sc-plan-badge",children:"Current"})]}),a.description&&y("p",{className:"sc-sub",children:a.description}),y("p",{className:"sc-plan-price",children:a.price===0?y("span",{className:"sc-plan-amount",children:"Free"}):M(Wt,{children:[M("span",{className:"sc-plan-amount",children:["$",a.price.toLocaleString()]}),M("span",{className:"sc-plan-interval",children:["/",a.interval]})]})}),M("div",{className:"sc-facts",children:[M("div",{className:"sc-fact",children:[y("span",{className:"sc-fact-key",children:"Included"}),y("span",{children:a.included_units===null?"Unlimited":`${a.included_units.toLocaleString()} ${a.unit}${a.included_units===1?"":"s"}`})]}),a.overage_per_unit>0&&M("div",{className:"sc-fact",children:[y("span",{className:"sc-fact-key",children:"Then"}),M("span",{children:["$",a.overage_per_unit," / ",a.unit]})]}),a.trial_days>0&&M("div",{className:"sc-fact",children:[y("span",{className:"sc-fact-key",children:"Trial"}),M("span",{children:[a.trial_days," days"]})]}),o&&M("div",{className:"sc-plan-compute",children:[y("span",{className:"sc-fact-key",children:"Runs on"}),a.route_allow===null||a.route_allow.length===0?y("span",{children:a.route_allow===null?"any compute":"no compute"}):y("ul",{className:"sc-compute",children:a.route_allow.map(R=>y("li",{className:Gt.has(R)?"sc-compute-own":void 0,children:Ht[R]??R},R))})]})]}),y("button",{type:"button",className:f?"sc-btn":"sc-btn sc-btn-primary",disabled:f||m!==null,onClick:()=>void d(a),children:f?"Your plan":m===a.id?a.selectable?"Switching\u2026":"Opening\u2026":a.selectable?"Choose":`Subscribe \u2014 $${a.price.toLocaleString()}/${a.interval}`})]},a.id)})}),u&&y("p",{className:"sc-error",children:u})]})}import{useCallback as J,useEffect as Z,useMemo as Ze,useRef as Jt,useState as $}from"react";var Ne=class{#t;#s=null;#n=null;#e;#o=new Set;constructor(t){this.#e=t,this.#t=t.token??null}get token(){return this.#t}get expiresAt(){return this.#s}get canRefresh(){return!!this.#e.endpoint}get refreshAt(){return!this.canRefresh||this.#s===null?null:Math.max(Date.now()+1e4,this.#s-6e4)}subscribe(t){return this.#o.add(t),()=>this.#o.delete(t)}async ensure(){return this.#t?this.#t:this.refresh()}async refresh(){if(this.#n)return this.#n;let t=this.#e.endpoint;if(!t)throw new Error("This Soba session cannot be refreshed. Pass `sessionEndpoint` so the provider can mint a new one.");let n=this.#e.fetchImpl??fetch.bind(globalThis);this.#n=(async()=>{let o=await n(t,{method:"POST",headers:{"content-type":"application/json"},credentials:"same-origin",body:JSON.stringify(this.#e.user?{user:this.#e.user}:{})});if(!o.ok)throw new Error(`Could not start a Soba session (${o.status} from ${t}).`);let s=await o.json(),r=s.session??s.token;if(!r)throw new Error(`${t} answered without a \`session\`. See @soba-so/react's README.`);let m=s.expires_in??s.expiresIn;this.#t=r,this.#s=typeof m=="number"?Date.now()+m*1e3:null;for(let h of this.#o)h();return r})();try{return await this.#n}finally{this.#n=null}}};function vt(e,t=fetch.bind(globalThis)){return async(n,o)=>{let s=await t(n,o);if(s.status!==401||!e.canRefresh)return s;let r;try{r=await e.refresh()}catch{return s}return t(n,Kt(o,r))}}function Kt(e,t){let n=new Headers(e?.headers);return n.set("authorization",`Bearer ${t}`),{...e,headers:n}}var Ct="data-soba-react",wt=!1;function Je(){if(wt||typeof document>"u"||(wt=!0,document.querySelector(`style[${Ct}]`)))return;let e=document.createElement("style");e.setAttribute(Ct,""),e.textContent=`.soba-connect {
2
+ var be=class extends Error{status;constructor(t,n){super(t),this.name="ConnectError",this.status=n}},le=class{session;baseUrl;doFetch;constructor(t){this.session=t.session,this.baseUrl=(t.baseUrl??"").replace(/\/+$/,""),this.doFetch=t.fetchImpl??fetch.bind(globalThis)}context(){return this.request("GET","/v1/connect")}async machines(){return(await this.request("GET","/v1/machines")).machines}lookup(t){return this.request("GET",`/v1/device/lookup?code=${encodeURIComponent(t)}`)}approve(t){return this.request("POST","/v1/device/approve",{user_code:t})}deny(t){return this.request("POST","/v1/device/deny",{user_code:t})}plans(){return this.request("GET","/v1/plans")}selectPlan(t){return this.request("POST","/v1/plans/select",{plan:t})}checkoutPlan(t,n){return this.request("POST","/v1/plans/checkout",{plan:t,...n?.successUrl?{success_url:n.successUrl}:{},...n?.cancelUrl?{cancel_url:n.cancelUrl}:{}})}leavePlan(){return this.request("DELETE","/v1/plans/select")}approveRuntime(t,n){return this.request("POST","/v1/runtimes/approve",{machine_id:t,runtime_id:n})}async request(t,n,i){let s=await this.doFetch(`${this.baseUrl}${n}`,{method:t,headers:{authorization:`Bearer ${this.session}`,...i?{"content-type":"application/json"}:{}},...i?{body:JSON.stringify(i)}:{}}),o={};try{o=await s.json()}catch{}if(!s.ok){let d=typeof o.error=="string"?o.error:`Request failed (${s.status})`;throw new be(d,s.status)}return o}};function Pe(e){return e.authenticated===!0?{tone:"ok",text:"signed in"}:e.authenticated===!1?{tone:"warn",text:e.auth_hint??"signed out on that machine"}:{tone:"unknown",text:"could not tell"}}function Ee(e){return e.state==="busy"?{tone:"busy",text:`serving ${e.active} of ${e.capacity}`}:e.state==="online"?{tone:"ok",text:"connected"}:{tone:"off",text:"asleep or offline"}}import{jsx as L,jsxs as X}from"react/jsx-runtime";function H({machines:e,onApproveRuntime:t}){return e.length?L("div",{children:e.map(n=>{let i=Ee(n);return X("div",{className:"sc-machine",children:[X("div",{className:"sc-row-between",children:[X("div",{className:"sc-row",children:[L("span",{className:`sc-dot sc-dot-${i.tone}`,"aria-hidden":"true"}),L("strong",{children:n.label??"This machine"})]}),L("span",{className:"sc-note",children:i.text})]}),L("p",{className:"sc-note",children:[n.platform,n.arch,n.version&&`worker ${n.version}`,n.always_on&&"always on"].filter(Boolean).join(" \xB7 ")}),X("ul",{className:"sc-runtimes",children:[n.runtimes.map(s=>{let o=Pe(s);return s.quarantined?X("li",{className:"sc-row-between",children:[L("span",{children:s.display_name}),t?L("button",{type:"button",className:"sc-btn",onClick:()=>t(n.id,s.id),children:"New here. Let it serve"}):L("span",{className:"sc-tone-warn",children:"new, not serving yet"})]},s.id):X("li",{className:"sc-row-between",children:[L("span",{children:s.display_name}),L("span",{className:`sc-tone-${o.tone}`,children:o.text})]},s.id)}),!n.runtimes.length&&L("li",{className:"sc-note",children:"No runtime advertised. Install Claude Code, Codex or Ollama on that machine."})]})]},n.id)})}):L("p",{className:"sc-note",children:"Nothing connected yet."})}import{useCallback as de,useEffect as pe,useId as mt,useMemo as ye,useRef as ht,useState as U}from"react";var Ge="soba";function ze(e){return`${Ge}://connect?url=${encodeURIComponent(e)}`}var dt=1600;async function Me(e,t={}){if(typeof window>"u"||typeof document>"u")return"unknown";let n=t.graceMs??dt,i=document.visibilityState==="visible"&&document.hasFocus(),s=!1,o=()=>{s=!0},d=()=>{document.visibilityState==="hidden"&&(s=!0)};window.addEventListener("blur",o),window.addEventListener("pagehide",o),document.addEventListener("visibilitychange",d);try{window.location.href=ze(e)}catch{return"absent"}return await new Promise(p=>setTimeout(p,n)),window.removeEventListener("blur",o),window.removeEventListener("pagehide",o),document.removeEventListener("visibilitychange",d),i?s?"opened":"absent":"unknown"}import{jsx as We,jsxs as pt}from"react/jsx-runtime";function ue({className:e}){return pt("svg",{viewBox:"0 0 24 24","aria-hidden":"true",focusable:"false",className:e,children:[We("path",{d:"M18.125 7.039A8.6 8.6 0 1 0 18.125 16.961A6 6 0 0 1 18.125 7.039Z",fill:"currentColor"}),We("path",{d:"M19.925 7.039A8.6 8.6 0 0 1 19.925 16.961A6 6 0 0 0 19.925 7.039Z",fill:"currentColor"})]})}import{Fragment as Ct,jsx as a,jsxs as v}from"react/jsx-runtime";var ft=2e3,gt=1e4,bt=9e4,yt="/c/";function vt(e){let t=Math.max(0,Math.round(e/1e3));return`${Math.floor(t/60)}:${String(t%60).padStart(2,"0")}`}function _e({client:e,initialCode:t,onConnected:n,showStatus:i=!0,initialContext:s=null,initialMachines:o,onClose:d,headingId:p,theme:u}){let y=!!s&&o!==void 0,[m,r]=U(y?t?"code":i&&(o?.length??0)>0?"manage":"choose":"loading"),[g,R]=U(s),[C,$]=U(o??[]),[S,T]=U(t??""),[f,W]=U(null),[k,N]=U(null),[B,I]=U(!1),[te,J]=U(0),[q,Se]=U(()=>Date.now()),[Z,K]=U(null),[Y,he]=U(null),ne=mt(),V=p??ne,F=ht(null);pe(()=>{if(!e||y)return;let c=!0;return Promise.all([e.context(),e.machines()]).then(([x,E])=>{c&&(R(x),$(E),t?r("code"):i&&E.length>0?r("manage"):r("choose"))}).catch(x=>{c&&(N(x.message),r("choose"))}),()=>{c=!1}},[e,t,i,y]),pe(()=>{o&&$(o)},[o]),pe(()=>{if(!e||m!=="manage")return;let c=!0,x=setInterval(async()=>{try{let E=await e.machines();c&&$(E)}catch{}},gt);return()=>{c=!1,clearInterval(x)}},[m,e]),pe(()=>{if(!e||m!=="waiting")return;let c=!0,x=setInterval(async()=>{try{let E=await e.machines();if(!c)return;$(E);let re=F.current;if(!re)return;let ae=E.filter(ce=>!re.has(ce.id)),ie=ae.find(ce=>ce.state!=="offline")??ae[0];ie&&(he(ie.id),r("connected"),n?.(E))}catch{}},ft);return()=>{c=!1,clearInterval(x)}},[m,e,n]);let Ne=de(async()=>{if(e){N(null),I(!0);try{let c=await e.lookup(S);W(c),r("confirm")}catch(c){N(c.message)}finally{I(!1)}}},[e,S]),fe=de(async()=>{if(e){N(null),I(!0);try{try{F.current=new Set((await e.machines()).map(c=>c.id))}catch{F.current=new Set(C.map(c=>c.id))}await e.approve(S),r("waiting"),J(Date.now())}catch(c){N(c.message)}finally{I(!1)}}},[e,S,C]),oe=de(async()=>{if(e){I(!0);try{await e.deny(S),r("denied")}catch(c){N(c.message)}finally{I(!1)}}},[e,S]),A=ye(()=>g?.connect_url??null,[g]),ge=ye(()=>{if(!A)return null;try{let c=new URL(A);return c.origin+yt+c.pathname.split("/").filter(Boolean).pop()}catch{return null}},[A]),se=de(async()=>{if(A){N(null),K(null),r("launch"),I(!0);try{K(await Me(A))}finally{I(!1)}}},[A]),D=ye(()=>C.find(c=>c.id===Y),[C,Y]),w=ye(()=>{if(!f)return null;if(f.approved||f.denied)return"answered";let c=f.expires_at?Date.parse(f.expires_at):Number.NaN;return Number.isFinite(c)&&c<=q?"expired":"live"},[f,q]);pe(()=>{if(!(m==="confirm"&&w==="live"||m==="waiting"))return;let x=setInterval(()=>Se(Date.now()),1e3);return()=>clearInterval(x)},[m,w]);let h=de(async(c,x)=>{if(e)try{await e.approveRuntime(c,x),$(await e.machines())}catch(E){N(E.message)}},[e]);return m==="loading"?a("div",{className:"soba-connect",...u?{"data-theme":u}:{},children:a("div",{className:"sc-card",children:a("p",{className:"sc-note",children:"Loading\u2026"})})}):v("div",{className:"soba-connect",...u?{"data-theme":u}:{},children:[d&&a("button",{type:"button",className:"sc-modal-close",onClick:d,"aria-label":"Close",children:"\xD7"}),m==="manage"&&v("div",{className:"sc-card",children:[a("h2",{className:"sc-title",children:"Your compute"}),v("p",{className:"sc-sub",children:[g?.app.name??"This app"," runs on these machines, while they are awake."]}),a(H,{machines:C,onApproveRuntime:h}),k&&a("p",{className:"sc-error",children:k}),a("button",{type:"button",className:"sc-btn",style:{marginTop:16},onClick:()=>r("choose"),children:"Connect another machine"})]}),m==="choose"&&v("div",{className:"sc-card",children:[a("span",{className:"sc-mark","aria-hidden":"true",children:a(ue,{})}),a("h2",{className:"sc-h",id:V,children:"Connect your AI"}),a("p",{className:"sc-p",children:"Use access you already have. Nothing here is charged to you."}),A?v("div",{className:"sc-stack",style:{marginTop:20},children:[v("button",{type:"button",className:"sc-opt sc-opt-primary",onClick:()=>void se(),children:[a(ue,{className:"sc-opt-mark"}),a("span",{className:"sc-opt-label",children:"Continue with Soba Connect"})]}),v("p",{className:"sc-note",children:["It runs on the machine you want to use and holds the credential there. Nothing you are signed into is sent to ",g?.app.name??"this app","."]}),a("button",{type:"button",className:"sc-btn",onClick:()=>r("code"),children:"I have a code"})]}):a("p",{className:"sc-error",children:"This app has no publishable key yet, so there is nothing to pair against."})]}),m==="launch"&&v("div",{className:"sc-card",children:[a("span",{className:"sc-mark","aria-hidden":"true",children:a(ue,{})}),a("h2",{className:"sc-h",id:V,children:Z==="absent"?"Soba Connect did not open":"Continue in Soba Connect\u2026"}),Z==="absent"?a("p",{className:"sc-p",children:"Nothing opened on this machine, so it is probably not installed here. Install it, or pair a different machine using the link below."}):a("p",{className:"sc-p",children:"It should be opening on this machine. Start the pairing there, and it will show you a short code to enter here."}),v("div",{className:"sc-stack",style:{marginTop:18},children:[Z==="absent"&&a("a",{className:"sc-btn sc-btn-primary",href:ge??"https://www.soba.so",target:"_blank",rel:"noreferrer noopener",children:"Get Soba Connect"}),a("button",{type:"button",className:"sc-btn",onClick:()=>r("code"),children:"I have a code"}),a("button",{type:"button",className:"sc-btn",disabled:B,onClick:()=>void se(),children:B?"Opening\u2026":"Try again"}),A&&v("details",{className:"sc-details",children:[a("summary",{children:"Pairing a different machine?"}),a("p",{className:"sc-label",children:"Paste this link into Soba Connect on that machine"}),a("code",{className:"sc-code",children:A}),a("p",{className:"sc-note",children:"It will show you a short code. Nothing is pasted back: the credential is written straight to that machine."})]})]})]}),m==="code"&&v("div",{className:"sc-card",children:[a("h2",{className:"sc-title",children:"Enter the code from that machine"}),a("p",{className:"sc-sub",children:"Eight characters, shown by Soba Connect once you paste the link."}),v("form",{className:"sc-stack",onSubmit:c=>{c.preventDefault(),Ne()},children:[a("input",{className:"sc-input",value:S,onChange:c=>T(c.target.value),placeholder:"ACDE-F234",autoComplete:"off",autoFocus:!0,"aria-label":"Pairing code"}),k&&a("p",{className:"sc-error",children:k}),a("button",{type:"submit",className:"sc-btn sc-btn-primary",disabled:B||S.length<8,children:B?"Checking\u2026":"Continue"})]})]}),m==="confirm"&&f&&v("div",{className:"sc-card",children:[a("h2",{className:"sc-title",children:"Attach this machine to your account?"}),v("p",{className:"sc-sub",children:["Once you approve, ",g?.app.name??"this app"," may send your runs to it. It can never see the account or the keys on it."]}),v("ul",{className:"sc-facts",children:[a(me,{k:"Code",v:f.user_code}),a(me,{k:"Machine",v:f.hostname??"not stated"}),a(me,{k:"System",v:[f.platform,f.arch].filter(Boolean).join(" / ")||"not stated"}),a(me,{k:"Asked by",v:f.client??"not stated"}),f.labels.length>0&&a(me,{k:"Labels",v:f.labels.join(", ")})]}),a("p",{className:"sc-note",style:{marginTop:12},children:"Every line above is what that machine said about itself. If none of it looks like a computer of yours, say no."}),w==="expired"&&a("p",{className:"sc-error",children:"That code has expired. Ask the machine for a new one \u2014 it prints a fresh code each time it starts."}),w==="answered"&&a("p",{className:"sc-error",children:"That code has already been answered. If it was not you, deny the next one."}),k&&a("p",{className:"sc-error",children:k}),v("div",{className:"sc-row",style:{marginTop:16},children:[a("button",{type:"button",className:"sc-btn sc-btn-primary",onClick:()=>void fe(),disabled:B||w!=="live",children:"Approve"}),a("button",{type:"button",className:"sc-btn",onClick:()=>void oe(),disabled:B||w==="answered",children:"No, deny it"}),a("button",{type:"button",className:"sc-btn sc-btn-quiet",onClick:()=>r("code"),disabled:B,children:"Back"})]}),w==="live"&&f.expires_at&&v("p",{className:"sc-note",style:{marginTop:10},children:["This code expires in ",vt(Date.parse(f.expires_at)-q),"."]})]}),m==="waiting"&&v("div",{className:"sc-card",children:[a("h2",{className:"sc-title",id:V,children:"Approved. Waiting for it to connect\u2026"}),a("p",{className:"sc-sub",children:"The worker is starting on that machine. This page will change on its own the moment it arrives."}),a("p",{className:"sc-note",children:"If nothing happens, look at Soba Connect on that machine: it says what it is doing."}),te>0&&q-te>bt&&v("div",{className:"sc-stack",style:{marginTop:14},children:[a("p",{className:"sc-note sc-tone-warn",children:"Still nothing. Soba Connect may not be running on that machine, or it may not have finished starting. This keeps watching either way."}),a("button",{type:"button",className:"sc-btn",onClick:()=>r("choose"),children:"Start over"})]})]}),m==="connected"&&v("div",{className:"sc-card",children:[a("h2",{className:"sc-title",id:V,children:D?.label?`${D.label} is connected`:"Connected"}),v("p",{className:"sc-sub",children:[g?.app.name??"This app"," will use ",D?.label?"it":"this machine"," from now on, while it is awake."]}),i&&v(Ct,{children:[a(H,{machines:C,onApproveRuntime:h}),a("button",{type:"button",className:"sc-btn",style:{marginTop:16},onClick:()=>r("manage"),children:"Done"})]})]}),m==="denied"&&v("div",{className:"sc-card",children:[a("h2",{className:"sc-title",id:V,children:"Declined"}),a("p",{className:"sc-sub",children:"That machine was not attached to your account, and the terminal has been told so."}),a("button",{type:"button",className:"sc-btn",style:{marginTop:16},onClick:()=>r("choose"),children:"Back to the start"})]})]})}function me({k:e,v:t}){return v("li",{className:"sc-fact",children:[a("span",{className:"sc-fact-key",children:e}),a("span",{children:t})]})}import{useEffect as wt,useRef as Te}from"react";var ve=0,Re=null;function Je(){if(typeof document>"u")return()=>{};ve===0&&(Re=document.body.style.overflow,document.body.style.overflow="hidden"),ve+=1;let e=!1;return()=>{e||(e=!0,ve-=1,ve===0&&(document.body.style.overflow=Re??"",Re=null))}}import{jsx as Ze}from"react/jsx-runtime";function Ie({open:e,onClose:t,labelledBy:n,theme:i,children:s}){let o=Te(null),d=Te(null),p=Te(null);return wt(()=>{let u=o.current;if(u){if(!e){u.open&&u.close();return}return u.open||u.showModal(),document.activeElement===u&&d.current?.focus(),Je()}},[e]),Ze("dialog",{ref:o,className:"soba-connect sc-modal","aria-labelledby":n,...i?{"data-theme":i}:{},onCancel:u=>{u.preventDefault(),t()},onPointerDown:u=>{p.current=u.target},onClick:u=>{u.target===u.currentTarget&&p.current===u.currentTarget&&t()},children:Ze("div",{className:"sc-modal-sheet",ref:d,tabIndex:-1,children:s})})}var pn=180*24*60*60*1e3;import{createContext as St,useContext as Nt}from"react";var Ae=St(null);function M(){let e=Nt(Ae);if(!e)throw new Error("useSoba() must be used inside a <SobaProvider>.");return e}import{jsx as Q}from"react/jsx-runtime";function kt({className:e}){let{compute:t}=M(),n=e?`soba-connect ${e}`:"soba-connect";return t.loading&&!t.machines.length?Q("div",{className:n,children:Q("p",{className:"sc-note",children:"Loading\u2026"})}):t.error&&!t.machines.length?Q("div",{className:n,children:Q("p",{className:"sc-error",children:t.error.message})}):Q("div",{className:n,children:Q(H,{machines:t.machines})})}import{useEffect as Et,useRef as et,useState as Mt}from"react";import{useId as Pt}from"react";import{createContext as Ke,useContext as Ye}from"react";var Le=Ke(null);function Xe(){return Ye(Le)}var Oe=Ke({context:null,machines:void 0,theme:"light"});function Qe(){return Ye(Oe)}import{jsx as ee,jsxs as $e}from"react/jsx-runtime";function Ue({open:e,onOpenChange:t,initialCode:n,onConnected:i,showStatus:s}){let{error:o}=M(),d=Xe(),p=Qe(),u=()=>t(!1),y=Pt();return $e(Ie,{open:e,onClose:u,labelledBy:y,theme:p.theme,children:[o?$e("div",{className:"sc-card",children:[ee("h2",{className:"sc-title",id:y,children:"Could not start"}),ee("p",{className:"sc-error",children:o.message})]}):!d&&!p.context?$e("div",{className:"sc-card",children:[ee("h2",{className:"sc-title",id:y,children:"One moment"}),ee("p",{className:"sc-note",children:"Getting your compute\u2026"})]}):ee(_e,{client:d,onClose:u,headingId:y,theme:p.theme,initialContext:p.context,...p.machines!==void 0?{initialMachines:p.machines}:{},...n?{initialCode:n}:{},...i?{onConnected:i}:{},...s===void 0?{}:{showStatus:s}}),ee("p",{className:"sc-modal-foot",children:"Secured by Soba"})]})}import{Fragment as tt,jsx as Be,jsxs as nt}from"react/jsx-runtime";function qe({children:e,variant:t,className:n,initialCode:i,onConnected:s,defaultOpen:o,open:d,onOpenChange:p,showConnected:u=!0}){let{compute:y}=M(),[m,r]=Mt(o??!!i),g=et(null),R=d!==void 0,C=R?d:m,$=N=>{R||r(N),p?.(N)},S=et(C);Et(()=>{S.current&&!C&&g.current?.focus(),S.current=C},[C]);let T=y.machines.find(N=>N.state!=="offline")??y.machines[0],f=T?.runtimes?.find(N=>!N.quarantined)??T?.runtimes?.[0],W=u&&T!==void 0,k=T?.state==="online"?"ok":T?.state==="busy"?"busy":"off";return nt(tt,{children:[Be("button",{ref:g,type:"button",className:["sc-btn",W?"sc-btn-connected":t==="outline"?"":"sc-btn-primary",n].filter(Boolean).join(" "),onClick:()=>$(!0),children:e??(W?nt(tt,{children:[Be("i",{className:`sc-dot sc-dot-${k}`,"aria-hidden":"true"}),f?.display_name??"Connected",T?.label?` \xB7 ${T.label}`:""]}):"Connect compute")}),Be(Ue,{open:C,onOpenChange:$,...i?{initialCode:i}:{},...s?{onConnected:s}:{}})]})}import{jsx as De,jsxs as Rt}from"react/jsx-runtime";function _t({initialCode:e,onConnected:t,className:n,showStatus:i=!0}){let{compute:s}=M(),o=s.machines.length>0;return Rt("div",{className:n?`soba-connect ${n}`:"soba-connect",children:[i&&De(H,{machines:s.machines}),De("div",{style:{marginTop:i&&o?14:0},children:De(qe,{variant:i&&o?"outline":"primary",...e?{initialCode:e}:{},...t?{onConnected:t}:{}})})]})}var Tt=new Set(["delta","thinking","status","done","error"]);function Ce(e){let t;try{t=JSON.parse(e)}catch{return null}if(!t||typeof t!="object")return null;let n=t,i=n.type==="event"?n.event:n;if(!i||typeof i!="object")return null;let s=i;if(typeof s.type!="string"||!Tt.has(s.type))return null;let o={type:s.type};return typeof s.text=="string"&&(o.text=s.text),typeof s.message=="string"&&(o.message=s.message),typeof s.tool=="string"&&(o.tool=s.tool),typeof s.tier=="string"&&(o.tier=s.tier),s.usage&&typeof s.usage=="object"&&(o.usage=s.usage),o}async function*Fe(e){let t=e.body;if(!t)throw new Error("That run response had no body to stream.");let n=(e.headers.get("content-type")??"").includes("ndjson"),i=t.getReader(),s=new TextDecoder,o="",d=[];try{for(;;){let u=await i.read();if(u.done)break;for(o+=s.decode(u.value,{stream:!0});;){let y=o.indexOf(`
3
+ `);if(y===-1)break;let m=st(o.slice(0,y));if(o=o.slice(y+1),n){let r=m.trim()?Ce(m):null;r&&(yield r);continue}if(m===""){let r=d.join(`
4
+ `);if(d=[],r==="[DONE]")return;let g=r?Ce(r):null;g&&(yield g);continue}ot(m,d)}}!n&&o&&ot(st(o),d);let p=n?o.trim():d.join(`
5
+ `);if(p&&p!=="[DONE]"){let u=Ce(p);u&&(yield u)}}finally{i.cancel().catch(()=>{})}}function ot(e,t){if(!e||e.startsWith(":"))return;let n=e.indexOf(":");if(n===-1||e.slice(0,n)!=="data")return;let i=e.slice(n+1);t.push(i.startsWith(" ")?i.slice(1):i)}function st(e){return e.endsWith("\r")?e.slice(0,-1):e}async function It(e){let t="";for await(let n of e)if(n.type==="delta"&&n.text&&(t+=n.text),n.type==="error")throw new Error(n.message??"The run ended with an error.");return t}import{useState as rt}from"react";import{jsx as at,jsxs as Lt}from"react/jsx-runtime";function At({plan:e,successUrl:t,cancelUrl:n,label:i,className:s}){let{plan:o}=M(),[d,p]=rt(!1),[u,y]=rt(null);async function m(){p(!0),y(null);try{let r=await o.checkout(e.id,{...t?{successUrl:t}:{},...n?{cancelUrl:n}:{}});window.location.assign(r)}catch(r){y(r.message),p(!1)}}return Lt("div",{className:s?`soba-connect ${s}`:"soba-connect",children:[at("button",{type:"button",className:"sc-btn sc-btn-primary",disabled:d,onClick:()=>void m(),children:d?"Opening\u2026":i??`Subscribe \u2014 $${e.price.toLocaleString()}/${e.interval}`}),u&&at("p",{className:"sc-error",children:u})]})}import{useState as it}from"react";import{Fragment as Bt,jsx as b,jsxs as _}from"react/jsx-runtime";var Ot={"user-hardware":"your own machine","user-subscription":"your own AI subscription","open-weights":"open models we host",frontier:"frontier models"},$t=new Set(["user-hardware","user-subscription"]);function we(e){return e?`soba-connect ${e}`:"soba-connect"}function Ut({onSelect:e,successUrl:t,cancelUrl:n,showCompute:i=!0,className:s}){let{plan:o}=M(),[d,p]=it(null),[u,y]=it(null);if(o.error)return b("div",{className:we(s),children:b("div",{className:"sc-card",children:b("p",{className:"sc-error",children:o.error.message})})});if(o.loading)return b("div",{className:we(s),children:b("div",{className:"sc-card",children:b("p",{className:"sc-note",children:"Loading plans\u2026"})})});if(o.plans.length===0)return b("div",{className:we(s),children:b("div",{className:"sc-card",children:b("p",{className:"sc-note",children:"This app has no plans yet."})})});async function m(r){p(r.id),y(null);try{if(r.selectable)await o.select(r.id);else if(e)e(r);else{let g=await o.checkout(r.id,{...t?{successUrl:t}:{},...n?{cancelUrl:n}:{}});window.location.assign(g);return}}catch(g){y(g.message)}finally{p(null)}}return _("div",{className:we(s),children:[b("div",{className:"sc-plans",children:o.plans.map(r=>{let g=o.current?.plan_id===r.id;return _("div",{className:g?"sc-plan sc-plan-current":"sc-plan",children:[_("div",{className:"sc-row-between",children:[b("span",{className:"sc-title",children:r.name}),g&&b("span",{className:"sc-plan-badge",children:"Current"})]}),r.description&&b("p",{className:"sc-sub",children:r.description}),b("p",{className:"sc-plan-price",children:r.price===0?b("span",{className:"sc-plan-amount",children:"Free"}):_(Bt,{children:[_("span",{className:"sc-plan-amount",children:["$",r.price.toLocaleString()]}),_("span",{className:"sc-plan-interval",children:["/",r.interval]})]})}),_("div",{className:"sc-facts",children:[_("div",{className:"sc-fact",children:[b("span",{className:"sc-fact-key",children:"Included"}),b("span",{children:r.included_units===null?"Unlimited":`${r.included_units.toLocaleString()} ${r.unit}${r.included_units===1?"":"s"}`})]}),r.overage_per_unit>0&&_("div",{className:"sc-fact",children:[b("span",{className:"sc-fact-key",children:"Then"}),_("span",{children:["$",r.overage_per_unit," / ",r.unit]})]}),r.trial_days>0&&_("div",{className:"sc-fact",children:[b("span",{className:"sc-fact-key",children:"Trial"}),_("span",{children:[r.trial_days," days"]})]}),i&&_("div",{className:"sc-plan-compute",children:[b("span",{className:"sc-fact-key",children:"Runs on"}),r.route_allow===null||r.route_allow.length===0?b("span",{children:r.route_allow===null?"any compute":"no compute"}):b("ul",{className:"sc-compute",children:r.route_allow.map(R=>b("li",{className:$t.has(R)?"sc-compute-own":void 0,children:Ot[R]??R},R))})]})]}),b("button",{type:"button",className:g?"sc-btn":"sc-btn sc-btn-primary",disabled:g||d!==null,onClick:()=>void m(r),children:g?"Your plan":d===r.id?r.selectable?"Switching\u2026":"Opening\u2026":r.selectable?"Choose":`Subscribe \u2014 $${r.price.toLocaleString()}/${r.interval}`})]},r.id)})}),u&&b("p",{className:"sc-error",children:u})]})}import{useCallback as G,useEffect as z,useMemo as He,useRef as Dt,useState as O}from"react";var xe=class{#t;#o=null;#n=null;#e;#s=new Set;constructor(t){this.#e=t,this.#t=t.token??null}get token(){return this.#t}get expiresAt(){return this.#o}get canRefresh(){return!!this.#e.endpoint}get refreshAt(){return!this.canRefresh||this.#o===null?null:Math.max(Date.now()+1e4,this.#o-6e4)}subscribe(t){return this.#s.add(t),()=>this.#s.delete(t)}async ensure(){return this.#t?this.#t:this.refresh()}async refresh(){if(this.#n)return this.#n;let t=this.#e.endpoint;if(!t)throw new Error("This Soba session cannot be refreshed. Pass `sessionEndpoint` so the provider can mint a new one.");let n=this.#e.fetchImpl??fetch.bind(globalThis);this.#n=(async()=>{let i=await n(t,{method:"POST",headers:{"content-type":"application/json"},credentials:"same-origin",body:JSON.stringify(this.#e.user?{user:this.#e.user}:{})});if(!i.ok)throw new Error(`Could not start a Soba session (${i.status} from ${t}).`);let s=await i.json(),o=s.session??s.token;if(!o)throw new Error(`${t} answered without a \`session\`. See @soba-so/react's README.`);let d=s.expires_in??s.expiresIn;this.#t=o,this.#o=typeof d=="number"?Date.now()+d*1e3:null;for(let p of this.#s)p();return o})();try{return await this.#n}finally{this.#n=null}}};function ct(e,t=fetch.bind(globalThis)){return async(n,i)=>{let s=await t(n,i);if(s.status!==401||!e.canRefresh)return s;let o;try{o=await e.refresh()}catch{return s}return t(n,qt(i,o))}}function qt(e,t){let n=new Headers(e?.headers);return n.set("authorization",`Bearer ${t}`),{...e,headers:n}}var lt="data-soba-react",ut=!1;function je(){if(ut||typeof document>"u"||(ut=!0,document.querySelector(`style[${lt}]`)))return;let e=document.createElement("style");e.setAttribute(lt,""),e.textContent=`.soba-connect {
6
6
  --sc-ground: #ffffff;
7
7
  --sc-sheet: #ffffff;
8
8
  --sc-raised: #f6f6f7;
@@ -413,6 +413,10 @@ a.sc-btn {
413
413
  place-items: center;
414
414
  }
415
415
 
416
+ .sc-modal:not([open]) {
417
+ display: none;
418
+ }
419
+
416
420
  .sc-modal::backdrop {
417
421
  background: rgb(15 15 17 / 55%);
418
422
  }
@@ -510,7 +514,11 @@ a.sc-btn {
510
514
  .sc-opt {
511
515
  display: flex;
512
516
  align-items: center;
517
+
518
+ justify-content: center;
513
519
  gap: 10px;
520
+
521
+ position: relative;
514
522
  width: 100%;
515
523
  padding: 12px 14px;
516
524
  border: 1.5px solid var(--sc-line-2, #dcdce0);
@@ -544,8 +552,43 @@ a.sc-btn {
544
552
  min-width: 0;
545
553
  }
546
554
 
555
+ .sc-opt-primary {
556
+
557
+ background: var(--sc-accent, #18181b);
558
+ color: var(--sc-accent-fg, #ffffff);
559
+ border-color: var(--sc-accent, #18181b);
560
+ }
561
+
562
+ .sc-opt-primary:hover {
563
+ opacity: 0.9;
564
+ background: var(--sc-accent, #18181b);
565
+ }
566
+
567
+ .sc-details {
568
+ text-align: left;
569
+ font-size: 13px;
570
+ }
571
+
572
+ .sc-details > summary {
573
+ cursor: pointer;
574
+ color: var(--sc-muted, #6b6b73);
575
+ padding: 6px 0;
576
+ }
577
+
578
+ .sc-details > summary:hover {
579
+ color: var(--sc-text, #1a1a1c);
580
+ }
581
+
582
+ .sc-opt:has(.sc-opt-last) {
583
+ padding-right: 76px;
584
+ padding-left: 76px;
585
+ }
586
+
547
587
  .sc-opt-last {
548
- margin-left: auto;
588
+ position: absolute;
589
+ right: 10px;
590
+ top: 50%;
591
+ transform: translateY(-50%);
549
592
  flex: none;
550
593
  font-size: 11px;
551
594
  font-weight: 600;
@@ -577,4 +620,4 @@ a.sc-btn {
577
620
  .sc-btn-connected .sc-dot {
578
621
  flex: none;
579
622
  }
580
- `,document.head.appendChild(e)}import{jsx as Ye}from"react/jsx-runtime";var Zt="https://www.soba.so",Yt=15e3;function Xt(e){let{children:t,session:n,sessionEndpoint:o,user:s,runEndpoint:r,theme:m,initialMachines:h,initialConnect:u=null,initialPlans:v,initialCurrentPlan:d=null,baseUrl:a=Zt,pollMs:f=Yt,injectStyles:R=!0,fetchImpl:w,onError:T}=e,[x,I]=$(n??null),[N,Y]=$(null),[g,B]=$(u),[j,U]=$(null),[V,q]=$(u===null),[H,ke]=$(h??[]),[K,ae]=$(null),[ie,fe]=$(h===void 0),[X,Se]=$(v??[]),[Q,ee]=$(d),[te,ce]=$(null),[ge,be]=$(v===void 0),le=Jt(T);le.current=T;let D=J(l=>{Y(l),le.current?.(l)},[]);Z(()=>{R&&Je()},[R]);let S=Ze(()=>new Ne({...n?{token:n}:{},...o?{endpoint:o}:{},...s?{user:s}:{},...w?{fetchImpl:w}:{}}),[n,o,s,w]);Z(()=>{let l=!0,k=S.subscribe(()=>{l&&I(S.token)});return!S.token&&!S.canRefresh?D(new Error("<SobaProvider> needs a `session` or a `sessionEndpoint`. A browser cannot mint one: that takes your secret key.")):S.ensure().then(()=>l&&I(S.token),A=>l&&D(A)),()=>{l=!1,k()}},[S,D]),Z(()=>{N&&(q(!1),fe(!1),be(!1),U(l=>l??N),ae(l=>l??N),ce(l=>l??N))},[N]),Z(()=>{let l=S.refreshAt;if(l===null)return;let k=setTimeout(()=>{S.refresh().catch(A=>D(A))},Math.max(0,l-Date.now()));return()=>clearTimeout(k)},[S,D,x]);let p=Ze(()=>x?new de({session:x,baseUrl:a,fetchImpl:vt(S,w??fetch.bind(globalThis))}):null,[x,a,S,w]);Z(()=>{if(!p)return;let l=!0;return q(!0),p.context().then(k=>{l&&(B(k),U(null),q(!1))},k=>{l&&(U(k),q(!1))}),()=>{l=!1}},[p]);let E=J(async()=>{if(p)try{let l=await p.machines();ke(l),ae(null)}catch(l){ae(l)}finally{fe(!1)}},[p]),F=J(async()=>{if(p)try{let l=await p.plans();Se(l.plans),ee(l.current),ce(null)}catch(l){ce(l)}finally{be(!1)}},[p]);Z(()=>{p&&F()},[p,F]);let ue=J(async l=>{if(!p)throw new Error("No session yet.");await p.selectPlan(l),await F()},[p,F]),i=J(async(l,k)=>{if(!p)throw new Error("No session yet.");let A=await p.checkoutPlan(l,k);if(!A.url)throw new Error("Checkout could not be started.");return A.url},[p]),C=J(async()=>{if(!p)throw new Error("No session yet.");await p.leavePlan(),await F()},[p,F]);Z(()=>{if(!p)return;let l=!0;E();let k=setInterval(()=>{typeof document<"u"&&document.hidden||l&&E()},f);return()=>{l=!1,clearInterval(k)}},[p,E,f]);let P=J(async l=>{if(!r)throw new Error("Pass `runEndpoint` to <SobaProvider> to start runs from the browser. It is your own route: it holds your secret key, calls soba.run(), and forwards the stream.");let{signal:k,...A}=l,Pe=await(w??fetch.bind(globalThis))(r,{method:"POST",headers:{"content-type":"application/json",accept:"text/event-stream"},credentials:"same-origin",body:JSON.stringify(A),...k?{signal:k}:{}});if(!Pe.ok)throw new Error(`${r} answered ${Pe.status}.`);return Ke(Pe)},[r,w]),ne=Ze(()=>({session:x,client:p,error:N,plan:{plans:X,current:Q,plan:Q?X.find(l=>l.id===Q.plan_id)??null:null,loading:ge,error:te,select:ue,checkout:i,leave:C,refresh:F},compute:{machines:H,connected:H.length>0,online:H.some(l=>l.state!=="offline"),loading:ie,error:K,refresh:E},connect:{app:g?.app??null,command:g?.command??null,publishableKey:g?.publishable_key??null,loading:V,error:j},run:P}),[x,p,N,H,ie,K,E,X,Q,ge,te,ue,i,C,F,g,V,j,P]);return Ye(Fe.Provider,{value:p,children:Ye(je.Provider,{value:{context:g,machines:ie?void 0:H,theme:m??g?.theme??"light"},children:Ye(De.Provider,{value:ne,children:t})})})}export{Ot as ComputeStatus,ze as ConnectButton,qt as ConnectCompute,He as ConnectModal,jt as SobaCheckout,zt as SobaPlans,Xt as SobaProvider,Ft as collectText,Je as injectStyles,we as parseEvent,Ke as readEvents,_ as useSoba};
623
+ `,document.head.appendChild(e)}import{jsx as Ve}from"react/jsx-runtime";var Ft="https://www.soba.so",jt=15e3;function Ht(e){let{children:t,session:n,sessionEndpoint:i,user:s,runEndpoint:o,theme:d,initialMachines:p,initialConnect:u=null,initialPlans:y,initialCurrentPlan:m=null,baseUrl:r=Ft,pollMs:g=jt,injectStyles:R=!0,fetchImpl:C,onError:$}=e,[S,T]=O(n??null),[f,W]=O(null),[k,N]=O(u),[B,I]=O(null),[te,J]=O(u===null),[q,Se]=O(p??[]),[Z,K]=O(null),[Y,he]=O(p===void 0),[ne,V]=O(y??[]),[F,Ne]=O(m),[fe,oe]=O(null),[A,ge]=O(y===void 0),se=Dt($);se.current=$;let D=G(l=>{W(l),se.current?.(l)},[]);z(()=>{R&&je()},[R]);let w=He(()=>new xe({...n?{token:n}:{},...i?{endpoint:i}:{},...s?{user:s}:{},...C?{fetchImpl:C}:{}}),[n,i,s,C]);z(()=>{let l=!0,P=w.subscribe(()=>{l&&T(w.token)});return!w.token&&!w.canRefresh?D(new Error("<SobaProvider> needs a `session` or a `sessionEndpoint`. A browser cannot mint one: that takes your secret key.")):w.ensure().then(()=>l&&T(w.token),j=>l&&D(j)),()=>{l=!1,P()}},[w,D]),z(()=>{f&&(J(!1),he(!1),ge(!1),I(l=>l??f),K(l=>l??f),oe(l=>l??f))},[f]),z(()=>{let l=w.refreshAt;if(l===null)return;let P=setTimeout(()=>{w.refresh().catch(j=>D(j))},Math.max(0,l-Date.now()));return()=>clearTimeout(P)},[w,D,S]);let h=He(()=>S?new le({session:S,baseUrl:r,fetchImpl:ct(w,C??fetch.bind(globalThis))}):null,[S,r,w,C]);z(()=>{if(!h)return;let l=!0;return J(!0),h.context().then(P=>{l&&(N(P),I(null),J(!1))},P=>{l&&(I(P),J(!1))}),()=>{l=!1}},[h]);let c=G(async()=>{if(h)try{let l=await h.machines();Se(l),K(null)}catch(l){K(l)}finally{he(!1)}},[h]),x=G(async()=>{if(h)try{let l=await h.plans();V(l.plans),Ne(l.current),oe(null)}catch(l){oe(l)}finally{ge(!1)}},[h]);z(()=>{h&&x()},[h,x]);let E=G(async l=>{if(!h)throw new Error("No session yet.");await h.selectPlan(l),await x()},[h,x]),re=G(async(l,P)=>{if(!h)throw new Error("No session yet.");let j=await h.checkoutPlan(l,P);if(!j.url)throw new Error("Checkout could not be started.");return j.url},[h]),ae=G(async()=>{if(!h)throw new Error("No session yet.");await h.leavePlan(),await x()},[h,x]);z(()=>{if(!h)return;let l=!0;c();let P=setInterval(()=>{typeof document<"u"&&document.hidden||l&&c()},g);return()=>{l=!1,clearInterval(P)}},[h,c,g]);let ie=G(async l=>{if(!o)throw new Error("Pass `runEndpoint` to <SobaProvider> to start runs from the browser. It is your own route: it holds your secret key, calls soba.run(), and forwards the stream.");let{signal:P,...j}=l,ke=await(C??fetch.bind(globalThis))(o,{method:"POST",headers:{"content-type":"application/json",accept:"text/event-stream"},credentials:"same-origin",body:JSON.stringify(j),...P?{signal:P}:{}});if(!ke.ok)throw new Error(`${o} answered ${ke.status}.`);return Fe(ke)},[o,C]),ce=He(()=>({session:S,client:h,error:f,plan:{plans:ne,current:F,plan:F?ne.find(l=>l.id===F.plan_id)??null:null,loading:A,error:fe,select:E,checkout:re,leave:ae,refresh:x},compute:{machines:q,connected:q.length>0,online:q.some(l=>l.state!=="offline"),loading:Y,error:Z,refresh:c},connect:{app:k?.app??null,command:k?.command??null,publishableKey:k?.publishable_key??null,loading:te,error:B},run:ie}),[S,h,f,q,Y,Z,c,ne,F,A,fe,E,re,ae,x,k,te,B,ie]);return Ve(Le.Provider,{value:h,children:Ve(Oe.Provider,{value:{context:k,machines:Y?void 0:q,theme:d??k?.theme??"light"},children:Ve(Ae.Provider,{value:ce,children:t})})})}export{kt as ComputeStatus,qe as ConnectButton,_t as ConnectCompute,Ue as ConnectModal,At as SobaCheckout,Ut as SobaPlans,Ht as SobaProvider,It as collectText,je as injectStyles,Ce as parseEvent,Fe as readEvents,M as useSoba};
package/dist/styles.css CHANGED
@@ -409,6 +409,10 @@ a.sc-btn {
409
409
  place-items: center;
410
410
  }
411
411
 
412
+ .sc-modal:not([open]) {
413
+ display: none;
414
+ }
415
+
412
416
  .sc-modal::backdrop {
413
417
  background: rgb(15 15 17 / 55%);
414
418
  }
@@ -506,7 +510,11 @@ a.sc-btn {
506
510
  .sc-opt {
507
511
  display: flex;
508
512
  align-items: center;
513
+
514
+ justify-content: center;
509
515
  gap: 10px;
516
+
517
+ position: relative;
510
518
  width: 100%;
511
519
  padding: 12px 14px;
512
520
  border: 1.5px solid var(--sc-line-2, #dcdce0);
@@ -540,8 +548,43 @@ a.sc-btn {
540
548
  min-width: 0;
541
549
  }
542
550
 
551
+ .sc-opt-primary {
552
+
553
+ background: var(--sc-accent, #18181b);
554
+ color: var(--sc-accent-fg, #ffffff);
555
+ border-color: var(--sc-accent, #18181b);
556
+ }
557
+
558
+ .sc-opt-primary:hover {
559
+ opacity: 0.9;
560
+ background: var(--sc-accent, #18181b);
561
+ }
562
+
563
+ .sc-details {
564
+ text-align: left;
565
+ font-size: 13px;
566
+ }
567
+
568
+ .sc-details > summary {
569
+ cursor: pointer;
570
+ color: var(--sc-muted, #6b6b73);
571
+ padding: 6px 0;
572
+ }
573
+
574
+ .sc-details > summary:hover {
575
+ color: var(--sc-text, #1a1a1c);
576
+ }
577
+
578
+ .sc-opt:has(.sc-opt-last) {
579
+ padding-right: 76px;
580
+ padding-left: 76px;
581
+ }
582
+
543
583
  .sc-opt-last {
544
- margin-left: auto;
584
+ position: absolute;
585
+ right: 10px;
586
+ top: 50%;
587
+ transform: translateY(-50%);
545
588
  flex: none;
546
589
  font-size: 11px;
547
590
  font-weight: 600;
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@soba-so/react",
3
- "version": "0.0.9",
3
+ "version": "0.0.10",
4
4
  "description": "Connect the AI your users already pay for, from your own React app.",
5
5
  "license": "UNLICENSED",
6
6
  "homepage": "https://soba.so/docs/components",