@bodhiapp/bodhi-browser-types 0.0.20 → 0.0.22
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/dist/bodhiext.d.ts +201 -0
- package/dist/common.d.ts +37 -0
- package/dist/index.d.ts +6 -0
- package/dist/index.js +113 -0
- package/dist/protocol.d.ts +222 -0
- package/package.json +19 -7
- package/bodhiext.ts +0 -255
- package/common.ts +0 -99
- package/index.ts +0 -88
- package/protocol.ts +0 -315
|
@@ -0,0 +1,201 @@
|
|
|
1
|
+
import { OpenAiApiError, PingResponse, CreateChatCompletionRequest, CreateChatCompletionResponse, CreateChatCompletionStreamResponse } from '@bodhiapp/ts-client';
|
|
2
|
+
/**
|
|
3
|
+
* HTTP response wrapper - body can be success type OR error type
|
|
4
|
+
* Use isApiErrorResponse() to narrow the type based on status
|
|
5
|
+
*/
|
|
6
|
+
export interface ApiResponse<T = unknown> {
|
|
7
|
+
body: T | OpenAiApiError;
|
|
8
|
+
status: number;
|
|
9
|
+
headers: Record<string, string>;
|
|
10
|
+
}
|
|
11
|
+
/**
|
|
12
|
+
* Stream chunk returned by sendStreamRequest
|
|
13
|
+
*
|
|
14
|
+
* This is the chunk structure yielded by the ReadableStream from sendStreamRequest.
|
|
15
|
+
* Different from StreamChunkMessage which is the internal message wrapper.
|
|
16
|
+
*/
|
|
17
|
+
export interface StreamChunk {
|
|
18
|
+
body: unknown;
|
|
19
|
+
headers?: Record<string, string>;
|
|
20
|
+
status?: number;
|
|
21
|
+
done?: boolean;
|
|
22
|
+
}
|
|
23
|
+
/**
|
|
24
|
+
* Server state information returned by /bodhi/v1/info endpoint
|
|
25
|
+
*/
|
|
26
|
+
export interface ServerStateInfo {
|
|
27
|
+
/** Current application status */
|
|
28
|
+
status: 'setup' | 'ready' | 'resource-admin' | 'error' | 'unreachable';
|
|
29
|
+
/** Application version */
|
|
30
|
+
version?: string;
|
|
31
|
+
/** Server URL (added by extension) */
|
|
32
|
+
url?: string;
|
|
33
|
+
/** Error details if status is 'error' or 'unreachable' */
|
|
34
|
+
error?: {
|
|
35
|
+
message: string;
|
|
36
|
+
type?: string;
|
|
37
|
+
code?: string;
|
|
38
|
+
param?: string;
|
|
39
|
+
};
|
|
40
|
+
}
|
|
41
|
+
/**
|
|
42
|
+
* API error thrown when server returns HTTP 4xx/5xx
|
|
43
|
+
* Used for streaming responses (non-streaming returns ApiResponse)
|
|
44
|
+
*/
|
|
45
|
+
export interface ApiError extends Error {
|
|
46
|
+
response: {
|
|
47
|
+
status: number;
|
|
48
|
+
body: OpenAiApiError;
|
|
49
|
+
headers?: Record<string, string>;
|
|
50
|
+
};
|
|
51
|
+
}
|
|
52
|
+
/**
|
|
53
|
+
* Operation error thrown when HTTP request couldn't complete
|
|
54
|
+
* (network unreachable, timeout, extension error)
|
|
55
|
+
*/
|
|
56
|
+
export interface OperationError extends Error {
|
|
57
|
+
error: {
|
|
58
|
+
message: string;
|
|
59
|
+
type: string;
|
|
60
|
+
};
|
|
61
|
+
}
|
|
62
|
+
/**
|
|
63
|
+
* Union of all extension-thrown errors
|
|
64
|
+
*/
|
|
65
|
+
export type ExtensionError = ApiError | OperationError;
|
|
66
|
+
/**
|
|
67
|
+
* Type guard: API error (has response field)
|
|
68
|
+
*/
|
|
69
|
+
export declare function isApiError(err: unknown): err is ApiError;
|
|
70
|
+
/**
|
|
71
|
+
* Type guard: Operation error (has error field, no response)
|
|
72
|
+
*/
|
|
73
|
+
export declare function isOperationError(err: unknown): err is OperationError;
|
|
74
|
+
/**
|
|
75
|
+
* Chat API uses types from @bodhiapp/ts-client.
|
|
76
|
+
* Consumers should import these types directly from @bodhiapp/ts-client:
|
|
77
|
+
* - ChatCompletionRequestMessage
|
|
78
|
+
* - ChatCompletionResponseMessage
|
|
79
|
+
* - CreateChatCompletionRequest
|
|
80
|
+
* - CreateChatCompletionResponse
|
|
81
|
+
* - CreateChatCompletionStreamResponse
|
|
82
|
+
* - ChatChoice
|
|
83
|
+
* - ChatChoiceStream
|
|
84
|
+
* - ChatCompletionStreamResponseDelta
|
|
85
|
+
*/
|
|
86
|
+
/**
|
|
87
|
+
* Chat completions API interface
|
|
88
|
+
*/
|
|
89
|
+
export interface ChatCompletionsApi {
|
|
90
|
+
/**
|
|
91
|
+
* Create a chat completion
|
|
92
|
+
*
|
|
93
|
+
* Non-streaming: Returns ApiResponse - caller checks status for success/error
|
|
94
|
+
* Streaming: Yields chunks via AsyncIterable - throws ApiError or OperationError on error
|
|
95
|
+
*
|
|
96
|
+
* @param params - Chat completion parameters
|
|
97
|
+
* @returns Non-streaming: Promise<ApiResponse<CreateChatCompletionResponse>>, Streaming: AsyncIterable<CreateChatCompletionStreamResponse>
|
|
98
|
+
*/
|
|
99
|
+
create(params: CreateChatCompletionRequest & {
|
|
100
|
+
stream?: false;
|
|
101
|
+
}): Promise<ApiResponse<CreateChatCompletionResponse>>;
|
|
102
|
+
create(params: CreateChatCompletionRequest & {
|
|
103
|
+
stream: true;
|
|
104
|
+
}): AsyncIterable<CreateChatCompletionStreamResponse>;
|
|
105
|
+
create(params: CreateChatCompletionRequest): Promise<ApiResponse<CreateChatCompletionResponse>> | AsyncIterable<CreateChatCompletionStreamResponse>;
|
|
106
|
+
}
|
|
107
|
+
/**
|
|
108
|
+
* Chat API namespace
|
|
109
|
+
*/
|
|
110
|
+
export interface ChatApi {
|
|
111
|
+
completions: ChatCompletionsApi;
|
|
112
|
+
}
|
|
113
|
+
/**
|
|
114
|
+
* Public window.bodhiext interface
|
|
115
|
+
*
|
|
116
|
+
* This interface defines all methods available to web pages through window.bodhiext.
|
|
117
|
+
* The extension creates this interface in inject.ts and attaches it to the window object.
|
|
118
|
+
*/
|
|
119
|
+
export interface BodhiExtPublicApi {
|
|
120
|
+
/**
|
|
121
|
+
* Send a generic API request through the extension to the backend server.
|
|
122
|
+
*
|
|
123
|
+
* @template TReq - Request body type (inferred from body parameter)
|
|
124
|
+
* @template TRes - Response body type (must be specified explicitly)
|
|
125
|
+
* @param method - HTTP method (GET, POST, PUT, DELETE, etc.)
|
|
126
|
+
* @param endpoint - API endpoint path (e.g., '/v1/chat/completions')
|
|
127
|
+
* @param body - Optional request body (will be JSON stringified)
|
|
128
|
+
* @param headers - Optional additional headers
|
|
129
|
+
* @returns Promise resolving to ApiResponse with body, headers, and status
|
|
130
|
+
*/
|
|
131
|
+
sendApiRequest<TReq = unknown, TRes = unknown>(method: string, endpoint: string, body?: TReq, headers?: Record<string, string>): Promise<ApiResponse<TRes>>;
|
|
132
|
+
/**
|
|
133
|
+
* Send a streaming API request through the extension.
|
|
134
|
+
*
|
|
135
|
+
* Used for SSE (Server-Sent Events) endpoints like streaming chat completions.
|
|
136
|
+
* Returns a ReadableStream that yields StreamChunk objects.
|
|
137
|
+
*
|
|
138
|
+
* @template TReq - Request body type (inferred from body parameter)
|
|
139
|
+
* @param method - HTTP method (typically POST for streaming)
|
|
140
|
+
* @param endpoint - API endpoint path (e.g., '/v1/chat/completions')
|
|
141
|
+
* @param body - Optional request body
|
|
142
|
+
* @param headers - Optional additional headers
|
|
143
|
+
* @returns ReadableStream yielding StreamChunk objects
|
|
144
|
+
*/
|
|
145
|
+
sendStreamRequest<TReq = unknown>(method: string, endpoint: string, body?: TReq, headers?: Record<string, string>): ReadableStream<StreamChunk>;
|
|
146
|
+
/**
|
|
147
|
+
* Send a generic extension request.
|
|
148
|
+
*
|
|
149
|
+
* Used for extension-specific operations like test_connection, get_extension_id, etc.
|
|
150
|
+
* This is a low-level API for extension capabilities.
|
|
151
|
+
*
|
|
152
|
+
* @param action - Extension action name (e.g., 'test_connection')
|
|
153
|
+
* @param params - Optional action parameters
|
|
154
|
+
* @returns Promise resolving to action-specific response
|
|
155
|
+
*/
|
|
156
|
+
sendExtRequest(action: string, params?: any): Promise<any>;
|
|
157
|
+
/**
|
|
158
|
+
* Simple health check to verify extension connectivity.
|
|
159
|
+
*
|
|
160
|
+
* Returns ApiResponse - caller should check status to determine success/error.
|
|
161
|
+
* On success (2xx), body is PingResponse. On error (4xx/5xx), body is OpenAiApiError.
|
|
162
|
+
*
|
|
163
|
+
* @returns Promise resolving to ApiResponse<PingResponse>
|
|
164
|
+
*/
|
|
165
|
+
ping(): Promise<ApiResponse<PingResponse>>;
|
|
166
|
+
/**
|
|
167
|
+
* Get server state information from /bodhi/v1/info endpoint.
|
|
168
|
+
*
|
|
169
|
+
* Returns the current status of the backend server including
|
|
170
|
+
* whether it's in setup mode, ready, or has errors.
|
|
171
|
+
*
|
|
172
|
+
* @returns Promise resolving to ServerStateInfo
|
|
173
|
+
*/
|
|
174
|
+
serverState(): Promise<ServerStateInfo>;
|
|
175
|
+
/**
|
|
176
|
+
* OpenAI-compatible chat API.
|
|
177
|
+
*
|
|
178
|
+
* Provides chat completion functionality compatible with OpenAI's API structure.
|
|
179
|
+
*/
|
|
180
|
+
chat: ChatApi;
|
|
181
|
+
/**
|
|
182
|
+
* Get the extension ID.
|
|
183
|
+
*
|
|
184
|
+
* The extension ID is fetched asynchronously during initialization.
|
|
185
|
+
* This method returns a promise that resolves to the extension ID once available.
|
|
186
|
+
*
|
|
187
|
+
* @returns Promise resolving to the extension ID string
|
|
188
|
+
*/
|
|
189
|
+
getExtensionId(): Promise<string>;
|
|
190
|
+
}
|
|
191
|
+
/**
|
|
192
|
+
* Window augmentation for TypeScript
|
|
193
|
+
*
|
|
194
|
+
* Declares the optional bodhiext property on the Window interface.
|
|
195
|
+
* This allows TypeScript code to access window.bodhiext with proper typing.
|
|
196
|
+
*/
|
|
197
|
+
declare global {
|
|
198
|
+
interface Window {
|
|
199
|
+
bodhiext?: BodhiExtPublicApi;
|
|
200
|
+
}
|
|
201
|
+
}
|
package/dist/common.d.ts
ADDED
|
@@ -0,0 +1,37 @@
|
|
|
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
|
+
readonly AUTH_ERROR: "auth_error";
|
|
30
|
+
};
|
|
31
|
+
export type ConnectionErrorType = (typeof ERROR_TYPES)[keyof typeof ERROR_TYPES];
|
|
32
|
+
export declare const DOCUMENT_STATE_COMPLETE = "complete";
|
|
33
|
+
export declare const EVENT_INITIALIZED = "bodhiext:initialized";
|
|
34
|
+
export declare const BODHI_STREAM_PORT = "BODHI_STREAM_PORT";
|
|
35
|
+
export declare const ORIGIN_WILDCARD = "*";
|
|
36
|
+
export declare const ERROR_MISSING_REQUEST_ID = "Invalid message format: missing requestId or request";
|
|
37
|
+
export declare const ERROR_CONNECTION_CLOSED = "Connection closed unexpectedly";
|
package/dist/index.d.ts
ADDED
|
@@ -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';
|
package/dist/index.js
ADDED
|
@@ -0,0 +1,113 @@
|
|
|
1
|
+
function isNonNullObject(value) {
|
|
2
|
+
return value !== null && typeof value === "object";
|
|
3
|
+
}
|
|
4
|
+
function isOpenAiApiErrorBody(body) {
|
|
5
|
+
return isNonNullObject(body) && "error" in body && isNonNullObject(body.error) && "message" in body.error && typeof body.error.message === "string" && "type" in body.error && typeof body.error.type === "string";
|
|
6
|
+
}
|
|
7
|
+
function isOperationErrorStructure(obj) {
|
|
8
|
+
return isNonNullObject(obj) && "message" in obj && typeof obj.message === "string" && "type" in obj && typeof obj.type === "string";
|
|
9
|
+
}
|
|
10
|
+
const MESSAGE_TYPES = {
|
|
11
|
+
API_REQUEST: "BODHI_API_REQUEST",
|
|
12
|
+
API_RESPONSE: "BODHI_API_RESPONSE",
|
|
13
|
+
STREAM_REQUEST: "BODHI_STREAM_REQUEST",
|
|
14
|
+
STREAM_CHUNK: "BODHI_STREAM_CHUNK",
|
|
15
|
+
STREAM_ERROR: "BODHI_STREAM_ERROR",
|
|
16
|
+
STREAM_API_ERROR: "BODHI_STREAM_API_ERROR",
|
|
17
|
+
ERROR: "BODHI_ERROR",
|
|
18
|
+
EXT_REQUEST: "BODHI_EXT_REQUEST",
|
|
19
|
+
EXT_RESPONSE: "BODHI_EXT_RESPONSE"
|
|
20
|
+
};
|
|
21
|
+
function isOperationErrorResponse(msg) {
|
|
22
|
+
return isNonNullObject(msg) && "error" in msg && isOperationErrorStructure(msg.error);
|
|
23
|
+
}
|
|
24
|
+
function isApiErrorResponse(response) {
|
|
25
|
+
return isNonNullObject(response) && typeof response.status === "number" && response.status >= 400 && isOpenAiApiErrorBody(response.body);
|
|
26
|
+
}
|
|
27
|
+
function isApiSuccessResponse(response) {
|
|
28
|
+
return response !== null && typeof response === "object" && typeof response.status === "number" && response.status >= 200 && response.status < 300 && "body" in response;
|
|
29
|
+
}
|
|
30
|
+
function isStreamChunk(msg) {
|
|
31
|
+
return msg !== null && typeof msg === "object" && msg.type === MESSAGE_TYPES.STREAM_CHUNK;
|
|
32
|
+
}
|
|
33
|
+
function isStreamApiError(msg) {
|
|
34
|
+
return msg !== null && typeof msg === "object" && msg.type === MESSAGE_TYPES.STREAM_API_ERROR;
|
|
35
|
+
}
|
|
36
|
+
function isStreamError(msg) {
|
|
37
|
+
return msg !== null && typeof msg === "object" && msg.type === MESSAGE_TYPES.STREAM_ERROR;
|
|
38
|
+
}
|
|
39
|
+
function isExtError(res) {
|
|
40
|
+
return res !== null && typeof res === "object" && "error" in res;
|
|
41
|
+
}
|
|
42
|
+
function isApiError(err) {
|
|
43
|
+
return err instanceof Error && "response" in err && typeof err.response === "object" && err.response !== null && typeof err.response.status === "number" && "body" in err.response;
|
|
44
|
+
}
|
|
45
|
+
function isOperationError(err) {
|
|
46
|
+
return err instanceof Error && "error" in err && !("response" in err) && isOperationErrorStructure(err.error);
|
|
47
|
+
}
|
|
48
|
+
const CONTENT_TYPE_JSON = "application/json";
|
|
49
|
+
const CONTENT_TYPE_EVENT_STREAM = "text/event-stream";
|
|
50
|
+
const CONTENT_TYPE_HEADER = "Content-Type";
|
|
51
|
+
const HTTP_METHOD_GET = "GET";
|
|
52
|
+
const HTTP_METHOD_POST = "POST";
|
|
53
|
+
const ENDPOINT_PING = "/ping";
|
|
54
|
+
const ENDPOINT_CHAT_COMPLETIONS = "/v1/chat/completions";
|
|
55
|
+
const DEFAULT_API_BASE_URL = "http://localhost:1135";
|
|
56
|
+
const DEFAULT_API_TIMEOUT = 1e4;
|
|
57
|
+
const DEFAULT_STREAM_TIMEOUT = 6e4;
|
|
58
|
+
const STORAGE_KEY_BACKEND_URL = "backendUrl";
|
|
59
|
+
const SSE_DONE_MARKER = "[DONE]";
|
|
60
|
+
const SSE_DATA_PREFIX = "data: ";
|
|
61
|
+
const SSE_CHUNK_DELIMITER = "\n\n";
|
|
62
|
+
const EXT_ACTIONS = {
|
|
63
|
+
GET_EXTENSION_ID: "get_extension_id",
|
|
64
|
+
TEST_CONNECTION: "test_connection"
|
|
65
|
+
};
|
|
66
|
+
const ERROR_TYPES = {
|
|
67
|
+
NETWORK_ERROR: "network_error",
|
|
68
|
+
EXTENSION_ERROR: "extension_error",
|
|
69
|
+
TIMEOUT_ERROR: "timeout_error",
|
|
70
|
+
AUTH_ERROR: "auth_error"
|
|
71
|
+
};
|
|
72
|
+
const DOCUMENT_STATE_COMPLETE = "complete";
|
|
73
|
+
const EVENT_INITIALIZED = "bodhiext:initialized";
|
|
74
|
+
const BODHI_STREAM_PORT = "BODHI_STREAM_PORT";
|
|
75
|
+
const ORIGIN_WILDCARD = "*";
|
|
76
|
+
const ERROR_MISSING_REQUEST_ID = "Invalid message format: missing requestId or request";
|
|
77
|
+
const ERROR_CONNECTION_CLOSED = "Connection closed unexpectedly";
|
|
78
|
+
export {
|
|
79
|
+
BODHI_STREAM_PORT,
|
|
80
|
+
CONTENT_TYPE_EVENT_STREAM,
|
|
81
|
+
CONTENT_TYPE_HEADER,
|
|
82
|
+
CONTENT_TYPE_JSON,
|
|
83
|
+
DEFAULT_API_BASE_URL,
|
|
84
|
+
DEFAULT_API_TIMEOUT,
|
|
85
|
+
DEFAULT_STREAM_TIMEOUT,
|
|
86
|
+
DOCUMENT_STATE_COMPLETE,
|
|
87
|
+
ENDPOINT_CHAT_COMPLETIONS,
|
|
88
|
+
ENDPOINT_PING,
|
|
89
|
+
ERROR_CONNECTION_CLOSED,
|
|
90
|
+
ERROR_MISSING_REQUEST_ID,
|
|
91
|
+
ERROR_TYPES,
|
|
92
|
+
EVENT_INITIALIZED,
|
|
93
|
+
EXT_ACTIONS,
|
|
94
|
+
HTTP_METHOD_GET,
|
|
95
|
+
HTTP_METHOD_POST,
|
|
96
|
+
MESSAGE_TYPES,
|
|
97
|
+
ORIGIN_WILDCARD,
|
|
98
|
+
SSE_CHUNK_DELIMITER,
|
|
99
|
+
SSE_DATA_PREFIX,
|
|
100
|
+
SSE_DONE_MARKER,
|
|
101
|
+
STORAGE_KEY_BACKEND_URL,
|
|
102
|
+
isApiError,
|
|
103
|
+
isApiErrorResponse,
|
|
104
|
+
isApiSuccessResponse,
|
|
105
|
+
isExtError,
|
|
106
|
+
isOpenAiApiErrorBody,
|
|
107
|
+
isOperationError,
|
|
108
|
+
isOperationErrorResponse,
|
|
109
|
+
isOperationErrorStructure,
|
|
110
|
+
isStreamApiError,
|
|
111
|
+
isStreamChunk,
|
|
112
|
+
isStreamError
|
|
113
|
+
};
|
|
@@ -0,0 +1,222 @@
|
|
|
1
|
+
import { OpenAiApiError, ErrorBody } from '@bodhiapp/ts-client';
|
|
2
|
+
import { ApiResponse, ServerStateInfo } from './bodhiext';
|
|
3
|
+
/**
|
|
4
|
+
* Validate OpenAI API error body structure
|
|
5
|
+
* { error: { message: string, type: string } }
|
|
6
|
+
*/
|
|
7
|
+
export declare function isOpenAiApiErrorBody(body: unknown): body is OpenAiApiError;
|
|
8
|
+
/**
|
|
9
|
+
* Validate OperationErrorResponse structure
|
|
10
|
+
* { message: string, type: string }
|
|
11
|
+
*/
|
|
12
|
+
export declare function isOperationErrorStructure(obj: unknown): obj is OperationErrorResponse;
|
|
13
|
+
export declare const MESSAGE_TYPES: {
|
|
14
|
+
readonly API_REQUEST: "BODHI_API_REQUEST";
|
|
15
|
+
readonly API_RESPONSE: "BODHI_API_RESPONSE";
|
|
16
|
+
readonly STREAM_REQUEST: "BODHI_STREAM_REQUEST";
|
|
17
|
+
readonly STREAM_CHUNK: "BODHI_STREAM_CHUNK";
|
|
18
|
+
readonly STREAM_ERROR: "BODHI_STREAM_ERROR";
|
|
19
|
+
readonly STREAM_API_ERROR: "BODHI_STREAM_API_ERROR";
|
|
20
|
+
readonly ERROR: "BODHI_ERROR";
|
|
21
|
+
readonly EXT_REQUEST: "BODHI_EXT_REQUEST";
|
|
22
|
+
readonly EXT_RESPONSE: "BODHI_EXT_RESPONSE";
|
|
23
|
+
};
|
|
24
|
+
export interface ApiRequest<T = unknown> {
|
|
25
|
+
method: string;
|
|
26
|
+
endpoint: string;
|
|
27
|
+
body?: T;
|
|
28
|
+
headers?: Record<string, string>;
|
|
29
|
+
}
|
|
30
|
+
export interface ApiRequestMessage<TReq = unknown> {
|
|
31
|
+
type: string;
|
|
32
|
+
requestId: string;
|
|
33
|
+
request: ApiRequest<TReq>;
|
|
34
|
+
}
|
|
35
|
+
/**
|
|
36
|
+
* Operation-level error response (network unreachable, timeout, extension error)
|
|
37
|
+
* NOT an API error (those come through ApiResponse with OpenAiApiError body)
|
|
38
|
+
* This is a response type, not a thrown error
|
|
39
|
+
*/
|
|
40
|
+
export interface OperationErrorResponse {
|
|
41
|
+
message: string;
|
|
42
|
+
type: string;
|
|
43
|
+
}
|
|
44
|
+
/**
|
|
45
|
+
* Success API response message (HTTP request completed, regardless of status code)
|
|
46
|
+
*/
|
|
47
|
+
export interface ApiResponseSuccessMessage<T = unknown> {
|
|
48
|
+
type: string;
|
|
49
|
+
requestId: string;
|
|
50
|
+
response: ApiResponse<T>;
|
|
51
|
+
}
|
|
52
|
+
/**
|
|
53
|
+
* Operation error response message - HTTP request couldn't complete
|
|
54
|
+
*/
|
|
55
|
+
export interface OperationErrorResponseMessage {
|
|
56
|
+
type: string;
|
|
57
|
+
requestId: string;
|
|
58
|
+
error: OperationErrorResponse;
|
|
59
|
+
}
|
|
60
|
+
/**
|
|
61
|
+
* API response message - discriminated union
|
|
62
|
+
*/
|
|
63
|
+
export type ApiResponseMessage<T = unknown> = ApiResponseSuccessMessage<T> | OperationErrorResponseMessage;
|
|
64
|
+
/**
|
|
65
|
+
* Type guard for operation error response
|
|
66
|
+
*/
|
|
67
|
+
export declare function isOperationErrorResponse(msg: ApiResponseMessage): msg is OperationErrorResponseMessage;
|
|
68
|
+
/**
|
|
69
|
+
* Type guard to check if response is an API error (4xx/5xx)
|
|
70
|
+
* Narrows body type to OpenAiApiError
|
|
71
|
+
*/
|
|
72
|
+
export declare function isApiErrorResponse<T>(response: ApiResponse<T>): response is ApiResponse<T> & {
|
|
73
|
+
body: OpenAiApiError;
|
|
74
|
+
status: number;
|
|
75
|
+
};
|
|
76
|
+
/**
|
|
77
|
+
* Type guard to check if response is successful (2xx)
|
|
78
|
+
* Narrows body type to T
|
|
79
|
+
*/
|
|
80
|
+
export declare function isApiSuccessResponse<T>(response: ApiResponse<T>): response is ApiResponse<T> & {
|
|
81
|
+
body: T;
|
|
82
|
+
status: number;
|
|
83
|
+
};
|
|
84
|
+
export interface ErrorMessage {
|
|
85
|
+
type: string;
|
|
86
|
+
requestId: string;
|
|
87
|
+
response: {
|
|
88
|
+
body: ErrorBody;
|
|
89
|
+
status: number;
|
|
90
|
+
headers: Record<string, string>;
|
|
91
|
+
};
|
|
92
|
+
}
|
|
93
|
+
/**
|
|
94
|
+
* Stream chunk message - successful SSE chunk received
|
|
95
|
+
* Uses ApiResponse<T> wrapper for consistency with non-streaming pattern
|
|
96
|
+
*/
|
|
97
|
+
export interface StreamChunkMessage<T = unknown> {
|
|
98
|
+
type: typeof MESSAGE_TYPES.STREAM_CHUNK;
|
|
99
|
+
requestId: string;
|
|
100
|
+
response: ApiResponse<T>;
|
|
101
|
+
}
|
|
102
|
+
/**
|
|
103
|
+
* Stream API error message - server returned error response (not SSE)
|
|
104
|
+
* E.g., 400/401/500 JSON error instead of SSE stream
|
|
105
|
+
*/
|
|
106
|
+
export interface StreamApiErrorMessage {
|
|
107
|
+
type: typeof MESSAGE_TYPES.STREAM_API_ERROR;
|
|
108
|
+
requestId: string;
|
|
109
|
+
response: ApiResponse<OpenAiApiError>;
|
|
110
|
+
}
|
|
111
|
+
/**
|
|
112
|
+
* Stream error message - network/extension level error
|
|
113
|
+
* E.g., connection refused, timeout, extension error
|
|
114
|
+
*/
|
|
115
|
+
export interface StreamErrorMessage {
|
|
116
|
+
type: typeof MESSAGE_TYPES.STREAM_ERROR;
|
|
117
|
+
requestId: string;
|
|
118
|
+
error: OperationErrorResponse;
|
|
119
|
+
}
|
|
120
|
+
/**
|
|
121
|
+
* Union type for all streaming messages
|
|
122
|
+
*/
|
|
123
|
+
export type StreamMessage<T = unknown> = StreamChunkMessage<T> | StreamApiErrorMessage | StreamErrorMessage;
|
|
124
|
+
/**
|
|
125
|
+
* Type guard for stream chunk message
|
|
126
|
+
*/
|
|
127
|
+
export declare function isStreamChunk<T>(msg: StreamMessage<T>): msg is StreamChunkMessage<T>;
|
|
128
|
+
/**
|
|
129
|
+
* Type guard for stream API error
|
|
130
|
+
*/
|
|
131
|
+
export declare function isStreamApiError(msg: StreamMessage): msg is StreamApiErrorMessage;
|
|
132
|
+
/**
|
|
133
|
+
* Type guard for stream error
|
|
134
|
+
*/
|
|
135
|
+
export declare function isStreamError(msg: StreamMessage): msg is StreamErrorMessage;
|
|
136
|
+
/**
|
|
137
|
+
* Interface for stream controller to handle SSE responses
|
|
138
|
+
*/
|
|
139
|
+
export interface StreamController {
|
|
140
|
+
enqueue: (chunk: any) => void;
|
|
141
|
+
error: (err: Error) => void;
|
|
142
|
+
complete: () => void;
|
|
143
|
+
}
|
|
144
|
+
/**
|
|
145
|
+
* Interface for SSE data chunk
|
|
146
|
+
*/
|
|
147
|
+
export interface SSEChunk {
|
|
148
|
+
done?: boolean;
|
|
149
|
+
[key: string]: any;
|
|
150
|
+
}
|
|
151
|
+
/**
|
|
152
|
+
* Generic extension request interface
|
|
153
|
+
*/
|
|
154
|
+
export interface ExtRequest {
|
|
155
|
+
action: string;
|
|
156
|
+
params?: any;
|
|
157
|
+
}
|
|
158
|
+
/**
|
|
159
|
+
* Generic extension request message
|
|
160
|
+
*/
|
|
161
|
+
export interface ExtRequestMessage {
|
|
162
|
+
type: 'BODHI_EXT_REQUEST';
|
|
163
|
+
requestId: string;
|
|
164
|
+
request: ExtRequest;
|
|
165
|
+
}
|
|
166
|
+
/**
|
|
167
|
+
* Extension-level error structure
|
|
168
|
+
*/
|
|
169
|
+
export interface ExtError {
|
|
170
|
+
message: string;
|
|
171
|
+
type?: string;
|
|
172
|
+
}
|
|
173
|
+
/**
|
|
174
|
+
* Error response for extension operations
|
|
175
|
+
*/
|
|
176
|
+
export interface ExtErrorResponse {
|
|
177
|
+
error: ExtError;
|
|
178
|
+
}
|
|
179
|
+
/**
|
|
180
|
+
* Union type for extension response (flattened - no wrapper for success)
|
|
181
|
+
* Success: T (the actual response data)
|
|
182
|
+
* Error: { error: ExtError }
|
|
183
|
+
*/
|
|
184
|
+
export type ExtResponse<T = unknown> = T | ExtErrorResponse;
|
|
185
|
+
/**
|
|
186
|
+
* Type guard to check if extension response is an error
|
|
187
|
+
*/
|
|
188
|
+
export declare function isExtError<T>(res: ExtResponse<T>): res is ExtErrorResponse;
|
|
189
|
+
/**
|
|
190
|
+
* Generic extension response message
|
|
191
|
+
*/
|
|
192
|
+
export interface ExtResponseMessage<T = unknown> {
|
|
193
|
+
type: 'BODHI_EXT_RESPONSE';
|
|
194
|
+
requestId: string;
|
|
195
|
+
response: ExtResponse<T>;
|
|
196
|
+
}
|
|
197
|
+
/**
|
|
198
|
+
* Get Extension ID request (no params needed)
|
|
199
|
+
*/
|
|
200
|
+
export interface GetExtensionIdRequest extends ExtRequest {
|
|
201
|
+
action: 'get_extension_id';
|
|
202
|
+
params?: undefined;
|
|
203
|
+
}
|
|
204
|
+
/**
|
|
205
|
+
* Get Extension ID response body
|
|
206
|
+
*/
|
|
207
|
+
export interface GetExtensionIdResponse {
|
|
208
|
+
extension_id: string;
|
|
209
|
+
}
|
|
210
|
+
/**
|
|
211
|
+
* Test Connection request
|
|
212
|
+
*/
|
|
213
|
+
export interface TestConnectionRequest extends ExtRequest {
|
|
214
|
+
action: 'test_connection';
|
|
215
|
+
params: {
|
|
216
|
+
url: string;
|
|
217
|
+
};
|
|
218
|
+
}
|
|
219
|
+
/**
|
|
220
|
+
* Test Connection response body (reuses ServerStateInfo)
|
|
221
|
+
*/
|
|
222
|
+
export type TestConnectionResponse = ServerStateInfo;
|
package/package.json
CHANGED
|
@@ -1,20 +1,32 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@bodhiapp/bodhi-browser-types",
|
|
3
|
-
"version": "0.0.
|
|
3
|
+
"version": "0.0.22",
|
|
4
4
|
"description": "TypeScript types for Bodhi Browser Extension",
|
|
5
5
|
"type": "module",
|
|
6
|
-
"main": "index.
|
|
7
|
-
"types": "index.ts",
|
|
6
|
+
"main": "dist/index.js",
|
|
7
|
+
"types": "dist/index.d.ts",
|
|
8
8
|
"exports": {
|
|
9
9
|
".": {
|
|
10
|
-
"types": "./index.ts",
|
|
11
|
-
"import": "./index.
|
|
12
|
-
"require": "./index.ts"
|
|
10
|
+
"types": "./dist/index.d.ts",
|
|
11
|
+
"import": "./dist/index.js"
|
|
13
12
|
}
|
|
14
13
|
},
|
|
15
14
|
"files": [
|
|
16
|
-
"
|
|
15
|
+
"dist"
|
|
17
16
|
],
|
|
17
|
+
"scripts": {
|
|
18
|
+
"build": "vite build",
|
|
19
|
+
"clean": "rimraf dist"
|
|
20
|
+
},
|
|
21
|
+
"peerDependencies": {
|
|
22
|
+
"@bodhiapp/ts-client": ">=0.1.0"
|
|
23
|
+
},
|
|
24
|
+
"devDependencies": {
|
|
25
|
+
"vite": "^7.1.12",
|
|
26
|
+
"vite-plugin-dts": "^4.5.4",
|
|
27
|
+
"rimraf": "^6.0.1",
|
|
28
|
+
"typescript": "^5.8.3"
|
|
29
|
+
},
|
|
18
30
|
"repository": {
|
|
19
31
|
"type": "git",
|
|
20
32
|
"url": "https://github.com/BodhiSearch/bodhi-js.git",
|
package/bodhiext.ts
DELETED
|
@@ -1,255 +0,0 @@
|
|
|
1
|
-
/**
|
|
2
|
-
* Public API types for window.bodhiext interface
|
|
3
|
-
*
|
|
4
|
-
* This file defines the contract web pages use to communicate with the Bodhi browser extension.
|
|
5
|
-
* Used primarily by inject.ts to create the window.bodhiext API surface.
|
|
6
|
-
*/
|
|
7
|
-
|
|
8
|
-
import type { OpenAiApiError, PingResponse, CreateChatCompletionRequest, CreateChatCompletionResponse, CreateChatCompletionStreamResponse } from '@bodhiapp/ts-client';
|
|
9
|
-
import { isOperationErrorStructure } from './protocol';
|
|
10
|
-
|
|
11
|
-
//-----------------------------------------------------------------------------------
|
|
12
|
-
// HTTP RESPONSE TYPES
|
|
13
|
-
//-----------------------------------------------------------------------------------
|
|
14
|
-
|
|
15
|
-
/**
|
|
16
|
-
* HTTP response wrapper - body can be success type OR error type
|
|
17
|
-
* Use isApiErrorResponse() to narrow the type based on status
|
|
18
|
-
*/
|
|
19
|
-
export interface ApiResponse<T = unknown> {
|
|
20
|
-
body: T | OpenAiApiError;
|
|
21
|
-
status: number;
|
|
22
|
-
headers: Record<string, string>;
|
|
23
|
-
}
|
|
24
|
-
|
|
25
|
-
/**
|
|
26
|
-
* Stream chunk returned by sendStreamRequest
|
|
27
|
-
*
|
|
28
|
-
* This is the chunk structure yielded by the ReadableStream from sendStreamRequest.
|
|
29
|
-
* Different from StreamChunkMessage which is the internal message wrapper.
|
|
30
|
-
*/
|
|
31
|
-
export interface StreamChunk {
|
|
32
|
-
body: unknown;
|
|
33
|
-
headers?: Record<string, string>;
|
|
34
|
-
status?: number;
|
|
35
|
-
done?: boolean;
|
|
36
|
-
}
|
|
37
|
-
|
|
38
|
-
/**
|
|
39
|
-
* Server state information returned by /bodhi/v1/info endpoint
|
|
40
|
-
*/
|
|
41
|
-
export interface ServerStateInfo {
|
|
42
|
-
/** Current application status */
|
|
43
|
-
status: 'setup' | 'ready' | 'resource-admin' | 'error' | 'unreachable';
|
|
44
|
-
/** Application version */
|
|
45
|
-
version?: string;
|
|
46
|
-
/** Server URL (added by extension) */
|
|
47
|
-
url?: string;
|
|
48
|
-
/** Error details if status is 'error' or 'unreachable' */
|
|
49
|
-
error?: {
|
|
50
|
-
message: string;
|
|
51
|
-
type?: string;
|
|
52
|
-
code?: string;
|
|
53
|
-
param?: string;
|
|
54
|
-
};
|
|
55
|
-
}
|
|
56
|
-
|
|
57
|
-
//-----------------------------------------------------------------------------------
|
|
58
|
-
// ERROR TYPES (Thrown by extension)
|
|
59
|
-
//-----------------------------------------------------------------------------------
|
|
60
|
-
|
|
61
|
-
/**
|
|
62
|
-
* API error thrown when server returns HTTP 4xx/5xx
|
|
63
|
-
* Used for streaming responses (non-streaming returns ApiResponse)
|
|
64
|
-
*/
|
|
65
|
-
export interface ApiError extends Error {
|
|
66
|
-
response: {
|
|
67
|
-
status: number;
|
|
68
|
-
body: OpenAiApiError;
|
|
69
|
-
headers?: Record<string, string>;
|
|
70
|
-
};
|
|
71
|
-
}
|
|
72
|
-
|
|
73
|
-
/**
|
|
74
|
-
* Operation error thrown when HTTP request couldn't complete
|
|
75
|
-
* (network unreachable, timeout, extension error)
|
|
76
|
-
*/
|
|
77
|
-
export interface OperationError extends Error {
|
|
78
|
-
error: {
|
|
79
|
-
message: string;
|
|
80
|
-
type: string; // Relaxed: any string allowed for custom error types
|
|
81
|
-
};
|
|
82
|
-
}
|
|
83
|
-
|
|
84
|
-
/**
|
|
85
|
-
* Union of all extension-thrown errors
|
|
86
|
-
*/
|
|
87
|
-
export type ExtensionError = ApiError | OperationError;
|
|
88
|
-
|
|
89
|
-
/**
|
|
90
|
-
* Type guard: API error (has response field)
|
|
91
|
-
*/
|
|
92
|
-
export function isApiError(err: unknown): err is ApiError {
|
|
93
|
-
return (
|
|
94
|
-
err instanceof Error &&
|
|
95
|
-
'response' in err &&
|
|
96
|
-
typeof (err as ApiError).response === 'object' &&
|
|
97
|
-
(err as ApiError).response !== null &&
|
|
98
|
-
typeof (err as ApiError).response.status === 'number' &&
|
|
99
|
-
'body' in (err as ApiError).response
|
|
100
|
-
);
|
|
101
|
-
}
|
|
102
|
-
|
|
103
|
-
/**
|
|
104
|
-
* Type guard: Operation error (has error field, no response)
|
|
105
|
-
*/
|
|
106
|
-
export function isOperationError(err: unknown): err is OperationError {
|
|
107
|
-
return err instanceof Error && 'error' in err && !('response' in err) && isOperationErrorStructure((err as OperationError).error);
|
|
108
|
-
}
|
|
109
|
-
|
|
110
|
-
//-----------------------------------------------------------------------------------
|
|
111
|
-
// CHAT API TYPES (OpenAI-compatible from @bodhiapp/ts-client)
|
|
112
|
-
//-----------------------------------------------------------------------------------
|
|
113
|
-
|
|
114
|
-
/**
|
|
115
|
-
* Chat API uses types from @bodhiapp/ts-client.
|
|
116
|
-
* Consumers should import these types directly from @bodhiapp/ts-client:
|
|
117
|
-
* - ChatCompletionRequestMessage
|
|
118
|
-
* - ChatCompletionResponseMessage
|
|
119
|
-
* - CreateChatCompletionRequest
|
|
120
|
-
* - CreateChatCompletionResponse
|
|
121
|
-
* - CreateChatCompletionStreamResponse
|
|
122
|
-
* - ChatChoice
|
|
123
|
-
* - ChatChoiceStream
|
|
124
|
-
* - ChatCompletionStreamResponseDelta
|
|
125
|
-
*/
|
|
126
|
-
|
|
127
|
-
/**
|
|
128
|
-
* Chat completions API interface
|
|
129
|
-
*/
|
|
130
|
-
export interface ChatCompletionsApi {
|
|
131
|
-
/**
|
|
132
|
-
* Create a chat completion
|
|
133
|
-
*
|
|
134
|
-
* Non-streaming: Returns ApiResponse - caller checks status for success/error
|
|
135
|
-
* Streaming: Yields chunks via AsyncIterable - throws ApiError or OperationError on error
|
|
136
|
-
*
|
|
137
|
-
* @param params - Chat completion parameters
|
|
138
|
-
* @returns Non-streaming: Promise<ApiResponse<CreateChatCompletionResponse>>, Streaming: AsyncIterable<CreateChatCompletionStreamResponse>
|
|
139
|
-
*/
|
|
140
|
-
create(params: CreateChatCompletionRequest & { stream?: false }): Promise<ApiResponse<CreateChatCompletionResponse>>;
|
|
141
|
-
create(params: CreateChatCompletionRequest & { stream: true }): AsyncIterable<CreateChatCompletionStreamResponse>;
|
|
142
|
-
create(params: CreateChatCompletionRequest): Promise<ApiResponse<CreateChatCompletionResponse>> | AsyncIterable<CreateChatCompletionStreamResponse>;
|
|
143
|
-
}
|
|
144
|
-
|
|
145
|
-
/**
|
|
146
|
-
* Chat API namespace
|
|
147
|
-
*/
|
|
148
|
-
export interface ChatApi {
|
|
149
|
-
completions: ChatCompletionsApi;
|
|
150
|
-
}
|
|
151
|
-
|
|
152
|
-
//-----------------------------------------------------------------------------------
|
|
153
|
-
// PUBLIC API INTERFACE
|
|
154
|
-
//-----------------------------------------------------------------------------------
|
|
155
|
-
|
|
156
|
-
/**
|
|
157
|
-
* Public window.bodhiext interface
|
|
158
|
-
*
|
|
159
|
-
* This interface defines all methods available to web pages through window.bodhiext.
|
|
160
|
-
* The extension creates this interface in inject.ts and attaches it to the window object.
|
|
161
|
-
*/
|
|
162
|
-
export interface BodhiExtPublicApi {
|
|
163
|
-
/**
|
|
164
|
-
* Send a generic API request through the extension to the backend server.
|
|
165
|
-
*
|
|
166
|
-
* @template TReq - Request body type (inferred from body parameter)
|
|
167
|
-
* @template TRes - Response body type (must be specified explicitly)
|
|
168
|
-
* @param method - HTTP method (GET, POST, PUT, DELETE, etc.)
|
|
169
|
-
* @param endpoint - API endpoint path (e.g., '/v1/chat/completions')
|
|
170
|
-
* @param body - Optional request body (will be JSON stringified)
|
|
171
|
-
* @param headers - Optional additional headers
|
|
172
|
-
* @returns Promise resolving to ApiResponse with body, headers, and status
|
|
173
|
-
*/
|
|
174
|
-
sendApiRequest<TReq = unknown, TRes = unknown>(method: string, endpoint: string, body?: TReq, headers?: Record<string, string>): Promise<ApiResponse<TRes>>;
|
|
175
|
-
|
|
176
|
-
/**
|
|
177
|
-
* Send a streaming API request through the extension.
|
|
178
|
-
*
|
|
179
|
-
* Used for SSE (Server-Sent Events) endpoints like streaming chat completions.
|
|
180
|
-
* Returns a ReadableStream that yields StreamChunk objects.
|
|
181
|
-
*
|
|
182
|
-
* @template TReq - Request body type (inferred from body parameter)
|
|
183
|
-
* @param method - HTTP method (typically POST for streaming)
|
|
184
|
-
* @param endpoint - API endpoint path (e.g., '/v1/chat/completions')
|
|
185
|
-
* @param body - Optional request body
|
|
186
|
-
* @param headers - Optional additional headers
|
|
187
|
-
* @returns ReadableStream yielding StreamChunk objects
|
|
188
|
-
*/
|
|
189
|
-
sendStreamRequest<TReq = unknown>(method: string, endpoint: string, body?: TReq, headers?: Record<string, string>): ReadableStream<StreamChunk>;
|
|
190
|
-
|
|
191
|
-
/**
|
|
192
|
-
* Send a generic extension request.
|
|
193
|
-
*
|
|
194
|
-
* Used for extension-specific operations like test_connection, get_extension_id, etc.
|
|
195
|
-
* This is a low-level API for extension capabilities.
|
|
196
|
-
*
|
|
197
|
-
* @param action - Extension action name (e.g., 'test_connection')
|
|
198
|
-
* @param params - Optional action parameters
|
|
199
|
-
* @returns Promise resolving to action-specific response
|
|
200
|
-
*/
|
|
201
|
-
sendExtRequest(action: string, params?: any): Promise<any>;
|
|
202
|
-
|
|
203
|
-
/**
|
|
204
|
-
* Simple health check to verify extension connectivity.
|
|
205
|
-
*
|
|
206
|
-
* Returns ApiResponse - caller should check status to determine success/error.
|
|
207
|
-
* On success (2xx), body is PingResponse. On error (4xx/5xx), body is OpenAiApiError.
|
|
208
|
-
*
|
|
209
|
-
* @returns Promise resolving to ApiResponse<PingResponse>
|
|
210
|
-
*/
|
|
211
|
-
ping(): Promise<ApiResponse<PingResponse>>;
|
|
212
|
-
|
|
213
|
-
/**
|
|
214
|
-
* Get server state information from /bodhi/v1/info endpoint.
|
|
215
|
-
*
|
|
216
|
-
* Returns the current status of the backend server including
|
|
217
|
-
* whether it's in setup mode, ready, or has errors.
|
|
218
|
-
*
|
|
219
|
-
* @returns Promise resolving to ServerStateInfo
|
|
220
|
-
*/
|
|
221
|
-
serverState(): Promise<ServerStateInfo>;
|
|
222
|
-
|
|
223
|
-
/**
|
|
224
|
-
* OpenAI-compatible chat API.
|
|
225
|
-
*
|
|
226
|
-
* Provides chat completion functionality compatible with OpenAI's API structure.
|
|
227
|
-
*/
|
|
228
|
-
chat: ChatApi;
|
|
229
|
-
|
|
230
|
-
/**
|
|
231
|
-
* Get the extension ID.
|
|
232
|
-
*
|
|
233
|
-
* The extension ID is fetched asynchronously during initialization.
|
|
234
|
-
* This method returns a promise that resolves to the extension ID once available.
|
|
235
|
-
*
|
|
236
|
-
* @returns Promise resolving to the extension ID string
|
|
237
|
-
*/
|
|
238
|
-
getExtensionId(): Promise<string>;
|
|
239
|
-
}
|
|
240
|
-
|
|
241
|
-
//-----------------------------------------------------------------------------------
|
|
242
|
-
// WINDOW AUGMENTATION
|
|
243
|
-
//-----------------------------------------------------------------------------------
|
|
244
|
-
|
|
245
|
-
/**
|
|
246
|
-
* Window augmentation for TypeScript
|
|
247
|
-
*
|
|
248
|
-
* Declares the optional bodhiext property on the Window interface.
|
|
249
|
-
* This allows TypeScript code to access window.bodhiext with proper typing.
|
|
250
|
-
*/
|
|
251
|
-
declare global {
|
|
252
|
-
interface Window {
|
|
253
|
-
bodhiext?: BodhiExtPublicApi;
|
|
254
|
-
}
|
|
255
|
-
}
|
package/common.ts
DELETED
|
@@ -1,99 +0,0 @@
|
|
|
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
|
-
|
|
8
|
-
//-----------------------------------------------------------------------------------
|
|
9
|
-
// HTTP CONSTANTS
|
|
10
|
-
//-----------------------------------------------------------------------------------
|
|
11
|
-
|
|
12
|
-
export const CONTENT_TYPE_JSON = 'application/json';
|
|
13
|
-
export const CONTENT_TYPE_EVENT_STREAM = 'text/event-stream';
|
|
14
|
-
export const CONTENT_TYPE_HEADER = 'Content-Type';
|
|
15
|
-
export const HTTP_METHOD_GET = 'GET';
|
|
16
|
-
export const HTTP_METHOD_POST = 'POST';
|
|
17
|
-
|
|
18
|
-
//-----------------------------------------------------------------------------------
|
|
19
|
-
// API ENDPOINTS
|
|
20
|
-
//-----------------------------------------------------------------------------------
|
|
21
|
-
|
|
22
|
-
export const ENDPOINT_PING = '/ping';
|
|
23
|
-
export const ENDPOINT_CHAT_COMPLETIONS = '/v1/chat/completions';
|
|
24
|
-
|
|
25
|
-
//-----------------------------------------------------------------------------------
|
|
26
|
-
// DEFAULT VALUES
|
|
27
|
-
//-----------------------------------------------------------------------------------
|
|
28
|
-
|
|
29
|
-
export const DEFAULT_API_BASE_URL = 'http://localhost:1135';
|
|
30
|
-
export const DEFAULT_API_TIMEOUT = 10000; // 10 seconds for API requests
|
|
31
|
-
export const DEFAULT_STREAM_TIMEOUT = 60000; // 60 seconds for streaming
|
|
32
|
-
|
|
33
|
-
//-----------------------------------------------------------------------------------
|
|
34
|
-
// STORAGE
|
|
35
|
-
//-----------------------------------------------------------------------------------
|
|
36
|
-
|
|
37
|
-
export const STORAGE_KEY_BACKEND_URL = 'backendUrl';
|
|
38
|
-
|
|
39
|
-
//-----------------------------------------------------------------------------------
|
|
40
|
-
// SSE (Server-Sent Events)
|
|
41
|
-
//-----------------------------------------------------------------------------------
|
|
42
|
-
|
|
43
|
-
export const SSE_DONE_MARKER = '[DONE]';
|
|
44
|
-
export const SSE_DATA_PREFIX = 'data: ';
|
|
45
|
-
export const SSE_CHUNK_DELIMITER = '\n\n';
|
|
46
|
-
|
|
47
|
-
//-----------------------------------------------------------------------------------
|
|
48
|
-
// EXTENSION ACTIONS
|
|
49
|
-
//-----------------------------------------------------------------------------------
|
|
50
|
-
|
|
51
|
-
export const EXT_ACTIONS = {
|
|
52
|
-
GET_EXTENSION_ID: 'get_extension_id',
|
|
53
|
-
TEST_CONNECTION: 'test_connection',
|
|
54
|
-
} as const;
|
|
55
|
-
|
|
56
|
-
//-----------------------------------------------------------------------------------
|
|
57
|
-
// ERROR TYPES
|
|
58
|
-
//-----------------------------------------------------------------------------------
|
|
59
|
-
|
|
60
|
-
export const ERROR_TYPES = {
|
|
61
|
-
NETWORK_ERROR: 'network_error',
|
|
62
|
-
EXTENSION_ERROR: 'extension_error',
|
|
63
|
-
TIMEOUT_ERROR: 'timeout_error',
|
|
64
|
-
AUTH_ERROR: 'auth_error',
|
|
65
|
-
} as const;
|
|
66
|
-
|
|
67
|
-
// Type union for connection error types
|
|
68
|
-
export type ConnectionErrorType = (typeof ERROR_TYPES)[keyof typeof ERROR_TYPES];
|
|
69
|
-
|
|
70
|
-
//-----------------------------------------------------------------------------------
|
|
71
|
-
// DOCUMENT STATES
|
|
72
|
-
//-----------------------------------------------------------------------------------
|
|
73
|
-
|
|
74
|
-
export const DOCUMENT_STATE_COMPLETE = 'complete';
|
|
75
|
-
|
|
76
|
-
//-----------------------------------------------------------------------------------
|
|
77
|
-
// EVENT NAMES
|
|
78
|
-
//-----------------------------------------------------------------------------------
|
|
79
|
-
|
|
80
|
-
export const EVENT_INITIALIZED = 'bodhiext:initialized';
|
|
81
|
-
|
|
82
|
-
//-----------------------------------------------------------------------------------
|
|
83
|
-
// PORT NAMES
|
|
84
|
-
//-----------------------------------------------------------------------------------
|
|
85
|
-
|
|
86
|
-
export const BODHI_STREAM_PORT = 'BODHI_STREAM_PORT';
|
|
87
|
-
|
|
88
|
-
//-----------------------------------------------------------------------------------
|
|
89
|
-
// FALLBACKS
|
|
90
|
-
//-----------------------------------------------------------------------------------
|
|
91
|
-
|
|
92
|
-
export const ORIGIN_WILDCARD = '*';
|
|
93
|
-
|
|
94
|
-
//-----------------------------------------------------------------------------------
|
|
95
|
-
// ERROR MESSAGES
|
|
96
|
-
//-----------------------------------------------------------------------------------
|
|
97
|
-
|
|
98
|
-
export const ERROR_MISSING_REQUEST_ID = 'Invalid message format: missing requestId or request';
|
|
99
|
-
export const ERROR_CONNECTION_CLOSED = 'Connection closed unexpectedly';
|
package/index.ts
DELETED
|
@@ -1,88 +0,0 @@
|
|
|
1
|
-
// Bodhi Browser Extension - Shared Types and Constants
|
|
2
|
-
// This package provides the shared protocol definitions for communication
|
|
3
|
-
// between web pages, external extensions, and bodhi-browser-ext
|
|
4
|
-
//
|
|
5
|
-
// NOTE: OpenAI types (CreateChatCompletionRequest, PingResponse, etc.)
|
|
6
|
-
// are NOT re-exported. Import them directly from '@bodhiapp/ts-client' when needed.
|
|
7
|
-
|
|
8
|
-
//-----------------------------------------------------------------------------------
|
|
9
|
-
// PUBLIC API TYPES (window.bodhiext)
|
|
10
|
-
//-----------------------------------------------------------------------------------
|
|
11
|
-
|
|
12
|
-
export type { ApiResponse, StreamChunk, ServerStateInfo, ApiError, OperationError, ExtensionError, ChatCompletionsApi, ChatApi, BodhiExtPublicApi } from './bodhiext';
|
|
13
|
-
|
|
14
|
-
export { isApiError, isOperationError } from './bodhiext';
|
|
15
|
-
|
|
16
|
-
//-----------------------------------------------------------------------------------
|
|
17
|
-
// INTERNAL PROTOCOL TYPES
|
|
18
|
-
//-----------------------------------------------------------------------------------
|
|
19
|
-
|
|
20
|
-
export type {
|
|
21
|
-
ApiRequest,
|
|
22
|
-
ApiRequestMessage,
|
|
23
|
-
OperationErrorResponse,
|
|
24
|
-
ApiResponseSuccessMessage,
|
|
25
|
-
OperationErrorResponseMessage,
|
|
26
|
-
ApiResponseMessage,
|
|
27
|
-
ErrorMessage,
|
|
28
|
-
StreamChunkMessage,
|
|
29
|
-
StreamApiErrorMessage,
|
|
30
|
-
StreamErrorMessage,
|
|
31
|
-
StreamMessage,
|
|
32
|
-
StreamController,
|
|
33
|
-
SSEChunk,
|
|
34
|
-
ExtRequest,
|
|
35
|
-
ExtRequestMessage,
|
|
36
|
-
ExtError,
|
|
37
|
-
ExtErrorResponse,
|
|
38
|
-
ExtResponse,
|
|
39
|
-
ExtResponseMessage,
|
|
40
|
-
GetExtensionIdRequest,
|
|
41
|
-
GetExtensionIdResponse,
|
|
42
|
-
TestConnectionRequest,
|
|
43
|
-
TestConnectionResponse,
|
|
44
|
-
} from './protocol';
|
|
45
|
-
|
|
46
|
-
export {
|
|
47
|
-
MESSAGE_TYPES,
|
|
48
|
-
isOperationErrorResponse,
|
|
49
|
-
isApiErrorResponse,
|
|
50
|
-
isApiSuccessResponse,
|
|
51
|
-
isStreamChunk,
|
|
52
|
-
isStreamApiError,
|
|
53
|
-
isStreamError,
|
|
54
|
-
isExtError,
|
|
55
|
-
isOpenAiApiErrorBody,
|
|
56
|
-
isOperationErrorStructure,
|
|
57
|
-
} from './protocol';
|
|
58
|
-
|
|
59
|
-
//-----------------------------------------------------------------------------------
|
|
60
|
-
// COMMON CONSTANTS
|
|
61
|
-
//-----------------------------------------------------------------------------------
|
|
62
|
-
|
|
63
|
-
export {
|
|
64
|
-
CONTENT_TYPE_JSON,
|
|
65
|
-
CONTENT_TYPE_EVENT_STREAM,
|
|
66
|
-
CONTENT_TYPE_HEADER,
|
|
67
|
-
HTTP_METHOD_GET,
|
|
68
|
-
HTTP_METHOD_POST,
|
|
69
|
-
ENDPOINT_PING,
|
|
70
|
-
ENDPOINT_CHAT_COMPLETIONS,
|
|
71
|
-
DEFAULT_API_BASE_URL,
|
|
72
|
-
DEFAULT_API_TIMEOUT,
|
|
73
|
-
DEFAULT_STREAM_TIMEOUT,
|
|
74
|
-
STORAGE_KEY_BACKEND_URL,
|
|
75
|
-
SSE_DONE_MARKER,
|
|
76
|
-
SSE_DATA_PREFIX,
|
|
77
|
-
SSE_CHUNK_DELIMITER,
|
|
78
|
-
EXT_ACTIONS,
|
|
79
|
-
ERROR_TYPES,
|
|
80
|
-
DOCUMENT_STATE_COMPLETE,
|
|
81
|
-
EVENT_INITIALIZED,
|
|
82
|
-
BODHI_STREAM_PORT,
|
|
83
|
-
ORIGIN_WILDCARD,
|
|
84
|
-
ERROR_MISSING_REQUEST_ID,
|
|
85
|
-
ERROR_CONNECTION_CLOSED,
|
|
86
|
-
} from './common';
|
|
87
|
-
|
|
88
|
-
export type { ConnectionErrorType } from './common';
|
package/protocol.ts
DELETED
|
@@ -1,315 +0,0 @@
|
|
|
1
|
-
/**
|
|
2
|
-
* Internal extension protocol types
|
|
3
|
-
*
|
|
4
|
-
* Message passing types and constants for communication between
|
|
5
|
-
* inject.ts, content.ts, and background.ts (service worker).
|
|
6
|
-
* Used primarily by background/*, content.ts files.
|
|
7
|
-
*/
|
|
8
|
-
|
|
9
|
-
import type { OpenAiApiError, ErrorBody } from '@bodhiapp/ts-client';
|
|
10
|
-
import type { ApiResponse, ServerStateInfo } from './bodhiext';
|
|
11
|
-
|
|
12
|
-
//-----------------------------------------------------------------------------------
|
|
13
|
-
// VALIDATION HELPERS
|
|
14
|
-
//-----------------------------------------------------------------------------------
|
|
15
|
-
|
|
16
|
-
/**
|
|
17
|
-
* Private helper: Check if value is non-null object
|
|
18
|
-
* Not exported - implementation detail for other helpers
|
|
19
|
-
*/
|
|
20
|
-
function isNonNullObject(value: unknown): value is Record<string, unknown> {
|
|
21
|
-
return value !== null && typeof value === 'object';
|
|
22
|
-
}
|
|
23
|
-
|
|
24
|
-
/**
|
|
25
|
-
* Validate OpenAI API error body structure
|
|
26
|
-
* { error: { message: string, type: string } }
|
|
27
|
-
*/
|
|
28
|
-
export function isOpenAiApiErrorBody(body: unknown): body is OpenAiApiError {
|
|
29
|
-
return (
|
|
30
|
-
isNonNullObject(body) &&
|
|
31
|
-
'error' in body &&
|
|
32
|
-
isNonNullObject(body.error) &&
|
|
33
|
-
'message' in body.error &&
|
|
34
|
-
typeof body.error.message === 'string' &&
|
|
35
|
-
'type' in body.error &&
|
|
36
|
-
typeof body.error.type === 'string'
|
|
37
|
-
);
|
|
38
|
-
}
|
|
39
|
-
|
|
40
|
-
/**
|
|
41
|
-
* Validate OperationErrorResponse structure
|
|
42
|
-
* { message: string, type: string }
|
|
43
|
-
*/
|
|
44
|
-
export function isOperationErrorStructure(obj: unknown): obj is OperationErrorResponse {
|
|
45
|
-
return isNonNullObject(obj) && 'message' in obj && typeof obj.message === 'string' && 'type' in obj && typeof obj.type === 'string';
|
|
46
|
-
}
|
|
47
|
-
|
|
48
|
-
//-----------------------------------------------------------------------------------
|
|
49
|
-
// MESSAGE TYPE CONSTANTS
|
|
50
|
-
//-----------------------------------------------------------------------------------
|
|
51
|
-
|
|
52
|
-
export const MESSAGE_TYPES = {
|
|
53
|
-
API_REQUEST: 'BODHI_API_REQUEST',
|
|
54
|
-
API_RESPONSE: 'BODHI_API_RESPONSE',
|
|
55
|
-
STREAM_REQUEST: 'BODHI_STREAM_REQUEST',
|
|
56
|
-
STREAM_CHUNK: 'BODHI_STREAM_CHUNK',
|
|
57
|
-
STREAM_ERROR: 'BODHI_STREAM_ERROR',
|
|
58
|
-
STREAM_API_ERROR: 'BODHI_STREAM_API_ERROR',
|
|
59
|
-
ERROR: 'BODHI_ERROR',
|
|
60
|
-
EXT_REQUEST: 'BODHI_EXT_REQUEST',
|
|
61
|
-
EXT_RESPONSE: 'BODHI_EXT_RESPONSE',
|
|
62
|
-
} as const;
|
|
63
|
-
|
|
64
|
-
//-----------------------------------------------------------------------------------
|
|
65
|
-
// API REQUEST/RESPONSE TYPES
|
|
66
|
-
//-----------------------------------------------------------------------------------
|
|
67
|
-
|
|
68
|
-
export interface ApiRequest<T = unknown> {
|
|
69
|
-
method: string;
|
|
70
|
-
endpoint: string;
|
|
71
|
-
body?: T;
|
|
72
|
-
headers?: Record<string, string>;
|
|
73
|
-
}
|
|
74
|
-
|
|
75
|
-
export interface ApiRequestMessage<TReq = unknown> {
|
|
76
|
-
type: string;
|
|
77
|
-
requestId: string;
|
|
78
|
-
request: ApiRequest<TReq>;
|
|
79
|
-
}
|
|
80
|
-
|
|
81
|
-
/**
|
|
82
|
-
* Operation-level error response (network unreachable, timeout, extension error)
|
|
83
|
-
* NOT an API error (those come through ApiResponse with OpenAiApiError body)
|
|
84
|
-
* This is a response type, not a thrown error
|
|
85
|
-
*/
|
|
86
|
-
export interface OperationErrorResponse {
|
|
87
|
-
message: string;
|
|
88
|
-
type: string; // Relaxed: any string allowed for custom error types
|
|
89
|
-
}
|
|
90
|
-
|
|
91
|
-
/**
|
|
92
|
-
* Success API response message (HTTP request completed, regardless of status code)
|
|
93
|
-
*/
|
|
94
|
-
export interface ApiResponseSuccessMessage<T = unknown> {
|
|
95
|
-
type: string;
|
|
96
|
-
requestId: string;
|
|
97
|
-
response: ApiResponse<T>;
|
|
98
|
-
}
|
|
99
|
-
|
|
100
|
-
/**
|
|
101
|
-
* Operation error response message - HTTP request couldn't complete
|
|
102
|
-
*/
|
|
103
|
-
export interface OperationErrorResponseMessage {
|
|
104
|
-
type: string;
|
|
105
|
-
requestId: string;
|
|
106
|
-
error: OperationErrorResponse;
|
|
107
|
-
}
|
|
108
|
-
|
|
109
|
-
/**
|
|
110
|
-
* API response message - discriminated union
|
|
111
|
-
*/
|
|
112
|
-
export type ApiResponseMessage<T = unknown> = ApiResponseSuccessMessage<T> | OperationErrorResponseMessage;
|
|
113
|
-
|
|
114
|
-
/**
|
|
115
|
-
* Type guard for operation error response
|
|
116
|
-
*/
|
|
117
|
-
export function isOperationErrorResponse(msg: ApiResponseMessage): msg is OperationErrorResponseMessage {
|
|
118
|
-
return isNonNullObject(msg) && 'error' in msg && isOperationErrorStructure(msg.error);
|
|
119
|
-
}
|
|
120
|
-
|
|
121
|
-
/**
|
|
122
|
-
* Type guard to check if response is an API error (4xx/5xx)
|
|
123
|
-
* Narrows body type to OpenAiApiError
|
|
124
|
-
*/
|
|
125
|
-
export function isApiErrorResponse<T>(response: ApiResponse<T>): response is ApiResponse<T> & { body: OpenAiApiError; status: number } {
|
|
126
|
-
return isNonNullObject(response) && typeof response.status === 'number' && response.status >= 400 && isOpenAiApiErrorBody(response.body);
|
|
127
|
-
}
|
|
128
|
-
|
|
129
|
-
/**
|
|
130
|
-
* Type guard to check if response is successful (2xx)
|
|
131
|
-
* Narrows body type to T
|
|
132
|
-
*/
|
|
133
|
-
export function isApiSuccessResponse<T>(response: ApiResponse<T>): response is ApiResponse<T> & { body: T; status: number } {
|
|
134
|
-
return response !== null && typeof response === 'object' && typeof response.status === 'number' && response.status >= 200 && response.status < 300 && 'body' in response;
|
|
135
|
-
}
|
|
136
|
-
|
|
137
|
-
export interface ErrorMessage {
|
|
138
|
-
type: string;
|
|
139
|
-
requestId: string;
|
|
140
|
-
response: {
|
|
141
|
-
body: ErrorBody;
|
|
142
|
-
status: number;
|
|
143
|
-
headers: Record<string, string>;
|
|
144
|
-
};
|
|
145
|
-
}
|
|
146
|
-
|
|
147
|
-
//-----------------------------------------------------------------------------------
|
|
148
|
-
// STREAMING MESSAGE TYPES (Discriminated Union)
|
|
149
|
-
//-----------------------------------------------------------------------------------
|
|
150
|
-
|
|
151
|
-
/**
|
|
152
|
-
* Stream chunk message - successful SSE chunk received
|
|
153
|
-
* Uses ApiResponse<T> wrapper for consistency with non-streaming pattern
|
|
154
|
-
*/
|
|
155
|
-
export interface StreamChunkMessage<T = unknown> {
|
|
156
|
-
type: typeof MESSAGE_TYPES.STREAM_CHUNK;
|
|
157
|
-
requestId: string;
|
|
158
|
-
response: ApiResponse<T>;
|
|
159
|
-
}
|
|
160
|
-
|
|
161
|
-
/**
|
|
162
|
-
* Stream API error message - server returned error response (not SSE)
|
|
163
|
-
* E.g., 400/401/500 JSON error instead of SSE stream
|
|
164
|
-
*/
|
|
165
|
-
export interface StreamApiErrorMessage {
|
|
166
|
-
type: typeof MESSAGE_TYPES.STREAM_API_ERROR;
|
|
167
|
-
requestId: string;
|
|
168
|
-
response: ApiResponse<OpenAiApiError>;
|
|
169
|
-
}
|
|
170
|
-
|
|
171
|
-
/**
|
|
172
|
-
* Stream error message - network/extension level error
|
|
173
|
-
* E.g., connection refused, timeout, extension error
|
|
174
|
-
*/
|
|
175
|
-
export interface StreamErrorMessage {
|
|
176
|
-
type: typeof MESSAGE_TYPES.STREAM_ERROR;
|
|
177
|
-
requestId: string;
|
|
178
|
-
error: OperationErrorResponse;
|
|
179
|
-
}
|
|
180
|
-
|
|
181
|
-
/**
|
|
182
|
-
* Union type for all streaming messages
|
|
183
|
-
*/
|
|
184
|
-
export type StreamMessage<T = unknown> = StreamChunkMessage<T> | StreamApiErrorMessage | StreamErrorMessage;
|
|
185
|
-
|
|
186
|
-
/**
|
|
187
|
-
* Type guard for stream chunk message
|
|
188
|
-
*/
|
|
189
|
-
export function isStreamChunk<T>(msg: StreamMessage<T>): msg is StreamChunkMessage<T> {
|
|
190
|
-
return msg !== null && typeof msg === 'object' && msg.type === MESSAGE_TYPES.STREAM_CHUNK;
|
|
191
|
-
}
|
|
192
|
-
|
|
193
|
-
/**
|
|
194
|
-
* Type guard for stream API error
|
|
195
|
-
*/
|
|
196
|
-
export function isStreamApiError(msg: StreamMessage): msg is StreamApiErrorMessage {
|
|
197
|
-
return msg !== null && typeof msg === 'object' && msg.type === MESSAGE_TYPES.STREAM_API_ERROR;
|
|
198
|
-
}
|
|
199
|
-
|
|
200
|
-
/**
|
|
201
|
-
* Type guard for stream error
|
|
202
|
-
*/
|
|
203
|
-
export function isStreamError(msg: StreamMessage): msg is StreamErrorMessage {
|
|
204
|
-
return msg !== null && typeof msg === 'object' && msg.type === MESSAGE_TYPES.STREAM_ERROR;
|
|
205
|
-
}
|
|
206
|
-
|
|
207
|
-
/**
|
|
208
|
-
* Interface for stream controller to handle SSE responses
|
|
209
|
-
*/
|
|
210
|
-
export interface StreamController {
|
|
211
|
-
enqueue: (chunk: any) => void;
|
|
212
|
-
error: (err: Error) => void;
|
|
213
|
-
complete: () => void;
|
|
214
|
-
}
|
|
215
|
-
|
|
216
|
-
/**
|
|
217
|
-
* Interface for SSE data chunk
|
|
218
|
-
*/
|
|
219
|
-
export interface SSEChunk {
|
|
220
|
-
done?: boolean;
|
|
221
|
-
[key: string]: any;
|
|
222
|
-
}
|
|
223
|
-
|
|
224
|
-
//-----------------------------------------------------------------------------------
|
|
225
|
-
// GENERIC EXTENSION REQUEST/RESPONSE TYPES
|
|
226
|
-
//-----------------------------------------------------------------------------------
|
|
227
|
-
|
|
228
|
-
/**
|
|
229
|
-
* Generic extension request interface
|
|
230
|
-
*/
|
|
231
|
-
export interface ExtRequest {
|
|
232
|
-
action: string;
|
|
233
|
-
params?: any;
|
|
234
|
-
}
|
|
235
|
-
|
|
236
|
-
/**
|
|
237
|
-
* Generic extension request message
|
|
238
|
-
*/
|
|
239
|
-
export interface ExtRequestMessage {
|
|
240
|
-
type: 'BODHI_EXT_REQUEST';
|
|
241
|
-
requestId: string;
|
|
242
|
-
request: ExtRequest;
|
|
243
|
-
}
|
|
244
|
-
|
|
245
|
-
/**
|
|
246
|
-
* Extension-level error structure
|
|
247
|
-
*/
|
|
248
|
-
export interface ExtError {
|
|
249
|
-
message: string;
|
|
250
|
-
type?: string;
|
|
251
|
-
}
|
|
252
|
-
|
|
253
|
-
/**
|
|
254
|
-
* Error response for extension operations
|
|
255
|
-
*/
|
|
256
|
-
export interface ExtErrorResponse {
|
|
257
|
-
error: ExtError;
|
|
258
|
-
}
|
|
259
|
-
|
|
260
|
-
/**
|
|
261
|
-
* Union type for extension response (flattened - no wrapper for success)
|
|
262
|
-
* Success: T (the actual response data)
|
|
263
|
-
* Error: { error: ExtError }
|
|
264
|
-
*/
|
|
265
|
-
export type ExtResponse<T = unknown> = T | ExtErrorResponse;
|
|
266
|
-
|
|
267
|
-
/**
|
|
268
|
-
* Type guard to check if extension response is an error
|
|
269
|
-
*/
|
|
270
|
-
export function isExtError<T>(res: ExtResponse<T>): res is ExtErrorResponse {
|
|
271
|
-
return res !== null && typeof res === 'object' && 'error' in res;
|
|
272
|
-
}
|
|
273
|
-
|
|
274
|
-
/**
|
|
275
|
-
* Generic extension response message
|
|
276
|
-
*/
|
|
277
|
-
export interface ExtResponseMessage<T = unknown> {
|
|
278
|
-
type: 'BODHI_EXT_RESPONSE';
|
|
279
|
-
requestId: string;
|
|
280
|
-
response: ExtResponse<T>;
|
|
281
|
-
}
|
|
282
|
-
|
|
283
|
-
//-----------------------------------------------------------------------------------
|
|
284
|
-
// ACTION-SPECIFIC TYPES
|
|
285
|
-
//-----------------------------------------------------------------------------------
|
|
286
|
-
|
|
287
|
-
/**
|
|
288
|
-
* Get Extension ID request (no params needed)
|
|
289
|
-
*/
|
|
290
|
-
export interface GetExtensionIdRequest extends ExtRequest {
|
|
291
|
-
action: 'get_extension_id';
|
|
292
|
-
params?: undefined;
|
|
293
|
-
}
|
|
294
|
-
|
|
295
|
-
/**
|
|
296
|
-
* Get Extension ID response body
|
|
297
|
-
*/
|
|
298
|
-
export interface GetExtensionIdResponse {
|
|
299
|
-
extension_id: string;
|
|
300
|
-
}
|
|
301
|
-
|
|
302
|
-
/**
|
|
303
|
-
* Test Connection request
|
|
304
|
-
*/
|
|
305
|
-
export interface TestConnectionRequest extends ExtRequest {
|
|
306
|
-
action: 'test_connection';
|
|
307
|
-
params: {
|
|
308
|
-
url: string;
|
|
309
|
-
};
|
|
310
|
-
}
|
|
311
|
-
|
|
312
|
-
/**
|
|
313
|
-
* Test Connection response body (reuses ServerStateInfo)
|
|
314
|
-
*/
|
|
315
|
-
export type TestConnectionResponse = ServerStateInfo;
|