@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.
- package/LICENSE +21 -0
- package/README.md +448 -2
- package/dist/client.js +163 -0
- package/dist/client.js.map +1 -0
- package/dist/commander-i18n.js +52 -0
- package/dist/commander-i18n.js.map +1 -0
- package/dist/commands/api.js +104 -0
- package/dist/commands/api.js.map +1 -0
- package/dist/commands/auth.js +104 -0
- package/dist/commands/auth.js.map +1 -0
- package/dist/commands/catalog.js +72 -0
- package/dist/commands/catalog.js.map +1 -0
- package/dist/commands/config.js +302 -0
- package/dist/commands/config.js.map +1 -0
- package/dist/commands/heartbeat.js +199 -0
- package/dist/commands/heartbeat.js.map +1 -0
- package/dist/commands/incidents.js +265 -0
- package/dist/commands/incidents.js.map +1 -0
- package/dist/commands/maintenance.js +211 -0
- package/dist/commands/maintenance.js.map +1 -0
- package/dist/commands/reports.js +170 -0
- package/dist/commands/reports.js.map +1 -0
- package/dist/commands/scenarios.js +361 -0
- package/dist/commands/scenarios.js.map +1 -0
- package/dist/commands/servers-add.js +152 -0
- package/dist/commands/servers-add.js.map +1 -0
- package/dist/commands/servers-checks.js +56 -0
- package/dist/commands/servers-checks.js.map +1 -0
- package/dist/commands/servers.js +424 -0
- package/dist/commands/servers.js.map +1 -0
- package/dist/config.js +107 -0
- package/dist/config.js.map +1 -0
- package/dist/confirm.js +34 -0
- package/dist/confirm.js.map +1 -0
- package/dist/context.js +27 -0
- package/dist/context.js.map +1 -0
- package/dist/duration.js +20 -0
- package/dist/duration.js.map +1 -0
- package/dist/errors.js +73 -0
- package/dist/errors.js.map +1 -0
- package/dist/files.js +36 -0
- package/dist/files.js.map +1 -0
- package/dist/generated/openapi.js +6 -0
- package/dist/generated/openapi.js.map +1 -0
- package/dist/i18n.js +757 -0
- package/dist/i18n.js.map +1 -0
- package/dist/index.js +58 -0
- package/dist/index.js.map +1 -0
- package/dist/json-error.js +10 -0
- package/dist/json-error.js.map +1 -0
- package/dist/output.js +43 -0
- package/dist/output.js.map +1 -0
- package/dist/scenarios/config.js +228 -0
- package/dist/scenarios/config.js.map +1 -0
- package/dist/scenarios/plan.js +159 -0
- package/dist/scenarios/plan.js.map +1 -0
- package/dist/servers-config/export.js +72 -0
- package/dist/servers-config/export.js.map +1 -0
- package/dist/servers-config/fields.js +172 -0
- package/dist/servers-config/fields.js.map +1 -0
- package/dist/servers-config/forbidden-host.js +75 -0
- package/dist/servers-config/forbidden-host.js.map +1 -0
- package/dist/servers-config/host-pattern.js +6 -0
- package/dist/servers-config/host-pattern.js.map +1 -0
- package/dist/servers-config/parse.js +260 -0
- package/dist/servers-config/parse.js.map +1 -0
- package/dist/servers-config/plan.js +492 -0
- package/dist/servers-config/plan.js.map +1 -0
- package/dist/servers-update.js +157 -0
- package/dist/servers-update.js.map +1 -0
- package/dist/status-page.js +15 -0
- package/dist/status-page.js.map +1 -0
- package/dist/text-length.js +8 -0
- package/dist/text-length.js.map +1 -0
- package/dist/write-failure.js +37 -0
- package/dist/write-failure.js.map +1 -0
- package/package.json +70 -4
|
@@ -0,0 +1,492 @@
|
|
|
1
|
+
import { CliError, ExitCode } from '../errors.js';
|
|
2
|
+
import { t } from '../i18n.js';
|
|
3
|
+
import { duplicateKey, isDuplicateOf, sameValue } from './fields.js';
|
|
4
|
+
import { isForbiddenHost } from './forbidden-host.js';
|
|
5
|
+
const fail = (message) => {
|
|
6
|
+
throw new CliError(message, ExitCode.Usage);
|
|
7
|
+
};
|
|
8
|
+
/**
|
|
9
|
+
* Pure: compares the `servers` section with the account. Everything the
|
|
10
|
+
* API would reject mid-way — an ambiguous match, a protocol change, a
|
|
11
|
+
* duplicate monitor, a plan limit, a create without its password — is
|
|
12
|
+
* raised here, before any write.
|
|
13
|
+
*
|
|
14
|
+
* `account` must hold ALL servers of the account: duplicates and the
|
|
15
|
+
* servers limit are account-wide.
|
|
16
|
+
*/
|
|
17
|
+
export function buildServersPlan(desired, projectId, account, features, plannedScenarioCreates = 0,
|
|
18
|
+
// `servers add` always creates: a server of the same name is not a match
|
|
19
|
+
// there, since only heartbeats are told apart by name.
|
|
20
|
+
options = {}) {
|
|
21
|
+
const inProject = account.filter((s) => s.project_id === projectId && s.protocol !== 'scenario');
|
|
22
|
+
const byId = new Map(account.map((s) => [s.id, s]));
|
|
23
|
+
const claimed = new Set();
|
|
24
|
+
const steps = [];
|
|
25
|
+
checkNames(desired);
|
|
26
|
+
for (const entry of desired) {
|
|
27
|
+
const server = options.createOnly
|
|
28
|
+
? undefined
|
|
29
|
+
: matchServer(entry, byId, inProject, projectId);
|
|
30
|
+
if (server) {
|
|
31
|
+
if (claimed.has(server.id))
|
|
32
|
+
fail(t.applyClaimedTwice(entry.at, server.id));
|
|
33
|
+
claimed.add(server.id);
|
|
34
|
+
// Changing the protocol wipes what belongs to the old one: HTTP
|
|
35
|
+
// credentials, the LLM key, the heartbeat token.
|
|
36
|
+
if (server.protocol !== entry.protocol) {
|
|
37
|
+
fail(t.applyProtocolChange(entry.at, server.id, server.protocol));
|
|
38
|
+
}
|
|
39
|
+
steps.push(diffServer(entry, server));
|
|
40
|
+
}
|
|
41
|
+
else {
|
|
42
|
+
steps.push(createStep(entry, projectId, features));
|
|
43
|
+
}
|
|
44
|
+
}
|
|
45
|
+
checkHosts(steps);
|
|
46
|
+
checkRequestSize(steps);
|
|
47
|
+
checkAuth(steps, byId);
|
|
48
|
+
checkLlm(steps, byId);
|
|
49
|
+
checkDuplicates(steps, account);
|
|
50
|
+
checkPlan(steps, account, features, plannedScenarioCreates);
|
|
51
|
+
const unmanaged = inProject
|
|
52
|
+
.filter((s) => !claimed.has(s.id))
|
|
53
|
+
.map((s) => ({ id: s.id, name: s.name }));
|
|
54
|
+
return { steps, unmanaged };
|
|
55
|
+
}
|
|
56
|
+
function matchServer(entry, byId, inProject, projectId) {
|
|
57
|
+
if (entry.id !== undefined) {
|
|
58
|
+
const server = byId.get(entry.id);
|
|
59
|
+
// A pinned id that is gone is an error, not a reason to create a copy.
|
|
60
|
+
if (!server || server.protocol === 'scenario') {
|
|
61
|
+
return fail(t.applyIdNotFound(entry.at, entry.id));
|
|
62
|
+
}
|
|
63
|
+
if (server.project_id !== projectId) {
|
|
64
|
+
return fail(t.applyIdOtherProject(entry.at, entry.id, server.project_id));
|
|
65
|
+
}
|
|
66
|
+
return server;
|
|
67
|
+
}
|
|
68
|
+
const byName = inProject.filter((s) => s.name === entry.name);
|
|
69
|
+
if (byName.length > 1)
|
|
70
|
+
fail(t.applyAmbiguousName(entry.at, entry.name ?? ''));
|
|
71
|
+
return byName[0];
|
|
72
|
+
}
|
|
73
|
+
/**
|
|
74
|
+
* Entries without an id are found by name on every run, so such names must
|
|
75
|
+
* be unique in the file. Entries pinned by id may share a name, as two
|
|
76
|
+
* servers of the project may (an own export has them); a name shared with a
|
|
77
|
+
* server the file does not mention makes the name match itself ambiguous,
|
|
78
|
+
* and `matchServer` stops there.
|
|
79
|
+
*/
|
|
80
|
+
function checkNames(desired) {
|
|
81
|
+
const fileNames = new Map();
|
|
82
|
+
for (const entry of desired) {
|
|
83
|
+
if (entry.name === null)
|
|
84
|
+
continue;
|
|
85
|
+
const other = fileNames.get(entry.name);
|
|
86
|
+
if (other && (other.id === undefined || entry.id === undefined)) {
|
|
87
|
+
fail(t.applyDuplicateName(entry.at, other.at, entry.name));
|
|
88
|
+
}
|
|
89
|
+
if (!other || entry.id === undefined)
|
|
90
|
+
fileNames.set(entry.name, entry);
|
|
91
|
+
}
|
|
92
|
+
}
|
|
93
|
+
function diffServer(entry, server) {
|
|
94
|
+
const current = server;
|
|
95
|
+
const body = {};
|
|
96
|
+
const fields = [];
|
|
97
|
+
// `name: null` on a pinned entry clears the name, as the API does; an
|
|
98
|
+
// entry without `name` leaves it alone.
|
|
99
|
+
if (entry.nameGiven && entry.name !== server.name) {
|
|
100
|
+
body.name = entry.name;
|
|
101
|
+
fields.push('name');
|
|
102
|
+
}
|
|
103
|
+
for (const [field, value] of Object.entries(entry.fields)) {
|
|
104
|
+
if (!sameValue(field, value, current[field])) {
|
|
105
|
+
// `body: null` would be stored as the string "null"; clear with "".
|
|
106
|
+
body[field] = field === 'body' && value === null ? '' : value;
|
|
107
|
+
fields.push(field);
|
|
108
|
+
}
|
|
109
|
+
}
|
|
110
|
+
// Values never come back from the API, so a set secret is always sent.
|
|
111
|
+
for (const [field, value] of Object.entries(entry.secrets)) {
|
|
112
|
+
body[field] = value;
|
|
113
|
+
fields.push(field);
|
|
114
|
+
}
|
|
115
|
+
if (!fields.length) {
|
|
116
|
+
return { kind: 'unchanged', entry, serverId: server.id };
|
|
117
|
+
}
|
|
118
|
+
return { kind: 'update', entry, serverId: server.id, fields, body };
|
|
119
|
+
}
|
|
120
|
+
function createStep(entry, projectId, features) {
|
|
121
|
+
const f = entry.fields;
|
|
122
|
+
const warnings = [];
|
|
123
|
+
if (entry.protocol !== 'heartbeat' && !f.host) {
|
|
124
|
+
fail(t.applyFieldRequired(entry.at, 'host'));
|
|
125
|
+
}
|
|
126
|
+
if (entry.protocol === 'tcp' && f.port === undefined) {
|
|
127
|
+
fail(t.applyFieldRequired(entry.at, 'port'));
|
|
128
|
+
}
|
|
129
|
+
if (entry.protocol === 'keyword' && !f.keyword) {
|
|
130
|
+
fail(t.applyFieldRequired(entry.at, 'keyword'));
|
|
131
|
+
}
|
|
132
|
+
if (entry.protocol === 'dns' && !f.dns_record_types) {
|
|
133
|
+
fail(t.applyFieldRequired(entry.at, 'dns_record_types'));
|
|
134
|
+
}
|
|
135
|
+
if (entry.protocol === 'llm' && !f.llm_provider) {
|
|
136
|
+
fail(t.applyFieldRequired(entry.at, 'llm_provider'));
|
|
137
|
+
}
|
|
138
|
+
// An empty Basic password is legal; only its absence is not.
|
|
139
|
+
if (f.http_auth_type === 'basic' &&
|
|
140
|
+
entry.secrets.http_auth_password === undefined) {
|
|
141
|
+
fail(t.applyFieldRequired(entry.at, 'http_auth_password'));
|
|
142
|
+
}
|
|
143
|
+
if (f.http_auth_type === 'bearer' && !entry.secrets.http_auth_token) {
|
|
144
|
+
fail(t.applyFieldRequired(entry.at, 'http_auth_token'));
|
|
145
|
+
}
|
|
146
|
+
if (entry.protocol === 'llm' && entry.secrets.llm_api_key && !f.llm_model) {
|
|
147
|
+
fail(t.applyFieldRequired(entry.at, 'llm_model'));
|
|
148
|
+
}
|
|
149
|
+
if (entry.protocol === 'llm' && !entry.secrets.llm_api_key) {
|
|
150
|
+
warnings.push(t.applyLlmAvailability(entry.name ?? entry.at));
|
|
151
|
+
}
|
|
152
|
+
const isHttp = entry.protocol === 'http' || entry.protocol === 'keyword';
|
|
153
|
+
return {
|
|
154
|
+
kind: 'create',
|
|
155
|
+
entry,
|
|
156
|
+
warnings,
|
|
157
|
+
body: {
|
|
158
|
+
// Fields the API requires for every protocol, with the panel defaults.
|
|
159
|
+
is_follow_redirects: isHttp,
|
|
160
|
+
request_timeout: 30,
|
|
161
|
+
check_interval: 300,
|
|
162
|
+
is_ssl_check: false,
|
|
163
|
+
is_domain_check: false,
|
|
164
|
+
// Without locations the API stores its own default (Moscow and
|
|
165
|
+
// St Petersburg) without checking the plan; on Free they are not
|
|
166
|
+
// available, and every later edit of the server would be refused.
|
|
167
|
+
// The panel sends all locations of the plan, and so does this.
|
|
168
|
+
locations: features.available_locations,
|
|
169
|
+
// HEAD has no body, so a keyword check needs GET to see the page.
|
|
170
|
+
...(isHttp && {
|
|
171
|
+
http_method: entry.protocol === 'keyword' ? 'get' : 'head',
|
|
172
|
+
}),
|
|
173
|
+
...(entry.protocol === 'keyword' && { keyword_mode: 'present' }),
|
|
174
|
+
...f,
|
|
175
|
+
...entry.secrets,
|
|
176
|
+
...(entry.protocol === 'heartbeat' && { host: 'heartbeat' }),
|
|
177
|
+
...(f.body === null && { body: '' }),
|
|
178
|
+
project_id: projectId,
|
|
179
|
+
protocol: entry.protocol,
|
|
180
|
+
...(entry.name !== null && { name: entry.name }),
|
|
181
|
+
},
|
|
182
|
+
};
|
|
183
|
+
}
|
|
184
|
+
/**
|
|
185
|
+
* HTTP credentials as they end up after the write: Basic needs a username,
|
|
186
|
+
* switching the type needs the new secret, and a set `Authorization`
|
|
187
|
+
* header would clash with them (`server_http_auth_header_conflict`).
|
|
188
|
+
*/
|
|
189
|
+
/**
|
|
190
|
+
* The backend refuses an internal address only when the host is set or
|
|
191
|
+
* changed, so a server created before the rule keeps working and stays
|
|
192
|
+
* editable; the file may list it unchanged.
|
|
193
|
+
*/
|
|
194
|
+
function checkHosts(steps) {
|
|
195
|
+
for (const step of steps) {
|
|
196
|
+
if (step.kind === 'unchanged')
|
|
197
|
+
continue;
|
|
198
|
+
const host = step.body.host;
|
|
199
|
+
if (typeof host === 'string' && isForbiddenHost(host)) {
|
|
200
|
+
fail(`${step.entry.at}.host: ${t.cfgHostInternal}`);
|
|
201
|
+
}
|
|
202
|
+
}
|
|
203
|
+
}
|
|
204
|
+
// The API's JSON body limit (`main.ts`); a larger request is refused
|
|
205
|
+
// before validation, after the writes ahead of it in the plan.
|
|
206
|
+
const MAX_REQUEST_BYTES = 10 * 1024 * 1024;
|
|
207
|
+
function checkRequestSize(steps) {
|
|
208
|
+
for (const step of steps) {
|
|
209
|
+
if (step.kind === 'unchanged')
|
|
210
|
+
continue;
|
|
211
|
+
const bytes = Buffer.byteLength(JSON.stringify(step.body), 'utf8');
|
|
212
|
+
if (bytes > MAX_REQUEST_BYTES) {
|
|
213
|
+
fail(t.applyRequestTooLarge(step.entry.at, MAX_REQUEST_BYTES));
|
|
214
|
+
}
|
|
215
|
+
}
|
|
216
|
+
}
|
|
217
|
+
function checkAuth(steps, byId) {
|
|
218
|
+
for (const step of steps) {
|
|
219
|
+
if (step.kind === 'unchanged')
|
|
220
|
+
continue;
|
|
221
|
+
const current = step.kind === 'update' ? byId.get(step.serverId) : undefined;
|
|
222
|
+
const body = step.body;
|
|
223
|
+
const type = (body.http_auth_type ??
|
|
224
|
+
current?.http_auth_type ??
|
|
225
|
+
'none');
|
|
226
|
+
// A secret of the other type would be accepted and ignored.
|
|
227
|
+
if (body.http_auth_password !== undefined && type !== 'basic') {
|
|
228
|
+
fail(t.applyAuthSecretMismatch(step.entry.at, 'http_auth_password', type));
|
|
229
|
+
}
|
|
230
|
+
if (body.http_auth_token !== undefined && type !== 'bearer') {
|
|
231
|
+
fail(t.applyAuthSecretMismatch(step.entry.at, 'http_auth_token', type));
|
|
232
|
+
}
|
|
233
|
+
// The login as written in the file, sent or not: an unchanged login
|
|
234
|
+
// next to `none` would be wiped by the API and fail the next run.
|
|
235
|
+
const login = body.http_auth_username ?? step.entry.fields.http_auth_username;
|
|
236
|
+
if (login != null && type !== 'basic') {
|
|
237
|
+
fail(t.applyAuthSecretMismatch(step.entry.at, 'http_auth_username', type));
|
|
238
|
+
}
|
|
239
|
+
if (type === 'none')
|
|
240
|
+
continue;
|
|
241
|
+
const username = body.http_auth_username ?? current?.http_auth_username;
|
|
242
|
+
if (type === 'basic' && !String(username ?? '').trim()) {
|
|
243
|
+
fail(t.applyFieldRequired(step.entry.at, 'http_auth_username'));
|
|
244
|
+
}
|
|
245
|
+
const typeChanged = !current || current.http_auth_type !== type;
|
|
246
|
+
const secret = type === 'basic' ? 'http_auth_password' : 'http_auth_token';
|
|
247
|
+
if (typeChanged && body[secret] === undefined) {
|
|
248
|
+
fail(t.applyFieldRequired(step.entry.at, secret));
|
|
249
|
+
}
|
|
250
|
+
const headers = (body.headers ?? current?.headers ?? []);
|
|
251
|
+
if (headers.some((h) => h.key.trim().toLowerCase() === 'authorization')) {
|
|
252
|
+
fail(t.applyAuthHeaderConflict(step.entry.at));
|
|
253
|
+
}
|
|
254
|
+
}
|
|
255
|
+
}
|
|
256
|
+
/**
|
|
257
|
+
* The LLM configuration as it ends up (`assertLlmConfigUsable`): a key
|
|
258
|
+
* needs a model, and a model without a key is dropped by the backend — the
|
|
259
|
+
* duplicate check would then compare a model that is never stored.
|
|
260
|
+
*/
|
|
261
|
+
function checkLlm(steps, byId) {
|
|
262
|
+
for (const step of steps) {
|
|
263
|
+
if (step.kind === 'unchanged' || step.entry.protocol !== 'llm')
|
|
264
|
+
continue;
|
|
265
|
+
const current = step.kind === 'update' ? byId.get(step.serverId) : undefined;
|
|
266
|
+
const body = step.body;
|
|
267
|
+
const hasKey = body.llm_api_key !== undefined
|
|
268
|
+
? Boolean(body.llm_api_key)
|
|
269
|
+
: current?.llm_check_mode === 'inference';
|
|
270
|
+
const model = body.llm_model ?? current?.llm_model ?? null;
|
|
271
|
+
if (hasKey && !model) {
|
|
272
|
+
fail(t.applyFieldRequired(step.entry.at, 'llm_model'));
|
|
273
|
+
}
|
|
274
|
+
if (!hasKey && body.llm_model !== undefined) {
|
|
275
|
+
fail(`${step.entry.at}.llm_model: ${t.cfgLlmModelWithoutKey}`);
|
|
276
|
+
}
|
|
277
|
+
}
|
|
278
|
+
}
|
|
279
|
+
/**
|
|
280
|
+
* The backend rejects a monitor equal to another one anywhere in the
|
|
281
|
+
* account, and it checks every request against the state at that moment.
|
|
282
|
+
* So the plan is replayed in execution order (updates, then creates): a
|
|
283
|
+
* swap of addresses between two servers collides on its first PATCH and
|
|
284
|
+
* is refused here, before any write.
|
|
285
|
+
*/
|
|
286
|
+
function checkDuplicates(steps, account) {
|
|
287
|
+
const states = new Map();
|
|
288
|
+
for (const server of account) {
|
|
289
|
+
if (server.protocol === 'scenario')
|
|
290
|
+
continue;
|
|
291
|
+
states.set(`#${server.id}`, {
|
|
292
|
+
state: server,
|
|
293
|
+
label: server.name ?? server.host,
|
|
294
|
+
});
|
|
295
|
+
}
|
|
296
|
+
const ordered = [
|
|
297
|
+
...steps.filter((s) => s.kind === 'update'),
|
|
298
|
+
...steps.filter((s) => s.kind === 'create'),
|
|
299
|
+
];
|
|
300
|
+
for (const step of ordered) {
|
|
301
|
+
// Creates and existing servers keep separate keys: a label like `#123`
|
|
302
|
+
// must not land on the slot of server 123.
|
|
303
|
+
const slot = step.kind === 'create' ? `create:${step.entry.at}` : `#${step.serverId}`;
|
|
304
|
+
const previous = states.get(slot);
|
|
305
|
+
const state = { ...previous?.state, ...step.body };
|
|
306
|
+
const label = step.entry.name ?? previous?.label ?? step.entry.at;
|
|
307
|
+
const key = duplicateKey(state);
|
|
308
|
+
// The backend checks only a create or a write that changes the identity:
|
|
309
|
+
// a duplicate made before the check existed can still be edited.
|
|
310
|
+
if (previous && duplicateKey(previous.state) === key) {
|
|
311
|
+
states.set(slot, { state, label });
|
|
312
|
+
continue;
|
|
313
|
+
}
|
|
314
|
+
for (const [other, item] of states) {
|
|
315
|
+
if (other !== slot && isDuplicateOf(state, item.state)) {
|
|
316
|
+
fail(t.applyDuplicate(label, item.label));
|
|
317
|
+
}
|
|
318
|
+
}
|
|
319
|
+
states.set(slot, { state, label });
|
|
320
|
+
}
|
|
321
|
+
}
|
|
322
|
+
// Fields whose presence in a PATCH makes the backend re-check the plan
|
|
323
|
+
// (`ServerWriteService.update` → `validateServerFeatures`).
|
|
324
|
+
const FEATURE_TRIGGERS = [
|
|
325
|
+
'check_interval',
|
|
326
|
+
'locations',
|
|
327
|
+
'is_ssl_check',
|
|
328
|
+
'is_domain_check',
|
|
329
|
+
'is_blocklist_check',
|
|
330
|
+
'is_latency_alert_enabled',
|
|
331
|
+
'latency_trigger_ms',
|
|
332
|
+
'incident_confirm_delay',
|
|
333
|
+
'llm_api_key',
|
|
334
|
+
'success_http_codes',
|
|
335
|
+
];
|
|
336
|
+
/**
|
|
337
|
+
* What a write needs from the plan, as the backend checks it: on create
|
|
338
|
+
* the new server, on update the server as it will be after the PATCH —
|
|
339
|
+
* so a server kept from a richer plan fails as soon as it is touched.
|
|
340
|
+
*/
|
|
341
|
+
function requirements(step, current) {
|
|
342
|
+
if (step.kind === 'unchanged')
|
|
343
|
+
return { features: [] };
|
|
344
|
+
const body = step.body;
|
|
345
|
+
if (step.kind === 'update' &&
|
|
346
|
+
!FEATURE_TRIGGERS.some((field) => field in body)) {
|
|
347
|
+
return { features: [] };
|
|
348
|
+
}
|
|
349
|
+
const merged = {
|
|
350
|
+
...current,
|
|
351
|
+
...body,
|
|
352
|
+
};
|
|
353
|
+
const needs = [];
|
|
354
|
+
const byProtocol = {
|
|
355
|
+
keyword: 'keyword_monitoring_enabled',
|
|
356
|
+
dns: 'dns_monitoring_enabled',
|
|
357
|
+
heartbeat: 'heartbeat_monitoring_enabled',
|
|
358
|
+
llm: 'ai_monitoring_enabled',
|
|
359
|
+
};
|
|
360
|
+
const protocolFeature = byProtocol[merged.protocol];
|
|
361
|
+
if (protocolFeature)
|
|
362
|
+
needs.push(protocolFeature);
|
|
363
|
+
const inference = body.llm_api_key !== undefined
|
|
364
|
+
? Boolean(body.llm_api_key)
|
|
365
|
+
: current?.llm_check_mode === 'inference';
|
|
366
|
+
if (merged.protocol === 'llm' && inference)
|
|
367
|
+
needs.push('ai_inference_enabled');
|
|
368
|
+
if (merged.is_ssl_check === true)
|
|
369
|
+
needs.push('ssl_monitoring_enabled');
|
|
370
|
+
if (merged.is_domain_check === true)
|
|
371
|
+
needs.push('domain_monitoring_enabled');
|
|
372
|
+
// The backend reads only the sent value here: old rows have it on.
|
|
373
|
+
if (body.is_blocklist_check === true) {
|
|
374
|
+
needs.push('blocklist_monitoring_enabled');
|
|
375
|
+
}
|
|
376
|
+
if (merged.is_latency_alert_enabled === true) {
|
|
377
|
+
needs.push('latency_alerts_enabled');
|
|
378
|
+
}
|
|
379
|
+
if (typeof body.incident_confirm_delay === 'number' &&
|
|
380
|
+
body.incident_confirm_delay > 0) {
|
|
381
|
+
needs.push('incident_debounce_enabled');
|
|
382
|
+
}
|
|
383
|
+
const codes = body.success_http_codes?.map((c) => c.trim().toLowerCase());
|
|
384
|
+
if (codes && !(codes.length === 1 && codes[0] === '2xx')) {
|
|
385
|
+
needs.push('custom_success_http_codes_enabled');
|
|
386
|
+
}
|
|
387
|
+
return {
|
|
388
|
+
features: needs,
|
|
389
|
+
interval: merged.check_interval,
|
|
390
|
+
locations: merged.locations,
|
|
391
|
+
};
|
|
392
|
+
}
|
|
393
|
+
function checkPlan(steps, account, features, plannedScenarioCreates) {
|
|
394
|
+
const byId = new Map(account.map((s) => [s.id, s]));
|
|
395
|
+
const creates = steps.filter((s) => s.kind === 'create').length;
|
|
396
|
+
// An account already over the limit after a downgrade may still edit
|
|
397
|
+
// its servers; only new ones are refused.
|
|
398
|
+
if (creates + plannedScenarioCreates > 0 &&
|
|
399
|
+
account.length + creates + plannedScenarioCreates > features.servers_limit) {
|
|
400
|
+
fail(t.applyServersLimit(features.servers_limit, account.length, creates + plannedScenarioCreates));
|
|
401
|
+
}
|
|
402
|
+
for (const step of steps) {
|
|
403
|
+
if (step.kind === 'unchanged')
|
|
404
|
+
continue;
|
|
405
|
+
const current = step.kind === 'update' ? byId.get(step.serverId) : undefined;
|
|
406
|
+
const needed = requirements(step, current);
|
|
407
|
+
for (const feature of needed.features) {
|
|
408
|
+
if (!features[feature]) {
|
|
409
|
+
fail(t.applyFeatureUnavailable(step.entry.at, feature));
|
|
410
|
+
}
|
|
411
|
+
}
|
|
412
|
+
if (needed.interval !== undefined &&
|
|
413
|
+
needed.interval < features.min_check_interval_seconds) {
|
|
414
|
+
fail(t.applyIntervalTooLow(step.entry.at, features.min_check_interval_seconds));
|
|
415
|
+
}
|
|
416
|
+
const unavailable = (needed.locations ?? []).filter((l) => !features.available_locations.includes(l));
|
|
417
|
+
if (unavailable.length) {
|
|
418
|
+
fail(t.applyLocationsUnavailable(step.entry.at, unavailable.join(', ')));
|
|
419
|
+
}
|
|
420
|
+
}
|
|
421
|
+
}
|
|
422
|
+
/**
|
|
423
|
+
* The scenario side of the plan limits: the number of scenarios, their
|
|
424
|
+
* minimal interval and maximal timeout. Checked together with the servers
|
|
425
|
+
* so a full apply never stops on the scenarios after servers were written.
|
|
426
|
+
*/
|
|
427
|
+
export function checkScenarioLimits(steps, existingScenarios, features) {
|
|
428
|
+
const creates = steps.filter((s) => s.kind === 'create').length;
|
|
429
|
+
// The backend checks the plan on a create and on any change to the
|
|
430
|
+
// scenario or its interval (`validateScenarioFeatures`); a rename alone
|
|
431
|
+
// passes even on a plan without scenarios.
|
|
432
|
+
const gated = steps.filter((s) => s.kind === 'create' ||
|
|
433
|
+
(s.kind === 'update' && (s.fields ?? []).some((f) => f !== 'name')));
|
|
434
|
+
if (features.scenarios_limit <= 0 && gated.length) {
|
|
435
|
+
fail(t.applyFeatureUnavailable('scenarios', 'scenarios_limit'));
|
|
436
|
+
}
|
|
437
|
+
if (creates && existingScenarios + creates > features.scenarios_limit) {
|
|
438
|
+
fail(t.applyScenariosLimit(features.scenarios_limit, existingScenarios, creates));
|
|
439
|
+
}
|
|
440
|
+
for (const step of gated) {
|
|
441
|
+
const { name, interval, timeout } = step.scenario;
|
|
442
|
+
if (interval < features.scenario_min_check_interval_seconds) {
|
|
443
|
+
fail(t.applyIntervalTooLow(name, features.scenario_min_check_interval_seconds));
|
|
444
|
+
}
|
|
445
|
+
if (timeout > features.scenario_max_timeout_seconds) {
|
|
446
|
+
fail(t.applyScenarioTimeoutTooHigh(name, features.scenario_max_timeout_seconds));
|
|
447
|
+
}
|
|
448
|
+
}
|
|
449
|
+
}
|
|
450
|
+
/**
|
|
451
|
+
* Plan checks for one PATCH of `servers update`, the same the backend runs:
|
|
452
|
+
* features of the server as it will be, the minimal interval, available
|
|
453
|
+
* locations, and for scenarios their own limits. Null when it fits.
|
|
454
|
+
*/
|
|
455
|
+
export function patchPlanProblem(server, body, features) {
|
|
456
|
+
if (server.protocol === 'scenario') {
|
|
457
|
+
// The API checks the plan of a scenario only when its schedule or run
|
|
458
|
+
// changes; a rename or a new description passes on any plan.
|
|
459
|
+
if (!['check_interval', 'request_timeout', 'locations'].some((field) => field in body)) {
|
|
460
|
+
return null;
|
|
461
|
+
}
|
|
462
|
+
if (features.scenarios_limit <= 0)
|
|
463
|
+
return 'scenarios_limit';
|
|
464
|
+
const interval = body.check_interval ?? server.check_interval;
|
|
465
|
+
const timeout = body.request_timeout ?? server.request_timeout;
|
|
466
|
+
if (interval < features.scenario_min_check_interval_seconds) {
|
|
467
|
+
return `interval ≥ ${features.scenario_min_check_interval_seconds}`;
|
|
468
|
+
}
|
|
469
|
+
if (timeout > features.scenario_max_timeout_seconds) {
|
|
470
|
+
return `timeout ≤ ${features.scenario_max_timeout_seconds}`;
|
|
471
|
+
}
|
|
472
|
+
return null;
|
|
473
|
+
}
|
|
474
|
+
const step = {
|
|
475
|
+
kind: 'update',
|
|
476
|
+
serverId: server.id,
|
|
477
|
+
body,
|
|
478
|
+
fields: Object.keys(body),
|
|
479
|
+
entry: { at: `#${server.id}` },
|
|
480
|
+
};
|
|
481
|
+
const needed = requirements(step, server);
|
|
482
|
+
const missing = needed.features.find((feature) => !features[feature]);
|
|
483
|
+
if (missing)
|
|
484
|
+
return missing;
|
|
485
|
+
if (needed.interval !== undefined &&
|
|
486
|
+
needed.interval < features.min_check_interval_seconds) {
|
|
487
|
+
return `interval ≥ ${features.min_check_interval_seconds}`;
|
|
488
|
+
}
|
|
489
|
+
const unavailable = (needed.locations ?? []).filter((l) => !features.available_locations.includes(l));
|
|
490
|
+
return unavailable.length ? unavailable.join(', ') : null;
|
|
491
|
+
}
|
|
492
|
+
//# sourceMappingURL=plan.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"plan.js","sourceRoot":"","sources":["../../src/servers-config/plan.ts"],"names":[],"mappings":"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"}
|