38 lines
2.1 KiB
JavaScript
38 lines
2.1 KiB
JavaScript
export function maintenanceEnd(item) {
|
||
return Math.min(item.endsAt, item.cancelledAt ?? Infinity, item.completedAt ?? Infinity);
|
||
}
|
||
|
||
export function maintenancePhase(item, now = Date.now()) {
|
||
if (item.cancelledAt !== null && item.cancelledAt <= now) return 'cancelled';
|
||
if (item.completedAt !== null && item.completedAt <= now) return 'completed';
|
||
if (now >= item.endsAt) return 'ended';
|
||
return now < item.startsAt ? 'scheduled' : 'active';
|
||
}
|
||
|
||
export function affectsService(item, serviceId, time = Date.now()) {
|
||
return (!item.serviceIds.length || item.serviceIds.includes(serviceId)) && item.startsAt <= time && time < maintenanceEnd(item);
|
||
}
|
||
|
||
export function validateMaintenance(input, serviceIds) {
|
||
for (const key of ['titleRu', 'titleEn', 'messageRu', 'messageEn']) {
|
||
if (typeof input[key] !== 'string' || !input[key].trim() || input[key].length > 2000) throw new Error(`Provide ${key} (1–2000 characters)`);
|
||
}
|
||
if (!Number.isSafeInteger(input.startsAt) || !Number.isSafeInteger(input.endsAt) || input.endsAt <= input.startsAt) throw new Error('End must be after start');
|
||
if (!Array.isArray(input.serviceIds) || input.serviceIds.some(id => !serviceIds.includes(id)) || new Set(input.serviceIds).size !== input.serviceIds.length) throw new Error('Unknown or duplicate service');
|
||
return input;
|
||
}
|
||
|
||
export function parseInstant(value) {
|
||
const valid = typeof value === 'string' && /^\d{4}-\d{2}-\d{2}T(?:[01]\d|2[0-3]):[0-5]\d(?::[0-5]\d(?:\.\d{1,3})?)?(?:Z|[+-]\d{2}:\d{2})$/.test(value) && Number.isFinite(Date.parse(value));
|
||
if (!valid || new Date(`${value.slice(0, 10)}T00:00:00Z`).toISOString().slice(0, 10) !== value.slice(0, 10)) throw new Error('Use a valid ISO timestamp with an explicit timezone, for example 2026-10-13T02:00:00+03:00');
|
||
return Date.parse(value);
|
||
}
|
||
|
||
export function combinedStatus(availability, scenario, maintenance = false) {
|
||
if (maintenance) return 'maintenance';
|
||
if (availability === 'down' || availability === 'unknown') return availability;
|
||
if (scenario && ['down', 'degraded'].includes(scenario.status)) return 'degraded';
|
||
if (scenario?.status === 'unknown') return 'unknown';
|
||
return availability;
|
||
}
|