@statuser/cli 0.0.0-stage → 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 (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,157 @@
1
+ import { isForbiddenHost } from './servers-config/forbidden-host.js';
2
+ import { HOST_PATTERN } from './servers-config/host-pattern.js';
3
+ import { textLength } from './text-length.js';
4
+ // Mirrors the backend: SSL and domain checks run for http, keyword and dns;
5
+ // the incident confirmation delay is ignored by dns, heartbeat and scenario;
6
+ // the latency alert exists for http, keyword, tcp and llm.
7
+ const SSL_DOMAIN = ['http', 'keyword', 'dns'];
8
+ const NO_CONFIRM_DELAY = ['dns', 'heartbeat', 'scenario'];
9
+ const LATENCY = ['http', 'keyword', 'tcp', 'llm'];
10
+ const sameSet = (a, b) => a.length === b.length && [...a].sort().join() === [...b].sort().join();
11
+ /**
12
+ * Pure: the PATCH for one server. Only fields that actually change are
13
+ * sent; a field that does not apply to the protocol is reported instead of
14
+ * being sent — the backend would silently reset it rather than reject it.
15
+ */
16
+ export function planServerPatch(server, change) {
17
+ const body = {};
18
+ const fields = [];
19
+ const notApplicable = [];
20
+ const set = (field, key, value) => {
21
+ body[key] = value;
22
+ fields.push(field);
23
+ };
24
+ if (change.name !== undefined && change.name.trim() !== server.name) {
25
+ set('name', 'name', change.name.trim());
26
+ }
27
+ if (change.host !== undefined) {
28
+ // The address of a heartbeat or a scenario is made by the system.
29
+ if (server.protocol === 'heartbeat' || server.protocol === 'scenario') {
30
+ notApplicable.push('host');
31
+ }
32
+ else if (change.host.trim() !== server.host) {
33
+ set('host', 'host', change.host.trim());
34
+ }
35
+ }
36
+ if (change.description !== undefined) {
37
+ const description = change.description.trim() || null;
38
+ if (description !== (server.description ?? null)) {
39
+ set('description', 'description', description);
40
+ }
41
+ }
42
+ if (change.interval !== undefined &&
43
+ change.interval !== server.check_interval) {
44
+ set('interval', 'check_interval', change.interval);
45
+ }
46
+ if (change.timeout !== undefined) {
47
+ if (server.protocol === 'heartbeat' || server.protocol === 'dns') {
48
+ notApplicable.push('timeout');
49
+ }
50
+ else if (change.timeout !== server.request_timeout) {
51
+ set('timeout', 'request_timeout', change.timeout);
52
+ }
53
+ }
54
+ if (change.regions !== undefined) {
55
+ if (server.protocol === 'heartbeat' || server.protocol === 'dns') {
56
+ notApplicable.push('regions');
57
+ }
58
+ else if (server.protocol === 'scenario' && change.regions.length !== 1) {
59
+ notApplicable.push('regions');
60
+ }
61
+ else if (!sameSet(change.regions, server.locations ?? [])) {
62
+ set('regions', 'locations', change.regions);
63
+ }
64
+ }
65
+ if (change.confirmDelay !== undefined) {
66
+ if (NO_CONFIRM_DELAY.includes(server.protocol)) {
67
+ notApplicable.push('confirm-delay');
68
+ }
69
+ else if (change.confirmDelay !== server.incident_confirm_delay) {
70
+ set('confirm-delay', 'incident_confirm_delay', change.confirmDelay);
71
+ }
72
+ }
73
+ for (const [flag, key, current] of [
74
+ ['ssl', 'is_ssl_check', server.is_ssl_check],
75
+ ['domain', 'is_domain_check', server.is_domain_check],
76
+ ['blocklist', 'is_blocklist_check', server.is_blocklist_check],
77
+ ]) {
78
+ const wanted = change[flag];
79
+ if (wanted === undefined)
80
+ continue;
81
+ if (!SSL_DOMAIN.includes(server.protocol))
82
+ notApplicable.push(flag);
83
+ else if (wanted !== current)
84
+ set(flag, key, wanted);
85
+ }
86
+ if (change.latency !== undefined) {
87
+ if (!LATENCY.includes(server.protocol))
88
+ notApplicable.push('latency');
89
+ else if (change.latency === false) {
90
+ if (server.is_latency_alert_enabled) {
91
+ set('latency', 'is_latency_alert_enabled', false);
92
+ }
93
+ }
94
+ else if (!server.is_latency_alert_enabled ||
95
+ server.latency_trigger_ms !== change.latency) {
96
+ body.is_latency_alert_enabled = true;
97
+ set('latency', 'latency_trigger_ms', change.latency);
98
+ }
99
+ }
100
+ return { body, fields, notApplicable };
101
+ }
102
+ const SCENARIO_TIMEOUTS = [15, 30, 45, 60, 120];
103
+ const MAX_INTERVAL = {
104
+ heartbeat: 31_536_000,
105
+ scenario: 86_400,
106
+ };
107
+ /**
108
+ * Whether the server accepts the planned values, as the backend checks
109
+ * them for its protocol. All targets are checked before the first PATCH:
110
+ * a timeout valid for HTTP but not for a scenario would otherwise stop the
111
+ * batch half-way.
112
+ */
113
+ export function bulkTargetProblem(server, plan) {
114
+ // The API's limits for the text fields (`CreateServerDto`).
115
+ if ('name' in plan.body) {
116
+ const name = plan.body.name;
117
+ if (!name)
118
+ return 'name: empty';
119
+ if (textLength(name) > 150)
120
+ return 'name ≤ 150';
121
+ }
122
+ if ('host' in plan.body) {
123
+ const host = plan.body.host;
124
+ if (!HOST_PATTERN.test(host) || textLength(host) > 300)
125
+ return 'host';
126
+ if (isForbiddenHost(host))
127
+ return 'host: internal address';
128
+ }
129
+ if (typeof plan.body.description === 'string' &&
130
+ textLength(plan.body.description) > 500) {
131
+ return 'description ≤ 500';
132
+ }
133
+ const interval = plan.body.check_interval ?? server.check_interval;
134
+ const timeout = plan.body.request_timeout ?? server.request_timeout;
135
+ if ('check_interval' in plan.body) {
136
+ const max = MAX_INTERVAL[server.protocol] ?? 3600;
137
+ if (interval < 60 || interval > max)
138
+ return `interval 60–${max}`;
139
+ }
140
+ if ('request_timeout' in plan.body) {
141
+ if (server.protocol === 'scenario') {
142
+ if (!SCENARIO_TIMEOUTS.includes(timeout)) {
143
+ return `timeout ${SCENARIO_TIMEOUTS.join('/')}`;
144
+ }
145
+ }
146
+ else if (timeout < 1 || timeout > 60) {
147
+ return 'timeout 1–60';
148
+ }
149
+ }
150
+ if (server.protocol === 'scenario' &&
151
+ ('check_interval' in plan.body || 'request_timeout' in plan.body) &&
152
+ interval < timeout) {
153
+ return 'interval ≥ timeout';
154
+ }
155
+ return null;
156
+ }
157
+ //# sourceMappingURL=servers-update.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"servers-update.js","sourceRoot":"","sources":["../src/servers-update.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,15 @@
1
+ import { CliError, ExitCode } from './errors.js';
2
+ import { t } from './i18n.js';
3
+ /** Ids of the servers shown on a status page, for `--all-servers`. */
4
+ export async function pageServerIds(client, pageId) {
5
+ const page = await client.call({
6
+ method: 'GET',
7
+ path: `/v1/status-pages/${pageId}`,
8
+ });
9
+ const ids = page.servers.map((server) => server.server_id);
10
+ if (!ids.length) {
11
+ throw new CliError(t.maintenancePageEmpty(pageId), ExitCode.Usage);
12
+ }
13
+ return ids;
14
+ }
15
+ //# sourceMappingURL=status-page.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"status-page.js","sourceRoot":"","sources":["../src/status-page.ts"],"names":[],"mappings":"AACA,OAAO,EAAE,QAAQ,EAAE,QAAQ,EAAE,MAAM,aAAa,CAAC;AAEjD,OAAO,EAAE,CAAC,EAAE,MAAM,WAAW,CAAC;AAI9B,sEAAsE;AACtE,MAAM,CAAC,KAAK,UAAU,aAAa,CACjC,MAAsB,EACtB,MAAc;IAEd,MAAM,IAAI,GAAG,MAAM,MAAM,CAAC,IAAI,CAAa;QACzC,MAAM,EAAE,KAAK;QACb,IAAI,EAAE,oBAAoB,MAAM,EAAE;KACnC,CAAC,CAAC;IACH,MAAM,GAAG,GAAG,IAAI,CAAC,OAAO,CAAC,GAAG,CAAC,CAAC,MAAM,EAAE,EAAE,CAAC,MAAM,CAAC,SAAS,CAAC,CAAC;IAC3D,IAAI,CAAC,GAAG,CAAC,MAAM,EAAE,CAAC;QAChB,MAAM,IAAI,QAAQ,CAAC,CAAC,CAAC,oBAAoB,CAAC,MAAM,CAAC,EAAE,QAAQ,CAAC,KAAK,CAAC,CAAC;IACrE,CAAC;IACD,OAAO,GAAG,CAAC;AACb,CAAC"}
@@ -0,0 +1,8 @@
1
+ /**
2
+ * Length as the API's `@MaxLength` counts it (class-validator `isLength`):
3
+ * a surrogate pair is one character, so an emoji counts once, not twice.
4
+ */
5
+ export function textLength(value) {
6
+ return (value.length - (value.match(/[\uD800-\uDBFF][\uDC00-\uDFFF]/g) ?? []).length);
7
+ }
8
+ //# sourceMappingURL=text-length.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"text-length.js","sourceRoot":"","sources":["../src/text-length.ts"],"names":[],"mappings":"AAAA;;;GAGG;AACH,MAAM,UAAU,UAAU,CAAC,KAAa;IACtC,OAAO,CACL,KAAK,CAAC,MAAM,GAAG,CAAC,KAAK,CAAC,KAAK,CAAC,iCAAiC,CAAC,IAAI,EAAE,CAAC,CAAC,MAAM,CAC7E,CAAC;AACJ,CAAC"}
@@ -0,0 +1,37 @@
1
+ import { ExitCode, NotSentError, StatuserApiError, } from './errors.js';
2
+ import { t } from './i18n.js';
3
+ /**
4
+ * A request that never left and a 4xx refusal are known outcomes. After a
5
+ * dropped connection, a timeout or a 5xx the write may have been stored
6
+ * before the answer failed, so the outcome is unknown.
7
+ */
8
+ export function describeWriteFailure(name, error) {
9
+ if (error instanceof NotSentError) {
10
+ return {
11
+ name,
12
+ message: t.deployStopped(name, error.message),
13
+ exitCode: ExitCode.Failure,
14
+ outcome_unknown: false,
15
+ };
16
+ }
17
+ if (error instanceof StatuserApiError && error.status < 500) {
18
+ return {
19
+ name,
20
+ message: t.deployStopped(name, error.format()),
21
+ exitCode: error.exitCode,
22
+ outcome_unknown: false,
23
+ };
24
+ }
25
+ const detail = error instanceof StatuserApiError
26
+ ? error.format()
27
+ : error instanceof Error
28
+ ? error.message
29
+ : String(error);
30
+ return {
31
+ name,
32
+ message: t.applyUnknownOutcome(name, detail),
33
+ exitCode: ExitCode.Failure,
34
+ outcome_unknown: true,
35
+ };
36
+ }
37
+ //# sourceMappingURL=write-failure.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"write-failure.js","sourceRoot":"","sources":["../src/write-failure.ts"],"names":[],"mappings":"AAAA,OAAO,EACL,QAAQ,EACR,YAAY,EACZ,gBAAgB,GAEjB,MAAM,aAAa,CAAC;AACrB,OAAO,EAAE,CAAC,EAAE,MAAM,WAAW,CAAC;AAU9B;;;;GAIG;AACH,MAAM,UAAU,oBAAoB,CAClC,IAAY,EACZ,KAAc;IAEd,IAAI,KAAK,YAAY,YAAY,EAAE,CAAC;QAClC,OAAO;YACL,IAAI;YACJ,OAAO,EAAE,CAAC,CAAC,aAAa,CAAC,IAAI,EAAE,KAAK,CAAC,OAAO,CAAC;YAC7C,QAAQ,EAAE,QAAQ,CAAC,OAAO;YAC1B,eAAe,EAAE,KAAK;SACvB,CAAC;IACJ,CAAC;IACD,IAAI,KAAK,YAAY,gBAAgB,IAAI,KAAK,CAAC,MAAM,GAAG,GAAG,EAAE,CAAC;QAC5D,OAAO;YACL,IAAI;YACJ,OAAO,EAAE,CAAC,CAAC,aAAa,CAAC,IAAI,EAAE,KAAK,CAAC,MAAM,EAAE,CAAC;YAC9C,QAAQ,EAAE,KAAK,CAAC,QAAQ;YACxB,eAAe,EAAE,KAAK;SACvB,CAAC;IACJ,CAAC;IACD,MAAM,MAAM,GACV,KAAK,YAAY,gBAAgB;QAC/B,CAAC,CAAC,KAAK,CAAC,MAAM,EAAE;QAChB,CAAC,CAAC,KAAK,YAAY,KAAK;YACtB,CAAC,CAAC,KAAK,CAAC,OAAO;YACf,CAAC,CAAC,MAAM,CAAC,KAAK,CAAC,CAAC;IACtB,OAAO;QACL,IAAI;QACJ,OAAO,EAAE,CAAC,CAAC,mBAAmB,CAAC,IAAI,EAAE,MAAM,CAAC;QAC5C,QAAQ,EAAE,QAAQ,CAAC,OAAO;QAC1B,eAAe,EAAE,IAAI;KACtB,CAAC;AACJ,CAAC"}
package/package.json CHANGED
@@ -1,6 +1,72 @@
1
1
  {
2
2
  "name": "@statuser/cli",
3
- "version": "0.0.0-stage",
4
- "stub": true,
5
- "description": "Temporary package placeholder for staged publishing"
6
- }
3
+ "version": "0.1.0",
4
+ "description": "Statuser.cloud command line: scenario checks as code, maintenance windows in CI, heartbeat for cron jobs",
5
+ "keywords": [
6
+ "statuser",
7
+ "monitoring",
8
+ "uptime",
9
+ "status-page",
10
+ "playwright",
11
+ "heartbeat",
12
+ "cli"
13
+ ],
14
+ "homepage": "https://statuser.cloud",
15
+ "repository": {
16
+ "type": "git",
17
+ "url": "git+https://github.com/statuser-cloud/cli.git"
18
+ },
19
+ "bugs": {
20
+ "url": "https://github.com/statuser-cloud/cli/issues"
21
+ },
22
+ "license": "MIT",
23
+ "type": "module",
24
+ "bin": {
25
+ "statuser": "dist/index.js"
26
+ },
27
+ "files": [
28
+ "dist",
29
+ "README.md",
30
+ "LICENSE"
31
+ ],
32
+ "engines": {
33
+ "node": ">=20.19.0"
34
+ },
35
+ "scripts": {
36
+ "build": "tsc -p tsconfig.json && chmod +x dist/index.js",
37
+ "dev": "tsx src/index.ts",
38
+ "start": "node dist/index.js",
39
+ "fetch-spec": "tsx scripts/fetch-spec.ts",
40
+ "typecheck": "tsc -p tsconfig.json --noEmit",
41
+ "lint": "eslint \"src/**/*.ts\" \"scripts/**/*.ts\" \"test/**/*.ts\"",
42
+ "lint:fix": "eslint --fix \"src/**/*.ts\" \"scripts/**/*.ts\" \"test/**/*.ts\"",
43
+ "format": "prettier --write \"src/**/*.ts\" \"scripts/**/*.ts\" \"test/**/*.ts\"",
44
+ "format:check": "prettier --check \"src/**/*.ts\" \"scripts/**/*.ts\" \"test/**/*.ts\"",
45
+ "test": "vitest run",
46
+ "prepublishOnly": "npm run build"
47
+ },
48
+ "dependencies": {
49
+ "commander": "^14.0.0"
50
+ },
51
+ "devDependencies": {
52
+ "@eslint/js": "^9.39.4",
53
+ "@types/node": "^22.10.5",
54
+ "@typescript-eslint/eslint-plugin": "^8.72.1",
55
+ "@typescript-eslint/parser": "^8.72.1",
56
+ "esbuild": "^0.28.2",
57
+ "eslint": "^9.17.0",
58
+ "eslint-config-prettier": "^10.1.8",
59
+ "globals": "^17.6.0",
60
+ "openapi-typescript": "^7.5.2",
61
+ "postject": "^1.0.0-alpha.6",
62
+ "prettier": "^3.4.2",
63
+ "tsx": "^4.19.2",
64
+ "typescript": "^5.7.2",
65
+ "vitest": "^4.1.12"
66
+ },
67
+ "overrides": {
68
+ "@typescript-eslint/typescript-estree": {
69
+ "minimatch": "^11.0.1"
70
+ }
71
+ }
72
+ }