@bodhiapp/bodhi-js 0.0.1

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 (47) hide show
  1. package/README.md +26 -0
  2. package/dist/bodhi-browser-ext/src/types/bodhiext.d.ts +202 -0
  3. package/dist/bodhi-browser-ext/src/types/common.d.ts +36 -0
  4. package/dist/bodhi-browser-ext/src/types/index.d.ts +6 -0
  5. package/dist/bodhi-browser-ext/src/types/protocol.d.ts +223 -0
  6. package/dist/bodhi-js-sdk/core/src/direct-client-base.d.ts +129 -0
  7. package/dist/bodhi-js-sdk/core/src/errors.d.ts +23 -0
  8. package/dist/bodhi-js-sdk/core/src/facade-client-base.d.ts +130 -0
  9. package/dist/bodhi-js-sdk/core/src/index.d.ts +19 -0
  10. package/dist/bodhi-js-sdk/core/src/interface.d.ts +228 -0
  11. package/dist/bodhi-js-sdk/core/src/logger.d.ts +13 -0
  12. package/dist/bodhi-js-sdk/core/src/oauth.d.ts +45 -0
  13. package/dist/bodhi-js-sdk/core/src/onboarding/config.d.ts +10 -0
  14. package/dist/bodhi-js-sdk/core/src/onboarding/index.d.ts +5 -0
  15. package/dist/bodhi-js-sdk/core/src/onboarding/modal.d.ts +80 -0
  16. package/dist/bodhi-js-sdk/core/src/onboarding/protocol-utils.d.ts +33 -0
  17. package/dist/bodhi-js-sdk/core/src/platform.d.ts +11 -0
  18. package/dist/bodhi-js-sdk/core/src/storage.d.ts +81 -0
  19. package/dist/bodhi-js-sdk/core/src/types/api.d.ts +34 -0
  20. package/dist/bodhi-js-sdk/core/src/types/callback.d.ts +23 -0
  21. package/dist/bodhi-js-sdk/core/src/types/client-state.d.ts +191 -0
  22. package/dist/bodhi-js-sdk/core/src/types/config.d.ts +26 -0
  23. package/dist/bodhi-js-sdk/core/src/types/html.d.ts +9 -0
  24. package/dist/bodhi-js-sdk/core/src/types/index.d.ts +15 -0
  25. package/dist/bodhi-js-sdk/core/src/types/platform.d.ts +16 -0
  26. package/dist/bodhi-js-sdk/core/src/types/user-info.d.ts +59 -0
  27. package/dist/bodhi-js-sdk/web/src/constants.d.ts +9 -0
  28. package/dist/bodhi-js-sdk/web/src/direct-client.d.ts +24 -0
  29. package/dist/bodhi-js-sdk/web/src/ext-client.d.ts +151 -0
  30. package/dist/bodhi-js-sdk/web/src/facade-client.d.ts +43 -0
  31. package/dist/bodhi-js-sdk/web/src/index.d.ts +5 -0
  32. package/dist/bodhi-js-sdk/web/src/interface.d.ts +4 -0
  33. package/dist/bodhi-web.cjs.js +749 -0
  34. package/dist/bodhi-web.cjs.js.map +1 -0
  35. package/dist/bodhi-web.esm.d.ts +1 -0
  36. package/dist/bodhi-web.esm.js +749 -0
  37. package/dist/bodhi-web.esm.js.map +1 -0
  38. package/dist/setup-modal/src/types/extension.d.ts +24 -0
  39. package/dist/setup-modal/src/types/index.d.ts +20 -0
  40. package/dist/setup-modal/src/types/lna.d.ts +56 -0
  41. package/dist/setup-modal/src/types/message-types.d.ts +169 -0
  42. package/dist/setup-modal/src/types/platform.d.ts +32 -0
  43. package/dist/setup-modal/src/types/protocol.d.ts +71 -0
  44. package/dist/setup-modal/src/types/server.d.ts +63 -0
  45. package/dist/setup-modal/src/types/state.d.ts +43 -0
  46. package/dist/setup-modal/src/types/type-guards.d.ts +27 -0
  47. package/package.json +54 -0
@@ -0,0 +1,130 @@
1
+ import { CreateChatCompletionStreamResponse } from '@bodhiapp/ts-client';
2
+ import { IConnectionClient } from './interface';
3
+ import { Logger } from './logger';
4
+ import { BodhiClientUserPrefsManager } from './storage';
5
+ import { ApiResponseResult, AuthLoggedIn, AuthLoggedOut, AuthState, BackendServerState, ClientState, ConnectionMode, DirectState, ExtensionState, InitParams, SerializedClientState, SerializedDirectState, SerializedExtensionState, StateChange, StateChangeCallback } from './types';
6
+
7
+ /**
8
+ * Base facade client with common delegation logic
9
+ *
10
+ * @template TConfig - Configuration type for this facade
11
+ * @template TExtClient - Extension client type (implements IConnectionClient with SerializedExtensionState)
12
+ * @template TDirectClient - Direct client type (implements IConnectionClient with SerializedDirectState)
13
+ */
14
+ export declare abstract class BaseFacadeClient<TConfig, TExtClient extends IConnectionClient<unknown, SerializedExtensionState>, TDirectClient extends IConnectionClient<unknown, SerializedDirectState>> {
15
+ protected logger: Logger;
16
+ protected extClient: TExtClient;
17
+ protected directClient: TDirectClient;
18
+ protected prefs: BodhiClientUserPrefsManager;
19
+ protected connectionMode: ConnectionMode | null;
20
+ protected authClientId: string;
21
+ protected config: TConfig;
22
+ protected onStateChange: StateChangeCallback;
23
+ constructor(authClientId: string, config: TConfig, onStateChange?: StateChangeCallback, storagePrefix?: string);
24
+ /**
25
+ * Create logger instance
26
+ * Subclasses extract logLevel from their specific config type
27
+ */
28
+ protected abstract createLogger(config: TConfig): Logger;
29
+ /**
30
+ * Create extension-based client (ExtClient or WindowBodhiextClient)
31
+ */
32
+ protected abstract createExtClient(config: TConfig, onStateChange: (change: StateChange) => void): TExtClient;
33
+ /**
34
+ * Create direct HTTP client (DirectExtClient or DirectWebClient)
35
+ */
36
+ protected abstract createDirectClient(authClientId: string, config: TConfig, onStateChange: (change: StateChange) => void): TDirectClient;
37
+ /**
38
+ * Notify client state change by calling facade's callback with discriminated union
39
+ */
40
+ private notifyStateChange;
41
+ /**
42
+ * Handle state changes from internal clients (extClient or directClient)
43
+ * For client state changes, notifyStateChange that persists and notifies
44
+ * For auth state changes, notify the callback directly
45
+ */
46
+ private handleInternalStateChange;
47
+ /**
48
+ * Serialize current state for persistence
49
+ * Returns SerializedClientState with nested client states
50
+ */
51
+ serialize(): SerializedClientState;
52
+ /**
53
+ * Debug dump of facade client internal state
54
+ * Aggregates debug info from both internal clients
55
+ */
56
+ debug(): Promise<Record<string, unknown>>;
57
+ /**
58
+ * Persist current state to storage
59
+ */
60
+ persist(): void;
61
+ /**
62
+ * Set or update the state change callback
63
+ */
64
+ setStateCallback(callback: StateChangeCallback): void;
65
+ /**
66
+ * Check if connection mode is null or direct
67
+ * Used for delegation - prefers direct on fresh install
68
+ */
69
+ protected isNotSetOrDirect(): boolean;
70
+ /**
71
+ * Initialize client based on current connectionMode
72
+ *
73
+ * State Management:
74
+ * - Facade owns persistence via prefs - savedState param is NOT used
75
+ * - Restores connectionMode and internal client states from prefs.getSerializedClientState()
76
+ * - On fresh install (no saved state), defaults to connectionMode: null
77
+ *
78
+ * InitParams (optional):
79
+ * - serverUrl: Direct mode server URL (overrides saved state)
80
+ * - testConnection: Test server connectivity during init
81
+ * - timeoutMs: Extension mode discovery timeout
82
+ * - selectedConnection, savedState: Internal use only (not for external callers)
83
+ *
84
+ * Eager Connection Detection (when connectionMode is null):
85
+ * Tries direct first, then extension, auto-selecting first one with server ready
86
+ */
87
+ init(params?: InitParams): Promise<ExtensionState | DirectState>;
88
+ getState(): ClientState;
89
+ isClientInitialized(): boolean;
90
+ isServerReady(): boolean;
91
+ sendExtRequest<TParams = void, TRes = unknown>(action: string, params?: TParams): Promise<TRes>;
92
+ sendApiRequest<TReq = void, TRes = unknown>(method: string, endpoint: string, body?: TReq, headers?: Record<string, string>, authenticated?: boolean): Promise<ApiResponseResult<TRes>>;
93
+ login(): Promise<AuthLoggedIn>;
94
+ logout(): Promise<AuthLoggedOut>;
95
+ getAuthState(): Promise<AuthState>;
96
+ pingApi(): Promise<ApiResponseResult<{
97
+ message: string;
98
+ }>>;
99
+ fetchModels(): Promise<ApiResponseResult<{
100
+ data: Array<{
101
+ id: string;
102
+ object: string;
103
+ }>;
104
+ }>>;
105
+ getServerState(): Promise<BackendServerState>;
106
+ stream<TReq = unknown, TRes = unknown>(method: string, endpoint: string, body?: TReq, headers?: Record<string, string>, authenticated?: boolean): AsyncGenerator<TRes>;
107
+ streamChat(model: string, prompt: string, authenticated?: boolean): AsyncGenerator<CreateChatCompletionStreamResponse>;
108
+ getConnectionMode(): ConnectionMode | null;
109
+ setConnectionMode(mode: ConnectionMode): Promise<ClientState>;
110
+ /**
111
+ * Test extension connectivity regardless of current connection mode
112
+ * Fresh connection test - injects testConnection: true internally
113
+ * @param timeoutMs - Optional timeout for extension discovery
114
+ */
115
+ testExtensionConnectivity(timeoutMs?: number): Promise<ExtensionState>;
116
+ /**
117
+ * Test direct server connectivity
118
+ * Fresh connection test - injects testConnection: true internally
119
+ * @param serverUrl - Optional server URL to test. If not provided, uses saved serverUrl from state
120
+ */
121
+ testDirectConnectivity(serverUrl?: string): Promise<DirectState>;
122
+ /**
123
+ * Get current extension state (regardless of current connection mode)
124
+ */
125
+ getExtensionState(): Promise<ExtensionState>;
126
+ /**
127
+ * Get current direct server state
128
+ */
129
+ getDirectState(): Promise<DirectState>;
130
+ }
@@ -0,0 +1,19 @@
1
+ /**
2
+ * @bodhiapp/bodhi-js-core - Minimal shared types and interfaces
3
+ *
4
+ * This package contains the minimal shared code between ext and web SDKs:
5
+ * - Types (ApiResponseResult, ClientState, UserInfo, etc.)
6
+ * - Error factories (createApiError, createOperationError)
7
+ * - Logger (centralized logging)
8
+ * - UIClient interface (base interface)
9
+ */
10
+ export * from './types';
11
+ export * from './logger';
12
+ export * from './interface';
13
+ export * from './platform';
14
+ export * from './storage';
15
+ export * from './onboarding';
16
+ export * from './oauth';
17
+ export * from './direct-client-base';
18
+ export * from './facade-client-base';
19
+ export { isOperationError, type OperationError } from '../../../bodhi-browser-ext/src/types';
@@ -0,0 +1,228 @@
1
+ import { CreateChatCompletionStreamResponse } from '@bodhiapp/ts-client';
2
+ import { ApiResponseResult, AuthLoggedIn, AuthLoggedOut, AuthState, BackendServerState, ClientState, ConnectionMode, DirectState, ExtensionState, InitParams, StateChangeCallback } from './types';
3
+
4
+ /**
5
+ * ConnectionClient - Base interface for all client implementations
6
+ *
7
+ * Defines common interface for:
8
+ * - IExtensionClient (chrome.runtime or window.bodhiext)
9
+ * - DirectClient (direct HTTP fetch)
10
+ *
11
+ * Includes both connection methods (API calls, streaming) and auth methods.
12
+ *
13
+ * @template IParams - The init params type for this client
14
+ * @template SerialState - The serialized state type for persistence
15
+ */
16
+ export interface IConnectionClient<IParams = unknown, SerialState = unknown> {
17
+ /**
18
+ * Initialize client discovery/connectivity
19
+ * - IExtensionClient: Discover bodhi-browser-ext extension
20
+ * - DirectClient: Test HTTP connectivity to server
21
+ *
22
+ * @param params - ExtParams or DirectParams (discriminated by serverUrl presence)
23
+ * @returns ClientState (ExtensionState or DirectState based on active connection mode)
24
+ */
25
+ init(params: IParams): Promise<ClientState>;
26
+ /**
27
+ * Get current client state
28
+ * @returns ClientState with status and connectionMode
29
+ */
30
+ getState(): ClientState;
31
+ /**
32
+ * Check if client is initialized (has handle/url configured)
33
+ * - DirectClient: serverUrl is set
34
+ * - ExtensionClient: extension is 'ready'
35
+ * @returns true if client is ready to make requests
36
+ */
37
+ isClientInitialized(): boolean;
38
+ /**
39
+ * Check if backend server is ready (status === 'ready')
40
+ * @returns true if server is connected and ready
41
+ */
42
+ isServerReady(): boolean;
43
+ /**
44
+ * Send API request to local server
45
+ * @param authenticated - If true, injects access token automatically
46
+ * @returns ApiResponseResult with response or operation error
47
+ */
48
+ sendApiRequest<TReq = void, TRes = unknown>(method: string, endpoint: string, body?: TReq, headers?: Record<string, string>, authenticated?: boolean): Promise<ApiResponseResult<TRes>>;
49
+ /**
50
+ * Ping API endpoint
51
+ * @returns ApiResponseResult with ping response
52
+ */
53
+ pingApi(): Promise<ApiResponseResult<{
54
+ message: string;
55
+ }>>;
56
+ /**
57
+ * Fetch available models from /v1/models
58
+ * @returns ApiResponseResult with models list
59
+ */
60
+ fetchModels(): Promise<ApiResponseResult<{
61
+ data: Array<{
62
+ id: string;
63
+ object: string;
64
+ }>;
65
+ }>>;
66
+ /**
67
+ * Get backend server state
68
+ * Calls /bodhi/v1/info and returns structured server state
69
+ * @returns BackendServerState with status and version
70
+ */
71
+ getServerState(): Promise<BackendServerState>;
72
+ /**
73
+ * Generic streaming request
74
+ * - IExtensionClient: chrome.runtime.connect port or window.bodhiext stream
75
+ * - DirectClient: Server-Sent Events (SSE) via fetch
76
+ *
77
+ * @returns AsyncGenerator yielding response chunks
78
+ */
79
+ stream<TReq = unknown, TRes = unknown>(method: string, endpoint: string, body?: TReq, headers?: Record<string, string>, authenticated?: boolean): AsyncGenerator<TRes>;
80
+ /**
81
+ * Chat streaming (convenience wrapper for stream)
82
+ * @returns AsyncGenerator yielding chat completion chunks
83
+ */
84
+ streamChat(model: string, prompt: string, authenticated?: boolean): AsyncGenerator<CreateChatCompletionStreamResponse>;
85
+ /**
86
+ * Login via OAuth
87
+ * - IExtensionClient: Delegates to extension (chrome.identity or browser redirect)
88
+ * - DirectClient: Direct HTTP OAuth flow
89
+ * @returns AuthLoggedIn with login state and user info
90
+ */
91
+ login(): Promise<AuthLoggedIn>;
92
+ /**
93
+ * Logout and revoke tokens
94
+ * @returns AuthLoggedOut with logged out state
95
+ */
96
+ logout(): Promise<AuthLoggedOut>;
97
+ /**
98
+ * Get current authentication state
99
+ * @returns AuthState (discriminated union: AuthLoggedIn | AuthLoggedOut)
100
+ */
101
+ getAuthState(): Promise<AuthState>;
102
+ /**
103
+ * Set or update the state change callback
104
+ * Allows setting callback after construction (for React dependency injection)
105
+ * @param callback - Callback invoked on client state or auth state changes
106
+ */
107
+ setStateCallback(callback: StateChangeCallback): void;
108
+ /**
109
+ * Serialize client state for persistence
110
+ * @returns Serialized state suitable for localStorage/chrome.storage
111
+ */
112
+ serialize(): SerialState;
113
+ /**
114
+ * Debug dump of client internal state
115
+ * Returns free-form object for console.log or UI display
116
+ * Includes transient state (unlike serialize which is for persistence)
117
+ * Fetches live authState via async call
118
+ * @returns Promise resolving to object with internal state for debugging
119
+ */
120
+ debug(): Promise<Record<string, unknown>>;
121
+ }
122
+ /**
123
+ * IExtensionClient - Extension-specific client interface
124
+ *
125
+ * Extends IConnectionClient with sendExtRequest for direct extension communication.
126
+ *
127
+ * Implementations:
128
+ * - Ext2ExtClient: chrome.runtime.sendMessage (extension context)
129
+ * - Web2ExtClient: window.bodhiext (web page context)
130
+ *
131
+ * @template IParams - The init params type for this client
132
+ * @template SerialState - The serialized state type for persistence
133
+ */
134
+ export interface IExtensionClient<IParams = unknown, SerialState = unknown> extends IConnectionClient<IParams, SerialState> {
135
+ /**
136
+ * Send extension request
137
+ * Communicates with bodhi-browser-ext extension via:
138
+ * - chrome.runtime.sendMessage (extension context)
139
+ * - window.bodhiext (web context)
140
+ *
141
+ * @param action - Extension action (e.g., 'DISCOVER_EXTENSION', 'LOGIN')
142
+ * @param params - Action parameters
143
+ * @returns Response from extension
144
+ */
145
+ sendExtRequest<TParams = void, TRes = unknown>(action: string, params?: TParams): Promise<TRes>;
146
+ }
147
+ /**
148
+ * DirectClient - Direct HTTP client interface
149
+ *
150
+ * Extends IConnectionClient with no additional methods.
151
+ * Communicates directly with local server via HTTP fetch (no extension intermediary).
152
+ *
153
+ * @template IParams - The init params type for this client
154
+ * @template SerialState - The serialized state type for persistence
155
+ */
156
+ export interface IDirectClient<IParams = unknown, SerialState = unknown> extends IConnectionClient<IParams, SerialState> {
157
+ }
158
+ /**
159
+ * UIClient - Facade client with connection mode switching
160
+ *
161
+ * Combination of ConnectionClient + connection mode management.
162
+ * Internally holds both IExtensionClient and DirectClient, delegates to active client.
163
+ *
164
+ * Usage:
165
+ * ```
166
+ * const uiClient: UIClient = new UIClientImpl(extensionClient);
167
+ * await uiClient.init({ serverUrl: 'http://localhost:1135' }); // Init direct
168
+ * uiClient.setConnectionMode('extension'); // Switch to extension mode
169
+ * ```
170
+ */
171
+ export type UIClient = IConnectionClient<InitParams> & {
172
+ /**
173
+ * Set connection mode and switch active client
174
+ * @param mode - 'direct' or 'extension'
175
+ * @returns Promise with connection mode result
176
+ */
177
+ setConnectionMode(mode: ConnectionMode): Promise<ClientState>;
178
+ /**
179
+ * Get current connection mode
180
+ * @returns 'direct', 'extension', or null if not set
181
+ */
182
+ getConnectionMode(): ConnectionMode | null;
183
+ /**
184
+ * Test extension connectivity regardless of current connection mode
185
+ * Initializes extension client and tests backend server connection
186
+ * @param timeoutMs - Optional timeout for extension discovery
187
+ * @returns ExtensionState with extension status and server state
188
+ */
189
+ testExtensionConnectivity(timeoutMs?: number): Promise<ExtensionState>;
190
+ /**
191
+ * Test direct server connectivity
192
+ * Initializes direct client and tests backend server connection
193
+ * @param serverUrl - Optional server URL to test. If not provided, uses saved serverUrl from state
194
+ * @returns DirectState with server status and URL
195
+ */
196
+ testDirectConnectivity(serverUrl?: string): Promise<DirectState>;
197
+ /**
198
+ * Get current extension state (regardless of current connection mode)
199
+ * Returns extension status and backend server state
200
+ * @returns ExtensionState
201
+ */
202
+ getExtensionState(): Promise<ExtensionState>;
203
+ /**
204
+ * Get current direct server state (if configured)
205
+ * Returns direct server status and URL
206
+ * @returns DirectState
207
+ */
208
+ getDirectState(): Promise<DirectState>;
209
+ };
210
+ /**
211
+ * Web-specific UIClient interface with OAuth callback handling
212
+ * Defines the contract for web mode clients
213
+ */
214
+ export interface IWebUIClient extends UIClient {
215
+ /**
216
+ * Handle OAuth callback after redirect (web mode only)
217
+ * @param code - Authorization code from OAuth provider
218
+ * @param state - State parameter for CSRF protection
219
+ * @returns AuthLoggedIn with login state and user info
220
+ */
221
+ handleOAuthCallback(code: string, state: string): Promise<AuthLoggedIn>;
222
+ }
223
+ /**
224
+ * Type guard to check if client has OAuth callback handling (web mode)
225
+ * @param client - Client to check
226
+ * @returns true if client is IWebUIClient with handleOAuthCallback method
227
+ */
228
+ export declare function isWebUIClient(client: UIClient): client is IWebUIClient;
@@ -0,0 +1,13 @@
1
+ import { LogLevel } from './types/config';
2
+
3
+ export declare class Logger {
4
+ private prefix;
5
+ private level;
6
+ constructor(prefix: string, level?: LogLevel | 'silent');
7
+ private shouldLog;
8
+ private ts;
9
+ debug(...args: unknown[]): void;
10
+ info(...args: unknown[]): void;
11
+ warn(...args: unknown[]): void;
12
+ error(...args: unknown[]): void;
13
+ }
@@ -0,0 +1,45 @@
1
+ import { UserInfo } from './types';
2
+
3
+ /**
4
+ * Base64 URL encode a buffer (for PKCE)
5
+ */
6
+ export declare function base64UrlEncode(buffer: ArrayBuffer): string;
7
+ /**
8
+ * Generate a random code verifier for PKCE
9
+ */
10
+ export declare function generateCodeVerifier(): string;
11
+ /**
12
+ * Generate code challenge from verifier for PKCE
13
+ */
14
+ export declare function generateCodeChallenge(verifier: string): Promise<string>;
15
+ /**
16
+ * Parse JWT token and return payload
17
+ */
18
+ export declare function parseJwt(token: string): Record<string, unknown>;
19
+ /**
20
+ * Extract UserInfo from JWT token
21
+ */
22
+ export declare function extractUserInfo(token: string): UserInfo;
23
+ export interface OAuthEndpoints {
24
+ authorize: string;
25
+ token: string;
26
+ revoke: string;
27
+ }
28
+ /**
29
+ * Create OAuth endpoints from auth server URL
30
+ */
31
+ export declare function createOAuthEndpoints(authServerUrl: string): OAuthEndpoints;
32
+ export interface RefreshTokenResponse {
33
+ access_token: string;
34
+ refresh_token?: string;
35
+ id_token?: string;
36
+ expires_in: number;
37
+ }
38
+ /**
39
+ * Refresh access token using refresh token
40
+ * @param tokenEndpoint - OAuth token endpoint URL
41
+ * @param refreshToken - Current refresh token
42
+ * @param clientId - OAuth client ID
43
+ * @returns New tokens or null if refresh failed
44
+ */
45
+ export declare function refreshAccessToken(tokenEndpoint: string, refreshToken: string, clientId: string): Promise<RefreshTokenResponse | null>;
@@ -0,0 +1,10 @@
1
+ import { Browser, OS } from '../../../../setup-modal/src/types';
2
+
3
+ /**
4
+ * Browser configurations with extension store URLs
5
+ */
6
+ export declare const BROWSER_CONFIGS: Browser[];
7
+ /**
8
+ * Operating system configurations with download URLs
9
+ */
10
+ export declare const OS_CONFIGS: OS[];
@@ -0,0 +1,5 @@
1
+ /**
2
+ * Onboarding module - Framework-agnostic setup modal
3
+ */
4
+ export { OnboardingModal, type AsyncRequestHandler, type AsyncRequestHandlers, type ModalEvent, type ModalEventMap, type OnboardingModalConfig, } from './modal';
5
+ export { BROWSER_CONFIGS, OS_CONFIGS } from './config';
@@ -0,0 +1,80 @@
1
+ import { MessageType, RequestMessage, ResponsePayload } from '../../../../setup-modal/src/types';
2
+
3
+ import type * as ModalTypes from '@bodhiapp/setup-modal/types';
4
+ /**
5
+ * Async handler for modal requests
6
+ * Supports both sync and async responses
7
+ */
8
+ export type AsyncRequestHandler<K extends MessageType> = ((msg: RequestMessage<K>) => Promise<ResponsePayload<K>>) | ((msg: RequestMessage<K>) => ResponsePayload<K>);
9
+ /**
10
+ * Map of message types to async request handlers
11
+ */
12
+ export type AsyncRequestHandlers = {
13
+ [K in MessageType]?: AsyncRequestHandler<K>;
14
+ };
15
+ export type ModalEvent = 'complete' | 'close' | 'refresh' | 'lna_connect' | 'lna_skip' | 'confirm_server_install' | 'select_connection';
16
+ /**
17
+ * Event payload types for type-safe event handlers
18
+ */
19
+ export interface ModalEventMap {
20
+ complete: [];
21
+ close: [];
22
+ refresh: [];
23
+ lna_connect: [serverUrl: string];
24
+ lna_skip: [];
25
+ confirm_server_install: [];
26
+ select_connection: [connection: 'lna' | 'extension'];
27
+ }
28
+ /**
29
+ * Configuration options for OnboardingModal
30
+ */
31
+ export interface OnboardingModalConfig {
32
+ /**
33
+ * Path to modal HTML file relative to extension root
34
+ * Used with chrome.runtime.getURL() in extension context
35
+ * @default 'src/sdk/core/onboarding/modal.html'
36
+ */
37
+ modalHtmlPath?: string;
38
+ /**
39
+ * Message handlers for iframe requests
40
+ * Required - delegates all business logic to external handlers
41
+ */
42
+ handlers: AsyncRequestHandlers;
43
+ }
44
+ /**
45
+ * OnboardingModal manages the setup modal iframe
46
+ * Infrastructure layer only - delegates business logic to handlers
47
+ */
48
+ export declare class OnboardingModal {
49
+ private overlayElement;
50
+ private iframeElement;
51
+ private isIframeReady;
52
+ private currentSetupState;
53
+ private messageHandler;
54
+ private modalHtmlPath;
55
+ private handlers;
56
+ constructor(config: OnboardingModalConfig);
57
+ /**
58
+ * Show the modal with the given state
59
+ * State building is handled by SetupModalProcessor
60
+ */
61
+ show(state: ModalTypes.SetupState): void;
62
+ /**
63
+ * Update the modal state
64
+ * Used by SetupModalProcessor to push state updates to the modal
65
+ */
66
+ updateState(state: ModalTypes.SetupState): void;
67
+ /**
68
+ * Destroy the modal and clean up
69
+ */
70
+ destroy(): void;
71
+ /**
72
+ * Handle postMessage from iframe
73
+ * Pure routing - delegates to external handlers
74
+ */
75
+ private handleMessage;
76
+ /**
77
+ * Send current state to modal iframe using event message
78
+ */
79
+ private sendStateToModal;
80
+ }
@@ -0,0 +1,33 @@
1
+ import { MessageType, RequestPayload, ResponsePayload, RequestMessage, RequestId } from '../../../../setup-modal/src/types';
2
+
3
+ /** Build fire-and-forget event message */
4
+ export declare function buildEvent<T extends MessageType>(type: T, payload: RequestPayload<T>): {
5
+ kind: "event";
6
+ type: T;
7
+ payload: RequestPayload<T>;
8
+ };
9
+ /** Build response message with requestId correlation */
10
+ export declare function buildResponse<T extends MessageType>(requestId: RequestId, type: T, payload: ResponsePayload<T>): {
11
+ kind: "response";
12
+ type: T;
13
+ requestId: RequestId;
14
+ payload: ResponsePayload<T>;
15
+ };
16
+ /** Build error message */
17
+ export declare function buildError(requestId: RequestId, error: {
18
+ code: string;
19
+ message: string;
20
+ details?: unknown;
21
+ }): {
22
+ kind: "error";
23
+ requestId: RequestId;
24
+ error: {
25
+ code: string;
26
+ message: string;
27
+ details?: unknown;
28
+ };
29
+ };
30
+ /** Type-safe request handler - processes incoming requests and returns response */
31
+ export declare function handleRequest<T extends MessageType>(message: RequestMessage<T>, handlers: Partial<{
32
+ [K in MessageType]: (payload: RequestPayload<K>) => ResponsePayload<K>;
33
+ }>): ReturnType<typeof buildResponse> | null;
@@ -0,0 +1,11 @@
1
+ import { BrowserInfo, OSInfo } from './types';
2
+
3
+ /**
4
+ * Detects the current browser using UAParser.js
5
+ */
6
+ export declare function detectBrowser(): BrowserInfo;
7
+ /**
8
+ * Detects the current operating system using UAParser.js
9
+ * Maps all OS variants to simplified supported types
10
+ */
11
+ export declare function detectOS(): OSInfo;
@@ -0,0 +1,81 @@
1
+ /**
2
+ * Namespaced storage key generator
3
+ *
4
+ * Creates consistent storage keys with prefixes to avoid conflicts between
5
+ * different connection modes and other applications.
6
+ */
7
+ export interface StorageKeys {
8
+ ACCESS_TOKEN: string;
9
+ REFRESH_TOKEN: string;
10
+ EXPIRES_AT: string;
11
+ CODE_VERIFIER: string;
12
+ STATE: string;
13
+ RESOURCE_SCOPE: string;
14
+ }
15
+ /**
16
+ * Create namespaced storage keys with a given prefix
17
+ *
18
+ * @param prefix - Namespace prefix (e.g., 'bodhi:direct', 'bodhi:web')
19
+ * @returns Storage keys object with namespaced keys
20
+ */
21
+ export declare function createStorageKeys(prefix: string): StorageKeys;
22
+ /**
23
+ * Standard prefixes for different connection modes
24
+ */
25
+ export declare const STORAGE_PREFIXES: {
26
+ readonly DIRECT: "bodhi:direct";
27
+ readonly WEB: "bodhi:web";
28
+ readonly EXT: "bodhi:ext";
29
+ };
30
+ /**
31
+ * User Preferences Storage Manager
32
+ *
33
+ * Manages localStorage for user preferences including connection mode,
34
+ * server URL, and other client configuration.
35
+ *
36
+ * Storage keys use configurable prefix to namespace all app storage.
37
+ * Defaults to 'bodhijs:' for SDK usage.
38
+ */
39
+ /**
40
+ * Manager for reading/writing user preferences to localStorage
41
+ */
42
+ export declare class BodhiClientUserPrefsManager {
43
+ private readonly storagePrefix;
44
+ private readonly STORAGE_KEYS;
45
+ private readonly SERVER_INSTALL_KEY;
46
+ /**
47
+ * @param storagePrefix - Prefix for localStorage keys (default: 'bodhijs:')
48
+ */
49
+ constructor(storagePrefix?: string);
50
+ /**
51
+ * Get direct connection status (LNA permission state)
52
+ */
53
+ getDirectStatus(): 'granted' | 'skipped' | 'denied' | null;
54
+ /**
55
+ * Set direct connection status (LNA permission state)
56
+ */
57
+ setDirectStatus(status: 'granted' | 'skipped' | 'denied' | null): void;
58
+ /**
59
+ * Clear all preferences
60
+ */
61
+ clear(): void;
62
+ /**
63
+ * Check if server install was confirmed
64
+ * (Separate from connection prefs - stored at server:installed key)
65
+ */
66
+ isServerInstallConfirmed(): boolean;
67
+ /**
68
+ * Set server install confirmation
69
+ */
70
+ setServerInstallConfirmed(confirmed: boolean): void;
71
+ /**
72
+ * Get serialized client state
73
+ */
74
+ getSerializedClientState<T>(): T | null;
75
+ /**
76
+ * Set serialized client state
77
+ */
78
+ setSerializedClientState<T>(state: T): void;
79
+ private getStorageValue;
80
+ private setStorageValue;
81
+ }