← All @molecule/* packages · App templates
@molecule/api-resource-status-pageAPI resource · status-page · API (Node) · v1.0.1 · Apache-2.0
Status page resource with service monitoring, incidents, and uptime
npm install @molecule/api-resource-status-page@molecule/api-resource-status-page is an API resource: the routes, validation and storage for status-page, built on the database and auth cores so it runs on whichever providers your app has bonded.
import { createRequestHandler } from '@molecule/api-resource'
import { createRequestHandlerMap, routes } from '@molecule/api-resource-status-page'
// The handler map is a FACTORY (like api-resource-device) — build it with
// the createRequestHandler from @molecule/api-resource (mlcl inject does this):
const requestHandlerMap = createRequestHandlerMap(createRequestHandler)
// Public reads: GET /status, GET /status/services, GET /status/services/:id,
// GET /status/incidents, GET /status/uptime
// Admin-only: POST/PATCH/DELETE /status/services(/:id),
// POST/PATCH /status/incidents(/:id)Works with: @molecule/api-bond, @molecule/api-database, @molecule/api-i18n, @molecule/api-locales-status-page, @molecule/api-resource
Auto-generated, AI-first package reference for the molecule.dev ecosystem. It is written to be read by coding agents as much as by people, and is generated from this package's source — edit
src/index.tsJSDoc, not this file.
Status page resource for molecule.dev.
Public status-page backend: monitored services, incidents with lifecycle updates, health-check history, and uptime windows. The read endpoints power a public status page; the mutation endpoints are for operators.
import { createRequestHandler } from '@molecule/api-resource'
import { createRequestHandlerMap, routes } from '@molecule/api-resource-status-page'
// The handler map is a FACTORY (like api-resource-device) — build it with
// the createRequestHandler from @molecule/api-resource (mlcl inject does this):
const requestHandlerMap = createRequestHandlerMap(createRequestHandler)
// Public reads: GET /status, GET /status/services, GET /status/services/:id,
// GET /status/incidents, GET /status/uptime
// Admin-only: POST/PATCH/DELETE /status/services(/:id),
// POST/PATCH /status/incidents(/:id)
resource
npm install @molecule/api-resource-status-page @molecule/api-bond @molecule/api-database @molecule/api-i18n @molecule/api-locales-status-page @molecule/api-monitoring @molecule/api-notifications @molecule/api-permissions @molecule/api-resource @molecule/api-scheduler zod
CheckPropsHealth check result properties.
type CheckProps = z.infer<typeof checkPropsSchema>
CreateIncidentPropsFields accepted when creating a new incident.
type CreateIncidentProps = z.infer<typeof createIncidentPropsSchema>
CreateServicePropsFields accepted when creating a new service.
type CreateServiceProps = z.infer<typeof createServicePropsSchema>
IncidentPropsFull incident record properties.
type IncidentProps = z.infer<typeof incidentPropsSchema>
ServicePropsFull service record properties.
type ServiceProps = z.infer<typeof servicePropsSchema>
UpdateIncidentPropsUpdatable incident fields.
type UpdateIncidentProps = z.infer<typeof updateIncidentPropsSchema>
UpdateServicePropsUpdatable service fields.
type UpdateServiceProps = z.infer<typeof updateServicePropsSchema>
UptimeWindowPropsUptime window statistics properties.
type UptimeWindowProps = z.infer<typeof uptimeWindowPropsSchema>
createRequestHandlerMap(createRequestHandler)Creates the full request handler map for the Status resource. Maps handler names
(matching route definitions) to Express middleware via createRequestHandler.
requireAdmin is the status-management authorizer middleware referenced by the
mutating routes (createService/updateService/deleteService/createIncident/
updateIncident). It must live here as a real handler-map key so the mlcl
injector's route scanner preserves it — a bare middleware string that isn't a
handler-map key is silently dropped (which is why the previous 'auth' gate was
inert and the mutating routes shipped public). It is already an Express
middleware, so it is NOT wrapped in createRequestHandler.
function createRequestHandlerMap(
createRequestHandler: (
handler: Handler,
) => (req: MoleculeRequest, res: MoleculeResponse, next: MoleculeNextFunction) => Promise<void>,
): Record<string, MoleculeRequestHandler>
createRequestHandler — Factory from @molecule/api-resource that wraps handler configs into Express middleware.Returns: A record mapping handler names to Express middleware functions.
createResource()Creates a new status resource definition.
function createResource(): types.Resource<unknown>
Returns: The status resource descriptor with name, tableName, and schema.
isStatusAdmin(res)Resolves whether the current request's session belongs to an actor authorized
to administer the status page (create/update/delete services + incidents).
Fail-closed: returns false when there is no authenticated session, and
otherwise only true when the session carries an admin claim or a bonded
permissions provider grants the manage status permission.
Use this for in-handler defense-in-depth (it does not depend on the route middleware being preserved by the injector).
function isStatusAdmin(res: MoleculeResponse): Promise<boolean>
res — The response whose locals.session is inspected.Returns: true when the session is an authorized status page admin.
requireAdmin()Route middleware that gates the admin-only status page mutation routes. Calls
next() only for an authenticated status page admin; otherwise forwards an
error to the framework error handler — Unauthorized when no session is
present, Forbidden when the session is authenticated but not authorized to
manage the status page.
Exposed as a request-handler-map key so the injector's route scanner keeps it
(unlike the inert global 'auth' string, which is dropped).
function requireAdmin(): MoleculeRequestHandler
Returns: An Express-compatible middleware function.
checkPropsSchemaSchema for a single health check result.
const checkPropsSchema: z.ZodObject<
{
id: z.ZodString
serviceId: z.ZodString
status: z.ZodEnum<{ up: 'up'; down: 'down'; degraded: 'degraded' }>
httpStatus: z.ZodOptional<z.ZodNumber>
latencyMs: z.ZodOptional<z.ZodNumber>
error: z.ZodOptional<z.ZodString>
checkedAt: z.ZodString
},
z.core.$strip
>
createIncidentPropsSchemaSchema for creating a new incident.
const createIncidentPropsSchema: z.ZodObject<
{
status: z.ZodEnum<{
investigating: 'investigating'
identified: 'identified'
monitoring: 'monitoring'
resolved: 'resolved'
}>
serviceId: z.ZodString
title: z.ZodString
description: z.ZodOptional<z.ZodString>
severity: z.ZodEnum<{ minor: 'minor'; major: 'major'; critical: 'critical' }>
autoDetected: z.ZodDefault<z.ZodBoolean>
startedAt: z.ZodString
},
z.core.$strip
>
createServicePropsSchemaSchema for creating a new service.
const createServicePropsSchema: z.ZodObject<
{
name: z.ZodString
url: z.ZodString
method: z.ZodDefault<z.ZodEnum<{ GET: 'GET'; HEAD: 'HEAD'; POST: 'POST' }>>
expectedStatus: z.ZodDefault<z.ZodNumber>
timeoutMs: z.ZodDefault<z.ZodNumber>
intervalMs: z.ZodDefault<z.ZodNumber>
groupName: z.ZodOptional<z.ZodString>
enabled: z.ZodDefault<z.ZodBoolean>
},
z.core.$strip
>
i18nNamespaceThe i18n namespace for the status resource.
const i18nNamespace: 'status'
i18nRegisteredThe i18n registered.
const i18nRegistered: true
incidentPropsSchemaFull schema for a service incident.
const incidentPropsSchema: z.ZodObject<
{
id: z.ZodString
createdAt: z.ZodString
updatedAt: z.ZodString
serviceId: z.ZodString
title: z.ZodString
description: z.ZodOptional<z.ZodString>
severity: z.ZodEnum<{ minor: 'minor'; major: 'major'; critical: 'critical' }>
status: z.ZodEnum<{
investigating: 'investigating'
identified: 'identified'
monitoring: 'monitoring'
resolved: 'resolved'
}>
autoDetected: z.ZodDefault<z.ZodBoolean>
startedAt: z.ZodString
resolvedAt: z.ZodOptional<z.ZodString>
},
z.core.$strip
>
resourceThe status resource definition.
const resource: types.Resource<unknown>
routesRoute array for status page endpoints: public read routes and admin-gated mutation routes.
const routes: (
| { method: 'get'; path: string; middlewares: never[]; handler: string }
| { method: 'post'; path: string; middlewares: string[]; handler: string }
| { method: 'patch'; path: string; middlewares: string[]; handler: string }
| { method: 'delete'; path: string; middlewares: string[]; handler: string }
)[]
servicePropsSchemaFull schema for a monitored service.
const servicePropsSchema: z.ZodObject<
{
id: z.ZodString
createdAt: z.ZodString
updatedAt: z.ZodString
name: z.ZodString
url: z.ZodString
method: z.ZodDefault<z.ZodEnum<{ GET: 'GET'; HEAD: 'HEAD'; POST: 'POST' }>>
expectedStatus: z.ZodDefault<z.ZodNumber>
timeoutMs: z.ZodDefault<z.ZodNumber>
intervalMs: z.ZodDefault<z.ZodNumber>
groupName: z.ZodOptional<z.ZodString>
enabled: z.ZodDefault<z.ZodBoolean>
},
z.core.$strip
>
STATUS_ADMIN_PERMISSIONSession-claim permission string ('status:manage') that, when present in a
session's permissions array, grants status page administration without a
bonded permissions provider.
const STATUS_ADMIN_PERMISSION: 'status:manage'
STATUS_PERMISSION_ACTIONPermission action checked against @molecule/api-permissions for status page
administration.
const STATUS_PERMISSION_ACTION: 'manage'
STATUS_PERMISSION_RESOURCEPermission resource checked against @molecule/api-permissions for status page
administration.
const STATUS_PERMISSION_RESOURCE: 'status'
updateIncidentPropsSchemaSchema for updating an existing incident (all fields optional).
const updateIncidentPropsSchema: z.ZodObject<
{
status: z.ZodOptional<
z.ZodEnum<{
investigating: 'investigating'
identified: 'identified'
monitoring: 'monitoring'
resolved: 'resolved'
}>
>
title: z.ZodOptional<z.ZodString>
description: z.ZodOptional<z.ZodOptional<z.ZodString>>
severity: z.ZodOptional<z.ZodEnum<{ minor: 'minor'; major: 'major'; critical: 'critical' }>>
resolvedAt: z.ZodOptional<z.ZodOptional<z.ZodString>>
},
z.core.$strip
>
updateServicePropsSchemaSchema for updating an existing service (all fields optional).
const updateServicePropsSchema: z.ZodObject<
{
name: z.ZodOptional<z.ZodString>
url: z.ZodOptional<z.ZodString>
method: z.ZodOptional<z.ZodDefault<z.ZodEnum<{ GET: 'GET'; HEAD: 'HEAD'; POST: 'POST' }>>>
expectedStatus: z.ZodOptional<z.ZodDefault<z.ZodNumber>>
timeoutMs: z.ZodOptional<z.ZodDefault<z.ZodNumber>>
intervalMs: z.ZodOptional<z.ZodDefault<z.ZodNumber>>
groupName: z.ZodOptional<z.ZodOptional<z.ZodString>>
enabled: z.ZodOptional<z.ZodDefault<z.ZodBoolean>>
},
z.core.$strip
>
uptimeWindowPropsSchemaSchema for a pre-computed uptime statistics window.
const uptimeWindowPropsSchema: z.ZodObject<
{
id: z.ZodString
serviceId: z.ZodString
window: z.ZodEnum<{ '1h': '1h'; '24h': '24h'; '7d': '7d'; '30d': '30d'; '90d': '90d' }>
uptimePct: z.ZodNumber
totalChecks: z.ZodNumber
upChecks: z.ZodNumber
avgLatencyMs: z.ZodNumber
},
z.core.$strip
>
handlersMembers:
handlers.createIncident — function: Creates a new incident record. Validates the request body againsthandlers.createService — function: Creates a new monitored service. Validates the request body againsthandlers.deleteService — function: Deletes a monitored service by ID. Returns 404 if the service does not exist.handlers.getService — function: Returns a single service by ID along with the last 50 check results.handlers.getStatus — function: Returns the aggregated system health status.handlers.getUptime — function: Returns uptime window statistics for all services, or filtered byhandlers.listIncidents — function: Lists incidents with support for ?status= filtering and paginationhandlers.listServices — function: Lists all services along with each service's latest check result.handlers.updateIncident — function: Updates an existing incident by ID. Validates the request body againsthandlers.updateService — function: Updates an existing monitored service by ID. Validates the request bodytypesMembers:
types.CheckProps — type: Health check result properties.types.CreateIncidentProps — type: Fields accepted when creating a new incident.types.CreateServiceProps — type: Fields accepted when creating a new service.types.IncidentProps — type: Full incident record properties.types.ServiceProps — type: Full service record properties.types.UpdateIncidentProps — type: Updatable incident fields.types.UpdateServiceProps — type: Updatable service fields.types.UptimeWindowProps — type: Uptime window statistics properties.types.Resource — type: An object describing the status resource.zMembers:
z.core — namespacez.infer — typez.output — typez.input — typez.JSONType — typez.globalRegistry — constz.GlobalMeta — interfacez.registry — functionz.config — functionz.$output — constz.$input — constz.$brand — constz.clone — functionz.regexes — namespacez.treeifyError — functionz.prettifyError — functionz.formatError — functionz.flattenError — functionz.TimePrecision — constz.util — namespacez.NEVER — const: A special constant with type neverz.toJSONSchema — functionz.fromJSONSchema — function: Converts a JSON Schema to a Zod schema. This function should be considered semi-experimental. It's behavior is liable to change.z.locales — namespacez.ZodISODateTime — interfacez.ZodISODate — interfacez.ZodISOTime — interfacez.ZodISODuration — interfacez.iso — namespacez.ZodCoercedString — interfacez.ZodCoercedNumber — interfacez.ZodCoercedBigInt — interfacez.ZodCoercedBoolean — interfacez.ZodCoercedDate — interfacez.coerce — namespacez.string — functionz.email — functionz.guid — functionz.uuid — functionz.uuidv4 — functionz.uuidv6 — functionz.uuidv7 — functionz.url — functionz.httpUrl — functionz.emoji — functionz.nanoid — functionz.cuid — function: Validates a CUID v1 string.z.cuid2 — functionz.ulid — functionz.xid — functionz.ksuid — functionz.ipv4 — functionz.mac — functionz.ipv6 — functionz.cidrv4 — functionz.cidrv6 — functionz.base64 — functionz.base64url — functionz.e164 — functionz.jwt — functionz.stringFormat — functionz.hostname — functionz.hex — functionz.hash — functionz.number — functionz.int — functionz.float32 — functionz.float64 — functionz.int32 — functionz.uint32 — functionz.boolean — functionz.bigint — functionz.int64 — functionz.uint64 — functionz.symbol — functionz.any — functionz.unknown — functionz.never — functionz.date — functionz.array — functionz.keyof — functionz.object — functionz.strictObject — functionz.looseObject — functionz.union — functionz.xor — function: Creates an exclusive union (XOR) where exactly one option must match.z.discriminatedUnion — functionz.intersection — functionz.tuple — functionz.record — functionz.partialRecord — functionz.looseRecord — functionz.map — functionz.set — functionz.nativeEnum — functionz.literal — functionz.file — functionz.transform — functionz.optional — functionz.exactOptional — functionz.nullable — functionz.nullish — functionz._default — functionz.prefault — functionz.nonoptional — functionz.success — functionz.nan — functionz.pipe — functionz.codec — functionz.invertCodec — functionz.readonly — functionz.templateLiteral — functionz.lazy — functionz.promise — functionz._function — functionz.check — functionz.custom — functionz.refine — functionz.superRefine — functionz.json — functionz.preprocess — functionz.ZodStandardSchemaWithJSON — typez.ZodType — interfacez._ZodType — interfacez._ZodString — interfacez.ZodString — interfacez.ZodStringFormat — interfacez.ZodEmail — interfacez.ZodGUID — interfacez.ZodUUID — interfacez.ZodURL — interfacez.ZodEmoji — interfacez.ZodNanoID — interfacez.ZodCUID — interfacez.ZodCUID2 — interfacez.ZodULID — interfacez.ZodXID — interfacez.ZodKSUID — interfacez.ZodIPv4 — interfacez.ZodMAC — interfacez.ZodIPv6 — interfacez.ZodCIDRv4 — interfacez.ZodCIDRv6 — interfacez.ZodBase64 — interfacez.ZodBase64URL — interfacez.ZodE164 — interfacez.ZodJWT — interfacez.ZodCustomStringFormat — interfacez._ZodNumber — interfacez.ZodNumber — interfacez.ZodNumberFormat — interfacez.ZodInt — interfacez.ZodFloat32 — interfacez.ZodFloat64 — interfacez.ZodInt32 — interfacez.ZodUInt32 — interfacez._ZodBoolean — interfacez.ZodBoolean — interfacez._ZodBigInt — interfacez.ZodBigInt — interfacez.ZodBigIntFormat — interfacez.ZodSymbol — interfacez.ZodUndefined — interfacez.undefined — functionz.ZodNull — interfacez.null — functionz.ZodAny — interfacez.ZodUnknown — interfacez.ZodNever — interfacez.ZodVoid — interfacez.void — functionz._ZodDate — interfacez.ZodDate — interfacez.ZodArray — interfacez.SafeExtendShape — typez.ZodObject — interfacez.ZodUnion — interfacez.ZodXor — interfacez.ZodDiscriminatedUnion — interfacez.ZodIntersection — interfacez.ZodTuple — interfacez.ZodRecord — interfacez.ZodMap — interfacez.ZodSet — interfacez.ZodEnum — interfacez.enum — functionz.ZodLiteral — interfacez.ZodFile — interfacez.ZodTransform — interfacez.ZodOptional — interfacez.ZodExactOptional — interfacez.ZodNullable — interfacez.ZodDefault — interfacez.ZodPrefault — interfacez.ZodNonOptional — interfacez.ZodSuccess — interfacez.ZodCatch — interfacez.catch — functionz.ZodNaN — interfacez.ZodPipe — interfacez.ZodCodec — interfacez.ZodPreprocess — interfacez.ZodReadonly — interfacez.ZodTemplateLiteral — interfacez.ZodLazy — interfacez.ZodPromise — interfacez.ZodFunction — interfacez.function — functionz.ZodCustom — interfacez.describe — constz.meta — constz.instanceof — functionz.stringbool — constz.ZodJSONSchemaInternals — interfacez.ZodJSONSchema — interfacez.lt — functionz.lte — functionz.gt — functionz.gte — functionz.positive — functionz.negative — functionz.nonpositive — functionz.nonnegative — functionz.multipleOf — functionz.maxSize — functionz.minSize — functionz.size — functionz.maxLength — functionz.minLength — functionz.length — functionz.regex — functionz.lowercase — functionz.uppercase — functionz.includes — functionz.startsWith — functionz.endsWith — functionz.property — functionz.mime — functionz.overwrite — functionz.normalize — functionz.trim — functionz.toLowerCase — functionz.toUpperCase — functionz.slugify — functionz.RefinementCtx — interfacez.ZodIssue — typez.ZodError — interface: An Error-like class used to store Zod validation issues.z.ZodRealError — constz.ZodFlattenedError — typez.ZodFormattedError — typez.ZodErrorMap — interfacez.IssueData — typez.ZodSafeParseResult — typez.ZodSafeParseSuccess — typez.ZodSafeParseError — typez.parse — constz.parseAsync — constz.safeParse — constz.safeParseAsync — constz.encode — constz.decode — constz.encodeAsync — constz.decodeAsync — constz.safeEncode — constz.safeDecode — constz.safeEncodeAsync — constz.safeDecodeAsync — constz.setErrorMap — functionz.getErrorMap — functionz.TypeOf — typez.Infer — typez.ZodFirstPartySchemaTypes — typez.ZodIssueCode — constz.inferFlattenedErrors — typez.inferFormattedError — typez.BRAND — type: Use z.$brand insteadz.ZodTypeAny — interfacez.ZodSchema — interfacez.Schema — interfacez.ZodRawShape — type: Included for Zod 3 compatibilityz.ZodFirstPartyTypeKind — enumPeer dependencies:
@molecule/api-bond ^1.0.1@molecule/api-database ^1.0.1@molecule/api-i18n ^1.0.1@molecule/api-monitoring ^1.0.1@molecule/api-notifications ^1.0.1@molecule/api-permissions ^1.0.1@molecule/api-resource ^1.0.1@molecule/api-scheduler ^1.0.1@molecule/api-locales-status-page ^1.0.1@molecule/api-bond@molecule/api-database@molecule/api-i18n@molecule/api-locales-status-page@molecule/api-monitoring@molecule/api-notifications@molecule/api-permissions@molecule/api-resource@molecule/api-schedulerzodThe GET routes are PUBLIC by design — a status page is a public surface; do
not put them behind auth. The mutating routes are ADMIN-ONLY and DENY by
default: they are gated by the requireAdmin middleware AND re-checked
inside every mutation handler via isStatusAdmin — fail-closed
defense-in-depth that holds even if a route scanner drops the middleware.
"Admin" resolves as: an admin session claim (isAdmin: true,
role: 'admin', roles containing 'admin', or a 'status:manage' /
'admin' entry in session.permissions) OR a bonded
@molecule/api-permissions grant of manage on status. Until the app
grants one of those, every mutation is denied — grant the claim/permission
at startup, do NOT strip the gate: an open mutation surface lets any caller
deface the public status page (fabricate outages, delete services).
Handler text flows through t() with English defaults; the companion
locale bond @molecule/api-locales-status-page provides translations.
Tables: setup/*.sql creates services, incidents, checks, and
uptimeWindows. An mlcl-scaffolded API replays these setup files
automatically on migrate; anywhere else run them once — nothing at runtime
creates them.
Integration checklist — drive the real UI (live preview, no mocks), adapt each item to this app's actual status-page screens/flows, and check every box off one by one. A box you can't check is an integration bug to fix — not a skip. Verify BEHAVIOR and the public/admin split, not just that CRUD compiles:
operational when no enabled service's
latest check is down or degraded ("All systems operational"), down
if ANY latest check is down, else degraded if any is degraded — the
banner reflects the WORST service, and a service with no check reads
unknown (which never turns the banner red). GET /status/services lists
each service with its latest check.investigating, startedAt)
persists it and it shows on the public GET /status/incidents. The affected
service reads down/degraded on the page because its latest check says so
(checks are monitor-written, never typed in), so the overall banner goes
non-green while the incident is open.resolved (with resolvedAt) moves it to history —
the public list filtered ?status=resolved includes it while the active
incidents drop it — and once the affected service's latest check returns
to up, GET /status recovers to "All systems operational" (the banner
tracks live check state, so a still-down check keeps it red).manage status grant (403),
and nothing changes — enforced twice (the requireAdmin route middleware
AND the in-handler isStatusAdmin re-check). A non-admin has NO path to
fabricate an outage, delete a service, or post a fake incident, and no
endpoint sets a service up/down at all (that is monitor-written).