@matter/node 0.15.2-alpha.0-20250717-3607eeac6 → 0.15.2-alpha.0-20250718-7e661c331
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/dist/cjs/behavior/internal/BehaviorBacking.d.ts +2 -2
- package/dist/cjs/behavior/internal/BehaviorBacking.d.ts.map +1 -1
- package/dist/cjs/behavior/internal/BehaviorBacking.js +6 -1
- package/dist/cjs/behavior/internal/BehaviorBacking.js.map +1 -1
- package/dist/cjs/behavior/internal/ClientBehaviorBacking.d.ts +1 -6
- package/dist/cjs/behavior/internal/ClientBehaviorBacking.d.ts.map +1 -1
- package/dist/cjs/behavior/internal/ClientBehaviorBacking.js +0 -5
- package/dist/cjs/behavior/internal/ClientBehaviorBacking.js.map +1 -1
- package/dist/cjs/behavior/internal/ServerBehaviorBacking.d.ts +0 -3
- package/dist/cjs/behavior/internal/ServerBehaviorBacking.d.ts.map +1 -1
- package/dist/cjs/behavior/internal/ServerBehaviorBacking.js +0 -15
- package/dist/cjs/behavior/internal/ServerBehaviorBacking.js.map +1 -1
- package/dist/cjs/behavior/state/managed/Datasource.js +7 -3
- package/dist/cjs/behavior/state/managed/Datasource.js.map +1 -1
- package/dist/cjs/behavior/supervision/RootSupervisor.d.ts +2 -2
- package/dist/cjs/behavior/supervision/RootSupervisor.d.ts.map +1 -1
- package/dist/cjs/behavior/supervision/RootSupervisor.js +12 -10
- package/dist/cjs/behavior/supervision/RootSupervisor.js.map +1 -1
- package/dist/cjs/node/ClientNode.d.ts.map +1 -1
- package/dist/cjs/node/ClientNode.js +2 -2
- package/dist/cjs/node/ClientNode.js.map +1 -1
- package/dist/cjs/node/ServerNode.js +2 -2
- package/dist/cjs/node/ServerNode.js.map +1 -1
- package/dist/cjs/node/client/ClientEndpointInitializer.d.ts.map +1 -1
- package/dist/cjs/node/client/ClientEndpointInitializer.js +5 -4
- package/dist/cjs/node/client/ClientEndpointInitializer.js.map +2 -2
- package/dist/cjs/node/client/ClientStructure.d.ts +14 -2
- package/dist/cjs/node/client/ClientStructure.d.ts.map +1 -1
- package/dist/cjs/node/client/ClientStructure.js +21 -3
- package/dist/cjs/node/client/ClientStructure.js.map +1 -1
- package/dist/cjs/node/server/ServerEndpointInitializer.d.ts.map +1 -1
- package/dist/cjs/node/server/ServerEndpointInitializer.js +2 -1
- package/dist/cjs/node/server/ServerEndpointInitializer.js.map +1 -1
- package/dist/cjs/node/server/ServerEnvironment.d.ts.map +1 -1
- package/dist/cjs/node/server/ServerEnvironment.js +0 -2
- package/dist/cjs/node/server/ServerEnvironment.js.map +1 -1
- package/dist/cjs/storage/EndpointStore.d.ts +4 -4
- package/dist/cjs/storage/EndpointStore.d.ts.map +1 -1
- package/dist/cjs/storage/EndpointStore.js +9 -7
- package/dist/cjs/storage/EndpointStore.js.map +1 -1
- package/dist/cjs/storage/client/ClientEndpointStore.d.ts +24 -0
- package/dist/cjs/storage/client/ClientEndpointStore.d.ts.map +1 -0
- package/dist/cjs/storage/client/ClientEndpointStore.js +67 -0
- package/dist/cjs/storage/client/ClientEndpointStore.js.map +6 -0
- package/dist/cjs/storage/client/ClientNodeStore.d.ts +13 -3
- package/dist/cjs/storage/client/ClientNodeStore.d.ts.map +1 -1
- package/dist/cjs/storage/client/ClientNodeStore.js +24 -3
- package/dist/cjs/storage/client/ClientNodeStore.js.map +1 -1
- package/dist/cjs/storage/client/ClientNodeStores.d.ts +2 -2
- package/dist/cjs/storage/client/ClientNodeStores.d.ts.map +1 -1
- package/dist/cjs/storage/client/ClientNodeStores.js +1 -1
- package/dist/cjs/storage/client/ClientNodeStores.js.map +1 -1
- package/dist/cjs/storage/client/DatasourceCache.d.ts +2 -2
- package/dist/cjs/storage/client/DatasourceCache.d.ts.map +1 -1
- package/dist/cjs/storage/client/DatasourceCache.js +5 -3
- package/dist/cjs/storage/client/DatasourceCache.js.map +1 -1
- package/dist/cjs/storage/client/RemoteWriteParticipant.d.ts +30 -0
- package/dist/cjs/storage/client/RemoteWriteParticipant.d.ts.map +1 -0
- package/dist/cjs/storage/client/RemoteWriteParticipant.js +66 -0
- package/dist/cjs/storage/client/RemoteWriteParticipant.js.map +6 -0
- package/dist/cjs/storage/client/RemoteWriter.d.ts +29 -0
- package/dist/cjs/storage/client/RemoteWriter.d.ts.map +1 -0
- package/dist/cjs/storage/client/RemoteWriter.js +73 -0
- package/dist/cjs/storage/client/RemoteWriter.js.map +6 -0
- package/dist/cjs/storage/server/DatasourceStore.d.ts +0 -3
- package/dist/cjs/storage/server/DatasourceStore.d.ts.map +1 -1
- package/dist/cjs/storage/server/DatasourceStore.js.map +1 -1
- package/dist/cjs/storage/server/ServerEndpointStore.d.ts +4 -0
- package/dist/cjs/storage/server/ServerEndpointStore.d.ts.map +1 -1
- package/dist/cjs/storage/server/ServerEndpointStore.js +8 -0
- package/dist/cjs/storage/server/ServerEndpointStore.js.map +1 -1
- package/dist/cjs/storage/server/ServerNodeStore.d.ts +3 -2
- package/dist/cjs/storage/server/ServerNodeStore.d.ts.map +1 -1
- package/dist/cjs/storage/server/ServerNodeStore.js.map +1 -1
- package/dist/esm/behavior/internal/BehaviorBacking.d.ts +2 -2
- package/dist/esm/behavior/internal/BehaviorBacking.d.ts.map +1 -1
- package/dist/esm/behavior/internal/BehaviorBacking.js +6 -1
- package/dist/esm/behavior/internal/BehaviorBacking.js.map +1 -1
- package/dist/esm/behavior/internal/ClientBehaviorBacking.d.ts +1 -6
- package/dist/esm/behavior/internal/ClientBehaviorBacking.d.ts.map +1 -1
- package/dist/esm/behavior/internal/ClientBehaviorBacking.js +0 -5
- package/dist/esm/behavior/internal/ClientBehaviorBacking.js.map +1 -1
- package/dist/esm/behavior/internal/ServerBehaviorBacking.d.ts +0 -3
- package/dist/esm/behavior/internal/ServerBehaviorBacking.d.ts.map +1 -1
- package/dist/esm/behavior/internal/ServerBehaviorBacking.js +0 -15
- package/dist/esm/behavior/internal/ServerBehaviorBacking.js.map +1 -1
- package/dist/esm/behavior/state/managed/Datasource.js +7 -3
- package/dist/esm/behavior/state/managed/Datasource.js.map +1 -1
- package/dist/esm/behavior/supervision/RootSupervisor.d.ts +2 -2
- package/dist/esm/behavior/supervision/RootSupervisor.d.ts.map +1 -1
- package/dist/esm/behavior/supervision/RootSupervisor.js +12 -10
- package/dist/esm/behavior/supervision/RootSupervisor.js.map +1 -1
- package/dist/esm/node/ClientNode.d.ts.map +1 -1
- package/dist/esm/node/ClientNode.js +2 -2
- package/dist/esm/node/ClientNode.js.map +1 -1
- package/dist/esm/node/ServerNode.js +2 -2
- package/dist/esm/node/ServerNode.js.map +1 -1
- package/dist/esm/node/client/ClientEndpointInitializer.d.ts.map +1 -1
- package/dist/esm/node/client/ClientEndpointInitializer.js +5 -4
- package/dist/esm/node/client/ClientEndpointInitializer.js.map +2 -2
- package/dist/esm/node/client/ClientStructure.d.ts +14 -2
- package/dist/esm/node/client/ClientStructure.d.ts.map +1 -1
- package/dist/esm/node/client/ClientStructure.js +21 -3
- package/dist/esm/node/client/ClientStructure.js.map +1 -1
- package/dist/esm/node/server/ServerEndpointInitializer.d.ts.map +1 -1
- package/dist/esm/node/server/ServerEndpointInitializer.js +2 -1
- package/dist/esm/node/server/ServerEndpointInitializer.js.map +1 -1
- package/dist/esm/node/server/ServerEnvironment.d.ts.map +1 -1
- package/dist/esm/node/server/ServerEnvironment.js +0 -2
- package/dist/esm/node/server/ServerEnvironment.js.map +1 -1
- package/dist/esm/storage/EndpointStore.d.ts +4 -4
- package/dist/esm/storage/EndpointStore.d.ts.map +1 -1
- package/dist/esm/storage/EndpointStore.js +9 -7
- package/dist/esm/storage/EndpointStore.js.map +1 -1
- package/dist/esm/storage/client/ClientEndpointStore.d.ts +24 -0
- package/dist/esm/storage/client/ClientEndpointStore.d.ts.map +1 -0
- package/dist/esm/storage/client/ClientEndpointStore.js +47 -0
- package/dist/esm/storage/client/ClientEndpointStore.js.map +6 -0
- package/dist/esm/storage/client/ClientNodeStore.d.ts +13 -3
- package/dist/esm/storage/client/ClientNodeStore.d.ts.map +1 -1
- package/dist/esm/storage/client/ClientNodeStore.js +24 -3
- package/dist/esm/storage/client/ClientNodeStore.js.map +1 -1
- package/dist/esm/storage/client/ClientNodeStores.d.ts +2 -2
- package/dist/esm/storage/client/ClientNodeStores.d.ts.map +1 -1
- package/dist/esm/storage/client/ClientNodeStores.js +1 -1
- package/dist/esm/storage/client/ClientNodeStores.js.map +1 -1
- package/dist/esm/storage/client/DatasourceCache.d.ts +2 -2
- package/dist/esm/storage/client/DatasourceCache.d.ts.map +1 -1
- package/dist/esm/storage/client/DatasourceCache.js +5 -3
- package/dist/esm/storage/client/DatasourceCache.js.map +1 -1
- package/dist/esm/storage/client/RemoteWriteParticipant.d.ts +30 -0
- package/dist/esm/storage/client/RemoteWriteParticipant.d.ts.map +1 -0
- package/dist/esm/storage/client/RemoteWriteParticipant.js +46 -0
- package/dist/esm/storage/client/RemoteWriteParticipant.js.map +6 -0
- package/dist/esm/storage/client/RemoteWriter.d.ts +29 -0
- package/dist/esm/storage/client/RemoteWriter.d.ts.map +1 -0
- package/dist/esm/storage/client/RemoteWriter.js +53 -0
- package/dist/esm/storage/client/RemoteWriter.js.map +6 -0
- package/dist/esm/storage/server/DatasourceStore.d.ts +0 -3
- package/dist/esm/storage/server/DatasourceStore.d.ts.map +1 -1
- package/dist/esm/storage/server/DatasourceStore.js.map +1 -1
- package/dist/esm/storage/server/ServerEndpointStore.d.ts +4 -0
- package/dist/esm/storage/server/ServerEndpointStore.d.ts.map +1 -1
- package/dist/esm/storage/server/ServerEndpointStore.js +8 -0
- package/dist/esm/storage/server/ServerEndpointStore.js.map +1 -1
- package/dist/esm/storage/server/ServerNodeStore.d.ts +3 -2
- package/dist/esm/storage/server/ServerNodeStore.d.ts.map +1 -1
- package/dist/esm/storage/server/ServerNodeStore.js.map +1 -1
- package/package.json +7 -7
- package/src/behavior/internal/BehaviorBacking.ts +3 -2
- package/src/behavior/internal/ClientBehaviorBacking.ts +0 -15
- package/src/behavior/internal/ServerBehaviorBacking.ts +0 -19
- package/src/behavior/state/managed/Datasource.ts +10 -3
- package/src/behavior/supervision/RootSupervisor.ts +18 -15
- package/src/node/ClientNode.ts +4 -2
- package/src/node/ServerNode.ts +2 -2
- package/src/node/client/ClientEndpointInitializer.ts +7 -3
- package/src/node/client/ClientStructure.ts +26 -6
- package/src/node/server/ServerEndpointInitializer.ts +3 -1
- package/src/node/server/ServerEnvironment.ts +0 -2
- package/src/storage/EndpointStore.ts +9 -9
- package/src/storage/client/ClientEndpointStore.ts +53 -0
- package/src/storage/client/ClientNodeStore.ts +38 -6
- package/src/storage/client/ClientNodeStores.ts +3 -4
- package/src/storage/client/DatasourceCache.ts +10 -7
- package/src/storage/client/RemoteWriteParticipant.ts +62 -0
- package/src/storage/client/RemoteWriter.ts +81 -0
- package/src/storage/server/DatasourceStore.ts +1 -6
- package/src/storage/server/ServerEndpointStore.ts +9 -0
- package/src/storage/server/ServerNodeStore.ts +4 -2
|
@@ -11,11 +11,8 @@ import type { SupportedElements } from "#endpoint/properties/Behaviors.js";
|
|
|
11
11
|
import { camelize } from "#general";
|
|
12
12
|
import { FieldValue } from "#model";
|
|
13
13
|
import { Val } from "#protocol";
|
|
14
|
-
import { NodeStore } from "#storage/NodeStore.js";
|
|
15
|
-
import { DatasourceStore } from "#storage/server/DatasourceStore.js";
|
|
16
14
|
import { ClusterType, TlvNoResponse } from "#types";
|
|
17
15
|
import { Behavior } from "../Behavior.js";
|
|
18
|
-
import { Datasource } from "../state/managed/Datasource.js";
|
|
19
16
|
import { BehaviorBacking } from "./BehaviorBacking.js";
|
|
20
17
|
|
|
21
18
|
const NoElements = new Set<string>();
|
|
@@ -24,20 +21,8 @@ const NoElements = new Set<string>();
|
|
|
24
21
|
* This class backs the server implementation of a behavior.
|
|
25
22
|
*/
|
|
26
23
|
export class ServerBehaviorBacking extends BehaviorBacking {
|
|
27
|
-
#store?: Datasource.Store;
|
|
28
24
|
#elements?: SupportedElements;
|
|
29
25
|
|
|
30
|
-
override get store() {
|
|
31
|
-
if (!this.#store) {
|
|
32
|
-
this.#store = this.createStore();
|
|
33
|
-
}
|
|
34
|
-
return this.#store;
|
|
35
|
-
}
|
|
36
|
-
|
|
37
|
-
protected createStore() {
|
|
38
|
-
return this.#nodeStore.storeForEndpoint(this.endpoint).createStoreForBehavior(this.type.id, DatasourceStore);
|
|
39
|
-
}
|
|
40
|
-
|
|
41
26
|
get elements() {
|
|
42
27
|
return this.#elements;
|
|
43
28
|
}
|
|
@@ -70,10 +55,6 @@ export class ServerBehaviorBacking extends BehaviorBacking {
|
|
|
70
55
|
finalizeState();
|
|
71
56
|
}
|
|
72
57
|
|
|
73
|
-
get #nodeStore() {
|
|
74
|
-
return this.endpoint.env.get(NodeStore);
|
|
75
|
-
}
|
|
76
|
-
|
|
77
58
|
/**
|
|
78
59
|
* Schema may specify that state fields default to the value of another field. We apply these defaults after
|
|
79
60
|
* initialization when the other field should be defined.
|
|
@@ -284,6 +284,7 @@ interface Internals extends Datasource.Options {
|
|
|
284
284
|
interactionObserver(session?: AccessControl.Session): MaybePromise<void>;
|
|
285
285
|
events: Datasource.InternalEvents;
|
|
286
286
|
changedEventFor(key: string): undefined | Datasource.Events[any];
|
|
287
|
+
persistentFields: Set<string>;
|
|
287
288
|
}
|
|
288
289
|
|
|
289
290
|
/**
|
|
@@ -339,6 +340,8 @@ function configure(options: Datasource.Options): Internals {
|
|
|
339
340
|
|
|
340
341
|
let changedEventIndex: undefined | Map<string, undefined | Datasource.InternalEvents[`${string}$Changed`]>;
|
|
341
342
|
|
|
343
|
+
const persistentFields = options.supervisor.persistentKeys(options.primaryKey);
|
|
344
|
+
|
|
342
345
|
return {
|
|
343
346
|
...options,
|
|
344
347
|
primaryKey: options.primaryKey === "id" ? "id" : "name",
|
|
@@ -347,6 +350,7 @@ function configure(options: Datasource.Options): Internals {
|
|
|
347
350
|
values,
|
|
348
351
|
featuresKey,
|
|
349
352
|
manageVersion: true,
|
|
353
|
+
persistentFields,
|
|
350
354
|
|
|
351
355
|
interactionObserver(session?: ValueSupervisor.Session) {
|
|
352
356
|
function handleObserverError(error: any) {
|
|
@@ -390,6 +394,10 @@ function configure(options: Datasource.Options): Internals {
|
|
|
390
394
|
};
|
|
391
395
|
}
|
|
392
396
|
|
|
397
|
+
function isExternal(store?: Datasource.Store): store is Datasource.ExternallyMutableStore {
|
|
398
|
+
return !!store && "externalSet" in store;
|
|
399
|
+
}
|
|
400
|
+
|
|
393
401
|
/**
|
|
394
402
|
* If the store supports external mutation, add a listener to update internal state and notify observers.
|
|
395
403
|
*
|
|
@@ -398,7 +406,7 @@ function configure(options: Datasource.Options): Internals {
|
|
|
398
406
|
*/
|
|
399
407
|
function configureExternalChanges(internals: Internals) {
|
|
400
408
|
const { store } = internals;
|
|
401
|
-
if (!
|
|
409
|
+
if (!isExternal(store)) {
|
|
402
410
|
return;
|
|
403
411
|
}
|
|
404
412
|
|
|
@@ -507,7 +515,6 @@ function createReference(resource: Transaction.Resource, internals: Internals, s
|
|
|
507
515
|
});
|
|
508
516
|
|
|
509
517
|
const fields = internals.supervisor.memberNames;
|
|
510
|
-
const persistentFields = internals.supervisor.persistentNames;
|
|
511
518
|
|
|
512
519
|
// This is the actual reference
|
|
513
520
|
const reference: Val.Reference<Val.Struct> = {
|
|
@@ -762,7 +769,7 @@ function createReference(resource: Transaction.Resource, internals: Internals, s
|
|
|
762
769
|
}
|
|
763
770
|
changes.changeList.add(name);
|
|
764
771
|
|
|
765
|
-
if (persistentFields.has(name)) {
|
|
772
|
+
if (internals.persistentFields.has(name)) {
|
|
766
773
|
if (changes.persistent === undefined) {
|
|
767
774
|
changes.persistent = {};
|
|
768
775
|
}
|
|
@@ -59,7 +59,6 @@ export class RootSupervisor implements ValueSupervisor {
|
|
|
59
59
|
#rootSchema: Schema;
|
|
60
60
|
#root: ValueSupervisor;
|
|
61
61
|
#memberNames?: Set<string>;
|
|
62
|
-
#persistentNames?: Set<string>;
|
|
63
62
|
#attributeNamesToIds?: Map<string, AttributeId>; // Whenever we need more than Attributes and Fields, we need to generalize
|
|
64
63
|
|
|
65
64
|
/**
|
|
@@ -144,23 +143,27 @@ export class RootSupervisor implements ValueSupervisor {
|
|
|
144
143
|
}
|
|
145
144
|
|
|
146
145
|
/**
|
|
147
|
-
*
|
|
146
|
+
* Retrieve names or IDs of fields configured as non-volatile.
|
|
148
147
|
*/
|
|
149
|
-
|
|
150
|
-
|
|
151
|
-
|
|
152
|
-
|
|
153
|
-
|
|
154
|
-
|
|
155
|
-
|
|
156
|
-
|
|
157
|
-
|
|
158
|
-
|
|
159
|
-
) {
|
|
160
|
-
|
|
148
|
+
persistentKeys(key: "id" | "name" = "name") {
|
|
149
|
+
const persistent = new Set<string>();
|
|
150
|
+
|
|
151
|
+
for (const member of this.#members) {
|
|
152
|
+
// TODO: We should handle writable/fabric scoped being non-volatile already in the conformance interpreter
|
|
153
|
+
if (
|
|
154
|
+
member.effectiveQuality.nonvolatile ||
|
|
155
|
+
member.effectiveAccess.writable ||
|
|
156
|
+
member.effectiveAccess.fabricScoped
|
|
157
|
+
) {
|
|
158
|
+
if (key === "id") {
|
|
159
|
+
const id = member.effectiveId;
|
|
160
|
+
if (id !== undefined) {
|
|
161
|
+
persistent.add(id.toString());
|
|
162
|
+
continue;
|
|
163
|
+
}
|
|
161
164
|
}
|
|
165
|
+
persistent.add(camelize(member.name));
|
|
162
166
|
}
|
|
163
|
-
this.#persistentNames = persistent;
|
|
164
167
|
}
|
|
165
168
|
return persistent;
|
|
166
169
|
}
|
package/src/node/ClientNode.ts
CHANGED
|
@@ -14,7 +14,7 @@ import { EndpointInitializer } from "#endpoint/properties/EndpointInitializer.js
|
|
|
14
14
|
import { Identity, Lifecycle, MaybePromise } from "#general";
|
|
15
15
|
import { Interactable } from "#protocol";
|
|
16
16
|
import { ClientNodeStore } from "#storage/client/ClientNodeStore.js";
|
|
17
|
-
import {
|
|
17
|
+
import { RemoteWriter } from "#storage/client/RemoteWriter.js";
|
|
18
18
|
import { ServerNodeStore } from "#storage/server/ServerNodeStore.js";
|
|
19
19
|
import { Matter, MatterModel } from "@matter/model";
|
|
20
20
|
import { ClientEndpointInitializer } from "./client/ClientEndpointInitializer.js";
|
|
@@ -58,12 +58,14 @@ export class ClientNode extends Node<ClientNode.RootEndpoint> {
|
|
|
58
58
|
|
|
59
59
|
override initialize() {
|
|
60
60
|
const store = this.env.get(ServerNodeStore).clientStores.storeForNode(this);
|
|
61
|
-
|
|
61
|
+
|
|
62
62
|
this.env.set(ClientNodeStore, store);
|
|
63
63
|
|
|
64
64
|
const initializer = new ClientEndpointInitializer(this);
|
|
65
65
|
this.env.set(EndpointInitializer, initializer);
|
|
66
66
|
|
|
67
|
+
store.write = RemoteWriter(this, initializer.structure);
|
|
68
|
+
|
|
67
69
|
initializer.structure.loadCache();
|
|
68
70
|
|
|
69
71
|
return super.initialize();
|
package/src/node/ServerNode.ts
CHANGED
|
@@ -17,7 +17,7 @@ import { Endpoint } from "#endpoint/Endpoint.js";
|
|
|
17
17
|
import type { Environment } from "#general";
|
|
18
18
|
import { asyncNew, Construction, DiagnosticSource, errorOf, Identity, MatterError } from "#general";
|
|
19
19
|
import { FabricManager, Interactable, OccurrenceManager, ServerInteraction, SessionManager } from "#protocol";
|
|
20
|
-
import {
|
|
20
|
+
import { ServerNodeStore } from "#storage/server/ServerNodeStore.js";
|
|
21
21
|
import { RootEndpoint as BaseRootEndpoint } from "../endpoints/root.js";
|
|
22
22
|
import { Node } from "./Node.js";
|
|
23
23
|
import { ClientNodes } from "./client/ClientNodes.js";
|
|
@@ -192,7 +192,7 @@ export class ServerNode<T extends ServerNode.RootEndpoint = ServerNode.RootEndpo
|
|
|
192
192
|
await this.env.get(SessionManager).clear();
|
|
193
193
|
await this.env.get(FabricManager).clear();
|
|
194
194
|
await this.env.get(OccurrenceManager).clear();
|
|
195
|
-
await this.env.get(
|
|
195
|
+
await this.env.get(ServerNodeStore).erase();
|
|
196
196
|
}
|
|
197
197
|
|
|
198
198
|
/**
|
|
@@ -12,6 +12,7 @@ import { ServerBehaviorBacking } from "#behavior/internal/ServerBehaviorBacking.
|
|
|
12
12
|
import { Endpoint } from "#endpoint/Endpoint.js";
|
|
13
13
|
import { EndpointInitializer } from "#endpoint/properties/EndpointInitializer.js";
|
|
14
14
|
import type { ClientNode } from "#node/ClientNode.js";
|
|
15
|
+
import { ClientNodeStore } from "#storage/client/ClientNodeStore.js";
|
|
15
16
|
import { NodeStore } from "#storage/NodeStore.js";
|
|
16
17
|
import { ClientStructure } from "./ClientStructure.js";
|
|
17
18
|
|
|
@@ -23,7 +24,7 @@ export class ClientEndpointInitializer extends EndpointInitializer {
|
|
|
23
24
|
constructor(node: ClientNode) {
|
|
24
25
|
super();
|
|
25
26
|
this.#node = node;
|
|
26
|
-
this.#store = node.env.get(
|
|
27
|
+
this.#store = node.env.get(ClientNodeStore);
|
|
27
28
|
}
|
|
28
29
|
|
|
29
30
|
async eraseDescendant(endpoint: Endpoint) {
|
|
@@ -45,11 +46,14 @@ export class ClientEndpointInitializer extends EndpointInitializer {
|
|
|
45
46
|
}
|
|
46
47
|
|
|
47
48
|
override createBacking(endpoint: Endpoint, type: Behavior.Type): BehaviorBacking {
|
|
49
|
+
// Non-cluster behaviors are local operation the same server behaviors
|
|
48
50
|
if ((type as ClusterBehavior.Type).cluster === undefined) {
|
|
49
|
-
|
|
51
|
+
const store = this.structure.storeForLocal(endpoint, type);
|
|
52
|
+
return new ServerBehaviorBacking(endpoint, type, store, endpoint.behaviors.optionsFor(type));
|
|
50
53
|
}
|
|
51
54
|
|
|
52
|
-
|
|
55
|
+
// Cluster behaviors are clients to a remote cluster
|
|
56
|
+
const store = this.structure.storeForRemote(endpoint, type as ClusterBehavior.Type);
|
|
53
57
|
return new ClientBehaviorBacking(endpoint, type, store, endpoint.behaviors.optionsFor(type));
|
|
54
58
|
}
|
|
55
59
|
|
|
@@ -4,6 +4,7 @@
|
|
|
4
4
|
* SPDX-License-Identifier: Apache-2.0
|
|
5
5
|
*/
|
|
6
6
|
|
|
7
|
+
import { Behavior } from "#behavior/Behavior.js";
|
|
7
8
|
import { ClusterBehavior } from "#behavior/cluster/ClusterBehavior.js";
|
|
8
9
|
import { Datasource } from "#behavior/state/managed/Datasource.js";
|
|
9
10
|
import { DescriptorCluster } from "#clusters/descriptor";
|
|
@@ -14,7 +15,7 @@ import type { ClientNode } from "#node/ClientNode.js";
|
|
|
14
15
|
import { ReadScope, type Read, type ReadResult } from "#protocol";
|
|
15
16
|
import { DatasourceCache } from "#storage/client/DatasourceCache.js";
|
|
16
17
|
import { ClientNodeStore } from "#storage/index.js";
|
|
17
|
-
import type { AttributeId, ClusterId, CommandId, DeviceTypeId, EndpointNumber } from "#types";
|
|
18
|
+
import type { AttributeId, ClusterId, ClusterType, CommandId, DeviceTypeId, EndpointNumber } from "#types";
|
|
18
19
|
import { ClientBehavior } from "./ClientBehavior.js";
|
|
19
20
|
|
|
20
21
|
const DEVICE_TYPE_LIST_ATTR_ID = DescriptorCluster.attributes.deviceTypeList.id;
|
|
@@ -65,15 +66,24 @@ export class ClientStructure {
|
|
|
65
66
|
}
|
|
66
67
|
|
|
67
68
|
/**
|
|
68
|
-
* Obtain the store for a
|
|
69
|
+
* Obtain the store for a remote cluster.
|
|
69
70
|
*/
|
|
70
|
-
|
|
71
|
+
storeForRemote(endpoint: Endpoint, type: ClusterBehavior.Type) {
|
|
71
72
|
const endpointStructure = this.#endpointFor(endpoint.number);
|
|
72
73
|
const clusterStructure = this.#clusterFor(endpointStructure, type.cluster.id);
|
|
73
74
|
|
|
74
75
|
return clusterStructure.store;
|
|
75
76
|
}
|
|
76
77
|
|
|
78
|
+
/**
|
|
79
|
+
*
|
|
80
|
+
* @param request
|
|
81
|
+
* @returns
|
|
82
|
+
*/
|
|
83
|
+
storeForLocal(endpoint: Endpoint, type: Behavior.Type) {
|
|
84
|
+
return this.#nodeStore.storeForEndpoint(endpoint).createStoreForLocalBehavior(type.id);
|
|
85
|
+
}
|
|
86
|
+
|
|
77
87
|
/**
|
|
78
88
|
* Inject version filters into a Read or Subscribe request.
|
|
79
89
|
*/
|
|
@@ -166,6 +176,18 @@ export class ClientStructure {
|
|
|
166
176
|
}
|
|
167
177
|
}
|
|
168
178
|
|
|
179
|
+
/**
|
|
180
|
+
* Obtain the {@link ClusterType} for an endpoint number and cluster ID.
|
|
181
|
+
*/
|
|
182
|
+
clusterFor(endpoint: EndpointNumber, cluster: ClusterId) {
|
|
183
|
+
const ep = this.#endpointFor(endpoint);
|
|
184
|
+
if (!ep) {
|
|
185
|
+
return;
|
|
186
|
+
}
|
|
187
|
+
|
|
188
|
+
return this.#clusterFor(ep, cluster)?.behavior?.cluster;
|
|
189
|
+
}
|
|
190
|
+
|
|
169
191
|
/**
|
|
170
192
|
* Apply new attribute values for specific endpoint/cluster.
|
|
171
193
|
*
|
|
@@ -309,9 +331,7 @@ export class ClientStructure {
|
|
|
309
331
|
|
|
310
332
|
cluster = {
|
|
311
333
|
id,
|
|
312
|
-
store: this.#nodeStore
|
|
313
|
-
.storeForEndpoint(endpoint.endpoint)
|
|
314
|
-
.createStoreForBehavior(id.toString(), DatasourceCache),
|
|
334
|
+
store: this.#nodeStore.storeForEndpoint(endpoint.endpoint).createStoreForBehavior(id.toString()),
|
|
315
335
|
};
|
|
316
336
|
endpoint.clusters[id] = cluster;
|
|
317
337
|
|
|
@@ -59,7 +59,9 @@ export class ServerEndpointInitializer extends EndpointInitializer {
|
|
|
59
59
|
* initializes.
|
|
60
60
|
*/
|
|
61
61
|
createBacking(endpoint: Endpoint, type: Behavior.Type): BehaviorBacking {
|
|
62
|
-
|
|
62
|
+
const store = this.#store.storeForEndpoint(endpoint).createStoreForBehavior(type.id);
|
|
63
|
+
|
|
64
|
+
return new ServerBehaviorBacking(endpoint, type, store, endpoint.behaviors.optionsFor(type));
|
|
63
65
|
}
|
|
64
66
|
|
|
65
67
|
/**
|
|
@@ -10,7 +10,6 @@ import { Crypto, Observable } from "#general";
|
|
|
10
10
|
import { ServerEndpointInitializer } from "#node/server/ServerEndpointInitializer.js";
|
|
11
11
|
import type { ServerNode } from "#node/ServerNode.js";
|
|
12
12
|
import { FabricManager, SessionManager } from "#protocol";
|
|
13
|
-
import { NodeStore } from "#storage/NodeStore.js";
|
|
14
13
|
import { ServerNodeStore } from "#storage/server/ServerNodeStore.js";
|
|
15
14
|
import { IdentityService } from "./IdentityService.js";
|
|
16
15
|
|
|
@@ -26,7 +25,6 @@ export namespace ServerEnvironment {
|
|
|
26
25
|
|
|
27
26
|
// Install support services
|
|
28
27
|
const store = await ServerNodeStore.create(env, node.id);
|
|
29
|
-
env.set(NodeStore, store);
|
|
30
28
|
env.set(ServerNodeStore, store);
|
|
31
29
|
env.set(EndpointInitializer, new ServerEndpointInitializer(env));
|
|
32
30
|
env.set(IdentityService, new IdentityService(node));
|
|
@@ -7,13 +7,12 @@
|
|
|
7
7
|
import type { Datasource } from "#behavior/state/managed/Datasource.js";
|
|
8
8
|
import { StorageContext, SupportedStorageTypes } from "#general";
|
|
9
9
|
import { Val } from "#protocol";
|
|
10
|
-
import { DatasourceStore } from "./server/DatasourceStore.js";
|
|
11
10
|
|
|
12
11
|
/**
|
|
13
12
|
* Persistence for state values associated with a specific endpoint.
|
|
14
13
|
*/
|
|
15
14
|
export class EndpointStore {
|
|
16
|
-
protected initialValues =
|
|
15
|
+
protected initialValues = new Map<string, Val.Struct>();
|
|
17
16
|
|
|
18
17
|
#storage: StorageContext;
|
|
19
18
|
|
|
@@ -31,15 +30,15 @@ export class EndpointStore {
|
|
|
31
30
|
}
|
|
32
31
|
|
|
33
32
|
/**
|
|
34
|
-
*
|
|
33
|
+
* Extract initial values for a behavior. Derivatives invoke this when instantiating a store. The values are then
|
|
34
|
+
* owned by the store.
|
|
35
35
|
*/
|
|
36
|
-
|
|
37
|
-
const initialValues = this.initialValues
|
|
36
|
+
protected consumeInitialValues(behaviorId: string) {
|
|
37
|
+
const initialValues = this.initialValues.get(behaviorId);
|
|
38
38
|
if (initialValues !== undefined) {
|
|
39
|
-
|
|
39
|
+
this.initialValues.delete(behaviorId);
|
|
40
40
|
}
|
|
41
|
-
|
|
42
|
-
return factory(this, behaviorId, initialValues) as ReturnType<T>;
|
|
41
|
+
return initialValues;
|
|
43
42
|
}
|
|
44
43
|
|
|
45
44
|
/**
|
|
@@ -102,7 +101,8 @@ export class EndpointStore {
|
|
|
102
101
|
this.#knownBehaviors = new Set(await this.storage.contexts());
|
|
103
102
|
|
|
104
103
|
for (const behaviorId of this.#knownBehaviors) {
|
|
105
|
-
const behaviorValues =
|
|
104
|
+
const behaviorValues = {} as Val.Struct;
|
|
105
|
+
this.initialValues.set(behaviorId, behaviorValues);
|
|
106
106
|
const behaviorStorage = this.storage.createContext(behaviorId);
|
|
107
107
|
|
|
108
108
|
const storedValues = await behaviorStorage.values();
|
|
@@ -0,0 +1,53 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* @license
|
|
3
|
+
* Copyright 2022-2025 Matter.js Authors
|
|
4
|
+
* SPDX-License-Identifier: Apache-2.0
|
|
5
|
+
*/
|
|
6
|
+
|
|
7
|
+
import { StorageContext, Transaction } from "#general";
|
|
8
|
+
import { EndpointStore } from "#storage/EndpointStore.js";
|
|
9
|
+
import { DatasourceStore } from "#storage/server/DatasourceStore.js";
|
|
10
|
+
import type { EndpointNumber } from "#types";
|
|
11
|
+
import type { ClientNodeStore } from "./ClientNodeStore.js";
|
|
12
|
+
import { DatasourceCache } from "./DatasourceCache.js";
|
|
13
|
+
import { RemoteWriteParticipant } from "./RemoteWriteParticipant.js";
|
|
14
|
+
|
|
15
|
+
export class ClientEndpointStore extends EndpointStore {
|
|
16
|
+
#owner: ClientNodeStore;
|
|
17
|
+
#number: EndpointNumber;
|
|
18
|
+
|
|
19
|
+
constructor(owner: ClientNodeStore, number: EndpointNumber, storage: StorageContext) {
|
|
20
|
+
super(storage);
|
|
21
|
+
this.#owner = owner;
|
|
22
|
+
this.#number = number;
|
|
23
|
+
}
|
|
24
|
+
|
|
25
|
+
get number() {
|
|
26
|
+
return this.#number;
|
|
27
|
+
}
|
|
28
|
+
|
|
29
|
+
participantFor(transaction: Transaction) {
|
|
30
|
+
let participant = transaction.getParticipant(this.#owner);
|
|
31
|
+
if (participant === undefined) {
|
|
32
|
+
participant = new RemoteWriteParticipant(this.#owner);
|
|
33
|
+
transaction.addParticipants(participant);
|
|
34
|
+
}
|
|
35
|
+
return participant;
|
|
36
|
+
}
|
|
37
|
+
|
|
38
|
+
/**
|
|
39
|
+
* Create a {@link Datasource.ExternallyMutableStore} for a behavior.
|
|
40
|
+
*/
|
|
41
|
+
createStoreForBehavior(behaviorId: string) {
|
|
42
|
+
const initialValues = this.consumeInitialValues(behaviorId);
|
|
43
|
+
return DatasourceCache(this, behaviorId, initialValues);
|
|
44
|
+
}
|
|
45
|
+
|
|
46
|
+
/**
|
|
47
|
+
* Create a {@link Datasource.Store} for a behavior that does not track a remote cluster.
|
|
48
|
+
*/
|
|
49
|
+
createStoreForLocalBehavior(behaviorId: string) {
|
|
50
|
+
const initialValues = this.consumeInitialValues(behaviorId);
|
|
51
|
+
return DatasourceStore(this, behaviorId, initialValues);
|
|
52
|
+
}
|
|
53
|
+
}
|
|
@@ -5,14 +5,46 @@
|
|
|
5
5
|
*/
|
|
6
6
|
|
|
7
7
|
import { Endpoint } from "#endpoint/Endpoint.js";
|
|
8
|
-
import { InternalError, StorageContext } from "#general";
|
|
9
|
-
import {
|
|
8
|
+
import { InternalError, StorageContext, StorageContextFactory } from "#general";
|
|
9
|
+
import type { ClientNode } from "#node/ClientNode.js";
|
|
10
10
|
import { EndpointNumber } from "#types";
|
|
11
11
|
import { NodeStore } from "../NodeStore.js";
|
|
12
|
+
import { ClientEndpointStore } from "./ClientEndpointStore.js";
|
|
13
|
+
import type { RemoteWriter } from "./RemoteWriter.js";
|
|
12
14
|
|
|
15
|
+
/**
|
|
16
|
+
* {@link ClientNode} persistence.
|
|
17
|
+
*/
|
|
13
18
|
export class ClientNodeStore extends NodeStore {
|
|
19
|
+
#id: string;
|
|
14
20
|
#storage?: StorageContext;
|
|
15
|
-
#stores = new Map<EndpointNumber,
|
|
21
|
+
#stores = new Map<EndpointNumber, ClientEndpointStore>();
|
|
22
|
+
#write?: RemoteWriter;
|
|
23
|
+
|
|
24
|
+
constructor(id: string, storage: StorageContextFactory) {
|
|
25
|
+
super(storage);
|
|
26
|
+
this.#id = id;
|
|
27
|
+
}
|
|
28
|
+
|
|
29
|
+
override toString() {
|
|
30
|
+
return `client-node-store#${this.#id}`;
|
|
31
|
+
}
|
|
32
|
+
|
|
33
|
+
get id() {
|
|
34
|
+
return this.#id;
|
|
35
|
+
}
|
|
36
|
+
|
|
37
|
+
get write() {
|
|
38
|
+
if (this.#write === undefined) {
|
|
39
|
+
throw new InternalError("Write attempt on ClientNodeStore without writer installed");
|
|
40
|
+
}
|
|
41
|
+
|
|
42
|
+
return this.#write;
|
|
43
|
+
}
|
|
44
|
+
|
|
45
|
+
set write(write: RemoteWriter) {
|
|
46
|
+
this.#write = write;
|
|
47
|
+
}
|
|
16
48
|
|
|
17
49
|
get endpointStores() {
|
|
18
50
|
return this.#stores.values();
|
|
@@ -23,7 +55,7 @@ export class ClientNodeStore extends NodeStore {
|
|
|
23
55
|
return this.#storage?.clearAll();
|
|
24
56
|
}
|
|
25
57
|
|
|
26
|
-
override storeForEndpoint(endpoint: Endpoint)
|
|
58
|
+
override storeForEndpoint(endpoint: Endpoint) {
|
|
27
59
|
const { number } = endpoint;
|
|
28
60
|
|
|
29
61
|
if (this.#storage === undefined) {
|
|
@@ -32,7 +64,7 @@ export class ClientNodeStore extends NodeStore {
|
|
|
32
64
|
|
|
33
65
|
let store = this.#stores.get(number);
|
|
34
66
|
if (store === undefined) {
|
|
35
|
-
store = new
|
|
67
|
+
store = new ClientEndpointStore(this, number, this.#storage.createContext(number.toString()));
|
|
36
68
|
this.#stores.set(number, store);
|
|
37
69
|
}
|
|
38
70
|
|
|
@@ -47,7 +79,7 @@ export class ClientNodeStore extends NodeStore {
|
|
|
47
79
|
continue;
|
|
48
80
|
}
|
|
49
81
|
|
|
50
|
-
const store = new
|
|
82
|
+
const store = new ClientEndpointStore(this, number, this.#storage.createContext(id));
|
|
51
83
|
await store.load();
|
|
52
84
|
this.#stores.set(number, store);
|
|
53
85
|
}
|
|
@@ -7,7 +7,6 @@
|
|
|
7
7
|
import { Construction, MatterAggregateError, StorageContext } from "#general";
|
|
8
8
|
import type { ClientNode } from "#node/ClientNode.js";
|
|
9
9
|
import type { Node } from "#node/Node.js";
|
|
10
|
-
import { NodeStore } from "../NodeStore.js";
|
|
11
10
|
import { ClientNodeStore } from "./ClientNodeStore.js";
|
|
12
11
|
|
|
13
12
|
const CLIENT_ID_PREFIX = "peer";
|
|
@@ -17,7 +16,7 @@ const CLIENT_ID_PREFIX = "peer";
|
|
|
17
16
|
*/
|
|
18
17
|
export class ClientNodeStores {
|
|
19
18
|
#storage: StorageContext;
|
|
20
|
-
#stores = {} as Record<string,
|
|
19
|
+
#stores = {} as Record<string, ClientNodeStore>;
|
|
21
20
|
#construction: Construction<ClientNodeStores>;
|
|
22
21
|
#nextAutomaticId = 1;
|
|
23
22
|
|
|
@@ -72,7 +71,7 @@ export class ClientNodeStores {
|
|
|
72
71
|
*
|
|
73
72
|
* These stores are cached internally by ID.
|
|
74
73
|
*/
|
|
75
|
-
storeForNode(node: ClientNode):
|
|
74
|
+
storeForNode(node: ClientNode): ClientNodeStore {
|
|
76
75
|
this.#construction.assert();
|
|
77
76
|
|
|
78
77
|
const store = this.#stores[node.id];
|
|
@@ -97,7 +96,7 @@ export class ClientNodeStores {
|
|
|
97
96
|
}
|
|
98
97
|
|
|
99
98
|
#createNodeStore(id: string) {
|
|
100
|
-
const store = new ClientNodeStore(this.#storage.createContext(id));
|
|
99
|
+
const store = new ClientNodeStore(id, this.#storage.createContext(id));
|
|
101
100
|
store.construction.start();
|
|
102
101
|
this.#stores[id] = store;
|
|
103
102
|
return store;
|
|
@@ -5,10 +5,10 @@
|
|
|
5
5
|
*/
|
|
6
6
|
|
|
7
7
|
import { Datasource } from "#behavior/state/managed/Datasource.js";
|
|
8
|
-
import { InternalError } from "#general";
|
|
8
|
+
import { InternalError, Transaction } from "#general";
|
|
9
9
|
import { Val } from "#protocol";
|
|
10
|
-
import {
|
|
11
|
-
import {
|
|
10
|
+
import type { ClientEndpointStore } from "./ClientEndpointStore.js";
|
|
11
|
+
import type { RemoteWriteParticipant } from "./RemoteWriteParticipant.js";
|
|
12
12
|
|
|
13
13
|
/**
|
|
14
14
|
* Factory function for the default implementation of {@link Datasource.ExternallyMutableStore}.
|
|
@@ -16,7 +16,7 @@ import { DatasourceStore } from "../server/DatasourceStore.js";
|
|
|
16
16
|
* This implements storage for attribute values for a single cluster loaded from remote nodes.
|
|
17
17
|
*/
|
|
18
18
|
export function DatasourceCache(
|
|
19
|
-
store:
|
|
19
|
+
store: ClientEndpointStore,
|
|
20
20
|
behaviorId: string,
|
|
21
21
|
initialValues: Val.Struct | undefined,
|
|
22
22
|
): Datasource.ExternallyMutableStore {
|
|
@@ -26,7 +26,12 @@ export function DatasourceCache(
|
|
|
26
26
|
}
|
|
27
27
|
|
|
28
28
|
return {
|
|
29
|
-
|
|
29
|
+
initialValues,
|
|
30
|
+
|
|
31
|
+
async set(transaction: Transaction, values: Val.Struct) {
|
|
32
|
+
const participant = store.participantFor(transaction) as RemoteWriteParticipant;
|
|
33
|
+
participant.set(store.number, behaviorId, values);
|
|
34
|
+
},
|
|
30
35
|
|
|
31
36
|
async externalSet(values: Val.Struct) {
|
|
32
37
|
if (typeof values[DatasourceCache.VERSION_KEY] === "number") {
|
|
@@ -57,8 +62,6 @@ export function DatasourceCache(
|
|
|
57
62
|
};
|
|
58
63
|
}
|
|
59
64
|
|
|
60
|
-
DatasourceCache satisfies DatasourceStore.Type;
|
|
61
|
-
|
|
62
65
|
export namespace DatasourceCache {
|
|
63
66
|
/**
|
|
64
67
|
* Standard key for storing the version.
|
|
@@ -0,0 +1,62 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* @license
|
|
3
|
+
* Copyright 2022-2025 Matter.js Authors
|
|
4
|
+
* SPDX-License-Identifier: Apache-2.0
|
|
5
|
+
*/
|
|
6
|
+
|
|
7
|
+
import { Transaction } from "#general";
|
|
8
|
+
import { Val } from "#protocol";
|
|
9
|
+
import { EndpointNumber } from "#types";
|
|
10
|
+
import type { ClientNodeStore } from "./ClientNodeStore.js";
|
|
11
|
+
import type { RemoteWriter } from "./RemoteWriter.js";
|
|
12
|
+
|
|
13
|
+
/**
|
|
14
|
+
* A transaction participant that persists changes to a remote node.
|
|
15
|
+
*
|
|
16
|
+
* There is one of these for node/transaction pair. All attributes in a transaction commit with a single interaction.
|
|
17
|
+
*/
|
|
18
|
+
export class RemoteWriteParticipant implements Transaction.Participant {
|
|
19
|
+
#request: RemoteWriter.Request = [];
|
|
20
|
+
#store: ClientNodeStore;
|
|
21
|
+
|
|
22
|
+
/**
|
|
23
|
+
* There is one participant for each transaction/client node pair. We therefore use the store as the role.
|
|
24
|
+
*/
|
|
25
|
+
get role() {
|
|
26
|
+
return this.#store;
|
|
27
|
+
}
|
|
28
|
+
|
|
29
|
+
/**
|
|
30
|
+
* Add an attribute update to the write request.
|
|
31
|
+
*/
|
|
32
|
+
set(endpointNumber: EndpointNumber, behaviorId: string, values: Val.Struct) {
|
|
33
|
+
this.#request.push({
|
|
34
|
+
number: endpointNumber,
|
|
35
|
+
behaviorId: behaviorId,
|
|
36
|
+
values,
|
|
37
|
+
});
|
|
38
|
+
}
|
|
39
|
+
|
|
40
|
+
async commit2() {
|
|
41
|
+
if (!this.#request.length) {
|
|
42
|
+
return;
|
|
43
|
+
}
|
|
44
|
+
|
|
45
|
+
const request = this.#request;
|
|
46
|
+
this.#request = [];
|
|
47
|
+
|
|
48
|
+
await this.#store.write(request);
|
|
49
|
+
}
|
|
50
|
+
|
|
51
|
+
rollback() {
|
|
52
|
+
this.#request = [];
|
|
53
|
+
}
|
|
54
|
+
|
|
55
|
+
toString() {
|
|
56
|
+
return `writer#${this.#store.id}`;
|
|
57
|
+
}
|
|
58
|
+
|
|
59
|
+
constructor(store: ClientNodeStore) {
|
|
60
|
+
this.#store = store;
|
|
61
|
+
}
|
|
62
|
+
}
|