/** * Verification core — the single central authority for what counts as a * pass or a failure when re-verifying a proctored environment. * * Two callers feed it: * - the runtime {@link ../checkpoint checkpoint}, which gathers facts from * the live capture tracks it already holds, and * - the resume probe (packages/vue), which re-acquires media after a * mid-assessment refresh and gathers facts from the fresh streams. * * They differ only in HOW they gather the facts and HOW they render the * verdict (a drift `CheckpointChange` vs a candidate-facing * `ResumeCheckItem`). The RULE — precedence, loudness-independence, and the * graceful skips — lives here and nowhere else, so the two can never drift * apart. * * Purity is the contract: no DOM, no `getUserMedia`, no timers, no I/O. Every * function takes already-normalised facts and returns a neutral verdict. The * side-effecting gathering (enumeration, re-acquisition, frame capture, the * server ping) stays in the callers — this module only decides. */ /** Tri-state permission, mirroring the browser's Permissions API. */ export type PermissionFact = "granted" | "denied" | "unknown"; /** * Whether the selected device id is still enumerated. * - `present` the id we saved is in the current device list * - `absent` the kind IS enumerable but our id is gone (unplugged) * - `cannot-tell` enumeration unavailable, or this kind can't be listed * (ids censored without a media grant; Safari never lists * audiooutput) — unknown, NOT missing */ export type PresenceFact = "present" | "absent" | "cannot-tell"; /** * The liveness of the capture track for this device. * - `live` the browser is delivering frames/samples * - `ended` track.readyState === "ended" (unplugged / stopped) * - `muted` track.muted === true — browser-owned, set when the source * stops delivering data (OS mute / grabbed by another app). * Loudness-independent: a quiet room is NOT muted. * - `none` no track to inspect (unavailable, not a failure) */ export type TrackFact = "live" | "ended" | "muted" | "none"; export interface DeviceFacts { /** * Whether the session depends on this device's PERMISSION. Only when true is * a `denied` permission treated as a regression — a policy that never needed * the mic can't false-flag a lost mic permission. Presence and track are * still checked regardless (a speaker has no permission of its own but its * presence still matters). */ required: boolean; permission: PermissionFact; presence: PresenceFact; track: TrackFact; } /** * The neutral device verdict — the FIRST tripped rule, in root-cause order, or * `ok`. Each caller maps these to its own vocabulary (e.g. `permission-denied` * → checkpoint `permission-lost` / resume `blocked`). */ export type DeviceVerdict = "ok" | "permission-denied" | "device-absent" | "track-ended" | "track-muted"; /** Permission regression, only when the session depends on the permission. */ export declare function permissionVerdict(facts: { required: boolean; permission: PermissionFact; }): "ok" | "denied"; /** Selected device gone — only `absent` fails; `cannot-tell` is a skip. */ export declare function presenceVerdict(facts: { presence: PresenceFact; }): "ok" | "absent"; /** Capture track liveness. Loudness plays no part — `live`/`none` pass. */ export declare function trackVerdict(facts: { track: TrackFact; }): "ok" | "ended" | "muted"; /** * Evaluate one device against the shared rule as a single verdict. * * Precedence is root-cause order: a lost permission explains a missing device * which explains a dead track, so we report the earliest, most actionable * cause. Composed from the granular atoms above so there is exactly one * definition of each rule. Any fact the browser couldn't answer (`unknown` / * `cannot-tell` / `none`) skips its rule — unknown is never broken. */ export declare function deviceVerdict(facts: DeviceFacts): DeviceVerdict; export type DisplayFact = "single" | "extended" | "unknown"; export interface DisplayFacts { /** The display state that passed preflight (the comparison point). */ baseline: DisplayFact; /** The display state now. `unknown` when `screen.isExtended` is unsupported. */ current: DisplayFact; } export type DisplayVerdict = "ok" | "external-monitor"; /** * Flag only a NEW second display: single at baseline, extended now. A baseline * that was already extended can't regress, and an `unknown` current reading * (non-Chromium) passes rather than guessing. */ export declare function displayVerdict(facts: DisplayFacts): DisplayVerdict; export interface FullscreenFacts { inFullscreen: boolean; } export type FullscreenVerdict = "ok" | "not-fullscreen"; export declare function fullscreenVerdict(facts: FullscreenFacts): FullscreenVerdict; export type ScreenShareVerdict = "needs-reshare"; /** * A refresh unconditionally drops the `getDisplayMedia` capture, and only a * fresh candidate gesture can re-acquire it — so there is no passing state to * probe. Kept as a function (not a bare constant) so the reason lives here * alongside the other verdict rules rather than being special-cased inline. */ export declare function screenShareVerdict(): ScreenShareVerdict; export interface ConnectionFacts { /** `true`/`false` from a reachability probe, or `not-probed` when skipped. */ reachable: boolean | "not-probed"; } export type ConnectionVerdict = "ok" | "offline"; /** * Reachability, not a speed test. A caller that doesn't probe connectivity * passes `not-probed` and the check is skipped (unavailable, not offline). */ export declare function connectionVerdict(facts: ConnectionFacts): ConnectionVerdict; //# sourceMappingURL=verification-core.d.ts.map