Files
browser/openspec/changes/implement-plugin-bridge-and-sdk/design.md
T
2026-07-11 14:56:10 +08:00

6.3 KiB

Context

The registry change added a validated game plugin manifest and marketplace-ready plugin metadata, but plugin pages still have only documentation-level bridge notes. The next backlog item needs a concrete contract that lets plugin UI request platform abilities without learning platform credentials, run connection details, host paths, storage backends, or AI provider keys.

The implementation spans three roots:

  • plugins/ owns the author-facing TypeScript SDK, manifest bridge declarations, and example plugin usage.
  • platform_web/ owns the browser host-side bridge contracts and utility checks used by future plugin pages.
  • platform/ owns the authoritative permission/session validation before privileged bridge requests are accepted.

Goals / Non-Goals

Goals:

  • Define a typed bridge request/response contract for plugin pages.
  • Enforce bridge actions against manifest-declared plugin permissions and AI purposes.
  • Provide SDK helpers for plugin authors to check permissions and build safe bridge requests.
  • Add platform validators/services/API routes for bridge session and action authorization.
  • Keep plugin pages mediated by platform APIs instead of direct run, socket, host path, credential, artifact storage, or AI provider access.
  • Add tests proving forbidden bridge actions fail and allowed scoped actions pass.

Non-Goals:

  • Do not implement plugin iframe loading or a complete marketplace UI in this change.
  • Do not execute plugin lifecycle actions or server workflows end to end.
  • Do not expose raw AI provider keys, run credentials, direct sockets, raw host paths, or storage backend endpoints.
  • Do not add billing, cloud host sales, provider marketplace, or unrelated SaaS marketplace behavior.
  • Do not introduce cross-root runtime imports; mirrored contracts remain explicit at ownership boundaries.

Decisions

Decision 1: Bridge permissions are evaluated from manifest metadata

The platform will authorize bridge actions from the installed plugin metadata produced by manifest registration. Requests include plugin ID, route key, optional server instance ID, action name, and purpose-specific payload metadata. The platform checks that the requested action maps to declared plugin permissions and AI purposes before returning an allowed decision.

Alternative considered: trust the browser SDK to decide permission outcomes. Rejected because plugin UI code is not a security boundary and can be modified by authors or users.

Decision 2: Use narrow bridge action names instead of generic RPC

The bridge contract will model first-party action names such as server.instances.read, jobs.dispatch, logs.query, artifacts.open, files.request, and ai.invoke. Each action maps to specific permission requirements.

Alternative considered: expose a generic api.request bridge that proxies arbitrary platform paths. Rejected because arbitrary request forwarding makes permission reviews harder and risks exposing unrelated platform APIs to plugin pages.

Decision 3: SDK helpers create typed envelopes, not direct transport

The SDK will provide types, permission helpers, request builders, and runtime guards. It will not own network transport or platform authentication. platform_web/ host code can later use the same envelopes to communicate with embedded plugin pages.

Alternative considered: ship a full SDK client that calls platform APIs directly from plugin page code. Rejected because plugin pages must remain behind the platform host bridge and must not receive raw auth storage.

Decision 4: Duplicate root-owned contract shapes deliberately

plugins/, platform_web/, and platform/ will each own local contract definitions that mirror the bridge surface they need. Tests and OpenSpec requirements keep the shapes aligned until a future generated contract package exists.

Alternative considered: import TypeScript SDK types directly into the frontend or backend. Rejected because the repository rules require explicit contract packages or copied/generated contracts instead of casual cross-root imports.

Decision 5: AI bridge requests carry purposes, not provider configuration

ai.invoke bridge requests will include an AI purpose and bounded input metadata. Platform validation confirms the purpose is allowed by the plugin manifest. Provider base URLs, API keys, model routing, and raw responses remain controlled by platform services.

Alternative considered: let plugin pages choose provider IDs or submit provider credentials. Rejected because AI provider keys and routing policy belong to platform/.

Risks / Trade-offs

  • [Risk] Mirrored TypeScript and Go action constants can drift. Mitigation: add focused tests and keep the action/permission matrix small until generated contracts are introduced.
  • [Risk] Early bridge action names may be too coarse for later workflows. Mitigation: keep request payloads metadata-only where possible and add new actions through explicit OpenSpec changes.
  • [Risk] Browser host work may need iframe lifecycle decisions later. Mitigation: this change establishes only host-side contracts/utilities, leaving page loading to the console-shell change.
  • [Risk] Permission checks can become duplicated between platform and host utilities. Mitigation: platform remains authoritative; host checks are UX preflight only.

Migration Plan

  1. Add the bridge contract and permission matrix in OpenSpec.
  2. Extend plugin manifest schema/types and the development example with bridge page requirements.
  3. Add SDK helpers and tests for typed bridge envelopes and local permission checks.
  4. Add platform bridge DTO/domain/validator/service/API route with tests for authorization decisions.
  5. Add platform_web bridge host types/utilities and tests for safe context construction.
  6. Validate with plugin tests, frontend tests, platform tests, scripts/check-structure.sh, and strict OpenSpec validation.

Rollback is straightforward before downstream UI depends on it: remove the bridge API route, SDK helpers, frontend host utilities, manifest bridge fields, and this change's OpenSpec artifacts.

Open Questions

  • Whether future plugin page loading should use iframe postMessage, module federation, static asset hosting, or another sandbox strategy.
  • Whether a later generated contract package should replace copied bridge action constants across roots.