collabSupport/services/voiceDiag/checks/index.js
jmcqueen b802383441 Add Prisma SD-WAN voice-quality enrichment for /phonestatus + /voicediag
Introduces a full Palo Alto Prisma SD-WAN integration (dual-mode SASE
OAuth 2.0 / legacy CloudGenix auth, pagination, 429 backoff, session
priming) that surfaces per-path latency/jitter/loss/MOS, site
healthscore, link state, and alarm data for a store. Wired into the
/phonestatus WAN follow-up and eight new /voicediag WAN checks graded
against ITU-T G.114 / RFC 3550 defaults (env-overridable via
WAN_STANDARD_*).

Also adds a shape-aware detail renderer for /voicediag (per-link
tables with verdict icons instead of a stringified JSON dump) and a
--window flag (15m / 1h / 6h / 24h / 1d, env default via
WAN_STANDARD_WINDOW_MINUTES) so operators can widen the look-back
without redeploying. scripts/prismaProbe.js is bundled as a CLI for
schema iteration against a live tenant.

Co-authored-by: Cursor <cursoragent@cursor.com>
2026-07-09 09:45:29 -04:00

103 lines
4 KiB
JavaScript

// src/services/voiceDiag/checks/index.js
//
// Ordered registry of every /voicediag check. Order matters — the
// renderer walks this list to produce the output, so put the checks a
// human operator would notice first (DND, forwarding) at the top,
// then the deeper feature-config ones, then finally the online-device
// summary which is often the last thing they want to see.
//
// Adding a new check
// 1. Drop a new file next to this one (e.g. `myNewCheck.js`) that
// exports the check descriptor as its default export or a named
// export.
// 2. Add it to CHECKS below in the position you want it to render.
// 3. If it exports a `remediations: {actionId: handler}` map, the
// voiceDiagService remediation registry will pick it up
// automatically. Action ids must be globally unique across all
// checks — a collision throws at startup.
//
// Every check must export an object matching:
//
// {
// id: string, // stable, snake_case, globally unique
// label: string, // human-readable heading
// requires: string[], // subset of ['personId','phoneStatus',
// // 'telephonyProfile'] — runner skips
// // the check if any are missing on ctx
// scope: string, // primary Webex scope needed; surfaced
// // in the skipped message on 401/403/404
// run: async (ctx) => CheckResult,
// remediations?: { [actionId: string]: async (bot, data, requester) => void }
// }
import { dndCheck } from './dnd.js';
import { callForwardingCheck } from './callForwarding.js';
import { callWaitingCheck } from './callWaiting.js';
import { voicemailCheck } from './voicemail.js';
import { callInterceptCheck } from './callIntercept.js';
import { hotelingCheck } from './hoteling.js';
import { executiveAssistantCheck } from './executiveAssistant.js';
import { outgoingPermissionCheck } from './outgoingPermission.js';
import { phoneOnlineCheck } from './phoneOnline.js';
import { portTypeCheck } from './port/portType.js';
import { portVlanCheck } from './port/portVlan.js';
import { portPoeCheck } from './port/portPoe.js';
import { portEnabledCheck } from './port/portEnabled.js';
import { wanSiteCheck } from './wan/wanSite.js';
import { wanHealthscoreCheck } from './wan/wanHealthscore.js';
import { wanLinkStateCheck } from './wan/wanLinkState.js';
import { wanLatencyCheck } from './wan/wanLatency.js';
import { wanJitterCheck } from './wan/wanJitter.js';
import { wanLossCheck } from './wan/wanLoss.js';
import { wanMosCheck } from './wan/wanMos.js';
import { wanAlarmsCheck } from './wan/wanAlarms.js';
// Order: user-facing feature signals first (things an operator can
// see from the phone UI), then LAN-side port hygiene, then the WAN
// bucket (Prisma SD-WAN — the "network edge" one hop out from the
// LAN), then the broad-brush online summary last so it acts as a
// reachability closer.
export const CHECKS = [
dndCheck,
callForwardingCheck,
callInterceptCheck,
callWaitingCheck,
voicemailCheck,
hotelingCheck,
executiveAssistantCheck,
outgoingPermissionCheck,
portTypeCheck,
portVlanCheck,
portPoeCheck,
portEnabledCheck,
wanSiteCheck,
wanHealthscoreCheck,
wanLinkStateCheck,
wanLatencyCheck,
wanJitterCheck,
wanLossCheck,
wanMosCheck,
wanAlarmsCheck,
phoneOnlineCheck,
];
const _byId = new Map();
for (const c of CHECKS) {
if (!c || typeof c !== 'object') {
throw new Error('voicediag: encountered non-object check in registry');
}
if (!c.id || typeof c.id !== 'string') {
throw new Error('voicediag: check is missing required "id" string');
}
const key = c.id.toLowerCase();
if (_byId.has(key)) {
throw new Error(`voicediag: duplicate check id "${c.id}"`);
}
_byId.set(key, c);
}
/** Case-insensitive lookup so `--only DND` and `--only dnd` both work. */
export function getCheckById(id) {
if (!id) return null;
return _byId.get(String(id).toLowerCase().trim()) || null;
}