npm package discovery and stats viewer.

Discover Tips

  • General search

    [free text search, go nuts!]

  • Package details

    pkg:[package-name]

  • User packages

    @[username]

Sponsor

Optimize Toolset

I’ve always been into building performant and accessible sites, but lately I’ve been taking it extremely seriously. So much so that I’ve been building a tool to help me optimize and monitor the sites that I build to make sure that I’m making an attempt to offer the best experience to those who visit them. If you’re into performant, accessible and SEO friendly sites, you might like it too! You can check it out at Optimize Toolset.

About

Hi, 👋, I’m Ryan Hefner  and I built this site for me, and you! The goal of this site was to provide an easy way for me to check the stats on my npm packages, both for prioritizing issues and updates, and to give me a little kick in the pants to keep up on stuff.

As I was building it, I realized that I was actually using the tool to build the tool, and figured I might as well put this out there and hopefully others will find it to be a fast and useful way to search and browse npm packages as I have.

If you’re interested in other things I’m working on, follow me on Twitter or check out the open source projects I’ve been publishing on GitHub.

I am also working on a Twitter bot for this site to tweet the most popular, newest, random packages from npm. Please follow that account now and it will start sending out packages soon–ish.

Open Software & Tools

This site wouldn’t be possible without the immense generosity and tireless efforts from the people who make contributions to the world and share their work via open source initiatives. Thank you 🙏

© 2026 – Pkg Stats / Ryan Hefner

@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-sdk

Setup

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 hostOrigin is 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 via openModal. closeHostContainer closes 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 | .Asset

Versioning

The SDK version is available at runtime via ExtensionSdkVersion:

import { ExtensionSdkVersion } from '@structdk/extension-sdk';

console.log('SDK version:', ExtensionSdkVersion);

License

MIT