# @zerotal/monitor — public API surface

<!-- AUTO-GENERATED by scripts/api-surface.ts. Do not edit by hand.
     Run `bun run api:surface` to regenerate after an intentional API change. -->

> Not a guide — this is a flat, alphabetical snapshot used to detect unintended
> API changes. For how to use these, read the [documentation](https://zerotal.dev/docs).

## .  `(./src/index.ts)`

class MonitorAuthMiddleware = {
  new (): MonitorAuthMiddleware
  handle: (http: HttpContext, next: NextFn) => Promise<Response | void>
}

class MonitorPayloadMiddleware = {
  new (): MonitorPayloadMiddleware
  handle: (http: HttpContext, next: NextFn) => Promise<Response | void>
}

class MonitorProvider = {
  new (app: Application): MonitorProvider
  static dependsOn: (typeof FlowProvider)[]
  static environments: AppEnvironment[]
  static priority?: number
  static provides: readonly ['monitor', 'monitor.store', 'monitor.panel']
  devProcesses: () => DevProcessDefinition[]
  doctorChecks: () => DoctorCheck[]
  onBooted: () => Promise<void>
  onBooting: () => Promise<void>
  onRegister: () => void
  onRequestProcessed: (_ctx: HttpContext) => Promise<void>
  onRequestReceived: (_ctx: HttpContext) => Promise<void>
  onResponseSent: (_ctx: HttpContext) => Promise<void>
  onStarted: () => Promise<void>
  onStarting: () => Promise<void>
  onStopped: () => Promise<void>
  onStopping: () => Promise<void>
  replContext: () => Record<string, unknown>
}

class MonitorStore = {
  new (opts?: MonitorStoreOptions): MonitorStore
  bindApp: (app: AppShape) => void
  bufferQuery: (ctx: object, q: RequestQuery) => void
  collectRequestState: (ctx: object) => RequestState
  dispose: () => void
  forgetFailed: (id: number) => Promise<boolean>
  markNPlus: (ctx: object) => void
  prune: () => number
  recordCache: (hit: boolean, key?: string) => void
  recordDeploy: (sha: string) => void
  recordEvent: (e: {    kind: string;    label: string;    status?: 'ok' | 'warn' | 'bad' | 'info';    route?: string | null;    data?: Record<string, unknown>;}) => void
  recordException: (error: Error | {    type: string;    message: string;}, location?: string, user?: string | null) => void
  recordHttp: (h: {    host: string;    ms: number;    error?: boolean;}) => void
  recordJob: (job: {    status: string;    className?: string;    queue?: string;    ms?: number;    error?: string | null;}) => void
  recordMail: (m: Omit<MailEntry, 'id' | 'when'> & {    when?: string;}) => void
  recordQuery: (q: {    sql: string;    ms: number;    location?: string;}) => void
  recordRequest: (r: {    method: string;    path: string;    status: number;    ms: number;    queries?: RequestQuery[];    logs?: unknown;    nplus?: boolean;    spans?: unknown;    user?: string | null;    ip?: string | null;    memKb?: number;    context?: Record<string, unknown>;    payload?: RequestPayload | null;    error?: string | null;}) => void
  requeueDead: (id: number) => Promise<boolean>
  retentionDays: () => number
  retentionMode: () => RetentionMode
  retryFailed: (id: number) => Promise<boolean>
  routeDetail: (method: string, path: string, range?: MonitorRange) => Promise<RouteDetail>
  snapshot: (range?: MonitorRange) => Promise<MonitorSnapshot>
  storageInfo: () => StorageInfo
  toggleQueuePaused: (name: string) => boolean
  wipe: () => number
}

const Monitor = {    readonly recordRequest: (r: {        method: string;        path: string;        status: number;        ms: number;        queries?: RequestQuery[];        logs?: unknown;        nplus?: boolean;        spans?: unknown;        user?: string | null;        ip?: string | null;        memKb?: number;        context?: Record<string, unknown>;        payload?: RequestPayload | null;        error?: string | null;    }) => void | undefined;    readonly recordException: (error: Error | {        type: string;        message: string;    }, location?: string | undefined, user?: string | null | undefined) => void | undefined;    readonly recordQuery: (q: {        sql: string;        ms: number;        location?: string;    }) => void | undefined;    readonly recordHttp: (h: {        host: string;        ms: number;        error?: boolean;    }) => void | undefined;    readonly recordCache: (hit: boolean, key?: string | undefined) => void | undefined;    readonly recordMail: (m: Omit<MailEntry, 'id' | 'when'> & {        when?: string;    }) => void | undefined;    readonly recordDeploy: (sha: string) => void | undefined;    readonly recordJob: (job: {        status: string;        className?: string;        queue?: string;        ms?: number;        error?: string | null;    }) => void | undefined;    readonly context: (data: Record<string, unknown>) => void;    readonly snapshot: (range?: MonitorRange | undefined) => Promise<MonitorSnapshot> | undefined;    readonly store: MonitorStore | undefined;}

const MonitorPanel = {    configure(sections: Record<string, boolean> | undefined): void;    host(): MonitorPanelHost;    sections(): MonitorSection[];    find(id: string): MonitorSection | undefined;    reset(): void;}

function evaluateAlerts = (snap: MonitorSnapshot, thresholds?: AlertThresholds) => AlertNotice[]

function installMonitorEventBridge = (store: MonitorStore) => () => void

function MonitorConfig = (options?: Partial<MonitorConfigShape>) => ResolvedMonitorConfig

function onAlert = (fn: AlertHandler) => () => void

function renderPrometheus = (snap: MonitorSnapshot) => string

interface Alert = {
  text: string
  tone: 'red' | 'amber'
}

interface AlertContext = {
  apdex: number
  errorRate: number
  p50: number
  p95: number
  p99: number
  pending: number
  rolledBack: number
  rpm: number
  slowRoutes: RouteStat[]
  topException: string | null
}

interface AlertEntry = {
  context: AlertContext
  count: number
  detail: string
  firstSeen: string
  id: string
  lastSeen: string
  level: 'warning' | 'critical'
  metric: string
  occurrences: {    when: string;    detail: string;    value: number;}[]
  status: 'info' | 'ok' | 'warn' | 'bad'
  threshold: number
  title: string
  unit: string
  value: number
}

interface AlertNotice = {
  detail: string
  id: string
  level: 'warning' | 'critical'
  metric: string
  threshold: number
  title: string
  unit: string
  value: number
}

interface AlertThresholds = {
  errorRatePct?: number
  p95Ms?: number
  queuePending?: number
  rolledBackInWindow?: number
}

interface CacheKey = {
  hits: number
  key: string
  rate: number
}

interface CacheStats = {
  evictions: number
  hitRate: number
  hits: number
  keys: CacheKey[]
  misses: number
}

interface CheckIn = {
  cron: string
  last: string
  name: string
  status: 'ok' | 'late' | 'missed'
}

interface CommandEntry = {
  code: number
  ms: number
  name: string
  status: 'ok' | 'bad'
  when: string
}

interface ConnectedClient = {
  actions: number
  connectedFor: string
  id: string
  ip: string
  lastActivity: string
  user: string | null
}

interface DbStat = {
  label: string
  sub: string
  tone?: Tone
  value: string
}

interface DeadJob = {
  attempts: number
  deadAt: string
  error: string
  id: number
  name: string
}

interface Deploy = {
  at: number
  sha: string
  when: string
}

interface ExceptionGroup = {
  count: number
  d1: number
  d30: number
  d7: number
  frames: string[]
  lastSeen: string
  location: string
  message: string
  series: number[]
  type: string
  users: number
}

interface FailedJob = {
  attempts: number
  error: string
  failedAt: string
  id: number
  name: string
  tags: string[]
}

interface FeedEvent = {
  detail: string
  label: string
  route: string | null
  status: 'info' | 'ok' | 'warn' | 'bad'
  when: string
}

interface Gauge = {
  label: string
  sub: string
  value: number
}

interface HealthEntry = {
  detail: string
  name: string
  ok: boolean
}

interface JobEntry = {
  className: string
  error: string | null
  ms: number
  queue: string
  status: string
  when: string
}

interface MailEntry = {
  body: string
  id: number
  mailer: string
  ms: number
  status: 'queued' | 'failed' | 'sent'
  subject: string
  to: string
  when: string
}

interface MemoryRoute = {
  count: number
  memKb: number
  method: string
  path: string
}

interface MigrationEntry = {
  direction: string
  ms: number
  name: string
  ok: boolean
  when: string
}

interface ModelEvent = {
  model: string
  operation: 'created' | 'updated' | 'deleted'
  table: string
  when: string
}

interface ModelStat = {
  created: number
  deleted: number
  model: string
  table: string
  total: number
  updated: number
}

interface MonitorConfigShape = {
  accent?: string | undefined
  alertCooldownMs?: number | undefined
  alertThresholds?: AlertThresholds | undefined
  alertWebhook?: string | undefined
  alerts?: boolean | undefined
  apdexTargetMs?: number | undefined
  auth?: ((user: unknown) => boolean | Promise<boolean>) | undefined
  capturePayloads?: boolean | undefined
  deploy?: string | undefined
  metrics?: boolean | undefined
  metricsPath?: string | undefined
  path?: string | undefined
  payloadMaxBytes?: number | undefined
  record?: boolean | undefined
  refreshMs?: number | undefined
  region?: string | undefined
  retentionDays?: number | undefined
  retentionMode?: RetentionMode | undefined
  sections?: Record<string, boolean> | undefined
  slowQueryMs?: number | undefined
  slowRequestMs?: number | undefined
  snapshotCacheMs?: number | undefined
  storage?: string | undefined
  subtitle?: string | undefined
  title?: string | undefined
  zerotalVersion?: string | undefined
}

interface MonitorSection = {
  group?: string
  icon?: string
  id: string
  label: string
  resolve: (range: MonitorRange) => Promise<MonitorSectionData> | MonitorSectionData
  sort?: number
}

interface MonitorSectionData = {
  stats?: MonitorStat[]
  tables?: MonitorTable[]
}

interface MonitorSnapshot = {
  alertHistory: AlertEntry[]
  alerts: Alert[]
  apdex: number
  cache: CacheStats
  checkins: CheckIn[]
  commands: CommandEntry[]
  dbStats: DbStat[]
  deadLetter: DeadJob[]
  deploys: Deploy[]
  exceptions: ExceptionGroup[]
  failedJobs: FailedJob[]
  gauges: Gauge[]
  health: HealthEntry[]
  jobTags: string[]
  jobsSeries: number[]
  logs: FeedEvent[]
  mail: MailEntry[]
  meta: SystemMeta
  migrations: MigrationEntry[]
  models: ModelStat[]
  notifications: NotificationEntry[]
  nplusOnes: NPlusOne[]
  outgoingHttp: OutgoingHttp[]
  percentiles: Percentile[]
  pulse: PulseStats
  queueStats: QueueMetric[]
  queues: QueueRow[]
  range: MonitorRange
  realtime: RealtimeStats
  recentModels: ModelEvent[]
  requests: RequestEntry[]
  scheduledJobs: ScheduledJob[]
  scheduledRuns: FeedEvent[]
  security: FeedEvent[]
  slowJobs: JobEntry[]
  slowQueries: SlowQuery[]
  slowRequests: RequestEntry[]
  slowRoutes: RouteStat[]
  statCards: StatCard[]
  storage: StorageInfo
  throughput: number[]
  topMemory: MemoryRoute[]
  topUsers: UserUsage[]
  transactions: TxStats
  uptimeChecks: UptimeCheck[]
  workers: Worker[]
}

interface MonitorStat = {
  detail?: string
  label: string
  percent?: number
  tone?: MonitorTone
  value: string | number
}

interface MonitorStoreOptions = {
  apdexTargetMs?: number | undefined
  deploy?: string | undefined
  region?: string | undefined
  retentionDays?: number | undefined
  retentionMode?: RetentionMode | undefined
  slowQueryMs?: number | undefined
  slowRequestMs?: number | undefined
  snapshotCacheMs?: number | undefined
  storage?: string | undefined
  zerotalVersion?: string | undefined
}

interface MonitorTable = {
  columns: MonitorTableColumn[]
  empty?: string
  rows: MonitorRow[]
  title: string
}

interface MonitorTableColumn = {
  align?: 'start' | 'end'
  format?: (value: unknown, row: MonitorRow) => string
  key: string
  label: string
  mono?: boolean
  tone?: (value: unknown, row: MonitorRow) => MonitorTone | null
}

interface NotificationEntry = {
  channel: string
  ms: number
  notification: string
  recipient: string
  status: 'ok' | 'bad'
  when: string
}

interface NPlusOne = {
  fingerprint: string
  lastSeen: string
  occurrences: number
  route: string | null
  worstCount: number
}

interface OutgoingHttp = {
  calls: number
  errRate: number
  host: string
  p95: number
}

interface Percentile = {
  label: string
  value: number
}

interface PulseStats = {
  activeConnections: number
  activeRequests: number
  errorRatePct: number
  requestsPerSec: number
}

interface QueueMetric = {
  label: string
  sub: string
  tone?: Tone
  value: string
}

interface QueueRow = {
  name: string
  paused: boolean
  pending: number
  series: number[]
  throughput: number
  wait: number
}

interface RealtimeStats = {
  actionsPerMin: number
  activeConnections: number
  avgActionMs: number
  avgMemKb: number
  clients: ConnectedClient[]
  closed: number
  components: {    name: string;    actions: number;    avgMs: number;}[]
  opened: number
  recentActions: WsAction[]
  series: number[]
  slowActions: {    component: string;    action: string;    ms: number;    when: string;}[]
}

interface RequestEntry = {
  context: Record<string, unknown>
  error: string | null
  id: number
  ip: string | null
  logs: RequestLog[]
  memKb: number
  method: string
  ms: number
  nplus: boolean
  path: string
  payload: RequestPayload | null
  queries: RequestQuery[]
  spans: RequestSpan[]
  status: number
  user: string | null
  when: string
}

interface RequestLog = {
  level: 'error' | 'info' | 'warn'
  msg: string
}

interface RequestPayload = {
  reqBody: string
  reqHeaders: Record<string, string>
  resBody: string
}

interface RequestQuery = {
  ms: number
  sql: string
}

interface RequestSpan = {
  dur: number
  kind: SpanKind
  label: string
  start: number
}

interface ResolvedMonitorConfig = {
  accent: string
  alertCooldownMs: number
  alertThresholds?: AlertThresholds | undefined
  alertWebhook?: string | undefined
  alerts: boolean
  apdexTargetMs: number
  auth: (user: unknown) => boolean | Promise<boolean>
  capturePayloads: boolean
  deploy?: string | undefined
  metrics: boolean
  metricsPath: string
  path: string
  payloadMaxBytes: number
  record: boolean
  refreshMs: number
  region?: string | undefined
  retentionDays: number
  retentionMode: RetentionMode
  sections?: Record<string, boolean> | undefined
  slowQueryMs: number
  slowRequestMs: number
  snapshotCacheMs: number
  storage: string
  subtitle: string
  title: string
  zerotalVersion?: string | undefined
}

interface RouteDetail = {
  avgMs: number
  errorCount: number
  errorRate: number
  errors: number[]
  latency: number[]
  maxMs: number
  method: string
  p50: number
  p95: number
  p99: number
  path: string
  range: MonitorRange
  recent: RequestEntry[]
  rpm: number
  slowest: RequestEntry[]
  statusDist: StatusClassCount[]
  throughput: number[]
  total: number
}

interface RouteStat = {
  method: string
  ms: number
  path: string
}

interface ScheduledJob = {
  name: string
  queue: string
  runsIn: string
  tag: string
}

interface SlowQuery = {
  callers: number
  location: string
  ms: number
  sql: string
}

interface StatCard = {
  delta: number
  label: string
  series: number[]
  value: string
}

interface StatusClassCount = {
  count: number
  label: '2xx' | '3xx' | '4xx' | '5xx'
}

interface StorageInfo = {
  archived: number
  cacheEvents: number
  deploys: number
  exceptions: number
  httpCalls: number
  jobs: number
  mail: number
  oldestMs: number | null
  queries: number
  requests: number
}

interface SystemMeta = {
  bun: string
  deploy: string
  environment: string
  region: string
  uptime: string
  zerotal: string
}

interface TxStats = {
  avgMs: number
  committed: number
  rolledBack: number
}

interface UptimeCheck = {
  ms: number
  name: string
  ok: boolean
  uptime: string
}

interface UserUsage = {
  id: string
  requests: number
}

interface Worker = {
  jobsPerMin: number
  name: string
  processes: number
  series: number[]
  status: 'running' | 'paused' | 'stopped'
}

interface WsAction = {
  action: string
  component: string
  context: Record<string, unknown>
  id: number
  ip: string | null
  memKb: number
  ms: number
  nplus: boolean
  ok: boolean
  queries: RequestQuery[]
  user: string | null
  when: string
}

type MonitorRange = 'live' | '1h' | '24h' | '7d'

type MonitorRow = {    [x: string]: unknown;}

type MonitorTone = 'default' | 'good' | 'warn' | 'bad'

type SpanKind = 'boot' | 'middleware' | 'controller' | 'query' | 'cache' | 'http' | 'view'

type Tone = 'ok' | 'warn' | 'bad' | 'neutral'

value MonitorLayout = unknown

value MonitorPage = unknown
