@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.
- package/README.md +26 -0
- package/dist/bodhi-browser-ext/src/types/bodhiext.d.ts +202 -0
- package/dist/bodhi-browser-ext/src/types/common.d.ts +36 -0
- package/dist/bodhi-browser-ext/src/types/index.d.ts +6 -0
- package/dist/bodhi-browser-ext/src/types/protocol.d.ts +223 -0
- package/dist/bodhi-js-sdk/core/src/direct-client-base.d.ts +129 -0
- package/dist/bodhi-js-sdk/core/src/errors.d.ts +23 -0
- package/dist/bodhi-js-sdk/core/src/facade-client-base.d.ts +130 -0
- package/dist/bodhi-js-sdk/core/src/index.d.ts +19 -0
- package/dist/bodhi-js-sdk/core/src/interface.d.ts +228 -0
- package/dist/bodhi-js-sdk/core/src/logger.d.ts +13 -0
- package/dist/bodhi-js-sdk/core/src/oauth.d.ts +45 -0
- package/dist/bodhi-js-sdk/core/src/onboarding/config.d.ts +10 -0
- package/dist/bodhi-js-sdk/core/src/onboarding/index.d.ts +5 -0
- package/dist/bodhi-js-sdk/core/src/onboarding/modal.d.ts +80 -0
- package/dist/bodhi-js-sdk/core/src/onboarding/protocol-utils.d.ts +33 -0
- package/dist/bodhi-js-sdk/core/src/platform.d.ts +11 -0
- package/dist/bodhi-js-sdk/core/src/storage.d.ts +81 -0
- package/dist/bodhi-js-sdk/core/src/types/api.d.ts +34 -0
- package/dist/bodhi-js-sdk/core/src/types/callback.d.ts +23 -0
- package/dist/bodhi-js-sdk/core/src/types/client-state.d.ts +191 -0
- package/dist/bodhi-js-sdk/core/src/types/config.d.ts +26 -0
- package/dist/bodhi-js-sdk/core/src/types/html.d.ts +9 -0
- package/dist/bodhi-js-sdk/core/src/types/index.d.ts +15 -0
- package/dist/bodhi-js-sdk/core/src/types/platform.d.ts +16 -0
- package/dist/bodhi-js-sdk/core/src/types/user-info.d.ts +59 -0
- package/dist/bodhi-js-sdk/web/src/constants.d.ts +9 -0
- package/dist/bodhi-js-sdk/web/src/direct-client.d.ts +24 -0
- package/dist/bodhi-js-sdk/web/src/ext-client.d.ts +151 -0
- package/dist/bodhi-js-sdk/web/src/facade-client.d.ts +43 -0
- package/dist/bodhi-js-sdk/web/src/index.d.ts +5 -0
- package/dist/bodhi-js-sdk/web/src/interface.d.ts +4 -0
- package/dist/bodhi-web.cjs.js +749 -0
- package/dist/bodhi-web.cjs.js.map +1 -0
- package/dist/bodhi-web.esm.d.ts +1 -0
- package/dist/bodhi-web.esm.js +749 -0
- package/dist/bodhi-web.esm.js.map +1 -0
- package/dist/setup-modal/src/types/extension.d.ts +24 -0
- package/dist/setup-modal/src/types/index.d.ts +20 -0
- package/dist/setup-modal/src/types/lna.d.ts +56 -0
- package/dist/setup-modal/src/types/message-types.d.ts +169 -0
- package/dist/setup-modal/src/types/platform.d.ts +32 -0
- package/dist/setup-modal/src/types/protocol.d.ts +71 -0
- package/dist/setup-modal/src/types/server.d.ts +63 -0
- package/dist/setup-modal/src/types/state.d.ts +43 -0
- package/dist/setup-modal/src/types/type-guards.d.ts +27 -0
- package/package.json +54 -0
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"bodhi-web.esm.js","sources":["../src/direct-client.ts","../src/constants.ts","../src/ext-client.ts","../src/facade-client.ts"],"sourcesContent":["/**\n * DirectWebClient - Direct HTTP client for web mode\n *\n * Uses browser redirect OAuth flow with localStorage for token storage.\n */\n\nimport {\n DirectClientBase,\n STORAGE_PREFIXES,\n generateCodeChallenge,\n generateCodeVerifier,\n isApiResultOperationError,\n isApiResultSuccess,\n type AuthLoggedIn,\n type AuthLoggedOut,\n type DirectClientBaseConfig,\n type StateChangeCallback,\n} from '@bodhiapp/bodhi-js-core';\n\n/**\n * Configuration for DirectWebClient\n */\nexport interface DirectWebClientConfig extends DirectClientBaseConfig {\n redirectUri: string;\n}\n\n/**\n * DirectWebClient - Web mode implementation using browser redirect OAuth\n */\nexport class DirectWebClient extends DirectClientBase {\n private redirectUri: string;\n\n constructor(config: DirectWebClientConfig, onStateChange?: StateChangeCallback) {\n super({ ...config, storagePrefix: STORAGE_PREFIXES.DIRECT }, 'DirectWebClient', onStateChange);\n this.redirectUri = config.redirectUri;\n }\n\n // ============================================================================\n // Authentication (Browser Redirect OAuth)\n // ============================================================================\n\n async login(): Promise<AuthLoggedIn> {\n const existingAuth = await this.getAuthState();\n if (existingAuth.isLoggedIn) {\n return existingAuth;\n }\n\n const resourceScope = await this.requestResourceAccess();\n const fullScope = `openid profile email roles ${this.userScope} ${resourceScope}`;\n\n const codeVerifier = generateCodeVerifier();\n const codeChallenge = await generateCodeChallenge(codeVerifier);\n const state = generateCodeVerifier();\n\n localStorage.setItem(this.storageKeys.CODE_VERIFIER, codeVerifier);\n localStorage.setItem(this.storageKeys.STATE, state);\n\n const authUrl = new URL(this.authEndpoints.authorize);\n authUrl.searchParams.set('client_id', this.authClientId);\n authUrl.searchParams.set('response_type', 'code');\n authUrl.searchParams.set('redirect_uri', this.redirectUri);\n authUrl.searchParams.set('scope', fullScope);\n authUrl.searchParams.set('code_challenge', codeChallenge);\n authUrl.searchParams.set('code_challenge_method', 'S256');\n authUrl.searchParams.set('state', state);\n\n window.location.href = authUrl.toString();\n // Note: This line is never reached due to redirect, but TypeScript requires a return\n throw new Error('Redirect initiated');\n }\n\n async handleOAuthCallback(code: string, state: string): Promise<AuthLoggedIn> {\n const storedState = localStorage.getItem(this.storageKeys.STATE);\n if (!storedState || storedState !== state) {\n throw new Error('Invalid state parameter - possible CSRF attack');\n }\n\n await this.exchangeCodeForTokens(code);\n\n localStorage.removeItem(this.storageKeys.CODE_VERIFIER);\n localStorage.removeItem(this.storageKeys.STATE);\n\n const authState = await this.getAuthState();\n\n if (!authState.isLoggedIn) {\n throw new Error('Login failed');\n }\n\n const result: AuthLoggedIn = authState;\n\n this.setAuthState(result);\n return result;\n }\n\n async logout(): Promise<AuthLoggedOut> {\n const refreshToken = localStorage.getItem(this.storageKeys.REFRESH_TOKEN);\n\n if (refreshToken) {\n try {\n const params = new URLSearchParams({\n token: refreshToken,\n client_id: this.authClientId,\n token_type_hint: 'refresh_token',\n });\n\n await fetch(this.authEndpoints.revoke, {\n method: 'POST',\n headers: {\n 'Content-Type': 'application/x-www-form-urlencoded',\n },\n body: params,\n });\n } catch (error) {\n this.logger.warn('Token revocation failed:', error);\n }\n }\n\n localStorage.removeItem(this.storageKeys.ACCESS_TOKEN);\n localStorage.removeItem(this.storageKeys.REFRESH_TOKEN);\n localStorage.removeItem(this.storageKeys.EXPIRES_AT);\n localStorage.removeItem(this.storageKeys.RESOURCE_SCOPE);\n\n const result = {\n isLoggedIn: false as const,\n };\n\n this.setAuthState(result);\n return result;\n }\n\n // ============================================================================\n // OAuth Helper Methods\n // ============================================================================\n\n protected async requestResourceAccess(): Promise<string> {\n const response = await this.sendApiRequest<{ app_client_id: string }, { scope: string }>(\n 'POST',\n '/bodhi/v1/apps/request-access',\n { app_client_id: this.authClientId },\n {},\n false\n );\n\n if (isApiResultOperationError(response)) {\n throw new Error('Failed to get resource access scope from server');\n }\n\n if (!isApiResultSuccess(response)) {\n throw new Error('Failed to get resource access scope from server: API error');\n }\n\n const scope = response.body.scope;\n localStorage.setItem(this.storageKeys.RESOURCE_SCOPE, scope);\n return scope;\n }\n\n protected async exchangeCodeForTokens(code: string): Promise<void> {\n const codeVerifier = localStorage.getItem(this.storageKeys.CODE_VERIFIER);\n if (!codeVerifier) {\n throw new Error('Code verifier not found');\n }\n\n const response = await fetch(this.authEndpoints.token, {\n method: 'POST',\n headers: {\n 'Content-Type': 'application/x-www-form-urlencoded',\n },\n body: new URLSearchParams({\n grant_type: 'authorization_code',\n code,\n redirect_uri: this.redirectUri,\n client_id: this.authClientId,\n code_verifier: codeVerifier,\n }),\n });\n\n if (!response.ok) {\n const errorText = await response.text();\n throw new Error(`Token exchange failed: ${response.status} ${errorText}`);\n }\n\n const tokens = await response.json();\n\n localStorage.setItem(this.storageKeys.ACCESS_TOKEN, tokens.access_token);\n if (tokens.refresh_token) {\n localStorage.setItem(this.storageKeys.REFRESH_TOKEN, tokens.refresh_token);\n }\n\n if (tokens.expires_in) {\n const expiresAt = Date.now() + tokens.expires_in * 1000;\n localStorage.setItem(this.storageKeys.EXPIRES_AT, expiresAt.toString());\n }\n }\n\n // ============================================================================\n // Storage Implementation (localStorage)\n // ============================================================================\n\n protected async _storageGet(key: string): Promise<string | null> {\n return localStorage.getItem(key);\n }\n\n protected async _storageSet(items: Record<string, string | number>): Promise<void> {\n Object.entries(items).forEach(([key, value]) => {\n localStorage.setItem(key, String(value));\n });\n }\n\n protected async _storageRemove(keys: string[]): Promise<void> {\n keys.forEach((key) => localStorage.removeItem(key));\n }\n\n protected _getRedirectUri(): string {\n return this.redirectUri;\n }\n}\n","/**\n * Constants for web2ext communication\n */\n\nimport { STORAGE_PREFIXES, createStorageKeys } from '@bodhiapp/bodhi-js-core';\n\nexport const POLL_INTERVAL = 500; // Poll every 100ms\nexport const POLL_TIMEOUT = 5000; // 5s timeout\n\n/**\n * LocalStorage keys for OAuth tokens and PKCE flow (namespaced with 'bodhi:web' prefix)\n */\nexport const STORAGE_KEYS = createStorageKeys(STORAGE_PREFIXES.WEB);\n","import {\n BACKEND_SERVER_NOT_REACHABLE,\n EXTENSION_STATE_NOT_FOUND,\n EXTENSION_STATE_NOT_INITIALIZED,\n Logger,\n NOOP_STATE_CALLBACK,\n PENDING_EXTENSION_READY,\n SERVER_ERROR_CODES,\n backendServerNotReady,\n createApiError,\n createOAuthEndpoints,\n createOperationError,\n extractUserInfo,\n generateCodeChallenge,\n generateCodeVerifier,\n isApiResultOperationError,\n isApiResultSuccess,\n refreshAccessToken,\n type ApiResponseResult,\n type AuthLoggedIn,\n type AuthLoggedOut,\n type AuthState,\n type BackendServerState,\n type ClientState,\n type ExtensionState,\n type IExtensionClient,\n type InitParams,\n type OAuthEndpoints,\n type RefreshTokenResponse,\n type ServerInfoResponse,\n type StateChangeCallback,\n} from '@bodhiapp/bodhi-js-core';\nimport { type BodhiExtPublicApi, type StreamChunk } from '@bodhiapp/bodhi-browser/types';\nimport type { CreateChatCompletionStreamResponse, OpenAiApiError } from '@bodhiapp/ts-client';\nimport { POLL_INTERVAL, POLL_TIMEOUT, STORAGE_KEYS } from './constants';\nimport { WebClientConfig } from './facade-client';\n\n// Empty object type for future-proofing\nexport type SerializedWebExtensionState = { extensionId?: string };\n\n/**\n * WindowBodhiextClient - web mode extension client using window.bodhiext\n *\n * Communicates with bodhi-browser-ext via window.bodhiext API\n *\n * Implements IExtensionClient interface with state callback for state changes\n * Additionally provides handleOAuthCallback for web-specific OAuth flow\n *\n */\nexport class WindowBodhiextClient implements IExtensionClient {\n private state: ExtensionState = EXTENSION_STATE_NOT_INITIALIZED;\n private logger: Logger;\n private bodhiext: BodhiExtPublicApi | null = null;\n private authClientId: string;\n private config: WebClientConfig;\n private authEndpoints: OAuthEndpoints;\n private onStateChange: StateChangeCallback;\n private refreshPromise: Promise<string | null> | null = null;\n\n constructor(authClientId: string, config: WebClientConfig, onStateChange?: StateChangeCallback) {\n this.logger = new Logger('WindowBodhiextClient', config.logLevel);\n this.authClientId = authClientId;\n this.config = config;\n this.authEndpoints = createOAuthEndpoints(this.config.authServerUrl);\n this.onStateChange = onStateChange ?? NOOP_STATE_CALLBACK;\n }\n\n /**\n * Set client state and notify callback\n */\n private setState(newState: ExtensionState): void {\n this.state = newState;\n this.logger.info(`{state: ${JSON.stringify(newState)}} - Setting client state`);\n this.onStateChange({ type: 'client-state', state: newState });\n }\n\n /**\n * Set auth state and notify callback\n */\n private setAuthState(authState: AuthState): void {\n this.onStateChange({ type: 'auth-state', state: authState });\n }\n\n /**\n * Set or update the state change callback\n */\n setStateCallback(callback: StateChangeCallback): void {\n this.onStateChange = callback;\n }\n\n // ============================================================================\n // Extension Communication\n // ============================================================================\n\n /**\n * Ensure bodhiext is available, attempting to acquire it if not already set\n * @throws Error if client not initialized\n */\n private ensureBodhiext(): void {\n if (!this.bodhiext && window.bodhiext) {\n this.logger.info('Acquiring window.bodhiext reference');\n this.bodhiext = window.bodhiext;\n }\n if (!this.bodhiext) {\n throw new Error('Client not initialized');\n }\n }\n\n /**\n * Send extension request via window.bodhiext.sendExtRequest\n */\n\n async sendExtRequest<TParams = void, TRes = unknown>(\n action: string,\n params?: TParams\n ): Promise<TRes> {\n this.ensureBodhiext();\n return this.bodhiext!.sendExtRequest(action, params) as Promise<TRes>;\n }\n\n /**\n * Send API message via window.bodhiext.sendApiRequest\n * Converts ApiResponse to ApiResponseResult\n */\n async sendApiRequest<TReq = void, TRes = unknown>(\n method: string,\n endpoint: string,\n body?: TReq,\n headers?: Record<string, string>,\n authenticated?: boolean\n ): Promise<ApiResponseResult<TRes>> {\n try {\n this.ensureBodhiext();\n } catch (err) {\n return {\n error: {\n message: err instanceof Error ? err.message : String(err),\n type: 'extension_error',\n },\n };\n }\n try {\n let requestHeaders = headers || {};\n\n // Token injection for authenticated requests\n if (authenticated) {\n const accessToken = await this._getAccessTokenRaw();\n if (!accessToken) {\n return {\n error: {\n message: 'Not authenticated. Please log in first.',\n type: 'extension_error',\n },\n };\n }\n requestHeaders = {\n ...requestHeaders,\n Authorization: `Bearer ${accessToken}`,\n };\n }\n\n const response = await this.bodhiext!.sendApiRequest<unknown, TRes>(\n method,\n endpoint,\n body,\n requestHeaders\n );\n return response;\n } catch (e) {\n const errorObj = (e as { error?: { message?: string; type?: string } })?.error;\n const message = errorObj?.message ?? (e instanceof Error ? e.message : String(e));\n const errorType = errorObj?.type || 'extension_error';\n return {\n error: {\n message,\n type: errorType,\n },\n };\n }\n }\n\n /**\n * Get current client state\n */\n getState(): ClientState {\n return this.state;\n }\n\n isClientInitialized(): boolean {\n return this.state.extension === 'ready';\n }\n\n isServerReady(): boolean {\n return this.isClientInitialized() && this.state.server.status === 'ready';\n }\n\n /**\n * Initialize extension discovery with optional timeout\n * Returns ExtensionState with extension and server status\n *\n * Note: Web mode uses stateless discovery (always polls for window.bodhiext)\n * No extensionId storage/restoration needed - window.bodhiext handle is ephemeral\n */\n async init(params: InitParams = {}): Promise<ExtensionState> {\n // testConnection: false, selectedConnection: false → not-initialized\n if (!params.testConnection && !params.selectedConnection) {\n this.logger.info('No testConnection or selectedConnection, returning not-initialized state');\n return EXTENSION_STATE_NOT_INITIALIZED;\n }\n\n // IDEMPOTENCY: If already have handle and not testing, skip polling\n if (this.bodhiext && !params.testConnection) {\n this.logger.debug('Already have bodhiext handle, skipping polling');\n return this.state;\n }\n\n // Only poll if don't have handle yet\n if (!this.bodhiext) {\n // Priority: params > constructor defaults > constants\n const timeoutMs =\n params.timeoutMs ?? this.config.initParams?.extension?.timeoutMs ?? POLL_TIMEOUT;\n const intervalMs =\n params.intervalMs ?? this.config.initParams?.extension?.intervalMs ?? POLL_INTERVAL;\n const startTime = Date.now();\n\n // Poll for window.bodhiext\n const found = await new Promise<boolean>((resolve) => {\n const check = () => {\n if (window.bodhiext) {\n this.bodhiext = window.bodhiext;\n resolve(true);\n return;\n }\n if (Date.now() - startTime >= timeoutMs) {\n resolve(false);\n return;\n }\n setTimeout(check, intervalMs);\n };\n check();\n });\n\n if (!found) {\n this.logger.warn(`Extension discovery timed out`);\n this.setState(EXTENSION_STATE_NOT_FOUND);\n return this.state;\n }\n }\n\n // Have handle - build state\n const extensionId = await this.bodhiext!.getExtensionId();\n this.logger.info(`Extension discovered: ${extensionId}`);\n\n const state: ExtensionState = {\n type: 'extension',\n extension: 'ready',\n extensionId,\n server: PENDING_EXTENSION_READY,\n };\n\n // Test server connectivity if requested\n if (params.testConnection) {\n try {\n const serverState = await this.getServerState();\n this.setState({ ...state, server: serverState });\n this.logger.info(`Server connectivity tested: ${serverState.status}`);\n } catch (error) {\n this.logger.error(`Failed to get server state:`, error);\n this.setState({ ...state, server: BACKEND_SERVER_NOT_REACHABLE });\n }\n } else {\n this.setState(state);\n }\n\n return this.state;\n }\n\n // ============================================================================\n // OAuth Methods\n // ============================================================================\n\n /**\n * Request resource access scope from backend\n * Required for authenticated API access\n */\n private async requestResourceAccess(): Promise<string> {\n this.ensureBodhiext();\n\n const response = await this.bodhiext!.sendApiRequest<\n { app_client_id: string },\n { scope: string }\n >('POST', '/bodhi/v1/apps/request-access', {\n app_client_id: this.authClientId,\n });\n\n if (!isApiResultSuccess(response)) {\n throw new Error('Failed to get resource access scope: API error');\n }\n\n const scope = response.body.scope;\n localStorage.setItem(STORAGE_KEYS.RESOURCE_SCOPE, scope);\n return scope;\n }\n\n /**\n * Login via browser redirect OAuth2 + PKCE flow\n * @returns AuthLoggedIn (though in practice, this redirects and never returns)\n */\n async login(): Promise<AuthLoggedIn> {\n // Check if already logged in\n const existingAuth = await this.getAuthState();\n if (existingAuth.isLoggedIn) {\n return existingAuth;\n }\n\n // Ensure extension discovered\n this.ensureBodhiext();\n\n // Request resource access scope\n const resourceScope = await this.requestResourceAccess();\n\n // Generate PKCE verifier and challenge\n const codeVerifier = generateCodeVerifier();\n const codeChallenge = await generateCodeChallenge(codeVerifier);\n\n // Generate state for CSRF protection\n const state = generateCodeVerifier();\n\n // Store verifier and state for callback\n localStorage.setItem(STORAGE_KEYS.CODE_VERIFIER, codeVerifier);\n localStorage.setItem(STORAGE_KEYS.STATE, state);\n\n // Build OAuth authorization URL\n const scopes = ['openid', 'profile', 'email', 'roles', this.config.userScope, resourceScope];\n\n const params = new URLSearchParams({\n response_type: 'code',\n client_id: this.authClientId,\n redirect_uri: this.config.redirectUri,\n scope: scopes.join(' '),\n state: state,\n code_challenge: codeChallenge,\n code_challenge_method: 'S256',\n });\n\n const authUrl = `${this.authEndpoints.authorize}?${params}`;\n\n // Redirect to authorization server\n window.location.href = authUrl;\n\n // TypeScript requires a return statement, but this code never executes\n // because the browser redirects above\n return new Promise(() => {});\n }\n\n /**\n * Handle OAuth callback with authorization code\n * Should be called from callback page with extracted URL params\n * @returns AuthLoggedIn with login state and user info\n */\n async handleOAuthCallback(code: string, state: string): Promise<AuthLoggedIn> {\n // Validate state to prevent CSRF\n const storedState = localStorage.getItem(STORAGE_KEYS.STATE);\n if (!storedState || storedState !== state) {\n throw new Error('Invalid state parameter - possible CSRF attack');\n }\n\n // Exchange code for tokens\n await this.exchangeCodeForTokens(code);\n\n // Clean up temporary storage\n localStorage.removeItem(STORAGE_KEYS.CODE_VERIFIER);\n localStorage.removeItem(STORAGE_KEYS.STATE);\n\n const authState = await this.getAuthState();\n\n if (!authState.isLoggedIn) {\n throw new Error('Login failed');\n }\n\n this.setAuthState(authState);\n return authState;\n }\n\n /**\n * Exchange authorization code for tokens\n */\n private async exchangeCodeForTokens(code: string): Promise<void> {\n const codeVerifier = localStorage.getItem(STORAGE_KEYS.CODE_VERIFIER);\n if (!codeVerifier) {\n throw new Error('Code verifier not found');\n }\n\n const params = new URLSearchParams({\n grant_type: 'authorization_code',\n client_id: this.authClientId,\n code: code,\n redirect_uri: this.config.redirectUri,\n code_verifier: codeVerifier,\n });\n\n const response = await fetch(this.authEndpoints.token, {\n method: 'POST',\n headers: {\n 'Content-Type': 'application/x-www-form-urlencoded',\n },\n body: params,\n });\n\n if (!response.ok) {\n const errorText = await response.text();\n throw new Error(`Token exchange failed: ${response.status} ${errorText}`);\n }\n\n const tokenData = await response.json();\n\n if (!tokenData.access_token) {\n throw new Error('No access token received');\n }\n\n // Store tokens in localStorage\n localStorage.setItem(STORAGE_KEYS.ACCESS_TOKEN, tokenData.access_token);\n if (tokenData.refresh_token) {\n localStorage.setItem(STORAGE_KEYS.REFRESH_TOKEN, tokenData.refresh_token);\n }\n\n // Calculate and store expiration time\n if (tokenData.expires_in) {\n const expiresAt = Date.now() + tokenData.expires_in * 1000;\n localStorage.setItem(STORAGE_KEYS.EXPIRES_AT, expiresAt.toString());\n }\n }\n\n /**\n * Logout user and revoke tokens\n * @returns AuthLoggedOut with logged out state\n */\n async logout(): Promise<AuthLoggedOut> {\n const refreshToken = localStorage.getItem(STORAGE_KEYS.REFRESH_TOKEN);\n\n // Attempt to revoke token at auth server\n if (refreshToken) {\n try {\n const params = new URLSearchParams({\n token: refreshToken,\n client_id: this.authClientId,\n token_type_hint: 'refresh_token',\n });\n\n await fetch(this.authEndpoints.revoke, {\n method: 'POST',\n headers: {\n 'Content-Type': 'application/x-www-form-urlencoded',\n },\n body: params,\n });\n } catch (error) {\n this.logger.warn('Token revocation failed:', error);\n }\n }\n\n // Clear all OAuth-related localStorage keys\n localStorage.removeItem(STORAGE_KEYS.ACCESS_TOKEN);\n localStorage.removeItem(STORAGE_KEYS.REFRESH_TOKEN);\n localStorage.removeItem(STORAGE_KEYS.EXPIRES_AT);\n localStorage.removeItem(STORAGE_KEYS.CODE_VERIFIER);\n localStorage.removeItem(STORAGE_KEYS.STATE);\n localStorage.removeItem(STORAGE_KEYS.RESOURCE_SCOPE);\n\n const result = {\n isLoggedIn: false as const,\n };\n\n this.setAuthState(result);\n return result;\n }\n\n /**\n * Get current authentication state\n */\n async getAuthState(): Promise<AuthState> {\n const accessToken = await this._getAccessTokenRaw();\n\n if (!accessToken) {\n return { isLoggedIn: false };\n }\n\n try {\n const userInfo = extractUserInfo(accessToken);\n return { isLoggedIn: true, userInfo, accessToken };\n } catch (error) {\n this.logger.error('Failed to parse token:', error);\n return { isLoggedIn: false };\n }\n }\n\n /**\n * Get current access token\n * Returns null if not logged in or token expired\n */\n protected async _getAccessTokenRaw(): Promise<string | null> {\n const accessToken = localStorage.getItem(STORAGE_KEYS.ACCESS_TOKEN);\n const expiresAt = localStorage.getItem(STORAGE_KEYS.EXPIRES_AT);\n\n if (!accessToken) {\n return null;\n }\n\n // Check if token is expired\n if (expiresAt) {\n const expirationTime = parseInt(expiresAt, 10);\n if (Date.now() >= expirationTime - 5 * 1000) {\n // Token expired - try to refresh\n const refreshToken = localStorage.getItem(STORAGE_KEYS.REFRESH_TOKEN);\n if (refreshToken) {\n return this._tryRefreshToken(refreshToken);\n }\n return null;\n }\n }\n\n return accessToken;\n }\n\n /**\n * Try to refresh access token using refresh token\n * Race condition prevention: Returns existing promise if refresh already in progress\n */\n private async _tryRefreshToken(refreshToken: string): Promise<string | null> {\n // If already refreshing, return the existing promise (avoids duplicate requests)\n if (this.refreshPromise) {\n this.logger.debug('Refresh already in progress, returning existing promise');\n return this.refreshPromise;\n }\n\n // Start refresh and store promise\n this.refreshPromise = this._doRefreshToken(refreshToken);\n\n try {\n return await this.refreshPromise;\n } finally {\n this.refreshPromise = null;\n }\n }\n\n /**\n * Perform the actual token refresh\n */\n private async _doRefreshToken(refreshToken: string): Promise<string | null> {\n this.logger.debug('Refreshing access token');\n\n try {\n const tokens = await refreshAccessToken(\n this.authEndpoints.token,\n refreshToken,\n this.authClientId\n );\n\n if (tokens) {\n this._storeRefreshedTokens(tokens);\n const userInfo = extractUserInfo(tokens.access_token);\n this.setAuthState({\n isLoggedIn: true,\n userInfo,\n accessToken: tokens.access_token,\n });\n this.logger.info('Token refreshed successfully');\n return tokens.access_token;\n }\n } catch (error) {\n this.logger.warn('Token refresh failed:', error);\n }\n\n // Refresh failed - throw error (don't clear tokens, may be temp issue)\n this.logger.warn('Token refresh failed, keeping tokens for manual retry');\n throw createOperationError(\n 'Access token expired and unable to refresh. Try logging out and logging in again.',\n 'token_refresh_failed'\n );\n }\n\n /**\n * Store refreshed tokens\n */\n private _storeRefreshedTokens(tokens: RefreshTokenResponse): void {\n const expiresAt = Date.now() + tokens.expires_in * 1000;\n\n localStorage.setItem(STORAGE_KEYS.ACCESS_TOKEN, tokens.access_token);\n localStorage.setItem(STORAGE_KEYS.EXPIRES_AT, String(expiresAt));\n\n // Update refresh token if provided (Keycloak token rotation)\n if (tokens.refresh_token) {\n localStorage.setItem(STORAGE_KEYS.REFRESH_TOKEN, tokens.refresh_token);\n }\n }\n\n /**\n * Ping API\n */\n async pingApi(): Promise<ApiResponseResult<{ message: string }>> {\n return this.sendApiRequest<void, { message: string }>('GET', '/ping');\n }\n\n /**\n * Fetch models\n */\n async fetchModels(): Promise<ApiResponseResult<{ data: Array<{ id: string; object: string }> }>> {\n return this.sendApiRequest<void, { data: Array<{ id: string; object: string }> }>(\n 'GET',\n '/v1/models',\n undefined,\n undefined,\n true\n );\n }\n\n /**\n * Get backend server state\n * Calls /bodhi/v1/info and returns structured server state\n */\n async getServerState(): Promise<BackendServerState> {\n const result = await this.sendApiRequest<void, ServerInfoResponse>('GET', '/bodhi/v1/info');\n\n if (isApiResultOperationError(result)) {\n return BACKEND_SERVER_NOT_REACHABLE;\n }\n\n if (!isApiResultSuccess(result)) {\n return BACKEND_SERVER_NOT_REACHABLE;\n }\n\n const body = result.body;\n\n switch (body.status) {\n case 'ready':\n return { status: 'ready', version: body.version || 'unknown' };\n case 'setup':\n return backendServerNotReady('setup', body.version || 'unknown');\n case 'resource-admin':\n return backendServerNotReady('resource-admin', body.version || 'unknown');\n case 'error':\n return backendServerNotReady(\n 'error',\n body.version || 'unknown',\n body.error\n ? { message: body.error.message, type: body.error.type }\n : SERVER_ERROR_CODES.SERVER_NOT_READY\n );\n default:\n return BACKEND_SERVER_NOT_REACHABLE;\n }\n }\n\n /**\n * Generic streaming via window.bodhiext.sendStreamRequest\n * Wraps ReadableStream as AsyncGenerator\n */\n async *stream<TReq = unknown, TRes = unknown>(\n method: string,\n endpoint: string,\n body?: TReq,\n headers?: Record<string, string>,\n authenticated: boolean = true\n ): AsyncGenerator<TRes> {\n this.ensureBodhiext();\n let requestHeaders = headers || {};\n // Token injection for authenticated requests\n if (authenticated) {\n const accessToken = await this._getAccessTokenRaw();\n if (!accessToken) {\n throw new Error('Not authenticated. Please log in first.');\n }\n requestHeaders = {\n ...requestHeaders,\n Authorization: `Bearer ${accessToken}`,\n };\n }\n\n const stream = this.bodhiext!.sendStreamRequest<TReq>(method, endpoint, body, requestHeaders);\n const reader = stream.getReader();\n\n try {\n while (true) {\n const { value, done } = await reader.read();\n if (done || (value as StreamChunk)?.done) {\n break;\n }\n yield (value as StreamChunk).body as TRes;\n }\n } catch (err) {\n // Convert discriminated error types to ConnectionError/ApiError\n if (err instanceof Error) {\n // Check for 'response' field = API error\n if ('response' in err) {\n const apiErr = err as Error & { response: { status: number; body: OpenAiApiError } };\n throw createApiError(err.message, apiErr.response.status, apiErr.response.body);\n }\n // Check for 'error' field = network/extension error\n if ('error' in err) {\n throw createOperationError(err.message, 'extension_error');\n }\n // Fallback for other errors\n throw createOperationError(err.message, 'extension_error');\n }\n throw err;\n } finally {\n reader.releaseLock();\n }\n }\n\n /**\n * Chat streaming\n */\n async *streamChat(\n model: string,\n prompt: string,\n authenticated: boolean = true\n ): AsyncGenerator<CreateChatCompletionStreamResponse> {\n yield* this.stream<\n { model: string; messages: Array<{ role: string; content: string }>; stream: true },\n CreateChatCompletionStreamResponse\n >(\n 'POST',\n '/v1/chat/completions',\n {\n model,\n messages: [{ role: 'user', content: prompt }],\n stream: true,\n },\n undefined,\n authenticated\n );\n }\n\n /**\n * Serialize web extension client state (all transient, nothing to persist)\n */\n serialize(): SerializedWebExtensionState {\n return {\n extensionId:\n this.state.type === 'extension' && this.state.extension === 'ready'\n ? this.state.extensionId\n : undefined,\n } as SerializedWebExtensionState;\n }\n\n /**\n * Debug dump of WindowBodhiextClient internal state\n */\n async debug(): Promise<Record<string, unknown>> {\n return {\n type: 'WindowBodhiextClient',\n state: this.state,\n authState: await this.getAuthState(),\n bodhiextAvailable: this.bodhiext !== null,\n authClientId: this.authClientId,\n authServerUrl: this.config.authServerUrl,\n redirectUri: this.config.redirectUri,\n userScope: this.config.userScope,\n };\n }\n}\n","/**\n * WebUIClient - Public facade client for web mode\n *\n * Wraps either DirectClient or InternalWebUIClient based on user preferences.\n * Delegates all UIClient methods to the active client instance.\n */\n\nimport {\n BaseFacadeClient,\n Logger,\n STORAGE_PREFIXES,\n type AuthLoggedIn,\n type IWebUIClient,\n type LogLevel,\n type StateChange,\n type StateChangeCallback,\n type UserScope,\n} from '@bodhiapp/bodhi-js-core';\nimport { DirectWebClient } from './direct-client';\nimport { WindowBodhiextClient } from './ext-client';\n\n/**\n * Configuration for WebClient OAuth\n */\nexport interface WebClientConfig {\n authServerUrl: string;\n redirectUri: string;\n userScope: UserScope;\n logLevel: LogLevel;\n initParams?: {\n extension?: {\n timeoutMs?: number;\n intervalMs?: number;\n };\n };\n}\n\n/**\n * WebUIClient - Public facade for web mode\n *\n * Automatically switches between DirectClient and InternalWebUIClient\n * based on stored user preferences.\n */\nexport class WebUIClient\n extends BaseFacadeClient<WebClientConfig, WindowBodhiextClient, DirectWebClient>\n implements IWebUIClient\n{\n constructor(\n authClientId: string,\n config: {\n redirectUri: string;\n authServerUrl?: string;\n userScope?: UserScope;\n logLevel?: LogLevel;\n initParams?: {\n extension?: {\n timeoutMs?: number;\n intervalMs?: number;\n };\n };\n },\n onStateChange?: StateChangeCallback,\n storagePrefix?: string\n ) {\n // Normalize config with defaults\n const normalizedConfig: WebClientConfig = {\n redirectUri: config.redirectUri,\n authServerUrl: config.authServerUrl || 'https://id.getbodhi.app/realms/bodhi',\n userScope: config.userScope || 'scope_user_user',\n logLevel: config.logLevel || 'warn',\n initParams: config.initParams,\n };\n\n super(authClientId, normalizedConfig, onStateChange, storagePrefix);\n }\n\n protected createLogger(config: WebClientConfig): Logger {\n return new Logger('WebUIClient', config.logLevel);\n }\n\n protected createExtClient(\n config: WebClientConfig,\n onStateChange: (change: StateChange) => void\n ): WindowBodhiextClient {\n return new WindowBodhiextClient(this.authClientId, config, onStateChange);\n }\n\n protected createDirectClient(\n authClientId: string,\n config: WebClientConfig,\n onStateChange: (change: StateChange) => void\n ): DirectWebClient {\n return new DirectWebClient(\n {\n authClientId,\n authServerUrl: config.authServerUrl,\n redirectUri: config.redirectUri,\n userScope: config.userScope,\n logLevel: config.logLevel,\n storagePrefix: STORAGE_PREFIXES.WEB,\n },\n onStateChange\n );\n }\n\n // ============================================================================\n // Web-specific OAuth Callback\n // ============================================================================\n async handleOAuthCallback(code: string, state: string): Promise<AuthLoggedIn> {\n // Delegate to active client based on connection mode\n if (this.connectionMode === 'direct') {\n return this.directClient.handleOAuthCallback(code, state);\n }\n return this.extClient.handleOAuthCallback(code, state);\n }\n}\n"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1,24 @@
|
|
|
1
|
+
export type ExtensionErrorCode = 'ext-not-installed' | 'ext-connection-failed' | 'ext-unsupported-version';
|
|
2
|
+
export declare const EXT_NOT_INSTALLED: ExtensionErrorCode;
|
|
3
|
+
export declare const EXT_CONNECTION_FAILED: ExtensionErrorCode;
|
|
4
|
+
export declare const EXT_UNSUPPORTED_VERSION: ExtensionErrorCode;
|
|
5
|
+
export interface ExtensionStateReady {
|
|
6
|
+
/** Current extension status */
|
|
7
|
+
status: 'ready';
|
|
8
|
+
/** Extension version */
|
|
9
|
+
version: string;
|
|
10
|
+
/** Extension ID (always present when ready) */
|
|
11
|
+
id: string;
|
|
12
|
+
}
|
|
13
|
+
export interface ExtensionStateNotReady {
|
|
14
|
+
/** Current extension status */
|
|
15
|
+
status: 'unreachable' | 'not-installed' | 'unsupported';
|
|
16
|
+
/** Error details */
|
|
17
|
+
error: {
|
|
18
|
+
/** Error message */
|
|
19
|
+
message: string;
|
|
20
|
+
/** Error code */
|
|
21
|
+
code: ExtensionErrorCode;
|
|
22
|
+
};
|
|
23
|
+
}
|
|
24
|
+
export type ExtensionState = ExtensionStateReady | ExtensionStateNotReady;
|
|
@@ -0,0 +1,20 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Consolidated types for setup-modal
|
|
3
|
+
*
|
|
4
|
+
* This folder contains all domain and protocol types organized by domain.
|
|
5
|
+
* It is designed to be independent and copyable to other packages.
|
|
6
|
+
*/
|
|
7
|
+
export type { BrowserType, OSType, EnvState, SupportedBrowser, NotSupportedBrowser, Browser, SupportedOS, NotSupportedOS, OS } from './platform';
|
|
8
|
+
export type { ExtensionErrorCode, ExtensionStateReady, ExtensionStateNotReady, ExtensionState } from './extension';
|
|
9
|
+
export { EXT_NOT_INSTALLED, EXT_CONNECTION_FAILED, EXT_UNSUPPORTED_VERSION } from './extension';
|
|
10
|
+
export type { ServerErrorCode, ServerStateReady, ServerStateReachable, ServerStatePending, ServerStateUnreachable, ServerStateError, ServerState } from './server';
|
|
11
|
+
export { SERVER_PENDING_EXT_READY, SERVER_CONN_REFUSED, SERVER_CONN_TIMEOUT, SERVER_NOT_FOUND, SERVER_NETWORK_UNREACHABLE, SERVER_SERVICE_UNAVAILABLE, SERVER_UNEXPECTED_ERROR, SERVER_IN_SETUP_STATUS, SERVER_IN_ADMIN_STATUS, } from './server';
|
|
12
|
+
export type { LnaErrorCode, LnaStatePrompt, LnaStateSkipped, LnaStateGranted, LnaStateUnreachable, LnaStateDenied, LnaStateUnsupported, LnaState, LnaServerStatePending, LnaServerStateReady, LnaServerStateSetup, LnaServerStateResourceAdmin, LnaServerStateError, LnaServerState, } from './lna';
|
|
13
|
+
export { LNA_UNREACHABLE, LNA_PERMISSION_DENIED } from './lna';
|
|
14
|
+
export { SetupStep, DEFAULT_USER_CONFIRMATIONS, DEFAULT_SETUP_STATE } from './state';
|
|
15
|
+
export type { SelectedConnection, UserConfirmations, SetupState } from './state';
|
|
16
|
+
export type { RequestId, MessageKind, RequestMessage, ResponseMessage, ErrorMessage, EventMessage, ProtocolMessage } from './protocol';
|
|
17
|
+
export { isRequestMessage, isResponseMessage, isErrorMessage, isEventMessage } from './protocol';
|
|
18
|
+
export type { MessageTypeRegistry, MessageType, RequestPayload, ResponsePayload, RequestHandlers } from './message-types';
|
|
19
|
+
export { MSG, isMessageType } from './message-types';
|
|
20
|
+
export { isExtensionStateReady, isExtensionStateNotReady, isServerStateReady, isServerStateReachable, isServerStatePending, isServerStateUnreachable, isServerStateError, isLnaStatePrompt, isLnaStateSkipped, isLnaStateGranted, isLnaStateUnreachable, isLnaStateDenied, isLnaStateUnsupported, isLnaServerStatePending, isLnaServerStateReady, isLnaServerStateSetup, isLnaServerStateResourceAdmin, isLnaServerStateError, isSupportedBrowser, isNotSupportedBrowser, isSupportedOS, isNotSupportedOS, } from './type-guards';
|
|
@@ -0,0 +1,56 @@
|
|
|
1
|
+
export type LnaErrorCode = 'lna-unreachable' | 'lna-permission-denied';
|
|
2
|
+
export declare const LNA_UNREACHABLE: LnaErrorCode;
|
|
3
|
+
export declare const LNA_PERMISSION_DENIED: LnaErrorCode;
|
|
4
|
+
export interface LnaStatePrompt {
|
|
5
|
+
status: 'prompt';
|
|
6
|
+
serverUrl?: string;
|
|
7
|
+
}
|
|
8
|
+
export interface LnaStateSkipped {
|
|
9
|
+
status: 'skipped';
|
|
10
|
+
serverUrl?: string;
|
|
11
|
+
}
|
|
12
|
+
export interface LnaStateGranted {
|
|
13
|
+
status: 'granted';
|
|
14
|
+
serverUrl: string;
|
|
15
|
+
}
|
|
16
|
+
export interface LnaStateUnreachable {
|
|
17
|
+
status: 'unreachable';
|
|
18
|
+
serverUrl: string;
|
|
19
|
+
error: {
|
|
20
|
+
message: string;
|
|
21
|
+
code: LnaErrorCode;
|
|
22
|
+
};
|
|
23
|
+
}
|
|
24
|
+
export interface LnaStateDenied {
|
|
25
|
+
status: 'denied';
|
|
26
|
+
error: {
|
|
27
|
+
message: string;
|
|
28
|
+
code: LnaErrorCode;
|
|
29
|
+
};
|
|
30
|
+
}
|
|
31
|
+
export interface LnaStateUnsupported {
|
|
32
|
+
status: 'unsupported';
|
|
33
|
+
}
|
|
34
|
+
export type LnaState = LnaStatePrompt | LnaStateSkipped | LnaStateGranted | LnaStateUnreachable | LnaStateDenied | LnaStateUnsupported;
|
|
35
|
+
export interface LnaServerStatePending {
|
|
36
|
+
status: 'pending-lna-ready';
|
|
37
|
+
}
|
|
38
|
+
export interface LnaServerStateReady {
|
|
39
|
+
status: 'ready';
|
|
40
|
+
version: string;
|
|
41
|
+
}
|
|
42
|
+
export interface LnaServerStateSetup {
|
|
43
|
+
status: 'setup';
|
|
44
|
+
version: string;
|
|
45
|
+
}
|
|
46
|
+
export interface LnaServerStateResourceAdmin {
|
|
47
|
+
status: 'resource-admin';
|
|
48
|
+
version: string;
|
|
49
|
+
}
|
|
50
|
+
export interface LnaServerStateError {
|
|
51
|
+
status: 'error';
|
|
52
|
+
error: {
|
|
53
|
+
message: string;
|
|
54
|
+
};
|
|
55
|
+
}
|
|
56
|
+
export type LnaServerState = LnaServerStatePending | LnaServerStateReady | LnaServerStateSetup | LnaServerStateResourceAdmin | LnaServerStateError;
|
|
@@ -0,0 +1,169 @@
|
|
|
1
|
+
import { SetupState } from './state';
|
|
2
|
+
|
|
3
|
+
/**
|
|
4
|
+
* Central registry mapping message types to their payload/response shapes
|
|
5
|
+
* Single source of truth - everything else is inferred!
|
|
6
|
+
*/
|
|
7
|
+
export interface MessageTypeRegistry {
|
|
8
|
+
/**
|
|
9
|
+
* Modal is ready and requesting initial state
|
|
10
|
+
* Sent on modal mount
|
|
11
|
+
*/
|
|
12
|
+
'modal:ready': {
|
|
13
|
+
request: void;
|
|
14
|
+
response: {
|
|
15
|
+
setupState: SetupState;
|
|
16
|
+
};
|
|
17
|
+
};
|
|
18
|
+
/**
|
|
19
|
+
* User requested to refresh platform detection
|
|
20
|
+
* Triggers re-detection of browser, OS, extension, server
|
|
21
|
+
*/
|
|
22
|
+
'modal:refresh': {
|
|
23
|
+
request: void;
|
|
24
|
+
response: {
|
|
25
|
+
setupState: SetupState;
|
|
26
|
+
};
|
|
27
|
+
};
|
|
28
|
+
/**
|
|
29
|
+
* User requested to close the modal
|
|
30
|
+
* Parent should hide/destroy modal
|
|
31
|
+
*/
|
|
32
|
+
'modal:close': {
|
|
33
|
+
request: void;
|
|
34
|
+
response: void;
|
|
35
|
+
};
|
|
36
|
+
/**
|
|
37
|
+
* Setup completed successfully
|
|
38
|
+
* Signals parent that user has finished setup
|
|
39
|
+
*/
|
|
40
|
+
'modal:complete': {
|
|
41
|
+
request: void;
|
|
42
|
+
response: void;
|
|
43
|
+
};
|
|
44
|
+
/**
|
|
45
|
+
* User requested LNA connection to specific server URL
|
|
46
|
+
* Triggers LNA permission request and connection attempt
|
|
47
|
+
*/
|
|
48
|
+
'modal:lna:connect': {
|
|
49
|
+
request: {
|
|
50
|
+
serverUrl: string;
|
|
51
|
+
};
|
|
52
|
+
response: {
|
|
53
|
+
success: boolean;
|
|
54
|
+
};
|
|
55
|
+
};
|
|
56
|
+
/**
|
|
57
|
+
* User chose to skip LNA setup
|
|
58
|
+
* Falls back to extension-only mode
|
|
59
|
+
*/
|
|
60
|
+
'modal:lna:skip': {
|
|
61
|
+
request: void;
|
|
62
|
+
response: {
|
|
63
|
+
success: boolean;
|
|
64
|
+
};
|
|
65
|
+
};
|
|
66
|
+
/**
|
|
67
|
+
* User confirmed server installation status
|
|
68
|
+
* Used when server needs to be installed
|
|
69
|
+
*/
|
|
70
|
+
'modal:confirm-server-install': {
|
|
71
|
+
request: {
|
|
72
|
+
confirmed: boolean;
|
|
73
|
+
};
|
|
74
|
+
response: {
|
|
75
|
+
success: boolean;
|
|
76
|
+
};
|
|
77
|
+
};
|
|
78
|
+
/**
|
|
79
|
+
* User selected preferred connection method
|
|
80
|
+
* Allows choosing between LNA and Extension paths
|
|
81
|
+
*/
|
|
82
|
+
'modal:select-connection': {
|
|
83
|
+
request: {
|
|
84
|
+
connection: 'lna' | 'extension';
|
|
85
|
+
};
|
|
86
|
+
response: {
|
|
87
|
+
success: boolean;
|
|
88
|
+
};
|
|
89
|
+
};
|
|
90
|
+
/**
|
|
91
|
+
* Parent sending updated state to modal
|
|
92
|
+
* Fired when platform detection results change
|
|
93
|
+
*/
|
|
94
|
+
'parent:state-update': {
|
|
95
|
+
request: {
|
|
96
|
+
setupState: SetupState;
|
|
97
|
+
};
|
|
98
|
+
response: void;
|
|
99
|
+
};
|
|
100
|
+
}
|
|
101
|
+
/**
|
|
102
|
+
* Union of all valid message type strings
|
|
103
|
+
* Derived from MessageTypeRegistry keys
|
|
104
|
+
*/
|
|
105
|
+
export type MessageType = keyof MessageTypeRegistry;
|
|
106
|
+
/**
|
|
107
|
+
* Extract request payload type for a given message type
|
|
108
|
+
* Returns the 'request' field from the registry entry
|
|
109
|
+
*/
|
|
110
|
+
export type RequestPayload<T extends MessageType> = MessageTypeRegistry[T]['request'];
|
|
111
|
+
/**
|
|
112
|
+
* Extract response payload type for a given message type
|
|
113
|
+
* Returns the 'response' field from the registry entry
|
|
114
|
+
*/
|
|
115
|
+
export type ResponsePayload<T extends MessageType> = MessageTypeRegistry[T]['response'];
|
|
116
|
+
/**
|
|
117
|
+
* Message type constants - Type-safe identifiers
|
|
118
|
+
*
|
|
119
|
+
* @example
|
|
120
|
+
* switch (message.type) {
|
|
121
|
+
* case MSG.MODAL_READY:
|
|
122
|
+
* // Type-safe constant, no typos possible
|
|
123
|
+
* break;
|
|
124
|
+
* }
|
|
125
|
+
*/
|
|
126
|
+
export declare const MSG: {
|
|
127
|
+
readonly MODAL_READY: "modal:ready";
|
|
128
|
+
readonly MODAL_REFRESH: "modal:refresh";
|
|
129
|
+
readonly MODAL_CLOSE: "modal:close";
|
|
130
|
+
readonly MODAL_COMPLETE: "modal:complete";
|
|
131
|
+
readonly MODAL_LNA_CONNECT: "modal:lna:connect";
|
|
132
|
+
readonly MODAL_LNA_SKIP: "modal:lna:skip";
|
|
133
|
+
readonly MODAL_CONFIRM_SERVER_INSTALL: "modal:confirm-server-install";
|
|
134
|
+
readonly MODAL_SELECT_CONNECTION: "modal:select-connection";
|
|
135
|
+
readonly PARENT_STATE_UPDATE: "parent:state-update";
|
|
136
|
+
};
|
|
137
|
+
/**
|
|
138
|
+
* Type guard that narrows RequestMessage to specific type WITH payload typing
|
|
139
|
+
*
|
|
140
|
+
* Use this for full type safety when you need access to typed payload fields.
|
|
141
|
+
* The guard narrows the generic RequestMessage to RequestMessage<T> where T
|
|
142
|
+
* determines the payload type.
|
|
143
|
+
*
|
|
144
|
+
* @example
|
|
145
|
+
* if (isMessageType(msg, MSG.MODAL_LNA_CONNECT)) {
|
|
146
|
+
* // msg.payload is { serverUrl: string } - fully typed!
|
|
147
|
+
* console.log(msg.payload.serverUrl); // Autocomplete works!
|
|
148
|
+
* }
|
|
149
|
+
*/
|
|
150
|
+
export declare function isMessageType<T extends MessageType>(msg: {
|
|
151
|
+
type: string;
|
|
152
|
+
}, type: T): msg is {
|
|
153
|
+
type: T;
|
|
154
|
+
};
|
|
155
|
+
/**
|
|
156
|
+
* Type-safe request handler map
|
|
157
|
+
* Enforces correct payload access AND correct return type for each message
|
|
158
|
+
*
|
|
159
|
+
* Each handler receives a RequestMessage<K> where K is the specific message type,
|
|
160
|
+
* providing full type safety for payload access. The handler must return the
|
|
161
|
+
* correct ResponsePayload<K> type.
|
|
162
|
+
*/
|
|
163
|
+
export type RequestHandlers = {
|
|
164
|
+
[K in MessageType]?: (msg: {
|
|
165
|
+
type: K;
|
|
166
|
+
requestId: string;
|
|
167
|
+
payload: RequestPayload<K>;
|
|
168
|
+
}) => ResponsePayload<K>;
|
|
169
|
+
};
|
|
@@ -0,0 +1,32 @@
|
|
|
1
|
+
export type BrowserType = 'chrome' | 'edge' | 'firefox' | 'safari' | 'unknown';
|
|
2
|
+
export type OSType = 'macos' | 'windows' | 'linux' | 'unknown';
|
|
3
|
+
export interface EnvState {
|
|
4
|
+
os: OSType;
|
|
5
|
+
browser: BrowserType;
|
|
6
|
+
}
|
|
7
|
+
export interface SupportedBrowser {
|
|
8
|
+
id: BrowserType;
|
|
9
|
+
status: 'supported';
|
|
10
|
+
name: string;
|
|
11
|
+
extension_url: string;
|
|
12
|
+
}
|
|
13
|
+
export interface NotSupportedBrowser {
|
|
14
|
+
id: BrowserType;
|
|
15
|
+
status: 'not-supported';
|
|
16
|
+
name: string;
|
|
17
|
+
github_issue_url?: string;
|
|
18
|
+
}
|
|
19
|
+
export type Browser = SupportedBrowser | NotSupportedBrowser;
|
|
20
|
+
export interface SupportedOS {
|
|
21
|
+
id: OSType;
|
|
22
|
+
status: 'supported';
|
|
23
|
+
name: string;
|
|
24
|
+
download_url: string;
|
|
25
|
+
}
|
|
26
|
+
export interface NotSupportedOS {
|
|
27
|
+
id: OSType;
|
|
28
|
+
status: 'not-supported';
|
|
29
|
+
name: string;
|
|
30
|
+
github_issue_url?: string;
|
|
31
|
+
}
|
|
32
|
+
export type OS = SupportedOS | NotSupportedOS;
|
|
@@ -0,0 +1,71 @@
|
|
|
1
|
+
import { MessageType, RequestPayload, ResponsePayload } from './message-types';
|
|
2
|
+
|
|
3
|
+
/** Branded type for type-safe request IDs */
|
|
4
|
+
export type RequestId = string & {
|
|
5
|
+
readonly __brand: 'RequestId';
|
|
6
|
+
};
|
|
7
|
+
/** Message kind discriminator */
|
|
8
|
+
export type MessageKind = 'request' | 'response' | 'error' | 'event';
|
|
9
|
+
/**
|
|
10
|
+
* Request message - expects a response
|
|
11
|
+
* Sent by either modal or parent to request an action
|
|
12
|
+
*/
|
|
13
|
+
export interface RequestMessage<T extends MessageType = MessageType> {
|
|
14
|
+
readonly kind: 'request';
|
|
15
|
+
readonly type: T;
|
|
16
|
+
readonly requestId: RequestId;
|
|
17
|
+
readonly payload: RequestPayload<T>;
|
|
18
|
+
}
|
|
19
|
+
/**
|
|
20
|
+
* Response message - correlates to a request
|
|
21
|
+
* Sent in response to a RequestMessage with matching requestId
|
|
22
|
+
*/
|
|
23
|
+
export interface ResponseMessage<T extends MessageType = MessageType> {
|
|
24
|
+
readonly kind: 'response';
|
|
25
|
+
readonly type: T;
|
|
26
|
+
readonly requestId: RequestId;
|
|
27
|
+
readonly payload: ResponsePayload<T>;
|
|
28
|
+
}
|
|
29
|
+
/**
|
|
30
|
+
* Error response - indicates request failure
|
|
31
|
+
* Sent instead of ResponseMessage when request cannot be fulfilled
|
|
32
|
+
*/
|
|
33
|
+
export interface ErrorMessage {
|
|
34
|
+
readonly kind: 'error';
|
|
35
|
+
readonly requestId: RequestId;
|
|
36
|
+
readonly error: {
|
|
37
|
+
code: string;
|
|
38
|
+
message: string;
|
|
39
|
+
details?: unknown;
|
|
40
|
+
};
|
|
41
|
+
}
|
|
42
|
+
/**
|
|
43
|
+
* Event message - fire-and-forget notification
|
|
44
|
+
* No response expected, used for one-way state updates
|
|
45
|
+
*/
|
|
46
|
+
export interface EventMessage<T extends MessageType = MessageType> {
|
|
47
|
+
readonly kind: 'event';
|
|
48
|
+
readonly type: T;
|
|
49
|
+
readonly payload: RequestPayload<T>;
|
|
50
|
+
}
|
|
51
|
+
/**
|
|
52
|
+
* Union of all protocol messages
|
|
53
|
+
* Discriminated by 'kind' field for type narrowing
|
|
54
|
+
*/
|
|
55
|
+
export type ProtocolMessage = RequestMessage | ResponseMessage | ErrorMessage | EventMessage;
|
|
56
|
+
/**
|
|
57
|
+
* Type guard to check if message is a request
|
|
58
|
+
*/
|
|
59
|
+
export declare function isRequestMessage(msg: ProtocolMessage): msg is RequestMessage;
|
|
60
|
+
/**
|
|
61
|
+
* Type guard to check if message is a response
|
|
62
|
+
*/
|
|
63
|
+
export declare function isResponseMessage(msg: ProtocolMessage): msg is ResponseMessage;
|
|
64
|
+
/**
|
|
65
|
+
* Type guard to check if message is an error
|
|
66
|
+
*/
|
|
67
|
+
export declare function isErrorMessage(msg: ProtocolMessage): msg is ErrorMessage;
|
|
68
|
+
/**
|
|
69
|
+
* Type guard to check if message is an event
|
|
70
|
+
*/
|
|
71
|
+
export declare function isEventMessage(msg: ProtocolMessage): msg is EventMessage;
|
|
@@ -0,0 +1,63 @@
|
|
|
1
|
+
export type ServerErrorCode = 'server-pending-ext-ready' | 'server-conn-refused' | 'server-conn-timeout' | 'server-not-found' | 'server-network-unreachable' | 'server-service-unavailable' | 'server-unexpected-error' | 'server-in-setup-status' | 'server-in-admin-status';
|
|
2
|
+
export declare const SERVER_PENDING_EXT_READY: ServerErrorCode;
|
|
3
|
+
export declare const SERVER_CONN_REFUSED: ServerErrorCode;
|
|
4
|
+
export declare const SERVER_CONN_TIMEOUT: ServerErrorCode;
|
|
5
|
+
export declare const SERVER_NOT_FOUND: ServerErrorCode;
|
|
6
|
+
export declare const SERVER_NETWORK_UNREACHABLE: ServerErrorCode;
|
|
7
|
+
export declare const SERVER_SERVICE_UNAVAILABLE: ServerErrorCode;
|
|
8
|
+
export declare const SERVER_UNEXPECTED_ERROR: ServerErrorCode;
|
|
9
|
+
export declare const SERVER_IN_SETUP_STATUS: ServerErrorCode;
|
|
10
|
+
export declare const SERVER_IN_ADMIN_STATUS: ServerErrorCode;
|
|
11
|
+
export interface ServerStateReady {
|
|
12
|
+
/** Current server status */
|
|
13
|
+
status: 'ready';
|
|
14
|
+
/** Server version */
|
|
15
|
+
version: string;
|
|
16
|
+
}
|
|
17
|
+
export interface ServerStateReachable {
|
|
18
|
+
/** Current server status */
|
|
19
|
+
status: 'setup' | 'resource-admin';
|
|
20
|
+
/** Server version */
|
|
21
|
+
version: string;
|
|
22
|
+
/** Error details */
|
|
23
|
+
error: {
|
|
24
|
+
/** Error message */
|
|
25
|
+
message: string;
|
|
26
|
+
/** Error code */
|
|
27
|
+
code: ServerErrorCode;
|
|
28
|
+
};
|
|
29
|
+
}
|
|
30
|
+
export interface ServerStatePending {
|
|
31
|
+
/** Current server status */
|
|
32
|
+
status: 'pending-extension-ready';
|
|
33
|
+
/** Error details */
|
|
34
|
+
error: {
|
|
35
|
+
/** Error message */
|
|
36
|
+
message: string;
|
|
37
|
+
/** Error code */
|
|
38
|
+
code: ServerErrorCode;
|
|
39
|
+
};
|
|
40
|
+
}
|
|
41
|
+
export interface ServerStateUnreachable {
|
|
42
|
+
/** Current server status */
|
|
43
|
+
status: 'unreachable';
|
|
44
|
+
/** Error details */
|
|
45
|
+
error: {
|
|
46
|
+
/** Error message */
|
|
47
|
+
message: string;
|
|
48
|
+
/** Error code */
|
|
49
|
+
code: ServerErrorCode;
|
|
50
|
+
};
|
|
51
|
+
}
|
|
52
|
+
export interface ServerStateError {
|
|
53
|
+
/** Current server status */
|
|
54
|
+
status: 'error';
|
|
55
|
+
/** Error details */
|
|
56
|
+
error: {
|
|
57
|
+
/** Error message */
|
|
58
|
+
message: string;
|
|
59
|
+
/** Error code */
|
|
60
|
+
code: ServerErrorCode;
|
|
61
|
+
};
|
|
62
|
+
}
|
|
63
|
+
export type ServerState = ServerStateReady | ServerStateReachable | ServerStatePending | ServerStateUnreachable | ServerStateError;
|
|
@@ -0,0 +1,43 @@
|
|
|
1
|
+
import { Browser, EnvState, OS } from './platform';
|
|
2
|
+
import { ExtensionState } from './extension';
|
|
3
|
+
import { ServerState } from './server';
|
|
4
|
+
import { LnaServerState, LnaState } from './lna';
|
|
5
|
+
|
|
6
|
+
export declare enum SetupStep {
|
|
7
|
+
PLATFORM_CHECK = "platform-check",
|
|
8
|
+
SERVER_SETUP = "server-setup",
|
|
9
|
+
LNA_SETUP = "lna-setup",
|
|
10
|
+
EXTENSION_SETUP = "extension-setup",
|
|
11
|
+
COMPLETE = "complete"
|
|
12
|
+
}
|
|
13
|
+
export type SelectedConnection = 'lna' | 'extension' | null;
|
|
14
|
+
export interface UserConfirmations {
|
|
15
|
+
/** Whether user has confirmed server installation */
|
|
16
|
+
serverInstall: boolean;
|
|
17
|
+
}
|
|
18
|
+
export declare const DEFAULT_USER_CONFIRMATIONS: UserConfirmations;
|
|
19
|
+
export interface SetupState {
|
|
20
|
+
/** Extension state details */
|
|
21
|
+
extension: ExtensionState;
|
|
22
|
+
/** Server state details (via extension) */
|
|
23
|
+
server: ServerState;
|
|
24
|
+
/** LNA connection state */
|
|
25
|
+
lna: LnaState;
|
|
26
|
+
/** Server state details (via LNA) */
|
|
27
|
+
lnaServer: LnaServerState;
|
|
28
|
+
/** Environment detection */
|
|
29
|
+
env: EnvState;
|
|
30
|
+
/** Browser platforms list */
|
|
31
|
+
browsers: Browser[];
|
|
32
|
+
/** Operating systems list */
|
|
33
|
+
os: OS[];
|
|
34
|
+
/** User confirmations for manual steps */
|
|
35
|
+
userConfirmations: UserConfirmations;
|
|
36
|
+
/** User's preferred connection method (null = auto-select based on priority) */
|
|
37
|
+
selectedConnection: SelectedConnection;
|
|
38
|
+
}
|
|
39
|
+
/**
|
|
40
|
+
* Default setup state used during initialization before parent sends real state
|
|
41
|
+
* Represents "loading" state - unknown platform, no extension, no server
|
|
42
|
+
*/
|
|
43
|
+
export declare const DEFAULT_SETUP_STATE: SetupState;
|
|
@@ -0,0 +1,27 @@
|
|
|
1
|
+
import { ExtensionState, ExtensionStateNotReady, ExtensionStateReady } from './extension';
|
|
2
|
+
import { ServerState, ServerStateError, ServerStatePending, ServerStateReachable, ServerStateReady, ServerStateUnreachable } from './server';
|
|
3
|
+
import { LnaServerState, LnaServerStateError, LnaServerStatePending, LnaServerStateReady, LnaServerStateResourceAdmin, LnaServerStateSetup, LnaState, LnaStateDenied, LnaStateGranted, LnaStatePrompt, LnaStateSkipped, LnaStateUnreachable, LnaStateUnsupported } from './lna';
|
|
4
|
+
import { Browser, NotSupportedBrowser, NotSupportedOS, OS, SupportedBrowser, SupportedOS } from './platform';
|
|
5
|
+
|
|
6
|
+
export declare function isExtensionStateReady(ext: ExtensionState): ext is ExtensionStateReady;
|
|
7
|
+
export declare function isExtensionStateNotReady(ext: ExtensionState): ext is ExtensionStateNotReady;
|
|
8
|
+
export declare function isServerStateReady(server: ServerState): server is ServerStateReady;
|
|
9
|
+
export declare function isServerStateReachable(server: ServerState): server is ServerStateReachable;
|
|
10
|
+
export declare function isServerStatePending(server: ServerState): server is ServerStatePending;
|
|
11
|
+
export declare function isServerStateUnreachable(server: ServerState): server is ServerStateUnreachable;
|
|
12
|
+
export declare function isServerStateError(server: ServerState): server is ServerStateError;
|
|
13
|
+
export declare function isLnaStatePrompt(lna: LnaState): lna is LnaStatePrompt;
|
|
14
|
+
export declare function isLnaStateSkipped(lna: LnaState): lna is LnaStateSkipped;
|
|
15
|
+
export declare function isLnaStateGranted(lna: LnaState): lna is LnaStateGranted;
|
|
16
|
+
export declare function isLnaStateUnreachable(lna: LnaState): lna is LnaStateUnreachable;
|
|
17
|
+
export declare function isLnaStateDenied(lna: LnaState): lna is LnaStateDenied;
|
|
18
|
+
export declare function isLnaStateUnsupported(lna: LnaState): lna is LnaStateUnsupported;
|
|
19
|
+
export declare function isLnaServerStatePending(server: LnaServerState): server is LnaServerStatePending;
|
|
20
|
+
export declare function isLnaServerStateReady(server: LnaServerState): server is LnaServerStateReady;
|
|
21
|
+
export declare function isLnaServerStateSetup(server: LnaServerState): server is LnaServerStateSetup;
|
|
22
|
+
export declare function isLnaServerStateResourceAdmin(server: LnaServerState): server is LnaServerStateResourceAdmin;
|
|
23
|
+
export declare function isLnaServerStateError(server: LnaServerState): server is LnaServerStateError;
|
|
24
|
+
export declare function isSupportedBrowser(browser: Browser): browser is SupportedBrowser;
|
|
25
|
+
export declare function isNotSupportedBrowser(browser: Browser): browser is NotSupportedBrowser;
|
|
26
|
+
export declare function isSupportedOS(os: OS): os is SupportedOS;
|
|
27
|
+
export declare function isNotSupportedOS(os: OS): os is NotSupportedOS;
|