@bodhiapp/bodhi-js-react 0.0.3 → 0.0.5

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (32) hide show
  1. package/dist/bodhi-browser-ext/src/types/bodhiext.d.ts +0 -1
  2. package/dist/bodhi-browser-ext/src/types/protocol.d.ts +0 -1
  3. package/dist/bodhi-js-sdk/core/src/build-info.d.ts +1 -0
  4. package/dist/bodhi-js-sdk/core/src/errors.d.ts +0 -1
  5. package/dist/bodhi-js-sdk/core/src/facade-client-base.d.ts +1 -2
  6. package/dist/bodhi-js-sdk/core/src/index.d.ts +1 -0
  7. package/dist/bodhi-js-sdk/core/src/interface.d.ts +0 -1
  8. package/dist/bodhi-js-sdk/core/src/logger.d.ts +0 -1
  9. package/dist/bodhi-js-sdk/core/src/oauth.d.ts +0 -1
  10. package/dist/bodhi-js-sdk/core/src/onboarding/config.d.ts +0 -1
  11. package/dist/bodhi-js-sdk/core/src/onboarding/modal.d.ts +0 -1
  12. package/dist/bodhi-js-sdk/core/src/onboarding/protocol-utils.d.ts +0 -1
  13. package/dist/bodhi-js-sdk/core/src/platform.d.ts +0 -1
  14. package/dist/bodhi-js-sdk/core/src/storage.d.ts +12 -0
  15. package/dist/bodhi-js-sdk/core/src/types/api.d.ts +0 -1
  16. package/dist/bodhi-js-sdk/core/src/types/callback.d.ts +0 -1
  17. package/dist/bodhi-js-sdk/core/src/types/client-state.d.ts +0 -1
  18. package/dist/bodhi-js-sdk/core/src/types/config.d.ts +0 -1
  19. package/dist/bodhi-js-sdk/core/src/types/platform.d.ts +0 -1
  20. package/dist/bodhi-js-sdk/react/src/BodhiProvider.d.ts +3 -3
  21. package/dist/bodhi-js-sdk/react/src/SetupModalProcessor.d.ts +2 -2
  22. package/dist/bodhi-js-sdk/react/src/build-info.d.ts +1 -0
  23. package/dist/bodhi-js-sdk/react/src/client-ctx.d.ts +0 -1
  24. package/dist/bodhi-js-sdk/react/src/index.d.ts +1 -0
  25. package/dist/bodhi-react.cjs.js +2 -2
  26. package/dist/bodhi-react.esm.d.ts +1 -0
  27. package/dist/bodhi-react.esm.js +173 -175
  28. package/dist/setup-modal/src/types/message-types.d.ts +0 -1
  29. package/dist/setup-modal/src/types/protocol.d.ts +0 -1
  30. package/dist/setup-modal/src/types/state.d.ts +0 -1
  31. package/dist/setup-modal/src/types/type-guards.d.ts +0 -1
  32. package/package.json +6 -5
@@ -1,5 +1,4 @@
1
1
  import { OpenAiApiError, PingResponse, CreateChatCompletionRequest, CreateChatCompletionResponse, CreateChatCompletionStreamResponse } from '@bodhiapp/ts-client';
2
-
3
2
  /**
4
3
  * HTTP response wrapper - body can be success type OR error type
5
4
  * Use isApiErrorResponse() to narrow the type based on status
@@ -1,6 +1,5 @@
1
1
  import { OpenAiApiError, ErrorBody } from '@bodhiapp/ts-client';
2
2
  import { ApiResponse, ServerStateInfo } from './bodhiext';
3
-
4
3
  /**
5
4
  * Validate OpenAI API error body structure
6
5
  * { error: { message: string, type: string } }
@@ -0,0 +1 @@
1
+ export declare const BUILD_MODE: string;
@@ -1,6 +1,5 @@
1
1
  import { ApiError, OperationError } from '../../../bodhi-browser-ext/src/types';
2
2
  import { OpenAiApiError } from '@bodhiapp/ts-client';
3
-
4
3
  /**
5
4
  * Create API error (HTTP 4xx/5xx from server)
6
5
  * Thrown for streaming responses when server returns error
@@ -3,7 +3,6 @@ import { IConnectionClient } from './interface';
3
3
  import { Logger } from './logger';
4
4
  import { BodhiClientUserPrefsManager } from './storage';
5
5
  import { ApiResponseResult, AuthLoggedIn, AuthLoggedOut, AuthState, BackendServerState, ClientState, ConnectionMode, DirectState, ExtensionState, InitParams, SerializedClientState, SerializedDirectState, SerializedExtensionState, StateChange, StateChangeCallback } from './types';
6
-
7
6
  /**
8
7
  * Base facade client with common delegation logic
9
8
  *
@@ -20,7 +19,7 @@ export declare abstract class BaseFacadeClient<TConfig, TExtClient extends IConn
20
19
  protected authClientId: string;
21
20
  protected config: TConfig;
22
21
  protected onStateChange: StateChangeCallback;
23
- constructor(authClientId: string, config: TConfig, onStateChange?: StateChangeCallback, storagePrefix?: string);
22
+ constructor(authClientId: string, config: TConfig, onStateChange?: StateChangeCallback, storagePrefix?: string, basePath?: string);
24
23
  /**
25
24
  * Create logger instance
26
25
  * Subclasses extract logLevel from their specific config type
@@ -17,3 +17,4 @@ export * from './oauth';
17
17
  export * from './direct-client-base';
18
18
  export * from './facade-client-base';
19
19
  export { isOperationError, type OperationError } from '../../../bodhi-browser-ext/src/types';
20
+ export { BUILD_MODE as CORE_BUILD_MODE } from './build-info';
@@ -1,6 +1,5 @@
1
1
  import { CreateChatCompletionStreamResponse } from '@bodhiapp/ts-client';
2
2
  import { ApiResponseResult, AuthLoggedIn, AuthLoggedOut, AuthState, BackendServerState, ClientState, ConnectionMode, DirectState, ExtensionState, InitParams, StateChangeCallback } from './types';
3
-
4
3
  /**
5
4
  * ConnectionClient - Base interface for all client implementations
6
5
  *
@@ -1,5 +1,4 @@
1
1
  import { LogLevel } from './types/config';
2
-
3
2
  export declare class Logger {
4
3
  private prefix;
5
4
  private level;
@@ -1,5 +1,4 @@
1
1
  import { UserInfo } from './types';
2
-
3
2
  /**
4
3
  * Base64 URL encode a buffer (for PKCE)
5
4
  */
@@ -1,5 +1,4 @@
1
1
  import { Browser, OS } from '../../../../setup-modal/src/types';
2
-
3
2
  /**
4
3
  * Browser configurations with extension store URLs
5
4
  */
@@ -1,5 +1,4 @@
1
1
  import { MessageType, RequestMessage, ResponsePayload } from '../../../../setup-modal/src/types';
2
-
3
2
  import type * as ModalTypes from '@bodhiapp/setup-modal/types';
4
3
  /**
5
4
  * Async handler for modal requests
@@ -1,5 +1,4 @@
1
1
  import { MessageType, RequestPayload, ResponsePayload, RequestMessage, RequestId } from '../../../../setup-modal/src/types';
2
-
3
2
  /** Build fire-and-forget event message */
4
3
  export declare function buildEvent<T extends MessageType>(type: T, payload: RequestPayload<T>): {
5
4
  kind: "event";
@@ -1,5 +1,4 @@
1
1
  import { BrowserInfo, OSInfo } from './types';
2
-
3
2
  /**
4
3
  * Detects the current browser using UAParser.js
5
4
  */
@@ -27,6 +27,18 @@ export declare const STORAGE_PREFIXES: {
27
27
  readonly WEB: "bodhi:web";
28
28
  readonly EXT: "bodhi:ext";
29
29
  };
30
+ /**
31
+ * Create storage prefix with basePath for path isolation
32
+ *
33
+ * @param basePath - Base path of app (e.g., '/', '/app1/')
34
+ * @param prefix - Storage prefix (e.g., 'bodhi:web', 'bodhijs:')
35
+ * @returns Combined prefix with basePath isolation
36
+ *
37
+ * Examples:
38
+ * - createStoragePrefixWithBasePath('/', 'bodhi:web') => '/:bodhi:web'
39
+ * - createStoragePrefixWithBasePath('/app1/', 'bodhi:web') => '/app1/:bodhi:web'
40
+ */
41
+ export declare function createStoragePrefixWithBasePath(basePath: string, prefix: string): string;
30
42
  /**
31
43
  * User Preferences Storage Manager
32
44
  *
@@ -1,6 +1,5 @@
1
1
  import { ApiResponse, OperationErrorResponse } from '../../../../bodhi-browser-ext/src/types';
2
2
  import { OpenAiApiError } from '@bodhiapp/ts-client';
3
-
4
3
  /**
5
4
  * Public API result type - discriminated union without protocol fields
6
5
  *
@@ -1,6 +1,5 @@
1
1
  import { ClientState } from './client-state';
2
2
  import { AuthState } from './user-info';
3
-
4
3
  /**
5
4
  * Discriminated union for state changes.
6
5
  * Allows single callback to handle both client state and auth state changes.
@@ -1,5 +1,4 @@
1
1
  import { OperationErrorResponse } from '../../../../bodhi-browser-ext/src/types';
2
-
3
2
  /**
4
3
  * Serialized direct client state for persistence
5
4
  * Stores minimal state needed to restore direct connection
@@ -1,5 +1,4 @@
1
1
  import { UserScope } from './user-info';
2
-
3
2
  /**
4
3
  * Log levels for client logging
5
4
  */
@@ -1,5 +1,4 @@
1
1
  import { BrowserType, OSType } from '../../../../setup-modal/src/types';
2
-
3
2
  /**
4
3
  * Browser detection result
5
4
  */
@@ -1,14 +1,14 @@
1
1
  import { AuthState, LogLevel, UIClient } from '../../core/src/index.ts';
2
2
  import { ReactNode } from 'react';
3
3
  import { ClientContextState } from './client-ctx';
4
-
5
4
  export type SetupState = 'ready' | 'loading' | 'loaded';
6
5
  export interface BodhiProviderProps {
7
6
  children: ReactNode;
8
7
  client: UIClient;
9
8
  modalHtmlPath?: string;
10
9
  handleCallback?: boolean;
11
- callbackUrl?: string;
10
+ callbackPath?: string;
11
+ basePath?: string;
12
12
  logLevel?: LogLevel;
13
13
  }
14
14
  export interface BodhiContext {
@@ -23,5 +23,5 @@ export interface BodhiContext {
23
23
  hideSetup: () => void;
24
24
  }
25
25
  export declare const BodhiReactContext: import('react').Context<BodhiContext | null>;
26
- export declare function BodhiProvider({ children, client, modalHtmlPath, handleCallback, callbackUrl, logLevel, }: BodhiProviderProps): import("react/jsx-runtime").JSX.Element;
26
+ export declare function BodhiProvider({ children, client, modalHtmlPath, handleCallback, callbackPath, basePath, logLevel, }: BodhiProviderProps): import("react/jsx-runtime").JSX.Element;
27
27
  export declare function useBodhi(): BodhiContext;
@@ -1,16 +1,16 @@
1
1
  import { UIClient, LogLevel } from '../../core/src/index.ts';
2
2
  import { SetupState } from './BodhiProvider';
3
-
4
3
  interface SetupModalProcessorProps {
5
4
  client: UIClient;
6
5
  modalHtmlPath?: string;
7
6
  hideSetup: () => void;
8
7
  onSetupReady?: () => void;
9
8
  setupState: SetupState;
9
+ basePath?: string;
10
10
  logLevel?: LogLevel;
11
11
  }
12
12
  /**
13
13
  * SetupModalProcessor - Headless React component managing setup modal business logic
14
14
  */
15
- export declare function SetupModalProcessor({ client, modalHtmlPath, hideSetup, onSetupReady, setupState, logLevel, }: SetupModalProcessorProps): null;
15
+ export declare function SetupModalProcessor({ client, modalHtmlPath, hideSetup, onSetupReady, setupState, basePath, logLevel, }: SetupModalProcessorProps): null;
16
16
  export {};
@@ -0,0 +1 @@
1
+ export declare const BUILD_MODE: string;
@@ -1,5 +1,4 @@
1
1
  import { ClientState } from '../../core/src/index.ts';
2
-
3
2
  export interface ClientContextNotInitialized {
4
3
  type: 'not-initialized';
5
4
  }
@@ -12,3 +12,4 @@ export { createApiError, createOperationError } from '../../core/src/index.ts';
12
12
  export type { AuthState, UIClient } from '../../core/src/index.ts';
13
13
  export { isAuthError, isAuthLoggedIn, isClientReady } from '../../core/src/index.ts';
14
14
  export { isOperationError, type OperationError } from '../../core/src/index.ts';
15
+ export { BUILD_MODE as REACT_BUILD_MODE } from './build-info';
@@ -1,2 +1,2 @@
1
- "use strict";Object.defineProperty(exports,Symbol.toStringTag,{value:"Module"});const N=require("react/jsx-runtime"),s=require("@bodhiapp/bodhi-js-core"),n=require("react"),m={MODAL_READY:"modal:ready",MODAL_REFRESH:"modal:refresh",MODAL_CLOSE:"modal:close",MODAL_COMPLETE:"modal:complete",MODAL_LNA_CONNECT:"modal:lna:connect",MODAL_LNA_SKIP:"modal:lna:skip",MODAL_CONFIRM_SERVER_INSTALL:"modal:confirm-server-install",MODAL_SELECT_CONNECTION:"modal:select-connection"};function H({client:e,modalHtmlPath:i,hideSetup:v,onSetupReady:C,setupState:I,logLevel:_="warn"}){const A=I!=="ready",O=n.useMemo(()=>new s.Logger("SetupModalProcessor",_),[_]),c=n.useRef(null),l=n.useMemo(()=>new s.BodhiClientUserPrefsManager,[]),S=n.useRef(null),g=n.useCallback(t=>t==="direct"?"lna":t==="extension"?"extension":null,[]),x=n.useCallback(t=>t.extension==="ready"?{status:"ready",version:"unknown",id:t.extensionId}:t.extension==="not-found"?{status:"not-installed",error:{message:"Extension not found",code:"ext-not-installed"}}:{status:"unreachable",error:{message:"Client not initialized",code:"ext-connection-failed"}},[]),p=n.useCallback(t=>{if(t.server.status==="pending-extension-ready")return{status:"pending-extension-ready",error:{message:"Extension not ready",code:"server-pending-ext-ready"}};const r=t.server;switch(r.status){case"ready":return{status:"ready",version:r.version};case"setup":return{status:"setup",version:r.version,error:{message:r.error.message,code:"server-in-setup-status"}};case"resource-admin":return{status:"resource-admin",version:r.version,error:{message:r.error.message,code:"server-in-admin-status"}};case"error":return{status:"error",error:{message:r.error.message,code:"server-unexpected-error"}};case"not-reachable":return{status:"unreachable",error:{message:r.error.message,code:"server-conn-refused"}}}},[]),h=n.useCallback(t=>{if(t.server.status==="not-connected")return{status:"pending-lna-ready"};const r=t.server;switch(r.status){case"ready":return{status:"ready",version:r.version};case"setup":return{status:"setup",version:r.version};case"resource-admin":return{status:"resource-admin",version:r.version};case"error":case"not-reachable":return{status:"error",error:{message:r.error.message}}}},[]),L=n.useCallback((t,r)=>{if(t.server.status!=="pending-extension-ready"){const o=t.server.status;if(o==="ready"||o==="setup"||o==="resource-admin")return!0}if(r.server.status!=="not-connected"){const o=r.server.status;if(o==="ready"||o==="setup"||o==="resource-admin")return!0}return!1},[]),R=n.useCallback((t,r,o)=>{if(r==="skipped")return{status:"skipped",serverUrl:o};if(t.server.status!=="not-connected"){const a=t.server;return a.status==="ready"||a.status==="setup"||a.status==="resource-admin"?{status:"granted",serverUrl:o}:{status:"unreachable",serverUrl:o,error:{message:a.error.message,code:"lna-unreachable"}}}return r==="granted"?{status:"granted",serverUrl:o}:{status:"prompt",serverUrl:o}},[]),d=n.useCallback(async(t=!1)=>{const r=s.detectBrowser().type,o=s.detectOS().type;let a=await e.getExtensionState();(a.extension==="not-initialized"||t)&&(a=await e.testExtensionConnectivity());let u=await e.getDirectState();const y=l.getDirectStatus();y==="granted"&&(u.server.status==="not-connected"||t)&&(u=await e.testDirectConnectivity());const E=s.getServerUrl(u)||"http://localhost:1135",F=R(u,y,E);return e.getConnectionMode()===null&&(s.isDirectServerReady(u)?await e.setConnectionMode("direct"):s.isExtensionServerReady(a)&&await e.setConnectionMode("extension")),l.isServerInstallConfirmed()||L(a,u)&&l.setServerInstallConfirmed(!0),{extension:x(a),server:p(a),lna:F,lnaServer:h(u),env:{browser:r,os:o},browsers:s.BROWSER_CONFIGS,os:s.OS_CONFIGS,userConfirmations:{serverInstall:l.isServerInstallConfirmed()},selectedConnection:g(e.getConnectionMode())}},[e,l,x,p,h,g,R,L]),f=n.useCallback(()=>{if(!S.current)throw new Error("Cannot get state: currentStateRef is null");return{...S.current,userConfirmations:{serverInstall:l.isServerInstallConfirmed()},selectedConnection:g(e.getConnectionMode())}},[l,e,g]),w=n.useMemo(()=>({[m.MODAL_READY]:async()=>(O.info("MODAL_READY: building initial state"),{setupState:f()}),[m.MODAL_REFRESH]:async()=>{var o;O.info("MODAL_REFRESH: refreshing state");const t=await d(!0);S.current=t;const r=f();return O.info(`MODAL_REFRESH: state refreshed
2
- `,JSON.stringify(r,null,2)),(o=c.current)==null||o.updateState(f()),{setupState:r}},[m.MODAL_LNA_CONNECT]:async t=>{var u,y;const r=t.payload.serverUrl;console.log("[SetupModalProcessor] LNA connect:",r);const o=await e.testDirectConnectivity(r);if(o.server.status!=="not-connected"){const b=o.server.status;if(b==="ready"||b==="setup"||b==="resource-admin"){l.setDirectStatus("granted"),e.getConnectionMode()===null&&await e.setConnectionMode("direct");const E=await d();return S.current=E,(u=c.current)==null||u.updateState(f()),{success:!0}}}const a=await d();return S.current=a,(y=c.current)==null||y.updateState(f()),{success:!1}},[m.MODAL_LNA_SKIP]:async()=>{var r;l.setDirectStatus("skipped");const t=await d();return S.current=t,(r=c.current)==null||r.updateState(f()),{success:!0}},[m.MODAL_CLOSE]:()=>{v()},[m.MODAL_COMPLETE]:()=>{v()},[m.MODAL_CONFIRM_SERVER_INSTALL]:t=>{var r;return l.setServerInstallConfirmed(t.payload.confirmed),(r=c.current)==null||r.updateState(f()),{success:!0}},[m.MODAL_SELECT_CONNECTION]:async t=>{var a;const o=t.payload.connection==="lna"?"direct":"extension";return await e.setConnectionMode(o),(a=c.current)==null||a.updateState(f()),{success:!0}}}),[O,e,l,d,f,h,v]);return n.useEffect(()=>(c.current=new s.OnboardingModal({modalHtmlPath:i,handlers:w}),()=>{var t;(t=c.current)==null||t.destroy(),c.current=null}),[i,w]),n.useEffect(()=>{A&&c.current?d(!0).then(t=>{var r;S.current=t,(r=c.current)==null||r.show(t),C==null||C()}).catch(t=>{console.error("[SetupModalProcessor] buildSetupState failed:",t)}):!A&&c.current&&c.current.destroy()},[A,d,C]),null}const D=n.createContext(null);D.displayName="BodhiContext";function G({children:e,client:i,modalHtmlPath:v,handleCallback:C=!0,callbackUrl:I="/callback",logLevel:_="warn"}){const A=n.useRef(!1),O=n.useRef(!1),[c,l]=n.useState({type:"not-initialized"}),[S,g]=n.useState(null),[x,p]=n.useState(!1),[h,L]=n.useState("ready");n.useEffect(()=>{const a=u=>{switch(u.type){case"client-state":l(u.state);break;case"auth-state":g(u.state),p(!1);break}};return i.setStateCallback(a),()=>{i.setStateCallback(s.NOOP_STATE_CALLBACK)}},[i]);const R=n.useCallback(async()=>{L("loading")},[]),d=n.useCallback(()=>{L("ready")},[]),f=n.useCallback(()=>{L("loaded")},[]),w=n.useCallback(async a=>{l({type:"initializing"});try{await i.init(a||{})}catch(u){console.error("[BodhiProvider] Init failed:",u)}},[i]);n.useEffect(()=>{if(O.current)return;O.current=!0,(async()=>{if(await w(),!C)return;const u=new URL(window.location.href);if(u.pathname!==I)return;const y=u.searchParams.get("code"),b=u.searchParams.get("state");!y||!b||A.current||(A.current=!0,s.isWebUIClient(i)&&(p(!0),i.handleOAuthCallback(y,b).then(()=>{window.history.replaceState({},"","/")}).catch(E=>{console.error("OAuth callback failed:",E),g({isLoggedIn:!1,error:{message:E instanceof Error?E.message:"OAuth callback failed",code:"OAUTH_CALLBACK_FAILED"}}),p(!1),window.history.replaceState({},"","/")})))})()},[w,i,C,I]);const t=n.useCallback(async()=>{p(!0);try{await i.login()}catch(a){g({isLoggedIn:!1,error:{message:a instanceof Error?a.message:"Login failed",code:"LOGIN_FAILED"}}),p(!1)}},[i]),r=n.useCallback(async()=>{try{await i.logout()}catch(a){g({isLoggedIn:!1,error:{message:a instanceof Error?a.message:"Logout failed",code:"LOGOUT_FAILED"}})}},[i]),o=n.useMemo(()=>({client:i,clientState:c,auth:S,authLoading:x,login:t,logout:r,showSetup:R,hideSetup:d,setupState:h}),[i,c,S,x,h,t,r,R,d]);return N.jsxs(D.Provider,{value:o,children:[N.jsx(H,{client:i,modalHtmlPath:v,hideSetup:d,onSetupReady:f,setupState:h,logLevel:_}),e]})}function K(){const e=n.useContext(D);if(!e)throw new Error("useBodhi must be used within BodhiProvider");return{client:e.client,clientState:e.clientState,setupState:e.setupState,auth:e.auth,authLoading:e.authLoading,login:e.login,logout:e.logout,showSetup:e.showSetup,hideSetup:e.hideSetup}}function P(e){return e.type==="not-initialized"}function k(e){return e.type==="initializing"}function M(e){return!(P(e)||k(e))}function z(e){return M(e)?s.isClientReady(e):!1}function T(e){if(P(e))return{ready:!1,actualState:"not-initialized",mode:null};if(k(e))return{ready:!1,actualState:"initializing",mode:null};const i=s.isExtensionState(e)?"extension":"direct",v=s.isClientReady(e),C=s.isExtensionState(e)?e.extension:e.server.status==="not-connected"?"not-connected":"ready";return{ready:v,actualState:C,mode:i}}function j(e){if(!M(e))return{ready:!1,actualState:"n/a"};const i=e.server;return{ready:i.status==="ready",actualState:i.status}}function B(e){return M(e)?s.isClientReady(e)&&e.server.status==="ready":!1}const U={isNotInitialized:P,isInitializing:k,isInitialized:M,isReady:z,getClientInitState:T,getServerState:j,isOverallReady:B};Object.defineProperty(exports,"createApiError",{enumerable:!0,get:()=>s.createApiError});Object.defineProperty(exports,"createOperationError",{enumerable:!0,get:()=>s.createOperationError});Object.defineProperty(exports,"isApiResultError",{enumerable:!0,get:()=>s.isApiResultError});Object.defineProperty(exports,"isApiResultOperationError",{enumerable:!0,get:()=>s.isApiResultOperationError});Object.defineProperty(exports,"isApiResultSuccess",{enumerable:!0,get:()=>s.isApiResultSuccess});Object.defineProperty(exports,"isAuthError",{enumerable:!0,get:()=>s.isAuthError});Object.defineProperty(exports,"isAuthLoggedIn",{enumerable:!0,get:()=>s.isAuthLoggedIn});Object.defineProperty(exports,"isClientReady",{enumerable:!0,get:()=>s.isClientReady});Object.defineProperty(exports,"isDirectState",{enumerable:!0,get:()=>s.isDirectState});Object.defineProperty(exports,"isExtensionState",{enumerable:!0,get:()=>s.isExtensionState});Object.defineProperty(exports,"isOperationError",{enumerable:!0,get:()=>s.isOperationError});exports.BodhiProvider=G;exports.BodhiReactContext=D;exports.ClientCtxState=U;exports.getClientInitState=T;exports.getServerState=j;exports.isClientCtxInitialized=M;exports.isClientCtxInitializing=k;exports.isClientCtxNotInitialized=P;exports.isClientCtxReady=z;exports.isOverallReady=B;exports.useBodhi=K;
1
+ "use strict";Object.defineProperty(exports,Symbol.toStringTag,{value:"Module"});const B=require("react/jsx-runtime"),s=require("@bodhiapp/bodhi-js-core"),n=require("react"),p={MODAL_READY:"modal:ready",MODAL_REFRESH:"modal:refresh",MODAL_CLOSE:"modal:close",MODAL_COMPLETE:"modal:complete",MODAL_LNA_CONNECT:"modal:lna:connect",MODAL_LNA_SKIP:"modal:lna:skip",MODAL_CONFIRM_SERVER_INSTALL:"modal:confirm-server-install",MODAL_SELECT_CONNECTION:"modal:select-connection"};function H({client:e,modalHtmlPath:o,hideSetup:y,onSetupReady:m,setupState:I,basePath:v="/",logLevel:D="warn"}){const b=I!=="ready",O=n.useMemo(()=>new s.Logger("SetupModalProcessor",D),[D]),c=n.useRef(null),l=n.useMemo(()=>new s.BodhiClientUserPrefsManager(s.createStoragePrefixWithBasePath(v,"bodhijs:")),[v]),S=n.useRef(null),C=n.useCallback(t=>t==="direct"?"lna":t==="extension"?"extension":null,[]),L=n.useCallback(t=>t.extension==="ready"?{status:"ready",version:"unknown",id:t.extensionId}:t.extension==="not-found"?{status:"not-installed",error:{message:"Extension not found",code:"ext-not-installed"}}:{status:"unreachable",error:{message:"Client not initialized",code:"ext-connection-failed"}},[]),g=n.useCallback(t=>{if(t.server.status==="pending-extension-ready")return{status:"pending-extension-ready",error:{message:"Extension not ready",code:"server-pending-ext-ready"}};const r=t.server;switch(r.status){case"ready":return{status:"ready",version:r.version};case"setup":return{status:"setup",version:r.version,error:{message:r.error.message,code:"server-in-setup-status"}};case"resource-admin":return{status:"resource-admin",version:r.version,error:{message:r.error.message,code:"server-in-admin-status"}};case"error":return{status:"error",error:{message:r.error.message,code:"server-unexpected-error"}};case"not-reachable":return{status:"unreachable",error:{message:r.error.message,code:"server-conn-refused"}}}},[]),E=n.useCallback(t=>{if(t.server.status==="not-connected")return{status:"pending-lna-ready"};const r=t.server;switch(r.status){case"ready":return{status:"ready",version:r.version};case"setup":return{status:"setup",version:r.version};case"resource-admin":return{status:"resource-admin",version:r.version};case"error":case"not-reachable":return{status:"error",error:{message:r.error.message}}}},[]),A=n.useCallback((t,r)=>{if(t.server.status!=="pending-extension-ready"){const i=t.server.status;if(i==="ready"||i==="setup"||i==="resource-admin")return!0}if(r.server.status!=="not-connected"){const i=r.server.status;if(i==="ready"||i==="setup"||i==="resource-admin")return!0}return!1},[]),R=n.useCallback((t,r,i)=>{if(r==="skipped")return{status:"skipped",serverUrl:i};if(t.server.status!=="not-connected"){const a=t.server;return a.status==="ready"||a.status==="setup"||a.status==="resource-admin"?{status:"granted",serverUrl:i}:{status:"unreachable",serverUrl:i,error:{message:a.error.message,code:"lna-unreachable"}}}return r==="granted"?{status:"granted",serverUrl:i}:{status:"prompt",serverUrl:i}},[]),d=n.useCallback(async(t=!1)=>{const r=s.detectBrowser().type,i=s.detectOS().type;let a=await e.getExtensionState();(a.extension==="not-initialized"||t)&&(a=await e.testExtensionConnectivity());let u=await e.getDirectState();const h=l.getDirectStatus();h==="granted"&&(u.server.status==="not-connected"||t)&&(u=await e.testDirectConnectivity());const M=s.getServerUrl(u)||"http://localhost:1135",U=R(u,h,M);return e.getConnectionMode()===null&&(s.isDirectServerReady(u)?await e.setConnectionMode("direct"):s.isExtensionServerReady(a)&&await e.setConnectionMode("extension")),l.isServerInstallConfirmed()||A(a,u)&&l.setServerInstallConfirmed(!0),{extension:L(a),server:g(a),lna:U,lnaServer:E(u),env:{browser:r,os:i},browsers:s.BROWSER_CONFIGS,os:s.OS_CONFIGS,userConfirmations:{serverInstall:l.isServerInstallConfirmed()},selectedConnection:C(e.getConnectionMode())}},[e,l,L,g,E,C,R,A]),f=n.useCallback(()=>{if(!S.current)throw new Error("Cannot get state: currentStateRef is null");return{...S.current,userConfirmations:{serverInstall:l.isServerInstallConfirmed()},selectedConnection:C(e.getConnectionMode())}},[l,e,C]),x=n.useMemo(()=>({[p.MODAL_READY]:async()=>(O.info("MODAL_READY: building initial state"),{setupState:f()}),[p.MODAL_REFRESH]:async()=>{O.info("MODAL_REFRESH: refreshing state");const t=await d(!0);S.current=t;const r=f();return O.info(`MODAL_REFRESH: state refreshed
2
+ `,JSON.stringify(r,null,2)),c.current?.updateState(f()),{setupState:r}},[p.MODAL_LNA_CONNECT]:async t=>{const r=t.payload.serverUrl;console.log("[SetupModalProcessor] LNA connect:",r);const i=await e.testDirectConnectivity(r);if(i.server.status!=="not-connected"){const u=i.server.status;if(u==="ready"||u==="setup"||u==="resource-admin"){l.setDirectStatus("granted"),e.getConnectionMode()===null&&await e.setConnectionMode("direct");const h=await d();return S.current=h,c.current?.updateState(f()),{success:!0}}}const a=await d();return S.current=a,c.current?.updateState(f()),{success:!1}},[p.MODAL_LNA_SKIP]:async()=>{l.setDirectStatus("skipped");const t=await d();return S.current=t,c.current?.updateState(f()),{success:!0}},[p.MODAL_CLOSE]:()=>{y()},[p.MODAL_COMPLETE]:()=>{y()},[p.MODAL_CONFIRM_SERVER_INSTALL]:t=>(l.setServerInstallConfirmed(t.payload.confirmed),c.current?.updateState(f()),{success:!0}),[p.MODAL_SELECT_CONNECTION]:async t=>{const i=t.payload.connection==="lna"?"direct":"extension";return await e.setConnectionMode(i),c.current?.updateState(f()),{success:!0}}}),[O,e,l,d,f,E,y]);return n.useEffect(()=>(c.current=new s.OnboardingModal({modalHtmlPath:o,handlers:x}),()=>{c.current?.destroy(),c.current=null}),[o,x]),n.useEffect(()=>{b&&c.current?d(!0).then(t=>{S.current=t,c.current?.show(t),m?.()}).catch(t=>{console.error("[SetupModalProcessor] buildSetupState failed:",t)}):!b&&c.current&&c.current.destroy()},[b,d,m]),null}const _=n.createContext(null);_.displayName="BodhiContext";function G({children:e,client:o,modalHtmlPath:y,handleCallback:m=!0,callbackPath:I="/callback",basePath:v="/",logLevel:D="warn"}){const b=n.useRef(!1),O=n.useRef(!1),[c,l]=n.useState({type:"not-initialized"}),[S,C]=n.useState(null),[L,g]=n.useState(!1),[E,A]=n.useState("ready");n.useEffect(()=>{const a=u=>{switch(u.type){case"client-state":l(u.state);break;case"auth-state":C(u.state),g(!1);break}};return o.setStateCallback(a),()=>{o.setStateCallback(s.NOOP_STATE_CALLBACK)}},[o]);const R=n.useCallback(async()=>{A("loading")},[]),d=n.useCallback(()=>{A("ready")},[]),f=n.useCallback(()=>{A("loaded")},[]),x=n.useCallback(async a=>{l({type:"initializing"});try{await o.init(a||{})}catch(u){console.error("[BodhiProvider] Init failed:",u)}},[o]);n.useEffect(()=>{if(O.current)return;O.current=!0,(async()=>{if(await x(),!m)return;const u=new URL(window.location.href);if(u.pathname!==I)return;const h=u.searchParams.get("code"),P=u.searchParams.get("state");!h||!P||b.current||(b.current=!0,s.isWebUIClient(o)&&(g(!0),o.handleOAuthCallback(h,P).then(()=>{window.history.replaceState({},"",v)}).catch(M=>{console.error("OAuth callback failed:",M),C({isLoggedIn:!1,error:{message:M instanceof Error?M.message:"OAuth callback failed",code:"OAUTH_CALLBACK_FAILED"}}),g(!1),window.history.replaceState({},"",v)})))})()},[x,o,m,I,v]);const t=n.useCallback(async()=>{g(!0);try{await o.login()}catch(a){C({isLoggedIn:!1,error:{message:a instanceof Error?a.message:"Login failed",code:"LOGIN_FAILED"}}),g(!1)}},[o]),r=n.useCallback(async()=>{try{await o.logout()}catch(a){C({isLoggedIn:!1,error:{message:a instanceof Error?a.message:"Logout failed",code:"LOGOUT_FAILED"}})}},[o]),i=n.useMemo(()=>({client:o,clientState:c,auth:S,authLoading:L,login:t,logout:r,showSetup:R,hideSetup:d,setupState:E}),[o,c,S,L,E,t,r,R,d]);return B.jsxs(_.Provider,{value:i,children:[B.jsx(H,{client:o,modalHtmlPath:y,hideSetup:d,onSetupReady:f,setupState:E,basePath:v,logLevel:D}),e]})}function K(){const e=n.useContext(_);if(!e)throw new Error("useBodhi must be used within BodhiProvider");return{client:e.client,clientState:e.clientState,setupState:e.setupState,auth:e.auth,authLoading:e.authLoading,login:e.login,logout:e.logout,showSetup:e.showSetup,hideSetup:e.hideSetup}}function k(e){return e.type==="not-initialized"}function N(e){return e.type==="initializing"}function w(e){return!(k(e)||N(e))}function T(e){return w(e)?s.isClientReady(e):!1}function z(e){if(k(e))return{ready:!1,actualState:"not-initialized",mode:null};if(N(e))return{ready:!1,actualState:"initializing",mode:null};const o=s.isExtensionState(e)?"extension":"direct",y=s.isClientReady(e),m=s.isExtensionState(e)?e.extension:e.server.status==="not-connected"?"not-connected":"ready";return{ready:y,actualState:m,mode:o}}function j(e){if(!w(e))return{ready:!1,actualState:"n/a"};const o=e.server;return{ready:o.status==="ready",actualState:o.status}}function F(e){return w(e)?s.isClientReady(e)&&e.server.status==="ready":!1}const V={isNotInitialized:k,isInitializing:N,isInitialized:w,isReady:T,getClientInitState:z,getServerState:j,isOverallReady:F},W="production";Object.defineProperty(exports,"createApiError",{enumerable:!0,get:()=>s.createApiError});Object.defineProperty(exports,"createOperationError",{enumerable:!0,get:()=>s.createOperationError});Object.defineProperty(exports,"isApiResultError",{enumerable:!0,get:()=>s.isApiResultError});Object.defineProperty(exports,"isApiResultOperationError",{enumerable:!0,get:()=>s.isApiResultOperationError});Object.defineProperty(exports,"isApiResultSuccess",{enumerable:!0,get:()=>s.isApiResultSuccess});Object.defineProperty(exports,"isAuthError",{enumerable:!0,get:()=>s.isAuthError});Object.defineProperty(exports,"isAuthLoggedIn",{enumerable:!0,get:()=>s.isAuthLoggedIn});Object.defineProperty(exports,"isClientReady",{enumerable:!0,get:()=>s.isClientReady});Object.defineProperty(exports,"isDirectState",{enumerable:!0,get:()=>s.isDirectState});Object.defineProperty(exports,"isExtensionState",{enumerable:!0,get:()=>s.isExtensionState});Object.defineProperty(exports,"isOperationError",{enumerable:!0,get:()=>s.isOperationError});exports.BodhiProvider=G;exports.BodhiReactContext=_;exports.ClientCtxState=V;exports.REACT_BUILD_MODE=W;exports.getClientInitState=z;exports.getServerState=j;exports.isClientCtxInitialized=w;exports.isClientCtxInitializing=N;exports.isClientCtxNotInitialized=k;exports.isClientCtxReady=T;exports.isOverallReady=F;exports.useBodhi=K;
@@ -1 +1,2 @@
1
1
  export * from './bodhi-js-sdk/react/src/index'
2
+ export {}
@@ -1,8 +1,8 @@
1
1
  import { jsxs as G, jsx as K } from "react/jsx-runtime";
2
- import { Logger as U, BodhiClientUserPrefsManager as V, detectBrowser as W, detectOS as Y, getServerUrl as j, isDirectServerReady as J, isExtensionServerReady as q, OS_CONFIGS as Q, BROWSER_CONFIGS as X, OnboardingModal as Z, NOOP_STATE_CALLBACK as $, isWebUIClient as ee, isClientReady as T, isExtensionState as F } from "@bodhiapp/bodhi-js-core";
3
- import { createApiError as Ce, createOperationError as me, isApiResultError as ve, isApiResultOperationError as ye, isApiResultSuccess as he, isAuthError as Le, isAuthLoggedIn as Ee, isClientReady as Ae, isDirectState as Oe, isExtensionState as we, isOperationError as xe } from "@bodhiapp/bodhi-js-core";
4
- import { useMemo as R, useRef as b, useCallback as c, useEffect as N, createContext as te, useState as I, useContext as re } from "react";
5
- const m = {
2
+ import { Logger as V, BodhiClientUserPrefsManager as W, createStoragePrefixWithBasePath as j, detectBrowser as Y, detectOS as J, getServerUrl as q, isDirectServerReady as Q, isExtensionServerReady as X, OS_CONFIGS as Z, BROWSER_CONFIGS as $, OnboardingModal as ee, NOOP_STATE_CALLBACK as te, isWebUIClient as re, isClientReady as B, isExtensionState as U } from "@bodhiapp/bodhi-js-core";
3
+ import { createApiError as ve, createOperationError as he, isApiResultError as Le, isApiResultOperationError as Ee, isApiResultSuccess as Oe, isAuthError as Ae, isAuthLoggedIn as we, isClientReady as xe, isDirectState as Me, isExtensionState as _e, isOperationError as De } from "@bodhiapp/bodhi-js-core";
4
+ import { useMemo as I, useRef as N, useCallback as c, useEffect as b, createContext as ne, useState as R, useContext as se } from "react";
5
+ const p = {
6
6
  // Modal lifecycle
7
7
  MODAL_READY: "modal:ready",
8
8
  MODAL_REFRESH: "modal:refresh",
@@ -16,18 +16,22 @@ const m = {
16
16
  // Connection selection
17
17
  MODAL_SELECT_CONNECTION: "modal:select-connection"
18
18
  };
19
- function ne({
19
+ function ae({
20
20
  client: e,
21
- modalHtmlPath: a,
22
- hideSetup: v,
23
- onSetupReady: S,
21
+ modalHtmlPath: s,
22
+ hideSetup: C,
23
+ onSetupReady: m,
24
24
  setupState: _,
25
+ basePath: y = "/",
25
26
  logLevel: D = "warn"
26
27
  }) {
27
- const A = _ !== "ready", y = R(() => new U("SetupModalProcessor", D), [D]), i = b(null), u = R(() => new V(), []), f = b(null), g = c(
28
+ const E = _ !== "ready", v = I(() => new V("SetupModalProcessor", D), [D]), i = N(null), u = I(
29
+ () => new W(j(y, "bodhijs:")),
30
+ [y]
31
+ ), f = N(null), S = c(
28
32
  (t) => t === "direct" ? "lna" : t === "extension" ? "extension" : null,
29
33
  []
30
- ), w = c((t) => t.extension === "ready" ? {
34
+ ), A = c((t) => t.extension === "ready" ? {
31
35
  status: "ready",
32
36
  version: "unknown",
33
37
  // TODO: have ExtensionState also get extension version
@@ -38,7 +42,7 @@ function ne({
38
42
  } : {
39
43
  status: "unreachable",
40
44
  error: { message: "Client not initialized", code: "ext-connection-failed" }
41
- }, []), p = c((t) => {
45
+ }, []), g = c((t) => {
42
46
  if (t.server.status === "pending-extension-ready")
43
47
  return {
44
48
  status: "pending-extension-ready",
@@ -89,62 +93,62 @@ function ne({
89
93
  }, []), O = c(
90
94
  (t, r) => {
91
95
  if (t.server.status !== "pending-extension-ready") {
92
- const s = t.server.status;
93
- if (s === "ready" || s === "setup" || s === "resource-admin")
96
+ const a = t.server.status;
97
+ if (a === "ready" || a === "setup" || a === "resource-admin")
94
98
  return !0;
95
99
  }
96
100
  if (r.server.status !== "not-connected") {
97
- const s = r.server.status;
98
- if (s === "ready" || s === "setup" || s === "resource-admin")
101
+ const a = r.server.status;
102
+ if (a === "ready" || a === "setup" || a === "resource-admin")
99
103
  return !0;
100
104
  }
101
105
  return !1;
102
106
  },
103
107
  []
104
- ), x = c(
105
- (t, r, s) => {
108
+ ), w = c(
109
+ (t, r, a) => {
106
110
  if (r === "skipped")
107
- return { status: "skipped", serverUrl: s };
111
+ return { status: "skipped", serverUrl: a };
108
112
  if (t.server.status !== "not-connected") {
109
113
  const n = t.server;
110
- return n.status === "ready" || n.status === "setup" || n.status === "resource-admin" ? { status: "granted", serverUrl: s } : {
114
+ return n.status === "ready" || n.status === "setup" || n.status === "resource-admin" ? { status: "granted", serverUrl: a } : {
111
115
  status: "unreachable",
112
- serverUrl: s,
116
+ serverUrl: a,
113
117
  error: { message: n.error.message, code: "lna-unreachable" }
114
118
  };
115
119
  }
116
- return r === "granted" ? { status: "granted", serverUrl: s } : { status: "prompt", serverUrl: s };
120
+ return r === "granted" ? { status: "granted", serverUrl: a } : { status: "prompt", serverUrl: a };
117
121
  },
118
122
  []
119
123
  ), d = c(
120
124
  async (t = !1) => {
121
- const r = W().type, s = Y().type;
125
+ const r = Y().type, a = J().type;
122
126
  let n = await e.getExtensionState();
123
127
  (n.extension === "not-initialized" || t) && (n = await e.testExtensionConnectivity());
124
128
  let o = await e.getDirectState();
125
- const C = u.getDirectStatus();
126
- C === "granted" && (o.server.status === "not-connected" || t) && (o = await e.testDirectConnectivity());
127
- const E = j(o) || "http://localhost:1135", H = x(o, C, E);
128
- return e.getConnectionMode() === null && (J(o) ? await e.setConnectionMode("direct") : q(n) && await e.setConnectionMode("extension")), u.isServerInstallConfirmed() || O(n, o) && u.setServerInstallConfirmed(!0), {
129
- extension: w(n),
130
- server: p(n),
129
+ const L = u.getDirectStatus();
130
+ L === "granted" && (o.server.status === "not-connected" || t) && (o = await e.testDirectConnectivity());
131
+ const M = q(o) || "http://localhost:1135", H = w(o, L, M);
132
+ return e.getConnectionMode() === null && (Q(o) ? await e.setConnectionMode("direct") : X(n) && await e.setConnectionMode("extension")), u.isServerInstallConfirmed() || O(n, o) && u.setServerInstallConfirmed(!0), {
133
+ extension: A(n),
134
+ server: g(n),
131
135
  lna: H,
132
136
  lnaServer: h(o),
133
- env: { browser: r, os: s },
134
- browsers: X,
135
- os: Q,
137
+ env: { browser: r, os: a },
138
+ browsers: $,
139
+ os: Z,
136
140
  userConfirmations: { serverInstall: u.isServerInstallConfirmed() },
137
- selectedConnection: g(e.getConnectionMode())
141
+ selectedConnection: S(e.getConnectionMode())
138
142
  };
139
143
  },
140
144
  [
141
145
  e,
142
146
  u,
143
- w,
144
- p,
145
- h,
147
+ A,
146
148
  g,
147
- x,
149
+ h,
150
+ S,
151
+ w,
148
152
  O
149
153
  ]
150
154
  ), l = c(() => {
@@ -157,156 +161,148 @@ function ne({
157
161
  serverInstall: u.isServerInstallConfirmed()
158
162
  },
159
163
  // Override selectedConnection from client (in case changed via handler)
160
- selectedConnection: g(e.getConnectionMode())
164
+ selectedConnection: S(e.getConnectionMode())
161
165
  };
162
- }, [u, e, g]), M = R(
166
+ }, [u, e, S]), x = I(
163
167
  () => ({
164
- [m.MODAL_READY]: async () => (y.info("MODAL_READY: building initial state"), { setupState: l() }),
165
- [m.MODAL_REFRESH]: async () => {
166
- var s;
167
- y.info("MODAL_REFRESH: refreshing state");
168
+ [p.MODAL_READY]: async () => (v.info("MODAL_READY: building initial state"), { setupState: l() }),
169
+ [p.MODAL_REFRESH]: async () => {
170
+ v.info("MODAL_REFRESH: refreshing state");
168
171
  const t = await d(!0);
169
172
  f.current = t;
170
173
  const r = l();
171
- return y.info(`MODAL_REFRESH: state refreshed
172
- `, JSON.stringify(r, null, 2)), (s = i.current) == null || s.updateState(l()), { setupState: r };
174
+ return v.info(`MODAL_REFRESH: state refreshed
175
+ `, JSON.stringify(r, null, 2)), i.current?.updateState(l()), { setupState: r };
173
176
  },
174
- [m.MODAL_LNA_CONNECT]: async (t) => {
175
- var o, C;
177
+ [p.MODAL_LNA_CONNECT]: async (t) => {
176
178
  const r = t.payload.serverUrl;
177
179
  console.log("[SetupModalProcessor] LNA connect:", r);
178
- const s = await e.testDirectConnectivity(r);
179
- if (s.server.status !== "not-connected") {
180
- const L = s.server.status;
181
- if (L === "ready" || L === "setup" || L === "resource-admin") {
180
+ const a = await e.testDirectConnectivity(r);
181
+ if (a.server.status !== "not-connected") {
182
+ const o = a.server.status;
183
+ if (o === "ready" || o === "setup" || o === "resource-admin") {
182
184
  u.setDirectStatus("granted"), e.getConnectionMode() === null && await e.setConnectionMode("direct");
183
- const E = await d();
184
- return f.current = E, (o = i.current) == null || o.updateState(l()), { success: !0 };
185
+ const L = await d();
186
+ return f.current = L, i.current?.updateState(l()), { success: !0 };
185
187
  }
186
188
  }
187
189
  const n = await d();
188
- return f.current = n, (C = i.current) == null || C.updateState(l()), { success: !1 };
190
+ return f.current = n, i.current?.updateState(l()), { success: !1 };
189
191
  },
190
- [m.MODAL_LNA_SKIP]: async () => {
191
- var r;
192
+ [p.MODAL_LNA_SKIP]: async () => {
192
193
  u.setDirectStatus("skipped");
193
194
  const t = await d();
194
- return f.current = t, (r = i.current) == null || r.updateState(l()), { success: !0 };
195
- },
196
- [m.MODAL_CLOSE]: () => {
197
- v();
195
+ return f.current = t, i.current?.updateState(l()), { success: !0 };
198
196
  },
199
- [m.MODAL_COMPLETE]: () => {
200
- v();
197
+ [p.MODAL_CLOSE]: () => {
198
+ C();
201
199
  },
202
- [m.MODAL_CONFIRM_SERVER_INSTALL]: (t) => {
203
- var r;
204
- return u.setServerInstallConfirmed(t.payload.confirmed), (r = i.current) == null || r.updateState(l()), { success: !0 };
200
+ [p.MODAL_COMPLETE]: () => {
201
+ C();
205
202
  },
206
- [m.MODAL_SELECT_CONNECTION]: async (t) => {
207
- var n;
208
- const s = t.payload.connection === "lna" ? "direct" : "extension";
209
- return await e.setConnectionMode(s), (n = i.current) == null || n.updateState(l()), { success: !0 };
203
+ [p.MODAL_CONFIRM_SERVER_INSTALL]: (t) => (u.setServerInstallConfirmed(t.payload.confirmed), i.current?.updateState(l()), { success: !0 }),
204
+ [p.MODAL_SELECT_CONNECTION]: async (t) => {
205
+ const a = t.payload.connection === "lna" ? "direct" : "extension";
206
+ return await e.setConnectionMode(a), i.current?.updateState(l()), { success: !0 };
210
207
  }
211
208
  }),
212
- [y, e, u, d, l, h, v]
209
+ [v, e, u, d, l, h, C]
213
210
  );
214
- return N(() => (i.current = new Z({ modalHtmlPath: a, handlers: M }), () => {
215
- var t;
216
- (t = i.current) == null || t.destroy(), i.current = null;
217
- }), [a, M]), N(() => {
218
- A && i.current ? d(!0).then((t) => {
219
- var r;
220
- f.current = t, (r = i.current) == null || r.show(t), S == null || S();
211
+ return b(() => (i.current = new ee({ modalHtmlPath: s, handlers: x }), () => {
212
+ i.current?.destroy(), i.current = null;
213
+ }), [s, x]), b(() => {
214
+ E && i.current ? d(!0).then((t) => {
215
+ f.current = t, i.current?.show(t), m?.();
221
216
  }).catch((t) => {
222
217
  console.error("[SetupModalProcessor] buildSetupState failed:", t);
223
- }) : !A && i.current && i.current.destroy();
224
- }, [A, d, S]), null;
218
+ }) : !E && i.current && i.current.destroy();
219
+ }, [E, d, m]), null;
225
220
  }
226
- const k = te(null);
227
- k.displayName = "BodhiContext";
228
- function le({
221
+ const z = ne(null);
222
+ z.displayName = "BodhiContext";
223
+ function Se({
229
224
  children: e,
230
- client: a,
231
- modalHtmlPath: v,
232
- handleCallback: S = !0,
233
- callbackUrl: _ = "/callback",
225
+ client: s,
226
+ modalHtmlPath: C,
227
+ handleCallback: m = !0,
228
+ callbackPath: _ = "/callback",
229
+ basePath: y = "/",
234
230
  logLevel: D = "warn"
235
231
  }) {
236
- const A = b(!1), y = b(!1), [i, u] = I(
232
+ const E = N(!1), v = N(!1), [i, u] = R(
237
233
  { type: "not-initialized" }
238
234
  // Start with UI state, client.init() will update
239
- ), [f, g] = I(null), [w, p] = I(!1), [h, O] = I("ready");
240
- N(() => {
235
+ ), [f, S] = R(null), [A, g] = R(!1), [h, O] = R("ready");
236
+ b(() => {
241
237
  const n = (o) => {
242
238
  switch (o.type) {
243
239
  case "client-state":
244
240
  u(o.state);
245
241
  break;
246
242
  case "auth-state":
247
- g(o.state), p(!1);
243
+ S(o.state), g(!1);
248
244
  break;
249
245
  }
250
246
  };
251
- return a.setStateCallback(n), () => {
252
- a.setStateCallback($);
247
+ return s.setStateCallback(n), () => {
248
+ s.setStateCallback(te);
253
249
  };
254
- }, [a]);
255
- const x = c(async () => {
250
+ }, [s]);
251
+ const w = c(async () => {
256
252
  O("loading");
257
253
  }, []), d = c(() => {
258
254
  O("ready");
259
255
  }, []), l = c(() => {
260
256
  O("loaded");
261
- }, []), M = c(
257
+ }, []), x = c(
262
258
  async (n) => {
263
259
  u({ type: "initializing" });
264
260
  try {
265
- await a.init(n || {});
261
+ await s.init(n || {});
266
262
  } catch (o) {
267
263
  console.error("[BodhiProvider] Init failed:", o);
268
264
  }
269
265
  },
270
- [a]
266
+ [s]
271
267
  );
272
- N(() => {
273
- if (y.current) return;
274
- y.current = !0, (async () => {
275
- if (await M(), !S) return;
268
+ b(() => {
269
+ if (v.current) return;
270
+ v.current = !0, (async () => {
271
+ if (await x(), !m) return;
276
272
  const o = new URL(window.location.href);
277
273
  if (o.pathname !== _) return;
278
- const C = o.searchParams.get("code"), L = o.searchParams.get("state");
279
- !C || !L || A.current || (A.current = !0, ee(a) && (p(!0), a.handleOAuthCallback(C, L).then(() => {
280
- window.history.replaceState({}, "", "/");
281
- }).catch((E) => {
282
- console.error("OAuth callback failed:", E), g({
274
+ const L = o.searchParams.get("code"), k = o.searchParams.get("state");
275
+ !L || !k || E.current || (E.current = !0, re(s) && (g(!0), s.handleOAuthCallback(L, k).then(() => {
276
+ window.history.replaceState({}, "", y);
277
+ }).catch((M) => {
278
+ console.error("OAuth callback failed:", M), S({
283
279
  isLoggedIn: !1,
284
280
  error: {
285
- message: E instanceof Error ? E.message : "OAuth callback failed",
281
+ message: M instanceof Error ? M.message : "OAuth callback failed",
286
282
  code: "OAUTH_CALLBACK_FAILED"
287
283
  }
288
- }), p(!1), window.history.replaceState({}, "", "/");
284
+ }), g(!1), window.history.replaceState({}, "", y);
289
285
  })));
290
286
  })();
291
- }, [M, a, S, _]);
287
+ }, [x, s, m, _, y]);
292
288
  const t = c(async () => {
293
- p(!0);
289
+ g(!0);
294
290
  try {
295
- await a.login();
291
+ await s.login();
296
292
  } catch (n) {
297
- g({
293
+ S({
298
294
  isLoggedIn: !1,
299
295
  error: {
300
296
  message: n instanceof Error ? n.message : "Login failed",
301
297
  code: "LOGIN_FAILED"
302
298
  }
303
- }), p(!1);
299
+ }), g(!1);
304
300
  }
305
- }, [a]), r = c(async () => {
301
+ }, [s]), r = c(async () => {
306
302
  try {
307
- await a.logout();
303
+ await s.logout();
308
304
  } catch (n) {
309
- g({
305
+ S({
310
306
  isLoggedIn: !1,
311
307
  error: {
312
308
  message: n instanceof Error ? n.message : "Logout failed",
@@ -314,37 +310,38 @@ function le({
314
310
  }
315
311
  });
316
312
  }
317
- }, [a]), s = R(
313
+ }, [s]), a = I(
318
314
  () => ({
319
- client: a,
315
+ client: s,
320
316
  clientState: i,
321
317
  auth: f,
322
- authLoading: w,
318
+ authLoading: A,
323
319
  login: t,
324
320
  logout: r,
325
- showSetup: x,
321
+ showSetup: w,
326
322
  hideSetup: d,
327
323
  setupState: h
328
324
  }),
329
- [a, i, f, w, h, t, r, x, d]
325
+ [s, i, f, A, h, t, r, w, d]
330
326
  );
331
- return /* @__PURE__ */ G(k.Provider, { value: s, children: [
327
+ return /* @__PURE__ */ G(z.Provider, { value: a, children: [
332
328
  /* @__PURE__ */ K(
333
- ne,
329
+ ae,
334
330
  {
335
- client: a,
336
- modalHtmlPath: v,
331
+ client: s,
332
+ modalHtmlPath: C,
337
333
  hideSetup: d,
338
334
  onSetupReady: l,
339
335
  setupState: h,
336
+ basePath: y,
340
337
  logLevel: D
341
338
  }
342
339
  ),
343
340
  e
344
341
  ] });
345
342
  }
346
- function fe() {
347
- const e = re(k);
343
+ function ge() {
344
+ const e = se(z);
348
345
  if (!e) throw new Error("useBodhi must be used within BodhiProvider");
349
346
  return {
350
347
  client: e.client,
@@ -358,70 +355,71 @@ function fe() {
358
355
  hideSetup: e.hideSetup
359
356
  };
360
357
  }
361
- function z(e) {
358
+ function P(e) {
362
359
  return e.type === "not-initialized";
363
360
  }
364
- function B(e) {
361
+ function F(e) {
365
362
  return e.type === "initializing";
366
363
  }
367
- function P(e) {
368
- return !(z(e) || B(e));
364
+ function T(e) {
365
+ return !(P(e) || F(e));
369
366
  }
370
- function se(e) {
371
- return P(e) ? T(e) : !1;
367
+ function oe(e) {
368
+ return T(e) ? B(e) : !1;
372
369
  }
373
- function ae(e) {
374
- if (z(e))
370
+ function ie(e) {
371
+ if (P(e))
375
372
  return { ready: !1, actualState: "not-initialized", mode: null };
376
- if (B(e))
373
+ if (F(e))
377
374
  return { ready: !1, actualState: "initializing", mode: null };
378
- const a = F(e) ? "extension" : "direct", v = T(e), S = F(e) ? e.extension : e.server.status === "not-connected" ? "not-connected" : "ready";
379
- return { ready: v, actualState: S, mode: a };
375
+ const s = U(e) ? "extension" : "direct", C = B(e), m = U(e) ? e.extension : e.server.status === "not-connected" ? "not-connected" : "ready";
376
+ return { ready: C, actualState: m, mode: s };
380
377
  }
381
- function oe(e) {
382
- if (!P(e))
378
+ function ue(e) {
379
+ if (!T(e))
383
380
  return { ready: !1, actualState: "n/a" };
384
- const a = e.server;
381
+ const s = e.server;
385
382
  return {
386
- ready: a.status === "ready",
387
- actualState: a.status
383
+ ready: s.status === "ready",
384
+ actualState: s.status
388
385
  };
389
386
  }
390
- function ie(e) {
391
- return P(e) ? T(e) && e.server.status === "ready" : !1;
387
+ function ce(e) {
388
+ return T(e) ? B(e) && e.server.status === "ready" : !1;
392
389
  }
393
- const Se = {
390
+ const pe = {
394
391
  // Type guards
395
- isNotInitialized: z,
396
- isInitializing: B,
397
- isInitialized: P,
398
- isReady: se,
392
+ isNotInitialized: P,
393
+ isInitializing: F,
394
+ isInitialized: T,
395
+ isReady: oe,
399
396
  // Derived state
400
- getClientInitState: ae,
401
- getServerState: oe,
402
- isOverallReady: ie
403
- };
397
+ getClientInitState: ie,
398
+ getServerState: ue,
399
+ isOverallReady: ce
400
+ }, Ce = "production";
404
401
  export {
405
- le as BodhiProvider,
406
- k as BodhiReactContext,
407
- Se as ClientCtxState,
408
- Ce as createApiError,
409
- me as createOperationError,
410
- ae as getClientInitState,
411
- oe as getServerState,
412
- ve as isApiResultError,
413
- ye as isApiResultOperationError,
414
- he as isApiResultSuccess,
415
- Le as isAuthError,
416
- Ee as isAuthLoggedIn,
417
- P as isClientCtxInitialized,
418
- B as isClientCtxInitializing,
419
- z as isClientCtxNotInitialized,
420
- se as isClientCtxReady,
421
- Ae as isClientReady,
422
- Oe as isDirectState,
423
- we as isExtensionState,
424
- xe as isOperationError,
425
- ie as isOverallReady,
426
- fe as useBodhi
402
+ Se as BodhiProvider,
403
+ z as BodhiReactContext,
404
+ pe as ClientCtxState,
405
+ Ce as REACT_BUILD_MODE,
406
+ ve as createApiError,
407
+ he as createOperationError,
408
+ ie as getClientInitState,
409
+ ue as getServerState,
410
+ Le as isApiResultError,
411
+ Ee as isApiResultOperationError,
412
+ Oe as isApiResultSuccess,
413
+ Ae as isAuthError,
414
+ we as isAuthLoggedIn,
415
+ T as isClientCtxInitialized,
416
+ F as isClientCtxInitializing,
417
+ P as isClientCtxNotInitialized,
418
+ oe as isClientCtxReady,
419
+ xe as isClientReady,
420
+ Me as isDirectState,
421
+ _e as isExtensionState,
422
+ De as isOperationError,
423
+ ce as isOverallReady,
424
+ ge as useBodhi
427
425
  };
@@ -1,5 +1,4 @@
1
1
  import { SetupState } from './state';
2
-
3
2
  /**
4
3
  * Central registry mapping message types to their payload/response shapes
5
4
  * Single source of truth - everything else is inferred!
@@ -1,5 +1,4 @@
1
1
  import { MessageType, RequestPayload, ResponsePayload } from './message-types';
2
-
3
2
  /** Branded type for type-safe request IDs */
4
3
  export type RequestId = string & {
5
4
  readonly __brand: 'RequestId';
@@ -2,7 +2,6 @@ import { Browser, EnvState, OS } from './platform';
2
2
  import { ExtensionState } from './extension';
3
3
  import { ServerState } from './server';
4
4
  import { LnaServerState, LnaState } from './lna';
5
-
6
5
  export declare enum SetupStep {
7
6
  PLATFORM_CHECK = "platform-check",
8
7
  SERVER_SETUP = "server-setup",
@@ -2,7 +2,6 @@ import { ExtensionState, ExtensionStateNotReady, ExtensionStateReady } from './e
2
2
  import { ServerState, ServerStateError, ServerStatePending, ServerStateReachable, ServerStateReady, ServerStateUnreachable } from './server';
3
3
  import { LnaServerState, LnaServerStateError, LnaServerStatePending, LnaServerStateReady, LnaServerStateResourceAdmin, LnaServerStateSetup, LnaState, LnaStateDenied, LnaStateGranted, LnaStatePrompt, LnaStateSkipped, LnaStateUnreachable, LnaStateUnsupported } from './lna';
4
4
  import { Browser, NotSupportedBrowser, NotSupportedOS, OS, SupportedBrowser, SupportedOS } from './platform';
5
-
6
5
  export declare function isExtensionStateReady(ext: ExtensionState): ext is ExtensionStateReady;
7
6
  export declare function isExtensionStateNotReady(ext: ExtensionState): ext is ExtensionStateNotReady;
8
7
  export declare function isServerStateReady(server: ServerState): server is ServerStateReady;
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@bodhiapp/bodhi-js-react",
3
- "version": "0.0.3",
3
+ "version": "0.0.5",
4
4
  "description": "React bindings for Bodhi Browser SDK",
5
5
  "type": "module",
6
6
  "main": "dist/bodhi-react.cjs.js",
@@ -34,14 +34,15 @@
34
34
  "lint:fix": "prettier --write . && eslint . --ext .js,.jsx,.ts,.tsx --fix"
35
35
  },
36
36
  "dependencies": {
37
- "@bodhiapp/bodhi-js-core": "0.0.3",
38
- "@bodhiapp/ts-client": "^0.1.7"
37
+ "@bodhiapp/bodhi-js-core": "0.0.5",
38
+ "@bodhiapp/ts-client": "0.1.8"
39
39
  },
40
40
  "peerDependencies": {
41
41
  "react": "^18.3.0 || ^19.0.0"
42
42
  },
43
43
  "devDependencies": {
44
44
  "@eslint/js": "^9.23.0",
45
+ "@types/node": "^20.19.10",
45
46
  "@types/react": "^19.0.0",
46
47
  "@typescript-eslint/eslint-plugin": "8.28.0",
47
48
  "@typescript-eslint/parser": "8.28.0",
@@ -52,7 +53,7 @@
52
53
  "rimraf": "^6.0.1",
53
54
  "tslib": "^2.6.2",
54
55
  "typescript": "^5.8.3",
55
- "vite": "^5.2.0",
56
- "vite-plugin-dts": "^3.9.1"
56
+ "vite": "^7.1.12",
57
+ "vite-plugin-dts": "^4.5.4"
57
58
  }
58
59
  }