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

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/dist/index.d.mts CHANGED
@@ -1,5 +1,5 @@
1
1
  import * as _noya_app_state_manager from '@noya-app/state-manager';
2
- import { MultiplayerUser, EphemeralUserData, ConnectionEvent, Task, MultiplayerStateManager, StateManager, Get, StateManagerOptions, MultiplayerStateManagerOptions, SyncAdapterOptions, TSchema, Static } from '@noya-app/state-manager';
2
+ import { MultiplayerUser, EphemeralUserData, ConnectionEvent, Task, MultiplayerStateManager, AssetManager, StateManager, Get, StateManagerOptions, MultiplayerStateManagerOptions, SyncAdapterOptions, TSchema, Static } from '@noya-app/state-manager';
3
3
  export * from '@noya-app/state-manager';
4
4
  import React, { SetStateAction } from 'react';
5
5
  import { Observable, PathKey, GetWithPath } from '@noya-app/observable';
@@ -51,7 +51,7 @@ type StateInspectorOptions = {
51
51
  colorScheme?: "light" | "dark";
52
52
  anchor?: StateInspectorAnchor;
53
53
  };
54
- declare const StateInspector: React.MemoExoticComponent<(<S, M, E>({ state, connectionEvents, connectedUsers, tasks, userId, unstyled, colorScheme, multiplayerStateManager, ephemeralUserData, anchor, forceInit, ...props }: {
54
+ declare const StateInspector: React.MemoExoticComponent<(<S, M, E>({ state, connectionEvents, connectedUsers, tasks, userId, unstyled, colorScheme, multiplayerStateManager, assetManager, ephemeralUserData, anchor, forceInit, ...props }: {
55
55
  state: S;
56
56
  connectionEvents?: ConnectionEvent<S>[] | undefined;
57
57
  connectedUsers?: MultiplayerUser[] | undefined;
@@ -59,6 +59,7 @@ declare const StateInspector: React.MemoExoticComponent<(<S, M, E>({ state, conn
59
59
  userId?: string | undefined;
60
60
  unstyled?: boolean | undefined;
61
61
  multiplayerStateManager: MultiplayerStateManager<S, M>;
62
+ assetManager: AssetManager;
62
63
  ephemeralUserData: EphemeralUserData<E>;
63
64
  forceInit: () => void;
64
65
  } & StateInspectorOptions & Omit<React.DetailedHTMLProps<React.HTMLAttributes<HTMLDivElement>, HTMLDivElement>, "ref">) => React.JSX.Element | null)>;
@@ -76,7 +77,7 @@ declare function useEphemeralUserData<E>(ephemeralUserData: EphemeralUserData<E>
76
77
  currentUserId: string | undefined;
77
78
  };
78
79
  type UseMultiplayerStateOptions<S, M = void, E = void> = MultiplayerStateManagerOptions<S, M> & {
79
- sync?: (options: Pick<SyncAdapterOptions<S, M, E>, "ms" | "ephemeralUserData">) => void;
80
+ sync?: (options: Pick<SyncAdapterOptions<S, M, E>, "ms" | "ephemeralUserData" | "assetManager">) => void;
80
81
  trackConnectionEvents?: boolean;
81
82
  trackTasks?: boolean;
82
83
  inspector?: boolean | StateInspectorOptions;
@@ -88,6 +89,9 @@ declare function useMultiplayerState<S, M = void, E = void>(initialState: S | ((
88
89
  connectedUsers: MultiplayerUser[];
89
90
  ephemeralUserData: EphemeralUserData<E>;
90
91
  multiplayerStateManager: MultiplayerStateManager<S, M>;
92
+ assets: _noya_app_state_manager.Asset[];
93
+ createAsset: (options: Uint8Array | _noya_app_state_manager.CreateAssetOptions) => Promise<_noya_app_state_manager.Asset>;
94
+ deleteAsset: (id: string) => Promise<void>;
91
95
  }];
92
96
 
93
97
  type AppViewType = "editable" | "readOnly" | "preview";
@@ -131,10 +135,10 @@ type HostToIframeMessage = {
131
135
  declare function useBroadcastConnectedUsers(connectedUsers: MultiplayerUser[]): void;
132
136
  declare function useBroadcastMenuItems<T>(menuItems: any[], handleSelectMenuItem: (value: T) => void): void;
133
137
  declare function isEmbeddedApp(): boolean;
134
- type UseNoyaAppStateOptions<S, M = void, E = void> = UseMultiplayerStateOptions<S, M, E> & {
138
+ type UseNoyaStateOptions<S, M = void, E = void> = UseMultiplayerStateOptions<S, M, E> & {
135
139
  localStorageKey?: string;
136
140
  };
137
- type UseNoyaAppStateResult<S, M = void, E = void> = [
141
+ type UseNoyaStateResult<S, M = void, E = void> = [
138
142
  ReturnType<typeof useMultiplayerState<S, M, E>>[0],
139
143
  ReturnType<typeof useMultiplayerState<S, M, E>>[1],
140
144
  ReturnType<typeof useMultiplayerState<S, M, E>>[2] & {
@@ -147,18 +151,18 @@ type UseNoyaAppStateResult<S, M = void, E = void> = [
147
151
  *
148
152
  * There are 3 ways to use this hook:
149
153
  *
150
- * 1. Pass an initial state: `useNoyaAppState(initialState)`
151
- * 2. Pass an initial state and a schema: `useNoyaAppState(initialState, { schema })`
152
- * 3. Pass only a schema, and a conforming initial state is created automatically: `useNoyaAppState({ schema })`
154
+ * 1. Pass an initial state: `useNoyaState(initialState)`
155
+ * 2. Pass an initial state and a schema: `useNoyaState(initialState, { schema })`
156
+ * 3. Pass only a schema, and a conforming initial state is created automatically: `useNoyaState({ schema })`
153
157
  */
154
- declare function useNoyaAppState<S, M = void, E = void, O extends UseNoyaAppStateOptions<S, M, E> = UseNoyaAppStateOptions<S, M, E>>(...args: [
158
+ declare function useNoyaState<S, M = void, E = void, O extends UseNoyaStateOptions<S, M, E> = UseNoyaStateOptions<S, M, E>>(...args: [
155
159
  initialState: O["schema"] extends TSchema ? Static<O["schema"]> | (() => Static<O["schema"]>) : S | (() => S),
156
160
  options?: O
157
161
  ] | [options: O & {
158
162
  schema: TSchema;
159
- }]): UseNoyaAppStateResult<O["schema"] extends TSchema ? Static<O["schema"]> : S, M, E>;
163
+ }]): UseNoyaStateResult<O["schema"] extends TSchema ? Static<O["schema"]> : S, M, E>;
160
164
 
161
165
  declare function useObservable<T>(observable: Observable<T>): T;
162
166
  declare function useObservable<T, P extends PathKey[]>(observable: Observable<T>, path: P): GetWithPath<T, P>;
163
167
 
164
- export { type AppData, type AppTheme, type AppViewType, type GetAppDataOptions, type HostToIframeMessage, type IframeToHostMessage, StateInspector, type StateInspectorAnchor, type StateInspectorOptions, type UseMultiplayerStateOptions, type UseNoyaAppStateOptions, type UseNoyaAppStateResult, UserNameTag, UserPointer, UserPointerContainer, type UserPointerData, UserPointerIcon, type UserPointerProps, UserPointersOverlay, type UserPointersOverlayProps, createDefaultAppData, enforceSchema, getAppData, getAvatarInitials, getAvatarStyle, isEmbeddedApp, parseAppDataParameter, useBroadcastConnectedUsers, useBroadcastMenuItems, useEphemeralUserData, useManagedHistory, useManagedState, useMultiplayerState, useNoyaAppState, useObservable, useSyncMultiplayerStateManager, useSyncStateManager };
168
+ export { type AppData, type AppTheme, type AppViewType, type GetAppDataOptions, type HostToIframeMessage, type IframeToHostMessage, StateInspector, type StateInspectorAnchor, type StateInspectorOptions, type UseMultiplayerStateOptions, type UseNoyaStateOptions, type UseNoyaStateResult, UserNameTag, UserPointer, UserPointerContainer, type UserPointerData, UserPointerIcon, type UserPointerProps, UserPointersOverlay, type UserPointersOverlayProps, createDefaultAppData, enforceSchema, getAppData, getAvatarInitials, getAvatarStyle, isEmbeddedApp, parseAppDataParameter, useBroadcastConnectedUsers, useBroadcastMenuItems, useEphemeralUserData, useManagedHistory, useManagedState, useMultiplayerState, useNoyaState, useObservable, useSyncMultiplayerStateManager, useSyncStateManager };
package/dist/index.d.ts CHANGED
@@ -1,5 +1,5 @@
1
1
  import * as _noya_app_state_manager from '@noya-app/state-manager';
2
- import { MultiplayerUser, EphemeralUserData, ConnectionEvent, Task, MultiplayerStateManager, StateManager, Get, StateManagerOptions, MultiplayerStateManagerOptions, SyncAdapterOptions, TSchema, Static } from '@noya-app/state-manager';
2
+ import { MultiplayerUser, EphemeralUserData, ConnectionEvent, Task, MultiplayerStateManager, AssetManager, StateManager, Get, StateManagerOptions, MultiplayerStateManagerOptions, SyncAdapterOptions, TSchema, Static } from '@noya-app/state-manager';
3
3
  export * from '@noya-app/state-manager';
4
4
  import React, { SetStateAction } from 'react';
5
5
  import { Observable, PathKey, GetWithPath } from '@noya-app/observable';
@@ -51,7 +51,7 @@ type StateInspectorOptions = {
51
51
  colorScheme?: "light" | "dark";
52
52
  anchor?: StateInspectorAnchor;
53
53
  };
54
- declare const StateInspector: React.MemoExoticComponent<(<S, M, E>({ state, connectionEvents, connectedUsers, tasks, userId, unstyled, colorScheme, multiplayerStateManager, ephemeralUserData, anchor, forceInit, ...props }: {
54
+ declare const StateInspector: React.MemoExoticComponent<(<S, M, E>({ state, connectionEvents, connectedUsers, tasks, userId, unstyled, colorScheme, multiplayerStateManager, assetManager, ephemeralUserData, anchor, forceInit, ...props }: {
55
55
  state: S;
56
56
  connectionEvents?: ConnectionEvent<S>[] | undefined;
57
57
  connectedUsers?: MultiplayerUser[] | undefined;
@@ -59,6 +59,7 @@ declare const StateInspector: React.MemoExoticComponent<(<S, M, E>({ state, conn
59
59
  userId?: string | undefined;
60
60
  unstyled?: boolean | undefined;
61
61
  multiplayerStateManager: MultiplayerStateManager<S, M>;
62
+ assetManager: AssetManager;
62
63
  ephemeralUserData: EphemeralUserData<E>;
63
64
  forceInit: () => void;
64
65
  } & StateInspectorOptions & Omit<React.DetailedHTMLProps<React.HTMLAttributes<HTMLDivElement>, HTMLDivElement>, "ref">) => React.JSX.Element | null)>;
@@ -76,7 +77,7 @@ declare function useEphemeralUserData<E>(ephemeralUserData: EphemeralUserData<E>
76
77
  currentUserId: string | undefined;
77
78
  };
78
79
  type UseMultiplayerStateOptions<S, M = void, E = void> = MultiplayerStateManagerOptions<S, M> & {
79
- sync?: (options: Pick<SyncAdapterOptions<S, M, E>, "ms" | "ephemeralUserData">) => void;
80
+ sync?: (options: Pick<SyncAdapterOptions<S, M, E>, "ms" | "ephemeralUserData" | "assetManager">) => void;
80
81
  trackConnectionEvents?: boolean;
81
82
  trackTasks?: boolean;
82
83
  inspector?: boolean | StateInspectorOptions;
@@ -88,6 +89,9 @@ declare function useMultiplayerState<S, M = void, E = void>(initialState: S | ((
88
89
  connectedUsers: MultiplayerUser[];
89
90
  ephemeralUserData: EphemeralUserData<E>;
90
91
  multiplayerStateManager: MultiplayerStateManager<S, M>;
92
+ assets: _noya_app_state_manager.Asset[];
93
+ createAsset: (options: Uint8Array | _noya_app_state_manager.CreateAssetOptions) => Promise<_noya_app_state_manager.Asset>;
94
+ deleteAsset: (id: string) => Promise<void>;
91
95
  }];
92
96
 
93
97
  type AppViewType = "editable" | "readOnly" | "preview";
@@ -131,10 +135,10 @@ type HostToIframeMessage = {
131
135
  declare function useBroadcastConnectedUsers(connectedUsers: MultiplayerUser[]): void;
132
136
  declare function useBroadcastMenuItems<T>(menuItems: any[], handleSelectMenuItem: (value: T) => void): void;
133
137
  declare function isEmbeddedApp(): boolean;
134
- type UseNoyaAppStateOptions<S, M = void, E = void> = UseMultiplayerStateOptions<S, M, E> & {
138
+ type UseNoyaStateOptions<S, M = void, E = void> = UseMultiplayerStateOptions<S, M, E> & {
135
139
  localStorageKey?: string;
136
140
  };
137
- type UseNoyaAppStateResult<S, M = void, E = void> = [
141
+ type UseNoyaStateResult<S, M = void, E = void> = [
138
142
  ReturnType<typeof useMultiplayerState<S, M, E>>[0],
139
143
  ReturnType<typeof useMultiplayerState<S, M, E>>[1],
140
144
  ReturnType<typeof useMultiplayerState<S, M, E>>[2] & {
@@ -147,18 +151,18 @@ type UseNoyaAppStateResult<S, M = void, E = void> = [
147
151
  *
148
152
  * There are 3 ways to use this hook:
149
153
  *
150
- * 1. Pass an initial state: `useNoyaAppState(initialState)`
151
- * 2. Pass an initial state and a schema: `useNoyaAppState(initialState, { schema })`
152
- * 3. Pass only a schema, and a conforming initial state is created automatically: `useNoyaAppState({ schema })`
154
+ * 1. Pass an initial state: `useNoyaState(initialState)`
155
+ * 2. Pass an initial state and a schema: `useNoyaState(initialState, { schema })`
156
+ * 3. Pass only a schema, and a conforming initial state is created automatically: `useNoyaState({ schema })`
153
157
  */
154
- declare function useNoyaAppState<S, M = void, E = void, O extends UseNoyaAppStateOptions<S, M, E> = UseNoyaAppStateOptions<S, M, E>>(...args: [
158
+ declare function useNoyaState<S, M = void, E = void, O extends UseNoyaStateOptions<S, M, E> = UseNoyaStateOptions<S, M, E>>(...args: [
155
159
  initialState: O["schema"] extends TSchema ? Static<O["schema"]> | (() => Static<O["schema"]>) : S | (() => S),
156
160
  options?: O
157
161
  ] | [options: O & {
158
162
  schema: TSchema;
159
- }]): UseNoyaAppStateResult<O["schema"] extends TSchema ? Static<O["schema"]> : S, M, E>;
163
+ }]): UseNoyaStateResult<O["schema"] extends TSchema ? Static<O["schema"]> : S, M, E>;
160
164
 
161
165
  declare function useObservable<T>(observable: Observable<T>): T;
162
166
  declare function useObservable<T, P extends PathKey[]>(observable: Observable<T>, path: P): GetWithPath<T, P>;
163
167
 
164
- export { type AppData, type AppTheme, type AppViewType, type GetAppDataOptions, type HostToIframeMessage, type IframeToHostMessage, StateInspector, type StateInspectorAnchor, type StateInspectorOptions, type UseMultiplayerStateOptions, type UseNoyaAppStateOptions, type UseNoyaAppStateResult, UserNameTag, UserPointer, UserPointerContainer, type UserPointerData, UserPointerIcon, type UserPointerProps, UserPointersOverlay, type UserPointersOverlayProps, createDefaultAppData, enforceSchema, getAppData, getAvatarInitials, getAvatarStyle, isEmbeddedApp, parseAppDataParameter, useBroadcastConnectedUsers, useBroadcastMenuItems, useEphemeralUserData, useManagedHistory, useManagedState, useMultiplayerState, useNoyaAppState, useObservable, useSyncMultiplayerStateManager, useSyncStateManager };
168
+ export { type AppData, type AppTheme, type AppViewType, type GetAppDataOptions, type HostToIframeMessage, type IframeToHostMessage, StateInspector, type StateInspectorAnchor, type StateInspectorOptions, type UseMultiplayerStateOptions, type UseNoyaStateOptions, type UseNoyaStateResult, UserNameTag, UserPointer, UserPointerContainer, type UserPointerData, UserPointerIcon, type UserPointerProps, UserPointersOverlay, type UserPointersOverlayProps, createDefaultAppData, enforceSchema, getAppData, getAvatarInitials, getAvatarStyle, isEmbeddedApp, parseAppDataParameter, useBroadcastConnectedUsers, useBroadcastMenuItems, useEphemeralUserData, useManagedHistory, useManagedState, useMultiplayerState, useNoyaState, useObservable, useSyncMultiplayerStateManager, useSyncStateManager };
package/dist/index.js CHANGED
@@ -50,7 +50,7 @@ __export(src_exports, {
50
50
  useManagedHistory: () => useManagedHistory,
51
51
  useManagedState: () => useManagedState,
52
52
  useMultiplayerState: () => useMultiplayerState,
53
- useNoyaAppState: () => useNoyaAppState,
53
+ useNoyaState: () => useNoyaState,
54
54
  useObservable: () => useObservable,
55
55
  useSyncMultiplayerStateManager: () => useSyncMultiplayerStateManager,
56
56
  useSyncStateManager: () => useSyncStateManager
@@ -554,6 +554,7 @@ var StateInspector = (0, import_react5.memo)(function StateInspector2({
554
554
  unstyled,
555
555
  colorScheme = "light",
556
556
  multiplayerStateManager,
557
+ assetManager,
557
558
  ephemeralUserData,
558
559
  anchor = "right",
559
560
  forceInit,
@@ -593,6 +594,10 @@ var StateInspector = (0, import_react5.memo)(function StateInspector2({
593
594
  "noya-multiplayer-react-show-ephemeral",
594
595
  false
595
596
  );
597
+ const [showAssets, setShowAssets] = useLocalStorageState(
598
+ "noya-multiplayer-react-show-assets",
599
+ false
600
+ );
596
601
  (0, import_react5.useEffect)(() => {
597
602
  shouldTrackEvents$.set(showEvents);
598
603
  }, [showEvents]);
@@ -606,6 +611,7 @@ var StateInspector = (0, import_react5.memo)(function StateInspector2({
606
611
  }, [connectionEvents]);
607
612
  const ephemeral = useEphemeralUserData(ephemeralUserData);
608
613
  const historySnapshot = useManagedHistory(multiplayerStateManager.sm);
614
+ const assets = useObservable(assetManager.assets$);
609
615
  (0, import_react5.useEffect)(() => {
610
616
  if (historyContainerRef.current) {
611
617
  historyContainerRef.current.scrollTop = historyContainerRef.current.scrollHeight;
@@ -921,6 +927,46 @@ var StateInspector = (0, import_react5.memo)(function StateInspector2({
921
927
  ))
922
928
  )))
923
929
  ),
930
+ /* @__PURE__ */ import_react5.default.createElement(
931
+ DisclosureSection,
932
+ {
933
+ open: showAssets,
934
+ setOpen: setShowAssets,
935
+ title: "Assets",
936
+ colorScheme,
937
+ right: /* @__PURE__ */ import_react5.default.createElement("span", { style: { display: "flex", gap: "4px" } }, /* @__PURE__ */ import_react5.default.createElement(
938
+ SmallButton,
939
+ {
940
+ theme,
941
+ onClick: () => {
942
+ const input = document.createElement("input");
943
+ input.type = "file";
944
+ input.onchange = () => {
945
+ const file = input.files?.[0];
946
+ if (file) {
947
+ const reader = new FileReader();
948
+ reader.onload = () => {
949
+ const buffer = reader.result;
950
+ assetManager.create(new Uint8Array(buffer));
951
+ };
952
+ reader.readAsArrayBuffer(file);
953
+ }
954
+ };
955
+ input.click();
956
+ }
957
+ },
958
+ "Upload"
959
+ ))
960
+ },
961
+ /* @__PURE__ */ import_react5.default.createElement("div", { style: styles.sectionInner }, assets.map((asset) => /* @__PURE__ */ import_react5.default.createElement(InspectorRow, { key: asset.id, colorScheme }, /* @__PURE__ */ import_react5.default.createElement(import_react_inspector.ObjectInspector, { name: asset.id, data: asset, theme }), /* @__PURE__ */ import_react5.default.createElement(
962
+ SmallButton,
963
+ {
964
+ theme,
965
+ onClick: () => assetManager.delete(asset.id)
966
+ },
967
+ "Delete"
968
+ ))))
969
+ ),
924
970
  /* @__PURE__ */ import_react5.default.createElement(
925
971
  DisclosureSection,
926
972
  {
@@ -1124,7 +1170,7 @@ function SmallButton({
1124
1170
  display: "inline-flex",
1125
1171
  alignItems: "center",
1126
1172
  justifyContent: "center",
1127
- padding: "2px 0",
1173
+ padding: "0",
1128
1174
  cursor: "pointer",
1129
1175
  ...style
1130
1176
  }
@@ -1134,10 +1180,13 @@ function SmallButton({
1134
1180
  }
1135
1181
 
1136
1182
  // src/inspector/useStateInspector.tsx
1137
- function createPortalElement() {
1138
- const el = document.createElement("div");
1139
- el.id = "noya-multiplayer-react-inspector-portal";
1140
- return el;
1183
+ function createShadowRootElement() {
1184
+ const host = document.createElement("div");
1185
+ host.id = "noya-multiplayer-react-inspector-host";
1186
+ const shadowRoot = host.attachShadow({ mode: "open" });
1187
+ const container = document.createElement("div");
1188
+ shadowRoot.appendChild(container);
1189
+ return { host, container };
1141
1190
  }
1142
1191
  function useStateInspector({
1143
1192
  state,
@@ -1149,6 +1198,7 @@ function useStateInspector({
1149
1198
  colorScheme,
1150
1199
  anchor,
1151
1200
  multiplayerStateManager,
1201
+ assetManager,
1152
1202
  ephemeralUserData,
1153
1203
  forceInit
1154
1204
  }) {
@@ -1156,12 +1206,12 @@ function useStateInspector({
1156
1206
  (0, import_react6.useLayoutEffect)(() => {
1157
1207
  if (disabled)
1158
1208
  return;
1159
- const portalElement = createPortalElement();
1160
- const root2 = (0, import_client.createRoot)(portalElement);
1161
- document.body.appendChild(portalElement);
1209
+ const { host, container } = createShadowRootElement();
1210
+ const root2 = (0, import_client.createRoot)(container);
1211
+ document.body.appendChild(host);
1162
1212
  setRoot(root2);
1163
1213
  return () => {
1164
- document.body.removeChild(portalElement);
1214
+ document.body.removeChild(host);
1165
1215
  };
1166
1216
  }, [disabled]);
1167
1217
  (0, import_react6.useLayoutEffect)(() => {
@@ -1180,6 +1230,7 @@ function useStateInspector({
1180
1230
  anchor,
1181
1231
  forceInit,
1182
1232
  multiplayerStateManager,
1233
+ assetManager,
1183
1234
  ephemeralUserData
1184
1235
  }
1185
1236
  )
@@ -1195,7 +1246,8 @@ function useStateInspector({
1195
1246
  userId,
1196
1247
  tasks,
1197
1248
  forceInit,
1198
- ephemeralUserData
1249
+ ephemeralUserData,
1250
+ assetManager
1199
1251
  ]);
1200
1252
  }
1201
1253
 
@@ -1310,6 +1362,7 @@ function useMultiplayerState(initialState, options) {
1310
1362
  const [multiplayerStateManager] = (0, import_react7.useState)(
1311
1363
  () => new import_state_manager.MultiplayerStateManager(initialState, rest)
1312
1364
  );
1365
+ const [assetManager] = (0, import_react7.useState)(() => new import_state_manager.AssetManager());
1313
1366
  const syncRef = (0, import_react7.useRef)(sync);
1314
1367
  const [connectionEvents, setConnectionEvents] = (0, import_react7.useState)();
1315
1368
  const [connectedUsers, setConnectedUsers] = (0, import_react7.useState)([]);
@@ -1318,6 +1371,7 @@ function useMultiplayerState(initialState, options) {
1318
1371
  );
1319
1372
  const [tasks, setTasks] = (0, import_react7.useState)([]);
1320
1373
  const [userId, setUserId] = (0, import_react7.useState)();
1374
+ const assets = useObservable(assetManager.assets$);
1321
1375
  const extras = (0, import_react7.useMemo)(() => {
1322
1376
  return {
1323
1377
  tasks,
@@ -1325,7 +1379,10 @@ function useMultiplayerState(initialState, options) {
1325
1379
  connectionEvents,
1326
1380
  connectedUsers,
1327
1381
  ephemeralUserData,
1328
- multiplayerStateManager
1382
+ multiplayerStateManager,
1383
+ assets,
1384
+ createAsset: assetManager.create,
1385
+ deleteAsset: assetManager.delete
1329
1386
  // evaluate: async (code: string) => {
1330
1387
  // const payload = await rpcManager.request({ type: "eval", code });
1331
1388
  // if (payload.type !== "eval") {
@@ -1339,7 +1396,9 @@ function useMultiplayerState(initialState, options) {
1339
1396
  connectionEvents,
1340
1397
  connectedUsers,
1341
1398
  ephemeralUserData,
1342
- multiplayerStateManager
1399
+ multiplayerStateManager,
1400
+ assetManager,
1401
+ assets
1343
1402
  ]);
1344
1403
  const globalTrackEvents = useObservable(shouldTrackEvents$);
1345
1404
  const globalTrackTasks = useObservable(shouldTrackTasks$);
@@ -1373,13 +1432,14 @@ function useMultiplayerState(initialState, options) {
1373
1432
  if (syncRef.current) {
1374
1433
  return syncRef.current({
1375
1434
  ms: multiplayerStateManager,
1435
+ assetManager,
1376
1436
  ephemeralUserData,
1377
1437
  onConnectionEvent: (e) => trackEventsCallbackRef.current?.(e),
1378
1438
  onChangeConnectedUsers: (users, userId2) => trackConnectedUsersCallbackRef.current?.(users, userId2),
1379
1439
  onChangeTasks: (tasks2) => trackTasksCallbackRef.current?.(tasks2)
1380
1440
  });
1381
1441
  }
1382
- }, [ephemeralUserData, multiplayerStateManager]);
1442
+ }, [assetManager, ephemeralUserData, multiplayerStateManager]);
1383
1443
  const state = useSyncMultiplayerStateManager(multiplayerStateManager);
1384
1444
  const forceInit = (0, import_react7.useCallback)(() => {
1385
1445
  const state2 = initialState instanceof Function ? initialState() : initialState;
@@ -1409,6 +1469,7 @@ function useMultiplayerState(initialState, options) {
1409
1469
  useStateInspector({
1410
1470
  ephemeralUserData,
1411
1471
  multiplayerStateManager,
1472
+ assetManager,
1412
1473
  state,
1413
1474
  connectionEvents,
1414
1475
  connectedUsers,
@@ -1498,7 +1559,7 @@ function useBroadcastMenuItems(menuItems, handleSelectMenuItem) {
1498
1559
  function isEmbeddedApp() {
1499
1560
  return window.self !== window.top;
1500
1561
  }
1501
- function useNoyaAppState(...args) {
1562
+ function useNoyaState(...args) {
1502
1563
  const [initialState, options] = typeof args[0] === "object" && args[0] !== null && "schema" in args[0] && import_state_manager2.TypeGuard.IsSchema(args[0].schema) ? [null, args[0]] : [args[0], args[1]];
1503
1564
  const [
1504
1565
  {
@@ -1549,7 +1610,7 @@ function useNoyaAppState(...args) {
1549
1610
  useManagedHistory,
1550
1611
  useManagedState,
1551
1612
  useMultiplayerState,
1552
- useNoyaAppState,
1613
+ useNoyaState,
1553
1614
  useObservable,
1554
1615
  useSyncMultiplayerStateManager,
1555
1616
  useSyncStateManager,