Openstatus sdk www.openstatus.dev
at status-report 722 lines 22 kB view raw view rendered
1# OpenStatus Node.js SDK (Beta) 2 3[![JSR](https://jsr.io/badges/@openstatus/sdk-node)](https://jsr.io/@openstatus/sdk-node) 4[![npm](https://img.shields.io/npm/v/@openstatus/sdk-node)](https://www.npmjs.com/package/@openstatus/sdk-node) 5[![License: MIT](https://img.shields.io/badge/License-MIT-yellow.svg)](https://opensource.org/licenses/MIT) 6 7Official Node.js SDK for [OpenStatus](https://openstatus.dev) - The open-source status page with uptime monitoring. 8 9## Features 10 11### Status Page 12- **Status Reports** - Manage incident and maintenance reports with update timelines 13 14### Monitoring 15- **HTTP Monitoring** - Monitor websites and APIs with customizable assertions 16- **TCP Monitoring** - Check database connections and other TCP services 17- **DNS Monitoring** - Verify DNS records and resolution 18 19- **Global Regions** - Monitor from 28 locations worldwide 20- **Type-safe** - Full TypeScript support with generated types from protobuf 21 22## Installation 23 24### JSR 25 26```bash 27npx jsr add @openstatus/sdk-node 28``` 29 30### npm 31 32```bash 33npm install @openstatus/sdk-node 34``` 35 36### Deno 37 38```typescript 39import { openstatus } from "jsr:@openstatus/sdk-node"; 40``` 41 42## Quick Start 43 44```typescript 45import { 46 HTTPMethod, 47 NumberComparator, 48 openstatus, 49 Periodicity, 50 Region, 51} from "@openstatus/sdk-node"; 52 53const headers = { 54 "x-openstatus-key": `${process.env.OPENSTATUS_API_KEY}`, 55}; 56 57// Create a monitor 58const { monitor } = await openstatus.monitor.v1.MonitorService 59 .createHTTPMonitor( 60 { 61 monitor: { 62 name: "My API", 63 url: "https://api.example.com/health", 64 periodicity: Periodicity.PERIODICITY_1M, 65 method: HTTPMethod.HTTP_METHOD_GET, 66 regions: [Region.FLY_AMS, Region.FLY_IAD, Region.FLY_SYD], 67 active: true, 68 statusCodeAssertions: [ 69 { comparator: NumberComparator.EQUAL, target: BigInt(200) }, 70 ], 71 }, 72 }, 73 { headers }, 74 ); 75 76console.log(`Monitor created: ${monitor?.id}`); 77 78// List all monitors 79const { httpMonitors, tcpMonitors, dnsMonitors, totalSize } = await openstatus 80 .monitor.v1.MonitorService.listMonitors({}, { headers }); 81 82console.log(`Found ${totalSize} monitors`); 83``` 84 85## Authentication 86 87All API requests require an API key. Get yours from the 88[OpenStatus dashboard](https://www.openstatus.dev/app). 89 90```typescript 91const headers = { 92 "x-openstatus-key": `${process.env.OPENSTATUS_API_KEY}`, 93}; 94 95// Pass headers to any service method 96await openstatus.monitor.v1.MonitorService.listMonitors({}, { headers }); 97``` 98 99## Environment Variables 100 101| Variable | Description | Default | 102| -------------------- | ----------------------- | -------------------------------- | 103| `OPENSTATUS_API_KEY` | Your OpenStatus API key | - | 104| `OPENSTATUS_API_URL` | Custom API endpoint | `https://api.openstatus.dev/rpc` | 105 106## API Reference 107 108### Monitor Service 109 110#### `createHTTPMonitor(request, options)` 111 112Create an HTTP/HTTPS monitor. 113 114```typescript 115import { HTTPMethod, Periodicity, Region } from "@openstatus/sdk-node"; 116 117const { monitor } = await openstatus.monitor.v1.MonitorService 118 .createHTTPMonitor( 119 { 120 monitor: { 121 name: "My Website", 122 url: "https://example.com", 123 periodicity: Periodicity.PERIODICITY_1M, 124 method: HTTPMethod.HTTP_METHOD_GET, 125 regions: [Region.FLY_AMS, Region.FLY_IAD, Region.FLY_SYD], 126 active: true, 127 }, 128 }, 129 { headers }, 130 ); 131``` 132 133#### `updateHTTPMonitor(request, options)` 134 135Update an existing HTTP monitor. 136 137```typescript 138const { monitor } = await openstatus.monitor.v1.MonitorService 139 .updateHTTPMonitor( 140 { 141 id: "mon_123", 142 monitor: { 143 name: "Updated Name", 144 active: false, 145 }, 146 }, 147 { headers }, 148 ); 149``` 150 151#### `createTCPMonitor(request, options)` 152 153Create a TCP connection monitor. 154 155```typescript 156const { monitor } = await openstatus.monitor.v1.MonitorService.createTCPMonitor( 157 { 158 monitor: { 159 name: "Database", 160 uri: "db.example.com:5432", 161 periodicity: Periodicity.PERIODICITY_5M, 162 regions: [Region.FLY_AMS, Region.FLY_IAD], 163 active: true, 164 }, 165 }, 166 { headers }, 167); 168``` 169 170#### `updateTCPMonitor(request, options)` 171 172Update an existing TCP monitor. 173 174```typescript 175const { monitor } = await openstatus.monitor.v1.MonitorService.updateTCPMonitor( 176 { 177 id: "mon_123", 178 monitor: { 179 name: "Updated Database Monitor", 180 }, 181 }, 182 { headers }, 183); 184``` 185 186#### `createDNSMonitor(request, options)` 187 188Create a DNS resolution monitor. 189 190```typescript 191import { RecordComparator } from "@openstatus/sdk-node"; 192 193const { monitor } = await openstatus.monitor.v1.MonitorService.createDNSMonitor( 194 { 195 monitor: { 196 name: "DNS Check", 197 uri: "example.com", 198 periodicity: Periodicity.PERIODICITY_10M, 199 regions: [Region.FLY_AMS], 200 active: true, 201 recordAssertions: [ 202 { 203 record: "A", 204 comparator: RecordComparator.EQUAL, 205 target: "93.184.216.34", 206 }, 207 ], 208 }, 209 }, 210 { headers }, 211); 212``` 213 214#### `updateDNSMonitor(request, options)` 215 216Update an existing DNS monitor. 217 218```typescript 219const { monitor } = await openstatus.monitor.v1.MonitorService.updateDNSMonitor( 220 { 221 id: "mon_123", 222 monitor: { 223 name: "Updated DNS Check", 224 }, 225 }, 226 { headers }, 227); 228``` 229 230#### `listMonitors(request, options)` 231 232List all monitors with pagination. Returns monitors grouped by type. 233 234```typescript 235const { httpMonitors, tcpMonitors, dnsMonitors, nextPageToken, totalSize } = 236 await openstatus.monitor.v1.MonitorService.listMonitors( 237 { pageSize: 10, pageToken: "" }, 238 { headers }, 239 ); 240``` 241 242#### `triggerMonitor(request, options)` 243 244Trigger an immediate check. 245 246```typescript 247const { success } = await openstatus.monitor.v1.MonitorService.triggerMonitor( 248 { id: "mon_123" }, 249 { headers }, 250); 251``` 252 253#### `deleteMonitor(request, options)` 254 255Delete a monitor. 256 257```typescript 258const { success } = await openstatus.monitor.v1.MonitorService.deleteMonitor( 259 { id: "mon_123" }, 260 { headers }, 261); 262``` 263 264#### `getMonitorStatus(request, options)` 265 266Get the current status of a monitor across all configured regions. 267 268```typescript 269import { MonitorStatus, Region } from "@openstatus/sdk-node"; 270 271const { id, regions } = await openstatus.monitor.v1.MonitorService 272 .getMonitorStatus( 273 { id: "mon_123" }, 274 { headers }, 275 ); 276 277// regions is an array of { region, status } 278// region: Region enum value (e.g., Region.FLY_AMS) 279// status: MonitorStatus.ACTIVE, MonitorStatus.DEGRADED, or MonitorStatus.ERROR 280for (const { region, status } of regions) { 281 console.log(`${Region[region]}: ${MonitorStatus[status]}`); 282} 283``` 284 285#### `getMonitorSummary(request, options)` 286 287Get aggregated metrics and latency percentiles for a monitor. 288 289```typescript 290import { TimeRange } from "@openstatus/sdk-node"; 291 292const summary = await openstatus.monitor.v1.MonitorService.getMonitorSummary( 293 { 294 id: "mon_123", 295 timeRange: TimeRange.TIME_RANGE_7D, // TIME_RANGE_1D, TIME_RANGE_7D, or TIME_RANGE_14D 296 regions: [], // optional: filter by specific regions 297 }, 298 { headers }, 299); 300 301console.log(`Last ping: ${summary.lastPingAt}`); 302console.log(`Success: ${summary.totalSuccessful}`); 303console.log(`Degraded: ${summary.totalDegraded}`); 304console.log(`Failed: ${summary.totalFailed}`); 305console.log(`P50 latency: ${summary.p50}ms`); 306console.log(`P75 latency: ${summary.p75}ms`); 307console.log(`P90 latency: ${summary.p90}ms`); 308console.log(`P95 latency: ${summary.p95}ms`); 309console.log(`P99 latency: ${summary.p99}ms`); 310``` 311 312### Health Service 313 314Check API health status (no authentication required). 315 316```typescript 317import { ServingStatus } from "@openstatus/sdk-node"; 318 319const { status } = await openstatus.health.v1.HealthService.check({}); 320console.log(ServingStatus[status]); // "SERVING" 321``` 322 323### Status Report Service 324 325Manage incident and maintenance reports with update timelines. 326 327#### `createStatusReport(request, options)` 328 329Create a new status report. 330 331```typescript 332import { StatusReportStatus } from "@openstatus/sdk-node"; 333 334const { statusReport } = await openstatus.statusReport.v1.StatusReportService 335 .createStatusReport( 336 { 337 title: "API Degradation", 338 status: StatusReportStatus.INVESTIGATING, 339 message: "We are investigating reports of increased latency.", 340 date: "2024-01-15T10:30:00", 341 pageId: "page_123", 342 pageComponentIds: ["comp_456"], 343 notify: true, 344 }, 345 { headers }, 346 ); 347 348console.log(`Status report created: ${statusReport?.id}`); 349``` 350 351#### `getStatusReport(request, options)` 352 353Get a status report by ID (includes full update timeline). 354 355```typescript 356const { statusReport } = await openstatus.statusReport.v1.StatusReportService 357 .getStatusReport( 358 { id: "sr_123" }, 359 { headers }, 360 ); 361 362console.log(`Title: ${statusReport?.title}`); 363console.log(`Status: ${StatusReportStatus[statusReport?.status ?? 0]}`); 364 365// Access update timeline 366for (const update of statusReport?.updates ?? []) { 367 console.log(`${update.date}: ${update.message}`); 368} 369``` 370 371#### `listStatusReports(request, options)` 372 373List all status reports with pagination and optional filtering. 374 375```typescript 376import { StatusReportStatus } from "@openstatus/sdk-node"; 377 378const { statusReports, totalSize } = await openstatus.statusReport.v1 379 .StatusReportService.listStatusReports( 380 { 381 limit: 10, 382 offset: 0, 383 statuses: [StatusReportStatus.INVESTIGATING, StatusReportStatus.IDENTIFIED], 384 }, 385 { headers }, 386 ); 387 388console.log(`Found ${totalSize} status reports`); 389``` 390 391#### `updateStatusReport(request, options)` 392 393Update status report metadata (title, page components). 394 395```typescript 396const { statusReport } = await openstatus.statusReport.v1.StatusReportService 397 .updateStatusReport( 398 { 399 id: "sr_123", 400 title: "Updated Title", 401 pageComponentIds: ["comp_456", "comp_789"], 402 }, 403 { headers }, 404 ); 405``` 406 407#### `deleteStatusReport(request, options)` 408 409Delete a status report and all its updates. 410 411```typescript 412const { success } = await openstatus.statusReport.v1.StatusReportService 413 .deleteStatusReport( 414 { id: "sr_123" }, 415 { headers }, 416 ); 417``` 418 419#### `addStatusReportUpdate(request, options)` 420 421Add a new update to an existing status report timeline. 422 423```typescript 424import { StatusReportStatus } from "@openstatus/sdk-node"; 425 426const { statusReport } = await openstatus.statusReport.v1.StatusReportService 427 .addStatusReportUpdate( 428 { 429 statusReportId: "sr_123", 430 status: StatusReportStatus.IDENTIFIED, 431 message: "The issue has been identified as a database connection problem.", 432 date: "2024-01-15T11:00:00", // optional, defaults to current time 433 notify: true, 434 }, 435 { headers }, 436 ); 437``` 438 439### Status Report Status 440 441| Enum Value | Description | 442| --------------- | ------------------------------- | 443| `UNSPECIFIED` | Default/unspecified status | 444| `INVESTIGATING` | Actively investigating the issue | 445| `IDENTIFIED` | Root cause has been identified | 446| `MONITORING` | Fix deployed, monitoring | 447| `RESOLVED` | Issue fully resolved | 448 449## Monitor Options 450 451### HTTP Monitor 452 453| Option | Type | Required | Description | 454| ---------------------- | ------------------- | -------- | --------------------------------------------------- | 455| `name` | string | Yes | Monitor name (max 256 chars) | 456| `url` | string | Yes | URL to monitor (max 2048 chars) | 457| `periodicity` | Periodicity | Yes | Check interval (see [Periodicity](#periodicity)) | 458| `method` | HTTPMethod | No | HTTP method (see [HTTP Methods](#http-methods)) | 459| `body` | string | No | Request body | 460| `headers` | Headers[] | No | Custom headers (`{ key: string, value: string }[]`) | 461| `timeout` | bigint | No | Timeout in ms (default: 45000, max: 120000) | 462| `retry` | bigint | No | Retry attempts (default: 3, max: 10) | 463| `followRedirects` | boolean | No | Follow redirects (default: true) | 464| `regions` | Region[] | No | [Regions](#regions) for checks | 465| `active` | boolean | No | Enable monitoring (default: false) | 466| `public` | boolean | No | Public visibility (default: false) | 467| `degradedAt` | bigint | No | Latency threshold (ms) for degraded status | 468| `description` | string | No | Monitor description (max 1024 chars) | 469| `statusCodeAssertions` | array | No | [Status code assertions](#status-code-assertions) | 470| `bodyAssertions` | array | No | [Body assertions](#body-assertions) | 471| `headerAssertions` | array | No | [Header assertions](#header-assertions) | 472| `openTelemetry` | OpenTelemetryConfig | No | OpenTelemetry export configuration | 473 474### TCP Monitor 475 476| Option | Type | Required | Description | 477| --------------- | ------------------- | -------- | ------------------------------------------------ | 478| `name` | string | Yes | Monitor name (max 256 chars) | 479| `uri` | string | Yes | `host:port` to monitor (max 2048 chars) | 480| `periodicity` | Periodicity | Yes | Check interval (see [Periodicity](#periodicity)) | 481| `timeout` | bigint | No | Timeout in ms (default: 45000, max: 120000) | 482| `retry` | bigint | No | Retry attempts (default: 3, max: 10) | 483| `regions` | Region[] | No | [Regions](#regions) for checks | 484| `active` | boolean | No | Enable monitoring (default: false) | 485| `public` | boolean | No | Public visibility (default: false) | 486| `degradedAt` | bigint | No | Latency threshold (ms) for degraded status | 487| `description` | string | No | Monitor description (max 1024 chars) | 488| `openTelemetry` | OpenTelemetryConfig | No | OpenTelemetry export configuration | 489 490### DNS Monitor 491 492| Option | Type | Required | Description | 493| ------------------ | ------------------- | -------- | ------------------------------------------------ | 494| `name` | string | Yes | Monitor name (max 256 chars) | 495| `uri` | string | Yes | Domain to resolve (max 2048 chars) | 496| `periodicity` | Periodicity | Yes | Check interval (see [Periodicity](#periodicity)) | 497| `timeout` | bigint | No | Timeout in ms (default: 45000, max: 120000) | 498| `retry` | bigint | No | Retry attempts (default: 3, max: 10) | 499| `regions` | Region[] | No | [Regions](#regions) for checks | 500| `active` | boolean | No | Enable monitoring (default: false) | 501| `public` | boolean | No | Public visibility (default: false) | 502| `degradedAt` | bigint | No | Latency threshold (ms) for degraded status | 503| `description` | string | No | Monitor description (max 1024 chars) | 504| `recordAssertions` | array | No | [DNS record assertions](#dns-record-assertions) | 505| `openTelemetry` | OpenTelemetryConfig | No | OpenTelemetry export configuration | 506 507### Periodicity 508 509| Enum Value | Description | 510| ----------------- | ----------- | 511| `PERIODICITY_30S` | Every 30s | 512| `PERIODICITY_1M` | Every 1m | 513| `PERIODICITY_5M` | Every 5m | 514| `PERIODICITY_10M` | Every 10m | 515| `PERIODICITY_30M` | Every 30m | 516| `PERIODICITY_1H` | Every 1h | 517 518### HTTP Methods 519 520| Enum Value | Description | 521| --------------------- | ----------- | 522| `HTTP_METHOD_GET` | GET | 523| `HTTP_METHOD_POST` | POST | 524| `HTTP_METHOD_HEAD` | HEAD | 525| `HTTP_METHOD_PUT` | PUT | 526| `HTTP_METHOD_PATCH` | PATCH | 527| `HTTP_METHOD_DELETE` | DELETE | 528| `HTTP_METHOD_TRACE` | TRACE | 529| `HTTP_METHOD_CONNECT` | CONNECT | 530| `HTTP_METHOD_OPTIONS` | OPTIONS | 531 532## Assertions 533 534All assertion comparators are exported as enums from the SDK. 535 536### Status Code Assertions 537 538Validate HTTP response status codes using `NumberComparator`. 539 540```typescript 541import { NumberComparator } from "@openstatus/sdk-node"; 542 543{ 544 statusCodeAssertions: [ 545 { comparator: NumberComparator.EQUAL, target: BigInt(200) }, 546 { comparator: NumberComparator.LESS_THAN, target: BigInt(400) }, 547 ]; 548} 549``` 550 551**NumberComparator values:** 552 553| Enum Value | Description | 554| ----------------------- | --------------------- | 555| `EQUAL` | Equal to target | 556| `NOT_EQUAL` | Not equal to target | 557| `GREATER_THAN` | Greater than target | 558| `GREATER_THAN_OR_EQUAL` | Greater than or equal | 559| `LESS_THAN` | Less than target | 560| `LESS_THAN_OR_EQUAL` | Less than or equal | 561 562### Body Assertions 563 564Validate response body content using `StringComparator`. 565 566```typescript 567import { StringComparator } from "@openstatus/sdk-node"; 568 569{ 570 bodyAssertions: [ 571 { comparator: StringComparator.CONTAINS, target: '"status":"ok"' }, 572 { comparator: StringComparator.NOT_EMPTY, target: "" }, 573 ]; 574} 575``` 576 577**StringComparator values:** 578 579| Enum Value | Description | 580| ----------------------- | --------------------------- | 581| `CONTAINS` | Contains target string | 582| `NOT_CONTAINS` | Does not contain target | 583| `EQUAL` | Equal to target | 584| `NOT_EQUAL` | Not equal to target | 585| `EMPTY` | Body is empty | 586| `NOT_EMPTY` | Body is not empty | 587| `GREATER_THAN` | Lexicographically greater | 588| `GREATER_THAN_OR_EQUAL` | Lexicographically >= target | 589| `LESS_THAN` | Lexicographically less | 590| `LESS_THAN_OR_EQUAL` | Lexicographically <= target | 591 592### Header Assertions 593 594Validate response headers using `StringComparator`. 595 596```typescript 597import { StringComparator } from "@openstatus/sdk-node"; 598 599{ 600 headerAssertions: [ 601 { 602 key: "content-type", 603 comparator: StringComparator.CONTAINS, 604 target: "application/json", 605 }, 606 ]; 607} 608``` 609 610### DNS Record Assertions 611 612Validate DNS records using `RecordComparator`. 613 614```typescript 615import { RecordComparator } from "@openstatus/sdk-node"; 616 617{ 618 recordAssertions: [ 619 { 620 record: "A", 621 comparator: RecordComparator.EQUAL, 622 target: "93.184.216.34", 623 }, 624 { record: "CNAME", comparator: RecordComparator.CONTAINS, target: "cdn" }, 625 ]; 626} 627``` 628 629**RecordComparator values:** 630 631| Enum Value | Description | 632| -------------- | ----------------------- | 633| `EQUAL` | Equal to target | 634| `NOT_EQUAL` | Not equal to target | 635| `CONTAINS` | Contains target string | 636| `NOT_CONTAINS` | Does not contain target | 637 638**Supported record types:** `A`, `AAAA`, `CNAME`, `MX`, `TXT` 639 640## Regions 641 642Monitor from 28 global locations across multiple providers. Use the `Region` 643enum: 644 645```typescript 646import { Region } from "@openstatus/sdk-node"; 647 648// Example: Use specific regions 649regions: [Region.FLY_AMS, Region.FLY_IAD, Region.KOYEB_FRA]; 650``` 651 652### Fly.io Regions 653 654| Enum Value | Location | 655| ---------- | --------------- | 656| `FLY_AMS` | Amsterdam | 657| `FLY_ARN` | Stockholm | 658| `FLY_BOM` | Mumbai | 659| `FLY_CDG` | Paris | 660| `FLY_DFW` | Dallas | 661| `FLY_EWR` | Newark | 662| `FLY_FRA` | Frankfurt | 663| `FLY_GRU` | São Paulo | 664| `FLY_IAD` | Washington D.C. | 665| `FLY_JNB` | Johannesburg | 666| `FLY_LAX` | Los Angeles | 667| `FLY_LHR` | London | 668| `FLY_NRT` | Tokyo | 669| `FLY_ORD` | Chicago | 670| `FLY_SJC` | San Jose | 671| `FLY_SIN` | Singapore | 672| `FLY_SYD` | Sydney | 673| `FLY_YYZ` | Toronto | 674 675### Koyeb Regions 676 677| Enum Value | Location | 678| ----------- | ------------- | 679| `KOYEB_FRA` | Frankfurt | 680| `KOYEB_PAR` | Paris | 681| `KOYEB_SFO` | San Francisco | 682| `KOYEB_SIN` | Singapore | 683| `KOYEB_TYO` | Tokyo | 684| `KOYEB_WAS` | Washington | 685 686### Railway Regions 687 688| Enum Value | Location | 689| ------------------------- | -------------- | 690| `RAILWAY_US_WEST2` | US West | 691| `RAILWAY_US_EAST4` | US East | 692| `RAILWAY_EUROPE_WEST4` | Europe West | 693| `RAILWAY_ASIA_SOUTHEAST1` | Asia Southeast | 694 695## Error Handling 696 697The SDK uses Connect RPC. Errors include a `code` and `message`: 698 699```typescript 700import { ConnectError } from "@connectrpc/connect"; 701 702try { 703 await openstatus.monitor.v1.MonitorService.deleteMonitor( 704 { id: "invalid" }, 705 { headers }, 706 ); 707} catch (error) { 708 if (error instanceof ConnectError) { 709 console.error(`Error ${error.code}: ${error.message}`); 710 } 711} 712``` 713 714## Related 715 716- [OpenStatus](https://openstatus.dev) - Open-source monitoring platform 717- [Documentation](https://docs.openstatus.dev) - Full API documentation 718- [Status Page](https://status.openstatus.dev) - OpenStatus service status 719 720## License 721 722MIT