@noya-app/noya-multiplayer-react 0.1.23 → 0.1.25

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
@@ -50,6 +50,7 @@ __export(src_exports, {
50
50
  useManagedState: () => useManagedState,
51
51
  useMultiplayerState: () => useMultiplayerState,
52
52
  useNoyaAppState: () => useNoyaAppState,
53
+ useObservable: () => useObservable,
53
54
  useSyncMultiplayerStateManager: () => useSyncMultiplayerStateManager,
54
55
  useSyncStateManager: () => useSyncStateManager
55
56
  });
@@ -250,7 +251,82 @@ var UserPointerIcon = (0, import_react2.memo)(function CursorIcon({
250
251
 
251
252
  // src/hooks.ts
252
253
  var import_state_manager = require("@noya-app/state-manager");
253
- var import_react6 = require("react");
254
+ var import_react7 = require("react");
255
+ var import_client2 = require("react-dom/client");
256
+
257
+ // src/components/ErrorOverlay.tsx
258
+ var import_react3 = __toESM(require("react"));
259
+ function ErrorOverlay({
260
+ error
261
+ }) {
262
+ return /* @__PURE__ */ import_react3.default.createElement(
263
+ "div",
264
+ {
265
+ style: {
266
+ position: "fixed",
267
+ top: "20px",
268
+ left: "50%",
269
+ transform: "translateX(-50%)",
270
+ maxWidth: "80%",
271
+ width: "fit-content",
272
+ padding: "12px 20px",
273
+ background: "white",
274
+ color: "black",
275
+ zIndex: 1e4,
276
+ display: "flex",
277
+ flexDirection: "column",
278
+ justifyContent: "center",
279
+ borderRadius: "4px",
280
+ boxShadow: "0 4px 6px rgba(0, 0, 0, 0.1)",
281
+ fontFamily: "'__Inter_6b0edc', '__Inter_Fallback_6b0edc', -apple-system, BlinkMacSystemFont, 'Helvetica Neue', 'Segoe UI', Roboto, Helvetica, Arial, sans-serif",
282
+ fontSize: "14px",
283
+ fontWeight: 400,
284
+ lineHeight: "19px"
285
+ }
286
+ },
287
+ 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(
288
+ "code",
289
+ {
290
+ style: {
291
+ background: "rgba(255, 0, 0, 0.1)",
292
+ color: "rgba(255, 0, 0, 0.5)",
293
+ padding: "2px 4px",
294
+ borderRadius: "4px"
295
+ }
296
+ },
297
+ error.reason
298
+ ), ". 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.")),
299
+ /* @__PURE__ */ import_react3.default.createElement(
300
+ "div",
301
+ {
302
+ style: {
303
+ height: "1px",
304
+ background: "rgba(0, 0, 0, 0.1)",
305
+ margin: "12px -20px"
306
+ }
307
+ }
308
+ ),
309
+ /* @__PURE__ */ import_react3.default.createElement(
310
+ "button",
311
+ {
312
+ style: {
313
+ background: "black",
314
+ color: "white",
315
+ padding: "8px 16px",
316
+ borderRadius: "4px",
317
+ cursor: "pointer",
318
+ fontSize: "14px",
319
+ fontWeight: 700,
320
+ lineHeight: "19px"
321
+ },
322
+ onClick: () => {
323
+ window.location.reload();
324
+ }
325
+ },
326
+ "Reload"
327
+ )
328
+ );
329
+ }
254
330
 
255
331
  // src/globals.ts
256
332
  var import_observable = require("@noya-app/observable");
@@ -258,18 +334,18 @@ var shouldTrackEvents$ = new import_observable.Observable(false);
258
334
  var shouldTrackTasks$ = new import_observable.Observable(false);
259
335
 
260
336
  // src/inspector/useStateInspector.tsx
261
- var import_react5 = __toESM(require("react"));
337
+ var import_react6 = __toESM(require("react"));
262
338
  var import_client = require("react-dom/client");
263
339
 
264
340
  // src/inspector/StateInspector.tsx
265
- var import_react4 = __toESM(require("react"));
341
+ var import_react5 = __toESM(require("react"));
266
342
  var import_react_inspector = require("react-inspector");
267
343
 
268
344
  // src/inspector/useLocalStorageState.tsx
269
- var import_react3 = __toESM(require("react"));
345
+ var import_react4 = __toESM(require("react"));
270
346
  var localStorage = typeof window !== "undefined" ? window.localStorage : null;
271
347
  function useLocalStorageState(key, defaultValue) {
272
- const [state, setState] = import_react3.default.useState(() => {
348
+ const [state, setState] = import_react4.default.useState(() => {
273
349
  const value = localStorage?.getItem(key);
274
350
  let result = defaultValue;
275
351
  if (value) {
@@ -314,7 +390,7 @@ function ToggleButton({
314
390
  theme,
315
391
  anchor
316
392
  }) {
317
- return /* @__PURE__ */ import_react4.default.createElement(
393
+ return /* @__PURE__ */ import_react5.default.createElement(
318
394
  "span",
319
395
  {
320
396
  role: "button",
@@ -335,7 +411,7 @@ function ToggleButton({
335
411
  setShowInspector(!showInspector);
336
412
  }
337
413
  },
338
- /* @__PURE__ */ import_react4.default.createElement("span", { style: { width: "12px", height: "12px" } }, showInspector === (anchor === "right") ? /* @__PURE__ */ import_react4.default.createElement(
414
+ /* @__PURE__ */ import_react5.default.createElement("span", { style: { width: "12px", height: "12px" } }, showInspector === (anchor === "right") ? /* @__PURE__ */ import_react5.default.createElement(
339
415
  "svg",
340
416
  {
341
417
  xmlns: "http://www.w3.org/2000/svg",
@@ -345,7 +421,7 @@ function ToggleButton({
345
421
  stroke: "currentColor",
346
422
  className: "size-6"
347
423
  },
348
- /* @__PURE__ */ import_react4.default.createElement(
424
+ /* @__PURE__ */ import_react5.default.createElement(
349
425
  "path",
350
426
  {
351
427
  strokeLinecap: "round",
@@ -353,7 +429,7 @@ function ToggleButton({
353
429
  d: "m5.25 4.5 7.5 7.5-7.5 7.5m6-15 7.5 7.5-7.5 7.5"
354
430
  }
355
431
  )
356
- ) : /* @__PURE__ */ import_react4.default.createElement(
432
+ ) : /* @__PURE__ */ import_react5.default.createElement(
357
433
  "svg",
358
434
  {
359
435
  xmlns: "http://www.w3.org/2000/svg",
@@ -363,7 +439,7 @@ function ToggleButton({
363
439
  stroke: "currentColor",
364
440
  className: "size-6"
365
441
  },
366
- /* @__PURE__ */ import_react4.default.createElement(
442
+ /* @__PURE__ */ import_react5.default.createElement(
367
443
  "path",
368
444
  {
369
445
  strokeLinecap: "round",
@@ -386,7 +462,7 @@ function DisclosureSection({
386
462
  }) {
387
463
  const theme = colorScheme === "light" ? lightTheme : darkTheme;
388
464
  const borderColor = colorScheme === "light" ? "rgba(0,0,0,0.1)" : "rgba(255,255,255,0.1)";
389
- return /* @__PURE__ */ import_react4.default.createElement(
465
+ return /* @__PURE__ */ import_react5.default.createElement(
390
466
  "div",
391
467
  {
392
468
  style: {
@@ -396,7 +472,7 @@ function DisclosureSection({
396
472
  ...style
397
473
  }
398
474
  },
399
- /* @__PURE__ */ import_react4.default.createElement(
475
+ /* @__PURE__ */ import_react5.default.createElement(
400
476
  "div",
401
477
  {
402
478
  onClick: () => setOpen?.(!open),
@@ -410,7 +486,7 @@ function DisclosureSection({
410
486
  ...open && { borderBottom: `1px solid ${borderColor}` }
411
487
  }
412
488
  },
413
- setOpen && /* @__PURE__ */ import_react4.default.createElement(
489
+ setOpen && /* @__PURE__ */ import_react5.default.createElement(
414
490
  Arrow,
415
491
  {
416
492
  expanded: open,
@@ -421,7 +497,7 @@ function DisclosureSection({
421
497
  }
422
498
  }
423
499
  ),
424
- /* @__PURE__ */ import_react4.default.createElement("span", { style: { flex: "1 1 0", userSelect: "none" } }, title),
500
+ /* @__PURE__ */ import_react5.default.createElement("span", { style: { flex: "1 1 0", userSelect: "none" } }, title),
425
501
  right
426
502
  ),
427
503
  open && children
@@ -435,7 +511,7 @@ function InspectorRow({
435
511
  variant
436
512
  }) {
437
513
  const solidBorderColor = colorScheme === "light" ? "rgb(223 223 223)" : "rgb(29 29 29)";
438
- return /* @__PURE__ */ import_react4.default.createElement(
514
+ return /* @__PURE__ */ import_react5.default.createElement(
439
515
  "div",
440
516
  {
441
517
  style: {
@@ -453,7 +529,7 @@ function InspectorRow({
453
529
  ...style
454
530
  }
455
531
  },
456
- /* @__PURE__ */ import_react4.default.createElement(
532
+ /* @__PURE__ */ import_react5.default.createElement(
457
533
  "span",
458
534
  {
459
535
  style: {
@@ -468,7 +544,7 @@ function InspectorRow({
468
544
  );
469
545
  }
470
546
  var HISTORY_ELEMENT_PREFIX = "noya-multiplayer-history-";
471
- var StateInspector = (0, import_react4.memo)(function StateInspector2({
547
+ var StateInspector = (0, import_react5.memo)(function StateInspector2({
472
548
  state,
473
549
  connectionEvents,
474
550
  connectedUsers,
@@ -482,12 +558,12 @@ var StateInspector = (0, import_react4.memo)(function StateInspector2({
482
558
  forceInit,
483
559
  ...props
484
560
  }) {
485
- const [didMount, setDidMount] = import_react4.default.useState(false);
486
- (0, import_react4.useLayoutEffect)(() => {
561
+ const [didMount, setDidMount] = import_react5.default.useState(false);
562
+ (0, import_react5.useLayoutEffect)(() => {
487
563
  setDidMount(true);
488
564
  }, []);
489
- const eventsContainerRef = import_react4.default.useRef(null);
490
- const historyContainerRef = import_react4.default.useRef(null);
565
+ const eventsContainerRef = import_react5.default.useRef(null);
566
+ const historyContainerRef = import_react5.default.useRef(null);
491
567
  const [showInspector, setShowInspector] = useLocalStorageState(
492
568
  "noya-multiplayer-react-show-inspector",
493
569
  true
@@ -516,25 +592,25 @@ var StateInspector = (0, import_react4.memo)(function StateInspector2({
516
592
  "noya-multiplayer-react-show-ephemeral",
517
593
  false
518
594
  );
519
- (0, import_react4.useEffect)(() => {
595
+ (0, import_react5.useEffect)(() => {
520
596
  shouldTrackEvents$.set(showEvents);
521
597
  }, [showEvents]);
522
- (0, import_react4.useEffect)(() => {
598
+ (0, import_react5.useEffect)(() => {
523
599
  shouldTrackTasks$.set(showTasks);
524
600
  }, [showTasks]);
525
- (0, import_react4.useEffect)(() => {
601
+ (0, import_react5.useEffect)(() => {
526
602
  if (eventsContainerRef.current) {
527
603
  eventsContainerRef.current.scrollTop = eventsContainerRef.current.scrollHeight;
528
604
  }
529
605
  }, [connectionEvents]);
530
606
  const ephemeral = useEphemeralUserData(ephemeralUserData);
531
607
  const historySnapshot = useManagedHistory(multiplayerStateManager.sm);
532
- (0, import_react4.useEffect)(() => {
608
+ (0, import_react5.useEffect)(() => {
533
609
  if (historyContainerRef.current) {
534
610
  historyContainerRef.current.scrollTop = historyContainerRef.current.scrollHeight;
535
611
  }
536
612
  }, [historySnapshot]);
537
- (0, import_react4.useEffect)(() => {
613
+ (0, import_react5.useEffect)(() => {
538
614
  if (!historyContainerRef.current)
539
615
  return;
540
616
  const historyEntry = historyContainerRef.current.querySelector(
@@ -571,7 +647,7 @@ var StateInspector = (0, import_react4.memo)(function StateInspector2({
571
647
  if (!didMount)
572
648
  return null;
573
649
  if (!showInspector) {
574
- return /* @__PURE__ */ import_react4.default.createElement(
650
+ return /* @__PURE__ */ import_react5.default.createElement(
575
651
  "div",
576
652
  {
577
653
  ...props,
@@ -583,7 +659,7 @@ var StateInspector = (0, import_react4.memo)(function StateInspector2({
583
659
  },
584
660
  onClick: () => setShowInspector(true)
585
661
  },
586
- /* @__PURE__ */ import_react4.default.createElement(
662
+ /* @__PURE__ */ import_react5.default.createElement(
587
663
  ToggleButton,
588
664
  {
589
665
  showInspector,
@@ -594,7 +670,7 @@ var StateInspector = (0, import_react4.memo)(function StateInspector2({
594
670
  )
595
671
  );
596
672
  }
597
- return /* @__PURE__ */ import_react4.default.createElement(
673
+ return /* @__PURE__ */ import_react5.default.createElement(
598
674
  "div",
599
675
  {
600
676
  ...props,
@@ -603,7 +679,7 @@ var StateInspector = (0, import_react4.memo)(function StateInspector2({
603
679
  ...props.style
604
680
  }
605
681
  },
606
- /* @__PURE__ */ import_react4.default.createElement(
682
+ /* @__PURE__ */ import_react5.default.createElement(
607
683
  DisclosureSection,
608
684
  {
609
685
  isFirst: true,
@@ -615,7 +691,7 @@ var StateInspector = (0, import_react4.memo)(function StateInspector2({
615
691
  flex: "0 0 auto",
616
692
  maxHeight: "200px"
617
693
  },
618
- right: /* @__PURE__ */ import_react4.default.createElement(
694
+ right: /* @__PURE__ */ import_react5.default.createElement(
619
695
  ToggleButton,
620
696
  {
621
697
  showInspector,
@@ -625,14 +701,14 @@ var StateInspector = (0, import_react4.memo)(function StateInspector2({
625
701
  }
626
702
  )
627
703
  },
628
- /* @__PURE__ */ import_react4.default.createElement("div", { style: { ...styles.sectionInner, flex: "0 0 auto" } }, connectedUsers?.map((user) => /* @__PURE__ */ import_react4.default.createElement(
704
+ /* @__PURE__ */ import_react5.default.createElement("div", { style: { ...styles.sectionInner, flex: "0 0 auto" } }, connectedUsers?.map((user) => /* @__PURE__ */ import_react5.default.createElement(
629
705
  InspectorRow,
630
706
  {
631
707
  key: user.id,
632
708
  colorScheme,
633
709
  variant: user.id === userId ? "up" : void 0
634
710
  },
635
- user.image && /* @__PURE__ */ import_react4.default.createElement(
711
+ user.image && /* @__PURE__ */ import_react5.default.createElement(
636
712
  "img",
637
713
  {
638
714
  src: user.image,
@@ -653,7 +729,7 @@ var StateInspector = (0, import_react4.memo)(function StateInspector2({
653
729
  " (",
654
730
  ellipsis(user.id.toString(), 8, "middle"),
655
731
  ")"
656
- )), !connectedUsers && /* @__PURE__ */ import_react4.default.createElement(
732
+ )), !connectedUsers && /* @__PURE__ */ import_react5.default.createElement(
657
733
  "div",
658
734
  {
659
735
  style: {
@@ -664,17 +740,17 @@ var StateInspector = (0, import_react4.memo)(function StateInspector2({
664
740
  gap: "4px"
665
741
  }
666
742
  },
667
- /* @__PURE__ */ import_react4.default.createElement("span", null, "No connected users")
743
+ /* @__PURE__ */ import_react5.default.createElement("span", null, "No connected users")
668
744
  ))
669
745
  ),
670
- /* @__PURE__ */ import_react4.default.createElement(
746
+ /* @__PURE__ */ import_react5.default.createElement(
671
747
  DisclosureSection,
672
748
  {
673
749
  title: "Data",
674
750
  colorScheme,
675
751
  setOpen: setShowData,
676
752
  open: showData,
677
- right: /* @__PURE__ */ import_react4.default.createElement(
753
+ right: /* @__PURE__ */ import_react5.default.createElement(
678
754
  "span",
679
755
  {
680
756
  style: {
@@ -682,7 +758,7 @@ var StateInspector = (0, import_react4.memo)(function StateInspector2({
682
758
  gap: "4px"
683
759
  }
684
760
  },
685
- /* @__PURE__ */ import_react4.default.createElement(
761
+ /* @__PURE__ */ import_react5.default.createElement(
686
762
  SmallButton,
687
763
  {
688
764
  theme,
@@ -694,14 +770,14 @@ var StateInspector = (0, import_react4.memo)(function StateInspector2({
694
770
  )
695
771
  )
696
772
  },
697
- /* @__PURE__ */ import_react4.default.createElement("div", { style: styles.sectionInner }, /* @__PURE__ */ import_react4.default.createElement(InspectorRow, { colorScheme }, /* @__PURE__ */ import_react4.default.createElement(
773
+ /* @__PURE__ */ import_react5.default.createElement("div", { style: styles.sectionInner }, /* @__PURE__ */ import_react5.default.createElement(InspectorRow, { colorScheme }, /* @__PURE__ */ import_react5.default.createElement(
698
774
  import_react_inspector.ObjectInspector,
699
775
  {
700
776
  name: multiplayerStateManager.schema ? "state" : void 0,
701
777
  data: state,
702
778
  theme
703
779
  }
704
- )), multiplayerStateManager.schema && /* @__PURE__ */ import_react4.default.createElement(InspectorRow, { colorScheme }, /* @__PURE__ */ import_react4.default.createElement(
780
+ )), multiplayerStateManager.schema && /* @__PURE__ */ import_react5.default.createElement(InspectorRow, { colorScheme }, /* @__PURE__ */ import_react5.default.createElement(
705
781
  import_react_inspector.ObjectInspector,
706
782
  {
707
783
  name: "schema",
@@ -710,14 +786,14 @@ var StateInspector = (0, import_react4.memo)(function StateInspector2({
710
786
  }
711
787
  )))
712
788
  ),
713
- /* @__PURE__ */ import_react4.default.createElement(
789
+ /* @__PURE__ */ import_react5.default.createElement(
714
790
  DisclosureSection,
715
791
  {
716
792
  open: showHistory,
717
793
  setOpen: setShowHistory,
718
794
  title: "History",
719
795
  colorScheme,
720
- right: /* @__PURE__ */ import_react4.default.createElement(
796
+ right: /* @__PURE__ */ import_react5.default.createElement(
721
797
  "span",
722
798
  {
723
799
  style: {
@@ -725,7 +801,7 @@ var StateInspector = (0, import_react4.memo)(function StateInspector2({
725
801
  gap: "4px"
726
802
  }
727
803
  },
728
- /* @__PURE__ */ import_react4.default.createElement(
804
+ /* @__PURE__ */ import_react5.default.createElement(
729
805
  SmallButton,
730
806
  {
731
807
  disabled: !historySnapshot.canUndo,
@@ -734,7 +810,7 @@ var StateInspector = (0, import_react4.memo)(function StateInspector2({
734
810
  multiplayerStateManager.undo();
735
811
  }
736
812
  },
737
- /* @__PURE__ */ import_react4.default.createElement("span", { style: { width: "12px", height: "12px" } }, /* @__PURE__ */ import_react4.default.createElement(
813
+ /* @__PURE__ */ import_react5.default.createElement("span", { style: { width: "12px", height: "12px" } }, /* @__PURE__ */ import_react5.default.createElement(
738
814
  "svg",
739
815
  {
740
816
  xmlns: "http://www.w3.org/2000/svg",
@@ -742,7 +818,7 @@ var StateInspector = (0, import_react4.memo)(function StateInspector2({
742
818
  height: "1em",
743
819
  viewBox: "0 0 20 20"
744
820
  },
745
- /* @__PURE__ */ import_react4.default.createElement(
821
+ /* @__PURE__ */ import_react5.default.createElement(
746
822
  "path",
747
823
  {
748
824
  fill: "currentColor",
@@ -751,7 +827,7 @@ var StateInspector = (0, import_react4.memo)(function StateInspector2({
751
827
  )
752
828
  ))
753
829
  ),
754
- /* @__PURE__ */ import_react4.default.createElement(
830
+ /* @__PURE__ */ import_react5.default.createElement(
755
831
  SmallButton,
756
832
  {
757
833
  disabled: !historySnapshot.canRedo,
@@ -760,7 +836,7 @@ var StateInspector = (0, import_react4.memo)(function StateInspector2({
760
836
  multiplayerStateManager.redo();
761
837
  }
762
838
  },
763
- /* @__PURE__ */ import_react4.default.createElement("span", { style: { width: "12px", height: "12px" } }, /* @__PURE__ */ import_react4.default.createElement(
839
+ /* @__PURE__ */ import_react5.default.createElement("span", { style: { width: "12px", height: "12px" } }, /* @__PURE__ */ import_react5.default.createElement(
764
840
  "svg",
765
841
  {
766
842
  xmlns: "http://www.w3.org/2000/svg",
@@ -768,7 +844,7 @@ var StateInspector = (0, import_react4.memo)(function StateInspector2({
768
844
  height: "1em",
769
845
  viewBox: "0 0 20 20"
770
846
  },
771
- /* @__PURE__ */ import_react4.default.createElement(
847
+ /* @__PURE__ */ import_react5.default.createElement(
772
848
  "path",
773
849
  {
774
850
  fill: "currentColor",
@@ -779,7 +855,7 @@ var StateInspector = (0, import_react4.memo)(function StateInspector2({
779
855
  )
780
856
  )
781
857
  },
782
- /* @__PURE__ */ import_react4.default.createElement("div", { ref: historyContainerRef, style: styles.sectionInner }, /* @__PURE__ */ import_react4.default.createElement(
858
+ /* @__PURE__ */ import_react5.default.createElement("div", { ref: historyContainerRef, style: styles.sectionInner }, /* @__PURE__ */ import_react5.default.createElement(
783
859
  "div",
784
860
  {
785
861
  id: `${HISTORY_ELEMENT_PREFIX}0`,
@@ -793,7 +869,7 @@ var StateInspector = (0, import_react4.memo)(function StateInspector2({
793
869
  background: historySnapshot.historyIndex === 0 ? "rgb(59 130 246 / 15%)" : void 0
794
870
  }
795
871
  },
796
- /* @__PURE__ */ import_react4.default.createElement(
872
+ /* @__PURE__ */ import_react5.default.createElement(
797
873
  "span",
798
874
  {
799
875
  style: {
@@ -805,7 +881,7 @@ var StateInspector = (0, import_react4.memo)(function StateInspector2({
805
881
  },
806
882
  "Initial state"
807
883
  )
808
- ), historySnapshot.history.map((entry, index) => /* @__PURE__ */ import_react4.default.createElement(
884
+ ), historySnapshot.history.map((entry, index) => /* @__PURE__ */ import_react5.default.createElement(
809
885
  "div",
810
886
  {
811
887
  id: `${HISTORY_ELEMENT_PREFIX}${index + 1}`,
@@ -816,7 +892,7 @@ var StateInspector = (0, import_react4.memo)(function StateInspector2({
816
892
  background: index + 1 === historySnapshot.historyIndex ? "rgb(59 130 246 / 15%)" : void 0
817
893
  }
818
894
  },
819
- "name" in entry.metadata && typeof entry.metadata.name === "string" && /* @__PURE__ */ import_react4.default.createElement(
895
+ "name" in entry.metadata && typeof entry.metadata.name === "string" && /* @__PURE__ */ import_react5.default.createElement(
820
896
  "pre",
821
897
  {
822
898
  style: {
@@ -827,7 +903,7 @@ var StateInspector = (0, import_react4.memo)(function StateInspector2({
827
903
  },
828
904
  entry.metadata.name
829
905
  ),
830
- entry.redoPatches?.map((patch, j) => /* @__PURE__ */ import_react4.default.createElement(
906
+ entry.redoPatches?.map((patch, j) => /* @__PURE__ */ import_react5.default.createElement(
831
907
  "pre",
832
908
  {
833
909
  key: j,
@@ -837,14 +913,14 @@ var StateInspector = (0, import_react4.memo)(function StateInspector2({
837
913
  flexWrap: "wrap"
838
914
  }
839
915
  },
840
- 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 })),
841
- 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 })),
842
- 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))),
843
- 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)))
916
+ 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 })),
917
+ 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 })),
918
+ 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))),
919
+ 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)))
844
920
  ))
845
921
  )))
846
922
  ),
847
- /* @__PURE__ */ import_react4.default.createElement(
923
+ /* @__PURE__ */ import_react5.default.createElement(
848
924
  DisclosureSection,
849
925
  {
850
926
  title: "Tasks",
@@ -852,7 +928,7 @@ var StateInspector = (0, import_react4.memo)(function StateInspector2({
852
928
  open: showTasks,
853
929
  setOpen: setShowTasks
854
930
  },
855
- /* @__PURE__ */ import_react4.default.createElement("div", { style: styles.sectionInner }, tasks?.map((task) => /* @__PURE__ */ import_react4.default.createElement(
931
+ /* @__PURE__ */ import_react5.default.createElement("div", { style: styles.sectionInner }, tasks?.map((task) => /* @__PURE__ */ import_react5.default.createElement(
856
932
  InspectorRow,
857
933
  {
858
934
  key: task.id,
@@ -861,7 +937,7 @@ var StateInspector = (0, import_react4.memo)(function StateInspector2({
861
937
  backgroundColor: task.status === "done" ? "rgba(0,255,0,0.2)" : task.status === "error" ? "rgba(255,0,0,0.2)" : void 0
862
938
  }
863
939
  },
864
- /* @__PURE__ */ import_react4.default.createElement(
940
+ /* @__PURE__ */ import_react5.default.createElement(
865
941
  import_react_inspector.ObjectInspector,
866
942
  {
867
943
  name: task.name,
@@ -871,7 +947,7 @@ var StateInspector = (0, import_react4.memo)(function StateInspector2({
871
947
  )
872
948
  )))
873
949
  ),
874
- /* @__PURE__ */ import_react4.default.createElement(
950
+ /* @__PURE__ */ import_react5.default.createElement(
875
951
  DisclosureSection,
876
952
  {
877
953
  open: showEphemeral,
@@ -879,7 +955,7 @@ var StateInspector = (0, import_react4.memo)(function StateInspector2({
879
955
  title: "Ephemeral User Data",
880
956
  colorScheme
881
957
  },
882
- /* @__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(
958
+ /* @__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(
883
959
  import_react_inspector.ObjectInspector,
884
960
  {
885
961
  name: key,
@@ -889,7 +965,7 @@ var StateInspector = (0, import_react4.memo)(function StateInspector2({
889
965
  }
890
966
  ))))
891
967
  ),
892
- /* @__PURE__ */ import_react4.default.createElement(
968
+ /* @__PURE__ */ import_react5.default.createElement(
893
969
  DisclosureSection,
894
970
  {
895
971
  open: showEvents,
@@ -897,8 +973,8 @@ var StateInspector = (0, import_react4.memo)(function StateInspector2({
897
973
  title: "Events",
898
974
  colorScheme
899
975
  },
900
- /* @__PURE__ */ import_react4.default.createElement("div", { ref: eventsContainerRef, style: styles.sectionInner }, connectionEvents?.map(
901
- (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(
976
+ /* @__PURE__ */ import_react5.default.createElement("div", { ref: eventsContainerRef, style: styles.sectionInner }, connectionEvents?.map(
977
+ (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(
902
978
  InspectorRow,
903
979
  {
904
980
  key: index,
@@ -908,10 +984,10 @@ var StateInspector = (0, import_react4.memo)(function StateInspector2({
908
984
  padding: "0px 12px 1px"
909
985
  }
910
986
  },
911
- /* @__PURE__ */ import_react4.default.createElement(
987
+ /* @__PURE__ */ import_react5.default.createElement(
912
988
  import_react_inspector.ObjectInspector,
913
989
  {
914
- data: event.message,
990
+ data: event.type === "error" ? event.error : event.message,
915
991
  theme,
916
992
  nodeRenderer: ({
917
993
  depth,
@@ -921,7 +997,7 @@ var StateInspector = (0, import_react4.memo)(function StateInspector2({
921
997
  expanded
922
998
  }) => {
923
999
  const direction = event.type === "send" ? "up" : "down";
924
- return depth === 0 ? /* @__PURE__ */ import_react4.default.createElement(ObjectRootLabel, { direction, data }) : /* @__PURE__ */ import_react4.default.createElement(
1000
+ return depth === 0 ? /* @__PURE__ */ import_react5.default.createElement(ObjectRootLabel, { direction, data }) : /* @__PURE__ */ import_react5.default.createElement(
925
1001
  import_react_inspector.ObjectLabel,
926
1002
  {
927
1003
  direction,
@@ -934,7 +1010,7 @@ var StateInspector = (0, import_react4.memo)(function StateInspector2({
934
1010
  }
935
1011
  )
936
1012
  )
937
- ), !connectionEvents && /* @__PURE__ */ import_react4.default.createElement(
1013
+ ), !connectionEvents && /* @__PURE__ */ import_react5.default.createElement(
938
1014
  "div",
939
1015
  {
940
1016
  style: {
@@ -945,18 +1021,18 @@ var StateInspector = (0, import_react4.memo)(function StateInspector2({
945
1021
  gap: "4px"
946
1022
  }
947
1023
  },
948
- /* @__PURE__ */ import_react4.default.createElement("span", null, "No recorded events")
1024
+ /* @__PURE__ */ import_react5.default.createElement("span", null, "No recorded events")
949
1025
  ))
950
1026
  )
951
1027
  );
952
1028
  });
953
1029
  var ObjectRootLabel = ({ name, data, direction }) => {
954
1030
  if (typeof name === "string") {
955
- 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 }));
1031
+ 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 }));
956
1032
  }
957
1033
  if (direction === "up" || direction === "down") {
958
1034
  const arrow = direction === "up" ? "\u2191" : "\u2193";
959
- return /* @__PURE__ */ import_react4.default.createElement("span", null, /* @__PURE__ */ import_react4.default.createElement(
1035
+ return /* @__PURE__ */ import_react5.default.createElement("span", null, /* @__PURE__ */ import_react5.default.createElement(
960
1036
  "span",
961
1037
  {
962
1038
  style: {
@@ -973,9 +1049,9 @@ var ObjectRootLabel = ({ name, data, direction }) => {
973
1049
  }
974
1050
  },
975
1051
  arrow
976
- ), /* @__PURE__ */ import_react4.default.createElement(import_react_inspector.ObjectPreview, { data }));
1052
+ ), /* @__PURE__ */ import_react5.default.createElement(import_react_inspector.ObjectPreview, { data }));
977
1053
  } else {
978
- return /* @__PURE__ */ import_react4.default.createElement(import_react_inspector.ObjectPreview, { data });
1054
+ return /* @__PURE__ */ import_react5.default.createElement(import_react_inspector.ObjectPreview, { data });
979
1055
  }
980
1056
  };
981
1057
  function Arrow({
@@ -983,7 +1059,7 @@ function Arrow({
983
1059
  onClick,
984
1060
  style
985
1061
  }) {
986
- return /* @__PURE__ */ import_react4.default.createElement(
1062
+ return /* @__PURE__ */ import_react5.default.createElement(
987
1063
  "span",
988
1064
  {
989
1065
  role: "button",
@@ -1026,7 +1102,7 @@ function SmallButton({
1026
1102
  theme,
1027
1103
  disabled
1028
1104
  }) {
1029
- return /* @__PURE__ */ import_react4.default.createElement(
1105
+ return /* @__PURE__ */ import_react5.default.createElement(
1030
1106
  "button",
1031
1107
  {
1032
1108
  type: "button",
@@ -1075,8 +1151,8 @@ function useStateInspector({
1075
1151
  ephemeralUserData,
1076
1152
  forceInit
1077
1153
  }) {
1078
- const [root, setRoot] = import_react5.default.useState(null);
1079
- (0, import_react5.useLayoutEffect)(() => {
1154
+ const [root, setRoot] = import_react6.default.useState(null);
1155
+ (0, import_react6.useLayoutEffect)(() => {
1080
1156
  if (disabled)
1081
1157
  return;
1082
1158
  const portalElement = createPortalElement();
@@ -1087,11 +1163,11 @@ function useStateInspector({
1087
1163
  document.body.removeChild(portalElement);
1088
1164
  };
1089
1165
  }, [disabled]);
1090
- (0, import_react5.useLayoutEffect)(() => {
1166
+ (0, import_react6.useLayoutEffect)(() => {
1091
1167
  if (!root)
1092
1168
  return;
1093
1169
  root.render(
1094
- /* @__PURE__ */ import_react5.default.createElement(
1170
+ /* @__PURE__ */ import_react6.default.createElement(
1095
1171
  StateInspector,
1096
1172
  {
1097
1173
  state,
@@ -1124,27 +1200,27 @@ function useStateInspector({
1124
1200
 
1125
1201
  // src/hooks.ts
1126
1202
  function useSyncStateManager(stateManager, path) {
1127
- const getSnapshot = (0, import_react6.useCallback)(
1203
+ const getSnapshot = (0, import_react7.useCallback)(
1128
1204
  () => typeof path === "string" ? stateManager.getState(path) : stateManager.getState(),
1129
1205
  [stateManager, path]
1130
1206
  );
1131
- return (0, import_react6.useSyncExternalStore)(
1207
+ return (0, import_react7.useSyncExternalStore)(
1132
1208
  stateManager.addListener,
1133
1209
  getSnapshot,
1134
1210
  getSnapshot
1135
1211
  );
1136
1212
  }
1137
1213
  function useManagedState(createInitialState, options) {
1138
- const [stateManager] = (0, import_react6.useState)(
1214
+ const [stateManager] = (0, import_react7.useState)(
1139
1215
  () => new import_state_manager.StateManager(createInitialState(), options)
1140
1216
  );
1141
1217
  const state = useSyncStateManager(stateManager);
1142
- const setState = (0, import_react6.useCallback)(
1218
+ const setState = (0, import_react7.useCallback)(
1143
1219
  (...args) => {
1144
1220
  const [metadata, action] = args.length === 1 ? [void 0, args[0]] : args;
1145
1221
  if (metadata === void 0) {
1146
1222
  const performActionNoMetadata = stateManager.performAction;
1147
- if (typeof action === "function") {
1223
+ if (action instanceof Function) {
1148
1224
  performActionNoMetadata({
1149
1225
  run: action,
1150
1226
  undo: () => state
@@ -1157,7 +1233,7 @@ function useManagedState(createInitialState, options) {
1157
1233
  }
1158
1234
  } else {
1159
1235
  const performActionWithMetadata = stateManager.performAction;
1160
- if (typeof action === "function") {
1236
+ if (action instanceof Function) {
1161
1237
  performActionWithMetadata(metadata, {
1162
1238
  run: action,
1163
1239
  undo: () => state
@@ -1175,22 +1251,54 @@ function useManagedState(createInitialState, options) {
1175
1251
  return [state, setState, stateManager];
1176
1252
  }
1177
1253
  function useManagedHistory(stateManager) {
1178
- return (0, import_react6.useSyncExternalStore)(
1254
+ return (0, import_react7.useSyncExternalStore)(
1179
1255
  stateManager.historyEmittor.addListener,
1180
1256
  stateManager.getHistorySnapshot,
1181
1257
  stateManager.getHistorySnapshot
1182
1258
  );
1183
1259
  }
1184
1260
  function useSyncMultiplayerStateManager(multiplayerStateManager) {
1185
- return (0, import_react6.useSyncExternalStore)(
1261
+ return (0, import_react7.useSyncExternalStore)(
1186
1262
  multiplayerStateManager.addListener,
1187
1263
  multiplayerStateManager.getOptimisticState,
1188
1264
  multiplayerStateManager.getOptimisticState
1189
1265
  );
1190
1266
  }
1191
- function useEphemeralUserData(ephemeralUserData) {
1192
- return (0, import_react6.useSyncExternalStore)(
1193
- ephemeralUserData.addListener,
1267
+ function throttle(fn, ms) {
1268
+ let lastCall = 0;
1269
+ let timeoutId = null;
1270
+ return (...args) => {
1271
+ const now = Date.now();
1272
+ if (now - lastCall < ms) {
1273
+ if (timeoutId)
1274
+ clearTimeout(timeoutId);
1275
+ timeoutId = setTimeout(
1276
+ () => {
1277
+ lastCall = now;
1278
+ fn(...args);
1279
+ },
1280
+ ms - (now - lastCall)
1281
+ );
1282
+ return;
1283
+ }
1284
+ lastCall = now;
1285
+ return fn(...args);
1286
+ };
1287
+ }
1288
+ function useEphemeralUserData(ephemeralUserData, options) {
1289
+ const throttledAddListener = (0, import_react7.useMemo)(() => {
1290
+ const throttleMs = options?.throttle ?? 0;
1291
+ if (throttleMs > 0) {
1292
+ const addListener = (fn) => {
1293
+ const throttledFn = throttle(fn, throttleMs);
1294
+ return ephemeralUserData.addListener(throttledFn);
1295
+ };
1296
+ return addListener;
1297
+ }
1298
+ return ephemeralUserData.addListener;
1299
+ }, [ephemeralUserData, options?.throttle]);
1300
+ return (0, import_react7.useSyncExternalStore)(
1301
+ throttledAddListener,
1194
1302
  ephemeralUserData.getSnapshot,
1195
1303
  ephemeralUserData.getSnapshot
1196
1304
  );
@@ -1198,18 +1306,18 @@ function useEphemeralUserData(ephemeralUserData) {
1198
1306
  var defaultStubSync = (0, import_state_manager.stubSync)();
1199
1307
  function useMultiplayerState(initialState, options) {
1200
1308
  const { sync = defaultStubSync, ...rest } = options ?? {};
1201
- const [multiplayerStateManager] = (0, import_react6.useState)(
1309
+ const [multiplayerStateManager] = (0, import_react7.useState)(
1202
1310
  () => new import_state_manager.MultiplayerStateManager(initialState, rest)
1203
1311
  );
1204
- const syncRef = (0, import_react6.useRef)(sync);
1205
- const [connectionEvents, setConnectionEvents] = (0, import_react6.useState)();
1206
- const [connectedUsers, setConnectedUsers] = (0, import_react6.useState)([]);
1207
- const [ephemeralUserData] = (0, import_react6.useState)(
1312
+ const syncRef = (0, import_react7.useRef)(sync);
1313
+ const [connectionEvents, setConnectionEvents] = (0, import_react7.useState)();
1314
+ const [connectedUsers, setConnectedUsers] = (0, import_react7.useState)([]);
1315
+ const [ephemeralUserData] = (0, import_react7.useState)(
1208
1316
  () => new import_state_manager.EphemeralUserData()
1209
1317
  );
1210
- const [tasks, setTasks] = (0, import_react6.useState)([]);
1211
- const [userId, setUserId] = (0, import_react6.useState)();
1212
- const extras = (0, import_react6.useMemo)(() => {
1318
+ const [tasks, setTasks] = (0, import_react7.useState)([]);
1319
+ const [userId, setUserId] = (0, import_react7.useState)();
1320
+ const extras = (0, import_react7.useMemo)(() => {
1213
1321
  return {
1214
1322
  tasks,
1215
1323
  userId,
@@ -1236,22 +1344,22 @@ function useMultiplayerState(initialState, options) {
1236
1344
  const globalTrackTasks = useObservable(shouldTrackTasks$);
1237
1345
  const shouldTrackEvents = options?.trackConnectionEvents ?? globalTrackEvents;
1238
1346
  const shouldTrackTasks = options?.trackTasks ?? globalTrackTasks;
1239
- const trackEventsCallbackRef = (0, import_react6.useRef)();
1240
- const trackConnectedUsersCallbackRef = (0, import_react6.useRef)();
1241
- const trackTasksCallbackRef = (0, import_react6.useRef)();
1242
- (0, import_react6.useEffect)(() => {
1347
+ const trackEventsCallbackRef = (0, import_react7.useRef)();
1348
+ const trackConnectedUsersCallbackRef = (0, import_react7.useRef)();
1349
+ const trackTasksCallbackRef = (0, import_react7.useRef)();
1350
+ (0, import_react7.useEffect)(() => {
1243
1351
  trackEventsCallbackRef.current = shouldTrackEvents ? (e) => setConnectionEvents((events) => {
1244
1352
  const updated = events ? [...events, e] : [e];
1245
1353
  return updated.length > 50 ? updated.slice(-50) : updated;
1246
1354
  }) : void 0;
1247
1355
  }, [shouldTrackEvents]);
1248
- (0, import_react6.useEffect)(() => {
1356
+ (0, import_react7.useEffect)(() => {
1249
1357
  trackConnectedUsersCallbackRef.current = (users, userId2) => {
1250
1358
  setConnectedUsers(users);
1251
1359
  setUserId(userId2);
1252
1360
  };
1253
1361
  }, []);
1254
- (0, import_react6.useEffect)(() => {
1362
+ (0, import_react7.useEffect)(() => {
1255
1363
  trackTasksCallbackRef.current = shouldTrackTasks ? (tasks2) => {
1256
1364
  setTasks((old) => {
1257
1365
  const newIds = new Set(tasks2.map((t) => t.id));
@@ -1260,7 +1368,7 @@ function useMultiplayerState(initialState, options) {
1260
1368
  });
1261
1369
  } : void 0;
1262
1370
  }, [shouldTrackTasks]);
1263
- (0, import_react6.useEffect)(() => {
1371
+ (0, import_react7.useEffect)(() => {
1264
1372
  if (syncRef.current) {
1265
1373
  return syncRef.current({
1266
1374
  ms: multiplayerStateManager,
@@ -1272,12 +1380,31 @@ function useMultiplayerState(initialState, options) {
1272
1380
  }
1273
1381
  }, [ephemeralUserData, multiplayerStateManager]);
1274
1382
  const state = useSyncMultiplayerStateManager(multiplayerStateManager);
1275
- const forceInit = (0, import_react6.useCallback)(() => {
1276
- const state2 = typeof initialState === "function" ? initialState() : initialState;
1383
+ const forceInit = (0, import_react7.useCallback)(() => {
1384
+ const state2 = initialState instanceof Function ? initialState() : initialState;
1277
1385
  const schema = options?.schema;
1278
1386
  multiplayerStateManager.sm.clearHistory();
1279
1387
  multiplayerStateManager.sendInit({ force: true, state: state2, schema });
1280
1388
  }, [initialState, multiplayerStateManager, options?.schema]);
1389
+ const [unrecoverableError, setUnrecoverableError] = (0, import_react7.useState)();
1390
+ (0, import_react7.useEffect)(() => {
1391
+ return multiplayerStateManager.errorEmitter.addListener((error) => {
1392
+ setUnrecoverableError(error);
1393
+ });
1394
+ }, [multiplayerStateManager]);
1395
+ (0, import_react7.useEffect)(() => {
1396
+ if (!unrecoverableError)
1397
+ return;
1398
+ const el = document.createElement("div");
1399
+ el.id = "noya-multiplayer-react-error-overlay";
1400
+ document.body.appendChild(el);
1401
+ const root = (0, import_client2.createRoot)(el);
1402
+ root.render((0, import_react7.createElement)(ErrorOverlay, { error: unrecoverableError }));
1403
+ return () => {
1404
+ root.unmount();
1405
+ el.remove();
1406
+ };
1407
+ });
1281
1408
  useStateInspector({
1282
1409
  ephemeralUserData,
1283
1410
  multiplayerStateManager,
@@ -1295,7 +1422,7 @@ function useMultiplayerState(initialState, options) {
1295
1422
 
1296
1423
  // src/noyaApp.ts
1297
1424
  var import_state_manager2 = require("@noya-app/state-manager");
1298
- var import_react7 = require("react");
1425
+ var import_react8 = require("react");
1299
1426
  function createDefaultAppData(initialState) {
1300
1427
  return {
1301
1428
  theme: "light",
@@ -1322,7 +1449,7 @@ function getAppData(initialState) {
1322
1449
  }
1323
1450
  }
1324
1451
  function useAppData(initialState, { schema } = {}) {
1325
- const appData = (0, import_react7.useMemo)(() => {
1452
+ const appData = (0, import_react8.useMemo)(() => {
1326
1453
  return getAppData(
1327
1454
  schema ? (0, import_state_manager2.createValue)(schema, initialState) : initialState
1328
1455
  );
@@ -1330,7 +1457,7 @@ function useAppData(initialState, { schema } = {}) {
1330
1457
  return appData;
1331
1458
  }
1332
1459
  function useBroadcastConnectedUsers(connectedUsers) {
1333
- (0, import_react7.useEffect)(() => {
1460
+ (0, import_react8.useEffect)(() => {
1334
1461
  if (!isEmbeddedApp())
1335
1462
  return;
1336
1463
  const message = {
@@ -1341,7 +1468,7 @@ function useBroadcastConnectedUsers(connectedUsers) {
1341
1468
  }, [connectedUsers]);
1342
1469
  }
1343
1470
  function useBroadcastMenuItems(menuItems, handleSelectMenuItem) {
1344
- (0, import_react7.useEffect)(() => {
1471
+ (0, import_react8.useEffect)(() => {
1345
1472
  if (!isEmbeddedApp())
1346
1473
  return;
1347
1474
  const message = {
@@ -1364,7 +1491,7 @@ function isEmbeddedApp() {
1364
1491
  return window.self !== window.top;
1365
1492
  }
1366
1493
  function useNoyaAppState(initialState, options) {
1367
- const [state] = (0, import_react7.useState)(initialState);
1494
+ const [state] = (0, import_react8.useState)(initialState);
1368
1495
  const {
1369
1496
  multiplayerUrl,
1370
1497
  inspector,
@@ -1374,7 +1501,7 @@ function useNoyaAppState(initialState, options) {
1374
1501
  } = useAppData(state, {
1375
1502
  schema: options.schema
1376
1503
  });
1377
- const sync = (0, import_react7.useMemo)(() => {
1504
+ const sync = (0, import_react8.useMemo)(() => {
1378
1505
  return multiplayerUrl ? (0, import_state_manager2.webSocketSync)(multiplayerUrl) : (0, import_state_manager2.localStorageSync)({ key: options.localStorageKey || "noya-app" });
1379
1506
  }, [multiplayerUrl, options.localStorageKey]);
1380
1507
  const result = useMultiplayerState(noyaAppInitialState, {
@@ -1384,7 +1511,7 @@ function useNoyaAppState(initialState, options) {
1384
1511
  });
1385
1512
  const [, , extras] = result;
1386
1513
  useBroadcastConnectedUsers(extras.connectedUsers);
1387
- const mergedExtras = (0, import_react7.useMemo)(() => {
1514
+ const mergedExtras = (0, import_react8.useMemo)(() => {
1388
1515
  return { ...extras, theme, viewType };
1389
1516
  }, [extras, theme, viewType]);
1390
1517
  return [result[0], result[1], mergedExtras];
@@ -1410,6 +1537,7 @@ function useNoyaAppState(initialState, options) {
1410
1537
  useManagedState,
1411
1538
  useMultiplayerState,
1412
1539
  useNoyaAppState,
1540
+ useObservable,
1413
1541
  useSyncMultiplayerStateManager,
1414
1542
  useSyncStateManager,
1415
1543
  ...require("@noya-app/state-manager")