matter.js icon indicating copy to clipboard operation
matter.js copied to clipboard

Refactor ClusterServer

Open lauckhart opened this issue 7 months ago • 3 comments

The overall goal of these changes is address consistency issues that were breaking ACL checks on global attributes. As usual this ballooned into a bunch of updates but mostly interrelated except a few places where I lacked self control.

First, to do this cleanly I cleared out some tech debt:

- A new `ClusterServer` interface exposes only the public portions of ClusterServer required by all APIs.
- The new interface uses ClusterType rather than Cluster<any, any, any, any, any>.
- I refactored other APIs to use ClusterType rather than Cluster as necessary to make typing work.  Should work the same but the definitions are simpler.  It will be a breaking change if folks specified generic parameters explicitly but the complexity of the old typing system makes this unlikely.
- ClusterServerObj and ClusterServerObjInternal still exist but are implementations of ClusterServer and are only used by legacy APIs.
- Modified ClusterServerObj and ClientServerObj to use ClusterType.  Also added default template parameters so they can be used generically without adornment.
- On ClusterServer, attribute servers were previously public but command and event servers were "internal" although they were accessed by various other modules.  All servers are now exposed consistently as properties of ClusterServer.
- I reverted changes to the legacy API where the legacy Endpoint was passed as EndpointInterface.  This makes the extensions provided by the *Obj* interfaces available without casting.
- Global attributes now live on behavior.state and their behavior is consistent with that of "normal" attributes.
- ClusterServerBacking now initializes the global attributes directly.
- There is no longer significant code in ClusterServer (the factory function) relevant to ClusterServerBacking.  It now creates element servers directly and no longer uses ClusterServer().
- This should serve as an optimization as it removes a couple layers of functions from interactions, some redundant validity checks, and generation of redundant accessors.

The model and behavior APIs received various updates:

- The behavior API now uses model.members instead of model.attributes to determine applicable attributes.  This allows inherited members to contribute where before they could be hidden if the child model only overrode a subset of members.
- ClusterModel#members now includes global attributes as members.
- ClusterServerBacking populates the global list attributes for attributes, commands and events based on enabled features.
- ClusterModel#members also receives various fixes to improve edge-case correctness.
- I had previously created an operational "supportedFeatures" on ClusterModel that defined the FeatureSet explicitly.  On the model this is converted to instead use the defaults defined in the FeatureMap attribute.
- We now handle default state values more robustly.  In particular, if you disable an attribute or field but then reenable it, any default value defined in the original state class will be reinstated.  And if no other default is present in the class or the cluster, we will use the default from the model.
- RootSupervisor previously removed elements that were not enabled by conformance.  We now leave these elements in place so the accessors are defined on the underlying class.  This allows us to generate an error if e.g. an non-conformant attribute value is set.  This will still be a compile time error in TS but we now also catch runtime errors if the attribute is set via JS or a TS cast.
- Global attributes are not present in the types for `ClusterBehavior#state` but they are present on the JS object and accessible by casting `ClusterBehavior#state` to `GlobalAttributeState`.

Made some improvements to testing:

- When dumping errors now displays `Error#cause` and/or `AggregateError#errors`.
- For TTYs, displays the name of every test in the terminal as it executes.  This seems to slow things down a bit but anecdotally appears to only be ~10% so leaving as is for now.
- We also include full error details when testing crashes due to unhandled error.

And a few other high-level updates:

- Matter.js now requires node 18+.
- The library target for TypeScript is now es2022.  This enables typing for various features that are available in all runtimes we support, including some that we already use such as Error.cause.  This apparently had a side effect of modifying transpilation to include class properties that are undefined which required additional changes in a few places, nothing breaking though.  Happily, I believe this means we no longer need to do "foo?: Type = undefined" on state classes and can instead just do "foo?: Type".
- The spec model is now based on Matter 1.3.0.1 (previously 1.3.0.0).  This also fixes default booleans (values were inverted) and handling of provisional requirements (should have been treated as optional).
- Did a small amount of global wordsmithing.

lauckhart avatar Jul 27 '24 17:07 lauckhart