@observeone/cli 1.10.0 → 1.12.0
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 +46 -2
- package/dist/README.md +46 -2
- package/dist/commands/ai-check/index.d.ts.map +1 -1
- package/dist/commands/ai-check/index.js +1 -0
- package/dist/commands/ai-check/index.js.map +1 -1
- package/dist/commands/alert-channel.d.ts.map +1 -1
- package/dist/commands/alert-channel.js +30 -1
- package/dist/commands/alert-channel.js.map +1 -1
- package/dist/commands/apply.d.ts.map +1 -1
- package/dist/commands/apply.js +114 -80
- package/dist/commands/apply.js.map +1 -1
- package/dist/commands/check.d.ts.map +1 -1
- package/dist/commands/check.js +38 -1
- package/dist/commands/check.js.map +1 -1
- package/dist/commands/export.d.ts.map +1 -1
- package/dist/commands/export.js +2 -13
- package/dist/commands/export.js.map +1 -1
- package/dist/commands/heartbeat.d.ts.map +1 -1
- package/dist/commands/heartbeat.js +1 -0
- package/dist/commands/heartbeat.js.map +1 -1
- package/dist/commands/monitor.d.ts.map +1 -1
- package/dist/commands/monitor.js +40 -3
- package/dist/commands/monitor.js.map +1 -1
- package/dist/commands/resource-command.factory.d.ts +2 -0
- package/dist/commands/resource-command.factory.d.ts.map +1 -1
- package/dist/commands/resource-command.factory.js +15 -5
- package/dist/commands/resource-command.factory.js.map +1 -1
- package/dist/commands/suite/formatters.js +2 -2
- package/dist/commands/suite/formatters.js.map +1 -1
- package/dist/commands/suite/index.d.ts.map +1 -1
- package/dist/commands/suite/index.js +6 -0
- package/dist/commands/suite/index.js.map +1 -1
- package/dist/commands/suite/pull.d.ts +6 -0
- package/dist/commands/suite/pull.d.ts.map +1 -0
- package/dist/commands/suite/pull.js +61 -0
- package/dist/commands/suite/pull.js.map +1 -0
- package/dist/commands/suite/push.d.ts +6 -0
- package/dist/commands/suite/push.d.ts.map +1 -0
- package/dist/commands/suite/push.js +92 -0
- package/dist/commands/suite/push.js.map +1 -0
- package/dist/commands/suite/update.d.ts +6 -0
- package/dist/commands/suite/update.d.ts.map +1 -0
- package/dist/commands/suite/update.js +48 -0
- package/dist/commands/suite/update.js.map +1 -0
- package/dist/interfaces/api-client.interface.d.ts +4 -1
- package/dist/interfaces/api-client.interface.d.ts.map +1 -1
- package/dist/package.json +5 -2
- package/dist/services/api-client.service.d.ts +40 -1
- package/dist/services/api-client.service.d.ts.map +1 -1
- package/dist/services/api-client.service.js +103 -16
- package/dist/services/api-client.service.js.map +1 -1
- package/dist/services/output.service.d.ts.map +1 -1
- package/dist/services/output.service.js +23 -8
- package/dist/services/output.service.js.map +1 -1
- package/dist/types/index.d.ts +21 -2
- package/dist/types/index.d.ts.map +1 -1
- package/dist/utils/deep-equal.d.ts +6 -0
- package/dist/utils/deep-equal.d.ts.map +1 -1
- package/dist/utils/deep-equal.js +11 -0
- package/dist/utils/deep-equal.js.map +1 -1
- package/dist/utils/list-query.d.ts +6 -0
- package/dist/utils/list-query.d.ts.map +1 -0
- package/dist/utils/list-query.js +32 -0
- package/dist/utils/list-query.js.map +1 -0
- package/package.json +9 -3
package/README.md
CHANGED
|
@@ -71,8 +71,11 @@ obs export -f my-stack.json
|
|
|
71
71
|
```
|
|
72
72
|
|
|
73
73
|
### `obs apply`
|
|
74
|
-
Sync your local JSON configuration to the ObserveOne backend.
|
|
74
|
+
Sync your local JSON configuration to the ObserveOne backend. Only changed resources are updated — unchanged ones are skipped.
|
|
75
75
|
```bash
|
|
76
|
+
# Preview what would change (no writes)
|
|
77
|
+
obs apply --dry-run
|
|
78
|
+
|
|
76
79
|
# Sync obs.json
|
|
77
80
|
obs apply
|
|
78
81
|
|
|
@@ -80,6 +83,19 @@ obs apply
|
|
|
80
83
|
obs apply -f my-stack.json
|
|
81
84
|
```
|
|
82
85
|
|
|
86
|
+
`--dry-run` fetches remote state, runs the full diff, and prints a git-style preview:
|
|
87
|
+
```
|
|
88
|
+
~ monitor "Production API"
|
|
89
|
+
- cron_expression: "*/5 * * * *"
|
|
90
|
+
+ cron_expression: "*/10 * * * *"
|
|
91
|
+
|
|
92
|
+
+ monitor "Staging DB" (new)
|
|
93
|
+
|
|
94
|
+
Monitors: 1 to create, 1 to update, 12 unchanged
|
|
95
|
+
|
|
96
|
+
Run without --dry-run to apply.
|
|
97
|
+
```
|
|
98
|
+
|
|
83
99
|
**Example `obs.json` schema:**
|
|
84
100
|
```json
|
|
85
101
|
{
|
|
@@ -88,7 +104,7 @@ obs apply -f my-stack.json
|
|
|
88
104
|
"name": "Production Website",
|
|
89
105
|
"description": "Main landing page monitor",
|
|
90
106
|
"url": "https://example.com",
|
|
91
|
-
"
|
|
107
|
+
"cron_expression": "*/5 * * * *",
|
|
92
108
|
"alert_on_failure": true
|
|
93
109
|
}
|
|
94
110
|
],
|
|
@@ -119,6 +135,7 @@ You can manually create, read, update, delete, and toggle individual resources d
|
|
|
119
135
|
```bash
|
|
120
136
|
obs monitor create --name "Frontend" --url "https://example.com" --interval "*/5 * * * *"
|
|
121
137
|
obs monitor list
|
|
138
|
+
obs monitor list --search "Front" --status up --is-active true --limit 10 --page 1 --json
|
|
122
139
|
obs monitor get <id>
|
|
123
140
|
obs monitor update <id> --name "Updated Frontend" --interval "*/10 * * * *"
|
|
124
141
|
obs monitor toggle <id>
|
|
@@ -129,6 +146,7 @@ obs monitor delete <id> -y
|
|
|
129
146
|
```bash
|
|
130
147
|
obs check create --name "Auth API" --url "https://api.example.com/auth" --method "POST"
|
|
131
148
|
obs check list
|
|
149
|
+
obs check list --search "Auth" --status paused --is-active false --json
|
|
132
150
|
obs check update <id> --method "GET"
|
|
133
151
|
obs check toggle <id>
|
|
134
152
|
obs check delete <id> -y
|
|
@@ -138,11 +156,18 @@ obs check delete <id> -y
|
|
|
138
156
|
```bash
|
|
139
157
|
obs heartbeat create --name "Daily Backup" --period 86400 --grace 3600
|
|
140
158
|
obs heartbeat list
|
|
159
|
+
obs heartbeat list --search "Backup" --status late --limit 5 --json
|
|
141
160
|
obs heartbeat update <id> --period 43200
|
|
142
161
|
obs heartbeat toggle <id>
|
|
143
162
|
obs heartbeat delete <id> -y
|
|
144
163
|
```
|
|
145
164
|
|
|
165
|
+
List filtering notes:
|
|
166
|
+
- `--search` matches visible fields server-side.
|
|
167
|
+
- `--status` uses each resource's real status values.
|
|
168
|
+
- `--is-active true|false` filters by activation state separately from status.
|
|
169
|
+
- `--page` and `--limit` enable server-side pagination.
|
|
170
|
+
|
|
146
171
|
### Alert Channels
|
|
147
172
|
```bash
|
|
148
173
|
obs alert-channel create --name "Ops Email" --type email --email "ops@example.com"
|
|
@@ -283,6 +308,25 @@ Append `--json` to **any** command. The CLI will automatically suppress all huma
|
|
|
283
308
|
}
|
|
284
309
|
```
|
|
285
310
|
|
|
311
|
+
For filtered list commands, the `data` payload is paginated:
|
|
312
|
+
```json
|
|
313
|
+
{
|
|
314
|
+
"status": "SUCCESS",
|
|
315
|
+
"data": {
|
|
316
|
+
"items": [],
|
|
317
|
+
"pagination": {
|
|
318
|
+
"page": 1,
|
|
319
|
+
"limit": 10,
|
|
320
|
+
"total": 0,
|
|
321
|
+
"totalPages": 0
|
|
322
|
+
}
|
|
323
|
+
},
|
|
324
|
+
"metadata": {
|
|
325
|
+
"timestamp": "2026-04-22T12:00:00.000Z"
|
|
326
|
+
}
|
|
327
|
+
}
|
|
328
|
+
```
|
|
329
|
+
|
|
286
330
|
### Headless Login
|
|
287
331
|
Agents can authenticate securely using existing credentials:
|
|
288
332
|
```bash
|
package/dist/README.md
CHANGED
|
@@ -71,8 +71,11 @@ obs export -f my-stack.json
|
|
|
71
71
|
```
|
|
72
72
|
|
|
73
73
|
### `obs apply`
|
|
74
|
-
Sync your local JSON configuration to the ObserveOne backend.
|
|
74
|
+
Sync your local JSON configuration to the ObserveOne backend. Only changed resources are updated — unchanged ones are skipped.
|
|
75
75
|
```bash
|
|
76
|
+
# Preview what would change (no writes)
|
|
77
|
+
obs apply --dry-run
|
|
78
|
+
|
|
76
79
|
# Sync obs.json
|
|
77
80
|
obs apply
|
|
78
81
|
|
|
@@ -80,6 +83,19 @@ obs apply
|
|
|
80
83
|
obs apply -f my-stack.json
|
|
81
84
|
```
|
|
82
85
|
|
|
86
|
+
`--dry-run` fetches remote state, runs the full diff, and prints a git-style preview:
|
|
87
|
+
```
|
|
88
|
+
~ monitor "Production API"
|
|
89
|
+
- cron_expression: "*/5 * * * *"
|
|
90
|
+
+ cron_expression: "*/10 * * * *"
|
|
91
|
+
|
|
92
|
+
+ monitor "Staging DB" (new)
|
|
93
|
+
|
|
94
|
+
Monitors: 1 to create, 1 to update, 12 unchanged
|
|
95
|
+
|
|
96
|
+
Run without --dry-run to apply.
|
|
97
|
+
```
|
|
98
|
+
|
|
83
99
|
**Example `obs.json` schema:**
|
|
84
100
|
```json
|
|
85
101
|
{
|
|
@@ -88,7 +104,7 @@ obs apply -f my-stack.json
|
|
|
88
104
|
"name": "Production Website",
|
|
89
105
|
"description": "Main landing page monitor",
|
|
90
106
|
"url": "https://example.com",
|
|
91
|
-
"
|
|
107
|
+
"cron_expression": "*/5 * * * *",
|
|
92
108
|
"alert_on_failure": true
|
|
93
109
|
}
|
|
94
110
|
],
|
|
@@ -119,6 +135,7 @@ You can manually create, read, update, delete, and toggle individual resources d
|
|
|
119
135
|
```bash
|
|
120
136
|
obs monitor create --name "Frontend" --url "https://example.com" --interval "*/5 * * * *"
|
|
121
137
|
obs monitor list
|
|
138
|
+
obs monitor list --search "Front" --status up --is-active true --limit 10 --page 1 --json
|
|
122
139
|
obs monitor get <id>
|
|
123
140
|
obs monitor update <id> --name "Updated Frontend" --interval "*/10 * * * *"
|
|
124
141
|
obs monitor toggle <id>
|
|
@@ -129,6 +146,7 @@ obs monitor delete <id> -y
|
|
|
129
146
|
```bash
|
|
130
147
|
obs check create --name "Auth API" --url "https://api.example.com/auth" --method "POST"
|
|
131
148
|
obs check list
|
|
149
|
+
obs check list --search "Auth" --status paused --is-active false --json
|
|
132
150
|
obs check update <id> --method "GET"
|
|
133
151
|
obs check toggle <id>
|
|
134
152
|
obs check delete <id> -y
|
|
@@ -138,11 +156,18 @@ obs check delete <id> -y
|
|
|
138
156
|
```bash
|
|
139
157
|
obs heartbeat create --name "Daily Backup" --period 86400 --grace 3600
|
|
140
158
|
obs heartbeat list
|
|
159
|
+
obs heartbeat list --search "Backup" --status late --limit 5 --json
|
|
141
160
|
obs heartbeat update <id> --period 43200
|
|
142
161
|
obs heartbeat toggle <id>
|
|
143
162
|
obs heartbeat delete <id> -y
|
|
144
163
|
```
|
|
145
164
|
|
|
165
|
+
List filtering notes:
|
|
166
|
+
- `--search` matches visible fields server-side.
|
|
167
|
+
- `--status` uses each resource's real status values.
|
|
168
|
+
- `--is-active true|false` filters by activation state separately from status.
|
|
169
|
+
- `--page` and `--limit` enable server-side pagination.
|
|
170
|
+
|
|
146
171
|
### Alert Channels
|
|
147
172
|
```bash
|
|
148
173
|
obs alert-channel create --name "Ops Email" --type email --email "ops@example.com"
|
|
@@ -283,6 +308,25 @@ Append `--json` to **any** command. The CLI will automatically suppress all huma
|
|
|
283
308
|
}
|
|
284
309
|
```
|
|
285
310
|
|
|
311
|
+
For filtered list commands, the `data` payload is paginated:
|
|
312
|
+
```json
|
|
313
|
+
{
|
|
314
|
+
"status": "SUCCESS",
|
|
315
|
+
"data": {
|
|
316
|
+
"items": [],
|
|
317
|
+
"pagination": {
|
|
318
|
+
"page": 1,
|
|
319
|
+
"limit": 10,
|
|
320
|
+
"total": 0,
|
|
321
|
+
"totalPages": 0
|
|
322
|
+
}
|
|
323
|
+
},
|
|
324
|
+
"metadata": {
|
|
325
|
+
"timestamp": "2026-04-22T12:00:00.000Z"
|
|
326
|
+
}
|
|
327
|
+
}
|
|
328
|
+
```
|
|
329
|
+
|
|
286
330
|
### Headless Login
|
|
287
331
|
Agents can authenticate securely using existing credentials:
|
|
288
332
|
```bash
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../../src/commands/ai-check/index.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,OAAO,EAAE,MAAM,WAAW,CAAC;AACpC,OAAO,EAAE,cAAc,EAAE,MAAM,sCAAsC,CAAC;AACtE,OAAO,EAAE,UAAU,EAAE,MAAM,0CAA0C,CAAC;AACtE,OAAO,EAAE,cAAc,EAAE,MAAM,sCAAsC,CAAC;AAStE,wBAAgB,oBAAoB,CAClC,aAAa,EAAE,cAAc,EAC7B,SAAS,EAAE,UAAU,EACrB,aAAa,EAAE,cAAc,GAC5B,OAAO,
|
|
1
|
+
{"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../../src/commands/ai-check/index.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,OAAO,EAAE,MAAM,WAAW,CAAC;AACpC,OAAO,EAAE,cAAc,EAAE,MAAM,sCAAsC,CAAC;AACtE,OAAO,EAAE,UAAU,EAAE,MAAM,0CAA0C,CAAC;AACtE,OAAO,EAAE,cAAc,EAAE,MAAM,sCAAsC,CAAC;AAStE,wBAAgB,oBAAoB,CAClC,aAAa,EAAE,cAAc,EAC7B,SAAS,EAAE,UAAU,EACrB,aAAa,EAAE,cAAc,GAC5B,OAAO,CAeT"}
|
|
@@ -8,6 +8,7 @@ import { createAiCheckStatusCommand } from './status.js';
|
|
|
8
8
|
import { createAiCheckWaitCommand } from './wait.js';
|
|
9
9
|
export function createAiCheckCommand(configService, apiClient, outputService) {
|
|
10
10
|
const aiCheck = new Command('ai-check').description('Manage and run AI-powered tests');
|
|
11
|
+
aiCheck._hidden = true;
|
|
11
12
|
aiCheck.addCommand(createAiCheckRunCommand(configService, apiClient, outputService), {
|
|
12
13
|
isDefault: true,
|
|
13
14
|
});
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"index.js","sourceRoot":"","sources":["../../../src/commands/ai-check/index.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,OAAO,EAAE,MAAM,WAAW,CAAC;AAIpC,OAAO,EAAE,uBAAuB,EAAE,MAAM,UAAU,CAAC;AACnD,OAAO,EAAE,wBAAwB,EAAE,MAAM,WAAW,CAAC;AACrD,OAAO,EAAE,uBAAuB,EAAE,MAAM,UAAU,CAAC;AACnD,OAAO,EAAE,0BAA0B,EAAE,MAAM,aAAa,CAAC;AACzD,OAAO,EAAE,0BAA0B,EAAE,MAAM,aAAa,CAAC;AACzD,OAAO,EAAE,0BAA0B,EAAE,MAAM,aAAa,CAAC;AACzD,OAAO,EAAE,wBAAwB,EAAE,MAAM,WAAW,CAAC;AAErD,MAAM,UAAU,oBAAoB,CAClC,aAA6B,EAC7B,SAAqB,EACrB,aAA6B;IAE7B,MAAM,OAAO,GAAG,IAAI,OAAO,CAAC,UAAU,CAAC,CAAC,WAAW,CAAC,iCAAiC,CAAC,CAAC;
|
|
1
|
+
{"version":3,"file":"index.js","sourceRoot":"","sources":["../../../src/commands/ai-check/index.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,OAAO,EAAE,MAAM,WAAW,CAAC;AAIpC,OAAO,EAAE,uBAAuB,EAAE,MAAM,UAAU,CAAC;AACnD,OAAO,EAAE,wBAAwB,EAAE,MAAM,WAAW,CAAC;AACrD,OAAO,EAAE,uBAAuB,EAAE,MAAM,UAAU,CAAC;AACnD,OAAO,EAAE,0BAA0B,EAAE,MAAM,aAAa,CAAC;AACzD,OAAO,EAAE,0BAA0B,EAAE,MAAM,aAAa,CAAC;AACzD,OAAO,EAAE,0BAA0B,EAAE,MAAM,aAAa,CAAC;AACzD,OAAO,EAAE,wBAAwB,EAAE,MAAM,WAAW,CAAC;AAErD,MAAM,UAAU,oBAAoB,CAClC,aAA6B,EAC7B,SAAqB,EACrB,aAA6B;IAE7B,MAAM,OAAO,GAAG,IAAI,OAAO,CAAC,UAAU,CAAC,CAAC,WAAW,CAAC,iCAAiC,CAAC,CAAC;IACtF,OAA2C,CAAC,OAAO,GAAG,IAAI,CAAC;IAE5D,OAAO,CAAC,UAAU,CAAC,uBAAuB,CAAC,aAAa,EAAE,SAAS,EAAE,aAAa,CAAC,EAAE;QACnF,SAAS,EAAE,IAAI;KAChB,CAAC,CAAC;IACH,OAAO,CAAC,UAAU,CAAC,wBAAwB,CAAC,aAAa,EAAE,SAAS,EAAE,aAAa,CAAC,CAAC,CAAC;IACtF,OAAO,CAAC,UAAU,CAAC,uBAAuB,CAAC,aAAa,EAAE,SAAS,EAAE,aAAa,CAAC,CAAC,CAAC;IACrF,OAAO,CAAC,UAAU,CAAC,0BAA0B,CAAC,aAAa,EAAE,SAAS,EAAE,aAAa,CAAC,CAAC,CAAC;IACxF,OAAO,CAAC,UAAU,CAAC,0BAA0B,CAAC,aAAa,EAAE,SAAS,EAAE,aAAa,CAAC,CAAC,CAAC;IACxF,OAAO,CAAC,UAAU,CAAC,0BAA0B,CAAC,aAAa,EAAE,SAAS,EAAE,aAAa,CAAC,CAAC,CAAC;IACxF,OAAO,CAAC,UAAU,CAAC,wBAAwB,CAAC,aAAa,EAAE,SAAS,EAAE,aAAa,CAAC,CAAC,CAAC;IAEtF,OAAO,OAAO,CAAC;AACjB,CAAC"}
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"alert-channel.d.ts","sourceRoot":"","sources":["../../src/commands/alert-channel.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,OAAO,EAAE,MAAM,WAAW,CAAC;
|
|
1
|
+
{"version":3,"file":"alert-channel.d.ts","sourceRoot":"","sources":["../../src/commands/alert-channel.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,OAAO,EAAE,MAAM,WAAW,CAAC;AAGpC,OAAO,EAAE,cAAc,EAAE,MAAM,mCAAmC,CAAC;AACnE,OAAO,EAAE,UAAU,EAAE,MAAM,uCAAuC,CAAC;AACnE,OAAO,EAAE,cAAc,EAAE,MAAM,mCAAmC,CAAC;AAoEnE,wBAAgB,yBAAyB,CACvC,aAAa,EAAE,cAAc,EAC7B,SAAS,EAAE,UAAU,EACrB,aAAa,EAAE,cAAc,GAC5B,OAAO,CAuJT"}
|
|
@@ -1,3 +1,4 @@
|
|
|
1
|
+
import chalk from 'chalk';
|
|
1
2
|
import inquirer from 'inquirer';
|
|
2
3
|
import { createResourceCommand } from './resource-command.factory.js';
|
|
3
4
|
const channelTypes = [
|
|
@@ -54,7 +55,7 @@ async function buildConfigFromOptions(type, options, existingConfig) {
|
|
|
54
55
|
return config;
|
|
55
56
|
}
|
|
56
57
|
export function createAlertChannelCommand(configService, apiClient, outputService) {
|
|
57
|
-
|
|
58
|
+
const cmd = createResourceCommand(configService, apiClient, outputService, {
|
|
58
59
|
resourceName: 'alert-channel',
|
|
59
60
|
pluralName: 'alert channels',
|
|
60
61
|
description: 'Manage alert channels',
|
|
@@ -159,5 +160,33 @@ export function createAlertChannelCommand(configService, apiClient, outputServic
|
|
|
159
160
|
};
|
|
160
161
|
},
|
|
161
162
|
});
|
|
163
|
+
cmd
|
|
164
|
+
.command('test <id>')
|
|
165
|
+
.description('Send a test notification through an alert channel')
|
|
166
|
+
.action(async (id) => {
|
|
167
|
+
const isJson = process.env.OBS_JSON_OUTPUT === 'true';
|
|
168
|
+
try {
|
|
169
|
+
const channelId = parseInt(id);
|
|
170
|
+
if (isNaN(channelId))
|
|
171
|
+
throw new Error('Invalid channel ID');
|
|
172
|
+
const result = await apiClient.testAlertChannel(channelId);
|
|
173
|
+
if (isJson) {
|
|
174
|
+
outputService.formatJsonOutput({ success: result.success, message: result.message });
|
|
175
|
+
return;
|
|
176
|
+
}
|
|
177
|
+
console.log(chalk.bold(`\n ${result.message}\n`));
|
|
178
|
+
}
|
|
179
|
+
catch (err) {
|
|
180
|
+
const msg = err.message || 'Failed to test alert channel';
|
|
181
|
+
if (isJson) {
|
|
182
|
+
outputService.formatJsonOutput({ status: 'ERROR', error: { message: msg } });
|
|
183
|
+
}
|
|
184
|
+
else {
|
|
185
|
+
console.error(chalk.red(`\n ${msg}\n`));
|
|
186
|
+
}
|
|
187
|
+
process.exit(1);
|
|
188
|
+
}
|
|
189
|
+
});
|
|
190
|
+
return cmd;
|
|
162
191
|
}
|
|
163
192
|
//# sourceMappingURL=alert-channel.js.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"alert-channel.js","sourceRoot":"","sources":["../../src/commands/alert-channel.ts"],"names":[],"mappings":"AACA,OAAO,QAAQ,MAAM,UAAU,CAAC;
|
|
1
|
+
{"version":3,"file":"alert-channel.js","sourceRoot":"","sources":["../../src/commands/alert-channel.ts"],"names":[],"mappings":"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"}
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"apply.d.ts","sourceRoot":"","sources":["../../src/commands/apply.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,OAAO,EAAE,MAAM,WAAW,CAAC;AACpC,OAAO,EAAE,cAAc,EAAE,MAAM,mCAAmC,CAAC;AACnE,OAAO,EAAE,UAAU,EAAE,MAAM,uCAAuC,CAAC;AACnE,OAAO,EAAE,cAAc,EAAE,MAAM,mCAAmC,CAAC;
|
|
1
|
+
{"version":3,"file":"apply.d.ts","sourceRoot":"","sources":["../../src/commands/apply.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,OAAO,EAAE,MAAM,WAAW,CAAC;AACpC,OAAO,EAAE,cAAc,EAAE,MAAM,mCAAmC,CAAC;AACnE,OAAO,EAAE,UAAU,EAAE,MAAM,uCAAuC,CAAC;AACnE,OAAO,EAAE,cAAc,EAAE,MAAM,mCAAmC,CAAC;AA2FnE,wBAAgB,kBAAkB,CAChC,aAAa,EAAE,cAAc,EAC7B,SAAS,EAAE,UAAU,EACrB,aAAa,EAAE,cAAc,GAC5B,OAAO,CA6aT"}
|
package/dist/commands/apply.js
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
import { Command } from 'commander';
|
|
2
2
|
import { readFileSync, existsSync } from 'fs';
|
|
3
3
|
import ora from 'ora';
|
|
4
|
-
import { deepEqual, normalizeResource } from '../utils/deep-equal.js';
|
|
4
|
+
import { deepEqual, normalizeResource, diffObjects } from '../utils/deep-equal.js';
|
|
5
5
|
const chunkArray = (arr, size) => {
|
|
6
6
|
const result = [];
|
|
7
7
|
for (let i = 0; i < arr.length; i += size) {
|
|
@@ -10,15 +10,58 @@ const chunkArray = (arr, size) => {
|
|
|
10
10
|
return result;
|
|
11
11
|
};
|
|
12
12
|
const delay = (ms) => new Promise((resolve) => setTimeout(resolve, ms));
|
|
13
|
+
function printDryRun(entries, summary) {
|
|
14
|
+
const chalk = {
|
|
15
|
+
green: (s) => `\x1b[32m${s}\x1b[0m`,
|
|
16
|
+
red: (s) => `\x1b[31m${s}\x1b[0m`,
|
|
17
|
+
yellow: (s) => `\x1b[33m${s}\x1b[0m`,
|
|
18
|
+
bold: (s) => `\x1b[1m${s}\x1b[0m`,
|
|
19
|
+
dim: (s) => `\x1b[2m${s}\x1b[0m`,
|
|
20
|
+
};
|
|
21
|
+
if (entries.length === 0) {
|
|
22
|
+
console.log(chalk.dim(' No changes. Everything is up to date.'));
|
|
23
|
+
return;
|
|
24
|
+
}
|
|
25
|
+
for (const entry of entries) {
|
|
26
|
+
if (entry.type === 'create') {
|
|
27
|
+
console.log(chalk.green(`+ ${entry.resource} "${entry.name}" (new)`));
|
|
28
|
+
}
|
|
29
|
+
else {
|
|
30
|
+
console.log(chalk.yellow(`~ ${entry.resource} "${entry.name}"`));
|
|
31
|
+
if (entry.diff) {
|
|
32
|
+
for (const [key, { from, to }] of Object.entries(entry.diff)) {
|
|
33
|
+
console.log(chalk.red(` - ${key}: ${JSON.stringify(from)}`));
|
|
34
|
+
console.log(chalk.green(` + ${key}: ${JSON.stringify(to)}`));
|
|
35
|
+
}
|
|
36
|
+
}
|
|
37
|
+
}
|
|
38
|
+
console.log('');
|
|
39
|
+
}
|
|
40
|
+
const totals = [
|
|
41
|
+
['Monitors', summary.monitors],
|
|
42
|
+
['API Checks', summary.apiChecks],
|
|
43
|
+
['Heartbeats', summary.heartbeats],
|
|
44
|
+
['AI Checks', summary.aiChecks],
|
|
45
|
+
];
|
|
46
|
+
for (const [label, s] of totals) {
|
|
47
|
+
if (s.created + s.updated + s.unchanged > 0) {
|
|
48
|
+
console.log(` ${label}: ${s.created} to create, ${s.updated} to update, ${s.unchanged} unchanged`);
|
|
49
|
+
}
|
|
50
|
+
}
|
|
51
|
+
console.log('');
|
|
52
|
+
console.log(chalk.dim(' Run without --dry-run to apply.'));
|
|
53
|
+
}
|
|
13
54
|
export function createApplyCommand(configService, apiClient, outputService) {
|
|
14
55
|
const apply = new Command('apply')
|
|
15
56
|
.description('Apply configuration from a JSON file (declarative workflow)')
|
|
16
57
|
.argument('[file]', 'Path to the JSON configuration file')
|
|
17
58
|
.option('-f, --file <path>', 'Path to the JSON configuration file')
|
|
18
59
|
.option('-j, --json', 'Output in JSON format')
|
|
60
|
+
.option('--dry-run', 'Preview changes without applying them')
|
|
19
61
|
.action(async (fileArg, options) => {
|
|
20
62
|
const isVerbose = process.env.OBS_VERBOSE === 'true';
|
|
21
63
|
const isJson = process.env.OBS_JSON_OUTPUT === 'true' || options.json === true;
|
|
64
|
+
const isDryRun = options.dryRun === true;
|
|
22
65
|
if (isJson) {
|
|
23
66
|
outputService.enableJsonMode();
|
|
24
67
|
}
|
|
@@ -74,6 +117,7 @@ export function createApplyCommand(configService, apiClient, outputService) {
|
|
|
74
117
|
aiChecks: { created: 0, updated: 0, unchanged: 0, errors: 0 },
|
|
75
118
|
};
|
|
76
119
|
const errors = [];
|
|
120
|
+
const dryRunEntries = [];
|
|
77
121
|
const delayMs = 1000; // 1 second between chunks to respect 100 req/min rate limit
|
|
78
122
|
// 1. Process URL Monitors
|
|
79
123
|
if (config.monitors && Array.isArray(config.monitors)) {
|
|
@@ -95,14 +139,14 @@ export function createApplyCommand(configService, apiClient, outputService) {
|
|
|
95
139
|
name: monitorConfig.name,
|
|
96
140
|
url: monitorConfig.url,
|
|
97
141
|
timeout_ms: monitorConfig.timeout_ms || 30000,
|
|
98
|
-
|
|
142
|
+
interval: monitorConfig.interval,
|
|
99
143
|
alert_on_failure: monitorConfig.alert_on_failure ?? true,
|
|
100
144
|
}, { timeout_ms: 30000, alert_on_failure: true });
|
|
101
145
|
const normalizedRemote = normalizeResource({
|
|
102
146
|
name: existing.name,
|
|
103
147
|
url: existing.url,
|
|
104
148
|
timeout_ms: existing.timeout_ms || 30000,
|
|
105
|
-
|
|
149
|
+
interval: existing.interval,
|
|
106
150
|
alert_on_failure: existing.alert_on_failure ?? true,
|
|
107
151
|
}, { timeout_ms: 30000, alert_on_failure: true });
|
|
108
152
|
// Skip update if no changes
|
|
@@ -111,26 +155,40 @@ export function createApplyCommand(configService, apiClient, outputService) {
|
|
|
111
155
|
summary.monitors.unchanged++;
|
|
112
156
|
return;
|
|
113
157
|
}
|
|
158
|
+
summary.monitors.updated++;
|
|
159
|
+
if (isDryRun) {
|
|
160
|
+
dryRunEntries.push({
|
|
161
|
+
type: 'update',
|
|
162
|
+
resource: 'monitor',
|
|
163
|
+
name: monitorConfig.name,
|
|
164
|
+
diff: diffObjects(normalizedRemote, normalizedLocal),
|
|
165
|
+
});
|
|
166
|
+
return;
|
|
167
|
+
}
|
|
114
168
|
logProgress(`Updating monitor: ${monitorConfig.name}`);
|
|
115
169
|
await apiClient.updateUrlMonitor(existing.id, {
|
|
116
170
|
name: monitorConfig.name || existing.name,
|
|
117
171
|
url: monitorConfig.url || existing.url,
|
|
118
172
|
timeout_ms: monitorConfig.timeout_ms || existing.timeout_ms || 30000,
|
|
119
|
-
|
|
120
|
-
monitorConfig.cron_expression ||
|
|
121
|
-
existing.cron_expression,
|
|
173
|
+
interval: monitorConfig.interval || existing.interval,
|
|
122
174
|
alert_on_failure: monitorConfig.alert_on_failure ?? existing.alert_on_failure ?? true,
|
|
123
175
|
});
|
|
124
|
-
summary.monitors.updated++;
|
|
125
176
|
}
|
|
126
177
|
else {
|
|
178
|
+
summary.monitors.created++;
|
|
179
|
+
if (isDryRun) {
|
|
180
|
+
dryRunEntries.push({
|
|
181
|
+
type: 'create',
|
|
182
|
+
resource: 'monitor',
|
|
183
|
+
name: monitorConfig.name,
|
|
184
|
+
});
|
|
185
|
+
return;
|
|
186
|
+
}
|
|
127
187
|
logProgress(`Creating monitor: ${monitorConfig.name}`);
|
|
128
188
|
await apiClient.createUrlMonitor({
|
|
129
189
|
...monitorConfig,
|
|
130
|
-
cron_expression: monitorConfig.interval || monitorConfig.cron_expression,
|
|
131
190
|
timeout_ms: monitorConfig.timeout_ms || 30000,
|
|
132
191
|
});
|
|
133
|
-
summary.monitors.created++;
|
|
134
192
|
}
|
|
135
193
|
}
|
|
136
194
|
catch (err) {
|
|
@@ -182,6 +240,16 @@ export function createApplyCommand(configService, apiClient, outputService) {
|
|
|
182
240
|
summary.apiChecks.unchanged++;
|
|
183
241
|
return;
|
|
184
242
|
}
|
|
243
|
+
summary.apiChecks.updated++;
|
|
244
|
+
if (isDryRun) {
|
|
245
|
+
dryRunEntries.push({
|
|
246
|
+
type: 'update',
|
|
247
|
+
resource: 'api-check',
|
|
248
|
+
name: checkConfig.name,
|
|
249
|
+
diff: diffObjects(normalizedRemote, normalizedLocal),
|
|
250
|
+
});
|
|
251
|
+
return;
|
|
252
|
+
}
|
|
185
253
|
logProgress(`Updating API check: ${checkConfig.name}`);
|
|
186
254
|
await apiClient.updateApiCheck(existing.id, {
|
|
187
255
|
name: checkConfig.name || existing.name,
|
|
@@ -190,16 +258,23 @@ export function createApplyCommand(configService, apiClient, outputService) {
|
|
|
190
258
|
timeout_ms: checkConfig.timeout_ms || existing.timeout_ms || 30000,
|
|
191
259
|
alert_on_failure: checkConfig.alert_on_failure ?? existing.alert_on_failure ?? true,
|
|
192
260
|
});
|
|
193
|
-
summary.apiChecks.updated++;
|
|
194
261
|
}
|
|
195
262
|
else {
|
|
263
|
+
summary.apiChecks.created++;
|
|
264
|
+
if (isDryRun) {
|
|
265
|
+
dryRunEntries.push({
|
|
266
|
+
type: 'create',
|
|
267
|
+
resource: 'api-check',
|
|
268
|
+
name: checkConfig.name,
|
|
269
|
+
});
|
|
270
|
+
return;
|
|
271
|
+
}
|
|
196
272
|
logProgress(`Creating API check: ${checkConfig.name}`);
|
|
197
273
|
await apiClient.createApiCheck({
|
|
198
274
|
...checkConfig,
|
|
199
275
|
timeout_ms: checkConfig.timeout_ms || 30000,
|
|
200
276
|
method: checkConfig.method?.toUpperCase() || 'GET',
|
|
201
277
|
});
|
|
202
|
-
summary.apiChecks.created++;
|
|
203
278
|
}
|
|
204
279
|
}
|
|
205
280
|
catch (err) {
|
|
@@ -247,6 +322,16 @@ export function createApplyCommand(configService, apiClient, outputService) {
|
|
|
247
322
|
summary.heartbeats.unchanged++;
|
|
248
323
|
return;
|
|
249
324
|
}
|
|
325
|
+
summary.heartbeats.updated++;
|
|
326
|
+
if (isDryRun) {
|
|
327
|
+
dryRunEntries.push({
|
|
328
|
+
type: 'update',
|
|
329
|
+
resource: 'heartbeat',
|
|
330
|
+
name: hbConfig.name,
|
|
331
|
+
diff: diffObjects(normalizedRemote, normalizedLocal),
|
|
332
|
+
});
|
|
333
|
+
return;
|
|
334
|
+
}
|
|
250
335
|
logProgress(`Updating heartbeat: ${hbConfig.name}`);
|
|
251
336
|
await apiClient.updateHeartbeat(existing.id, {
|
|
252
337
|
name: hbConfig.name || existing.name,
|
|
@@ -254,15 +339,22 @@ export function createApplyCommand(configService, apiClient, outputService) {
|
|
|
254
339
|
description: hbConfig.description || existing.description || 'Updated via CLI',
|
|
255
340
|
grace_period: hbConfig.grace_period || existing.grace_period || 60,
|
|
256
341
|
});
|
|
257
|
-
summary.heartbeats.updated++;
|
|
258
342
|
}
|
|
259
343
|
else {
|
|
344
|
+
summary.heartbeats.created++;
|
|
345
|
+
if (isDryRun) {
|
|
346
|
+
dryRunEntries.push({
|
|
347
|
+
type: 'create',
|
|
348
|
+
resource: 'heartbeat',
|
|
349
|
+
name: hbConfig.name,
|
|
350
|
+
});
|
|
351
|
+
return;
|
|
352
|
+
}
|
|
260
353
|
logProgress(`Creating heartbeat: ${hbConfig.name}`);
|
|
261
354
|
await apiClient.createHeartbeat({
|
|
262
355
|
name: hbConfig.name,
|
|
263
356
|
period: hbConfig.period,
|
|
264
357
|
});
|
|
265
|
-
summary.heartbeats.created++;
|
|
266
358
|
}
|
|
267
359
|
}
|
|
268
360
|
catch (err) {
|
|
@@ -278,76 +370,18 @@ export function createApplyCommand(configService, apiClient, outputService) {
|
|
|
278
370
|
await delay(delayMs);
|
|
279
371
|
}
|
|
280
372
|
}
|
|
281
|
-
// 4.
|
|
282
|
-
if (config.ai_checks && Array.isArray(config.ai_checks)) {
|
|
283
|
-
|
|
284
|
-
const existingAiChecks = await apiClient.getTests();
|
|
285
|
-
const existingByName = new Map(existingAiChecks.map((t) => [t.name, t]));
|
|
286
|
-
const chunks = chunkArray(config.ai_checks, 5);
|
|
287
|
-
for (let i = 0; i < chunks.length; i++) {
|
|
288
|
-
const chunk = chunks[i];
|
|
289
|
-
await Promise.all(chunk.map(async (aiConfig) => {
|
|
290
|
-
try {
|
|
291
|
-
if (!aiConfig.name || !aiConfig.url || !aiConfig.prompt) {
|
|
292
|
-
throw new Error("AI check must have 'name', 'url', and 'prompt'");
|
|
293
|
-
}
|
|
294
|
-
const existing = existingByName.get(aiConfig.name);
|
|
295
|
-
if (existing) {
|
|
296
|
-
// Normalize both objects for comparison
|
|
297
|
-
const normalizedLocal = normalizeResource({
|
|
298
|
-
name: aiConfig.name,
|
|
299
|
-
url: aiConfig.url,
|
|
300
|
-
prompt: aiConfig.prompt,
|
|
301
|
-
description: aiConfig.description || '',
|
|
302
|
-
}, { description: '' });
|
|
303
|
-
const normalizedRemote = normalizeResource({
|
|
304
|
-
name: existing.name,
|
|
305
|
-
url: existing.url,
|
|
306
|
-
prompt: existing.prompt,
|
|
307
|
-
description: existing.description || '',
|
|
308
|
-
}, { description: '' });
|
|
309
|
-
// Skip update if no changes
|
|
310
|
-
if (deepEqual(normalizedLocal, normalizedRemote)) {
|
|
311
|
-
logProgress(`AI check unchanged: ${aiConfig.name}`);
|
|
312
|
-
summary.aiChecks.unchanged++;
|
|
313
|
-
return;
|
|
314
|
-
}
|
|
315
|
-
logProgress(`Updating AI check: ${aiConfig.name}`);
|
|
316
|
-
await apiClient.updateTest(existing.id, {
|
|
317
|
-
name: aiConfig.name || existing.name,
|
|
318
|
-
url: aiConfig.url || existing.url,
|
|
319
|
-
prompt: aiConfig.prompt || existing.prompt,
|
|
320
|
-
description: aiConfig.description || existing.description || '',
|
|
321
|
-
});
|
|
322
|
-
summary.aiChecks.updated++;
|
|
323
|
-
}
|
|
324
|
-
else {
|
|
325
|
-
logProgress(`Creating AI check: ${aiConfig.name}`);
|
|
326
|
-
await apiClient.createTest({
|
|
327
|
-
name: aiConfig.name,
|
|
328
|
-
url: aiConfig.url,
|
|
329
|
-
prompt: aiConfig.prompt,
|
|
330
|
-
description: aiConfig.description || 'Created via CLI',
|
|
331
|
-
});
|
|
332
|
-
summary.aiChecks.created++;
|
|
333
|
-
}
|
|
334
|
-
}
|
|
335
|
-
catch (err) {
|
|
336
|
-
const errorObj = err;
|
|
337
|
-
const details = errorObj.response?.data?.error ||
|
|
338
|
-
errorObj.response?.data?.message ||
|
|
339
|
-
errorObj.message;
|
|
340
|
-
errors.push(`AI Check '${aiConfig.name || 'unknown'}': ${details}`);
|
|
341
|
-
summary.aiChecks.errors++;
|
|
342
|
-
}
|
|
343
|
-
}));
|
|
344
|
-
if (i < chunks.length - 1)
|
|
345
|
-
await delay(delayMs);
|
|
346
|
-
}
|
|
373
|
+
// 4. Browser checks are currently disabled
|
|
374
|
+
if (config.ai_checks && Array.isArray(config.ai_checks) && config.ai_checks.length > 0) {
|
|
375
|
+
outputService.warning('Browser checks are currently disabled. Skipping ai_checks entries.');
|
|
347
376
|
}
|
|
348
377
|
if (spinner) {
|
|
349
378
|
spinner.stop();
|
|
350
379
|
}
|
|
380
|
+
if (isDryRun) {
|
|
381
|
+
console.log('');
|
|
382
|
+
printDryRun(dryRunEntries, summary);
|
|
383
|
+
return;
|
|
384
|
+
}
|
|
351
385
|
if (isJson) {
|
|
352
386
|
outputService.formatJsonOutput({
|
|
353
387
|
summary,
|
|
@@ -368,7 +402,7 @@ export function createApplyCommand(configService, apiClient, outputService) {
|
|
|
368
402
|
console.log('');
|
|
369
403
|
outputService.error('Some resources failed to apply:');
|
|
370
404
|
errors.forEach((e) => console.log(` - ${e}`));
|
|
371
|
-
process.exit(1);
|
|
405
|
+
process.exit(1);
|
|
372
406
|
}
|
|
373
407
|
}
|
|
374
408
|
}
|