UNPKG

@alteriom/mqtt-schema

Version:

Alteriom MQTT v1 schemas, TypeScript types, and validation helpers for web integration

229 lines (162 loc) 8.07 kB
# @alteriom/mqtt-schema Alteriom MQTT v1 JSON Schemas, TypeScript types, and production‑ready validation helpers for integrating firmware MQTT payloads into web or backend services. ## Why this exists 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: - Canonical, versioned JSON Schemas (`schema_version: 1` series) - Embedded (tree‑shakeable) schema objects — no runtime file I/O - Precompiled Ajv validators (fast + consistent across CJS / ESM) - TypeScript interfaces & type guards generated from the same source schema set - Message classification helper that infers the schema kind heuristically - Forward‑compatible design: unknown extra properties are ignored unless explicitly constrained ## Features - Dual build: CommonJS + ESM (Node 16+ / bundlers) - Zero configuration: just import and validate - Helpful error paths (JSON Pointer style) - Lightweight (Ajv peer dependency, schemas embedded) - Ships original schema JSON files (optional consumption) ## Installation ```bash npm install @alteriom/mqtt-schema ajv ajv-formats ``` ## Quick Start Validate a JSON payload (object already parsed): ```ts import { validators } from '@alteriom/mqtt-schema'; const payload = JSON.parse(rawMqttString); const result = validators.sensorData(payload); if (!result.valid) { console.error('Invalid sensor data', result.errors); } ``` Classify and validate automatically: ```ts import { classifyAndValidate } from '@alteriom/mqtt-schema'; const { kind, result } = classifyAndValidate(payload); if (result.valid) { console.log('Message kind:', kind); } else { console.warn('Validation errors', result.errors); } ``` Use strong TypeScript types after classification: ```ts import { classifyAndValidate, isSensorDataMessage, SensorDataMessage } from '@alteriom/mqtt-schema'; const { result } = classifyAndValidate(payload); if (result.valid && isSensorDataMessage(payload)) { const data: SensorDataMessage = payload; Object.entries(data.sensors).forEach(([name, s]) => { console.log(name, s.value, s.unit); }); } ``` Access raw schema JSON (if you need to introspect or power form generation): ```ts import envelopeSchema from '@alteriom/mqtt-schema/schemas/envelope.schema.json'; ``` ## API Surface ```ts import { validators, validateMessage, classifyAndValidate } from '@alteriom/mqtt-schema'; // 1. Direct validator by message kind validators.sensorData(payload); // => { valid: boolean; errors?: string[] } // 2. Generic function validateMessage('sensorData', payload); // 3. Classify unknown payload then validate const { kind, result } = classifyAndValidate(payload); // 4. Type guards (when available) // if (isSensorDataMessage(payload)) { ... } ``` Validation result format: ```ts interface ValidationResult { valid: boolean; errors?: string[]; // Each item contains instancePath + message } ``` ### Performance Notes 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. ### Embedded Schemas `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. ## Provided Schemas (v1) | File | Purpose | |------|---------| | envelope.schema.json | Base required envelope fields | | sensor_data.schema.json | Telemetry payload with sensors map | | sensor_heartbeat.schema.json | Lightweight heartbeat (firmware_version may be omitted) | | sensor_status.schema.json | Sensor status / presence updates | | gateway_info.schema.json | Gateway identity & capabilities | | gateway_metrics.schema.json | Gateway performance metrics | | firmware_status.schema.json | Firmware update lifecycle events | | control_response.schema.json | Command/control response messages | ## Exports | Export | Type | Description | |--------|------|-------------| | `validators` | object | Precompiled validators per message type | | `validateMessage(kind,data)` | fn | Run a specific validator by key | | `classifyAndValidate(data)` | fn | Heuristic classification + validation | | `SensorDataMessage` etc. | TS interfaces | Strongly typed shapes | | `isSensorDataMessage` etc. | type guards | Runtime narrowing helpers | | `schemas/*.json` | JSON | Original schema assets (optional) | ### Validator Keys `sensorData`, `sensorHeartbeat`, `sensorStatus`, `gatewayInfo`, `gatewayMetrics`, `firmwareStatus`, `controlResponse` ### Classification Heuristics (Simplified) - `metrics` → `gatewayMetrics` - `sensors` → `sensorData` - `progress_pct` or OTA status keywords → `firmwareStatus` - `status` + `device_type: sensor` → `sensorStatus` - `status: ok|error` (no other match) → `controlResponse` - `device_type: gateway` → `gatewayInfo` - fallback → `sensorHeartbeat` ## Versioning Policy Schema stability is paramount. We track two related versions: | Concept | Meaning | |---------|---------| | `schema_version` (in payload) | Wire format major. Only increments for breaking changes. | | npm package version | Follows semver; patch/minor may add optional properties or tooling, major aligns with `schema_version` bump. | 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). ## TypeScript / Bundler Notes - Works in TS >= 5, Node >= 16, Vite / Webpack / ESBuild. - Tree shaking: unused validators pruned when using ESM builds. - No side effects besides Ajv instance creation. ## Roadmap - Optional custom Ajv injection hook - JSON Schema → Zod conversion example - Runtime metrics helper (count validation categories) ## Contributing Issues & PRs welcome. Ensure firmware repo schemas remain the authoritative source—do not manually edit generated `schema_data.ts`. ## Security Schemas are static. No network access. Supply-chain risk minimized by keeping dependencies minimal (Ajv + formats only). ## License MIT ## Registry Mirrors This package is published to BOTH: - Public npm registry: `https://registry.npmjs.org` (primary) - GitHub Packages registry: `https://npm.pkg.github.com` (mirror for visibility in repo Packages tab) ### Installing from GitHub Packages (optional) Create or update an `.npmrc` with a scoped registry override (auth token with `read:packages` required): ``` @alteriom:registry=https://npm.pkg.github.com //npm.pkg.github.com/:_authToken=${GITHUB_TOKEN} ``` Then install normally: ``` npm install @alteriom/mqtt-schema ajv ajv-formats ``` If you omit the override, npmjs.org is used (recommended for most consumers). ### Why dual publish? - GitHub Packages listing provides provenance + quick visibility in the repo UI. - npm remains the canonical public distribution source (faster, anonymous installs allowed). ### Operational Notes | Aspect | Behavior | |--------|----------| | Build artifact | Built once, same tarball published to both registries. | | Version uniqueness | Same version must not be republished; bump if any change needed. | | Auth (GitHub) | Always required for install from GitHub Packages, even for public repos. | | Tarball parity | Do not rebuild between publishes; workflows ensure single build. | | Fallback strategy | If mirror publish fails (e.g., transient), primary npm publish still stands. | | Provenance flag | Applied for npm (GitHub ignores currently). | ### Verifying a Release ```bash npm view @alteriom/mqtt-schema version npm view @alteriom/mqtt-schema version --registry=https://npm.pkg.github.com ``` Both should return the same version.