Plugin development
Plugin handlers
Handlers connect manifest declarations to Lua functions. Plugins can declare the handler types below.
Handler modules
A handler module returns a table of functions. Each declared operation identifies one module and one function in that table.
- Commands and events.
- Schedules and webhooks.
- HTTP actions and page actions.
- Pages, public widget projections and automation handlers.
local blokebot = require("blokebot")
local handlers = {
handle_command = function(input)
blokebot.responses.chat("Received " .. input.route)
return nil
end,
}
return handlersFeature handlers
- The event handler receives the event identity.
- The event handler receives the source.
- The event handler receives the timestamp.
- Command
- The handler receives the normalized route and ordered arguments for the current channel.
- Typed Twitch event
- The handler receives the typed event data.
- Raw Twitch event
- The handler receives the declared EventSub identity and a validated raw event map.
- BlokeBot event
- The handler receives the event identity and source name.
- Schedule
- The handler receives the input that BlokeBot stored when the feature created the schedule.
HTTP actions and page actions
A page action receives only the exact fields in its manifest declaration.
- An HTTP action receives method from the fixed authenticated endpoint.
- An HTTP action receives headers from the fixed authenticated endpoint.
- An HTTP action receives bodyBase64 from the fixed authenticated endpoint.
[[features.dispatch.actions]]
kind = "page"
id = "review-item"
module = "main"
operation = "review_item"
inputs = [
{ id = "item_id", name = "Item ID", valueKind = "number", required = true },
{ id = "decision", name = "Decision", valueKind = "string", required = true },
]
[[features.dispatch.actions]]
kind = "http"
id = "refresh-item"
module = "main"
operation = "refresh_item"Webhooks
A webhook either accepts public requests or calls one plugin authentication handler before it calls the webhook handler.
BlokeBot checks authentication and handles the webhook within one request. A plugin or feature change cancels both steps.
- Use public authentication only when the webhook intentionally accepts public requests.
- Return false from the authentication handler to reject a request.
- Do not create an identity from request headers.
Migrations
It can use storage and redaction-safe diagnostics.
Before activation, BlokeBot runs one selected migration chain. If a migration fails, BlokeBot faults the selected installation.
- A migration handler receives migrationId.
- A migration handler receives fromVersion.
- A migration handler receives toVersion.
[[migrations]]
id = "schema-v1"
fromVersion = "0.0.0"
toVersion = "0.1.0"
module = "main"
entryPoint = "migrate"Cancellation
Cancellation stops a coroutine that waits for a host result. A late result does not resume the coroutine.
Cancellation does not undo an effect that completed first.
- The cancellation rule applies to chat.
- The cancellation rule applies to schedules.
- The cancellation rule applies to HTTP.
- The cancellation rule applies to SQLite.
- The cancellation rule applies to other effects.
Public widget projections
A widget render handler receives input.configuration, not a page session, browser credential or private host payload. context.current derives the resolved host, feature, full document and widget instance on the server.
The context's widget.mode is live, preview-live or preview-sample. Preview handlers must not admit, drain, advance or acknowledge production work. Read a non-consuming projection or return sample data instead.
Trusted server Lua can use its own declared settings, storage and HTTP APIs to construct a public-safe result. Never return secrets, private viewer information or management authority to the browser, diagnostics or asset URLs.
The widget browser document runs in an isolated script-enabled frame. Declared relative HTML/CSS/JS assets work through scoped public asset delivery; a management-page action bridge is not available.
local blokebot = require("blokebot")
return {
render_widget = function(input)
local context = blokebot.context.current()
assert(context.kind == "widget")
if context.widget.mode == "preview-sample" then
return { text = "Sample heading" }
end
-- Read only public-safe, non-consuming state here.
return { text = input.configuration.text }
end,
}