Getting Started
Configuard turns a flat list of configuration rows — typically the contents
of a config database table — into a nested, typed, immutable object your
runtime can read safely.
Install
Section titled “Install”npm i configuardnotation is a runtime dependency and is
installed with it.
The Shape of a Row
Section titled “The Shape of a Row”Each row is an IConfigItem — a key in
dot/bracket notation, a raw string value, and the metadata that says how to
parse it and who may see it. Here is a small device config used throughout these
docs:
[ { "accessor": "system", "appAccess": null, "key": "@UIColors", "type": "string", "listType": "csl", "value": "Blue,Red,Green,Amber", "options": null, "defaultValue": null, "editable": false, "requiresReboot": false, "encrypt": false, "description": "Reusable list of allowed UI colors." }, { "accessor": "system", "appAccess": null, "key": "company.name", "type": "string", "listType": "none", "value": "Acme", "options": null, "defaultValue": null, "editable": true, "requiresReboot": false, "encrypt": false, "description": "Display name of the operator." }, { "accessor": "system", "appAccess": null, "key": "device.port", "type": "integer", "listType": "none", "value": "8080", "options": null, "defaultValue": "8080", "editable": false, "requiresReboot": true, "encrypt": false, "description": "Port the device listens on. Reboot to apply." }, { "accessor": "system", "appAccess": null, "key": "device.config.updateOnBoot", "type": "boolean", "listType": "none", "value": "true", "options": null, "defaultValue": "true", "editable": true, "requiresReboot": false, "encrypt": false, "description": "Whether the device refreshes its config on boot." }, { "accessor": "system", "appAccess": null, "key": "device.config.lifeSpan", "type": "integer", "listType": "none", "value": "1440", "options": null, "defaultValue": "1440", "editable": true, "requiresReboot": false, "encrypt": false, "description": "Config validity window, in minutes." }, { "accessor": "system", "appAccess": null, "key": "device.ui.accent", "type": "string", "listType": "none", "value": "Amber", "options": "${@UIColors}", "defaultValue": "Blue", "editable": true, "requiresReboot": false, "encrypt": false, "description": "Accent color, constrained to the @UIColors list." }, { "accessor": "system", "appAccess": null, "key": "device.protocol.transports", "type": "string", "listType": "array", "value": "http,mqtt", "options": null, "defaultValue": null, "editable": true, "requiresReboot": true, "encrypt": false, "description": "Enabled transports, parsed into a string array." }, { "accessor": "system", "appAccess": null, "key": "environment.host", "type": "string", "listType": "none", "value": "device.local", "options": null, "defaultValue": null, "editable": true, "requiresReboot": false, "encrypt": false, "description": "Base hostname for device endpoints." }, { "accessor": "system", "appAccess": null, "key": "device.diagnostics.uploadUrl", "type": "string", "listType": "none", "value": "https://${environment.host}/upload", "options": null, "defaultValue": null, "editable": true, "requiresReboot": false, "encrypt": false, "description": "Diagnostics endpoint, templated off environment.host." }, { "accessor": "system", "appAccess": null, "key": "db.password", "type": "string", "listType": "none", "value": "enc:5f3a9c2e7b104d8f", "options": null, "defaultValue": null, "editable": true, "requiresReboot": false, "encrypt": true, "description": "Database password, stored encrypted at rest." }]Build and Read
Section titled “Build and Read”Pass the rows to the constructor with the accessor doing the reading. The result is built once, deep-frozen, and read by notation path:
import { Configuard, AccessorType } from 'configuard';
const cfg = new Configuard(rows, { accessor: AccessorType.SYSTEM });
cfg.data;// {// company: { name: 'Acme' },// device: {// port: 8080,// config: { updateOnBoot: true, lifeSpan: 1440 },// ui: { accent: 'Amber' },// protocol: { transports: ['http', 'mqtt'] },// diagnostics: { uploadUrl: 'https://device.local/upload' }// },// environment: { host: 'device.local' },// db: { password: 'enc:5f3a9c2e7b104d8f' } // encrypted — no decrypt hook here// }
cfg.get<number>('device.port'); // 8080 — a number, not "8080"cfg.get('device.protocol.transports'); // ['http', 'mqtt']cfg.has('device.ui.accent'); // trueNote what the build did for you: strings were cast to their declared
type ("8080" → 8080), the
array row was split into a list, the ${environment.host}
template was resolved, and the whole object
was frozen so nothing downstream
can mutate live config.
The Lifecycle
Section titled “The Lifecycle”Configuard sits across the whole life of a setting, not just the read:
- Store — keep settings as rows in one
configtable. - Build & use —
new Configuard(rows)produces the nested, type-cast, ABAC-filtered object for your runtime. Read it via.data/.get()/.has(). - Edit in a UI —
Configuard.parseFlat()returns the same flat list with templates resolved and option lists expanded, ready to render as form fields. - Save back —
Configuard.serializeFlat()validates the edits, serializes them to DB strings, and returns the diff to persist.
Configuard also fails loud: a corrupt row throws at construction rather than silently producing a partial object.
- The Config Item — the row shape and the
configtable. - Value & List Types — how a raw string becomes a typed value.
- Access Control (ABAC) — who sees which rows.
- Admin UI Workflow — the
parseFlat→ edit →serializeFlatround trip.