mirror of
https://github.com/penpot/penpot.git
synced 2026-05-31 20:58:08 +00:00
Memories use a system of progressive disclosure: Starting from a root memory, memories reference other memories using explicit references. The new system of hierarchical memories replaces AGENTS.md files. GitHub #9215 Co-authored-by: Michael Panchenko <michael.panchenko@oraios-ai.de> Co-authored-by: Codex <codex@openai.com>
3.0 KiB
3.0 KiB
Plugins Architecture and Workflow
plugins/: standalone TypeScript/pnpm workspace for Plugin API packages and sample plugins. Related to, distinct from, frontend CLJS Plugin API runtime.
Layout
libs/plugin-types: TypeScript declarations for the public Penpot Plugin API. Type-only package; runtime behavior is implemented elsewhere.libs/plugins-runtime: runtime that loads plugins and exposes/generated API behavior to plugin code.libs/plugins-styles: reusable styling package for plugins.apps/*-plugin: sample/development plugins.apps/e2e: plugin e2e tests.
Dev Workflow
- From
plugins/: installpnpm -r install; runtime dev serverpnpm run startorpnpm run start:app:runtime; sample pluginpnpm run start:plugin:<name>; build runtimepnpm run build:runtime; build pluginspnpm run build:plugins; lintpnpm run lint; formatpnpm run format:check/pnpm run format; testspnpm run test; e2epnpm run test:e2e. - If a change affects public Plugin API types or runtime, update
plugins/CHANGELOG.md. Prefix type/signature entries with**plugin-types:**; runtime behavior entries with**plugin-runtime:**. - JS Plugin API behavior inside Penpot app:
mem:frontend/plugin-api-to-cljs-binding; TS declarations are not runtime code; many API objects are CLJS proxies infrontend/src/app/plugins/*.cljs.
Sandbox and global cleanup
- The runtime uses SES compartments. Public API return values are passed through
ses.safeReturnbefore crossing back to plugin code. - Plugin
fetchis sanitized: credentials are omitted and Authorization is blanked. The exposed response only includes ok/status/statusText/url/text/json. - Timer callbacks are wrapped to mark plugin-originated errors, and timeout/interval IDs are tracked so plugin close can clear them.
- Plugin-originated errors are tracked in a WeakMap instead of mutating error objects, because SES can freeze errors.
- Closing a plugin removes public API keys from the compartment globalThis.
Lifecycle
- Loading a plugin closes existing non-background plugins and resets the runtime registry. Be careful around
allowBackgroundsemantics when changing load/close behavior. - If sandbox evaluation fails, the runtime marks the error as plugin-originated, closes the plugin, and rethrows.
plugin-managerremoves event listeners, timers, intervals, and modal state on close, and marks the plugin destroyed. Listener callbacks check that flag because Penpot events can fire after close.
Modal/UI behavior
- Modal URL preparation differs by manifest version: v1 uses query string parameters, v2 puts parameters in the URL hash.
openModalis idempotent for the same iframe source and avoids reopening when the target URL is already displayed.- Modal permissions are derived from manifest permissions (
allow:downloads,clipboard:read,clipboard:write). resizeModalclamps to at least 200x200 and at most the window minus margins, adjusting transform so the modal remains in the viewport.