@noya-app/noya-multiplayer-react 0.1.42 → 0.1.44

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/dist/index.js CHANGED
@@ -31,94 +31,70 @@ var __toCommonJS = (mod) => __copyProps(__defProp({}, "__esModule", { value: tru
31
31
  // src/index.ts
32
32
  var src_exports = {};
33
33
  __export(src_exports, {
34
+ AnyEphemeralUserDataManagerContext: () => AnyEphemeralUserDataManagerContext,
35
+ ConnectedUsersContext: () => ConnectedUsersContext,
36
+ FallbackUntilInitialized: () => FallbackUntilInitialized,
34
37
  StateInspector: () => StateInspector,
35
- UserNameTag: () => UserNameTag,
36
- UserPointer: () => UserPointer2,
37
- UserPointerContainer: () => UserPointerContainer,
38
- UserPointerIcon: () => UserPointerIcon,
39
38
  UserPointersOverlay: () => UserPointersOverlay,
40
39
  createDefaultAppData: () => createDefaultAppData,
41
40
  createNoyaContext: () => createNoyaContext,
42
41
  enforceSchema: () => enforceSchema,
43
42
  getAppData: () => getAppData,
44
- getAvatarInitials: () => getAvatarInitials,
45
- getAvatarStyle: () => getAvatarStyle,
46
43
  isEmbeddedApp: () => isEmbeddedApp,
47
44
  parseAppDataParameter: () => parseAppDataParameter,
45
+ useAIManager: () => useAIManager,
46
+ useAnyEphemeralUserData: () => useAnyEphemeralUserData,
48
47
  useAsset: () => useAsset,
49
48
  useAssetManager: () => useAssetManager,
50
49
  useAssets: () => useAssets,
51
50
  useBroadcastConnectedUsers: () => useBroadcastConnectedUsers,
52
51
  useBroadcastMenuItems: () => useBroadcastMenuItems,
53
- useEphemeralUserData: () => useEphemeralUserData,
52
+ useConnectedUsersManager: () => useConnectedUsersManager,
53
+ useCurrentUserId: () => useCurrentUserId,
54
+ useIsInitialized: () => useIsInitialized,
54
55
  useManagedHistory: () => useManagedHistory,
55
56
  useManagedState: () => useManagedState,
56
57
  useMultiplayerState: () => useMultiplayerState,
57
58
  useNoyaState: () => useNoyaState,
58
59
  useObservable: () => useObservable,
60
+ useSecret: () => useSecret,
61
+ useSecretManager: () => useSecretManager,
62
+ useSecrets: () => useSecrets,
59
63
  useSyncMultiplayerStateManager: () => useSyncMultiplayerStateManager,
60
- useSyncStateManager: () => useSyncStateManager
64
+ useSyncStateManager: () => useSyncStateManager,
65
+ useWorkflowManager: () => useWorkflowManager
61
66
  });
62
67
  module.exports = __toCommonJS(src_exports);
63
68
  __reExport(src_exports, require("@noya-app/state-manager"), module.exports);
64
69
 
65
- // src/avatarStyle.ts
66
- function hashCode(string) {
67
- let hash = 0;
68
- for (const char of string) {
69
- hash = char.charCodeAt(0) + ((hash << 5) - hash);
70
- }
71
- return hash;
72
- }
73
- function elementFromHash(array, hash) {
74
- return array[Math.abs(hash) % array.length];
75
- }
76
- function getAvatarInitials(name) {
77
- return name.split(" ").filter((c) => c.length > 0).map((c) => c[0]).join("").toLocaleUpperCase();
78
- }
79
- function getAvatarStyle(name) {
80
- const hash = hashCode(name);
81
- const color = elementFromHash(Object.values(colors500), hash);
82
- return {
83
- color: "white",
84
- backgroundColor: color
85
- // primaryColors: {
86
- // "500": color,
87
- // "800": darkerColor,
88
- // },
89
- };
90
- }
91
- var colors500 = {
92
- red500: "#ef4444",
93
- orange500: "#f97316",
94
- amber500: "#f59e0b",
95
- yellow500: "#eab308",
96
- lime500: "#84cc16",
97
- green500: "#22c55e",
98
- emerald500: "#10b981",
99
- teal500: "#14b8a6",
100
- cyan500: "#06b6d4",
101
- sky500: "#0ea5e9",
102
- blue500: "#3b82f6",
103
- indigo500: "#6366f1",
104
- violet500: "#8b5cf6",
105
- purple500: "#a855f7",
106
- fuchsia500: "#d946ef",
107
- pink500: "#ec4899",
108
- rose500: "#f43f5e"
109
- };
110
-
111
70
  // src/components/UserPointersOverlay.tsx
71
+ var import_react_utils = require("@noya-app/react-utils");
112
72
  var import_react2 = __toESM(require("react"));
113
73
 
114
74
  // src/useObservable.ts
115
75
  var import_react = require("react");
116
- function useObservable(observable, path) {
76
+ function useObservable(observable, pathOrSelector, options) {
117
77
  const { get, listen } = (0, import_react.useMemo)(() => {
118
- const listen2 = path ? (callback) => observable.subscribe(path, callback) : observable.subscribe;
119
- const get2 = path ? () => observable.get(path) : observable.get;
78
+ if (!observable) {
79
+ return {
80
+ get: () => void 0,
81
+ listen: () => () => {
82
+ }
83
+ };
84
+ }
85
+ if (typeof pathOrSelector === "function") {
86
+ const mappedObservable = observable.map(pathOrSelector, {
87
+ isEqual: options?.isEqual
88
+ });
89
+ return {
90
+ get: mappedObservable.get,
91
+ listen: mappedObservable.subscribe
92
+ };
93
+ }
94
+ const listen2 = pathOrSelector ? (callback) => observable.subscribe(pathOrSelector, callback) : observable.subscribe;
95
+ const get2 = pathOrSelector ? () => observable.get(pathOrSelector) : observable.get;
120
96
  return { get: get2, listen: listen2 };
121
- }, [observable, path]);
97
+ }, [observable, pathOrSelector, options?.isEqual]);
122
98
  return (0, import_react.useSyncExternalStore)(listen, get, get);
123
99
  }
124
100
 
@@ -126,136 +102,78 @@ function useObservable(observable, path) {
126
102
  function shouldShow(hideAfter, updatedAt) {
127
103
  return !!updatedAt && Date.now() - updatedAt < hideAfter;
128
104
  }
129
- var UserPointer_ = function UserPointer({
105
+ var UserPointerInternal = (0, import_react_utils.memoGeneric)(function UserPointerInternal2({
130
106
  user,
131
- ephemeralUserData,
132
- hideAfter = 5e3
107
+ ephemeralUserDataManager,
108
+ hideAfter = 5e3,
109
+ renderUserPointer
133
110
  }) {
134
- const metadata = useObservable(ephemeralUserData.metadata$, [
111
+ const metadata = useObservable(ephemeralUserDataManager.metadata$, [
112
+ user.id
113
+ ]);
114
+ const data = useObservable(ephemeralUserDataManager.data$, [
135
115
  user.id
136
116
  ]);
137
- const data = useObservable(ephemeralUserData.data$, [user.id]);
138
- const avatarStyle = (0, import_react2.useMemo)(() => getAvatarStyle(user.id), [user.id]);
139
117
  const [, setForceUpdate] = (0, import_react2.useState)(0);
140
118
  const updatedAt = metadata?.updatedAt ?? 0;
119
+ const show = shouldShow(hideAfter, updatedAt);
141
120
  (0, import_react2.useEffect)(() => {
142
- if (!shouldShow(hideAfter, updatedAt)) return;
121
+ if (!show) return;
143
122
  const timeoutId = setTimeout(() => {
144
123
  setForceUpdate((prev) => prev + 1);
145
124
  }, hideAfter);
146
125
  return () => clearTimeout(timeoutId);
147
- }, [hideAfter, updatedAt]);
148
- const show = shouldShow(hideAfter, updatedAt);
149
- if (!data || !data.pointer) return null;
150
- return /* @__PURE__ */ import_react2.default.createElement(UserPointerContainer, { key: user.id, point: data.pointer, show }, /* @__PURE__ */ import_react2.default.createElement(UserPointerIcon, { color: avatarStyle.backgroundColor }), /* @__PURE__ */ import_react2.default.createElement(UserNameTag, { background: avatarStyle.backgroundColor }, user.name));
151
- };
152
- var UserPointer2 = (0, import_react2.memo)(UserPointer_);
153
- var UserPointerContainer = (0, import_react2.memo)(function UserPointerContainer2({
154
- point,
155
- children,
156
- show = true
157
- }) {
158
- return /* @__PURE__ */ import_react2.default.createElement(
159
- "div",
160
- {
161
- style: {
162
- position: "absolute",
163
- top: 0,
164
- left: 0,
165
- transform: `translate(${Math.round(point.x)}px, ${Math.round(
166
- point.y
167
- )}px)`,
168
- opacity: show ? 1 : 0,
169
- transition: "transform 0.1s, opacity 0.2s"
170
- }
171
- },
172
- children
173
- );
126
+ }, [hideAfter, show, updatedAt]);
127
+ if (!data?.pointer) return null;
128
+ return renderUserPointer({
129
+ userId: user.id,
130
+ name: user.name,
131
+ point: data.pointer,
132
+ visible: show
133
+ });
174
134
  });
175
- var UserNameTag = (0, import_react2.memo)(function UserNameTag2({
176
- background,
177
- children
135
+ var UserPointersOverlay = (0, import_react_utils.memoGeneric)(function UserPointers({
136
+ connectedUsersManager,
137
+ ephemeralUserDataManager,
138
+ renderUserPointer
178
139
  }) {
179
- return /* @__PURE__ */ import_react2.default.createElement(
180
- "span",
181
- {
182
- style: {
183
- position: "relative",
184
- top: "8px",
185
- left: "15px",
186
- fontSize: 11,
187
- lineHeight: "1",
188
- fontWeight: 500,
189
- boxShadow: "0 1px 1px rgba(0,0,0,0.1)",
190
- padding: "2px 4px 3px",
191
- pointerEvents: "none",
192
- letterSpacing: "-0.3px",
193
- outline: `1px solid rgba(255,255,255,0.3)`,
194
- outlineOffset: "-1px",
195
- background,
196
- color: "white"
197
- }
198
- },
199
- children
200
- );
201
- });
202
- var UserPointersOverlay = (0, import_react2.memo)(function UserPointers({ connectedUsers, ephemeralUserData }) {
203
- const currentUserId = useObservable(ephemeralUserData.currentUserId$);
140
+ const currentUserId = useObservable(ephemeralUserDataManager.currentUserId$);
141
+ const connectedUsers = useObservable(connectedUsersManager.connectedUsers$);
204
142
  return /* @__PURE__ */ import_react2.default.createElement(import_react2.default.Fragment, null, connectedUsers.map((user) => {
205
143
  if (user.id === currentUserId) return null;
206
144
  return /* @__PURE__ */ import_react2.default.createElement(
207
- UserPointer2,
145
+ UserPointerInternal,
208
146
  {
209
147
  key: user.id,
210
148
  user,
211
- ephemeralUserData
149
+ ephemeralUserDataManager,
150
+ renderUserPointer
212
151
  }
213
152
  );
214
153
  }));
215
154
  });
216
- var UserPointerIcon = (0, import_react2.memo)(function CursorIcon({
217
- color = "black"
218
- }) {
219
- return /* @__PURE__ */ import_react2.default.createElement(
220
- "svg",
221
- {
222
- width: "15",
223
- height: "15",
224
- viewBox: "0 0 15 15",
225
- fill: "none",
226
- xmlns: "http://www.w3.org/2000/svg",
227
- style: {
228
- position: "absolute",
229
- filter: "drop-shadow(0 1px 1px rgba(0,0,0,0.1))"
230
- // filter: "drop-shadow(0 1px 1px rgba(0,0,0,0.6))",
231
- }
232
- },
233
- /* @__PURE__ */ import_react2.default.createElement(
234
- "path",
235
- {
236
- fillRule: "evenodd",
237
- clipRule: "evenodd",
238
- 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",
239
- fill: color
240
- }
241
- ),
242
- /* @__PURE__ */ import_react2.default.createElement(
243
- "path",
244
- {
245
- fillRule: "evenodd",
246
- clipRule: "evenodd",
247
- 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",
248
- fill: "rgba(255,255,255,0.5)"
249
- }
250
- )
251
- );
252
- });
253
155
 
254
156
  // src/hooks.ts
255
157
  var import_state_manager = require("@noya-app/state-manager");
256
158
  var import_react7 = require("react");
257
159
  var import_client2 = require("react-dom/client");
258
160
 
161
+ // ../noya-state-manager/src/SecretManager.ts
162
+ var import_observable = require("@noya-app/observable");
163
+ var SecretManager = class {
164
+ constructor(rpcManager) {
165
+ this.rpcManager = rpcManager;
166
+ }
167
+ secrets$ = new import_observable.Observable([]);
168
+ isInitialized$ = new import_observable.Observable(false);
169
+ async createSecret(name, value) {
170
+ return await this.rpcManager.request({ type: "createSecret", name, value });
171
+ }
172
+ async deleteSecret(name) {
173
+ return await this.rpcManager.request({ type: "deleteSecret", name });
174
+ }
175
+ };
176
+
259
177
  // src/components/ErrorOverlay.tsx
260
178
  var import_react3 = __toESM(require("react"));
261
179
  function ErrorOverlay({
@@ -331,15 +249,16 @@ function ErrorOverlay({
331
249
  }
332
250
 
333
251
  // src/globals.ts
334
- var import_observable = require("@noya-app/observable");
335
- var shouldTrackEvents$ = new import_observable.Observable(false);
336
- var shouldTrackTasks$ = new import_observable.Observable(false);
252
+ var import_observable2 = require("@noya-app/observable");
253
+ var shouldTrackEvents$ = new import_observable2.Observable(false);
254
+ var shouldTrackTasks$ = new import_observable2.Observable(false);
337
255
 
338
256
  // src/inspector/useStateInspector.tsx
339
257
  var import_react6 = __toESM(require("react"));
340
258
  var import_client = require("react-dom/client");
341
259
 
342
260
  // src/inspector/StateInspector.tsx
261
+ var import_react_utils2 = require("@noya-app/react-utils");
343
262
  var import_react5 = __toESM(require("react"));
344
263
  var import_react_inspector = require("react-inspector");
345
264
 
@@ -523,7 +442,7 @@ function InspectorRow({
523
442
  padding: "2px 12px 1px",
524
443
  display: "flex",
525
444
  alignItems: "center",
526
- background: variant === "up" ? "rgba(0,255,0,0.1)" : variant === "down" ? "rgba(255,0,0,0.1)" : selected ? "rgb(59 130 246 / 15%)" : void 0,
445
+ background: variant === "up" ? "rgba(0,255,0,0.1)" : variant === "down" ? "transparent" : selected ? "rgb(59 130 246 / 15%)" : void 0,
527
446
  // background:
528
447
  // colorScheme === "light"
529
448
  // ? "rgba(0,0,0,0.05)"
@@ -546,17 +465,17 @@ function InspectorRow({
546
465
  );
547
466
  }
548
467
  var HISTORY_ELEMENT_PREFIX = "noya-multiplayer-history-";
549
- var StateInspector = (0, import_react5.memo)(function StateInspector2({
468
+ var StateInspector = (0, import_react_utils2.memoGeneric)(function StateInspector2({
550
469
  state,
551
470
  connectionEvents,
552
- connectedUsers,
553
471
  tasks,
554
- userId,
555
472
  unstyled,
556
473
  colorScheme = "light",
557
474
  multiplayerStateManager,
558
475
  assetManager,
559
- ephemeralUserData,
476
+ secretManager,
477
+ connectedUsersManager,
478
+ ephemeralUserDataManager,
560
479
  anchor = "right",
561
480
  forceInit,
562
481
  ...props
@@ -599,6 +518,10 @@ var StateInspector = (0, import_react5.memo)(function StateInspector2({
599
518
  "noya-multiplayer-react-show-assets",
600
519
  false
601
520
  );
521
+ const [showSecrets, setShowSecrets] = useLocalStorageState(
522
+ "noya-multiplayer-react-show-secrets",
523
+ false
524
+ );
602
525
  (0, import_react5.useEffect)(() => {
603
526
  shouldTrackEvents$.set(showEvents);
604
527
  }, [showEvents]);
@@ -610,9 +533,12 @@ var StateInspector = (0, import_react5.memo)(function StateInspector2({
610
533
  eventsContainerRef.current.scrollTop = eventsContainerRef.current.scrollHeight;
611
534
  }
612
535
  }, [connectionEvents]);
613
- const ephemeral = useEphemeralUserData(ephemeralUserData);
536
+ const ephemeral = useObservable(ephemeralUserDataManager.data$);
614
537
  const historySnapshot = useManagedHistory(multiplayerStateManager.sm);
615
538
  const assets = useObservable(assetManager.assets$);
539
+ const secrets = useObservable(secretManager.secrets$);
540
+ const connectedUsers = useObservable(connectedUsersManager.connectedUsers$);
541
+ const userId = useObservable(connectedUsersManager.currentUserId$);
616
542
  (0, import_react5.useEffect)(() => {
617
543
  if (historyContainerRef.current) {
618
544
  historyContainerRef.current.scrollTop = historyContainerRef.current.scrollHeight;
@@ -995,6 +921,37 @@ var StateInspector = (0, import_react5.memo)(function StateInspector2({
995
921
  )
996
922
  )))
997
923
  ),
924
+ /* @__PURE__ */ import_react5.default.createElement(
925
+ DisclosureSection,
926
+ {
927
+ title: "Secrets",
928
+ colorScheme,
929
+ open: showSecrets,
930
+ setOpen: setShowSecrets,
931
+ right: /* @__PURE__ */ import_react5.default.createElement(
932
+ SmallButton,
933
+ {
934
+ theme,
935
+ onClick: () => {
936
+ const name = prompt("Enter secret name");
937
+ if (!name) return;
938
+ const value = prompt("Enter secret value");
939
+ if (!value) return;
940
+ secretManager.createSecret(name, value);
941
+ }
942
+ },
943
+ "Create"
944
+ )
945
+ },
946
+ /* @__PURE__ */ import_react5.default.createElement("div", { style: styles.sectionInner }, secrets.map((secret) => /* @__PURE__ */ import_react5.default.createElement(InspectorRow, { key: secret.id, colorScheme }, /* @__PURE__ */ import_react5.default.createElement(import_react_inspector.ObjectInspector, { data: secret, theme }), /* @__PURE__ */ import_react5.default.createElement(
947
+ SmallButton,
948
+ {
949
+ theme,
950
+ onClick: () => secretManager.deleteSecret(secret.name)
951
+ },
952
+ "Delete"
953
+ ))))
954
+ ),
998
955
  /* @__PURE__ */ import_react5.default.createElement(
999
956
  DisclosureSection,
1000
957
  {
@@ -1191,15 +1148,15 @@ function createShadowRootElement() {
1191
1148
  function useStateInspector({
1192
1149
  state,
1193
1150
  connectionEvents,
1194
- connectedUsers,
1195
1151
  tasks,
1196
- userId,
1197
1152
  disabled = false,
1198
1153
  colorScheme,
1199
1154
  anchor,
1200
1155
  multiplayerStateManager,
1201
1156
  assetManager,
1202
- ephemeralUserData,
1157
+ secretManager,
1158
+ connectedUsersManager,
1159
+ ephemeralUserDataManager,
1203
1160
  forceInit
1204
1161
  }) {
1205
1162
  const [root, setRoot] = import_react6.default.useState(null);
@@ -1221,31 +1178,31 @@ function useStateInspector({
1221
1178
  {
1222
1179
  state,
1223
1180
  connectionEvents,
1224
- connectedUsers,
1225
1181
  tasks,
1226
- userId,
1227
1182
  colorScheme,
1228
1183
  anchor,
1229
1184
  forceInit,
1230
1185
  multiplayerStateManager,
1231
1186
  assetManager,
1232
- ephemeralUserData
1187
+ secretManager,
1188
+ ephemeralUserDataManager,
1189
+ connectedUsersManager
1233
1190
  }
1234
1191
  )
1235
1192
  );
1236
1193
  }, [
1237
1194
  anchor,
1238
1195
  colorScheme,
1239
- connectedUsers,
1240
1196
  connectionEvents,
1241
1197
  root,
1242
1198
  state,
1243
1199
  multiplayerStateManager,
1244
- userId,
1245
1200
  tasks,
1246
1201
  forceInit,
1247
- ephemeralUserData,
1248
- assetManager
1202
+ ephemeralUserDataManager,
1203
+ assetManager,
1204
+ secretManager,
1205
+ connectedUsersManager
1249
1206
  ]);
1250
1207
  }
1251
1208
 
@@ -1315,95 +1272,63 @@ function useSyncMultiplayerStateManager(multiplayerStateManager) {
1315
1272
  multiplayerStateManager.getOptimisticState
1316
1273
  );
1317
1274
  }
1318
- function throttle(fn, ms) {
1319
- let lastCall = 0;
1320
- let timeoutId = null;
1321
- return (...args) => {
1322
- const now = Date.now();
1323
- if (now - lastCall < ms) {
1324
- if (timeoutId) clearTimeout(timeoutId);
1325
- timeoutId = setTimeout(
1326
- () => {
1327
- lastCall = now;
1328
- fn(...args);
1329
- },
1330
- ms - (now - lastCall)
1331
- );
1332
- return;
1333
- }
1334
- lastCall = now;
1335
- return fn(...args);
1336
- };
1337
- }
1338
- function useEphemeralUserData(ephemeralUserData, options) {
1339
- const throttledAddListener = (0, import_react7.useMemo)(() => {
1340
- const throttleMs = options?.throttle ?? 0;
1341
- if (throttleMs > 0) {
1342
- const addListener = (fn) => {
1343
- const throttledFn = throttle(fn, throttleMs);
1344
- return ephemeralUserData.addListener(throttledFn);
1345
- };
1346
- return addListener;
1347
- }
1348
- return ephemeralUserData.addListener;
1349
- }, [ephemeralUserData, options?.throttle]);
1350
- return (0, import_react7.useSyncExternalStore)(
1351
- throttledAddListener,
1352
- ephemeralUserData.getSnapshot,
1353
- ephemeralUserData.getSnapshot
1354
- );
1355
- }
1356
1275
  var defaultStubSync = (0, import_state_manager.stubSync)();
1357
1276
  function useMultiplayerState(initialState, options) {
1358
1277
  const { sync = defaultStubSync, ...rest } = options ?? {};
1278
+ const [rpcManager] = (0, import_react7.useState)(
1279
+ () => new import_state_manager.RPCManager()
1280
+ );
1359
1281
  const [multiplayerStateManager] = (0, import_react7.useState)(
1360
1282
  () => new import_state_manager.MultiplayerStateManager(initialState, rest)
1361
1283
  );
1362
1284
  const [assetManager] = (0, import_react7.useState)(() => new import_state_manager.AssetManager());
1285
+ const [aiManager] = (0, import_react7.useState)(() => new import_state_manager.AIManager(rpcManager));
1286
+ const [workflowManager] = (0, import_react7.useState)(() => new import_state_manager.WorkflowManager(rpcManager));
1287
+ const [secretManager] = (0, import_react7.useState)(() => new SecretManager(rpcManager));
1288
+ const [connectedUsersManager] = (0, import_react7.useState)(() => new import_state_manager.ConnectedUsersManager());
1363
1289
  const syncRef = (0, import_react7.useRef)(sync);
1364
1290
  const [connectionEvents, setConnectionEvents] = (0, import_react7.useState)();
1365
- const [connectedUsers, setConnectedUsers] = (0, import_react7.useState)([]);
1366
- const [ephemeralUserData] = (0, import_react7.useState)(
1367
- () => new import_state_manager.EphemeralUserData()
1291
+ const [ephemeralUserDataManager] = (0, import_react7.useState)(
1292
+ () => new import_state_manager.EphemeralUserDataManager()
1368
1293
  );
1369
1294
  const [tasks, setTasks] = (0, import_react7.useState)([]);
1370
- const [userId, setUserId] = (0, import_react7.useState)();
1371
1295
  const assets = useObservable(assetManager.assets$);
1372
1296
  const extras = (0, import_react7.useMemo)(() => {
1373
1297
  return {
1374
1298
  tasks,
1375
- userId,
1376
1299
  connectionEvents,
1377
- connectedUsers,
1378
- ephemeralUserData,
1300
+ connectedUsersManager,
1301
+ ephemeralUserDataManager,
1379
1302
  multiplayerStateManager,
1380
1303
  assets,
1381
1304
  assetManager,
1305
+ aiManager,
1306
+ rpcManager,
1307
+ workflowManager,
1308
+ secretManager,
1382
1309
  createAsset: assetManager.create,
1383
1310
  deleteAsset: assetManager.delete
1384
- // evaluate: async (code: string) => {
1385
- // const payload = await rpcManager.request({ type: "eval", code });
1386
- // if (payload.type !== "eval") {
1387
- // throw new Error(`Unexpected rpc response type: ${payload.type}`);
1388
- // }
1389
- // },
1311
+ // connectionStatus,
1312
+ // isConnected: connectionStatus === "connected",
1390
1313
  };
1391
1314
  }, [
1392
1315
  tasks,
1393
- userId,
1394
1316
  connectionEvents,
1395
- connectedUsers,
1396
- ephemeralUserData,
1317
+ connectedUsersManager,
1318
+ ephemeralUserDataManager,
1397
1319
  multiplayerStateManager,
1320
+ assets,
1398
1321
  assetManager,
1399
- assets
1322
+ aiManager,
1323
+ rpcManager,
1324
+ workflowManager,
1325
+ secretManager
1400
1326
  ]);
1401
1327
  const globalTrackEvents = useObservable(shouldTrackEvents$);
1402
1328
  const globalTrackTasks = useObservable(shouldTrackTasks$);
1403
1329
  const shouldTrackEvents = options?.trackConnectionEvents ?? globalTrackEvents;
1404
1330
  const shouldTrackTasks = options?.trackTasks ?? globalTrackTasks;
1405
1331
  const trackEventsCallbackRef = (0, import_react7.useRef)();
1406
- const trackConnectedUsersCallbackRef = (0, import_react7.useRef)();
1407
1332
  const trackTasksCallbackRef = (0, import_react7.useRef)();
1408
1333
  (0, import_react7.useEffect)(() => {
1409
1334
  trackEventsCallbackRef.current = shouldTrackEvents ? (e) => setConnectionEvents((events) => {
@@ -1411,12 +1336,6 @@ function useMultiplayerState(initialState, options) {
1411
1336
  return updated.length > 50 ? updated.slice(-50) : updated;
1412
1337
  }) : void 0;
1413
1338
  }, [shouldTrackEvents]);
1414
- (0, import_react7.useEffect)(() => {
1415
- trackConnectedUsersCallbackRef.current = (users, userId2) => {
1416
- setConnectedUsers(users);
1417
- setUserId(userId2);
1418
- };
1419
- }, []);
1420
1339
  (0, import_react7.useEffect)(() => {
1421
1340
  trackTasksCallbackRef.current = shouldTrackTasks ? (tasks2) => {
1422
1341
  setTasks((old) => {
@@ -1431,13 +1350,26 @@ function useMultiplayerState(initialState, options) {
1431
1350
  return syncRef.current({
1432
1351
  ms: multiplayerStateManager,
1433
1352
  assetManager,
1434
- ephemeralUserData,
1353
+ workflowManager,
1354
+ secretManager,
1355
+ rpcManager,
1356
+ aiManager,
1357
+ ephemeralUserDataManager,
1358
+ connectedUsersManager,
1435
1359
  onConnectionEvent: (e) => trackEventsCallbackRef.current?.(e),
1436
- onChangeConnectedUsers: (users, userId2) => trackConnectedUsersCallbackRef.current?.(users, userId2),
1437
1360
  onChangeTasks: (tasks2) => trackTasksCallbackRef.current?.(tasks2)
1438
1361
  });
1439
1362
  }
1440
- }, [assetManager, ephemeralUserData, multiplayerStateManager]);
1363
+ }, [
1364
+ assetManager,
1365
+ ephemeralUserDataManager,
1366
+ multiplayerStateManager,
1367
+ workflowManager,
1368
+ secretManager,
1369
+ rpcManager,
1370
+ aiManager,
1371
+ connectedUsersManager
1372
+ ]);
1441
1373
  const state = useSyncMultiplayerStateManager(multiplayerStateManager);
1442
1374
  const forceInit = (0, import_react7.useCallback)(() => {
1443
1375
  const state2 = initialState instanceof Function ? initialState() : initialState;
@@ -1472,14 +1404,14 @@ function useMultiplayerState(initialState, options) {
1472
1404
  };
1473
1405
  });
1474
1406
  useStateInspector({
1475
- ephemeralUserData,
1407
+ ephemeralUserDataManager,
1476
1408
  multiplayerStateManager,
1477
1409
  assetManager,
1410
+ secretManager,
1478
1411
  state,
1479
1412
  connectionEvents,
1480
- connectedUsers,
1413
+ connectedUsersManager,
1481
1414
  tasks,
1482
- userId,
1483
1415
  forceInit,
1484
1416
  disabled: !options?.inspector,
1485
1417
  ...typeof options?.inspector === "object" && options.inspector
@@ -1528,15 +1460,20 @@ function getAppData(initialState, schema, options) {
1528
1460
  appData.initialState = enforceSchema(appData.initialState, schema);
1529
1461
  return appData;
1530
1462
  }
1531
- function useBroadcastConnectedUsers(connectedUsers) {
1463
+ function useBroadcastConnectedUsers(connectedUsersManager) {
1532
1464
  (0, import_react8.useEffect)(() => {
1533
1465
  if (!isEmbeddedApp()) return;
1534
- const message = {
1535
- type: "multiplayer.setUsers",
1536
- payload: { users: connectedUsers }
1537
- };
1538
- parent?.postMessage(message, "*");
1539
- }, [connectedUsers]);
1466
+ const unsubscribe = connectedUsersManager.connectedUsers$.subscribe(
1467
+ (users) => {
1468
+ const message = {
1469
+ type: "multiplayer.setUsers",
1470
+ payload: { users }
1471
+ };
1472
+ parent?.postMessage(message, "*");
1473
+ }
1474
+ );
1475
+ return unsubscribe;
1476
+ }, [connectedUsersManager]);
1540
1477
  }
1541
1478
  function useBroadcastMenuItems(menuItems, handleSelectMenuItem) {
1542
1479
  (0, import_react8.useEffect)(() => {
@@ -1584,7 +1521,7 @@ function useNoyaState(...args) {
1584
1521
  sync: options?.sync ?? sync
1585
1522
  });
1586
1523
  const [, , extras] = result;
1587
- useBroadcastConnectedUsers(extras.connectedUsers);
1524
+ useBroadcastConnectedUsers(extras.connectedUsersManager);
1588
1525
  const mergedExtras = (0, import_react8.useMemo)(() => {
1589
1526
  return { ...extras, theme, viewType };
1590
1527
  }, [extras, theme, viewType]);
@@ -1592,6 +1529,7 @@ function useNoyaState(...args) {
1592
1529
  }
1593
1530
 
1594
1531
  // src/NoyaStateContext.tsx
1532
+ var import_observable3 = require("@noya-app/observable");
1595
1533
  var import_react9 = __toESM(require("react"));
1596
1534
  var AnyNoyaStateContext = (0, import_react9.createContext)(void 0);
1597
1535
  function useAnyNoyaStateContext() {
@@ -1625,32 +1563,114 @@ function useAssetManager() {
1625
1563
  [assetManager]
1626
1564
  );
1627
1565
  }
1566
+ function useAIManager() {
1567
+ const { aiManager } = useAnyNoyaStateContext();
1568
+ return aiManager;
1569
+ }
1570
+ function useSecretManager() {
1571
+ const { secretManager } = useAnyNoyaStateContext();
1572
+ return secretManager;
1573
+ }
1574
+ function useSecrets() {
1575
+ const { secretManager } = useAnyNoyaStateContext();
1576
+ return useObservable(secretManager.secrets$);
1577
+ }
1578
+ function useSecret(name) {
1579
+ const { secretManager } = useAnyNoyaStateContext();
1580
+ return useObservable(
1581
+ secretManager.secrets$,
1582
+ (0, import_react9.useCallback)((secrets) => secrets.find((s) => s.name === name), [name])
1583
+ );
1584
+ }
1585
+ function useIsInitialized() {
1586
+ const { ms, secretManager, assetManager } = useAnyNoyaStateContext();
1587
+ const isInitializedObservable = (0, import_react9.useMemo)(
1588
+ () => import_observable3.Observable.combine(
1589
+ [
1590
+ ms.isInitialized$,
1591
+ secretManager.isInitialized$,
1592
+ assetManager.isInitialized$
1593
+ ],
1594
+ (values) => values.every((v) => v)
1595
+ ),
1596
+ [ms, secretManager, assetManager]
1597
+ );
1598
+ return useObservable(isInitializedObservable);
1599
+ }
1600
+ function useWorkflowManager() {
1601
+ const { workflowManager } = useAnyNoyaStateContext();
1602
+ return workflowManager;
1603
+ }
1604
+ var ConnectedUsersContext = (0, import_react9.createContext)(void 0);
1605
+ function useConnectedUsersManager() {
1606
+ return (0, import_react9.useContext)(ConnectedUsersContext);
1607
+ }
1608
+ var AnyEphemeralUserDataManagerContext = (0, import_react9.createContext)(void 0);
1609
+ function useAnyEphemeralUserData() {
1610
+ return (0, import_react9.useContext)(AnyEphemeralUserDataManagerContext);
1611
+ }
1612
+ function useCurrentUserId() {
1613
+ const connectedUsersManager = useConnectedUsersManager();
1614
+ return useObservable(connectedUsersManager?.currentUserId$);
1615
+ }
1616
+ var FallbackUntilInitialized = ({
1617
+ children,
1618
+ fallback
1619
+ }) => {
1620
+ const isInitialized = useIsInitialized();
1621
+ return isInitialized ? children : fallback ?? null;
1622
+ };
1628
1623
  function createNoyaContext({
1629
1624
  schema,
1630
1625
  mergeHistoryEntries
1631
1626
  }) {
1632
1627
  const NoyaStateContext = AnyNoyaStateContext;
1628
+ const EphemeralUserDataManagerContext = AnyEphemeralUserDataManagerContext;
1633
1629
  function NoyaStateProvider({
1634
1630
  children,
1635
1631
  initialState,
1636
1632
  ...options
1637
1633
  }) {
1638
- const [, , { multiplayerStateManager, assetManager }] = useNoyaState(
1639
- initialState,
1634
+ const [
1635
+ ,
1636
+ ,
1640
1637
  {
1641
- ...options,
1642
- schema,
1643
- mergeHistoryEntries
1638
+ multiplayerStateManager,
1639
+ assetManager,
1640
+ workflowManager,
1641
+ secretManager,
1642
+ aiManager,
1643
+ ephemeralUserDataManager,
1644
+ connectedUsersManager
1644
1645
  }
1645
- );
1646
+ ] = useNoyaState(initialState, {
1647
+ ...options,
1648
+ schema,
1649
+ mergeHistoryEntries
1650
+ });
1646
1651
  const value = (0, import_react9.useMemo)(
1647
1652
  () => ({
1648
1653
  ms: multiplayerStateManager,
1649
- assetManager
1654
+ assetManager,
1655
+ workflowManager,
1656
+ secretManager,
1657
+ aiManager
1650
1658
  }),
1651
- [multiplayerStateManager, assetManager]
1659
+ [
1660
+ multiplayerStateManager,
1661
+ assetManager,
1662
+ workflowManager,
1663
+ secretManager,
1664
+ aiManager
1665
+ ]
1652
1666
  );
1653
- return /* @__PURE__ */ import_react9.default.createElement(AnyNoyaStateContext.Provider, { value }, children);
1667
+ return /* @__PURE__ */ import_react9.default.createElement(AnyNoyaStateContext.Provider, { value }, /* @__PURE__ */ import_react9.default.createElement(ConnectedUsersContext.Provider, { value: connectedUsersManager }, /* @__PURE__ */ import_react9.default.createElement(
1668
+ EphemeralUserDataManagerContext.Provider,
1669
+ {
1670
+ value: ephemeralUserDataManager
1671
+ },
1672
+ options.fallback !== void 0 ? /* @__PURE__ */ import_react9.default.createElement(FallbackUntilInitialized, { fallback: options.fallback }, children) : children
1673
+ )));
1654
1674
  }
1655
1675
  function useValue(path, options) {
1656
1676
  const { ms } = useAnyNoyaStateContext();
@@ -1686,13 +1706,23 @@ function createNoyaContext({
1686
1706
  const { ms } = useAnyNoyaStateContext();
1687
1707
  return ms;
1688
1708
  }
1709
+ function useEphemeralUserDataManager() {
1710
+ const ephemeralUserData = (0, import_react9.useContext)(EphemeralUserDataManagerContext);
1711
+ if (!ephemeralUserData) {
1712
+ throw new Error(
1713
+ "useEphemeralUserData must be used within a NoyaStateProvider"
1714
+ );
1715
+ }
1716
+ return ephemeralUserData;
1717
+ }
1689
1718
  return {
1690
1719
  Context: NoyaStateContext,
1691
1720
  Provider: NoyaStateProvider,
1692
1721
  useValue,
1693
1722
  useSetValue,
1694
1723
  useValueState,
1695
- useStateManager
1724
+ useStateManager,
1725
+ useEphemeralUserDataManager
1696
1726
  // useAssets,
1697
1727
  // useAssetManager,
1698
1728
  // useAsset,
@@ -1700,33 +1730,38 @@ function createNoyaContext({
1700
1730
  }
1701
1731
  // Annotate the CommonJS export names for ESM import in node:
1702
1732
  0 && (module.exports = {
1733
+ AnyEphemeralUserDataManagerContext,
1734
+ ConnectedUsersContext,
1735
+ FallbackUntilInitialized,
1703
1736
  StateInspector,
1704
- UserNameTag,
1705
- UserPointer,
1706
- UserPointerContainer,
1707
- UserPointerIcon,
1708
1737
  UserPointersOverlay,
1709
1738
  createDefaultAppData,
1710
1739
  createNoyaContext,
1711
1740
  enforceSchema,
1712
1741
  getAppData,
1713
- getAvatarInitials,
1714
- getAvatarStyle,
1715
1742
  isEmbeddedApp,
1716
1743
  parseAppDataParameter,
1744
+ useAIManager,
1745
+ useAnyEphemeralUserData,
1717
1746
  useAsset,
1718
1747
  useAssetManager,
1719
1748
  useAssets,
1720
1749
  useBroadcastConnectedUsers,
1721
1750
  useBroadcastMenuItems,
1722
- useEphemeralUserData,
1751
+ useConnectedUsersManager,
1752
+ useCurrentUserId,
1753
+ useIsInitialized,
1723
1754
  useManagedHistory,
1724
1755
  useManagedState,
1725
1756
  useMultiplayerState,
1726
1757
  useNoyaState,
1727
1758
  useObservable,
1759
+ useSecret,
1760
+ useSecretManager,
1761
+ useSecrets,
1728
1762
  useSyncMultiplayerStateManager,
1729
1763
  useSyncStateManager,
1764
+ useWorkflowManager,
1730
1765
  ...require("@noya-app/state-manager")
1731
1766
  });
1732
1767
  //# sourceMappingURL=index.js.map