betterstackmanager 0.1.0 → 0.2.1

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/README.md CHANGED
@@ -31,8 +31,12 @@ The documentation for this project is contained within the `docs` directory.
31
31
  ## Links
32
32
 
33
33
  - [Documentation](https://codeberg.org/Cyanic76/BSM.js/src/branch/main/docs)
34
- - [NPM](https://www.npmjs.com/package/betterstackmanager)
35
- - [Discord server](https://cyanic.me/next)
34
+ - [Source Code](https://codeberg.org/Cyanic76/BSM.js/)
35
+ - [Discord server](https://cyanic.me/discord)
36
+
37
+ Get the package on
38
+ [Codeberg](https://codeberg.org/Cyanic76/-/packages/npm/betterstackmanager/) or on
39
+ [NPM](https://www.npmjs.com/package/betterstackmanager).
36
40
 
37
41
  ## Contributing & Help
38
42
 
@@ -6,7 +6,15 @@ The `Client` interface is the main entry point to interact with BetterStack.
6
6
 
7
7
  ## `client`
8
8
 
9
- `new Client(token)`
9
+ This function defines your BetterStack API client.
10
+
11
+ `new Client()`
12
+
13
+ ## client.login(token)
14
+
15
+ `client.login(token)`
16
+
17
+ This function is the point where your token is first used.
10
18
 
11
19
  | Value | Type | Required | About |
12
20
  |-|-|-|-|
@@ -14,4 +22,12 @@ The `Client` interface is the main entry point to interact with BetterStack.
14
22
 
15
23
  ## Classes
16
24
 
17
- The Client constructor includes the `incidents` class.
25
+ The Client constructor includes the following classes.
26
+
27
+ - `incidentComments`
28
+ - `incidents`,
29
+ - `monitors`
30
+
31
+ ## Event listeners
32
+
33
+ The Client constructor does not currently listen to any upstream event.
@@ -14,14 +14,14 @@ The errors generated via this module fall in 3 categories:
14
14
  | status | HTTP Response code (usually 4XX or 5XX) |
15
15
  | data | The error data. |
16
16
 
17
- # NetworkError
17
+ ## NetworkError
18
18
 
19
19
  | Value | Type |
20
20
  |-|-|
21
21
  | name | `NetworkError` |
22
22
  | message | The error message. |
23
23
 
24
- # RequestError
24
+ ## RequestError
25
25
 
26
26
  | Value | Type |
27
27
  |-|-|
@@ -47,6 +47,18 @@ This can return:
47
47
  - HTTP 200 with an array of incident comments if it was successful.
48
48
  - HTTP 404 if the given incident doesn't exist.
49
49
 
50
+ ## remove(incidentId, incidentCommentId)
51
+
52
+ Delete a comment from an incident.
53
+
54
+ | Value | Type | Required | About |
55
+ |-|-|-|-|
56
+ | `incidentId` | Number | true | Specify the ID of the incident. |
57
+ | `incidentCommentId` | Number | true | Specify the ID of the incident comment. |
58
+
59
+ This can return:
60
+ - HTTP 204 if it was successful.
61
+
50
62
  ## update(incidentId, incidentCommentId, incidentCommentText)
51
63
 
52
64
  Edit an existing comment on an incident.
@@ -19,9 +19,8 @@ Acknowledge an existing incident.
19
19
  | `incidentId` | Number | true | Specify the ID of the incident. |
20
20
 
21
21
  This can return:
22
-
23
- - HTTP 200 if it was successful,
24
- - HTTP 409 if that incident was already acknowledged.
22
+ - If successful: HTTP 200 with the incident data,
23
+ - If already acknowledged: HTTP 409 with the error message.
25
24
 
26
25
  ## `create`
27
26
 
@@ -43,9 +42,7 @@ Create a new incident. `incidentData` is an object with the following properties
43
42
  | `policy_id` | String | false | Policy escalation ID with which the incident should be escalated. |
44
43
 
45
44
  This can return:
46
-
47
- - HTTP 201 if the incident was successfully created,
48
- - HTTP 404 if the token was not provided.
45
+ - If successful: HTTP 201 and the Incident object containing its data.
49
46
 
50
47
  Most optional options can also be found in the [upstream](https://betterstack.com/docs/uptime/api/create-a-new-incident/) documentation.
51
48
 
@@ -74,9 +71,8 @@ Some properties in the `escalationData` value are only required depending on wha
74
71
  Other properties of this value can be found in the [upstream](https://betterstack.com/docs/uptime/api/escalate-an-ongoing-incident/) documentation, though they're not required.
75
72
 
76
73
  This can return:
77
-
78
- - HTTP 200 if the incident was successfully escalated,
79
- - HTTP 409 if the incident was already resolved.
74
+ - If successful: HTTP 200 with the incident data,
75
+ - If already escalated: HTTP 409 with the error message.
80
76
 
81
77
  ## `get`
82
78
 
@@ -87,8 +83,7 @@ Fetch an existing incident.
87
83
  | `incidentId` | Number | true | Specify the ID of the incident. |
88
84
 
89
85
  This can return:
90
-
91
- - HTTP 200 with the incident data as an Object if it was successful.
86
+ - If successful: HTTP 200 with the incident data.
92
87
 
93
88
  ## `remove`
94
89
 
@@ -101,8 +96,7 @@ Delete an existing incident.
101
96
  | `incidentId` | Number | true | Specify the ID of the incident. |
102
97
 
103
98
  This can return:
104
-
105
- - HTTP 204 if it was successful.
99
+ - If successful: HTTP 204 and an empty body.
106
100
 
107
101
  ## `resolve`
108
102
 
@@ -115,9 +109,8 @@ Resolve and close an existing incident.
115
109
  | `incidentId` | Number | true | Specify the ID of the incident. |
116
110
 
117
111
  This can return:
118
-
119
- - HTTP 200 if it was successful,
120
- - HTTP 409 if that incident was already resolved.
112
+ - If successful: HTTP 200 with the incident data.
113
+ - If already resolved: HTTP 409 with the error message.
121
114
 
122
115
  ## `search`
123
116
 
@@ -139,5 +132,4 @@ This can return:
139
132
  | `acknowledged` | Boolean | false | Whether to query only incidents that are acknowledged or not. |
140
133
 
141
134
  This can return:
142
-
143
- - HTTP 200 with a list of incidents.
135
+ - If successful: HTTP 200 with a list of Incidents objects.
@@ -0,0 +1,115 @@
1
+ # Monitors
2
+
3
+ Class: `client.monitors`
4
+
5
+ This is the point from which all monitors can be managed.
6
+
7
+ Methods: `create`, `edit`, `get`, `getAll`, `getHistory`, `getSLA`, `remove`.
8
+
9
+ ## `create`
10
+
11
+ `create(monitorData)`
12
+
13
+ Create a new monitor.
14
+
15
+ > You should refer to [upstream documentation](https://betterstack.com/docs/uptime/api/create-a-new-monitor/) to learn more about this call.
16
+
17
+ | Value | Type | Required | About |
18
+ |-|-|-|-|
19
+ | `monitorData` | Object | true | The monitor data. |
20
+ | `monitorData.team_name` | String | true | The team which owns the monitor. |
21
+
22
+ This can return:
23
+ - If successful: HTTP 201 and the Monitor object containing the data.
24
+ - If it fails: HTTP 422 with the error message.
25
+
26
+ > Once you've created a monitor, you should expect its ID in the `data.id` value as a String.
27
+
28
+ ## `edit`
29
+
30
+ `edit(id, monitorData)`
31
+
32
+ Edit an existing monitor.
33
+
34
+ > You should refer to [upstream documentation](https://betterstack.com/docs/uptime/api/update-an-existing-monitor/) to learn more about this call.
35
+
36
+ | Value | Type | Required | About |
37
+ |-|-|-|-|
38
+ | `id` | Number | true | The monitor ID. |
39
+ | `monitorData` | Object | true | The monitor data. |
40
+
41
+ This can return:
42
+ - If successful: HTTP 200 and the Monitor object containing the new data.
43
+ - If it fails: HTTP 422 with the error message.
44
+
45
+ ## `get`
46
+
47
+ `get(id)`
48
+
49
+ Get a single monitor.
50
+
51
+ | Value | Type | Required | About |
52
+ |-|-|-|-|
53
+ | `id` | Number | true | The monitor ID. |
54
+
55
+ This can return:
56
+ - If successful: HTTP 200 and the Monitor object containing the data.
57
+
58
+ ## `getAll`
59
+
60
+ `getAll(perPage, page, name, url)`
61
+
62
+ Query bulk monitors.
63
+
64
+ | Value | Type | Required | About |
65
+ |-|-|-|-|
66
+ | `perPage` | Number | false | Amount of monitors per page. Default value is 50. |
67
+ | `page` | Number | false | Results page number. Default value is 1. |
68
+ | `name` | String | false | Pronounceable name of monitors. |
69
+ | `url` | String | false | URL of monitors. |
70
+
71
+ > This method supports **pagination**!
72
+
73
+ This can return:
74
+ - If successful: HTTP 200 and a list of Monitors.
75
+
76
+ ## `getHistory`
77
+
78
+ `getHistory(monitorId)`
79
+
80
+ Get the response time history of an existing monitor.
81
+
82
+ | Value | Type | Required | About |
83
+ |-|-|-|-|
84
+ | `monitorId` | Number | true | Specify the ID of the monitor. |
85
+
86
+ This can return:
87
+ - If successful: HTTP 200 and a Monitor Response Time History object.
88
+
89
+ ## `getSLA`
90
+
91
+ `getSLA(monitorId, from, to)`
92
+
93
+ Get the availability summary of an existing monitor.
94
+
95
+ | Value | Type | Required | About |
96
+ |-|-|-|-|
97
+ | `monitorId` | Number | true | Specify the ID of the monitor. |
98
+ | `from` | String `YYYY-MM-DD` | false | Start date. |
99
+ | `to` | String `YYYY-MM-DD` | false | End date. |
100
+
101
+ This can return:
102
+ - If successful: HTTP 200 and a [Monitor Availability](//codeberg.org/Cyanic76/BSM.js/src/branch/main/docs/objects/Monitor.md#availability) object containing the data.
103
+
104
+ ## `remove`
105
+
106
+ `remove(monitorId)`
107
+
108
+ Delete an existing monitor.
109
+
110
+ | Value | Type | Required | About |
111
+ |-|-|-|-|
112
+ | `monitorId` | Number | true | Specify the ID of the monitor. |
113
+
114
+ This can return:
115
+ - If successful: HTTP 204 and an empty body.
@@ -0,0 +1,75 @@
1
+ # Monitor Groups
2
+
3
+ Class: `client.monitorGroups`
4
+
5
+ Methods: `create`, `edit`, `get`, `listMonitors`, `remove`.
6
+
7
+ ## `create`
8
+
9
+ `create(monitorGroup)`
10
+
11
+ Create a new monitor group.
12
+
13
+ | Value | Type | Required | About |
14
+ |-|-|-|-|
15
+ | `monitorGroup.team_name` | String | true | The team name that will own this group. |
16
+ | `monitorGroup.paused` | Boolean | false | Pause monitoring for all monitors in this group. |
17
+ | `monitorGroup.name` | String | false | The name of this group. |
18
+ | `monitorGroup.sort_index` | Number | false | How to sort this group. |
19
+
20
+ ## `edit`
21
+
22
+ `edit(id, monitorGroup)`
23
+
24
+ Edit an existing monitor group.
25
+
26
+ | Value | Type | Required | About |
27
+ |-|-|-|-|
28
+ | `id` | Number | true | The monitor group ID. |
29
+ | `monitorGroup.team_name` | String | true | The team name that will own this group. |
30
+ | `monitorGroup.paused` | Boolean | false | Pause monitoring for all monitors in this group. |
31
+ | `monitorGroup.name` | String | false | The name of this group. |
32
+ | `monitorGroup.sort_index` | Number | false | How to sort this group. |
33
+
34
+ ## `get`
35
+
36
+ `get(monitorGroupId)`
37
+
38
+ Get a single monitor group.
39
+
40
+ | Value | Type | Required | About |
41
+ |-|-|-|-|
42
+ | `monitorGroupId` | Number | true | Specify the ID of the monitor group. |
43
+
44
+ This can return:
45
+ - If successful: HTTP 200 and the Monitor Group object containing the data.
46
+
47
+ ## `listMonitors`
48
+
49
+ `listMonitors(monitorGroupId)`
50
+
51
+ Show monitors that belong to a group.
52
+
53
+ | Value | Type | Required | About |
54
+ |-|-|-|-|
55
+ | `monitorGroupId` | Number | true | Specify the ID of the monitor group. |
56
+ | `perPage` | Number | false | Amount of monitors per page. Default value is 50. |
57
+ | `page` | Number | false | Results page number. Default value is 1. |
58
+
59
+ > This method supports **pagination**!
60
+
61
+ This can return:
62
+ - If successful: HTTP 200 and a list of Monitors.
63
+
64
+ ## `remove`
65
+
66
+ `remove(monitorGroupId)`
67
+
68
+ Delete an existing monitor group.
69
+
70
+ | Value | Type | Required | About |
71
+ |-|-|-|-|
72
+ | `monitorGroupId` | Number | true | Specify the ID of the monitor group. |
73
+
74
+ This can return:
75
+ - If successful: HTTP 204 and an empty body.
@@ -0,0 +1,29 @@
1
+ # Utils
2
+
3
+ This group of functions is never exported.
4
+
5
+ Functions: `checkDateFormat`, `validateMonitorData`.
6
+
7
+ ## `checkDateFormat(date)`
8
+
9
+ Test a date string against the `YYYY-MM-DD` format.
10
+
11
+ | Value | Type | Required | About |
12
+ |-|-|-|-|
13
+ | `date` | String | true | Date string. |
14
+
15
+ Returns:
16
+ - `true` if the check succeeds.
17
+ - `false` if the check fails.
18
+
19
+ ## `validateMonitorData(data)`
20
+
21
+ Check for most values of a Monitor.
22
+
23
+ | Value | Type | Required | About |
24
+ |-|-|-|-|
25
+ | `data` | Object | true | Monitor object. |
26
+
27
+ Returns:
28
+ - `true` if the check succeeds.
29
+ - An Error and its reason if the check fails.
@@ -17,12 +17,12 @@ The `data` property has many sub-properties, including the following:
17
17
 
18
18
  | Property | Type | Description |
19
19
  |-|-|-|
20
- | `id` | String | The ID of the incident comment. |
21
- | `comment` | String | The comment. |
22
- | `user_id` | Number | The ID of the author. |
23
- | `user_email` | String | The email address of the author. |
24
- | `created_at` | String | The ISO-formatted timestamp at which the incident comment was created. |
25
- | `updated_at` | String | The ISO-formatted timestamp at which the incident comment was last edited. |
20
+ | `attributes.id` | String | The ID of the incident comment. |
21
+ | `attributes.comment` | String | The comment. |
22
+ | `attributes.user_id` | Number | The ID of the author. |
23
+ | `attributes.user_email` | String | The email address of the author. |
24
+ | `attributes.created_at` | String | The ISO-formatted timestamp at which the incident comment was created. |
25
+ | `attributes.updated_at` | String | The ISO-formatted timestamp at which the incident comment was last edited. |
26
26
 
27
27
  ## Example
28
28
 
@@ -5,3 +5,133 @@ A Monitor object has the following properties.
5
5
  > The namespace is `data`.
6
6
 
7
7
  Get the attributes on the [upstream documentation](https://betterstack.com/docs/uptime/api/monitors-api-response-params/).
8
+
9
+ ## List
10
+
11
+ An Array of monitors.
12
+
13
+ You should refer to the [upstream documentation](https://betterstack.com/docs/uptime/api/list-all-existing-monitors/).
14
+
15
+ ## Availability
16
+
17
+ ### attributes
18
+
19
+ The following depend whether you're looking for data since the monitor was created or for data within a given date range.
20
+
21
+ | Property | Type | Description |
22
+ |-|-|-|
23
+ | `attributes.availability` | Number | Percentage of uptime. |
24
+ | `attributes.total_downtime` | Number | Number of seconds of downtime. |
25
+ | `attributes.number_of_incidents` | Number | Number of incidents. |
26
+ | `attributes.longest_incident` | Number | Duration of the longest incident in seconds. |
27
+ | `attributes.average_incident` | Number | Duration of the average incident in seconds. |
28
+
29
+ ### Example
30
+
31
+ ```json
32
+ {
33
+ "data": {
34
+ "id": "1",
35
+ "type": "monitor_sla",
36
+ "attributes": {
37
+ "availability": 99.98,
38
+ "total_downtime": 600, // => 10 min
39
+ "number_of_incidents": 3,
40
+ "longest_incident": 300, // => 5 min
41
+ "average_incident": 200, // => 3 min 20 seconds
42
+ }
43
+ }
44
+ }
45
+ ```
46
+
47
+ ## Response Time
48
+
49
+ ### attributes
50
+
51
+ | Property | Type | Description |
52
+ |-|-|-|
53
+ | `id` | String | Monitor ID. |
54
+ | `type` | String | "monitor_response_times". |
55
+ | `attributes.regions` | Array | List of times by regions. |
56
+ | `attributes.regions.region` | String | Region. |
57
+ | `attributes.regions.response_times` | Array | List of times. |
58
+ | `attributes.regions.response_times[item]` | Object | Response data. |
59
+ | `attributes.regions.response_times[item].at` | String | Timestamp of the response. |
60
+ | `attributes.regions.response_times[item].response_time` | Number | Time of the response in seconds. |
61
+ | `attributes.regions.response_times[item].name_lookup_time` | Number | Time of the DNS lookup in seconds. |
62
+ | `attributes.regions.response_times[item].connection_time` | Number | Time of the connection in seconds. |
63
+ | `attributes.regions.response_times[item].tls_handshake_time` | Number | Time of the TLS handshake in seconds. |
64
+ | `attributes.regions.response_times[item].data_transfer_time` | Number | Time of the data transfer in seconds. |
65
+
66
+ ### Example
67
+
68
+ ```json
69
+ {
70
+ "data": {
71
+ "id": "270985",
72
+ "type": "monitor_response_times",
73
+ "attributes": {
74
+ "regions": [
75
+ {
76
+ "region": "us",
77
+ "response_times": [
78
+ {
79
+ "at": "2025-04-03T11:00:57.000Z",
80
+ "response_time": 0.47273,
81
+ "name_lookup_time": 0.00002,
82
+ "connection_time": 0.14187,
83
+ "tls_handshake_time": 0.19929,
84
+ "data_transfer_time": 0.13154
85
+ },
86
+ {
87
+ "at": "2025-04-03T11:01:27.000Z",
88
+ "response_time": 0.41211,
89
+ "name_lookup_time": 0.00002,
90
+ "connection_time": 0.13058,
91
+ "tls_handshake_time": 0.17109,
92
+ "data_transfer_time": 0.11042
93
+ },
94
+ {
95
+ "at": "2025-04-03T11:04:27.000Z",
96
+ "response_time": 0.41943,
97
+ "name_lookup_time": 0.00002,
98
+ "connection_time": 0.10908,
99
+ "tls_handshake_time": 0.19844,
100
+ "data_transfer_time": 0.11188
101
+ }
102
+ ]
103
+ },
104
+ {
105
+ "region": "eu",
106
+ "response_times": [
107
+ {
108
+ "at": "2025-04-03T11:13:27.000Z",
109
+ "response_time": 0.60383,
110
+ "name_lookup_time": 0.00002,
111
+ "connection_time": 0.15449,
112
+ "tls_handshake_time": 0.31218,
113
+ "data_transfer_time": 0.13714
114
+ },
115
+ {
116
+ "at": "2025-04-03T11:13:57.000Z",
117
+ "response_time": 0.36093,
118
+ "name_lookup_time": 0.00002,
119
+ "connection_time": 0.12147,
120
+ "tls_handshake_time": 0.12925,
121
+ "data_transfer_time": 0.11019
122
+ },
123
+ {
124
+ "at": "2025-04-03T11:17:27.000Z",
125
+ "response_time": 0.34252,
126
+ "name_lookup_time": 0.00002,
127
+ "connection_time": 0.10989,
128
+ "tls_handshake_time": 0.1224,
129
+ "data_transfer_time": 0.11021
130
+ }
131
+ ]
132
+ }
133
+ ]
134
+ }
135
+ }
136
+ }
137
+ ```
package/docs/readme.md CHANGED
@@ -4,8 +4,19 @@ Manage your Better Stack incidents & more using the API with this library.
4
4
 
5
5
  You're in the **user-facing documentation**.
6
6
 
7
+ ## Directories
8
+
9
+ - `classes/`
10
+ - `etc/`
11
+ - `objects/`
12
+ - `upstream/`
13
+
7
14
  ## Links
8
15
 
9
- - [Source code](https://codeberg.org/Cyanic76/BSM.js)
10
- - [NPM](https://www.npmjs.com/package/betterstackmanager)
11
- - [Discord server](https://cyanic.me/next)
16
+ - [Documentation](https://codeberg.org/Cyanic76/BSM.js/src/branch/main/docs)
17
+ - [Source Code](https://codeberg.org/Cyanic76/BSM.js/)
18
+ - [Discord server](https://cyanic.me/discord)
19
+
20
+ Get the package on
21
+ [Codeberg](https://codeberg.org/Cyanic76/-/packages/npm/betterstackmanager/) or on
22
+ [NPM](https://www.npmjs.com/package/betterstackmanager).
@@ -6,7 +6,7 @@ When getting a result from an method that support pagination, you may check the
6
6
  |-|-|-|
7
7
  | `pagination.first` | String | URL to the first page of results. |
8
8
  | `pagination.last` | String | URL to the last page of results. |
9
- | `pagination.prev` | String|null | URL to the previous page of results. If you're on the first page, you'll get `null`. |
10
- | `pagination.next` | String|null | URL to the next page of results. If you're on the last page, you'll get `null`. |
9
+ | `pagination.prev` | String/null | URL to the previous page of results. If you're on the first page, you'll get `null`. |
10
+ | `pagination.next` | String/null | URL to the next page of results. If you're on the last page, you'll get `null`. |
11
11
 
12
- See [upstream documentation](https://betterstack.com/docs/uptime/api/pagination).
12
+ You may as well refer to the [upstream documentation](https://betterstack.com/docs/uptime/api/pagination).
@@ -1,5 +1,5 @@
1
1
  const BSM = require('betterstackmanager');
2
- const config = require('./config.json');
2
+ const config = require('../config.json');
3
3
 
4
4
  const client = new BSM.Client(config.token);
5
5
 
@@ -1,5 +1,5 @@
1
1
  const BSM = require('betterstackmanager');
2
- const config = require('./config.json');
2
+ const config = require('../config.json');
3
3
 
4
4
  const client = new BSM.Client(config.token);
5
5
 
@@ -1,5 +1,5 @@
1
1
  const BSM = require('betterstackmanager');
2
- const config = require('./config.json');
2
+ const config = require('../config.json');
3
3
 
4
4
  const client = new BSM.Client(config.token);
5
5
 
@@ -1,5 +1,5 @@
1
1
  const BSM = require('betterstackmanager');
2
- const config = require('./config.json');
2
+ const config = require('../config.json');
3
3
 
4
4
  const client = new BSM.Client(config.token);
5
5
 
@@ -1,5 +1,5 @@
1
1
  const BSM = require('betterstackmanager');
2
- const config = require('./config.json');
2
+ const config = require('../config.json');
3
3
 
4
4
  const client = new BSM.Client(config.token);
5
5
 
@@ -10,28 +10,16 @@ You'll need to have, at least,
10
10
  - your **global API** key,
11
11
  - a mail address.
12
12
 
13
- ## Following examples
13
+ ## Examples
14
14
 
15
- All examples show how to get your BSM client up and running.
16
-
17
- ## acknowledgeIncident.js
18
-
19
- This short example acknowledges an incident with the given ID.
20
-
21
- ## createIncident.js
22
-
23
- This short example creates an incident with the given name, summary and explanation.
24
-
25
- ## createIncidentComment.js
26
-
27
- This example appends a new comment to an existing incident.
28
-
29
- ## resolveIncident.js
30
-
31
- This example resolves an existing incident with the given ID.
15
+ You'll find examples in the subfolders. They're grouped by the topic they cover.
32
16
 
33
17
  ## Links
34
18
 
35
- - [Source code](https://codeberg.org/Cyanic76/BSM.js)
36
- - [NPM](https://www.npmjs.com/package/betterstackmanager)
37
- - [Discord server](https://cyanic.me/next)
19
+ - [Documentation](https://codeberg.org/Cyanic76/BSM.js/src/branch/main/docs)
20
+ - [Source Code](https://codeberg.org/Cyanic76/BSM.js/)
21
+ - [Discord server](https://cyanic.me/discord)
22
+
23
+ Get the package on
24
+ [Codeberg](https://codeberg.org/Cyanic76/-/packages/npm/betterstackmanager/) or on
25
+ [NPM](https://www.npmjs.com/package/betterstackmanager).
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "betterstackmanager",
3
- "version": "0.1.0",
3
+ "version": "0.2.1",
4
4
  "description": "Interact with Better Stack in Node.JS",
5
5
  "license": "GPL-3.0-only",
6
6
  "author": "Cyanic76",
@@ -12,6 +12,6 @@
12
12
  "lib": "src"
13
13
  },
14
14
  "dependencies": {
15
- "axios": "^1.13.2"
15
+ "axios": "^1.13.4"
16
16
  }
17
17
  }
@@ -1,7 +1,9 @@
1
1
  const axios = require('axios');
2
2
 
3
- const Incidents = require('../etc/Incident');
4
- const IncidentComments = require('../etc/IncidentComment');
3
+ const Incidents = require('../etc/Incident'),
4
+ IncidentComments = require('../etc/IncidentComment'),
5
+ Monitors = require('../etc/Monitor'),
6
+ MonitorGroup = require('../etc/MonitorGroup');
5
7
 
6
8
  const { handleError } = require('../errors/Error');
7
9
 
@@ -18,11 +20,14 @@ class Client {
18
20
  }
19
21
  });
20
22
 
21
- // Get the right classes as found in the folder.
23
+ // Get the right classes as found in the /src/etc folder.
22
24
  this.incidents = new Incidents(this);
23
25
  this.incidentComments = new IncidentComments(this);
26
+ this.monitors = new Monitors(this);
27
+ this.monitorGroups = new MonitorGroup(this);
24
28
  }
25
29
 
30
+ // Handle HTTP requests to the upstream API.
26
31
  async delete (endpoint) {
27
32
  try {
28
33
  const response = await this.client.delete(endpoint);
@@ -0,0 +1,63 @@
1
+ /**
2
+ * Function used to validate date formatting.
3
+ * @param {String} date
4
+ * @returns
5
+ */
6
+ function checkDateFormat(date) {
7
+ const dateRegex = new RegExp(/^\d{4}\-(0[1-9]|1[012])\-(0[1-9]|[12][0-9]|3[01])$/);
8
+ return date.match(dateRegex);
9
+ }
10
+
11
+ /**
12
+ * Function used to validate monitor data.
13
+ * @param {Object} data
14
+ * @returns
15
+ */
16
+ function validateMonitorData(data) {
17
+
18
+ // Validate common properties first
19
+ if(data.monitor_type && typeof(data.monitor_type) != "string") throw new Error("monitor_type must be a String.");
20
+ if(data.url && typeof(data.url) != "string") throw new Error("monitor_url must be a String.");
21
+ if(data.pronounceable_name && typeof(data.pronounceable_name) != "string") throw new Error("pronounceable_name must be a String.");
22
+ if(data.email && typeof(data.email) != "boolean") throw new Error("email must be a Boolean.");
23
+ if(data.sms && typeof(data.sms) != "boolean") throw new Error("sms must be a Boolean.");
24
+ if(data.call && typeof(data.call) != "boolean") throw new Error("call must be a Boolean.");
25
+ if(data.critical_alert && typeof(data.critical_alert) != "boolean") throw new Error("critical_alert must be a Boolean.");
26
+ if(data.check_frequency && isNaN(data.check_frequency)) throw new Error("check_frequency must be a Number.");
27
+ if(data.domain_expiration && isNaN(data.domain_expiration)) throw new Error("domain_expiration must be a Number.");
28
+ if(data.ssl_expiration && isNaN(data.ssl_expiration)) throw new Error("ssl_expiration must be a Number.");
29
+ if(data.expiration_policy_id && isNaN(data.expiration_policy_id)) throw new Error("expiration_policy_id must be a Number.");
30
+ if(data.follow_redirects && typeof(data.follow_redirects) != "boolean") throw new Error("follow_redirects must be a Boolean.");
31
+ if(data.team_wait && isNaN(data.team_wait)) throw new Error("team_wait must be a Number.");
32
+ if(data.paused && typeof(data.paused) != "boolean") throw new Error("paused must be a Boolean.");
33
+ if(data.recovery_period && isNaN(data.recovery_period)) throw new Error("recovery_period must be a Number.");
34
+ if(data.verify_ssl && typeof(data.verify_ssl) != "boolean") throw new Error("verify_ssl must be a Boolean.");
35
+ if(data.confirmation_period && isNaN(data.confirmation_period)) throw new Error("confirmation_period must be a Number.");
36
+ if(data.request_timeout && isNaN(data.request_timeout)) throw new Error("request_timeout must be a Number.");
37
+ if(data.remember_cookies && typeof(data.remember_cookies) != "boolean") throw new Error("remember_cookies must be a Boolean.");
38
+
39
+ // Validate HTTP method
40
+ if(data.http_method){
41
+ const allowedMethods = ["GET", "HEAD", "PATCH", "POST", "PUT"];
42
+ if(!allowedMethods.includes(data.http_method)) throw new Error("http_method must be GET, HEAD, PATCH, POST or PUT (case-sensitive).");
43
+ };
44
+
45
+ // Validate headers
46
+ if(data.request_headers && typeof(data.request_headers) != "object") throw new Error("request_headers must be an Array of Object.");
47
+
48
+ // Validate status codes
49
+ if(data.expected_status_codes){
50
+ if(typeof(data.expected_status_codes) != "object") throw new Error("expected_status_codes must be an Array of Numbers.");
51
+ data.expected_status_codes.forEach(i => {
52
+ if(isNaN(i)) throw new Error(`expected_status_codes: All values must be Numbers. ${i} is not a Number.`);
53
+ });
54
+ };
55
+
56
+ // Here, we send "true" in any case. Or else, we'd get errors.
57
+ return true;
58
+ }
59
+
60
+ module.exports = {
61
+ checkDateFormat,
62
+ validateMonitorData
63
+ };
@@ -1,7 +1,8 @@
1
+ const util = require('../client/utils');
2
+
1
3
  class Incidents {
2
4
  /**
3
- * @param {string} token
4
- * @param {string} baseURL
5
+ * @param {Client} client
5
6
  */
6
7
  constructor(client) {
7
8
  this.client = client;
@@ -19,7 +20,7 @@ class Incidents {
19
20
  if(!incidentData.name) throw new Error("Incident creation: name is a required incident option.");
20
21
  if(!incidentData.summary) throw new Error("Incident creation: summary is a required incident option.");
21
22
  if(!incidentData.description) throw new Error("Incident creation: description is a required incident option.");
22
- if(!incidentData.email || typeof(incidentData.email) != 'boolean') throw new Error("Incident creation: email is a required boolean incident option.");
23
+ if(incidentData.email && typeof(incidentData.email) != 'boolean') throw new Error("Incident creation: email is a required boolean incident option.");
23
24
 
24
25
  // Modify a copy of the provided object.
25
26
  const data = { ...incidentData };
@@ -41,8 +42,8 @@ class Incidents {
41
42
  */
42
43
 
43
44
  async acknowledge(incidentId) {
44
- if(!incidentId) throw new Error("Incident acknowledgement: incidentId is a required incident option.");
45
- if(isNaN(incidentId)) throw new Error("Incident acknowledgement: incidentId is not a Number.");
45
+ if(!incidentId || incidentId && isNaN(incidentId)) throw new Error("Incident acknowledgement: incidentId must be a Number.");
46
+ if(incidentId < 1) throw new Error("Incident acknowledgement: incidentId must be greater than 0.");
46
47
 
47
48
  try {
48
49
  return await this.client.post(`/v3/incidents/${incidentId}/acknowledge`);
@@ -58,8 +59,8 @@ class Incidents {
58
59
  */
59
60
 
60
61
  async get(incidentId) {
61
- if(!incidentId) throw new Error("Incident fetching: incidentId is a required incident option.");
62
- if(isNaN(incidentId)) throw new Error("Incident acknowledgement: incidentId is not a Number.");
62
+ if(!incidentId || incidentId && isNaN(incidentId)) throw new Error("Incident: incidentId must be a Number.");
63
+ if(incidentId < 1) throw new Error("Incident: incidentId must be greater than 0.");
63
64
 
64
65
  try {
65
66
  return await this.client.get(`/v3/incidents/${incidentId}`);
@@ -84,8 +85,8 @@ class Incidents {
84
85
  async search(perPage, page, from, to, monitorId, heartbeatId, resolved, acknowledged, metadata) {
85
86
 
86
87
  // Test both timestamps against the YYYY-MM-DD format.
87
- const dateRegEx = /(19[7-9]\d|20[0-3]\d)-(0[1-9]|1[0-2])-(0[1-9]|[12][0-9]|3[01])/;
88
- if(from != null && from != undefined && !from.match(dateRegEx) || to != null && to != undefined && !to.match(dateRegEx)) throw new Error("Incident search: Both timestamps must be formatted as YYYY-MM-DD.");
88
+ if(from != null && from != undefined && !util.checkDateFormat(from) ||
89
+ to != null && to != undefined && !util.checkDateFormat(to)) throw new Error("Incident search: Both timestamps must be formatted as YYYY-MM-DD.");
89
90
 
90
91
  // Both following values are only boolean values.
91
92
  if(monitorId != null && monitorId != undefined && isNaN(monitorId)) throw new Error("Incident search: Monitor ID must be a number.");
@@ -121,8 +122,7 @@ class Incidents {
121
122
  */
122
123
 
123
124
  async resolve(incidentId) {
124
- if(!incidentId) throw new Error("Incident resolution: incidentId is a required incident option.");
125
- if(isNaN(incidentId)) throw new Error("Incident acknowledgement: incidentId is not a Number.");
125
+ if(!incidentId || incidentId && isNaN(incidentId) || incidentId && parseInt(incidentId) < 1) throw new Error("Incident resolution: incidentId must be a positive Number.");
126
126
 
127
127
  try {
128
128
  return await this.client.post(`/v3/incidents/${incidentId}/resolve`);
@@ -141,10 +141,10 @@ class Incidents {
141
141
  async escalate(incidentId, escalationData){
142
142
 
143
143
  // Before trying anything, check some things right away.
144
- if(!incidentId || !escalationData) throw new Error("Incident resolution: incidentId and escalationData are required incident options.");
145
- if(isNaN(incidentId)) throw new Error("Incident acknowledgement: incidentId is not a Number.");
144
+ if(!escalationData) throw new Error("Incident escalation: escalationData is required.");
145
+ if(!incidentId || incidentId && isNaN(incidentId) || incidentId && parseInt(incidentId) < 1) throw new Error("Incident escalation: incidentId must be a positive Number.");
146
146
  const allowedTypes = ["User", "Team", "Schedule", "Policy", "Organization"];
147
- if(!allowedTypes.includes(escalationData.type)) throw new Error("Incident resolution: Escalation Type is invalid.");
147
+ if(!allowedTypes.includes(escalationData.type)) throw new Error("Incident escalation: Escalation Type is invalid.");
148
148
 
149
149
  switch(escalationData.type){
150
150
  case 'User':
@@ -176,11 +176,10 @@ class Incidents {
176
176
  */
177
177
  async remove(incidentId){
178
178
 
179
- if(!incidentId) throw new Error("Incident deletion: incidentId is a required incident option.");
180
- if(isNaN(incidentId)) throw new Error("Incident acknowledgement: incidentId is not a Number.");
179
+ if(!incidentId || incidentId && isNaN(incidentId) || incidentId && parseInt(incidentId) < 1) throw new Error("Incident deletion: incidentId must be a positive Number.");
181
180
 
182
181
  try {
183
- return await this.client.remove(`/v3/incidents/${incidentId}`);
182
+ return await this.client.delete(`/v3/incidents/${incidentId}`);
184
183
  } catch(error) {
185
184
  throw error;
186
185
  }
@@ -1,7 +1,6 @@
1
1
  class IncidentComments {
2
2
  /**
3
- * @param {string} token
4
- * @param {string} baseURL
3
+ * @param {Client} client
5
4
  */
6
5
  constructor(client) {
7
6
  this.client = client;
@@ -16,7 +15,7 @@ class IncidentComments {
16
15
  async create(incidentId, incidentCommentText) {
17
16
 
18
17
  if(!incidentId || !incidentCommentText) throw new Error("Incident comment creation: incidentId and incidentCommentText are required options.");
19
- if(isNaN(incidentId)) throw new Error("Incident comment creation: incidentId must be a Number.");
18
+ if(isNaN(incidentId) || incidentId < 1) throw new Error("Incident comment creation: incidentId must be a Number greater than 0.");
20
19
 
21
20
  try {
22
21
  return await this.client.post(`/v2/incidents/${incidentId}/comments`, {
@@ -35,8 +34,9 @@ class IncidentComments {
35
34
  */
36
35
  async get(incidentId, incidentCommentId) {
37
36
 
38
- if(!incidentId || !incidentCommentId) throw new Error("Incident comment fetch: incidentId, incidentCommentId are required options.");
37
+ if(!incidentId || !incidentCommentId) throw new Error("Incident comment fetch: incidentId and incidentCommentId are required options.");
39
38
  if(isNaN(incidentId) || isNaN(incidentCommentId)) throw new Error("Incident comment fetch: incidentId and incidentCommentId must both be Numbers.");
39
+ if(incidentId < 1 || incidentCommentId < 1) throw new Error("Incident comment fetch: incidentId and incidentCommentId must be greater than 0.");
40
40
 
41
41
  try {
42
42
  return await this.client.get(`/v2/incidents/${incidentId}/comments/${incidentCommentId}`);
@@ -53,8 +53,8 @@ class IncidentComments {
53
53
  */
54
54
  async getAll(incidentId) {
55
55
 
56
- if(!incidentId) throw new Error("Incident comment fetch: incidentId is a required options.");
57
- if(isNaN(incidentId)) throw new Error("Incident comment fetch: incidentId must be a Number.");
56
+ if(!incidentId || incidentId && isNaN(incidentId)) throw new Error("Incident comment fetch: incidentId is a required option.");
57
+ if(incidentId < 1) throw new Error("Incident comment fetch: incidentId must be a positive Number.");
58
58
 
59
59
  try {
60
60
  return await this.client.get(`/v2/incidents/${incidentId}/comments`);
@@ -64,6 +64,19 @@ class IncidentComments {
64
64
 
65
65
  }
66
66
 
67
+ async remove(incidentId, incidentCommentId) {
68
+
69
+ if(!incidentId || !incidentCommentId || incidentId && isNaN(incidentId) || incidentCommentId && isNaN(incidentCommentId)) throw new Error("Incident comment removal: incidentId and incidentCommentId must be Numbers.");
70
+ if(incidentId < 1 || incidentCommentId < 1) throw new Error("Incident comment removal: incidentId and incidentCommentId must be a positive Number.");
71
+
72
+ try {
73
+ return await this.client.delete(`/v2/incidents/${incidentId}/comments/${incidentCommentId}`);
74
+ } catch(error) {
75
+ throw error;
76
+ }
77
+
78
+ }
79
+
67
80
  /**
68
81
  * Edit an existing incident comment.
69
82
  * @param {Number} incidentId
@@ -73,8 +86,9 @@ class IncidentComments {
73
86
  */
74
87
  async update(incidentId, incidentCommentId, incidentCommentText) {
75
88
 
76
- if(!incidentId || !incidentCommentId || !incidentCommentText ) throw new Error("Incident comment update: incidentId, incidentCommentId, incidentCommentText are required options.");
77
- if(isNaN(incidentId) || isNaN(incidentCommentId)) throw new Error("Incident comment update: incidentId and incidentCommentId must both be Numbers.");
89
+ if(!incidentId || !incidentCommentId || !incidentCommentText) throw new Error("Incident comment update: incidentId, incidentCommentId, incidentCommentText are required options.");
90
+ if(isNaN(incidentId) || isNaN(incidentCommentId)) throw new Error("Incident comment update: incidentId and incidentCommentId must be Numbers.");
91
+ if(incidentId < 1 || incidentCommentId < 1) throw new Error("Incident comment update: incidentId and incidentCommentId must be a positive Number.");
78
92
 
79
93
  try {
80
94
  return await this.client.patch(`/v2/incidents/${incidentId}/comments/${incidentCommentId}`, {
@@ -0,0 +1,152 @@
1
+ const util = require('../client/utils');
2
+
3
+ class Monitor {
4
+ /**
5
+ * @param {Client} client
6
+ */
7
+ constructor(client) {
8
+ this.client = client;
9
+ };
10
+
11
+ /**
12
+ * Create a monitor.
13
+ * @param {String} teamName
14
+ * @param {Object} monitorData
15
+ * @returns
16
+ */
17
+ async create(monitorData) {
18
+ if(!monitorData) throw new Error("Monitor creation: data must be passed as an Object.");
19
+ if(!monitorData.team_name) throw new Error("Monitor creation: data.team_name must be passed as a String.");
20
+
21
+ // Validate our new monitor first.
22
+ try {
23
+ util.validateMonitorData(monitorData);
24
+ } catch(error) {
25
+ throw error;
26
+ }
27
+
28
+ try {
29
+ return await this.client.post('/v2/monitors/', monitorData);
30
+ } catch(error) {
31
+ throw error;
32
+ }
33
+ }
34
+
35
+ async edit(id, monitorData) {
36
+ if(!id || id && isNaN(id)) throw new Error("Monitor update: id must be a Number.");
37
+ if(id < 0) throw new Error("Monitor update: id must be greater than 0.");
38
+
39
+ // Validate our new monitor first.
40
+ try {
41
+ util.validateMonitorData(monitorData);
42
+ } catch(error) {
43
+ throw error;
44
+ }
45
+
46
+ try {
47
+ return await this.client.patch(`/v2/monitors/${id}`, monitorData);
48
+ } catch(error) {
49
+ throw error;
50
+ }
51
+ }
52
+
53
+ /**
54
+ * Get a monitor.
55
+ * @param {Number} id
56
+ */
57
+ async get(id) {
58
+ if(!id || id && isNaN(id)) throw new Error("Monitor: id must be a Number.");
59
+ if(id < 0) throw new Error("Monitor: id must be greater than 0.")
60
+
61
+ try {
62
+ return await this.client.get(`/v2/monitors/${id}`);
63
+ } catch(error) {
64
+ throw error;
65
+ }
66
+ }
67
+
68
+ /**
69
+ * Get all the monitors.
70
+ * @param {Number} perPage
71
+ * @param {Number} page
72
+ * @param {String} name
73
+ * @param {String} url
74
+ */
75
+ async getAll(perPage, page, name, url){
76
+ if(page && isNaN(page) || page && !isNaN(page) && page < 1) throw new Error("Monitor List: pageId must be a number greater than or equal to 0.");
77
+ if(perPage && isNaN(perPage) || perPage && perPage > 250 || perPage && perPage < 1) throw new Error("Monitor List: perPage must be a number between 1 and 250.");
78
+
79
+ let endpoint = '/v2/monitors?';
80
+
81
+ // Build query from passed parameters
82
+ let parameters = {
83
+ "perPage": perPage ? perPage : 50,
84
+ "page": page ? page : 1,
85
+ "name": name ? name : null,
86
+ "url": url ? url : null
87
+ }
88
+ for (let key in parameters) {
89
+ let value = parameters[key];
90
+ if(value != null) endpoint += `${key}=${value}&`;
91
+ };
92
+
93
+ try {
94
+ return await this.client.get(endpoint);
95
+ } catch(error) {
96
+ throw error;
97
+ }
98
+ }
99
+
100
+ async getResponseHistory(monitorId) {
101
+ if(!monitorId || monitorId && isNaN(monitorId)) throw new Error("Monitor History: monitorId must be a Number.");
102
+ if(monitorId < 0) throw new Error("Monitor History: monitorId must be greater than 0.")
103
+
104
+ try {
105
+ return await this.client.get(`/v2/monitors/${monitorId}/response-times`);
106
+ } catch(error) {
107
+ throw error;
108
+ }
109
+ }
110
+
111
+ /**
112
+ * Get the availability summary of the monitor.
113
+ * @param {Number} monitorId
114
+ * @param {String} from
115
+ * @param {String} to
116
+ * @returns
117
+ */
118
+ async getSLA(monitorId, from, to){
119
+ if(!monitorId || monitorId && isNaN(monitorId)) throw new Error("Monitor SLA: monitorId must be a Number.");
120
+ if(monitorId < 0) throw new Error("Monitor SLA: monitorId must be greater than 0.")
121
+
122
+ if(!util.checkDateFormat(from) || !util.checkDateFormat(to)) throw new Error("Monitor SLA: Bad date format.");
123
+
124
+ try {
125
+ return await this.client.get(`/v2/monitors/${monitorId}/sla`, {
126
+ from: from,
127
+ to: to
128
+ });
129
+ } catch(error) {
130
+ throw error;
131
+ }
132
+ }
133
+
134
+ /**
135
+ * Delete an existing monitor.
136
+ * @param {Number} monitorId
137
+ * @returns
138
+ */
139
+ async remove(monitorId) {
140
+ if(!monitorId || monitorId && isNaN(monitorId)) throw new Error("Monitor deletion: monitorId must be a Number.");
141
+ if(monitorId < 0) throw new Error("Monitor deletion: monitorId must be greater than 0.");
142
+
143
+ try {
144
+ return await this.client.delete(`/v3/monitors/${monitorId}`);
145
+ } catch(error) {
146
+ throw error;
147
+ }
148
+ };
149
+
150
+ }
151
+
152
+ module.exports = { Monitor };
@@ -0,0 +1,122 @@
1
+ class MonitorGroup {
2
+ /**
3
+ * @param {Client} client
4
+ */
5
+ constructor(client) {
6
+ this.client = client;
7
+ };
8
+
9
+ /**
10
+ * Create a new monitor group.
11
+ * @param {Object} monitorGroup
12
+ * @returns
13
+ */
14
+ async create(monitorGroup) {
15
+
16
+ if(!monitorGroup) throw new Error("Montior Group: Must provide a Monitor Group object.");
17
+ if(!monitorGroup.team_name) throw new Error("Monitor Group: Team Name must be provided.");
18
+ if(monitorGroup.paused && typeof(monitorGroup.paused) != "Boolean") throw new Error("Monitor Group: paused must be either true or false.");
19
+ if(monitorGroup.sort_index && isNaN(monitorGroup.sort_index) || monitorGroup.sort_index && parseInt(monitorGroup.sort_index) < 1) throw new Error("Monitor Group: sort_index must be a positive number.");
20
+
21
+ try {
22
+ return await this.client.post(`/v2/monitor-groups/`, {
23
+ monitorGroup
24
+ });
25
+ } catch(error) {
26
+ throw error;
27
+ }
28
+
29
+ }
30
+
31
+ /**
32
+ * Edit an existing monitor group.
33
+ * @param {Number} id
34
+ * @param {Object} monitorGroup
35
+ * @returns
36
+ */
37
+ async edit(id, monitorGroup) {
38
+
39
+ if(!id || !monitorGroup) throw new Error("Montior Group: Must provide an ID and a Monitor Group object.");
40
+ if(parseInt(id) < 1 || isNaN(id)) throw new Error("Monitor Group: The ID must be a positive Number.");
41
+ if(monitorGroup.paused && typeof(monitorGroup.paused) != "Boolean") throw new Error("Monitor Group: paused must be either true or false.");
42
+ if(monitorGroup.sort_index && isNaN(monitorGroup.sort_index) || monitorGroup.sort_index && parseInt(monitorGroup.sort_index) < 1) throw new Error("Monitor Group: sort_index must be a positive number.");
43
+
44
+ try {
45
+ return await this.client.patch(`/v2/monitor-groups/`, {
46
+ monitorGroup
47
+ });
48
+ } catch(error) {
49
+ throw error;
50
+ }
51
+
52
+ }
53
+
54
+ /**
55
+ * Get an existing monitor group.
56
+ * @param {Number} monitorGroupId
57
+ * @returns
58
+ */
59
+ async get(monitorGroupId) {
60
+
61
+ if(!monitorGroupId || monitorGroupId && isNaN(monitorGroupId) || monitorGroupId && monitorGroupId < 1) throw new Error("Montior Group Deletion: ID must be a positive number.");
62
+
63
+ try {
64
+ return await this.client.get(`/v2/monitor-groups/${monitorGroupId}`);
65
+ } catch(error) {
66
+ throw error;
67
+ }
68
+
69
+ }
70
+
71
+ /**
72
+ * List monitors that belong to this group.
73
+ * @param {Number} monitorGroupId
74
+ * @param {Number} perPage
75
+ * @param {Number} page
76
+ * @returns
77
+ */
78
+ async listMonitors(monitorGroupId, perPage, page) {
79
+ if(!monitorGroupId || monitorGroupId && isNaN(monitorGroupId) || monitorGroupId && monitorGroupId < 1) throw new Error("Monitor Group ID must be a positive number.");
80
+
81
+ if(page && isNaN(page) || page && !isNaN(page) && page < 1) throw new Error("pageId must be a number greater than or equal to 0.");
82
+ if(perPage && isNaN(perPage) || perPage && perPage > 250 || perPage && perPage < 1) throw new Error("perPage must be a number between 1 and 250.");
83
+
84
+ const endpoint = `/v2/monitor-groups/${monitorGroupId}/monitors`;
85
+
86
+ // Build query from passed parameters
87
+ let parameters = {
88
+ "perPage": perPage ? perPage : 50,
89
+ "page": page ? page : 1
90
+ }
91
+ for (let key in parameters) {
92
+ let value = parameters[key];
93
+ if(value != null) endpoint += `${key}=${value}&`;
94
+ };
95
+
96
+ try {
97
+ return await this.client.get(endpoint);
98
+ } catch(error) {
99
+ throw error;
100
+ }
101
+
102
+ }
103
+
104
+ /**
105
+ * Delete an existing monitor group.
106
+ * @param {Number} monitorGroupId
107
+ * @returns
108
+ */
109
+ async remove(monitorGroupId) {
110
+
111
+ if(!monitorGroupId || monitorGroupId && isNaN(monitorGroupId) || monitorGroupId && monitorGroupId < 1) throw new Error("Montior Group Deletion: ID must be a positive number.");
112
+
113
+ try {
114
+ return await this.client.delete(`/v2/monitor-groups/${monitorGroupId}`);
115
+ } catch(error) {
116
+ throw error;
117
+ }
118
+
119
+ }
120
+ }
121
+
122
+ module.exports = { MonitorGroup };
package/src/index.js CHANGED
@@ -1,8 +1,15 @@
1
- const { Client } = require('./client');
2
- const { Incidents } = require('./etc/Incident');
1
+ const { Client } = require('./client'),
2
+ { Incidents } = require('./etc/Incident'),
3
+ { IncidentComments } = require('./etc/IncidentComment'),
4
+ { Monitor } = require('./etc/Monitor'),
5
+ { MonitorGroup } = require('./etc/MonitorGroup');
3
6
 
4
7
  module.exports = {
5
8
  Client,
6
9
 
7
10
  Incidents,
11
+ IncidentComments,
12
+
13
+ Monitor,
14
+ MonitorGroup
8
15
  };
package/src/readme.md ADDED
@@ -0,0 +1,21 @@
1
+ # BSM - Better Stack Manager
2
+
3
+ Manage your Better Stack incidents & more using the API with this library.
4
+
5
+ You're in the **source code**.
6
+
7
+ ## Directories
8
+
9
+ - `client/` - The main client code and other utilities.
10
+ - `errors/` - The error handler.
11
+ - `etc/` - Other classes as defined in the documentation.
12
+
13
+ ## Links
14
+
15
+ - [Documentation](https://codeberg.org/Cyanic76/BSM.js/src/branch/main/docs)
16
+ - [Source Code](https://codeberg.org/Cyanic76/BSM.js/)
17
+ - [Discord server](https://cyanic.me/discord)
18
+
19
+ Get the package on
20
+ [Codeberg](https://codeberg.org/Cyanic76/-/packages/npm/betterstackmanager/) or on
21
+ [NPM](https://www.npmjs.com/package/betterstackmanager).