Skip to content

Validate Runtime Invariants

This guide shows how to build manual defensive checks using only invariant constants exported by the contract.

import {
LEGATO_INVARIANTS,
POSITION_MIN,
type PlaybackSnapshot,
} from '@ddgutierrezc/legato-contract';

@ddgutierrezc/legato-contract does not export a runtime validator helper. The checks below are consumer-side usage built from exported constants.

function validateSnapshot(snapshot: PlaybackSnapshot): string[] {
const violations: string[] = [];
if (snapshot.position < POSITION_MIN) {
violations.push(LEGATO_INVARIANTS.POSITION_NON_NEGATIVE);
}
if (snapshot.duration !== null && snapshot.duration < POSITION_MIN) {
violations.push(LEGATO_INVARIANTS.OPTIONAL_NUMERIC_FIELDS_NON_NEGATIVE);
}
if (
snapshot.bufferedPosition !== undefined &&
snapshot.bufferedPosition !== null &&
snapshot.bufferedPosition < POSITION_MIN
) {
violations.push(LEGATO_INVARIANTS.OPTIONAL_NUMERIC_FIELDS_NON_NEGATIVE);
}
const { items, currentIndex } = snapshot.queue;
const inBounds = currentIndex === null || (currentIndex >= 0 && currentIndex < items.length);
if (!inBounds) {
violations.push(LEGATO_INVARIANTS.QUEUE_CURRENT_INDEX_IN_BOUNDS);
}
if (snapshot.currentTrack) {
if (snapshot.currentTrack.id.trim().length === 0) {
violations.push(LEGATO_INVARIANTS.TRACK_ID_MUST_BE_NON_EMPTY);
}
if (snapshot.currentTrack.url.trim().length === 0) {
violations.push(LEGATO_INVARIANTS.TRACK_URL_MUST_BE_NON_EMPTY);
}
}
return violations;
}

Use the returned invariant messages to decide your strategy:

  • reject incoming data,
  • log and continue with fallback state,
  • or route diagnostics to your observability pipeline.

You have a transport-neutral defensive validation layer that reuses contract constants as canonical invariant messages without depending on unexported runtime helpers.