@statuser/cli 0.0.0-stage → 0.1.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.
Files changed (77) hide show
  1. package/LICENSE +21 -0
  2. package/README.md +448 -2
  3. package/dist/client.js +163 -0
  4. package/dist/client.js.map +1 -0
  5. package/dist/commander-i18n.js +52 -0
  6. package/dist/commander-i18n.js.map +1 -0
  7. package/dist/commands/api.js +104 -0
  8. package/dist/commands/api.js.map +1 -0
  9. package/dist/commands/auth.js +104 -0
  10. package/dist/commands/auth.js.map +1 -0
  11. package/dist/commands/catalog.js +72 -0
  12. package/dist/commands/catalog.js.map +1 -0
  13. package/dist/commands/config.js +302 -0
  14. package/dist/commands/config.js.map +1 -0
  15. package/dist/commands/heartbeat.js +199 -0
  16. package/dist/commands/heartbeat.js.map +1 -0
  17. package/dist/commands/incidents.js +265 -0
  18. package/dist/commands/incidents.js.map +1 -0
  19. package/dist/commands/maintenance.js +211 -0
  20. package/dist/commands/maintenance.js.map +1 -0
  21. package/dist/commands/reports.js +170 -0
  22. package/dist/commands/reports.js.map +1 -0
  23. package/dist/commands/scenarios.js +361 -0
  24. package/dist/commands/scenarios.js.map +1 -0
  25. package/dist/commands/servers-add.js +152 -0
  26. package/dist/commands/servers-add.js.map +1 -0
  27. package/dist/commands/servers-checks.js +56 -0
  28. package/dist/commands/servers-checks.js.map +1 -0
  29. package/dist/commands/servers.js +424 -0
  30. package/dist/commands/servers.js.map +1 -0
  31. package/dist/config.js +107 -0
  32. package/dist/config.js.map +1 -0
  33. package/dist/confirm.js +34 -0
  34. package/dist/confirm.js.map +1 -0
  35. package/dist/context.js +27 -0
  36. package/dist/context.js.map +1 -0
  37. package/dist/duration.js +20 -0
  38. package/dist/duration.js.map +1 -0
  39. package/dist/errors.js +73 -0
  40. package/dist/errors.js.map +1 -0
  41. package/dist/files.js +36 -0
  42. package/dist/files.js.map +1 -0
  43. package/dist/generated/openapi.js +6 -0
  44. package/dist/generated/openapi.js.map +1 -0
  45. package/dist/i18n.js +757 -0
  46. package/dist/i18n.js.map +1 -0
  47. package/dist/index.js +58 -0
  48. package/dist/index.js.map +1 -0
  49. package/dist/json-error.js +10 -0
  50. package/dist/json-error.js.map +1 -0
  51. package/dist/output.js +43 -0
  52. package/dist/output.js.map +1 -0
  53. package/dist/scenarios/config.js +228 -0
  54. package/dist/scenarios/config.js.map +1 -0
  55. package/dist/scenarios/plan.js +159 -0
  56. package/dist/scenarios/plan.js.map +1 -0
  57. package/dist/servers-config/export.js +72 -0
  58. package/dist/servers-config/export.js.map +1 -0
  59. package/dist/servers-config/fields.js +172 -0
  60. package/dist/servers-config/fields.js.map +1 -0
  61. package/dist/servers-config/forbidden-host.js +75 -0
  62. package/dist/servers-config/forbidden-host.js.map +1 -0
  63. package/dist/servers-config/host-pattern.js +6 -0
  64. package/dist/servers-config/host-pattern.js.map +1 -0
  65. package/dist/servers-config/parse.js +260 -0
  66. package/dist/servers-config/parse.js.map +1 -0
  67. package/dist/servers-config/plan.js +492 -0
  68. package/dist/servers-config/plan.js.map +1 -0
  69. package/dist/servers-update.js +157 -0
  70. package/dist/servers-update.js.map +1 -0
  71. package/dist/status-page.js +15 -0
  72. package/dist/status-page.js.map +1 -0
  73. package/dist/text-length.js +8 -0
  74. package/dist/text-length.js.map +1 -0
  75. package/dist/write-failure.js +37 -0
  76. package/dist/write-failure.js.map +1 -0
  77. package/package.json +70 -4
@@ -0,0 +1,211 @@
1
+ import { authedClient, globalOptions } from '../context.js';
2
+ import { parseDuration } from '../duration.js';
3
+ import { CliError, ExitCode, StatuserApiError } from '../errors.js';
4
+ import { t } from '../i18n.js';
5
+ import { confirmDeletion } from '../confirm.js';
6
+ import { formatTime, printJson, printLine, printTable } from '../output.js';
7
+ import { pageServerIds } from '../status-page.js';
8
+ import { parseId } from './servers.js';
9
+ import { textLength } from '../text-length.js';
10
+ const DEFAULT_WINDOW = '30m';
11
+ // `MaxLength` of an update message in the API.
12
+ const MESSAGE_MAX_LENGTH = 65_535;
13
+ /**
14
+ * Planned maintenance is shown on the status page and announced to
15
+ * subscribers; it does NOT mute alerts. Pausing checks around a deploy is a
16
+ * separate step (`servers pause` / `servers resume --from`).
17
+ */
18
+ export function registerMaintenanceCommands(program) {
19
+ const maintenance = program
20
+ .command('maintenance')
21
+ .description(t.cmdMaintenance);
22
+ maintenance
23
+ .command('start')
24
+ .description(t.cmdMaintenanceStart)
25
+ .requiredOption('--page <id>', t.optPage, parseId)
26
+ .requiredOption('--title <title>', t.optTitle)
27
+ .requiredOption('--description <text>', t.optDescription)
28
+ .option('--servers <ids>', t.optServers)
29
+ .option('--all-servers', t.optAllServers)
30
+ .option('--for <duration>', t.optFor, DEFAULT_WINDOW)
31
+ .action(async (opts, command) => {
32
+ const windowMs = parseDuration(opts.for);
33
+ const servers = pickServers(opts);
34
+ const { client } = await authedClient(command);
35
+ const now = new Date();
36
+ const created = await createMaintenance(client, opts, servers, now, windowMs);
37
+ if (globalOptions(command).json)
38
+ printJson(created);
39
+ else
40
+ printLine(t.maintenanceStarted(created.id, created.ended_at));
41
+ });
42
+ maintenance
43
+ .command('schedule')
44
+ .description(t.cmdMaintenanceSchedule)
45
+ .requiredOption('--page <id>', t.optPage, parseId)
46
+ .requiredOption('--at <datetime>', t.optAt)
47
+ .requiredOption('--title <title>', t.optTitle)
48
+ .requiredOption('--description <text>', t.optDescription)
49
+ .option('--servers <ids>', t.optServers)
50
+ .option('--all-servers', t.optAllServers)
51
+ .option('--for <duration>', t.optFor, DEFAULT_WINDOW)
52
+ .action(async (opts, command) => {
53
+ const windowMs = parseDuration(opts.for);
54
+ // A start in the past would announce what already happened; work
55
+ // going on now is opened by `start`.
56
+ const start = Date.parse(opts.at);
57
+ if (Number.isNaN(start) || start <= Date.now()) {
58
+ throw new CliError(t.maintenanceAtInvalid(opts.at), ExitCode.Usage);
59
+ }
60
+ const servers = pickServers(opts);
61
+ const { client } = await authedClient(command);
62
+ const created = await createMaintenance(client, opts, servers, new Date(start), windowMs);
63
+ if (globalOptions(command).json)
64
+ printJson(created);
65
+ else {
66
+ printLine(t.maintenanceScheduled(created.id, formatTime(created.started_at), formatTime(created.ended_at)));
67
+ }
68
+ });
69
+ maintenance
70
+ .command('list')
71
+ .description(t.cmdMaintenanceList)
72
+ .requiredOption('--page <id>', t.optPage, parseId)
73
+ .action(async (opts, command) => {
74
+ const { client } = await authedClient(command);
75
+ const list = await client.call({
76
+ method: 'GET',
77
+ path: `/v1/status-pages/${opts.page}/planned-maintenances`,
78
+ });
79
+ if (globalOptions(command).json) {
80
+ printJson(list);
81
+ return;
82
+ }
83
+ if (!list.length) {
84
+ printLine(t.maintenanceEmpty);
85
+ return;
86
+ }
87
+ printTable([t.colId, t.colTitle, t.colStarted, t.colEnd], list.map((item) => [
88
+ item.id,
89
+ item.title,
90
+ formatTime(item.started_at),
91
+ formatTime(item.ended_at),
92
+ ]));
93
+ });
94
+ maintenance
95
+ .command('delete')
96
+ .description(t.cmdMaintenanceDelete)
97
+ .argument('<maintenanceId>', 'id', parseId)
98
+ .requiredOption('--page <id>', t.optPage, parseId)
99
+ .option('--yes', t.optYes)
100
+ .action(async (id, opts, command) => {
101
+ const { client } = await authedClient(command);
102
+ const base = `/v1/status-pages/${opts.page}/planned-maintenances`;
103
+ const current = (await client.call({ method: 'GET', path: base })).find((item) => item.id === id);
104
+ if (!current) {
105
+ throw new StatuserApiError(404, t.notFound(id), 'not_found');
106
+ }
107
+ await confirmDeletion(t.confirmDeleteMaintenance(id, current.title), opts.yes);
108
+ await client.call({ method: 'DELETE', path: `${base}/${id}` });
109
+ if (globalOptions(command).json)
110
+ printJson({ deleted: true, id });
111
+ else
112
+ printLine(t.deletedOne(id));
113
+ });
114
+ maintenance
115
+ .command('end')
116
+ .description(t.cmdMaintenanceEnd)
117
+ .argument('<maintenanceId>', 'id', parseId)
118
+ .requiredOption('--page <id>', t.optPage, parseId)
119
+ .option('--message <text>', t.optMessage)
120
+ .action(async (id, opts, command) => {
121
+ // Checked before the window is closed: a message the API rejects after
122
+ // the PATCH would leave the window closed without its announcement.
123
+ if (opts.message !== undefined) {
124
+ const text = opts.message.trim();
125
+ if (!text || textLength(text) > MESSAGE_MAX_LENGTH) {
126
+ throw new CliError(t.messageInvalid(MESSAGE_MAX_LENGTH), ExitCode.Usage);
127
+ }
128
+ }
129
+ const { client } = await authedClient(command);
130
+ const base = `/v1/status-pages/${opts.page}/planned-maintenances`;
131
+ const list = await client.call({
132
+ method: 'GET',
133
+ path: base,
134
+ });
135
+ const current = list.find((item) => item.id === id);
136
+ if (!current) {
137
+ throw new StatuserApiError(404, t.notFound(id), 'status_page_planned_maintenance_not_found');
138
+ }
139
+ // A repeated `end` (retried CI job) must not move an already passed
140
+ // end date forward to the new "now".
141
+ const now = new Date();
142
+ const alreadyEnded = new Date(current.ended_at) <= now;
143
+ let result = current;
144
+ if (!alreadyEnded) {
145
+ result = await client.call({
146
+ method: 'PATCH',
147
+ path: `${base}/${id}`,
148
+ body: { ended_at: now.toISOString() },
149
+ });
150
+ }
151
+ // Changing the date alone adds nothing to the timeline and notifies
152
+ // nobody; a message does both. The same message already in the
153
+ // timeline means a retried step: subscribers are not told twice.
154
+ const message = opts.message?.trim();
155
+ const alreadyPosted = !!message &&
156
+ current.updates.some((update) => update.message.trim() === message);
157
+ if (message && !alreadyPosted) {
158
+ try {
159
+ result = await client.call({
160
+ method: 'POST',
161
+ path: `${base}/${id}/updates`,
162
+ body: { message },
163
+ });
164
+ }
165
+ catch (error) {
166
+ throw new CliError(t.maintenanceMessageFailed(error instanceof StatuserApiError
167
+ ? error.format()
168
+ : String(error)), error instanceof StatuserApiError
169
+ ? error.exitCode
170
+ : ExitCode.Failure);
171
+ }
172
+ }
173
+ if (globalOptions(command).json) {
174
+ printJson({ ...result, already_ended: alreadyEnded });
175
+ }
176
+ else {
177
+ printLine(alreadyEnded ? t.maintenanceAlreadyEnded(id) : t.maintenanceEnded(id));
178
+ }
179
+ });
180
+ }
181
+ /** The servers named on the command line, or `all` for the whole page. */
182
+ function pickServers(opts) {
183
+ if (opts.servers && opts.allServers) {
184
+ throw new CliError(t.maintenanceBothServers, ExitCode.Usage);
185
+ }
186
+ if (opts.allServers)
187
+ return 'all';
188
+ const ids = (opts.servers ?? '')
189
+ .split(',')
190
+ .map((raw) => raw.trim())
191
+ .filter(Boolean)
192
+ .map(parseId);
193
+ if (!ids.length)
194
+ throw new CliError(t.maintenanceNoServers, ExitCode.Usage);
195
+ return ids;
196
+ }
197
+ async function createMaintenance(client, opts, servers, start, windowMs) {
198
+ const serverIds = servers === 'all' ? await pageServerIds(client, opts.page) : servers;
199
+ return client.call({
200
+ method: 'POST',
201
+ path: `/v1/status-pages/${opts.page}/planned-maintenances`,
202
+ body: {
203
+ title: opts.title,
204
+ description: opts.description,
205
+ started_at: start.toISOString(),
206
+ ended_at: new Date(start.getTime() + windowMs).toISOString(),
207
+ servers: serverIds.map((id) => ({ id })),
208
+ },
209
+ });
210
+ }
211
+ //# sourceMappingURL=maintenance.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"maintenance.js","sourceRoot":"","sources":["../../src/commands/maintenance.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,170 @@
1
+ import { authedClient, globalOptions } from '../context.js';
2
+ import { CliError, ExitCode, StatuserApiError } from '../errors.js';
3
+ import { t } from '../i18n.js';
4
+ import { formatTime, printJson, printLine, printTable } from '../output.js';
5
+ import { pageServerIds } from '../status-page.js';
6
+ import { splitList } from './incidents.js';
7
+ import { parseId } from './servers.js';
8
+ // `not_affected` drops a server from the report; it is not a way to state
9
+ // an impact, so the CLI does not offer it.
10
+ const IMPACTS = ['downtime', 'degraded'];
11
+ const UPDATE_STATUSES = ['downtime', 'degraded', 'resolved'];
12
+ /**
13
+ * Public incident reports on a status page. Every message goes to the page
14
+ * timeline and to its subscribers in the page language, so the CLI never
15
+ * writes a message of its own: `--message` is required everywhere.
16
+ */
17
+ export function registerReportsCommands(program) {
18
+ const reports = program.command('reports').description(t.cmdReports);
19
+ reports
20
+ .command('list')
21
+ .description(t.cmdReportsList)
22
+ .requiredOption('--page <id>', t.optPage, parseId)
23
+ .action(async (opts, command) => {
24
+ const { client } = await authedClient(command);
25
+ const list = await listReports(client, opts.page);
26
+ if (globalOptions(command).json) {
27
+ printJson(list);
28
+ return;
29
+ }
30
+ if (!list.length) {
31
+ printLine(t.reportsEmpty);
32
+ return;
33
+ }
34
+ printTable([t.colId, t.colTitle, t.colStatus, t.colStarted], list.map((report) => [
35
+ report.id,
36
+ report.title,
37
+ t.serverImpact(report.current_status),
38
+ formatTime(report.started_at),
39
+ ]));
40
+ });
41
+ reports
42
+ .command('create')
43
+ .description(t.cmdReportsCreate)
44
+ .requiredOption('--page <id>', t.optPage, parseId)
45
+ .requiredOption('--title <title>', t.optTitle)
46
+ .requiredOption('--message <text>', t.optReportMessage)
47
+ .option('--servers <ids>', t.optServers)
48
+ .option('--all-servers', t.optAllServers)
49
+ .option('--status <status>', t.optImpact, 'downtime')
50
+ .option('--incident <ids>', t.optLinkedIncidents)
51
+ .action(async (opts, command) => {
52
+ const status = parseStatus(opts.status, IMPACTS);
53
+ if (opts.servers && opts.allServers) {
54
+ throw new CliError(t.maintenanceBothServers, ExitCode.Usage);
55
+ }
56
+ let serverIds = splitList(opts.servers).map(parseId);
57
+ if (!serverIds.length && !opts.allServers) {
58
+ throw new CliError(t.maintenanceNoServers, ExitCode.Usage);
59
+ }
60
+ const { client } = await authedClient(command);
61
+ if (opts.allServers)
62
+ serverIds = await pageServerIds(client, opts.page);
63
+ const report = await client.call({
64
+ method: 'POST',
65
+ path: `/v1/status-pages/${opts.page}/incident-reports`,
66
+ body: {
67
+ title: opts.title,
68
+ initial_message: opts.message,
69
+ started_at: new Date().toISOString(),
70
+ servers: serverIds.map((id) => ({ server_id: id, status })),
71
+ incident_ids: splitList(opts.incident).map(parseId),
72
+ },
73
+ });
74
+ if (globalOptions(command).json)
75
+ printJson(report);
76
+ else
77
+ printLine(t.reportCreated(report.id));
78
+ });
79
+ reports
80
+ .command('update')
81
+ .description(t.cmdReportsUpdate)
82
+ .argument('<reportId>', 'id', parseId)
83
+ .requiredOption('--page <id>', t.optPage, parseId)
84
+ .requiredOption('--message <text>', t.optReportMessage)
85
+ .option('--status <status>', t.optUpdateStatus)
86
+ .action(async (id, opts, command) => {
87
+ const status = opts.status
88
+ ? parseStatus(opts.status, UPDATE_STATUSES)
89
+ : undefined;
90
+ const { client } = await authedClient(command);
91
+ const report = await findReport(client, opts.page, id);
92
+ const updated = await postUpdate(client, opts.page, report, {
93
+ message: opts.message,
94
+ status,
95
+ });
96
+ if (globalOptions(command).json)
97
+ printJson(updated);
98
+ else
99
+ printLine(t.reportUpdated(id));
100
+ });
101
+ reports
102
+ .command('resolve')
103
+ .description(t.cmdReportsResolve)
104
+ .argument('<reportId>', 'id', parseId)
105
+ .requiredOption('--page <id>', t.optPage, parseId)
106
+ .requiredOption('--message <text>', t.optReportMessage)
107
+ .action(async (id, opts, command) => {
108
+ const { client } = await authedClient(command);
109
+ const report = await findReport(client, opts.page, id);
110
+ // A retried CI step must not send subscribers a second "resolved".
111
+ if (report.current_status === 'resolved') {
112
+ if (globalOptions(command).json) {
113
+ printJson({ ...report, already_resolved: true });
114
+ }
115
+ else {
116
+ printLine(t.reportAlreadyResolved(id));
117
+ }
118
+ return;
119
+ }
120
+ const updated = await postUpdate(client, opts.page, report, {
121
+ message: opts.message,
122
+ status: 'resolved',
123
+ });
124
+ if (globalOptions(command).json)
125
+ printJson(updated);
126
+ else
127
+ printLine(t.reportResolved(id));
128
+ });
129
+ }
130
+ async function listReports(client, pageId) {
131
+ return client.call({
132
+ method: 'GET',
133
+ path: `/v1/status-pages/${pageId}/incident-reports`,
134
+ });
135
+ }
136
+ async function findReport(client, pageId, id) {
137
+ const report = (await listReports(client, pageId)).find((r) => r.id === id);
138
+ if (!report) {
139
+ throw new StatuserApiError(404, t.notFound(id), 'status_page_incident_report_not_found');
140
+ }
141
+ return report;
142
+ }
143
+ /**
144
+ * An update carries the full list of affected servers with their statuses,
145
+ * not a patch: servers left out would drop from the report. The current
146
+ * list is the report's own (`servers[].id` there is the server id).
147
+ */
148
+ async function postUpdate(client, pageId, report, change) {
149
+ const servers = report.servers
150
+ .filter((server) => server.status !== 'not_affected')
151
+ .map((server) => ({
152
+ server_id: server.id,
153
+ status: change.status ?? server.status,
154
+ }));
155
+ if (!servers.length) {
156
+ throw new CliError(t.reportNoServers(report.id), ExitCode.Usage);
157
+ }
158
+ return client.call({
159
+ method: 'POST',
160
+ path: `/v1/status-pages/${pageId}/incident-reports/${report.id}/updates`,
161
+ body: { message: change.message, servers },
162
+ });
163
+ }
164
+ function parseStatus(raw, allowed) {
165
+ if (!allowed.includes(raw)) {
166
+ throw new CliError(t.statusChoice(allowed.join(', ')), ExitCode.Usage);
167
+ }
168
+ return raw;
169
+ }
170
+ //# sourceMappingURL=reports.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"reports.js","sourceRoot":"","sources":["../../src/commands/reports.ts"],"names":[],"mappings":"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"}