@matter/node 0.16.0-alpha.0-20251108-514b3f69e → 0.16.0-alpha.0-20251110-c4c70a41b
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/cluster/ClientBehavior.d.ts +0 -7
- package/dist/cjs/behavior/cluster/ClientBehavior.d.ts.map +1 -1
- package/dist/cjs/behavior/cluster/ClientBehavior.js +2 -8
- package/dist/cjs/behavior/cluster/ClientBehavior.js.map +2 -2
- package/dist/cjs/behavior/cluster/ClusterBehavior.d.ts +1 -1
- package/dist/cjs/behavior/cluster/ClusterBehavior.d.ts.map +1 -1
- package/dist/cjs/behavior/cluster/ClusterBehavior.js +9 -4
- package/dist/cjs/behavior/cluster/ClusterBehavior.js.map +1 -1
- package/dist/cjs/behavior/cluster/ClusterBehaviorCache.d.ts +7 -1
- package/dist/cjs/behavior/cluster/ClusterBehaviorCache.d.ts.map +1 -1
- package/dist/cjs/behavior/cluster/ClusterBehaviorCache.js +7 -5
- package/dist/cjs/behavior/cluster/ClusterBehaviorCache.js.map +1 -1
- package/dist/cjs/behavior/cluster/ClusterBehaviorType.d.ts +57 -0
- package/dist/cjs/behavior/cluster/ClusterBehaviorType.d.ts.map +1 -0
- package/dist/cjs/behavior/cluster/{ClusterBehaviorUtil.js → ClusterBehaviorType.js} +70 -39
- package/dist/cjs/behavior/cluster/ClusterBehaviorType.js.map +6 -0
- package/dist/cjs/behavior/cluster/ClusterEvents.d.ts +1 -1
- package/dist/cjs/behavior/cluster/ClusterEvents.d.ts.map +1 -1
- package/dist/cjs/behavior/cluster/ClusterState.d.ts +1 -1
- package/dist/cjs/behavior/cluster/ClusterState.d.ts.map +1 -1
- package/dist/cjs/behavior/cluster/ValidatedElements.js +2 -2
- package/dist/cjs/behavior/cluster/ValidatedElements.js.map +1 -1
- package/dist/cjs/behavior/cluster/{ClusterBehaviorUtil.d.ts → cluster-behavior-utils.d.ts} +10 -8
- package/dist/cjs/behavior/cluster/cluster-behavior-utils.d.ts.map +1 -0
- package/dist/cjs/behavior/cluster/cluster-behavior-utils.js +41 -0
- package/dist/cjs/behavior/cluster/cluster-behavior-utils.js.map +6 -0
- package/dist/cjs/behavior/cluster/index.d.ts +2 -1
- package/dist/cjs/behavior/cluster/index.d.ts.map +1 -1
- package/dist/cjs/behavior/cluster/index.js +2 -1
- package/dist/cjs/behavior/cluster/index.js.map +1 -1
- package/dist/cjs/behavior/context/server/LocalActorContext.d.ts +4 -0
- package/dist/cjs/behavior/context/server/LocalActorContext.d.ts.map +1 -1
- package/dist/cjs/behavior/context/server/LocalActorContext.js +2 -3
- package/dist/cjs/behavior/context/server/LocalActorContext.js.map +1 -1
- package/dist/cjs/behavior/context/server/RemoteActorContext.d.ts +4 -0
- package/dist/cjs/behavior/context/server/RemoteActorContext.d.ts.map +1 -1
- package/dist/cjs/behavior/context/server/RemoteActorContext.js +1 -0
- package/dist/cjs/behavior/context/server/RemoteActorContext.js.map +1 -1
- package/dist/cjs/behavior/internal/BehaviorBacking.js +2 -2
- package/dist/cjs/behavior/internal/BehaviorBacking.js.map +1 -1
- package/dist/cjs/behavior/system/commissioning/CommissioningServer.d.ts.map +1 -1
- package/dist/cjs/behavior/system/commissioning/CommissioningServer.js +3 -3
- package/dist/cjs/behavior/system/commissioning/CommissioningServer.js.map +1 -1
- package/dist/cjs/behaviors/operational-credentials/OperationalCredentialsServer.js +1 -1
- package/dist/cjs/behaviors/operational-credentials/OperationalCredentialsServer.js.map +1 -1
- package/dist/cjs/behaviors/operational-credentials/VendorIdVerification.d.ts +6 -1
- package/dist/cjs/behaviors/operational-credentials/VendorIdVerification.d.ts.map +1 -1
- package/dist/cjs/behaviors/operational-credentials/VendorIdVerification.js +2 -2
- package/dist/cjs/behaviors/operational-credentials/VendorIdVerification.js.map +1 -1
- package/dist/cjs/endpoint/Endpoint.d.ts +8 -0
- package/dist/cjs/endpoint/Endpoint.d.ts.map +1 -1
- package/dist/cjs/endpoint/Endpoint.js +11 -3
- package/dist/cjs/endpoint/Endpoint.js.map +1 -1
- package/dist/cjs/endpoint/properties/Behaviors.d.ts +1 -1
- package/dist/cjs/endpoint/properties/Behaviors.d.ts.map +1 -1
- package/dist/cjs/endpoint/properties/Behaviors.js +6 -3
- package/dist/cjs/endpoint/properties/Behaviors.js.map +1 -1
- package/dist/cjs/endpoint/properties/EndpointInitializer.d.ts +0 -4
- package/dist/cjs/endpoint/properties/EndpointInitializer.d.ts.map +1 -1
- package/dist/cjs/endpoint/properties/EndpointInitializer.js +0 -6
- package/dist/cjs/endpoint/properties/EndpointInitializer.js.map +1 -1
- package/dist/cjs/node/Node.d.ts.map +1 -1
- package/dist/cjs/node/Node.js +2 -1
- package/dist/cjs/node/Node.js.map +1 -1
- package/dist/cjs/node/client/ClientCommandMethod.d.ts +11 -0
- package/dist/cjs/node/client/ClientCommandMethod.d.ts.map +1 -0
- package/dist/cjs/node/client/ClientCommandMethod.js +69 -0
- package/dist/cjs/node/client/ClientCommandMethod.js.map +6 -0
- package/dist/cjs/node/client/ClientEndpointInitializer.d.ts +0 -2
- package/dist/cjs/node/client/ClientEndpointInitializer.d.ts.map +1 -1
- package/dist/cjs/node/client/ClientEndpointInitializer.js +3 -34
- package/dist/cjs/node/client/ClientEndpointInitializer.js.map +1 -1
- package/dist/cjs/node/client/ClientStructure.d.ts.map +1 -1
- package/dist/cjs/node/client/ClientStructure.js +164 -32
- package/dist/cjs/node/client/ClientStructure.js.map +2 -2
- package/dist/cjs/node/client/ClientStructureEvents.d.ts +22 -0
- package/dist/cjs/node/client/ClientStructureEvents.d.ts.map +1 -0
- package/dist/cjs/node/client/ClientStructureEvents.js +92 -0
- package/dist/cjs/node/client/ClientStructureEvents.js.map +6 -0
- package/dist/cjs/node/client/PeerBehavior.d.ts +14 -1
- package/dist/cjs/node/client/PeerBehavior.d.ts.map +1 -1
- package/dist/cjs/node/client/PeerBehavior.js +111 -71
- package/dist/cjs/node/client/PeerBehavior.js.map +1 -1
- package/dist/cjs/node/client/Peers.d.ts +17 -0
- package/dist/cjs/node/client/Peers.d.ts.map +1 -1
- package/dist/cjs/node/client/Peers.js +96 -42
- package/dist/cjs/node/client/Peers.js.map +1 -1
- package/dist/cjs/node/server/ServerSubscription.d.ts +1 -1
- package/dist/cjs/node/server/ServerSubscription.d.ts.map +1 -1
- package/dist/cjs/node/server/ServerSubscription.js +2 -3
- package/dist/cjs/node/server/ServerSubscription.js.map +1 -1
- package/dist/esm/behavior/cluster/ClientBehavior.d.ts +0 -7
- package/dist/esm/behavior/cluster/ClientBehavior.d.ts.map +1 -1
- package/dist/esm/behavior/cluster/ClientBehavior.js +2 -8
- package/dist/esm/behavior/cluster/ClientBehavior.js.map +2 -2
- package/dist/esm/behavior/cluster/ClusterBehavior.d.ts +1 -1
- package/dist/esm/behavior/cluster/ClusterBehavior.d.ts.map +1 -1
- package/dist/esm/behavior/cluster/ClusterBehavior.js +9 -4
- package/dist/esm/behavior/cluster/ClusterBehavior.js.map +1 -1
- package/dist/esm/behavior/cluster/ClusterBehaviorCache.d.ts +7 -1
- package/dist/esm/behavior/cluster/ClusterBehaviorCache.d.ts.map +1 -1
- package/dist/esm/behavior/cluster/ClusterBehaviorCache.js +7 -5
- package/dist/esm/behavior/cluster/ClusterBehaviorCache.js.map +1 -1
- package/dist/esm/behavior/cluster/ClusterBehaviorType.d.ts +57 -0
- package/dist/esm/behavior/cluster/ClusterBehaviorType.d.ts.map +1 -0
- package/dist/esm/behavior/cluster/{ClusterBehaviorUtil.js → ClusterBehaviorType.js} +66 -35
- package/dist/esm/behavior/cluster/ClusterBehaviorType.js.map +6 -0
- package/dist/esm/behavior/cluster/ClusterEvents.d.ts +1 -1
- package/dist/esm/behavior/cluster/ClusterEvents.d.ts.map +1 -1
- package/dist/esm/behavior/cluster/ClusterState.d.ts +1 -1
- package/dist/esm/behavior/cluster/ClusterState.d.ts.map +1 -1
- package/dist/esm/behavior/cluster/ValidatedElements.js +1 -1
- package/dist/esm/behavior/cluster/{ClusterBehaviorUtil.d.ts → cluster-behavior-utils.d.ts} +10 -8
- package/dist/esm/behavior/cluster/cluster-behavior-utils.d.ts.map +1 -0
- package/dist/esm/behavior/cluster/cluster-behavior-utils.js +21 -0
- package/dist/esm/behavior/cluster/cluster-behavior-utils.js.map +6 -0
- package/dist/esm/behavior/cluster/index.d.ts +2 -1
- package/dist/esm/behavior/cluster/index.d.ts.map +1 -1
- package/dist/esm/behavior/cluster/index.js +2 -1
- package/dist/esm/behavior/cluster/index.js.map +1 -1
- package/dist/esm/behavior/context/server/LocalActorContext.d.ts +4 -0
- package/dist/esm/behavior/context/server/LocalActorContext.d.ts.map +1 -1
- package/dist/esm/behavior/context/server/LocalActorContext.js +2 -3
- package/dist/esm/behavior/context/server/LocalActorContext.js.map +1 -1
- package/dist/esm/behavior/context/server/RemoteActorContext.d.ts +4 -0
- package/dist/esm/behavior/context/server/RemoteActorContext.d.ts.map +1 -1
- package/dist/esm/behavior/context/server/RemoteActorContext.js +1 -0
- package/dist/esm/behavior/context/server/RemoteActorContext.js.map +1 -1
- package/dist/esm/behavior/internal/BehaviorBacking.js +2 -2
- package/dist/esm/behavior/internal/BehaviorBacking.js.map +1 -1
- package/dist/esm/behavior/system/commissioning/CommissioningServer.d.ts.map +1 -1
- package/dist/esm/behavior/system/commissioning/CommissioningServer.js +4 -3
- package/dist/esm/behavior/system/commissioning/CommissioningServer.js.map +1 -1
- package/dist/esm/behaviors/operational-credentials/OperationalCredentialsServer.js +1 -1
- package/dist/esm/behaviors/operational-credentials/OperationalCredentialsServer.js.map +1 -1
- package/dist/esm/behaviors/operational-credentials/VendorIdVerification.d.ts +6 -1
- package/dist/esm/behaviors/operational-credentials/VendorIdVerification.d.ts.map +1 -1
- package/dist/esm/behaviors/operational-credentials/VendorIdVerification.js +1 -1
- package/dist/esm/behaviors/operational-credentials/VendorIdVerification.js.map +1 -1
- package/dist/esm/endpoint/Endpoint.d.ts +8 -0
- package/dist/esm/endpoint/Endpoint.d.ts.map +1 -1
- package/dist/esm/endpoint/Endpoint.js +11 -3
- package/dist/esm/endpoint/Endpoint.js.map +1 -1
- package/dist/esm/endpoint/properties/Behaviors.d.ts +1 -1
- package/dist/esm/endpoint/properties/Behaviors.d.ts.map +1 -1
- package/dist/esm/endpoint/properties/Behaviors.js +6 -3
- package/dist/esm/endpoint/properties/Behaviors.js.map +1 -1
- package/dist/esm/endpoint/properties/EndpointInitializer.d.ts +0 -4
- package/dist/esm/endpoint/properties/EndpointInitializer.d.ts.map +1 -1
- package/dist/esm/endpoint/properties/EndpointInitializer.js +0 -6
- package/dist/esm/endpoint/properties/EndpointInitializer.js.map +1 -1
- package/dist/esm/node/Node.d.ts.map +1 -1
- package/dist/esm/node/Node.js +2 -1
- package/dist/esm/node/Node.js.map +1 -1
- package/dist/esm/node/client/ClientCommandMethod.d.ts +11 -0
- package/dist/esm/node/client/ClientCommandMethod.d.ts.map +1 -0
- package/dist/esm/node/client/ClientCommandMethod.js +49 -0
- package/dist/esm/node/client/ClientCommandMethod.js.map +6 -0
- package/dist/esm/node/client/ClientEndpointInitializer.d.ts +0 -2
- package/dist/esm/node/client/ClientEndpointInitializer.d.ts.map +1 -1
- package/dist/esm/node/client/ClientEndpointInitializer.js +3 -34
- package/dist/esm/node/client/ClientEndpointInitializer.js.map +1 -1
- package/dist/esm/node/client/ClientStructure.d.ts.map +1 -1
- package/dist/esm/node/client/ClientStructure.js +164 -32
- package/dist/esm/node/client/ClientStructure.js.map +2 -2
- package/dist/esm/node/client/ClientStructureEvents.d.ts +22 -0
- package/dist/esm/node/client/ClientStructureEvents.d.ts.map +1 -0
- package/dist/esm/node/client/ClientStructureEvents.js +72 -0
- package/dist/esm/node/client/ClientStructureEvents.js.map +6 -0
- package/dist/esm/node/client/PeerBehavior.d.ts +14 -1
- package/dist/esm/node/client/PeerBehavior.d.ts.map +1 -1
- package/dist/esm/node/client/PeerBehavior.js +119 -74
- package/dist/esm/node/client/PeerBehavior.js.map +1 -1
- package/dist/esm/node/client/Peers.d.ts +17 -0
- package/dist/esm/node/client/Peers.d.ts.map +1 -1
- package/dist/esm/node/client/Peers.js +106 -43
- package/dist/esm/node/client/Peers.js.map +1 -1
- package/dist/esm/node/server/ServerSubscription.d.ts +1 -1
- package/dist/esm/node/server/ServerSubscription.d.ts.map +1 -1
- package/dist/esm/node/server/ServerSubscription.js +2 -3
- package/dist/esm/node/server/ServerSubscription.js.map +1 -1
- package/package.json +7 -7
- package/src/behavior/cluster/ClientBehavior.ts +2 -16
- package/src/behavior/cluster/ClusterBehavior.ts +9 -4
- package/src/behavior/cluster/ClusterBehaviorCache.ts +16 -9
- package/src/behavior/cluster/{ClusterBehaviorUtil.ts → ClusterBehaviorType.ts} +160 -64
- package/src/behavior/cluster/ClusterEvents.ts +1 -1
- package/src/behavior/cluster/ClusterState.ts +1 -1
- package/src/behavior/cluster/ValidatedElements.ts +1 -1
- package/src/behavior/cluster/cluster-behavior-utils.ts +48 -0
- package/src/behavior/cluster/index.ts +2 -1
- package/src/behavior/context/server/LocalActorContext.ts +8 -4
- package/src/behavior/context/server/RemoteActorContext.ts +6 -0
- package/src/behavior/internal/BehaviorBacking.ts +2 -2
- package/src/behavior/system/commissioning/CommissioningServer.ts +4 -3
- package/src/behaviors/operational-credentials/OperationalCredentialsServer.ts +1 -1
- package/src/behaviors/operational-credentials/VendorIdVerification.ts +3 -2
- package/src/endpoint/Endpoint.ts +23 -3
- package/src/endpoint/properties/Behaviors.ts +12 -6
- package/src/endpoint/properties/EndpointInitializer.ts +0 -7
- package/src/node/Node.ts +2 -1
- package/src/node/client/ClientCommandMethod.ts +63 -0
- package/src/node/client/ClientEndpointInitializer.ts +6 -39
- package/src/node/client/ClientStructure.ts +133 -27
- package/src/node/client/ClientStructureEvents.ts +97 -0
- package/src/node/client/PeerBehavior.ts +185 -104
- package/src/node/client/Peers.ts +131 -51
- package/src/node/server/ServerSubscription.ts +3 -3
- package/dist/cjs/behavior/cluster/ClusterBehaviorUtil.d.ts.map +0 -1
- package/dist/cjs/behavior/cluster/ClusterBehaviorUtil.js.map +0 -6
- package/dist/esm/behavior/cluster/ClusterBehaviorUtil.d.ts.map +0 -1
- package/dist/esm/behavior/cluster/ClusterBehaviorUtil.js.map +0 -6
|
@@ -15,7 +15,12 @@ export let nextInternalId = 1;
|
|
|
15
15
|
|
|
16
16
|
let ReadOnly: LocalActorContext | undefined;
|
|
17
17
|
|
|
18
|
-
export interface LocalActorContext extends ValueSupervisor.LocalActorSession {
|
|
18
|
+
export interface LocalActorContext extends ValueSupervisor.LocalActorSession {
|
|
19
|
+
/**
|
|
20
|
+
* @deprecated use `context.fabric === undefined` or `hasLocalActor(context)` to detect a local actor
|
|
21
|
+
*/
|
|
22
|
+
offline: true;
|
|
23
|
+
}
|
|
19
24
|
|
|
20
25
|
/**
|
|
21
26
|
* The context for operations triggered locally, either for in-process node implementations or remote nodes that are
|
|
@@ -80,9 +85,6 @@ export const LocalActorContext = {
|
|
|
80
85
|
const context = Object.freeze({
|
|
81
86
|
...options,
|
|
82
87
|
|
|
83
|
-
// Disable access level enforcement
|
|
84
|
-
offline: true,
|
|
85
|
-
|
|
86
88
|
transaction,
|
|
87
89
|
activity: frame,
|
|
88
90
|
|
|
@@ -101,6 +103,8 @@ export const LocalActorContext = {
|
|
|
101
103
|
|
|
102
104
|
resolve: transaction.resolve.bind(transaction),
|
|
103
105
|
reject: transaction.reject.bind(transaction),
|
|
106
|
+
|
|
107
|
+
offline: true,
|
|
104
108
|
});
|
|
105
109
|
|
|
106
110
|
return context;
|
|
@@ -45,6 +45,11 @@ export interface RemoteActorContext extends ValueSupervisor.RemoteActorSession {
|
|
|
45
45
|
* The priority of actions in this context.
|
|
46
46
|
*/
|
|
47
47
|
priority?: Priority;
|
|
48
|
+
|
|
49
|
+
/**
|
|
50
|
+
* @deprecated use `context.fabric !== undefined` or `hasRemoteActor(context)` to detect a remote actor
|
|
51
|
+
*/
|
|
52
|
+
offline?: false;
|
|
48
53
|
}
|
|
49
54
|
|
|
50
55
|
/**
|
|
@@ -185,6 +190,7 @@ export function RemoteActorContext(options: RemoteActorContext.Options) {
|
|
|
185
190
|
exchange,
|
|
186
191
|
subject,
|
|
187
192
|
largeMessage: exchange?.channel.supportsLargeMessages,
|
|
193
|
+
offline: false,
|
|
188
194
|
|
|
189
195
|
fabric: fabric?.fabricIndex ?? FabricIndex.NO_FABRIC,
|
|
190
196
|
transaction,
|
|
@@ -4,7 +4,7 @@
|
|
|
4
4
|
* SPDX-License-Identifier: Apache-2.0
|
|
5
5
|
*/
|
|
6
6
|
|
|
7
|
-
import {
|
|
7
|
+
import { isClientBehavior } from "#behavior/cluster/cluster-behavior-utils.js";
|
|
8
8
|
import { OnlineEvent } from "#behavior/Events.js";
|
|
9
9
|
import { Migration } from "#behavior/state/migrations/Migration.js";
|
|
10
10
|
import type { Agent } from "#endpoint/Agent.js";
|
|
@@ -185,7 +185,7 @@ export abstract class BehaviorBacking {
|
|
|
185
185
|
*/
|
|
186
186
|
createBehavior(agent: Agent, type: Behavior.Type) {
|
|
187
187
|
const behavior = new this.#type(agent, this);
|
|
188
|
-
if (behavior instanceof type ||
|
|
188
|
+
if (behavior instanceof type || isClientBehavior(type)) {
|
|
189
189
|
return behavior;
|
|
190
190
|
}
|
|
191
191
|
|
|
@@ -18,6 +18,7 @@ import {
|
|
|
18
18
|
Logger,
|
|
19
19
|
MatterFlowError,
|
|
20
20
|
Mutex,
|
|
21
|
+
MutexClosedError,
|
|
21
22
|
Observable,
|
|
22
23
|
} from "#general";
|
|
23
24
|
import { DatatypeModel, FieldElement } from "#model";
|
|
@@ -159,14 +160,14 @@ export class CommissioningServer extends Behavior {
|
|
|
159
160
|
const sessions = this.agent.get(SessionsBehavior);
|
|
160
161
|
if (Object.keys(sessions.state.sessions).length > 0) {
|
|
161
162
|
// We have still open sessions, wait for them to close
|
|
162
|
-
this.reactTo(sessions.events.closed, this.#
|
|
163
|
+
this.reactTo(sessions.events.closed, this.#resetAfterSessionsClear);
|
|
163
164
|
} else {
|
|
164
165
|
this.#triggerFactoryReset();
|
|
165
166
|
}
|
|
166
167
|
}
|
|
167
168
|
}
|
|
168
169
|
|
|
169
|
-
#
|
|
170
|
+
#resetAfterSessionsClear() {
|
|
170
171
|
const sessions = this.agent.get(SessionsBehavior);
|
|
171
172
|
if (Object.keys(sessions.state.sessions).length === 0) {
|
|
172
173
|
this.#triggerFactoryReset();
|
|
@@ -174,7 +175,7 @@ export class CommissioningServer extends Behavior {
|
|
|
174
175
|
}
|
|
175
176
|
|
|
176
177
|
#triggerFactoryReset() {
|
|
177
|
-
this.env.runtime.add((this.endpoint as ServerNode).erase());
|
|
178
|
+
this.env.runtime.add((this.endpoint as ServerNode).erase().catch(e => MutexClosedError.accept(e)));
|
|
178
179
|
}
|
|
179
180
|
|
|
180
181
|
#monitorFailsafe(failsafe: FailsafeContext) {
|
|
@@ -405,7 +405,7 @@ export class OperationalCredentialsServer extends OperationalCredentialsBehavior
|
|
|
405
405
|
};
|
|
406
406
|
}
|
|
407
407
|
|
|
408
|
-
await fabric.
|
|
408
|
+
await fabric.leave(this.context.session.id);
|
|
409
409
|
// The state is updated on removal via commissionedFabricChanged event, see constructor
|
|
410
410
|
|
|
411
411
|
return {
|
|
@@ -3,8 +3,8 @@
|
|
|
3
3
|
* Copyright 2022-2025 Matter.js Authors
|
|
4
4
|
* SPDX-License-Identifier: Apache-2.0
|
|
5
5
|
*/
|
|
6
|
-
|
|
7
|
-
import { OperationalCredentials } from "#clusters/operational-credentials";
|
|
6
|
+
|
|
7
|
+
import type { OperationalCredentials } from "#clusters/operational-credentials";
|
|
8
8
|
import {
|
|
9
9
|
Bytes,
|
|
10
10
|
Crypto,
|
|
@@ -22,6 +22,7 @@ import { ClientNodeInteraction } from "#node/client/ClientNodeInteraction.js";
|
|
|
22
22
|
import type { ClientNode } from "#node/ClientNode.js";
|
|
23
23
|
import { Icac, Noc, NodeSession, Rcac, Vvsc } from "#protocol";
|
|
24
24
|
import { FabricId, FabricIndex, ReceivedStatusResponseError, StatusResponse, VendorId } from "#types";
|
|
25
|
+
import { OperationalCredentialsClient } from "../operational-credentials/OperationalCredentialsClient.js";
|
|
25
26
|
|
|
26
27
|
const logger = Logger.get("VendorIdVerification");
|
|
27
28
|
|
package/src/endpoint/Endpoint.ts
CHANGED
|
@@ -191,13 +191,33 @@ export class Endpoint<T extends EndpointType = EndpointType.Empty> {
|
|
|
191
191
|
stateOf<T extends Behavior.Type>(type: T): Immutable<Behavior.StateOf<T>>;
|
|
192
192
|
|
|
193
193
|
stateOf(type: Behavior.Type | string) {
|
|
194
|
+
const state = this.maybeStateOf(type as any);
|
|
195
|
+
if (state) {
|
|
196
|
+
return state;
|
|
197
|
+
}
|
|
198
|
+
|
|
199
|
+
const id = typeof type === "string" ? type : type.id;
|
|
200
|
+
throw new ImplementationError(`Behavior ${id} is not supported by ${this}`);
|
|
201
|
+
}
|
|
202
|
+
|
|
203
|
+
/**
|
|
204
|
+
* Version of {@link stateOf} that returns undefined instead of throwing if the requested behavior unsupported.
|
|
205
|
+
*/
|
|
206
|
+
maybeStateOf(type: string): Immutable<Val.Struct>;
|
|
207
|
+
|
|
208
|
+
/**
|
|
209
|
+
* Version of {@link stateOf} that returns undefined instead of throwing if the requested behavior unsupported.
|
|
210
|
+
*/
|
|
211
|
+
maybeStateOf<T extends Behavior.Type>(type: T): Immutable<Behavior.StateOf<T>>;
|
|
212
|
+
|
|
213
|
+
maybeStateOf(type: Behavior.Type | string) {
|
|
194
214
|
if (typeof type === "string") {
|
|
195
215
|
if (!(type in this.#stateView)) {
|
|
196
|
-
|
|
216
|
+
return undefined;
|
|
197
217
|
}
|
|
198
218
|
} else {
|
|
199
219
|
if (!this.behaviors.has(type)) {
|
|
200
|
-
|
|
220
|
+
return undefined;
|
|
201
221
|
}
|
|
202
222
|
type = type.id;
|
|
203
223
|
}
|
|
@@ -371,7 +391,7 @@ export class Endpoint<T extends EndpointType = EndpointType.Empty> {
|
|
|
371
391
|
}
|
|
372
392
|
} else {
|
|
373
393
|
if (!this.behaviors.has(type)) {
|
|
374
|
-
throw new ImplementationError(`Behavior ${type.id} is not supported by this
|
|
394
|
+
throw new ImplementationError(`Behavior ${type.id} is not supported by ${this}`);
|
|
375
395
|
}
|
|
376
396
|
type = type.id;
|
|
377
397
|
}
|
|
@@ -393,7 +393,11 @@ export class Behaviors {
|
|
|
393
393
|
/**
|
|
394
394
|
* Determine if a specified behavior is supported and active.
|
|
395
395
|
*/
|
|
396
|
-
isActive(type: Behavior.Type) {
|
|
396
|
+
isActive(type: Behavior.Type | string) {
|
|
397
|
+
if (typeof type === "string") {
|
|
398
|
+
return this.#backings[type] !== undefined;
|
|
399
|
+
}
|
|
400
|
+
|
|
397
401
|
const backing = this.#backings[type.id];
|
|
398
402
|
return !!backing && backing.type.supports(type);
|
|
399
403
|
}
|
|
@@ -463,11 +467,6 @@ export class Behaviors {
|
|
|
463
467
|
this.#supported = { ...this.#supported };
|
|
464
468
|
}
|
|
465
469
|
|
|
466
|
-
// TODO how to better solve that?
|
|
467
|
-
if (this.#endpoint.env.has(EndpointInitializer)) {
|
|
468
|
-
type = this.#endpoint.env.get(EndpointInitializer).finalizeType(type);
|
|
469
|
-
}
|
|
470
|
-
|
|
471
470
|
this.#supported[type.id] = type;
|
|
472
471
|
|
|
473
472
|
this.#augmentEndpoint(type);
|
|
@@ -672,6 +671,13 @@ export class Behaviors {
|
|
|
672
671
|
|
|
673
672
|
const backing = this.#endpoint.env.get(EndpointInitializer).createBacking(this.#endpoint, myType);
|
|
674
673
|
this.#backings[backing.type.id] = backing;
|
|
674
|
+
|
|
675
|
+
// The EndpointInitializer may choose to replace the behavior implementation. If so the replacement should be
|
|
676
|
+
// compatible, but update our support map to designate the specific implementation
|
|
677
|
+
if (backing.type !== myType) {
|
|
678
|
+
this.#supported[backing.type.id] = backing.type;
|
|
679
|
+
}
|
|
680
|
+
|
|
675
681
|
if (!this.#protocol) {
|
|
676
682
|
this.#protocol = this.#endpoint.env.get(ProtocolService);
|
|
677
683
|
}
|
|
@@ -41,11 +41,4 @@ export abstract class EndpointInitializer {
|
|
|
41
41
|
* Invoked after behaviors are initialized but before the initialization transaction commits.
|
|
42
42
|
*/
|
|
43
43
|
behaviorsInitialized(_agent: Agent) {}
|
|
44
|
-
|
|
45
|
-
/**
|
|
46
|
-
* Allows Initializer to manipulate the type before it is used to create a backing or behavior.
|
|
47
|
-
*/
|
|
48
|
-
finalizeType(type: Behavior.Type): Behavior.Type {
|
|
49
|
-
return type;
|
|
50
|
-
}
|
|
51
44
|
}
|
package/src/node/Node.ts
CHANGED
|
@@ -177,7 +177,8 @@ export abstract class Node<T extends Node.CommonRootEndpoint = Node.CommonRootEn
|
|
|
177
177
|
|
|
178
178
|
override async close() {
|
|
179
179
|
this.lifecycle.targetState = "offline";
|
|
180
|
-
await this.lifecycle.mutex.
|
|
180
|
+
await this.lifecycle.mutex.close();
|
|
181
|
+
await this.closeWithMutex();
|
|
181
182
|
}
|
|
182
183
|
|
|
183
184
|
protected async closeWithMutex() {
|
|
@@ -0,0 +1,63 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* @license
|
|
3
|
+
* Copyright 2022-2025 Matter.js Authors
|
|
4
|
+
* SPDX-License-Identifier: Apache-2.0
|
|
5
|
+
*/
|
|
6
|
+
|
|
7
|
+
import { ClusterBehavior } from "#behavior/cluster/ClusterBehavior.js";
|
|
8
|
+
import type { ClientNode } from "#node/ClientNode.js";
|
|
9
|
+
import { Node } from "#node/Node.js";
|
|
10
|
+
import { ClientInteraction, Invoke } from "#protocol";
|
|
11
|
+
import { Status, StatusResponseError } from "#types";
|
|
12
|
+
|
|
13
|
+
/**
|
|
14
|
+
* Create the command method for a client behavior.
|
|
15
|
+
*/
|
|
16
|
+
export function ClientCommandMethod(name: string) {
|
|
17
|
+
// This is our usual hack to give a function a proper name in stack traces
|
|
18
|
+
const temp = {
|
|
19
|
+
// The actual implementation
|
|
20
|
+
[name](this: ClusterBehavior, fields?: {}) {
|
|
21
|
+
return invokeOnPeer(this, name, fields);
|
|
22
|
+
},
|
|
23
|
+
};
|
|
24
|
+
|
|
25
|
+
return temp[name];
|
|
26
|
+
}
|
|
27
|
+
|
|
28
|
+
/**
|
|
29
|
+
* Invokes a command remotely on behalf of client behaviors.
|
|
30
|
+
*/
|
|
31
|
+
async function invokeOnPeer(behavior: ClusterBehavior, command: string, fields?: {}) {
|
|
32
|
+
const node = behavior.env.get(Node) as ClientNode;
|
|
33
|
+
|
|
34
|
+
// TODO when implementing TCP add needed logic for Large messages
|
|
35
|
+
const chunks = (node.interaction as ClientInteraction).invoke(
|
|
36
|
+
Invoke({
|
|
37
|
+
commands: [
|
|
38
|
+
Invoke.ConcreteCommandRequest<any>({
|
|
39
|
+
endpoint: behavior.endpoint,
|
|
40
|
+
cluster: behavior.cluster,
|
|
41
|
+
command,
|
|
42
|
+
fields,
|
|
43
|
+
}),
|
|
44
|
+
],
|
|
45
|
+
}),
|
|
46
|
+
);
|
|
47
|
+
|
|
48
|
+
for await (const chunk of chunks) {
|
|
49
|
+
for (const entry of chunk) {
|
|
50
|
+
// We send only one command, so we only get one response back
|
|
51
|
+
switch (entry.kind) {
|
|
52
|
+
case "cmd-status":
|
|
53
|
+
if (entry.status !== Status.Success) {
|
|
54
|
+
throw StatusResponseError.create(entry.status, undefined, entry.clusterStatus);
|
|
55
|
+
}
|
|
56
|
+
return;
|
|
57
|
+
|
|
58
|
+
case "cmd-response":
|
|
59
|
+
return entry.data;
|
|
60
|
+
}
|
|
61
|
+
}
|
|
62
|
+
}
|
|
63
|
+
}
|
|
@@ -11,12 +11,10 @@ import { ClientBehaviorBacking } from "#behavior/internal/ClientBehaviorBacking.
|
|
|
11
11
|
import { ServerBehaviorBacking } from "#behavior/internal/ServerBehaviorBacking.js";
|
|
12
12
|
import { Endpoint } from "#endpoint/Endpoint.js";
|
|
13
13
|
import { EndpointInitializer } from "#endpoint/properties/EndpointInitializer.js";
|
|
14
|
-
import { FeatureBitmap } from "#model";
|
|
15
14
|
import { PeerBehavior } from "#node/client/PeerBehavior.js";
|
|
16
15
|
import type { ClientNode } from "#node/ClientNode.js";
|
|
17
16
|
import { ClientNodeStore } from "#storage/client/ClientNodeStore.js";
|
|
18
17
|
import { NodeStore } from "#storage/NodeStore.js";
|
|
19
|
-
import { AttributeId, CommandId } from "#types";
|
|
20
18
|
import { ClientStructure } from "./ClientStructure.js";
|
|
21
19
|
|
|
22
20
|
export class ClientEndpointInitializer extends EndpointInitializer {
|
|
@@ -55,44 +53,13 @@ export class ClientEndpointInitializer extends EndpointInitializer {
|
|
|
55
53
|
return new ServerBehaviorBacking(endpoint, type, store, endpoint.behaviors.optionsFor(type));
|
|
56
54
|
}
|
|
57
55
|
|
|
58
|
-
// Cluster behaviors
|
|
59
|
-
|
|
60
|
-
|
|
61
|
-
}
|
|
62
|
-
|
|
63
|
-
/** Convert the Cluster type to a ClientBehavior */
|
|
64
|
-
override finalizeType(type: Behavior.Type): Behavior.Type {
|
|
65
|
-
const cluster = (type as ClusterBehavior.Type).cluster;
|
|
66
|
-
if (cluster === undefined) {
|
|
67
|
-
return type;
|
|
68
|
-
}
|
|
69
|
-
|
|
70
|
-
const features: FeatureBitmap = {};
|
|
71
|
-
for (const f in cluster.features) {
|
|
72
|
-
features[f] = true;
|
|
73
|
-
}
|
|
74
|
-
const attributeNames = new Array<string>();
|
|
75
|
-
const attributes = new Array<AttributeId>();
|
|
76
|
-
for (const [name, attr] of Object.entries(cluster.attributes)) {
|
|
77
|
-
attributeNames.push(name);
|
|
78
|
-
attributes.push(attr.id);
|
|
79
|
-
}
|
|
80
|
-
const commandNames = new Array<string>();
|
|
81
|
-
const commands = new Array<CommandId>();
|
|
82
|
-
for (const [name, cmd] of Object.entries(cluster.commands)) {
|
|
83
|
-
commandNames.push(name);
|
|
84
|
-
commands.push(cmd.requestId);
|
|
85
|
-
}
|
|
56
|
+
// Cluster behaviors must be instrumented for access to a remote cluster. If already instrumented this is a
|
|
57
|
+
// no-op, otherwise it creates a new type extension
|
|
58
|
+
const peerType = PeerBehavior({ kind: "known", behavior: type as ClusterBehavior.Type });
|
|
86
59
|
|
|
87
|
-
|
|
88
|
-
|
|
89
|
-
|
|
90
|
-
features,
|
|
91
|
-
attributes,
|
|
92
|
-
commands,
|
|
93
|
-
attributeNames,
|
|
94
|
-
commandNames,
|
|
95
|
-
});
|
|
60
|
+
// Activate remote behavior
|
|
61
|
+
const store = this.structure.storeForRemote(endpoint, peerType);
|
|
62
|
+
return new ClientBehaviorBacking(endpoint, type, store, endpoint.behaviors.optionsFor(peerType));
|
|
96
63
|
}
|
|
97
64
|
|
|
98
65
|
get structure() {
|
|
@@ -11,6 +11,7 @@ import { Descriptor } from "#clusters/descriptor";
|
|
|
11
11
|
import { Endpoint } from "#endpoint/Endpoint.js";
|
|
12
12
|
import { EndpointType } from "#endpoint/type/EndpointType.js";
|
|
13
13
|
import { RootEndpoint } from "#endpoints/root";
|
|
14
|
+
import { InternalError, Logger } from "#general";
|
|
14
15
|
import {
|
|
15
16
|
AcceptedCommandList,
|
|
16
17
|
AttributeList,
|
|
@@ -22,13 +23,17 @@ import {
|
|
|
22
23
|
type FeatureBitmap,
|
|
23
24
|
} from "#model";
|
|
24
25
|
import type { ClientNode } from "#node/ClientNode.js";
|
|
26
|
+
import type { Node } from "#node/Node.js";
|
|
25
27
|
import { ReadScope, type Read, type ReadResult } from "#protocol";
|
|
26
28
|
import { DatasourceCache } from "#storage/client/DatasourceCache.js";
|
|
27
29
|
import { ClientNodeStore } from "#storage/index.js";
|
|
28
30
|
import type { AttributeId, ClusterId, ClusterType, CommandId, EndpointNumber } from "#types";
|
|
29
31
|
import { ClientEventEmitter } from "./ClientEventEmitter.js";
|
|
32
|
+
import { ClientStructureEvents } from "./ClientStructureEvents.js";
|
|
30
33
|
import { PeerBehavior } from "./PeerBehavior.js";
|
|
31
34
|
|
|
35
|
+
const logger = Logger.get("ClientStructure");
|
|
36
|
+
|
|
32
37
|
const DEVICE_TYPE_LIST_ATTR_ID = Descriptor.Cluster.attributes.deviceTypeList.id;
|
|
33
38
|
const SERVER_LIST_ATTR_ID = Descriptor.Cluster.attributes.serverList.id;
|
|
34
39
|
const PARTS_LIST_ATTR_ID = Descriptor.Cluster.attributes.partsList.id;
|
|
@@ -42,6 +47,8 @@ export class ClientStructure {
|
|
|
42
47
|
#emitEvent: ClientEventEmitter;
|
|
43
48
|
#node: ClientNode;
|
|
44
49
|
#subscribedFabricFiltered?: boolean;
|
|
50
|
+
#pending = new Map<EndpointStructure, "erase" | "reparent">();
|
|
51
|
+
#events: ClientStructureEvents;
|
|
45
52
|
|
|
46
53
|
constructor(node: ClientNode) {
|
|
47
54
|
this.#node = node;
|
|
@@ -51,6 +58,7 @@ export class ClientStructure {
|
|
|
51
58
|
clusters: {},
|
|
52
59
|
};
|
|
53
60
|
this.#emitEvent = ClientEventEmitter(node, this);
|
|
61
|
+
this.#events = this.#node.env.get(ClientStructureEvents);
|
|
54
62
|
}
|
|
55
63
|
|
|
56
64
|
/**
|
|
@@ -76,7 +84,20 @@ export class ClientStructure {
|
|
|
76
84
|
}
|
|
77
85
|
|
|
78
86
|
const cluster = this.#clusterFor(endpoint, id);
|
|
79
|
-
this.#
|
|
87
|
+
this.#synchronizeCluster(endpoint, cluster);
|
|
88
|
+
}
|
|
89
|
+
}
|
|
90
|
+
|
|
91
|
+
for (const [endpoint, opcode] of this.#pending.entries()) {
|
|
92
|
+
this.#pending.delete(endpoint);
|
|
93
|
+
|
|
94
|
+
switch (opcode) {
|
|
95
|
+
case "reparent":
|
|
96
|
+
this.#install(endpoint);
|
|
97
|
+
break;
|
|
98
|
+
|
|
99
|
+
default:
|
|
100
|
+
throw new InternalError(`Unexpected ${opcode} operation in initial hierarchy load`);
|
|
80
101
|
}
|
|
81
102
|
}
|
|
82
103
|
}
|
|
@@ -142,10 +163,14 @@ export class ClientStructure {
|
|
|
142
163
|
* Update the node structure by applying attribute changes.
|
|
143
164
|
*/
|
|
144
165
|
async *mutate(request: Read, changes: ReadResult) {
|
|
145
|
-
|
|
166
|
+
// Ensure mutations run serially and integrate properly with node lifecycle
|
|
167
|
+
using _lock = await this.#node.lifecycle.mutex.lock();
|
|
146
168
|
|
|
169
|
+
// We collect updates and only apply when we transition clusters
|
|
147
170
|
let currentUpdates: AttributeUpdates | undefined;
|
|
148
171
|
|
|
172
|
+
// Apply changes
|
|
173
|
+
const scope = ReadScope(request);
|
|
149
174
|
for await (const chunk of changes) {
|
|
150
175
|
for (const change of chunk) {
|
|
151
176
|
switch (change.kind) {
|
|
@@ -164,9 +189,32 @@ export class ClientStructure {
|
|
|
164
189
|
yield chunk;
|
|
165
190
|
}
|
|
166
191
|
|
|
192
|
+
// The last cluster still needs its changes applied
|
|
167
193
|
if (currentUpdates) {
|
|
168
194
|
await this.#updateCluster(currentUpdates);
|
|
169
195
|
}
|
|
196
|
+
|
|
197
|
+
// We don't apply structural changes until we've processed all attribute data if a.) listeners might otherwise
|
|
198
|
+
// see partially initialized endpoints, or b.) the change requires an async operation
|
|
199
|
+
for (const [endpoint, opcode] of this.#pending.entries()) {
|
|
200
|
+
this.#pending.delete(endpoint);
|
|
201
|
+
|
|
202
|
+
switch (opcode) {
|
|
203
|
+
case "reparent":
|
|
204
|
+
this.#install(endpoint);
|
|
205
|
+
break;
|
|
206
|
+
|
|
207
|
+
case "erase":
|
|
208
|
+
logger.debug(`Removing endpoint ${endpoint.endpoint} because it is no longer present on the peer`);
|
|
209
|
+
delete this.#endpoints[endpoint.endpoint.number];
|
|
210
|
+
try {
|
|
211
|
+
await endpoint.endpoint.delete();
|
|
212
|
+
} catch (e) {
|
|
213
|
+
logger.error(`Error erasing peer endpoint ${endpoint.endpoint}:`, e);
|
|
214
|
+
}
|
|
215
|
+
break;
|
|
216
|
+
}
|
|
217
|
+
}
|
|
170
218
|
}
|
|
171
219
|
|
|
172
220
|
/** Reference to the default subscription used when the node was started. */
|
|
@@ -246,10 +294,11 @@ export class ClientStructure {
|
|
|
246
294
|
* This is invoked in a batch when we've collected all sequential values for the current endpoint/cluster.
|
|
247
295
|
*/
|
|
248
296
|
async #updateCluster(attrs: AttributeUpdates) {
|
|
297
|
+
// TODO: Detect changes in revision/features/attributes/commands and update behavior if needed
|
|
249
298
|
const endpoint = this.#endpointFor(attrs.endpointId);
|
|
250
299
|
const cluster = this.#clusterFor(endpoint, attrs.clusterId);
|
|
251
300
|
await cluster.store.externalSet(attrs.values);
|
|
252
|
-
this.#
|
|
301
|
+
this.#synchronizeCluster(endpoint, cluster);
|
|
253
302
|
}
|
|
254
303
|
|
|
255
304
|
/**
|
|
@@ -260,18 +309,15 @@ export class ClientStructure {
|
|
|
260
309
|
*
|
|
261
310
|
* Invoked once we've loaded all attributes in an interaction.
|
|
262
311
|
*/
|
|
263
|
-
#
|
|
264
|
-
const attrs = cluster.store.initialValues ?? {};
|
|
265
|
-
|
|
312
|
+
#synchronizeCluster(endpoint: EndpointStructure, cluster: ClusterStructure) {
|
|
266
313
|
// Generate a behavior if enough information is available
|
|
267
|
-
|
|
268
|
-
if (cluster.behavior === undefined) {
|
|
314
|
+
if (cluster.behavior === undefined && cluster.store.initialValues) {
|
|
269
315
|
const {
|
|
270
316
|
[ClusterRevision.id]: clusterRevision,
|
|
271
317
|
[FeatureMap.id]: features,
|
|
272
318
|
[AttributeList.id]: attributeList,
|
|
273
319
|
[AcceptedCommandList.id]: commandList,
|
|
274
|
-
} =
|
|
320
|
+
} = cluster.store.initialValues;
|
|
275
321
|
|
|
276
322
|
if (typeof clusterRevision === "number") {
|
|
277
323
|
cluster.revision = clusterRevision;
|
|
@@ -297,11 +343,20 @@ export class ClientStructure {
|
|
|
297
343
|
) {
|
|
298
344
|
cluster.behavior = PeerBehavior(cluster as PeerBehavior.ClusterShape);
|
|
299
345
|
endpoint.endpoint.behaviors.require(cluster.behavior);
|
|
346
|
+
if (endpoint.endpoint.lifecycle.isInstalled) {
|
|
347
|
+
this.#events.emitCluster(endpoint.endpoint, cluster.behavior);
|
|
348
|
+
}
|
|
300
349
|
}
|
|
301
350
|
}
|
|
302
351
|
|
|
303
352
|
// Special handling for descriptor cluster
|
|
304
353
|
if (cluster.id === Descriptor.Cluster.id) {
|
|
354
|
+
let attrs;
|
|
355
|
+
if (cluster.behavior && endpoint.endpoint.behaviors.isActive(cluster.behavior.id)) {
|
|
356
|
+
attrs = endpoint.endpoint.stateOf(cluster.behavior);
|
|
357
|
+
} else {
|
|
358
|
+
attrs = cluster.store.initialValues ?? {};
|
|
359
|
+
}
|
|
305
360
|
this.#synchronizeDescriptor(endpoint, attrs);
|
|
306
361
|
}
|
|
307
362
|
}
|
|
@@ -356,31 +411,52 @@ export class ClientStructure {
|
|
|
356
411
|
}
|
|
357
412
|
}
|
|
358
413
|
|
|
414
|
+
// The remaining logic deals with the parts list
|
|
359
415
|
const partsList = attrs[PARTS_LIST_ATTR_ID];
|
|
360
|
-
if (Array.isArray(partsList)) {
|
|
361
|
-
|
|
362
|
-
|
|
363
|
-
continue;
|
|
364
|
-
}
|
|
416
|
+
if (!Array.isArray(partsList)) {
|
|
417
|
+
return;
|
|
418
|
+
}
|
|
365
419
|
|
|
366
|
-
|
|
420
|
+
// Ensure an endpoint is present and installed for each part in the partsList
|
|
421
|
+
for (const partNo of partsList) {
|
|
422
|
+
if (typeof partNo !== "number") {
|
|
423
|
+
continue;
|
|
424
|
+
}
|
|
367
425
|
|
|
368
|
-
|
|
369
|
-
|
|
370
|
-
|
|
371
|
-
|
|
372
|
-
|
|
373
|
-
|
|
374
|
-
|
|
375
|
-
break;
|
|
376
|
-
}
|
|
426
|
+
const part = this.#endpointFor(partNo as EndpointNumber);
|
|
427
|
+
|
|
428
|
+
let isAlreadyDescendant = false;
|
|
429
|
+
for (let owner = this.#ownerOf(part); owner; owner = this.#ownerOf(owner)) {
|
|
430
|
+
if (owner === endpoint) {
|
|
431
|
+
isAlreadyDescendant = true;
|
|
432
|
+
break;
|
|
377
433
|
}
|
|
434
|
+
}
|
|
378
435
|
|
|
379
|
-
|
|
436
|
+
if (isAlreadyDescendant) {
|
|
437
|
+
continue;
|
|
438
|
+
}
|
|
439
|
+
|
|
440
|
+
part.pendingOwner = endpoint;
|
|
441
|
+
this.#pending.set(part, "reparent");
|
|
442
|
+
}
|
|
443
|
+
|
|
444
|
+
// For the root partsList specifically, if an endpoint is no longer present then it has been removd from the
|
|
445
|
+
// node. Schedule for erase
|
|
446
|
+
if (endpoint.endpoint.maybeNumber === 0) {
|
|
447
|
+
const numbersUsed = new Set(partsList);
|
|
448
|
+
for (const descendent of (endpoint.endpoint as Node).endpoints) {
|
|
449
|
+
// Skip root endpoint and uninitialized numbers (though latter shouldn't be possible)
|
|
450
|
+
if (!descendent.maybeNumber) {
|
|
380
451
|
continue;
|
|
381
452
|
}
|
|
382
453
|
|
|
383
|
-
|
|
454
|
+
if (!numbersUsed.has(descendent.number)) {
|
|
455
|
+
const endpoint = this.#endpoints[descendent.number];
|
|
456
|
+
if (endpoint) {
|
|
457
|
+
this.#pending.set(endpoint, "erase");
|
|
458
|
+
}
|
|
459
|
+
}
|
|
384
460
|
}
|
|
385
461
|
}
|
|
386
462
|
}
|
|
@@ -415,6 +491,7 @@ export class ClientStructure {
|
|
|
415
491
|
}
|
|
416
492
|
|
|
417
493
|
cluster = {
|
|
494
|
+
kind: "discovered",
|
|
418
495
|
id,
|
|
419
496
|
store: this.#nodeStore.storeForEndpoint(endpoint.endpoint).createStoreForBehavior(id.toString()),
|
|
420
497
|
};
|
|
@@ -422,6 +499,33 @@ export class ClientStructure {
|
|
|
422
499
|
|
|
423
500
|
return cluster;
|
|
424
501
|
}
|
|
502
|
+
|
|
503
|
+
#ownerOf(endpoint: EndpointStructure) {
|
|
504
|
+
if (endpoint.pendingOwner) {
|
|
505
|
+
return endpoint.pendingOwner;
|
|
506
|
+
}
|
|
507
|
+
|
|
508
|
+
// Do not return the ServerNode if this is the ClientNode
|
|
509
|
+
if (endpoint.endpoint.number === 0) {
|
|
510
|
+
return;
|
|
511
|
+
}
|
|
512
|
+
|
|
513
|
+
const ownerNumber = endpoint.endpoint.owner?.maybeNumber;
|
|
514
|
+
if (ownerNumber !== undefined) {
|
|
515
|
+
return this.#endpointFor(ownerNumber);
|
|
516
|
+
}
|
|
517
|
+
}
|
|
518
|
+
|
|
519
|
+
#install(endpoint: EndpointStructure) {
|
|
520
|
+
const { pendingOwner } = endpoint;
|
|
521
|
+
if (!pendingOwner) {
|
|
522
|
+
return;
|
|
523
|
+
}
|
|
524
|
+
|
|
525
|
+
endpoint.endpoint.owner = pendingOwner.endpoint;
|
|
526
|
+
endpoint.pendingOwner = undefined;
|
|
527
|
+
this.#events.emitEndpoint(endpoint.endpoint);
|
|
528
|
+
}
|
|
425
529
|
}
|
|
426
530
|
|
|
427
531
|
interface AttributeUpdates {
|
|
@@ -433,11 +537,13 @@ interface AttributeUpdates {
|
|
|
433
537
|
}
|
|
434
538
|
|
|
435
539
|
interface EndpointStructure {
|
|
540
|
+
pendingOwner?: EndpointStructure;
|
|
436
541
|
endpoint: Endpoint;
|
|
437
542
|
clusters: Record<ClusterId, ClusterStructure>;
|
|
438
543
|
}
|
|
439
544
|
|
|
440
|
-
interface ClusterStructure extends Partial<PeerBehavior.
|
|
545
|
+
interface ClusterStructure extends Partial<PeerBehavior.DiscoveredClusterShape> {
|
|
546
|
+
kind: "discovered";
|
|
441
547
|
id: ClusterId;
|
|
442
548
|
behavior?: ClusterBehavior.Type;
|
|
443
549
|
store: Datasource.ExternallyMutableStore;
|