@bodhiapp/bodhi-js-core 0.0.35 → 0.0.36

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.
@@ -94,5 +94,5 @@ var Q={xmlns:"http://www.w3.org/2000/svg",width:24,height:24,viewBox:"0 0 24 24"
94
94
  border-radius: 12px;
95
95
  background: white;
96
96
  box-shadow: 0 20px 60px rgba(0, 0, 0, 0.3);
97
- `,this.overlayElement.appendChild(this.iframeElement),document.body.appendChild(this.overlayElement),this.messageHandler=this.handleMessage.bind(this),window.addEventListener("message",this.messageHandler))}showLoading(){this.show(ne)}updateState(e){this.currentSetupState=e,this.sendStateToModal()}destroy(){this.messageHandler&&(window.removeEventListener("message",this.messageHandler),this.messageHandler=null),this.overlayElement&&(this.overlayElement.remove(),this.overlayElement=null,this.iframeElement=null),this.isIframeReady=!1,this.currentSetupState=null}async handleMessage(e){const t=e.data;if(!re(t)||e.source!==this.iframeElement?.contentWindow)return;const n=this.handlers[t.type];if(!n){console.warn("[OnboardingModalV2] No handler for message type:",t.type);return}try{t.type===T.MODAL_READY&&(this.isIframeReady=!0);const r=await n(t),a={kind:"response",type:t.type,requestId:t.requestId,payload:r};this.iframeElement?.contentWindow?.postMessage(a,"*")}catch(r){console.error("[OnboardingModalV2] Handler error:",r);const a={kind:"error",requestId:t.requestId,error:{code:"handler-error",message:r instanceof Error?r.message:"Handler execution failed"}};this.iframeElement?.contentWindow?.postMessage(a,"*")}}sendStateToModal(){if(!this.isIframeReady||!this.iframeElement||!this.currentSetupState)return;const e={kind:"event",type:T.PARENT_STATE_UPDATE,payload:this.currentSetupState};this.iframeElement.contentWindow?.postMessage(e,"*")}}const oe=[{id:"chrome",status:"supported",name:"Google Chrome",extension_url:"https://chromewebstore.google.com/detail/bodhi-browser-extension/bjdjhiombmfbcoeojijpfckljjghmjbf"},{id:"edge",status:"supported",name:"Microsoft Edge",extension_url:"https://chromewebstore.google.com/detail/bodhi-browser-extension/bjdjhiombmfbcoeojijpfckljjghmjbf"},{id:"firefox",status:"not-supported",name:"Mozilla Firefox",github_issue_url:"https://github.com/BodhiSearch/bodhi-js/issues/1"},{id:"safari",status:"not-supported",name:"Safari",github_issue_url:"https://github.com/BodhiSearch/bodhi-js/issues/2"},{id:"unknown",status:"not-supported",name:"Unknown Browser",github_issue_url:"https://github.com/BodhiSearch/bodhi-js/issues/3"}],ie=[{id:"macos",status:"supported",name:"macOS",download_url:"https://getbodhi.app/"},{id:"windows",status:"supported",name:"Windows",download_url:"https://getbodhi.app/"},{id:"linux",status:"supported",name:"Linux",download_url:"https://getbodhi.app/"},{id:"unknown",status:"not-supported",name:"Unknown OS",github_issue_url:"https://github.com/BodhiSearch/bodhi-js/issues/4"}];function k(o){return btoa(String.fromCharCode(...new Uint8Array(o))).replace(/\+/g,"-").replace(/\//g,"_").replace(/=/g,"")}function se(){const o=new Uint8Array(32);return crypto.getRandomValues(o),k(o.buffer)}async function ue(o){const t=new TextEncoder().encode(o),n=await crypto.subtle.digest("SHA-256",t);return k(n)}function O(o){const t=o.split(".")[1].replace(/-/g,"+").replace(/_/g,"/"),n=decodeURIComponent(atob(t).split("").map(r=>"%"+("00"+r.charCodeAt(0).toString(16)).slice(-2)).join(""));return JSON.parse(n)}function v(o){const e=O(o);return{sub:e.sub,email:e.email,name:e.name,given_name:e.given_name,family_name:e.family_name,preferred_username:e.preferred_username}}function U(o){return{authorize:`${o}/protocol/openid-connect/auth`,token:`${o}/protocol/openid-connect/token`,revoke:`${o}/protocol/openid-connect/revoke`}}async function D(o,e,t){try{const n=await fetch(o,{method:"POST",headers:{"Content-Type":"application/x-www-form-urlencoded"},body:new URLSearchParams({grant_type:"refresh_token",refresh_token:e,client_id:t})});if(!n.ok)try{return(await n.json()).error==="invalid_grant"?{success:!1,error:"invalid_grant"}:{success:!1,error:"other_error"}}catch{return{success:!1,error:"other_error"}}const r=await n.json();return{success:!0,tokens:{access_token:r.access_token,refresh_token:r.refresh_token,id_token:r.id_token,expires_in:r.expires_in||3600}}}catch{return{success:!1,error:"network_error"}}}class y{constructor(e){this.client=e}}class F extends y{create(e){return e.stream===!0?this.client.stream("POST","/v1/chat/completions",e,void 0,!0):this.client.sendApiRequest("POST","/v1/chat/completions",e,void 0,!0).then(t=>h.unwrapResponse(t))}}class S extends y{constructor(e){super(e),this.completions=new F(e)}}class E extends y{async*list(){const e=await this.client.sendApiRequest("GET","/v1/models",void 0,void 0,!0),t=h.unwrapResponse(e);for(const n of t.data)yield n}async retrieve(e){const t=await this.client.sendApiRequest("GET",`/v1/models/${e}`,void 0,void 0,!0);return h.unwrapResponse(t)}}class C extends y{async create(e){const t=await this.client.sendApiRequest("POST","/v1/embeddings",e,void 0,!0);return h.unwrapResponse(t)}}class N extends y{async list(){const e=await this.client.sendApiRequest("GET","/bodhi/v1/apps/mcps",void 0,void 0,!0);return h.unwrapResponse(e)}}async function B(o,e=x){const t=`${o}/bodhi/v1/info`;try{const n=new AbortController,r=setTimeout(()=>n.abort(),e),a=await fetch(t,{method:"GET",headers:{"Content-Type":"application/json"},signal:n.signal});if(clearTimeout(r),a.ok&&a.status===200){const i=await a.json();return{success:!0,serverInfo:{status:i.status||"unknown",version:i.version||"unknown",deployment:i.deployment,client_id:i.client_id}}}try{const i=await a.json();if(i?.error?.message&&i?.error?.type)return{success:!1,error:i.error}}catch{}return{success:!1,error:{message:`Server returned ${a.status}: ${a.statusText}`,type:"server-error"}}}catch(n){return{success:!1,error:{message:`Cannot reach server: ${n instanceof Error?n.message:"Network error"}`,type:"network-error"}}}}class ce{constructor(e,t){this.serverUrl=null,this.storage=null,this.state=l.DIRECT_STATE_NOT_INITIALIZED,this.refreshPromise=null,this.logger=new L(e.loggerPrefix,e.logLevel),this.authClientId=e.authClientId,this.authServerUrl=e.authServerUrl,this.authEndpoints=U(this.authServerUrl),this.storageKeys=I(e.storagePrefix),this.onStateChange=t??l.NOOP_STATE_CALLBACK,this.apiTimeoutMs=e.apiTimeoutMs??x,this.storage=e.storage??null,this.initialTokens=e.initialTokens}setState(e){this.state=e,this.onStateChange({type:"client-state",state:e})}setAuthState(e){this.onStateChange({type:"auth-state",state:e})}setStateCallback(e){this.onStateChange=e}async init(e){this.initialTokens&&(await this._bootstrapInitialTokens(this.initialTokens),this.initialTokens=void 0);const t=e.serverUrl??e.savedState?.url??this.serverUrl;if(this.serverUrl&&this.serverUrl===t&&!e.testConnection)return this.logger.debug("Already initialized with serverUrl, skipping init"),this.state;if(this.serverUrl=t,!this.serverUrl)return this.logger.info("No serverUrl provided, returning not-initialized state"),l.DIRECT_STATE_NOT_INITIALIZED;if(this.logger.info("Initializing with serverUrl:",this.serverUrl),e.testConnection){const n=await this.testConnectivity();let r;if(n.success&&n.serverInfo){const a=n.serverInfo.status,i=n.serverInfo.version;a==="ready"?r={status:"ready",version:i,error:null,deployment:n.serverInfo.deployment??null,client_id:n.serverInfo.client_id??null}:a==="setup"||a==="resource_admin"||a==="error"?r=l.backendServerNotReady(a,i,void 0,n.serverInfo.deployment,n.serverInfo.client_id):r=l.BACKEND_SERVER_NOT_REACHABLE}else this.logger.warn("Connection failed:",n.error),r=l.BACKEND_SERVER_NOT_REACHABLE;return this.setState({type:"direct",url:t,server:r}),this.logger.info("Initialized with testConnection, server state:",r.status),this.state}return e.selectedConnection?(this.setState({type:"direct",url:t,server:l.BACKEND_SERVER_NOT_CONNECTED}),this.logger.info("Initialized with selectedConnection, server state: not-connected"),this.state):(this.logger.info("No selectedConnection, returning not-initialized state"),l.DIRECT_STATE_NOT_INITIALIZED)}getState(){return this.state}isClientInitialized(){return this.serverUrl!==null}isServerReady(){return this.isClientInitialized()&&this.state.type==="direct"&&this.state.server.status==="ready"}ensureInitialized(){if(!this.serverUrl)throw new h.BodhiError("not_initialized","DirectClient not initialized. Call init(serverUrl) first.")}async sendApiRequest(e,t,n,r,a=!0){if(!this.serverUrl)throw new h.BodhiError("not_initialized","Client not initialized - connection failed");const i=`${this.serverUrl}${t}`;this.logger.debug(`${e} ${i}`);try{const d=new AbortController,u=setTimeout(()=>d.abort(),this.apiTimeoutMs),f={"Content-Type":"application/json",...r};if(a){const p=await this._getAccessTokenRaw();p&&(f.Authorization=`Bearer ${p}`)}const m=await fetch(i,{method:e,headers:f,body:n?JSON.stringify(n):void 0,signal:d.signal});clearTimeout(u);const s={};return m.headers.forEach((p,g)=>{s[g]=p}),{body:await m.json(),status:m.status,headers:s}}catch(d){const u=d instanceof Error?d.message:"Unknown error";throw d instanceof Error&&d.name==="AbortError"?new h.BodhiError("timeout_error",`[bodhi-js-sdk/direct] network timeout: api request not completed within configured/default timeout of ${this.apiTimeoutMs}ms`):new h.BodhiError("network_error",`Network error: ${u}`)}}async pingApi(){return this.sendApiRequest("GET","/ping",void 0,{},!1)}async getServerState(){const e=await this.testConnectivity();if(!e.success)return{status:"not-reachable",version:null,error:e.error||{message:"Connection failed",type:"network_error"}};const t=e.serverInfo,n={deployment:t.deployment??null,client_id:t.client_id??null};switch(t.status){case"ready":return{status:"ready",version:t.version,error:null,...n};case"setup":return{status:"setup",version:t.version,error:{message:"Setup required",type:"extension_error"},...n};case"resource_admin":return{status:"resource_admin",version:t.version,error:{message:"Resource admin required",type:"extension_error"},...n};case"error":return{status:"error",version:t.version||"unknown",error:{message:"Server error",type:"extension_error"},...n};default:return{status:"not-reachable",version:null,error:{message:"Unknown status",type:"extension_error"}}}}async*stream(e,t,n,r,a=!0){if(!this.serverUrl)throw new h.BodhiError("not_initialized","Client not initialized - connection failed");const i=`${this.serverUrl}${t}`;this.logger.debug(`Stream ${e} ${i}`);const d={"Content-Type":"application/json",Accept:"text/event-stream",...r};if(a){const c=await this._getAccessTokenRaw();c&&(d.Authorization=`Bearer ${c}`)}let u;try{u=await fetch(i,{method:e,headers:d,body:n?JSON.stringify(n):void 0})}catch(c){const p=c instanceof Error?c.message:"Unknown error";throw new h.BodhiError("network_error",`Network error: ${p}`)}if(!u.ok){let c;try{c=await u.json()}catch{c={error:{message:`HTTP ${u.status}`,type:"api_error"}}}const p=c?.error?.message||`HTTP ${u.status}`;throw new h.BodhiApiError(u.status,c,p)}if(!u.body)throw new h.BodhiError("network_error","Response body is null");const f=u.body.getReader(),m=new TextDecoder;let s="";try{for(;;){const{done:c,value:p}=await f.read();if(c)break;s+=m.decode(p,{stream:!0});const g=s.split(`
97
+ `,this.overlayElement.appendChild(this.iframeElement),document.body.appendChild(this.overlayElement),this.messageHandler=this.handleMessage.bind(this),window.addEventListener("message",this.messageHandler))}showLoading(){this.show(ne)}updateState(e){this.currentSetupState=e,this.sendStateToModal()}destroy(){this.messageHandler&&(window.removeEventListener("message",this.messageHandler),this.messageHandler=null),this.overlayElement&&(this.overlayElement.remove(),this.overlayElement=null,this.iframeElement=null),this.isIframeReady=!1,this.currentSetupState=null}async handleMessage(e){const t=e.data;if(!re(t)||e.source!==this.iframeElement?.contentWindow)return;const n=this.handlers[t.type];if(!n){console.warn("[OnboardingModalV2] No handler for message type:",t.type);return}try{t.type===T.MODAL_READY&&(this.isIframeReady=!0);const r=await n(t),a={kind:"response",type:t.type,requestId:t.requestId,payload:r};this.iframeElement?.contentWindow?.postMessage(a,"*")}catch(r){console.error("[OnboardingModalV2] Handler error:",r);const a={kind:"error",requestId:t.requestId,error:{code:"handler-error",message:r instanceof Error?r.message:"Handler execution failed"}};this.iframeElement?.contentWindow?.postMessage(a,"*")}}sendStateToModal(){if(!this.isIframeReady||!this.iframeElement||!this.currentSetupState)return;const e={kind:"event",type:T.PARENT_STATE_UPDATE,payload:this.currentSetupState};this.iframeElement.contentWindow?.postMessage(e,"*")}}const oe=[{id:"chrome",status:"supported",name:"Google Chrome",extension_url:"https://chromewebstore.google.com/detail/bodhi-browser-extension/bjdjhiombmfbcoeojijpfckljjghmjbf"},{id:"edge",status:"supported",name:"Microsoft Edge",extension_url:"https://chromewebstore.google.com/detail/bodhi-browser-extension/bjdjhiombmfbcoeojijpfckljjghmjbf"},{id:"firefox",status:"not-supported",name:"Mozilla Firefox",github_issue_url:"https://github.com/BodhiSearch/bodhi-js/issues/1"},{id:"safari",status:"not-supported",name:"Safari",github_issue_url:"https://github.com/BodhiSearch/bodhi-js/issues/2"},{id:"unknown",status:"not-supported",name:"Unknown Browser",github_issue_url:"https://github.com/BodhiSearch/bodhi-js/issues/3"}],ie=[{id:"macos",status:"supported",name:"macOS",download_url:"https://getbodhi.app/"},{id:"windows",status:"supported",name:"Windows",download_url:"https://getbodhi.app/"},{id:"linux",status:"supported",name:"Linux",download_url:"https://getbodhi.app/"},{id:"unknown",status:"not-supported",name:"Unknown OS",github_issue_url:"https://github.com/BodhiSearch/bodhi-js/issues/4"}];function k(o){return btoa(String.fromCharCode(...new Uint8Array(o))).replace(/\+/g,"-").replace(/\//g,"_").replace(/=/g,"")}function se(){const o=new Uint8Array(32);return crypto.getRandomValues(o),k(o.buffer)}async function ue(o){const t=new TextEncoder().encode(o),n=await crypto.subtle.digest("SHA-256",t);return k(n)}function O(o){const t=o.split(".")[1].replace(/-/g,"+").replace(/_/g,"/"),n=decodeURIComponent(atob(t).split("").map(r=>"%"+("00"+r.charCodeAt(0).toString(16)).slice(-2)).join(""));return JSON.parse(n)}function v(o){const e=O(o);return{sub:e.sub,email:e.email,name:e.name,given_name:e.given_name,family_name:e.family_name,preferred_username:e.preferred_username}}function U(o){return{authorize:`${o}/protocol/openid-connect/auth`,token:`${o}/protocol/openid-connect/token`,revoke:`${o}/protocol/openid-connect/revoke`}}async function D(o,e,t){try{const n=await fetch(o,{method:"POST",headers:{"Content-Type":"application/x-www-form-urlencoded"},body:new URLSearchParams({grant_type:"refresh_token",refresh_token:e,client_id:t})});if(!n.ok)try{return(await n.json()).error==="invalid_grant"?{success:!1,error:"invalid_grant"}:{success:!1,error:"other_error"}}catch{return{success:!1,error:"other_error"}}const r=await n.json();return{success:!0,tokens:{access_token:r.access_token,refresh_token:r.refresh_token,id_token:r.id_token,expires_in:r.expires_in||3600}}}catch{return{success:!1,error:"network_error"}}}class y{constructor(e){this.client=e}}class F extends y{create(e){return e.stream===!0?this.client.stream("POST","/v1/chat/completions",e,void 0,!0):this.client.sendApiRequest("POST","/v1/chat/completions",e,void 0,!0).then(t=>h.unwrapResponse(t))}}class S extends y{constructor(e){super(e),this.completions=new F(e)}}class E extends y{async*list(){const e=await this.client.sendApiRequest("GET","/v1/models",void 0,void 0,!0),t=h.unwrapResponse(e);for(const n of t.data)yield n}async retrieve(e){const t=await this.client.sendApiRequest("GET",`/v1/models/${e}`,void 0,void 0,!0);return h.unwrapResponse(t)}}class C extends y{async create(e){const t=await this.client.sendApiRequest("POST","/v1/embeddings",e,void 0,!0);return h.unwrapResponse(t)}}class N extends y{async list(){const e=await this.client.sendApiRequest("GET","/bodhi/v1/apps/mcps",void 0,void 0,!0);return h.unwrapResponse(e)}}async function B(o,e=x){const t=`${o}/bodhi/v1/info`;try{const n=new AbortController,r=setTimeout(()=>n.abort(),e),a=await fetch(t,{method:"GET",headers:{"Content-Type":"application/json"},signal:n.signal});if(clearTimeout(r),a.ok&&a.status===200){const i=await a.json();return{success:!0,serverInfo:{status:i.status||"unknown",version:i.version||"unknown",deployment:i.deployment,client_id:i.client_id}}}try{const i=await a.json();if(i?.error?.message&&i?.error?.type)return{success:!1,error:i.error}}catch{}return{success:!1,error:{message:`Server returned ${a.status}: ${a.statusText}`,type:"server-error"}}}catch(n){return{success:!1,error:{message:`Cannot reach server: ${n instanceof Error?n.message:"Network error"}`,type:"network-error"}}}}class ce{constructor(e,t){this.serverUrl=null,this.storage=null,this.state=l.DIRECT_STATE_NOT_INITIALIZED,this.refreshPromise=null,this.initPromise=null,this.logger=new L(e.loggerPrefix,e.logLevel),this.authClientId=e.authClientId,this.authServerUrl=e.authServerUrl,this.authEndpoints=U(this.authServerUrl),this.storageKeys=I(e.storagePrefix),this.onStateChange=t??l.NOOP_STATE_CALLBACK,this.apiTimeoutMs=e.apiTimeoutMs??x,this.storage=e.storage??null,this.initialTokens=e.initialTokens}setState(e){this.state=e,this.onStateChange({type:"client-state",state:e})}setAuthState(e){this.onStateChange({type:"auth-state",state:e})}setStateCallback(e){this.onStateChange=e}async init(e){this.initialTokens&&(await this._bootstrapInitialTokens(this.initialTokens),this.initialTokens=void 0);const t=e.serverUrl??e.savedState?.url??this.serverUrl;return this.serverUrl&&this.serverUrl===t&&!e.testConnection?this.initPromise&&e.selectedConnection?(this.logger.debug("Init in-flight for same URL, awaiting existing init"),this.initPromise):(this.logger.debug("Already initialized with serverUrl, skipping init"),this.state):(this.serverUrl=t,this.serverUrl?(this.logger.info("Initializing with serverUrl:",this.serverUrl),e.testConnection?(this.initPromise=(async()=>{try{const n=await this.testConnectivity();let r;if(n.success&&n.serverInfo){const a=n.serverInfo.status,i=n.serverInfo.version;a==="ready"?r={status:"ready",version:i,error:null,deployment:n.serverInfo.deployment??null,client_id:n.serverInfo.client_id??null}:a==="setup"||a==="resource_admin"||a==="error"?r=l.backendServerNotReady(a,i,void 0,n.serverInfo.deployment,n.serverInfo.client_id):r=l.BACKEND_SERVER_NOT_REACHABLE}else this.logger.warn("Connection failed:",n.error),r=l.BACKEND_SERVER_NOT_REACHABLE;return this.setState({type:"direct",url:t,server:r}),this.logger.info("Initialized with testConnection, server state:",r.status),this.state}finally{this.initPromise=null}})(),this.initPromise):e.selectedConnection?(this.setState({type:"direct",url:t,server:l.BACKEND_SERVER_NOT_CONNECTED}),this.logger.info("Initialized with selectedConnection, server state: not-connected"),this.state):(this.logger.info("No selectedConnection, returning not-initialized state"),l.DIRECT_STATE_NOT_INITIALIZED)):(this.logger.info("No serverUrl provided, returning not-initialized state"),l.DIRECT_STATE_NOT_INITIALIZED))}getState(){return this.state}isClientInitialized(){return this.serverUrl!==null}isServerReady(){return this.isClientInitialized()&&this.state.type==="direct"&&this.state.server.status==="ready"}ensureInitialized(){if(!this.serverUrl)throw new h.BodhiError("not_initialized","DirectClient not initialized. Call init(serverUrl) first.")}async sendApiRequest(e,t,n,r,a=!0){if(!this.serverUrl)throw new h.BodhiError("not_initialized","Client not initialized - connection failed");const i=`${this.serverUrl}${t}`;this.logger.debug(`${e} ${i}`);try{const d=new AbortController,u=setTimeout(()=>d.abort(),this.apiTimeoutMs),f={"Content-Type":"application/json",...r};if(a){const p=await this._getAccessTokenRaw();p&&(f.Authorization=`Bearer ${p}`)}const m=await fetch(i,{method:e,headers:f,body:n?JSON.stringify(n):void 0,signal:d.signal});clearTimeout(u);const s={};return m.headers.forEach((p,g)=>{s[g]=p}),{body:await m.json(),status:m.status,headers:s}}catch(d){const u=d instanceof Error?d.message:"Unknown error";throw d instanceof Error&&d.name==="AbortError"?new h.BodhiError("timeout_error",`[bodhi-js-sdk/direct] network timeout: api request not completed within configured/default timeout of ${this.apiTimeoutMs}ms`):new h.BodhiError("network_error",`Network error: ${u}`)}}async pingApi(){return this.sendApiRequest("GET","/ping",void 0,{},!1)}async getServerState(){const e=await this.testConnectivity();if(!e.success)return{status:"not-reachable",version:null,error:e.error||{message:"Connection failed",type:"network_error"}};const t=e.serverInfo,n={deployment:t.deployment??null,client_id:t.client_id??null};switch(t.status){case"ready":return{status:"ready",version:t.version,error:null,...n};case"setup":return{status:"setup",version:t.version,error:{message:"Setup required",type:"extension_error"},...n};case"resource_admin":return{status:"resource_admin",version:t.version,error:{message:"Resource admin required",type:"extension_error"},...n};case"error":return{status:"error",version:t.version||"unknown",error:{message:"Server error",type:"extension_error"},...n};default:return{status:"not-reachable",version:null,error:{message:"Unknown status",type:"extension_error"}}}}async*stream(e,t,n,r,a=!0){if(!this.serverUrl)throw new h.BodhiError("not_initialized","Client not initialized - connection failed");const i=`${this.serverUrl}${t}`;this.logger.debug(`Stream ${e} ${i}`);const d={"Content-Type":"application/json",Accept:"text/event-stream",...r};if(a){const c=await this._getAccessTokenRaw();c&&(d.Authorization=`Bearer ${c}`)}let u;try{u=await fetch(i,{method:e,headers:d,body:n?JSON.stringify(n):void 0})}catch(c){const p=c instanceof Error?c.message:"Unknown error";throw new h.BodhiError("network_error",`Network error: ${p}`)}if(!u.ok){let c;try{c=await u.json()}catch{c={error:{message:`HTTP ${u.status}`,type:"api_error"}}}const p=c?.error?.message||`HTTP ${u.status}`;throw new h.BodhiApiError(u.status,c,p)}if(!u.body)throw new h.BodhiError("network_error","Response body is null");const f=u.body.getReader(),m=new TextDecoder;let s="";try{for(;;){const{done:c,value:p}=await f.read();if(c)break;s+=m.decode(p,{stream:!0});const g=s.split(`
98
98
  `);s=g.pop()||"";for(const A of g)if(A.startsWith("data: ")){const b=A.slice(6).trim();if(b==="[DONE]")return;try{yield JSON.parse(b)}catch(H){this.logger.warn("Failed to parse SSE data:",b,H)}}}}finally{f.releaseLock()}}async streamText(e,t,n,r,a=!0){if(!this.serverUrl)throw new h.BodhiError("not_initialized","Client not initialized - connection failed");const i=`${this.serverUrl}${t}`,d={...r};if(a){const s=await this._getAccessTokenRaw();s&&(d.Authorization=`Bearer ${s}`)}const u=await fetch(i,{method:e,headers:d,body:n?JSON.stringify(n):void 0}),f={};u.headers.forEach((s,c)=>{f[c]=s});async function*m(){if(!u.body)return;const s=u.body.getReader(),c=new TextDecoder;try{for(;;){const{done:p,value:g}=await s.read();if(p)break;yield c.decode(g,{stream:!0})}}finally{s.releaseLock()}}return{status:u.status,headers:f,body:m()}}get chat(){return this._chat??=new S(this)}get models(){return this._models??=new E(this)}get embeddings(){return this._embeddings??=new C(this)}get mcps(){return this._mcps??=new N(this)}async testConnectivity(){return this.ensureInitialized(),this.logger.debug("Testing connectivity to:",this.serverUrl),B(this.serverUrl,this.apiTimeoutMs)}serialize(){return this.serverUrl?{url:this.serverUrl}:{}}async debug(){return{type:"DirectClient",serverUrl:this.serverUrl,state:this.state,authState:await this.getAuthState(),authClientId:this.authClientId,authServerUrl:this.authServerUrl}}async requestAccess(e){return this.sendApiRequest("POST","/bodhi/v1/apps/request-access",e,{},!1)}async getAccessRequestStatus(e){return this.sendApiRequest("GET",`/bodhi/v1/apps/access-requests/${e}?app_client_id=${encodeURIComponent(this.authClientId)}`,void 0,{},!1)}async pollAccessRequestStatus(e,t){return R(n=>this.getAccessRequestStatus(n),e,t)}async getAuthState(){const e=await this._getAccessTokenRaw();if(!e)return{status:"unauthenticated",user:null,accessToken:null,error:null,refreshToken:null,expiresAt:null,isTokenRefresh:!1};const t=v(e),n=await this._storageGet(this.storageKeys.REFRESH_TOKEN),r=await this._storageGet(this.storageKeys.EXPIRES_AT);return{status:"authenticated",user:t,accessToken:e,error:null,refreshToken:n??null,expiresAt:r?parseInt(r,10):null,isTokenRefresh:!1}}async logout(){await this.revokeRefreshToken(),await this.clearAuthStorage();const e={status:"unauthenticated",user:null,accessToken:null,error:null,refreshToken:null,expiresAt:null,isTokenRefresh:!1};return this.setAuthState(e),e}async _getAccessTokenRaw(){const e=await this._storageGet(this.storageKeys.ACCESS_TOKEN),t=await this._storageGet(this.storageKeys.EXPIRES_AT);if(!e)return null;if(t){const n=parseInt(t,10);if(Date.now()>=n-5*1e3){const r=await this._storageGet(this.storageKeys.REFRESH_TOKEN);return r?this._tryRefreshToken(r):null}}return e}async _tryRefreshToken(e){if(this.refreshPromise)return this.logger.debug("Refresh already in progress, returning existing promise"),this.refreshPromise;this.refreshPromise=this._doRefreshToken(e);try{return await this.refreshPromise}finally{this.refreshPromise=null}}async _doRefreshToken(e){this.logger.debug("Refreshing access token");try{const t=await D(this.authEndpoints.token,e,this.authClientId);if(t.success){await this._storeRefreshedTokens(t.tokens);const n=v(t.tokens.access_token),r=Date.now()+t.tokens.expires_in*1e3;return this.setAuthState({status:"authenticated",user:n,accessToken:t.tokens.access_token,error:null,refreshToken:t.tokens.refresh_token??null,expiresAt:r,isTokenRefresh:!0}),this.logger.info("Token refreshed successfully"),t.tokens.access_token}if(t.error==="invalid_grant")return this.logger.warn("Refresh token expired or revoked, clearing tokens and logging out"),await this.clearAuthStorage(),this.setAuthState({status:"unauthenticated",user:null,accessToken:null,error:null,refreshToken:null,expiresAt:null,isTokenRefresh:!1}),null}catch(t){this.logger.warn("Token refresh failed:",t)}throw this.logger.warn("Token refresh failed, keeping tokens for manual retry"),new h.BodhiError("auth_error","Access token expired and unable to refresh. Try logging out and logging in again.")}async _storeRefreshedTokens(e){const t=Date.now()+e.expires_in*1e3,n={[this.storageKeys.ACCESS_TOKEN]:e.access_token,[this.storageKeys.EXPIRES_AT]:String(t)};e.refresh_token&&(n[this.storageKeys.REFRESH_TOKEN]=e.refresh_token),await this._storageSet(n)}async exchangeCodeForTokens(e){const t=await this._storageGet(this.storageKeys.CODE_VERIFIER);if(!t)throw new Error("Code verifier not found");const n=this._getRedirectUri();try{const r=await fetch(this.authEndpoints.token,{method:"POST",headers:{"Content-Type":"application/x-www-form-urlencoded"},body:new URLSearchParams({grant_type:"authorization_code",code:e,redirect_uri:n,client_id:this.authClientId,code_verifier:t})});if(!r.ok){const d=await r.text();throw new Error(`Token exchange failed: ${r.status} ${d}`)}const a=await r.json(),i=Date.now()+(a.expires_in||3600)*1e3;await this._storageSet({[this.storageKeys.ACCESS_TOKEN]:a.access_token,[this.storageKeys.REFRESH_TOKEN]:a.refresh_token||"",[this.storageKeys.EXPIRES_AT]:String(i)})}finally{await this._storageRemove([this.storageKeys.CODE_VERIFIER,this.storageKeys.STATE])}}async revokeRefreshToken(){const e=await this._storageGet(this.storageKeys.REFRESH_TOKEN);if(e)try{const t=new URLSearchParams({token:e,client_id:this.authClientId,token_type_hint:"refresh_token"});await fetch(this.authEndpoints.revoke,{method:"POST",headers:{"Content-Type":"application/x-www-form-urlencoded"},body:t})}catch(t){this.logger.warn("Token revocation failed:",t)}}async clearAuthStorage(){await this._storageRemove([this.storageKeys.ACCESS_TOKEN,this.storageKeys.REFRESH_TOKEN,this.storageKeys.EXPIRES_AT])}async _bootstrapInitialTokens(e){const t={[this.storageKeys.ACCESS_TOKEN]:e.accessToken};if(e.refreshToken&&(t[this.storageKeys.REFRESH_TOKEN]=e.refreshToken),e.expiresAt!==void 0&&(t[this.storageKeys.EXPIRES_AT]=String(e.expiresAt)),await this._storageSet(t),e.expiresAt!==void 0&&Date.now()>=e.expiresAt-5*1e3)e.refreshToken?await this._tryRefreshToken(e.refreshToken):this.setAuthState({status:"unauthenticated",user:null,accessToken:null,error:null,refreshToken:null,expiresAt:null,isTokenRefresh:!1});else{const r=v(e.accessToken);this.setAuthState({status:"authenticated",user:r,accessToken:e.accessToken,error:null,refreshToken:e.refreshToken??null,expiresAt:e.expiresAt??null,isTokenRefresh:!1})}}async _storageGet(e){if(!this.storage)throw new Error("No storage adapter configured");return this.storage.get(e)}async _storageSet(e){if(!this.storage)throw new Error("No storage adapter configured");await this.storage.set(e)}async _storageRemove(e){if(!this.storage)throw new Error("No storage adapter configured");await this.storage.remove(e)}}function V(o){return async(e,t)=>{const n=new Headers(t?.headers),r=await o();return r&&n.set("Authorization",`Bearer ${r}`),fetch(e,{...t,headers:n})}}function Q(o){return async(e,t)=>{const n=typeof e=="string"?e:e.toString(),r=new URL(n).pathname,a=t?.method||"GET",i={};t?.headers&&new Headers(t.headers).forEach((c,p)=>{i[p]=c});const d=t?.body?JSON.parse(t.body):void 0,u=await o.streamText(a,r,d,i,!0),f=new TextEncoder,m=new ReadableStream({async start(s){try{for await(const c of u.body)s.enqueue(f.encode(c));s.close()}catch(c){s.error(c)}}});return new Response(m,{status:u.status,headers:u.headers})}}class de{constructor(e,t,n){this.connectionMode=null,this.authClientId=e,this.config=t,this.onStateChange=n??l.NOOP_STATE_CALLBACK,this.logger=this.createLogger(t);const r=this.createStoragePrefix(t);this.prefs=new M(r),this.extClient=this.createExtClient(t,a=>this.handleInternalStateChange(a)),this.directClient=this.createDirectClient(e,t,a=>this.handleInternalStateChange(a))}notifyStateChange(){this.persist(),this.onStateChange({type:"client-state",state:this.getState()}),this.getAuthState().then(e=>{this.onStateChange({type:"auth-state",state:e})}).catch(e=>{this.logger.error("Failed to get auth state after client-state change:",e)})}handleInternalStateChange(e){e.type==="client-state"?this.notifyStateChange():e.type==="auth-state"&&this.getAuthState().then(t=>{this.onStateChange({type:"auth-state",state:t})}).catch(t=>{this.logger.error("Failed to get auth state after client-state change:",t)})}serialize(){return{connectionMode:this.connectionMode,direct:this.directClient.serialize(),extension:this.extClient.serialize()}}async debug(){return{type:"FacadeClient",connectionMode:this.connectionMode,authClientId:this.authClientId,config:this.config,extClient:await this.extClient.debug(),directClient:await this.directClient.debug()}}persist(){const e=this.serialize();this.prefs.setSerializedClientState(e),this.logger.debug("Persisted state:",JSON.stringify(e,null,2))}setStateCallback(e){this.onStateChange=e}isNotSetOrDirect(){return this.connectionMode==null||this.connectionMode==="direct"}async init(e={}){const t=this.prefs.getSerializedClientState()??{connectionMode:null,direct:{},extension:{}};if(this.connectionMode===null&&t.connectionMode&&(this.connectionMode=t.connectionMode,this.logger.info("Restored connectionMode from storage:",t.connectionMode)),this.connectionMode===null)return this.logger.info("{connectionMode: null} - Eager connection detection"),await this.directClient.init({savedState:t.direct,selectedConnection:!0,testConnection:!0,serverUrl:e.serverUrl}),this.directClient.isServerReady()&&(this.connectionMode="direct",this.logger.info("Auto-detected direct connection (server ready)")),this.connectionMode===null?(await this.extClient.init({savedState:t.extension,selectedConnection:!0,testConnection:!0,timeoutMs:e.timeoutMs}),this.extClient.isServerReady()&&(this.connectionMode="extension",this.logger.info("Auto-detected extension connection (server ready)"))):await this.extClient.init({savedState:t.extension,selectedConnection:!1,testConnection:!1}),this.notifyStateChange(),this.getState();const n=this.connectionMode==="direct",r=this.connectionMode==="extension";return await this.extClient.init({savedState:t.extension,selectedConnection:r,testConnection:r&&e.testConnection,timeoutMs:e.timeoutMs}),await this.directClient.init({savedState:t.direct,selectedConnection:n,testConnection:n&&e.testConnection,serverUrl:e.serverUrl}),this.notifyStateChange(),!e.testConnection&&this.isClientInitialized()&&!this.isServerReady()&&(this.logger.info("Triggering async server state refresh"),(this.isNotSetOrDirect()?this.directClient:this.extClient).init({testConnection:!0,selectedConnection:!0}).catch(i=>{this.logger.warn("Async server state refresh failed:",i)})),this.getState()}getState(){return this.isNotSetOrDirect()?this.directClient.getState():this.extClient.getState()}isClientInitialized(){return this.isNotSetOrDirect()?this.directClient.isClientInitialized():this.extClient.isClientInitialized()}isServerReady(){return this.isNotSetOrDirect()?this.directClient.isServerReady():this.extClient.isServerReady()}sendExtRequest(e,t){if(this.isNotSetOrDirect())throw new Error("sendExtRequest not available on direct connection");return this.extClient.sendExtRequest(e,t)}sendApiRequest(e,t,n,r,a){return this.isNotSetOrDirect()?this.directClient.sendApiRequest(e,t,n,r,a):this.extClient.sendApiRequest(e,t,n,r,a)}login(e){return this.isNotSetOrDirect()?this.directClient.login(e):this.extClient.login(e)}logout(){return this.isNotSetOrDirect()?this.directClient.logout():this.extClient.logout()}getAuthState(){return this.isNotSetOrDirect()?this.directClient.getAuthState():this.extClient.getAuthState()}requestAccess(e){return this.isNotSetOrDirect()?this.directClient.requestAccess(e):this.extClient.requestAccess(e)}getAccessRequestStatus(e){return this.isNotSetOrDirect()?this.directClient.getAccessRequestStatus(e):this.extClient.getAccessRequestStatus(e)}pollAccessRequestStatus(e,t){return this.isNotSetOrDirect()?this.directClient.pollAccessRequestStatus(e,t):this.extClient.pollAccessRequestStatus(e,t)}pingApi(){return this.isNotSetOrDirect()?this.directClient.pingApi():this.extClient.pingApi()}async getServerState(){return this.isNotSetOrDirect()?this.directClient.getServerState():this.extClient.getServerState()}stream(e,t,n,r,a){return this.isNotSetOrDirect()?this.directClient.stream(e,t,n,r,a):this.extClient.stream(e,t,n,r,a)}async streamText(e,t,n,r,a){return this.isNotSetOrDirect()?this.directClient.streamText(e,t,n,r,a):this.extClient.streamText(e,t,n,r,a)}get chat(){return this._chat??=new S(this)}get models(){return this._models??=new E(this)}get embeddings(){return this._embeddings??=new C(this)}get mcps(){return this._mcps??=new N(this)}createMcpTransportConfig(e){if(this.isNotSetOrDirect()){const t=this.directClient.getState(),n=l.isDirectState(t)&&t.url||"";return{url:new URL(`${n}${e}`),fetch:V(async()=>(await this.getAuthState()).accessToken)}}return{url:new URL(`http://bodhi-ext${e}`),fetch:Q(this)}}getConnectionMode(){return this.connectionMode}async setConnectionMode(e){if(this.logger.info("Switching connection mode to:",e),e==="direct"){if(!this.directClient.isClientInitialized())throw new Error(l.SERVER_ERROR_CODES.SERVER_NOT_READY.message)}else if(e==="extension"){if(!this.extClient.isClientInitialized())throw new Error(l.SERVER_ERROR_CODES.SERVER_NOT_READY.message)}else throw new Error("Invalid connection mode");return this.connectionMode=e,this.notifyStateChange(),this.getState()}async testExtensionConnectivity(e){const t=await this.extClient.init({testConnection:!0,timeoutMs:e});return this.notifyStateChange(),t}async testDirectConnectivity(e){const t=e??this.directClient.serialize().url;if(!t)return this.directClient.getState();const n=await this.directClient.init({serverUrl:t,testConnection:!0});return this.notifyStateChange(),n}async getExtensionState(){const e=this.extClient.getState();if(l.isExtensionState(e))return e;throw new Error("extClient did not return an ExtensionState")}async getDirectState(){const e=this.directClient.getState();if(l.isDirectState(e))return e;throw new Error("directClient did not return a DirectState")}}const fe="production";Object.defineProperty(exports,"BodhiApiError",{enumerable:!0,get:()=>h.BodhiApiError});Object.defineProperty(exports,"BodhiError",{enumerable:!0,get:()=>h.BodhiError});Object.defineProperty(exports,"unwrapResponse",{enumerable:!0,get:()=>h.unwrapResponse});exports.BACKEND_SERVER_NOT_CONNECTED=l.BACKEND_SERVER_NOT_CONNECTED;exports.BACKEND_SERVER_NOT_REACHABLE=l.BACKEND_SERVER_NOT_REACHABLE;exports.DIRECT_STATE_NOT_INITIALIZED=l.DIRECT_STATE_NOT_INITIALIZED;exports.EXTENSION_STATE_NOT_FOUND=l.EXTENSION_STATE_NOT_FOUND;exports.EXTENSION_STATE_NOT_INITIALIZED=l.EXTENSION_STATE_NOT_INITIALIZED;exports.INITIAL_AUTH_STATE=l.INITIAL_AUTH_STATE;exports.InMemoryStorage=l.InMemoryStorage;exports.NOOP_STATE_CALLBACK=l.NOOP_STATE_CALLBACK;exports.PENDING_EXTENSION_READY=l.PENDING_EXTENSION_READY;exports.SERVER_ERROR_CODES=l.SERVER_ERROR_CODES;exports.backendServerNotReady=l.backendServerNotReady;exports.buildError=l.buildError;exports.buildEvent=l.buildEvent;exports.buildResponse=l.buildResponse;exports.createApiError=l.createApiError;exports.createDirectStateNotReachable=l.createDirectStateNotReachable;exports.createDirectStateNotReady=l.createDirectStateNotReady;exports.createDirectStateReady=l.createDirectStateReady;exports.createExtensionStateNotFound=l.createExtensionStateNotFound;exports.createExtensionStateNotInitialized=l.createExtensionStateNotInitialized;exports.createOperationError=l.createOperationError;exports.getBackendServerState=l.getBackendServerState;exports.getExtensionId=l.getExtensionId;exports.getServerUrl=l.getServerUrl;exports.handleRequest=l.handleRequest;exports.isAuthError=l.isAuthError;exports.isAuthLoading=l.isAuthLoading;exports.isAuthenticated=l.isAuthenticated;exports.isClientReady=l.isClientReady;exports.isDirectClientReady=l.isDirectClientReady;exports.isDirectServerReady=l.isDirectServerReady;exports.isDirectState=l.isDirectState;exports.isExtensionClientReady=l.isExtensionClientReady;exports.isExtensionServerReady=l.isExtensionServerReady;exports.isExtensionState=l.isExtensionState;exports.isServerReady=l.isServerReady;exports.throwAccessRequestDenialError=l.throwAccessRequestDenialError;exports.APIResource=y;exports.AccessRequestBuilder=q;exports.BROWSER_CONFIGS=oe;exports.BaseFacadeClient=de;exports.BodhiClientUserPrefsManager=M;exports.CORE_BUILD_MODE=fe;exports.Chat=S;exports.Completions=F;exports.DEFAULT_API_TIMEOUT_MS=x;exports.DEFAULT_POLL_INTERVAL_MS=z;exports.DEFAULT_POLL_TIMEOUT_MS=P;exports.DirectClientBase=ce;exports.Embeddings=C;exports.Logger=L;exports.LoginOptionsBuilder=W;exports.Mcps=N;exports.Models=E;exports.OS_CONFIGS=ie;exports.OnboardingModal=ee;exports.OnboardingModalV2=le;exports.STORAGE_PREFIXES=J;exports.base64UrlEncode=k;exports.createDirectMcpFetch=V;exports.createExtensionMcpFetch=Q;exports.createOAuthEndpoints=U;exports.createStorageKeys=I;exports.createStoragePrefixWithBasePath=X;exports.detectBrowser=G;exports.detectOS=Y;exports.extractUserInfo=v;exports.generateCodeChallenge=ue;exports.generateCodeVerifier=se;exports.isWebUIClient=$;exports.openPopupReview=K;exports.parseJwt=O;exports.pollAccessRequestUntilResolved=R;exports.refreshAccessToken=D;exports.testServerConnectivity=B;
@@ -1,6 +1,6 @@
1
1
  import { unwrapResponse as g, BodhiError as h, BodhiApiError as I } from "@bodhiapp/bodhi-browser-types";
2
2
  import { BodhiApiError as Me, BodhiError as Ie, unwrapResponse as Oe } from "@bodhiapp/bodhi-browser-types";
3
- import { createOperationError as O, throwAccessRequestDenialError as U, buildResponse as D, buildError as F, buildEvent as B, DIRECT_STATE_NOT_INITIALIZED as b, NOOP_STATE_CALLBACK as A, backendServerNotReady as V, BACKEND_SERVER_NOT_CONNECTED as Q, BACKEND_SERVER_NOT_REACHABLE as k, isDirectState as S, SERVER_ERROR_CODES as E, isExtensionState as H } from "./types/index.esm.js";
3
+ import { createOperationError as O, throwAccessRequestDenialError as U, buildResponse as D, buildError as F, buildEvent as B, DIRECT_STATE_NOT_INITIALIZED as b, NOOP_STATE_CALLBACK as A, backendServerNotReady as V, BACKEND_SERVER_NOT_REACHABLE as k, BACKEND_SERVER_NOT_CONNECTED as Q, isDirectState as S, SERVER_ERROR_CODES as E, isExtensionState as H } from "./types/index.esm.js";
4
4
  import { EXTENSION_STATE_NOT_FOUND as De, EXTENSION_STATE_NOT_INITIALIZED as Fe, INITIAL_AUTH_STATE as Be, InMemoryStorage as Ve, PENDING_EXTENSION_READY as Qe, createApiError as He, createDirectStateNotReachable as qe, createDirectStateNotReady as We, createDirectStateReady as Ke, createExtensionStateNotFound as $e, createExtensionStateNotInitialized as Ge, getBackendServerState as Ye, getExtensionId as Je, getServerUrl as Xe, handleRequest as Ze, isAuthError as et, isAuthLoading as tt, isAuthenticated as nt, isClientReady as rt, isDirectClientReady as at, isDirectServerReady as lt, isExtensionClientReady as ot, isExtensionServerReady as it, isServerReady as st } from "./types/index.esm.js";
5
5
  import { UAParser as _ } from "ua-parser-js";
6
6
  import { DEFAULT_SETUP_STATE as q, isRequestMessage as W, MSG as K } from "@bodhiapp/setup-modal-types";
@@ -768,7 +768,7 @@ async function ue(l, e = T) {
768
768
  }
769
769
  class je {
770
770
  constructor(e, t) {
771
- this.serverUrl = null, this.storage = null, this.state = b, this.refreshPromise = null, this.logger = new J(e.loggerPrefix, e.logLevel), this.authClientId = e.authClientId, this.authServerUrl = e.authServerUrl, this.authEndpoints = oe(this.authServerUrl), this.storageKeys = X(e.storagePrefix), this.onStateChange = t ?? A, this.apiTimeoutMs = e.apiTimeoutMs ?? T, this.storage = e.storage ?? null, this.initialTokens = e.initialTokens;
771
+ this.serverUrl = null, this.storage = null, this.state = b, this.refreshPromise = null, this.initPromise = null, this.logger = new J(e.loggerPrefix, e.logLevel), this.authClientId = e.authClientId, this.authServerUrl = e.authServerUrl, this.authEndpoints = oe(this.authServerUrl), this.storageKeys = X(e.storagePrefix), this.onStateChange = t ?? A, this.apiTimeoutMs = e.apiTimeoutMs ?? T, this.storage = e.storage ?? null, this.initialTokens = e.initialTokens;
772
772
  }
773
773
  /**
774
774
  * Set client state and notify callback
@@ -794,33 +794,32 @@ class je {
794
794
  async init(e) {
795
795
  this.initialTokens && (await this._bootstrapInitialTokens(this.initialTokens), this.initialTokens = void 0);
796
796
  const t = e.serverUrl ?? e.savedState?.url ?? this.serverUrl;
797
- if (this.serverUrl && this.serverUrl === t && !e.testConnection)
798
- return this.logger.debug("Already initialized with serverUrl, skipping init"), this.state;
799
- if (this.serverUrl = t, !this.serverUrl)
800
- return this.logger.info("No serverUrl provided, returning not-initialized state"), b;
801
- if (this.logger.info("Initializing with serverUrl:", this.serverUrl), e.testConnection) {
802
- const n = await this.testConnectivity();
803
- let r;
804
- if (n.success && n.serverInfo) {
805
- const a = n.serverInfo.status, o = n.serverInfo.version;
806
- a === "ready" ? r = {
807
- status: "ready",
808
- version: o,
809
- error: null,
810
- deployment: n.serverInfo.deployment ?? null,
811
- client_id: n.serverInfo.client_id ?? null
812
- } : a === "setup" || a === "resource_admin" || a === "error" ? r = V(
813
- a,
814
- o,
815
- void 0,
816
- n.serverInfo.deployment,
817
- n.serverInfo.client_id
818
- ) : r = k;
819
- } else
820
- this.logger.warn("Connection failed:", n.error), r = k;
821
- return this.setState({ type: "direct", url: t, server: r }), this.logger.info("Initialized with testConnection, server state:", r.status), this.state;
822
- }
823
- return e.selectedConnection ? (this.setState({ type: "direct", url: t, server: Q }), this.logger.info("Initialized with selectedConnection, server state: not-connected"), this.state) : (this.logger.info("No selectedConnection, returning not-initialized state"), b);
797
+ return this.serverUrl && this.serverUrl === t && !e.testConnection ? this.initPromise && e.selectedConnection ? (this.logger.debug("Init in-flight for same URL, awaiting existing init"), this.initPromise) : (this.logger.debug("Already initialized with serverUrl, skipping init"), this.state) : (this.serverUrl = t, this.serverUrl ? (this.logger.info("Initializing with serverUrl:", this.serverUrl), e.testConnection ? (this.initPromise = (async () => {
798
+ try {
799
+ const n = await this.testConnectivity();
800
+ let r;
801
+ if (n.success && n.serverInfo) {
802
+ const a = n.serverInfo.status, o = n.serverInfo.version;
803
+ a === "ready" ? r = {
804
+ status: "ready",
805
+ version: o,
806
+ error: null,
807
+ deployment: n.serverInfo.deployment ?? null,
808
+ client_id: n.serverInfo.client_id ?? null
809
+ } : a === "setup" || a === "resource_admin" || a === "error" ? r = V(
810
+ a,
811
+ o,
812
+ void 0,
813
+ n.serverInfo.deployment,
814
+ n.serverInfo.client_id
815
+ ) : r = k;
816
+ } else
817
+ this.logger.warn("Connection failed:", n.error), r = k;
818
+ return this.setState({ type: "direct", url: t, server: r }), this.logger.info("Initialized with testConnection, server state:", r.status), this.state;
819
+ } finally {
820
+ this.initPromise = null;
821
+ }
822
+ })(), this.initPromise) : e.selectedConnection ? (this.setState({ type: "direct", url: t, server: Q }), this.logger.info("Initialized with selectedConnection, server state: not-connected"), this.state) : (this.logger.info("No selectedConnection, returning not-initialized state"), b)) : (this.logger.info("No serverUrl provided, returning not-initialized state"), b));
824
823
  }
825
824
  getState() {
826
825
  return this.state;