Browse topics
On this page
Events API
Typed pub/sub between applets over the host event bus.
The Events API gives your applet typed publish/subscribe over the host event bus. Prefer defineEvent for a typed channel with a Zod-validated payload; fall back to the raw ctx.sdk.events bridge only when you need an untyped escape hatch.
Scope required: events:emit (to emit), events:listen (to subscribe)
Usage
defineEvent declares a named channel and its payload schema. The returned object gives you emit and on:
import { z } from "zod";
import { defineEvent } from "@rightplace/applet-sdk/v2";
import { Feed } from "./entities";
export const feedAdded = defineEvent("rss.feedAdded", z.object({ feed: Feed.schema }));
// after mount
await feedAdded.emit({ feed });
const off = feedAdded.on(({ feed }) => updateBadge(feed));
off();
Internal entity write events stay applet private. Each entity write auto-emits entity:{name}:inserted|updated|deleted inside the applet, but cross-applet visibility requires an explicit re-emit through defineEvent.
Raw bridge
When you need the untyped event bus directly, reach for ctx.sdk.events inside a method’s run. Lint treats this as an escape hatch and prefers defineEvent.
await ctx.sdk.events.emit("rss.feedAdded", { feedId: id });
const off = ctx.sdk.events.listen("rss.feedAdded", payload => {
console.log(payload.feedId);
});
off();
Manifest Configuration
Declare the scopes your applet uses in applet.json:
{
"scopes": ["events:emit", "events:listen"]
}
Notes
defineEventis the typed, lint-clean path;ctx.sdk.eventsis the raw escape hatch.emitrequiresevents:emit;on/listenrequiresevents:listen. Declare each scope you use inapplet.json::scopes[].- Entity write events (
entity:{name}:inserted|updated|deleted) are applet private. Re-emit throughdefineEventto make them visible to other applets. off()(returned byonandlisten) removes the subscription.