verstak-docs/docs/MILESTONE_PLATFORM_RUNTIME_...

9.0 KiB
Raw Blame History

Milestone 5b — Frontend Bundle Host / Plugin API Stub

Цель

Первый настоящий frontend plugin host слой: shell умеет загружать frontend bundle плагина, давать ему ограниченный VerstakPluginAPI stub и рендерить view/settings panel через зарегистрированный component id.

Что реализовано

1. Bundle Contract

Плагин регистрирует компоненты через глобальную функцию:

window.VerstakPluginRegister('verstak.platform-test', {
  components: {
    'DiagnosticsPanel': {
      mount: function(containerEl, props, api) {
        // Рендерит UI в containerEl
        // containerEl — div, созданный PluginBundleHost
        // api — ограниченный VerstakPluginAPI
      },
      unmount: function(containerEl) {
        // Очистка при смене view/unmount
        containerEl.innerHTML = '';
      }
    },
    'PlatformTestSettings': {
      mount: function(containerEl, props, api) { /*...*/ },
      unmount: function(containerEl) { /*...*/ }
    }
  }
});

VerstakPluginAPI — ограниченный API, передаваемый в mount():

Метод Статус Описание
api.pluginId Работает ID плагина
api.capabilities.has(id) Stub Возвращает false (planned: реальный запрос к registry)
api.events.publish(type, payload) Stub Логирует в console (planned: event bus bridge)
api.events.subscribe(type, handler) Stub Логирует в console (planned: event bus bridge)
api.settings.read(key) Stub Возвращает null (planned: backend storage namespace)
api.settings.write(key, value) Stub Логирует в console (planned: backend storage)
api.commands.execute(id, args) Stub Логирует в console (planned: command execution)

2. Безопасная резолюция asset path

Backend методы:

Метод Описание
GetPluginFrontendInfo(pluginID) Возвращает frontend metadata (entry, style, rootPath, name, icon, version)
GetPluginAssetContent(pluginID, assetPath) Читает файл из директории плагина с валидацией безопасности

Проверки безопасности:

  • Абсолютные пути (начинающиеся с / или \) — отклоняются
  • Path traversal (..) — отклоняется
  • Выход за пределы plugin root — отклоняется через filepath.Abs + strings.HasPrefix

3. FrontendPluginHost

PluginBundleHost.svelte — загружает и рендерит плагин бандлы:

  1. Получает plugin frontend info через GetPluginFrontendInfo()
  2. Если у плагина есть frontend entry — загружает JS контент через GetPluginAssetContent()
  3. Выполняет bundle через new Function(content) (безопасно: нет доступа к внешней области видимости)
  4. Ждёт вызов VerstakPluginRegister и находит компонент по componentId
  5. Создаёт VerstakPluginAPI и вызывает component.mount(container, props, api)
  6. При смене view — вызывает component.unmount(container) и очищает

Error boundary:

  • Если bundle не загружается — fallback с pluginID, componentId, error text
  • Если компонент не найден — показывает доступные components
  • Если mount выбрасывает исключение — fallback без падения shell
  • Все состояния: idle, loading, error, loaded

4. ViewContainer.svelte

  • Проверяет наличие frontend bundle у плагина
  • Если есть — рендерит PluginBundleHost
  • Если нет — показывает "frontend bundle not available" placeholder
  • Badge в заголовке: "frontend bundle" (зелёный) или "no frontend bundle" (красный)

5. PluginManager — Settings Panel

  • Убран hardcoded platform-test settings form
  • Settings panel рендерится через PluginBundleHost, если у плагина есть frontend entry
  • Если нет — показывает "Settings panel frontend bundle not available"

6. platform-test plugin — Real Frontend Bundle

frontend/dist/index.js (14.6 KB):

  • Регистрирует компоненты через VerstakPluginRegister
  • Диагностическая панель:
    • Plugin name, version, ID
    • " Frontend Bundle Loaded" badge
    • Test results summary
    • Capabilities status section
    • API methods info
  • Settings panel:
    • Plugin name + ID
    • Interactive counter (increment/decrement/reset)
    • Demo settings list
  • Темная тема (совпадает с shell)

frontend/style.css (4.9 KB):

  • Shared dark-theme styles
  • Используется обоими компонентами

7. Тесты

Backend (11 новых тестов в internal/api/app_test.go):

Тест Проверяет
GetPluginFrontendInfo (known) Полные данные для плагина с frontend
GetPluginFrontendInfo (no frontend) Статус "no-frontend"
GetPluginFrontendInfo (unknown) Статус "not-found"
GetPluginAssetContent (existing) Чтение существующего файла
GetPluginAssetContent (style) Чтение style.css
GetPluginAssetContent (absolute path) Отклонение / и \
GetPluginAssetContent (path traversal) Отклонение ..
GetPluginAssetContent (path escape) Отклонение выхода за root
GetPluginAssetContent (not found) Ошибка для неизвестного pluginID
GetPluginAssetContent (no frontend) Ошибка если нет frontend
GetPluginAssetContent (missing file) Ошибка если файл не существует

Smoke test (frontend bundle checks):

  • Manifest объявляет frontend.entry = "frontend/dist/index.js"
  • Файл бандла существует на диске
  • Бандл содержит "VerstakPluginRegister"
  • Компоненты DiagnosticsPanel и PlatformTestSettings зарегистрированы

8. Security Constraints

Сценарий Результат
frontend entry ../etc/passwd Отклоняется (path traversal)
frontend entry /etc/passwd Отклоняется (absolute path)
Плагин без frontend Не ломает UI, показывает placeholder
Плагин с missing entry Error fallback с понятным сообщением
Bundle execution error Error fallback, shell не падает
Компонент не найден в bundle Error fallback со списком доступных components

Изменённые файлы

verstak-desktop

Файл Изменение
internal/api/app.go + GetPluginFrontendInfo(), GetPluginAssetContent() с path validation
internal/api/app_test.go NEW: 11 тестов
frontend/src/lib/plugin-host/VerstakPluginAPI.js NEW: Bundle contract + API stub
frontend/src/lib/plugin-host/PluginBundleHost.svelte NEW: Загрузка/рендер бандлов, error boundary
frontend/src/lib/shell/ViewContainer.svelte Обновлён: PluginBundleHost вместо placeholder
frontend/src/lib/plugin-manager/PluginManager.svelte Обновлён: Settings через PluginBundleHost
cmd/smoke-platform/main.go Обновлён: frontend bundle checks
docs/PLUGIN_RUNTIME.md Обновлён: bundle contract, security

verstak-official-plugins

Файл Изменение
plugins/platform-test/frontend/src/index.js NEW: DiagnosticsPanel + SettingsPanel
plugins/platform-test/frontend/style.css NEW: Dark theme styles
plugins/platform-test/frontend/dist/index.js REPLACED: VerstakPluginRegister contract

verstak-docs

| docs/MILESTONE_PLATFORM_RUNTIME_5b.md | NEW: этот документ |

Проверки

go test ./internal/... -count=1    → ✅ 56 PASS (all packages)
go vet ./...                       → ✅ clean
cd frontend && npm run build       → ✅ built (72.98 KB gzip:21.64 KB)
bash scripts/smoke-platform.sh     → ✅ 4 теста (plugin + enable/disable + workspace + contributions + frontend bundle)
bash scripts/build.sh              → ✅ wails build

Non-goals (не реализовано)

  • Official notes/files/editor extraction
  • Backend sidecar runtime
  • Secrets
  • Полноценный command palette
  • Remote plugin registry
  • Прямой доступ плагина к Wails backend methods (кроме VerstakPluginAPI)