Add node location access RPCs and operator visibility

This commit is contained in:
William Valentin
2026-02-16 12:30:55 -08:00
parent 1d16cd54e6
commit fe8674e108
19 changed files with 693 additions and 15 deletions
+75
View File
@@ -18,6 +18,22 @@ export interface NodeRegisterParams {
capabilities: string[];
}
export interface NodeLocationSetParams {
connectionId: string;
latitude: number;
longitude: number;
accuracyMeters?: number;
altitudeMeters?: number;
headingDegrees?: number;
speedMps?: number;
source?: 'gps' | 'network' | 'manual' | 'unknown';
capturedAt?: number;
}
export interface NodeLocationGetParams {
connectionId: string;
}
// ── Server → Client ────────────────────────────────────────────
export interface GatewayResponse {
@@ -170,6 +186,65 @@ export function parseNodeRegisterParams(params: unknown): NodeRegisterParams | n
};
}
export function parseNodeLocationSetParams(params: unknown): NodeLocationSetParams | null {
if (!params || typeof params !== 'object') {
return null;
}
const p = params as Record<string, unknown>;
if (typeof p.connectionId !== 'string' || !p.connectionId.trim()) {
return null;
}
if (typeof p.latitude !== 'number' || !Number.isFinite(p.latitude) || p.latitude < -90 || p.latitude > 90) {
return null;
}
if (typeof p.longitude !== 'number' || !Number.isFinite(p.longitude) || p.longitude < -180 || p.longitude > 180) {
return null;
}
if (p.accuracyMeters !== undefined && (typeof p.accuracyMeters !== 'number' || !Number.isFinite(p.accuracyMeters) || p.accuracyMeters < 0)) {
return null;
}
if (p.altitudeMeters !== undefined && (typeof p.altitudeMeters !== 'number' || !Number.isFinite(p.altitudeMeters))) {
return null;
}
if (p.headingDegrees !== undefined && (typeof p.headingDegrees !== 'number' || !Number.isFinite(p.headingDegrees) || p.headingDegrees < 0 || p.headingDegrees > 360)) {
return null;
}
if (p.speedMps !== undefined && (typeof p.speedMps !== 'number' || !Number.isFinite(p.speedMps) || p.speedMps < 0)) {
return null;
}
if (p.capturedAt !== undefined && (typeof p.capturedAt !== 'number' || !Number.isFinite(p.capturedAt) || p.capturedAt <= 0)) {
return null;
}
if (p.source !== undefined && !['gps', 'network', 'manual', 'unknown'].includes(String(p.source))) {
return null;
}
return {
connectionId: p.connectionId,
latitude: p.latitude,
longitude: p.longitude,
accuracyMeters: p.accuracyMeters as number | undefined,
altitudeMeters: p.altitudeMeters as number | undefined,
headingDegrees: p.headingDegrees as number | undefined,
speedMps: p.speedMps as number | undefined,
source: p.source as NodeLocationSetParams['source'] | undefined,
capturedAt: p.capturedAt as number | undefined,
};
}
export function parseNodeLocationGetParams(params: unknown): NodeLocationGetParams | null {
if (!params || typeof params !== 'object') {
return null;
}
const p = params as Record<string, unknown>;
if (typeof p.connectionId !== 'string' || !p.connectionId.trim()) {
return null;
}
return {
connectionId: p.connectionId,
};
}
export function makeResponse(id: number, result: unknown): GatewayResponse {
return { id, result };
}