/** * The components a package is made of, besides its resources: * * event("checklist:item:validation_dispatched", async (ctx) => { … }) * execute(async (ctx) => { … }) * * An event answers a notification by name — what the notifications API * delivers with `source` and `action`. The execute component answers * everything else the agent hands over: `ctx.payload` parsed, `ctx.raw` as * received. Neither carries an action lifecycle; what the handler returns is * the result. */ import type { EventContext, ExecuteContext } from "./handler"; import type { Resource } from "./resource"; import { isResource } from "./resource"; export type EventFn = (ctx: EventContext) => Promise | R; export type ExecuteFn = (ctx: ExecuteContext) => Promise | R; export interface EventComponent { readonly kind: "event"; /** The notification's action name, e.g. `checklist:item:validation_dispatched`. */ readonly name: string; /** The notification source the name implies: its first segment. */ readonly source: string; readonly fn: EventFn; } export interface ExecuteComponent { readonly kind: "execute"; readonly fn: ExecuteFn; } export type Component = Resource | EventComponent | ExecuteComponent; export function event( name: string, fn: EventFn ): EventComponent { if (!name || typeof name !== "string") throw new Error("event(): a name is required"); if (typeof fn !== "function") throw new Error(`event(${name}): a handler is required`); return { kind: "event", name, source: name.split(":")[0], fn: fn as EventFn }; } export function execute(fn: ExecuteFn): ExecuteComponent { if (typeof fn !== "function") throw new Error("execute(): a handler is required"); return { kind: "execute", fn: fn as ExecuteFn }; } export const isEvent = (v: unknown): v is EventComponent => !!v && typeof v === "object" && (v as EventComponent).kind === "event" && typeof (v as EventComponent).fn === "function" && !isResource(v); export const isExecute = (v: unknown): v is ExecuteComponent => !!v && typeof v === "object" && (v as ExecuteComponent).kind === "execute" && typeof (v as ExecuteComponent).fn === "function" && !isResource(v);