Replace the old Lisp-like array expression representation
(["AND", ["PARAM", ...], ...]) with a class hierarchy rooted in
an abstract Expression class (Literal, Parameter, Binary, Unary,
FunctionCall, Conditional). This gives compile-time type safety
to expression construction, evaluation, and pattern matching.
Key changes:
- New lib/common/expression.ts defines the class hierarchy with
map/evaluate/toString methods
- Rewrite parser as hand-rolled recursive descent, removing the
parsimmon dependency
- Extend Path with a colon separator to unify parameter identity
and attributes into a single address space (e.g.
"Device.WiFi.SSID.1.Name:writable"). The colon field tracks
how many trailing segments are attribute qualifiers. PathSet
rewritten with separate param/attr segment indexes
- Flatten device attribute representation in the UI to
colon-delimited keys mirroring the new path syntax
Replace .eslintrc.json with eslint.config.js using the new flat config
format required by ESLint 10. Swap @typescript-eslint/eslint-plugin and
@typescript-eslint/parser for the unified typescript-eslint package.
Upgrade TypeScript to 5.9 and @types/node to 25. Apply automatic code
fixes: remove unused catch bindings and preserve error cause in auth
header parsing.
The previous approach was simplistic and could result in inefficient queries
in certain edge cases, notably causing MongoDB to not utilize existing indexes
when querying by last inform timestamps given upper and lower bounds. The new
implementation leverages our existing expression minimizer code and can
therefore generate more efficient queries or at least queries that can take
advantage of existing indexes.
Only happens in HTTPS because seemingly somewhere in the stack up to
50mb of data is being buffered potentially triggering a timeout at a
higher level if not drained fast enough.
This commit also includes other streams related improvements.
Some devices preserve cookies set in a previous session and pass them
on to the next session. The presence of a session cookie in the Inform
request causes an unnecessary DB query and, in some edge cases, an
Invalid Session error.