@alteriom/mqtt-schema 0.2.1 → 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 ADDED
@@ -0,0 +1,7 @@
1
+ # Changelog (Moved)
2
+
3
+ The canonical changelog is maintained at:
4
+
5
+ `docs/mqtt_schema/CHANGELOG.md`
6
+
7
+ This root file is intentionally minimal to avoid duplication and ensure release integrity scripts target a single source of truth.
package/README.md CHANGED
@@ -1,7 +1,71 @@
1
1
  # @alteriom/mqtt-schema
2
2
 
3
+ ![Metadata Compliance](https://github.com/Alteriom/alteriom-mqtt-schema/actions/workflows/metadata-compliance.yml/badge.svg)
4
+ ![npm version](https://img.shields.io/npm/v/@alteriom/mqtt-schema.svg)
5
+ ![npm downloads](https://img.shields.io/npm/dm/@alteriom/mqtt-schema.svg)
6
+ ![license](https://img.shields.io/npm/l/@alteriom/mqtt-schema.svg)
7
+ ![npm total downloads](https://img.shields.io/npm/dt/@alteriom/mqtt-schema.svg)
8
+ ![node version](https://img.shields.io/node/v/@alteriom/mqtt-schema.svg)
9
+ ![peer ajv](https://img.shields.io/badge/peer%20ajv-%3E%3D8.0.0-blue.svg)
10
+ ![latest tag](https://img.shields.io/github/v/tag/Alteriom/alteriom-mqtt-schema?label=tag)
11
+ [![bundle size](https://img.shields.io/bundlephobia/minzip/@alteriom/mqtt-schema)](https://bundlephobia.com/package/@alteriom/mqtt-schema)
12
+
3
13
  Alteriom MQTT v1 JSON Schemas, TypeScript types, and production‑ready validation helpers for integrating firmware MQTT payloads into web or backend services.
4
14
 
15
+ > NOTE: OTA manifest CI validation workflow file could not be added via automated API due to path constraints; it can be added manually post-merge if still absent.
16
+
17
+ See also: `docs/SCHEMA_MAP.md` for complete schema listing.
18
+
19
+ ## OTA Firmware Manifest Schema (NEW in 0.3.0)
20
+
21
+ The package now includes the OTA firmware manifest schema used by build + deployment tooling.
22
+
23
+ Import the schema JSON directly:
24
+ ```ts
25
+ import otaManifestSchema from '@alteriom/mqtt-schema/schemas/ota/ota-manifest.schema.json';
26
+ ```
27
+
28
+ Types:
29
+ ```ts
30
+ import { OtaManifest, isRichManifest } from '@alteriom/mqtt-schema/types/ota-manifest';
31
+ ```
32
+
33
+ Shapes supported (oneOf):
34
+ - Rich manifest:
35
+ ```json
36
+ {
37
+ "environment": "universal-sensor",
38
+ "branch": "main",
39
+ "manifests": { "dev": { /* richEntry */ }, "prod": { /* richEntry */ } }
40
+ }
41
+ ```
42
+ - Minimal environment map:
43
+ ```json
44
+ {
45
+ "universal-sensor": { "dev": { /* minimalChannel */ } }
46
+ }
47
+ ```
48
+
49
+ Chunk hashing variants (mutually exclusive):
50
+ 1. Structured objects (offset + size + sha256)
51
+ 2. Array of lowercase sha256 strings
52
+
53
+ Validation example:
54
+ ```ts
55
+ import Ajv from 'ajv';
56
+ import schema from '@alteriom/mqtt-schema/schemas/ota/ota-manifest.schema.json';
57
+ import { OtaManifest } from '@alteriom/mqtt-schema/types/ota-manifest';
58
+
59
+ const ajv = new Ajv({ allErrors: true });
60
+ const validate = ajv.compile<OtaManifest>(schema as any);
61
+ const manifest: OtaManifest = JSON.parse(raw);
62
+ if (!validate(manifest)) {
63
+ console.error(validate.errors);
64
+ }
65
+ ```
66
+
67
+ ---
68
+
5
69
  ## Why this exists
6
70
  Firmware emits structured MQTT payloads that must remain tightly aligned with web, analytics, and gateway logic. This package is the single source of truth for:
7
71
 
@@ -101,9 +165,11 @@ interface ValidationResult {
101
165
  ```
102
166
 
103
167
  ### Performance Notes
168
+
104
169
  All Ajv validator functions are compiled once at module load. For typical web usage (tens to hundreds of validations per page/session) this is faster and simpler than on‑demand compilation. If you need custom Ajv options (e.g., different formats), open an issue—an override hook can be added without breaking changes.
105
170
 
106
171
  ### Embedded Schemas
172
+
107
173
  `schema_data.ts` is auto‑generated during build. This avoids dynamic `require()` / `import` of JSON and works cleanly in both Node ESM and bundlers without JSON import assertions. The original JSON files are still published under `schemas/` for tooling or documentation pipelines.
108
174
 
109
175
  ## Provided Schemas (v1)
@@ -129,8 +195,11 @@ All Ajv validator functions are compiled once at module load. For typical web us
129
195
  | `SensorDataMessage` etc. | TS interfaces | Strongly typed shapes |
130
196
  | `isSensorDataMessage` etc. | type guards | Runtime narrowing helpers |
131
197
  | `schemas/*.json` | JSON | Original schema assets (optional) |
198
+ | `schemas/ota/ota-manifest.schema.json` | JSON | OTA firmware manifest schema (rich + minimal) |
199
+ | `types/ota-manifest` | TS types | OtaManifest union + helpers |
132
200
 
133
201
  ### Validator Keys
202
+
134
203
  `sensorData`, `sensorHeartbeat`, `sensorStatus`, `gatewayInfo`, `gatewayMetrics`, `firmwareStatus`, `controlResponse`
135
204
 
136
205
  ### Classification Heuristics (Simplified)
@@ -154,6 +223,8 @@ Schema stability is paramount. We track two related versions:
154
223
 
155
224
  Backward‑compatible additions: new optional properties or enums, documented in CHANGELOG. Breaking: new required fields, structural changes, or removed properties (triggers parallel `v2` schema path & coordinated firmware rollout).
156
225
 
226
+ Backward-compatible schema additions to OTA manifest WILL use minor bumps.
227
+
157
228
  ## TypeScript / Bundler Notes
158
229
 
159
230
  - Works in TS >= 5, Node >= 16, Vite / Webpack / ESBuild.
@@ -165,6 +236,8 @@ Backward‑compatible additions: new optional properties or enums, documented in
165
236
  - Optional custom Ajv injection hook
166
237
  - JSON Schema → Zod conversion example
167
238
  - Runtime metrics helper (count validation categories)
239
+ - Signed OTA manifest extension
240
+ - Delta / compressed OTA metadata fields
168
241
 
169
242
  ## Contributing
170
243
 
@@ -177,52 +250,3 @@ Schemas are static. No network access. Supply-chain risk minimized by keeping de
177
250
  ## License
178
251
 
179
252
  MIT
180
-
181
- ## Registry Mirrors
182
-
183
- This package is published to BOTH:
184
-
185
- - Public npm registry: `https://registry.npmjs.org` (primary)
186
- - GitHub Packages registry: `https://npm.pkg.github.com` (mirror for visibility in repo Packages tab)
187
-
188
- ### Installing from GitHub Packages (optional)
189
-
190
- Create or update an `.npmrc` with a scoped registry override (auth token with `read:packages` required):
191
-
192
- ```
193
- @alteriom:registry=https://npm.pkg.github.com
194
- //npm.pkg.github.com/:_authToken=${GITHUB_TOKEN}
195
- ```
196
-
197
- Then install normally:
198
-
199
- ```
200
- npm install @alteriom/mqtt-schema ajv ajv-formats
201
- ```
202
-
203
- If you omit the override, npmjs.org is used (recommended for most consumers).
204
-
205
- ### Why dual publish?
206
-
207
- - GitHub Packages listing provides provenance + quick visibility in the repo UI.
208
- - npm remains the canonical public distribution source (faster, anonymous installs allowed).
209
-
210
- ### Operational Notes
211
-
212
- | Aspect | Behavior |
213
- |--------|----------|
214
- | Build artifact | Built once, same tarball published to both registries. |
215
- | Version uniqueness | Same version must not be republished; bump if any change needed. |
216
- | Auth (GitHub) | Always required for install from GitHub Packages, even for public repos. |
217
- | Tarball parity | Do not rebuild between publishes; workflows ensure single build. |
218
- | Fallback strategy | If mirror publish fails (e.g., transient), primary npm publish still stands. |
219
- | Provenance flag | Applied for npm (GitHub ignores currently). |
220
-
221
- ### Verifying a Release
222
-
223
- ```bash
224
- npm view @alteriom/mqtt-schema version
225
- npm view @alteriom/mqtt-schema version --registry=https://npm.pkg.github.com
226
- ```
227
-
228
- Both should return the same version.
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@alteriom/mqtt-schema",
3
- "version": "0.2.1",
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",
@@ -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,18 +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
  ],
63
75
  "publishConfig": {
64
76
  "access": "public"
65
77
  },
78
+ "engines": {
79
+ "node": ">=16.0.0"
80
+ },
66
81
  "scripts": {
67
82
  "prebuild": "npm run clean && node scripts/copy-schemas.cjs",
68
83
  "build:cjs": "tsc -p tsconfig.json",
@@ -75,7 +90,13 @@
75
90
  "verify:schemas": "node scripts/check-schema-sync.cjs",
76
91
  "verify:release": "node scripts/check-release-integrity.cjs",
77
92
  "verify": "npm run verify:schemas && npm run verify:release && npm test",
78
- "release:prepare": "node scripts/release-prepare.cjs"
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"
79
100
  },
80
101
  "keywords": [
81
102
  "alteriom",
@@ -83,15 +104,20 @@
83
104
  "iot",
84
105
  "schema",
85
106
  "validation",
86
- "typescript"
107
+ "typescript",
108
+ "ota"
87
109
  ],
88
110
  "peerDependencies": {
89
111
  "ajv": ">=8.0.0"
90
112
  },
91
113
  "devDependencies": {
114
+ "@alteriom/repository-metadata-manager": "^1.2.4",
92
115
  "ajv": "^8.17.0",
93
116
  "ajv-formats": "^2.1.1",
94
117
  "rimraf": "^5.0.5",
95
118
  "typescript": "^5.4.0"
119
+ },
120
+ "dependencies": {
121
+ "dotenv": "^17.2.2"
96
122
  }
97
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
+ }