@uptimerobot/cli 0.1.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.
Files changed (108) hide show
  1. package/LICENSE +201 -0
  2. package/README.md +179 -0
  3. package/bin/run.js +43 -0
  4. package/dist/api/client.js +95 -0
  5. package/dist/api/errors.js +26 -0
  6. package/dist/commands/alert-contacts/create.js +10 -0
  7. package/dist/commands/alert-contacts/delete.js +10 -0
  8. package/dist/commands/alert-contacts/get.js +10 -0
  9. package/dist/commands/alert-contacts/list.js +10 -0
  10. package/dist/commands/alert-contacts/update.js +10 -0
  11. package/dist/commands/auth/login.js +51 -0
  12. package/dist/commands/auth/logout.js +33 -0
  13. package/dist/commands/auth/status.js +38 -0
  14. package/dist/commands/auth/whoami.js +6 -0
  15. package/dist/commands/incidents/activity-log.js +10 -0
  16. package/dist/commands/incidents/alerts.js +10 -0
  17. package/dist/commands/incidents/comments/create.js +10 -0
  18. package/dist/commands/incidents/comments/delete.js +10 -0
  19. package/dist/commands/incidents/comments/list.js +10 -0
  20. package/dist/commands/incidents/comments/update.js +10 -0
  21. package/dist/commands/incidents/get.js +10 -0
  22. package/dist/commands/incidents/list.js +10 -0
  23. package/dist/commands/integrations/create.js +10 -0
  24. package/dist/commands/integrations/delete.js +10 -0
  25. package/dist/commands/integrations/get.js +10 -0
  26. package/dist/commands/integrations/list.js +10 -0
  27. package/dist/commands/integrations/update.js +10 -0
  28. package/dist/commands/maintenance-windows/create.js +10 -0
  29. package/dist/commands/maintenance-windows/delete.js +10 -0
  30. package/dist/commands/maintenance-windows/get.js +10 -0
  31. package/dist/commands/maintenance-windows/list.js +10 -0
  32. package/dist/commands/maintenance-windows/update.js +10 -0
  33. package/dist/commands/monitor-groups/create.js +10 -0
  34. package/dist/commands/monitor-groups/delete.js +10 -0
  35. package/dist/commands/monitor-groups/get.js +10 -0
  36. package/dist/commands/monitor-groups/list.js +10 -0
  37. package/dist/commands/monitor-groups/update.js +10 -0
  38. package/dist/commands/monitors/bulk/pause.js +10 -0
  39. package/dist/commands/monitors/bulk/start.js +10 -0
  40. package/dist/commands/monitors/bulk/update.js +10 -0
  41. package/dist/commands/monitors/create/api.js +10 -0
  42. package/dist/commands/monitors/create/dns.js +10 -0
  43. package/dist/commands/monitors/create/heartbeat.js +10 -0
  44. package/dist/commands/monitors/create/http.js +10 -0
  45. package/dist/commands/monitors/create/keyword.js +10 -0
  46. package/dist/commands/monitors/create/ping.js +10 -0
  47. package/dist/commands/monitors/create/port.js +10 -0
  48. package/dist/commands/monitors/create/udp.js +10 -0
  49. package/dist/commands/monitors/create/visual-comparison.js +10 -0
  50. package/dist/commands/monitors/delete.js +10 -0
  51. package/dist/commands/monitors/get.js +10 -0
  52. package/dist/commands/monitors/list.js +10 -0
  53. package/dist/commands/monitors/pause.js +10 -0
  54. package/dist/commands/monitors/reset.js +10 -0
  55. package/dist/commands/monitors/schema.js +57 -0
  56. package/dist/commands/monitors/start.js +10 -0
  57. package/dist/commands/monitors/stats/response-time/all.js +10 -0
  58. package/dist/commands/monitors/stats/response-time.js +10 -0
  59. package/dist/commands/monitors/stats/uptime.js +10 -0
  60. package/dist/commands/monitors/update.js +10 -0
  61. package/dist/commands/monitors/uptime-stats.js +10 -0
  62. package/dist/commands/status-pages/announcements/create.js +10 -0
  63. package/dist/commands/status-pages/announcements/get.js +10 -0
  64. package/dist/commands/status-pages/announcements/list.js +10 -0
  65. package/dist/commands/status-pages/announcements/pin.js +10 -0
  66. package/dist/commands/status-pages/announcements/unpin.js +10 -0
  67. package/dist/commands/status-pages/announcements/update.js +10 -0
  68. package/dist/commands/status-pages/create.js +10 -0
  69. package/dist/commands/status-pages/delete.js +10 -0
  70. package/dist/commands/status-pages/get.js +10 -0
  71. package/dist/commands/status-pages/list.js +10 -0
  72. package/dist/commands/status-pages/update.js +10 -0
  73. package/dist/commands/tags/delete.js +10 -0
  74. package/dist/commands/tags/list.js +10 -0
  75. package/dist/commands/user/alert-contacts.js +10 -0
  76. package/dist/commands/user/all-alert-contacts.js +10 -0
  77. package/dist/commands/user/get.js +5 -0
  78. package/dist/commands/user/me.js +10 -0
  79. package/dist/generated/operations.js +7631 -0
  80. package/dist/lib/auth.js +60 -0
  81. package/dist/lib/base-command.js +21 -0
  82. package/dist/lib/cli-errors.js +80 -0
  83. package/dist/lib/command-suggestions.js +44 -0
  84. package/dist/lib/credential-store.js +152 -0
  85. package/dist/lib/flag-name.js +11 -0
  86. package/dist/lib/invocation.js +74 -0
  87. package/dist/lib/objects.js +34 -0
  88. package/dist/lib/operation-command.js +486 -0
  89. package/dist/lib/operation-parser-error.js +28 -0
  90. package/dist/lib/request-curation.js +76 -0
  91. package/dist/lib/request-example.js +82 -0
  92. package/dist/lib/request-preview.js +25 -0
  93. package/dist/lib/request.js +301 -0
  94. package/dist/lib/sensitive-fields.js +19 -0
  95. package/dist/lib/types.js +1 -0
  96. package/dist/output/columns.js +221 -0
  97. package/dist/output/display-width.js +34 -0
  98. package/dist/output/normalize-result.js +28 -0
  99. package/dist/output/pagination-notice.js +27 -0
  100. package/dist/output/renderer.js +145 -0
  101. package/dist/output/request-progress.js +15 -0
  102. package/dist/output/resolve-format.js +32 -0
  103. package/dist/output/style.js +57 -0
  104. package/dist/runtime/parse-input.js +35 -0
  105. package/dist/runtime/types.js +1 -0
  106. package/dist/runtime/validate-input.js +63 -0
  107. package/openapi/openapi.yaml +9034 -0
  108. package/package.json +135 -0
@@ -0,0 +1,145 @@
1
+ import { isRecord } from '../lib/objects.js';
2
+ import { displayWidth, truncateToWidth } from './display-width.js';
3
+ import { paint, statusGlyph } from './style.js';
4
+ const DEFAULT_TABLE_COLUMN_WIDTH = 48;
5
+ const FORMATTERS = {
6
+ json: formatJson,
7
+ jsonl: formatJsonLines,
8
+ plain: formatPlain,
9
+ table: formatTable,
10
+ };
11
+ export function formatOutput(format, payload, options = {}) {
12
+ return FORMATTERS[format](payload, options);
13
+ }
14
+ function formatJson(payload) {
15
+ return JSON.stringify(payload);
16
+ }
17
+ function formatJsonLines(payload) {
18
+ const collection = extractCollection(payload);
19
+ if (collection) {
20
+ if (collection.length === 0)
21
+ return undefined;
22
+ return collection.map((item) => JSON.stringify(item)).join('\n');
23
+ }
24
+ return JSON.stringify(payload);
25
+ }
26
+ function formatPlain(payload, options) {
27
+ const collection = extractCollection(payload);
28
+ if (!collection)
29
+ return formatValue(payload, '');
30
+ if (collection.length === 0)
31
+ return undefined;
32
+ const columns = resolveColumns(collection, options);
33
+ return collection
34
+ .map((item) => isRecord(item)
35
+ ? columns.map((column) => renderCell(item, column, '')).join('\t')
36
+ : formatValue(item, ''))
37
+ .join('\n');
38
+ }
39
+ function formatTable(payload, options) {
40
+ const data = extractCollection(payload);
41
+ if (!data)
42
+ return JSON.stringify(payload, null, 2);
43
+ if (data.length === 0)
44
+ return 'No results.';
45
+ const columns = resolveColumns(data, options);
46
+ const rows = data.map((item) => {
47
+ const row = isRecord(item) ? item : { value: item };
48
+ return columns.map((column) => {
49
+ const cell = toCell(column.key, singleLine(renderCell(row, column, '—')));
50
+ return { ...cell, text: truncate(cell.text, column.maxWidth) };
51
+ });
52
+ });
53
+ const headings = columns.map((column) => ({ style: 'bold', text: truncate(column.header, column.maxWidth) }));
54
+ const widths = columns.map((_, index) => Math.max(displayWidth(headings[index].text), ...rows.map((row) => displayWidth(row[index].text))));
55
+ return [formatRow(headings, widths), ...rows.map((row) => formatRow(row, widths))].join('\n');
56
+ }
57
+ function resolveColumns(rows, options) {
58
+ if (options.columns !== undefined && options.columns.length > 0) {
59
+ return options.columns.map((spec) => ({
60
+ format: spec.format,
61
+ header: (spec.header ?? defaultHeader(lastSegment(spec.key))).toUpperCase(),
62
+ key: spec.key,
63
+ maxWidth: spec.maxWidth ?? DEFAULT_TABLE_COLUMN_WIDTH,
64
+ }));
65
+ }
66
+ const keys = options.allColumns === true ? allKeys(rows) : firstColumns(rows);
67
+ return keys.map((key) => ({
68
+ header: defaultHeader(key),
69
+ key,
70
+ maxWidth: DEFAULT_TABLE_COLUMN_WIDTH,
71
+ }));
72
+ }
73
+ function defaultHeader(key) {
74
+ return key.replace(/([a-z])([A-Z])/g, '$1 $2').toUpperCase();
75
+ }
76
+ function lastSegment(key) {
77
+ const segments = key.split('.');
78
+ return segments[segments.length - 1] ?? key;
79
+ }
80
+ function renderCell(row, column, nullValue) {
81
+ const value = resolvePath(row, column.key);
82
+ return formatValue(column.format ? column.format(value, row) : value, nullValue);
83
+ }
84
+ function resolvePath(row, path) {
85
+ if (!path.includes('.'))
86
+ return row[path];
87
+ return path
88
+ .split('.')
89
+ .reduce((value, segment) => (isRecord(value) ? value[segment] : undefined), row);
90
+ }
91
+ function toCell(column, text) {
92
+ if (!/status$/i.test(column))
93
+ return { text };
94
+ const status = statusGlyph(text);
95
+ if (!status)
96
+ return { text };
97
+ return { style: status.style, text: `${status.glyph} ${text}` };
98
+ }
99
+ function extractCollection(payload) {
100
+ if (Array.isArray(payload))
101
+ return payload;
102
+ if (!isRecord(payload))
103
+ return undefined;
104
+ if (Array.isArray(payload.items))
105
+ return payload.items;
106
+ if (Array.isArray(payload.data))
107
+ return payload.data;
108
+ return undefined;
109
+ }
110
+ function firstColumns(rows) {
111
+ const first = rows[0];
112
+ if (!isRecord(first))
113
+ return ['value'];
114
+ return Object.keys(first).slice(0, 8);
115
+ }
116
+ function allKeys(rows) {
117
+ const keys = new Set();
118
+ for (const row of rows) {
119
+ if (!isRecord(row))
120
+ continue;
121
+ for (const key of Object.keys(row))
122
+ keys.add(key);
123
+ }
124
+ return keys.size > 0 ? [...keys] : ['value'];
125
+ }
126
+ function formatRow(cells, widths) {
127
+ return cells
128
+ .map((cell, index) => {
129
+ const padding = ' '.repeat(Math.max(0, widths[index] - displayWidth(cell.text)));
130
+ return (cell.style === undefined ? cell.text : paint(cell.style, cell.text)) + padding;
131
+ })
132
+ .join(' ')
133
+ .trimEnd();
134
+ }
135
+ function truncate(value, maxWidth) {
136
+ return truncateToWidth(value, maxWidth);
137
+ }
138
+ function singleLine(value) {
139
+ return value.replace(/[\t\r\n]+/g, ' ');
140
+ }
141
+ function formatValue(value, nullValue) {
142
+ if (typeof value === 'object' && value !== null)
143
+ return JSON.stringify(value);
144
+ return value === undefined || value === null ? nullValue : String(value);
145
+ }
@@ -0,0 +1,15 @@
1
+ import { ux } from '@oclif/core';
2
+ export async function withRequestProgress(enabled, request) {
3
+ if (!enabled)
4
+ return request();
5
+ ux.action.start('Loading');
6
+ try {
7
+ const result = await request();
8
+ ux.action.stop(result.response.ok ? 'done' : 'failed');
9
+ return result;
10
+ }
11
+ catch (error) {
12
+ ux.action.stop('failed');
13
+ throw error;
14
+ }
15
+ }
@@ -0,0 +1,32 @@
1
+ const OUTPUT_FORMATS = new Set(['json', 'jsonl', 'plain', 'table']);
2
+ export function resolveFormat(flags, mode, env = process.env) {
3
+ if (flags.raw === true)
4
+ return 'json';
5
+ if (typeof flags.format === 'string')
6
+ return flags.format;
7
+ if (flags.json === true)
8
+ return 'json';
9
+ const environmentFormat = outputFormatFromEnvironment(env);
10
+ if (environmentFormat)
11
+ return environmentFormat;
12
+ if (mode === 'agent' || process.stdout.isTTY !== true)
13
+ return 'json';
14
+ return 'table';
15
+ }
16
+ export function outputFormatFromEnvironment(env) {
17
+ const value = env.UPTIMEROBOT_OUTPUT?.toLowerCase();
18
+ return value && OUTPUT_FORMATS.has(value) ? value : undefined;
19
+ }
20
+ export function requestedFormatFromArgv(argv) {
21
+ let format;
22
+ for (let index = 0; index < argv.length; index += 1) {
23
+ const value = argv[index];
24
+ if (value?.startsWith('--format='))
25
+ format = value.slice('--format='.length).toLowerCase();
26
+ else if (value === '--format' && argv[index + 1] !== undefined) {
27
+ format = argv[index + 1]?.toLowerCase();
28
+ index += 1;
29
+ }
30
+ }
31
+ return format;
32
+ }
@@ -0,0 +1,57 @@
1
+ const ANSI_RESET = '\u001B[0m';
2
+ const ANSI_CODES = {
3
+ bold: '\u001B[1m',
4
+ dim: '\u001B[2m',
5
+ green: '\u001B[32m',
6
+ red: '\u001B[31m',
7
+ yellow: '\u001B[33m',
8
+ };
9
+ const OK = { glyph: '●', style: 'green' };
10
+ const BAD = { glyph: '✗', style: 'red' };
11
+ const WARN = { glyph: '▲', style: 'yellow' };
12
+ const MUTED = { glyph: '◌', style: 'dim' };
13
+ // Exact-match on the casing the API emits; unknown values must pass through unstyled.
14
+ const STATUS_GLYPHS = {
15
+ Active: OK,
16
+ Archived: MUTED,
17
+ CantSend: MUTED,
18
+ DOWN: BAD,
19
+ ENABLED: OK,
20
+ InQueue: MUTED,
21
+ LOOKS_DOWN: BAD,
22
+ NOT_DELIVERED: BAD,
23
+ NotActivated: WARN,
24
+ Offline: MUTED,
25
+ Ongoing: BAD,
26
+ PAUSED: MUTED,
27
+ Paused: MUTED,
28
+ Pending: WARN,
29
+ Published: OK,
30
+ Resolved: OK,
31
+ STARTED: MUTED,
32
+ SUCCESS: OK,
33
+ Sent: OK,
34
+ ToMigrate: WARN,
35
+ UP: OK,
36
+ active: OK,
37
+ error: BAD,
38
+ paused: MUTED,
39
+ success: OK,
40
+ };
41
+ export function colorEnabled() {
42
+ const noColor = process.env.NO_COLOR;
43
+ if (noColor !== undefined && noColor !== '')
44
+ return false;
45
+ const forceColor = process.env.FORCE_COLOR;
46
+ if (forceColor !== undefined && forceColor !== '')
47
+ return forceColor !== '0';
48
+ return process.stdout.isTTY === true;
49
+ }
50
+ export function paint(style, text) {
51
+ if (!colorEnabled())
52
+ return text;
53
+ return `${ANSI_CODES[style]}${text}${ANSI_RESET}`;
54
+ }
55
+ export function statusGlyph(value) {
56
+ return STATUS_GLYPHS[value];
57
+ }
@@ -0,0 +1,35 @@
1
+ import { flagName } from '../lib/flag-name.js';
2
+ export function parseInput(operation, args, flags) {
3
+ const input = { path: {}, query: {} };
4
+ for (const parameter of operation.parameters) {
5
+ const rawValue = parameter.in === 'path' ? args[parameter.name] : flags[flagName(parameter.name)];
6
+ if (rawValue === undefined)
7
+ continue;
8
+ const value = coerceValue(parameter, rawValue);
9
+ if (parameter.in === 'path')
10
+ input.path[parameter.name] = value;
11
+ if (parameter.in === 'query')
12
+ input.query[parameter.name] = value;
13
+ }
14
+ return input;
15
+ }
16
+ function coerceValue(parameter, value) {
17
+ if (parameter.type === 'array') {
18
+ const values = Array.isArray(value) ? value : [value];
19
+ return values.map(String);
20
+ }
21
+ if (parameter.type === 'number' || parameter.type === 'integer') {
22
+ // Keep the raw spelling: validation checks the numeric format, and the
23
+ // wire value stays exact for 64-bit IDs and cursors that lose precision
24
+ // as JavaScript numbers.
25
+ return String(value);
26
+ }
27
+ if (parameter.type === 'boolean') {
28
+ if (value === true || value === 'true')
29
+ return true;
30
+ if (value === false || value === 'false')
31
+ return false;
32
+ return String(value);
33
+ }
34
+ return String(value);
35
+ }
@@ -0,0 +1 @@
1
+ export {};
@@ -0,0 +1,63 @@
1
+ export class InputValidationError extends Error {
2
+ path;
3
+ expected;
4
+ constructor(path, expected, message) {
5
+ super(message);
6
+ this.path = path;
7
+ this.expected = expected;
8
+ }
9
+ }
10
+ export function validateInput(operation, input) {
11
+ for (const parameter of operation.parameters) {
12
+ const value = (parameter.in === 'path' ? input.path : input.query)[parameter.name];
13
+ if (value === undefined) {
14
+ if (parameter.required) {
15
+ throw new InputValidationError(parameter.name, 'a value', `${parameter.name} is required.`);
16
+ }
17
+ continue;
18
+ }
19
+ const expected = firstIssue(parameter, value);
20
+ if (expected) {
21
+ throw new InputValidationError(parameter.name, expected, `Invalid ${parameter.name}: ${expected}`);
22
+ }
23
+ }
24
+ return input;
25
+ }
26
+ function firstIssue(parameter, value) {
27
+ switch (parameter.type) {
28
+ case 'array':
29
+ if (!Array.isArray(value) || value.some((item) => typeof item !== 'string')) {
30
+ return 'Expected a list of values';
31
+ }
32
+ break;
33
+ case 'boolean':
34
+ if (typeof value !== 'boolean')
35
+ return 'Expected a boolean';
36
+ break;
37
+ case 'integer':
38
+ // Numeric formats are validated on the raw string so that 64-bit IDs
39
+ // and cursors keep their exact spelling on the wire.
40
+ if (typeof value !== 'string' || !/^-?\d+$/.test(value))
41
+ return 'Expected an integer';
42
+ break;
43
+ case 'number':
44
+ if (typeof value !== 'string' || !/^-?(?:\d+\.?\d*|\.\d+)$/.test(value)) {
45
+ return 'Expected a number';
46
+ }
47
+ break;
48
+ default:
49
+ if (typeof value !== 'string')
50
+ return 'Expected a string';
51
+ }
52
+ const numeric = parameter.type === 'integer' || parameter.type === 'number';
53
+ if (numeric && parameter.minimum !== undefined && Number(value) < parameter.minimum) {
54
+ return `Expected at least ${parameter.minimum}`;
55
+ }
56
+ if (numeric && parameter.maximum !== undefined && Number(value) > parameter.maximum) {
57
+ return `Expected at most ${parameter.maximum}`;
58
+ }
59
+ if (parameter.enum && !parameter.enum.includes(value)) {
60
+ return `Expected one of: ${parameter.enum.map(String).join(', ')}`;
61
+ }
62
+ return undefined;
63
+ }