Plugin SDK reference
Build, package, and ship a plugin to the Aeonzap marketplace using @aeonzap/plugin-sdk.
Overview
The @aeonzap/plugin-sdk package gives you a typed entrypoint, a manifest builder, and lifecycle hooks. A plugin is a single npm package that exports a default plugin definition. The runtime loads the package inside an isolated worker, hands it a scoped client, and routes events to your handlers based on the manifest you declare.
Install
npm install @aeonzap/plugin-sdk
npm install --save-dev @aeonzap/plugin-cliManifest fields
Every plugin ships a manifest. The CLI validates it before publish. Unknown fields are rejected so your plugin keeps working when the SDK adds new ones.
| Field | Type | Required | Description |
|---|---|---|---|
id | string | yes | Reverse-DNS identifier, e.g. com.acme.reviews |
name | string | yes | Human-readable name shown in the marketplace |
version | semver | yes | Plugin version. Marketplace enforces semver. |
scopes | string[] | yes | Capabilities you request from the merchant |
settings | JSONSchema | no | Schema rendered as a config form |
icon | string | no | Path to a 256x256 PNG inside your package |
pricing | object | no | free | one_time | subscription | usage |
definePlugin
The default export of your plugin must be the result of definePlugin. The function is purely descriptive — no side effects run at import time.
import { definePlugin } from '@aeonzap/plugin-sdk';
export default definePlugin({
id: 'com.acme.reviews',
name: 'Acme Reviews',
version: '1.0.0',
scopes: ['orders.read', 'customers.read', 'storefront.blocks.write'],
settings: {
type: 'object',
properties: {
autoPublish: { type: 'boolean', default: false },
minRating: { type: 'integer', minimum: 1, maximum: 5, default: 3 },
},
},
hooks: {
install: async (ctx) => ctx.log.info('reviews installed'),
configure: async (ctx, settings) => ctx.kv.put('settings', settings),
uninstall: async (ctx) => ctx.kv.clear(),
},
events: {
'order.fulfilled': async (ctx, evt) => {
await ctx.email.send({ to: evt.customer.email, template: 'review-request' });
},
},
});Lifecycle hooks
- install — fires once when a merchant installs the plugin. Allocate KV keys, register webhooks, seed defaults.
- configure — fires every time settings change. Re-validate, re-subscribe, refresh caches.
- uninstall — fires when a merchant removes the plugin. You have 60 seconds to clean up; after that the worker is force-killed.
Settings schema
Settings use JSON Schema draft 2020-12. The dashboard renders forms automatically — string, number, boolean, enum, and nested objects all map to native controls. Use format: "secret" to render a masked field that is encrypted at rest.
Scopes
Scopes follow a resource.verb shape. Merchants see the full list before install and can revoke individual scopes later.
| Scope | Grants |
|---|---|
orders.read | Read order objects via the inbound API |
orders.write | Create and update orders |
customers.read | Read customer profiles |
products.write | Create, update, archive products |
storefront.blocks.write | Register and update storefront blocks |
notifications.send | Send email, SMS, WhatsApp, push to merchant customers |
Sample plugin in 50 lines
import { definePlugin } from '@aeonzap/plugin-sdk';
export default definePlugin({
id: 'com.acme.lowstock',
name: 'Low Stock Alerts',
version: '0.1.0',
scopes: ['products.read', 'notifications.send'],
settings: {
type: 'object',
properties: {
threshold: { type: 'integer', minimum: 1, default: 5 },
channel: { type: 'string', enum: ['email', 'whatsapp'], default: 'email' },
},
},
hooks: {
install: async (ctx) => {
await ctx.kv.put('seen', {});
},
},
events: {
'product.inventory.updated': async (ctx, evt) => {
const { threshold, channel } = await ctx.settings.get();
if (evt.inventory.available > threshold) return;
const seen: Record<string, number> = await ctx.kv.get('seen');
if (seen[evt.product.id] === evt.inventory.available) return;
seen[evt.product.id] = evt.inventory.available;
await ctx.kv.put('seen', seen);
await ctx.notify.send({
channel,
to: 'merchant',
template: 'low-stock',
data: {
product: evt.product.title,
left: evt.inventory.available,
},
});
},
},
});Publishing
Run aeonzap publish from the package root. The CLI bundles your code with esbuild, signs the artifact, and uploads it to the marketplace queue. Reviews typically clear in under 24 hours.