Plugin Development Guide
The WASM Plugin SDK is a planned feature and is not yet available. This guide documents the intended architecture and API for future implementation. Check the GitHub project board for current status.
Build custom plugins to extend Olympus platform functionality using WebAssembly (WASM) and our Plugin SDK.
Overview
Plugins allow you to:
- Add custom business logic to orders, payments, and workflows
- Integrate with external systems and APIs
- Create custom reports and analytics
- Extend the UI with new screens and components
- Automate workflows based on triggers
┌─────────────────────────────────────────────────────────────────┐
│ PLUGIN ARCHITECTURE │
├─────────────────────────────────────────────────────────────────┤
│ │
│ ┌─────────────────────────────────────────────────────────┐ │
│ │ Your Plugin (WASM) │ │
│ │ ┌─────────────┐ ┌─────────────┐ ┌─────────────┐ │ │
│ │ │ Handlers │ │ State │ │ External │ │ │
│ │ │ (Hooks) │ │ Storage │ │ APIs │ │ │
│ │ └─────────────┘ └─────────────┘ └─────────────┘ │ │
│ └─────────────────────────────────────────────────────────┘ │
│ │ │
│ ┌─────────┴─────────┐ │
│ │ Plugin Runtime │ │
│ │ (Sandboxed) │ │
│ └─────────┬─────────┘ │
│ │ │
│ ┌─────────────────────────────────────────────────────────┐ │
│ │ Olympus Platform │ │
│ │ Orders │ Payments │ Inventory │ Analytics │ Users │ │
│ └─────────────────────────────────────────────────────────┘ │
│ │
└─────────────────────────────────────────────────────────────────┘
Getting Started
Prerequisites
- Node.js 18+ or Rust toolchain
- Olympus Developer Account (developers.olympuscloud.ai)
- Plugin SDK CLI (
npm install -g @olympus/plugin-cli)
Create a New Plugin
# Install the CLI
npm install -g @olympus/plugin-cli
# Create a new plugin project
olympus-plugin create my-plugin
# Choose your template
? Select plugin type:
> Order Modifier (Modify order calculations)
Webhook Handler (Handle external events)
Report Generator (Custom analytics)
UI Extension (Add screens/widgets)
Integration (Connect external service)
# Navigate to project
cd my-plugin
# Install dependencies
npm install
# Start development server
npm run dev
Project Structure
my-plugin/
├── olympus-plugin.json # Plugin manifest
├── src/
│ ├── index.ts # Entry point
│ ├── handlers/ # Hook handlers
│ │ ├── order.ts
│ │ └── payment.ts
│ ├── ui/ # UI components (optional)
│ │ └── settings.tsx
│ └── lib/ # Utility functions
│ └── api.ts
├── tests/
│ └── handlers.test.ts
├── package.json
└── tsconfig.json
Plugin Manifest
The olympus-plugin.json defines your plugin's configuration:
{
"name": "my-custom-plugin",
"version": "1.0.0",
"displayName": "My Custom Plugin",
"description": "Adds custom functionality to orders",
"author": {
"name": "Your Company",
"email": "dev@yourcompany.com",
"website": "https://yourcompany.com"
},
"icon": "./assets/icon.png",
"category": "operations",
"permissions": [
"orders:read",
"orders:write",
"payments:read",
"storage:read",
"storage:write"
],
"hooks": [
"order.beforeCreate",
"order.afterCreate",
"payment.beforeProcess"
],
"entrypoints": {
"main": "./dist/index.wasm",
"settings": "./dist/settings.js"
},
"settings": {
"schema": "./settings-schema.json"
},
"pricing": {
"type": "subscription",
"price": 29.99,
"currency": "USD",
"interval": "monthly",
"trial": 14
},
"requirements": {
"minPlatformVersion": "2.0.0",
"plans": ["professional", "enterprise"]
}
}
Manifest Fields
| Field | Required | Description |
|---|---|---|
name | Yes | Unique identifier (lowercase, hyphens) |
version | Yes | Semantic version (1.0.0) |
displayName | Yes | Human-readable name |
description | Yes | Brief description (max 200 chars) |
author | Yes | Developer/company info |
permissions | Yes | Required data access |
hooks | No | Platform events to handle |
entrypoints | Yes | WASM and JS entry files |
pricing | No | Free if not specified |
Permissions
Plugins must declare required permissions:
Data Permissions
| Permission | Access |
|---|---|
orders:read | Read order data |
orders:write | Create/modify orders |
payments:read | Read payment info |
payments:write | Process payments |
inventory:read | Read inventory levels |
inventory:write | Modify inventory |
customers:read | Read customer data |
customers:write | Modify customer data |
employees:read | Read employee data |
analytics:read | Access analytics data |
System Permissions
| Permission | Access |
|---|---|
storage:read | Read plugin storage |
storage:write | Write plugin storage |
webhooks:register | Register webhook endpoints |
notifications:send | Send push notifications |
http:external | Make external HTTP requests |
ui:inject | Inject UI components |
Permission Best Practices
Plugins that request more permissions than they need will face longer review times and lower installation rates. Users can see exactly which permissions your plugin requests, so only declare what you actually use.
- Request minimum permissions - Only what you need
- Explain why - Users see permission requests
- Handle denial gracefully - Some permissions may be denied
- Audit regularly - Remove unused permissions
Hooks & Extension Points
Available Hooks
Order Hooks
// Before order is created
export async function onOrderBeforeCreate(
context: HookContext,
order: OrderDraft
): Promise<OrderDraft | HookError> {
// Validate or modify order before creation
if (order.items.length === 0) {
return { error: 'ORDER_EMPTY', message: 'Order must have items' };
}
// Add custom field
order.metadata.customField = 'value';
return order;
}
// After order is created
export async function onOrderAfterCreate(
context: HookContext,
order: Order
): Promise<void> {
// Sync to external system
await externalApi.syncOrder(order);
}
// Before order total is calculated
export async function onOrderCalculate(
context: HookContext,
order: OrderDraft,
totals: OrderTotals
): Promise<OrderTotals> {
// Apply custom discount
if (order.metadata.loyaltyTier === 'gold') {
totals.discount += totals.subtotal * 0.1;
}
return totals;
}
Payment Hooks
// Before payment is processed
export async function onPaymentBeforeProcess(
context: HookContext,
payment: PaymentRequest
): Promise<PaymentRequest | HookError> {
// Add fraud check
const fraudScore = await fraudService.check(payment);
if (fraudScore > 0.8) {
return { error: 'FRAUD_DETECTED', message: 'Payment flagged for review' };
}
return payment;
}
// After payment completes
export async function onPaymentAfterProcess(
context: HookContext,
payment: Payment
): Promise<void> {
// Update external accounting
await accountingService.recordPayment(payment);
}
Inventory Hooks
// Before inventory update
export async function onInventoryBeforeUpdate(
context: HookContext,
update: InventoryUpdate
): Promise<InventoryUpdate> {
// Auto-reorder when low
if (update.newQuantity < update.reorderPoint) {
await supplierApi.createOrder(update.itemId, update.reorderQuantity);
}
return update;
}
Hook Context
Every hook receives a context object:
interface HookContext {
// Tenant information
tenantId: string;
locationId: string;
// User who triggered the action
userId: string;
userRole: string;
// Plugin storage
storage: PluginStorage;
// Logging
logger: Logger;
// Configuration
settings: PluginSettings;
// Platform APIs
api: PlatformAPI;
}
Plugin Storage
Persist data between executions:
// Key-value storage
await context.storage.set('lastSync', Date.now());
const lastSync = await context.storage.get('lastSync');
// Structured storage
await context.storage.setObject('config', {
apiKey: 'xxx',
enabled: true
});
const config = await context.storage.getObject('config');
// List operations
await context.storage.push('processedOrders', orderId);
const orders = await context.storage.list('processedOrders');
// Delete
await context.storage.delete('oldKey');
Storage Limits
| Plan | Storage Limit | Operations/min |
|---|---|---|
| Free | 1 MB | 100 |
| Pro | 100 MB | 1,000 |
| Enterprise | 1 GB | 10,000 |
External API Calls
Make HTTP requests to external services:
import { http } from '@olympus/plugin-sdk';
// GET request
const response = await http.get('https://api.example.com/data', {
headers: {
'Authorization': `Bearer ${apiKey}`
}
});
// POST request
const result = await http.post('https://api.example.com/webhook', {
body: JSON.stringify({ orderId: order.id }),
headers: {
'Content-Type': 'application/json'
}
});
// Handle errors
try {
const data = await http.get(url);
} catch (error) {
if (error.status === 429) {
// Rate limited
await sleep(1000);
return retry();
}
throw error;
}
HTTP Restrictions
- HTTPS only (no HTTP)
- Timeout: 30 seconds max
- Response size: 10 MB max
- Rate limit: 100 requests/minute
- Allowed domains must be declared in manifest
UI Extensions
Add custom UI components:
Settings Screen
// src/ui/settings.tsx
import { SettingsForm, TextInput, Toggle } from '@olympus/plugin-ui';
export function PluginSettings({ settings, onChange }) {
return (
<SettingsForm>
<TextInput
label="API Key"
value={settings.apiKey}
onChange={(value) => onChange({ ...settings, apiKey: value })}
type="password"
/>
<Toggle
label="Enable auto-sync"
value={settings.autoSync}
onChange={(value) => onChange({ ...settings, autoSync: value })}
/>
</SettingsForm>
);
}
Dashboard Widget
// src/ui/widget.tsx
import { Widget, Chart, Metric } from '@olympus/plugin-ui';
export function DashboardWidget({ data }) {
return (
<Widget title="My Plugin Stats">
<Metric
label="Orders Processed"
value={data.ordersProcessed}
trend="+12%"
/>
<Chart
type="line"
data={data.dailyTrend}
/>
</Widget>
);
}
Menu Extension
// Add menu item to staff shell
export const menuExtension = {
location: 'staff.sidebar',
item: {
label: 'My Plugin',
icon: 'plugin-icon',
route: '/plugins/my-plugin'
}
};
Testing
Unit Tests
// tests/handlers.test.ts
import { describe, it, expect } from 'vitest';
import { createMockContext } from '@olympus/plugin-testing';
import { onOrderBeforeCreate } from '../src/handlers/order';
describe('Order Handler', () => {
it('should add custom field', async () => {
const context = createMockContext();
const order = { items: [{ id: '1', quantity: 1 }], metadata: {} };
const result = await onOrderBeforeCreate(context, order);
expect(result.metadata.customField).toBe('value');
});
it('should reject empty orders', async () => {
const context = createMockContext();
const order = { items: [], metadata: {} };
const result = await onOrderBeforeCreate(context, order);
expect(result.error).toBe('ORDER_EMPTY');
});
});
Integration Tests
// tests/integration.test.ts
import { PluginTestEnvironment } from '@olympus/plugin-testing';
describe('Plugin Integration', () => {
let env: PluginTestEnvironment;
beforeAll(async () => {
env = await PluginTestEnvironment.create({
manifest: './olympus-plugin.json',
mockData: './tests/fixtures'
});
});
it('should process order correctly', async () => {
const order = await env.createOrder({
items: [{ menuItemId: 'burger', quantity: 2 }]
});
// Plugin hooks are automatically invoked
expect(order.metadata.customField).toBeDefined();
expect(order.totals.discount).toBeGreaterThan(0);
});
});
Local Development
# Start development server with hot reload
npm run dev
# Run tests
npm test
# Run tests with coverage
npm run test:coverage
# Lint and type check
npm run lint
npm run typecheck
Building & Packaging
Build for Production
# Build WASM and JS bundles
npm run build
# Output:
# dist/
# index.wasm # Main plugin logic
# settings.js # Settings UI
# widget.js # Dashboard widget
Validate Package
# Run validation checks
olympus-plugin validate
# Checks:
# ✓ Manifest schema valid
# ✓ Permissions declared correctly
# ✓ WASM binary under size limit
# ✓ No security issues detected
# ✓ All hooks properly exported
Package for Submission
# Create submission package
olympus-plugin package
# Output: my-plugin-1.0.0.opkg
Publishing
Submission Process
- Create Developer Account at developers.olympuscloud.ai
- Submit Plugin via dashboard or CLI
- Automated Review - Security scan, API compliance
- Manual Review - Functionality, UX, policy compliance (1-3 days)
- Published - Available in marketplace
Submission Checklist
| Requirement | Description |
|---|---|
| Screenshots | Minimum 3 showing key features |
| Documentation | Help docs or README |
| Privacy Policy | If accessing customer data |
| Support Contact | Email or help desk URL |
| Test Account | For reviewer testing |
| Changelog | What's new in this version |
Submit via CLI
# Login to developer account
olympus-plugin login
# Submit for review
olympus-plugin submit
# Check submission status
olympus-plugin status
Version Updates
# Bump version
npm version patch # 1.0.0 -> 1.0.1
npm version minor # 1.0.0 -> 1.1.0
npm version major # 1.0.0 -> 2.0.0
# Submit update
olympus-plugin submit --update
Best Practices
Performance
| Practice | Why |
|---|---|
| Minimize storage operations | Storage has latency |
| Cache external API responses | Reduce HTTP calls |
| Use async/await properly | Don't block the runtime |
| Keep WASM bundle small | Faster cold starts |
Security
| Practice | Why |
|---|---|
| Never hardcode secrets | Use plugin settings |
| Validate all input | Prevent injection |
| Sanitize output | Prevent XSS |
| Use HTTPS only | Encrypt data in transit |
| Minimal permissions | Principle of least privilege |
Error Handling
export async function onOrderBeforeCreate(context, order) {
try {
// Plugin logic
return await processOrder(order);
} catch (error) {
// Log error for debugging
context.logger.error('Order processing failed', { error, orderId: order.id });
// Return graceful error (doesn't block order)
return order;
// OR: Block order with error
// return { error: 'PROCESSING_FAILED', message: 'Please try again' };
}
}
API Reference
REST API Documentation
See complete API reference at:
- REST API Examples - API integration examples
Quick Reference
import {
// Hook types
HookContext,
HookResult,
// Data types
Order,
Payment,
Customer,
// Utilities
http,
crypto,
// UI components
SettingsForm,
Widget,
} from '@olympus/plugin-sdk';
Support
Resources
| Resource | URL |
|---|---|
| Developer Docs | developers.olympuscloud.ai/docs |
| API Reference | developers.olympuscloud.ai/api |
| Community Forum | developers.olympuscloud.ai/community |
| GitHub Examples | github.com/olympuscloud/plugin-examples |
| Office Hours | Thursdays 2pm PT |
Getting Help
- Community Forum: General questions
- GitHub Issues: Bug reports
- Email: developers@olympuscloud.ai
- Priority Support: Partner tier developers
Related Guides
- Developer Portal Overview - Account setup and marketplace
- Webhooks Guide - Event handling
- OAuth Guide - Authentication
- REST API Examples - API usage examples