Creating Plugins
This guide will walk you through creating plugins for Trove.
Plugin Structure
A Trove plugin is a TypeScript module that exports a plugin definition:
import type { CoreSystem, Plugin } from "trove/core/types.ts";
export default {
// Required: Plugin identification
name: "my-plugin",
version: "1.0.0",
// Optional: Plugin initialization
async initialize(core: CoreSystem) {
// Setup code
},
// Optional: Cleanup
async shutdown() {
// Cleanup code
},
// Optional: Hook handlers
hooks: {
"event:received": async (context) => {
// Process events
},
},
} satisfies Plugin;
Plugin Types
Event Processing Plugins
Process events and optionally create new ones:
export default {
name: "image-processor",
version: "1.0.0",
async initialize(core) {
// Register our schema
await core.registerSchema({
id: "image.processed",
version: "1.0",
schema: {
type: "object",
properties: {
originalId: { type: "string" },
width: { type: "number" },
height: { type: "number" },
},
},
});
},
hooks: {
"event:received": async ({ event, core }) => {
if (event.schema.id !== "image.uploaded") return;
// Process image
const imageFile = event.files[0];
const dimensions = await getImageDimensions(imageFile);
// Create processed event
await core.createEvent({
schema: "image.processed",
payload: {
originalId: event.id.id,
...dimensions,
},
links: [{
type: "parent",
targetEvent: event.id,
}],
});
},
},
};
Storage Plugins
Implement storage backends:
export default {
name: "my-storage",
version: "1.0.0",
capabilities: ["storage:events"],
async initialize(core) {
// Setup storage connection
},
// Implement storage interface
async saveEvent(event) {
// Store event
},
async getEvent(id) {
// Retrieve event
},
async queryEvents(query) {
// Search events
},
};
Web Plugins
Add HTTP endpoints:
export default {
name: "my-api",
version: "1.0.0",
capabilities: ["http:handler"],
hooks: {
"http:request": async ({ request }) => {
if (request.url.endsWith("/api/my-endpoint")) {
return new Response("Hello from my plugin!", {
status: 200,
headers: {
"Content-Type": "text/plain",
},
});
}
// Return null to pass to next handler
return null;
},
},
};
Plugin Configuration
Plugins can accept configuration through the core config:
// In your Trove configuration
{
plugins: {
"my-plugin": {
option1: "value1",
option2: "value2"
}
}
}
// In your plugin
export default {
name: "my-plugin",
async initialize(core) {
const config = core.config.plugins[this.name];
this.option1 = config.option1;
}
};
Testing Plugins
Create test files alongside your plugins:
// my-plugin.test.ts
import { assertEquals } from "https://deno.land/std/testing/asserts.ts";
import { createTestCore } from "trove/test/utils.ts";
import myPlugin from "./my-plugin.ts";
Deno.test("my plugin processes events correctly", async () => {
const core = await createTestCore();
await core.loadPlugin(myPlugin);
const event = await core.createEvent({
schema: "test.event",
payload: {/* ... */},
});
// Assert expected behavior
});
Publishing Plugins
- Create a repository for your plugin
- Add documentation
- Add tests
- Publish to a Deno module registry or host on GitHub
- Add to Trove's plugin directory (optional)
Best Practices
- Use TypeScript for type safety
- Handle errors gracefully
- Clean up resources in shutdown
- Document hook usage
- Follow semantic versioning
- Include tests
- Provide clear documentation