@weavix/sdk-core
v0.0.40
Published
Framework-agnostic plugin SDK runtime — host API, event system, UI helpers, and shared storage.
Readme
@weavix/sdk-core
Framework-agnostic plugin SDK runtime — host API, event system, UI helpers, and shared storage.
This package is a base layer. Domain-specific SDK packages (e.g.
@weavix/tracker-plugin-sdk) build typed wrappers on top of it. If you are building a Tracker plugin, you likely want that package instead.
Installation
npm install @weavix/sdk-coreQuick start
import { hostApi, uiApi, on } from '@weavix/sdk-core';
// Initialize the bridge (must be called first)
hostApi.init({ autoResize: true });
// Subscribe to host events
on('theme.changed', (theme) => {
document.body.dataset.theme = theme;
});
// Notify the host that the plugin is ready
await hostApi.notifyReady();hostApi
Singleton for communicating with the host. Call hostApi.init() before using any other method.
hostApi.init(options)
Initializes the plugin: reads parameters from the URL and sets up the postMessage bridge.
hostApi.init({ autoResize: true });| Parameter | Type | Default | Description |
|-----------|------|---------|-------------|
| autoResize | boolean | true | Automatically resize the iframe height when content changes |
Call once at plugin startup.
Reading context
const theme = await hostApi.getTheme(); // 'light' | 'light-hc' | 'dark' | 'dark-hc' | 'system' | undefined
const lang = await hostApi.getLanguage(); // 'ru' | 'en' | ...
const userId = await hostApi.getUserId(); // string | undefined
const orgId = await hostApi.getOrgId(); // string | undefined
const isYateam = await hostApi.getIsYateam(); // boolean
const isOrbita = await hostApi.getIsOrbita(); // boolean
const ctx = await hostApi.getContext(); // depends on the slotSynchronous getters (available after init())
const slot = hostApi.getSlot(); // string — current slot name
const service = hostApi.getService(); // string — service identifier
const queryParams = hostApi.getQueryParams(); // Record<string, string>
const entityId = hostApi.getEntityId(); // string | null
const entityMeta = hostApi.getEntityMeta(); // Record<string, string> | undefined
const ctxLevel = hostApi.getContextLevel(); // 'basic' | 'full'Plugin lifecycle
// Notify the host that the plugin is ready to display
await hostApi.notifyReady();
// Explicitly set the container height
await hostApi.updateContentSize({ height: 500 });
// Disable auto-resize
hostApi.disableAutoResize();
// Ask the host to close the plugin
await hostApi.close({ reason: 'done' });
// Block / unblock host-initiated close
await hostApi.preventClose({ prevent: true });External APIs
Proxy for calling third-party HTTP APIs through the host. Domains are declared in the plugin manifest (permissions.external).
import { hostApi } from '@weavix/sdk-core';
// Check and request credentials via dialog if needed
const { success } = await hostApi.externalApiAuthCheckAndRequest({
domains: ['api.example.com'],
});
if (!success) return;
// Proxy HTTP request through the host
const { status, body } = await hostApi.externalApiCall({
url: 'https://api.example.com/v1/items',
method: 'GET',
});hostApi.externalApiAuthGetStatus(payload)
| Parameter | Type | Default | Description |
|-----------|------|---------|-------------|
| domains | string[] \| undefined | all plugin domains | Domains to check |
| contextType | 'user' \| 'organization' \| undefined | — | Credential context type |
Returns Promise<{ domains: ExternalApiAuthGetStatusDomain[] }>.
hostApi.externalApiAuthRequest(payload)
| Parameter | Type | Description |
|-----------|------|-------------|
| domains | ExternalApiDomainInfo[] | Domains with optional dialog hints |
ExternalApiDomainInfo:
| Field | Type | Description |
|-------|------|-------------|
| domain | string | Domain from the manifest |
| instructions | string \| { en?: string; ru?: string } | Optional dialog hint |
Returns Promise<{ success: boolean }>. success: false means the user dismissed the dialog or the timeout (~5 minutes) elapsed.
hostApi.externalApiAuthRevoke(payload)
| Parameter | Type | Description |
|-----------|------|-------------|
| domains | string[] | Domains to revoke (at least one) |
| contextType | 'user' \| 'organization' \| undefined | Credential context type |
Returns Promise<{ success: boolean }>.
hostApi.externalApiAuthCheckAndRequest(payload)
Combines getStatus + request for unauthenticated domains only. Parameters are identical to externalApiAuthGetStatus.
Returns Promise<{ success: boolean }>. Returns { success: true } immediately if all domains are already authenticated.
hostApi.externalApiCall(payload)
| Parameter | Type | Default | Description |
|-----------|------|---------|-------------|
| url | string | — | Full request URL (required) |
| method | 'GET' \| 'POST' \| 'PUT' \| 'PATCH' \| 'DELETE' | — | HTTP method (required) |
| headers | Record<string, string> | — | Additional headers |
| body | Record<string, unknown> | — | Request body |
| timeoutMs | number | — | Timeout in milliseconds |
| contextType | 'user' \| 'organization' \| undefined | — | Credential context |
Returns Promise<{ status: number; headers?: Record<string, string>; body?: Record<string, unknown> }>.
On proxy error, throws PluginActionError with code EXTERNAL_API_CALL_ERROR (1013).
uiApi
Host UI methods: navigation, toast notifications, confirmation dialog.
uiApi.navigate(request)
Opens a path in the host application or an external URL.
import { uiApi } from '@weavix/sdk-core';
await uiApi.navigate({
path: '/queues/MYQUEUE',
params: { tab: 'settings' },
options: { newTab: true },
});| Field | Type | Description |
|-------|------|-------------|
| path | string | Path or URL (required) |
| params | QueryParams | Query parameters |
| options.newTab | boolean | Open in a new tab |
uiApi.toaster.add(options)
Shows a toast notification in the host application.
Permission: Requires
"toaster"inpermissions.uiof the plugin manifest.
import { uiApi } from '@weavix/sdk-core';
// Simple toast
uiApi.toaster.add({ title: 'Saved', theme: 'success' });
// Toast with action
uiApi.toaster.add({
title: 'Item deleted',
theme: 'info',
content: 'QUEUE-123',
actions: [
{ label: 'Undo', onClick: () => { /* handle */ } },
],
});| Parameter | Type | Default | Description |
|-----------|------|---------|-------------|
| title | string | — | Toast title (required, max 200 chars) |
| name | string | auto | Unique key for deduplication |
| theme | 'success' \| 'danger' \| 'warning' \| 'info' | 'info' | Theme |
| content | string | — | Body text (max 500 chars) |
| autoHiding | number | 5000 | Display time in ms (1000–30000) |
| isClosable | boolean | true | Show close button |
| actions | ToastAction[] | — | Action buttons (max 2) |
ToastAction:
| Field | Type | Description |
|-------|------|-------------|
| label | string | Button label (max 50 chars) |
| onClick | () => void | Click callback |
Returns Promise<{ name: string }>.
uiApi.confirm.show(options)
Shows a confirmation dialog.
Permission: Requires
"confirm"inpermissions.uiof the plugin manifest.
import { uiApi } from '@weavix/sdk-core';
const { confirmed } = await uiApi.confirm.show({
title: 'Delete issue?',
message: 'This action cannot be undone.',
textButtonApply: 'Delete',
textButtonCancel: 'Cancel',
theme: 'danger',
});
if (confirmed) {
// perform deletion
}| Parameter | Type | Default | Description |
|-----------|------|---------|-------------|
| message | string | — | Dialog body text (required) |
| title | string | — | Dialog title |
| textButtonApply | string | — | Confirm button label |
| textButtonCancel | string | — | Cancel button label |
| theme | 'normal' \| 'danger' | 'normal' | Confirm button theme |
Returns Promise<{ confirmed: boolean }>. Timeout: 5 minutes.
storageApi
Organisation-level JSON storage. Data is shared across all plugin users in the organisation; write permission is determined by the host via the canWrite field in the response.
Currently the only available context is storageApi.orgShared.
storageApi.orgShared.get(bucket?)
import { storageApi } from '@weavix/sdk-core';
const record = await storageApi.orgShared.get('settings');
// record: StorageRecord | null
// { key, version, data, canWrite, createdAt, updatedAt }| Parameter | Type | Default | Description |
|-----------|------|---------|-------------|
| bucket | string \| undefined | 'default' (set by host) | Record key |
Returns Promise<StorageRecord | null>.
storageApi.orgShared.patch(options)
Merge-patch: fields from data are merged onto the current record. A null value deletes the key. Returns the full merged StorageRecord with the new version.
// Create a record
await storageApi.orgShared.patch({
bucket: 'settings',
data: { theme: 'dark', notifications: true },
version: 0,
});
// Update without explicit version — SDK resolves conflicts automatically
await storageApi.orgShared.patch({
bucket: 'settings',
data: { count: 42 },
});
// Delete a field — pass null
await storageApi.orgShared.patch({
bucket: 'settings',
data: { theme: null },
});| Parameter | Type | Default | Description |
|-----------|------|---------|-------------|
| bucket | string | 'default' (set by host) | Record key |
| data | Record<string, unknown> | — | Merge-doc; null deletes a field |
| version | number \| undefined | auto-resolve | Expected current version |
Versioning modes:
- With explicit
version— single request;VERSION_CONFLICTis thrown to the caller. Passversion: 0to create a new record. - Without
version— SDK reads the current version viaget, then patches. Retries up to 2 times onVERSION_CONFLICT. Worst case: 6 round-trips.
Storage types
import type {
StorageContextType, // 'orgShared'
StorageRecord, // { key, version, data, canWrite, createdAt, updatedAt }
} from '@weavix/sdk-core';Events
The host can push events to the plugin. Subscribe via on() or eventBus.on().
Last-value cache: if an event was already dispatched before a subscription, the callback is invoked synchronously with the cached value at subscription time.
on(method, callback)
import { on } from '@weavix/sdk-core';
const unsubscribe = on('theme.changed', (theme) => {
console.log('Theme:', theme);
});
// Unsubscribe
unsubscribe();eventBus.on(method, callback)
import { eventBus } from '@weavix/sdk-core';
const unsubscribe = eventBus.on('language.changed', (lang) => {
console.log('Language:', lang);
});Supported events
| Method | Payload type | Description |
|--------|-------------|-------------|
| theme.changed | Theme | Host theme changed |
| language.changed | string | Host language changed |
| userId.changed | string | User ID changed |
| orgId.changed | string | Organisation ID changed |
| isYateam.changed | boolean | Yandex-Team flag changed |
| isOrbita.changed | boolean | Orbita flag changed |
| context.changed | Record<string, unknown> | Slot context changed |
| toast.action.clicked | { name: string; actionId: string } | Toast action button clicked |
Utilities
getLocalizedString(value, language?)
Resolves a LocalizedString (a plain string or { ru, en, ... } object) for the given language.
import { getLocalizedString } from '@weavix/sdk-core';
const label = getLocalizedString({ ru: 'Задача', en: 'Issue' }, 'en'); // 'Issue'
const plain = getLocalizedString('plain string', 'en'); // 'plain string'getField(obj, path)
Safely reads a nested field of an object by dot-separated path.
import { getField } from '@weavix/sdk-core';
const value = getField({ a: { b: 42 } }, 'a.b'); // 42Error handling
All SDK method errors are instances of PluginActionError with a numeric error code.
import { PluginActionError, VERSION_CONFLICT } from '@weavix/sdk-core';
try {
await storageApi.orgShared.patch({ bucket: 'cfg', data: { x: 1 }, version: 0 });
} catch (e) {
if (e instanceof PluginActionError) {
console.log(e.code, e.message, e.errorData);
}
}Error codes
| Code | Constant | When |
|------|----------|------|
| 1002 | VALIDATION_ERROR | Request data failed validation |
| 1003 | METHOD_NOT_SUPPORTED | Method not supported in this configuration |
| 1004 | MISSING_REQUIRED_SCOPE | Plugin lacks the required permission scope |
| 1005 | CONTEXT_ERROR | Failed to fetch or parse slot context |
| 1007 | RATE_LIMIT_EXCEEDED | Request rate limit exceeded |
| 1008 | CONFIRM_ALREADY_OPEN | A confirmation dialog is already open |
| 1010 | VERSION_CONFLICT | Storage record version mismatch |
| 1011 | DATA_TOO_LARGE | Data exceeds 256 KiB |
| 1012 | BAD_KEY | Bucket key failed validation |
| 1013 | EXTERNAL_API_CALL_ERROR | External API proxy call failed |
Related packages
| Package | Purpose |
|---------|---------|
| @weavix/sdk-react | React wrapper: PluginProvider, hooks |
| @weavix/tracker-plugin-sdk | Typed wrapper for Tracker plugins (recommended) |
| @weavix/tracker-plugin-sdk-react | React integration for Tracker plugins |
| @weavix/tracker-api-types | Tracker Public API v3 types |
License
SEE LICENSE IN LICENSE
