@noya-app/noya-multiplayer-react 0.1.24 → 0.1.26

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.mjs CHANGED
@@ -201,6 +201,7 @@ import {
201
201
  stubSync
202
202
  } from "@noya-app/state-manager";
203
203
  import {
204
+ createElement,
204
205
  useCallback,
205
206
  useEffect as useEffect3,
206
207
  useMemo as useMemo3,
@@ -208,6 +209,81 @@ import {
208
209
  useState as useState2,
209
210
  useSyncExternalStore as useSyncExternalStore2
210
211
  } from "react";
212
+ import { createRoot as createRoot2 } from "react-dom/client";
213
+
214
+ // src/components/ErrorOverlay.tsx
215
+ import React2 from "react";
216
+ function ErrorOverlay({
217
+ error
218
+ }) {
219
+ return /* @__PURE__ */ React2.createElement(
220
+ "div",
221
+ {
222
+ style: {
223
+ position: "fixed",
224
+ top: "20px",
225
+ left: "50%",
226
+ transform: "translateX(-50%)",
227
+ maxWidth: "80%",
228
+ width: "fit-content",
229
+ padding: "12px 20px",
230
+ background: "white",
231
+ color: "black",
232
+ zIndex: 1e4,
233
+ display: "flex",
234
+ flexDirection: "column",
235
+ justifyContent: "center",
236
+ borderRadius: "4px",
237
+ boxShadow: "0 4px 6px rgba(0, 0, 0, 0.1)",
238
+ fontFamily: "'__Inter_6b0edc', '__Inter_Fallback_6b0edc', -apple-system, BlinkMacSystemFont, 'Helvetica Neue', 'Segoe UI', Roboto, Helvetica, Arial, sans-serif",
239
+ fontSize: "14px",
240
+ fontWeight: 400,
241
+ lineHeight: "19px"
242
+ }
243
+ },
244
+ 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(
245
+ "code",
246
+ {
247
+ style: {
248
+ background: "rgba(255, 0, 0, 0.1)",
249
+ color: "rgba(255, 0, 0, 0.5)",
250
+ padding: "2px 4px",
251
+ borderRadius: "4px"
252
+ }
253
+ },
254
+ error.reason
255
+ ), ". 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.")),
256
+ /* @__PURE__ */ React2.createElement(
257
+ "div",
258
+ {
259
+ style: {
260
+ height: "1px",
261
+ background: "rgba(0, 0, 0, 0.1)",
262
+ margin: "12px -20px"
263
+ }
264
+ }
265
+ ),
266
+ /* @__PURE__ */ React2.createElement(
267
+ "button",
268
+ {
269
+ style: {
270
+ background: "black",
271
+ color: "white",
272
+ padding: "8px 16px",
273
+ borderRadius: "4px",
274
+ cursor: "pointer",
275
+ fontSize: "14px",
276
+ fontWeight: 700,
277
+ lineHeight: "19px"
278
+ },
279
+ onClick: () => {
280
+ window.location.reload();
281
+ }
282
+ },
283
+ "Reload"
284
+ )
285
+ );
286
+ }
211
287
 
212
288
  // src/globals.ts
213
289
  import { Observable } from "@noya-app/observable";
@@ -215,11 +291,11 @@ var shouldTrackEvents$ = new Observable(false);
215
291
  var shouldTrackTasks$ = new Observable(false);
216
292
 
217
293
  // src/inspector/useStateInspector.tsx
218
- import React4, { useLayoutEffect as useLayoutEffect2 } from "react";
294
+ import React5, { useLayoutEffect as useLayoutEffect2 } from "react";
219
295
  import { createRoot } from "react-dom/client";
220
296
 
221
297
  // src/inspector/StateInspector.tsx
222
- import React3, {
298
+ import React4, {
223
299
  memo as memo2,
224
300
  useEffect as useEffect2,
225
301
  useLayoutEffect
@@ -234,10 +310,10 @@ import {
234
310
  } from "react-inspector";
235
311
 
236
312
  // src/inspector/useLocalStorageState.tsx
237
- import React2 from "react";
313
+ import React3 from "react";
238
314
  var localStorage = typeof window !== "undefined" ? window.localStorage : null;
239
315
  function useLocalStorageState(key, defaultValue) {
240
- const [state, setState] = React2.useState(() => {
316
+ const [state, setState] = React3.useState(() => {
241
317
  const value = localStorage?.getItem(key);
242
318
  let result = defaultValue;
243
319
  if (value) {
@@ -282,7 +358,7 @@ function ToggleButton({
282
358
  theme,
283
359
  anchor
284
360
  }) {
285
- return /* @__PURE__ */ React3.createElement(
361
+ return /* @__PURE__ */ React4.createElement(
286
362
  "span",
287
363
  {
288
364
  role: "button",
@@ -303,7 +379,7 @@ function ToggleButton({
303
379
  setShowInspector(!showInspector);
304
380
  }
305
381
  },
306
- /* @__PURE__ */ React3.createElement("span", { style: { width: "12px", height: "12px" } }, showInspector === (anchor === "right") ? /* @__PURE__ */ React3.createElement(
382
+ /* @__PURE__ */ React4.createElement("span", { style: { width: "12px", height: "12px" } }, showInspector === (anchor === "right") ? /* @__PURE__ */ React4.createElement(
307
383
  "svg",
308
384
  {
309
385
  xmlns: "http://www.w3.org/2000/svg",
@@ -313,7 +389,7 @@ function ToggleButton({
313
389
  stroke: "currentColor",
314
390
  className: "size-6"
315
391
  },
316
- /* @__PURE__ */ React3.createElement(
392
+ /* @__PURE__ */ React4.createElement(
317
393
  "path",
318
394
  {
319
395
  strokeLinecap: "round",
@@ -321,7 +397,7 @@ function ToggleButton({
321
397
  d: "m5.25 4.5 7.5 7.5-7.5 7.5m6-15 7.5 7.5-7.5 7.5"
322
398
  }
323
399
  )
324
- ) : /* @__PURE__ */ React3.createElement(
400
+ ) : /* @__PURE__ */ React4.createElement(
325
401
  "svg",
326
402
  {
327
403
  xmlns: "http://www.w3.org/2000/svg",
@@ -331,7 +407,7 @@ function ToggleButton({
331
407
  stroke: "currentColor",
332
408
  className: "size-6"
333
409
  },
334
- /* @__PURE__ */ React3.createElement(
410
+ /* @__PURE__ */ React4.createElement(
335
411
  "path",
336
412
  {
337
413
  strokeLinecap: "round",
@@ -354,7 +430,7 @@ function DisclosureSection({
354
430
  }) {
355
431
  const theme = colorScheme === "light" ? lightTheme : darkTheme;
356
432
  const borderColor = colorScheme === "light" ? "rgba(0,0,0,0.1)" : "rgba(255,255,255,0.1)";
357
- return /* @__PURE__ */ React3.createElement(
433
+ return /* @__PURE__ */ React4.createElement(
358
434
  "div",
359
435
  {
360
436
  style: {
@@ -364,7 +440,7 @@ function DisclosureSection({
364
440
  ...style
365
441
  }
366
442
  },
367
- /* @__PURE__ */ React3.createElement(
443
+ /* @__PURE__ */ React4.createElement(
368
444
  "div",
369
445
  {
370
446
  onClick: () => setOpen?.(!open),
@@ -378,7 +454,7 @@ function DisclosureSection({
378
454
  ...open && { borderBottom: `1px solid ${borderColor}` }
379
455
  }
380
456
  },
381
- setOpen && /* @__PURE__ */ React3.createElement(
457
+ setOpen && /* @__PURE__ */ React4.createElement(
382
458
  Arrow,
383
459
  {
384
460
  expanded: open,
@@ -389,7 +465,7 @@ function DisclosureSection({
389
465
  }
390
466
  }
391
467
  ),
392
- /* @__PURE__ */ React3.createElement("span", { style: { flex: "1 1 0", userSelect: "none" } }, title),
468
+ /* @__PURE__ */ React4.createElement("span", { style: { flex: "1 1 0", userSelect: "none" } }, title),
393
469
  right
394
470
  ),
395
471
  open && children
@@ -403,7 +479,7 @@ function InspectorRow({
403
479
  variant
404
480
  }) {
405
481
  const solidBorderColor = colorScheme === "light" ? "rgb(223 223 223)" : "rgb(29 29 29)";
406
- return /* @__PURE__ */ React3.createElement(
482
+ return /* @__PURE__ */ React4.createElement(
407
483
  "div",
408
484
  {
409
485
  style: {
@@ -421,7 +497,7 @@ function InspectorRow({
421
497
  ...style
422
498
  }
423
499
  },
424
- /* @__PURE__ */ React3.createElement(
500
+ /* @__PURE__ */ React4.createElement(
425
501
  "span",
426
502
  {
427
503
  style: {
@@ -450,12 +526,12 @@ var StateInspector = memo2(function StateInspector2({
450
526
  forceInit,
451
527
  ...props
452
528
  }) {
453
- const [didMount, setDidMount] = React3.useState(false);
529
+ const [didMount, setDidMount] = React4.useState(false);
454
530
  useLayoutEffect(() => {
455
531
  setDidMount(true);
456
532
  }, []);
457
- const eventsContainerRef = React3.useRef(null);
458
- const historyContainerRef = React3.useRef(null);
533
+ const eventsContainerRef = React4.useRef(null);
534
+ const historyContainerRef = React4.useRef(null);
459
535
  const [showInspector, setShowInspector] = useLocalStorageState(
460
536
  "noya-multiplayer-react-show-inspector",
461
537
  true
@@ -539,7 +615,7 @@ var StateInspector = memo2(function StateInspector2({
539
615
  if (!didMount)
540
616
  return null;
541
617
  if (!showInspector) {
542
- return /* @__PURE__ */ React3.createElement(
618
+ return /* @__PURE__ */ React4.createElement(
543
619
  "div",
544
620
  {
545
621
  ...props,
@@ -551,7 +627,7 @@ var StateInspector = memo2(function StateInspector2({
551
627
  },
552
628
  onClick: () => setShowInspector(true)
553
629
  },
554
- /* @__PURE__ */ React3.createElement(
630
+ /* @__PURE__ */ React4.createElement(
555
631
  ToggleButton,
556
632
  {
557
633
  showInspector,
@@ -562,7 +638,7 @@ var StateInspector = memo2(function StateInspector2({
562
638
  )
563
639
  );
564
640
  }
565
- return /* @__PURE__ */ React3.createElement(
641
+ return /* @__PURE__ */ React4.createElement(
566
642
  "div",
567
643
  {
568
644
  ...props,
@@ -571,7 +647,7 @@ var StateInspector = memo2(function StateInspector2({
571
647
  ...props.style
572
648
  }
573
649
  },
574
- /* @__PURE__ */ React3.createElement(
650
+ /* @__PURE__ */ React4.createElement(
575
651
  DisclosureSection,
576
652
  {
577
653
  isFirst: true,
@@ -583,7 +659,7 @@ var StateInspector = memo2(function StateInspector2({
583
659
  flex: "0 0 auto",
584
660
  maxHeight: "200px"
585
661
  },
586
- right: /* @__PURE__ */ React3.createElement(
662
+ right: /* @__PURE__ */ React4.createElement(
587
663
  ToggleButton,
588
664
  {
589
665
  showInspector,
@@ -593,14 +669,14 @@ var StateInspector = memo2(function StateInspector2({
593
669
  }
594
670
  )
595
671
  },
596
- /* @__PURE__ */ React3.createElement("div", { style: { ...styles.sectionInner, flex: "0 0 auto" } }, connectedUsers?.map((user) => /* @__PURE__ */ React3.createElement(
672
+ /* @__PURE__ */ React4.createElement("div", { style: { ...styles.sectionInner, flex: "0 0 auto" } }, connectedUsers?.map((user) => /* @__PURE__ */ React4.createElement(
597
673
  InspectorRow,
598
674
  {
599
675
  key: user.id,
600
676
  colorScheme,
601
677
  variant: user.id === userId ? "up" : void 0
602
678
  },
603
- user.image && /* @__PURE__ */ React3.createElement(
679
+ user.image && /* @__PURE__ */ React4.createElement(
604
680
  "img",
605
681
  {
606
682
  src: user.image,
@@ -621,7 +697,7 @@ var StateInspector = memo2(function StateInspector2({
621
697
  " (",
622
698
  ellipsis(user.id.toString(), 8, "middle"),
623
699
  ")"
624
- )), !connectedUsers && /* @__PURE__ */ React3.createElement(
700
+ )), !connectedUsers && /* @__PURE__ */ React4.createElement(
625
701
  "div",
626
702
  {
627
703
  style: {
@@ -632,17 +708,17 @@ var StateInspector = memo2(function StateInspector2({
632
708
  gap: "4px"
633
709
  }
634
710
  },
635
- /* @__PURE__ */ React3.createElement("span", null, "No connected users")
711
+ /* @__PURE__ */ React4.createElement("span", null, "No connected users")
636
712
  ))
637
713
  ),
638
- /* @__PURE__ */ React3.createElement(
714
+ /* @__PURE__ */ React4.createElement(
639
715
  DisclosureSection,
640
716
  {
641
717
  title: "Data",
642
718
  colorScheme,
643
719
  setOpen: setShowData,
644
720
  open: showData,
645
- right: /* @__PURE__ */ React3.createElement(
721
+ right: /* @__PURE__ */ React4.createElement(
646
722
  "span",
647
723
  {
648
724
  style: {
@@ -650,7 +726,7 @@ var StateInspector = memo2(function StateInspector2({
650
726
  gap: "4px"
651
727
  }
652
728
  },
653
- /* @__PURE__ */ React3.createElement(
729
+ /* @__PURE__ */ React4.createElement(
654
730
  SmallButton,
655
731
  {
656
732
  theme,
@@ -662,14 +738,14 @@ var StateInspector = memo2(function StateInspector2({
662
738
  )
663
739
  )
664
740
  },
665
- /* @__PURE__ */ React3.createElement("div", { style: styles.sectionInner }, /* @__PURE__ */ React3.createElement(InspectorRow, { colorScheme }, /* @__PURE__ */ React3.createElement(
741
+ /* @__PURE__ */ React4.createElement("div", { style: styles.sectionInner }, /* @__PURE__ */ React4.createElement(InspectorRow, { colorScheme }, /* @__PURE__ */ React4.createElement(
666
742
  ObjectInspector,
667
743
  {
668
744
  name: multiplayerStateManager.schema ? "state" : void 0,
669
745
  data: state,
670
746
  theme
671
747
  }
672
- )), multiplayerStateManager.schema && /* @__PURE__ */ React3.createElement(InspectorRow, { colorScheme }, /* @__PURE__ */ React3.createElement(
748
+ )), multiplayerStateManager.schema && /* @__PURE__ */ React4.createElement(InspectorRow, { colorScheme }, /* @__PURE__ */ React4.createElement(
673
749
  ObjectInspector,
674
750
  {
675
751
  name: "schema",
@@ -678,14 +754,14 @@ var StateInspector = memo2(function StateInspector2({
678
754
  }
679
755
  )))
680
756
  ),
681
- /* @__PURE__ */ React3.createElement(
757
+ /* @__PURE__ */ React4.createElement(
682
758
  DisclosureSection,
683
759
  {
684
760
  open: showHistory,
685
761
  setOpen: setShowHistory,
686
762
  title: "History",
687
763
  colorScheme,
688
- right: /* @__PURE__ */ React3.createElement(
764
+ right: /* @__PURE__ */ React4.createElement(
689
765
  "span",
690
766
  {
691
767
  style: {
@@ -693,7 +769,7 @@ var StateInspector = memo2(function StateInspector2({
693
769
  gap: "4px"
694
770
  }
695
771
  },
696
- /* @__PURE__ */ React3.createElement(
772
+ /* @__PURE__ */ React4.createElement(
697
773
  SmallButton,
698
774
  {
699
775
  disabled: !historySnapshot.canUndo,
@@ -702,7 +778,7 @@ var StateInspector = memo2(function StateInspector2({
702
778
  multiplayerStateManager.undo();
703
779
  }
704
780
  },
705
- /* @__PURE__ */ React3.createElement("span", { style: { width: "12px", height: "12px" } }, /* @__PURE__ */ React3.createElement(
781
+ /* @__PURE__ */ React4.createElement("span", { style: { width: "12px", height: "12px" } }, /* @__PURE__ */ React4.createElement(
706
782
  "svg",
707
783
  {
708
784
  xmlns: "http://www.w3.org/2000/svg",
@@ -710,7 +786,7 @@ var StateInspector = memo2(function StateInspector2({
710
786
  height: "1em",
711
787
  viewBox: "0 0 20 20"
712
788
  },
713
- /* @__PURE__ */ React3.createElement(
789
+ /* @__PURE__ */ React4.createElement(
714
790
  "path",
715
791
  {
716
792
  fill: "currentColor",
@@ -719,7 +795,7 @@ var StateInspector = memo2(function StateInspector2({
719
795
  )
720
796
  ))
721
797
  ),
722
- /* @__PURE__ */ React3.createElement(
798
+ /* @__PURE__ */ React4.createElement(
723
799
  SmallButton,
724
800
  {
725
801
  disabled: !historySnapshot.canRedo,
@@ -728,7 +804,7 @@ var StateInspector = memo2(function StateInspector2({
728
804
  multiplayerStateManager.redo();
729
805
  }
730
806
  },
731
- /* @__PURE__ */ React3.createElement("span", { style: { width: "12px", height: "12px" } }, /* @__PURE__ */ React3.createElement(
807
+ /* @__PURE__ */ React4.createElement("span", { style: { width: "12px", height: "12px" } }, /* @__PURE__ */ React4.createElement(
732
808
  "svg",
733
809
  {
734
810
  xmlns: "http://www.w3.org/2000/svg",
@@ -736,7 +812,7 @@ var StateInspector = memo2(function StateInspector2({
736
812
  height: "1em",
737
813
  viewBox: "0 0 20 20"
738
814
  },
739
- /* @__PURE__ */ React3.createElement(
815
+ /* @__PURE__ */ React4.createElement(
740
816
  "path",
741
817
  {
742
818
  fill: "currentColor",
@@ -747,7 +823,7 @@ var StateInspector = memo2(function StateInspector2({
747
823
  )
748
824
  )
749
825
  },
750
- /* @__PURE__ */ React3.createElement("div", { ref: historyContainerRef, style: styles.sectionInner }, /* @__PURE__ */ React3.createElement(
826
+ /* @__PURE__ */ React4.createElement("div", { ref: historyContainerRef, style: styles.sectionInner }, /* @__PURE__ */ React4.createElement(
751
827
  "div",
752
828
  {
753
829
  id: `${HISTORY_ELEMENT_PREFIX}0`,
@@ -761,7 +837,7 @@ var StateInspector = memo2(function StateInspector2({
761
837
  background: historySnapshot.historyIndex === 0 ? "rgb(59 130 246 / 15%)" : void 0
762
838
  }
763
839
  },
764
- /* @__PURE__ */ React3.createElement(
840
+ /* @__PURE__ */ React4.createElement(
765
841
  "span",
766
842
  {
767
843
  style: {
@@ -773,7 +849,7 @@ var StateInspector = memo2(function StateInspector2({
773
849
  },
774
850
  "Initial state"
775
851
  )
776
- ), historySnapshot.history.map((entry, index) => /* @__PURE__ */ React3.createElement(
852
+ ), historySnapshot.history.map((entry, index) => /* @__PURE__ */ React4.createElement(
777
853
  "div",
778
854
  {
779
855
  id: `${HISTORY_ELEMENT_PREFIX}${index + 1}`,
@@ -784,7 +860,7 @@ var StateInspector = memo2(function StateInspector2({
784
860
  background: index + 1 === historySnapshot.historyIndex ? "rgb(59 130 246 / 15%)" : void 0
785
861
  }
786
862
  },
787
- "name" in entry.metadata && typeof entry.metadata.name === "string" && /* @__PURE__ */ React3.createElement(
863
+ "name" in entry.metadata && typeof entry.metadata.name === "string" && /* @__PURE__ */ React4.createElement(
788
864
  "pre",
789
865
  {
790
866
  style: {
@@ -795,7 +871,7 @@ var StateInspector = memo2(function StateInspector2({
795
871
  },
796
872
  entry.metadata.name
797
873
  ),
798
- entry.redoPatches?.map((patch, j) => /* @__PURE__ */ React3.createElement(
874
+ entry.redoPatches?.map((patch, j) => /* @__PURE__ */ React4.createElement(
799
875
  "pre",
800
876
  {
801
877
  key: j,
@@ -805,14 +881,14 @@ var StateInspector = memo2(function StateInspector2({
805
881
  flexWrap: "wrap"
806
882
  }
807
883
  },
808
- patch.op === "add" && /* @__PURE__ */ React3.createElement(React3.Fragment, null, /* @__PURE__ */ React3.createElement("span", { style: { fontStyle: "italic" } }, pathToString(patch.path)), " = ", /* @__PURE__ */ React3.createElement(ObjectInspector, { data: patch.value, theme })),
809
- patch.op === "replace" && /* @__PURE__ */ React3.createElement(React3.Fragment, null, /* @__PURE__ */ React3.createElement("span", { style: { fontStyle: "italic" } }, pathToString(patch.path)), " = ", /* @__PURE__ */ React3.createElement(ObjectInspector, { data: patch.value, theme })),
810
- patch.op === "remove" && /* @__PURE__ */ React3.createElement(React3.Fragment, null, /* @__PURE__ */ React3.createElement("span", { style: { color: theme.OBJECT_VALUE_STRING_COLOR } }, "delete", " "), /* @__PURE__ */ React3.createElement("span", { style: { fontStyle: "italic" } }, pathToString(patch.path))),
811
- patch.op === "move" && /* @__PURE__ */ React3.createElement(React3.Fragment, null, /* @__PURE__ */ React3.createElement("span", { style: { fontStyle: "italic" } }, pathToString(patch.from)), " -> ", /* @__PURE__ */ React3.createElement("span", { style: { fontStyle: "italic" } }, pathToString(patch.path)))
884
+ patch.op === "add" && /* @__PURE__ */ React4.createElement(React4.Fragment, null, /* @__PURE__ */ React4.createElement("span", { style: { fontStyle: "italic" } }, pathToString(patch.path)), " = ", /* @__PURE__ */ React4.createElement(ObjectInspector, { data: patch.value, theme })),
885
+ patch.op === "replace" && /* @__PURE__ */ React4.createElement(React4.Fragment, null, /* @__PURE__ */ React4.createElement("span", { style: { fontStyle: "italic" } }, pathToString(patch.path)), " = ", /* @__PURE__ */ React4.createElement(ObjectInspector, { data: patch.value, theme })),
886
+ patch.op === "remove" && /* @__PURE__ */ React4.createElement(React4.Fragment, null, /* @__PURE__ */ React4.createElement("span", { style: { color: theme.OBJECT_VALUE_STRING_COLOR } }, "delete", " "), /* @__PURE__ */ React4.createElement("span", { style: { fontStyle: "italic" } }, pathToString(patch.path))),
887
+ patch.op === "move" && /* @__PURE__ */ React4.createElement(React4.Fragment, null, /* @__PURE__ */ React4.createElement("span", { style: { fontStyle: "italic" } }, pathToString(patch.from)), " -> ", /* @__PURE__ */ React4.createElement("span", { style: { fontStyle: "italic" } }, pathToString(patch.path)))
812
888
  ))
813
889
  )))
814
890
  ),
815
- /* @__PURE__ */ React3.createElement(
891
+ /* @__PURE__ */ React4.createElement(
816
892
  DisclosureSection,
817
893
  {
818
894
  title: "Tasks",
@@ -820,7 +896,7 @@ var StateInspector = memo2(function StateInspector2({
820
896
  open: showTasks,
821
897
  setOpen: setShowTasks
822
898
  },
823
- /* @__PURE__ */ React3.createElement("div", { style: styles.sectionInner }, tasks?.map((task) => /* @__PURE__ */ React3.createElement(
899
+ /* @__PURE__ */ React4.createElement("div", { style: styles.sectionInner }, tasks?.map((task) => /* @__PURE__ */ React4.createElement(
824
900
  InspectorRow,
825
901
  {
826
902
  key: task.id,
@@ -829,7 +905,7 @@ var StateInspector = memo2(function StateInspector2({
829
905
  backgroundColor: task.status === "done" ? "rgba(0,255,0,0.2)" : task.status === "error" ? "rgba(255,0,0,0.2)" : void 0
830
906
  }
831
907
  },
832
- /* @__PURE__ */ React3.createElement(
908
+ /* @__PURE__ */ React4.createElement(
833
909
  ObjectInspector,
834
910
  {
835
911
  name: task.name,
@@ -839,7 +915,7 @@ var StateInspector = memo2(function StateInspector2({
839
915
  )
840
916
  )))
841
917
  ),
842
- /* @__PURE__ */ React3.createElement(
918
+ /* @__PURE__ */ React4.createElement(
843
919
  DisclosureSection,
844
920
  {
845
921
  open: showEphemeral,
@@ -847,7 +923,7 @@ var StateInspector = memo2(function StateInspector2({
847
923
  title: "Ephemeral User Data",
848
924
  colorScheme
849
925
  },
850
- /* @__PURE__ */ React3.createElement("div", { style: styles.sectionInner }, Object.entries(ephemeral).map(([key, value]) => /* @__PURE__ */ React3.createElement(InspectorRow, { key, colorScheme }, /* @__PURE__ */ React3.createElement(
926
+ /* @__PURE__ */ React4.createElement("div", { style: styles.sectionInner }, Object.entries(ephemeral).map(([key, value]) => /* @__PURE__ */ React4.createElement(InspectorRow, { key, colorScheme }, /* @__PURE__ */ React4.createElement(
851
927
  ObjectInspector,
852
928
  {
853
929
  name: key,
@@ -857,7 +933,7 @@ var StateInspector = memo2(function StateInspector2({
857
933
  }
858
934
  ))))
859
935
  ),
860
- /* @__PURE__ */ React3.createElement(
936
+ /* @__PURE__ */ React4.createElement(
861
937
  DisclosureSection,
862
938
  {
863
939
  open: showEvents,
@@ -865,8 +941,8 @@ var StateInspector = memo2(function StateInspector2({
865
941
  title: "Events",
866
942
  colorScheme
867
943
  },
868
- /* @__PURE__ */ React3.createElement("div", { ref: eventsContainerRef, style: styles.sectionInner }, connectionEvents?.map(
869
- (event, index) => event.type === "stateChange" ? /* @__PURE__ */ React3.createElement(InspectorRow, { key: index, colorScheme }, "connection:", " ", /* @__PURE__ */ React3.createElement("span", { style: { fontStyle: "italic" } }, event.state.toLowerCase())) : /* @__PURE__ */ React3.createElement(
944
+ /* @__PURE__ */ React4.createElement("div", { ref: eventsContainerRef, style: styles.sectionInner }, connectionEvents?.map(
945
+ (event, index) => event.type === "stateChange" ? /* @__PURE__ */ React4.createElement(InspectorRow, { key: index, colorScheme }, "connection:", " ", /* @__PURE__ */ React4.createElement("span", { style: { fontStyle: "italic" } }, event.state.toLowerCase())) : /* @__PURE__ */ React4.createElement(
870
946
  InspectorRow,
871
947
  {
872
948
  key: index,
@@ -876,10 +952,10 @@ var StateInspector = memo2(function StateInspector2({
876
952
  padding: "0px 12px 1px"
877
953
  }
878
954
  },
879
- /* @__PURE__ */ React3.createElement(
955
+ /* @__PURE__ */ React4.createElement(
880
956
  ObjectInspector,
881
957
  {
882
- data: event.message,
958
+ data: event.type === "error" ? event.error : event.message,
883
959
  theme,
884
960
  nodeRenderer: ({
885
961
  depth,
@@ -889,7 +965,7 @@ var StateInspector = memo2(function StateInspector2({
889
965
  expanded
890
966
  }) => {
891
967
  const direction = event.type === "send" ? "up" : "down";
892
- return depth === 0 ? /* @__PURE__ */ React3.createElement(ObjectRootLabel, { direction, data }) : /* @__PURE__ */ React3.createElement(
968
+ return depth === 0 ? /* @__PURE__ */ React4.createElement(ObjectRootLabel, { direction, data }) : /* @__PURE__ */ React4.createElement(
893
969
  ObjectLabel,
894
970
  {
895
971
  direction,
@@ -902,7 +978,7 @@ var StateInspector = memo2(function StateInspector2({
902
978
  }
903
979
  )
904
980
  )
905
- ), !connectionEvents && /* @__PURE__ */ React3.createElement(
981
+ ), !connectionEvents && /* @__PURE__ */ React4.createElement(
906
982
  "div",
907
983
  {
908
984
  style: {
@@ -913,18 +989,18 @@ var StateInspector = memo2(function StateInspector2({
913
989
  gap: "4px"
914
990
  }
915
991
  },
916
- /* @__PURE__ */ React3.createElement("span", null, "No recorded events")
992
+ /* @__PURE__ */ React4.createElement("span", null, "No recorded events")
917
993
  ))
918
994
  )
919
995
  );
920
996
  });
921
997
  var ObjectRootLabel = ({ name, data, direction }) => {
922
998
  if (typeof name === "string") {
923
- return /* @__PURE__ */ React3.createElement("span", null, /* @__PURE__ */ React3.createElement(ObjectName, { name }), /* @__PURE__ */ React3.createElement("span", null, ": "), /* @__PURE__ */ React3.createElement(ObjectPreview, { data }));
999
+ return /* @__PURE__ */ React4.createElement("span", null, /* @__PURE__ */ React4.createElement(ObjectName, { name }), /* @__PURE__ */ React4.createElement("span", null, ": "), /* @__PURE__ */ React4.createElement(ObjectPreview, { data }));
924
1000
  }
925
1001
  if (direction === "up" || direction === "down") {
926
1002
  const arrow = direction === "up" ? "\u2191" : "\u2193";
927
- return /* @__PURE__ */ React3.createElement("span", null, /* @__PURE__ */ React3.createElement(
1003
+ return /* @__PURE__ */ React4.createElement("span", null, /* @__PURE__ */ React4.createElement(
928
1004
  "span",
929
1005
  {
930
1006
  style: {
@@ -941,9 +1017,9 @@ var ObjectRootLabel = ({ name, data, direction }) => {
941
1017
  }
942
1018
  },
943
1019
  arrow
944
- ), /* @__PURE__ */ React3.createElement(ObjectPreview, { data }));
1020
+ ), /* @__PURE__ */ React4.createElement(ObjectPreview, { data }));
945
1021
  } else {
946
- return /* @__PURE__ */ React3.createElement(ObjectPreview, { data });
1022
+ return /* @__PURE__ */ React4.createElement(ObjectPreview, { data });
947
1023
  }
948
1024
  };
949
1025
  function Arrow({
@@ -951,7 +1027,7 @@ function Arrow({
951
1027
  onClick,
952
1028
  style
953
1029
  }) {
954
- return /* @__PURE__ */ React3.createElement(
1030
+ return /* @__PURE__ */ React4.createElement(
955
1031
  "span",
956
1032
  {
957
1033
  role: "button",
@@ -994,7 +1070,7 @@ function SmallButton({
994
1070
  theme,
995
1071
  disabled
996
1072
  }) {
997
- return /* @__PURE__ */ React3.createElement(
1073
+ return /* @__PURE__ */ React4.createElement(
998
1074
  "button",
999
1075
  {
1000
1076
  type: "button",
@@ -1043,7 +1119,7 @@ function useStateInspector({
1043
1119
  ephemeralUserData,
1044
1120
  forceInit
1045
1121
  }) {
1046
- const [root, setRoot] = React4.useState(null);
1122
+ const [root, setRoot] = React5.useState(null);
1047
1123
  useLayoutEffect2(() => {
1048
1124
  if (disabled)
1049
1125
  return;
@@ -1059,7 +1135,7 @@ function useStateInspector({
1059
1135
  if (!root)
1060
1136
  return;
1061
1137
  root.render(
1062
- /* @__PURE__ */ React4.createElement(
1138
+ /* @__PURE__ */ React5.createElement(
1063
1139
  StateInspector,
1064
1140
  {
1065
1141
  state,
@@ -1112,7 +1188,7 @@ function useManagedState(createInitialState, options) {
1112
1188
  const [metadata, action] = args.length === 1 ? [void 0, args[0]] : args;
1113
1189
  if (metadata === void 0) {
1114
1190
  const performActionNoMetadata = stateManager.performAction;
1115
- if (typeof action === "function") {
1191
+ if (action instanceof Function) {
1116
1192
  performActionNoMetadata({
1117
1193
  run: action,
1118
1194
  undo: () => state
@@ -1125,7 +1201,7 @@ function useManagedState(createInitialState, options) {
1125
1201
  }
1126
1202
  } else {
1127
1203
  const performActionWithMetadata = stateManager.performAction;
1128
- if (typeof action === "function") {
1204
+ if (action instanceof Function) {
1129
1205
  performActionWithMetadata(metadata, {
1130
1206
  run: action,
1131
1207
  undo: () => state
@@ -1273,11 +1349,30 @@ function useMultiplayerState(initialState, options) {
1273
1349
  }, [ephemeralUserData, multiplayerStateManager]);
1274
1350
  const state = useSyncMultiplayerStateManager(multiplayerStateManager);
1275
1351
  const forceInit = useCallback(() => {
1276
- const state2 = typeof initialState === "function" ? initialState() : initialState;
1352
+ const state2 = initialState instanceof Function ? initialState() : initialState;
1277
1353
  const schema = options?.schema;
1278
1354
  multiplayerStateManager.sm.clearHistory();
1279
1355
  multiplayerStateManager.sendInit({ force: true, state: state2, schema });
1280
1356
  }, [initialState, multiplayerStateManager, options?.schema]);
1357
+ const [unrecoverableError, setUnrecoverableError] = useState2();
1358
+ useEffect3(() => {
1359
+ return multiplayerStateManager.errorEmitter.addListener((error) => {
1360
+ setUnrecoverableError(error);
1361
+ });
1362
+ }, [multiplayerStateManager]);
1363
+ useEffect3(() => {
1364
+ if (!unrecoverableError)
1365
+ return;
1366
+ const el = document.createElement("div");
1367
+ el.id = "noya-multiplayer-react-error-overlay";
1368
+ document.body.appendChild(el);
1369
+ const root = createRoot2(el);
1370
+ root.render(createElement(ErrorOverlay, { error: unrecoverableError }));
1371
+ return () => {
1372
+ root.unmount();
1373
+ el.remove();
1374
+ };
1375
+ });
1281
1376
  useStateInspector({
1282
1377
  ephemeralUserData,
1283
1378
  multiplayerStateManager,
@@ -1295,7 +1390,7 @@ function useMultiplayerState(initialState, options) {
1295
1390
 
1296
1391
  // src/noyaApp.ts
1297
1392
  import {
1298
- createValue,
1393
+ createOrCastValue,
1299
1394
  localStorageSync,
1300
1395
  webSocketSync
1301
1396
  } from "@noya-app/state-manager";
@@ -1328,7 +1423,7 @@ function getAppData(initialState) {
1328
1423
  function useAppData(initialState, { schema } = {}) {
1329
1424
  const appData = useMemo4(() => {
1330
1425
  return getAppData(
1331
- schema ? createValue(schema, initialState) : initialState
1426
+ schema ? createOrCastValue(schema, initialState) : initialState
1332
1427
  );
1333
1428
  }, [initialState, schema]);
1334
1429
  return appData;