Developer

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

  • defineEvent is the typed, lint-clean path; ctx.sdk.events is the raw escape hatch.
  • emit requires events:emit; on / listen requires events:listen. Declare each scope you use in applet.json::scopes[].
  • Entity write events (entity:{name}:inserted|updated|deleted) are applet private. Re-emit through defineEvent to make them visible to other applets.
  • off() (returned by on and listen) removes the subscription.