Creating a Plugin
import { Steps } from ‘@astrojs/starlight/components’;
Creating a Plugin
Section titled “Creating a Plugin”This guide walks you through building a plugin that sends a Slack notification when a new order is paid.
Prerequisites
Section titled “Prerequisites”- ecommus running locally (see Quick Start)
- Basic TypeScript knowledge
Step-by-Step
Section titled “Step-by-Step”-
Create the plugin folder
Terminal window mkdir plugins/slack-notifycd plugins/slack-notify -
Create
package.json{"name": "@ecommus/plugin-slack-notify","version": "1.0.0","type": "module","main": "src/index.ts","ecommus": {"name": "slack-notify","version": "1.0.0","description": "Send Slack notifications on order events","author": "Your Name","permissions": ["events.subscribe"],"settingsSchema": {"webhookUrl": {"label": "Slack Webhook URL","type": "string","required": true,"placeholder": "https://hooks.slack.com/services/..."},"channel": {"label": "Channel","type": "string","default": "#orders","placeholder": "#orders"}}}} -
Create
src/index.tsimport type { PluginInit } from "@ecommus/plugin-sdk";const init: PluginInit = async (ctx) => {ctx.registerHook("order.paid", async (event) => {// Load settings for the current tenantconst settings = await ctx.db.query.settings.findFirst({where: (s, { and, eq }) =>and(eq(s.tenantId, event.tenantId),eq(s.key, "plugin:slack-notify:settings")),});if (!settings?.value) return;const { webhookUrl, channel } = settings.value as Record<string, string>;if (!webhookUrl) return;const { orderId, total, currency } = event.payload;await fetch(webhookUrl, {method: "POST",headers: { "Content-Type": "application/json" },body: JSON.stringify({text: `New order paid: #${orderId} — ${total} ${currency} ${channel ?? ""}`.trim(),}),});ctx.logger.info({ orderId }, "Slack notification sent");});};export default init; -
Restart the API server
The plugin loader runs at startup. Stop and restart
node scripts/dev.mjsto pick up the new plugin.You should see in the logs:
[plugin-loader] Loaded: slack-notify v1.0.0 -
Configure settings in the admin
Navigate to Admin → Integrations → slack-notify → Settings and enter your Slack webhook URL.
The form is auto-generated from the
settingsSchemayou defined inpackage.json. -
Test it
Create and pay for a test order. You should receive a Slack message.
Plugin Structure Reference
Section titled “Plugin Structure Reference”plugins/my-plugin/├── package.json ← manifest (required)├── src/│ └── index.ts ← PluginInit export default (required)├── README.md ← optional docs└── tests/ └── my-plugin.test.ts ← optional testsTypeScript Tips
Section titled “TypeScript Tips”- Import types from
@ecommus/plugin-sdk— it’s a pure type package with no runtime overhead - The
initfunction can be async — await any setup operations - Use
ctx.loggerinstead ofconsole.logfor structured logging - Access the database with
ctx.db— the full Drizzle instance
Publishing Your Plugin
Section titled “Publishing Your Plugin”If you want to publish your plugin as an npm package:
- Set
"publishConfig": { "access": "public" }inpackage.json - Follow our versioning policy (SemVer)
- Tag your package with
ecommus-pluginon npm for discoverability