@noya-app/noya-multiplayer-react 0.1.65 → 0.1.67

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/dist/index.mjs CHANGED
@@ -3982,6 +3982,7 @@ var activityEventSchema = Type.Object({
3982
3982
  // ../noya-schemas/src/asset.ts
3983
3983
  var assetSchema = Type.Object({
3984
3984
  id: Type.String(),
3985
+ stableId: Type.String(),
3985
3986
  url: Type.String(),
3986
3987
  createdAt: Type.String(),
3987
3988
  size: Type.Number(),
@@ -4487,6 +4488,26 @@ var flatResourceSchema = Type.Object({
4487
4488
  fileId: Nullable(Type.String()),
4488
4489
  resourceId: Nullable(Type.String())
4489
4490
  });
4491
+ function getChangedResourceProperties({
4492
+ oldResource,
4493
+ newResource,
4494
+ oldPath,
4495
+ newPath
4496
+ }) {
4497
+ const changed = {};
4498
+ if (newPath !== void 0 && (oldPath ?? oldResource.path) !== newPath) {
4499
+ changed.path = newPath;
4500
+ }
4501
+ const oldAssetId = oldResource.type === "asset" ? oldResource.assetId : void 0;
4502
+ const newAssetId = newResource.type === "asset" ? newResource.assetId : void 0;
4503
+ if (oldAssetId !== newAssetId) {
4504
+ changed.assetId = newAssetId;
4505
+ }
4506
+ if (newResource.type === "asset" && newResource.asset !== void 0) {
4507
+ changed.asset = newResource.asset;
4508
+ }
4509
+ return changed;
4510
+ }
4490
4511
  function diffResourceMaps(resourceMap, newResourceMap, idProperty) {
4491
4512
  const oldIdToPathMap = new Map(
4492
4513
  Object.entries(resourceMap).map(([path2, entity]) => [
@@ -4513,7 +4534,7 @@ function diffResourceMaps(resourceMap, newResourceMap, idProperty) {
4513
4534
  const removedResources = Object.values(resourceMap).filter(
4514
4535
  (entity) => !newIds.has(entity[idProperty])
4515
4536
  );
4516
- const modifiedResources = [...sameIds].flatMap((id) => {
4537
+ const sameIdModifiedResources = [...sameIds].flatMap((id) => {
4517
4538
  const oldResource = Object.values(resourceMap).find(
4518
4539
  (resource) => resource[idProperty] === id
4519
4540
  );
@@ -4523,17 +4544,54 @@ function diffResourceMaps(resourceMap, newResourceMap, idProperty) {
4523
4544
  if (!oldResource || !newResource) return [];
4524
4545
  const oldPath = oldIdToPathMap.get(id);
4525
4546
  const newPath = newIdToPathMap.get(id);
4526
- const oldAssetId = oldResource.type === "asset" ? oldResource.assetId : void 0;
4527
- const newAssetId = newResource.type === "asset" ? newResource.assetId : void 0;
4528
- const changedProperties = {
4529
- ...oldPath !== newPath ? { path: newPath } : {},
4530
- ...oldAssetId !== newAssetId ? { assetId: newAssetId } : {},
4531
- ...newResource.type === "asset" && newResource.asset !== void 0 ? { asset: newResource.asset } : {}
4532
- };
4547
+ const changedProperties = getChangedResourceProperties({
4548
+ oldResource,
4549
+ newResource,
4550
+ oldPath,
4551
+ newPath
4552
+ });
4533
4553
  if (Object.keys(changedProperties).length === 0) return [];
4534
4554
  return [{ id, stableId: newResource.stableId, ...changedProperties }];
4535
4555
  });
4536
- return { addedResources, removedResources, modifiedResources };
4556
+ const removedResourcesByPath = new Map(
4557
+ removedResources.map((resource) => [resource.path, resource])
4558
+ );
4559
+ const swappedPaths = /* @__PURE__ */ new Set();
4560
+ const swappedModifiedResources = [];
4561
+ for (const addedResource of addedResources) {
4562
+ const existingResource = removedResourcesByPath.get(addedResource.path);
4563
+ if (!existingResource) continue;
4564
+ if (existingResource.type !== addedResource.type) continue;
4565
+ if (existingResource[idProperty] === addedResource[idProperty]) continue;
4566
+ swappedPaths.add(addedResource.path);
4567
+ const changedProperties = getChangedResourceProperties({
4568
+ oldResource: existingResource,
4569
+ newResource: addedResource,
4570
+ oldPath: existingResource.path,
4571
+ newPath: addedResource.path
4572
+ });
4573
+ if (Object.keys(changedProperties).length === 0) continue;
4574
+ const id = existingResource[idProperty];
4575
+ swappedModifiedResources.push({
4576
+ id,
4577
+ stableId: existingResource.stableId,
4578
+ ...changedProperties
4579
+ });
4580
+ }
4581
+ const filteredAddedResources = addedResources.filter(
4582
+ (resource) => !swappedPaths.has(resource.path)
4583
+ );
4584
+ const filteredRemovedResources = removedResources.filter(
4585
+ (resource) => !swappedPaths.has(resource.path)
4586
+ );
4587
+ return {
4588
+ addedResources: filteredAddedResources,
4589
+ removedResources: filteredRemovedResources,
4590
+ modifiedResources: [
4591
+ ...sameIdModifiedResources,
4592
+ ...swappedModifiedResources
4593
+ ]
4594
+ };
4537
4595
  }
4538
4596
 
4539
4597
  // ../noya-schemas/src/resourceTree.ts
@@ -4554,7 +4612,7 @@ import {
4554
4612
  Observable
4555
4613
  } from "@noya-app/observable";
4556
4614
  import { useJsonMemo, useStableCallback } from "@noya-app/react-utils";
4557
- import React16, {
4615
+ import React17, {
4558
4616
  createContext,
4559
4617
  useCallback as useCallback3,
4560
4618
  useContext,
@@ -4568,6 +4626,7 @@ import {
4568
4626
  createOrCastValue,
4569
4627
  isEmbeddedApp,
4570
4628
  localStorageSync,
4629
+ NoyaManager as NoyaManager3,
4571
4630
  parentFrameSync,
4572
4631
  stubSync as stubSync2,
4573
4632
  TypeGuard,
@@ -4714,6 +4773,26 @@ var FILE_TYPE_TO_EXTENSION = {
4714
4773
  };
4715
4774
  var FILE_EXTENSION_TO_TYPE = invert(FILE_TYPE_TO_EXTENSION);
4716
4775
 
4776
+ // ../noya-utils/src/memoize.ts
4777
+ function memoize(f) {
4778
+ const intermediateCache = /* @__PURE__ */ new Map();
4779
+ const cache = /* @__PURE__ */ new Map();
4780
+ let intermediateCacheIndex = 0;
4781
+ return (...values) => {
4782
+ let key = "";
4783
+ for (const value of values) {
4784
+ if (!intermediateCache.has(value)) {
4785
+ intermediateCache.set(value, `${intermediateCacheIndex++}`);
4786
+ }
4787
+ key += intermediateCache.get(value) + ":";
4788
+ }
4789
+ if (!cache.has(key)) {
4790
+ cache.set(key, f(...values));
4791
+ }
4792
+ return cache.get(key);
4793
+ };
4794
+ }
4795
+
4717
4796
  // ../noya-utils/src/memoizeDeep.ts
4718
4797
  var TOKEN_OBJECT = Symbol("object");
4719
4798
  var TOKEN_ARRAY = Symbol("array");
@@ -5940,19 +6019,17 @@ async function importAll(buffer, noyaManager, {
5940
6019
  }
5941
6020
  if (assets.length) {
5942
6021
  await Promise.all(
5943
- noyaManager.assetManager.assets$.get().map((asset) => noyaManager.assetManager.delete(asset.id))
6022
+ noyaManager.assetManager.assets$.get().map((asset) => noyaManager.assetManager.delete(asset.stableId))
5944
6023
  );
5945
- const idPairs = await Promise.all(
6024
+ await Promise.all(
5946
6025
  assets.map(async (asset) => {
5947
- const newAsset = await noyaManager.assetManager.create({
6026
+ await noyaManager.assetManager.create({
5948
6027
  data: assetMap[asset.id],
5949
- contentType: asset.contentType
6028
+ contentType: asset.contentType,
6029
+ stableId: asset.stableId
5950
6030
  });
5951
- return [asset.id, newAsset.id];
5952
6031
  })
5953
6032
  );
5954
- const replacementMap = Object.fromEntries(idPairs);
5955
- state = replaceDeep(state, replacementMap);
5956
6033
  }
5957
6034
  noyaManager.initialState = state;
5958
6035
  noyaManager.forceInit();
@@ -6468,7 +6545,14 @@ var StateInspector = memoGeneric(function StateInspector2({
6468
6545
  "Upload"
6469
6546
  ))
6470
6547
  },
6471
- /* @__PURE__ */ React14.createElement(StateInspectorDisclosureRowInner, null, assets.map((asset) => /* @__PURE__ */ React14.createElement(StateInspectorRow, { key: asset.id, colorScheme }, /* @__PURE__ */ React14.createElement(ObjectInspector4, { name: asset.id, data: asset, theme }), /* @__PURE__ */ React14.createElement(
6548
+ /* @__PURE__ */ React14.createElement(StateInspectorDisclosureRowInner, null, assets.map((asset) => /* @__PURE__ */ React14.createElement(StateInspectorRow, { key: asset.id, colorScheme }, /* @__PURE__ */ React14.createElement(
6549
+ ObjectInspector4,
6550
+ {
6551
+ name: asset.id,
6552
+ data: truncateAsset(asset),
6553
+ theme
6554
+ }
6555
+ ), /* @__PURE__ */ React14.createElement(
6472
6556
  StateInspectorButton,
6473
6557
  {
6474
6558
  theme,
@@ -6493,10 +6577,8 @@ var StateInspector = memoGeneric(function StateInspector2({
6493
6577
  "Are you sure you want to delete all resources?"
6494
6578
  );
6495
6579
  if (!ok) return;
6496
- await Promise.all(
6497
- resources.map(
6498
- (resource) => resourceManager.deleteResource({ id: resource.id })
6499
- )
6580
+ await resourceManager.deleteResource(
6581
+ resources.map((resource) => ({ id: resource.id }))
6500
6582
  );
6501
6583
  }
6502
6584
  },
@@ -6709,6 +6791,12 @@ var StateInspector = memoGeneric(function StateInspector2({
6709
6791
  )
6710
6792
  );
6711
6793
  });
6794
+ var truncateAsset = memoize((asset) => {
6795
+ if (asset.url.startsWith("data:") || asset.url.startsWith("blob:")) {
6796
+ return { ...asset, url: ellipsis(asset.url, 40) };
6797
+ }
6798
+ return asset;
6799
+ });
6712
6800
 
6713
6801
  // src/inspector/useStateInspector.tsx
6714
6802
  function createShadowRootElement() {
@@ -6719,6 +6807,17 @@ function createShadowRootElement() {
6719
6807
  shadowRoot.appendChild(container);
6720
6808
  return { host, container };
6721
6809
  }
6810
+ function createStateInspectorRoot() {
6811
+ const { host, container } = createShadowRootElement();
6812
+ const root = createRoot(container);
6813
+ document.body.appendChild(host);
6814
+ return {
6815
+ root,
6816
+ unmount: () => {
6817
+ document.body.removeChild(host);
6818
+ }
6819
+ };
6820
+ }
6722
6821
  function useStateInspector({
6723
6822
  noyaManager,
6724
6823
  disabled = false,
@@ -6728,13 +6827,9 @@ function useStateInspector({
6728
6827
  const [root, setRoot] = React15.useState(null);
6729
6828
  useIsomorphicLayoutEffect(() => {
6730
6829
  if (disabled) return;
6731
- const { host, container } = createShadowRootElement();
6732
- const root2 = createRoot(container);
6733
- document.body.appendChild(host);
6830
+ const { root: root2, unmount } = createStateInspectorRoot();
6734
6831
  setRoot(root2);
6735
- return () => {
6736
- document.body.removeChild(host);
6737
- };
6832
+ return unmount;
6738
6833
  }, [disabled]);
6739
6834
  useIsomorphicLayoutEffect(() => {
6740
6835
  if (!root) return;
@@ -6752,22 +6847,18 @@ function useStateInspector({
6752
6847
  }
6753
6848
 
6754
6849
  // src/hooks.ts
6755
- function useSyncStateManager(stateManager, path2) {
6756
- const getSnapshot = useCallback2(
6757
- () => typeof path2 === "string" ? stateManager.getState(path2) : stateManager.getState(),
6758
- [stateManager, path2]
6850
+ function useManagedState(createInitialState, options) {
6851
+ const [stateManager] = useState2(
6852
+ () => new StateManager(createInitialState(), options)
6759
6853
  );
6760
- return useSyncExternalStore2(
6854
+ const getSnapshot = useCallback2(() => {
6855
+ return stateManager.getState();
6856
+ }, [stateManager]);
6857
+ const state = useSyncExternalStore2(
6761
6858
  stateManager.addListener,
6762
6859
  getSnapshot,
6763
6860
  getSnapshot
6764
6861
  );
6765
- }
6766
- function useManagedState(createInitialState, options) {
6767
- const [stateManager] = useState2(
6768
- () => new StateManager(createInitialState(), options)
6769
- );
6770
- const state = useSyncStateManager(stateManager);
6771
6862
  const setState = useCallback2(
6772
6863
  (...args) => {
6773
6864
  const [metadata, action] = args.length === 1 ? [void 0, args[0]] : args;
@@ -6810,15 +6901,7 @@ function useManagedHistory(stateManager) {
6810
6901
  stateManager.getHistorySnapshot
6811
6902
  );
6812
6903
  }
6813
- function useMultiplayerState(initialState, options) {
6814
- const {
6815
- sync = stubSync(),
6816
- inspector,
6817
- ...rest
6818
- } = options ?? {};
6819
- const [noyaManager] = useState2(
6820
- () => new NoyaManager2(initialState, rest)
6821
- );
6904
+ function useBindNoyaManager(noyaManager, options) {
6822
6905
  const state = useObservable(
6823
6906
  noyaManager.multiplayerStateManager.optimisticState$
6824
6907
  );
@@ -6842,7 +6925,7 @@ function useMultiplayerState(initialState, options) {
6842
6925
  assets
6843
6926
  };
6844
6927
  }, [noyaManager, assets]);
6845
- const syncRef = useRef2(sync);
6928
+ const syncRef = useRef2(options?.sync);
6846
6929
  useEffect3(() => {
6847
6930
  if (syncRef.current) {
6848
6931
  return syncRef.current({ noyaManager });
@@ -6851,11 +6934,22 @@ function useMultiplayerState(initialState, options) {
6851
6934
  useErrorOverlay(noyaManager);
6852
6935
  useStateInspector({
6853
6936
  noyaManager,
6854
- disabled: !inspector,
6855
- ...typeof inspector === "object" && inspector
6937
+ disabled: !options?.inspector,
6938
+ ...typeof options?.inspector === "object" && options?.inspector
6856
6939
  });
6857
6940
  return [state, noyaManager.multiplayerStateManager.setState, extras];
6858
6941
  }
6942
+ function useMultiplayerState(initialState, options) {
6943
+ const {
6944
+ sync = stubSync(),
6945
+ inspector,
6946
+ ...rest
6947
+ } = options ?? {};
6948
+ const [noyaManager] = useState2(
6949
+ () => new NoyaManager2(initialState, rest)
6950
+ );
6951
+ return useBindNoyaManager(noyaManager, { sync, inspector });
6952
+ }
6859
6953
  function useErrorOverlay(noyaManager) {
6860
6954
  const unrecoverableError = useObservable(noyaManager.unrecoverableError);
6861
6955
  useEffect3(() => {
@@ -6911,7 +7005,11 @@ function getAppData(initialState, schema, options) {
6911
7005
  appData.initialState = enforceSchema(appData.initialState, schema);
6912
7006
  return appData;
6913
7007
  }
6914
- function useNoyaState(...args) {
7008
+ function getSyncAdapter(params) {
7009
+ const { multiplayerUrl, offlineStorageKey, debug } = params ?? {};
7010
+ return isEmbeddedApp() ? parentFrameSync({ debug }) : multiplayerUrl ? webSocketSync({ url: multiplayerUrl, debug }) : offlineStorageKey ? localStorageSync({ key: offlineStorageKey }) : stubSync2();
7011
+ }
7012
+ function useNoyaStateInternal(...args) {
6915
7013
  const [initialState, options] = typeof args[0] === "object" && args[0] !== null && "schema" in args[0] && TypeGuard.IsSchema(args[0].schema) ? [null, args[0]] : [args[0], args[1]];
6916
7014
  const [
6917
7015
  {
@@ -6927,13 +7025,16 @@ function useNoyaState(...args) {
6927
7025
  });
6928
7026
  });
6929
7027
  const sync = useMemo3(() => {
6930
- return isEmbeddedApp() ? parentFrameSync({ debug: options?.debug }) : multiplayerUrl ? webSocketSync({
6931
- url: multiplayerUrl,
7028
+ return getSyncAdapter({
7029
+ multiplayerUrl,
7030
+ offlineStorageKey: options?.offlineStorageKey,
6932
7031
  debug: options?.debug
6933
- }) : options?.offlineStorageKey ? localStorageSync({ key: options.offlineStorageKey }) : stubSync2();
7032
+ });
6934
7033
  }, [multiplayerUrl, options?.offlineStorageKey, options?.debug]);
6935
- const result = useMultiplayerState(noyaAppInitialState, {
6936
- ...options,
7034
+ const [noyaManager] = useState3(
7035
+ () => new NoyaManager3(noyaAppInitialState, options)
7036
+ );
7037
+ const result = useBindNoyaManager(noyaManager, {
6937
7038
  inspector: options?.inspector ?? inspector,
6938
7039
  sync: options?.sync ?? sync
6939
7040
  });
@@ -6944,11 +7045,166 @@ function useNoyaState(...args) {
6944
7045
  return [result[0], result[1], mergedExtras];
6945
7046
  }
6946
7047
 
7048
+ // src/singleton.tsx
7049
+ import {
7050
+ NoyaManager as NoyaManager4
7051
+ } from "@noya-app/state-manager";
7052
+ import React16 from "react";
7053
+ var noyaManagerSingleton;
7054
+ var noyaSingletonBindings;
7055
+ function initializeNoyaSingleton(options) {
7056
+ if (noyaManagerSingleton) {
7057
+ throw new Error(
7058
+ "Noya has already been initialized. Call `useNoyaState` instead."
7059
+ );
7060
+ }
7061
+ const {
7062
+ initialState,
7063
+ sync,
7064
+ inspector,
7065
+ theme,
7066
+ viewType,
7067
+ offlineStorageKey,
7068
+ multiplayerUrl,
7069
+ ...managerOptions
7070
+ } = options ?? {};
7071
+ const appData = getAppData(
7072
+ initialState ?? null,
7073
+ managerOptions?.schema,
7074
+ { overrideExistingState: managerOptions?.overrideExistingState }
7075
+ );
7076
+ noyaManagerSingleton = new NoyaManager4(
7077
+ appData.initialState,
7078
+ managerOptions
7079
+ );
7080
+ const resolvedSync = sync ?? getSyncAdapter({
7081
+ multiplayerUrl: multiplayerUrl ?? appData.multiplayerUrl,
7082
+ offlineStorageKey,
7083
+ debug: managerOptions?.debug
7084
+ });
7085
+ try {
7086
+ resolvedSync({ noyaManager: noyaManagerSingleton });
7087
+ } catch (error) {
7088
+ console.warn("Failed to activate sync", error);
7089
+ }
7090
+ const resolvedInspector = inspector ?? appData.inspector;
7091
+ const resolvedTheme = theme ?? appData.theme ?? "light";
7092
+ const resolvedViewType = viewType ?? appData.viewType ?? "editable";
7093
+ if (resolvedInspector) {
7094
+ const { root } = createStateInspectorRoot();
7095
+ root.render(
7096
+ /* @__PURE__ */ React16.createElement(
7097
+ StateInspector,
7098
+ {
7099
+ noyaManager: noyaManagerSingleton,
7100
+ colorScheme: resolvedInspector === true ? resolvedTheme : resolvedInspector.colorScheme,
7101
+ anchor: resolvedInspector === true ? "bottom right" : resolvedInspector.anchor
7102
+ }
7103
+ )
7104
+ );
7105
+ }
7106
+ noyaSingletonBindings = {
7107
+ sync: resolvedSync,
7108
+ inspector: resolvedInspector,
7109
+ theme: resolvedTheme,
7110
+ viewType: resolvedViewType
7111
+ };
7112
+ }
7113
+ function getNoyaManagerSingleton() {
7114
+ if (!noyaManagerSingleton || !noyaSingletonBindings) {
7115
+ throw new Error(
7116
+ "Noya has not been initialized. Call initializeNoya once before using Noya hooks."
7117
+ );
7118
+ }
7119
+ return noyaManagerSingleton;
7120
+ }
7121
+ function getNoyaSingletonBindings() {
7122
+ return noyaSingletonBindings;
7123
+ }
7124
+ function deleteNoyaSingleton() {
7125
+ noyaManagerSingleton = void 0;
7126
+ noyaSingletonBindings = void 0;
7127
+ }
7128
+
6947
7129
  // src/NoyaStateContext.tsx
7130
+ function resourceToCreateParameters(resource) {
7131
+ switch (resource.type) {
7132
+ case "directory":
7133
+ return {
7134
+ path: resource.path,
7135
+ type: "directory"
7136
+ };
7137
+ case "asset":
7138
+ return {
7139
+ path: resource.path,
7140
+ type: "asset",
7141
+ assetId: resource.assetId,
7142
+ asset: resource.asset
7143
+ };
7144
+ case "file":
7145
+ return {
7146
+ path: resource.path,
7147
+ type: "file",
7148
+ fileId: resource.fileId
7149
+ };
7150
+ case "resource":
7151
+ return {
7152
+ path: resource.path,
7153
+ type: "resource",
7154
+ fileId: resource.fileId,
7155
+ resourceId: resource.resourceId
7156
+ };
7157
+ default:
7158
+ throw new Error(`Unknown resource type: ${resource.type}`);
7159
+ }
7160
+ }
7161
+ function buildCreateResourcePayload({
7162
+ addedResources,
7163
+ modifiedResources,
7164
+ newResourceMap,
7165
+ resourceMap
7166
+ }) {
7167
+ const toCreateParameters = resourceToCreateParameters;
7168
+ const resourcesById = new Map(
7169
+ Object.values(resourceMap).map((resource) => [resource.id, resource])
7170
+ );
7171
+ const payload = [
7172
+ ...addedResources.map(toCreateParameters)
7173
+ ];
7174
+ const handledModifiedResourceIds = [];
7175
+ const assetReplacements = modifiedResources.filter(
7176
+ (resource) => resource.assetId !== void 0 || resource.asset !== void 0
7177
+ ).map((resource) => {
7178
+ const previousResource = resourcesById.get(resource.id);
7179
+ const path2 = resource.path ?? previousResource?.path;
7180
+ if (!path2) return void 0;
7181
+ const updated = newResourceMap[path2];
7182
+ if (!updated || updated.type !== "asset") return void 0;
7183
+ handledModifiedResourceIds.push(resource.id);
7184
+ return toCreateParameters(updated);
7185
+ }).filter(
7186
+ (resource) => resource !== void 0
7187
+ );
7188
+ const deduped = new Map(
7189
+ [...payload, ...assetReplacements].map((item) => [item.path, item])
7190
+ );
7191
+ return {
7192
+ payload: Array.from(deduped.values()),
7193
+ consumedModifiedResourceIds: [...new Set(handledModifiedResourceIds)]
7194
+ };
7195
+ }
6948
7196
  var AnyNoyaStateContext = createContext(void 0);
6949
7197
  function useAnyNoyaStateContext() {
6950
7198
  const value = useContext(AnyNoyaStateContext);
6951
7199
  if (!value) {
7200
+ const bindings = getNoyaSingletonBindings();
7201
+ if (bindings) {
7202
+ return {
7203
+ noyaManager: getNoyaManagerSingleton(),
7204
+ theme: bindings.theme,
7205
+ viewType: bindings.viewType
7206
+ };
7207
+ }
6952
7208
  throw new Error(
6953
7209
  "useNoyaStateContext must be used within a NoyaStateProvider"
6954
7210
  );
@@ -6975,7 +7231,7 @@ function useAsset(id) {
6975
7231
  const { noyaManager } = useAnyNoyaStateContext();
6976
7232
  const observable = useMemo4(
6977
7233
  () => noyaManager.assetManager.assets$.map(
6978
- (assets) => assets.find((a) => a.id === id)
7234
+ (assets) => assets.find((a) => a.stableId === id) ?? assets.find((a) => a.id === id)
6979
7235
  ),
6980
7236
  [noyaManager, id]
6981
7237
  );
@@ -7055,9 +7311,9 @@ function usePipelineManager() {
7055
7311
  const { noyaManager } = useAnyNoyaStateContext();
7056
7312
  return noyaManager.pipelineManager;
7057
7313
  }
7058
- var ConnectedUsersContext = createContext(void 0);
7059
7314
  function useConnectedUsersManager() {
7060
- return useContext(ConnectedUsersContext);
7315
+ const { noyaManager } = useAnyNoyaStateContext();
7316
+ return noyaManager.connectedUsersManager;
7061
7317
  }
7062
7318
  function useConnectedUsers() {
7063
7319
  const connectedUsersManager = useConnectedUsersManager();
@@ -7078,9 +7334,9 @@ function useConnectedUser(userId) {
7078
7334
  )
7079
7335
  );
7080
7336
  }
7081
- var AnyEphemeralUserDataManagerContext = createContext(void 0);
7082
7337
  function useAnyEphemeralUserData() {
7083
- return useContext(AnyEphemeralUserDataManagerContext);
7338
+ const { noyaManager } = useAnyNoyaStateContext();
7339
+ return noyaManager.ephemeralUserDataManager;
7084
7340
  }
7085
7341
  function useCurrentUserId() {
7086
7342
  const connectedUsersManager = useConnectedUsersManager();
@@ -7090,6 +7346,19 @@ function useIsProcessing() {
7090
7346
  const { noyaManager } = useAnyNoyaStateContext();
7091
7347
  return useObservable(noyaManager.isProcessing$);
7092
7348
  }
7349
+ function useFileName() {
7350
+ const { noyaManager } = useAnyNoyaStateContext();
7351
+ return useObservable(noyaManager.filePropertyManager.optimisticValue$);
7352
+ }
7353
+ function useFilePropertyManager() {
7354
+ const { noyaManager } = useAnyNoyaStateContext();
7355
+ return noyaManager.filePropertyManager;
7356
+ }
7357
+ function useSetFileNameState() {
7358
+ const fileName = useFileName();
7359
+ const filePropertyManager = useFilePropertyManager();
7360
+ return [fileName, filePropertyManager.updateName];
7361
+ }
7093
7362
  function useResourceManager() {
7094
7363
  const { noyaManager } = useAnyNoyaStateContext();
7095
7364
  return noyaManager.resourceManager;
@@ -7121,59 +7390,38 @@ function useResources({
7121
7390
  async (action) => {
7122
7391
  const newResourceMap = action instanceof Function ? action(resourceMap) : action;
7123
7392
  const { addedResources, removedResources, modifiedResources } = diffResourceMaps(resourceMap, newResourceMap, "id");
7124
- if (addedResources.length > 0) {
7125
- const payload = addedResources.map((resource) => {
7126
- switch (resource.type) {
7127
- case "directory":
7128
- return {
7129
- path: resource.path,
7130
- type: "directory"
7131
- };
7132
- case "asset":
7133
- return {
7134
- path: resource.path,
7135
- type: "asset",
7136
- assetId: resource.assetId,
7137
- asset: resource.asset
7138
- };
7139
- case "file":
7140
- return {
7141
- path: resource.path,
7142
- type: "file",
7143
- fileId: resource.fileId
7144
- };
7145
- case "resource":
7146
- return {
7147
- path: resource.path,
7148
- type: "resource",
7149
- fileId: resource.fileId,
7150
- resourceId: resource.resourceId
7151
- };
7152
- default:
7153
- throw new Error(
7154
- `Unknown resource type: ${resource.type}`
7155
- );
7156
- }
7157
- });
7158
- await resourceManager.createResource(payload);
7393
+ const { payload: createPayload, consumedModifiedResourceIds } = buildCreateResourcePayload({
7394
+ addedResources,
7395
+ modifiedResources,
7396
+ newResourceMap,
7397
+ resourceMap
7398
+ });
7399
+ if (createPayload.length > 0) {
7400
+ await resourceManager.createResource(createPayload);
7159
7401
  }
7160
- for (const resource of removedResources) {
7161
- await resourceManager.deleteResource({ id: resource.id });
7162
- if (shouldDeleteAssets && resource.type === "asset") {
7163
- try {
7402
+ const consumedModifiedResourceIdsSet = new Set(
7403
+ consumedModifiedResourceIds
7404
+ );
7405
+ const remainingModifiedResources = modifiedResources.filter(
7406
+ (resource) => !consumedModifiedResourceIdsSet.has(resource.id)
7407
+ );
7408
+ await resourceManager.deleteResource(
7409
+ removedResources.map((resource) => ({ id: resource.id }))
7410
+ );
7411
+ if (shouldDeleteAssets) {
7412
+ for (const resource of removedResources) {
7413
+ if (resource.type === "asset") {
7164
7414
  await assetManager.delete(resource.assetId);
7165
- } catch (error) {
7166
- console.error("Failed to delete asset:", error);
7167
7415
  }
7168
7416
  }
7169
7417
  }
7170
7418
  await Promise.all(
7171
- modifiedResources.map(
7419
+ remainingModifiedResources.map(
7172
7420
  ({ id, path: path2, assetId, asset }) => resourceManager.updateResource({
7173
7421
  id,
7174
7422
  path: path2,
7175
7423
  assetId,
7176
- asset
7424
+ ...assetId ? {} : asset ? { asset } : {}
7177
7425
  })
7178
7426
  )
7179
7427
  );
@@ -7220,41 +7468,25 @@ function createNoyaContext({
7220
7468
  safeEval
7221
7469
  }) {
7222
7470
  const NoyaStateContext = AnyNoyaStateContext;
7223
- const EphemeralUserDataManagerContext = AnyEphemeralUserDataManagerContext;
7224
7471
  function NoyaContextProvider({
7225
7472
  children,
7226
7473
  contextValue
7227
7474
  }) {
7228
- return /* @__PURE__ */ React16.createElement(AnyNoyaStateContext.Provider, { value: contextValue }, /* @__PURE__ */ React16.createElement(
7229
- ConnectedUsersContext.Provider,
7230
- {
7231
- value: contextValue.noyaManager.connectedUsersManager
7232
- },
7233
- /* @__PURE__ */ React16.createElement(
7234
- EphemeralUserDataManagerContext.Provider,
7235
- {
7236
- value: contextValue.noyaManager.ephemeralUserDataManager
7237
- },
7238
- children
7239
- )
7240
- ));
7475
+ return /* @__PURE__ */ React17.createElement(AnyNoyaStateContext.Provider, { value: contextValue }, children);
7241
7476
  }
7242
7477
  function NoyaStateProvider({
7243
7478
  children,
7244
7479
  initialState,
7245
7480
  ...options
7246
7481
  }) {
7247
- const [, , { noyaManager, theme, viewType }] = useNoyaState(
7248
- initialState,
7249
- {
7250
- schema,
7251
- mergeHistoryEntries,
7252
- outputTransforms,
7253
- inputs,
7254
- safeEval,
7255
- ...options
7256
- }
7257
- );
7482
+ const [, , { noyaManager, theme, viewType }] = useNoyaStateInternal(initialState, {
7483
+ schema,
7484
+ mergeHistoryEntries,
7485
+ outputTransforms,
7486
+ inputs,
7487
+ safeEval,
7488
+ ...options
7489
+ });
7258
7490
  const contextValue = useMemo4(
7259
7491
  () => ({
7260
7492
  noyaManager,
@@ -7263,7 +7495,7 @@ function createNoyaContext({
7263
7495
  }),
7264
7496
  [noyaManager, theme, viewType]
7265
7497
  );
7266
- return /* @__PURE__ */ React16.createElement(NoyaContextProvider, { contextValue }, options.fallback !== void 0 ? /* @__PURE__ */ React16.createElement(FallbackUntilInitialized, { fallback: options.fallback }, children) : children);
7498
+ return /* @__PURE__ */ React17.createElement(NoyaContextProvider, { contextValue }, options.fallback !== void 0 ? /* @__PURE__ */ React17.createElement(FallbackUntilInitialized, { fallback: options.fallback }, children) : children);
7267
7499
  }
7268
7500
  function useValue(path2, options) {
7269
7501
  const { noyaManager } = useAnyNoyaStateContext();
@@ -7305,13 +7537,8 @@ function createNoyaContext({
7305
7537
  return noyaManager.multiplayerStateManager;
7306
7538
  }
7307
7539
  function useEphemeralUserDataManager() {
7308
- const ephemeralUserData = useContext(EphemeralUserDataManagerContext);
7309
- if (!ephemeralUserData) {
7310
- throw new Error(
7311
- "useEphemeralUserData must be used within a NoyaStateProvider"
7312
- );
7313
- }
7314
- return ephemeralUserData;
7540
+ const { noyaManager } = useAnyNoyaStateContext();
7541
+ return noyaManager.ephemeralUserDataManager;
7315
7542
  }
7316
7543
  function useNoyaManager() {
7317
7544
  return useAnyNoyaStateContext().noyaManager;
@@ -7393,7 +7620,7 @@ function useCallableAITools() {
7393
7620
  // src/components/UserPointersOverlay.tsx
7394
7621
  import { Observable as Observable2 } from "@noya-app/observable";
7395
7622
  import { memoGeneric as memoGeneric2 } from "@noya-app/react-utils";
7396
- import React17, { useEffect as useEffect6, useMemo as useMemo5, useState as useState5 } from "react";
7623
+ import React18, { useEffect as useEffect6, useMemo as useMemo5, useState as useState5 } from "react";
7397
7624
  function shouldShow(hideAfter, updatedAt) {
7398
7625
  return !!updatedAt && Date.now() - updatedAt < hideAfter;
7399
7626
  }
@@ -7436,9 +7663,9 @@ var UserPointersOverlay = memoGeneric2(function UserPointers({
7436
7663
  }) {
7437
7664
  const currentUserId = useObservable(ephemeralUserDataManager.currentUserId$);
7438
7665
  const connectedUsers = useObservable(connectedUsersManager.connectedUsers$);
7439
- return /* @__PURE__ */ React17.createElement(React17.Fragment, null, connectedUsers.map((user) => {
7666
+ return /* @__PURE__ */ React18.createElement(React18.Fragment, null, connectedUsers.map((user) => {
7440
7667
  if (user.id === currentUserId) return null;
7441
- return /* @__PURE__ */ React17.createElement(
7668
+ return /* @__PURE__ */ React18.createElement(
7442
7669
  UserPointerInternal,
7443
7670
  {
7444
7671
  key: user.id,
@@ -7531,24 +7758,30 @@ var WebSocketConnection = class {
7531
7758
  }
7532
7759
  };
7533
7760
  export {
7534
- AnyEphemeralUserDataManagerContext,
7535
7761
  AnyNoyaStateContext,
7536
- ConnectedUsersContext,
7537
7762
  FallbackUntilInitialized,
7538
7763
  StateInspector,
7539
7764
  UserPointersOverlay,
7540
7765
  WebSocketConnection,
7766
+ buildCreateResourcePayload,
7541
7767
  createDefaultAppData,
7542
7768
  createNoyaContext,
7769
+ createStateInspectorRoot,
7543
7770
  decodeAll,
7771
+ deleteNoyaSingleton,
7544
7772
  encodeAll,
7545
7773
  enforceSchema,
7546
7774
  exportAll,
7547
7775
  fetchAssetMap,
7548
7776
  getAppData,
7777
+ getNoyaManagerSingleton,
7778
+ getNoyaSingletonBindings,
7779
+ getSyncAdapter,
7549
7780
  importAll,
7781
+ initializeNoyaSingleton,
7550
7782
  parseAppDataParameter,
7551
7783
  replaceDeep,
7784
+ resourceToCreateParameters,
7552
7785
  resourceToMediaItem,
7553
7786
  useAIManager,
7554
7787
  useActivityEvents,
@@ -7559,12 +7792,15 @@ export {
7559
7792
  useAsset,
7560
7793
  useAssetManager,
7561
7794
  useAssets,
7795
+ useBindNoyaManager,
7562
7796
  useCallableAITools,
7563
7797
  useColorScheme,
7564
7798
  useConnectedUser,
7565
7799
  useConnectedUsers,
7566
7800
  useConnectedUsersManager,
7567
7801
  useCurrentUserId,
7802
+ useFileName,
7803
+ useFilePropertyManager,
7568
7804
  useIOManager,
7569
7805
  useInputs,
7570
7806
  useIsInitialized,
@@ -7572,7 +7808,7 @@ export {
7572
7808
  useManagedHistory,
7573
7809
  useManagedState,
7574
7810
  useMultiplayerState,
7575
- useNoyaState,
7811
+ useNoyaStateInternal,
7576
7812
  useObservable,
7577
7813
  useOutputTransforms,
7578
7814
  usePipelineManager,
@@ -7583,8 +7819,8 @@ export {
7583
7819
  useSecret,
7584
7820
  useSecretManager,
7585
7821
  useSecrets,
7822
+ useSetFileNameState,
7586
7823
  useStateInspector,
7587
- useSyncStateManager,
7588
7824
  useViewType
7589
7825
  };
7590
7826
  //# sourceMappingURL=index.mjs.map