import { AccessRequestStatusResponse, CreateAccessRequest, CreateAccessRequestResponse } from '@bodhiapp/ts-client'; import { ExtClientApiRequestMessage, ExtClientApiResponseMessage, ExtClientRequestMessage, ExtClientResponseMessage } from './messages'; import { ApiResponse } from '@bodhiapp/bodhi-browser-types'; import { AuthState, LoginOptions, LogLevel } from '@bodhiapp/bodhi-js-core'; export type ClientExtState = 'setup' | 'ready' | 'error'; export interface BodhiExtClientConfig { authServerUrl?: string; extensionId?: string; logLevel?: LogLevel; attempts?: number; attemptWaitMs?: number; attemptTimeout?: number; } export { EXT2EXT_CLIENT_ACTIONS, EXT2EXT_CLIENT_MESSAGE_TYPES } from './constants'; export { isExtClientApiError } from './messages'; export type { ExtClientApiError, ExtClientApiResponseMessage } from './messages'; export declare class BodhiExtClient { private extensionId?; private isAuthenticating; private authClientId; private authServerUrl; private logger; private state; private listenersInitialized; private attempts; private attemptWaitMs; private attemptTimeout; private authEndpoints; private refreshPromise; private static base64UrlEncode; private static generateCodeVerifier; private static generateCodeChallenge; constructor(authClientId: string, config?: BodhiExtClientConfig); /** * Get current client state * @returns 'ready' if extension discovered, 'setup' otherwise */ getState(): ClientExtState; /** * Get extension IDs for current environment */ private getExtensionIdsForEnvironment; /** * Ping extension using bodhi-browser-ext's EXT_REQUEST protocol */ private pingExtension; /** * Sleep helper for retry delays */ private sleep; /** * Discover Bodhi extension sequentially through known IDs with retry logic * @param params Resolved discovery params */ private discoverBodhiExtension; /** * Setup all listeners for UI connections (idempotent) */ private setupListeners; /** * Initialize client: setup listeners and discover bodhi-browser-ext * @param params Resolved discovery params (already merged with constructor defaults) * @throws Error if discovery fails */ init(params?: { attempts?: number; attemptWaitMs?: number; attemptTimeout?: number; }): Promise; /** * Broadcast auth state change to all extension contexts * @private */ private broadcastAuthStateChange; /** * Get extension ID from bodhi-browser-ext via EXT_REQUEST * @returns Extension ID returned by bodhi-browser-ext */ getExtensionIdFromExt(): Promise; /** * Handle API request (EXT2EXT_CLIENT_API_REQUEST) * Forwards to bodhi-browser-ext via sendApiRequest * @param message API request message * @returns API response message (success or error) */ private handleApiRequest; /** * Handle action-based request (EXT2EXT_CLIENT_REQUEST) * Routes to ext2ext operations or local OAuth operations * @param message Action request message * @returns Action response message (success or error) */ private handleExtClientRequest; /** * Handle action from either EXT2EXT_CLIENT_REQUEST or EXT2EXT_CLIENT_API_REQUEST * Routes to either ext2ext operations, local operations, or API operations * Never throws - always returns a valid response message * @param message Either ExtClientRequestMessage or ExtClientApiRequestMessage * @returns Either ExtClientResponseMessage or ExtClientApiResponseMessage */ handleAction(message: ExtClientRequestMessage): Promise>; handleAction(message: ExtClientApiRequestMessage): Promise>; /** * Login user via access-request + OAuth2 + PKCE flow * @param options - Optional login options * @throws Error if login fails */ login(options?: LoginOptions): Promise; /** * Exchange authorization code for tokens (private helper for login) * @param code Authorization code from OAuth callback */ private exchangeCodeForTokens; /** * Get current authentication state * @returns AuthState (discriminated union: AuthLoggedIn | AuthLoggedOut) */ getAuthState(): Promise; /** * Logout current user and revoke tokens */ logout(): Promise; requestAccess(body: CreateAccessRequest): Promise>; getAccessRequestStatus(requestId: string): Promise>; pollAccessRequestStatus(requestId: string, options?: { intervalMs?: number; timeoutMs?: number; }): Promise; private performOAuthPkce; /** * Send EXT_REQUEST message to bodhi-browser-ext * @param action The action to perform * @param params Optional parameters * @returns Response body (unwrapped, throws on error) */ private sendExtRequest; /** * Send API_REQUEST message to bodhi-browser-ext for HTTP operations * @param method HTTP method (GET, POST, etc.) * @param endpoint API endpoint path * @param body Optional request body * @param headers Optional headers * @returns API response from LLM server via bodhi-browser-ext */ private sendApiRequest; /** * Send EXT_REQUEST message to bodhi-browser-ext and return full response * @param action The action to perform * @param params Optional parameters * @returns Full ExtResponseMessage from bodhi-browser-ext */ private sendExtRequestRaw; /** * Active streaming ports for cleanup */ private activeStreamPorts; /** * Streaming timeout in milliseconds (60 seconds, matches bodhi-browser-ext) */ private static readonly STREAM_TIMEOUT; /** * Register a chrome.runtime.onConnect listener for a streaming port. * Validates port name and message type, then delegates to handler. */ private registerStreamPortListener; /** * Generic stream relay: validates auth, connects to bodhi-browser-ext, * sets up timeout/disconnect handling, and delegates message forwarding * to the onBodhiMessage callback. * * @param onBodhiMessage Called for each message from bodhi-browser-ext. * Returns true if the stream is complete (triggers cleanup). */ private handleGenericStreamRelay; /** * Clean up a streaming port connection */ private cleanupStreamPort; /** * Handle SSE-parsed streaming request — translates STREAM_* messages to EXT2EXT_CLIENT_STREAM_* */ private handleStreamRequest; /** * Handle raw text streaming request — translates STREAM_TEXT_* messages to EXT2EXT_CLIENT_STREAM_TEXT_* */ private handleStreamTextRequest; private storeTokens; protected _getAccessTokenRaw(): Promise; /** * Try to refresh access token using refresh token * Race condition prevention: Returns existing promise if refresh already in progress */ private _tryRefreshToken; /** * Perform the actual token refresh */ private _doRefreshToken; /** * Store refreshed tokens */ private _storeRefreshedTokens; private clearTokens; private parseJwt; private createErrorClientNotInitialized; }