@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
package/README.md ADDED
@@ -0,0 +1,26 @@
1
+ # @bodhiapp/bodhi-js
2
+
3
+ Web SDK for Bodhi Browser - `window.bodhiext` communication.
4
+
5
+ ## Installation
6
+
7
+ ```bash
8
+ npm install @bodhiapp/bodhi-js
9
+ ```
10
+
11
+ ## Usage
12
+
13
+ ```typescript
14
+ import { WebUIClient } from '@bodhiapp/bodhi-js';
15
+
16
+ const client = new WebUIClient('your-client-id');
17
+ await client.init();
18
+ ```
19
+
20
+ ## Documentation
21
+
22
+ See [bodhi-browser/bodhi-js-sdk](https://github.com/BodhiSearch/bodhi-browser/tree/main/bodhi-js-sdk) for complete documentation.
23
+
24
+ ## License
25
+
26
+ MIT
@@ -0,0 +1,202 @@
1
+ import { OpenAiApiError, PingResponse, CreateChatCompletionRequest, CreateChatCompletionResponse, CreateChatCompletionStreamResponse } from '@bodhiapp/ts-client';
2
+
3
+ /**
4
+ * HTTP response wrapper - body can be success type OR error type
5
+ * Use isApiErrorResponse() to narrow the type based on status
6
+ */
7
+ export interface ApiResponse<T = unknown> {
8
+ body: T | OpenAiApiError;
9
+ status: number;
10
+ headers: Record<string, string>;
11
+ }
12
+ /**
13
+ * Stream chunk returned by sendStreamRequest
14
+ *
15
+ * This is the chunk structure yielded by the ReadableStream from sendStreamRequest.
16
+ * Different from StreamChunkMessage which is the internal message wrapper.
17
+ */
18
+ export interface StreamChunk {
19
+ body: unknown;
20
+ headers?: Record<string, string>;
21
+ status?: number;
22
+ done?: boolean;
23
+ }
24
+ /**
25
+ * Server state information returned by /bodhi/v1/info endpoint
26
+ */
27
+ export interface ServerStateInfo {
28
+ /** Current application status */
29
+ status: 'setup' | 'ready' | 'resource-admin' | 'error' | 'unreachable';
30
+ /** Application version */
31
+ version?: string;
32
+ /** Server URL (added by extension) */
33
+ url?: string;
34
+ /** Error details if status is 'error' or 'unreachable' */
35
+ error?: {
36
+ message: string;
37
+ type?: string;
38
+ code?: string;
39
+ param?: string;
40
+ };
41
+ }
42
+ /**
43
+ * API error thrown when server returns HTTP 4xx/5xx
44
+ * Used for streaming responses (non-streaming returns ApiResponse)
45
+ */
46
+ export interface ApiError extends Error {
47
+ response: {
48
+ status: number;
49
+ body: OpenAiApiError;
50
+ headers?: Record<string, string>;
51
+ };
52
+ }
53
+ /**
54
+ * Operation error thrown when HTTP request couldn't complete
55
+ * (network unreachable, timeout, extension error)
56
+ */
57
+ export interface OperationError extends Error {
58
+ error: {
59
+ message: string;
60
+ type: string;
61
+ };
62
+ }
63
+ /**
64
+ * Union of all extension-thrown errors
65
+ */
66
+ export type ExtensionError = ApiError | OperationError;
67
+ /**
68
+ * Type guard: API error (has response field)
69
+ */
70
+ export declare function isApiError(err: unknown): err is ApiError;
71
+ /**
72
+ * Type guard: Operation error (has error field, no response)
73
+ */
74
+ export declare function isOperationError(err: unknown): err is OperationError;
75
+ /**
76
+ * Chat API uses types from @bodhiapp/ts-client.
77
+ * Consumers should import these types directly from @bodhiapp/ts-client:
78
+ * - ChatCompletionRequestMessage
79
+ * - ChatCompletionResponseMessage
80
+ * - CreateChatCompletionRequest
81
+ * - CreateChatCompletionResponse
82
+ * - CreateChatCompletionStreamResponse
83
+ * - ChatChoice
84
+ * - ChatChoiceStream
85
+ * - ChatCompletionStreamResponseDelta
86
+ */
87
+ /**
88
+ * Chat completions API interface
89
+ */
90
+ export interface ChatCompletionsApi {
91
+ /**
92
+ * Create a chat completion
93
+ *
94
+ * Non-streaming: Returns ApiResponse - caller checks status for success/error
95
+ * Streaming: Yields chunks via AsyncIterable - throws ApiError or OperationError on error
96
+ *
97
+ * @param params - Chat completion parameters
98
+ * @returns Non-streaming: Promise<ApiResponse<CreateChatCompletionResponse>>, Streaming: AsyncIterable<CreateChatCompletionStreamResponse>
99
+ */
100
+ create(params: CreateChatCompletionRequest & {
101
+ stream?: false;
102
+ }): Promise<ApiResponse<CreateChatCompletionResponse>>;
103
+ create(params: CreateChatCompletionRequest & {
104
+ stream: true;
105
+ }): AsyncIterable<CreateChatCompletionStreamResponse>;
106
+ create(params: CreateChatCompletionRequest): Promise<ApiResponse<CreateChatCompletionResponse>> | AsyncIterable<CreateChatCompletionStreamResponse>;
107
+ }
108
+ /**
109
+ * Chat API namespace
110
+ */
111
+ export interface ChatApi {
112
+ completions: ChatCompletionsApi;
113
+ }
114
+ /**
115
+ * Public window.bodhiext interface
116
+ *
117
+ * This interface defines all methods available to web pages through window.bodhiext.
118
+ * The extension creates this interface in inject.ts and attaches it to the window object.
119
+ */
120
+ export interface BodhiExtPublicApi {
121
+ /**
122
+ * Send a generic API request through the extension to the backend server.
123
+ *
124
+ * @template TReq - Request body type (inferred from body parameter)
125
+ * @template TRes - Response body type (must be specified explicitly)
126
+ * @param method - HTTP method (GET, POST, PUT, DELETE, etc.)
127
+ * @param endpoint - API endpoint path (e.g., '/v1/chat/completions')
128
+ * @param body - Optional request body (will be JSON stringified)
129
+ * @param headers - Optional additional headers
130
+ * @returns Promise resolving to ApiResponse with body, headers, and status
131
+ */
132
+ sendApiRequest<TReq = unknown, TRes = unknown>(method: string, endpoint: string, body?: TReq, headers?: Record<string, string>): Promise<ApiResponse<TRes>>;
133
+ /**
134
+ * Send a streaming API request through the extension.
135
+ *
136
+ * Used for SSE (Server-Sent Events) endpoints like streaming chat completions.
137
+ * Returns a ReadableStream that yields StreamChunk objects.
138
+ *
139
+ * @template TReq - Request body type (inferred from body parameter)
140
+ * @param method - HTTP method (typically POST for streaming)
141
+ * @param endpoint - API endpoint path (e.g., '/v1/chat/completions')
142
+ * @param body - Optional request body
143
+ * @param headers - Optional additional headers
144
+ * @returns ReadableStream yielding StreamChunk objects
145
+ */
146
+ sendStreamRequest<TReq = unknown>(method: string, endpoint: string, body?: TReq, headers?: Record<string, string>): ReadableStream<StreamChunk>;
147
+ /**
148
+ * Send a generic extension request.
149
+ *
150
+ * Used for extension-specific operations like test_connection, get_extension_id, etc.
151
+ * This is a low-level API for extension capabilities.
152
+ *
153
+ * @param action - Extension action name (e.g., 'test_connection')
154
+ * @param params - Optional action parameters
155
+ * @returns Promise resolving to action-specific response
156
+ */
157
+ sendExtRequest(action: string, params?: any): Promise<any>;
158
+ /**
159
+ * Simple health check to verify extension connectivity.
160
+ *
161
+ * Returns ApiResponse - caller should check status to determine success/error.
162
+ * On success (2xx), body is PingResponse. On error (4xx/5xx), body is OpenAiApiError.
163
+ *
164
+ * @returns Promise resolving to ApiResponse<PingResponse>
165
+ */
166
+ ping(): Promise<ApiResponse<PingResponse>>;
167
+ /**
168
+ * Get server state information from /bodhi/v1/info endpoint.
169
+ *
170
+ * Returns the current status of the backend server including
171
+ * whether it's in setup mode, ready, or has errors.
172
+ *
173
+ * @returns Promise resolving to ServerStateInfo
174
+ */
175
+ serverState(): Promise<ServerStateInfo>;
176
+ /**
177
+ * OpenAI-compatible chat API.
178
+ *
179
+ * Provides chat completion functionality compatible with OpenAI's API structure.
180
+ */
181
+ chat: ChatApi;
182
+ /**
183
+ * Get the extension ID.
184
+ *
185
+ * The extension ID is fetched asynchronously during initialization.
186
+ * This method returns a promise that resolves to the extension ID once available.
187
+ *
188
+ * @returns Promise resolving to the extension ID string
189
+ */
190
+ getExtensionId(): Promise<string>;
191
+ }
192
+ /**
193
+ * Window augmentation for TypeScript
194
+ *
195
+ * Declares the optional bodhiext property on the Window interface.
196
+ * This allows TypeScript code to access window.bodhiext with proper typing.
197
+ */
198
+ declare global {
199
+ interface Window {
200
+ bodhiext?: BodhiExtPublicApi;
201
+ }
202
+ }
@@ -0,0 +1,36 @@
1
+ /**
2
+ * Shared constants for Bodhi Browser Extension
3
+ *
4
+ * Constants used by both inject.ts and background/content.ts scripts,
5
+ * or common to the entire extension.
6
+ */
7
+ export declare const CONTENT_TYPE_JSON = "application/json";
8
+ export declare const CONTENT_TYPE_EVENT_STREAM = "text/event-stream";
9
+ export declare const CONTENT_TYPE_HEADER = "Content-Type";
10
+ export declare const HTTP_METHOD_GET = "GET";
11
+ export declare const HTTP_METHOD_POST = "POST";
12
+ export declare const ENDPOINT_PING = "/ping";
13
+ export declare const ENDPOINT_CHAT_COMPLETIONS = "/v1/chat/completions";
14
+ export declare const DEFAULT_API_BASE_URL = "http://localhost:1135";
15
+ export declare const DEFAULT_API_TIMEOUT = 10000;
16
+ export declare const DEFAULT_STREAM_TIMEOUT = 60000;
17
+ export declare const STORAGE_KEY_BACKEND_URL = "backendUrl";
18
+ export declare const SSE_DONE_MARKER = "[DONE]";
19
+ export declare const SSE_DATA_PREFIX = "data: ";
20
+ export declare const SSE_CHUNK_DELIMITER = "\n\n";
21
+ export declare const EXT_ACTIONS: {
22
+ readonly GET_EXTENSION_ID: "get_extension_id";
23
+ readonly TEST_CONNECTION: "test_connection";
24
+ };
25
+ export declare const ERROR_TYPES: {
26
+ readonly NETWORK_ERROR: "network_error";
27
+ readonly EXTENSION_ERROR: "extension_error";
28
+ readonly TIMEOUT_ERROR: "timeout_error";
29
+ };
30
+ export type ConnectionErrorType = (typeof ERROR_TYPES)[keyof typeof ERROR_TYPES];
31
+ export declare const DOCUMENT_STATE_COMPLETE = "complete";
32
+ export declare const EVENT_INITIALIZED = "bodhiext:initialized";
33
+ export declare const BODHI_STREAM_PORT = "BODHI_STREAM_PORT";
34
+ export declare const ORIGIN_WILDCARD = "*";
35
+ export declare const ERROR_MISSING_REQUEST_ID = "Invalid message format: missing requestId or request";
36
+ export declare const ERROR_CONNECTION_CLOSED = "Connection closed unexpectedly";
@@ -0,0 +1,6 @@
1
+ export type { ApiResponse, StreamChunk, ServerStateInfo, ApiError, OperationError, ExtensionError, ChatCompletionsApi, ChatApi, BodhiExtPublicApi } from './bodhiext';
2
+ export { isApiError, isOperationError } from './bodhiext';
3
+ export type { ApiRequest, ApiRequestMessage, OperationErrorResponse, ApiResponseSuccessMessage, OperationErrorResponseMessage, ApiResponseMessage, ErrorMessage, StreamChunkMessage, StreamApiErrorMessage, StreamErrorMessage, StreamMessage, StreamController, SSEChunk, ExtRequest, ExtRequestMessage, ExtError, ExtErrorResponse, ExtResponse, ExtResponseMessage, GetExtensionIdRequest, GetExtensionIdResponse, TestConnectionRequest, TestConnectionResponse, } from './protocol';
4
+ export { MESSAGE_TYPES, isOperationErrorResponse, isApiErrorResponse, isApiSuccessResponse, isStreamChunk, isStreamApiError, isStreamError, isExtError, isOpenAiApiErrorBody, isOperationErrorStructure, } from './protocol';
5
+ export { CONTENT_TYPE_JSON, CONTENT_TYPE_EVENT_STREAM, CONTENT_TYPE_HEADER, HTTP_METHOD_GET, HTTP_METHOD_POST, ENDPOINT_PING, ENDPOINT_CHAT_COMPLETIONS, DEFAULT_API_BASE_URL, DEFAULT_API_TIMEOUT, DEFAULT_STREAM_TIMEOUT, STORAGE_KEY_BACKEND_URL, SSE_DONE_MARKER, SSE_DATA_PREFIX, SSE_CHUNK_DELIMITER, EXT_ACTIONS, ERROR_TYPES, DOCUMENT_STATE_COMPLETE, EVENT_INITIALIZED, BODHI_STREAM_PORT, ORIGIN_WILDCARD, ERROR_MISSING_REQUEST_ID, ERROR_CONNECTION_CLOSED, } from './common';
6
+ export type { ConnectionErrorType } from './common';
@@ -0,0 +1,223 @@
1
+ import { OpenAiApiError, ErrorBody } from '@bodhiapp/ts-client';
2
+ import { ApiResponse, ServerStateInfo } from './bodhiext';
3
+
4
+ /**
5
+ * Validate OpenAI API error body structure
6
+ * { error: { message: string, type: string } }
7
+ */
8
+ export declare function isOpenAiApiErrorBody(body: unknown): body is OpenAiApiError;
9
+ /**
10
+ * Validate OperationErrorResponse structure
11
+ * { message: string, type: string }
12
+ */
13
+ export declare function isOperationErrorStructure(obj: unknown): obj is OperationErrorResponse;
14
+ export declare const MESSAGE_TYPES: {
15
+ readonly API_REQUEST: "BODHI_API_REQUEST";
16
+ readonly API_RESPONSE: "BODHI_API_RESPONSE";
17
+ readonly STREAM_REQUEST: "BODHI_STREAM_REQUEST";
18
+ readonly STREAM_CHUNK: "BODHI_STREAM_CHUNK";
19
+ readonly STREAM_ERROR: "BODHI_STREAM_ERROR";
20
+ readonly STREAM_API_ERROR: "BODHI_STREAM_API_ERROR";
21
+ readonly ERROR: "BODHI_ERROR";
22
+ readonly EXT_REQUEST: "BODHI_EXT_REQUEST";
23
+ readonly EXT_RESPONSE: "BODHI_EXT_RESPONSE";
24
+ };
25
+ export interface ApiRequest<T = unknown> {
26
+ method: string;
27
+ endpoint: string;
28
+ body?: T;
29
+ headers?: Record<string, string>;
30
+ }
31
+ export interface ApiRequestMessage<TReq = unknown> {
32
+ type: string;
33
+ requestId: string;
34
+ request: ApiRequest<TReq>;
35
+ }
36
+ /**
37
+ * Operation-level error response (network unreachable, timeout, extension error)
38
+ * NOT an API error (those come through ApiResponse with OpenAiApiError body)
39
+ * This is a response type, not a thrown error
40
+ */
41
+ export interface OperationErrorResponse {
42
+ message: string;
43
+ type: string;
44
+ }
45
+ /**
46
+ * Success API response message (HTTP request completed, regardless of status code)
47
+ */
48
+ export interface ApiResponseSuccessMessage<T = unknown> {
49
+ type: string;
50
+ requestId: string;
51
+ response: ApiResponse<T>;
52
+ }
53
+ /**
54
+ * Operation error response message - HTTP request couldn't complete
55
+ */
56
+ export interface OperationErrorResponseMessage {
57
+ type: string;
58
+ requestId: string;
59
+ error: OperationErrorResponse;
60
+ }
61
+ /**
62
+ * API response message - discriminated union
63
+ */
64
+ export type ApiResponseMessage<T = unknown> = ApiResponseSuccessMessage<T> | OperationErrorResponseMessage;
65
+ /**
66
+ * Type guard for operation error response
67
+ */
68
+ export declare function isOperationErrorResponse(msg: ApiResponseMessage): msg is OperationErrorResponseMessage;
69
+ /**
70
+ * Type guard to check if response is an API error (4xx/5xx)
71
+ * Narrows body type to OpenAiApiError
72
+ */
73
+ export declare function isApiErrorResponse<T>(response: ApiResponse<T>): response is ApiResponse<T> & {
74
+ body: OpenAiApiError;
75
+ status: number;
76
+ };
77
+ /**
78
+ * Type guard to check if response is successful (2xx)
79
+ * Narrows body type to T
80
+ */
81
+ export declare function isApiSuccessResponse<T>(response: ApiResponse<T>): response is ApiResponse<T> & {
82
+ body: T;
83
+ status: number;
84
+ };
85
+ export interface ErrorMessage {
86
+ type: string;
87
+ requestId: string;
88
+ response: {
89
+ body: ErrorBody;
90
+ status: number;
91
+ headers: Record<string, string>;
92
+ };
93
+ }
94
+ /**
95
+ * Stream chunk message - successful SSE chunk received
96
+ * Uses ApiResponse<T> wrapper for consistency with non-streaming pattern
97
+ */
98
+ export interface StreamChunkMessage<T = unknown> {
99
+ type: typeof MESSAGE_TYPES.STREAM_CHUNK;
100
+ requestId: string;
101
+ response: ApiResponse<T>;
102
+ }
103
+ /**
104
+ * Stream API error message - server returned error response (not SSE)
105
+ * E.g., 400/401/500 JSON error instead of SSE stream
106
+ */
107
+ export interface StreamApiErrorMessage {
108
+ type: typeof MESSAGE_TYPES.STREAM_API_ERROR;
109
+ requestId: string;
110
+ response: ApiResponse<OpenAiApiError>;
111
+ }
112
+ /**
113
+ * Stream error message - network/extension level error
114
+ * E.g., connection refused, timeout, extension error
115
+ */
116
+ export interface StreamErrorMessage {
117
+ type: typeof MESSAGE_TYPES.STREAM_ERROR;
118
+ requestId: string;
119
+ error: OperationErrorResponse;
120
+ }
121
+ /**
122
+ * Union type for all streaming messages
123
+ */
124
+ export type StreamMessage<T = unknown> = StreamChunkMessage<T> | StreamApiErrorMessage | StreamErrorMessage;
125
+ /**
126
+ * Type guard for stream chunk message
127
+ */
128
+ export declare function isStreamChunk<T>(msg: StreamMessage<T>): msg is StreamChunkMessage<T>;
129
+ /**
130
+ * Type guard for stream API error
131
+ */
132
+ export declare function isStreamApiError(msg: StreamMessage): msg is StreamApiErrorMessage;
133
+ /**
134
+ * Type guard for stream error
135
+ */
136
+ export declare function isStreamError(msg: StreamMessage): msg is StreamErrorMessage;
137
+ /**
138
+ * Interface for stream controller to handle SSE responses
139
+ */
140
+ export interface StreamController {
141
+ enqueue: (chunk: any) => void;
142
+ error: (err: Error) => void;
143
+ complete: () => void;
144
+ }
145
+ /**
146
+ * Interface for SSE data chunk
147
+ */
148
+ export interface SSEChunk {
149
+ done?: boolean;
150
+ [key: string]: any;
151
+ }
152
+ /**
153
+ * Generic extension request interface
154
+ */
155
+ export interface ExtRequest {
156
+ action: string;
157
+ params?: any;
158
+ }
159
+ /**
160
+ * Generic extension request message
161
+ */
162
+ export interface ExtRequestMessage {
163
+ type: 'BODHI_EXT_REQUEST';
164
+ requestId: string;
165
+ request: ExtRequest;
166
+ }
167
+ /**
168
+ * Extension-level error structure
169
+ */
170
+ export interface ExtError {
171
+ message: string;
172
+ type?: string;
173
+ }
174
+ /**
175
+ * Error response for extension operations
176
+ */
177
+ export interface ExtErrorResponse {
178
+ error: ExtError;
179
+ }
180
+ /**
181
+ * Union type for extension response (flattened - no wrapper for success)
182
+ * Success: T (the actual response data)
183
+ * Error: { error: ExtError }
184
+ */
185
+ export type ExtResponse<T = unknown> = T | ExtErrorResponse;
186
+ /**
187
+ * Type guard to check if extension response is an error
188
+ */
189
+ export declare function isExtError<T>(res: ExtResponse<T>): res is ExtErrorResponse;
190
+ /**
191
+ * Generic extension response message
192
+ */
193
+ export interface ExtResponseMessage<T = unknown> {
194
+ type: 'BODHI_EXT_RESPONSE';
195
+ requestId: string;
196
+ response: ExtResponse<T>;
197
+ }
198
+ /**
199
+ * Get Extension ID request (no params needed)
200
+ */
201
+ export interface GetExtensionIdRequest extends ExtRequest {
202
+ action: 'get_extension_id';
203
+ params?: undefined;
204
+ }
205
+ /**
206
+ * Get Extension ID response body
207
+ */
208
+ export interface GetExtensionIdResponse {
209
+ extension_id: string;
210
+ }
211
+ /**
212
+ * Test Connection request
213
+ */
214
+ export interface TestConnectionRequest extends ExtRequest {
215
+ action: 'test_connection';
216
+ params: {
217
+ url: string;
218
+ };
219
+ }
220
+ /**
221
+ * Test Connection response body (reuses ServerStateInfo)
222
+ */
223
+ export type TestConnectionResponse = ServerStateInfo;
@@ -0,0 +1,129 @@
1
+ import { CreateChatCompletionStreamResponse } from '@bodhiapp/ts-client';
2
+ import { IDirectClient } from './interface';
3
+ import { Logger } from './logger';
4
+ import { OAuthEndpoints, RefreshTokenResponse } from './oauth';
5
+ import { StorageKeys } from './storage';
6
+ import { ApiResponseResult, AuthLoggedIn, AuthLoggedOut, AuthState, BackendServerState, ClientState, DirectState, InitParams, LogLevel, SerializedDirectState, StateChangeCallback } from './types';
7
+ /**
8
+ * DirectClientBase - Abstract base class for DirectClient implementations
9
+ *
10
+ * Contains common HTTP fetch and streaming logic shared between
11
+ * DirectExtClient and DirectWebClient.
12
+ */
13
+ export interface ConnectivityTestResult {
14
+ success: boolean;
15
+ serverInfo?: {
16
+ status: string;
17
+ version: string;
18
+ };
19
+ error?: {
20
+ message: string;
21
+ type: string;
22
+ };
23
+ }
24
+ /**
25
+ * Test connectivity to a local server
26
+ * @param serverUrl - The server URL to test
27
+ * @returns Promise with connectivity test result
28
+ */
29
+ export declare function testServerConnectivity(serverUrl: string): Promise<ConnectivityTestResult>;
30
+ /**
31
+ * Base configuration for DirectClient
32
+ */
33
+ export interface DirectClientBaseConfig {
34
+ authClientId: string;
35
+ authServerUrl?: string;
36
+ userScope?: string;
37
+ storagePrefix: string;
38
+ logLevel?: LogLevel;
39
+ }
40
+ /**
41
+ * DirectClientBase - Abstract base implementing common HTTP/streaming logic
42
+ */
43
+ export declare abstract class DirectClientBase implements IDirectClient {
44
+ protected logger: Logger;
45
+ protected serverUrl: string | null;
46
+ protected authClientId: string;
47
+ protected authServerUrl: string;
48
+ protected userScope: string;
49
+ protected authEndpoints: OAuthEndpoints;
50
+ protected storageKeys: StorageKeys;
51
+ protected state: DirectState;
52
+ private onStateChange;
53
+ private refreshPromise;
54
+ constructor(config: DirectClientBaseConfig, loggerPrefix: string, onStateChange?: StateChangeCallback);
55
+ /**
56
+ * Set client state and notify callback
57
+ */
58
+ protected setState(newState: DirectState): void;
59
+ /**
60
+ * Set auth state and notify callback
61
+ */
62
+ protected setAuthState(authState: AuthState): void;
63
+ /**
64
+ * Set or update the state change callback
65
+ */
66
+ setStateCallback(callback: StateChangeCallback): void;
67
+ init(params: InitParams): Promise<DirectState>;
68
+ getState(): ClientState;
69
+ isClientInitialized(): boolean;
70
+ isServerReady(): boolean;
71
+ /**
72
+ * Ensures client is initialized before operations
73
+ */
74
+ private ensureInitialized;
75
+ sendApiRequest<TReq = void, TRes = unknown>(method: string, endpoint: string, body?: TReq, headers?: Record<string, string>, authenticated?: boolean): Promise<ApiResponseResult<TRes>>;
76
+ pingApi(): Promise<ApiResponseResult<{
77
+ message: string;
78
+ }>>;
79
+ fetchModels(): Promise<ApiResponseResult<{
80
+ data: Array<{
81
+ id: string;
82
+ object: string;
83
+ }>;
84
+ }>>;
85
+ /**
86
+ * Get backend server state
87
+ * Calls /bodhi/v1/info and returns structured server state
88
+ */
89
+ getServerState(): Promise<BackendServerState>;
90
+ stream<TReq = unknown, TRes = unknown>(method: string, endpoint: string, body?: TReq, headers?: Record<string, string>, authenticated?: boolean): AsyncGenerator<TRes>;
91
+ streamChat(model: string, prompt: string, authenticated?: boolean): AsyncGenerator<CreateChatCompletionStreamResponse>;
92
+ /**
93
+ * Test connectivity to local server
94
+ */
95
+ testConnectivity(): Promise<ConnectivityTestResult>;
96
+ /**
97
+ * Serialize DirectClient state for persistence
98
+ */
99
+ serialize(): SerializedDirectState;
100
+ /**
101
+ * Debug dump of DirectClient internal state
102
+ */
103
+ debug(): Promise<Record<string, unknown>>;
104
+ abstract login(): Promise<AuthLoggedIn>;
105
+ abstract logout(): Promise<AuthLoggedOut>;
106
+ getAuthState(): Promise<AuthState>;
107
+ protected _getAccessTokenRaw(): Promise<string | null>;
108
+ /**
109
+ * Try to refresh access token using refresh token
110
+ * Race condition prevention: Returns existing promise if refresh already in progress
111
+ */
112
+ protected _tryRefreshToken(refreshToken: string): Promise<string | null>;
113
+ /**
114
+ * Perform the actual token refresh
115
+ */
116
+ private _doRefreshToken;
117
+ /**
118
+ * Store refreshed tokens
119
+ */
120
+ protected _storeRefreshedTokens(tokens: RefreshTokenResponse): Promise<void>;
121
+ protected requestResourceAccess(): Promise<string>;
122
+ protected exchangeCodeForTokens(code: string): Promise<void>;
123
+ protected revokeRefreshToken(): Promise<void>;
124
+ protected clearAuthStorage(): Promise<void>;
125
+ protected abstract _storageGet(key: string): Promise<string | null>;
126
+ protected abstract _storageSet(items: Record<string, string | number>): Promise<void>;
127
+ protected abstract _storageRemove(keys: string[]): Promise<void>;
128
+ protected abstract _getRedirectUri(): string;
129
+ }
@@ -0,0 +1,23 @@
1
+ import { ApiError, OperationError } from '../../../bodhi-browser-ext/src/types';
2
+ import { OpenAiApiError } from '@bodhiapp/ts-client';
3
+
4
+ /**
5
+ * Create API error (HTTP 4xx/5xx from server)
6
+ * Thrown for streaming responses when server returns error
7
+ *
8
+ * @param message - Error message
9
+ * @param status - HTTP status code
10
+ * @param body - Error body from server
11
+ * @param headers - Optional response headers
12
+ * @returns ApiError instance
13
+ */
14
+ export declare const createApiError: (message: string, status: number, body: OpenAiApiError, headers?: Record<string, string>) => ApiError;
15
+ /**
16
+ * Create operation error (network/extension level)
17
+ * Thrown when HTTP request couldn't complete
18
+ *
19
+ * @param message - Error message
20
+ * @param type - Error type (network_error, timeout_error, etc.)
21
+ * @returns OperationError instance
22
+ */
23
+ export declare const createOperationError: (message: string, type: string) => OperationError;