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.
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) {},
})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.
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
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.
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).
// 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.
// 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.
// 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()