
Security News
Ruby's Bundler 4.0.18 Extends Cooldown to bundle lock and bundle cache
The supply chain control that delays freshly published gems now covers lockfile generation and gem vendoring in Ruby projects.
@velocms/plugin-sdk
Advanced tools
Plugin SDK for VeloCMS — types, manifests, lifecycle hooks for first-party + community plugins
TypeScript SDK for VeloCMS plugin development.
npm install @velocms/plugin-sdk --save-dev
import type { PluginManifest, HookContext, AfterPostCreatePayload } from "@velocms/plugin-sdk";
// 1. Define your manifest
export const manifest: PluginManifest = {
$schema: "https://velocms.org/schemas/plugin-v2.json",
name: "@myorg/my-plugin",
displayName: "My Plugin",
version: "1.0.0",
description: "Sends a Slack notification on every new post.",
author: { name: "My Org", email: "plugins@myorg.com" },
type: "integration",
category: "social",
icon: "./icon.png",
engines: { velocms: ">=1.0.0" },
capabilities: {
content: { read: true },
network: true,
network_allowlist: ["hooks.slack.com"],
},
pricing: { model: "free" },
entry: { runtime: "./dist/runtime.js" },
permissions_displayed_to_user: [
"Read your posts",
"Make HTTP requests to Slack",
],
};
// 2. Export hook handlers
export async function afterPostCreate(
payload: AfterPostCreatePayload,
ctx: HookContext
): Promise<void> {
await ctx.fetch("https://hooks.slack.com/services/YOUR/WEBHOOK/URL", {
method: "POST",
headers: { "Content-Type": "application/json" },
body: JSON.stringify({
text: `New post published: ${payload.post.title}`,
}),
});
}
SDK version 1.0.0-alpha.2 adds a real-time event bus. Plugins can subscribe to
VeloCMS system events and emit custom namespaced events.
export const manifest: PluginManifest = {
// ...
capabilities: {
events: {
subscribe: ["post.published", "member.subscribed"],
emit_custom: true, // only if you call ctx.events.emit()
},
},
};
Register subscriptions in onAppStart — VeloCMS fires this hook once when
your plugin's runtime loads, which is where ctx.events.on() registrations
belong (registering inside a request-scoped hook like afterPostCreate
would re-subscribe the same handler on every invocation).
import type { OnAppStartPayload, HookContext } from "@velocms/plugin-sdk";
export async function onAppStart(
_payload: OnAppStartPayload,
ctx: HookContext
): Promise<void> {
ctx.events.on("post.published", async ({ post }) => {
await ctx.fetch("https://hooks.slack.com/services/xxx/yyy/zzz", {
method: "POST",
headers: { "Content-Type": "application/json" },
body: JSON.stringify({ text: `New post: ${post.title}` }),
});
});
ctx.events.on("member.subscribed", async ({ member, source }) => {
await ctx.kv.set("last_signup_source", source);
});
}
Custom events must be namespaced to your plugin's org prefix (@org/).
Other plugins can subscribe to your events by name. Emitting requires
capabilities.events.emit_custom: true in your manifest.
// Emitting (from within any hook handler that receives ctx)
await ctx.events.emit("@myorg/slack-notifier:webhook-sent", {
webhookUrl: "https://hooks.slack.com/...",
postTitle: post.title,
});
// Subscribing (from another plugin's onAppStart)
ctx.events.on("@myorg/slack-notifier:webhook-sent", async (payload) => {
await ctx.kv.set("last_slack_event", JSON.stringify(payload));
});
A plugin is just a module exporting a manifest plus one function per hook
name it wants to handle — there is no definePlugin() wrapper. VeloCMS
looks up handlers by matching the exported function name to the HookName
union.
import type {
PluginManifest,
OnAppStartPayload,
AfterPostPublishPayload,
HookContext,
} from "@velocms/plugin-sdk";
export const manifest: PluginManifest = {
$schema: "https://velocms.org/schemas/plugin-v2.json",
name: "@myorg/slack-notifier",
displayName: "Slack Notifier",
version: "1.0.0",
description: "Posts to Slack whenever a new post is published.",
author: { name: "My Org", email: "plugins@myorg.com" },
type: "integration",
category: "social",
icon: "./icon.png",
engines: { velocms: ">=1.0.0" },
capabilities: { network: true, network_allowlist: ["hooks.slack.com"] },
pricing: { model: "free" },
entry: { runtime: "./dist/runtime.js" },
permissions_displayed_to_user: ["Make HTTP requests to Slack"],
};
export async function onAppStart(
_payload: OnAppStartPayload,
ctx: HookContext
): Promise<void> {
ctx.log.info("Slack Notifier activated");
}
export async function afterPostPublish(
payload: AfterPostPublishPayload,
ctx: HookContext
): Promise<void> {
const webhookUrl = await ctx.kv.get("slack_webhook_url");
if (!webhookUrl) return;
await ctx.fetch(webhookUrl, {
method: "POST",
body: JSON.stringify({ text: `New post: ${payload.post.title}` }),
});
}
| Event | Payload |
|---|---|
post.created | { post: HookPost } |
post.updated | { post: HookPost; changedFields: string[] } |
post.published | { post: HookPost } |
post.unpublished | { post: HookPost } |
post.deleted | { postId: string; slug: string } |
member.subscribed | { member: HookMember; source: string } |
member.unsubscribed | { memberId: string } |
member.tier_changed | { member: HookMember; previousTier: string } |
comment.posted | { commentId: string; postId: string; authorEmail?: string } |
comment.approved | { commentId: string; postId: string } |
comment.deleted | { commentId: string; postId: string } |
page.published | { page: PageHookData } |
media.uploaded | { mediaId: string; filename: string; mimeType: string } |
plugin_events for 30 days.
Use this for debugging via the PocketBase admin panel.Full SDK reference: velocms.org/developers/sdk
npm run buildMIT
FAQs
Plugin SDK for VeloCMS — types, manifests, lifecycle hooks for first-party + community plugins
We found that @velocms/plugin-sdk demonstrated a healthy version release cadence and project activity because the last version was released less than a year ago. It has 2 open source maintainers collaborating on the project.
Did you know?

Socket for GitHub automatically highlights issues in each pull request and monitors the health of all your open source dependencies. Discover the contents of your packages and block harmful activity before you install or update your dependencies.

Security News
The supply chain control that delays freshly published gems now covers lockfile generation and gem vendoring in Ruby projects.

Security News
During a UK cyber test, a Mythos 5 agent used sockpuppets, social engineering, and prompt injection to try to get a maintainer to merge malware.

Company News
Socket is now in the AWS Security Hub Extended plan. Adopt it through AWS, apply committed spend, and block malicious open source packages.