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

@weavix/tracker-plugin-sdk

v0.1.7

Published

Core package for Tracker plugin SDK

Readme

@weavix/tracker-plugin-sdk

Core package for Tracker plugins (Weavix / npm).

Provides low-level host API, typed Tracker Public API proxy, UI helpers, shared storage, and event system.

For React applications, use @weavix/tracker-plugin-sdk-react — it provides TrackerPluginProvider, useTrackerPluginContext, hooks, and all exports from this package.

Installation

npm install @weavix/tracker-plugin-sdk

Peer dependencies: @weavix/tracker-api-plugin, @weavix/tracker-core.

Quick start

import { hostApi, trackerApi } from '@weavix/tracker-plugin-sdk';

// Initialise the plugin bridge (call once at startup)
hostApi.init({ autoResize: true });

// Get current theme
const theme = await hostApi.getTheme(); // 'light' | 'light-hc' | 'dark' | 'dark-hc' | 'system' | undefined

// Get current language
const language = await hostApi.getLanguage(); // 'ru' | 'en' | undefined

// Get slot context (e.g. current issue for slot 'issue.action')
const context = await hostApi.getContext();

// Notify the host that the plugin is ready
await hostApi.notifyReady();

// Resize the plugin container
await hostApi.updateContentSize({ height: 500 });

Tracker API

All Tracker Public API calls go through trackerApi.v3 — a typed proxy over HTTP methods. Keys are OpenAPI endpoint paths from @weavix/tracker-api-types; the IDE provides autocomplete and JSDoc.

Full endpoint reference: Tracker API Reference.

import { trackerApi } from '@weavix/tracker-plugin-sdk';

// GET — returns { data, headers }
const { data: issue } = await trackerApi.v3.get['/issues/{id}']({
  pathParams: { id: 'QUEUE-123' },
  queryParams: { expand: ['COMMENTS'] },
});

// POST
await trackerApi.v3.post['/v2/issues']({
  bodyParams: { queue: { key: 'TASK' }, summary: 'New issue' },
});

// PATCH
await trackerApi.v3.patch['/v2/issues/{id}']({
  pathParams: { id: 'QUEUE-123' },
  bodyParams: { summary: 'Updated title' },
});

// DELETE
await trackerApi.v3.delete['/v2/issues/{id}']({
  pathParams: { id: 'QUEUE-123' },
});

Queues

// List queues
const { data: queues } = await trackerApi.v3.get['/v2/queues']({
  queryParams: { page: 1, perPage: 100 },
});

// Get a specific queue
const { data: queue } = await trackerApi.v3.get['/v2/queues/{id}']({
  pathParams: { id: 'MYQUEUE' },
});

Issues

// Get issue by key
const { data: issue } = await trackerApi.v3.get['/issues/{id}']({
  pathParams: { id: 'QUEUE-123' },
});

// Create issue
const { data: newIssue } = await trackerApi.v3.post['/v2/issues']({
  bodyParams: {
    queue: { key: 'QUEUE' },
    summary: 'Issue title',
  },
});

// Search issues
const { data: issues } = await trackerApi.v3.post['/v2/issues/_search']({
  bodyParams: { filter: { queue: 'QUEUE' } },
});

hostApi

Singleton for communicating with the host. Call hostApi.init() before using any other method.

hostApi.init(options)

| Parameter | Type | Default | Description | |-----------|------|---------|-------------| | autoResize | boolean | true | Automatically resize the iframe height when content changes |

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 ctx      = await hostApi.getContext();     // SlotContextMap[slot]

Synchronous 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

await hostApi.notifyReady();
await hostApi.updateContentSize({ height: 500 });
hostApi.disableAutoResize();
await hostApi.close({ reason: 'done' });
await hostApi.preventClose({ prevent: true });

Toast notifications

Show toast notifications in the host application via uiApi.toaster.

Permission: Requires "toaster" in permissions.ui of the plugin manifest.

import { uiApi } from '@weavix/tracker-plugin-sdk';

// Simple toast
uiApi.toaster.add({
  title: 'Saved',
  theme: 'success',
});

// Toast with body text and custom duration
uiApi.toaster.add({
  title: 'Error',
  theme: 'danger',
  content: 'Failed to load data',
  autoHiding: 10000,
});

// Toast with action button
uiApi.toaster.add({
  title: 'Item deleted',
  theme: 'info',
  content: 'QUEUE-123',
  actions: [
    {
      label: 'Undo',
      onClick: () => {
        // handle click
      },
    },
  ],
});

uiApi.toaster.add(options)

| 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 }>.

Limits:

  • title — max 200 chars
  • content — max 500 chars
  • actions — max 2 buttons
  • Rate limit — 5 toasts per 10 seconds per plugin

Navigation

Open a path in the host application or an external URL via uiApi.navigate:

import { uiApi } from '@weavix/tracker-plugin-sdk';

await uiApi.navigate({
  path: '/queues/MYQUEUE',
  params: { tab: 'settings' },
  options: { newTab: true },
});

| Field | Type | Description | |-------|------|-------------| | path | string | Path or URL (required) | | params | Record<string, string \| number \| boolean \| null \| undefined \| (string \| number \| boolean \| null \| undefined)[]> | Query parameters | | options.newTab | boolean | Open in a new tab |

TrackerPluginProvider (React) intercepts external link clicks in the iframe and calls uiApi.navigate.


Storage API

storageApi — organisation-level JSON storage mediated by the host. Data is shared across all plugin users in the organisation; write permission is determined by the host via the canWrite field.

Currently the only available context is storageApi.orgShared.

import { storageApi } from '@weavix/tracker-plugin-sdk';

// Read
const record = await storageApi.orgShared.get('settings');
// record: { data: { theme: 'dark' }, version: 5, canWrite: true, ... } | null

// Create a new record
await storageApi.orgShared.patch({
  bucket: 'settings',
  data: { theme: 'dark', notifications: true },
  version: 0,
});

// Update without knowing the current version — SDK reads it and retries on conflict
await storageApi.orgShared.patch({
  bucket: 'settings',
  data: { count: 42 },
});

// Delete a field — pass null
await storageApi.orgShared.patch({
  bucket: 'settings',
  data: { theme: null },
});

storageApi.orgShared.get(bucket?)

Returns Promise<StorageRecord | null>.

| Parameter | Type | Default | Description | |-----------|------|---------|-------------| | bucket | string \| undefined | 'default' (set by host) | Record key |

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.

| 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:

  • With explicit version — single request; VERSION_CONFLICT is thrown to the caller. Pass version: 0 to create a new record.
  • Without version — SDK reads the current version, then patches. Retries up to 2 times on VERSION_CONFLICT (writes console.warn on each retry). Worst case: 6 round-trips.

Storage errors

| Code | Constant | When | |------|----------|------| | 1010 | VERSION_CONFLICT | Provided version does not match current | | 1011 | DATA_TOO_LARGE | Record size exceeds 256 KiB after the operation | | 1012 | BAD_KEY | bucket failed format or length validation |

import { PluginActionError, VERSION_CONFLICT, storageApi } from '@weavix/tracker-plugin-sdk';

try {
  await storageApi.orgShared.patch({ bucket: 'settings', data: { x: 1 }, version: 0 });
} catch (e) {
  if (e instanceof PluginActionError && e.code === VERSION_CONFLICT) {
    // notify the user that the version is stale
  }
}

Storage types

import type {
  StorageContextType, // 'orgShared'
  StorageRecord,      // { key, version, data, canWrite, createdAt, updatedAt }
  StorageGetPayload,
  StoragePatchPayload,
} from '@weavix/tracker-plugin-sdk';

External APIs

hostApi methods for calling external APIs through the host proxy. Domains and auth schemes are configured in permissions.external in the plugin manifest.

Direct fetch calls from the plugin are blocked by CSP — use the proxy.

import { hostApi } from '@weavix/tracker-plugin-sdk';

// Check if the user has credentials; show dialog if not
const { success } = await hostApi.externalApiAuthCheckAndRequest({
  domains: ['api.example.com'],
});
if (!success) {
  // user dismissed the dialog or timeout elapsed
  return;
}

// Proxy HTTP request — host injects auth headers
const { status, body } = await hostApi.externalApiCall({
  url: 'https://api.example.com/v1/items',
  method: 'GET',
});

Typical flow: externalApiAuthCheckAndRequest (or externalApiAuthGetStatus + externalApiAuthRequest) → externalApiCall. To revoke saved credentials: externalApiAuthRevoke.

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 (required, at least one) |

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. Timeout: ~5 minutes.

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); details in errorData (status, message, code, title).

External API errors

| Code | Constant | When | |------|----------|------| | 1013 | EXTERNAL_API_CALL_ERROR | externalApiCall proxy call failed |

import { EXTERNAL_API_CALL_ERROR, PluginActionError, hostApi } from '@weavix/tracker-plugin-sdk';

try {
  await hostApi.externalApiCall({ url: 'https://api.example.com/x', method: 'GET' });
} catch (e) {
  if (e instanceof PluginActionError && e.code === EXTERNAL_API_CALL_ERROR) {
    console.log(e.errorData);
  }
}

Error handling

import { trackerApi, PluginActionError } from '@weavix/tracker-plugin-sdk';

try {
  await trackerApi.v3.get['/issues/{id}']({ pathParams: { id: 'BAD' } });
} 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 |


API summary

hostApi

  • init(options?) — initialise the plugin bridge. Call once before all other methods.
  • getTheme() — current theme ('light' | 'light-hc' | 'dark' | 'dark-hc' | 'system')
  • getLanguage() — current language code ('ru', 'en', etc.)
  • getContext() — slot context (type depends on the slot; see SlotContextMap)
  • getSlot() — current slot name (call after init())
  • updateContentSize(request) — update the plugin container height
  • notifyReady() — notify the host that the plugin is ready
  • disableAutoResize() — disable automatic resizing
  • externalApiAuthGetStatus(payload) — credential status for domains
  • externalApiAuthRequest(payload) — show credential input dialog
  • externalApiAuthRevoke(payload) — revoke saved credentials
  • externalApiAuthCheckAndRequest(payload) — check and request credentials for unauthenticated domains
  • externalApiCall(payload) — proxy HTTP request to an external API

uiApi

  • uiApi.navigate(request) — navigate in the host application
  • uiApi.toaster.add(options) — show a toast notification
  • uiApi.confirm.show(options) — show a confirmation dialog (permission confirm in manifest)

trackerApi.v3

Typed proxy over Tracker Public API v3 endpoints:

  • trackerApi.v3.get[path](payload) — GET; payload: pathParams, optional queryParams
  • trackerApi.v3.post[path](payload) — POST; payload: bodyParams, optional pathParams, queryParams
  • trackerApi.v3.put[path](payload) — PUT
  • trackerApi.v3.patch[path](payload) — PATCH
  • trackerApi.v3.delete[path](payload) — DELETE; payload: pathParams, optional queryParams

All methods return Promise<{ data, headers }> where data is typed according to the endpoint response.


Types

import type {
  Theme,
  ApiCallResult,
  ApiCallPayload,
  TrackerApiCallOptions,
  ContentSizeUpdateRequest,
  SlotContextMap,
  BasicContext,
  ContextLevel,
  LocalizedString,
  Issue,
  Attachment,
  StorageContextType,
  StorageRecord,
  StorageGetPayload,
  StoragePatchPayload,
  ToastAction,
  ToastOptions,
  ConfirmOptions,
  ConfirmResult,
} from '@weavix/tracker-plugin-sdk';

Key types:

  • SlotContextMap, slot contexts, LocalizedString, and related types (Issue, Attachment, etc.) — from @weavix/tracker-core, re-exported from this package.
  • HTTP request/response types for trackerApi.v3 endpoints — from @weavix/tracker-api-plugin.

React integration

For React applications, use @weavix/tracker-plugin-sdk-react — TrackerPluginProvider, useTrackerPluginContext, useLocalizedString, and all exports from this package.


Related packages

| Package | Purpose | |---------|---------| | @weavix/tracker-plugin-sdk-react | React integration: TrackerPluginProvider, hooks | | @weavix/tracker-api-types | Tracker Public API v3 types | | @weavix/sdk-core | Base runtime (hostApi, uiApi, storageApi, events) | | @weavix/sdk-react | Base React wrapper |

License

UNLICENSED