Files
HiveGrid-Wireframes/hivegrid-cloud/packages/plugin-sdk/examples/capability-use/handler.ts
T

65 lines
2.2 KiB
TypeScript

/**
* Capability-use example — Phase 06 #23.
*
* One handler that touches every "regular" capability so the audit-
* trail page shows a non-trivial set of rows per invocation:
* 1. storage.read to fetch the tenant's Slack webhook URL
* 2. http.outbound to POST a notification to Slack
* 3. log everywhere for structured tracing
*
* When run with the host audit recorder wired in, each capability call
* emits one PluginCapabilityUse row with outcome=success / error and a
* sha256(payloadDescriptor). Tenant admins see exactly which channel
* received which event without the message body ever being persisted.
*/
import { defineHook } from "../../src/index.js";
export interface EntityCreatedInput {
readonly tenantId: string;
readonly entityName: string;
readonly recordId: string;
}
export const handleEntityCreated = defineHook<EntityCreatedInput, { posted: boolean }>(
async (input, ctx) => {
ctx.log.info(
{ tenantId: input.tenantId, entity: input.entityName },
"capability-use.handleEntityCreated invoked"
);
if (!ctx.storage) {
ctx.log.warn({}, "storage capability not bound — manifest must declare storage.read");
return { posted: false };
}
const webhookUrl = await ctx.storage.get(`slack:${input.tenantId}:webhook-url`);
if (!webhookUrl) {
ctx.log.info({ tenantId: input.tenantId }, "no slack webhook configured — skipping");
return { posted: false };
}
if (!ctx.http) {
ctx.log.warn({}, "http capability not bound — manifest must declare http.outbound");
return { posted: false };
}
const body = JSON.stringify({
text: `New ${input.entityName} created (id ${input.recordId})`,
});
const response = await ctx.http.fetch({
url: webhookUrl,
method: "POST",
headers: { "Content-Type": "application/json" },
body,
});
if (response.status >= 200 && response.status < 300) {
ctx.log.info({ status: response.status }, "slack webhook posted");
return { posted: true };
}
ctx.log.error(
{ status: response.status, body: response.body.slice(0, 256) },
"slack webhook returned non-2xx"
);
return { posted: false };
}
);