fix: removed duplicated type declarations

This commit is contained in:
2026-02-15 21:56:45 +01:00
parent 870031f1a0
commit 6784ab3f36
5 changed files with 542 additions and 642 deletions

View File

@@ -1,8 +1,9 @@
import { contextBridge, ipcRenderer } from 'electron';
import type { ElectronAPI } from './shared/electronApi';
// Expose protected methods that allow the renderer process to use
// ipcRenderer without exposing the entire object
contextBridge.exposeInMainWorld('electronAPI', {
export const electronAPI: ElectronAPI = {
// Projects
projects: {
create: (data: { name: string; description?: string; slug?: string; dataPath?: string }) => ipcRenderer.invoke('projects:create', data),
@@ -82,6 +83,17 @@ contextBridge.exposeInMainWorld('electronAPI', {
rebuild: () => ipcRenderer.invoke('postMedia:rebuild'),
},
// Sync
sync: {
configure: (config: unknown) => ipcRenderer.invoke('sync:configure', config),
start: (direction?: 'push' | 'pull' | 'bidirectional') => ipcRenderer.invoke('sync:start', direction),
getStatus: () => ipcRenderer.invoke('sync:getStatus'),
isConfigured: () => ipcRenderer.invoke('sync:isConfigured'),
getPendingCount: () => ipcRenderer.invoke('sync:getPendingCount'),
getLog: (limit?: number) => ipcRenderer.invoke('sync:getLog', limit),
stopAutoSync: () => ipcRenderer.invoke('sync:stopAutoSync'),
},
// Tasks
tasks: {
getAll: () => ipcRenderer.invoke('tasks:getAll'),
@@ -242,8 +254,8 @@ contextBridge.exposeInMainWorld('electronAPI', {
ipcRenderer.on('chat-stream-delta', subscription);
return () => ipcRenderer.removeListener('chat-stream-delta', subscription);
},
onToolCall: (callback: (data: { conversationId: string; toolCall: unknown }) => void) => {
const subscription = (_event: Electron.IpcRendererEvent, data: { conversationId: string; toolCall: unknown }) => callback(data);
onToolCall: (callback: (data: { conversationId: string; toolCall: { name: string; arguments: Record<string, unknown> } }) => void) => {
const subscription = (_event: Electron.IpcRendererEvent, data: { conversationId: string; toolCall: { name: string; arguments: Record<string, unknown> } }) => callback(data);
ipcRenderer.on('chat-tool-call', subscription);
return () => ipcRenderer.removeListener('chat-tool-call', subscription);
},
@@ -269,192 +281,6 @@ contextBridge.exposeInMainWorld('electronAPI', {
once: (channel: string, callback: (...args: unknown[]) => void) => {
ipcRenderer.once(channel, (_event, ...args) => callback(...args));
},
});
};
// Type definitions for the exposed API
export interface ElectronAPI {
projects: {
create: (data: { name: string; description?: string; slug?: string; dataPath?: string }) => Promise<unknown>;
update: (id: string, data: unknown) => Promise<unknown>;
delete: (id: string) => Promise<boolean>;
get: (id: string) => Promise<unknown>;
getAll: () => Promise<unknown[]>;
getActive: () => Promise<unknown>;
setActive: (id: string) => Promise<unknown>;
};
posts: {
create: (data: unknown) => Promise<unknown>;
update: (id: string, data: unknown) => Promise<unknown>;
delete: (id: string) => Promise<boolean>;
get: (id: string) => Promise<unknown>;
getAll: () => Promise<unknown[]>;
getByStatus: (status: string) => Promise<unknown[]>;
publish: (id: string) => Promise<unknown>;
unpublish: (id: string) => Promise<unknown>;
rebuildFromFiles: () => Promise<void>;
search: (query: string) => Promise<unknown[]>;
filter: (filter: unknown) => Promise<unknown[]>;
getTags: () => Promise<string[]>;
getCategories: () => Promise<string[]>;
getByYearMonth: () => Promise<{ year: number; month: number; count: number }[]>;
getTagsWithCounts: () => Promise<{ tag: string; count: number }[]>;
getCategoriesWithCounts: () => Promise<{ category: string; count: number }[]>;
getDashboardStats: () => Promise<{ totalPosts: number; draftCount: number; publishedCount: number; archivedCount: number }>;
getLinksTo: (id: string) => Promise<{ id: string; title: string; slug: string }[]>;
getLinkedBy: (id: string) => Promise<{ id: string; title: string; slug: string }[]>;
rebuildLinks: () => Promise<void>;
};
media: {
import: (sourcePath: string, metadata?: unknown) => Promise<unknown>;
importDialog: () => Promise<unknown[]>;
update: (id: string, data: unknown) => Promise<unknown>;
delete: (id: string) => Promise<boolean>;
get: (id: string) => Promise<unknown>;
getAll: () => Promise<unknown[]>;
rebuildFromFiles: () => Promise<void>;
};
dropbox: {
configure: (config: unknown) => Promise<void>;
isConfigured: () => Promise<boolean>;
getStatus: () => Promise<string>;
syncAll: () => Promise<unknown>;
startWatching: () => Promise<void>;
stopWatching: () => Promise<void>;
startPolling: () => Promise<void>;
stopPolling: () => Promise<void>;
getConflicts: () => Promise<unknown[]>;
resolveConflict: (conflictId: string, resolution: string) => Promise<void>;
getLastSyncTime: () => Promise<string | null>;
};
tasks: {
getAll: () => Promise<unknown[]>;
getRunning: () => Promise<unknown[]>;
cancel: (taskId: string) => Promise<boolean>;
clearCompleted: () => Promise<void>;
};
app: {
getDataPaths: () => Promise<{ database: string; posts: string; media: string }>;
openFolder: (folderPath: string) => Promise<string>;
showItemInFolder: (itemPath: string) => Promise<void>;
selectFolder: (title?: string) => Promise<string | null>;
getDefaultProjectPath: (projectId: string) => Promise<string>;
};
meta: {
getTags: () => Promise<string[]>;
getCategories: () => Promise<string[]>;
addTag: (tag: string) => Promise<string[]>;
removeTag: (tag: string) => Promise<string[]>;
addCategory: (category: string) => Promise<string[]>;
removeCategory: (category: string) => Promise<string[]>;
syncOnStartup: () => Promise<{ tags: string[]; categories: string[] }>;
};
tags: {
getAll: () => Promise<unknown[]>;
getWithCounts: () => Promise<unknown[]>;
get: (id: string) => Promise<unknown>;
getByName: (name: string) => Promise<unknown>;
create: (data: { name: string; color?: string }) => Promise<unknown>;
update: (id: string, data: { name?: string; color?: string | null }) => Promise<unknown>;
delete: (id: string) => Promise<boolean>;
merge: (sourceTagIds: string[], targetTagId: string) => Promise<void>;
rename: (id: string, newName: string) => Promise<unknown>;
getPostsWithTag: (tagId: string) => Promise<unknown[]>;
syncFromPosts: () => Promise<void>;
};
import: {
selectAndAnalyze: (uploadsFolder?: string) => Promise<unknown>;
analyzeFile: (filePath: string, uploadsFolder?: string) => Promise<unknown>;
selectUploadsFolder: () => Promise<string | null>;
execute: (reportJson: string, uploadsFolder?: string) => Promise<{ taskId: string; totalItems: number }>;
onProgress: (callback: (data: { step: string; detail?: string }) => void) => () => void;
onExecutionProgress: (callback: (data: {
taskId: string;
phase: string;
current: number;
total: number;
detail?: string;
eta?: number;
}) => void) => () => void;
};
importDefinitions: {
create: (name?: string) => Promise<unknown>;
get: (id: string) => Promise<unknown>;
getAll: () => Promise<unknown[]>;
update: (id: string, updates: unknown) => Promise<unknown>;
delete: (id: string) => Promise<boolean>;
};
metadataDiff: {
getStats: () => Promise<{
totalPosts: number;
publishedPosts: number;
draftPosts: number;
totalMedia: number;
}>;
scan: () => Promise<{
totalScanned: number;
postsWithDifferences: number;
differences: Array<{
postId: string;
title: string;
slug: string;
filePath?: string;
hasDifferences: boolean;
differences: Record<string, { dbValue: unknown; fileValue: unknown }>;
}>;
groups: Array<{
field: string;
label: string;
posts: Array<{
postId: string;
title: string;
slug: string;
dbValue: unknown;
fileValue: unknown;
}>;
}>;
}>;
syncDbToFile: (postIds: string[], groupLabel: string) => Promise<{ success: number; failed: number }>;
syncFileToDb: (postIds: string[], field: string, groupLabel: string) => Promise<{ success: number; failed: number }>;
};
chat: {
// API Key Management
checkReady: () => Promise<{ ready: boolean; error?: string; backend?: string }>;
validateApiKey: (apiKey: string) => Promise<{ isValid: boolean; models: Array<{ id: string; name: string }> }>;
setApiKey: (apiKey: string) => Promise<{ success: boolean; error?: string }>;
getApiKey: () => Promise<{ hasKey: boolean; maskedKey: string }>;
// Settings
getAvailableModels: () => Promise<{ success: boolean; models?: Array<{ id: string; name: string }>; selectedModel?: string; error?: string }>;
setDefaultModel: (modelId: string) => Promise<{ success: boolean; error?: string }>;
getSystemPrompt: () => Promise<{ success: boolean; prompt?: string; error?: string }>;
setSystemPrompt: (prompt: string) => Promise<{ success: boolean; error?: string }>;
// Conversations
getConversations: () => Promise<unknown[]>;
createConversation: (title?: string, model?: string) => Promise<unknown>;
getConversation: (id: string) => Promise<unknown>;
updateConversation: (id: string, updates: { title?: string; model?: string }) => Promise<unknown>;
deleteConversation: (id: string) => Promise<boolean>;
// Messaging
sendMessage: (conversationId: string, message: string) => Promise<string>;
abortMessage: (conversationId: string) => Promise<void>;
getHistory: (conversationId: string) => Promise<unknown[]>;
clearMessages: (conversationId: string) => Promise<void>;
setConversationModel: (conversationId: string, modelId: string) => Promise<void>;
// Event listeners
onStreamDelta: (callback: (data: { conversationId: string; delta: string }) => void) => () => void;
onToolCall: (callback: (data: { conversationId: string; toolCall: unknown }) => void) => () => void;
onToolResult: (callback: (data: { conversationId: string; result: unknown }) => void) => () => void;
onTitleUpdated: (callback: (data: { conversationId: string; title: string }) => void) => () => void;
};
on: (channel: string, callback: (...args: unknown[]) => void) => () => void;
once: (channel: string, callback: (...args: unknown[]) => void) => void;
}
declare global {
interface Window {
electronAPI: ElectronAPI;
}
}
contextBridge.exposeInMainWorld('electronAPI', electronAPI);

View File

@@ -0,0 +1,486 @@
// Type definitions for the Electron API exposed via preload
export interface ImportExecuteResult {
taskId: string;
totalItems: number;
}
export interface ImportExecutionProgress {
taskId: string;
phase: string;
current: number;
total: number;
detail?: string;
eta?: number;
}
export interface ImportCompleteResult {
taskId: string;
success: boolean;
posts: { imported: number; skipped: number; errors: number };
media: { imported: number; skipped: number; errors: number };
pages: { imported: number; skipped: number; errors: number };
tags: { created: number; skipped: number };
}
export interface ImportDefinitionData {
id: string;
projectId: string;
name: string;
wxrFilePath: string | null;
uploadsFolderPath: string | null;
lastAnalysisResult: unknown | null;
createdAt: string;
updatedAt: string;
}
export interface ProjectMetadata {
name: string;
description?: string;
dataPath?: string;
mainLanguage?: string;
}
export interface ProjectData {
id: string;
name: string;
slug: string;
description?: string;
dataPath?: string;
isActive: boolean;
createdAt: string;
updatedAt: string;
}
export interface PostData {
id: string;
projectId: string;
title: string;
slug: string;
excerpt?: string;
content: string;
status: 'draft' | 'published' | 'archived';
author?: string;
createdAt: string;
updatedAt: string;
publishedAt?: string;
tags: string[];
categories: string[];
}
export interface PostFilter {
status?: 'draft' | 'published' | 'archived';
tags?: string[];
categories?: string[];
year?: number;
month?: number;
from?: string;
to?: string;
}
export interface SearchResult {
id: string;
title: string;
slug: string;
excerpt?: string;
}
export interface MediaData {
id: string;
projectId: string;
filename: string;
originalName: string;
mimeType: string;
size: number;
width?: number;
height?: number;
title?: string;
alt?: string;
caption?: string;
author?: string;
createdAt: string;
updatedAt: string;
tags: string[];
}
export interface MediaFilter {
tags?: string[];
year?: number;
month?: number;
}
export interface MediaSearchResult {
id: string;
originalName: string;
title?: string;
mimeType: string;
createdAt: string;
}
export interface TaskProgress {
taskId: string;
status: 'pending' | 'running' | 'completed' | 'failed' | 'cancelled';
progress: number;
message: string;
startTime: string;
endTime?: string;
error?: string;
}
export interface SyncConfig {
autoSync: boolean;
syncInterval: number;
}
export interface SyncResult {
success: boolean;
pushed: number;
pulled: number;
conflicts: number;
errors: string[];
}
export interface PaginatedPostsResult {
items: PostData[];
hasMore: boolean;
total: number;
}
export interface DashboardStats {
totalPosts: number;
draftCount: number;
publishedCount: number;
archivedCount: number;
}
export interface TagCount {
tag: string;
count: number;
}
export interface CategoryCount {
category: string;
count: number;
}
export interface TagData {
id: string;
projectId: string;
name: string;
color?: string;
createdAt: string;
updatedAt: string;
}
export interface TagWithCount {
name: string;
color: string | null;
count: number;
}
export interface DeleteTagResult {
success: boolean;
postsUpdated: number;
}
export interface MergeTagsResult {
success: boolean;
postsUpdated: number;
tagsDeleted: number;
targetTag: string;
}
export interface RenameTagResult {
success: boolean;
postsUpdated: number;
oldName: string;
newName: string;
}
export interface SyncTagsResult {
discovered: number;
added: string[];
}
// Post-Media Link types
export interface MediaLinkData {
id: string;
projectId: string;
postId: string;
mediaId: string;
sortOrder: number;
createdAt: string;
}
// Chat/AI types
export interface ChatConversation {
id: string;
title: string;
model?: string;
createdAt: string;
updatedAt: string;
}
export interface ChatMessage {
id: string;
conversationId: string;
role: 'user' | 'assistant' | 'system' | 'tool';
content: string;
toolCallId?: string;
toolCalls?: string;
createdAt: string;
}
export interface ChatModel {
id: string;
name: string;
provider?: string;
}
export interface ChatReadyStatus {
ready: boolean;
error?: string;
backend?: string;
}
export interface ChatApiKeyStatus {
hasKey: boolean;
maskedKey: string;
}
export interface ChatStreamDelta {
conversationId: string;
delta: string;
}
export interface ChatToolCall {
conversationId: string;
toolCall: {
name: string;
arguments: Record<string, unknown>;
};
}
export interface ChatToolResult {
conversationId: string;
result: unknown;
}
export interface ChatTitleUpdate {
conversationId: string;
title: string;
}
export interface ElectronAPI {
projects: {
create: (data: { name: string; description?: string; slug?: string; dataPath?: string }) => Promise<ProjectData>;
update: (id: string, data: Partial<ProjectData>) => Promise<ProjectData | null>;
delete: (id: string) => Promise<boolean>;
deleteWithData: (id: string) => Promise<boolean>;
get: (id: string) => Promise<ProjectData | null>;
getAll: () => Promise<ProjectData[]>;
getActive: () => Promise<ProjectData | null>;
setActive: (id: string) => Promise<ProjectData | null>;
};
posts: {
create: (data: Partial<PostData>) => Promise<PostData>;
update: (id: string, data: Partial<PostData>) => Promise<PostData | null>;
delete: (id: string) => Promise<boolean>;
get: (id: string) => Promise<PostData | null>;
getAll: (options?: { limit?: number; offset?: number }) => Promise<PaginatedPostsResult>;
getByStatus: (status: string) => Promise<PostData[]>;
publish: (id: string) => Promise<PostData | null>;
discard: (id: string) => Promise<PostData | null>;
hasPublishedVersion: (id: string) => Promise<boolean>;
rebuildFromFiles: () => Promise<void>;
reindexText: () => Promise<void>;
search: (query: string) => Promise<SearchResult[]>;
filter: (filter: PostFilter) => Promise<PostData[]>;
getTags: () => Promise<string[]>;
getCategories: () => Promise<string[]>;
getByYearMonth: () => Promise<{ year: number; month: number; count: number }[]>;
getDashboardStats: () => Promise<DashboardStats>;
getTagsWithCounts: () => Promise<TagCount[]>;
getCategoriesWithCounts: () => Promise<CategoryCount[]>;
getLinksTo: (id: string) => Promise<PostData[]>;
getLinkedBy: (id: string) => Promise<PostData[]>;
rebuildLinks: () => Promise<void>;
isSlugAvailable: (slug: string, excludePostId?: string) => Promise<boolean>;
generateUniqueSlug: (title: string, excludePostId?: string) => Promise<string>;
};
media: {
import: (sourcePath: string, metadata?: Partial<MediaData>) => Promise<MediaData>;
importDialog: () => Promise<MediaData[]>;
update: (id: string, data: Partial<MediaData>) => Promise<MediaData | null>;
replaceFile: (id: string, newSourcePath: string) => Promise<MediaData | null>;
replaceFileDialog: (id: string) => Promise<MediaData | null>;
delete: (id: string) => Promise<boolean>;
get: (id: string) => Promise<MediaData | null>;
getUrl: (id: string) => Promise<string | null>;
getFilePath: (id: string) => Promise<string | null>;
getAll: () => Promise<MediaData[]>;
rebuildFromFiles: () => Promise<void>;
reindexText: () => Promise<void>;
getThumbnail: (id: string, size?: 'small' | 'medium' | 'large') => Promise<string | null>;
regenerateThumbnails: (id: string) => Promise<Record<string, string> | null>;
regenerateMissingThumbnails: () => Promise<{ processed: number; generated: number; failed: number }>;
filter: (filter: MediaFilter) => Promise<MediaData[]>;
search: (query: string) => Promise<MediaSearchResult[]>;
getByYearMonth: () => Promise<{ year: number; month: number; count: number }[]>;
getTags: () => Promise<string[]>;
getTagsWithCounts: () => Promise<TagCount[]>;
};
postMedia: {
link: (postId: string, mediaId: string) => Promise<MediaLinkData>;
unlink: (postId: string, mediaId: string) => Promise<void>;
linkMany: (postId: string, mediaIds: string[]) => Promise<{ linked: string[]; skipped: string[] }>;
unlinkMany: (postId: string, mediaIds: string[]) => Promise<{ unlinked: string[] }>;
getForPost: (postId: string) => Promise<MediaLinkData[]>;
getForMedia: (mediaId: string) => Promise<MediaLinkData[]>;
getMediaDataForPost: (postId: string) => Promise<Array<MediaLinkData & { media: MediaData }>>;
reorder: (postId: string, mediaIds: string[]) => Promise<void>;
isLinked: (postId: string, mediaId: string) => Promise<boolean>;
import: (postId: string, filePath: string) => Promise<MediaLinkData>;
rebuild: () => Promise<void>;
};
sync: {
configure: (config: SyncConfig) => Promise<void>;
start: (direction?: 'push' | 'pull' | 'bidirectional') => Promise<SyncResult>;
getStatus: () => Promise<'idle' | 'syncing' | 'error'>;
isConfigured: () => Promise<boolean>;
getPendingCount: () => Promise<{ posts: number; media: number }>;
getLog: (limit?: number) => Promise<unknown[]>;
stopAutoSync: () => Promise<void>;
};
tasks: {
getAll: () => Promise<TaskProgress[]>;
getRunning: () => Promise<TaskProgress[]>;
cancel: (taskId: string) => Promise<boolean>;
clearCompleted: () => Promise<void>;
};
app: {
getDataPaths: () => Promise<{ database: string; posts: string; media: string }>;
openFolder: (folderPath: string) => Promise<string>;
showItemInFolder: (itemPath: string) => Promise<void>;
selectFolder: (title?: string) => Promise<string | null>;
getDefaultProjectPath: (projectId: string) => Promise<string>;
readProjectMetadata: (folderPath: string) => Promise<{ name?: string; description?: string; mainLanguage?: string } | null>;
};
meta: {
getTags: () => Promise<string[]>;
getCategories: () => Promise<string[]>;
addTag: (tag: string) => Promise<string[]>;
removeTag: (tag: string) => Promise<string[]>;
addCategory: (category: string) => Promise<string[]>;
removeCategory: (category: string) => Promise<string[]>;
syncOnStartup: () => Promise<{ tags: string[]; categories: string[]; projectMetadata: ProjectMetadata | null }>;
getProjectMetadata: () => Promise<ProjectMetadata | null>;
setProjectMetadata: (metadata: { name: string; description?: string }) => Promise<ProjectMetadata | null>;
updateProjectMetadata: (updates: { name?: string; description?: string; dataPath?: string; mainLanguage?: string }) => Promise<ProjectMetadata | null>;
};
tags: {
getAll: () => Promise<TagData[]>;
getWithCounts: () => Promise<TagWithCount[]>;
get: (id: string) => Promise<TagData | null>;
getByName: (name: string) => Promise<TagData | null>;
create: (data: { name: string; color?: string }) => Promise<TagData>;
update: (id: string, data: { name?: string; color?: string | null }) => Promise<TagData | null>;
delete: (id: string) => Promise<DeleteTagResult>;
merge: (sourceTagIds: string[], targetTagId: string) => Promise<MergeTagsResult>;
rename: (id: string, newName: string) => Promise<RenameTagResult>;
getPostsWithTag: (tagId: string) => Promise<string[]>;
syncFromPosts: () => Promise<SyncTagsResult>;
};
import: {
selectAndAnalyze: (uploadsFolder?: string) => Promise<unknown>;
analyzeFile: (filePath: string, uploadsFolder?: string) => Promise<unknown>;
selectUploadsFolder: () => Promise<string | null>;
execute: (reportJson: string, uploadsFolder?: string) => Promise<ImportExecuteResult>;
onProgress: (callback: (data: { step: string; detail?: string }) => void) => () => void;
onExecutionProgress: (callback: (data: ImportExecutionProgress) => void) => () => void;
onComplete: (callback: (data: ImportCompleteResult) => void) => () => void;
};
importDefinitions: {
create: (name?: string) => Promise<ImportDefinitionData>;
get: (id: string) => Promise<ImportDefinitionData | null>;
getAll: () => Promise<ImportDefinitionData[]>;
update: (id: string, updates: Partial<Pick<ImportDefinitionData, 'name' | 'wxrFilePath' | 'uploadsFolderPath' | 'lastAnalysisResult'>>) => Promise<ImportDefinitionData | null>;
delete: (id: string) => Promise<boolean>;
onNameUpdated: (callback: (data: { definitionId: string; name: string }) => void) => () => void;
};
metadataDiff: {
getStats: () => Promise<{
totalPosts: number;
publishedPosts: number;
draftPosts: number;
totalMedia: number;
}>;
scan: () => Promise<{
totalScanned: number;
postsWithDifferences: number;
differences: Array<{
postId: string;
title: string;
slug: string;
filePath?: string;
hasDifferences: boolean;
differences: Record<string, { dbValue: unknown; fileValue: unknown }>;
}>;
groups: Array<{
field: string;
label: string;
posts: Array<{
postId: string;
title: string;
slug: string;
dbValue: unknown;
fileValue: unknown;
}>;
}>;
}>;
syncDbToFile: (postIds: string[], groupLabel: string) => Promise<{ success: number; failed: number }>;
syncFileToDb: (postIds: string[], field: string, groupLabel: string) => Promise<{ success: number; failed: number }>;
};
chat: {
// API Key Management
checkReady: () => Promise<ChatReadyStatus>;
validateApiKey: (apiKey: string) => Promise<{ isValid: boolean; models: ChatModel[] }>;
setApiKey: (apiKey: string) => Promise<{ success: boolean; error?: string }>;
getApiKey: () => Promise<ChatApiKeyStatus>;
// Settings
getAvailableModels: () => Promise<{ success: boolean; models?: ChatModel[]; selectedModel?: string; error?: string }>;
setDefaultModel: (modelId: string) => Promise<{ success: boolean; error?: string }>;
getSystemPrompt: () => Promise<{ success: boolean; prompt?: string; error?: string }>;
setSystemPrompt: (prompt: string) => Promise<{ success: boolean; error?: string }>;
// Conversations
getConversations: () => Promise<ChatConversation[]>;
createConversation: (title?: string, model?: string) => Promise<ChatConversation>;
getConversation: (id: string) => Promise<ChatConversation | null>;
updateConversation: (id: string, updates: { title?: string; model?: string }) => Promise<ChatConversation | null>;
deleteConversation: (id: string) => Promise<boolean>;
// Messaging
sendMessage: (conversationId: string, message: string) => Promise<{ success: boolean; message?: string; error?: string }>;
abortMessage: (conversationId: string) => Promise<void>;
getHistory: (conversationId: string) => Promise<ChatMessage[]>;
clearMessages: (conversationId: string) => Promise<void>;
setConversationModel: (conversationId: string, modelId: string) => Promise<void>;
// Taxonomy Analysis
analyzeTaxonomy: (categories: Array<{ name: string; slug: string; existsInProject: boolean }>, tags: Array<{ name: string; slug: string; existsInProject: boolean }>, modelId: string) => Promise<{ success: boolean; categoryMappings?: Record<string, string>; tagMappings?: Record<string, string>; error?: string }>;
// Media Analysis
analyzeMediaImage: (mediaId: string, language?: string) => Promise<{ success: boolean; title?: string; alt?: string; caption?: string; error?: string }>;
// Event listeners for streaming/progress
onStreamDelta: (callback: (data: ChatStreamDelta) => void) => () => void;
onToolCall: (callback: (data: ChatToolCall) => void) => () => void;
onToolResult: (callback: (data: ChatToolResult) => void) => () => void;
onTitleUpdated: (callback: (data: ChatTitleUpdate) => void) => () => void;
};
on: (channel: string, callback: (...args: unknown[]) => void) => () => void;
once: (channel: string, callback: (...args: unknown[]) => void) => void;
}