# Plugin system architecture The host Next.js app (`:3002`) injects a global namespace `window.__TEABLE_HOST__` during startup. Plugins are plain JS IIFE bundles that read this namespace at runtime — no ES imports, no iframes, no penpal bridge. ## Why this system exists The previous iframe/ZIP plugin system isolated plugins in sandboxed iframes, limiting API access to a penpal postMessage bridge. Adding or changing a plugin required rebuilding and re-deploying the host Next.js app. This system solves both problems: - **Full host API access**: Plugins run in the same React tree as the host, sharing the same React singleton. They can use any SDK hook, UI component, or OpenAPI helper directly. - **No host rebuild**: Upload a new IIFE bundle via `upload-bundle` and it's immediately available — the host loads it at runtime through PluginLoader. - **Shared dependencies**: React, ReactDOM, and all `@teable/*` packages are provided by the host, so plugin bundles are small (only contain the plugin's own code). The trade-off is that plugins are fully trusted (no sandboxing) — upload is gated by a developer whitelist and bundles are validated for security. ## Runtime flow ``` 1. Host app mounts HostInitializer (): window.__TEABLE_HOST__ = { React, ReactDOM, SDK: { useFields, useRecords, useTableId, useViewId, ... }, UILib: { Button, Dialog, Select, ... }, OpenAPI: { getRecords, updateRecords, ... }, events: EventBus instance, PluginSDK: { definePlugin, registerComponent, useSelection, getSelectionRecords }, // Native embeddable components (same React tree as the host app): openFormModal, // modal wrapper around the native form NativeGrid, // full native grid with providers NativeForm, // full native form (Tier-1 injection props supported) NativeFormScope, // Tier-2: state scope for custom form layouts NativeFormField, // Tier-2: single native form row useNativeForm, // Tier-2: headless hook { values, setValue, verify, submit, ... } } 2. Plugin loads (PluginLoader component) → fetch /api/plugin/:id/runtime/plugin.json (manifest) → check minAppVersion compatibility → inject CSS (if manifest.style exists) →