@alteriom/mqtt-schema 0.3.2 → 0.4.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +7 -1
- package/dist/cjs/generated/types.d.ts +46 -1
- package/dist/cjs/generated/types.js +18 -0
- package/dist/cjs/schema_data.d.ts +169 -0
- package/dist/cjs/schema_data.js +210 -2
- package/dist/cjs/schemas/mesh_alert.schema.json +66 -0
- package/dist/cjs/schemas/mesh_node_list.schema.json +50 -0
- package/dist/cjs/schemas/mesh_topology.schema.json +54 -0
- package/dist/cjs/schemas/mqtt_v1_bundle.json +4 -1
- package/dist/cjs/validators.d.ts +3 -0
- package/dist/cjs/validators.js +16 -1
- package/dist/esm/generated/types.js +15 -0
- package/dist/esm/schema_data.js +209 -1
- package/dist/esm/schemas/mesh_alert.schema.json +66 -0
- package/dist/esm/schemas/mesh_node_list.schema.json +50 -0
- package/dist/esm/schemas/mesh_topology.schema.json +54 -0
- package/dist/esm/schemas/mqtt_v1_bundle.json +4 -1
- package/dist/esm/validators.js +17 -2
- package/package.json +1 -5
- package/schemas/mesh_alert.schema.json +66 -0
- package/schemas/mesh_node_list.schema.json +50 -0
- package/schemas/mesh_topology.schema.json +54 -0
- package/schemas/mqtt_v1_bundle.json +4 -1
@@ -0,0 +1,54 @@
|
|
1
|
+
{
|
2
|
+
"$schema": "https://json-schema.org/draft/2020-12/schema",
|
3
|
+
"$id": "https://schemas.alteriom.io/mqtt/v1/mesh_topology.schema.json",
|
4
|
+
"title": "Mesh Network Topology v1",
|
5
|
+
"allOf": [{"$ref": "envelope.schema.json"}],
|
6
|
+
"type": "object",
|
7
|
+
"required": ["connections"],
|
8
|
+
"properties": {
|
9
|
+
"connections": {
|
10
|
+
"type": "array",
|
11
|
+
"items": {
|
12
|
+
"type": "object",
|
13
|
+
"required": ["from_node", "to_node"],
|
14
|
+
"properties": {
|
15
|
+
"from_node": {
|
16
|
+
"type": "string",
|
17
|
+
"description": "Source node ID"
|
18
|
+
},
|
19
|
+
"to_node": {
|
20
|
+
"type": "string",
|
21
|
+
"description": "Destination node ID"
|
22
|
+
},
|
23
|
+
"link_quality": {
|
24
|
+
"type": "number",
|
25
|
+
"minimum": 0,
|
26
|
+
"maximum": 1,
|
27
|
+
"description": "Link quality score (0-1)"
|
28
|
+
},
|
29
|
+
"latency_ms": {
|
30
|
+
"type": "integer",
|
31
|
+
"minimum": 0,
|
32
|
+
"description": "Link latency in milliseconds"
|
33
|
+
},
|
34
|
+
"hop_count": {
|
35
|
+
"type": "integer",
|
36
|
+
"minimum": 1,
|
37
|
+
"description": "Number of hops in path"
|
38
|
+
}
|
39
|
+
},
|
40
|
+
"additionalProperties": true
|
41
|
+
}
|
42
|
+
},
|
43
|
+
"root_node": {
|
44
|
+
"type": "string",
|
45
|
+
"description": "Root node ID (gateway/bridge)"
|
46
|
+
},
|
47
|
+
"total_connections": {
|
48
|
+
"type": "integer",
|
49
|
+
"minimum": 0,
|
50
|
+
"description": "Total number of connections"
|
51
|
+
}
|
52
|
+
},
|
53
|
+
"additionalProperties": true
|
54
|
+
}
|
@@ -9,6 +9,9 @@
|
|
9
9
|
"gateway_info": "gateway_info.schema.json",
|
10
10
|
"gateway_metrics": "gateway_metrics.schema.json",
|
11
11
|
"firmware_status": "firmware_status.schema.json",
|
12
|
-
"control_response": "control_response.schema.json"
|
12
|
+
"control_response": "control_response.schema.json",
|
13
|
+
"mesh_node_list": "mesh_node_list.schema.json",
|
14
|
+
"mesh_topology": "mesh_topology.schema.json",
|
15
|
+
"mesh_alert": "mesh_alert.schema.json"
|
13
16
|
}
|
14
17
|
}
|
package/dist/cjs/validators.d.ts
CHANGED
@@ -14,6 +14,9 @@ export declare const validators: {
|
|
14
14
|
gatewayMetrics: (d: unknown) => ValidationResult;
|
15
15
|
firmwareStatus: (d: unknown) => ValidationResult;
|
16
16
|
controlResponse: (d: unknown) => ValidationResult;
|
17
|
+
meshNodeList: (d: unknown) => ValidationResult;
|
18
|
+
meshTopology: (d: unknown) => ValidationResult;
|
19
|
+
meshAlert: (d: unknown) => ValidationResult;
|
17
20
|
};
|
18
21
|
export type ValidatorName = keyof typeof validators;
|
19
22
|
export declare function validateMessage(kind: ValidatorName, data: unknown): ValidationResult;
|
package/dist/cjs/validators.js
CHANGED
@@ -20,6 +20,9 @@ const gatewayInfo = schema_data_js_1.gateway_info_schema;
|
|
20
20
|
const gatewayMetrics = schema_data_js_1.gateway_metrics_schema;
|
21
21
|
const firmwareStatus = schema_data_js_1.firmware_status_schema;
|
22
22
|
const controlResponse = schema_data_js_1.control_response_schema;
|
23
|
+
const meshNodeList = schema_data_js_1.mesh_node_list_schema;
|
24
|
+
const meshTopology = schema_data_js_1.mesh_topology_schema;
|
25
|
+
const meshAlert = schema_data_js_1.mesh_alert_schema;
|
23
26
|
// Lazy singleton Ajv instance so consumers can optionally supply their own if needed.
|
24
27
|
let _ajv = null;
|
25
28
|
function getAjv(opts) {
|
@@ -51,6 +54,9 @@ const gatewayInfoValidate = ajv.compile(gatewayInfo);
|
|
51
54
|
const gatewayMetricsValidate = ajv.compile(gatewayMetrics);
|
52
55
|
const firmwareStatusValidate = ajv.compile(firmwareStatus);
|
53
56
|
const controlResponseValidate = ajv.compile(controlResponse);
|
57
|
+
const meshNodeListValidate = ajv.compile(meshNodeList);
|
58
|
+
const meshTopologyValidate = ajv.compile(meshTopology);
|
59
|
+
const meshAlertValidate = ajv.compile(meshAlert);
|
54
60
|
exports.validators = {
|
55
61
|
sensorData: (d) => toResult(sensorDataValidate, d),
|
56
62
|
sensorHeartbeat: (d) => toResult(sensorHeartbeatValidate, d),
|
@@ -58,7 +64,10 @@ exports.validators = {
|
|
58
64
|
gatewayInfo: (d) => toResult(gatewayInfoValidate, d),
|
59
65
|
gatewayMetrics: (d) => toResult(gatewayMetricsValidate, d),
|
60
66
|
firmwareStatus: (d) => toResult(firmwareStatusValidate, d),
|
61
|
-
controlResponse: (d) => toResult(controlResponseValidate, d)
|
67
|
+
controlResponse: (d) => toResult(controlResponseValidate, d),
|
68
|
+
meshNodeList: (d) => toResult(meshNodeListValidate, d),
|
69
|
+
meshTopology: (d) => toResult(meshTopologyValidate, d),
|
70
|
+
meshAlert: (d) => toResult(meshAlertValidate, d)
|
62
71
|
};
|
63
72
|
function validateMessage(kind, data) {
|
64
73
|
return exports.validators[kind](data);
|
@@ -71,6 +80,12 @@ function classifyAndValidate(data) {
|
|
71
80
|
return { kind: 'gatewayMetrics', result: exports.validators.gatewayMetrics(data) };
|
72
81
|
if (data.sensors)
|
73
82
|
return { kind: 'sensorData', result: exports.validators.sensorData(data) };
|
83
|
+
if (Array.isArray(data.nodes))
|
84
|
+
return { kind: 'meshNodeList', result: exports.validators.meshNodeList(data) };
|
85
|
+
if (Array.isArray(data.connections))
|
86
|
+
return { kind: 'meshTopology', result: exports.validators.meshTopology(data) };
|
87
|
+
if (Array.isArray(data.alerts))
|
88
|
+
return { kind: 'meshAlert', result: exports.validators.meshAlert(data) };
|
74
89
|
if (data.progress_pct !== undefined || (data.status && ['pending', 'downloading', 'flashing', 'verifying', 'rebooting', 'completed', 'failed'].includes(data.status)))
|
75
90
|
return { kind: 'firmwareStatus', result: exports.validators.firmwareStatus(data) };
|
76
91
|
if (data.status && ['online', 'offline', 'updating', 'error'].includes(data.status) && data.device_type === 'sensor')
|
@@ -26,11 +26,26 @@ export function isFirmwareStatusMessage(msg) {
|
|
26
26
|
export function isControlResponseMessage(msg) {
|
27
27
|
return msg && msg.schema_version === 1 && (msg.status === 'ok' || msg.status === 'error') && 'timestamp' in msg;
|
28
28
|
}
|
29
|
+
export function isMeshNodeListMessage(msg) {
|
30
|
+
return msg && msg.schema_version === 1 && msg.device_type === 'gateway' && Array.isArray(msg.nodes);
|
31
|
+
}
|
32
|
+
export function isMeshTopologyMessage(msg) {
|
33
|
+
return msg && msg.schema_version === 1 && msg.device_type === 'gateway' && Array.isArray(msg.connections);
|
34
|
+
}
|
35
|
+
export function isMeshAlertMessage(msg) {
|
36
|
+
return msg && msg.schema_version === 1 && msg.device_type === 'gateway' && Array.isArray(msg.alerts);
|
37
|
+
}
|
29
38
|
export function classifyMessage(msg) {
|
30
39
|
if (isSensorDataMessage(msg))
|
31
40
|
return msg;
|
32
41
|
if (isGatewayMetricsMessage(msg))
|
33
42
|
return msg;
|
43
|
+
if (isMeshNodeListMessage(msg))
|
44
|
+
return msg;
|
45
|
+
if (isMeshTopologyMessage(msg))
|
46
|
+
return msg;
|
47
|
+
if (isMeshAlertMessage(msg))
|
48
|
+
return msg;
|
34
49
|
if (isSensorStatusMessage(msg))
|
35
50
|
return msg;
|
36
51
|
if (isGatewayInfoMessage(msg))
|
package/dist/esm/schema_data.js
CHANGED
@@ -383,6 +383,211 @@ export const control_response_schema = {
|
|
383
383
|
},
|
384
384
|
"additionalProperties": true
|
385
385
|
};
|
386
|
+
export const mesh_node_list_schema = {
|
387
|
+
"$schema": "https://json-schema.org/draft/2020-12/schema",
|
388
|
+
"$id": "https://schemas.alteriom.io/mqtt/v1/mesh_node_list.schema.json",
|
389
|
+
"title": "Mesh Node List v1",
|
390
|
+
"allOf": [
|
391
|
+
{
|
392
|
+
"$ref": "envelope.schema.json"
|
393
|
+
}
|
394
|
+
],
|
395
|
+
"type": "object",
|
396
|
+
"required": [
|
397
|
+
"nodes"
|
398
|
+
],
|
399
|
+
"properties": {
|
400
|
+
"nodes": {
|
401
|
+
"type": "array",
|
402
|
+
"items": {
|
403
|
+
"type": "object",
|
404
|
+
"required": [
|
405
|
+
"node_id"
|
406
|
+
],
|
407
|
+
"properties": {
|
408
|
+
"node_id": {
|
409
|
+
"type": "string",
|
410
|
+
"description": "Unique node identifier"
|
411
|
+
},
|
412
|
+
"status": {
|
413
|
+
"type": "string",
|
414
|
+
"enum": [
|
415
|
+
"online",
|
416
|
+
"offline",
|
417
|
+
"unreachable"
|
418
|
+
],
|
419
|
+
"description": "Current node status"
|
420
|
+
},
|
421
|
+
"last_seen": {
|
422
|
+
"type": "string",
|
423
|
+
"format": "date-time",
|
424
|
+
"description": "Last communication timestamp"
|
425
|
+
},
|
426
|
+
"signal_strength": {
|
427
|
+
"type": "integer",
|
428
|
+
"minimum": -200,
|
429
|
+
"maximum": 0,
|
430
|
+
"description": "Signal strength in dBm"
|
431
|
+
}
|
432
|
+
},
|
433
|
+
"additionalProperties": true
|
434
|
+
}
|
435
|
+
},
|
436
|
+
"node_count": {
|
437
|
+
"type": "integer",
|
438
|
+
"minimum": 0,
|
439
|
+
"description": "Total number of nodes"
|
440
|
+
},
|
441
|
+
"mesh_id": {
|
442
|
+
"type": "string",
|
443
|
+
"description": "Mesh network identifier"
|
444
|
+
}
|
445
|
+
},
|
446
|
+
"additionalProperties": true
|
447
|
+
};
|
448
|
+
export const mesh_topology_schema = {
|
449
|
+
"$schema": "https://json-schema.org/draft/2020-12/schema",
|
450
|
+
"$id": "https://schemas.alteriom.io/mqtt/v1/mesh_topology.schema.json",
|
451
|
+
"title": "Mesh Network Topology v1",
|
452
|
+
"allOf": [
|
453
|
+
{
|
454
|
+
"$ref": "envelope.schema.json"
|
455
|
+
}
|
456
|
+
],
|
457
|
+
"type": "object",
|
458
|
+
"required": [
|
459
|
+
"connections"
|
460
|
+
],
|
461
|
+
"properties": {
|
462
|
+
"connections": {
|
463
|
+
"type": "array",
|
464
|
+
"items": {
|
465
|
+
"type": "object",
|
466
|
+
"required": [
|
467
|
+
"from_node",
|
468
|
+
"to_node"
|
469
|
+
],
|
470
|
+
"properties": {
|
471
|
+
"from_node": {
|
472
|
+
"type": "string",
|
473
|
+
"description": "Source node ID"
|
474
|
+
},
|
475
|
+
"to_node": {
|
476
|
+
"type": "string",
|
477
|
+
"description": "Destination node ID"
|
478
|
+
},
|
479
|
+
"link_quality": {
|
480
|
+
"type": "number",
|
481
|
+
"minimum": 0,
|
482
|
+
"maximum": 1,
|
483
|
+
"description": "Link quality score (0-1)"
|
484
|
+
},
|
485
|
+
"latency_ms": {
|
486
|
+
"type": "integer",
|
487
|
+
"minimum": 0,
|
488
|
+
"description": "Link latency in milliseconds"
|
489
|
+
},
|
490
|
+
"hop_count": {
|
491
|
+
"type": "integer",
|
492
|
+
"minimum": 1,
|
493
|
+
"description": "Number of hops in path"
|
494
|
+
}
|
495
|
+
},
|
496
|
+
"additionalProperties": true
|
497
|
+
}
|
498
|
+
},
|
499
|
+
"root_node": {
|
500
|
+
"type": "string",
|
501
|
+
"description": "Root node ID (gateway/bridge)"
|
502
|
+
},
|
503
|
+
"total_connections": {
|
504
|
+
"type": "integer",
|
505
|
+
"minimum": 0,
|
506
|
+
"description": "Total number of connections"
|
507
|
+
}
|
508
|
+
},
|
509
|
+
"additionalProperties": true
|
510
|
+
};
|
511
|
+
export const mesh_alert_schema = {
|
512
|
+
"$schema": "https://json-schema.org/draft/2020-12/schema",
|
513
|
+
"$id": "https://schemas.alteriom.io/mqtt/v1/mesh_alert.schema.json",
|
514
|
+
"title": "Mesh Network Alert v1",
|
515
|
+
"allOf": [
|
516
|
+
{
|
517
|
+
"$ref": "envelope.schema.json"
|
518
|
+
}
|
519
|
+
],
|
520
|
+
"type": "object",
|
521
|
+
"required": [
|
522
|
+
"alerts"
|
523
|
+
],
|
524
|
+
"properties": {
|
525
|
+
"alerts": {
|
526
|
+
"type": "array",
|
527
|
+
"items": {
|
528
|
+
"type": "object",
|
529
|
+
"required": [
|
530
|
+
"alert_type",
|
531
|
+
"severity",
|
532
|
+
"message"
|
533
|
+
],
|
534
|
+
"properties": {
|
535
|
+
"alert_type": {
|
536
|
+
"type": "string",
|
537
|
+
"enum": [
|
538
|
+
"low_memory",
|
539
|
+
"node_offline",
|
540
|
+
"connection_lost",
|
541
|
+
"high_latency",
|
542
|
+
"packet_loss",
|
543
|
+
"firmware_mismatch",
|
544
|
+
"configuration_error",
|
545
|
+
"security_warning",
|
546
|
+
"other"
|
547
|
+
],
|
548
|
+
"description": "Type of alert"
|
549
|
+
},
|
550
|
+
"severity": {
|
551
|
+
"type": "string",
|
552
|
+
"enum": [
|
553
|
+
"critical",
|
554
|
+
"warning",
|
555
|
+
"info"
|
556
|
+
],
|
557
|
+
"description": "Alert severity level"
|
558
|
+
},
|
559
|
+
"message": {
|
560
|
+
"type": "string",
|
561
|
+
"description": "Human-readable alert message"
|
562
|
+
},
|
563
|
+
"node_id": {
|
564
|
+
"type": "string",
|
565
|
+
"description": "Related node ID (if applicable)"
|
566
|
+
},
|
567
|
+
"metric_value": {
|
568
|
+
"type": "number",
|
569
|
+
"description": "Related metric value (if applicable)"
|
570
|
+
},
|
571
|
+
"threshold": {
|
572
|
+
"type": "number",
|
573
|
+
"description": "Threshold that triggered alert"
|
574
|
+
},
|
575
|
+
"alert_id": {
|
576
|
+
"type": "string",
|
577
|
+
"description": "Unique alert identifier"
|
578
|
+
}
|
579
|
+
},
|
580
|
+
"additionalProperties": true
|
581
|
+
}
|
582
|
+
},
|
583
|
+
"alert_count": {
|
584
|
+
"type": "integer",
|
585
|
+
"minimum": 0,
|
586
|
+
"description": "Total number of active alerts"
|
587
|
+
}
|
588
|
+
},
|
589
|
+
"additionalProperties": true
|
590
|
+
};
|
386
591
|
export const mqtt_v1_bundle_json = {
|
387
592
|
"$comment": "Convenience bundle referencing all v1 schema artifact filenames for tooling discovery.",
|
388
593
|
"version": 1,
|
@@ -394,7 +599,10 @@ export const mqtt_v1_bundle_json = {
|
|
394
599
|
"gateway_info": "gateway_info.schema.json",
|
395
600
|
"gateway_metrics": "gateway_metrics.schema.json",
|
396
601
|
"firmware_status": "firmware_status.schema.json",
|
397
|
-
"control_response": "control_response.schema.json"
|
602
|
+
"control_response": "control_response.schema.json",
|
603
|
+
"mesh_node_list": "mesh_node_list.schema.json",
|
604
|
+
"mesh_topology": "mesh_topology.schema.json",
|
605
|
+
"mesh_alert": "mesh_alert.schema.json"
|
398
606
|
}
|
399
607
|
};
|
400
608
|
export const ota_ota_manifest_schema = {
|
@@ -0,0 +1,66 @@
|
|
1
|
+
{
|
2
|
+
"$schema": "https://json-schema.org/draft/2020-12/schema",
|
3
|
+
"$id": "https://schemas.alteriom.io/mqtt/v1/mesh_alert.schema.json",
|
4
|
+
"title": "Mesh Network Alert v1",
|
5
|
+
"allOf": [{"$ref": "envelope.schema.json"}],
|
6
|
+
"type": "object",
|
7
|
+
"required": ["alerts"],
|
8
|
+
"properties": {
|
9
|
+
"alerts": {
|
10
|
+
"type": "array",
|
11
|
+
"items": {
|
12
|
+
"type": "object",
|
13
|
+
"required": ["alert_type", "severity", "message"],
|
14
|
+
"properties": {
|
15
|
+
"alert_type": {
|
16
|
+
"type": "string",
|
17
|
+
"enum": [
|
18
|
+
"low_memory",
|
19
|
+
"node_offline",
|
20
|
+
"connection_lost",
|
21
|
+
"high_latency",
|
22
|
+
"packet_loss",
|
23
|
+
"firmware_mismatch",
|
24
|
+
"configuration_error",
|
25
|
+
"security_warning",
|
26
|
+
"other"
|
27
|
+
],
|
28
|
+
"description": "Type of alert"
|
29
|
+
},
|
30
|
+
"severity": {
|
31
|
+
"type": "string",
|
32
|
+
"enum": ["critical", "warning", "info"],
|
33
|
+
"description": "Alert severity level"
|
34
|
+
},
|
35
|
+
"message": {
|
36
|
+
"type": "string",
|
37
|
+
"description": "Human-readable alert message"
|
38
|
+
},
|
39
|
+
"node_id": {
|
40
|
+
"type": "string",
|
41
|
+
"description": "Related node ID (if applicable)"
|
42
|
+
},
|
43
|
+
"metric_value": {
|
44
|
+
"type": "number",
|
45
|
+
"description": "Related metric value (if applicable)"
|
46
|
+
},
|
47
|
+
"threshold": {
|
48
|
+
"type": "number",
|
49
|
+
"description": "Threshold that triggered alert"
|
50
|
+
},
|
51
|
+
"alert_id": {
|
52
|
+
"type": "string",
|
53
|
+
"description": "Unique alert identifier"
|
54
|
+
}
|
55
|
+
},
|
56
|
+
"additionalProperties": true
|
57
|
+
}
|
58
|
+
},
|
59
|
+
"alert_count": {
|
60
|
+
"type": "integer",
|
61
|
+
"minimum": 0,
|
62
|
+
"description": "Total number of active alerts"
|
63
|
+
}
|
64
|
+
},
|
65
|
+
"additionalProperties": true
|
66
|
+
}
|
@@ -0,0 +1,50 @@
|
|
1
|
+
{
|
2
|
+
"$schema": "https://json-schema.org/draft/2020-12/schema",
|
3
|
+
"$id": "https://schemas.alteriom.io/mqtt/v1/mesh_node_list.schema.json",
|
4
|
+
"title": "Mesh Node List v1",
|
5
|
+
"allOf": [{"$ref": "envelope.schema.json"}],
|
6
|
+
"type": "object",
|
7
|
+
"required": ["nodes"],
|
8
|
+
"properties": {
|
9
|
+
"nodes": {
|
10
|
+
"type": "array",
|
11
|
+
"items": {
|
12
|
+
"type": "object",
|
13
|
+
"required": ["node_id"],
|
14
|
+
"properties": {
|
15
|
+
"node_id": {
|
16
|
+
"type": "string",
|
17
|
+
"description": "Unique node identifier"
|
18
|
+
},
|
19
|
+
"status": {
|
20
|
+
"type": "string",
|
21
|
+
"enum": ["online", "offline", "unreachable"],
|
22
|
+
"description": "Current node status"
|
23
|
+
},
|
24
|
+
"last_seen": {
|
25
|
+
"type": "string",
|
26
|
+
"format": "date-time",
|
27
|
+
"description": "Last communication timestamp"
|
28
|
+
},
|
29
|
+
"signal_strength": {
|
30
|
+
"type": "integer",
|
31
|
+
"minimum": -200,
|
32
|
+
"maximum": 0,
|
33
|
+
"description": "Signal strength in dBm"
|
34
|
+
}
|
35
|
+
},
|
36
|
+
"additionalProperties": true
|
37
|
+
}
|
38
|
+
},
|
39
|
+
"node_count": {
|
40
|
+
"type": "integer",
|
41
|
+
"minimum": 0,
|
42
|
+
"description": "Total number of nodes"
|
43
|
+
},
|
44
|
+
"mesh_id": {
|
45
|
+
"type": "string",
|
46
|
+
"description": "Mesh network identifier"
|
47
|
+
}
|
48
|
+
},
|
49
|
+
"additionalProperties": true
|
50
|
+
}
|
@@ -0,0 +1,54 @@
|
|
1
|
+
{
|
2
|
+
"$schema": "https://json-schema.org/draft/2020-12/schema",
|
3
|
+
"$id": "https://schemas.alteriom.io/mqtt/v1/mesh_topology.schema.json",
|
4
|
+
"title": "Mesh Network Topology v1",
|
5
|
+
"allOf": [{"$ref": "envelope.schema.json"}],
|
6
|
+
"type": "object",
|
7
|
+
"required": ["connections"],
|
8
|
+
"properties": {
|
9
|
+
"connections": {
|
10
|
+
"type": "array",
|
11
|
+
"items": {
|
12
|
+
"type": "object",
|
13
|
+
"required": ["from_node", "to_node"],
|
14
|
+
"properties": {
|
15
|
+
"from_node": {
|
16
|
+
"type": "string",
|
17
|
+
"description": "Source node ID"
|
18
|
+
},
|
19
|
+
"to_node": {
|
20
|
+
"type": "string",
|
21
|
+
"description": "Destination node ID"
|
22
|
+
},
|
23
|
+
"link_quality": {
|
24
|
+
"type": "number",
|
25
|
+
"minimum": 0,
|
26
|
+
"maximum": 1,
|
27
|
+
"description": "Link quality score (0-1)"
|
28
|
+
},
|
29
|
+
"latency_ms": {
|
30
|
+
"type": "integer",
|
31
|
+
"minimum": 0,
|
32
|
+
"description": "Link latency in milliseconds"
|
33
|
+
},
|
34
|
+
"hop_count": {
|
35
|
+
"type": "integer",
|
36
|
+
"minimum": 1,
|
37
|
+
"description": "Number of hops in path"
|
38
|
+
}
|
39
|
+
},
|
40
|
+
"additionalProperties": true
|
41
|
+
}
|
42
|
+
},
|
43
|
+
"root_node": {
|
44
|
+
"type": "string",
|
45
|
+
"description": "Root node ID (gateway/bridge)"
|
46
|
+
},
|
47
|
+
"total_connections": {
|
48
|
+
"type": "integer",
|
49
|
+
"minimum": 0,
|
50
|
+
"description": "Total number of connections"
|
51
|
+
}
|
52
|
+
},
|
53
|
+
"additionalProperties": true
|
54
|
+
}
|
@@ -9,6 +9,9 @@
|
|
9
9
|
"gateway_info": "gateway_info.schema.json",
|
10
10
|
"gateway_metrics": "gateway_metrics.schema.json",
|
11
11
|
"firmware_status": "firmware_status.schema.json",
|
12
|
-
"control_response": "control_response.schema.json"
|
12
|
+
"control_response": "control_response.schema.json",
|
13
|
+
"mesh_node_list": "mesh_node_list.schema.json",
|
14
|
+
"mesh_topology": "mesh_topology.schema.json",
|
15
|
+
"mesh_alert": "mesh_alert.schema.json"
|
13
16
|
}
|
14
17
|
}
|
package/dist/esm/validators.js
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
import Ajv from 'ajv/dist/2020.js';
|
2
2
|
import addFormats from 'ajv-formats';
|
3
3
|
// Schemas embedded via generated schema_data.ts (copy-schemas.cjs) to avoid filesystem dependency
|
4
|
-
import { envelope_schema, sensor_data_schema, sensor_heartbeat_schema, sensor_status_schema, gateway_info_schema, gateway_metrics_schema, firmware_status_schema, control_response_schema } from './schema_data.js';
|
4
|
+
import { envelope_schema, sensor_data_schema, sensor_heartbeat_schema, sensor_status_schema, gateway_info_schema, gateway_metrics_schema, firmware_status_schema, control_response_schema, mesh_node_list_schema, mesh_topology_schema, mesh_alert_schema } from './schema_data.js';
|
5
5
|
// Load JSON schemas via createRequire so it works in both CJS and ESM builds without import assertions.
|
6
6
|
// Bind embedded schema objects for Ajv consumption
|
7
7
|
const envelope = envelope_schema;
|
@@ -12,6 +12,9 @@ const gatewayInfo = gateway_info_schema;
|
|
12
12
|
const gatewayMetrics = gateway_metrics_schema;
|
13
13
|
const firmwareStatus = firmware_status_schema;
|
14
14
|
const controlResponse = control_response_schema;
|
15
|
+
const meshNodeList = mesh_node_list_schema;
|
16
|
+
const meshTopology = mesh_topology_schema;
|
17
|
+
const meshAlert = mesh_alert_schema;
|
15
18
|
// Lazy singleton Ajv instance so consumers can optionally supply their own if needed.
|
16
19
|
let _ajv = null;
|
17
20
|
function getAjv(opts) {
|
@@ -43,6 +46,9 @@ const gatewayInfoValidate = ajv.compile(gatewayInfo);
|
|
43
46
|
const gatewayMetricsValidate = ajv.compile(gatewayMetrics);
|
44
47
|
const firmwareStatusValidate = ajv.compile(firmwareStatus);
|
45
48
|
const controlResponseValidate = ajv.compile(controlResponse);
|
49
|
+
const meshNodeListValidate = ajv.compile(meshNodeList);
|
50
|
+
const meshTopologyValidate = ajv.compile(meshTopology);
|
51
|
+
const meshAlertValidate = ajv.compile(meshAlert);
|
46
52
|
export const validators = {
|
47
53
|
sensorData: (d) => toResult(sensorDataValidate, d),
|
48
54
|
sensorHeartbeat: (d) => toResult(sensorHeartbeatValidate, d),
|
@@ -50,7 +56,10 @@ export const validators = {
|
|
50
56
|
gatewayInfo: (d) => toResult(gatewayInfoValidate, d),
|
51
57
|
gatewayMetrics: (d) => toResult(gatewayMetricsValidate, d),
|
52
58
|
firmwareStatus: (d) => toResult(firmwareStatusValidate, d),
|
53
|
-
controlResponse: (d) => toResult(controlResponseValidate, d)
|
59
|
+
controlResponse: (d) => toResult(controlResponseValidate, d),
|
60
|
+
meshNodeList: (d) => toResult(meshNodeListValidate, d),
|
61
|
+
meshTopology: (d) => toResult(meshTopologyValidate, d),
|
62
|
+
meshAlert: (d) => toResult(meshAlertValidate, d)
|
54
63
|
};
|
55
64
|
export function validateMessage(kind, data) {
|
56
65
|
return validators[kind](data);
|
@@ -63,6 +72,12 @@ export function classifyAndValidate(data) {
|
|
63
72
|
return { kind: 'gatewayMetrics', result: validators.gatewayMetrics(data) };
|
64
73
|
if (data.sensors)
|
65
74
|
return { kind: 'sensorData', result: validators.sensorData(data) };
|
75
|
+
if (Array.isArray(data.nodes))
|
76
|
+
return { kind: 'meshNodeList', result: validators.meshNodeList(data) };
|
77
|
+
if (Array.isArray(data.connections))
|
78
|
+
return { kind: 'meshTopology', result: validators.meshTopology(data) };
|
79
|
+
if (Array.isArray(data.alerts))
|
80
|
+
return { kind: 'meshAlert', result: validators.meshAlert(data) };
|
66
81
|
if (data.progress_pct !== undefined || (data.status && ['pending', 'downloading', 'flashing', 'verifying', 'rebooting', 'completed', 'failed'].includes(data.status)))
|
67
82
|
return { kind: 'firmwareStatus', result: validators.firmwareStatus(data) };
|
68
83
|
if (data.status && ['online', 'offline', 'updating', 'error'].includes(data.status) && data.device_type === 'sensor')
|
package/package.json
CHANGED
@@ -1,6 +1,6 @@
|
|
1
1
|
{
|
2
2
|
"name": "@alteriom/mqtt-schema",
|
3
|
-
"version": "0.
|
3
|
+
"version": "0.4.0",
|
4
4
|
"description": "Alteriom MQTT v1 schemas, TypeScript types, and validation helpers for web integration",
|
5
5
|
"license": "MIT",
|
6
6
|
"author": "Alteriom Development Team",
|
@@ -94,7 +94,6 @@
|
|
94
94
|
"build": "npm run build:cjs && npm run build:esm && node scripts/copy-schemas.cjs",
|
95
95
|
"clean": "rimraf dist schemas",
|
96
96
|
"prepare": "npm run build",
|
97
|
-
|
98
97
|
"// Testing & Validation": "====================",
|
99
98
|
"lint": "echo 'No linter configured - consider adding ESLint for future releases'",
|
100
99
|
"test": "node test/validate-fixtures.cjs",
|
@@ -103,17 +102,14 @@
|
|
103
102
|
"verify:release": "node scripts/check-release-integrity.cjs",
|
104
103
|
"verify": "npm run verify:schemas && npm run verify:release && npm test",
|
105
104
|
"verify:all": "node scripts/verify_all.cjs",
|
106
|
-
|
107
105
|
"// Release Management": "====================",
|
108
106
|
"release:prepare": "node scripts/release-prepare.cjs",
|
109
107
|
"wiki:generate": "node scripts/generate-wiki.cjs",
|
110
|
-
|
111
108
|
"// Repository Metadata": "====================",
|
112
109
|
"metadata:report": "alteriom-metadata report --org-tag alteriom || echo 'metadata report failed'",
|
113
110
|
"metadata:validate": "alteriom-metadata validate --org-tag alteriom || echo 'metadata validate failed'",
|
114
111
|
"metadata:apply": "alteriom-metadata apply --org-tag alteriom",
|
115
112
|
"metadata:apply:dry": "alteriom-metadata dry-run --org-tag alteriom",
|
116
|
-
|
117
113
|
"// Legacy Aliases": "====================",
|
118
114
|
"validate:ota": "npm run test:ota"
|
119
115
|
},
|