@bodhiapp/bodhi-js 0.0.11 → 0.0.12
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/bodhi-web.cjs.js
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
"use strict";Object.defineProperty(exports,Symbol.toStringTag,{value:"Module"});const r=require("@bodhiapp/bodhi-js-core");class d extends r.DirectClientBase{constructor(e,t){const o=r.createStoragePrefixWithBasePath(e.basePath,r.STORAGE_PREFIXES.WEB_DIRECT),s={authClientId:e.authClientId,authServerUrl:e.authServerUrl,userScope:e.userScope,storagePrefix:o,logLevel:e.logLevel,loggerPrefix:"DirectWebClient"};super(s,t),this.redirectUri=e.redirectUri}async login(){const e=await this.getAuthState();if(e.status==="authenticated")return e;const t=await this.requestResourceAccess();if(r.isApiResultOperationError(t))throw r.createOperationError(t.error.message,t.error.type);if(r.isApiResultError(t)){const{message:n}=t.body.error;throw r.createOperationError(n,"auth_error")}if(!r.isApiResultSuccess(t))throw r.createOperationError(`Unexpected HTTP ${t.status}`,"auth_error");const o=t.body.scope;localStorage.setItem(this.storageKeys.RESOURCE_SCOPE,o);const s=`openid profile email roles ${this.userScope} ${o}`,a=r.generateCodeVerifier(),i=await r.generateCodeChallenge(a),h=r.generateCodeVerifier();localStorage.setItem(this.storageKeys.CODE_VERIFIER,a),localStorage.setItem(this.storageKeys.STATE,h);const c=new URL(this.authEndpoints.authorize);throw c.searchParams.set("client_id",this.authClientId),c.searchParams.set("response_type","code"),c.searchParams.set("redirect_uri",this.redirectUri),c.searchParams.set("scope",s),c.searchParams.set("code_challenge",i),c.searchParams.set("code_challenge_method","S256"),c.searchParams.set("state",h),window.location.href=c.toString(),new Error("Redirect initiated")}async handleOAuthCallback(e,t){const o=localStorage.getItem(this.storageKeys.STATE);if(!o||o!==t)throw new Error("Invalid state parameter - possible CSRF attack");await this.exchangeCodeForTokens(e),localStorage.removeItem(this.storageKeys.CODE_VERIFIER),localStorage.removeItem(this.storageKeys.STATE);const s=await this.getAuthState();if(s.status!=="authenticated")throw new Error("Login failed");return this.setAuthState(s),s}async logout(){const e=localStorage.getItem(this.storageKeys.REFRESH_TOKEN);if(e)try{const o=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:o})}catch(o){this.logger.warn("Token revocation failed:",o)}localStorage.removeItem(this.storageKeys.ACCESS_TOKEN),localStorage.removeItem(this.storageKeys.REFRESH_TOKEN),localStorage.removeItem(this.storageKeys.EXPIRES_AT),localStorage.removeItem(this.storageKeys.RESOURCE_SCOPE);const t={status:"unauthenticated",user:null,accessToken:null,error:null};return this.setAuthState(t),t}async exchangeCodeForTokens(e){const t=localStorage.getItem(this.storageKeys.CODE_VERIFIER);if(!t)throw new Error("Code verifier not found");const o=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:this.redirectUri,client_id:this.authClientId,code_verifier:t})});if(!o.ok){const a=await o.text();throw new Error(`Token exchange failed: ${o.status} ${a}`)}const s=await o.json();if(localStorage.setItem(this.storageKeys.ACCESS_TOKEN,s.access_token),s.refresh_token&&localStorage.setItem(this.storageKeys.REFRESH_TOKEN,s.refresh_token),s.expires_in){const a=Date.now()+s.expires_in*1e3;localStorage.setItem(this.storageKeys.EXPIRES_AT,a.toString())}}async _storageGet(e){return localStorage.getItem(e)}async _storageSet(e){Object.entries(e).forEach(([t,o])=>{localStorage.setItem(t,String(o))})}async _storageRemove(e){e.forEach(t=>localStorage.removeItem(t))}_getRedirectUri(){return this.redirectUri}}const g=500,E=5e3;class S{constructor(e,t,o){this.state=r.EXTENSION_STATE_NOT_INITIALIZED,this.bodhiext=null,this.refreshPromise=null,this.logger=new r.Logger("WindowBodhiextClient",t.logLevel),this.authClientId=e,this.config=t,this.authEndpoints=r.createOAuthEndpoints(this.config.authServerUrl),this.onStateChange=o??r.NOOP_STATE_CALLBACK;const s=r.createStoragePrefixWithBasePath(t.basePath,r.STORAGE_PREFIXES.WEB_EXT);this.storageKeys=r.createStorageKeys(s)}setState(e){this.state=e,this.logger.info(`{state: ${JSON.stringify(e)}} - Setting client state`),this.onStateChange({type:"client-state",state:e})}setAuthState(e){this.onStateChange({type:"auth-state",state:e})}setStateCallback(e){this.onStateChange=e}ensureBodhiext(){if(!this.bodhiext&&window.bodhiext&&(this.logger.info("Acquiring window.bodhiext reference"),this.bodhiext=window.bodhiext),!this.bodhiext)throw r.createOperationError("Client not initialized","extension_error")}async sendExtRequest(e,t){return this.ensureBodhiext(),this.bodhiext.sendExtRequest(e,t)}async sendApiRequest(e,t,o,s,a){try{this.ensureBodhiext()}catch(i){return{error:{message:i instanceof Error?i.message:String(i),type:"extension_error"}}}try{let i=s||{};if(a){const c=await this._getAccessTokenRaw();if(!c)return{error:{message:"Not authenticated. Please log in first.",type:"extension_error"}};i={...i,Authorization:`Bearer ${c}`}}return await this.bodhiext.sendApiRequest(e,t,o,i)}catch(i){const h=i?.error,c=h?.message??(i instanceof Error?i.message:String(i)),n=h?.type||"extension_error";return{error:{message:c,type:n}}}}getState(){return this.state}isClientInitialized(){return this.state.extension==="ready"}isServerReady(){return this.isClientInitialized()&&this.state.server.status==="ready"}async init(e={}){if(!e.testConnection&&!e.selectedConnection)return this.logger.info("No testConnection or selectedConnection, returning not-initialized state"),r.EXTENSION_STATE_NOT_INITIALIZED;if(this.bodhiext&&!e.testConnection)return this.logger.debug("Already have bodhiext handle, skipping polling"),this.state;if(!this.bodhiext){const s=e.timeoutMs??this.config.initParams?.extension?.timeoutMs??E,a=e.intervalMs??this.config.initParams?.extension?.intervalMs??g,i=Date.now();if(!await new Promise(c=>{const n=()=>{if(window.bodhiext){this.bodhiext=window.bodhiext,c(!0);return}if(Date.now()-i>=s){c(!1);return}setTimeout(n,a)};n()}))return this.logger.warn("Extension discovery timed out"),this.setState(r.EXTENSION_STATE_NOT_FOUND),this.state}const t=await this.bodhiext.getExtensionId();this.logger.info(`Extension discovered: ${t}`);const o={type:"extension",extension:"ready",extensionId:t,server:r.PENDING_EXTENSION_READY};if(e.testConnection)try{const s=await this.getServerState();this.setState({...o,server:s}),this.logger.info(`Server connectivity tested: ${s.status}`)}catch(s){this.logger.error("Failed to get server state:",s),this.setState({...o,server:r.BACKEND_SERVER_NOT_REACHABLE})}else this.setState(o);return this.state}async requestResourceAccess(){return this.ensureBodhiext(),this.bodhiext.sendApiRequest("POST","/bodhi/v1/apps/request-access",{app_client_id:this.authClientId})}async login(){const e=await this.getAuthState();if(e.status==="authenticated")return e;this.ensureBodhiext();const t=await this.requestResourceAccess();if(r.isApiResultOperationError(t))throw r.createOperationError(t.error.message,t.error.type);if(r.isApiResultError(t)){const{message:l}=t.body.error;throw r.createOperationError(l,"auth_error")}if(!r.isApiResultSuccess(t))throw r.createOperationError(`Unexpected HTTP ${t.status}`,"auth_error");const o=t.body.scope;localStorage.setItem(this.storageKeys.RESOURCE_SCOPE,o);const s=r.generateCodeVerifier(),a=await r.generateCodeChallenge(s),i=r.generateCodeVerifier();localStorage.setItem(this.storageKeys.CODE_VERIFIER,s),localStorage.setItem(this.storageKeys.STATE,i);const h=["openid","profile","email","roles",this.config.userScope,o],c=new URLSearchParams({response_type:"code",client_id:this.authClientId,redirect_uri:this.config.redirectUri,scope:h.join(" "),state:i,code_challenge:a,code_challenge_method:"S256"}),n=`${this.authEndpoints.authorize}?${c}`;return window.location.href=n,new Promise(()=>{})}async handleOAuthCallback(e,t){const o=localStorage.getItem(this.storageKeys.STATE);if(!o||o!==t)throw new Error("Invalid state parameter - possible CSRF attack");await this.exchangeCodeForTokens(e),localStorage.removeItem(this.storageKeys.CODE_VERIFIER),localStorage.removeItem(this.storageKeys.STATE);const s=await this.getAuthState();if(s.status!=="authenticated")throw new Error("Login failed");return this.setAuthState(s),s}async exchangeCodeForTokens(e){const t=localStorage.getItem(this.storageKeys.CODE_VERIFIER);if(!t)throw new Error("Code verifier not found");const o=new URLSearchParams({grant_type:"authorization_code",client_id:this.authClientId,code:e,redirect_uri:this.config.redirectUri,code_verifier:t}),s=await fetch(this.authEndpoints.token,{method:"POST",headers:{"Content-Type":"application/x-www-form-urlencoded"},body:o});if(!s.ok){const i=await s.text();throw new Error(`Token exchange failed: ${s.status} ${i}`)}const a=await s.json();if(!a.access_token)throw new Error("No access token received");if(localStorage.setItem(this.storageKeys.ACCESS_TOKEN,a.access_token),a.refresh_token&&localStorage.setItem(this.storageKeys.REFRESH_TOKEN,a.refresh_token),a.expires_in){const i=Date.now()+a.expires_in*1e3;localStorage.setItem(this.storageKeys.EXPIRES_AT,i.toString())}}async logout(){const e=localStorage.getItem(this.storageKeys.REFRESH_TOKEN);if(e)try{const o=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:o})}catch(o){this.logger.warn("Token revocation failed:",o)}localStorage.removeItem(this.storageKeys.ACCESS_TOKEN),localStorage.removeItem(this.storageKeys.REFRESH_TOKEN),localStorage.removeItem(this.storageKeys.EXPIRES_AT),localStorage.removeItem(this.storageKeys.CODE_VERIFIER),localStorage.removeItem(this.storageKeys.STATE),localStorage.removeItem(this.storageKeys.RESOURCE_SCOPE);const t={status:"unauthenticated",user:null,accessToken:null,error:null};return this.setAuthState(t),t}async getAuthState(){const e=await this._getAccessTokenRaw();if(!e)return{status:"unauthenticated",user:null,accessToken:null,error:null};try{return{status:"authenticated",user:r.extractUserInfo(e),accessToken:e,error:null}}catch(t){return this.logger.error("Failed to parse token:",t),{status:"unauthenticated",user:null,accessToken:null,error:null}}}async _getAccessTokenRaw(){const e=localStorage.getItem(this.storageKeys.ACCESS_TOKEN),t=localStorage.getItem(this.storageKeys.EXPIRES_AT);if(!e)return null;if(t){const o=parseInt(t,10);if(Date.now()>=o-5*1e3){const s=localStorage.getItem(this.storageKeys.REFRESH_TOKEN);return s?this._tryRefreshToken(s):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 r.refreshAccessToken(this.authEndpoints.token,e,this.authClientId);if(t){this._storeRefreshedTokens(t);const o=r.extractUserInfo(t.access_token);return this.setAuthState({status:"authenticated",user:o,accessToken:t.access_token,error:null}),this.logger.info("Token refreshed successfully"),t.access_token}}catch(t){this.logger.warn("Token refresh failed:",t)}throw this.logger.warn("Token refresh failed, keeping tokens for manual retry"),r.createOperationError("Access token expired and unable to refresh. Try logging out and logging in again.","token_refresh_failed")}_storeRefreshedTokens(e){const t=Date.now()+e.expires_in*1e3;localStorage.setItem(this.storageKeys.ACCESS_TOKEN,e.access_token),localStorage.setItem(this.storageKeys.EXPIRES_AT,String(t)),e.refresh_token&&localStorage.setItem(this.storageKeys.REFRESH_TOKEN,e.refresh_token)}async pingApi(){return this.sendApiRequest("GET","/ping")}async getServerState(){const e=await this.sendApiRequest("GET","/bodhi/v1/info");if(r.isApiResultOperationError(e)||!r.isApiResultSuccess(e))return r.BACKEND_SERVER_NOT_REACHABLE;const t=e.body;switch(t.status){case"ready":return{status:"ready",version:t.version||"unknown",error:null};case"setup":return r.backendServerNotReady("setup",t.version||"unknown");case"resource-admin":return r.backendServerNotReady("resource-admin",t.version||"unknown");case"error":return r.backendServerNotReady("error",t.version||"unknown",t.error?{message:t.error.message,type:t.error.type}:r.SERVER_ERROR_CODES.SERVER_NOT_READY);default:return r.BACKEND_SERVER_NOT_REACHABLE}}async*stream(e,t,o,s,a=!0){this.ensureBodhiext();let i=s||{};if(a){const n=await this._getAccessTokenRaw();if(!n)throw r.createOperationError("Not authenticated. Please log in first.","auth_error");i={...i,Authorization:`Bearer ${n}`}}const c=this.bodhiext.sendStreamRequest(e,t,o,i).getReader();try{for(;;){const{value:n,done:l}=await c.read();if(l||n?.done)break;yield n.body}}catch(n){if(n instanceof Error){if("response"in n){const l=n;throw r.createApiError(n.message,l.response.status,l.response.body)}throw"error"in n,r.createOperationError(n.message,"extension_error")}throw n}finally{c.releaseLock()}}get chat(){return this._chat??=new r.Chat(this)}get models(){return this._models??=new r.Models(this)}get embeddings(){return this._embeddings??=new r.Embeddings(this)}serialize(){return{extensionId:this.state.type==="extension"&&this.state.extension==="ready"?this.state.extensionId:void 0}}async debug(){return{type:"WindowBodhiextClient",state:this.state,authState:await this.getAuthState(),bodhiextAvailable:this.bodhiext!==null,authClientId:this.authClientId,authServerUrl:this.config.authServerUrl,redirectUri:this.config.redirectUri,userScope:this.config.userScope}}}function f(u){if(typeof window>"u")throw new Error("redirectUri required in non-browser environment");const e=u==="/"?"":u.replace(/\/$/,"");return`${window.location.origin}${e}/callback`}class _ extends r.BaseFacadeClient{constructor(e,t,o){const s=t||{},a={basePath:s.basePath||"/",redirectUri:s.redirectUri||f(s.basePath||"/"),authServerUrl:s.authServerUrl||"https://id.getbodhi.app/realms/bodhi",userScope:s.userScope||"scope_user_user",logLevel:s.logLevel||"warn",initParams:s.initParams};super(e,a,o)}createLogger(e){return new r.Logger("WebUIClient",e.logLevel)}createStoragePrefix(e){return r.createStoragePrefixWithBasePath(e.basePath,r.STORAGE_PREFIXES.WEB)}createExtClient(e,t){return new S(this.authClientId,{authServerUrl:e.authServerUrl,redirectUri:e.redirectUri,userScope:e.userScope,basePath:e.basePath,logLevel:e.logLevel,initParams:e.initParams},t)}createDirectClient(e,t,o){return new d({authClientId:e,authServerUrl:t.authServerUrl,redirectUri:t.redirectUri,userScope:t.userScope,logLevel:t.logLevel,basePath:t.basePath},o)}async handleOAuthCallback(e,t){return this.connectionMode==="direct"?this.directClient.handleOAuthCallback(e,t):this.extClient.handleOAuthCallback(e,t)}}const p="production";exports.WEB_BUILD_MODE=p;exports.WebUIClient=_;
|
|
1
|
+
"use strict";Object.defineProperty(exports,Symbol.toStringTag,{value:"Module"});const r=require("@bodhiapp/bodhi-js-core");class d extends r.DirectClientBase{constructor(e,t){const o=r.createStoragePrefixWithBasePath(e.basePath,r.STORAGE_PREFIXES.WEB_DIRECT),s={authClientId:e.authClientId,authServerUrl:e.authServerUrl,userScope:e.userScope,storagePrefix:o,logLevel:e.logLevel,loggerPrefix:"DirectWebClient"};super(s,t),this.redirectUri=e.redirectUri}async login(){const e=await this.getAuthState();if(e.status==="authenticated")return e;const t=await this.requestResourceAccess();if(r.isApiResultOperationError(t))throw r.createOperationError(t.error.message,t.error.type);if(r.isApiResultError(t)){const{message:n}=t.body.error;throw r.createOperationError(n,"auth_error")}if(!r.isApiResultSuccess(t))throw r.createOperationError(`Unexpected HTTP ${t.status}`,"auth_error");const o=t.body.scope;localStorage.setItem(this.storageKeys.RESOURCE_SCOPE,o);const s=`openid profile email roles ${this.userScope} ${o}`,i=r.generateCodeVerifier(),a=await r.generateCodeChallenge(i),h=r.generateCodeVerifier();localStorage.setItem(this.storageKeys.CODE_VERIFIER,i),localStorage.setItem(this.storageKeys.STATE,h);const c=new URL(this.authEndpoints.authorize);throw c.searchParams.set("client_id",this.authClientId),c.searchParams.set("response_type","code"),c.searchParams.set("redirect_uri",this.redirectUri),c.searchParams.set("scope",s),c.searchParams.set("code_challenge",a),c.searchParams.set("code_challenge_method","S256"),c.searchParams.set("state",h),window.location.href=c.toString(),new Error("Redirect initiated")}async handleOAuthCallback(e,t){const o=localStorage.getItem(this.storageKeys.STATE);if(!o||o!==t)throw new Error("Invalid state parameter - possible CSRF attack");await this.exchangeCodeForTokens(e),localStorage.removeItem(this.storageKeys.CODE_VERIFIER),localStorage.removeItem(this.storageKeys.STATE);const s=await this.getAuthState();if(s.status!=="authenticated")throw new Error("Login failed");return this.setAuthState(s),s}async logout(){const e=localStorage.getItem(this.storageKeys.REFRESH_TOKEN);if(e)try{const o=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:o})}catch(o){this.logger.warn("Token revocation failed:",o)}localStorage.removeItem(this.storageKeys.ACCESS_TOKEN),localStorage.removeItem(this.storageKeys.REFRESH_TOKEN),localStorage.removeItem(this.storageKeys.EXPIRES_AT),localStorage.removeItem(this.storageKeys.RESOURCE_SCOPE);const t={status:"unauthenticated",user:null,accessToken:null,error:null};return this.setAuthState(t),t}async exchangeCodeForTokens(e){const t=localStorage.getItem(this.storageKeys.CODE_VERIFIER);if(!t)throw new Error("Code verifier not found");const o=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:this.redirectUri,client_id:this.authClientId,code_verifier:t})});if(!o.ok){const i=await o.text();throw new Error(`Token exchange failed: ${o.status} ${i}`)}const s=await o.json();if(localStorage.setItem(this.storageKeys.ACCESS_TOKEN,s.access_token),s.refresh_token&&localStorage.setItem(this.storageKeys.REFRESH_TOKEN,s.refresh_token),s.expires_in){const i=Date.now()+s.expires_in*1e3;localStorage.setItem(this.storageKeys.EXPIRES_AT,i.toString())}}async _storageGet(e){return localStorage.getItem(e)}async _storageSet(e){Object.entries(e).forEach(([t,o])=>{localStorage.setItem(t,String(o))})}async _storageRemove(e){e.forEach(t=>localStorage.removeItem(t))}_getRedirectUri(){return this.redirectUri}}const g=500,S=5e3;class E{constructor(e,t,o){this.state=r.EXTENSION_STATE_NOT_INITIALIZED,this.bodhiext=null,this.refreshPromise=null,this.logger=new r.Logger("WindowBodhiextClient",t.logLevel),this.authClientId=e,this.config=t,this.authEndpoints=r.createOAuthEndpoints(this.config.authServerUrl),this.onStateChange=o??r.NOOP_STATE_CALLBACK;const s=r.createStoragePrefixWithBasePath(t.basePath,r.STORAGE_PREFIXES.WEB_EXT);this.storageKeys=r.createStorageKeys(s)}setState(e){this.state=e,this.logger.info(`{state: ${JSON.stringify(e)}} - Setting client state`),this.onStateChange({type:"client-state",state:e})}setAuthState(e){this.onStateChange({type:"auth-state",state:e})}setStateCallback(e){this.onStateChange=e}ensureBodhiext(){if(!this.bodhiext&&window.bodhiext&&(this.logger.info("Acquiring window.bodhiext reference"),this.bodhiext=window.bodhiext),!this.bodhiext)throw r.createOperationError("Client not initialized","extension_error")}async sendExtRequest(e,t){return this.ensureBodhiext(),this.bodhiext.sendExtRequest(e,t)}async sendApiRequest(e,t,o,s,i){try{this.ensureBodhiext()}catch(a){return{error:{message:a instanceof Error?a.message:String(a),type:"extension_error"}}}try{let a=s||{};if(i){const c=await this._getAccessTokenRaw();if(!c)return{error:{message:"Not authenticated. Please log in first.",type:"extension_error"}};a={...a,Authorization:`Bearer ${c}`}}return await this.bodhiext.sendApiRequest(e,t,o,a)}catch(a){const h=a?.error,c=h?.message??(a instanceof Error?a.message:String(a)),n=h?.type||"extension_error";return{error:{message:c,type:n}}}}getState(){return this.state}isClientInitialized(){return this.state.extension==="ready"}isServerReady(){return this.isClientInitialized()&&this.state.server.status==="ready"}async init(e={}){if(!e.testConnection&&!e.selectedConnection)return this.logger.info("No testConnection or selectedConnection, returning not-initialized state"),r.EXTENSION_STATE_NOT_INITIALIZED;if(this.bodhiext&&!e.testConnection)return this.logger.debug("Already have bodhiext handle, skipping polling"),this.state;if(!this.bodhiext){const s=e.timeoutMs??this.config.initParams?.extension?.timeoutMs??S,i=e.intervalMs??this.config.initParams?.extension?.intervalMs??g,a=Date.now();if(!await new Promise(c=>{const n=()=>{if(window.bodhiext){this.bodhiext=window.bodhiext,c(!0);return}if(Date.now()-a>=s){c(!1);return}setTimeout(n,i)};n()}))return this.logger.warn("Extension discovery timed out"),this.setState(r.EXTENSION_STATE_NOT_FOUND),this.state}const t=await this.bodhiext.getExtensionId();this.logger.info(`Extension discovered: ${t}`);const o={type:"extension",extension:"ready",extensionId:t,server:r.PENDING_EXTENSION_READY};if(e.testConnection)try{const s=await this.getServerState();this.setState({...o,server:s}),this.logger.info(`Server connectivity tested: ${s.status}`)}catch(s){this.logger.error("Failed to get server state:",s),this.setState({...o,server:r.BACKEND_SERVER_NOT_REACHABLE})}else this.setState(o);return this.state}async requestResourceAccess(){return this.ensureBodhiext(),this.bodhiext.sendApiRequest("POST","/bodhi/v1/apps/request-access",{app_client_id:this.authClientId})}async login(){const e=await this.getAuthState();if(e.status==="authenticated")return e;this.ensureBodhiext();const t=await this.requestResourceAccess();if(r.isApiResultOperationError(t))throw r.createOperationError(t.error.message,t.error.type);if(r.isApiResultError(t)){const{message:l}=t.body.error;throw r.createOperationError(l,"auth_error")}if(!r.isApiResultSuccess(t))throw r.createOperationError(`Unexpected HTTP ${t.status}`,"auth_error");const o=t.body.scope;localStorage.setItem(this.storageKeys.RESOURCE_SCOPE,o);const s=r.generateCodeVerifier(),i=await r.generateCodeChallenge(s),a=r.generateCodeVerifier();localStorage.setItem(this.storageKeys.CODE_VERIFIER,s),localStorage.setItem(this.storageKeys.STATE,a);const h=["openid","profile","email","roles",this.config.userScope,o],c=new URLSearchParams({response_type:"code",client_id:this.authClientId,redirect_uri:this.config.redirectUri,scope:h.join(" "),state:a,code_challenge:i,code_challenge_method:"S256"}),n=`${this.authEndpoints.authorize}?${c}`;return window.location.href=n,new Promise(()=>{})}async handleOAuthCallback(e,t){const o=localStorage.getItem(this.storageKeys.STATE);if(!o||o!==t)throw new Error("Invalid state parameter - possible CSRF attack");await this.exchangeCodeForTokens(e),localStorage.removeItem(this.storageKeys.CODE_VERIFIER),localStorage.removeItem(this.storageKeys.STATE);const s=await this.getAuthState();if(s.status!=="authenticated")throw new Error("Login failed");return this.setAuthState(s),s}async exchangeCodeForTokens(e){const t=localStorage.getItem(this.storageKeys.CODE_VERIFIER);if(!t)throw new Error("Code verifier not found");const o=new URLSearchParams({grant_type:"authorization_code",client_id:this.authClientId,code:e,redirect_uri:this.config.redirectUri,code_verifier:t}),s=await fetch(this.authEndpoints.token,{method:"POST",headers:{"Content-Type":"application/x-www-form-urlencoded"},body:o});if(!s.ok){const a=await s.text();throw new Error(`Token exchange failed: ${s.status} ${a}`)}const i=await s.json();if(!i.access_token)throw new Error("No access token received");if(localStorage.setItem(this.storageKeys.ACCESS_TOKEN,i.access_token),i.refresh_token&&localStorage.setItem(this.storageKeys.REFRESH_TOKEN,i.refresh_token),i.expires_in){const a=Date.now()+i.expires_in*1e3;localStorage.setItem(this.storageKeys.EXPIRES_AT,a.toString())}}async logout(){const e=localStorage.getItem(this.storageKeys.REFRESH_TOKEN);if(e)try{const o=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:o})}catch(o){this.logger.warn("Token revocation failed:",o)}localStorage.removeItem(this.storageKeys.ACCESS_TOKEN),localStorage.removeItem(this.storageKeys.REFRESH_TOKEN),localStorage.removeItem(this.storageKeys.EXPIRES_AT),localStorage.removeItem(this.storageKeys.CODE_VERIFIER),localStorage.removeItem(this.storageKeys.STATE),localStorage.removeItem(this.storageKeys.RESOURCE_SCOPE);const t={status:"unauthenticated",user:null,accessToken:null,error:null};return this.setAuthState(t),t}async getAuthState(){const e=await this._getAccessTokenRaw();if(!e)return{status:"unauthenticated",user:null,accessToken:null,error:null};try{return{status:"authenticated",user:r.extractUserInfo(e),accessToken:e,error:null}}catch(t){return this.logger.error("Failed to parse token:",t),{status:"unauthenticated",user:null,accessToken:null,error:null}}}async _getAccessTokenRaw(){const e=localStorage.getItem(this.storageKeys.ACCESS_TOKEN),t=localStorage.getItem(this.storageKeys.EXPIRES_AT);if(!e)return null;if(t){const o=parseInt(t,10);if(Date.now()>=o-5*1e3){const s=localStorage.getItem(this.storageKeys.REFRESH_TOKEN);return s?this._tryRefreshToken(s):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 r.refreshAccessToken(this.authEndpoints.token,e,this.authClientId);if(t.success){this._storeRefreshedTokens(t.tokens);const o=r.extractUserInfo(t.tokens.access_token);return this.setAuthState({status:"authenticated",user:o,accessToken:t.tokens.access_token,error:null}),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"),this.clearAuthStorage(),this.setAuthState({status:"unauthenticated",user:null,accessToken:null,error:null}),null}catch(t){this.logger.warn("Token refresh failed:",t)}throw this.logger.warn("Token refresh failed, keeping tokens for manual retry"),r.createOperationError("Access token expired and unable to refresh. Try logging out and logging in again.","token_refresh_failed")}clearAuthStorage(){localStorage.removeItem(this.storageKeys.ACCESS_TOKEN),localStorage.removeItem(this.storageKeys.REFRESH_TOKEN),localStorage.removeItem(this.storageKeys.EXPIRES_AT),localStorage.removeItem(this.storageKeys.RESOURCE_SCOPE)}_storeRefreshedTokens(e){const t=Date.now()+e.expires_in*1e3;localStorage.setItem(this.storageKeys.ACCESS_TOKEN,e.access_token),localStorage.setItem(this.storageKeys.EXPIRES_AT,String(t)),e.refresh_token&&localStorage.setItem(this.storageKeys.REFRESH_TOKEN,e.refresh_token)}async pingApi(){return this.sendApiRequest("GET","/ping")}async getServerState(){const e=await this.sendApiRequest("GET","/bodhi/v1/info");if(r.isApiResultOperationError(e)||!r.isApiResultSuccess(e))return r.BACKEND_SERVER_NOT_REACHABLE;const t=e.body;switch(t.status){case"ready":return{status:"ready",version:t.version||"unknown",error:null};case"setup":return r.backendServerNotReady("setup",t.version||"unknown");case"resource-admin":return r.backendServerNotReady("resource-admin",t.version||"unknown");case"error":return r.backendServerNotReady("error",t.version||"unknown",t.error?{message:t.error.message,type:t.error.type}:r.SERVER_ERROR_CODES.SERVER_NOT_READY);default:return r.BACKEND_SERVER_NOT_REACHABLE}}async*stream(e,t,o,s,i=!0){this.ensureBodhiext();let a=s||{};if(i){const n=await this._getAccessTokenRaw();if(!n)throw r.createOperationError("Not authenticated. Please log in first.","auth_error");a={...a,Authorization:`Bearer ${n}`}}const c=this.bodhiext.sendStreamRequest(e,t,o,a).getReader();try{for(;;){const{value:n,done:l}=await c.read();if(l||n?.done)break;yield n.body}}catch(n){if(n instanceof Error){if("response"in n){const l=n;throw r.createApiError(n.message,l.response.status,l.response.body)}throw"error"in n,r.createOperationError(n.message,"extension_error")}throw n}finally{c.releaseLock()}}get chat(){return this._chat??=new r.Chat(this)}get models(){return this._models??=new r.Models(this)}get embeddings(){return this._embeddings??=new r.Embeddings(this)}serialize(){return{extensionId:this.state.type==="extension"&&this.state.extension==="ready"?this.state.extensionId:void 0}}async debug(){return{type:"WindowBodhiextClient",state:this.state,authState:await this.getAuthState(),bodhiextAvailable:this.bodhiext!==null,authClientId:this.authClientId,authServerUrl:this.config.authServerUrl,redirectUri:this.config.redirectUri,userScope:this.config.userScope}}}function f(u){if(typeof window>"u")throw new Error("redirectUri required in non-browser environment");const e=u==="/"?"":u.replace(/\/$/,"");return`${window.location.origin}${e}/callback`}class _ extends r.BaseFacadeClient{constructor(e,t,o){const s=t||{},i={basePath:s.basePath||"/",redirectUri:s.redirectUri||f(s.basePath||"/"),authServerUrl:s.authServerUrl||"https://id.getbodhi.app/realms/bodhi",userScope:s.userScope||"scope_user_user",logLevel:s.logLevel||"warn",initParams:s.initParams};super(e,i,o)}createLogger(e){return new r.Logger("WebUIClient",e.logLevel)}createStoragePrefix(e){return r.createStoragePrefixWithBasePath(e.basePath,r.STORAGE_PREFIXES.WEB)}createExtClient(e,t){return new E(this.authClientId,{authServerUrl:e.authServerUrl,redirectUri:e.redirectUri,userScope:e.userScope,basePath:e.basePath,logLevel:e.logLevel,initParams:e.initParams},t)}createDirectClient(e,t,o){return new d({authClientId:e,authServerUrl:t.authServerUrl,redirectUri:t.redirectUri,userScope:t.userScope,logLevel:t.logLevel,basePath:t.basePath},o)}async handleOAuthCallback(e,t){return this.connectionMode==="direct"?this.directClient.handleOAuthCallback(e,t):this.extClient.handleOAuthCallback(e,t)}}const p="production";exports.WEB_BUILD_MODE=p;exports.WebUIClient=_;
|
package/dist/bodhi-web.esm.js
CHANGED
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import { DirectClientBase as R, createStoragePrefixWithBasePath as m, STORAGE_PREFIXES as _, isApiResultOperationError as E, createOperationError as h, isApiResultError as
|
|
1
|
+
import { DirectClientBase as R, createStoragePrefixWithBasePath as m, STORAGE_PREFIXES as _, isApiResultOperationError as E, createOperationError as h, isApiResultError as p, isApiResultSuccess as f, generateCodeVerifier as g, generateCodeChallenge as T, EXTENSION_STATE_NOT_INITIALIZED as w, Logger as I, createOAuthEndpoints as C, NOOP_STATE_CALLBACK as k, createStorageKeys as x, EXTENSION_STATE_NOT_FOUND as A, PENDING_EXTENSION_READY as v, BACKEND_SERVER_NOT_REACHABLE as d, extractUserInfo as y, refreshAccessToken as b, backendServerNotReady as S, SERVER_ERROR_CODES as O, createApiError as P, Chat as K, Models as U, Embeddings as N, BaseFacadeClient as L } from "@bodhiapp/bodhi-js-core";
|
|
2
2
|
class D extends R {
|
|
3
3
|
constructor(e, t) {
|
|
4
4
|
const s = m(
|
|
@@ -24,16 +24,16 @@ class D extends R {
|
|
|
24
24
|
const t = await this.requestResourceAccess();
|
|
25
25
|
if (E(t))
|
|
26
26
|
throw h(t.error.message, t.error.type);
|
|
27
|
-
if (
|
|
28
|
-
const { message:
|
|
29
|
-
throw h(
|
|
27
|
+
if (p(t)) {
|
|
28
|
+
const { message: i } = t.body.error;
|
|
29
|
+
throw h(i, "auth_error");
|
|
30
30
|
}
|
|
31
31
|
if (!f(t))
|
|
32
32
|
throw h(`Unexpected HTTP ${t.status}`, "auth_error");
|
|
33
33
|
const s = t.body.scope;
|
|
34
34
|
localStorage.setItem(this.storageKeys.RESOURCE_SCOPE, s);
|
|
35
|
-
const r = `openid profile email roles ${this.userScope} ${s}`,
|
|
36
|
-
localStorage.setItem(this.storageKeys.CODE_VERIFIER,
|
|
35
|
+
const r = `openid profile email roles ${this.userScope} ${s}`, a = g(), o = await T(a), c = g();
|
|
36
|
+
localStorage.setItem(this.storageKeys.CODE_VERIFIER, a), localStorage.setItem(this.storageKeys.STATE, c);
|
|
37
37
|
const n = new URL(this.authEndpoints.authorize);
|
|
38
38
|
throw n.searchParams.set("client_id", this.authClientId), n.searchParams.set("response_type", "code"), n.searchParams.set("redirect_uri", this.redirectUri), n.searchParams.set("scope", r), n.searchParams.set("code_challenge", o), n.searchParams.set("code_challenge_method", "S256"), n.searchParams.set("state", c), window.location.href = n.toString(), new Error("Redirect initiated");
|
|
39
39
|
}
|
|
@@ -96,13 +96,13 @@ class D extends R {
|
|
|
96
96
|
})
|
|
97
97
|
});
|
|
98
98
|
if (!s.ok) {
|
|
99
|
-
const
|
|
100
|
-
throw new Error(`Token exchange failed: ${s.status} ${
|
|
99
|
+
const a = await s.text();
|
|
100
|
+
throw new Error(`Token exchange failed: ${s.status} ${a}`);
|
|
101
101
|
}
|
|
102
102
|
const r = await s.json();
|
|
103
103
|
if (localStorage.setItem(this.storageKeys.ACCESS_TOKEN, r.access_token), r.refresh_token && localStorage.setItem(this.storageKeys.REFRESH_TOKEN, r.refresh_token), r.expires_in) {
|
|
104
|
-
const
|
|
105
|
-
localStorage.setItem(this.storageKeys.EXPIRES_AT,
|
|
104
|
+
const a = Date.now() + r.expires_in * 1e3;
|
|
105
|
+
localStorage.setItem(this.storageKeys.EXPIRES_AT, a.toString());
|
|
106
106
|
}
|
|
107
107
|
}
|
|
108
108
|
// ============================================================================
|
|
@@ -126,9 +126,9 @@ class D extends R {
|
|
|
126
126
|
const F = 500, B = 5e3;
|
|
127
127
|
class $ {
|
|
128
128
|
constructor(e, t, s) {
|
|
129
|
-
this.state = w, this.bodhiext = null, this.refreshPromise = null, this.logger = new I("WindowBodhiextClient", t.logLevel), this.authClientId = e, this.config = t, this.authEndpoints = C(this.config.authServerUrl), this.onStateChange = s ??
|
|
129
|
+
this.state = w, this.bodhiext = null, this.refreshPromise = null, this.logger = new I("WindowBodhiextClient", t.logLevel), this.authClientId = e, this.config = t, this.authEndpoints = C(this.config.authServerUrl), this.onStateChange = s ?? k;
|
|
130
130
|
const r = m(t.basePath, _.WEB_EXT);
|
|
131
|
-
this.storageKeys =
|
|
131
|
+
this.storageKeys = x(r);
|
|
132
132
|
}
|
|
133
133
|
/**
|
|
134
134
|
* Set client state and notify callback
|
|
@@ -169,7 +169,7 @@ class $ {
|
|
|
169
169
|
* Send API message via window.bodhiext.sendApiRequest
|
|
170
170
|
* Converts ApiResponse to ApiResponseResult
|
|
171
171
|
*/
|
|
172
|
-
async sendApiRequest(e, t, s, r,
|
|
172
|
+
async sendApiRequest(e, t, s, r, a) {
|
|
173
173
|
try {
|
|
174
174
|
this.ensureBodhiext();
|
|
175
175
|
} catch (o) {
|
|
@@ -182,7 +182,7 @@ class $ {
|
|
|
182
182
|
}
|
|
183
183
|
try {
|
|
184
184
|
let o = r || {};
|
|
185
|
-
if (
|
|
185
|
+
if (a) {
|
|
186
186
|
const n = await this._getAccessTokenRaw();
|
|
187
187
|
if (!n)
|
|
188
188
|
return {
|
|
@@ -203,11 +203,11 @@ class $ {
|
|
|
203
203
|
o
|
|
204
204
|
);
|
|
205
205
|
} catch (o) {
|
|
206
|
-
const c = o?.error, n = c?.message ?? (o instanceof Error ? o.message : String(o)),
|
|
206
|
+
const c = o?.error, n = c?.message ?? (o instanceof Error ? o.message : String(o)), i = c?.type || "extension_error";
|
|
207
207
|
return {
|
|
208
208
|
error: {
|
|
209
209
|
message: n,
|
|
210
|
-
type:
|
|
210
|
+
type: i
|
|
211
211
|
}
|
|
212
212
|
};
|
|
213
213
|
}
|
|
@@ -237,9 +237,9 @@ class $ {
|
|
|
237
237
|
if (this.bodhiext && !e.testConnection)
|
|
238
238
|
return this.logger.debug("Already have bodhiext handle, skipping polling"), this.state;
|
|
239
239
|
if (!this.bodhiext) {
|
|
240
|
-
const r = e.timeoutMs ?? this.config.initParams?.extension?.timeoutMs ?? B,
|
|
240
|
+
const r = e.timeoutMs ?? this.config.initParams?.extension?.timeoutMs ?? B, a = e.intervalMs ?? this.config.initParams?.extension?.intervalMs ?? F, o = Date.now();
|
|
241
241
|
if (!await new Promise((n) => {
|
|
242
|
-
const
|
|
242
|
+
const i = () => {
|
|
243
243
|
if (window.bodhiext) {
|
|
244
244
|
this.bodhiext = window.bodhiext, n(!0);
|
|
245
245
|
return;
|
|
@@ -248,9 +248,9 @@ class $ {
|
|
|
248
248
|
n(!1);
|
|
249
249
|
return;
|
|
250
250
|
}
|
|
251
|
-
setTimeout(
|
|
251
|
+
setTimeout(i, a);
|
|
252
252
|
};
|
|
253
|
-
|
|
253
|
+
i();
|
|
254
254
|
}))
|
|
255
255
|
return this.logger.warn("Extension discovery timed out"), this.setState(A), this.state;
|
|
256
256
|
}
|
|
@@ -299,7 +299,7 @@ class $ {
|
|
|
299
299
|
const t = await this.requestResourceAccess();
|
|
300
300
|
if (E(t))
|
|
301
301
|
throw h(t.error.message, t.error.type);
|
|
302
|
-
if (
|
|
302
|
+
if (p(t)) {
|
|
303
303
|
const { message: l } = t.body.error;
|
|
304
304
|
throw h(l, "auth_error");
|
|
305
305
|
}
|
|
@@ -307,7 +307,7 @@ class $ {
|
|
|
307
307
|
throw h(`Unexpected HTTP ${t.status}`, "auth_error");
|
|
308
308
|
const s = t.body.scope;
|
|
309
309
|
localStorage.setItem(this.storageKeys.RESOURCE_SCOPE, s);
|
|
310
|
-
const r = g(),
|
|
310
|
+
const r = g(), a = await T(r), o = g();
|
|
311
311
|
localStorage.setItem(this.storageKeys.CODE_VERIFIER, r), localStorage.setItem(this.storageKeys.STATE, o);
|
|
312
312
|
const c = ["openid", "profile", "email", "roles", this.config.userScope, s], n = new URLSearchParams({
|
|
313
313
|
response_type: "code",
|
|
@@ -315,10 +315,10 @@ class $ {
|
|
|
315
315
|
redirect_uri: this.config.redirectUri,
|
|
316
316
|
scope: c.join(" "),
|
|
317
317
|
state: o,
|
|
318
|
-
code_challenge:
|
|
318
|
+
code_challenge: a,
|
|
319
319
|
code_challenge_method: "S256"
|
|
320
|
-
}),
|
|
321
|
-
return window.location.href =
|
|
320
|
+
}), i = `${this.authEndpoints.authorize}?${n}`;
|
|
321
|
+
return window.location.href = i, new Promise(() => {
|
|
322
322
|
});
|
|
323
323
|
}
|
|
324
324
|
/**
|
|
@@ -360,11 +360,11 @@ class $ {
|
|
|
360
360
|
const o = await r.text();
|
|
361
361
|
throw new Error(`Token exchange failed: ${r.status} ${o}`);
|
|
362
362
|
}
|
|
363
|
-
const
|
|
364
|
-
if (!
|
|
363
|
+
const a = await r.json();
|
|
364
|
+
if (!a.access_token)
|
|
365
365
|
throw new Error("No access token received");
|
|
366
|
-
if (localStorage.setItem(this.storageKeys.ACCESS_TOKEN,
|
|
367
|
-
const o = Date.now() +
|
|
366
|
+
if (localStorage.setItem(this.storageKeys.ACCESS_TOKEN, a.access_token), a.refresh_token && localStorage.setItem(this.storageKeys.REFRESH_TOKEN, a.refresh_token), a.expires_in) {
|
|
367
|
+
const o = Date.now() + a.expires_in * 1e3;
|
|
368
368
|
localStorage.setItem(this.storageKeys.EXPIRES_AT, o.toString());
|
|
369
369
|
}
|
|
370
370
|
}
|
|
@@ -408,7 +408,7 @@ class $ {
|
|
|
408
408
|
if (!e)
|
|
409
409
|
return { status: "unauthenticated", user: null, accessToken: null, error: null };
|
|
410
410
|
try {
|
|
411
|
-
return { status: "authenticated", user:
|
|
411
|
+
return { status: "authenticated", user: y(e), accessToken: e, error: null };
|
|
412
412
|
} catch (t) {
|
|
413
413
|
return this.logger.error("Failed to parse token:", t), { status: "unauthenticated", user: null, accessToken: null, error: null };
|
|
414
414
|
}
|
|
@@ -455,16 +455,23 @@ class $ {
|
|
|
455
455
|
e,
|
|
456
456
|
this.authClientId
|
|
457
457
|
);
|
|
458
|
-
if (t) {
|
|
459
|
-
this._storeRefreshedTokens(t);
|
|
460
|
-
const s =
|
|
458
|
+
if (t.success) {
|
|
459
|
+
this._storeRefreshedTokens(t.tokens);
|
|
460
|
+
const s = y(t.tokens.access_token);
|
|
461
461
|
return this.setAuthState({
|
|
462
462
|
status: "authenticated",
|
|
463
463
|
user: s,
|
|
464
|
-
accessToken: t.access_token,
|
|
464
|
+
accessToken: t.tokens.access_token,
|
|
465
465
|
error: null
|
|
466
|
-
}), this.logger.info("Token refreshed successfully"), t.access_token;
|
|
466
|
+
}), this.logger.info("Token refreshed successfully"), t.tokens.access_token;
|
|
467
467
|
}
|
|
468
|
+
if (t.error === "invalid_grant")
|
|
469
|
+
return this.logger.warn("Refresh token expired or revoked, clearing tokens and logging out"), this.clearAuthStorage(), this.setAuthState({
|
|
470
|
+
status: "unauthenticated",
|
|
471
|
+
user: null,
|
|
472
|
+
accessToken: null,
|
|
473
|
+
error: null
|
|
474
|
+
}), null;
|
|
468
475
|
} catch (t) {
|
|
469
476
|
this.logger.warn("Token refresh failed:", t);
|
|
470
477
|
}
|
|
@@ -473,6 +480,9 @@ class $ {
|
|
|
473
480
|
"token_refresh_failed"
|
|
474
481
|
);
|
|
475
482
|
}
|
|
483
|
+
clearAuthStorage() {
|
|
484
|
+
localStorage.removeItem(this.storageKeys.ACCESS_TOKEN), localStorage.removeItem(this.storageKeys.REFRESH_TOKEN), localStorage.removeItem(this.storageKeys.EXPIRES_AT), localStorage.removeItem(this.storageKeys.RESOURCE_SCOPE);
|
|
485
|
+
}
|
|
476
486
|
/**
|
|
477
487
|
* Store refreshed tokens
|
|
478
488
|
*/
|
|
@@ -508,7 +518,7 @@ class $ {
|
|
|
508
518
|
return S(
|
|
509
519
|
"error",
|
|
510
520
|
t.version || "unknown",
|
|
511
|
-
t.error ? { message: t.error.message, type: t.error.type } :
|
|
521
|
+
t.error ? { message: t.error.message, type: t.error.type } : O.SERVER_NOT_READY
|
|
512
522
|
);
|
|
513
523
|
default:
|
|
514
524
|
return d;
|
|
@@ -518,35 +528,35 @@ class $ {
|
|
|
518
528
|
* Generic streaming via window.bodhiext.sendStreamRequest
|
|
519
529
|
* Wraps ReadableStream as AsyncGenerator
|
|
520
530
|
*/
|
|
521
|
-
async *stream(e, t, s, r,
|
|
531
|
+
async *stream(e, t, s, r, a = !0) {
|
|
522
532
|
this.ensureBodhiext();
|
|
523
533
|
let o = r || {};
|
|
524
|
-
if (
|
|
525
|
-
const
|
|
526
|
-
if (!
|
|
534
|
+
if (a) {
|
|
535
|
+
const i = await this._getAccessTokenRaw();
|
|
536
|
+
if (!i)
|
|
527
537
|
throw h("Not authenticated. Please log in first.", "auth_error");
|
|
528
538
|
o = {
|
|
529
539
|
...o,
|
|
530
|
-
Authorization: `Bearer ${
|
|
540
|
+
Authorization: `Bearer ${i}`
|
|
531
541
|
};
|
|
532
542
|
}
|
|
533
543
|
const n = this.bodhiext.sendStreamRequest(e, t, s, o).getReader();
|
|
534
544
|
try {
|
|
535
545
|
for (; ; ) {
|
|
536
|
-
const { value:
|
|
537
|
-
if (l ||
|
|
546
|
+
const { value: i, done: l } = await n.read();
|
|
547
|
+
if (l || i?.done)
|
|
538
548
|
break;
|
|
539
|
-
yield
|
|
549
|
+
yield i.body;
|
|
540
550
|
}
|
|
541
|
-
} catch (
|
|
542
|
-
if (
|
|
543
|
-
if ("response" in
|
|
544
|
-
const l =
|
|
545
|
-
throw
|
|
551
|
+
} catch (i) {
|
|
552
|
+
if (i instanceof Error) {
|
|
553
|
+
if ("response" in i) {
|
|
554
|
+
const l = i;
|
|
555
|
+
throw P(i.message, l.response.status, l.response.body);
|
|
546
556
|
}
|
|
547
|
-
throw "error" in
|
|
557
|
+
throw "error" in i ? h(i.message, "extension_error") : h(i.message, "extension_error");
|
|
548
558
|
}
|
|
549
|
-
throw
|
|
559
|
+
throw i;
|
|
550
560
|
} finally {
|
|
551
561
|
n.releaseLock();
|
|
552
562
|
}
|
|
@@ -593,9 +603,9 @@ function q(u) {
|
|
|
593
603
|
const e = u === "/" ? "" : u.replace(/\/$/, "");
|
|
594
604
|
return `${window.location.origin}${e}/callback`;
|
|
595
605
|
}
|
|
596
|
-
class
|
|
606
|
+
class H extends L {
|
|
597
607
|
constructor(e, t, s) {
|
|
598
|
-
const r = t || {},
|
|
608
|
+
const r = t || {}, a = {
|
|
599
609
|
basePath: r.basePath || "/",
|
|
600
610
|
redirectUri: r.redirectUri || q(r.basePath || "/"),
|
|
601
611
|
authServerUrl: r.authServerUrl || "https://id.getbodhi.app/realms/bodhi",
|
|
@@ -603,7 +613,7 @@ class z extends L {
|
|
|
603
613
|
logLevel: r.logLevel || "warn",
|
|
604
614
|
initParams: r.initParams
|
|
605
615
|
};
|
|
606
|
-
super(e,
|
|
616
|
+
super(e, a, s);
|
|
607
617
|
}
|
|
608
618
|
createLogger(e) {
|
|
609
619
|
return new I("WebUIClient", e.logLevel);
|
|
@@ -645,8 +655,8 @@ class z extends L {
|
|
|
645
655
|
return this.connectionMode === "direct" ? this.directClient.handleOAuthCallback(e, t) : this.extClient.handleOAuthCallback(e, t);
|
|
646
656
|
}
|
|
647
657
|
}
|
|
648
|
-
const
|
|
658
|
+
const z = "production";
|
|
649
659
|
export {
|
|
650
|
-
|
|
651
|
-
|
|
660
|
+
z as WEB_BUILD_MODE,
|
|
661
|
+
H as WebUIClient
|
|
652
662
|
};
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@bodhiapp/bodhi-js",
|
|
3
|
-
"version": "0.0.
|
|
3
|
+
"version": "0.0.12",
|
|
4
4
|
"description": "Web SDK for Bodhi Browser - window.bodhiext communication",
|
|
5
5
|
"type": "module",
|
|
6
6
|
"main": "dist/bodhi-web.cjs.js",
|
|
@@ -37,7 +37,7 @@
|
|
|
37
37
|
"typecheck": "tsc --noEmit"
|
|
38
38
|
},
|
|
39
39
|
"dependencies": {
|
|
40
|
-
"@bodhiapp/bodhi-js-core": "0.0.
|
|
40
|
+
"@bodhiapp/bodhi-js-core": "0.0.12",
|
|
41
41
|
"@bodhiapp/ts-client": "0.1.9"
|
|
42
42
|
},
|
|
43
43
|
"devDependencies": {
|