@noya-app/noya-multiplayer-react 0.1.44 → 0.1.46

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/index.js CHANGED
@@ -36,19 +36,17 @@ __export(src_exports, {
36
36
  FallbackUntilInitialized: () => FallbackUntilInitialized,
37
37
  StateInspector: () => StateInspector,
38
38
  UserPointersOverlay: () => UserPointersOverlay,
39
+ WebSocketConnection: () => WebSocketConnection,
39
40
  createDefaultAppData: () => createDefaultAppData,
40
41
  createNoyaContext: () => createNoyaContext,
41
42
  enforceSchema: () => enforceSchema,
42
43
  getAppData: () => getAppData,
43
- isEmbeddedApp: () => isEmbeddedApp,
44
44
  parseAppDataParameter: () => parseAppDataParameter,
45
45
  useAIManager: () => useAIManager,
46
46
  useAnyEphemeralUserData: () => useAnyEphemeralUserData,
47
47
  useAsset: () => useAsset,
48
48
  useAssetManager: () => useAssetManager,
49
49
  useAssets: () => useAssets,
50
- useBroadcastConnectedUsers: () => useBroadcastConnectedUsers,
51
- useBroadcastMenuItems: () => useBroadcastMenuItems,
52
50
  useConnectedUsersManager: () => useConnectedUsersManager,
53
51
  useCurrentUserId: () => useCurrentUserId,
54
52
  useIsInitialized: () => useIsInitialized,
@@ -60,7 +58,6 @@ __export(src_exports, {
60
58
  useSecret: () => useSecret,
61
59
  useSecretManager: () => useSecretManager,
62
60
  useSecrets: () => useSecrets,
63
- useSyncMultiplayerStateManager: () => useSyncMultiplayerStateManager,
64
61
  useSyncStateManager: () => useSyncStateManager,
65
62
  useWorkflowManager: () => useWorkflowManager
66
63
  });
@@ -155,31 +152,15 @@ var UserPointersOverlay = (0, import_react_utils.memoGeneric)(function UserPoint
155
152
 
156
153
  // src/hooks.ts
157
154
  var import_state_manager = require("@noya-app/state-manager");
158
- var import_react7 = require("react");
155
+ var import_react6 = require("react");
159
156
  var import_client2 = require("react-dom/client");
160
157
 
161
- // ../noya-state-manager/src/SecretManager.ts
162
- var import_observable = require("@noya-app/observable");
163
- var SecretManager = class {
164
- constructor(rpcManager) {
165
- this.rpcManager = rpcManager;
166
- }
167
- secrets$ = new import_observable.Observable([]);
168
- isInitialized$ = new import_observable.Observable(false);
169
- async createSecret(name, value) {
170
- return await this.rpcManager.request({ type: "createSecret", name, value });
171
- }
172
- async deleteSecret(name) {
173
- return await this.rpcManager.request({ type: "deleteSecret", name });
174
- }
175
- };
176
-
177
158
  // src/components/ErrorOverlay.tsx
178
- var import_react3 = __toESM(require("react"));
179
- function ErrorOverlay({
159
+ var React2 = __toESM(require("react"));
160
+ var ErrorOverlay = React2.memo(function ErrorOverlay2({
180
161
  error
181
162
  }) {
182
- return /* @__PURE__ */ import_react3.default.createElement(
163
+ return /* @__PURE__ */ React2.createElement(
183
164
  "div",
184
165
  {
185
166
  style: {
@@ -204,7 +185,7 @@ function ErrorOverlay({
204
185
  lineHeight: "19px"
205
186
  }
206
187
  },
207
- error.reason === "schemaMigration" ? /* @__PURE__ */ import_react3.default.createElement(import_react3.default.Fragment, null, /* @__PURE__ */ import_react3.default.createElement("p", null, "An updated version of Noya is available. Please reload the page to continue.")) : /* @__PURE__ */ import_react3.default.createElement(import_react3.default.Fragment, null, /* @__PURE__ */ import_react3.default.createElement("p", null, "An error occurred:", " ", /* @__PURE__ */ import_react3.default.createElement(
188
+ error.reason === "schemaMigration" ? /* @__PURE__ */ React2.createElement(React2.Fragment, null, /* @__PURE__ */ React2.createElement("p", null, "An updated version of Noya is available. Please reload the page to continue.")) : /* @__PURE__ */ React2.createElement(React2.Fragment, null, /* @__PURE__ */ React2.createElement("p", null, "An error occurred:", " ", /* @__PURE__ */ React2.createElement(
208
189
  "code",
209
190
  {
210
191
  style: {
@@ -215,8 +196,8 @@ function ErrorOverlay({
215
196
  }
216
197
  },
217
198
  error.reason
218
- ), ". Please reload the page to continue.", /* @__PURE__ */ import_react3.default.createElement("br", null), /* @__PURE__ */ import_react3.default.createElement("br", null), "If this happens repeatedly, please get in touch and the Noya team can help.")),
219
- /* @__PURE__ */ import_react3.default.createElement(
199
+ ), ". Please reload the page to continue.", /* @__PURE__ */ React2.createElement("br", null), /* @__PURE__ */ React2.createElement("br", null), "If this happens repeatedly, please get in touch and the Noya team can help.")),
200
+ /* @__PURE__ */ React2.createElement(
220
201
  "div",
221
202
  {
222
203
  style: {
@@ -226,7 +207,7 @@ function ErrorOverlay({
226
207
  }
227
208
  }
228
209
  ),
229
- /* @__PURE__ */ import_react3.default.createElement(
210
+ /* @__PURE__ */ React2.createElement(
230
211
  "button",
231
212
  {
232
213
  style: {
@@ -246,27 +227,22 @@ function ErrorOverlay({
246
227
  "Reload"
247
228
  )
248
229
  );
249
- }
250
-
251
- // src/globals.ts
252
- var import_observable2 = require("@noya-app/observable");
253
- var shouldTrackEvents$ = new import_observable2.Observable(false);
254
- var shouldTrackTasks$ = new import_observable2.Observable(false);
230
+ });
255
231
 
256
232
  // src/inspector/useStateInspector.tsx
257
- var import_react6 = __toESM(require("react"));
233
+ var import_react5 = __toESM(require("react"));
258
234
  var import_client = require("react-dom/client");
259
235
 
260
236
  // src/inspector/StateInspector.tsx
261
237
  var import_react_utils2 = require("@noya-app/react-utils");
262
- var import_react5 = __toESM(require("react"));
238
+ var import_react4 = __toESM(require("react"));
263
239
  var import_react_inspector = require("react-inspector");
264
240
 
265
241
  // src/inspector/useLocalStorageState.tsx
266
- var import_react4 = __toESM(require("react"));
242
+ var import_react3 = __toESM(require("react"));
267
243
  var localStorage = typeof window !== "undefined" ? window.localStorage : null;
268
244
  function useLocalStorageState(key, defaultValue) {
269
- const [state, setState] = import_react4.default.useState(() => {
245
+ const [state, setState] = import_react3.default.useState(() => {
270
246
  const value = localStorage?.getItem(key);
271
247
  let result = defaultValue;
272
248
  if (value) {
@@ -311,7 +287,7 @@ function ToggleButton({
311
287
  theme,
312
288
  anchor
313
289
  }) {
314
- return /* @__PURE__ */ import_react5.default.createElement(
290
+ return /* @__PURE__ */ import_react4.default.createElement(
315
291
  "span",
316
292
  {
317
293
  role: "button",
@@ -332,7 +308,7 @@ function ToggleButton({
332
308
  setShowInspector(!showInspector);
333
309
  }
334
310
  },
335
- /* @__PURE__ */ import_react5.default.createElement("span", { style: { width: "12px", height: "12px" } }, showInspector === (anchor === "right") ? /* @__PURE__ */ import_react5.default.createElement(
311
+ /* @__PURE__ */ import_react4.default.createElement("span", { style: { width: "12px", height: "12px" } }, showInspector === (anchor === "right") ? /* @__PURE__ */ import_react4.default.createElement(
336
312
  "svg",
337
313
  {
338
314
  xmlns: "http://www.w3.org/2000/svg",
@@ -342,7 +318,7 @@ function ToggleButton({
342
318
  stroke: "currentColor",
343
319
  className: "size-6"
344
320
  },
345
- /* @__PURE__ */ import_react5.default.createElement(
321
+ /* @__PURE__ */ import_react4.default.createElement(
346
322
  "path",
347
323
  {
348
324
  strokeLinecap: "round",
@@ -350,7 +326,7 @@ function ToggleButton({
350
326
  d: "m5.25 4.5 7.5 7.5-7.5 7.5m6-15 7.5 7.5-7.5 7.5"
351
327
  }
352
328
  )
353
- ) : /* @__PURE__ */ import_react5.default.createElement(
329
+ ) : /* @__PURE__ */ import_react4.default.createElement(
354
330
  "svg",
355
331
  {
356
332
  xmlns: "http://www.w3.org/2000/svg",
@@ -360,7 +336,7 @@ function ToggleButton({
360
336
  stroke: "currentColor",
361
337
  className: "size-6"
362
338
  },
363
- /* @__PURE__ */ import_react5.default.createElement(
339
+ /* @__PURE__ */ import_react4.default.createElement(
364
340
  "path",
365
341
  {
366
342
  strokeLinecap: "round",
@@ -383,7 +359,7 @@ function DisclosureSection({
383
359
  }) {
384
360
  const theme = colorScheme === "light" ? lightTheme : darkTheme;
385
361
  const borderColor = colorScheme === "light" ? "rgba(0,0,0,0.1)" : "rgba(255,255,255,0.1)";
386
- return /* @__PURE__ */ import_react5.default.createElement(
362
+ return /* @__PURE__ */ import_react4.default.createElement(
387
363
  "div",
388
364
  {
389
365
  style: {
@@ -393,7 +369,7 @@ function DisclosureSection({
393
369
  ...style
394
370
  }
395
371
  },
396
- /* @__PURE__ */ import_react5.default.createElement(
372
+ /* @__PURE__ */ import_react4.default.createElement(
397
373
  "div",
398
374
  {
399
375
  onClick: () => setOpen?.(!open),
@@ -407,7 +383,7 @@ function DisclosureSection({
407
383
  ...open && { borderBottom: `1px solid ${borderColor}` }
408
384
  }
409
385
  },
410
- setOpen && /* @__PURE__ */ import_react5.default.createElement(
386
+ setOpen && /* @__PURE__ */ import_react4.default.createElement(
411
387
  Arrow,
412
388
  {
413
389
  expanded: open,
@@ -418,7 +394,7 @@ function DisclosureSection({
418
394
  }
419
395
  }
420
396
  ),
421
- /* @__PURE__ */ import_react5.default.createElement("span", { style: { flex: "1 1 0", userSelect: "none" } }, title),
397
+ /* @__PURE__ */ import_react4.default.createElement("span", { style: { flex: "1 1 0", userSelect: "none" } }, title),
422
398
  right
423
399
  ),
424
400
  open && children
@@ -432,7 +408,7 @@ function InspectorRow({
432
408
  variant
433
409
  }) {
434
410
  const solidBorderColor = colorScheme === "light" ? "rgb(223 223 223)" : "rgb(29 29 29)";
435
- return /* @__PURE__ */ import_react5.default.createElement(
411
+ return /* @__PURE__ */ import_react4.default.createElement(
436
412
  "div",
437
413
  {
438
414
  style: {
@@ -450,7 +426,7 @@ function InspectorRow({
450
426
  ...style
451
427
  }
452
428
  },
453
- /* @__PURE__ */ import_react5.default.createElement(
429
+ /* @__PURE__ */ import_react4.default.createElement(
454
430
  "span",
455
431
  {
456
432
  style: {
@@ -466,26 +442,28 @@ function InspectorRow({
466
442
  }
467
443
  var HISTORY_ELEMENT_PREFIX = "noya-multiplayer-history-";
468
444
  var StateInspector = (0, import_react_utils2.memoGeneric)(function StateInspector2({
469
- state,
470
- connectionEvents,
471
- tasks,
472
- unstyled,
445
+ noyaManager,
473
446
  colorScheme = "light",
474
- multiplayerStateManager,
475
- assetManager,
476
- secretManager,
477
- connectedUsersManager,
478
- ephemeralUserDataManager,
479
447
  anchor = "right",
480
- forceInit,
448
+ unstyled = false,
481
449
  ...props
482
450
  }) {
483
- const [didMount, setDidMount] = import_react5.default.useState(false);
484
- (0, import_react5.useLayoutEffect)(() => {
451
+ const {
452
+ multiplayerStateManager,
453
+ assetManager,
454
+ connectedUsersManager,
455
+ secretManager,
456
+ ephemeralUserDataManager,
457
+ connectionEventManager,
458
+ taskManager
459
+ } = noyaManager;
460
+ const [didMount, setDidMount] = import_react4.default.useState(false);
461
+ const tasks = useObservable(taskManager.tasks$);
462
+ (0, import_react4.useLayoutEffect)(() => {
485
463
  setDidMount(true);
486
464
  }, []);
487
- const eventsContainerRef = import_react5.default.useRef(null);
488
- const historyContainerRef = import_react5.default.useRef(null);
465
+ const eventsContainerRef = import_react4.default.useRef(null);
466
+ const historyContainerRef = import_react4.default.useRef(null);
489
467
  const [showInspector, setShowInspector] = useLocalStorageState(
490
468
  "noya-multiplayer-react-show-inspector",
491
469
  true
@@ -522,29 +500,30 @@ var StateInspector = (0, import_react_utils2.memoGeneric)(function StateInspecto
522
500
  "noya-multiplayer-react-show-secrets",
523
501
  false
524
502
  );
525
- (0, import_react5.useEffect)(() => {
526
- shouldTrackEvents$.set(showEvents);
527
- }, [showEvents]);
528
- (0, import_react5.useEffect)(() => {
529
- shouldTrackTasks$.set(showTasks);
530
- }, [showTasks]);
531
- (0, import_react5.useEffect)(() => {
503
+ const connectionEvents = useObservable(connectionEventManager.events$);
504
+ (0, import_react4.useEffect)(() => {
532
505
  if (eventsContainerRef.current) {
533
506
  eventsContainerRef.current.scrollTop = eventsContainerRef.current.scrollHeight;
534
507
  }
535
508
  }, [connectionEvents]);
509
+ const multipeerStateInitialized = useObservable(
510
+ multiplayerStateManager.isInitialized$
511
+ );
536
512
  const ephemeral = useObservable(ephemeralUserDataManager.data$);
537
513
  const historySnapshot = useManagedHistory(multiplayerStateManager.sm);
538
514
  const assets = useObservable(assetManager.assets$);
515
+ const assetsInitialized = useObservable(assetManager.isInitialized$);
539
516
  const secrets = useObservable(secretManager.secrets$);
517
+ const secretsInitialized = useObservable(secretManager.isInitialized$);
540
518
  const connectedUsers = useObservable(connectedUsersManager.connectedUsers$);
541
519
  const userId = useObservable(connectedUsersManager.currentUserId$);
542
- (0, import_react5.useEffect)(() => {
520
+ const state = useObservable(multiplayerStateManager.optimisticState$);
521
+ (0, import_react4.useEffect)(() => {
543
522
  if (historyContainerRef.current) {
544
523
  historyContainerRef.current.scrollTop = historyContainerRef.current.scrollHeight;
545
524
  }
546
525
  }, [historySnapshot]);
547
- (0, import_react5.useEffect)(() => {
526
+ (0, import_react4.useEffect)(() => {
548
527
  if (!historyContainerRef.current) return;
549
528
  const historyEntry = historyContainerRef.current.querySelector(
550
529
  `#${HISTORY_ELEMENT_PREFIX}${historySnapshot.historyIndex}`
@@ -579,7 +558,7 @@ var StateInspector = (0, import_react_utils2.memoGeneric)(function StateInspecto
579
558
  };
580
559
  if (!didMount) return null;
581
560
  if (!showInspector) {
582
- return /* @__PURE__ */ import_react5.default.createElement(
561
+ return /* @__PURE__ */ import_react4.default.createElement(
583
562
  "div",
584
563
  {
585
564
  ...props,
@@ -591,7 +570,7 @@ var StateInspector = (0, import_react_utils2.memoGeneric)(function StateInspecto
591
570
  },
592
571
  onClick: () => setShowInspector(true)
593
572
  },
594
- /* @__PURE__ */ import_react5.default.createElement(
573
+ /* @__PURE__ */ import_react4.default.createElement(
595
574
  ToggleButton,
596
575
  {
597
576
  showInspector,
@@ -602,7 +581,7 @@ var StateInspector = (0, import_react_utils2.memoGeneric)(function StateInspecto
602
581
  )
603
582
  );
604
583
  }
605
- return /* @__PURE__ */ import_react5.default.createElement(
584
+ return /* @__PURE__ */ import_react4.default.createElement(
606
585
  "div",
607
586
  {
608
587
  ...props,
@@ -611,7 +590,7 @@ var StateInspector = (0, import_react_utils2.memoGeneric)(function StateInspecto
611
590
  ...props.style
612
591
  }
613
592
  },
614
- /* @__PURE__ */ import_react5.default.createElement(
593
+ /* @__PURE__ */ import_react4.default.createElement(
615
594
  DisclosureSection,
616
595
  {
617
596
  isFirst: true,
@@ -623,7 +602,7 @@ var StateInspector = (0, import_react_utils2.memoGeneric)(function StateInspecto
623
602
  flex: "0 0 auto",
624
603
  maxHeight: "200px"
625
604
  },
626
- right: /* @__PURE__ */ import_react5.default.createElement(
605
+ right: /* @__PURE__ */ import_react4.default.createElement(
627
606
  ToggleButton,
628
607
  {
629
608
  showInspector,
@@ -633,14 +612,14 @@ var StateInspector = (0, import_react_utils2.memoGeneric)(function StateInspecto
633
612
  }
634
613
  )
635
614
  },
636
- /* @__PURE__ */ import_react5.default.createElement("div", { style: { ...styles.sectionInner, flex: "0 0 auto" } }, connectedUsers?.map((user) => /* @__PURE__ */ import_react5.default.createElement(
615
+ /* @__PURE__ */ import_react4.default.createElement("div", { style: { ...styles.sectionInner, flex: "0 0 auto" } }, connectedUsers?.map((user) => /* @__PURE__ */ import_react4.default.createElement(
637
616
  InspectorRow,
638
617
  {
639
618
  key: user.id,
640
619
  colorScheme,
641
620
  variant: user.id === userId ? "up" : void 0
642
621
  },
643
- user.image && /* @__PURE__ */ import_react5.default.createElement(
622
+ user.image && /* @__PURE__ */ import_react4.default.createElement(
644
623
  "img",
645
624
  {
646
625
  src: user.image,
@@ -661,7 +640,7 @@ var StateInspector = (0, import_react_utils2.memoGeneric)(function StateInspecto
661
640
  " (",
662
641
  ellipsis(user.id.toString(), 8, "middle"),
663
642
  ")"
664
- )), !connectedUsers && /* @__PURE__ */ import_react5.default.createElement(
643
+ )), !connectedUsers && /* @__PURE__ */ import_react4.default.createElement(
665
644
  "div",
666
645
  {
667
646
  style: {
@@ -672,17 +651,22 @@ var StateInspector = (0, import_react_utils2.memoGeneric)(function StateInspecto
672
651
  gap: "4px"
673
652
  }
674
653
  },
675
- /* @__PURE__ */ import_react5.default.createElement("span", null, "No connected users")
654
+ /* @__PURE__ */ import_react4.default.createElement("span", null, "No connected users")
676
655
  ))
677
656
  ),
678
- /* @__PURE__ */ import_react5.default.createElement(
657
+ /* @__PURE__ */ import_react4.default.createElement(
679
658
  DisclosureSection,
680
659
  {
681
- title: "Data",
660
+ title: /* @__PURE__ */ import_react4.default.createElement(TitleLabel, null, "Data", /* @__PURE__ */ import_react4.default.createElement(
661
+ ColoredDot,
662
+ {
663
+ type: multipeerStateInitialized ? "success" : "error"
664
+ }
665
+ )),
682
666
  colorScheme,
683
667
  setOpen: setShowData,
684
668
  open: showData,
685
- right: /* @__PURE__ */ import_react5.default.createElement(
669
+ right: /* @__PURE__ */ import_react4.default.createElement(
686
670
  "span",
687
671
  {
688
672
  style: {
@@ -690,26 +674,26 @@ var StateInspector = (0, import_react_utils2.memoGeneric)(function StateInspecto
690
674
  gap: "4px"
691
675
  }
692
676
  },
693
- /* @__PURE__ */ import_react5.default.createElement(
677
+ /* @__PURE__ */ import_react4.default.createElement(
694
678
  SmallButton,
695
679
  {
696
680
  theme,
697
681
  onClick: () => {
698
- forceInit();
682
+ noyaManager.forceInit();
699
683
  }
700
684
  },
701
685
  "Reset"
702
686
  )
703
687
  )
704
688
  },
705
- /* @__PURE__ */ import_react5.default.createElement("div", { style: styles.sectionInner }, /* @__PURE__ */ import_react5.default.createElement(InspectorRow, { colorScheme }, /* @__PURE__ */ import_react5.default.createElement(
689
+ /* @__PURE__ */ import_react4.default.createElement("div", { style: styles.sectionInner }, /* @__PURE__ */ import_react4.default.createElement(InspectorRow, { colorScheme }, /* @__PURE__ */ import_react4.default.createElement(
706
690
  import_react_inspector.ObjectInspector,
707
691
  {
708
692
  name: multiplayerStateManager.schema ? "state" : void 0,
709
693
  data: state,
710
694
  theme
711
695
  }
712
- )), multiplayerStateManager.schema && /* @__PURE__ */ import_react5.default.createElement(InspectorRow, { colorScheme }, /* @__PURE__ */ import_react5.default.createElement(
696
+ )), multiplayerStateManager.schema && /* @__PURE__ */ import_react4.default.createElement(InspectorRow, { colorScheme }, /* @__PURE__ */ import_react4.default.createElement(
713
697
  import_react_inspector.ObjectInspector,
714
698
  {
715
699
  name: "schema",
@@ -718,14 +702,14 @@ var StateInspector = (0, import_react_utils2.memoGeneric)(function StateInspecto
718
702
  }
719
703
  )))
720
704
  ),
721
- /* @__PURE__ */ import_react5.default.createElement(
705
+ /* @__PURE__ */ import_react4.default.createElement(
722
706
  DisclosureSection,
723
707
  {
724
708
  open: showHistory,
725
709
  setOpen: setShowHistory,
726
710
  title: "History",
727
711
  colorScheme,
728
- right: /* @__PURE__ */ import_react5.default.createElement(
712
+ right: /* @__PURE__ */ import_react4.default.createElement(
729
713
  "span",
730
714
  {
731
715
  style: {
@@ -733,7 +717,7 @@ var StateInspector = (0, import_react_utils2.memoGeneric)(function StateInspecto
733
717
  gap: "4px"
734
718
  }
735
719
  },
736
- /* @__PURE__ */ import_react5.default.createElement(
720
+ /* @__PURE__ */ import_react4.default.createElement(
737
721
  SmallButton,
738
722
  {
739
723
  disabled: !historySnapshot.canUndo,
@@ -742,7 +726,7 @@ var StateInspector = (0, import_react_utils2.memoGeneric)(function StateInspecto
742
726
  multiplayerStateManager.undo();
743
727
  }
744
728
  },
745
- /* @__PURE__ */ import_react5.default.createElement("span", { style: { width: "12px", height: "12px" } }, /* @__PURE__ */ import_react5.default.createElement(
729
+ /* @__PURE__ */ import_react4.default.createElement("span", { style: { width: "12px", height: "12px" } }, /* @__PURE__ */ import_react4.default.createElement(
746
730
  "svg",
747
731
  {
748
732
  xmlns: "http://www.w3.org/2000/svg",
@@ -750,7 +734,7 @@ var StateInspector = (0, import_react_utils2.memoGeneric)(function StateInspecto
750
734
  height: "1em",
751
735
  viewBox: "0 0 20 20"
752
736
  },
753
- /* @__PURE__ */ import_react5.default.createElement(
737
+ /* @__PURE__ */ import_react4.default.createElement(
754
738
  "path",
755
739
  {
756
740
  fill: "currentColor",
@@ -759,7 +743,7 @@ var StateInspector = (0, import_react_utils2.memoGeneric)(function StateInspecto
759
743
  )
760
744
  ))
761
745
  ),
762
- /* @__PURE__ */ import_react5.default.createElement(
746
+ /* @__PURE__ */ import_react4.default.createElement(
763
747
  SmallButton,
764
748
  {
765
749
  disabled: !historySnapshot.canRedo,
@@ -768,7 +752,7 @@ var StateInspector = (0, import_react_utils2.memoGeneric)(function StateInspecto
768
752
  multiplayerStateManager.redo();
769
753
  }
770
754
  },
771
- /* @__PURE__ */ import_react5.default.createElement("span", { style: { width: "12px", height: "12px" } }, /* @__PURE__ */ import_react5.default.createElement(
755
+ /* @__PURE__ */ import_react4.default.createElement("span", { style: { width: "12px", height: "12px" } }, /* @__PURE__ */ import_react4.default.createElement(
772
756
  "svg",
773
757
  {
774
758
  xmlns: "http://www.w3.org/2000/svg",
@@ -776,7 +760,7 @@ var StateInspector = (0, import_react_utils2.memoGeneric)(function StateInspecto
776
760
  height: "1em",
777
761
  viewBox: "0 0 20 20"
778
762
  },
779
- /* @__PURE__ */ import_react5.default.createElement(
763
+ /* @__PURE__ */ import_react4.default.createElement(
780
764
  "path",
781
765
  {
782
766
  fill: "currentColor",
@@ -787,7 +771,7 @@ var StateInspector = (0, import_react_utils2.memoGeneric)(function StateInspecto
787
771
  )
788
772
  )
789
773
  },
790
- /* @__PURE__ */ import_react5.default.createElement("div", { ref: historyContainerRef, style: styles.sectionInner }, /* @__PURE__ */ import_react5.default.createElement(
774
+ /* @__PURE__ */ import_react4.default.createElement("div", { ref: historyContainerRef, style: styles.sectionInner }, /* @__PURE__ */ import_react4.default.createElement(
791
775
  "div",
792
776
  {
793
777
  id: `${HISTORY_ELEMENT_PREFIX}0`,
@@ -801,7 +785,7 @@ var StateInspector = (0, import_react_utils2.memoGeneric)(function StateInspecto
801
785
  background: historySnapshot.historyIndex === 0 ? "rgb(59 130 246 / 15%)" : void 0
802
786
  }
803
787
  },
804
- /* @__PURE__ */ import_react5.default.createElement(
788
+ /* @__PURE__ */ import_react4.default.createElement(
805
789
  "span",
806
790
  {
807
791
  style: {
@@ -813,7 +797,7 @@ var StateInspector = (0, import_react_utils2.memoGeneric)(function StateInspecto
813
797
  },
814
798
  "Initial state"
815
799
  )
816
- ), historySnapshot.history.map((entry, index) => /* @__PURE__ */ import_react5.default.createElement(
800
+ ), historySnapshot.history.map((entry, index) => /* @__PURE__ */ import_react4.default.createElement(
817
801
  "div",
818
802
  {
819
803
  id: `${HISTORY_ELEMENT_PREFIX}${index + 1}`,
@@ -824,7 +808,7 @@ var StateInspector = (0, import_react_utils2.memoGeneric)(function StateInspecto
824
808
  background: index + 1 === historySnapshot.historyIndex ? "rgb(59 130 246 / 15%)" : void 0
825
809
  }
826
810
  },
827
- "name" in entry.metadata && typeof entry.metadata.name === "string" && /* @__PURE__ */ import_react5.default.createElement(
811
+ "name" in entry.metadata && typeof entry.metadata.name === "string" && /* @__PURE__ */ import_react4.default.createElement(
828
812
  "pre",
829
813
  {
830
814
  style: {
@@ -836,7 +820,7 @@ var StateInspector = (0, import_react_utils2.memoGeneric)(function StateInspecto
836
820
  },
837
821
  entry.metadata.name
838
822
  ),
839
- entry.redoPatches?.map((patch, j) => /* @__PURE__ */ import_react5.default.createElement(
823
+ entry.redoPatches?.map((patch, j) => /* @__PURE__ */ import_react4.default.createElement(
840
824
  "pre",
841
825
  {
842
826
  key: j,
@@ -847,21 +831,34 @@ var StateInspector = (0, import_react_utils2.memoGeneric)(function StateInspecto
847
831
  margin: 0
848
832
  }
849
833
  },
850
- patch.op === "add" && /* @__PURE__ */ import_react5.default.createElement(import_react5.default.Fragment, null, /* @__PURE__ */ import_react5.default.createElement("span", { style: { fontStyle: "italic" } }, pathToString(patch.path)), " = ", /* @__PURE__ */ import_react5.default.createElement(import_react_inspector.ObjectInspector, { data: patch.value, theme })),
851
- patch.op === "replace" && /* @__PURE__ */ import_react5.default.createElement(import_react5.default.Fragment, null, /* @__PURE__ */ import_react5.default.createElement("span", { style: { fontStyle: "italic" } }, pathToString(patch.path)), " = ", /* @__PURE__ */ import_react5.default.createElement(import_react_inspector.ObjectInspector, { data: patch.value, theme })),
852
- patch.op === "remove" && /* @__PURE__ */ import_react5.default.createElement(import_react5.default.Fragment, null, /* @__PURE__ */ import_react5.default.createElement("span", { style: { color: theme.OBJECT_VALUE_STRING_COLOR } }, "delete", " "), /* @__PURE__ */ import_react5.default.createElement("span", { style: { fontStyle: "italic" } }, pathToString(patch.path))),
853
- patch.op === "move" && /* @__PURE__ */ import_react5.default.createElement(import_react5.default.Fragment, null, /* @__PURE__ */ import_react5.default.createElement("span", { style: { fontStyle: "italic" } }, pathToString(patch.from)), " -> ", /* @__PURE__ */ import_react5.default.createElement("span", { style: { fontStyle: "italic" } }, pathToString(patch.path)))
834
+ patch.op === "add" && /* @__PURE__ */ import_react4.default.createElement(import_react4.default.Fragment, null, /* @__PURE__ */ import_react4.default.createElement("span", { style: { fontStyle: "italic" } }, pathToString(patch.path)), " = ", /* @__PURE__ */ import_react4.default.createElement(import_react_inspector.ObjectInspector, { data: patch.value, theme })),
835
+ patch.op === "replace" && /* @__PURE__ */ import_react4.default.createElement(import_react4.default.Fragment, null, /* @__PURE__ */ import_react4.default.createElement("span", { style: { fontStyle: "italic" } }, pathToString(patch.path)), " = ", /* @__PURE__ */ import_react4.default.createElement(import_react_inspector.ObjectInspector, { data: patch.value, theme })),
836
+ patch.op === "remove" && /* @__PURE__ */ import_react4.default.createElement(import_react4.default.Fragment, null, /* @__PURE__ */ import_react4.default.createElement("span", { style: { color: theme.OBJECT_VALUE_STRING_COLOR } }, "delete", " "), /* @__PURE__ */ import_react4.default.createElement("span", { style: { fontStyle: "italic" } }, pathToString(patch.path))),
837
+ patch.op === "move" && /* @__PURE__ */ import_react4.default.createElement(import_react4.default.Fragment, null, /* @__PURE__ */ import_react4.default.createElement("span", { style: { fontStyle: "italic" } }, pathToString(patch.from)), " -> ", /* @__PURE__ */ import_react4.default.createElement("span", { style: { fontStyle: "italic" } }, pathToString(patch.path)))
854
838
  ))
855
839
  )))
856
840
  ),
857
- /* @__PURE__ */ import_react5.default.createElement(
841
+ /* @__PURE__ */ import_react4.default.createElement(
858
842
  DisclosureSection,
859
843
  {
860
844
  open: showAssets,
861
845
  setOpen: setShowAssets,
862
- title: "Assets",
846
+ title: /* @__PURE__ */ import_react4.default.createElement(TitleLabel, null, "Assets", /* @__PURE__ */ import_react4.default.createElement(ColoredDot, { type: assetsInitialized ? "success" : "error" })),
863
847
  colorScheme,
864
- right: /* @__PURE__ */ import_react5.default.createElement("span", { style: { display: "flex", gap: "4px" } }, /* @__PURE__ */ import_react5.default.createElement(
848
+ right: /* @__PURE__ */ import_react4.default.createElement("span", { style: { display: "flex", gap: "10px" } }, /* @__PURE__ */ import_react4.default.createElement(
849
+ SmallButton,
850
+ {
851
+ theme,
852
+ onClick: () => {
853
+ console.info(
854
+ "[StateInspector] Reloading assets",
855
+ noyaManager.id
856
+ );
857
+ assetManager.fetch();
858
+ }
859
+ },
860
+ "Reload"
861
+ ), /* @__PURE__ */ import_react4.default.createElement(
865
862
  SmallButton,
866
863
  {
867
864
  theme,
@@ -885,7 +882,7 @@ var StateInspector = (0, import_react_utils2.memoGeneric)(function StateInspecto
885
882
  "Upload"
886
883
  ))
887
884
  },
888
- /* @__PURE__ */ import_react5.default.createElement("div", { style: styles.sectionInner }, assets.map((asset) => /* @__PURE__ */ import_react5.default.createElement(InspectorRow, { key: asset.id, colorScheme }, /* @__PURE__ */ import_react5.default.createElement(import_react_inspector.ObjectInspector, { name: asset.id, data: asset, theme }), /* @__PURE__ */ import_react5.default.createElement(
885
+ /* @__PURE__ */ import_react4.default.createElement("div", { style: styles.sectionInner }, assets.map((asset) => /* @__PURE__ */ import_react4.default.createElement(InspectorRow, { key: asset.id, colorScheme }, /* @__PURE__ */ import_react4.default.createElement(import_react_inspector.ObjectInspector, { name: asset.id, data: asset, theme }), /* @__PURE__ */ import_react4.default.createElement(
889
886
  SmallButton,
890
887
  {
891
888
  theme,
@@ -894,7 +891,7 @@ var StateInspector = (0, import_react_utils2.memoGeneric)(function StateInspecto
894
891
  "Delete"
895
892
  ))))
896
893
  ),
897
- /* @__PURE__ */ import_react5.default.createElement(
894
+ /* @__PURE__ */ import_react4.default.createElement(
898
895
  DisclosureSection,
899
896
  {
900
897
  title: "Tasks",
@@ -902,7 +899,7 @@ var StateInspector = (0, import_react_utils2.memoGeneric)(function StateInspecto
902
899
  open: showTasks,
903
900
  setOpen: setShowTasks
904
901
  },
905
- /* @__PURE__ */ import_react5.default.createElement("div", { style: styles.sectionInner }, tasks?.map((task) => /* @__PURE__ */ import_react5.default.createElement(
902
+ /* @__PURE__ */ import_react4.default.createElement("div", { style: styles.sectionInner }, tasks?.map((task) => /* @__PURE__ */ import_react4.default.createElement(
906
903
  InspectorRow,
907
904
  {
908
905
  key: task.id,
@@ -911,7 +908,7 @@ var StateInspector = (0, import_react_utils2.memoGeneric)(function StateInspecto
911
908
  backgroundColor: task.status === "done" ? "rgba(0,255,0,0.2)" : task.status === "error" ? "rgba(255,0,0,0.2)" : void 0
912
909
  }
913
910
  },
914
- /* @__PURE__ */ import_react5.default.createElement(
911
+ /* @__PURE__ */ import_react4.default.createElement(
915
912
  import_react_inspector.ObjectInspector,
916
913
  {
917
914
  name: task.name,
@@ -921,14 +918,14 @@ var StateInspector = (0, import_react_utils2.memoGeneric)(function StateInspecto
921
918
  )
922
919
  )))
923
920
  ),
924
- /* @__PURE__ */ import_react5.default.createElement(
921
+ /* @__PURE__ */ import_react4.default.createElement(
925
922
  DisclosureSection,
926
923
  {
927
- title: "Secrets",
924
+ title: /* @__PURE__ */ import_react4.default.createElement(TitleLabel, null, "Secrets", /* @__PURE__ */ import_react4.default.createElement(ColoredDot, { type: secretsInitialized ? "success" : "error" })),
928
925
  colorScheme,
929
926
  open: showSecrets,
930
927
  setOpen: setShowSecrets,
931
- right: /* @__PURE__ */ import_react5.default.createElement(
928
+ right: /* @__PURE__ */ import_react4.default.createElement(
932
929
  SmallButton,
933
930
  {
934
931
  theme,
@@ -943,7 +940,7 @@ var StateInspector = (0, import_react_utils2.memoGeneric)(function StateInspecto
943
940
  "Create"
944
941
  )
945
942
  },
946
- /* @__PURE__ */ import_react5.default.createElement("div", { style: styles.sectionInner }, secrets.map((secret) => /* @__PURE__ */ import_react5.default.createElement(InspectorRow, { key: secret.id, colorScheme }, /* @__PURE__ */ import_react5.default.createElement(import_react_inspector.ObjectInspector, { data: secret, theme }), /* @__PURE__ */ import_react5.default.createElement(
943
+ /* @__PURE__ */ import_react4.default.createElement("div", { style: styles.sectionInner }, secrets.map((secret) => /* @__PURE__ */ import_react4.default.createElement(InspectorRow, { key: secret.id, colorScheme }, /* @__PURE__ */ import_react4.default.createElement(import_react_inspector.ObjectInspector, { data: secret, theme }), /* @__PURE__ */ import_react4.default.createElement(
947
944
  SmallButton,
948
945
  {
949
946
  theme,
@@ -952,7 +949,7 @@ var StateInspector = (0, import_react_utils2.memoGeneric)(function StateInspecto
952
949
  "Delete"
953
950
  ))))
954
951
  ),
955
- /* @__PURE__ */ import_react5.default.createElement(
952
+ /* @__PURE__ */ import_react4.default.createElement(
956
953
  DisclosureSection,
957
954
  {
958
955
  open: showEphemeral,
@@ -960,7 +957,7 @@ var StateInspector = (0, import_react_utils2.memoGeneric)(function StateInspecto
960
957
  title: "Ephemeral User Data",
961
958
  colorScheme
962
959
  },
963
- /* @__PURE__ */ import_react5.default.createElement("div", { style: styles.sectionInner }, Object.entries(ephemeral).map(([key, value]) => /* @__PURE__ */ import_react5.default.createElement(InspectorRow, { key, colorScheme }, /* @__PURE__ */ import_react5.default.createElement(
960
+ /* @__PURE__ */ import_react4.default.createElement("div", { style: styles.sectionInner }, Object.entries(ephemeral).map(([key, value]) => /* @__PURE__ */ import_react4.default.createElement(InspectorRow, { key, colorScheme }, /* @__PURE__ */ import_react4.default.createElement(
964
961
  import_react_inspector.ObjectInspector,
965
962
  {
966
963
  name: key,
@@ -970,7 +967,7 @@ var StateInspector = (0, import_react_utils2.memoGeneric)(function StateInspecto
970
967
  }
971
968
  ))))
972
969
  ),
973
- /* @__PURE__ */ import_react5.default.createElement(
970
+ /* @__PURE__ */ import_react4.default.createElement(
974
971
  DisclosureSection,
975
972
  {
976
973
  open: showEvents,
@@ -978,8 +975,8 @@ var StateInspector = (0, import_react_utils2.memoGeneric)(function StateInspecto
978
975
  title: "Events",
979
976
  colorScheme
980
977
  },
981
- /* @__PURE__ */ import_react5.default.createElement("div", { ref: eventsContainerRef, style: styles.sectionInner }, connectionEvents?.map(
982
- (event, index) => event.type === "stateChange" ? /* @__PURE__ */ import_react5.default.createElement(InspectorRow, { key: index, colorScheme }, "connection:", " ", /* @__PURE__ */ import_react5.default.createElement("span", { style: { fontStyle: "italic" } }, event.state.toLowerCase())) : /* @__PURE__ */ import_react5.default.createElement(
978
+ /* @__PURE__ */ import_react4.default.createElement("div", { ref: eventsContainerRef, style: styles.sectionInner }, connectionEvents?.map(
979
+ (event, index) => event.type === "stateChange" ? /* @__PURE__ */ import_react4.default.createElement(InspectorRow, { key: index, colorScheme }, "connection:", " ", /* @__PURE__ */ import_react4.default.createElement("span", { style: { fontStyle: "italic" } }, event.state.toLowerCase())) : /* @__PURE__ */ import_react4.default.createElement(
983
980
  InspectorRow,
984
981
  {
985
982
  key: index,
@@ -989,7 +986,7 @@ var StateInspector = (0, import_react_utils2.memoGeneric)(function StateInspecto
989
986
  padding: "0px 12px 1px"
990
987
  }
991
988
  },
992
- /* @__PURE__ */ import_react5.default.createElement(
989
+ /* @__PURE__ */ import_react4.default.createElement(
993
990
  import_react_inspector.ObjectInspector,
994
991
  {
995
992
  data: event.type === "error" ? event.error : event.message,
@@ -998,11 +995,10 @@ var StateInspector = (0, import_react_utils2.memoGeneric)(function StateInspecto
998
995
  depth,
999
996
  name,
1000
997
  data,
1001
- isNonenumerable,
1002
- expanded
998
+ isNonenumerable
1003
999
  }) => {
1004
1000
  const direction = event.type === "send" ? "up" : "down";
1005
- return depth === 0 ? /* @__PURE__ */ import_react5.default.createElement(ObjectRootLabel, { direction, data }) : /* @__PURE__ */ import_react5.default.createElement(
1001
+ return depth === 0 ? /* @__PURE__ */ import_react4.default.createElement(ObjectRootLabel, { direction, data }) : /* @__PURE__ */ import_react4.default.createElement(
1006
1002
  import_react_inspector.ObjectLabel,
1007
1003
  {
1008
1004
  direction,
@@ -1015,7 +1011,7 @@ var StateInspector = (0, import_react_utils2.memoGeneric)(function StateInspecto
1015
1011
  }
1016
1012
  )
1017
1013
  )
1018
- ), !connectionEvents && /* @__PURE__ */ import_react5.default.createElement(
1014
+ ), !connectionEvents && /* @__PURE__ */ import_react4.default.createElement(
1019
1015
  "div",
1020
1016
  {
1021
1017
  style: {
@@ -1026,18 +1022,18 @@ var StateInspector = (0, import_react_utils2.memoGeneric)(function StateInspecto
1026
1022
  gap: "4px"
1027
1023
  }
1028
1024
  },
1029
- /* @__PURE__ */ import_react5.default.createElement("span", null, "No recorded events")
1025
+ /* @__PURE__ */ import_react4.default.createElement("span", null, "No recorded events")
1030
1026
  ))
1031
1027
  )
1032
1028
  );
1033
1029
  });
1034
1030
  var ObjectRootLabel = ({ name, data, direction }) => {
1035
1031
  if (typeof name === "string") {
1036
- return /* @__PURE__ */ import_react5.default.createElement("span", null, /* @__PURE__ */ import_react5.default.createElement(import_react_inspector.ObjectName, { name }), /* @__PURE__ */ import_react5.default.createElement("span", null, ": "), /* @__PURE__ */ import_react5.default.createElement(import_react_inspector.ObjectPreview, { data }));
1032
+ return /* @__PURE__ */ import_react4.default.createElement("span", null, /* @__PURE__ */ import_react4.default.createElement(import_react_inspector.ObjectName, { name }), /* @__PURE__ */ import_react4.default.createElement("span", null, ": "), /* @__PURE__ */ import_react4.default.createElement(import_react_inspector.ObjectPreview, { data }));
1037
1033
  }
1038
1034
  if (direction === "up" || direction === "down") {
1039
1035
  const arrow = direction === "up" ? "\u2191" : "\u2193";
1040
- return /* @__PURE__ */ import_react5.default.createElement("span", null, /* @__PURE__ */ import_react5.default.createElement(
1036
+ return /* @__PURE__ */ import_react4.default.createElement("span", null, /* @__PURE__ */ import_react4.default.createElement(
1041
1037
  "span",
1042
1038
  {
1043
1039
  style: {
@@ -1054,9 +1050,9 @@ var ObjectRootLabel = ({ name, data, direction }) => {
1054
1050
  }
1055
1051
  },
1056
1052
  arrow
1057
- ), /* @__PURE__ */ import_react5.default.createElement(import_react_inspector.ObjectPreview, { data }));
1053
+ ), /* @__PURE__ */ import_react4.default.createElement(import_react_inspector.ObjectPreview, { data }));
1058
1054
  } else {
1059
- return /* @__PURE__ */ import_react5.default.createElement(import_react_inspector.ObjectPreview, { data });
1055
+ return /* @__PURE__ */ import_react4.default.createElement(import_react_inspector.ObjectPreview, { data });
1060
1056
  }
1061
1057
  };
1062
1058
  function Arrow({
@@ -1064,7 +1060,7 @@ function Arrow({
1064
1060
  onClick,
1065
1061
  style
1066
1062
  }) {
1067
- return /* @__PURE__ */ import_react5.default.createElement(
1063
+ return /* @__PURE__ */ import_react4.default.createElement(
1068
1064
  "span",
1069
1065
  {
1070
1066
  role: "button",
@@ -1106,7 +1102,7 @@ function SmallButton({
1106
1102
  theme,
1107
1103
  disabled
1108
1104
  }) {
1109
- return /* @__PURE__ */ import_react5.default.createElement(
1105
+ return /* @__PURE__ */ import_react4.default.createElement(
1110
1106
  "button",
1111
1107
  {
1112
1108
  type: "button",
@@ -1135,6 +1131,24 @@ function SmallButton({
1135
1131
  children
1136
1132
  );
1137
1133
  }
1134
+ function ColoredDot({ type }) {
1135
+ return /* @__PURE__ */ import_react4.default.createElement(
1136
+ "span",
1137
+ {
1138
+ style: {
1139
+ display: "inline-block",
1140
+ width: 6,
1141
+ height: 6,
1142
+ background: type === "success" ? "rgba(0,200,0,0.8)" : "rgba(200,0,0,0.8)",
1143
+ borderRadius: "50%",
1144
+ verticalAlign: "middle"
1145
+ }
1146
+ }
1147
+ );
1148
+ }
1149
+ function TitleLabel({ children }) {
1150
+ return /* @__PURE__ */ import_react4.default.createElement("span", { style: { display: "flex", alignItems: "center", gap: "4px" } }, children);
1151
+ }
1138
1152
 
1139
1153
  // src/inspector/useStateInspector.tsx
1140
1154
  function createShadowRootElement() {
@@ -1146,21 +1160,13 @@ function createShadowRootElement() {
1146
1160
  return { host, container };
1147
1161
  }
1148
1162
  function useStateInspector({
1149
- state,
1150
- connectionEvents,
1151
- tasks,
1163
+ noyaManager,
1152
1164
  disabled = false,
1153
1165
  colorScheme,
1154
- anchor,
1155
- multiplayerStateManager,
1156
- assetManager,
1157
- secretManager,
1158
- connectedUsersManager,
1159
- ephemeralUserDataManager,
1160
- forceInit
1166
+ anchor
1161
1167
  }) {
1162
- const [root, setRoot] = import_react6.default.useState(null);
1163
- (0, import_react6.useLayoutEffect)(() => {
1168
+ const [root, setRoot] = import_react5.default.useState(null);
1169
+ (0, import_react5.useLayoutEffect)(() => {
1164
1170
  if (disabled) return;
1165
1171
  const { host, container } = createShadowRootElement();
1166
1172
  const root2 = (0, import_client.createRoot)(container);
@@ -1170,60 +1176,39 @@ function useStateInspector({
1170
1176
  document.body.removeChild(host);
1171
1177
  };
1172
1178
  }, [disabled]);
1173
- (0, import_react6.useLayoutEffect)(() => {
1179
+ (0, import_react5.useLayoutEffect)(() => {
1174
1180
  if (!root) return;
1175
1181
  root.render(
1176
- /* @__PURE__ */ import_react6.default.createElement(
1182
+ /* @__PURE__ */ import_react5.default.createElement(
1177
1183
  StateInspector,
1178
1184
  {
1179
- state,
1180
- connectionEvents,
1181
- tasks,
1182
1185
  colorScheme,
1183
1186
  anchor,
1184
- forceInit,
1185
- multiplayerStateManager,
1186
- assetManager,
1187
- secretManager,
1188
- ephemeralUserDataManager,
1189
- connectedUsersManager
1187
+ noyaManager
1190
1188
  }
1191
1189
  )
1192
1190
  );
1193
- }, [
1194
- anchor,
1195
- colorScheme,
1196
- connectionEvents,
1197
- root,
1198
- state,
1199
- multiplayerStateManager,
1200
- tasks,
1201
- forceInit,
1202
- ephemeralUserDataManager,
1203
- assetManager,
1204
- secretManager,
1205
- connectedUsersManager
1206
- ]);
1191
+ }, [noyaManager, anchor, colorScheme, root]);
1207
1192
  }
1208
1193
 
1209
1194
  // src/hooks.ts
1210
1195
  function useSyncStateManager(stateManager, path) {
1211
- const getSnapshot = (0, import_react7.useCallback)(
1196
+ const getSnapshot = (0, import_react6.useCallback)(
1212
1197
  () => typeof path === "string" ? stateManager.getState(path) : stateManager.getState(),
1213
1198
  [stateManager, path]
1214
1199
  );
1215
- return (0, import_react7.useSyncExternalStore)(
1200
+ return (0, import_react6.useSyncExternalStore)(
1216
1201
  stateManager.addListener,
1217
1202
  getSnapshot,
1218
1203
  getSnapshot
1219
1204
  );
1220
1205
  }
1221
1206
  function useManagedState(createInitialState, options) {
1222
- const [stateManager] = (0, import_react7.useState)(
1207
+ const [stateManager] = (0, import_react6.useState)(
1223
1208
  () => new import_state_manager.StateManager(createInitialState(), options)
1224
1209
  );
1225
1210
  const state = useSyncStateManager(stateManager);
1226
- const setState = (0, import_react7.useCallback)(
1211
+ const setState = (0, import_react6.useCallback)(
1227
1212
  (...args) => {
1228
1213
  const [metadata, action] = args.length === 1 ? [void 0, args[0]] : args;
1229
1214
  if (metadata === void 0) {
@@ -1259,169 +1244,78 @@ function useManagedState(createInitialState, options) {
1259
1244
  return [state, setState, stateManager];
1260
1245
  }
1261
1246
  function useManagedHistory(stateManager) {
1262
- return (0, import_react7.useSyncExternalStore)(
1247
+ return (0, import_react6.useSyncExternalStore)(
1263
1248
  stateManager.historyEmittor.addListener,
1264
1249
  stateManager.getHistorySnapshot,
1265
1250
  stateManager.getHistorySnapshot
1266
1251
  );
1267
1252
  }
1268
- function useSyncMultiplayerStateManager(multiplayerStateManager) {
1269
- return (0, import_react7.useSyncExternalStore)(
1270
- multiplayerStateManager.addListener,
1271
- multiplayerStateManager.getOptimisticState,
1272
- multiplayerStateManager.getOptimisticState
1273
- );
1274
- }
1275
1253
  var defaultStubSync = (0, import_state_manager.stubSync)();
1276
1254
  function useMultiplayerState(initialState, options) {
1277
- const { sync = defaultStubSync, ...rest } = options ?? {};
1278
- const [rpcManager] = (0, import_react7.useState)(
1279
- () => new import_state_manager.RPCManager()
1255
+ const {
1256
+ sync = defaultStubSync,
1257
+ inspector,
1258
+ ...rest
1259
+ } = options ?? {};
1260
+ const [noyaManager] = (0, import_react6.useState)(
1261
+ () => new import_state_manager.NoyaManager(initialState, rest)
1280
1262
  );
1281
- const [multiplayerStateManager] = (0, import_react7.useState)(
1282
- () => new import_state_manager.MultiplayerStateManager(initialState, rest)
1263
+ const state = useObservable(
1264
+ noyaManager.multiplayerStateManager.optimisticState$
1283
1265
  );
1284
- const [assetManager] = (0, import_react7.useState)(() => new import_state_manager.AssetManager());
1285
- const [aiManager] = (0, import_react7.useState)(() => new import_state_manager.AIManager(rpcManager));
1286
- const [workflowManager] = (0, import_react7.useState)(() => new import_state_manager.WorkflowManager(rpcManager));
1287
- const [secretManager] = (0, import_react7.useState)(() => new SecretManager(rpcManager));
1288
- const [connectedUsersManager] = (0, import_react7.useState)(() => new import_state_manager.ConnectedUsersManager());
1289
- const syncRef = (0, import_react7.useRef)(sync);
1290
- const [connectionEvents, setConnectionEvents] = (0, import_react7.useState)();
1291
- const [ephemeralUserDataManager] = (0, import_react7.useState)(
1292
- () => new import_state_manager.EphemeralUserDataManager()
1293
- );
1294
- const [tasks, setTasks] = (0, import_react7.useState)([]);
1295
- const assets = useObservable(assetManager.assets$);
1296
- const extras = (0, import_react7.useMemo)(() => {
1266
+ const assets = useObservable(noyaManager.assetManager.assets$);
1267
+ const extras = (0, import_react6.useMemo)(() => {
1297
1268
  return {
1298
- tasks,
1299
- connectionEvents,
1300
- connectedUsersManager,
1301
- ephemeralUserDataManager,
1302
- multiplayerStateManager,
1303
- assets,
1304
- assetManager,
1305
- aiManager,
1306
- rpcManager,
1307
- workflowManager,
1308
- secretManager,
1309
- createAsset: assetManager.create,
1310
- deleteAsset: assetManager.delete
1311
- // connectionStatus,
1312
- // isConnected: connectionStatus === "connected",
1269
+ noyaManager,
1270
+ taskManager: noyaManager.taskManager,
1271
+ connectionEventManager: noyaManager.connectionEventManager,
1272
+ connectedUsersManager: noyaManager.connectedUsersManager,
1273
+ ephemeralUserDataManager: noyaManager.ephemeralUserDataManager,
1274
+ multiplayerStateManager: noyaManager.multiplayerStateManager,
1275
+ assetManager: noyaManager.assetManager,
1276
+ aiManager: noyaManager.aiManager,
1277
+ rpcManager: noyaManager.rpcManager,
1278
+ workflowManager: noyaManager.workflowManager,
1279
+ secretManager: noyaManager.secretManager,
1280
+ menuItemsManager: noyaManager.menuManager,
1281
+ createAsset: noyaManager.assetManager.create,
1282
+ deleteAsset: noyaManager.assetManager.delete,
1283
+ assets
1313
1284
  };
1314
- }, [
1315
- tasks,
1316
- connectionEvents,
1317
- connectedUsersManager,
1318
- ephemeralUserDataManager,
1319
- multiplayerStateManager,
1320
- assets,
1321
- assetManager,
1322
- aiManager,
1323
- rpcManager,
1324
- workflowManager,
1325
- secretManager
1326
- ]);
1327
- const globalTrackEvents = useObservable(shouldTrackEvents$);
1328
- const globalTrackTasks = useObservable(shouldTrackTasks$);
1329
- const shouldTrackEvents = options?.trackConnectionEvents ?? globalTrackEvents;
1330
- const shouldTrackTasks = options?.trackTasks ?? globalTrackTasks;
1331
- const trackEventsCallbackRef = (0, import_react7.useRef)();
1332
- const trackTasksCallbackRef = (0, import_react7.useRef)();
1333
- (0, import_react7.useEffect)(() => {
1334
- trackEventsCallbackRef.current = shouldTrackEvents ? (e) => setConnectionEvents((events) => {
1335
- const updated = events ? [...events, e] : [e];
1336
- return updated.length > 50 ? updated.slice(-50) : updated;
1337
- }) : void 0;
1338
- }, [shouldTrackEvents]);
1339
- (0, import_react7.useEffect)(() => {
1340
- trackTasksCallbackRef.current = shouldTrackTasks ? (tasks2) => {
1341
- setTasks((old) => {
1342
- const newIds = new Set(tasks2.map((t) => t.id));
1343
- const unchanged = old.filter((t) => !newIds.has(t.id));
1344
- return [...unchanged, ...tasks2];
1345
- });
1346
- } : void 0;
1347
- }, [shouldTrackTasks]);
1348
- (0, import_react7.useEffect)(() => {
1285
+ }, [noyaManager, assets]);
1286
+ const syncRef = (0, import_react6.useRef)(sync);
1287
+ (0, import_react6.useEffect)(() => {
1349
1288
  if (syncRef.current) {
1350
- return syncRef.current({
1351
- ms: multiplayerStateManager,
1352
- assetManager,
1353
- workflowManager,
1354
- secretManager,
1355
- rpcManager,
1356
- aiManager,
1357
- ephemeralUserDataManager,
1358
- connectedUsersManager,
1359
- onConnectionEvent: (e) => trackEventsCallbackRef.current?.(e),
1360
- onChangeTasks: (tasks2) => trackTasksCallbackRef.current?.(tasks2)
1361
- });
1289
+ return syncRef.current({ noyaManager });
1362
1290
  }
1363
- }, [
1364
- assetManager,
1365
- ephemeralUserDataManager,
1366
- multiplayerStateManager,
1367
- workflowManager,
1368
- secretManager,
1369
- rpcManager,
1370
- aiManager,
1371
- connectedUsersManager
1372
- ]);
1373
- const state = useSyncMultiplayerStateManager(multiplayerStateManager);
1374
- const forceInit = (0, import_react7.useCallback)(() => {
1375
- const state2 = initialState instanceof Function ? initialState() : initialState;
1376
- const schema = options?.schema;
1377
- multiplayerStateManager.sm.clearHistory();
1378
- multiplayerStateManager.sendInit({ force: true, state: state2, schema });
1379
- }, [initialState, multiplayerStateManager, options?.schema]);
1380
- const [unrecoverableError, setUnrecoverableError] = (0, import_react7.useState)();
1381
- (0, import_react7.useEffect)(() => {
1382
- return multiplayerStateManager.errorEmitter.addListener((error) => {
1383
- switch (error.reason) {
1384
- case "invalidDataType":
1385
- case "schemaMismatch":
1386
- case "outdatedSchema":
1387
- case "dataMigrationFailure":
1388
- case "schemaMigration":
1389
- setUnrecoverableError(error);
1390
- break;
1391
- }
1392
- });
1393
- }, [multiplayerStateManager]);
1394
- (0, import_react7.useEffect)(() => {
1291
+ }, [noyaManager]);
1292
+ useErrorOverlay(noyaManager);
1293
+ useStateInspector({
1294
+ noyaManager,
1295
+ disabled: !inspector,
1296
+ ...typeof inspector === "object" && inspector
1297
+ });
1298
+ return [state, noyaManager.multiplayerStateManager.setState, extras];
1299
+ }
1300
+ function useErrorOverlay(noyaManager) {
1301
+ const unrecoverableError = useObservable(noyaManager.unrecoverableError);
1302
+ (0, import_react6.useEffect)(() => {
1395
1303
  if (!unrecoverableError) return;
1396
1304
  const el = document.createElement("div");
1397
1305
  el.id = "noya-multiplayer-react-error-overlay";
1398
1306
  document.body.appendChild(el);
1399
1307
  const root = (0, import_client2.createRoot)(el);
1400
- root.render((0, import_react7.createElement)(ErrorOverlay, { error: unrecoverableError }));
1308
+ root.render((0, import_react6.createElement)(ErrorOverlay, { error: unrecoverableError }));
1401
1309
  return () => {
1402
1310
  root.unmount();
1403
1311
  el.remove();
1404
1312
  };
1405
1313
  });
1406
- useStateInspector({
1407
- ephemeralUserDataManager,
1408
- multiplayerStateManager,
1409
- assetManager,
1410
- secretManager,
1411
- state,
1412
- connectionEvents,
1413
- connectedUsersManager,
1414
- tasks,
1415
- forceInit,
1416
- disabled: !options?.inspector,
1417
- ...typeof options?.inspector === "object" && options.inspector
1418
- });
1419
- return [state, multiplayerStateManager.setState, extras];
1420
1314
  }
1421
1315
 
1422
1316
  // src/noyaApp.ts
1423
1317
  var import_state_manager2 = require("@noya-app/state-manager");
1424
- var import_react8 = require("react");
1318
+ var import_react7 = require("react");
1425
1319
  function createDefaultAppData(initialState) {
1426
1320
  return {
1427
1321
  theme: "light",
@@ -1460,43 +1354,6 @@ function getAppData(initialState, schema, options) {
1460
1354
  appData.initialState = enforceSchema(appData.initialState, schema);
1461
1355
  return appData;
1462
1356
  }
1463
- function useBroadcastConnectedUsers(connectedUsersManager) {
1464
- (0, import_react8.useEffect)(() => {
1465
- if (!isEmbeddedApp()) return;
1466
- const unsubscribe = connectedUsersManager.connectedUsers$.subscribe(
1467
- (users) => {
1468
- const message = {
1469
- type: "multiplayer.setUsers",
1470
- payload: { users }
1471
- };
1472
- parent?.postMessage(message, "*");
1473
- }
1474
- );
1475
- return unsubscribe;
1476
- }, [connectedUsersManager]);
1477
- }
1478
- function useBroadcastMenuItems(menuItems, handleSelectMenuItem) {
1479
- (0, import_react8.useEffect)(() => {
1480
- if (!isEmbeddedApp()) return;
1481
- const message = {
1482
- type: "application.setMenuItems",
1483
- payload: { menuItems }
1484
- };
1485
- parent?.postMessage(message, "*");
1486
- const listener = (event) => {
1487
- if (event.data.type === "application.selectMenuItem") {
1488
- handleSelectMenuItem(event.data.payload.value);
1489
- }
1490
- };
1491
- window.addEventListener("message", listener);
1492
- return () => {
1493
- window.removeEventListener("message", listener);
1494
- };
1495
- }, [handleSelectMenuItem, menuItems]);
1496
- }
1497
- function isEmbeddedApp() {
1498
- return window.self !== window.top;
1499
- }
1500
1357
  function useNoyaState(...args) {
1501
1358
  const [initialState, options] = typeof args[0] === "object" && args[0] !== null && "schema" in args[0] && import_state_manager2.TypeGuard.IsSchema(args[0].schema) ? [null, args[0]] : [args[0], args[1]];
1502
1359
  const [
@@ -1507,33 +1364,32 @@ function useNoyaState(...args) {
1507
1364
  theme,
1508
1365
  viewType
1509
1366
  }
1510
- ] = (0, import_react8.useState)(() => {
1367
+ ] = (0, import_react7.useState)(() => {
1511
1368
  return getAppData(initialState, options?.schema, {
1512
1369
  overrideExistingState: options?.overrideExistingState
1513
1370
  });
1514
1371
  });
1515
- const sync = (0, import_react8.useMemo)(() => {
1516
- return multiplayerUrl ? (0, import_state_manager2.webSocketSync)(multiplayerUrl) : options?.offlineStorageKey ? (0, import_state_manager2.localStorageSync)({ key: options.offlineStorageKey }) : (0, import_state_manager2.stubSync)();
1517
- }, [multiplayerUrl, options?.offlineStorageKey]);
1372
+ const sync = (0, import_react7.useMemo)(() => {
1373
+ return (0, import_state_manager2.isEmbeddedApp)() ? (0, import_state_manager2.parentFrameSync)({ debug: options?.debug }) : multiplayerUrl ? (0, import_state_manager2.webSocketSync)(multiplayerUrl) : options?.offlineStorageKey ? (0, import_state_manager2.localStorageSync)({ key: options.offlineStorageKey }) : (0, import_state_manager2.stubSync)();
1374
+ }, [multiplayerUrl, options?.offlineStorageKey, options?.debug]);
1518
1375
  const result = useMultiplayerState(noyaAppInitialState, {
1519
1376
  ...options,
1520
1377
  inspector: options?.inspector ?? inspector,
1521
1378
  sync: options?.sync ?? sync
1522
1379
  });
1523
1380
  const [, , extras] = result;
1524
- useBroadcastConnectedUsers(extras.connectedUsersManager);
1525
- const mergedExtras = (0, import_react8.useMemo)(() => {
1381
+ const mergedExtras = (0, import_react7.useMemo)(() => {
1526
1382
  return { ...extras, theme, viewType };
1527
1383
  }, [extras, theme, viewType]);
1528
1384
  return [result[0], result[1], mergedExtras];
1529
1385
  }
1530
1386
 
1531
1387
  // src/NoyaStateContext.tsx
1532
- var import_observable3 = require("@noya-app/observable");
1533
- var import_react9 = __toESM(require("react"));
1534
- var AnyNoyaStateContext = (0, import_react9.createContext)(void 0);
1388
+ var import_observable = require("@noya-app/observable");
1389
+ var import_react8 = __toESM(require("react"));
1390
+ var AnyNoyaStateContext = (0, import_react8.createContext)(void 0);
1535
1391
  function useAnyNoyaStateContext() {
1536
- const value = (0, import_react9.useContext)(AnyNoyaStateContext);
1392
+ const value = (0, import_react8.useContext)(AnyNoyaStateContext);
1537
1393
  if (!value) {
1538
1394
  throw new Error(
1539
1395
  "useNoyaStateContext must be used within a NoyaStateProvider"
@@ -1547,7 +1403,7 @@ function useAssets() {
1547
1403
  }
1548
1404
  function useAsset(id) {
1549
1405
  const { assetManager } = useAnyNoyaStateContext();
1550
- const observable = (0, import_react9.useMemo)(
1406
+ const observable = (0, import_react8.useMemo)(
1551
1407
  () => assetManager.assets$.map((assets) => assets.find((a) => a.id === id)),
1552
1408
  [assetManager, id]
1553
1409
  );
@@ -1555,7 +1411,7 @@ function useAsset(id) {
1555
1411
  }
1556
1412
  function useAssetManager() {
1557
1413
  const { assetManager } = useAnyNoyaStateContext();
1558
- return (0, import_react9.useMemo)(
1414
+ return (0, import_react8.useMemo)(
1559
1415
  () => ({
1560
1416
  create: assetManager.create,
1561
1417
  delete: assetManager.delete
@@ -1579,13 +1435,17 @@ function useSecret(name) {
1579
1435
  const { secretManager } = useAnyNoyaStateContext();
1580
1436
  return useObservable(
1581
1437
  secretManager.secrets$,
1582
- (0, import_react9.useCallback)((secrets) => secrets.find((s) => s.name === name), [name])
1438
+ (0, import_react8.useCallback)((secrets) => secrets.find((s) => s.name === name), [name])
1583
1439
  );
1584
1440
  }
1585
1441
  function useIsInitialized() {
1586
- const { ms, secretManager, assetManager } = useAnyNoyaStateContext();
1587
- const isInitializedObservable = (0, import_react9.useMemo)(
1588
- () => import_observable3.Observable.combine(
1442
+ const {
1443
+ multiplayerStateManager: ms,
1444
+ secretManager,
1445
+ assetManager
1446
+ } = useAnyNoyaStateContext();
1447
+ const isInitializedObservable = (0, import_react8.useMemo)(
1448
+ () => import_observable.Observable.combine(
1589
1449
  [
1590
1450
  ms.isInitialized$,
1591
1451
  secretManager.isInitialized$,
@@ -1601,13 +1461,13 @@ function useWorkflowManager() {
1601
1461
  const { workflowManager } = useAnyNoyaStateContext();
1602
1462
  return workflowManager;
1603
1463
  }
1604
- var ConnectedUsersContext = (0, import_react9.createContext)(void 0);
1464
+ var ConnectedUsersContext = (0, import_react8.createContext)(void 0);
1605
1465
  function useConnectedUsersManager() {
1606
- return (0, import_react9.useContext)(ConnectedUsersContext);
1466
+ return (0, import_react8.useContext)(ConnectedUsersContext);
1607
1467
  }
1608
- var AnyEphemeralUserDataManagerContext = (0, import_react9.createContext)(void 0);
1468
+ var AnyEphemeralUserDataManagerContext = (0, import_react8.createContext)(void 0);
1609
1469
  function useAnyEphemeralUserData() {
1610
- return (0, import_react9.useContext)(AnyEphemeralUserDataManagerContext);
1470
+ return (0, import_react8.useContext)(AnyEphemeralUserDataManagerContext);
1611
1471
  }
1612
1472
  function useCurrentUserId() {
1613
1473
  const connectedUsersManager = useConnectedUsersManager();
@@ -1631,51 +1491,29 @@ function createNoyaContext({
1631
1491
  initialState,
1632
1492
  ...options
1633
1493
  }) {
1634
- const [
1635
- ,
1636
- ,
1637
- {
1638
- multiplayerStateManager,
1639
- assetManager,
1640
- workflowManager,
1641
- secretManager,
1642
- aiManager,
1643
- ephemeralUserDataManager,
1644
- connectedUsersManager
1645
- }
1646
- ] = useNoyaState(initialState, {
1494
+ const [, , { noyaManager }] = useNoyaState(initialState, {
1647
1495
  ...options,
1648
1496
  schema,
1649
1497
  mergeHistoryEntries
1650
1498
  });
1651
- const value = (0, import_react9.useMemo)(
1652
- () => ({
1653
- ms: multiplayerStateManager,
1654
- assetManager,
1655
- workflowManager,
1656
- secretManager,
1657
- aiManager
1658
- }),
1659
- [
1660
- multiplayerStateManager,
1661
- assetManager,
1662
- workflowManager,
1663
- secretManager,
1664
- aiManager
1665
- ]
1666
- );
1667
- return /* @__PURE__ */ import_react9.default.createElement(AnyNoyaStateContext.Provider, { value }, /* @__PURE__ */ import_react9.default.createElement(ConnectedUsersContext.Provider, { value: connectedUsersManager }, /* @__PURE__ */ import_react9.default.createElement(
1668
- EphemeralUserDataManagerContext.Provider,
1499
+ return /* @__PURE__ */ import_react8.default.createElement(AnyNoyaStateContext.Provider, { value: noyaManager }, /* @__PURE__ */ import_react8.default.createElement(
1500
+ ConnectedUsersContext.Provider,
1669
1501
  {
1670
- value: ephemeralUserDataManager
1502
+ value: noyaManager.connectedUsersManager
1671
1503
  },
1672
- options.fallback !== void 0 ? /* @__PURE__ */ import_react9.default.createElement(FallbackUntilInitialized, { fallback: options.fallback }, children) : children
1673
- )));
1504
+ /* @__PURE__ */ import_react8.default.createElement(
1505
+ EphemeralUserDataManagerContext.Provider,
1506
+ {
1507
+ value: noyaManager.ephemeralUserDataManager
1508
+ },
1509
+ options.fallback !== void 0 ? /* @__PURE__ */ import_react8.default.createElement(FallbackUntilInitialized, { fallback: options.fallback }, children) : children
1510
+ )
1511
+ ));
1674
1512
  }
1675
1513
  function useValue(path, options) {
1676
- const { ms } = useAnyNoyaStateContext();
1514
+ const { multiplayerStateManager: ms } = useAnyNoyaStateContext();
1677
1515
  let actualPath = typeof path === "function" || !path ? "" : path;
1678
- const mappedObservable = (0, import_react9.useMemo)(() => {
1516
+ const mappedObservable = (0, import_react8.useMemo)(() => {
1679
1517
  if (typeof path === "function") {
1680
1518
  return ms.optimisticState$.map(path, { isEqual: options?.isEqual });
1681
1519
  }
@@ -1685,12 +1523,11 @@ function createNoyaContext({
1685
1523
  return value;
1686
1524
  }
1687
1525
  function useSetValue(path) {
1688
- const { ms } = useAnyNoyaStateContext();
1689
- const setValue = (0, import_react9.useCallback)(
1526
+ const { multiplayerStateManager: ms } = useAnyNoyaStateContext();
1527
+ const setValue = (0, import_react8.useCallback)(
1690
1528
  (...args) => {
1691
- const [metadata, value] = args.length === 2 ? args : [void 0, args[0]];
1692
- const setStateAtPath = ms.setStateAtPath;
1693
- setStateAtPath(metadata, path ?? "", value);
1529
+ const [metadata, value] = args.length === 2 ? args : [{}, args[0]];
1530
+ ms.setStateAtPath(metadata, path ?? "", value);
1694
1531
  },
1695
1532
  [ms, path]
1696
1533
  );
@@ -1703,11 +1540,11 @@ function createNoyaContext({
1703
1540
  return [value, setValue];
1704
1541
  }
1705
1542
  function useStateManager() {
1706
- const { ms } = useAnyNoyaStateContext();
1543
+ const { multiplayerStateManager: ms } = useAnyNoyaStateContext();
1707
1544
  return ms;
1708
1545
  }
1709
1546
  function useEphemeralUserDataManager() {
1710
- const ephemeralUserData = (0, import_react9.useContext)(EphemeralUserDataManagerContext);
1547
+ const ephemeralUserData = (0, import_react8.useContext)(EphemeralUserDataManagerContext);
1711
1548
  if (!ephemeralUserData) {
1712
1549
  throw new Error(
1713
1550
  "useEphemeralUserData must be used within a NoyaStateProvider"
@@ -1715,6 +1552,27 @@ function createNoyaContext({
1715
1552
  }
1716
1553
  return ephemeralUserData;
1717
1554
  }
1555
+ function useNoyaManager() {
1556
+ return useAnyNoyaStateContext();
1557
+ }
1558
+ function useLeftMenuItems() {
1559
+ const { menuManager } = useNoyaManager();
1560
+ return useObservable(menuManager.leftMenuItems$);
1561
+ }
1562
+ function useRightMenuItems() {
1563
+ const { menuManager } = useNoyaManager();
1564
+ return useObservable(menuManager.rightMenuItems$);
1565
+ }
1566
+ function useHandleMenuItem(callback) {
1567
+ const { menuManager } = useNoyaManager();
1568
+ (0, import_react8.useEffect)(() => {
1569
+ return menuManager.addListener(callback);
1570
+ }, [menuManager, callback]);
1571
+ }
1572
+ function useOnSelectMenuItemCallback() {
1573
+ const { menuManager } = useNoyaManager();
1574
+ return (0, import_react8.useCallback)((type) => menuManager.emit(type), [menuManager]);
1575
+ }
1718
1576
  return {
1719
1577
  Context: NoyaStateContext,
1720
1578
  Provider: NoyaStateProvider,
@@ -1722,12 +1580,110 @@ function createNoyaContext({
1722
1580
  useSetValue,
1723
1581
  useValueState,
1724
1582
  useStateManager,
1725
- useEphemeralUserDataManager
1726
- // useAssets,
1727
- // useAssetManager,
1728
- // useAsset,
1583
+ useEphemeralUserDataManager,
1584
+ useLeftMenuItems,
1585
+ useRightMenuItems,
1586
+ useHandleMenuItem,
1587
+ useOnSelectMenuItemCallback,
1588
+ useNoyaManager
1729
1589
  };
1730
1590
  }
1591
+
1592
+ // src/WebSocketConnection.ts
1593
+ var import_state_manager3 = require("@noya-app/state-manager");
1594
+ var WebSocketConnection = class {
1595
+ constructor(url, options = {}) {
1596
+ this.url = url;
1597
+ this.options = options;
1598
+ this.ws = new import_state_manager3.ReconnectingWebSocket({
1599
+ debug: options.debug,
1600
+ onopen: this.handleOpen,
1601
+ onmessage: this.handleMessage,
1602
+ onclose: this.handleClose,
1603
+ activityDetector: new import_state_manager3.UserActivityDetector()
1604
+ });
1605
+ }
1606
+ ws;
1607
+ pingCount = 0;
1608
+ pendingPingId;
1609
+ intervalId;
1610
+ async connect() {
1611
+ this.ws.connect(this.url.toString());
1612
+ this.intervalId = setInterval(() => {
1613
+ if (this.ws.state !== "OPEN") return;
1614
+ if (this.pendingPingId) {
1615
+ this.ws.close();
1616
+ return;
1617
+ }
1618
+ const pingId = (this.pingCount++).toString();
1619
+ const message = {
1620
+ type: "ping",
1621
+ id: pingId
1622
+ };
1623
+ this.pendingPingId = message.id;
1624
+ this.options.onConnectionEvent?.({
1625
+ type: "send",
1626
+ message
1627
+ });
1628
+ this.ws.send(JSON.stringify(message));
1629
+ }, 1e4);
1630
+ }
1631
+ handleOpen = () => {
1632
+ this.pendingPingId = void 0;
1633
+ if (this.options.debug) {
1634
+ console.info("ws connected");
1635
+ }
1636
+ this.options.onConnectionEvent?.({
1637
+ type: "stateChange",
1638
+ state: "OPEN"
1639
+ });
1640
+ };
1641
+ handleMessage = (event) => {
1642
+ if (this.options.debug) {
1643
+ console.info("ws receiving message ", event.data);
1644
+ }
1645
+ const parsed = JSON.parse(event.data);
1646
+ this.options.onConnectionEvent?.({
1647
+ type: "receive",
1648
+ message: parsed
1649
+ });
1650
+ if (parsed.type === "pong" && parsed.id === this.pendingPingId) {
1651
+ this.pendingPingId = void 0;
1652
+ }
1653
+ };
1654
+ handleClose = () => {
1655
+ this.pendingPingId = void 0;
1656
+ if (this.options.debug) {
1657
+ console.info("ws disconnected");
1658
+ }
1659
+ this.options.onConnectionEvent?.({
1660
+ type: "stateChange",
1661
+ state: "CLOSED"
1662
+ });
1663
+ };
1664
+ send(message) {
1665
+ if (this.options.debug) {
1666
+ console.info("ws sending message", message);
1667
+ }
1668
+ this.options.onConnectionEvent?.({
1669
+ type: "send",
1670
+ message
1671
+ });
1672
+ this.ws.send(JSON.stringify(message));
1673
+ }
1674
+ close() {
1675
+ if (this.intervalId) {
1676
+ clearInterval(this.intervalId);
1677
+ }
1678
+ this.ws.shutdown();
1679
+ }
1680
+ addListener(listener) {
1681
+ return this.ws.addListener(listener);
1682
+ }
1683
+ removeListener(listener) {
1684
+ return this.ws.removeListener(listener);
1685
+ }
1686
+ };
1731
1687
  // Annotate the CommonJS export names for ESM import in node:
1732
1688
  0 && (module.exports = {
1733
1689
  AnyEphemeralUserDataManagerContext,
@@ -1735,19 +1691,17 @@ function createNoyaContext({
1735
1691
  FallbackUntilInitialized,
1736
1692
  StateInspector,
1737
1693
  UserPointersOverlay,
1694
+ WebSocketConnection,
1738
1695
  createDefaultAppData,
1739
1696
  createNoyaContext,
1740
1697
  enforceSchema,
1741
1698
  getAppData,
1742
- isEmbeddedApp,
1743
1699
  parseAppDataParameter,
1744
1700
  useAIManager,
1745
1701
  useAnyEphemeralUserData,
1746
1702
  useAsset,
1747
1703
  useAssetManager,
1748
1704
  useAssets,
1749
- useBroadcastConnectedUsers,
1750
- useBroadcastMenuItems,
1751
1705
  useConnectedUsersManager,
1752
1706
  useCurrentUserId,
1753
1707
  useIsInitialized,
@@ -1759,7 +1713,6 @@ function createNoyaContext({
1759
1713
  useSecret,
1760
1714
  useSecretManager,
1761
1715
  useSecrets,
1762
- useSyncMultiplayerStateManager,
1763
1716
  useSyncStateManager,
1764
1717
  useWorkflowManager,
1765
1718
  ...require("@noya-app/state-manager")