@port-labs/plugins-sdk
v0.0.1
Published
Framework-agnostic SDK for Port embedded plugins (postMessage host bridge, page filter merge); optional React helpers under /react
Keywords
Readme
@port-labs/plugins-sdk
TypeScript/JavaScript SDK for Port custom plugins running inside the Port web app (usually in an iframe). For React, use usePortPluginData from @port-labs/plugins-sdk/react. For other stacks, the same host context is available via a small subscribe / snapshot store and synchronous getters. The package also helps merge dashboard page filters into Port entity-search queries (mergePageFilters).
Install
npm install @port-labs/plugins-sdkyarn add @port-labs/plugins-sdkpnpm add @port-labs/plugins-sdkOptional peer: react ≥ 18 — only required if you import @port-labs/plugins-sdk/react.
Node: use an LTS version compatible with your bundler; this package declares engines.node ≥ 22.
What it does
- Listens for messages from the Port host (
PORT_TOKEN,PLUGIN_DATA). - When embedded in an iframe, asks the parent once for a token (
REQUEST_PORT_TOKEN). - Exposes the latest host payload through
usePortPluginData(React) or getters andsubscribe+getSnapshot(Vue, Svelte, Solid, vanilla JS, etc.). - Provides
mergePageFiltersto combine your widget’s entity-search body with the page’s filter rules.
Host protocol
Your plugin and the Port UI must agree on these messages:
| Direction | event.data.type | Payload / role |
| ------------- | -------------------- | --------------------------------------- |
| Plugin → host | REQUEST_PORT_TOKEN | Ask the host for a JWT for Port API calls. |
| Host → plugin | PORT_TOKEN | { token: string } |
| Host → plugin | PLUGIN_DATA | { params, page, user, entity, baseUrl, theme? } |
Getters expose: params, page, user, entity, theme (via getParams(), getPage(), …), plus getToken() and getPortApiBaseUrl() (same data as PLUGIN_DATA plus the token). Call applyThemeCss() to inject the host theme stylesheet (see Theming and CSS variables).
Usage
React
Install react ≥ 18, then import from @port-labs/plugins-sdk/react:
npm install reactimport { usePortPluginData } from '@port-labs/plugins-sdk/react';
function MyPlugin() {
const { portToken, portApiBaseUrl, page, user, entity, params } = usePortPluginData();
if (!portToken) return <p>Waiting for host…</p>;
return (
<pre>{JSON.stringify({ page, user, entity, params }, null, 2)}</pre>
);
}To match the Port UI colors, opt in to host theme CSS with applyThemeCss from the same hook (see Theming and CSS variables).
Other frameworks (store + getters)
The same host data is available without React. Call initPortPluginMessaging() once early if you want (getters and subscribe call it automatically). Use subscribe(listener) to re-run when the host sends new data; read state with getSnapshot(). getServerSnapshot() is for SSR (empty static snapshot).
import {
getSnapshot,
getToken,
subscribe,
type PluginHostState,
} from '@port-labs/plugins-sdk';
function bindHostToView(update: (state: PluginHostState) => void) {
const unsub = subscribe(() => update(getSnapshot()));
update(getSnapshot());
return unsub;
}Synchronous reads anywhere (no extra listeners):
import { getToken, getPortApiBaseUrl } from '@port-labs/plugins-sdk';
async function callPortSearch(body: unknown) {
const token = getToken();
const base = getPortApiBaseUrl();
if (!token || !base) throw new Error('Plugin not ready');
// …
}Merging page filters with a widget search query
Use mergePageFilters so results respect both the widget query and the dashboard page filters (page.pageFilters). Types such as EntitiesQuery, PageQuery, and Blueprint are exported from this package for typing your query and blueprint objects.
import { getPage, mergePageFilters, type Blueprint, type EntitiesQuery } from '@port-labs/plugins-sdk';
const widgetQuery: EntitiesQuery = {
combinator: 'and',
rules: [/* your rules */],
};
const merged = mergePageFilters(widgetQuery, getPage()?.pageFilters, blueprint as Blueprint);mergeWidgetQueryWithPageQuery is an alias for mergePageFilters. The constant DASHBOARD_FILTERS_META_BLUEPRINT identifies dashboard-wide filter rules in page filter arrays.
Theming and CSS variables
The host can send a theme object on PLUGIN_DATA:
type Theme = {
mode: string;
css: string; // `:root { --background-primary: ...; --text-high: ...; }`
};The SDK stores this on theme in the snapshot and from usePortPluginData(). To opt in to applying the host theme CSS, call applyThemeCss() (from the main package or via the hook):
import { useEffect } from 'react';
import { usePortPluginData } from '@port-labs/plugins-sdk/react';
function MyPlugin() {
const { applyThemeCss } = usePortPluginData();
useEffect(() => {
applyThemeCss();
}, [applyThemeCss]); // `applyThemeCss` identity updates when host `theme.css` changes
// …
}Vanilla / non-React:
import { applyThemeCss, subscribe } from '@port-labs/plugins-sdk';
subscribe(() => {
applyThemeCss();
});
applyThemeCss();This injects a <style id="port-plugin-theme"> tag with the theme’s css into document.head. If the host omits theme or css, that element is removed.
In your own CSS, consume variables with safe fallbacks, for example:
body {
background: rgb(var(--primary, 245, 247, 250));
color: var(--text-high, #1a1a2e);
}
.plugin-container {
background: var(--background-primary, #fff);
}
.data-row {
background: var(--background-contrast, #fff);
border-color: var(--border-contrast-medium, #e2e8f0);
}Common variables you can reuse include (non-exhaustive):
--background-primary: main surface/background color--background-dim/--background-dim-transparent: softer backgrounds and cards--background-contrast: high-contrast surface--text-high/--text-medium/--text-low: primary, secondary, and subtle text--border-medium/--border-contrast-medium: border colors--primary: RGB triple for the primary color, used viargb(var(--primary))
API overview
React entry (@port-labs/plugins-sdk/react)
| Export | Description |
| ------ | ----------- |
| usePortPluginData | Hook backed by useSyncExternalStore over the same store as the main entry. Includes theme and applyThemeCss (identity updates when theme.css changes so useEffect(..., [applyThemeCss]) reapplies styles). |
| Types | Re-exported for convenience: Theme, PluginHostState, Page, User, Entity, Params (same as the main entry). |
Main entry (@port-labs/plugins-sdk)
| Export | Description |
| ------ | ----------- |
| getToken, getUser, getEntity, getPage, getParams, getPortApiBaseUrl, getTheme | Read the current snapshot. |
| applyThemeCss | Apply or clear host theme CSS in document.head (#port-plugin-theme). |
| initPortPluginMessaging | Ensures the listener is registered (also run automatically by getters and subscribe). |
| subscribe, getSnapshot, getServerSnapshot | Framework-agnostic reactive core (subscribe notifies; getSnapshot reads). |
| mergePageFilters | AND-merge widget EntitiesQuery with page filters and blueprint rules. |
| mergeWidgetQueryWithPageQuery | Alias for mergePageFilters. |
| Types | Host context: Page, User, Entity, Params, Theme, PluginHostState. Search/blueprint: EntitiesQuery, PageQuery, Blueprint, AnyEntitiesQueryRule, PluginParamType, PluginParamValue, … |
License
ISC
