feat(plugins): isolate device integrations
This commit is contained in:
@@ -0,0 +1,56 @@
|
||||
// Ordering rules remain plugin-private because revisions are vendor runtime state.
|
||||
import type { XgridsCameraPreviewState, XgridsK1State } from "./api";
|
||||
|
||||
function monotonicInteger(value: number | null | undefined): number | null {
|
||||
return typeof value === "number" && Number.isInteger(value) && value >= 0 ? value : null;
|
||||
}
|
||||
|
||||
function deviceSessionScope(state: XgridsK1State): string | null {
|
||||
const sessionId = state.device_session?.device_session_id;
|
||||
return typeof sessionId === "string" && sessionId.trim() ? sessionId : null;
|
||||
}
|
||||
|
||||
function cameraSnapshotIsAtLeastAsNew(
|
||||
current: XgridsCameraPreviewState,
|
||||
incoming: XgridsCameraPreviewState,
|
||||
): boolean {
|
||||
const currentRevision = monotonicInteger(current.revision);
|
||||
const incomingRevision = monotonicInteger(incoming.revision);
|
||||
|
||||
if (currentRevision !== null || incomingRevision !== null) {
|
||||
if (incomingRevision === null) return false;
|
||||
if (currentRevision === null) return true;
|
||||
if (incomingRevision !== currentRevision) return incomingRevision > currentRevision;
|
||||
}
|
||||
|
||||
const currentGeneration = monotonicInteger(current.generation);
|
||||
const incomingGeneration = monotonicInteger(incoming.generation);
|
||||
if (currentGeneration === null) return true;
|
||||
if (incomingGeneration === null) return false;
|
||||
return incomingGeneration >= currentGeneration;
|
||||
}
|
||||
|
||||
/**
|
||||
* Select an authoritative runtime snapshot without allowing asynchronous REST,
|
||||
* mutation, or event responses to roll camera preview state backwards.
|
||||
*
|
||||
* Revision is the primary ordering key. In particular, a stop snapshot with a
|
||||
* newer revision and a null generation is valid and must replace the active
|
||||
* generation. Generation is only a tie-breaker when revisions are equal or
|
||||
* absent.
|
||||
*/
|
||||
export function selectMonotonicXgridsState(
|
||||
current: XgridsK1State | null,
|
||||
incoming: XgridsK1State,
|
||||
): XgridsK1State {
|
||||
if (current && deviceSessionScope(current) !== deviceSessionScope(incoming)) {
|
||||
return incoming;
|
||||
}
|
||||
if (!current?.camera_preview) return incoming;
|
||||
if (!incoming.camera_preview) return current;
|
||||
// Backend snapshots are atomic. Reject the whole stale response instead of
|
||||
// combining camera/catalog/metrics fields captured at different moments.
|
||||
return cameraSnapshotIsAtLeastAsNew(current.camera_preview, incoming.camera_preview)
|
||||
? incoming
|
||||
: current;
|
||||
}
|
||||
Reference in New Issue
Block a user