@noya-app/noya-multiplayer-react 0.1.45 → 0.1.47

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/src/hooks.ts CHANGED
@@ -3,24 +3,12 @@
3
3
  import { GetAtPath } from "@noya-app/observable";
4
4
  import {
5
5
  ActionHandler,
6
- AIManager,
7
- AssetManager,
8
- ConnectedUsersManager,
9
- ConnectionEvent,
10
- EphemeralUserDataManager,
11
- MultiplayerStateManager,
12
- MultiplayerStateManagerError,
13
6
  MultiplayerStateManagerOptions,
14
- RPCManager,
15
- StandardRPCRequestPayload,
16
- StandardRPCResponsePayload,
7
+ NoyaManager,
17
8
  StateManager,
18
9
  StateManagerOptions,
19
10
  stubSync,
20
11
  SyncAdapter,
21
- SyncAdapterOptions,
22
- Task,
23
- WorkflowManager,
24
12
  } from "@noya-app/state-manager";
25
13
  import {
26
14
  createElement,
@@ -33,9 +21,7 @@ import {
33
21
  useSyncExternalStore,
34
22
  } from "react";
35
23
  import { createRoot } from "react-dom/client";
36
- import { SecretManager } from "../../noya-state-manager/src/SecretManager";
37
24
  import { ErrorOverlay } from "./components/ErrorOverlay";
38
- import { shouldTrackEvents$, shouldTrackTasks$ } from "./globals";
39
25
  import { StateInspectorOptions } from "./inspector/StateInspector";
40
26
  import { useStateInspector } from "./inspector/useStateInspector";
41
27
  import { useObservable } from "./useObservable";
@@ -134,190 +120,103 @@ export function useManagedHistory<S, M = void>(
134
120
  );
135
121
  }
136
122
 
137
- export function useSyncMultiplayerStateManager<S, M = void>(
138
- multiplayerStateManager: MultiplayerStateManager<S, M>
139
- ) {
140
- return useSyncExternalStore(
141
- multiplayerStateManager.addListener,
142
- multiplayerStateManager.getOptimisticState,
143
- multiplayerStateManager.getOptimisticState
144
- );
145
- }
146
-
147
- const defaultStubSync = stubSync();
148
-
149
123
  export type UseMultiplayerStateOptions<
150
124
  S,
151
- M = void,
125
+ M extends object = object,
152
126
  E extends object = object,
127
+ MenuT extends string = string,
153
128
  > = MultiplayerStateManagerOptions<S, M> & {
154
- sync?: (
155
- options: Pick<
156
- SyncAdapterOptions<S, M, E>,
157
- "ms" | "ephemeralUserDataManager" | "assetManager"
158
- >
159
- ) => void;
160
- trackConnectionEvents?: boolean;
161
- trackTasks?: boolean;
129
+ sync?: SyncAdapter<S, M, E, MenuT>;
162
130
  inspector?: boolean | StateInspectorOptions;
163
131
  };
164
132
 
165
- export function useMultiplayerState<S, M = void, E extends object = object>(
133
+ const defaultStubSync = stubSync<unknown, object, object, string>();
134
+
135
+ export function useMultiplayerState<
136
+ S,
137
+ M extends object = object,
138
+ E extends object = object,
139
+ MenuT extends string = string,
140
+ >(
166
141
  initialState: S | (() => S),
167
- options?: UseMultiplayerStateOptions<S, M, E>
142
+ options?: UseMultiplayerStateOptions<S, M, E, MenuT>
168
143
  ) {
169
- const { sync = defaultStubSync as unknown as SyncAdapter<S, M, E>, ...rest } =
170
- options ?? {};
171
-
172
- /** RPC */
173
-
174
- const [rpcManager] = useState(
175
- () =>
176
- new RPCManager<StandardRPCRequestPayload, StandardRPCResponsePayload>()
177
- );
178
- const [multiplayerStateManager] = useState(
179
- () => new MultiplayerStateManager<S, M>(initialState, rest)
144
+ const {
145
+ sync = defaultStubSync as unknown as SyncAdapter<S, M, E, MenuT>,
146
+ inspector,
147
+ ...rest
148
+ } = options ?? {};
149
+
150
+ const [noyaManager] = useState(
151
+ () => new NoyaManager<S, M, E, MenuT>(initialState, rest)
180
152
  );
181
- const [assetManager] = useState(() => new AssetManager());
182
- const [aiManager] = useState(() => new AIManager(rpcManager));
183
- const [workflowManager] = useState(() => new WorkflowManager(rpcManager));
184
- const [secretManager] = useState(() => new SecretManager(rpcManager));
185
- const [connectedUsersManager] = useState(() => new ConnectedUsersManager());
186
- const syncRef = useRef(sync);
187
153
 
188
- const [connectionEvents, setConnectionEvents] = useState<
189
- ConnectionEvent<S>[] | undefined
190
- >();
191
- const [ephemeralUserDataManager] = useState<EphemeralUserDataManager<E>>(
192
- () => new EphemeralUserDataManager()
154
+ const state = useObservable(
155
+ noyaManager.multiplayerStateManager.optimisticState$
193
156
  );
194
- const [tasks, setTasks] = useState<Task[]>([]);
195
- const assets = useObservable(assetManager.assets$);
196
- // const connectionStatus = useObservable(
197
- // multiplayerStateManager.connectionStatus$
198
- // );
199
-
200
- const extras = useMemo(() => {
157
+ const assets = useObservable(noyaManager.assetManager.assets$);
158
+
159
+ type ExtrasType = {
160
+ noyaManager: typeof noyaManager;
161
+ taskManager: typeof noyaManager.taskManager;
162
+ connectionEventManager: typeof noyaManager.connectionEventManager;
163
+ connectedUsersManager: typeof noyaManager.connectedUsersManager;
164
+ ephemeralUserDataManager: typeof noyaManager.ephemeralUserDataManager;
165
+ multiplayerStateManager: typeof noyaManager.multiplayerStateManager;
166
+ assetManager: typeof noyaManager.assetManager;
167
+ aiManager: typeof noyaManager.aiManager;
168
+ rpcManager: typeof noyaManager.rpcManager;
169
+ workflowManager: typeof noyaManager.workflowManager;
170
+ secretManager: typeof noyaManager.secretManager;
171
+ menuItemsManager: typeof noyaManager.menuManager;
172
+ createAsset: typeof noyaManager.assetManager.create;
173
+ deleteAsset: typeof noyaManager.assetManager.delete;
174
+ assets: typeof assets;
175
+ };
176
+
177
+ const extras = useMemo<ExtrasType>(() => {
201
178
  return {
202
- tasks,
203
- connectionEvents,
204
- connectedUsersManager,
205
- ephemeralUserDataManager,
206
- multiplayerStateManager,
179
+ noyaManager,
180
+ taskManager: noyaManager.taskManager,
181
+ connectionEventManager: noyaManager.connectionEventManager,
182
+ connectedUsersManager: noyaManager.connectedUsersManager,
183
+ ephemeralUserDataManager: noyaManager.ephemeralUserDataManager,
184
+ multiplayerStateManager: noyaManager.multiplayerStateManager,
185
+ assetManager: noyaManager.assetManager,
186
+ aiManager: noyaManager.aiManager,
187
+ rpcManager: noyaManager.rpcManager,
188
+ workflowManager: noyaManager.workflowManager,
189
+ secretManager: noyaManager.secretManager,
190
+ menuItemsManager: noyaManager.menuManager,
191
+ createAsset: noyaManager.assetManager.create,
192
+ deleteAsset: noyaManager.assetManager.delete,
207
193
  assets,
208
- assetManager,
209
- aiManager,
210
- rpcManager,
211
- workflowManager,
212
- secretManager,
213
- createAsset: assetManager.create,
214
- deleteAsset: assetManager.delete,
215
- // connectionStatus,
216
- // isConnected: connectionStatus === "connected",
217
194
  };
218
- }, [
219
- tasks,
220
- connectionEvents,
221
- connectedUsersManager,
222
- ephemeralUserDataManager,
223
- multiplayerStateManager,
224
- assets,
225
- assetManager,
226
- aiManager,
227
- rpcManager,
228
- workflowManager,
229
- secretManager,
230
- ]);
231
-
232
- const globalTrackEvents = useObservable(shouldTrackEvents$);
233
- const globalTrackTasks = useObservable(shouldTrackTasks$);
234
-
235
- const shouldTrackEvents = options?.trackConnectionEvents ?? globalTrackEvents;
236
- const shouldTrackTasks = options?.trackTasks ?? globalTrackTasks;
195
+ }, [noyaManager, assets]);
237
196
 
238
- const trackEventsCallbackRef = useRef<
239
- ((e: ConnectionEvent<S>) => void) | undefined
240
- >();
241
- const trackTasksCallbackRef = useRef<((tasks: Task[]) => void) | undefined>();
242
-
243
- useEffect(() => {
244
- trackEventsCallbackRef.current = shouldTrackEvents
245
- ? (e) =>
246
- setConnectionEvents((events) => {
247
- const updated = events ? [...events, e] : [e];
248
- return updated.length > 50 ? updated.slice(-50) : updated;
249
- })
250
- : undefined;
251
- }, [shouldTrackEvents]);
252
-
253
- useEffect(() => {
254
- trackTasksCallbackRef.current = shouldTrackTasks
255
- ? (tasks) => {
256
- setTasks((old) => {
257
- const newIds = new Set(tasks.map((t) => t.id));
258
-
259
- // merge old and new tasks, preferring new tasks
260
- const unchanged = old.filter((t) => !newIds.has(t.id));
261
-
262
- return [...unchanged, ...tasks];
263
- });
264
- }
265
- : undefined;
266
- }, [shouldTrackTasks]);
197
+ const syncRef = useRef(sync);
267
198
 
268
199
  useEffect(() => {
269
200
  if (syncRef.current) {
270
- return syncRef.current({
271
- ms: multiplayerStateManager,
272
- assetManager,
273
- workflowManager,
274
- secretManager,
275
- rpcManager,
276
- aiManager,
277
- ephemeralUserDataManager,
278
- connectedUsersManager,
279
- onConnectionEvent: (e) => trackEventsCallbackRef.current?.(e),
280
- onChangeTasks: (tasks) => trackTasksCallbackRef.current?.(tasks),
281
- });
201
+ return syncRef.current({ noyaManager });
282
202
  }
283
- }, [
284
- assetManager,
285
- ephemeralUserDataManager,
286
- multiplayerStateManager,
287
- workflowManager,
288
- secretManager,
289
- rpcManager,
290
- aiManager,
291
- connectedUsersManager,
292
- ]);
203
+ }, [noyaManager]);
293
204
 
294
- const state = useSyncMultiplayerStateManager(multiplayerStateManager);
205
+ useErrorOverlay<MenuT>(noyaManager);
295
206
 
296
- const forceInit = useCallback(() => {
297
- const state =
298
- initialState instanceof Function ? initialState() : initialState;
299
- const schema = options?.schema;
300
- multiplayerStateManager.sm.clearHistory();
301
- multiplayerStateManager.sendInit({ force: true, state, schema });
302
- }, [initialState, multiplayerStateManager, options?.schema]);
207
+ useStateInspector<S, M, E, MenuT>({
208
+ noyaManager,
209
+ disabled: !inspector,
210
+ ...(typeof inspector === "object" && inspector),
211
+ });
303
212
 
304
- const [unrecoverableError, setUnrecoverableError] = useState<
305
- MultiplayerStateManagerError | undefined
306
- >();
213
+ return [state, noyaManager.multiplayerStateManager.setState, extras] as const;
214
+ }
307
215
 
308
- useEffect(() => {
309
- return multiplayerStateManager.errorEmitter.addListener((error) => {
310
- switch (error.reason) {
311
- case "invalidDataType":
312
- case "schemaMismatch":
313
- case "outdatedSchema":
314
- case "dataMigrationFailure":
315
- case "schemaMigration":
316
- setUnrecoverableError(error);
317
- break;
318
- }
319
- });
320
- }, [multiplayerStateManager]);
216
+ function useErrorOverlay<MenuT extends string = string>(
217
+ noyaManager: NoyaManager<any, any, any, MenuT>
218
+ ) {
219
+ const unrecoverableError = useObservable(noyaManager.unrecoverableError);
321
220
 
322
221
  useEffect(() => {
323
222
  if (!unrecoverableError) return;
@@ -331,20 +230,4 @@ export function useMultiplayerState<S, M = void, E extends object = object>(
331
230
  el.remove();
332
231
  };
333
232
  });
334
-
335
- useStateInspector({
336
- ephemeralUserDataManager,
337
- multiplayerStateManager,
338
- assetManager,
339
- secretManager,
340
- state,
341
- connectionEvents,
342
- connectedUsersManager,
343
- tasks,
344
- forceInit,
345
- disabled: !options?.inspector,
346
- ...(typeof options?.inspector === "object" && options.inspector),
347
- });
348
-
349
- return [state, multiplayerStateManager.setState, extras] as const;
350
233
  }
package/src/index.ts CHANGED
@@ -5,3 +5,5 @@ export * from "./inspector/StateInspector";
5
5
  export * from "./noyaApp";
6
6
  export * from "./NoyaStateContext";
7
7
  export * from "./useObservable";
8
+ export { WebSocketConnection } from "./WebSocketConnection";
9
+ export type { ConnectionEvent, ConnectionOptions } from "./WebSocketConnection";
@@ -1,16 +1,7 @@
1
1
  "use client";
2
2
 
3
3
  import { memoGeneric } from "@noya-app/react-utils";
4
- import {
5
- AssetManager,
6
- ConnectedUsersManager,
7
- ConnectionEvent,
8
- EphemeralUserDataManager,
9
- ExtendedPathKey,
10
- MultiplayerStateManager,
11
- SecretManager,
12
- Task,
13
- } from "@noya-app/state-manager";
4
+ import { ExtendedPathKey, NoyaManager } from "@noya-app/state-manager";
14
5
  import React, {
15
6
  CSSProperties,
16
7
  ComponentPropsWithoutRef,
@@ -26,7 +17,6 @@ import {
26
17
  chromeDark,
27
18
  chromeLight,
28
19
  } from "react-inspector";
29
- import { shouldTrackEvents$, shouldTrackTasks$ } from "../globals";
30
20
  import { useManagedHistory } from "../hooks";
31
21
  import { useObservable } from "../useObservable";
32
22
  import { useLocalStorageState } from "./useLocalStorageState";
@@ -134,7 +124,7 @@ function DisclosureSection({
134
124
  }: {
135
125
  open: boolean;
136
126
  setOpen?: (value: boolean) => void;
137
- title: string;
127
+ title: React.ReactNode;
138
128
  right?: React.ReactNode;
139
129
  children: React.ReactNode;
140
130
  colorScheme: "light" | "dark";
@@ -254,36 +244,32 @@ export type StateInspectorOptions = {
254
244
 
255
245
  export const StateInspector = memoGeneric(function StateInspector<
256
246
  S,
257
- M,
247
+ M extends object,
258
248
  E extends object,
249
+ MenuT extends string = string,
259
250
  >({
260
- state,
261
- connectionEvents,
262
- tasks,
263
- unstyled,
251
+ noyaManager,
264
252
  colorScheme = "light",
265
- multiplayerStateManager,
266
- assetManager,
267
- secretManager,
268
- connectedUsersManager,
269
- ephemeralUserDataManager,
270
253
  anchor = "right",
271
- forceInit,
254
+ unstyled = false,
272
255
  ...props
273
256
  }: {
274
- state: S;
275
- connectionEvents?: ConnectionEvent<S>[];
276
- tasks?: Task[];
257
+ noyaManager: NoyaManager<S, M, E, MenuT>;
277
258
  unstyled?: boolean;
278
- multiplayerStateManager: MultiplayerStateManager<S, M>;
279
- assetManager: AssetManager;
280
- connectedUsersManager: ConnectedUsersManager;
281
- secretManager: SecretManager;
282
- ephemeralUserDataManager: EphemeralUserDataManager<E>;
283
- forceInit: () => void;
284
259
  } & StateInspectorOptions &
285
260
  ComponentPropsWithoutRef<"div">) {
261
+ const {
262
+ multiplayerStateManager,
263
+ assetManager,
264
+ connectedUsersManager,
265
+ secretManager,
266
+ ephemeralUserDataManager,
267
+ connectionEventManager,
268
+ taskManager,
269
+ } = noyaManager;
270
+
286
271
  const [didMount, setDidMount] = React.useState(false);
272
+ const tasks = useObservable(taskManager.tasks$);
287
273
 
288
274
  useLayoutEffect(() => {
289
275
  setDidMount(true);
@@ -329,13 +315,7 @@ export const StateInspector = memoGeneric(function StateInspector<
329
315
  false
330
316
  );
331
317
 
332
- useEffect(() => {
333
- shouldTrackEvents$.set(showEvents);
334
- }, [showEvents]);
335
-
336
- useEffect(() => {
337
- shouldTrackTasks$.set(showTasks);
338
- }, [showTasks]);
318
+ const connectionEvents = useObservable(connectionEventManager.events$);
339
319
 
340
320
  useEffect(() => {
341
321
  if (eventsContainerRef.current) {
@@ -344,12 +324,18 @@ export const StateInspector = memoGeneric(function StateInspector<
344
324
  }
345
325
  }, [connectionEvents]);
346
326
 
327
+ const multipeerStateInitialized = useObservable(
328
+ multiplayerStateManager.isInitialized$
329
+ );
347
330
  const ephemeral = useObservable(ephemeralUserDataManager.data$);
348
331
  const historySnapshot = useManagedHistory(multiplayerStateManager.sm);
349
332
  const assets = useObservable(assetManager.assets$);
333
+ const assetsInitialized = useObservable(assetManager.isInitialized$);
350
334
  const secrets = useObservable(secretManager.secrets$);
335
+ const secretsInitialized = useObservable(secretManager.isInitialized$);
351
336
  const connectedUsers = useObservable(connectedUsersManager.connectedUsers$);
352
337
  const userId = useObservable(connectedUsersManager.currentUserId$);
338
+ const state = useObservable(multiplayerStateManager.optimisticState$);
353
339
 
354
340
  useEffect(() => {
355
341
  if (historyContainerRef.current) {
@@ -496,7 +482,14 @@ export const StateInspector = memoGeneric(function StateInspector<
496
482
  </div>
497
483
  </DisclosureSection>
498
484
  <DisclosureSection
499
- title="Data"
485
+ title={
486
+ <TitleLabel>
487
+ Data
488
+ <ColoredDot
489
+ type={multipeerStateInitialized ? "success" : "error"}
490
+ />
491
+ </TitleLabel>
492
+ }
500
493
  colorScheme={colorScheme}
501
494
  setOpen={setShowData}
502
495
  open={showData}
@@ -511,7 +504,7 @@ export const StateInspector = memoGeneric(function StateInspector<
511
504
  // disabled={!historySnapshot.canUndo}
512
505
  theme={theme}
513
506
  onClick={() => {
514
- forceInit();
507
+ noyaManager.forceInit();
515
508
  }}
516
509
  >
517
510
  Reset
@@ -706,10 +699,27 @@ export const StateInspector = memoGeneric(function StateInspector<
706
699
  <DisclosureSection
707
700
  open={showAssets}
708
701
  setOpen={setShowAssets}
709
- title="Assets"
702
+ title={
703
+ <TitleLabel>
704
+ Assets
705
+ <ColoredDot type={assetsInitialized ? "success" : "error"} />
706
+ </TitleLabel>
707
+ }
710
708
  colorScheme={colorScheme}
711
709
  right={
712
- <span style={{ display: "flex", gap: "4px" }}>
710
+ <span style={{ display: "flex", gap: "10px" }}>
711
+ <SmallButton
712
+ theme={theme}
713
+ onClick={() => {
714
+ console.info(
715
+ "[StateInspector] Reloading assets",
716
+ noyaManager.id
717
+ );
718
+ assetManager.fetch();
719
+ }}
720
+ >
721
+ Reload
722
+ </SmallButton>
713
723
  <SmallButton
714
724
  theme={theme}
715
725
  onClick={() => {
@@ -779,7 +789,12 @@ export const StateInspector = memoGeneric(function StateInspector<
779
789
  </div>
780
790
  </DisclosureSection>
781
791
  <DisclosureSection
782
- title="Secrets"
792
+ title={
793
+ <TitleLabel>
794
+ Secrets
795
+ <ColoredDot type={secretsInitialized ? "success" : "error"} />
796
+ </TitleLabel>
797
+ }
783
798
  colorScheme={colorScheme}
784
799
  open={showSecrets}
785
800
  setOpen={setShowSecrets}
@@ -863,7 +878,6 @@ export const StateInspector = memoGeneric(function StateInspector<
863
878
  name,
864
879
  data,
865
880
  isNonenumerable,
866
- expanded,
867
881
  }: any) => {
868
882
  const direction = event.type === "send" ? "up" : "down";
869
883
 
@@ -1051,3 +1065,27 @@ function SmallButton({
1051
1065
  </button>
1052
1066
  );
1053
1067
  }
1068
+
1069
+ function ColoredDot({ type }: { type: "success" | "error" }) {
1070
+ return (
1071
+ <span
1072
+ style={{
1073
+ display: "inline-block",
1074
+ width: 6,
1075
+ height: 6,
1076
+ background:
1077
+ type === "success" ? "rgba(0,200,0,0.8)" : "rgba(200,0,0,0.8)",
1078
+ borderRadius: "50%",
1079
+ verticalAlign: "middle",
1080
+ }}
1081
+ />
1082
+ );
1083
+ }
1084
+
1085
+ function TitleLabel({ children }: { children: React.ReactNode }) {
1086
+ return (
1087
+ <span style={{ display: "flex", alignItems: "center", gap: "4px" }}>
1088
+ {children}
1089
+ </span>
1090
+ );
1091
+ }
@@ -1,14 +1,6 @@
1
1
  "use client";
2
2
 
3
- import {
4
- AssetManager,
5
- ConnectedUsersManager,
6
- ConnectionEvent,
7
- EphemeralUserDataManager,
8
- MultiplayerStateManager,
9
- SecretManager,
10
- Task,
11
- } from "@noya-app/state-manager";
3
+ import { NoyaManager } from "@noya-app/state-manager";
12
4
  import React, { ComponentProps, useLayoutEffect } from "react";
13
5
  import { createRoot } from "react-dom/client";
14
6
 
@@ -24,30 +16,19 @@ function createShadowRootElement() {
24
16
  return { host, container };
25
17
  }
26
18
 
27
- export function useStateInspector<S, M, E extends object>({
28
- state,
29
- connectionEvents,
30
- tasks,
19
+ export function useStateInspector<
20
+ S,
21
+ M extends object,
22
+ E extends object,
23
+ MenuT extends string = string,
24
+ >({
25
+ noyaManager,
31
26
  disabled = false,
32
27
  colorScheme,
33
28
  anchor,
34
- multiplayerStateManager,
35
- assetManager,
36
- secretManager,
37
- connectedUsersManager,
38
- ephemeralUserDataManager,
39
- forceInit,
40
29
  }: {
41
- state: S;
42
- connectionEvents?: ConnectionEvent<S>[];
43
- tasks?: Task[];
30
+ noyaManager: NoyaManager<S, M, E, MenuT>;
44
31
  disabled: boolean;
45
- multiplayerStateManager: MultiplayerStateManager<S, M>;
46
- assetManager: AssetManager;
47
- secretManager: SecretManager;
48
- connectedUsersManager: ConnectedUsersManager;
49
- ephemeralUserDataManager: EphemeralUserDataManager<E>;
50
- forceInit: () => void;
51
32
  } & Pick<ComponentProps<typeof StateInspector>, "colorScheme" | "anchor">) {
52
33
  const [root, setRoot] = React.useState<Root | null>(null);
53
34
 
@@ -71,35 +52,10 @@ export function useStateInspector<S, M, E extends object>({
71
52
 
72
53
  root.render(
73
54
  <StateInspector
74
- state={state}
75
- connectionEvents={connectionEvents}
76
- tasks={tasks}
77
55
  colorScheme={colorScheme}
78
56
  anchor={anchor}
79
- forceInit={forceInit}
80
- multiplayerStateManager={
81
- multiplayerStateManager as MultiplayerStateManager<any, any>
82
- }
83
- assetManager={assetManager}
84
- secretManager={secretManager}
85
- ephemeralUserDataManager={
86
- ephemeralUserDataManager as EphemeralUserDataManager<any>
87
- }
88
- connectedUsersManager={connectedUsersManager}
57
+ noyaManager={noyaManager}
89
58
  />
90
59
  );
91
- }, [
92
- anchor,
93
- colorScheme,
94
- connectionEvents,
95
- root,
96
- state,
97
- multiplayerStateManager,
98
- tasks,
99
- forceInit,
100
- ephemeralUserDataManager,
101
- assetManager,
102
- secretManager,
103
- connectedUsersManager,
104
- ]);
60
+ }, [noyaManager, anchor, colorScheme, root]);
105
61
  }