@alteriom/mqtt-schema 0.2.0 → 0.3.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/CHANGELOG.md +7 -0
- package/README.md +252 -174
- package/dist/cjs/schemas/control_response.schema.json +15 -15
- package/dist/cjs/schemas/envelope.schema.json +16 -16
- package/dist/cjs/schemas/firmware_status.schema.json +17 -17
- package/dist/cjs/schemas/gateway_info.schema.json +21 -21
- package/dist/cjs/schemas/gateway_metrics.schema.json +26 -26
- package/dist/cjs/schemas/mqtt_v1_bundle.json +14 -14
- package/dist/cjs/schemas/sensor_data.schema.json +33 -33
- package/dist/cjs/schemas/sensor_heartbeat.schema.json +14 -14
- package/dist/cjs/schemas/sensor_status.schema.json +14 -14
- package/dist/cjs/schemas/validation_rules.md +44 -44
- package/dist/esm/schemas/control_response.schema.json +15 -15
- package/dist/esm/schemas/envelope.schema.json +16 -16
- package/dist/esm/schemas/firmware_status.schema.json +17 -17
- package/dist/esm/schemas/gateway_info.schema.json +21 -21
- package/dist/esm/schemas/gateway_metrics.schema.json +26 -26
- package/dist/esm/schemas/mqtt_v1_bundle.json +14 -14
- package/dist/esm/schemas/sensor_data.schema.json +33 -33
- package/dist/esm/schemas/sensor_heartbeat.schema.json +14 -14
- package/dist/esm/schemas/sensor_status.schema.json +14 -14
- package/dist/esm/schemas/validation_rules.md +44 -44
- package/package.json +39 -7
- package/types/ota-manifest.d.ts +63 -0
@@ -1,44 +1,44 @@
|
|
1
|
-
# Validation Rules (Operational Layer)
|
2
|
-
|
3
|
-
This file captures dynamic / contextual validation that is OUTSIDE pure structural JSON Schema constraints.
|
4
|
-
|
5
|
-
## Timing & Rate
|
6
|
-
- Future timestamp drift: reject if > 5s ahead of server reference.
|
7
|
-
- Heartbeat interval recommended 30s; backend may rate-limit <10s.
|
8
|
-
- Sensor data soft min 30s unless negotiated high-frequency mode.
|
9
|
-
|
10
|
-
## Heartbeat Firmware Version Exception
|
11
|
-
- Only heartbeat topic may omit `firmware_version` when unchanged.
|
12
|
-
- All other topics require the field.
|
13
|
-
|
14
|
-
## Forbidden / Drop Conditions
|
15
|
-
| Reason | Condition |
|
16
|
-
|--------|----------|
|
17
|
-
| missing_fields | Required base fields absent (heartbeat firmware exception applied). |
|
18
|
-
| invalid_timestamp | Non-ISO 8601 / unparseable timestamp. |
|
19
|
-
| deprecated_keys | Usage of forbidden alias keys (f, fw, ver, version, u, up, rssi). |
|
20
|
-
| invalid_sensor_entry | Sensor object missing `value` key. |
|
21
|
-
| future_drift | Timestamp too far in future (>5s). |
|
22
|
-
| out_of_range | battery_level not 0-100 OR quality_score not 0-1. |
|
23
|
-
| invalid_numeric | Non-numeric where numeric expected. |
|
24
|
-
| spec_violation | Generic fallback after failed internal validation. |
|
25
|
-
|
26
|
-
## Sensor Object Semantics
|
27
|
-
- `value` REQUIRED.
|
28
|
-
- `unit`, `raw_value`, `calibrated_value`, `quality_score`, `name`, `location`, `additional_data` OPTIONAL.
|
29
|
-
- If `quality_score` present must be 0.0–1.0 inclusive.
|
30
|
-
|
31
|
-
## Metrics Constraints
|
32
|
-
- Gateway metrics MUST appear under `metrics` (never at top-level).
|
33
|
-
- Required minimal metric: `uptime_s`.
|
34
|
-
|
35
|
-
## Firmware Update Status
|
36
|
-
- `status` must be one of: pending, downloading, flashing, verifying, rebooting, completed, failed.
|
37
|
-
- `progress_pct` (if present) must be 0–100.
|
38
|
-
|
39
|
-
## Extensibility
|
40
|
-
- Unknown top-level keys tolerated (future evolution) except if they collide with any deprecated alias or reserved future keys announced in CHANGELOG.
|
41
|
-
|
42
|
-
## Versioning
|
43
|
-
- Current `schema_version`: 1
|
44
|
-
- Additions remain optional; breaking changes introduce new schema set.
|
1
|
+
# Validation Rules (Operational Layer)
|
2
|
+
|
3
|
+
This file captures dynamic / contextual validation that is OUTSIDE pure structural JSON Schema constraints.
|
4
|
+
|
5
|
+
## Timing & Rate
|
6
|
+
- Future timestamp drift: reject if > 5s ahead of server reference.
|
7
|
+
- Heartbeat interval recommended 30s; backend may rate-limit <10s.
|
8
|
+
- Sensor data soft min 30s unless negotiated high-frequency mode.
|
9
|
+
|
10
|
+
## Heartbeat Firmware Version Exception
|
11
|
+
- Only heartbeat topic may omit `firmware_version` when unchanged.
|
12
|
+
- All other topics require the field.
|
13
|
+
|
14
|
+
## Forbidden / Drop Conditions
|
15
|
+
| Reason | Condition |
|
16
|
+
|--------|----------|
|
17
|
+
| missing_fields | Required base fields absent (heartbeat firmware exception applied). |
|
18
|
+
| invalid_timestamp | Non-ISO 8601 / unparseable timestamp. |
|
19
|
+
| deprecated_keys | Usage of forbidden alias keys (f, fw, ver, version, u, up, rssi). |
|
20
|
+
| invalid_sensor_entry | Sensor object missing `value` key. |
|
21
|
+
| future_drift | Timestamp too far in future (>5s). |
|
22
|
+
| out_of_range | battery_level not 0-100 OR quality_score not 0-1. |
|
23
|
+
| invalid_numeric | Non-numeric where numeric expected. |
|
24
|
+
| spec_violation | Generic fallback after failed internal validation. |
|
25
|
+
|
26
|
+
## Sensor Object Semantics
|
27
|
+
- `value` REQUIRED.
|
28
|
+
- `unit`, `raw_value`, `calibrated_value`, `quality_score`, `name`, `location`, `additional_data` OPTIONAL.
|
29
|
+
- If `quality_score` present must be 0.0–1.0 inclusive.
|
30
|
+
|
31
|
+
## Metrics Constraints
|
32
|
+
- Gateway metrics MUST appear under `metrics` (never at top-level).
|
33
|
+
- Required minimal metric: `uptime_s`.
|
34
|
+
|
35
|
+
## Firmware Update Status
|
36
|
+
- `status` must be one of: pending, downloading, flashing, verifying, rebooting, completed, failed.
|
37
|
+
- `progress_pct` (if present) must be 0–100.
|
38
|
+
|
39
|
+
## Extensibility
|
40
|
+
- Unknown top-level keys tolerated (future evolution) except if they collide with any deprecated alias or reserved future keys announced in CHANGELOG.
|
41
|
+
|
42
|
+
## Versioning
|
43
|
+
- Current `schema_version`: 1
|
44
|
+
- Additions remain optional; breaking changes introduce new schema set.
|
package/package.json
CHANGED
@@ -1,16 +1,16 @@
|
|
1
1
|
{
|
2
2
|
"name": "@alteriom/mqtt-schema",
|
3
|
-
"version": "0.
|
3
|
+
"version": "0.3.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",
|
7
7
|
"repository": {
|
8
8
|
"type": "git",
|
9
|
-
"url": "https://github.com/Alteriom/alteriom-
|
9
|
+
"url": "https://github.com/Alteriom/alteriom-mqtt-schema.git"
|
10
10
|
},
|
11
|
-
"homepage": "https://github.com/Alteriom/alteriom-
|
11
|
+
"homepage": "https://github.com/Alteriom/alteriom-mqtt-schema#readme",
|
12
12
|
"bugs": {
|
13
|
-
"url": "https://github.com/Alteriom/alteriom-
|
13
|
+
"url": "https://github.com/Alteriom/alteriom-mqtt-schema/issues"
|
14
14
|
},
|
15
15
|
"type": "commonjs",
|
16
16
|
"main": "dist/cjs/index.js",
|
@@ -39,6 +39,13 @@
|
|
39
39
|
"./schemas/*": {
|
40
40
|
"default": "./schemas/*"
|
41
41
|
},
|
42
|
+
"./schemas/ota/ota-manifest.schema.json": {
|
43
|
+
"default": "./schemas/ota/ota-manifest.schema.json"
|
44
|
+
},
|
45
|
+
"./types/ota-manifest": {
|
46
|
+
"types": "./types/ota-manifest.d.ts",
|
47
|
+
"default": "./types/ota-manifest.d.ts"
|
48
|
+
},
|
42
49
|
"./package.json": "./package.json"
|
43
50
|
},
|
44
51
|
"typesVersions": {
|
@@ -51,15 +58,26 @@
|
|
51
58
|
],
|
52
59
|
"schemas/*": [
|
53
60
|
"schemas/*"
|
61
|
+
],
|
62
|
+
"types/ota-manifest": [
|
63
|
+
"types/ota-manifest.d.ts"
|
54
64
|
]
|
55
65
|
}
|
56
66
|
},
|
57
67
|
"files": [
|
58
68
|
"dist/",
|
59
69
|
"schemas/",
|
70
|
+
"types/",
|
60
71
|
"README.md",
|
61
|
-
"LICENSE"
|
72
|
+
"LICENSE",
|
73
|
+
"CHANGELOG.md"
|
62
74
|
],
|
75
|
+
"publishConfig": {
|
76
|
+
"access": "public"
|
77
|
+
},
|
78
|
+
"engines": {
|
79
|
+
"node": ">=16.0.0"
|
80
|
+
},
|
63
81
|
"scripts": {
|
64
82
|
"prebuild": "npm run clean && node scripts/copy-schemas.cjs",
|
65
83
|
"build:cjs": "tsc -p tsconfig.json",
|
@@ -69,7 +87,16 @@
|
|
69
87
|
"prepare": "npm run build",
|
70
88
|
"lint": "echo 'No linter configured'",
|
71
89
|
"test": "node test/validate-fixtures.cjs",
|
72
|
-
"
|
90
|
+
"verify:schemas": "node scripts/check-schema-sync.cjs",
|
91
|
+
"verify:release": "node scripts/check-release-integrity.cjs",
|
92
|
+
"verify": "npm run verify:schemas && npm run verify:release && npm test",
|
93
|
+
"release:prepare": "node scripts/release-prepare.cjs",
|
94
|
+
"wiki:generate": "node scripts/generate-wiki.cjs",
|
95
|
+
"metadata:report": "alteriom-metadata report --org-tag alteriom || echo 'metadata report failed'",
|
96
|
+
"metadata:validate": "alteriom-metadata validate --org-tag alteriom || echo 'metadata validate failed'",
|
97
|
+
"metadata:apply": "alteriom-metadata apply --org-tag alteriom",
|
98
|
+
"metadata:apply:dry": "alteriom-metadata dry-run --org-tag alteriom",
|
99
|
+
"validate:ota": "node scripts/validate-ota-manifest.js"
|
73
100
|
},
|
74
101
|
"keywords": [
|
75
102
|
"alteriom",
|
@@ -77,15 +104,20 @@
|
|
77
104
|
"iot",
|
78
105
|
"schema",
|
79
106
|
"validation",
|
80
|
-
"typescript"
|
107
|
+
"typescript",
|
108
|
+
"ota"
|
81
109
|
],
|
82
110
|
"peerDependencies": {
|
83
111
|
"ajv": ">=8.0.0"
|
84
112
|
},
|
85
113
|
"devDependencies": {
|
114
|
+
"@alteriom/repository-metadata-manager": "^1.2.4",
|
86
115
|
"ajv": "^8.17.0",
|
87
116
|
"ajv-formats": "^2.1.1",
|
88
117
|
"rimraf": "^5.0.5",
|
89
118
|
"typescript": "^5.4.0"
|
119
|
+
},
|
120
|
+
"dependencies": {
|
121
|
+
"dotenv": "^17.2.2"
|
90
122
|
}
|
91
123
|
}
|
@@ -0,0 +1,63 @@
|
|
1
|
+
// Type definitions for Alteriom OTA Manifest (rich + minimal variants)
|
2
|
+
// Generated manually alongside schema at schemas/ota/ota-manifest.schema.json
|
3
|
+
|
4
|
+
export interface OtaChunkObject {
|
5
|
+
index: number; // 0-based sequential index
|
6
|
+
offset: number; // byte offset within firmware binary
|
7
|
+
size: number; // chunk size in bytes
|
8
|
+
sha256: string; // lowercase hex sha256 of the chunk
|
9
|
+
}
|
10
|
+
|
11
|
+
// Rich manifest build entry (dev or prod)
|
12
|
+
export interface OtaRichEntryBase {
|
13
|
+
build_type: 'dev' | 'prod';
|
14
|
+
file: string; // firmware-dev.bin or firmware-prod.bin
|
15
|
+
size: number; // total firmware size (bytes)
|
16
|
+
sha256: string; // full firmware binary sha256
|
17
|
+
firmware_version: string; // semantic or build version string
|
18
|
+
built: string; // ISO8601 timestamp
|
19
|
+
ota_url: string; // absolute or relative fetch URL
|
20
|
+
chunk_size?: number; // size each chunk except possibly last
|
21
|
+
// Either structured objects OR array of sha256 strings
|
22
|
+
chunks?: OtaChunkObject[] | string[];
|
23
|
+
}
|
24
|
+
|
25
|
+
export type OtaRichEntry = OtaRichEntryBase;
|
26
|
+
|
27
|
+
export interface OtaRichManifest {
|
28
|
+
environment: string; // e.g. universal-sensor
|
29
|
+
branch: string; // source control branch build originated from
|
30
|
+
manifests: {
|
31
|
+
dev?: OtaRichEntry;
|
32
|
+
prod?: OtaRichEntry;
|
33
|
+
};
|
34
|
+
}
|
35
|
+
|
36
|
+
// Minimal variant channel entry
|
37
|
+
export interface OtaMinimalChannel {
|
38
|
+
file: string; // firmware-dev.bin / firmware-prod.bin
|
39
|
+
size: number; // bytes
|
40
|
+
sha256: string; // full firmware sha256
|
41
|
+
version: string; // version string
|
42
|
+
timestamp: string; // ISO8601 build time
|
43
|
+
chunk_size?: number;
|
44
|
+
chunks?: string[]; // hash-only list (no structured offsets)
|
45
|
+
}
|
46
|
+
|
47
|
+
export interface OtaMinimalEnv {
|
48
|
+
dev?: OtaMinimalChannel;
|
49
|
+
prod?: OtaMinimalChannel;
|
50
|
+
}
|
51
|
+
|
52
|
+
// Root minimal map: environment -> channels
|
53
|
+
export type OtaMinimalManifest = Record<string, OtaMinimalEnv>;
|
54
|
+
|
55
|
+
export type OtaManifest = OtaRichManifest | OtaMinimalManifest;
|
56
|
+
|
57
|
+
export function isRichManifest(m: OtaManifest): m is OtaRichManifest {
|
58
|
+
return (m as OtaRichManifest).manifests !== undefined && typeof (m as any).environment === 'string';
|
59
|
+
}
|
60
|
+
|
61
|
+
export function isMinimalManifest(m: OtaManifest): m is OtaMinimalManifest {
|
62
|
+
return !isRichManifest(m);
|
63
|
+
}
|