Skip to content

Writing a plugin

A plugin is a JavaScript module with a default export. It can be bundled with the app (src/plugins/*) or loaded at runtime from a URL or a local file — both use exactly the same API.

export default {
id: "my-plugin",
name: "My plugin",
version: "1.0.0",
description: "What it does",
setup(ctx) {
// Own persisted state + model data (namespaced to this plugin)
const slice = ctx.slice({ items: [] });
// Declare the data shape (shown in the Registry panel)
ctx.defineModel({ id: "item", fields: { id: "string", label: "string" } });
// The only place state may change
ctx.registerHandler("my-plugin/item.add", ({ payload }) => {
slice.set((prev) => ({ items: [...prev.items, payload] }));
});
// A named action, optional shortcut, shown in the command palette
ctx.registerCommand({
id: "my-plugin.add",
title: "My plugin: Add item",
shortcut: "mod+i",
event: "my-plugin/item.add",
payload: { id: "1", label: "Hello" },
});
// UI into a surface: topBar | leftSidebar | rightPanel | bottomPanel | statusBar
ctx.contribute({
id: "panel",
surface: "leftSidebar",
title: "My panel",
order: 20,
component: () => {
const { items } = slice.use(); // subscribe to own slice
return items.length + " items";
},
});
// A document view that work-area tabs can open
ctx.registerView({ id: "editor", component: ({ params }) => null });
// Replace a platform capability, e.g. a different file load/save
ctx.provideService({
files: {
openTextFile: async () => ({ name: "demo.txt", contents: "from a plugin" }),
saveTextFile: async () => ({ name: "demo.txt" }),
},
});
// Observe without changing state
ctx.on("shell/ready", (event) => console.log(event.payload));
},
dispose() {
// clean up timers, listeners you created yourself
},
};
UI action -> ctx.emit(event) -> handler -> (model change) -> slice.set -> UI refresh

UI never writes state directly. It emits an event; a handler decides what happens. Every event is visible live in the Events panel.

Documentation under CC BY 4.0 · © SCFlow contributors ·Back to supplychainflow.org