API Reference

Complete reference for every export in @bemindlabs/unicore-plugin-sdk.

definePlugin()

The main factory function. Validates your descriptor at load time and returns a typedPlugin object.

src/index.tstypescript
import { definePlugin, type PluginContext } from '@bemindlabs/unicore-plugin-sdk'

export default definePlugin({
  // Required
  id: 'acme-crm-sync',         // Unique reverse-domain or slug
  name: 'Acme CRM Sync',
  version: '1.2.0',            // SemVer string
  description: 'Two-way sync between UniCore contacts and Acme CRM.',

  // Optional metadata
  author: 'Acme Corp <[email protected]>',
  homepage: 'https://acme.com/unicore-plugin',
  tags: ['crm', 'sync', 'integration'],

  // Lifecycle hooks (all optional)
  async onInstall(ctx: PluginContext) {},
  async onActivate(ctx: PluginContext) {},
  async onDeactivate(ctx: PluginContext) {},
  async onUninstall(ctx: PluginContext) {},
  async onUpgrade(ctx: PluginContext, fromVersion: string) {},
})
Note: The id field must be globally unique. Use your organisation name as a namespace (e.g. acme-crm-sync). Changing the ID after publication will break existing installations.

PluginContext

The single argument passed to every lifecycle hook. Provides access to all platform services scoped to your plugin.

@bemindlabs/unicore-plugin-sdktypescript
interface PluginContext {
  /** Plugin identifier */
  pluginId: string

  /** Structured logger scoped to this plugin */
  log: Logger

  /** Prisma-compatible database client (shared connection pool) */
  db: PrismaClient

  /** Redis client for caching and pub/sub */
  cache: RedisClient

  /** Emit and subscribe to platform events */
  events: EventBus

  /** Call the AI engine — run prompts, embeddings, tool calls */
  ai: AiService

  /** Register HTTP route handlers (mounted at /api/plugins/:pluginId/) */
  router: PluginRouter

  /** Manage plugin-scoped key-value settings */
  settings: SettingsService

  /** Read the plugin's own package.json metadata */
  meta: PluginMeta

  /** Access other activated plugins by ID */
  getPlugin(id: string): PluginContext | undefined
}

ctx.log

Structured logger scoped to your plugin ID. Log output appears in the UniCore admin dashboard under Plugins → Logs and in container stdout.

Levels: debug · info · warn · error

src/index.tstypescript
async onActivate(ctx) {
  ctx.log.debug('Connecting to Acme API...')
  ctx.log.info('Plugin activated', { version: ctx.meta.version })
  ctx.log.warn('Rate limit approaching', { remaining: 10 })
  ctx.log.error('Connection failed', new Error('ETIMEDOUT'))
}

ctx.router

Register HTTP handlers. All routes are automatically mounted at/api/plugins/{pluginId}/and protected by the platform's JWT middleware. Supports get, post, put, patch, delete.

src/index.tstypescript
async onActivate(ctx) {
  // GET /api/plugins/acme-crm-sync/contacts
  ctx.router.get('/contacts', async (req, res) => {
    const contacts = await ctx.db.contact.findMany()
    res.json({ data: contacts })
  })

  // POST /api/plugins/acme-crm-sync/sync
  ctx.router.post('/sync', async (req, res) => {
    const { direction } = req.body as { direction: 'push' | 'pull' }
    await syncContacts(ctx, direction)
    res.json({ ok: true })
  })
}

ctx.events

Typed event bus backed by the platform's Kafka broker. Use it for inter-plugin communication and reacting to core platform events (e.g. contact:created,invoice:paid, agent:message).

src/index.tstypescript
// Emit a custom event
ctx.events.emit('acme-crm-sync:contact-synced', {
  contactId: 'c_123',
  direction: 'push',
})

// Subscribe to platform events
ctx.events.on('contact:created', async (payload) => {
  await pushContactToAcme(payload.contact)
})

// Subscribe to another plugin's events
ctx.events.on('acme-crm-sync:contact-synced', (payload) => {
  ctx.log.info('Synced', payload)
})

ctx.ai

Calls the platform's AI Engine (port 4200) using the tenant's configured provider and API key — your plugin never handles API keys directly. Supports chat completions, embeddings, image generation, and tool calling.

src/index.tstypescript
// Run a chat completion
const reply = await ctx.ai.chat({
  model: 'gpt-4o',            // or use the tenant's default model
  messages: [
    { role: 'system', content: 'You are a CRM assistant.' },
    { role: 'user', content: userMessage },
  ],
})

// Generate embeddings
const vector = await ctx.ai.embed({
  model: 'text-embedding-3-small',
  input: contactDescription,
})

// Tool calling
const result = await ctx.ai.chat({
  model: 'claude-opus-4-6',
  messages: [{ role: 'user', content: 'List my top 5 leads' }],
  tools: [listLeadsTool],
})

ctx.settings

Persist plugin-scoped configuration. Values are stored in PostgreSQL under the plugin's namespace. Sensitive values (e.g. API keys) are encrypted with AES-256-GCM before storage — pass { secret: true }when writing.

src/index.tstypescript
// Read a setting (returns undefined if not set)
const apiKey = await ctx.settings.get<string>('acme_api_key')

// Write a setting (encrypted at rest for sensitive keys)
await ctx.settings.set('acme_api_key', key, { secret: true })

// Delete a setting
await ctx.settings.delete('acme_api_key')

// Get all settings for this plugin
const all = await ctx.settings.getAll()