49 lines
1.9 KiB
JavaScript
49 lines
1.9 KiB
JavaScript
export const TELEMETRY_READINGS_MAX_ITEMS = 128;
|
|
export const TELEMETRY_READINGS_MAX_BYTES = 128 * 1024;
|
|
|
|
const READING_KEYS = new Set(["id", "label", "value", "unit", "observedAt"]);
|
|
const READING_ID = /^[a-z][a-z0-9._:-]{1,127}$/;
|
|
|
|
/**
|
|
* Validate the provider-neutral bounded telemetry collection accepted inside
|
|
* one current-position fact. Provider-specific payloads, raw sensor objects
|
|
* and arbitrary recursive JSON are deliberately excluded.
|
|
*/
|
|
export function isBoundedTelemetryReadings(value) {
|
|
if (!Array.isArray(value) || value.length > TELEMETRY_READINGS_MAX_ITEMS) return false;
|
|
let encoded;
|
|
try {
|
|
encoded = new TextEncoder().encode(JSON.stringify(value));
|
|
} catch {
|
|
return false;
|
|
}
|
|
if (encoded.byteLength > TELEMETRY_READINGS_MAX_BYTES) return false;
|
|
|
|
const ids = new Set();
|
|
for (const reading of value) {
|
|
if (!isPlainObject(reading) || Object.keys(reading).some((key) => !READING_KEYS.has(key))) return false;
|
|
if (typeof reading.id !== "string" || !READING_ID.test(reading.id) || ids.has(reading.id)) return false;
|
|
ids.add(reading.id);
|
|
if (typeof reading.label !== "string" || !reading.label.trim() || reading.label.length > 160) return false;
|
|
if (!isScalar(reading.value)) return false;
|
|
if (typeof reading.value === "string" && reading.value.length > 512) return false;
|
|
if (reading.unit !== undefined && (typeof reading.unit !== "string" || reading.unit.length > 32)) return false;
|
|
if (reading.observedAt !== undefined && !isIsoTimestamp(reading.observedAt)) return false;
|
|
}
|
|
return true;
|
|
}
|
|
|
|
function isScalar(value) {
|
|
return typeof value === "string"
|
|
|| typeof value === "boolean"
|
|
|| (typeof value === "number" && Number.isFinite(value));
|
|
}
|
|
|
|
function isIsoTimestamp(value) {
|
|
return typeof value === "string" && !Number.isNaN(Date.parse(value));
|
|
}
|
|
|
|
function isPlainObject(value) {
|
|
return Boolean(value) && typeof value === "object" && !Array.isArray(value);
|
|
}
|