SDK
Alert-only Miblo apps: types, sending, testing and status
A Miblo app with no screen that only alerts: screen: false, the alert types, alerts.send, test, status, a key against repeats, quiet hours and every error.
What an alert-only app is
Most apps don't need a screen: they only need to say when something happens. A goal, a site down, a broken build, a parcel out for delivery. An alert-only app is just that: it draws no card, never takes a turn among the app screens and is never pinned. It declares the kinds of alert it sends, and the person turns each one on or off in the Miblo app (Apps tab).
The alert shows over whatever the Miblo shows for a few seconds, then the screen comes back. Miblo's own alerts ("needs you", a finished session) always come first: yours waits for them.
In ten lines
import { MibloStatus } from '@miblo/status';
const miblo = new MibloStatus();
const alerts = miblo.alerts({ id: 'placar', tool: 'Placar' });
await alerts.declare({ name: 'Placar', types: [
{ id: 'gol', label: { pt: 'Gol', en: 'Goal' }, level: 'important' },
{ id: 'fim', label: { pt: 'Fim de jogo', en: 'Full time' }, level: 'info' },
] });
await alerts.send({ type: 'gol', title: 'GOAL: Flamengo!', text: 'Flamengo 2 x 1', key: 'match-123-goal-2' });from miblo_status import MibloStatus
miblo = MibloStatus()
alerts = miblo.alerts("placar", "Placar")
alerts.declare(name="Placar", types=[
{"id": "gol", "label": {"pt": "Gol", "en": "Goal"}, "level": "important"},
{"id": "fim", "label": {"pt": "Fim de jogo", "en": "Full time"}, "level": "info"},
])
alerts.send(type="gol", title="GOAL: Flamengo!", text="Flamengo 2 x 1", key="match-123-goal-2")declare() registers the app as alert-only (screen: false). No screen(), card or preview needed.
The alert types
Each type is { id, label, level, default, cooldownMin }, 1 to 8 per app:
id: lowercase letters, digits and-, up to 16 (neveron,off,later,testorhistory). It is each alert'stype.label: the name the person sees next to the switch, up to 24 characters, text or{ pt, en }.level:info(the notice) orimportant(the screen flashes first, like Miblo's own alerts). It is that type's maximum: animportantalert of aninfotype shows asinfo.default: on (true, the default) or off until the person turns it on.cooldownMin: optional, 0 to 1440. After an alert of this type, the next ones wait that many minutes.
send()
alerts.send({ type, title, text, level, seconds, key, dedupeMin, whenQuiet }) (also alerts.alert()):
titleup to 24 characters (required),textup to 40,seconds1 to 15 (default 8).key: a key for the event. The same key withindedupeMinminutes (default 10) is one alert: the answer is{ ok: true, duplicate: true }. Use it so the same goal is never told twice when your program reads the score again.whenQuiet: what to do during the person's quiet hours.'drop'(default) drops it;'later'keeps it (up to 3 per app) and delivers it when the quiet hours end. The client's default comes frommiblo.alerts({ id, tool, whenQuiet }).
For fire-and-forget programs, trySend() (try_send() in Python) never throws: it returns { ok, code, retryAfter }.
test() and status()
await alerts.test(); // "Test · Placar" on the Miblo, even before permission
const st = await alerts.status(); // permission, types on, quiet hours, how many left todayalerts.test()
st = alerts.status()test({ type, title, text })shows an alert whose title starts with "Test ·". It works before the person allows the alerts (it is there to see how it looks), but keeps a type turned off, quiet hours, the 2-minute gap and 10 tests a day.status()returns{ permission, types: [{ id, label, level, on }], quiet: { on, from, to, active, endsInS }, limit: { left, nextInS }, queued, last }.
Errors
Every error is a MibloError with a code:
alerts_off: the person has not allowed the app's alerts yet (asked: true: the first alert asked them in the Miblo app) or turned them off (asked: false).type_off: the person turned that type off (type).quiet: it is quiet hours;retryAftersays in how many seconds they end.rate_limited:retryAfterin seconds;reasonsays whether it was the type'scooldownor the app'slimit(1 every 2 minutes, 20 a day).bad_requestwithfield: a title too long, atypethe app did not declare.
As a store app
An alert-only community app is a zip with main.js and manifest.json, like any other (Publish to the store). In the manifest, screen: false and the types in alerts:
{
"id": "placar",
"name": { "pt": "Placar", "en": "Score" },
"promise": { "pt": "Avisa os gols do seu time", "en": "Tells you your team's goals" },
"screen": false,
"alerts": [
{ "id": "gol", "label": { "pt": "Gol", "en": "Goal" }, "level": "important", "default": true },
{ "id": "fim", "label": { "pt": "Fim de jogo", "en": "Full time" }, "level": "info", "default": true }
],
"settings": [],
"network": ["site.api.espn.com"],
"intervalMs": 60000
}main.js exports run(ctx) and returns no card: it sends alerts with ctx.alerts.send(...) or returns them in { alerts: [...] }:
export async function run(ctx) {
const match = await ctx.fetchJson('https://site.api.espn.com/...');
if (match.goals > (ctx.state.goals ?? 0)) {
ctx.state.goals = match.goals;
return { alerts: [{ type: 'gol', title: 'GOAL!', text: match.score, key: `${match.id}-${match.goals}` }] };
}
return {};
}In the submission wizard, answer "It only sends alerts" to the first question: instead of the card, it asks for the alert types. Screenshots are optional (a photo of an alert on the Miblo helps).
What the person controls
In the Miblo app (Apps tab), an alert-only app shows with an "Alerts" badge and no screen preview:
Allow alerts from the app (or not), and one switch per type.
Test alert, to see how it looks.
The history of the last alerts: when, the type, the title, and whether it was delivered or why not.
The Miblo's quiet hours (say, 22:00 to 08:00), which hold every app's alerts.
In a terminal: miblo apps alerts <id> on|off, miblo apps alerts <id> <type> on|off, miblo apps alerts <id> test, miblo apps alerts <id> history and miblo apps quiet.