@noya-app/noya-multiplayer-react 0.1.36 → 0.1.38

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.
@@ -1 +1 @@
1
- {"version":3,"sources":["../src/index.ts","../src/avatarStyle.ts","../src/components/UserPointersOverlay.tsx","../src/useObservable.ts","../src/hooks.ts","../src/components/ErrorOverlay.tsx","../src/globals.ts","../src/inspector/useStateInspector.tsx","../src/inspector/StateInspector.tsx","../src/inspector/useLocalStorageState.tsx","../src/noyaApp.ts"],"sourcesContent":["export * from \"@noya-app/state-manager\";\nexport * from \"./avatarStyle\";\nexport * from \"./components/UserPointersOverlay\";\nexport * from \"./hooks\";\nexport * from \"./inspector/StateInspector\";\nexport * from \"./noyaApp\";\nexport * from \"./useObservable\";\n","function hashCode(string: string) {\n let hash = 0;\n\n for (const char of string) {\n hash = char.charCodeAt(0) + ((hash << 5) - hash);\n }\n\n return hash;\n}\n\nfunction elementFromHash<T>(array: T[], hash: number): T {\n return array[Math.abs(hash) % array.length];\n}\n\nexport function getAvatarInitials(name: string) {\n return name\n .split(\" \")\n .filter((c) => c.length > 0)\n .map((c) => c[0])\n .join(\"\")\n .toLocaleUpperCase();\n}\n\n/**\n * Create a background color and initials from a name\n *\n * Adapted from https://mui.com/material-ui/react-avatar/\n */\nexport function getAvatarStyle(name: string) {\n const hash = hashCode(name);\n const color = elementFromHash(Object.values(colors500), hash);\n // const darkerColor = elementFromHash(Object.values(colors800), hash);\n\n return {\n color: \"white\",\n backgroundColor: color,\n // primaryColors: {\n // \"500\": color,\n // \"800\": darkerColor,\n // },\n };\n}\n\nconst colors500 = {\n red500: \"#ef4444\",\n orange500: \"#f97316\",\n amber500: \"#f59e0b\",\n yellow500: \"#eab308\",\n lime500: \"#84cc16\",\n green500: \"#22c55e\",\n emerald500: \"#10b981\",\n teal500: \"#14b8a6\",\n cyan500: \"#06b6d4\",\n sky500: \"#0ea5e9\",\n blue500: \"#3b82f6\",\n indigo500: \"#6366f1\",\n violet500: \"#8b5cf6\",\n purple500: \"#a855f7\",\n fuchsia500: \"#d946ef\",\n pink500: \"#ec4899\",\n rose500: \"#f43f5e\",\n};\n\n// const colors800 = {\n// red800: \"#991b1b\",\n// orange800: \"#9a3412\",\n// amber800: \"#92400e\",\n// yellow800: \"#854d0e\",\n// lime800: \"#3f6212\",\n// green800: \"#166534\",\n// emerald800: \"#065f46\",\n// teal800: \"#115e59\",\n// cyan800: \"#155e75\",\n// sky800: \"#075985\",\n// blue800: \"#1e40af\",\n// indigo800: \"#3730a3\",\n// violet800: \"#5b21b6\",\n// purple800: \"#6b21a8\",\n// fuchsia800: \"#86198f\",\n// pink800: \"#9d174d\",\n// rose800: \"#9f1239\",\n// };\n","\"use client\";\n\nimport { EphemeralUserData, MultiplayerUser } from \"@noya-app/state-manager\";\nimport React, { memo, useEffect, useMemo, useState } from \"react\";\nimport { getAvatarStyle } from \"../avatarStyle\";\nimport { useObservable } from \"../useObservable\";\n\ntype Point = { x: number; y: number };\n\nexport type UserPointerData = { pointer?: Point };\n\nexport type UserPointerProps<E extends UserPointerData> = {\n user: MultiplayerUser;\n ephemeralUserData: EphemeralUserData<E>;\n hideAfter?: number;\n};\n\nfunction shouldShow(hideAfter: number, updatedAt: number) {\n return !!updatedAt && Date.now() - updatedAt < hideAfter;\n}\n\nconst UserPointer_ = function UserPointer<E extends UserPointerData>({\n user,\n ephemeralUserData,\n hideAfter = 5000,\n}: UserPointerProps<E>) {\n const metadata = useObservable(ephemeralUserData.metadata$, [\n user.id,\n ] as const);\n const data = useObservable(ephemeralUserData.data$, [user.id] as const);\n const avatarStyle = useMemo(() => getAvatarStyle(user.id), [user.id]);\n\n const [, setForceUpdate] = useState(0);\n\n const updatedAt = metadata?.updatedAt ?? 0;\n\n useEffect(() => {\n if (!shouldShow(hideAfter, updatedAt)) return;\n\n const timeoutId = setTimeout(() => {\n setForceUpdate((prev) => prev + 1);\n }, hideAfter);\n\n return () => clearTimeout(timeoutId);\n }, [hideAfter, updatedAt]);\n\n const show = shouldShow(hideAfter, updatedAt);\n\n if (!data || !data.pointer) return null;\n\n return (\n <UserPointerContainer key={user.id} point={data.pointer} show={show}>\n <UserPointerIcon color={avatarStyle.backgroundColor} />\n <UserNameTag background={avatarStyle.backgroundColor}>\n {user.name}\n </UserNameTag>\n </UserPointerContainer>\n );\n};\n\nexport const UserPointer = memo(UserPointer_) as typeof UserPointer_;\n\nexport const UserPointerContainer = memo(function UserPointerContainer({\n point,\n children,\n show = true,\n}: {\n point: Point;\n children: React.ReactNode;\n show?: boolean;\n}) {\n return (\n <div\n style={{\n position: \"absolute\",\n top: 0,\n left: 0,\n transform: `translate(${Math.round(point.x)}px, ${Math.round(\n point.y\n )}px)`,\n opacity: show ? 1 : 0,\n transition: \"transform 0.1s, opacity 0.2s\",\n }}\n >\n {children}\n </div>\n );\n});\n\nexport const UserNameTag = memo(function UserNameTag({\n background,\n children,\n}: {\n background: string;\n children: React.ReactNode;\n}) {\n return (\n <span\n style={{\n position: \"relative\",\n top: \"8px\",\n left: \"15px\",\n fontSize: 11,\n lineHeight: \"1\",\n fontWeight: 500,\n boxShadow: \"0 1px 1px rgba(0,0,0,0.1)\",\n padding: \"2px 4px 3px\",\n pointerEvents: \"none\",\n letterSpacing: \"-0.3px\",\n outline: `1px solid rgba(255,255,255,0.3)`,\n outlineOffset: \"-1px\",\n background,\n color: \"white\",\n }}\n >\n {children}\n </span>\n );\n});\n\nexport type UserPointersOverlayProps<E extends UserPointerData> = {\n connectedUsers: MultiplayerUser[];\n ephemeralUserData: EphemeralUserData<E>;\n};\n\nexport const UserPointersOverlay = memo(function UserPointers<\n E extends UserPointerData,\n>({ connectedUsers, ephemeralUserData }: UserPointersOverlayProps<E>) {\n const currentUserId = useObservable(ephemeralUserData.currentUserId$);\n\n return (\n <>\n {connectedUsers.map((user) => {\n if (user.id === currentUserId) return null;\n\n return (\n <UserPointer\n key={user.id}\n user={user}\n ephemeralUserData={\n ephemeralUserData as unknown as EphemeralUserData<E>\n }\n />\n );\n })}\n </>\n );\n});\n\nexport const UserPointerIcon = memo(function CursorIcon({\n color = \"black\",\n}: {\n color?: string;\n}) {\n return (\n <svg\n width=\"15\"\n height=\"15\"\n viewBox=\"0 0 15 15\"\n fill=\"none\"\n xmlns=\"http://www.w3.org/2000/svg\"\n style={{\n position: \"absolute\",\n filter: \"drop-shadow(0 1px 1px rgba(0,0,0,0.1))\",\n // filter: \"drop-shadow(0 1px 1px rgba(0,0,0,0.6))\",\n }}\n >\n <path\n fillRule=\"evenodd\"\n clipRule=\"evenodd\"\n d=\"M3.29227 0.0451998C3.47033 -0.0361222 3.67946 -0.00606629 3.8274 0.122107L12.8587 7.94648C13.0134 8.08054 13.0708 8.29538 13.0035 8.48873C12.9362 8.68208 12.7578 8.81488 12.5533 8.8239L9.21887 8.97096L11.1504 13.2149C11.2648 13.4662 11.1538 13.7626 10.9026 13.877L8.75024 14.8575C8.499 14.972 8.20255 14.8611 8.08802 14.6099L6.15339 10.3665L3.86279 12.7817C3.72196 12.9302 3.50487 12.9779 3.31479 12.9021C3.1247 12.8263 3 12.6423 3 12.4376V0.500008C3 0.304264 3.11422 0.126522 3.29227 0.0451998Z\"\n fill={color}\n />\n <path\n fillRule=\"evenodd\"\n clipRule=\"evenodd\"\n d=\"M3.29227 0.048984C3.47033 -0.032338 3.67946 -0.00228211 3.8274 0.125891L12.8587 7.95026C13.0134 8.08432 13.0708 8.29916 13.0035 8.49251C12.9362 8.68586 12.7578 8.81866 12.5533 8.82768L9.21887 8.97474L11.1504 13.2187C11.2648 13.47 11.1538 13.7664 10.9026 13.8808L8.75024 14.8613C8.499 14.9758 8.20255 14.8649 8.08802 14.6137L6.15339 10.3703L3.86279 12.7855C3.72196 12.934 3.50487 12.9817 3.31479 12.9059C3.1247 12.8301 3 12.6461 3 12.4414V0.503792C3 0.308048 3.11422 0.130306 3.29227 0.048984ZM4 1.59852V11.1877L5.93799 9.14425C6.05238 9.02363 6.21924 8.96776 6.38319 8.99516C6.54715 9.02256 6.68677 9.12965 6.75573 9.2809L8.79056 13.7441L10.0332 13.178L8.00195 8.71497C7.93313 8.56376 7.94391 8.38824 8.03072 8.24659C8.11753 8.10494 8.26903 8.01566 8.435 8.00834L11.2549 7.88397L4 1.59852Z\"\n fill=\"rgba(255,255,255,0.5)\"\n />\n </svg>\n );\n});\n","import { GetWithPath, Observable, PathKey } from \"@noya-app/observable\";\nimport { useMemo, useSyncExternalStore } from \"react\";\n\nexport function useObservable<T>(observable: Observable<T>): T;\nexport function useObservable<T, P extends PathKey[]>(\n observable: Observable<T>,\n path: P\n): GetWithPath<T, P>;\nexport function useObservable<T, P extends PathKey[]>(\n observable: Observable<T>,\n path?: P\n) {\n const { get, listen } = useMemo(() => {\n const listen = path\n ? (callback: (value: GetWithPath<T, P>) => void) =>\n observable.listen(path, callback)\n : observable.listen;\n\n const get: () => void = path ? () => observable.get(path) : observable.get;\n\n return { get, listen };\n }, [observable, path]);\n\n return useSyncExternalStore(listen, get, get);\n}\n","\"use client\";\n\nimport {\n ActionHandler,\n ConnectionEvent,\n EphemeralUserData,\n Get,\n MultiplayerStateManager,\n MultiplayerStateManagerError,\n MultiplayerStateManagerOptions,\n MultiplayerUser,\n StateManager,\n StateManagerOptions,\n stubSync,\n SyncAdapter,\n SyncAdapterOptions,\n Task,\n} from \"@noya-app/state-manager\";\nimport {\n createElement,\n SetStateAction,\n useCallback,\n useEffect,\n useMemo,\n useRef,\n useState,\n useSyncExternalStore,\n} from \"react\";\nimport { createRoot } from \"react-dom/client\";\nimport { ErrorOverlay } from \"./components/ErrorOverlay\";\nimport { shouldTrackEvents$, shouldTrackTasks$ } from \"./globals\";\nimport { StateInspectorOptions } from \"./inspector/StateInspector\";\nimport { useStateInspector } from \"./inspector/useStateInspector\";\nimport { useObservable } from \"./useObservable\";\n\nexport function useSyncStateManager<S, M>(stateManager: StateManager<S, M>): S;\nexport function useSyncStateManager<S, M, P extends string>(\n stateManager: StateManager<S, M>,\n path: P\n): Get<S, P, unknown>;\nexport function useSyncStateManager<S, M>(\n stateManager: StateManager<S, M>,\n path?: string\n) {\n const getSnapshot = useCallback(\n () =>\n typeof path === \"string\"\n ? stateManager.getState(path)\n : stateManager.getState(),\n [stateManager, path]\n );\n\n return useSyncExternalStore(\n stateManager.addListener,\n getSnapshot,\n getSnapshot\n );\n}\n\nexport function useManagedState<S, M = void>(\n createInitialState: () => S,\n options?: StateManagerOptions<S, M>\n) {\n const [stateManager] = useState(\n () => new StateManager<S, M>(createInitialState(), options)\n );\n\n const state = useSyncStateManager(stateManager);\n\n const setState = useCallback(\n (\n ...args: M extends {}\n ? [metadata: M, action: SetStateAction<S>]\n : [action: SetStateAction<S>]\n ) => {\n const [metadata, action] =\n args.length === 1 ? [undefined, args[0]] : args;\n\n if (metadata === undefined) {\n const performActionNoMetadata = stateManager.performAction as (\n handler: ActionHandler<S>\n ) => void;\n\n if (action instanceof Function) {\n performActionNoMetadata({\n run: action,\n undo: () => state,\n });\n } else {\n performActionNoMetadata({\n run: () => action,\n undo: () => state,\n });\n }\n } else {\n const performActionWithMetadata = stateManager.performAction as (\n metadata: M,\n handler: ActionHandler<S>\n ) => void;\n\n if (action instanceof Function) {\n performActionWithMetadata(metadata, {\n run: action,\n undo: () => state,\n });\n } else {\n performActionWithMetadata(metadata, {\n run: () => action,\n undo: () => state,\n });\n }\n }\n },\n [state, stateManager]\n );\n\n return [state, setState, stateManager] as const;\n}\n\nexport function useManagedHistory<S, M = void>(\n stateManager: StateManager<S, M>\n) {\n return useSyncExternalStore(\n stateManager.historyEmittor.addListener,\n stateManager.getHistorySnapshot,\n stateManager.getHistorySnapshot\n );\n}\n\nexport function useSyncMultiplayerStateManager<S, M = void>(\n multiplayerStateManager: MultiplayerStateManager<S, M>\n) {\n return useSyncExternalStore(\n multiplayerStateManager.addListener,\n multiplayerStateManager.getOptimisticState,\n multiplayerStateManager.getOptimisticState\n );\n}\n\nfunction throttle<F extends (...args: any[]) => any>(fn: F, ms: number) {\n let lastCall = 0;\n let timeoutId: number | null = null;\n return (...args: Parameters<F>) => {\n const now = Date.now();\n if (now - lastCall < ms) {\n if (timeoutId) clearTimeout(timeoutId);\n timeoutId = setTimeout(\n () => {\n lastCall = now;\n fn(...args);\n },\n ms - (now - lastCall)\n ) as unknown as number;\n return;\n }\n lastCall = now;\n return fn(...args);\n };\n}\n\nexport function useEphemeralUserData<E>(\n ephemeralUserData: EphemeralUserData<E>,\n options?: {\n throttle?: number;\n }\n) {\n const throttledAddListener = useMemo(() => {\n const throttleMs = options?.throttle ?? 0;\n\n if (throttleMs > 0) {\n const addListener = (\n fn: Parameters<typeof ephemeralUserData.addListener>[0]\n ) => {\n const throttledFn = throttle(fn, throttleMs);\n return ephemeralUserData.addListener(throttledFn);\n };\n\n return addListener;\n }\n\n return ephemeralUserData.addListener;\n }, [ephemeralUserData, options?.throttle]);\n\n return useSyncExternalStore(\n throttledAddListener,\n ephemeralUserData.getSnapshot,\n ephemeralUserData.getSnapshot\n );\n}\n\nconst defaultStubSync = stubSync();\n\nexport type UseMultiplayerStateOptions<\n S,\n M = void,\n E = void,\n> = MultiplayerStateManagerOptions<S, M> & {\n sync?: (\n options: Pick<SyncAdapterOptions<S, M, E>, \"ms\" | \"ephemeralUserData\">\n ) => void;\n trackConnectionEvents?: boolean;\n trackTasks?: boolean;\n inspector?: boolean | StateInspectorOptions;\n};\n\nexport function useMultiplayerState<S, M = void, E = void>(\n initialState: S | (() => S),\n options?: UseMultiplayerStateOptions<S, M, E>\n) {\n const { sync = defaultStubSync as unknown as SyncAdapter<S, M, E>, ...rest } =\n options ?? {};\n\n const [multiplayerStateManager] = useState(\n () => new MultiplayerStateManager<S, M>(initialState, rest)\n );\n const syncRef = useRef(sync);\n\n const [connectionEvents, setConnectionEvents] = useState<\n ConnectionEvent<S>[] | undefined\n >();\n\n const [connectedUsers, setConnectedUsers] = useState<MultiplayerUser[]>([]);\n const [ephemeralUserData] = useState<EphemeralUserData<E>>(\n () => new EphemeralUserData()\n );\n const [tasks, setTasks] = useState<Task[]>([]);\n const [userId, setUserId] = useState<string | undefined>();\n\n const extras = useMemo(() => {\n return {\n tasks,\n userId,\n connectionEvents,\n connectedUsers,\n ephemeralUserData,\n multiplayerStateManager,\n // evaluate: async (code: string) => {\n // const payload = await rpcManager.request({ type: \"eval\", code });\n\n // if (payload.type !== \"eval\") {\n // throw new Error(`Unexpected rpc response type: ${payload.type}`);\n // }\n // },\n };\n }, [\n tasks,\n userId,\n connectionEvents,\n connectedUsers,\n ephemeralUserData,\n multiplayerStateManager,\n ]);\n\n const globalTrackEvents = useObservable(shouldTrackEvents$);\n const globalTrackTasks = useObservable(shouldTrackTasks$);\n\n const shouldTrackEvents = options?.trackConnectionEvents ?? globalTrackEvents;\n const shouldTrackTasks = options?.trackTasks ?? globalTrackTasks;\n\n const trackEventsCallbackRef = useRef<\n ((e: ConnectionEvent<S>) => void) | undefined\n >();\n const trackConnectedUsersCallbackRef = useRef<\n ((users: MultiplayerUser[], userId: string) => void) | undefined\n >();\n const trackTasksCallbackRef = useRef<((tasks: Task[]) => void) | undefined>();\n\n useEffect(() => {\n trackEventsCallbackRef.current = shouldTrackEvents\n ? (e) =>\n setConnectionEvents((events) => {\n const updated = events ? [...events, e] : [e];\n return updated.length > 50 ? updated.slice(-50) : updated;\n })\n : undefined;\n }, [shouldTrackEvents]);\n\n useEffect(() => {\n trackConnectedUsersCallbackRef.current = (users, userId) => {\n setConnectedUsers(users);\n setUserId(userId);\n };\n }, []);\n\n useEffect(() => {\n trackTasksCallbackRef.current = shouldTrackTasks\n ? (tasks) => {\n setTasks((old) => {\n const newIds = new Set(tasks.map((t) => t.id));\n\n // merge old and new tasks, preferring new tasks\n const unchanged = old.filter((t) => !newIds.has(t.id));\n\n return [...unchanged, ...tasks];\n });\n }\n : undefined;\n }, [shouldTrackTasks]);\n\n useEffect(() => {\n if (syncRef.current) {\n return syncRef.current({\n ms: multiplayerStateManager,\n ephemeralUserData,\n onConnectionEvent: (e) => trackEventsCallbackRef.current?.(e),\n onChangeConnectedUsers: (users, userId) =>\n trackConnectedUsersCallbackRef.current?.(users, userId),\n onChangeTasks: (tasks) => trackTasksCallbackRef.current?.(tasks),\n });\n }\n }, [ephemeralUserData, multiplayerStateManager]);\n\n const state = useSyncMultiplayerStateManager(multiplayerStateManager);\n\n const forceInit = useCallback(() => {\n const state =\n initialState instanceof Function ? initialState() : initialState;\n const schema = options?.schema;\n multiplayerStateManager.sm.clearHistory();\n multiplayerStateManager.sendInit({ force: true, state, schema });\n }, [initialState, multiplayerStateManager, options?.schema]);\n\n const [unrecoverableError, setUnrecoverableError] = useState<\n MultiplayerStateManagerError | undefined\n >();\n\n useEffect(() => {\n return multiplayerStateManager.errorEmitter.addListener((error) => {\n setUnrecoverableError(error);\n });\n }, [multiplayerStateManager]);\n\n useEffect(() => {\n if (!unrecoverableError) return;\n const el = document.createElement(\"div\");\n el.id = \"noya-multiplayer-react-error-overlay\";\n document.body.appendChild(el);\n const root = createRoot(el);\n root.render(createElement(ErrorOverlay, { error: unrecoverableError }));\n return () => {\n root.unmount();\n el.remove();\n };\n });\n\n useStateInspector({\n ephemeralUserData,\n multiplayerStateManager,\n state,\n connectionEvents,\n connectedUsers,\n tasks,\n userId,\n forceInit,\n disabled: !options?.inspector,\n ...(typeof options?.inspector === \"object\" && options.inspector),\n });\n\n return [state, multiplayerStateManager.setState, extras] as const;\n}\n","import { MultiplayerStateManagerError } from \"@noya-app/state-manager\";\nimport React from \"react\";\n\nexport function ErrorOverlay({\n error,\n}: {\n error: MultiplayerStateManagerError;\n}) {\n return (\n <div\n style={{\n position: \"fixed\",\n top: \"20px\",\n left: \"50%\",\n transform: \"translateX(-50%)\",\n maxWidth: \"80%\",\n width: \"fit-content\",\n padding: \"12px 20px\",\n background: \"white\",\n color: \"black\",\n zIndex: 10000,\n display: \"flex\",\n flexDirection: \"column\",\n justifyContent: \"center\",\n borderRadius: \"4px\",\n boxShadow: \"0 4px 6px rgba(0, 0, 0, 0.1)\",\n fontFamily:\n \"'__Inter_6b0edc', '__Inter_Fallback_6b0edc', -apple-system, BlinkMacSystemFont, 'Helvetica Neue', 'Segoe UI', Roboto, Helvetica, Arial, sans-serif\",\n fontSize: \"14px\",\n fontWeight: 400,\n lineHeight: \"19px\",\n }}\n >\n {error.reason === \"schemaMigration\" ? (\n <>\n <p>\n An updated version of Noya is available. Please reload the page to\n continue.\n </p>\n </>\n ) : (\n <>\n <p>\n An error occurred:{\" \"}\n <code\n style={{\n background: \"rgba(255, 0, 0, 0.1)\",\n color: \"rgba(255, 0, 0, 0.5)\",\n padding: \"2px 4px\",\n borderRadius: \"4px\",\n }}\n >\n {error.reason}\n </code>\n . Please reload the page to continue.\n <br />\n <br />\n If this happens repeatedly, please get in touch and the Noya team\n can help.\n </p>\n </>\n )}\n <div\n style={{\n height: \"1px\",\n background: \"rgba(0, 0, 0, 0.1)\",\n margin: \"12px -20px\",\n }}\n />\n <button\n style={{\n background: \"black\",\n color: \"white\",\n padding: \"8px 16px\",\n borderRadius: \"4px\",\n cursor: \"pointer\",\n fontSize: \"14px\",\n fontWeight: 700,\n lineHeight: \"19px\",\n }}\n onClick={() => {\n window.location.reload();\n }}\n >\n Reload\n </button>\n </div>\n );\n}\n","import { Observable } from \"@noya-app/observable\";\n\nexport const shouldTrackEvents$ = new Observable(false);\nexport const shouldTrackTasks$ = new Observable(false);\n","\"use client\";\n\nimport {\n ConnectionEvent,\n EphemeralUserData,\n MultiplayerStateManager,\n MultiplayerUser,\n Task,\n} from \"@noya-app/state-manager\";\nimport React, { ComponentProps, useLayoutEffect } from \"react\";\nimport { createRoot } from \"react-dom/client\";\n\nimport { Root } from \"react-dom/client\";\nimport { StateInspector } from \"./StateInspector\";\n\nfunction createPortalElement() {\n const el = document.createElement(\"div\");\n el.id = \"noya-multiplayer-react-inspector-portal\";\n return el;\n}\n\nexport function useStateInspector<S, M, E>({\n state,\n connectionEvents,\n connectedUsers,\n tasks,\n userId,\n disabled = false,\n colorScheme,\n anchor,\n multiplayerStateManager,\n ephemeralUserData,\n forceInit,\n}: {\n state: S;\n connectionEvents?: ConnectionEvent<S>[];\n connectedUsers?: MultiplayerUser[];\n tasks?: Task[];\n userId?: string;\n disabled: boolean;\n multiplayerStateManager: MultiplayerStateManager<S, M>;\n ephemeralUserData: EphemeralUserData<E>;\n forceInit: () => void;\n} & Pick<ComponentProps<typeof StateInspector>, \"colorScheme\" | \"anchor\">) {\n const [root, setRoot] = React.useState<Root | null>(null);\n\n useLayoutEffect(() => {\n if (disabled) return;\n\n const portalElement = createPortalElement();\n\n const root = createRoot(portalElement);\n\n document.body.appendChild(portalElement);\n\n setRoot(root);\n\n return () => {\n document.body.removeChild(portalElement);\n };\n }, [disabled]);\n\n useLayoutEffect(() => {\n if (!root) return;\n\n root.render(\n <StateInspector\n state={state}\n connectionEvents={connectionEvents}\n connectedUsers={connectedUsers}\n tasks={tasks}\n userId={userId}\n colorScheme={colorScheme}\n anchor={anchor}\n forceInit={forceInit}\n multiplayerStateManager={\n multiplayerStateManager as MultiplayerStateManager<any, any>\n }\n ephemeralUserData={ephemeralUserData as EphemeralUserData<any>}\n />\n );\n }, [\n anchor,\n colorScheme,\n connectedUsers,\n connectionEvents,\n root,\n state,\n multiplayerStateManager,\n userId,\n tasks,\n forceInit,\n ephemeralUserData,\n ]);\n}\n","\"use client\";\n\nimport {\n ConnectionEvent,\n EphemeralUserData,\n ExtendedPathKey,\n MultiplayerStateManager,\n MultiplayerUser,\n Task,\n} from \"@noya-app/state-manager\";\nimport React, {\n CSSProperties,\n ComponentPropsWithoutRef,\n FC,\n memo,\n useEffect,\n useLayoutEffect,\n} from \"react\";\nimport {\n ObjectInspector,\n ObjectLabel,\n ObjectName,\n ObjectPreview,\n chromeDark,\n chromeLight,\n} from \"react-inspector\";\nimport { shouldTrackEvents$, shouldTrackTasks$ } from \"../globals\";\nimport { useEphemeralUserData, useManagedHistory } from \"../hooks\";\nimport { useLocalStorageState } from \"./useLocalStorageState\";\n\nconst lightTheme = {\n ...chromeLight,\n BASE_BACKGROUND_COLOR: \"transparent\",\n OBJECT_NAME_COLOR: \"rgba(0,0,0,0.7)\",\n} as any;\n\nconst darkTheme = {\n ...chromeDark,\n BASE_BACKGROUND_COLOR: \"transparent\",\n OBJECT_NAME_COLOR: \"rgba(255,255,255,0.7)\",\n} as any;\n\nconst styles = {\n sectionInner: {\n flex: \"1 1 0\",\n overflowY: \"auto\",\n overflowX: \"hidden\",\n display: \"flex\",\n flexDirection: \"column\",\n },\n} as const;\n\nfunction ToggleButton({\n showInspector,\n setShowInspector,\n theme,\n anchor,\n}: {\n showInspector: boolean;\n setShowInspector: (value: boolean) => void;\n theme: typeof chromeLight;\n anchor: StateInspectorAnchor;\n}) {\n return (\n <span\n role=\"button\"\n style={{\n flex: \"0\",\n appearance: \"none\",\n color: theme.BASE_COLOR,\n border: \"none\",\n fontSize: \"12px\",\n whiteSpace: \"nowrap\",\n display: \"inline-flex\",\n alignItems: \"center\",\n justifyContent: \"center\",\n padding: \"2px 0\",\n }}\n onClick={(event) => {\n event.stopPropagation();\n\n setShowInspector(!showInspector);\n }}\n >\n <span style={{ width: \"12px\", height: \"12px\" }}>\n {showInspector === (anchor === \"right\") ? (\n <svg\n xmlns=\"http://www.w3.org/2000/svg\"\n fill=\"none\"\n viewBox=\"0 0 24 24\"\n strokeWidth={1.5}\n stroke=\"currentColor\"\n className=\"size-6\"\n >\n <path\n strokeLinecap=\"round\"\n strokeLinejoin=\"round\"\n d=\"m5.25 4.5 7.5 7.5-7.5 7.5m6-15 7.5 7.5-7.5 7.5\"\n />\n </svg>\n ) : (\n <svg\n xmlns=\"http://www.w3.org/2000/svg\"\n fill=\"none\"\n viewBox=\"0 0 24 24\"\n strokeWidth={1.5}\n stroke=\"currentColor\"\n className=\"size-6\"\n >\n <path\n strokeLinecap=\"round\"\n strokeLinejoin=\"round\"\n d=\"m18.75 4.5-7.5 7.5 7.5 7.5m-6-15L5.25 12l7.5 7.5\"\n />\n </svg>\n )}\n </span>\n </span>\n );\n}\n\nfunction DisclosureSection({\n open,\n setOpen,\n title,\n right,\n children,\n colorScheme,\n isFirst,\n style,\n}: {\n open: boolean;\n setOpen?: (value: boolean) => void;\n title: string;\n right?: React.ReactNode;\n children: React.ReactNode;\n colorScheme: \"light\" | \"dark\";\n isFirst?: boolean;\n style?: CSSProperties;\n}) {\n const theme = colorScheme === \"light\" ? lightTheme : darkTheme;\n\n const borderColor =\n colorScheme === \"light\" ? \"rgba(0,0,0,0.1)\" : \"rgba(255,255,255,0.1)\";\n\n return (\n <div\n style={{\n flex: open ? \"1 1 0\" : \"0\",\n display: \"flex\",\n flexDirection: \"column\",\n ...style,\n }}\n >\n <div\n onClick={() => setOpen?.(!open)}\n style={{\n cursor: \"default\",\n fontSize: \"12px\",\n padding: \"4px 10px\",\n display: \"flex\",\n alignItems: \"center\",\n ...(!isFirst && { borderTop: `1px solid ${borderColor}` }),\n ...(open && { borderBottom: `1px solid ${borderColor}` }),\n }}\n >\n {setOpen && (\n <Arrow\n expanded={open}\n style={{\n fontSize: theme.ARROW_FONT_SIZE,\n marginRight: theme.ARROW_MARGIN_RIGHT + 1,\n color: theme.ARROW_COLOR,\n }}\n />\n )}\n <span style={{ flex: \"1 1 0\", userSelect: \"none\" }}>{title}</span>\n {right}\n </div>\n {open && children}\n </div>\n );\n}\n\nfunction InspectorRow({\n children,\n colorScheme,\n selected,\n style,\n variant,\n}: {\n children: React.ReactNode;\n colorScheme: \"light\" | \"dark\";\n selected?: boolean;\n style?: CSSProperties;\n variant?: \"up\" | \"down\";\n}) {\n const solidBorderColor =\n colorScheme === \"light\" ? \"rgb(223 223 223)\" : \"rgb(29 29 29)\";\n\n return (\n <div\n style={{\n borderBottom: `1px solid ${solidBorderColor}`,\n fontSize: \"12px\",\n fontFamily: \"Menlo, monospace\",\n padding: \"2px 12px 1px\",\n display: \"flex\",\n alignItems: \"center\",\n background:\n variant === \"up\"\n ? \"rgba(0,255,0,0.1)\"\n : variant === \"down\"\n ? \"rgba(255,0,0,0.1)\"\n : selected\n ? \"rgb(59 130 246 / 15%)\"\n : undefined,\n // background:\n // colorScheme === \"light\"\n // ? \"rgba(0,0,0,0.05)\"\n // : \"rgba(255,255,255,0.05)\",\n ...style,\n }}\n >\n <span\n style={{\n fontFamily: \"Menlo, monospace\",\n fontSize: \"11px\",\n borderRadius: 4,\n display: \"inline-block\",\n }}\n >\n {children}\n </span>\n </div>\n );\n}\n\nconst HISTORY_ELEMENT_PREFIX = \"noya-multiplayer-history-\";\n\nexport type StateInspectorAnchor =\n | \"left\"\n | \"right\"\n | \"bottom left\"\n | \"bottom right\";\n\nexport type StateInspectorOptions = {\n colorScheme?: \"light\" | \"dark\";\n anchor?: StateInspectorAnchor;\n};\n\nexport const StateInspector = memo(function StateInspector<S, M, E>({\n state,\n connectionEvents,\n connectedUsers,\n tasks,\n userId,\n unstyled,\n colorScheme = \"light\",\n multiplayerStateManager,\n ephemeralUserData,\n anchor = \"right\",\n forceInit,\n ...props\n}: {\n state: S;\n connectionEvents?: ConnectionEvent<S>[];\n connectedUsers?: MultiplayerUser[];\n tasks?: Task[];\n userId?: string;\n unstyled?: boolean;\n multiplayerStateManager: MultiplayerStateManager<S, M>;\n ephemeralUserData: EphemeralUserData<E>;\n forceInit: () => void;\n} & StateInspectorOptions &\n ComponentPropsWithoutRef<\"div\">) {\n const [didMount, setDidMount] = React.useState(false);\n\n useLayoutEffect(() => {\n setDidMount(true);\n }, []);\n\n const eventsContainerRef = React.useRef<HTMLDivElement>(null);\n const historyContainerRef = React.useRef<HTMLDivElement>(null);\n\n const [showInspector, setShowInspector] = useLocalStorageState(\n \"noya-multiplayer-react-show-inspector\",\n true\n );\n const [showEvents, setShowEvents] = useLocalStorageState(\n \"noya-multiplayer-react-show-events\",\n false\n );\n const [showHistory, setShowHistory] = useLocalStorageState(\n \"noya-multiplayer-react-show-history\",\n false\n );\n const [showUsers, setShowUsers] = useLocalStorageState(\n \"noya-multiplayer-react-show-users\",\n true\n );\n const [showData, setShowData] = useLocalStorageState(\n \"noya-multiplayer-react-show-data\",\n true\n );\n const [showTasks, setShowTasks] = useLocalStorageState(\n \"noya-multiplayer-react-show-tasks\",\n false\n );\n const [showEphemeral, setShowEphemeral] = useLocalStorageState(\n \"noya-multiplayer-react-show-ephemeral\",\n false\n );\n\n useEffect(() => {\n shouldTrackEvents$.set(showEvents);\n }, [showEvents]);\n\n useEffect(() => {\n shouldTrackTasks$.set(showTasks);\n }, [showTasks]);\n\n useEffect(() => {\n if (eventsContainerRef.current) {\n eventsContainerRef.current.scrollTop =\n eventsContainerRef.current.scrollHeight;\n }\n }, [connectionEvents]);\n\n const ephemeral = useEphemeralUserData(ephemeralUserData);\n const historySnapshot = useManagedHistory(multiplayerStateManager.sm);\n\n useEffect(() => {\n if (historyContainerRef.current) {\n historyContainerRef.current.scrollTop =\n historyContainerRef.current.scrollHeight;\n }\n }, [historySnapshot]);\n\n // If history index changes, scroll to the new history entry into view\n useEffect(() => {\n if (!historyContainerRef.current) return;\n\n const historyEntry = historyContainerRef.current.querySelector(\n `#${HISTORY_ELEMENT_PREFIX}${historySnapshot.historyIndex}`\n );\n\n if (historyEntry) {\n historyEntry.scrollIntoView({\n block: \"nearest\",\n inline: \"nearest\",\n });\n }\n }, [historySnapshot.historyIndex]);\n\n const theme = colorScheme === \"light\" ? lightTheme : darkTheme;\n // const borderColor =\n // colorScheme === \"light\" ? \"rgba(0,0,0,0.1)\" : \"rgba(255,255,255,0.1)\";\n const solidBorderColor =\n colorScheme === \"light\" ? \"rgb(223 223 223)\" : \"rgb(29 29 29)\";\n\n const baseStyle: CSSProperties = {\n position: \"fixed\",\n top: 12,\n ...(anchor.includes(\"right\") ? { right: 12 } : { left: 12 }),\n bottom: 12,\n width: 400,\n background:\n colorScheme === \"light\" ? \"rgba(255,255,255,0.95)\" : \"rgba(0,0,0,0.95)\",\n backdropFilter: \"blur(48px)\",\n border: `1px solid ${solidBorderColor}`,\n // outlineOffset: -1,\n borderRadius: 4,\n display: \"flex\",\n flexDirection: \"column\",\n // gap: 12,\n color: theme.BASE_COLOR,\n overflow: \"hidden\",\n zIndex: 9999,\n lineHeight: \"13px\",\n };\n\n if (!didMount) return null;\n\n if (!showInspector) {\n return (\n <div\n {...props}\n style={{\n ...baseStyle,\n padding: \"4px 10px\",\n width: undefined,\n ...(anchor.includes(\"bottom\")\n ? { bottom: 12, top: undefined }\n : { bottom: undefined }),\n }}\n onClick={() => setShowInspector(true)}\n >\n <ToggleButton\n showInspector={showInspector}\n setShowInspector={setShowInspector}\n theme={theme}\n anchor={anchor}\n />\n </div>\n );\n }\n\n return (\n <div\n {...props}\n style={{\n ...(!unstyled && baseStyle),\n ...props.style,\n }}\n >\n <DisclosureSection\n isFirst\n open={showUsers}\n setOpen={setShowUsers}\n title=\"Users\"\n colorScheme={colorScheme}\n style={{\n flex: \"0 0 auto\",\n maxHeight: \"200px\",\n }}\n right={\n <ToggleButton\n showInspector={showInspector}\n setShowInspector={setShowInspector}\n theme={theme}\n anchor={anchor}\n />\n }\n >\n <div style={{ ...styles.sectionInner, flex: \"0 0 auto\" }}>\n {connectedUsers?.map((user) => (\n <InspectorRow\n key={user.id}\n colorScheme={colorScheme}\n variant={user.id === userId ? \"up\" : undefined}\n >\n {user.image && (\n <img\n src={user.image}\n alt={user.name}\n style={{\n width: \"12px\",\n height: \"12px\",\n borderRadius: \"50%\",\n marginRight: \"4px\",\n display: \"inline-block\",\n position: \"relative\",\n top: \"-1px\",\n background: solidBorderColor,\n }}\n />\n )}\n {user.name} ({ellipsis(user.id.toString(), 8, \"middle\")})\n </InspectorRow>\n ))}\n {!connectedUsers && (\n <div\n style={{\n padding: \"12px\",\n fontSize: \"12px\",\n display: \"flex\",\n flexDirection: \"column\",\n gap: \"4px\",\n }}\n >\n <span>No connected users</span>\n </div>\n )}\n </div>\n </DisclosureSection>\n <DisclosureSection\n title=\"Data\"\n colorScheme={colorScheme}\n setOpen={setShowData}\n open={showData}\n right={\n <span\n style={{\n display: \"flex\",\n gap: \"4px\",\n }}\n >\n <SmallButton\n // disabled={!historySnapshot.canUndo}\n theme={theme}\n onClick={() => {\n forceInit();\n }}\n >\n Reset\n </SmallButton>\n </span>\n }\n >\n <div style={styles.sectionInner}>\n <InspectorRow colorScheme={colorScheme}>\n <ObjectInspector\n name={multiplayerStateManager.schema ? \"state\" : undefined}\n data={state}\n theme={theme}\n />\n </InspectorRow>\n {multiplayerStateManager.schema && (\n <InspectorRow colorScheme={colorScheme}>\n <ObjectInspector\n name=\"schema\"\n data={multiplayerStateManager.schema}\n theme={theme}\n />\n </InspectorRow>\n )}\n </div>\n </DisclosureSection>\n <DisclosureSection\n open={showHistory}\n setOpen={setShowHistory}\n title=\"History\"\n colorScheme={colorScheme}\n right={\n <span\n style={{\n display: \"flex\",\n gap: \"4px\",\n }}\n >\n <SmallButton\n disabled={!historySnapshot.canUndo}\n theme={theme}\n onClick={() => {\n multiplayerStateManager.undo();\n }}\n >\n <span style={{ width: \"12px\", height: \"12px\" }}>\n <svg\n xmlns=\"http://www.w3.org/2000/svg\"\n width=\"1em\"\n height=\"1em\"\n viewBox=\"0 0 20 20\"\n >\n <path\n fill=\"currentColor\"\n d=\"M12 5H7V2L1 6l6 4V7h5c2.2 0 4 1.8 4 4s-1.8 4-4 4H7v2h5c3.3 0 6-2.7 6-6s-2.7-6-6-6\"\n />\n </svg>\n </span>\n </SmallButton>\n <SmallButton\n disabled={!historySnapshot.canRedo}\n theme={theme}\n onClick={() => {\n multiplayerStateManager.redo();\n }}\n >\n <span style={{ width: \"12px\", height: \"12px\" }}>\n <svg\n xmlns=\"http://www.w3.org/2000/svg\"\n width=\"1em\"\n height=\"1em\"\n viewBox=\"0 0 20 20\"\n >\n <path\n fill=\"currentColor\"\n d=\"M8 5h5V2l6 4l-6 4V7H8c-2.2 0-4 1.8-4 4s1.8 4 4 4h5v2H8c-3.3 0-6-2.7-6-6s2.7-6 6-6\"\n />\n </svg>\n </span>\n </SmallButton>\n </span>\n }\n >\n <div ref={historyContainerRef} style={styles.sectionInner}>\n <div\n id={`${HISTORY_ELEMENT_PREFIX}0`}\n style={{\n borderBottom: `1px solid ${solidBorderColor}`,\n fontSize: \"12px\",\n fontFamily: \"Menlo, monospace\",\n padding: \"2px 12px 1px\",\n display: \"flex\",\n alignItems: \"center\",\n background:\n historySnapshot.historyIndex === 0\n ? \"rgb(59 130 246 / 15%)\"\n : undefined,\n }}\n >\n <span\n style={{\n fontFamily: \"Menlo, monospace\",\n fontSize: \"11px\",\n borderRadius: 4,\n display: \"inline-block\",\n }}\n >\n Initial state\n </span>\n </div>\n {historySnapshot.history.map((entry, index) => (\n <div\n id={`${HISTORY_ELEMENT_PREFIX}${index + 1}`}\n key={index}\n style={{\n padding: \"0px 12px 1px\",\n borderBottom: `1px solid ${solidBorderColor}`,\n background:\n index + 1 === historySnapshot.historyIndex\n ? \"rgb(59 130 246 / 15%)\"\n : undefined,\n }}\n >\n {\"name\" in entry.metadata &&\n typeof entry.metadata.name === \"string\" && (\n <pre\n style={{\n fontSize: \"11px\",\n display: \"flex\",\n flexWrap: \"wrap\",\n }}\n >\n {entry.metadata.name}\n </pre>\n )}\n {entry.redoPatches?.map((patch, j) => (\n <pre\n key={j}\n style={{\n fontSize: \"11px\",\n display: \"flex\",\n flexWrap: \"wrap\",\n }}\n >\n {patch.op === \"add\" && (\n <>\n <span style={{ fontStyle: \"italic\" }}>\n {pathToString(patch.path)}\n </span>\n {\" = \"}\n <ObjectInspector data={patch.value} theme={theme} />\n </>\n )}\n {patch.op === \"replace\" && (\n <>\n <span style={{ fontStyle: \"italic\" }}>\n {pathToString(patch.path)}\n </span>\n {\" = \"}\n <ObjectInspector data={patch.value} theme={theme} />\n </>\n )}\n {patch.op === \"remove\" && (\n <>\n <span style={{ color: theme.OBJECT_VALUE_STRING_COLOR }}>\n delete{\" \"}\n </span>\n <span style={{ fontStyle: \"italic\" }}>\n {pathToString(patch.path)}\n </span>\n </>\n )}\n {patch.op === \"move\" && (\n <>\n <span style={{ fontStyle: \"italic\" }}>\n {pathToString(patch.from!)}\n </span>\n {\" -> \"}\n <span style={{ fontStyle: \"italic\" }}>\n {pathToString(patch.path)}\n </span>\n </>\n )}\n </pre>\n ))}\n </div>\n ))}\n </div>\n </DisclosureSection>\n <DisclosureSection\n title=\"Tasks\"\n colorScheme={colorScheme}\n open={showTasks}\n setOpen={setShowTasks}\n >\n <div style={styles.sectionInner}>\n {tasks?.map((task) => (\n <InspectorRow\n key={task.id}\n colorScheme={colorScheme}\n style={{\n backgroundColor:\n task.status === \"done\"\n ? \"rgba(0,255,0,0.2)\"\n : task.status === \"error\"\n ? \"rgba(255,0,0,0.2)\"\n : undefined,\n }}\n >\n <ObjectInspector\n name={task.name}\n data={task.payload}\n theme={theme}\n />\n </InspectorRow>\n ))}\n </div>\n </DisclosureSection>\n <DisclosureSection\n open={showEphemeral}\n setOpen={setShowEphemeral}\n title=\"Ephemeral User Data\"\n colorScheme={colorScheme}\n >\n <div style={styles.sectionInner}>\n {Object.entries(ephemeral).map(([key, value]) => (\n <InspectorRow key={key} colorScheme={colorScheme}>\n <ObjectInspector\n name={key}\n data={value}\n theme={theme}\n expandLevel={10}\n />\n </InspectorRow>\n ))}\n </div>\n </DisclosureSection>\n <DisclosureSection\n open={showEvents}\n setOpen={setShowEvents}\n title=\"Events\"\n colorScheme={colorScheme}\n >\n <div ref={eventsContainerRef} style={styles.sectionInner}>\n {connectionEvents?.map((event, index) =>\n event.type === \"stateChange\" ? (\n <InspectorRow key={index} colorScheme={colorScheme}>\n connection:{\" \"}\n <span style={{ fontStyle: \"italic\" }}>\n {event.state.toLowerCase()}\n </span>\n </InspectorRow>\n ) : (\n <InspectorRow\n key={index}\n colorScheme={colorScheme}\n variant={event.type === \"send\" ? \"up\" : \"down\"}\n style={{\n padding: \"0px 12px 1px\",\n }}\n >\n <ObjectInspector\n data={event.type === \"error\" ? event.error : event.message}\n theme={theme}\n nodeRenderer={({\n depth,\n name,\n data,\n isNonenumerable,\n expanded,\n }: any) => {\n const direction = event.type === \"send\" ? \"up\" : \"down\";\n\n return depth === 0 ? (\n <ObjectRootLabel direction={direction} data={data} />\n ) : (\n <ObjectLabel\n direction={direction}\n name={name}\n data={data}\n isNonenumerable={isNonenumerable}\n />\n );\n }}\n />\n </InspectorRow>\n )\n )}\n {!connectionEvents && (\n <div\n style={{\n padding: \"12px\",\n fontSize: \"12px\",\n display: \"flex\",\n flexDirection: \"column\",\n gap: \"4px\",\n }}\n >\n <span>No recorded events</span>\n </div>\n )}\n </div>\n </DisclosureSection>\n </div>\n );\n});\n\ntype MessageDirection = \"up\" | \"down\";\n\nconst ObjectRootLabel: FC<{\n name?: string;\n data: any;\n direction?: MessageDirection;\n}> = ({ name, data, direction }) => {\n if (typeof name === \"string\") {\n return (\n <span>\n <ObjectName name={name} />\n <span>: </span>\n <ObjectPreview data={data} />\n </span>\n );\n }\n if (direction === \"up\" || direction === \"down\") {\n const arrow = direction === \"up\" ? \"↑\" : \"↓\";\n\n return (\n <span>\n <span\n style={{\n background:\n direction === \"up\" ? \"rgba(0,255,0,0.2)\" : \"rgba(255,0,0,0.2)\",\n // color: \"white\",\n width: 12,\n height: 12,\n borderRadius: 2,\n display: \"inline-flex\",\n justifyContent: \"center\",\n alignItems: \"center\",\n marginRight: 4,\n lineHeight: \"12px\",\n }}\n >\n {arrow}\n </span>\n <ObjectPreview data={data} />\n </span>\n );\n } else {\n return <ObjectPreview data={data} />;\n }\n};\n\n// Rotates ▶️ or ▼ based on expanded state\nfunction Arrow({\n expanded,\n onClick,\n style,\n}: {\n expanded: boolean;\n onClick?: () => void;\n style?: CSSProperties;\n}) {\n return (\n <span\n role=\"button\"\n onClick={onClick}\n style={{\n display: \"inline-block\",\n textAlign: \"center\",\n transform: expanded ? \"rotate(0deg)\" : \"rotate(-90deg)\",\n fontFamily: \"Menlo, monospace\",\n ...style,\n }}\n >\n {\"▼\"}\n </span>\n );\n}\n\nfunction pathToString(extendedPath: ExtendedPathKey[]) {\n return extendedPath\n .map((key) =>\n typeof key === \"object\"\n ? `:${ellipsis(key.id.toString(), 8, \"middle\")}`\n : key\n )\n .map((key, index) =>\n index === 0 || (typeof key === \"string\" && key.startsWith(\":\"))\n ? key\n : `.${key}`\n )\n .join(\"\");\n}\n\ntype EllipsisPosition = \"start\" | \"middle\" | \"end\";\n\nfunction ellipsis(\n str: string,\n maxLength: number,\n position: EllipsisPosition = \"end\"\n) {\n if (str.length <= maxLength) return str;\n\n switch (position) {\n case \"start\":\n return `…${str.slice(str.length - maxLength)}`;\n case \"middle\":\n const halfLength = Math.floor(maxLength / 2);\n return `${str.slice(0, halfLength)}…${str.slice(str.length - halfLength)}`;\n case \"end\":\n return `${str.slice(0, maxLength)}…`;\n }\n}\n\nfunction SmallButton({\n children,\n onClick,\n style,\n theme,\n disabled,\n}: {\n children: React.ReactNode;\n onClick: () => void;\n style?: CSSProperties;\n theme: typeof chromeLight;\n disabled?: boolean;\n}) {\n return (\n <button\n type=\"button\"\n disabled={disabled}\n onClick={(event) => {\n event.stopPropagation();\n onClick();\n }}\n style={{\n flex: \"0\",\n appearance: \"none\",\n background: \"none\",\n color: theme.BASE_COLOR,\n opacity: disabled ? 0.25 : 1,\n border: \"none\",\n fontSize: \"12px\",\n whiteSpace: \"nowrap\",\n display: \"inline-flex\",\n alignItems: \"center\",\n justifyContent: \"center\",\n padding: \"2px 0\",\n cursor: \"pointer\",\n ...style,\n }}\n >\n {children}\n </button>\n );\n}\n","\"use client\";\n\nimport React from \"react\";\n\nconst localStorage = typeof window !== \"undefined\" ? window.localStorage : null;\n\nexport function useLocalStorageState<S>(\n key: string,\n defaultValue: S\n): [S, (value: S) => void] {\n const [state, setState] = React.useState<S>(() => {\n const value = localStorage?.getItem(key);\n let result = defaultValue;\n if (value) {\n try {\n result = JSON.parse(value);\n } catch (error) {\n console.error(\"Error parsing localStorage value\", error);\n }\n }\n return result;\n });\n\n const setLocalStorageState = (value: S) => {\n localStorage?.setItem(key, JSON.stringify(value));\n setState(value);\n };\n\n return [state, setLocalStorageState];\n}\n","/* eslint-disable no-restricted-globals */\nimport {\n createOrCastValue,\n findAllDefs,\n localStorageSync,\n MultiplayerUser,\n Static,\n stubSync,\n SyncAdapter,\n TSchema,\n TypeGuard,\n webSocketSync,\n} from \"@noya-app/state-manager\";\nimport { useEffect, useMemo, useState } from \"react\";\nimport { useMultiplayerState, UseMultiplayerStateOptions } from \"./hooks\";\nimport { StateInspectorOptions } from \"./inspector/StateInspector\";\n\nexport type AppViewType = \"editable\" | \"readOnly\" | \"preview\";\n\nexport type AppTheme = \"light\" | \"dark\";\n\nexport type AppData<State> = {\n multiplayerUrl?: string;\n theme: AppTheme;\n viewType: AppViewType;\n initialState: State;\n inspector: boolean | StateInspectorOptions;\n};\n\nexport function createDefaultAppData<State>(\n initialState: State\n): AppData<State> {\n return {\n theme: \"light\",\n viewType: \"editable\",\n initialState,\n inspector: false,\n };\n}\n\nexport type GetAppDataOptions = {\n window?: { location: { hash: string } };\n overrideExistingState?: boolean;\n};\n\nexport function enforceSchema<State>(\n initialState: State,\n schema?: TSchema\n): State {\n return schema\n ? (createOrCastValue({\n schema,\n value: initialState,\n defs: findAllDefs(schema),\n }) as State)\n : initialState;\n}\n\nexport function parseAppDataParameter(\n options?: GetAppDataOptions\n): AppData<unknown> | null {\n const window = options?.window ?? globalThis;\n const location = window.location;\n if (!location) return null;\n const urlHash = (location.hash || \"\").replace(/^#/, \"\");\n const params = new URLSearchParams(urlHash);\n const data = params.get(\"data\");\n if (!data) return null;\n try {\n return JSON.parse(data);\n } catch (e) {\n return null;\n }\n}\n\nexport function getAppData<State>(\n initialState: State | (() => State),\n schema?: TSchema,\n options?: GetAppDataOptions\n): AppData<State> {\n const resolvedInitialState =\n initialState instanceof Function ? initialState() : initialState;\n\n let appData =\n parseAppDataParameter(options) ??\n createDefaultAppData(resolvedInitialState);\n\n if (options?.overrideExistingState) {\n appData.initialState = resolvedInitialState;\n }\n\n appData.initialState = enforceSchema(appData.initialState, schema) as State;\n\n return appData as AppData<State>;\n}\n\nexport type IframeToHostMessage =\n | {\n type: \"application.setMenuItems\";\n payload: {\n menuItems: any[];\n };\n }\n | {\n type: \"multiplayer.setUsers\";\n payload: {\n users: any[];\n };\n };\n\nexport type HostToIframeMessage = {\n type: \"application.selectMenuItem\";\n payload: {\n value: string;\n };\n};\n\nexport function useBroadcastConnectedUsers(connectedUsers: MultiplayerUser[]) {\n useEffect(() => {\n if (!isEmbeddedApp()) return;\n\n const message: IframeToHostMessage = {\n type: \"multiplayer.setUsers\",\n payload: { users: connectedUsers },\n };\n\n parent?.postMessage(message, \"*\");\n }, [connectedUsers]);\n}\n\nexport function useBroadcastMenuItems<T>(\n menuItems: any[],\n handleSelectMenuItem: (value: T) => void\n) {\n useEffect(() => {\n if (!isEmbeddedApp()) return;\n\n const message: IframeToHostMessage = {\n type: \"application.setMenuItems\",\n payload: { menuItems },\n };\n\n parent?.postMessage(message, \"*\");\n\n const listener = (event: MessageEvent<HostToIframeMessage>) => {\n if (event.data.type === \"application.selectMenuItem\") {\n handleSelectMenuItem(event.data.payload.value as T);\n }\n };\n\n window.addEventListener(\"message\", listener);\n\n return () => {\n window.removeEventListener(\"message\", listener);\n };\n }, [handleSelectMenuItem, menuItems]);\n}\n\nexport function isEmbeddedApp() {\n return window.self !== window.top;\n}\n\nexport type UseNoyaAppStateOptions<\n S,\n M = void,\n E = void,\n> = UseMultiplayerStateOptions<S, M, E> & {\n localStorageKey?: string;\n};\n\nexport type UseNoyaAppStateResult<S, M = void, E = void> = [\n ReturnType<typeof useMultiplayerState<S, M, E>>[0],\n ReturnType<typeof useMultiplayerState<S, M, E>>[1],\n ReturnType<typeof useMultiplayerState<S, M, E>>[2] & {\n theme: AppTheme;\n viewType: AppViewType;\n },\n];\n\n/**\n * Sync data locally or to a multiplayer server.\n *\n * There are 3 ways to use this hook:\n *\n * 1. Pass an initial state: `useNoyaAppState(initialState)`\n * 2. Pass an initial state and a schema: `useNoyaAppState(initialState, { schema })`\n * 3. Pass only a schema, and a conforming initial state is created automatically: `useNoyaAppState({ schema })`\n */\nexport function useNoyaAppState<\n S,\n M = void,\n E = void,\n O extends UseNoyaAppStateOptions<S, M, E> = UseNoyaAppStateOptions<S, M, E>,\n>(\n ...args:\n | [\n initialState: O[\"schema\"] extends TSchema\n ? Static<O[\"schema\"]> | (() => Static<O[\"schema\"]>)\n : S | (() => S),\n options?: O,\n ]\n | [options: O & { schema: TSchema }]\n): UseNoyaAppStateResult<\n O[\"schema\"] extends TSchema ? Static<O[\"schema\"]> : S,\n M,\n E\n> {\n const [initialState, options] =\n typeof args[0] === \"object\" &&\n args[0] !== null &&\n \"schema\" in args[0] &&\n TypeGuard.IsSchema(args[0].schema)\n ? [null, args[0]]\n : [args[0], args[1]];\n\n // Keep these stable after initial render\n const [\n {\n multiplayerUrl,\n inspector,\n initialState: noyaAppInitialState,\n theme,\n viewType,\n },\n ] = useState(() => {\n return getAppData(initialState, options?.schema, {\n overrideExistingState: options?.overrideExistingState,\n });\n });\n\n const sync = useMemo((): SyncAdapter<S, M, E> => {\n return multiplayerUrl\n ? webSocketSync(multiplayerUrl)\n : options?.localStorageKey\n ? localStorageSync({ key: options.localStorageKey })\n : stubSync();\n }, [multiplayerUrl, options?.localStorageKey]);\n\n const result = useMultiplayerState(noyaAppInitialState as S, {\n ...options,\n inspector: options?.inspector ?? inspector,\n sync: options?.sync ?? sync,\n });\n\n const [, , extras] = result;\n\n useBroadcastConnectedUsers(extras.connectedUsers);\n\n const mergedExtras = useMemo(() => {\n return { ...extras, theme, viewType } as const;\n }, [extras, theme, viewType]);\n\n return [result[0], result[1], mergedExtras] as UseNoyaAppStateResult<\n O[\"schema\"] extends TSchema ? Static<O[\"schema\"]> : S,\n M,\n E\n >;\n}\n\n// function typeTest() {\n// const [a, setA] = useNoyaAppState(7);\n// const [b, setB] = useNoyaAppState(7, {\n// schema: Type.Number(),\n// });\n// const [c, setC] = useNoyaAppState({\n// schema: Type.Number(),\n// });\n// }\n"],"mappings":"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","names":["useMemo","listen","get","useMemo","UserPointer","UserPointerContainer","UserNameTag","useEffect","useMemo","useState","useSyncExternalStore","createRoot","React","React","useLayoutEffect","React","memo","useEffect","React","React","memo","StateInspector","useEffect","React","useLayoutEffect","root","useSyncExternalStore","useState","useMemo","useEffect","userId","tasks","state","createRoot","stubSync","useEffect","useMemo","useState","window","useEffect","useState","useMemo","stubSync"]}
1
+ {"version":3,"sources":["../src/index.ts","../src/avatarStyle.ts","../src/components/UserPointersOverlay.tsx","../src/useObservable.ts","../src/hooks.ts","../src/components/ErrorOverlay.tsx","../src/globals.ts","../src/inspector/useStateInspector.tsx","../src/inspector/StateInspector.tsx","../src/inspector/useLocalStorageState.tsx","../src/noyaApp.ts"],"sourcesContent":["export * from \"@noya-app/state-manager\";\nexport * from \"./avatarStyle\";\nexport * from \"./components/UserPointersOverlay\";\nexport * from \"./hooks\";\nexport * from \"./inspector/StateInspector\";\nexport * from \"./noyaApp\";\nexport * from \"./useObservable\";\n","function hashCode(string: string) {\n let hash = 0;\n\n for (const char of string) {\n hash = char.charCodeAt(0) + ((hash << 5) - hash);\n }\n\n return hash;\n}\n\nfunction elementFromHash<T>(array: T[], hash: number): T {\n return array[Math.abs(hash) % array.length];\n}\n\nexport function getAvatarInitials(name: string) {\n return name\n .split(\" \")\n .filter((c) => c.length > 0)\n .map((c) => c[0])\n .join(\"\")\n .toLocaleUpperCase();\n}\n\n/**\n * Create a background color and initials from a name\n *\n * Adapted from https://mui.com/material-ui/react-avatar/\n */\nexport function getAvatarStyle(name: string) {\n const hash = hashCode(name);\n const color = elementFromHash(Object.values(colors500), hash);\n // const darkerColor = elementFromHash(Object.values(colors800), hash);\n\n return {\n color: \"white\",\n backgroundColor: color,\n // primaryColors: {\n // \"500\": color,\n // \"800\": darkerColor,\n // },\n };\n}\n\nconst colors500 = {\n red500: \"#ef4444\",\n orange500: \"#f97316\",\n amber500: \"#f59e0b\",\n yellow500: \"#eab308\",\n lime500: \"#84cc16\",\n green500: \"#22c55e\",\n emerald500: \"#10b981\",\n teal500: \"#14b8a6\",\n cyan500: \"#06b6d4\",\n sky500: \"#0ea5e9\",\n blue500: \"#3b82f6\",\n indigo500: \"#6366f1\",\n violet500: \"#8b5cf6\",\n purple500: \"#a855f7\",\n fuchsia500: \"#d946ef\",\n pink500: \"#ec4899\",\n rose500: \"#f43f5e\",\n};\n\n// const colors800 = {\n// red800: \"#991b1b\",\n// orange800: \"#9a3412\",\n// amber800: \"#92400e\",\n// yellow800: \"#854d0e\",\n// lime800: \"#3f6212\",\n// green800: \"#166534\",\n// emerald800: \"#065f46\",\n// teal800: \"#115e59\",\n// cyan800: \"#155e75\",\n// sky800: \"#075985\",\n// blue800: \"#1e40af\",\n// indigo800: \"#3730a3\",\n// violet800: \"#5b21b6\",\n// purple800: \"#6b21a8\",\n// fuchsia800: \"#86198f\",\n// pink800: \"#9d174d\",\n// rose800: \"#9f1239\",\n// };\n","\"use client\";\n\nimport { EphemeralUserData, MultiplayerUser } from \"@noya-app/state-manager\";\nimport React, { memo, useEffect, useMemo, useState } from \"react\";\nimport { getAvatarStyle } from \"../avatarStyle\";\nimport { useObservable } from \"../useObservable\";\n\ntype Point = { x: number; y: number };\n\nexport type UserPointerData = { pointer?: Point };\n\nexport type UserPointerProps<E extends UserPointerData> = {\n user: MultiplayerUser;\n ephemeralUserData: EphemeralUserData<E>;\n hideAfter?: number;\n};\n\nfunction shouldShow(hideAfter: number, updatedAt: number) {\n return !!updatedAt && Date.now() - updatedAt < hideAfter;\n}\n\nconst UserPointer_ = function UserPointer<E extends UserPointerData>({\n user,\n ephemeralUserData,\n hideAfter = 5000,\n}: UserPointerProps<E>) {\n const metadata = useObservable(ephemeralUserData.metadata$, [\n user.id,\n ] as const);\n const data = useObservable(ephemeralUserData.data$, [user.id] as const);\n const avatarStyle = useMemo(() => getAvatarStyle(user.id), [user.id]);\n\n const [, setForceUpdate] = useState(0);\n\n const updatedAt = metadata?.updatedAt ?? 0;\n\n useEffect(() => {\n if (!shouldShow(hideAfter, updatedAt)) return;\n\n const timeoutId = setTimeout(() => {\n setForceUpdate((prev) => prev + 1);\n }, hideAfter);\n\n return () => clearTimeout(timeoutId);\n }, [hideAfter, updatedAt]);\n\n const show = shouldShow(hideAfter, updatedAt);\n\n if (!data || !data.pointer) return null;\n\n return (\n <UserPointerContainer key={user.id} point={data.pointer} show={show}>\n <UserPointerIcon color={avatarStyle.backgroundColor} />\n <UserNameTag background={avatarStyle.backgroundColor}>\n {user.name}\n </UserNameTag>\n </UserPointerContainer>\n );\n};\n\nexport const UserPointer = memo(UserPointer_) as typeof UserPointer_;\n\nexport const UserPointerContainer = memo(function UserPointerContainer({\n point,\n children,\n show = true,\n}: {\n point: Point;\n children: React.ReactNode;\n show?: boolean;\n}) {\n return (\n <div\n style={{\n position: \"absolute\",\n top: 0,\n left: 0,\n transform: `translate(${Math.round(point.x)}px, ${Math.round(\n point.y\n )}px)`,\n opacity: show ? 1 : 0,\n transition: \"transform 0.1s, opacity 0.2s\",\n }}\n >\n {children}\n </div>\n );\n});\n\nexport const UserNameTag = memo(function UserNameTag({\n background,\n children,\n}: {\n background: string;\n children: React.ReactNode;\n}) {\n return (\n <span\n style={{\n position: \"relative\",\n top: \"8px\",\n left: \"15px\",\n fontSize: 11,\n lineHeight: \"1\",\n fontWeight: 500,\n boxShadow: \"0 1px 1px rgba(0,0,0,0.1)\",\n padding: \"2px 4px 3px\",\n pointerEvents: \"none\",\n letterSpacing: \"-0.3px\",\n outline: `1px solid rgba(255,255,255,0.3)`,\n outlineOffset: \"-1px\",\n background,\n color: \"white\",\n }}\n >\n {children}\n </span>\n );\n});\n\nexport type UserPointersOverlayProps<E extends UserPointerData> = {\n connectedUsers: MultiplayerUser[];\n ephemeralUserData: EphemeralUserData<E>;\n};\n\nexport const UserPointersOverlay = memo(function UserPointers<\n E extends UserPointerData,\n>({ connectedUsers, ephemeralUserData }: UserPointersOverlayProps<E>) {\n const currentUserId = useObservable(ephemeralUserData.currentUserId$);\n\n return (\n <>\n {connectedUsers.map((user) => {\n if (user.id === currentUserId) return null;\n\n return (\n <UserPointer\n key={user.id}\n user={user}\n ephemeralUserData={\n ephemeralUserData as unknown as EphemeralUserData<E>\n }\n />\n );\n })}\n </>\n );\n});\n\nexport const UserPointerIcon = memo(function CursorIcon({\n color = \"black\",\n}: {\n color?: string;\n}) {\n return (\n <svg\n width=\"15\"\n height=\"15\"\n viewBox=\"0 0 15 15\"\n fill=\"none\"\n xmlns=\"http://www.w3.org/2000/svg\"\n style={{\n position: \"absolute\",\n filter: \"drop-shadow(0 1px 1px rgba(0,0,0,0.1))\",\n // filter: \"drop-shadow(0 1px 1px rgba(0,0,0,0.6))\",\n }}\n >\n <path\n fillRule=\"evenodd\"\n clipRule=\"evenodd\"\n d=\"M3.29227 0.0451998C3.47033 -0.0361222 3.67946 -0.00606629 3.8274 0.122107L12.8587 7.94648C13.0134 8.08054 13.0708 8.29538 13.0035 8.48873C12.9362 8.68208 12.7578 8.81488 12.5533 8.8239L9.21887 8.97096L11.1504 13.2149C11.2648 13.4662 11.1538 13.7626 10.9026 13.877L8.75024 14.8575C8.499 14.972 8.20255 14.8611 8.08802 14.6099L6.15339 10.3665L3.86279 12.7817C3.72196 12.9302 3.50487 12.9779 3.31479 12.9021C3.1247 12.8263 3 12.6423 3 12.4376V0.500008C3 0.304264 3.11422 0.126522 3.29227 0.0451998Z\"\n fill={color}\n />\n <path\n fillRule=\"evenodd\"\n clipRule=\"evenodd\"\n d=\"M3.29227 0.048984C3.47033 -0.032338 3.67946 -0.00228211 3.8274 0.125891L12.8587 7.95026C13.0134 8.08432 13.0708 8.29916 13.0035 8.49251C12.9362 8.68586 12.7578 8.81866 12.5533 8.82768L9.21887 8.97474L11.1504 13.2187C11.2648 13.47 11.1538 13.7664 10.9026 13.8808L8.75024 14.8613C8.499 14.9758 8.20255 14.8649 8.08802 14.6137L6.15339 10.3703L3.86279 12.7855C3.72196 12.934 3.50487 12.9817 3.31479 12.9059C3.1247 12.8301 3 12.6461 3 12.4414V0.503792C3 0.308048 3.11422 0.130306 3.29227 0.048984ZM4 1.59852V11.1877L5.93799 9.14425C6.05238 9.02363 6.21924 8.96776 6.38319 8.99516C6.54715 9.02256 6.68677 9.12965 6.75573 9.2809L8.79056 13.7441L10.0332 13.178L8.00195 8.71497C7.93313 8.56376 7.94391 8.38824 8.03072 8.24659C8.11753 8.10494 8.26903 8.01566 8.435 8.00834L11.2549 7.88397L4 1.59852Z\"\n fill=\"rgba(255,255,255,0.5)\"\n />\n </svg>\n );\n});\n","import { GetWithPath, Observable, PathKey } from \"@noya-app/observable\";\nimport { useMemo, useSyncExternalStore } from \"react\";\n\nexport function useObservable<T>(observable: Observable<T>): T;\nexport function useObservable<T, P extends PathKey[]>(\n observable: Observable<T>,\n path: P\n): GetWithPath<T, P>;\nexport function useObservable<T, P extends PathKey[]>(\n observable: Observable<T>,\n path?: P\n) {\n const { get, listen } = useMemo(() => {\n const listen = path\n ? (callback: (value: GetWithPath<T, P>) => void) =>\n observable.listen(path, callback)\n : observable.listen;\n\n const get: () => void = path ? () => observable.get(path) : observable.get;\n\n return { get, listen };\n }, [observable, path]);\n\n return useSyncExternalStore(listen, get, get);\n}\n","\"use client\";\n\nimport {\n ActionHandler,\n AssetManager,\n ConnectionEvent,\n EphemeralUserData,\n Get,\n MultiplayerStateManager,\n MultiplayerStateManagerError,\n MultiplayerStateManagerOptions,\n MultiplayerUser,\n StateManager,\n StateManagerOptions,\n stubSync,\n SyncAdapter,\n SyncAdapterOptions,\n Task,\n} from \"@noya-app/state-manager\";\nimport {\n createElement,\n SetStateAction,\n useCallback,\n useEffect,\n useMemo,\n useRef,\n useState,\n useSyncExternalStore,\n} from \"react\";\nimport { createRoot } from \"react-dom/client\";\nimport { ErrorOverlay } from \"./components/ErrorOverlay\";\nimport { shouldTrackEvents$, shouldTrackTasks$ } from \"./globals\";\nimport { StateInspectorOptions } from \"./inspector/StateInspector\";\nimport { useStateInspector } from \"./inspector/useStateInspector\";\nimport { useObservable } from \"./useObservable\";\n\nexport function useSyncStateManager<S, M>(stateManager: StateManager<S, M>): S;\nexport function useSyncStateManager<S, M, P extends string>(\n stateManager: StateManager<S, M>,\n path: P\n): Get<S, P, unknown>;\nexport function useSyncStateManager<S, M>(\n stateManager: StateManager<S, M>,\n path?: string\n) {\n const getSnapshot = useCallback(\n () =>\n typeof path === \"string\"\n ? stateManager.getState(path)\n : stateManager.getState(),\n [stateManager, path]\n );\n\n return useSyncExternalStore(\n stateManager.addListener,\n getSnapshot,\n getSnapshot\n );\n}\n\nexport function useManagedState<S, M = void>(\n createInitialState: () => S,\n options?: StateManagerOptions<S, M>\n) {\n const [stateManager] = useState(\n () => new StateManager<S, M>(createInitialState(), options)\n );\n\n const state = useSyncStateManager(stateManager);\n\n const setState = useCallback(\n (\n ...args: M extends {}\n ? [metadata: M, action: SetStateAction<S>]\n : [action: SetStateAction<S>]\n ) => {\n const [metadata, action] =\n args.length === 1 ? [undefined, args[0]] : args;\n\n if (metadata === undefined) {\n const performActionNoMetadata = stateManager.performAction as (\n handler: ActionHandler<S>\n ) => void;\n\n if (action instanceof Function) {\n performActionNoMetadata({\n run: action,\n undo: () => state,\n });\n } else {\n performActionNoMetadata({\n run: () => action,\n undo: () => state,\n });\n }\n } else {\n const performActionWithMetadata = stateManager.performAction as (\n metadata: M,\n handler: ActionHandler<S>\n ) => void;\n\n if (action instanceof Function) {\n performActionWithMetadata(metadata, {\n run: action,\n undo: () => state,\n });\n } else {\n performActionWithMetadata(metadata, {\n run: () => action,\n undo: () => state,\n });\n }\n }\n },\n [state, stateManager]\n );\n\n return [state, setState, stateManager] as const;\n}\n\nexport function useManagedHistory<S, M = void>(\n stateManager: StateManager<S, M>\n) {\n return useSyncExternalStore(\n stateManager.historyEmittor.addListener,\n stateManager.getHistorySnapshot,\n stateManager.getHistorySnapshot\n );\n}\n\nexport function useSyncMultiplayerStateManager<S, M = void>(\n multiplayerStateManager: MultiplayerStateManager<S, M>\n) {\n return useSyncExternalStore(\n multiplayerStateManager.addListener,\n multiplayerStateManager.getOptimisticState,\n multiplayerStateManager.getOptimisticState\n );\n}\n\nfunction throttle<F extends (...args: any[]) => any>(fn: F, ms: number) {\n let lastCall = 0;\n let timeoutId: number | null = null;\n return (...args: Parameters<F>) => {\n const now = Date.now();\n if (now - lastCall < ms) {\n if (timeoutId) clearTimeout(timeoutId);\n timeoutId = setTimeout(\n () => {\n lastCall = now;\n fn(...args);\n },\n ms - (now - lastCall)\n ) as unknown as number;\n return;\n }\n lastCall = now;\n return fn(...args);\n };\n}\n\nexport function useEphemeralUserData<E>(\n ephemeralUserData: EphemeralUserData<E>,\n options?: {\n throttle?: number;\n }\n) {\n const throttledAddListener = useMemo(() => {\n const throttleMs = options?.throttle ?? 0;\n\n if (throttleMs > 0) {\n const addListener = (\n fn: Parameters<typeof ephemeralUserData.addListener>[0]\n ) => {\n const throttledFn = throttle(fn, throttleMs);\n return ephemeralUserData.addListener(throttledFn);\n };\n\n return addListener;\n }\n\n return ephemeralUserData.addListener;\n }, [ephemeralUserData, options?.throttle]);\n\n return useSyncExternalStore(\n throttledAddListener,\n ephemeralUserData.getSnapshot,\n ephemeralUserData.getSnapshot\n );\n}\n\nconst defaultStubSync = stubSync();\n\nexport type UseMultiplayerStateOptions<\n S,\n M = void,\n E = void,\n> = MultiplayerStateManagerOptions<S, M> & {\n sync?: (\n options: Pick<\n SyncAdapterOptions<S, M, E>,\n \"ms\" | \"ephemeralUserData\" | \"assetManager\"\n >\n ) => void;\n trackConnectionEvents?: boolean;\n trackTasks?: boolean;\n inspector?: boolean | StateInspectorOptions;\n};\n\nexport function useMultiplayerState<S, M = void, E = void>(\n initialState: S | (() => S),\n options?: UseMultiplayerStateOptions<S, M, E>\n) {\n const { sync = defaultStubSync as unknown as SyncAdapter<S, M, E>, ...rest } =\n options ?? {};\n\n const [multiplayerStateManager] = useState(\n () => new MultiplayerStateManager<S, M>(initialState, rest)\n );\n const [assetManager] = useState(() => new AssetManager());\n const syncRef = useRef(sync);\n\n const [connectionEvents, setConnectionEvents] = useState<\n ConnectionEvent<S>[] | undefined\n >();\n\n const [connectedUsers, setConnectedUsers] = useState<MultiplayerUser[]>([]);\n const [ephemeralUserData] = useState<EphemeralUserData<E>>(\n () => new EphemeralUserData()\n );\n const [tasks, setTasks] = useState<Task[]>([]);\n const [userId, setUserId] = useState<string | undefined>();\n const assets = useObservable(assetManager.assets$);\n\n const extras = useMemo(() => {\n return {\n tasks,\n userId,\n connectionEvents,\n connectedUsers,\n ephemeralUserData,\n multiplayerStateManager,\n assets,\n createAsset: assetManager.create,\n deleteAsset: assetManager.delete,\n // evaluate: async (code: string) => {\n // const payload = await rpcManager.request({ type: \"eval\", code });\n\n // if (payload.type !== \"eval\") {\n // throw new Error(`Unexpected rpc response type: ${payload.type}`);\n // }\n // },\n };\n }, [\n tasks,\n userId,\n connectionEvents,\n connectedUsers,\n ephemeralUserData,\n multiplayerStateManager,\n assetManager,\n assets,\n ]);\n\n const globalTrackEvents = useObservable(shouldTrackEvents$);\n const globalTrackTasks = useObservable(shouldTrackTasks$);\n\n const shouldTrackEvents = options?.trackConnectionEvents ?? globalTrackEvents;\n const shouldTrackTasks = options?.trackTasks ?? globalTrackTasks;\n\n const trackEventsCallbackRef = useRef<\n ((e: ConnectionEvent<S>) => void) | undefined\n >();\n const trackConnectedUsersCallbackRef = useRef<\n ((users: MultiplayerUser[], userId: string) => void) | undefined\n >();\n const trackTasksCallbackRef = useRef<((tasks: Task[]) => void) | undefined>();\n\n useEffect(() => {\n trackEventsCallbackRef.current = shouldTrackEvents\n ? (e) =>\n setConnectionEvents((events) => {\n const updated = events ? [...events, e] : [e];\n return updated.length > 50 ? updated.slice(-50) : updated;\n })\n : undefined;\n }, [shouldTrackEvents]);\n\n useEffect(() => {\n trackConnectedUsersCallbackRef.current = (users, userId) => {\n setConnectedUsers(users);\n setUserId(userId);\n };\n }, []);\n\n useEffect(() => {\n trackTasksCallbackRef.current = shouldTrackTasks\n ? (tasks) => {\n setTasks((old) => {\n const newIds = new Set(tasks.map((t) => t.id));\n\n // merge old and new tasks, preferring new tasks\n const unchanged = old.filter((t) => !newIds.has(t.id));\n\n return [...unchanged, ...tasks];\n });\n }\n : undefined;\n }, [shouldTrackTasks]);\n\n useEffect(() => {\n if (syncRef.current) {\n return syncRef.current({\n ms: multiplayerStateManager,\n assetManager,\n ephemeralUserData,\n onConnectionEvent: (e) => trackEventsCallbackRef.current?.(e),\n onChangeConnectedUsers: (users, userId) =>\n trackConnectedUsersCallbackRef.current?.(users, userId),\n onChangeTasks: (tasks) => trackTasksCallbackRef.current?.(tasks),\n });\n }\n }, [assetManager, ephemeralUserData, multiplayerStateManager]);\n\n const state = useSyncMultiplayerStateManager(multiplayerStateManager);\n\n const forceInit = useCallback(() => {\n const state =\n initialState instanceof Function ? initialState() : initialState;\n const schema = options?.schema;\n multiplayerStateManager.sm.clearHistory();\n multiplayerStateManager.sendInit({ force: true, state, schema });\n }, [initialState, multiplayerStateManager, options?.schema]);\n\n const [unrecoverableError, setUnrecoverableError] = useState<\n MultiplayerStateManagerError | undefined\n >();\n\n useEffect(() => {\n return multiplayerStateManager.errorEmitter.addListener((error) => {\n setUnrecoverableError(error);\n });\n }, [multiplayerStateManager]);\n\n useEffect(() => {\n if (!unrecoverableError) return;\n const el = document.createElement(\"div\");\n el.id = \"noya-multiplayer-react-error-overlay\";\n document.body.appendChild(el);\n const root = createRoot(el);\n root.render(createElement(ErrorOverlay, { error: unrecoverableError }));\n return () => {\n root.unmount();\n el.remove();\n };\n });\n\n useStateInspector({\n ephemeralUserData,\n multiplayerStateManager,\n assetManager,\n state,\n connectionEvents,\n connectedUsers,\n tasks,\n userId,\n forceInit,\n disabled: !options?.inspector,\n ...(typeof options?.inspector === \"object\" && options.inspector),\n });\n\n return [state, multiplayerStateManager.setState, extras] as const;\n}\n","import { MultiplayerStateManagerError } from \"@noya-app/state-manager\";\nimport React from \"react\";\n\nexport function ErrorOverlay({\n error,\n}: {\n error: MultiplayerStateManagerError;\n}) {\n return (\n <div\n style={{\n position: \"fixed\",\n top: \"20px\",\n left: \"50%\",\n transform: \"translateX(-50%)\",\n maxWidth: \"80%\",\n width: \"fit-content\",\n padding: \"12px 20px\",\n background: \"white\",\n color: \"black\",\n zIndex: 10000,\n display: \"flex\",\n flexDirection: \"column\",\n justifyContent: \"center\",\n borderRadius: \"4px\",\n boxShadow: \"0 4px 6px rgba(0, 0, 0, 0.1)\",\n fontFamily:\n \"'__Inter_6b0edc', '__Inter_Fallback_6b0edc', -apple-system, BlinkMacSystemFont, 'Helvetica Neue', 'Segoe UI', Roboto, Helvetica, Arial, sans-serif\",\n fontSize: \"14px\",\n fontWeight: 400,\n lineHeight: \"19px\",\n }}\n >\n {error.reason === \"schemaMigration\" ? (\n <>\n <p>\n An updated version of Noya is available. Please reload the page to\n continue.\n </p>\n </>\n ) : (\n <>\n <p>\n An error occurred:{\" \"}\n <code\n style={{\n background: \"rgba(255, 0, 0, 0.1)\",\n color: \"rgba(255, 0, 0, 0.5)\",\n padding: \"2px 4px\",\n borderRadius: \"4px\",\n }}\n >\n {error.reason}\n </code>\n . Please reload the page to continue.\n <br />\n <br />\n If this happens repeatedly, please get in touch and the Noya team\n can help.\n </p>\n </>\n )}\n <div\n style={{\n height: \"1px\",\n background: \"rgba(0, 0, 0, 0.1)\",\n margin: \"12px -20px\",\n }}\n />\n <button\n style={{\n background: \"black\",\n color: \"white\",\n padding: \"8px 16px\",\n borderRadius: \"4px\",\n cursor: \"pointer\",\n fontSize: \"14px\",\n fontWeight: 700,\n lineHeight: \"19px\",\n }}\n onClick={() => {\n window.location.reload();\n }}\n >\n Reload\n </button>\n </div>\n );\n}\n","import { Observable } from \"@noya-app/observable\";\n\nexport const shouldTrackEvents$ = new Observable(false);\nexport const shouldTrackTasks$ = new Observable(false);\n","\"use client\";\n\nimport {\n AssetManager,\n ConnectionEvent,\n EphemeralUserData,\n MultiplayerStateManager,\n MultiplayerUser,\n Task,\n} from \"@noya-app/state-manager\";\nimport React, { ComponentProps, useLayoutEffect } from \"react\";\nimport { createRoot } from \"react-dom/client\";\n\nimport { Root } from \"react-dom/client\";\nimport { StateInspector } from \"./StateInspector\";\n\nfunction createShadowRootElement() {\n const host = document.createElement(\"div\");\n host.id = \"noya-multiplayer-react-inspector-host\";\n const shadowRoot = host.attachShadow({ mode: \"open\" });\n const container = document.createElement(\"div\");\n shadowRoot.appendChild(container);\n return { host, container };\n}\n\nexport function useStateInspector<S, M, E>({\n state,\n connectionEvents,\n connectedUsers,\n tasks,\n userId,\n disabled = false,\n colorScheme,\n anchor,\n multiplayerStateManager,\n assetManager,\n ephemeralUserData,\n forceInit,\n}: {\n state: S;\n connectionEvents?: ConnectionEvent<S>[];\n connectedUsers?: MultiplayerUser[];\n tasks?: Task[];\n userId?: string;\n disabled: boolean;\n multiplayerStateManager: MultiplayerStateManager<S, M>;\n assetManager: AssetManager;\n ephemeralUserData: EphemeralUserData<E>;\n forceInit: () => void;\n} & Pick<ComponentProps<typeof StateInspector>, \"colorScheme\" | \"anchor\">) {\n const [root, setRoot] = React.useState<Root | null>(null);\n\n useLayoutEffect(() => {\n if (disabled) return;\n\n const { host, container } = createShadowRootElement();\n const root = createRoot(container);\n\n document.body.appendChild(host);\n\n setRoot(root);\n\n return () => {\n document.body.removeChild(host);\n };\n }, [disabled]);\n\n useLayoutEffect(() => {\n if (!root) return;\n\n root.render(\n <StateInspector\n state={state}\n connectionEvents={connectionEvents}\n connectedUsers={connectedUsers}\n tasks={tasks}\n userId={userId}\n colorScheme={colorScheme}\n anchor={anchor}\n forceInit={forceInit}\n multiplayerStateManager={\n multiplayerStateManager as MultiplayerStateManager<any, any>\n }\n assetManager={assetManager}\n ephemeralUserData={ephemeralUserData as EphemeralUserData<any>}\n />\n );\n }, [\n anchor,\n colorScheme,\n connectedUsers,\n connectionEvents,\n root,\n state,\n multiplayerStateManager,\n userId,\n tasks,\n forceInit,\n ephemeralUserData,\n assetManager,\n ]);\n}\n","\"use client\";\n\nimport {\n AssetManager,\n ConnectionEvent,\n EphemeralUserData,\n ExtendedPathKey,\n MultiplayerStateManager,\n MultiplayerUser,\n Task,\n} from \"@noya-app/state-manager\";\nimport React, {\n CSSProperties,\n ComponentPropsWithoutRef,\n FC,\n memo,\n useEffect,\n useLayoutEffect,\n} from \"react\";\nimport {\n ObjectInspector,\n ObjectLabel,\n ObjectName,\n ObjectPreview,\n chromeDark,\n chromeLight,\n} from \"react-inspector\";\nimport { shouldTrackEvents$, shouldTrackTasks$ } from \"../globals\";\nimport { useEphemeralUserData, useManagedHistory } from \"../hooks\";\nimport { useObservable } from \"../useObservable\";\nimport { useLocalStorageState } from \"./useLocalStorageState\";\n\nconst lightTheme = {\n ...chromeLight,\n BASE_BACKGROUND_COLOR: \"transparent\",\n OBJECT_NAME_COLOR: \"rgba(0,0,0,0.7)\",\n} as any;\n\nconst darkTheme = {\n ...chromeDark,\n BASE_BACKGROUND_COLOR: \"transparent\",\n OBJECT_NAME_COLOR: \"rgba(255,255,255,0.7)\",\n} as any;\n\nconst styles = {\n sectionInner: {\n flex: \"1 1 0\",\n overflowY: \"auto\",\n overflowX: \"hidden\",\n display: \"flex\",\n flexDirection: \"column\",\n },\n} as const;\n\nfunction ToggleButton({\n showInspector,\n setShowInspector,\n theme,\n anchor,\n}: {\n showInspector: boolean;\n setShowInspector: (value: boolean) => void;\n theme: typeof chromeLight;\n anchor: StateInspectorAnchor;\n}) {\n return (\n <span\n role=\"button\"\n style={{\n flex: \"0\",\n appearance: \"none\",\n color: theme.BASE_COLOR,\n border: \"none\",\n fontSize: \"12px\",\n whiteSpace: \"nowrap\",\n display: \"inline-flex\",\n alignItems: \"center\",\n justifyContent: \"center\",\n padding: \"2px 0\",\n }}\n onClick={(event) => {\n event.stopPropagation();\n\n setShowInspector(!showInspector);\n }}\n >\n <span style={{ width: \"12px\", height: \"12px\" }}>\n {showInspector === (anchor === \"right\") ? (\n <svg\n xmlns=\"http://www.w3.org/2000/svg\"\n fill=\"none\"\n viewBox=\"0 0 24 24\"\n strokeWidth={1.5}\n stroke=\"currentColor\"\n className=\"size-6\"\n >\n <path\n strokeLinecap=\"round\"\n strokeLinejoin=\"round\"\n d=\"m5.25 4.5 7.5 7.5-7.5 7.5m6-15 7.5 7.5-7.5 7.5\"\n />\n </svg>\n ) : (\n <svg\n xmlns=\"http://www.w3.org/2000/svg\"\n fill=\"none\"\n viewBox=\"0 0 24 24\"\n strokeWidth={1.5}\n stroke=\"currentColor\"\n className=\"size-6\"\n >\n <path\n strokeLinecap=\"round\"\n strokeLinejoin=\"round\"\n d=\"m18.75 4.5-7.5 7.5 7.5 7.5m-6-15L5.25 12l7.5 7.5\"\n />\n </svg>\n )}\n </span>\n </span>\n );\n}\n\nfunction DisclosureSection({\n open,\n setOpen,\n title,\n right,\n children,\n colorScheme,\n isFirst,\n style,\n}: {\n open: boolean;\n setOpen?: (value: boolean) => void;\n title: string;\n right?: React.ReactNode;\n children: React.ReactNode;\n colorScheme: \"light\" | \"dark\";\n isFirst?: boolean;\n style?: CSSProperties;\n}) {\n const theme = colorScheme === \"light\" ? lightTheme : darkTheme;\n\n const borderColor =\n colorScheme === \"light\" ? \"rgba(0,0,0,0.1)\" : \"rgba(255,255,255,0.1)\";\n\n return (\n <div\n style={{\n flex: open ? \"1 1 0\" : \"0\",\n display: \"flex\",\n flexDirection: \"column\",\n ...style,\n }}\n >\n <div\n onClick={() => setOpen?.(!open)}\n style={{\n cursor: \"default\",\n fontSize: \"12px\",\n padding: \"4px 10px\",\n display: \"flex\",\n alignItems: \"center\",\n ...(!isFirst && { borderTop: `1px solid ${borderColor}` }),\n ...(open && { borderBottom: `1px solid ${borderColor}` }),\n }}\n >\n {setOpen && (\n <Arrow\n expanded={open}\n style={{\n fontSize: theme.ARROW_FONT_SIZE,\n marginRight: theme.ARROW_MARGIN_RIGHT + 1,\n color: theme.ARROW_COLOR,\n }}\n />\n )}\n <span style={{ flex: \"1 1 0\", userSelect: \"none\" }}>{title}</span>\n {right}\n </div>\n {open && children}\n </div>\n );\n}\n\nfunction InspectorRow({\n children,\n colorScheme,\n selected,\n style,\n variant,\n}: {\n children: React.ReactNode;\n colorScheme: \"light\" | \"dark\";\n selected?: boolean;\n style?: CSSProperties;\n variant?: \"up\" | \"down\";\n}) {\n const solidBorderColor =\n colorScheme === \"light\" ? \"rgb(223 223 223)\" : \"rgb(29 29 29)\";\n\n return (\n <div\n style={{\n borderBottom: `1px solid ${solidBorderColor}`,\n fontSize: \"12px\",\n fontFamily: \"Menlo, monospace\",\n padding: \"2px 12px 1px\",\n display: \"flex\",\n alignItems: \"center\",\n background:\n variant === \"up\"\n ? \"rgba(0,255,0,0.1)\"\n : variant === \"down\"\n ? \"rgba(255,0,0,0.1)\"\n : selected\n ? \"rgb(59 130 246 / 15%)\"\n : undefined,\n // background:\n // colorScheme === \"light\"\n // ? \"rgba(0,0,0,0.05)\"\n // : \"rgba(255,255,255,0.05)\",\n ...style,\n }}\n >\n <span\n style={{\n fontFamily: \"Menlo, monospace\",\n fontSize: \"11px\",\n borderRadius: 4,\n display: \"inline-block\",\n }}\n >\n {children}\n </span>\n </div>\n );\n}\n\nconst HISTORY_ELEMENT_PREFIX = \"noya-multiplayer-history-\";\n\nexport type StateInspectorAnchor =\n | \"left\"\n | \"right\"\n | \"bottom left\"\n | \"bottom right\";\n\nexport type StateInspectorOptions = {\n colorScheme?: \"light\" | \"dark\";\n anchor?: StateInspectorAnchor;\n};\n\nexport const StateInspector = memo(function StateInspector<S, M, E>({\n state,\n connectionEvents,\n connectedUsers,\n tasks,\n userId,\n unstyled,\n colorScheme = \"light\",\n multiplayerStateManager,\n assetManager,\n ephemeralUserData,\n anchor = \"right\",\n forceInit,\n ...props\n}: {\n state: S;\n connectionEvents?: ConnectionEvent<S>[];\n connectedUsers?: MultiplayerUser[];\n tasks?: Task[];\n userId?: string;\n unstyled?: boolean;\n multiplayerStateManager: MultiplayerStateManager<S, M>;\n assetManager: AssetManager;\n ephemeralUserData: EphemeralUserData<E>;\n forceInit: () => void;\n} & StateInspectorOptions &\n ComponentPropsWithoutRef<\"div\">) {\n const [didMount, setDidMount] = React.useState(false);\n\n useLayoutEffect(() => {\n setDidMount(true);\n }, []);\n\n const eventsContainerRef = React.useRef<HTMLDivElement>(null);\n const historyContainerRef = React.useRef<HTMLDivElement>(null);\n\n const [showInspector, setShowInspector] = useLocalStorageState(\n \"noya-multiplayer-react-show-inspector\",\n true\n );\n const [showEvents, setShowEvents] = useLocalStorageState(\n \"noya-multiplayer-react-show-events\",\n false\n );\n const [showHistory, setShowHistory] = useLocalStorageState(\n \"noya-multiplayer-react-show-history\",\n false\n );\n const [showUsers, setShowUsers] = useLocalStorageState(\n \"noya-multiplayer-react-show-users\",\n true\n );\n const [showData, setShowData] = useLocalStorageState(\n \"noya-multiplayer-react-show-data\",\n true\n );\n const [showTasks, setShowTasks] = useLocalStorageState(\n \"noya-multiplayer-react-show-tasks\",\n false\n );\n const [showEphemeral, setShowEphemeral] = useLocalStorageState(\n \"noya-multiplayer-react-show-ephemeral\",\n false\n );\n const [showAssets, setShowAssets] = useLocalStorageState(\n \"noya-multiplayer-react-show-assets\",\n false\n );\n\n useEffect(() => {\n shouldTrackEvents$.set(showEvents);\n }, [showEvents]);\n\n useEffect(() => {\n shouldTrackTasks$.set(showTasks);\n }, [showTasks]);\n\n useEffect(() => {\n if (eventsContainerRef.current) {\n eventsContainerRef.current.scrollTop =\n eventsContainerRef.current.scrollHeight;\n }\n }, [connectionEvents]);\n\n const ephemeral = useEphemeralUserData(ephemeralUserData);\n const historySnapshot = useManagedHistory(multiplayerStateManager.sm);\n const assets = useObservable(assetManager.assets$);\n\n useEffect(() => {\n if (historyContainerRef.current) {\n historyContainerRef.current.scrollTop =\n historyContainerRef.current.scrollHeight;\n }\n }, [historySnapshot]);\n\n // If history index changes, scroll to the new history entry into view\n useEffect(() => {\n if (!historyContainerRef.current) return;\n\n const historyEntry = historyContainerRef.current.querySelector(\n `#${HISTORY_ELEMENT_PREFIX}${historySnapshot.historyIndex}`\n );\n\n if (historyEntry) {\n historyEntry.scrollIntoView({\n block: \"nearest\",\n inline: \"nearest\",\n });\n }\n }, [historySnapshot.historyIndex]);\n\n const theme = colorScheme === \"light\" ? lightTheme : darkTheme;\n // const borderColor =\n // colorScheme === \"light\" ? \"rgba(0,0,0,0.1)\" : \"rgba(255,255,255,0.1)\";\n const solidBorderColor =\n colorScheme === \"light\" ? \"rgb(223 223 223)\" : \"rgb(29 29 29)\";\n\n const baseStyle: CSSProperties = {\n position: \"fixed\",\n top: 12,\n ...(anchor.includes(\"right\") ? { right: 12 } : { left: 12 }),\n bottom: 12,\n width: 400,\n background:\n colorScheme === \"light\" ? \"rgba(255,255,255,0.95)\" : \"rgba(0,0,0,0.95)\",\n backdropFilter: \"blur(48px)\",\n border: `1px solid ${solidBorderColor}`,\n // outlineOffset: -1,\n borderRadius: 4,\n display: \"flex\",\n flexDirection: \"column\",\n // gap: 12,\n color: theme.BASE_COLOR,\n overflow: \"hidden\",\n zIndex: 9999,\n lineHeight: \"13px\",\n };\n\n if (!didMount) return null;\n\n if (!showInspector) {\n return (\n <div\n {...props}\n style={{\n ...baseStyle,\n padding: \"4px 10px\",\n width: undefined,\n ...(anchor.includes(\"bottom\")\n ? { bottom: 12, top: undefined }\n : { bottom: undefined }),\n }}\n onClick={() => setShowInspector(true)}\n >\n <ToggleButton\n showInspector={showInspector}\n setShowInspector={setShowInspector}\n theme={theme}\n anchor={anchor}\n />\n </div>\n );\n }\n\n return (\n <div\n {...props}\n style={{\n ...(!unstyled && baseStyle),\n ...props.style,\n }}\n >\n <DisclosureSection\n isFirst\n open={showUsers}\n setOpen={setShowUsers}\n title=\"Users\"\n colorScheme={colorScheme}\n style={{\n flex: \"0 0 auto\",\n maxHeight: \"200px\",\n }}\n right={\n <ToggleButton\n showInspector={showInspector}\n setShowInspector={setShowInspector}\n theme={theme}\n anchor={anchor}\n />\n }\n >\n <div style={{ ...styles.sectionInner, flex: \"0 0 auto\" }}>\n {connectedUsers?.map((user) => (\n <InspectorRow\n key={user.id}\n colorScheme={colorScheme}\n variant={user.id === userId ? \"up\" : undefined}\n >\n {user.image && (\n <img\n src={user.image}\n alt={user.name}\n style={{\n width: \"12px\",\n height: \"12px\",\n borderRadius: \"50%\",\n marginRight: \"4px\",\n display: \"inline-block\",\n position: \"relative\",\n top: \"-1px\",\n background: solidBorderColor,\n }}\n />\n )}\n {user.name} ({ellipsis(user.id.toString(), 8, \"middle\")})\n </InspectorRow>\n ))}\n {!connectedUsers && (\n <div\n style={{\n padding: \"12px\",\n fontSize: \"12px\",\n display: \"flex\",\n flexDirection: \"column\",\n gap: \"4px\",\n }}\n >\n <span>No connected users</span>\n </div>\n )}\n </div>\n </DisclosureSection>\n <DisclosureSection\n title=\"Data\"\n colorScheme={colorScheme}\n setOpen={setShowData}\n open={showData}\n right={\n <span\n style={{\n display: \"flex\",\n gap: \"4px\",\n }}\n >\n <SmallButton\n // disabled={!historySnapshot.canUndo}\n theme={theme}\n onClick={() => {\n forceInit();\n }}\n >\n Reset\n </SmallButton>\n </span>\n }\n >\n <div style={styles.sectionInner}>\n <InspectorRow colorScheme={colorScheme}>\n <ObjectInspector\n name={multiplayerStateManager.schema ? \"state\" : undefined}\n data={state}\n theme={theme}\n />\n </InspectorRow>\n {multiplayerStateManager.schema && (\n <InspectorRow colorScheme={colorScheme}>\n <ObjectInspector\n name=\"schema\"\n data={multiplayerStateManager.schema}\n theme={theme}\n />\n </InspectorRow>\n )}\n </div>\n </DisclosureSection>\n <DisclosureSection\n open={showHistory}\n setOpen={setShowHistory}\n title=\"History\"\n colorScheme={colorScheme}\n right={\n <span\n style={{\n display: \"flex\",\n gap: \"4px\",\n }}\n >\n <SmallButton\n disabled={!historySnapshot.canUndo}\n theme={theme}\n onClick={() => {\n multiplayerStateManager.undo();\n }}\n >\n <span style={{ width: \"12px\", height: \"12px\" }}>\n <svg\n xmlns=\"http://www.w3.org/2000/svg\"\n width=\"1em\"\n height=\"1em\"\n viewBox=\"0 0 20 20\"\n >\n <path\n fill=\"currentColor\"\n d=\"M12 5H7V2L1 6l6 4V7h5c2.2 0 4 1.8 4 4s-1.8 4-4 4H7v2h5c3.3 0 6-2.7 6-6s-2.7-6-6-6\"\n />\n </svg>\n </span>\n </SmallButton>\n <SmallButton\n disabled={!historySnapshot.canRedo}\n theme={theme}\n onClick={() => {\n multiplayerStateManager.redo();\n }}\n >\n <span style={{ width: \"12px\", height: \"12px\" }}>\n <svg\n xmlns=\"http://www.w3.org/2000/svg\"\n width=\"1em\"\n height=\"1em\"\n viewBox=\"0 0 20 20\"\n >\n <path\n fill=\"currentColor\"\n d=\"M8 5h5V2l6 4l-6 4V7H8c-2.2 0-4 1.8-4 4s1.8 4 4 4h5v2H8c-3.3 0-6-2.7-6-6s2.7-6 6-6\"\n />\n </svg>\n </span>\n </SmallButton>\n </span>\n }\n >\n <div ref={historyContainerRef} style={styles.sectionInner}>\n <div\n id={`${HISTORY_ELEMENT_PREFIX}0`}\n style={{\n borderBottom: `1px solid ${solidBorderColor}`,\n fontSize: \"12px\",\n fontFamily: \"Menlo, monospace\",\n padding: \"2px 12px 1px\",\n display: \"flex\",\n alignItems: \"center\",\n background:\n historySnapshot.historyIndex === 0\n ? \"rgb(59 130 246 / 15%)\"\n : undefined,\n }}\n >\n <span\n style={{\n fontFamily: \"Menlo, monospace\",\n fontSize: \"11px\",\n borderRadius: 4,\n display: \"inline-block\",\n }}\n >\n Initial state\n </span>\n </div>\n {historySnapshot.history.map((entry, index) => (\n <div\n id={`${HISTORY_ELEMENT_PREFIX}${index + 1}`}\n key={index}\n style={{\n padding: \"0px 12px 1px\",\n borderBottom: `1px solid ${solidBorderColor}`,\n background:\n index + 1 === historySnapshot.historyIndex\n ? \"rgb(59 130 246 / 15%)\"\n : undefined,\n }}\n >\n {\"name\" in entry.metadata &&\n typeof entry.metadata.name === \"string\" && (\n <pre\n style={{\n fontSize: \"11px\",\n display: \"flex\",\n flexWrap: \"wrap\",\n }}\n >\n {entry.metadata.name}\n </pre>\n )}\n {entry.redoPatches?.map((patch, j) => (\n <pre\n key={j}\n style={{\n fontSize: \"11px\",\n display: \"flex\",\n flexWrap: \"wrap\",\n }}\n >\n {patch.op === \"add\" && (\n <>\n <span style={{ fontStyle: \"italic\" }}>\n {pathToString(patch.path)}\n </span>\n {\" = \"}\n <ObjectInspector data={patch.value} theme={theme} />\n </>\n )}\n {patch.op === \"replace\" && (\n <>\n <span style={{ fontStyle: \"italic\" }}>\n {pathToString(patch.path)}\n </span>\n {\" = \"}\n <ObjectInspector data={patch.value} theme={theme} />\n </>\n )}\n {patch.op === \"remove\" && (\n <>\n <span style={{ color: theme.OBJECT_VALUE_STRING_COLOR }}>\n delete{\" \"}\n </span>\n <span style={{ fontStyle: \"italic\" }}>\n {pathToString(patch.path)}\n </span>\n </>\n )}\n {patch.op === \"move\" && (\n <>\n <span style={{ fontStyle: \"italic\" }}>\n {pathToString(patch.from!)}\n </span>\n {\" -> \"}\n <span style={{ fontStyle: \"italic\" }}>\n {pathToString(patch.path)}\n </span>\n </>\n )}\n </pre>\n ))}\n </div>\n ))}\n </div>\n </DisclosureSection>\n <DisclosureSection\n open={showAssets}\n setOpen={setShowAssets}\n title=\"Assets\"\n colorScheme={colorScheme}\n right={\n <span style={{ display: \"flex\", gap: \"4px\" }}>\n <SmallButton\n theme={theme}\n onClick={() => {\n // get file input\n const input = document.createElement(\"input\");\n input.type = \"file\";\n input.onchange = () => {\n const file = input.files?.[0];\n if (file) {\n const reader = new FileReader();\n reader.onload = () => {\n const buffer = reader.result as ArrayBuffer;\n assetManager.create(new Uint8Array(buffer));\n };\n reader.readAsArrayBuffer(file);\n }\n };\n input.click();\n }}\n >\n Upload\n </SmallButton>\n </span>\n }\n >\n <div style={styles.sectionInner}>\n {assets.map((asset) => (\n <InspectorRow key={asset.id} colorScheme={colorScheme}>\n <ObjectInspector name={asset.id} data={asset} theme={theme} />\n <SmallButton\n theme={theme}\n onClick={() => assetManager.delete(asset.id)}\n >\n Delete\n </SmallButton>\n </InspectorRow>\n ))}\n </div>\n </DisclosureSection>\n <DisclosureSection\n title=\"Tasks\"\n colorScheme={colorScheme}\n open={showTasks}\n setOpen={setShowTasks}\n >\n <div style={styles.sectionInner}>\n {tasks?.map((task) => (\n <InspectorRow\n key={task.id}\n colorScheme={colorScheme}\n style={{\n backgroundColor:\n task.status === \"done\"\n ? \"rgba(0,255,0,0.2)\"\n : task.status === \"error\"\n ? \"rgba(255,0,0,0.2)\"\n : undefined,\n }}\n >\n <ObjectInspector\n name={task.name}\n data={task.payload}\n theme={theme}\n />\n </InspectorRow>\n ))}\n </div>\n </DisclosureSection>\n <DisclosureSection\n open={showEphemeral}\n setOpen={setShowEphemeral}\n title=\"Ephemeral User Data\"\n colorScheme={colorScheme}\n >\n <div style={styles.sectionInner}>\n {Object.entries(ephemeral).map(([key, value]) => (\n <InspectorRow key={key} colorScheme={colorScheme}>\n <ObjectInspector\n name={key}\n data={value}\n theme={theme}\n expandLevel={10}\n />\n </InspectorRow>\n ))}\n </div>\n </DisclosureSection>\n <DisclosureSection\n open={showEvents}\n setOpen={setShowEvents}\n title=\"Events\"\n colorScheme={colorScheme}\n >\n <div ref={eventsContainerRef} style={styles.sectionInner}>\n {connectionEvents?.map((event, index) =>\n event.type === \"stateChange\" ? (\n <InspectorRow key={index} colorScheme={colorScheme}>\n connection:{\" \"}\n <span style={{ fontStyle: \"italic\" }}>\n {event.state.toLowerCase()}\n </span>\n </InspectorRow>\n ) : (\n <InspectorRow\n key={index}\n colorScheme={colorScheme}\n variant={event.type === \"send\" ? \"up\" : \"down\"}\n style={{\n padding: \"0px 12px 1px\",\n }}\n >\n <ObjectInspector\n data={event.type === \"error\" ? event.error : event.message}\n theme={theme}\n nodeRenderer={({\n depth,\n name,\n data,\n isNonenumerable,\n expanded,\n }: any) => {\n const direction = event.type === \"send\" ? \"up\" : \"down\";\n\n return depth === 0 ? (\n <ObjectRootLabel direction={direction} data={data} />\n ) : (\n <ObjectLabel\n direction={direction}\n name={name}\n data={data}\n isNonenumerable={isNonenumerable}\n />\n );\n }}\n />\n </InspectorRow>\n )\n )}\n {!connectionEvents && (\n <div\n style={{\n padding: \"12px\",\n fontSize: \"12px\",\n display: \"flex\",\n flexDirection: \"column\",\n gap: \"4px\",\n }}\n >\n <span>No recorded events</span>\n </div>\n )}\n </div>\n </DisclosureSection>\n </div>\n );\n});\n\ntype MessageDirection = \"up\" | \"down\";\n\nconst ObjectRootLabel: FC<{\n name?: string;\n data: any;\n direction?: MessageDirection;\n}> = ({ name, data, direction }) => {\n if (typeof name === \"string\") {\n return (\n <span>\n <ObjectName name={name} />\n <span>: </span>\n <ObjectPreview data={data} />\n </span>\n );\n }\n if (direction === \"up\" || direction === \"down\") {\n const arrow = direction === \"up\" ? \"↑\" : \"↓\";\n\n return (\n <span>\n <span\n style={{\n background:\n direction === \"up\" ? \"rgba(0,255,0,0.2)\" : \"rgba(255,0,0,0.2)\",\n // color: \"white\",\n width: 12,\n height: 12,\n borderRadius: 2,\n display: \"inline-flex\",\n justifyContent: \"center\",\n alignItems: \"center\",\n marginRight: 4,\n lineHeight: \"12px\",\n }}\n >\n {arrow}\n </span>\n <ObjectPreview data={data} />\n </span>\n );\n } else {\n return <ObjectPreview data={data} />;\n }\n};\n\n// Rotates ▶️ or ▼ based on expanded state\nfunction Arrow({\n expanded,\n onClick,\n style,\n}: {\n expanded: boolean;\n onClick?: () => void;\n style?: CSSProperties;\n}) {\n return (\n <span\n role=\"button\"\n onClick={onClick}\n style={{\n display: \"inline-block\",\n textAlign: \"center\",\n transform: expanded ? \"rotate(0deg)\" : \"rotate(-90deg)\",\n fontFamily: \"Menlo, monospace\",\n ...style,\n }}\n >\n {\"▼\"}\n </span>\n );\n}\n\nfunction pathToString(extendedPath: ExtendedPathKey[]) {\n return extendedPath\n .map((key) =>\n typeof key === \"object\"\n ? `:${ellipsis(key.id.toString(), 8, \"middle\")}`\n : key\n )\n .map((key, index) =>\n index === 0 || (typeof key === \"string\" && key.startsWith(\":\"))\n ? key\n : `.${key}`\n )\n .join(\"\");\n}\n\ntype EllipsisPosition = \"start\" | \"middle\" | \"end\";\n\nfunction ellipsis(\n str: string,\n maxLength: number,\n position: EllipsisPosition = \"end\"\n) {\n if (str.length <= maxLength) return str;\n\n switch (position) {\n case \"start\":\n return `…${str.slice(str.length - maxLength)}`;\n case \"middle\":\n const halfLength = Math.floor(maxLength / 2);\n return `${str.slice(0, halfLength)}…${str.slice(str.length - halfLength)}`;\n case \"end\":\n return `${str.slice(0, maxLength)}…`;\n }\n}\n\nfunction SmallButton({\n children,\n onClick,\n style,\n theme,\n disabled,\n}: {\n children: React.ReactNode;\n onClick: () => void;\n style?: CSSProperties;\n theme: typeof chromeLight;\n disabled?: boolean;\n}) {\n return (\n <button\n type=\"button\"\n disabled={disabled}\n onClick={(event) => {\n event.stopPropagation();\n onClick();\n }}\n style={{\n flex: \"0\",\n appearance: \"none\",\n background: \"none\",\n color: theme.BASE_COLOR,\n opacity: disabled ? 0.25 : 1,\n border: \"none\",\n fontSize: \"12px\",\n whiteSpace: \"nowrap\",\n display: \"inline-flex\",\n alignItems: \"center\",\n justifyContent: \"center\",\n padding: \"0\",\n cursor: \"pointer\",\n ...style,\n }}\n >\n {children}\n </button>\n );\n}\n","\"use client\";\n\nimport React from \"react\";\n\nconst localStorage = typeof window !== \"undefined\" ? window.localStorage : null;\n\nexport function useLocalStorageState<S>(\n key: string,\n defaultValue: S\n): [S, (value: S) => void] {\n const [state, setState] = React.useState<S>(() => {\n const value = localStorage?.getItem(key);\n let result = defaultValue;\n if (value) {\n try {\n result = JSON.parse(value);\n } catch (error) {\n console.error(\"Error parsing localStorage value\", error);\n }\n }\n return result;\n });\n\n const setLocalStorageState = (value: S) => {\n localStorage?.setItem(key, JSON.stringify(value));\n setState(value);\n };\n\n return [state, setLocalStorageState];\n}\n","/* eslint-disable no-restricted-globals */\nimport {\n createOrCastValue,\n findAllDefs,\n localStorageSync,\n MultiplayerUser,\n Static,\n stubSync,\n SyncAdapter,\n TSchema,\n TypeGuard,\n webSocketSync,\n} from \"@noya-app/state-manager\";\nimport { useEffect, useMemo, useState } from \"react\";\nimport { useMultiplayerState, UseMultiplayerStateOptions } from \"./hooks\";\nimport { StateInspectorOptions } from \"./inspector/StateInspector\";\n\nexport type AppViewType = \"editable\" | \"readOnly\" | \"preview\";\n\nexport type AppTheme = \"light\" | \"dark\";\n\nexport type AppData<State> = {\n multiplayerUrl?: string;\n theme: AppTheme;\n viewType: AppViewType;\n initialState: State;\n inspector: boolean | StateInspectorOptions;\n};\n\nexport function createDefaultAppData<State>(\n initialState: State\n): AppData<State> {\n return {\n theme: \"light\",\n viewType: \"editable\",\n initialState,\n inspector: false,\n };\n}\n\nexport type GetAppDataOptions = {\n window?: { location: { hash: string } };\n overrideExistingState?: boolean;\n};\n\nexport function enforceSchema<State>(\n initialState: State,\n schema?: TSchema\n): State {\n return schema\n ? (createOrCastValue({\n schema,\n value: initialState,\n defs: findAllDefs(schema),\n }) as State)\n : initialState;\n}\n\nexport function parseAppDataParameter(\n options?: GetAppDataOptions\n): AppData<unknown> | null {\n const window = options?.window ?? globalThis;\n const location = window.location;\n if (!location) return null;\n const urlHash = (location.hash || \"\").replace(/^#/, \"\");\n const params = new URLSearchParams(urlHash);\n const data = params.get(\"data\");\n if (!data) return null;\n try {\n return JSON.parse(data);\n } catch (e) {\n return null;\n }\n}\n\nexport function getAppData<State>(\n initialState: State | (() => State),\n schema?: TSchema,\n options?: GetAppDataOptions\n): AppData<State> {\n const resolvedInitialState =\n initialState instanceof Function ? initialState() : initialState;\n\n let appData =\n parseAppDataParameter(options) ??\n createDefaultAppData(resolvedInitialState);\n\n if (options?.overrideExistingState) {\n appData.initialState = resolvedInitialState;\n }\n\n appData.initialState = enforceSchema(appData.initialState, schema) as State;\n\n return appData as AppData<State>;\n}\n\nexport type IframeToHostMessage =\n | {\n type: \"application.setMenuItems\";\n payload: {\n menuItems: any[];\n };\n }\n | {\n type: \"multiplayer.setUsers\";\n payload: {\n users: any[];\n };\n };\n\nexport type HostToIframeMessage = {\n type: \"application.selectMenuItem\";\n payload: {\n value: string;\n };\n};\n\nexport function useBroadcastConnectedUsers(connectedUsers: MultiplayerUser[]) {\n useEffect(() => {\n if (!isEmbeddedApp()) return;\n\n const message: IframeToHostMessage = {\n type: \"multiplayer.setUsers\",\n payload: { users: connectedUsers },\n };\n\n parent?.postMessage(message, \"*\");\n }, [connectedUsers]);\n}\n\nexport function useBroadcastMenuItems<T>(\n menuItems: any[],\n handleSelectMenuItem: (value: T) => void\n) {\n useEffect(() => {\n if (!isEmbeddedApp()) return;\n\n const message: IframeToHostMessage = {\n type: \"application.setMenuItems\",\n payload: { menuItems },\n };\n\n parent?.postMessage(message, \"*\");\n\n const listener = (event: MessageEvent<HostToIframeMessage>) => {\n if (event.data.type === \"application.selectMenuItem\") {\n handleSelectMenuItem(event.data.payload.value as T);\n }\n };\n\n window.addEventListener(\"message\", listener);\n\n return () => {\n window.removeEventListener(\"message\", listener);\n };\n }, [handleSelectMenuItem, menuItems]);\n}\n\nexport function isEmbeddedApp() {\n return window.self !== window.top;\n}\n\nexport type UseNoyaStateOptions<\n S,\n M = void,\n E = void,\n> = UseMultiplayerStateOptions<S, M, E> & {\n offlineStorageKey?: string;\n};\n\nexport type UseNoyaStateResult<S, M = void, E = void> = [\n ReturnType<typeof useMultiplayerState<S, M, E>>[0],\n ReturnType<typeof useMultiplayerState<S, M, E>>[1],\n ReturnType<typeof useMultiplayerState<S, M, E>>[2] & {\n theme: AppTheme;\n viewType: AppViewType;\n },\n];\n\n/**\n * Sync data locally or to a multiplayer server.\n *\n * There are 3 ways to use this hook:\n *\n * 1. Pass an initial state: `useNoyaState(initialState)`\n * 2. Pass an initial state and a schema: `useNoyaState(initialState, { schema })`\n * 3. Pass only a schema, and a conforming initial state is created automatically: `useNoyaState({ schema })`\n */\nexport function useNoyaState<\n S,\n M = void,\n E = void,\n O extends UseNoyaStateOptions<S, M, E> = UseNoyaStateOptions<S, M, E>,\n>(\n ...args:\n | [\n initialState: O[\"schema\"] extends TSchema\n ? Static<O[\"schema\"]> | (() => Static<O[\"schema\"]>)\n : S | (() => S),\n options?: O,\n ]\n | [options: O & { schema: TSchema }]\n): UseNoyaStateResult<\n O[\"schema\"] extends TSchema ? Static<O[\"schema\"]> : S,\n M,\n E\n> {\n const [initialState, options] =\n typeof args[0] === \"object\" &&\n args[0] !== null &&\n \"schema\" in args[0] &&\n TypeGuard.IsSchema(args[0].schema)\n ? [null, args[0]]\n : [args[0], args[1]];\n\n // Keep these stable after initial render\n const [\n {\n multiplayerUrl,\n inspector,\n initialState: noyaAppInitialState,\n theme,\n viewType,\n },\n ] = useState(() => {\n return getAppData(initialState, options?.schema, {\n overrideExistingState: options?.overrideExistingState,\n });\n });\n\n const sync = useMemo((): SyncAdapter<S, M, E> => {\n return multiplayerUrl\n ? webSocketSync(multiplayerUrl)\n : options?.offlineStorageKey\n ? localStorageSync({ key: options.offlineStorageKey })\n : stubSync();\n }, [multiplayerUrl, options?.offlineStorageKey]);\n\n const result = useMultiplayerState(noyaAppInitialState as S, {\n ...options,\n inspector: options?.inspector ?? inspector,\n sync: options?.sync ?? sync,\n });\n\n const [, , extras] = result;\n\n useBroadcastConnectedUsers(extras.connectedUsers);\n\n const mergedExtras = useMemo(() => {\n return { ...extras, theme, viewType } as const;\n }, [extras, theme, viewType]);\n\n return [result[0], result[1], mergedExtras] as UseNoyaStateResult<\n O[\"schema\"] extends TSchema ? Static<O[\"schema\"]> : S,\n M,\n E\n >;\n}\n\n// function typeTest() {\n// const [a, setA] = useNoyaState(7);\n// const [b, setB] = useNoyaState(7, {\n// schema: Type.Number(),\n// });\n// const [c, setC] = useNoyaState({\n// schema: Type.Number(),\n// });\n// }\n"],"mappings":"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","names":["useMemo","listen","get","useMemo","UserPointer","UserPointerContainer","UserNameTag","useEffect","useMemo","useState","useSyncExternalStore","createRoot","React","React","useLayoutEffect","React","memo","useEffect","React","React","memo","StateInspector","useEffect","React","useLayoutEffect","root","useSyncExternalStore","useState","useMemo","useEffect","userId","tasks","state","createRoot","stubSync","useEffect","useMemo","useState","window","useEffect","useState","useMemo","stubSync"]}
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@noya-app/noya-multiplayer-react",
3
- "version": "0.1.36",
3
+ "version": "0.1.38",
4
4
  "main": "./dist/index.js",
5
5
  "module": "./dist/index.mjs",
6
6
  "types": "./dist/index.d.ts",
@@ -12,7 +12,7 @@
12
12
  "dev": "npm run build -- --watch"
13
13
  },
14
14
  "dependencies": {
15
- "@noya-app/state-manager": "0.1.27",
15
+ "@noya-app/state-manager": "0.1.29",
16
16
  "@noya-app/emitter": "0.1.0",
17
17
  "@noya-app/observable": "0.1.1",
18
18
  "react-inspector": "6.0.2"
package/src/hooks.ts CHANGED
@@ -2,6 +2,7 @@
2
2
 
3
3
  import {
4
4
  ActionHandler,
5
+ AssetManager,
5
6
  ConnectionEvent,
6
7
  EphemeralUserData,
7
8
  Get,
@@ -196,7 +197,10 @@ export type UseMultiplayerStateOptions<
196
197
  E = void,
197
198
  > = MultiplayerStateManagerOptions<S, M> & {
198
199
  sync?: (
199
- options: Pick<SyncAdapterOptions<S, M, E>, "ms" | "ephemeralUserData">
200
+ options: Pick<
201
+ SyncAdapterOptions<S, M, E>,
202
+ "ms" | "ephemeralUserData" | "assetManager"
203
+ >
200
204
  ) => void;
201
205
  trackConnectionEvents?: boolean;
202
206
  trackTasks?: boolean;
@@ -213,6 +217,7 @@ export function useMultiplayerState<S, M = void, E = void>(
213
217
  const [multiplayerStateManager] = useState(
214
218
  () => new MultiplayerStateManager<S, M>(initialState, rest)
215
219
  );
220
+ const [assetManager] = useState(() => new AssetManager());
216
221
  const syncRef = useRef(sync);
217
222
 
218
223
  const [connectionEvents, setConnectionEvents] = useState<
@@ -225,6 +230,7 @@ export function useMultiplayerState<S, M = void, E = void>(
225
230
  );
226
231
  const [tasks, setTasks] = useState<Task[]>([]);
227
232
  const [userId, setUserId] = useState<string | undefined>();
233
+ const assets = useObservable(assetManager.assets$);
228
234
 
229
235
  const extras = useMemo(() => {
230
236
  return {
@@ -234,6 +240,9 @@ export function useMultiplayerState<S, M = void, E = void>(
234
240
  connectedUsers,
235
241
  ephemeralUserData,
236
242
  multiplayerStateManager,
243
+ assets,
244
+ createAsset: assetManager.create,
245
+ deleteAsset: assetManager.delete,
237
246
  // evaluate: async (code: string) => {
238
247
  // const payload = await rpcManager.request({ type: "eval", code });
239
248
 
@@ -249,6 +258,8 @@ export function useMultiplayerState<S, M = void, E = void>(
249
258
  connectedUsers,
250
259
  ephemeralUserData,
251
260
  multiplayerStateManager,
261
+ assetManager,
262
+ assets,
252
263
  ]);
253
264
 
254
265
  const globalTrackEvents = useObservable(shouldTrackEvents$);
@@ -301,6 +312,7 @@ export function useMultiplayerState<S, M = void, E = void>(
301
312
  if (syncRef.current) {
302
313
  return syncRef.current({
303
314
  ms: multiplayerStateManager,
315
+ assetManager,
304
316
  ephemeralUserData,
305
317
  onConnectionEvent: (e) => trackEventsCallbackRef.current?.(e),
306
318
  onChangeConnectedUsers: (users, userId) =>
@@ -308,7 +320,7 @@ export function useMultiplayerState<S, M = void, E = void>(
308
320
  onChangeTasks: (tasks) => trackTasksCallbackRef.current?.(tasks),
309
321
  });
310
322
  }
311
- }, [ephemeralUserData, multiplayerStateManager]);
323
+ }, [assetManager, ephemeralUserData, multiplayerStateManager]);
312
324
 
313
325
  const state = useSyncMultiplayerStateManager(multiplayerStateManager);
314
326
 
@@ -346,6 +358,7 @@ export function useMultiplayerState<S, M = void, E = void>(
346
358
  useStateInspector({
347
359
  ephemeralUserData,
348
360
  multiplayerStateManager,
361
+ assetManager,
349
362
  state,
350
363
  connectionEvents,
351
364
  connectedUsers,