# 接口定义

## 一、后端接口（Go）

> 文件位置：`internal/plugin/plugin.go`

```go
package plugin

import (
    "context"
    "time"

    "github.com/wailsapp/wails/v3/pkg/application"
)

// ========== 类型定义 ==========

type PluginID string

type PluginSource string

const (
    SourceBuiltin PluginSource = "builtin"
    SourceMarket PluginSource = "market"
)

// PluginMetadata 插件元数据（JSON 序列化传给前端）
type PluginMetadata struct {
    ID             PluginID     `json:"id"`
    Name           string       `json:"name"`
    Version        string       `json:"version"`
    Description    string       `json:"description"`
    Author         string       `json:"author"`
    Source         PluginSource `json:"source"`
    TabKey         string       `json:"tab_key,omitempty"`
    FileExtensions []string     `json:"file_extensions,omitempty"`
    InstallPath    string       `json:"install_path,omitempty"`
    InstalledAt    time.Time    `json:"installed_at,omitempty"`
    UISlots        []string     `json:"ui_slots,omitempty"` // 声明占用的 UI 插槽（Phase 3）
}

// PluginCapability 插件能力标志位
type PluginCapability int

const (
    CapabilityNone        PluginCapability = 0
    CapabilityTabProvider  PluginCapability = 1 << iota
    CapabilityFilePreview
    CapabilitySettings
)

func (c PluginCapability) Has(cap PluginCapability) bool {
    return c&cap != 0
}

// PreviewInfo 预览元信息
type PreviewInfo struct {
    Type            string         `json:"type"`
    Title           string         `json:"title"`
    Icon            string         `json:"icon,omitempty"`
    NeedsContainer  bool           `json:"needs_container,omitempty"`
    ContainerConfig map[string]any `json:"container_config,omitempty"`
    SupportsEdit    bool           `json:"supports_edit"`
    PreloadHint     string         `json:"preload_hint,omitempty"`
}

// TabDef Tab 定义
type TabDef struct {
    Key     string `json:"key"`
    Title   string `json:"title"`
    Icon    string `json:"icon,omitempty"`
    Enabled bool   `json:"enabled"`
    Order   int    `json:"order"`
}

// ========== 核心接口 ==========

// CoreServices 插件可访问的核心服务（由 adapter 实现，不挂在 App 上）
type CoreServices interface {
    Context() context.Context
    MainWindow() *application.WebviewWindow
    EmitEvent(eventName string, data ...any)
    FileSystem() any
    ConfigAPI() any
    GetFileServerURL() string
}

// Plugin 核心插件接口（所有插件必须实现）
type Plugin interface {
    Meta() PluginMetadata
    Capabilities() PluginCapability
    Init(ctx context.Context, core CoreServices) error
    Start() error
    Stop() error
}

// TabProvider Tab 提供者接口（可选，实现 CapabilityTabProvider 时需同时实现）
type TabProvider interface {
    Plugin
    TabDefinition() TabDef
    TabComponentPath() string
}

// FilePreviewHandler 文件预览处理器接口（可选，实现 CapabilityFilePreview 时需同时实现）
type FilePreviewHandler interface {
    Plugin
    CanPreview(filename string, mimeType string) bool
    PreviewInfo(filename string) PreviewInfo
}
```

## 二、PluginManager API

> 文件位置：`internal/plugin/manager.go`

```go
type Manager struct {
    mu         sync.RWMutex
    plugins    map[PluginID]Plugin
    core       CoreServices
    tabReg     *TabRegistry
    previewReg *PreviewRegistry
    ctx        context.Context
    initialized bool
}

// 生命周期
func NewManager(core CoreServices) *Manager
func (m *Manager) Register(p Plugin) error           // 注册 + 自动分发到子注册表
func (m *Manager) InitAll(ctx context.Context) error  // 初始化所有插件
func (m *Manager) StartByTabKey(tabKey string) error  // 按 Tab 懒启动
func (m *Manager) Shutdown() error                    // 停止所有插件

// 查询
func (m *Manager) GetPluginInfos() []PluginMetadata   // 前端展示用
func (m *Manager) ResolvePreview(filename string) (*PreviewInfo, PluginID)
func (m *Manager) GetTabDefinitions() []TabDef

// 外部插件管理（Phase 4+）
func (m *Manager) InstallPlugin(packagePath string) error
func (m *Manager) UninstallPlugin(id PluginID) error
func (m *Manager) SetPluginEnabled(id PluginID, enabled bool) error
func (m *Manager) CheckPluginUpdates() []PluginUpdateInfo
```

## 三、前端接口（TypeScript）

> 文件位置：`frontend/src/plugin/types.ts`

```typescript
/** 插件能力标志位 */
export enum PluginCapability {
  None = 0,
  TabProvider = 1 << 0,
  FilePreview = 1 << 1,
  Settings = 1 << 2,
}

export type PluginSource = 'builtin' | 'market'

/** 后端返回的插件元信息 */
export interface PluginMetadata {
  id: string
  name: string
  version: string
  description: string
  author: string
  source: PluginSource
  tab_key?: string
  file_extensions?: string[]
  install_path?: string
  installed_at?: string
  ui_slots?: string[]
}

/** Tab 插件定义（前端注册用） */
export interface TabPluginDefinition {
  key: string
  title: string
  icon?: string
  componentLoader: () => Promise<Component>
  defaultVisible?: boolean
  order?: number
  keepAlive?: boolean
}

/** 文件预览处理器定义 */
export interface FilePreviewHandlerDefinition {
  id: string
  name: string
  icon: string
  priority: number
  canHandle: (filename: string) => boolean
  getComponent?: () => Promise<Component>
  getRenderConfig?: (filePath: string) => RenderConfig
  supportsEdit?: boolean
}

/** 渲染配置 */
export interface RenderConfig {
  type: 'iframe' | 'html' | 'custom' | 'image' | 'video' | 'audio'
  src?: string
  htmlContent?: string
  props?: Record<string, unknown>
}
```

## 四、前端 Registry API

> 文件位置：`frontend/src/plugin/registry.ts`

```typescript
// === Tab 插件 ===
function registerTabPlugin(def: TabPluginDefinition): void
function getTabComponent(key: string): (() => Promise<Component>) | null
function getAllTabDefinitions(): TabPluginDefinition[]
function hasTabPlugin(key: string): boolean

// === 文件预览 ===
function registerPreviewHandler(handler: FilePreviewHandlerDefinition): void
function resolvePreviewHandler(filename: string): FilePreviewHandlerDefinition | null
function getAllPreviewHandlers(): ReadonlyArray<FilePreviewHandlerDefinition>

// === 调试 ===
function getRegistryStats(): { tabCount, previewHandlerCount, tabKeys, handlerIds }
```
