diff --git a/apps/web/package.json b/apps/web/package.json index 3380112..4271c9a 100644 --- a/apps/web/package.json +++ b/apps/web/package.json @@ -7,9 +7,8 @@ "build": "bun build src/index.ts --outdir dist" }, "dependencies": { - "elysia": "^1.4.27", "@elysiajs/cors": "^1.4.1", - "@elysiajs/swagger": "^1.3.1", + "elysia": "^1.4.27", "postgres": "^3.4.8" }, "devDependencies": { diff --git a/apps/web/src/dashboard/docs.html b/apps/web/src/dashboard/docs.html index 51efeb1..649d8e3 100644 --- a/apps/web/src/dashboard/docs.html +++ b/apps/web/src/dashboard/docs.html @@ -1,208 +1,370 @@ - + - PingQL — Query Language Docs + PingQL — Documentation - - -
- -

Query Language

-

A MongoDB-style query language for defining exactly when a monitor is up or down.

- - -

Overview

-

A PingQL query is a JSON object that runs against every ping result. If the query evaluates to true, the monitor is considered up. Use $consider: "down" to invert this.

-

By default (no query set), a monitor is up when the HTTP status code is below 400.

- - -

Fields

-

These are the values you can query against:

- - - - - - - - - - - -
FieldTypeDescription
statusnumberHTTP status code (e.g. 200, 404)
bodystringFull response body as text
headers.namestringResponse header value (e.g. headers.content-type)
$responseTimenumberRequest latency in milliseconds
$certExpirynumberDays until SSL certificate expires
$jsonobjectJSONPath expression against response body — see below
$selectobjectCSS selector against response HTML — see below
- - -

Operators

- - - - - - - - - - - - - - - - -
OperatorDescriptionTypes
$eqEqual toany
$neNot equal toany
$gtGreater thannumber
$gteGreater than or equalnumber
$ltLess thannumber
$lteLess than or equalnumber
$containsString contains substringstring
$startsWithString starts withstring
$endsWithString ends withstring
$regexMatches regular expressionstring
$existsField is present and non-nullany
$inValue is in arrayany
- - -

Basic Examples

- -

Status code

-
// Up if status is 200
-{ "status": 200 }
-
-// Up if status is 2xx or 3xx
-{ "status": { "$lt": 400 } }
- -

Response body

-
// Up if body contains "healthy"
-{ "body": { "$contains": "healthy" } }
-
-// Up if body matches a regex
-{ "body": { "$regex": "status.*(ok|healthy)" } }
- -

Headers

-
// Up if response is JSON
-{ "headers.content-type": { "$contains": "application/json" } }
- -

Response time

-
// Up if response is under 500ms
-{ "$responseTime": { "$lt": 500 } }
- -

SSL certificate expiry

-
// Up if cert expires in more than 14 days
-{ "$certExpiry": { "$gt": 14 } }
- - -

JSON Body — $json

-

Use $json to extract and compare a value from a JSON response body. The key is a dot-notation path, the value is a condition.

-
// Up if response JSON has { "status": "ok" }
-{ "$json": { "$.status": { "$eq": "ok" } } }
-
-// Up if search index has >= 1000 entries
-{ "$json": { "$.data.count": { "$gte": 1000 } } }
-
-// Nested path
-{ "$json": { "$.db.connections.active": { "$lt": 100 } } }
- - -

HTML Parsing — $select

-

Use $select to extract text from an HTML response using a CSS selector. Useful for monitoring public-facing pages where there's no API.

-
// Up if h1 text is "Example Domain"
-{ "$select": { "h1": { "$eq": "Example Domain" } } }
-
-// Up if status badge contains "operational"
-{ "$select": { ".status-badge": { "$contains": "operational" } } }
- - -

Logical Operators

-
// Up if status is 200 AND body contains "ok"
-{
-  "$and": [
-    { "status": 200 },
-    { "body": { "$contains": "ok" } }
-  ]
-}
-
-// Up if status is 200 OR 204
-{
-  "$or": [
-    { "status": 200 },
-    { "status": 204 }
-  ]
-}
-
-// Up if status is NOT 500
-{ "$not": { "status": 500 } }
- - -

$consider — Inverting the Result

-

By default, a query returning true means the monitor is up. Set $consider: "down" to invert this — if the conditions match, the monitor is down.

-
// DOWN if response time exceeds 2 seconds
-{
-  "$consider": "down",
-  "$responseTime": { "$gt": 2000 }
-}
-
-// DOWN if cert expires in less than 7 days
-{
-  "$consider": "down",
-  "$certExpiry": { "$lt": 7 }
-}
-
-// DOWN if any of these match
-{
-  "$consider": "down",
-  "$or": [
-    { "status": { "$gte": 500 } },
-    { "$responseTime": { "$gt": 5000 } }
-  ]
-}
- - -

Combining Multiple Queries

-

You can add multiple monitors pointing to the same URL with different queries — one for uptime, one for performance, one for content integrity.

-
// Monitor 1: basic uptime
-{ "status": { "$lt": 400 } }
-
-// Monitor 2: performance — down if slow
-{ "$consider": "down", "$responseTime": { "$gt": 1000 } }
-
-// Monitor 3: content — check API response shape
-{
-  "$and": [
-    { "status": 200 },
-    { "$json": { "$.ok": { "$eq": "true" } } }
-  ]
-}
- -
- ← Back to monitors - API Reference → -
- + +
+ PingQL docs + Dashboard →
- +
+ + + + + +
+ + +
+

Overview

+

PingQL is a developer-friendly uptime monitoring API. Monitors are defined with a URL, an interval, and an optional query that determines what "up" means for your service.

+

Base URL: https://api.pingql.com

+
+ + +
+

Authentication

+

All API requests require an account key passed as a Bearer token:

+
+
http
+
Authorization: Bearer XXXX-XXXX-XXXX-XXXX
+
+

Create an account at /dashboard or via the API. Keys are 16-character hex strings formatted as four groups.

+
+ + +
+

Account

+ +

Register

+
POST/account/register
+

Create a new account. Email is optional — used only for recovery and alerts.

+
+
json — request body
+
{ "email": "you@example.com" }  // optional
+
+
+
json — response
+
{ "key": "B8AE-9621-A963-F652", "email_registered": true }
+
+ +

Update Email

+
POST/account/email
+

Set or update the recovery email for an existing account.

+
+
json — request body
+
{ "email": "you@example.com" }
+
+
+ + +
+

Monitors

+ +

List

+
GET/monitors/
+

Returns all monitors for the authenticated account.

+ +

Create

+
POST/monitors/
+
+
json — request body
+
{
+  "name":       "My API",
+  "url":        "https://api.example.com/health",
+  "interval_s": 60,        // check every 60 seconds (min: 10)
+  "query":      { ... }   // optional — see Query Language below
+}
+
+ +

Get

+
GET/monitors/:id
+

Returns a monitor including its most recent ping results.

+ +

Update

+
PATCH/monitors/:id
+

Update any field. All fields are optional.

+ +

Delete

+
DELETE/monitors/:id
+ +

Toggle

+
POST/monitors/:id/toggle
+

Enable or disable a monitor without deleting it.

+ +

Ping History

+
GET/monitors/:id/pings?limit=100
+

Returns recent ping results for a monitor. Max 1000.

+
+ + +
+

Query Language — Fields

+

A PingQL query is a JSON object evaluated against each ping. If it returns true, the monitor is up. Default (no query): up when status < 400.

+ + + + + + + + + + + +
FieldTypeDescription
statusnumberHTTP status code
bodystringFull response body as text
headers.namestringResponse header, e.g. headers.content-type
$responseTimenumberRequest latency in milliseconds
$certExpirynumberDays until SSL certificate expires
$jsonobjectJSONPath expression against response body
$selectobjectCSS selector against response HTML
+
+ + +
+

Query Language — Operators

+ + + + + + + + + + + + + + +
OperatorDescriptionTypes
$eqEqual toany
$neNot equal toany
$gt / $gteGreater than / or equalnumber
$lt / $lteLess than / or equalnumber
$containsString contains substringstring
$startsWithString starts withstring
$endsWithString ends withstring
$regexMatches regular expressionstring
$existsField is present and non-nullany
$inValue is in arrayany
+
+
json
+
// simple equality shorthand
+{ "status": 200 }
+
+// operator form
+{ "status": { "$lt": 400 } }
+{ "body": { "$contains": "healthy" } }
+{ "headers.content-type": { "$contains": "application/json" } }
+
+
+ + +
+

$json — JSONPath

+

Extract and compare a value from a JSON response body. The key is a dot-notation path starting with $.

+
+
json
+
// response body: { "status": "ok", "db": { "connections": 12 } }
+
+{ "$json": { "$.status": { "$eq": "ok" } } }
+{ "$json": { "$.db.connections": { "$lt": 100 } } }
+
+
+ + +
+

$select — CSS Selector

+

Extract text content from an HTML response using a CSS selector. Useful for monitoring public pages without an API.

+
+
json
+
// matches if <h1> text is exactly "Example Domain"
+{ "$select": { "h1": { "$eq": "Example Domain" } } }
+
+// matches if status badge contains "operational"
+{ "$select": { ".status-badge": { "$contains": "operational" } } }
+
+
+ + +
+

Logical Operators

+
+
json
+
// $and — all conditions must match
+{ "$and": [{ "status": 200 }, { "body": { "$contains": "ok" } }] }
+
+// $or — any condition must match
+{ "$or": [{ "status": 200 }, { "status": 204 }] }
+
+// $not — invert a condition
+{ "$not": { "status": 500 } }
+
+
+ + +
+

$consider

+

By default, matching conditions mean the monitor is up. Set "$consider": "down" to flip this — if the conditions match, the monitor is down.

+
+
json
+
// down if response time exceeds 2 seconds
+{ "$consider": "down", "$responseTime": { "$gt": 2000 } }
+
+// down if cert expires in less than 7 days
+{ "$consider": "down", "$certExpiry": { "$lt": 7 } }
+
+// down if any of these match
+{
+  "$consider": "down",
+  "$or": [
+    { "status": { "$gte": 500 } },
+    { "$responseTime": { "$gt": 5000 } }
+  ]
+}
+
+
+ + +
+

Examples

+ +

Basic health endpoint

+
json
+
{ "status": 200, "body": { "$contains": "healthy" } }
+ +

JSON API response shape

+
json
+
{
+  "$and": [
+    { "status": 200 },
+    { "$json": { "$.ok": { "$eq": true } } }
+  ]
+}
+ +

Performance monitor (mark down if slow)

+
json
+
{ "$consider": "down", "$responseTime": { "$gt": 1000 } }
+ +

Cert expiry alert

+
json
+
{ "$consider": "down", "$certExpiry": { "$lt": 14 } }
+ +

Status page (HTML)

+
json
+
{ "$select": { ".status-indicator": { "$eq": "All systems operational" } } }
+
+ +
+ PingQL · Dashboard +
+ +
+
+ + diff --git a/apps/web/src/dashboard/home.html b/apps/web/src/dashboard/home.html index df8cc48..8dbe571 100644 --- a/apps/web/src/dashboard/home.html +++ b/apps/web/src/dashboard/home.html @@ -16,8 +16,6 @@