Repository: TabbyML/tabby
File: clients/tabby-chat-panel/src/index.ts (TypeScript)

Code before:
  updateActiveSelection: (context: Context | null) => void
}

export type ClientApiMethods = keyof ClientApi

export interface ClientApi {
  navigate: (context: Context, opts?: NavigateOpts) => void
  refresh: () => Promise<void>

  onSubmitMessage: (msg: string, relevantContext?: Context[]) => Promise<void>

  onApplyInEditor: (content: string, opts?: { languageId: string, smart: boolean }) => void

  // On current page is loaded.
  onLoaded: (params?: OnLoadedParams | undefined) => void

  // On user copy content to clipboard.
  onCopy: (content: string) => void

  onKeyboardEvent: (type: 'keydown' | 'keyup' | 'keypress', event: KeyboardEventInit) => void

  // this is inner function cover by tabby-threads
  // the function doesn't need to expose to client but can call by client
  hasCapability?: (capability: ClientApiMethods) => Promise<boolean>
}

export interface ChatMessage {
  message: string

  // Client side context - displayed in user message
  selectContext?: Context

  // Client side contexts - displayed in assistant message
  relevantContext?: Array<Context>

  // Client side active selection context - displayed in assistant message
  activeContext?: Context
}

export function createClient(target: HTMLIFrameElement, api: ClientApi): ServerApi {
  return createThreadFromIframe(target, {
    expose: {
      navigate: api.navigate,
      refresh: api.refresh,
      onSubmitMessage: api.onSubmitMessage,
      onApplyInEditor: api.onApplyInEditor,
      onLoaded: api.onLoaded,
      onCopy: api.onCopy,
      onKeyboardEvent: api.onKeyboardEvent,
      hasCapability: api.hasCapability,
    },

Review comment (suggestion):
I think using interface extends could be better?
```
export interface ClientApiMethods {
  // ...
}
export interface ClientApi extends ClientApiMethods {
  hasCapability(method: key of ClientApiMethods): Promise<boolean>
}
```

Code after:
  updateActiveSelection: (context: Context | null) => void
}

export interface ClientApiMethods {
  navigate: (context: Context, opts?: NavigateOpts) => void
  refresh: () => Promise<void>

  onSubmitMessage: (msg: string, relevantContext?: Context[]) => Promise<void>

  onApplyInEditor: (content: string, opts?: { languageId: string, smart: boolean }) => void

  // On current page is loaded.
  onLoaded: (params?: OnLoadedParams | undefined) => void

  // On user copy content to clipboard.
  onCopy: (content: string) => void

  onKeyboardEvent: (type: 'keydown' | 'keyup' | 'keypress', event: KeyboardEventInit) => void

}

export interface ClientApi extends ClientApiMethods {
  // this is inner function cover by tabby-threads
  // the function doesn't need to expose to client but can call by client
  hasCapability: (method: keyof ClientApiMethods) => Promise<boolean>
}

export interface ChatMessage {
  message: string

  // Client side context - displayed in user message
  selectContext?: Context

  // Client side contexts - displayed in assistant message
  relevantContext?: Array<Context>

  // Client side active selection context - displayed in assistant message
  activeContext?: Context
}

export function createClient(target: HTMLIFrameElement, api: ClientApiMethods): ServerApi {
  return createThreadFromIframe(target, {
    expose: {
      navigate: api.navigate,
      refresh: api.refresh,
      onSubmitMessage: api.onSubmitMessage,
      onApplyInEditor: api.onApplyInEditor,
      onLoaded: api.onLoaded,
      onCopy: api.onCopy,
      onKeyboardEvent: api.onKeyboardEvent,
    },