@structdk/extension-sdk
v1.0.6
Published
Framework agnostic SDK for building Struct extensions
Readme
@structdk/extension-sdk
SDK for building extensions for Struct PIM. Extensions run as iframes embedded inside the Struct PIM UI and communicate with the host via a postMessage-based API. This SDK abstracts that messaging layer into a simple, typed API.
Installation
npm install @structdk/extension-sdkSetup
Create an SDK instance using createStructSDK. Optionally pass the hostOrigin of your Struct PIM instance to restrict message acceptance to that origin only.
import { createStructSDK } from '@structdk/extension-sdk';
const struct = createStructSDK({ hostOrigin: 'https://your-struct-instance.struct.com' });If
hostOriginis not provided, all origins are accepted and a warning is printed to the console.
The returned object exposes actions, events, and a destroy() cleanup function.
Actions (struct.actions)
Actions are messages sent from your extension to Struct PIM.
getContext
Requests the current context from Struct PIM. Returns a promise that resolves with the context payload for the current extension point. This is the primary way to retrieve the session context (slug, language, user, entity info, etc.).
import { createStructSDK } from '@structdk/extension-sdk';
import type { TabContextPayload } from '@structdk/extension-sdk';
const struct = createStructSDK();
const ctx = await struct.actions.getContext<TabContextPayload>();
console.log('Entity:', ctx.entityType, ctx.entityId);
console.log('Slug:', ctx.slug);An optional GetContextOptions object can be passed to override the default timeout (10 000 ms):
const ctx = await struct.actions.getContext<TabContextPayload>({ timeoutMs: 5000 });The context payload type depends on the extension point. Use the appropriate typed payload for full type safety:
| Extension point | Payload type | Extra fields |
|-------------------|-------------------------------|-----------------------------------------------|
| Tab | TabContextPayload | entityId, entityType |
| Section | SectionContextPayload | entityId, entityType |
| Sidebar widget | SidebarWidgetContextPayload | entityId, entityType |
| Property | PropertyContextPayload | entityId, entityType |
| Exporter | ExporterContextPayload | selectedEntityIds, selectedEntityType |
| Search action | SearchActionContextPayload | selectedEntityIds, selectedEntityType |
| Page | PageContextPayload | (none) |
| Widget | WidgetContextPayload | (none) |
All payload types extend BaseContextPayload, which includes: messagingVersion, slug, currentLanguage?, currentUser?, currentSegments?.
openModal
Opens a modal inside the Struct PIM UI, rendering a URL in an iframe.
struct.actions.openModal({
id: 'my-modal',
url: 'https://your-extension.example.com/modal',
placement: 'center', // 'center' | 'left' | 'right'
size: 'medium', // 'small' | 'medium' | 'large'
});closeModal
Closes an open modal by its ID.
struct.actions.closeModal({ id: 'my-modal' });closeHostContainer
Asks the Struct PIM host to close the dialog that is currently hosting your extension iframe (e.g. the export-entities dialog or a search-action dialog). Use this when your extension has finished its work and the surrounding host dialog should be dismissed.
struct.actions.closeHostContainer();Only supported on the Exporter and SearchAction extension points — these are the only extension points whose iframes are embedded inside a dismissible host dialog. On any other extension point the host fires onActionRejectedEvent with reason Action "CLOSE_HOST_CONTAINER" is not supported for extension point type "<type>".
Not to be confused with
closeModal, which only closes a modal that the same extension previously opened viaopenModal.closeHostContainercloses the host dialog that contains the extension iframe itself.
showSnackbarMessage
Displays a snackbar notification in the Struct PIM UI.
struct.actions.showSnackbarMessage({
message: 'Changes saved successfully',
placement: 'bottom', // 'top' | 'bottom'
isError: false,
durationMs: 3000, // optional
});resizeContainer
Manually sets the iframe container height in pixels. Supported on Tab, Section, Property, and Sidebar Widget extension points.
struct.actions.resizeContainer({ height: 400 });enableAutoResize
Automatically adjusts the iframe height based on content using a ResizeObserver. Only one auto-resize observer can be active at a time. Supported on Tab, Section, Property, and Sidebar Widget extension points.
struct.actions.enableAutoResize({
maxHeight: 800, // optional — cap the height
debounceMs: 200, // optional — debounce delay (default 100ms)
});Events (struct.events)
Events are messages sent from Struct PIM to your extension. Each listener returns an unsubscribe function.
onEntityChangedEvent
Fired whenever the entity the extension is associated with is saved/updated. Relevant for tab, section, sidebar widget, and property extension points.
const unsubscribe = struct.events.onEntityChangedEvent((payload) => {
console.log(payload.entityType, 'with id', payload.entityId, 'changed');
});onLanguageChangedEvent
Fired whenever the user switches the active language in Struct PIM. Use this to re-fetch localized data or update the UI.
struct.events.onLanguageChangedEvent((payload) => {
console.log('Language changed to:', payload.currentLanguage);
});onSegmentChangedEvent
Fired whenever the active segment selection changes in Struct PIM.
struct.events.onSegmentChangedEvent((payload) => {
console.log('Segments changed:', payload.currentSegments);
});onActionRejectedEvent
Fired when the host rejects an action (e.g., a resize on an unsupported extension point).
struct.events.onActionRejectedEvent((payload) => {
console.warn(`Action rejected: ${payload.rejectedAction} — ${payload.reason}`);
});Cleanup
Call destroy() to unsubscribe all event listeners and stop any active auto-resize observer.
struct.destroy();Quick start
A minimal extension that retrieves its context and listens for changes:
import { createStructSDK } from '@structdk/extension-sdk';
import type { TabContextPayload } from '@structdk/extension-sdk';
// 1. Create SDK instance (optionally lock to a specific origin)
const struct = createStructSDK({ hostOrigin: 'https://your-struct-instance.struct.com' });
// 2. Request context from the host
const ctx = await struct.actions.getContext<TabContextPayload>();
console.log('Entity:', ctx.entityType, ctx.entityId);
console.log('Slug:', ctx.slug);
// 3. Auto-resize the iframe to fit content
struct.actions.enableAutoResize({ maxHeight: 800 });
// 4. Register event listeners for ongoing changes
struct.events.onEntityChangedEvent((payload) => {
console.log('Entity updated:', payload.entityId);
});
struct.events.onLanguageChangedEvent((payload) => {
console.log('Language:', payload.currentLanguage);
});
// 5. Clean up when done
struct.destroy();Types
All payload types are exported from the package root:
import type {
// SDK options
StructSDKOptions,
// Context payloads
BaseContextPayload,
TabContextPayload,
SectionContextPayload,
SidebarWidgetContextPayload,
PropertyContextPayload,
ExporterContextPayload,
SearchActionContextPayload,
PageContextPayload,
WidgetContextPayload,
// Event payloads
EntityChangedPayload,
LanguageChangedPayload,
SegmentChangedPayload,
ActionRejectedPayload,
// Action payloads
OpenModalPayload,
CloseModalPayload,
CloseHostContainerPayload,
ShowSnackbarMessagePayload,
ResizeContainerPayload,
// Options
AutoResizeOptions,
GetContextOptions,
} from '@structdk/extension-sdk';The StructEntityType enum is also exported:
import { StructEntityType } from '@structdk/extension-sdk';
// StructEntityType.Product | .Category | .Variant | .VariantGroup | .AssetVersioning
The SDK version is available at runtime via ExtensionSdkVersion:
import { ExtensionSdkVersion } from '@structdk/extension-sdk';
console.log('SDK version:', ExtensionSdkVersion);License
MIT
