@noya-app/noya-multiplayer-react 0.1.62 → 0.1.63

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
@@ -1119,9 +1119,15 @@ __export(src_exports, {
1119
1119
  WebSocketConnection: () => WebSocketConnection,
1120
1120
  createDefaultAppData: () => createDefaultAppData,
1121
1121
  createNoyaContext: () => createNoyaContext,
1122
+ decodeAll: () => decodeAll,
1123
+ encodeAll: () => encodeAll,
1122
1124
  enforceSchema: () => enforceSchema,
1125
+ exportAll: () => exportAll,
1126
+ fetchAssetMap: () => fetchAssetMap,
1123
1127
  getAppData: () => getAppData,
1128
+ importAll: () => importAll,
1124
1129
  parseAppDataParameter: () => parseAppDataParameter,
1130
+ replaceDeep: () => replaceDeep,
1125
1131
  useAIManager: () => useAIManager,
1126
1132
  useAnyEphemeralUserData: () => useAnyEphemeralUserData,
1127
1133
  useAnyNoyaManager: () => useAnyNoyaManager,
@@ -1156,12 +1162,12 @@ module.exports = __toCommonJS(src_exports);
1156
1162
  __reExport(src_exports, require("@noya-app/state-manager"), module.exports);
1157
1163
 
1158
1164
  // src/ai.ts
1159
- var import_react8 = require("react");
1165
+ var import_react17 = require("react");
1160
1166
 
1161
1167
  // src/NoyaStateContext.tsx
1162
1168
  var import_observable = require("@noya-app/observable");
1163
1169
  var import_react_utils3 = require("@noya-app/react-utils");
1164
- var import_react7 = __toESM(require("react"));
1170
+ var import_react16 = __toESM(require("react"));
1165
1171
 
1166
1172
  // ../../node_modules/@sinclair/typebox/build/esm/type/symbols/symbols.mjs
1167
1173
  var TransformKind = Symbol.for("TypeBox.Transform");
@@ -3587,6 +3593,71 @@ function Void(options = {}) {
3587
3593
  // ../../node_modules/@sinclair/typebox/build/esm/type/type/index.mjs
3588
3594
  var Type = type_exports3;
3589
3595
 
3596
+ // ../noya-schemas/src/asset.ts
3597
+ var assetSchema = Type.Object({
3598
+ id: Type.String(),
3599
+ url: Type.String(),
3600
+ createdAt: Type.String(),
3601
+ size: Type.Number(),
3602
+ contentType: Type.Optional(Type.String())
3603
+ });
3604
+
3605
+ // ../noya-schemas/src/encode.ts
3606
+ var SchemaMap = /* @__PURE__ */ new Map([
3607
+ [Kind, "_kind"],
3608
+ [Hint, "_hint"]
3609
+ ]);
3610
+ var InverseSchemaMap = new Map(
3611
+ Array.from(SchemaMap.entries()).map(([key, value]) => [value, key])
3612
+ );
3613
+ function encodeSchema(obj, symMap = SchemaMap) {
3614
+ function replaceSymbols(item) {
3615
+ if (Array.isArray(item)) {
3616
+ return item.map(replaceSymbols);
3617
+ } else if (typeof item === "object" && item !== null) {
3618
+ const newObj = {};
3619
+ for (const key in item) {
3620
+ if (Object.prototype.hasOwnProperty.call(item, key)) {
3621
+ const value = item[key];
3622
+ newObj[key] = replaceSymbols(value);
3623
+ }
3624
+ }
3625
+ for (const sym of Object.getOwnPropertySymbols(item)) {
3626
+ const stringKey = symMap.get(sym);
3627
+ if (stringKey) {
3628
+ newObj[stringKey] = replaceSymbols(item[sym]);
3629
+ }
3630
+ }
3631
+ return newObj;
3632
+ }
3633
+ return item;
3634
+ }
3635
+ return replaceSymbols(obj);
3636
+ }
3637
+ function decodeSchema(obj, strMap = InverseSchemaMap) {
3638
+ function replaceStringKeys(item) {
3639
+ if (Array.isArray(item)) {
3640
+ return item.map(replaceStringKeys);
3641
+ } else if (typeof item === "object" && item !== null) {
3642
+ const newObj = {};
3643
+ for (const key in item) {
3644
+ if (Object.prototype.hasOwnProperty.call(item, key)) {
3645
+ const value = item[key];
3646
+ const symbolKey = strMap.get(key);
3647
+ if (symbolKey) {
3648
+ newObj[symbolKey] = replaceStringKeys(value);
3649
+ } else {
3650
+ newObj[key] = replaceStringKeys(value);
3651
+ }
3652
+ }
3653
+ }
3654
+ return newObj;
3655
+ }
3656
+ return item;
3657
+ }
3658
+ return replaceStringKeys(obj);
3659
+ }
3660
+
3590
3661
  // ../noya-schemas/src/filesSchema.ts
3591
3662
  var encodingSchema = Type.Union([
3592
3663
  Type.Literal("utf-8"),
@@ -3607,8 +3678,13 @@ var fileSchema = Type.Object({
3607
3678
  content: Type.String(),
3608
3679
  encoding: encodingSchema
3609
3680
  });
3681
+ var noyaFileSchema = Type.Object({
3682
+ id: Type.String({ format: "uuid", default: "" }),
3683
+ kind: Type.Literal("noyaFile"),
3684
+ fileId: Type.String()
3685
+ });
3610
3686
  var mediaItemSchema = Type.Union(
3611
- [folderMediaItemSchema, assetMediaItemSchema, fileSchema],
3687
+ [folderMediaItemSchema, assetMediaItemSchema, fileSchema, noyaFileSchema],
3612
3688
  {
3613
3689
  discriminator: "kind"
3614
3690
  }
@@ -3949,12 +4025,12 @@ format_exports.Set("color", () => true);
3949
4025
  format_exports.Set("uuid", validateUUID);
3950
4026
 
3951
4027
  // src/noyaApp.ts
3952
- var import_state_manager2 = require("@noya-app/state-manager");
3953
- var import_react6 = require("react");
4028
+ var import_state_manager3 = require("@noya-app/state-manager");
4029
+ var import_react15 = require("react");
3954
4030
 
3955
4031
  // src/hooks.ts
3956
- var import_state_manager = require("@noya-app/state-manager");
3957
- var import_react5 = require("react");
4032
+ var import_state_manager2 = require("@noya-app/state-manager");
4033
+ var import_react14 = require("react");
3958
4034
  var import_client2 = require("react-dom/client");
3959
4035
 
3960
4036
  // src/components/ErrorOverlay.tsx
@@ -4032,14 +4108,14 @@ var ErrorOverlay = React.memo(function ErrorOverlay2({
4032
4108
  });
4033
4109
 
4034
4110
  // src/inspector/useStateInspector.tsx
4035
- var import_react4 = __toESM(require("react"));
4111
+ var import_react13 = __toESM(require("react"));
4036
4112
  var import_client = require("react-dom/client");
4037
4113
  var import_react_utils2 = require("@noya-app/react-utils");
4038
4114
 
4039
4115
  // src/inspector/StateInspector.tsx
4040
4116
  var import_react_utils = require("@noya-app/react-utils");
4041
- var import_react3 = __toESM(require("react"));
4042
- var import_react_inspector = require("react-inspector");
4117
+ var import_react12 = __toESM(require("react"));
4118
+ var import_react_inspector5 = require("react-inspector");
4043
4119
 
4044
4120
  // src/useObservable.ts
4045
4121
  var import_react = require("react");
@@ -4068,119 +4144,108 @@ function useObservable(observable, pathOrSelector, options) {
4068
4144
  return (0, import_react.useSyncExternalStore)(listen, get, get);
4069
4145
  }
4070
4146
 
4071
- // src/inspector/useLocalStorageState.tsx
4147
+ // src/inspector/ColoredDot.tsx
4072
4148
  var import_react2 = __toESM(require("react"));
4073
- var localStorage = typeof window !== "undefined" ? window.localStorage : null;
4074
- function useLocalStorageState(key, defaultValue) {
4075
- const [state, setState] = import_react2.default.useState(() => {
4076
- const value = localStorage?.getItem(key);
4077
- let result = defaultValue;
4078
- if (value) {
4079
- try {
4080
- result = JSON.parse(value);
4081
- } catch (error) {
4082
- console.error("Error parsing localStorage value", error);
4149
+ function ColoredDot({ type }) {
4150
+ return /* @__PURE__ */ import_react2.default.createElement(
4151
+ "span",
4152
+ {
4153
+ style: {
4154
+ display: "inline-block",
4155
+ width: 6,
4156
+ height: 6,
4157
+ background: type === "success" ? "rgba(0,200,0,0.8)" : "rgba(200,0,0,0.8)",
4158
+ borderRadius: "50%",
4159
+ verticalAlign: "middle"
4083
4160
  }
4084
4161
  }
4085
- return result;
4086
- });
4087
- const setLocalStorageState = (value) => {
4088
- localStorage?.setItem(key, JSON.stringify(value));
4089
- setState(value);
4090
- };
4091
- return [state, setLocalStorageState];
4162
+ );
4092
4163
  }
4093
4164
 
4094
- // src/inspector/StateInspector.tsx
4095
- var lightTheme = {
4165
+ // src/inspector/inspectorTheme.ts
4166
+ var import_react_inspector = require("react-inspector");
4167
+ var lightInspectorTheme = {
4096
4168
  ...import_react_inspector.chromeLight,
4097
4169
  BASE_BACKGROUND_COLOR: "transparent",
4098
4170
  OBJECT_NAME_COLOR: "rgba(0,0,0,0.7)"
4099
4171
  };
4100
- var darkTheme = {
4172
+ var darkInspectorTheme = {
4101
4173
  ...import_react_inspector.chromeDark,
4102
4174
  BASE_BACKGROUND_COLOR: "transparent",
4103
4175
  OBJECT_NAME_COLOR: "rgba(255,255,255,0.7)"
4104
4176
  };
4105
- var styles = {
4106
- sectionInner: {
4107
- flex: "1 1 0",
4108
- overflowY: "auto",
4109
- overflowX: "hidden",
4110
- display: "flex",
4111
- flexDirection: "column"
4177
+ var getStateInspectorTheme = (colorScheme) => {
4178
+ return colorScheme === "light" ? lightInspectorTheme : darkInspectorTheme;
4179
+ };
4180
+ var getStateInspectorBorderColor = (colorScheme) => {
4181
+ return colorScheme === "light" ? "rgb(223 223 223)" : "rgb(29 29 29)";
4182
+ };
4183
+
4184
+ // src/inspector/sections/EventsSection.tsx
4185
+ var import_react7 = __toESM(require("react"));
4186
+ var import_react_inspector3 = require("react-inspector");
4187
+
4188
+ // src/inspector/ObjectRootLabel.tsx
4189
+ var import_react3 = __toESM(require("react"));
4190
+ var import_react_inspector2 = require("react-inspector");
4191
+ var ObjectRootLabel = ({ name, data, direction }) => {
4192
+ if (typeof name === "string") {
4193
+ return /* @__PURE__ */ import_react3.default.createElement("span", null, /* @__PURE__ */ import_react3.default.createElement(import_react_inspector2.ObjectName, { name }), /* @__PURE__ */ import_react3.default.createElement("span", null, ": "), /* @__PURE__ */ import_react3.default.createElement(import_react_inspector2.ObjectPreview, { data }));
4194
+ }
4195
+ if (direction === "up" || direction === "down") {
4196
+ const arrow = direction === "up" ? "\u2191" : "\u2193";
4197
+ return /* @__PURE__ */ import_react3.default.createElement("span", null, /* @__PURE__ */ import_react3.default.createElement(
4198
+ "span",
4199
+ {
4200
+ style: {
4201
+ background: direction === "up" ? "rgba(0,255,0,0.2)" : "rgba(255,0,0,0.2)",
4202
+ // color: "white",
4203
+ width: 12,
4204
+ height: 12,
4205
+ borderRadius: 2,
4206
+ display: "inline-flex",
4207
+ justifyContent: "center",
4208
+ alignItems: "center",
4209
+ marginRight: 4,
4210
+ lineHeight: "12px"
4211
+ }
4212
+ },
4213
+ arrow
4214
+ ), /* @__PURE__ */ import_react3.default.createElement(import_react_inspector2.ObjectPreview, { data }));
4215
+ } else {
4216
+ return /* @__PURE__ */ import_react3.default.createElement(import_react_inspector2.ObjectPreview, { data });
4112
4217
  }
4113
4218
  };
4114
- function ToggleButton({
4115
- showInspector,
4116
- setShowInspector,
4117
- theme,
4118
- anchor
4219
+
4220
+ // src/inspector/StateInspectorDisclosureSection.tsx
4221
+ var import_react5 = __toESM(require("react"));
4222
+
4223
+ // src/inspector/StateInspectorArrow.tsx
4224
+ var import_react4 = __toESM(require("react"));
4225
+ function StateInspectorArrow({
4226
+ expanded,
4227
+ onClick,
4228
+ style
4119
4229
  }) {
4120
- const isRightAnchor = anchor === "right";
4121
- const rightIcon = /* @__PURE__ */ import_react3.default.createElement(
4122
- "svg",
4123
- {
4124
- xmlns: "http://www.w3.org/2000/svg",
4125
- fill: "none",
4126
- viewBox: "0 0 24 24",
4127
- strokeWidth: 1.5,
4128
- stroke: "currentColor",
4129
- className: "size-6"
4130
- },
4131
- /* @__PURE__ */ import_react3.default.createElement(
4132
- "path",
4133
- {
4134
- strokeLinecap: "round",
4135
- strokeLinejoin: "round",
4136
- d: "m5.25 4.5 7.5 7.5-7.5 7.5m6-15 7.5 7.5-7.5 7.5"
4137
- }
4138
- )
4139
- );
4140
- const leftIcon = /* @__PURE__ */ import_react3.default.createElement(
4141
- "svg",
4142
- {
4143
- xmlns: "http://www.w3.org/2000/svg",
4144
- fill: "none",
4145
- viewBox: "0 0 24 24",
4146
- strokeWidth: 1.5,
4147
- stroke: "currentColor",
4148
- className: "size-6"
4149
- },
4150
- /* @__PURE__ */ import_react3.default.createElement(
4151
- "path",
4152
- {
4153
- strokeLinecap: "round",
4154
- strokeLinejoin: "round",
4155
- d: "m18.75 4.5-7.5 7.5 7.5 7.5m-6-15L5.25 12l7.5 7.5"
4156
- }
4157
- )
4158
- );
4159
- return /* @__PURE__ */ import_react3.default.createElement(
4230
+ return /* @__PURE__ */ import_react4.default.createElement(
4160
4231
  "span",
4161
4232
  {
4162
4233
  role: "button",
4234
+ onClick,
4163
4235
  style: {
4164
- flex: "0",
4165
- appearance: "none",
4166
- color: theme.BASE_COLOR,
4167
- border: "none",
4168
- fontSize: "12px",
4169
- whiteSpace: "nowrap",
4170
- display: "inline-flex",
4171
- alignItems: "center",
4172
- justifyContent: "center",
4173
- padding: "2px 0"
4174
- },
4175
- onClick: (event) => {
4176
- event.stopPropagation();
4177
- setShowInspector(!showInspector);
4236
+ display: "inline-block",
4237
+ textAlign: "center",
4238
+ transform: expanded ? "rotate(0deg)" : "rotate(-90deg)",
4239
+ fontFamily: "Menlo, monospace",
4240
+ ...style
4178
4241
  }
4179
4242
  },
4180
- showInspector ? "Hide Inspector" : /* @__PURE__ */ import_react3.default.createElement("span", { style: { width: "12px", height: "12px" } }, isRightAnchor ? rightIcon : leftIcon)
4243
+ "\u25BC"
4181
4244
  );
4182
4245
  }
4183
- function DisclosureSection({
4246
+
4247
+ // src/inspector/StateInspectorDisclosureSection.tsx
4248
+ function StateInspectorDisclosureSection({
4184
4249
  open,
4185
4250
  setOpen,
4186
4251
  title,
@@ -4190,9 +4255,9 @@ function DisclosureSection({
4190
4255
  isFirst,
4191
4256
  style
4192
4257
  }) {
4193
- const theme = colorScheme === "light" ? lightTheme : darkTheme;
4258
+ const theme = colorScheme === "light" ? lightInspectorTheme : darkInspectorTheme;
4194
4259
  const borderColor = colorScheme === "light" ? "rgba(0,0,0,0.1)" : "rgba(255,255,255,0.1)";
4195
- return /* @__PURE__ */ import_react3.default.createElement(
4260
+ return /* @__PURE__ */ import_react5.default.createElement(
4196
4261
  "div",
4197
4262
  {
4198
4263
  style: {
@@ -4202,7 +4267,7 @@ function DisclosureSection({
4202
4267
  ...style
4203
4268
  }
4204
4269
  },
4205
- /* @__PURE__ */ import_react3.default.createElement(
4270
+ /* @__PURE__ */ import_react5.default.createElement(
4206
4271
  "div",
4207
4272
  {
4208
4273
  onClick: () => setOpen?.(!open),
@@ -4216,8 +4281,8 @@ function DisclosureSection({
4216
4281
  ...open && { borderBottom: `1px solid ${borderColor}` }
4217
4282
  }
4218
4283
  },
4219
- setOpen && /* @__PURE__ */ import_react3.default.createElement(
4220
- Arrow,
4284
+ setOpen && /* @__PURE__ */ import_react5.default.createElement(
4285
+ StateInspectorArrow,
4221
4286
  {
4222
4287
  expanded: open,
4223
4288
  style: {
@@ -4227,13 +4292,35 @@ function DisclosureSection({
4227
4292
  }
4228
4293
  }
4229
4294
  ),
4230
- /* @__PURE__ */ import_react3.default.createElement("span", { style: { flex: "1 1 0", userSelect: "none" } }, title),
4295
+ /* @__PURE__ */ import_react5.default.createElement("span", { style: { flex: "1 1 0", userSelect: "none" } }, title),
4231
4296
  right
4232
4297
  ),
4233
4298
  open && children
4234
4299
  );
4235
4300
  }
4236
- function InspectorRow({
4301
+ var StateInspectorDisclosureRowInner = (0, import_react5.forwardRef)(
4302
+ function StateInspectorDisclosureRowInner2(props, forwardedRef) {
4303
+ return /* @__PURE__ */ import_react5.default.createElement(
4304
+ "div",
4305
+ {
4306
+ style: {
4307
+ flex: "1 1 0",
4308
+ overflowY: "auto",
4309
+ overflowX: "hidden",
4310
+ display: "flex",
4311
+ flexDirection: "column",
4312
+ ...props.style
4313
+ },
4314
+ ...props,
4315
+ ref: forwardedRef
4316
+ }
4317
+ );
4318
+ }
4319
+ );
4320
+
4321
+ // src/inspector/StateInspectorRow.tsx
4322
+ var import_react6 = __toESM(require("react"));
4323
+ function StateInspectorRow({
4237
4324
  children,
4238
4325
  colorScheme,
4239
4326
  selected,
@@ -4241,7 +4328,7 @@ function InspectorRow({
4241
4328
  variant
4242
4329
  }) {
4243
4330
  const solidBorderColor = colorScheme === "light" ? "rgb(223 223 223)" : "rgb(29 29 29)";
4244
- return /* @__PURE__ */ import_react3.default.createElement(
4331
+ return /* @__PURE__ */ import_react6.default.createElement(
4245
4332
  "div",
4246
4333
  {
4247
4334
  style: {
@@ -4259,7 +4346,7 @@ function InspectorRow({
4259
4346
  ...style
4260
4347
  }
4261
4348
  },
4262
- /* @__PURE__ */ import_react3.default.createElement(
4349
+ /* @__PURE__ */ import_react6.default.createElement(
4263
4350
  "span",
4264
4351
  {
4265
4352
  style: {
@@ -4273,40 +4360,1007 @@ function InspectorRow({
4273
4360
  )
4274
4361
  );
4275
4362
  }
4276
- var HISTORY_ELEMENT_PREFIX = "noya-multiplayer-history-";
4277
- var StateInspector = (0, import_react_utils.memoGeneric)(function StateInspector2({
4278
- noyaManager,
4279
- colorScheme = "light",
4280
- anchor = "right",
4281
- unstyled = false,
4282
- ...props
4363
+
4364
+ // src/inspector/sections/EventsSection.tsx
4365
+ function EventsSection({
4366
+ showEvents,
4367
+ setShowEvents,
4368
+ colorScheme,
4369
+ eventsContainerRef,
4370
+ connectionEvents
4283
4371
  }) {
4284
- const {
4285
- multiplayerStateManager,
4286
- assetManager,
4287
- connectedUsersManager,
4288
- secretManager,
4289
- ephemeralUserDataManager,
4290
- connectionEventManager,
4291
- taskManager,
4292
- ioManager
4293
- } = noyaManager;
4294
- const [didMount, setDidMount] = import_react3.default.useState(false);
4295
- const tasks = useObservable(taskManager.tasks$);
4296
- const inputs = useObservable(ioManager.inputs$);
4297
- const outputTransforms = useObservable(ioManager.outputTransforms$);
4298
- (0, import_react3.useLayoutEffect)(() => {
4299
- setDidMount(true);
4300
- }, []);
4301
- const eventsContainerRef = import_react3.default.useRef(null);
4302
- const historyContainerRef = import_react3.default.useRef(null);
4303
- const [showInspector, setShowInspector] = useLocalStorageState(
4304
- "noya-multiplayer-react-show-inspector",
4305
- true
4372
+ const theme = getStateInspectorTheme(colorScheme);
4373
+ return /* @__PURE__ */ import_react7.default.createElement(
4374
+ StateInspectorDisclosureSection,
4375
+ {
4376
+ open: showEvents,
4377
+ setOpen: setShowEvents,
4378
+ title: "Events",
4379
+ colorScheme
4380
+ },
4381
+ /* @__PURE__ */ import_react7.default.createElement(StateInspectorDisclosureRowInner, { ref: eventsContainerRef }, connectionEvents?.map(
4382
+ (event, index) => event.type === "stateChange" ? /* @__PURE__ */ import_react7.default.createElement(StateInspectorRow, { key: index, colorScheme }, "connection:", " ", /* @__PURE__ */ import_react7.default.createElement("span", { style: { fontStyle: "italic" } }, event.state.toLowerCase())) : /* @__PURE__ */ import_react7.default.createElement(
4383
+ StateInspectorRow,
4384
+ {
4385
+ key: index,
4386
+ colorScheme,
4387
+ variant: event.type === "send" ? "up" : "down",
4388
+ style: {
4389
+ padding: "0px 12px 1px"
4390
+ }
4391
+ },
4392
+ /* @__PURE__ */ import_react7.default.createElement(
4393
+ import_react_inspector3.ObjectInspector,
4394
+ {
4395
+ data: event.type === "error" ? event.error : event.message,
4396
+ theme,
4397
+ nodeRenderer: ({ depth, name, data, isNonenumerable }) => {
4398
+ const direction = event.type === "send" ? "up" : "down";
4399
+ return depth === 0 ? /* @__PURE__ */ import_react7.default.createElement(ObjectRootLabel, { direction, data }) : /* @__PURE__ */ import_react7.default.createElement(
4400
+ import_react_inspector3.ObjectLabel,
4401
+ {
4402
+ direction,
4403
+ name,
4404
+ data,
4405
+ isNonenumerable
4406
+ }
4407
+ );
4408
+ }
4409
+ }
4410
+ )
4411
+ )
4412
+ ), !connectionEvents && /* @__PURE__ */ import_react7.default.createElement(
4413
+ "div",
4414
+ {
4415
+ style: {
4416
+ padding: "12px",
4417
+ fontSize: "12px",
4418
+ display: "flex",
4419
+ flexDirection: "column",
4420
+ gap: "4px"
4421
+ }
4422
+ },
4423
+ /* @__PURE__ */ import_react7.default.createElement("span", null, "No recorded events")
4424
+ ))
4306
4425
  );
4307
- const [showEvents, setShowEvents] = useLocalStorageState(
4308
- "noya-multiplayer-react-show-events",
4309
- false
4426
+ }
4427
+
4428
+ // src/inspector/sections/HistorySection.tsx
4429
+ var import_react9 = __toESM(require("react"));
4430
+ var import_react_inspector4 = require("react-inspector");
4431
+
4432
+ // src/inspector/StateInspectorButton.tsx
4433
+ var import_react8 = __toESM(require("react"));
4434
+ function StateInspectorButton({
4435
+ children,
4436
+ onClick,
4437
+ style,
4438
+ theme,
4439
+ disabled
4440
+ }) {
4441
+ return /* @__PURE__ */ import_react8.default.createElement(
4442
+ "button",
4443
+ {
4444
+ type: "button",
4445
+ disabled,
4446
+ onClick: (event) => {
4447
+ event.stopPropagation();
4448
+ onClick();
4449
+ },
4450
+ style: {
4451
+ flex: "0",
4452
+ appearance: "none",
4453
+ background: "none",
4454
+ color: theme.BASE_COLOR,
4455
+ opacity: disabled ? 0.25 : 1,
4456
+ border: "none",
4457
+ fontSize: "12px",
4458
+ whiteSpace: "nowrap",
4459
+ display: "inline-flex",
4460
+ alignItems: "center",
4461
+ justifyContent: "center",
4462
+ padding: "0",
4463
+ cursor: "pointer",
4464
+ ...style
4465
+ }
4466
+ },
4467
+ children
4468
+ );
4469
+ }
4470
+
4471
+ // src/inspector/utils.ts
4472
+ function pathToString(extendedPath) {
4473
+ return extendedPath.map(
4474
+ (key) => typeof key === "object" ? `:${ellipsis(key.id.toString(), 8, "middle")}` : key
4475
+ ).map(
4476
+ (key, index) => index === 0 || typeof key === "string" && key.startsWith(":") ? key : `.${key}`
4477
+ ).join("");
4478
+ }
4479
+ function ellipsis(str, maxLength, position = "end") {
4480
+ if (str.length <= maxLength) return str;
4481
+ switch (position) {
4482
+ case "start":
4483
+ return `\u2026${str.slice(str.length - maxLength)}`;
4484
+ case "middle": {
4485
+ const halfLength = Math.floor(maxLength / 2);
4486
+ return `${str.slice(0, halfLength)}\u2026${str.slice(str.length - halfLength)}`;
4487
+ }
4488
+ case "end":
4489
+ return `${str.slice(0, maxLength)}\u2026`;
4490
+ }
4491
+ }
4492
+ function uploadFile() {
4493
+ return new Promise((resolve, reject) => {
4494
+ const input = document.createElement("input");
4495
+ input.type = "file";
4496
+ input.onchange = () => {
4497
+ const file = input.files?.[0];
4498
+ if (file) {
4499
+ const reader = new FileReader();
4500
+ reader.onload = () => {
4501
+ const buffer = reader.result;
4502
+ const blob = new Blob([buffer]);
4503
+ resolve(blob);
4504
+ };
4505
+ reader.onerror = () => {
4506
+ reject(new Error("Failed to read file"));
4507
+ };
4508
+ reader.readAsArrayBuffer(file);
4509
+ }
4510
+ };
4511
+ input.click();
4512
+ });
4513
+ }
4514
+
4515
+ // src/inspector/sections/HistorySection.tsx
4516
+ var HISTORY_ELEMENT_PREFIX = "noya-multiplayer-history-";
4517
+ function HistorySection({
4518
+ showHistory,
4519
+ setShowHistory,
4520
+ colorScheme,
4521
+ historySnapshot,
4522
+ multiplayerStateManager
4523
+ }) {
4524
+ const ref = (0, import_react9.useRef)(null);
4525
+ const theme = getStateInspectorTheme(colorScheme);
4526
+ const solidBorderColor = getStateInspectorBorderColor(colorScheme);
4527
+ (0, import_react9.useEffect)(() => {
4528
+ if (ref.current) {
4529
+ ref.current.scrollTop = ref.current.scrollHeight;
4530
+ }
4531
+ }, [historySnapshot]);
4532
+ (0, import_react9.useEffect)(() => {
4533
+ if (!ref.current) return;
4534
+ const historyEntry = ref.current.querySelector(
4535
+ `#${HISTORY_ELEMENT_PREFIX}${historySnapshot.historyIndex}`
4536
+ );
4537
+ if (historyEntry) {
4538
+ historyEntry.scrollIntoView({
4539
+ block: "nearest",
4540
+ inline: "nearest"
4541
+ });
4542
+ }
4543
+ }, [historySnapshot.historyIndex]);
4544
+ return /* @__PURE__ */ import_react9.default.createElement(
4545
+ StateInspectorDisclosureSection,
4546
+ {
4547
+ open: showHistory,
4548
+ setOpen: setShowHistory,
4549
+ title: "History",
4550
+ colorScheme,
4551
+ right: /* @__PURE__ */ import_react9.default.createElement(
4552
+ "span",
4553
+ {
4554
+ style: {
4555
+ display: "flex",
4556
+ gap: "4px"
4557
+ }
4558
+ },
4559
+ /* @__PURE__ */ import_react9.default.createElement(
4560
+ StateInspectorButton,
4561
+ {
4562
+ disabled: !historySnapshot.canUndo,
4563
+ theme,
4564
+ onClick: () => {
4565
+ multiplayerStateManager.undo();
4566
+ }
4567
+ },
4568
+ /* @__PURE__ */ import_react9.default.createElement("span", { style: { width: "12px", height: "12px" } }, /* @__PURE__ */ import_react9.default.createElement(
4569
+ "svg",
4570
+ {
4571
+ xmlns: "http://www.w3.org/2000/svg",
4572
+ width: "1em",
4573
+ height: "1em",
4574
+ viewBox: "0 0 20 20"
4575
+ },
4576
+ /* @__PURE__ */ import_react9.default.createElement(
4577
+ "path",
4578
+ {
4579
+ fill: "currentColor",
4580
+ 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"
4581
+ }
4582
+ )
4583
+ ))
4584
+ ),
4585
+ /* @__PURE__ */ import_react9.default.createElement(
4586
+ StateInspectorButton,
4587
+ {
4588
+ disabled: !historySnapshot.canRedo,
4589
+ theme,
4590
+ onClick: () => {
4591
+ multiplayerStateManager.redo();
4592
+ }
4593
+ },
4594
+ /* @__PURE__ */ import_react9.default.createElement("span", { style: { width: "12px", height: "12px" } }, /* @__PURE__ */ import_react9.default.createElement(
4595
+ "svg",
4596
+ {
4597
+ xmlns: "http://www.w3.org/2000/svg",
4598
+ width: "1em",
4599
+ height: "1em",
4600
+ viewBox: "0 0 20 20"
4601
+ },
4602
+ /* @__PURE__ */ import_react9.default.createElement(
4603
+ "path",
4604
+ {
4605
+ fill: "currentColor",
4606
+ 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"
4607
+ }
4608
+ )
4609
+ ))
4610
+ )
4611
+ )
4612
+ },
4613
+ /* @__PURE__ */ import_react9.default.createElement(StateInspectorDisclosureRowInner, { ref }, /* @__PURE__ */ import_react9.default.createElement(
4614
+ "div",
4615
+ {
4616
+ id: `${HISTORY_ELEMENT_PREFIX}0`,
4617
+ style: {
4618
+ borderBottom: `1px solid ${solidBorderColor}`,
4619
+ fontSize: "12px",
4620
+ fontFamily: "Menlo, monospace",
4621
+ padding: "2px 12px 1px",
4622
+ display: "flex",
4623
+ alignItems: "center",
4624
+ background: historySnapshot.historyIndex === 0 ? "rgb(59 130 246 / 15%)" : void 0
4625
+ }
4626
+ },
4627
+ /* @__PURE__ */ import_react9.default.createElement(
4628
+ "span",
4629
+ {
4630
+ style: {
4631
+ fontFamily: "Menlo, monospace",
4632
+ fontSize: "11px",
4633
+ borderRadius: 4,
4634
+ display: "inline-block"
4635
+ }
4636
+ },
4637
+ "Initial state"
4638
+ )
4639
+ ), historySnapshot.history.map((entry, index) => {
4640
+ const metadata = entry.metadata;
4641
+ const { id, name, timestamp, ...rest } = metadata;
4642
+ return /* @__PURE__ */ import_react9.default.createElement(
4643
+ "div",
4644
+ {
4645
+ id: `${HISTORY_ELEMENT_PREFIX}${index + 1}`,
4646
+ key: index,
4647
+ style: {
4648
+ padding: "0px 12px 1px",
4649
+ borderBottom: `1px solid ${solidBorderColor}`,
4650
+ background: index + 1 === historySnapshot.historyIndex ? "rgb(59 130 246 / 15%)" : void 0
4651
+ }
4652
+ },
4653
+ typeof name === "string" && /* @__PURE__ */ import_react9.default.createElement(
4654
+ "pre",
4655
+ {
4656
+ style: {
4657
+ fontSize: "11px",
4658
+ display: "flex",
4659
+ flexWrap: "wrap",
4660
+ margin: 0
4661
+ }
4662
+ },
4663
+ entry.metadata.name,
4664
+ Object.keys(rest).length > 0 && /* @__PURE__ */ import_react9.default.createElement(import_react_inspector4.ObjectInspector, { data: rest, theme })
4665
+ ),
4666
+ entry.redoPatches?.map((patch, j) => /* @__PURE__ */ import_react9.default.createElement(
4667
+ "pre",
4668
+ {
4669
+ key: j,
4670
+ style: {
4671
+ fontSize: "11px",
4672
+ display: "flex",
4673
+ flexWrap: "wrap",
4674
+ margin: 0
4675
+ }
4676
+ },
4677
+ patch.op === "add" && /* @__PURE__ */ import_react9.default.createElement(import_react9.default.Fragment, null, /* @__PURE__ */ import_react9.default.createElement("span", { style: { fontStyle: "italic" } }, pathToString(patch.path)), " = ", /* @__PURE__ */ import_react9.default.createElement(import_react_inspector4.ObjectInspector, { data: patch.value, theme })),
4678
+ patch.op === "replace" && /* @__PURE__ */ import_react9.default.createElement(import_react9.default.Fragment, null, /* @__PURE__ */ import_react9.default.createElement("span", { style: { fontStyle: "italic" } }, pathToString(patch.path)), " = ", /* @__PURE__ */ import_react9.default.createElement(import_react_inspector4.ObjectInspector, { data: patch.value, theme })),
4679
+ patch.op === "remove" && /* @__PURE__ */ import_react9.default.createElement(import_react9.default.Fragment, null, /* @__PURE__ */ import_react9.default.createElement("span", { style: { color: theme.OBJECT_VALUE_STRING_COLOR } }, "delete", " "), /* @__PURE__ */ import_react9.default.createElement("span", { style: { fontStyle: "italic" } }, pathToString(patch.path))),
4680
+ patch.op === "move" && /* @__PURE__ */ import_react9.default.createElement(import_react9.default.Fragment, null, /* @__PURE__ */ import_react9.default.createElement("span", { style: { fontStyle: "italic" } }, pathToString(patch.from)), " -> ", /* @__PURE__ */ import_react9.default.createElement("span", { style: { fontStyle: "italic" } }, pathToString(patch.path)))
4681
+ ))
4682
+ );
4683
+ }))
4684
+ );
4685
+ }
4686
+
4687
+ // src/inspector/serialization.ts
4688
+ var import_state_manager = require("@noya-app/state-manager");
4689
+
4690
+ // src/inspector/zip/crc32.ts
4691
+ var CRC_TABLE = (() => {
4692
+ const t = new Uint32Array(256);
4693
+ for (let i = 0; i < 256; i++) {
4694
+ let c = i;
4695
+ for (let k = 0; k < 8; k++) c = c & 1 ? 3988292384 ^ c >>> 1 : c >>> 1;
4696
+ t[i] = c >>> 0;
4697
+ }
4698
+ return t;
4699
+ })();
4700
+ function crc32(u8) {
4701
+ let c = 4294967295;
4702
+ for (let i = 0; i < u8.length; i++)
4703
+ c = CRC_TABLE[(c ^ u8[i]) & 255] ^ c >>> 8;
4704
+ return (c ^ 4294967295) >>> 0;
4705
+ }
4706
+
4707
+ // src/inspector/zip/struct.ts
4708
+ var defineSchema = (s) => s;
4709
+ var defineSchemas = (m) => m;
4710
+ function sizeofFieldSpec(f, ctx) {
4711
+ if (f.type === "bytes")
4712
+ return typeof f.length === "function" ? f.length(ctx) : f.length;
4713
+ return f.type === "u8" ? 1 : f.type === "u16" ? 2 : 4;
4714
+ }
4715
+ function writeStruct(schema, values) {
4716
+ let total = 0;
4717
+ const ctx = { ...values };
4718
+ for (const f of schema) total += sizeofFieldSpec(f, ctx);
4719
+ const out = new Uint8Array(total);
4720
+ const view = new DataView(out.buffer);
4721
+ let o = 0;
4722
+ const vals = values;
4723
+ for (const f of schema) {
4724
+ if (f.type === "bytes") {
4725
+ const b = vals[f.name];
4726
+ out.set(b, o);
4727
+ o += b.length;
4728
+ continue;
4729
+ }
4730
+ const n = Number(vals[f.name]) >>> 0;
4731
+ if (f.type === "u8") {
4732
+ view.setUint8(o, n);
4733
+ o += 1;
4734
+ } else if (f.type === "u16") {
4735
+ view.setUint16(o, n, true);
4736
+ o += 2;
4737
+ } else {
4738
+ view.setUint32(o, n, true);
4739
+ o += 4;
4740
+ }
4741
+ }
4742
+ return out;
4743
+ }
4744
+ function readStruct(view, offset, schema) {
4745
+ const ctx = {};
4746
+ let o = offset;
4747
+ for (const f of schema) {
4748
+ if (f.type === "bytes") {
4749
+ const len = typeof f.length === "function" ? f.length(ctx) : f.length;
4750
+ const u8 = new Uint8Array(view.buffer, view.byteOffset + o, len);
4751
+ ctx[f.name] = new Uint8Array(u8);
4752
+ o += len;
4753
+ } else if (f.type === "u8") {
4754
+ ctx[f.name] = view.getUint8(o);
4755
+ o += 1;
4756
+ } else if (f.type === "u16") {
4757
+ ctx[f.name] = view.getUint16(o, true);
4758
+ o += 2;
4759
+ } else {
4760
+ ctx[f.name] = view.getUint32(o, true);
4761
+ o += 4;
4762
+ }
4763
+ }
4764
+ return { value: ctx, offset: o };
4765
+ }
4766
+
4767
+ // src/inspector/zip/TinyZip.ts
4768
+ var te = new TextEncoder();
4769
+ function utf8(s) {
4770
+ return te.encode(s);
4771
+ }
4772
+ function dosDateTime(d = /* @__PURE__ */ new Date()) {
4773
+ const time = d.getHours() << 11 | d.getMinutes() << 5 | Math.floor(d.getSeconds() / 2);
4774
+ const date = d.getFullYear() - 1980 << 9 | d.getMonth() + 1 << 5 | d.getDate();
4775
+ return { time, date };
4776
+ }
4777
+ var SIG = {
4778
+ LocalFile: 67324752,
4779
+ CentralFile: 33639248,
4780
+ EOCD: 101010256
4781
+ };
4782
+ var SCHEMA = defineSchemas({
4783
+ LocalFile: defineSchema([
4784
+ { name: "signature", type: "u32" },
4785
+ { name: "versionNeeded", type: "u16" },
4786
+ { name: "flags", type: "u16" },
4787
+ { name: "method", type: "u16" },
4788
+ { name: "time", type: "u16" },
4789
+ { name: "date", type: "u16" },
4790
+ { name: "crc32", type: "u32" },
4791
+ { name: "compSize", type: "u32" },
4792
+ { name: "uncompSize", type: "u32" },
4793
+ { name: "nameLen", type: "u16" },
4794
+ { name: "extraLen", type: "u16" },
4795
+ { name: "name", type: "bytes", length: (c) => c.nameLen },
4796
+ { name: "extra", type: "bytes", length: (c) => c.extraLen }
4797
+ ]),
4798
+ CentralFile: defineSchema([
4799
+ { name: "signature", type: "u32" },
4800
+ { name: "versionMadeBy", type: "u16" },
4801
+ { name: "versionNeeded", type: "u16" },
4802
+ { name: "flags", type: "u16" },
4803
+ { name: "method", type: "u16" },
4804
+ { name: "time", type: "u16" },
4805
+ { name: "date", type: "u16" },
4806
+ { name: "crc32", type: "u32" },
4807
+ { name: "compSize", type: "u32" },
4808
+ { name: "uncompSize", type: "u32" },
4809
+ { name: "nameLen", type: "u16" },
4810
+ { name: "extraLen", type: "u16" },
4811
+ { name: "commentLen", type: "u16" },
4812
+ { name: "diskStart", type: "u16" },
4813
+ { name: "intAttrs", type: "u16" },
4814
+ { name: "extAttrs", type: "u32" },
4815
+ { name: "localHeaderOffset", type: "u32" },
4816
+ { name: "name", type: "bytes", length: (c) => c.nameLen },
4817
+ { name: "extra", type: "bytes", length: (c) => c.extraLen },
4818
+ { name: "comment", type: "bytes", length: (c) => c.commentLen }
4819
+ ]),
4820
+ EOCD: defineSchema([
4821
+ { name: "signature", type: "u32" },
4822
+ { name: "diskNum", type: "u16" },
4823
+ { name: "cdStartDisk", type: "u16" },
4824
+ { name: "cdRecordsOnDisk", type: "u16" },
4825
+ { name: "cdRecordsTotal", type: "u16" },
4826
+ { name: "cdSize", type: "u32" },
4827
+ { name: "cdOffset", type: "u32" },
4828
+ { name: "commentLen", type: "u16" },
4829
+ { name: "comment", type: "bytes", length: (c) => c.commentLen }
4830
+ ])
4831
+ });
4832
+ function ensureSig(v, expect, where) {
4833
+ if (v !== expect)
4834
+ throw new Error(`Invalid signature for ${where}: 0x${v.toString(16)}`);
4835
+ }
4836
+ var TinyZip = class _TinyZip {
4837
+ _chunks = [];
4838
+ _offset = 0;
4839
+ _files = [];
4840
+ _rootPrefix = "";
4841
+ // e.g. "my-archive/" or ""
4842
+ _rootDirAdded = false;
4843
+ constructor(opts = {}) {
4844
+ if (opts.root) {
4845
+ const r = opts.root.replace(/^\/+|\/+$/g, "");
4846
+ if (r) this._rootPrefix = r + "/";
4847
+ }
4848
+ }
4849
+ _push(...arrs) {
4850
+ for (const a of arrs) {
4851
+ this._chunks.push(a);
4852
+ this._offset += a.length;
4853
+ }
4854
+ }
4855
+ _withRoot(name) {
4856
+ return this._rootPrefix && !name.startsWith(this._rootPrefix) ? this._rootPrefix + name.replace(/^\/+/, "") : name;
4857
+ }
4858
+ _ensureRootDir(date = /* @__PURE__ */ new Date()) {
4859
+ if (!this._rootPrefix || this._rootDirAdded) return;
4860
+ this._rootDirAdded = true;
4861
+ const dirName = this._rootPrefix;
4862
+ const nameBytes = utf8(dirName);
4863
+ const { time, date: dosDate } = dosDateTime(date);
4864
+ const localHeader = writeStruct(SCHEMA.LocalFile, {
4865
+ signature: SIG.LocalFile,
4866
+ versionNeeded: 20,
4867
+ flags: 2048,
4868
+ method: 0,
4869
+ time,
4870
+ date: dosDate,
4871
+ crc32: 0,
4872
+ compSize: 0,
4873
+ uncompSize: 0,
4874
+ nameLen: nameBytes.length,
4875
+ extraLen: 0,
4876
+ name: nameBytes,
4877
+ extra: new Uint8Array(0)
4878
+ });
4879
+ const localHeaderOffset = this._offset;
4880
+ this._push(localHeader);
4881
+ this._files.push({
4882
+ nameBytes,
4883
+ crc: 0,
4884
+ compSize: 0,
4885
+ uncompSize: 0,
4886
+ method: 0,
4887
+ time,
4888
+ dosDate,
4889
+ localHeaderOffset,
4890
+ externalAttrs: 16
4891
+ });
4892
+ }
4893
+ /** Add a file to the zip. "name" uses forward slashes for paths (e.g., "dir/file.txt"). */
4894
+ addFile(name, data, opts = {}) {
4895
+ const { date = /* @__PURE__ */ new Date() } = opts;
4896
+ this._ensureRootDir(date);
4897
+ const u8 = toU8(data);
4898
+ const fullName = this._withRoot(name);
4899
+ const nameBytes = utf8(fullName);
4900
+ const { time, date: dosDate } = dosDateTime(date);
4901
+ const crc = crc32(u8);
4902
+ const compSize = u8.length >>> 0;
4903
+ const uncompSize = u8.length >>> 0;
4904
+ const localHeaderOffset = this._offset;
4905
+ const localHeader = writeStruct(SCHEMA.LocalFile, {
4906
+ signature: SIG.LocalFile,
4907
+ versionNeeded: 20,
4908
+ flags: 2048,
4909
+ method: 0,
4910
+ time,
4911
+ date: dosDate,
4912
+ crc32: crc,
4913
+ compSize,
4914
+ uncompSize,
4915
+ nameLen: nameBytes.length,
4916
+ extraLen: 0,
4917
+ name: nameBytes,
4918
+ extra: new Uint8Array(0)
4919
+ });
4920
+ this._push(localHeader, u8);
4921
+ this._files.push({
4922
+ nameBytes,
4923
+ crc,
4924
+ compSize,
4925
+ uncompSize,
4926
+ method: 0,
4927
+ time,
4928
+ dosDate,
4929
+ localHeaderOffset,
4930
+ externalAttrs: 0
4931
+ });
4932
+ }
4933
+ // Create an explicit directory entry (name should end with "/").
4934
+ addDirectory(name, opts = {}) {
4935
+ const { date = /* @__PURE__ */ new Date() } = opts;
4936
+ this._ensureRootDir(date);
4937
+ const dirNameRaw = name.endsWith("/") ? name : name + "/";
4938
+ const fullName = this._withRoot(dirNameRaw);
4939
+ const nameBytes = utf8(fullName);
4940
+ const { time, date: dosDate } = dosDateTime(date);
4941
+ const localHeader = writeStruct(SCHEMA.LocalFile, {
4942
+ signature: SIG.LocalFile,
4943
+ versionNeeded: 20,
4944
+ flags: 2048,
4945
+ method: 0,
4946
+ time,
4947
+ date: dosDate,
4948
+ crc32: 0,
4949
+ compSize: 0,
4950
+ uncompSize: 0,
4951
+ nameLen: nameBytes.length,
4952
+ extraLen: 0,
4953
+ name: nameBytes,
4954
+ extra: new Uint8Array(0)
4955
+ });
4956
+ const localHeaderOffset = this._offset;
4957
+ this._push(localHeader);
4958
+ this._files.push({
4959
+ nameBytes,
4960
+ crc: 0,
4961
+ compSize: 0,
4962
+ uncompSize: 0,
4963
+ method: 0,
4964
+ time,
4965
+ dosDate,
4966
+ localHeaderOffset,
4967
+ externalAttrs: 16
4968
+ });
4969
+ }
4970
+ finish() {
4971
+ const cdStart = this._offset;
4972
+ for (const f of this._files) {
4973
+ const central = writeStruct(SCHEMA.CentralFile, {
4974
+ signature: SIG.CentralFile,
4975
+ versionMadeBy: 20,
4976
+ versionNeeded: 20,
4977
+ flags: 2048,
4978
+ method: f.method,
4979
+ time: f.time,
4980
+ date: f.dosDate,
4981
+ crc32: f.crc,
4982
+ compSize: f.compSize,
4983
+ uncompSize: f.uncompSize,
4984
+ nameLen: f.nameBytes.length,
4985
+ extraLen: 0,
4986
+ commentLen: 0,
4987
+ diskStart: 0,
4988
+ intAttrs: 0,
4989
+ extAttrs: f.externalAttrs,
4990
+ localHeaderOffset: f.localHeaderOffset,
4991
+ name: f.nameBytes,
4992
+ extra: new Uint8Array(0),
4993
+ comment: new Uint8Array(0)
4994
+ });
4995
+ this._push(central);
4996
+ }
4997
+ const cdSize = this._offset - cdStart;
4998
+ const eocd = writeStruct(SCHEMA.EOCD, {
4999
+ signature: SIG.EOCD,
5000
+ diskNum: 0,
5001
+ cdStartDisk: 0,
5002
+ cdRecordsOnDisk: this._files.length,
5003
+ cdRecordsTotal: this._files.length,
5004
+ cdSize,
5005
+ cdOffset: cdStart,
5006
+ commentLen: 0,
5007
+ comment: new Uint8Array(0)
5008
+ });
5009
+ this._push(eocd);
5010
+ const merged = new Uint8Array(this._offset);
5011
+ let offset = 0;
5012
+ for (const chunk of this._chunks) {
5013
+ merged.set(chunk, offset);
5014
+ offset += chunk.length;
5015
+ }
5016
+ return merged;
5017
+ }
5018
+ static create(files, opts = {}) {
5019
+ const zip = new _TinyZip(opts);
5020
+ for (const [name, data] of Object.entries(files)) {
5021
+ if (name.endsWith("/")) zip.addDirectory(name);
5022
+ else zip.addFile(name, data);
5023
+ }
5024
+ return zip.finish();
5025
+ }
5026
+ static parse(input) {
5027
+ const u8 = toU8(input);
5028
+ const view = new DataView(u8.buffer, u8.byteOffset, u8.byteLength);
5029
+ const eocdOff = findEOCDOffset(u8);
5030
+ const { value: eocd } = readStruct(view, eocdOff, SCHEMA.EOCD);
5031
+ ensureSig(eocd.signature, SIG.EOCD, "EOCD");
5032
+ if (eocd.commentLen !== 0) throw new Error("Unsupported: EOCD comment");
5033
+ if (eocd.diskNum !== 0 || eocd.cdStartDisk !== 0)
5034
+ throw new Error("Unsupported: multi-disk");
5035
+ const entries = [];
5036
+ let cdPtr = eocd.cdOffset;
5037
+ for (let i = 0; i < eocd.cdRecordsTotal; i++) {
5038
+ const { value: cdf, offset: next } = readStruct(
5039
+ view,
5040
+ cdPtr,
5041
+ SCHEMA.CentralFile
5042
+ );
5043
+ ensureSig(cdf.signature, SIG.CentralFile, "Central Directory");
5044
+ const name = new TextDecoder().decode(cdf.name);
5045
+ const isDir = (cdf.extAttrs & 16) !== 0 || name.endsWith("/");
5046
+ if (cdf.extraLen !== 0 || cdf.commentLen !== 0)
5047
+ throw new Error("Unsupported: extra/comment in central dir");
5048
+ entries.push({
5049
+ name,
5050
+ isDirectory: isDir,
5051
+ crc32: cdf.crc32 >>> 0,
5052
+ size: cdf.uncompSize >>> 0,
5053
+ compSize: cdf.compSize >>> 0,
5054
+ time: cdf.time >>> 0,
5055
+ dosDate: cdf.date >>> 0,
5056
+ localHeaderOffset: cdf.localHeaderOffset >>> 0
5057
+ });
5058
+ cdPtr = next;
5059
+ }
5060
+ const results = [];
5061
+ for (const e of entries) {
5062
+ const { value: lfh, offset: afterHeader } = readStruct(
5063
+ view,
5064
+ e.localHeaderOffset,
5065
+ SCHEMA.LocalFile
5066
+ );
5067
+ ensureSig(lfh.signature, SIG.LocalFile, "Local File");
5068
+ if (lfh.flags !== 2048)
5069
+ throw new Error("Unsupported: flags (expect UTF-8 only)");
5070
+ if (lfh.method !== 0)
5071
+ throw new Error("Unsupported: compression (expect store only)");
5072
+ if (lfh.extraLen !== 0)
5073
+ throw new Error("Unsupported: extra fields in local header");
5074
+ const dataStart = afterHeader;
5075
+ const dataEnd = dataStart + lfh.compSize;
5076
+ const data = e.isDirectory ? new Uint8Array(0) : new Uint8Array(u8.subarray(dataStart, dataEnd));
5077
+ results.push({ ...e, data });
5078
+ }
5079
+ return results;
5080
+ }
5081
+ // Quick utility: return a map of file data (directories omitted)
5082
+ static extract(input) {
5083
+ const entries = this.parse(input);
5084
+ const out = {};
5085
+ for (const e of entries) if (!e.isDirectory) out[e.name] = e.data;
5086
+ return out;
5087
+ }
5088
+ };
5089
+ function toU8(input) {
5090
+ if (typeof input === "string") return utf8(input);
5091
+ if (input instanceof Uint8Array) return input;
5092
+ return new Uint8Array(input);
5093
+ }
5094
+ function findEOCDOffset(u8) {
5095
+ const view = new DataView(u8.buffer, u8.byteOffset, u8.byteLength);
5096
+ const minSize = 22;
5097
+ if (u8.length >= minSize) {
5098
+ const at = u8.length - minSize;
5099
+ if (view.getUint32(at, true) === SIG.EOCD) return at;
5100
+ }
5101
+ const start = Math.max(0, u8.length - 1024);
5102
+ for (let i = u8.length - 4; i >= start; i--) {
5103
+ if (view.getUint32(i, true) === SIG.EOCD) return i;
5104
+ }
5105
+ throw new Error("EOCD not found");
5106
+ }
5107
+
5108
+ // src/inspector/serialization.ts
5109
+ async function fetchAssetMap(assets) {
5110
+ const res = await Promise.all(
5111
+ assets.map(async (asset) => {
5112
+ const url = asset.url;
5113
+ const response = await fetch(url);
5114
+ const data = await response.arrayBuffer();
5115
+ return [asset.id, data];
5116
+ })
5117
+ );
5118
+ return Object.fromEntries(res);
5119
+ }
5120
+ async function exportAll(noyaManager) {
5121
+ const { multiplayerStateManager, assetManager } = noyaManager;
5122
+ const assetMap = await fetchAssetMap(assetManager.assets$.get());
5123
+ return encodeAll({
5124
+ state: multiplayerStateManager.optimisticState$.get(),
5125
+ schema: multiplayerStateManager.schema,
5126
+ assets: assetManager.assets$.get(),
5127
+ assetMap
5128
+ });
5129
+ }
5130
+ function encodeAll({
5131
+ state,
5132
+ schema,
5133
+ assets,
5134
+ assetMap
5135
+ }) {
5136
+ const zip = new TinyZip();
5137
+ zip.addFile("state.json", JSON.stringify(state, null, 2));
5138
+ if (schema) {
5139
+ const encodedSchema = encodeSchema(schema);
5140
+ zip.addFile("schema.json", JSON.stringify(encodedSchema, null, 2));
5141
+ }
5142
+ if (assets.length) {
5143
+ zip.addFile("assets.json", JSON.stringify(assets, null, 2));
5144
+ }
5145
+ for (const [id, data] of Object.entries(assetMap)) {
5146
+ zip.addFile(`assets/${id}`, data);
5147
+ }
5148
+ return zip.finish();
5149
+ }
5150
+ async function importAll(buffer, noyaManager, {
5151
+ shouldAllowSchemaChange
5152
+ } = {}) {
5153
+ let { state, schema, assets, assetMap } = await decodeAll(buffer);
5154
+ if (shouldAllowSchemaChange && noyaManager.options.schema && schema) {
5155
+ const oldSchemaHash = (0, import_state_manager.createHash)(noyaManager.options.schema);
5156
+ const newSchemaHash = (0, import_state_manager.createHash)(schema);
5157
+ if (oldSchemaHash !== newSchemaHash) {
5158
+ const shouldAllow = shouldAllowSchemaChange({
5159
+ oldSchema: noyaManager.options.schema,
5160
+ newSchema: schema
5161
+ });
5162
+ if (!shouldAllow) {
5163
+ throw new Error("Schema change not allowed");
5164
+ }
5165
+ }
5166
+ }
5167
+ if (assets.length) {
5168
+ await Promise.all(
5169
+ noyaManager.assetManager.assets$.get().map((asset) => noyaManager.assetManager.delete(asset.id))
5170
+ );
5171
+ const idPairs = await Promise.all(
5172
+ assets.map(async (asset) => {
5173
+ const newAsset = await noyaManager.assetManager.create({
5174
+ data: assetMap[asset.id],
5175
+ contentType: asset.contentType
5176
+ });
5177
+ return [asset.id, newAsset.id];
5178
+ })
5179
+ );
5180
+ const replacementMap = Object.fromEntries(idPairs);
5181
+ state = replaceDeep(state, replacementMap);
5182
+ }
5183
+ noyaManager.initialState = state;
5184
+ noyaManager.forceInit();
5185
+ }
5186
+ function decodeAll(buffer) {
5187
+ const zip = TinyZip.extract(buffer);
5188
+ const stateFile = zip["state.json"];
5189
+ const schemaFile = zip["schema.json"];
5190
+ const assetsFile = zip["assets.json"];
5191
+ if (!stateFile) {
5192
+ throw new Error("State file not found");
5193
+ }
5194
+ const state = JSON.parse(new TextDecoder().decode(stateFile));
5195
+ let schema;
5196
+ if (schemaFile) {
5197
+ const encodedSchema = JSON.parse(new TextDecoder().decode(schemaFile));
5198
+ schema = decodeSchema(encodedSchema);
5199
+ }
5200
+ let assets = [];
5201
+ let assetMap = {};
5202
+ if (assetsFile) {
5203
+ assets = JSON.parse(new TextDecoder().decode(assetsFile));
5204
+ for (const asset of assets) {
5205
+ const data = zip[`assets/${asset.id}`];
5206
+ if (!data) {
5207
+ throw new Error(`Asset ${asset.id} not found`);
5208
+ }
5209
+ assetMap[asset.id] = data;
5210
+ }
5211
+ }
5212
+ return { state, schema, assets, assetMap };
5213
+ }
5214
+ function replaceDeep(obj, replacementMap) {
5215
+ switch (typeof obj) {
5216
+ case "object":
5217
+ if (obj === null) {
5218
+ return obj;
5219
+ }
5220
+ if (Array.isArray(obj)) {
5221
+ return obj.map((item) => replaceDeep(item, replacementMap));
5222
+ }
5223
+ return Object.fromEntries(
5224
+ Object.entries(obj).map(([key, value]) => [
5225
+ key,
5226
+ replaceDeep(value, replacementMap)
5227
+ ])
5228
+ );
5229
+ case "string":
5230
+ return replacementMap[obj] ?? obj;
5231
+ default:
5232
+ return obj;
5233
+ }
5234
+ }
5235
+
5236
+ // src/inspector/StateInspectorToggleButton.tsx
5237
+ var import_react10 = __toESM(require("react"));
5238
+ function StateInspectorToggleButton({
5239
+ showInspector,
5240
+ setShowInspector,
5241
+ theme,
5242
+ anchor
5243
+ }) {
5244
+ const isRightAnchor = anchor === "right";
5245
+ const rightIcon = /* @__PURE__ */ import_react10.default.createElement(
5246
+ "svg",
5247
+ {
5248
+ xmlns: "http://www.w3.org/2000/svg",
5249
+ fill: "none",
5250
+ viewBox: "0 0 24 24",
5251
+ strokeWidth: 1.5,
5252
+ stroke: "currentColor",
5253
+ className: "size-6"
5254
+ },
5255
+ /* @__PURE__ */ import_react10.default.createElement(
5256
+ "path",
5257
+ {
5258
+ strokeLinecap: "round",
5259
+ strokeLinejoin: "round",
5260
+ d: "m5.25 4.5 7.5 7.5-7.5 7.5m6-15 7.5 7.5-7.5 7.5"
5261
+ }
5262
+ )
5263
+ );
5264
+ const leftIcon = /* @__PURE__ */ import_react10.default.createElement(
5265
+ "svg",
5266
+ {
5267
+ xmlns: "http://www.w3.org/2000/svg",
5268
+ fill: "none",
5269
+ viewBox: "0 0 24 24",
5270
+ strokeWidth: 1.5,
5271
+ stroke: "currentColor",
5272
+ className: "size-6"
5273
+ },
5274
+ /* @__PURE__ */ import_react10.default.createElement(
5275
+ "path",
5276
+ {
5277
+ strokeLinecap: "round",
5278
+ strokeLinejoin: "round",
5279
+ d: "m18.75 4.5-7.5 7.5 7.5 7.5m-6-15L5.25 12l7.5 7.5"
5280
+ }
5281
+ )
5282
+ );
5283
+ return /* @__PURE__ */ import_react10.default.createElement(
5284
+ "span",
5285
+ {
5286
+ role: "button",
5287
+ style: {
5288
+ flex: "0",
5289
+ appearance: "none",
5290
+ color: theme.BASE_COLOR,
5291
+ border: "none",
5292
+ fontSize: "12px",
5293
+ whiteSpace: "nowrap",
5294
+ display: "inline-flex",
5295
+ alignItems: "center",
5296
+ justifyContent: "center",
5297
+ padding: "2px 0"
5298
+ },
5299
+ onClick: (event) => {
5300
+ event.stopPropagation();
5301
+ setShowInspector(!showInspector);
5302
+ }
5303
+ },
5304
+ showInspector ? "Hide Inspector" : /* @__PURE__ */ import_react10.default.createElement("span", { style: { width: "12px", height: "12px" } }, isRightAnchor ? rightIcon : leftIcon)
5305
+ );
5306
+ }
5307
+
5308
+ // src/inspector/useLocalStorageState.tsx
5309
+ var import_react11 = __toESM(require("react"));
5310
+ var localStorage = typeof window !== "undefined" ? window.localStorage : null;
5311
+ function useLocalStorageState(key, defaultValue) {
5312
+ const [state, setState] = import_react11.default.useState(() => {
5313
+ const value = localStorage?.getItem(key);
5314
+ let result = defaultValue;
5315
+ if (value) {
5316
+ try {
5317
+ result = JSON.parse(value);
5318
+ } catch (error) {
5319
+ console.error("Error parsing localStorage value", error);
5320
+ }
5321
+ }
5322
+ return result;
5323
+ });
5324
+ const setLocalStorageState = (value) => {
5325
+ localStorage?.setItem(key, JSON.stringify(value));
5326
+ setState(value);
5327
+ };
5328
+ return [state, setLocalStorageState];
5329
+ }
5330
+
5331
+ // src/inspector/StateInspector.tsx
5332
+ var StateInspector = (0, import_react_utils.memoGeneric)(function StateInspector2({
5333
+ noyaManager,
5334
+ colorScheme = "light",
5335
+ anchor = "right",
5336
+ unstyled = false,
5337
+ ...props
5338
+ }) {
5339
+ const {
5340
+ multiplayerStateManager,
5341
+ assetManager,
5342
+ connectedUsersManager,
5343
+ secretManager,
5344
+ ephemeralUserDataManager,
5345
+ connectionEventManager,
5346
+ taskManager,
5347
+ ioManager
5348
+ } = noyaManager;
5349
+ const [didMount, setDidMount] = import_react12.default.useState(false);
5350
+ const tasks = useObservable(taskManager.tasks$);
5351
+ const inputs = useObservable(ioManager.inputs$);
5352
+ const outputTransforms = useObservable(ioManager.outputTransforms$);
5353
+ (0, import_react12.useLayoutEffect)(() => {
5354
+ setDidMount(true);
5355
+ }, []);
5356
+ const eventsContainerRef = import_react12.default.useRef(null);
5357
+ const [showInspector, setShowInspector] = useLocalStorageState(
5358
+ "noya-multiplayer-react-show-inspector",
5359
+ true
5360
+ );
5361
+ const [showEvents, setShowEvents] = useLocalStorageState(
5362
+ "noya-multiplayer-react-show-events",
5363
+ false
4310
5364
  );
4311
5365
  const [showHistory, setShowHistory] = useLocalStorageState(
4312
5366
  "noya-multiplayer-react-show-history",
@@ -4345,7 +5399,7 @@ var StateInspector = (0, import_react_utils.memoGeneric)(function StateInspector
4345
5399
  false
4346
5400
  );
4347
5401
  const connectionEvents = useObservable(connectionEventManager.events$);
4348
- (0, import_react3.useEffect)(() => {
5402
+ (0, import_react12.useEffect)(() => {
4349
5403
  if (eventsContainerRef.current) {
4350
5404
  eventsContainerRef.current.scrollTop = eventsContainerRef.current.scrollHeight;
4351
5405
  }
@@ -4366,25 +5420,8 @@ var StateInspector = (0, import_react_utils.memoGeneric)(function StateInspector
4366
5420
  const outputTransformsInitialized = useObservable(
4367
5421
  ioManager.outputTransformsInitialized$
4368
5422
  );
4369
- (0, import_react3.useEffect)(() => {
4370
- if (historyContainerRef.current) {
4371
- historyContainerRef.current.scrollTop = historyContainerRef.current.scrollHeight;
4372
- }
4373
- }, [historySnapshot]);
4374
- (0, import_react3.useEffect)(() => {
4375
- if (!historyContainerRef.current) return;
4376
- const historyEntry = historyContainerRef.current.querySelector(
4377
- `#${HISTORY_ELEMENT_PREFIX}${historySnapshot.historyIndex}`
4378
- );
4379
- if (historyEntry) {
4380
- historyEntry.scrollIntoView({
4381
- block: "nearest",
4382
- inline: "nearest"
4383
- });
4384
- }
4385
- }, [historySnapshot.historyIndex]);
4386
- const theme = colorScheme === "light" ? lightTheme : darkTheme;
4387
- const solidBorderColor = colorScheme === "light" ? "rgb(223 223 223)" : "rgb(29 29 29)";
5423
+ const theme = getStateInspectorTheme(colorScheme);
5424
+ const solidBorderColor = getStateInspectorBorderColor(colorScheme);
4388
5425
  const baseStyle = {
4389
5426
  position: "fixed",
4390
5427
  top: 12,
@@ -4404,9 +5441,24 @@ var StateInspector = (0, import_react_utils.memoGeneric)(function StateInspector
4404
5441
  zIndex: 9999,
4405
5442
  lineHeight: "13px"
4406
5443
  };
5444
+ const handleExportAll = (0, import_react12.useCallback)(async () => {
5445
+ const buffer = await exportAll(noyaManager);
5446
+ (0, import_react_utils.downloadBlob)(new Blob([buffer]), "state.zip");
5447
+ }, [noyaManager]);
5448
+ const handleImportAll = (0, import_react12.useCallback)(async () => {
5449
+ const file = await uploadFile();
5450
+ const buffer = await file.arrayBuffer();
5451
+ importAll(buffer, noyaManager, {
5452
+ shouldAllowSchemaChange: () => {
5453
+ return confirm(
5454
+ `The imported state uses a different schema than the schema this app expects. Do you want to continue?`
5455
+ );
5456
+ }
5457
+ });
5458
+ }, [noyaManager]);
4407
5459
  if (!didMount) return null;
4408
5460
  if (!showInspector) {
4409
- return /* @__PURE__ */ import_react3.default.createElement(
5461
+ return /* @__PURE__ */ import_react12.default.createElement(
4410
5462
  "div",
4411
5463
  {
4412
5464
  ...props,
@@ -4418,8 +5470,8 @@ var StateInspector = (0, import_react_utils.memoGeneric)(function StateInspector
4418
5470
  },
4419
5471
  onClick: () => setShowInspector(true)
4420
5472
  },
4421
- /* @__PURE__ */ import_react3.default.createElement(
4422
- ToggleButton,
5473
+ /* @__PURE__ */ import_react12.default.createElement(
5474
+ StateInspectorToggleButton,
4423
5475
  {
4424
5476
  showInspector,
4425
5477
  setShowInspector,
@@ -4429,7 +5481,7 @@ var StateInspector = (0, import_react_utils.memoGeneric)(function StateInspector
4429
5481
  )
4430
5482
  );
4431
5483
  }
4432
- return /* @__PURE__ */ import_react3.default.createElement(
5484
+ return /* @__PURE__ */ import_react12.default.createElement(
4433
5485
  "div",
4434
5486
  {
4435
5487
  ...props,
@@ -4438,8 +5490,8 @@ var StateInspector = (0, import_react_utils.memoGeneric)(function StateInspector
4438
5490
  ...props.style
4439
5491
  }
4440
5492
  },
4441
- /* @__PURE__ */ import_react3.default.createElement(
4442
- DisclosureSection,
5493
+ /* @__PURE__ */ import_react12.default.createElement(
5494
+ StateInspectorDisclosureSection,
4443
5495
  {
4444
5496
  isFirst: true,
4445
5497
  open: showUsers,
@@ -4450,8 +5502,8 @@ var StateInspector = (0, import_react_utils.memoGeneric)(function StateInspector
4450
5502
  flex: "0 0 auto",
4451
5503
  maxHeight: "200px"
4452
5504
  },
4453
- right: /* @__PURE__ */ import_react3.default.createElement(
4454
- ToggleButton,
5505
+ right: /* @__PURE__ */ import_react12.default.createElement(
5506
+ StateInspectorToggleButton,
4455
5507
  {
4456
5508
  showInspector,
4457
5509
  setShowInspector,
@@ -4460,14 +5512,14 @@ var StateInspector = (0, import_react_utils.memoGeneric)(function StateInspector
4460
5512
  }
4461
5513
  )
4462
5514
  },
4463
- /* @__PURE__ */ import_react3.default.createElement("div", { style: { ...styles.sectionInner, flex: "0 0 auto" } }, connectedUsers?.map((user) => /* @__PURE__ */ import_react3.default.createElement(
4464
- InspectorRow,
5515
+ /* @__PURE__ */ import_react12.default.createElement(StateInspectorDisclosureRowInner, { style: { flex: "0 0 auto" } }, connectedUsers?.map((user) => /* @__PURE__ */ import_react12.default.createElement(
5516
+ StateInspectorRow,
4465
5517
  {
4466
5518
  key: user.id,
4467
5519
  colorScheme,
4468
5520
  variant: user.id === userId ? "up" : void 0
4469
5521
  },
4470
- user.image && /* @__PURE__ */ import_react3.default.createElement(
5522
+ user.image && /* @__PURE__ */ import_react12.default.createElement(
4471
5523
  "img",
4472
5524
  {
4473
5525
  src: user.image,
@@ -4488,7 +5540,7 @@ var StateInspector = (0, import_react_utils.memoGeneric)(function StateInspector
4488
5540
  " (",
4489
5541
  ellipsis(user.id.toString(), 8, "middle"),
4490
5542
  ")"
4491
- )), !connectedUsers && /* @__PURE__ */ import_react3.default.createElement(
5543
+ )), !connectedUsers && /* @__PURE__ */ import_react12.default.createElement(
4492
5544
  "div",
4493
5545
  {
4494
5546
  style: {
@@ -4499,13 +5551,13 @@ var StateInspector = (0, import_react_utils.memoGeneric)(function StateInspector
4499
5551
  gap: "4px"
4500
5552
  }
4501
5553
  },
4502
- /* @__PURE__ */ import_react3.default.createElement("span", null, "No connected users")
5554
+ /* @__PURE__ */ import_react12.default.createElement("span", null, "No connected users")
4503
5555
  ))
4504
5556
  ),
4505
- /* @__PURE__ */ import_react3.default.createElement(
4506
- DisclosureSection,
5557
+ /* @__PURE__ */ import_react12.default.createElement(
5558
+ StateInspectorDisclosureSection,
4507
5559
  {
4508
- title: /* @__PURE__ */ import_react3.default.createElement(TitleLabel, null, "Data", /* @__PURE__ */ import_react3.default.createElement(
5560
+ title: /* @__PURE__ */ import_react12.default.createElement(TitleLabel, null, "Data", /* @__PURE__ */ import_react12.default.createElement(
4509
5561
  ColoredDot,
4510
5562
  {
4511
5563
  type: multipeerStateInitialized ? "success" : "error"
@@ -4514,16 +5566,18 @@ var StateInspector = (0, import_react_utils.memoGeneric)(function StateInspector
4514
5566
  colorScheme,
4515
5567
  setOpen: setShowData,
4516
5568
  open: showData,
4517
- right: /* @__PURE__ */ import_react3.default.createElement(
5569
+ right: /* @__PURE__ */ import_react12.default.createElement(
4518
5570
  "span",
4519
5571
  {
4520
5572
  style: {
4521
5573
  display: "flex",
4522
- gap: "4px"
5574
+ gap: "12px"
4523
5575
  }
4524
5576
  },
4525
- /* @__PURE__ */ import_react3.default.createElement(
4526
- SmallButton,
5577
+ /* @__PURE__ */ import_react12.default.createElement(StateInspectorButton, { theme, onClick: handleImportAll }, "Import"),
5578
+ /* @__PURE__ */ import_react12.default.createElement(StateInspectorButton, { theme, onClick: handleExportAll }, "Export"),
5579
+ /* @__PURE__ */ import_react12.default.createElement(
5580
+ StateInspectorButton,
4527
5581
  {
4528
5582
  theme,
4529
5583
  onClick: () => {
@@ -4534,15 +5588,15 @@ var StateInspector = (0, import_react_utils.memoGeneric)(function StateInspector
4534
5588
  )
4535
5589
  )
4536
5590
  },
4537
- /* @__PURE__ */ import_react3.default.createElement("div", { style: styles.sectionInner }, /* @__PURE__ */ import_react3.default.createElement(InspectorRow, { colorScheme }, /* @__PURE__ */ import_react3.default.createElement(
4538
- import_react_inspector.ObjectInspector,
5591
+ /* @__PURE__ */ import_react12.default.createElement(StateInspectorDisclosureRowInner, null, /* @__PURE__ */ import_react12.default.createElement(StateInspectorRow, { colorScheme }, /* @__PURE__ */ import_react12.default.createElement(
5592
+ import_react_inspector5.ObjectInspector,
4539
5593
  {
4540
5594
  name: multiplayerStateManager.schema ? "state" : void 0,
4541
5595
  data: state,
4542
5596
  theme
4543
5597
  }
4544
- )), multiplayerStateManager.schema && /* @__PURE__ */ import_react3.default.createElement(InspectorRow, { colorScheme }, /* @__PURE__ */ import_react3.default.createElement(
4545
- import_react_inspector.ObjectInspector,
5598
+ )), multiplayerStateManager.schema && /* @__PURE__ */ import_react12.default.createElement(StateInspectorRow, { colorScheme }, /* @__PURE__ */ import_react12.default.createElement(
5599
+ import_react_inspector5.ObjectInspector,
4546
5600
  {
4547
5601
  name: "schema",
4548
5602
  data: multiplayerStateManager.schema,
@@ -4550,151 +5604,25 @@ var StateInspector = (0, import_react_utils.memoGeneric)(function StateInspector
4550
5604
  }
4551
5605
  )))
4552
5606
  ),
4553
- /* @__PURE__ */ import_react3.default.createElement(
4554
- DisclosureSection,
5607
+ /* @__PURE__ */ import_react12.default.createElement(
5608
+ HistorySection,
4555
5609
  {
4556
- open: showHistory,
4557
- setOpen: setShowHistory,
4558
- title: "History",
5610
+ showHistory,
5611
+ setShowHistory,
4559
5612
  colorScheme,
4560
- right: /* @__PURE__ */ import_react3.default.createElement(
4561
- "span",
4562
- {
4563
- style: {
4564
- display: "flex",
4565
- gap: "4px"
4566
- }
4567
- },
4568
- /* @__PURE__ */ import_react3.default.createElement(
4569
- SmallButton,
4570
- {
4571
- disabled: !historySnapshot.canUndo,
4572
- theme,
4573
- onClick: () => {
4574
- multiplayerStateManager.undo();
4575
- }
4576
- },
4577
- /* @__PURE__ */ import_react3.default.createElement("span", { style: { width: "12px", height: "12px" } }, /* @__PURE__ */ import_react3.default.createElement(
4578
- "svg",
4579
- {
4580
- xmlns: "http://www.w3.org/2000/svg",
4581
- width: "1em",
4582
- height: "1em",
4583
- viewBox: "0 0 20 20"
4584
- },
4585
- /* @__PURE__ */ import_react3.default.createElement(
4586
- "path",
4587
- {
4588
- fill: "currentColor",
4589
- 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"
4590
- }
4591
- )
4592
- ))
4593
- ),
4594
- /* @__PURE__ */ import_react3.default.createElement(
4595
- SmallButton,
4596
- {
4597
- disabled: !historySnapshot.canRedo,
4598
- theme,
4599
- onClick: () => {
4600
- multiplayerStateManager.redo();
4601
- }
4602
- },
4603
- /* @__PURE__ */ import_react3.default.createElement("span", { style: { width: "12px", height: "12px" } }, /* @__PURE__ */ import_react3.default.createElement(
4604
- "svg",
4605
- {
4606
- xmlns: "http://www.w3.org/2000/svg",
4607
- width: "1em",
4608
- height: "1em",
4609
- viewBox: "0 0 20 20"
4610
- },
4611
- /* @__PURE__ */ import_react3.default.createElement(
4612
- "path",
4613
- {
4614
- fill: "currentColor",
4615
- 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"
4616
- }
4617
- )
4618
- ))
4619
- )
4620
- )
4621
- },
4622
- /* @__PURE__ */ import_react3.default.createElement("div", { ref: historyContainerRef, style: styles.sectionInner }, /* @__PURE__ */ import_react3.default.createElement(
4623
- "div",
4624
- {
4625
- id: `${HISTORY_ELEMENT_PREFIX}0`,
4626
- style: {
4627
- borderBottom: `1px solid ${solidBorderColor}`,
4628
- fontSize: "12px",
4629
- fontFamily: "Menlo, monospace",
4630
- padding: "2px 12px 1px",
4631
- display: "flex",
4632
- alignItems: "center",
4633
- background: historySnapshot.historyIndex === 0 ? "rgb(59 130 246 / 15%)" : void 0
4634
- }
4635
- },
4636
- /* @__PURE__ */ import_react3.default.createElement(
4637
- "span",
4638
- {
4639
- style: {
4640
- fontFamily: "Menlo, monospace",
4641
- fontSize: "11px",
4642
- borderRadius: 4,
4643
- display: "inline-block"
4644
- }
4645
- },
4646
- "Initial state"
4647
- )
4648
- ), historySnapshot.history.map((entry, index) => /* @__PURE__ */ import_react3.default.createElement(
4649
- "div",
4650
- {
4651
- id: `${HISTORY_ELEMENT_PREFIX}${index + 1}`,
4652
- key: index,
4653
- style: {
4654
- padding: "0px 12px 1px",
4655
- borderBottom: `1px solid ${solidBorderColor}`,
4656
- background: index + 1 === historySnapshot.historyIndex ? "rgb(59 130 246 / 15%)" : void 0
4657
- }
4658
- },
4659
- "name" in entry.metadata && typeof entry.metadata.name === "string" && /* @__PURE__ */ import_react3.default.createElement(
4660
- "pre",
4661
- {
4662
- style: {
4663
- fontSize: "11px",
4664
- display: "flex",
4665
- flexWrap: "wrap",
4666
- margin: 0
4667
- }
4668
- },
4669
- entry.metadata.name
4670
- ),
4671
- entry.redoPatches?.map((patch, j) => /* @__PURE__ */ import_react3.default.createElement(
4672
- "pre",
4673
- {
4674
- key: j,
4675
- style: {
4676
- fontSize: "11px",
4677
- display: "flex",
4678
- flexWrap: "wrap",
4679
- margin: 0
4680
- }
4681
- },
4682
- patch.op === "add" && /* @__PURE__ */ import_react3.default.createElement(import_react3.default.Fragment, null, /* @__PURE__ */ import_react3.default.createElement("span", { style: { fontStyle: "italic" } }, pathToString(patch.path)), " = ", /* @__PURE__ */ import_react3.default.createElement(import_react_inspector.ObjectInspector, { data: patch.value, theme })),
4683
- patch.op === "replace" && /* @__PURE__ */ import_react3.default.createElement(import_react3.default.Fragment, null, /* @__PURE__ */ import_react3.default.createElement("span", { style: { fontStyle: "italic" } }, pathToString(patch.path)), " = ", /* @__PURE__ */ import_react3.default.createElement(import_react_inspector.ObjectInspector, { data: patch.value, theme })),
4684
- patch.op === "remove" && /* @__PURE__ */ import_react3.default.createElement(import_react3.default.Fragment, null, /* @__PURE__ */ import_react3.default.createElement("span", { style: { color: theme.OBJECT_VALUE_STRING_COLOR } }, "delete", " "), /* @__PURE__ */ import_react3.default.createElement("span", { style: { fontStyle: "italic" } }, pathToString(patch.path))),
4685
- patch.op === "move" && /* @__PURE__ */ import_react3.default.createElement(import_react3.default.Fragment, null, /* @__PURE__ */ import_react3.default.createElement("span", { style: { fontStyle: "italic" } }, pathToString(patch.from)), " -> ", /* @__PURE__ */ import_react3.default.createElement("span", { style: { fontStyle: "italic" } }, pathToString(patch.path)))
4686
- ))
4687
- )))
5613
+ historySnapshot,
5614
+ multiplayerStateManager
5615
+ }
4688
5616
  ),
4689
- /* @__PURE__ */ import_react3.default.createElement(
4690
- DisclosureSection,
5617
+ /* @__PURE__ */ import_react12.default.createElement(
5618
+ StateInspectorDisclosureSection,
4691
5619
  {
4692
5620
  open: showAssets,
4693
5621
  setOpen: setShowAssets,
4694
- title: /* @__PURE__ */ import_react3.default.createElement(TitleLabel, null, "Assets", /* @__PURE__ */ import_react3.default.createElement(ColoredDot, { type: assetsInitialized ? "success" : "error" })),
5622
+ title: /* @__PURE__ */ import_react12.default.createElement(TitleLabel, null, "Assets (", assets.length, ")", /* @__PURE__ */ import_react12.default.createElement(ColoredDot, { type: assetsInitialized ? "success" : "error" })),
4695
5623
  colorScheme,
4696
- right: /* @__PURE__ */ import_react3.default.createElement("span", { style: { display: "flex", gap: "10px" } }, /* @__PURE__ */ import_react3.default.createElement(
4697
- SmallButton,
5624
+ right: /* @__PURE__ */ import_react12.default.createElement("span", { style: { display: "flex", gap: "10px" } }, /* @__PURE__ */ import_react12.default.createElement(
5625
+ StateInspectorButton,
4698
5626
  {
4699
5627
  theme,
4700
5628
  onClick: () => {
@@ -4706,8 +5634,8 @@ var StateInspector = (0, import_react_utils.memoGeneric)(function StateInspector
4706
5634
  }
4707
5635
  },
4708
5636
  "Reload"
4709
- ), /* @__PURE__ */ import_react3.default.createElement(
4710
- SmallButton,
5637
+ ), /* @__PURE__ */ import_react12.default.createElement(
5638
+ StateInspectorButton,
4711
5639
  {
4712
5640
  theme,
4713
5641
  onClick: () => {
@@ -4730,8 +5658,8 @@ var StateInspector = (0, import_react_utils.memoGeneric)(function StateInspector
4730
5658
  "Upload"
4731
5659
  ))
4732
5660
  },
4733
- /* @__PURE__ */ import_react3.default.createElement("div", { style: styles.sectionInner }, assets.map((asset) => /* @__PURE__ */ import_react3.default.createElement(InspectorRow, { key: asset.id, colorScheme }, /* @__PURE__ */ import_react3.default.createElement(import_react_inspector.ObjectInspector, { name: asset.id, data: asset, theme }), /* @__PURE__ */ import_react3.default.createElement(
4734
- SmallButton,
5661
+ /* @__PURE__ */ import_react12.default.createElement(StateInspectorDisclosureRowInner, null, assets.map((asset) => /* @__PURE__ */ import_react12.default.createElement(StateInspectorRow, { key: asset.id, colorScheme }, /* @__PURE__ */ import_react12.default.createElement(import_react_inspector5.ObjectInspector, { name: asset.id, data: asset, theme }), /* @__PURE__ */ import_react12.default.createElement(
5662
+ StateInspectorButton,
4735
5663
  {
4736
5664
  theme,
4737
5665
  onClick: () => assetManager.delete(asset.id)
@@ -4739,15 +5667,15 @@ var StateInspector = (0, import_react_utils.memoGeneric)(function StateInspector
4739
5667
  "Delete"
4740
5668
  ))))
4741
5669
  ),
4742
- /* @__PURE__ */ import_react3.default.createElement(
4743
- DisclosureSection,
5670
+ /* @__PURE__ */ import_react12.default.createElement(
5671
+ StateInspectorDisclosureSection,
4744
5672
  {
4745
- title: /* @__PURE__ */ import_react3.default.createElement(TitleLabel, null, "Secrets", /* @__PURE__ */ import_react3.default.createElement(ColoredDot, { type: secretsInitialized ? "success" : "error" })),
5673
+ title: /* @__PURE__ */ import_react12.default.createElement(TitleLabel, null, "Secrets", /* @__PURE__ */ import_react12.default.createElement(ColoredDot, { type: secretsInitialized ? "success" : "error" })),
4746
5674
  colorScheme,
4747
5675
  open: showSecrets,
4748
5676
  setOpen: setShowSecrets,
4749
- right: /* @__PURE__ */ import_react3.default.createElement(
4750
- SmallButton,
5677
+ right: /* @__PURE__ */ import_react12.default.createElement(
5678
+ StateInspectorButton,
4751
5679
  {
4752
5680
  theme,
4753
5681
  onClick: () => {
@@ -4761,8 +5689,8 @@ var StateInspector = (0, import_react_utils.memoGeneric)(function StateInspector
4761
5689
  "Create"
4762
5690
  )
4763
5691
  },
4764
- /* @__PURE__ */ import_react3.default.createElement("div", { style: styles.sectionInner }, secrets.map((secret) => /* @__PURE__ */ import_react3.default.createElement(InspectorRow, { key: secret.id, colorScheme }, /* @__PURE__ */ import_react3.default.createElement(import_react_inspector.ObjectInspector, { data: secret, theme }), /* @__PURE__ */ import_react3.default.createElement(
4765
- SmallButton,
5692
+ /* @__PURE__ */ import_react12.default.createElement(StateInspectorDisclosureRowInner, null, secrets.map((secret) => /* @__PURE__ */ import_react12.default.createElement(StateInspectorRow, { key: secret.id, colorScheme }, /* @__PURE__ */ import_react12.default.createElement(import_react_inspector5.ObjectInspector, { data: secret, theme }), /* @__PURE__ */ import_react12.default.createElement(
5693
+ StateInspectorButton,
4766
5694
  {
4767
5695
  theme,
4768
5696
  onClick: () => secretManager.deleteSecret(secret.id)
@@ -4771,15 +5699,15 @@ var StateInspector = (0, import_react_utils.memoGeneric)(function StateInspector
4771
5699
  ))))
4772
5700
  ),
4773
5701
  " ",
4774
- /* @__PURE__ */ import_react3.default.createElement(
4775
- DisclosureSection,
5702
+ /* @__PURE__ */ import_react12.default.createElement(
5703
+ StateInspectorDisclosureSection,
4776
5704
  {
4777
5705
  open: showInputs,
4778
5706
  setOpen: setShowInputs,
4779
- title: /* @__PURE__ */ import_react3.default.createElement(TitleLabel, null, "Inputs", /* @__PURE__ */ import_react3.default.createElement(ColoredDot, { type: inputsInitialized ? "success" : "error" })),
5707
+ title: /* @__PURE__ */ import_react12.default.createElement(TitleLabel, null, "Inputs", /* @__PURE__ */ import_react12.default.createElement(ColoredDot, { type: inputsInitialized ? "success" : "error" })),
4780
5708
  colorScheme
4781
5709
  },
4782
- /* @__PURE__ */ import_react3.default.createElement("div", { style: styles.sectionInner }, inputs?.map((input) => /* @__PURE__ */ import_react3.default.createElement(InspectorRow, { key: input.id, colorScheme }, /* @__PURE__ */ import_react3.default.createElement(import_react_inspector.ObjectInspector, { data: input, theme }))), !inputs?.length && /* @__PURE__ */ import_react3.default.createElement(
5710
+ /* @__PURE__ */ import_react12.default.createElement(StateInspectorDisclosureRowInner, null, inputs?.map((input) => /* @__PURE__ */ import_react12.default.createElement(StateInspectorRow, { key: input.id, colorScheme }, /* @__PURE__ */ import_react12.default.createElement(import_react_inspector5.ObjectInspector, { data: input, theme }))), !inputs?.length && /* @__PURE__ */ import_react12.default.createElement(
4783
5711
  "div",
4784
5712
  {
4785
5713
  style: {
@@ -4790,15 +5718,15 @@ var StateInspector = (0, import_react_utils.memoGeneric)(function StateInspector
4790
5718
  gap: "4px"
4791
5719
  }
4792
5720
  },
4793
- /* @__PURE__ */ import_react3.default.createElement("span", null, "No inputs")
5721
+ /* @__PURE__ */ import_react12.default.createElement("span", null, "No inputs")
4794
5722
  ))
4795
5723
  ),
4796
- /* @__PURE__ */ import_react3.default.createElement(
4797
- DisclosureSection,
5724
+ /* @__PURE__ */ import_react12.default.createElement(
5725
+ StateInspectorDisclosureSection,
4798
5726
  {
4799
5727
  open: showOutputTransforms,
4800
5728
  setOpen: setShowOutputTransforms,
4801
- title: /* @__PURE__ */ import_react3.default.createElement(TitleLabel, null, "Output Transforms", /* @__PURE__ */ import_react3.default.createElement(
5729
+ title: /* @__PURE__ */ import_react12.default.createElement(TitleLabel, null, "Output Transforms", /* @__PURE__ */ import_react12.default.createElement(
4802
5730
  ColoredDot,
4803
5731
  {
4804
5732
  type: outputTransformsInitialized ? "success" : "error"
@@ -4806,7 +5734,7 @@ var StateInspector = (0, import_react_utils.memoGeneric)(function StateInspector
4806
5734
  )),
4807
5735
  colorScheme
4808
5736
  },
4809
- /* @__PURE__ */ import_react3.default.createElement("div", { style: styles.sectionInner }, outputTransforms?.map((transform) => /* @__PURE__ */ import_react3.default.createElement(InspectorRow, { key: transform.id, colorScheme }, /* @__PURE__ */ import_react3.default.createElement(import_react_inspector.ObjectInspector, { data: transform, theme }))), !outputTransforms?.length && /* @__PURE__ */ import_react3.default.createElement(
5737
+ /* @__PURE__ */ import_react12.default.createElement(StateInspectorDisclosureRowInner, null, outputTransforms?.map((transform) => /* @__PURE__ */ import_react12.default.createElement(StateInspectorRow, { key: transform.id, colorScheme }, /* @__PURE__ */ import_react12.default.createElement(import_react_inspector5.ObjectInspector, { data: transform, theme }))), !outputTransforms?.length && /* @__PURE__ */ import_react12.default.createElement(
4810
5738
  "div",
4811
5739
  {
4812
5740
  style: {
@@ -4817,19 +5745,19 @@ var StateInspector = (0, import_react_utils.memoGeneric)(function StateInspector
4817
5745
  gap: "4px"
4818
5746
  }
4819
5747
  },
4820
- /* @__PURE__ */ import_react3.default.createElement("span", null, "No output transforms")
5748
+ /* @__PURE__ */ import_react12.default.createElement("span", null, "No output transforms")
4821
5749
  ))
4822
5750
  ),
4823
- /* @__PURE__ */ import_react3.default.createElement(
4824
- DisclosureSection,
5751
+ /* @__PURE__ */ import_react12.default.createElement(
5752
+ StateInspectorDisclosureSection,
4825
5753
  {
4826
5754
  title: "Tasks",
4827
5755
  colorScheme,
4828
5756
  open: showTasks,
4829
5757
  setOpen: setShowTasks
4830
5758
  },
4831
- /* @__PURE__ */ import_react3.default.createElement("div", { style: styles.sectionInner }, tasks?.map((task) => /* @__PURE__ */ import_react3.default.createElement(
4832
- InspectorRow,
5759
+ /* @__PURE__ */ import_react12.default.createElement(StateInspectorDisclosureRowInner, null, tasks?.map((task) => /* @__PURE__ */ import_react12.default.createElement(
5760
+ StateInspectorRow,
4833
5761
  {
4834
5762
  key: task.id,
4835
5763
  colorScheme,
@@ -4837,8 +5765,8 @@ var StateInspector = (0, import_react_utils.memoGeneric)(function StateInspector
4837
5765
  backgroundColor: task.status === "done" ? "rgba(0,255,0,0.2)" : task.status === "error" ? "rgba(255,0,0,0.2)" : void 0
4838
5766
  }
4839
5767
  },
4840
- /* @__PURE__ */ import_react3.default.createElement(
4841
- import_react_inspector.ObjectInspector,
5768
+ /* @__PURE__ */ import_react12.default.createElement(
5769
+ import_react_inspector5.ObjectInspector,
4842
5770
  {
4843
5771
  name: task.name,
4844
5772
  data: task.payload,
@@ -4847,16 +5775,16 @@ var StateInspector = (0, import_react_utils.memoGeneric)(function StateInspector
4847
5775
  )
4848
5776
  )))
4849
5777
  ),
4850
- /* @__PURE__ */ import_react3.default.createElement(
4851
- DisclosureSection,
5778
+ /* @__PURE__ */ import_react12.default.createElement(
5779
+ StateInspectorDisclosureSection,
4852
5780
  {
4853
5781
  open: showEphemeral,
4854
5782
  setOpen: setShowEphemeral,
4855
5783
  title: "Ephemeral User Data",
4856
5784
  colorScheme
4857
5785
  },
4858
- /* @__PURE__ */ import_react3.default.createElement("div", { style: styles.sectionInner }, Object.entries(ephemeral).map(([key, value]) => /* @__PURE__ */ import_react3.default.createElement(InspectorRow, { key, colorScheme }, /* @__PURE__ */ import_react3.default.createElement(
4859
- import_react_inspector.ObjectInspector,
5786
+ /* @__PURE__ */ import_react12.default.createElement(StateInspectorDisclosureRowInner, null, Object.entries(ephemeral).map(([key, value]) => /* @__PURE__ */ import_react12.default.createElement(StateInspectorRow, { key, colorScheme }, /* @__PURE__ */ import_react12.default.createElement(
5787
+ import_react_inspector5.ObjectInspector,
4860
5788
  {
4861
5789
  name: key,
4862
5790
  data: value,
@@ -4865,187 +5793,20 @@ var StateInspector = (0, import_react_utils.memoGeneric)(function StateInspector
4865
5793
  }
4866
5794
  ))))
4867
5795
  ),
4868
- /* @__PURE__ */ import_react3.default.createElement(
4869
- DisclosureSection,
5796
+ /* @__PURE__ */ import_react12.default.createElement(
5797
+ EventsSection,
4870
5798
  {
4871
- open: showEvents,
4872
- setOpen: setShowEvents,
4873
- title: "Events",
4874
- colorScheme
4875
- },
4876
- /* @__PURE__ */ import_react3.default.createElement("div", { ref: eventsContainerRef, style: styles.sectionInner }, connectionEvents?.map(
4877
- (event, index) => event.type === "stateChange" ? /* @__PURE__ */ import_react3.default.createElement(InspectorRow, { key: index, colorScheme }, "connection:", " ", /* @__PURE__ */ import_react3.default.createElement("span", { style: { fontStyle: "italic" } }, event.state.toLowerCase())) : /* @__PURE__ */ import_react3.default.createElement(
4878
- InspectorRow,
4879
- {
4880
- key: index,
4881
- colorScheme,
4882
- variant: event.type === "send" ? "up" : "down",
4883
- style: {
4884
- padding: "0px 12px 1px"
4885
- }
4886
- },
4887
- /* @__PURE__ */ import_react3.default.createElement(
4888
- import_react_inspector.ObjectInspector,
4889
- {
4890
- data: event.type === "error" ? event.error : event.message,
4891
- theme,
4892
- nodeRenderer: ({
4893
- depth,
4894
- name,
4895
- data,
4896
- isNonenumerable
4897
- }) => {
4898
- const direction = event.type === "send" ? "up" : "down";
4899
- return depth === 0 ? /* @__PURE__ */ import_react3.default.createElement(ObjectRootLabel, { direction, data }) : /* @__PURE__ */ import_react3.default.createElement(
4900
- import_react_inspector.ObjectLabel,
4901
- {
4902
- direction,
4903
- name,
4904
- data,
4905
- isNonenumerable
4906
- }
4907
- );
4908
- }
4909
- }
4910
- )
4911
- )
4912
- ), !connectionEvents && /* @__PURE__ */ import_react3.default.createElement(
4913
- "div",
4914
- {
4915
- style: {
4916
- padding: "12px",
4917
- fontSize: "12px",
4918
- display: "flex",
4919
- flexDirection: "column",
4920
- gap: "4px"
4921
- }
4922
- },
4923
- /* @__PURE__ */ import_react3.default.createElement("span", null, "No recorded events")
4924
- ))
5799
+ connectionEvents,
5800
+ colorScheme,
5801
+ eventsContainerRef,
5802
+ showEvents,
5803
+ setShowEvents
5804
+ }
4925
5805
  )
4926
5806
  );
4927
5807
  });
4928
- var ObjectRootLabel = ({ name, data, direction }) => {
4929
- if (typeof name === "string") {
4930
- return /* @__PURE__ */ import_react3.default.createElement("span", null, /* @__PURE__ */ import_react3.default.createElement(import_react_inspector.ObjectName, { name }), /* @__PURE__ */ import_react3.default.createElement("span", null, ": "), /* @__PURE__ */ import_react3.default.createElement(import_react_inspector.ObjectPreview, { data }));
4931
- }
4932
- if (direction === "up" || direction === "down") {
4933
- const arrow = direction === "up" ? "\u2191" : "\u2193";
4934
- return /* @__PURE__ */ import_react3.default.createElement("span", null, /* @__PURE__ */ import_react3.default.createElement(
4935
- "span",
4936
- {
4937
- style: {
4938
- background: direction === "up" ? "rgba(0,255,0,0.2)" : "rgba(255,0,0,0.2)",
4939
- // color: "white",
4940
- width: 12,
4941
- height: 12,
4942
- borderRadius: 2,
4943
- display: "inline-flex",
4944
- justifyContent: "center",
4945
- alignItems: "center",
4946
- marginRight: 4,
4947
- lineHeight: "12px"
4948
- }
4949
- },
4950
- arrow
4951
- ), /* @__PURE__ */ import_react3.default.createElement(import_react_inspector.ObjectPreview, { data }));
4952
- } else {
4953
- return /* @__PURE__ */ import_react3.default.createElement(import_react_inspector.ObjectPreview, { data });
4954
- }
4955
- };
4956
- function Arrow({
4957
- expanded,
4958
- onClick,
4959
- style
4960
- }) {
4961
- return /* @__PURE__ */ import_react3.default.createElement(
4962
- "span",
4963
- {
4964
- role: "button",
4965
- onClick,
4966
- style: {
4967
- display: "inline-block",
4968
- textAlign: "center",
4969
- transform: expanded ? "rotate(0deg)" : "rotate(-90deg)",
4970
- fontFamily: "Menlo, monospace",
4971
- ...style
4972
- }
4973
- },
4974
- "\u25BC"
4975
- );
4976
- }
4977
- function pathToString(extendedPath) {
4978
- return extendedPath.map(
4979
- (key) => typeof key === "object" ? `:${ellipsis(key.id.toString(), 8, "middle")}` : key
4980
- ).map(
4981
- (key, index) => index === 0 || typeof key === "string" && key.startsWith(":") ? key : `.${key}`
4982
- ).join("");
4983
- }
4984
- function ellipsis(str, maxLength, position = "end") {
4985
- if (str.length <= maxLength) return str;
4986
- switch (position) {
4987
- case "start":
4988
- return `\u2026${str.slice(str.length - maxLength)}`;
4989
- case "middle":
4990
- const halfLength = Math.floor(maxLength / 2);
4991
- return `${str.slice(0, halfLength)}\u2026${str.slice(str.length - halfLength)}`;
4992
- case "end":
4993
- return `${str.slice(0, maxLength)}\u2026`;
4994
- }
4995
- }
4996
- function SmallButton({
4997
- children,
4998
- onClick,
4999
- style,
5000
- theme,
5001
- disabled
5002
- }) {
5003
- return /* @__PURE__ */ import_react3.default.createElement(
5004
- "button",
5005
- {
5006
- type: "button",
5007
- disabled,
5008
- onClick: (event) => {
5009
- event.stopPropagation();
5010
- onClick();
5011
- },
5012
- style: {
5013
- flex: "0",
5014
- appearance: "none",
5015
- background: "none",
5016
- color: theme.BASE_COLOR,
5017
- opacity: disabled ? 0.25 : 1,
5018
- border: "none",
5019
- fontSize: "12px",
5020
- whiteSpace: "nowrap",
5021
- display: "inline-flex",
5022
- alignItems: "center",
5023
- justifyContent: "center",
5024
- padding: "0",
5025
- cursor: "pointer",
5026
- ...style
5027
- }
5028
- },
5029
- children
5030
- );
5031
- }
5032
- function ColoredDot({ type }) {
5033
- return /* @__PURE__ */ import_react3.default.createElement(
5034
- "span",
5035
- {
5036
- style: {
5037
- display: "inline-block",
5038
- width: 6,
5039
- height: 6,
5040
- background: type === "success" ? "rgba(0,200,0,0.8)" : "rgba(200,0,0,0.8)",
5041
- borderRadius: "50%",
5042
- verticalAlign: "middle"
5043
- }
5044
- }
5045
- );
5046
- }
5047
5808
  function TitleLabel({ children }) {
5048
- return /* @__PURE__ */ import_react3.default.createElement("span", { style: { display: "flex", alignItems: "center", gap: "4px" } }, children);
5809
+ return /* @__PURE__ */ import_react12.default.createElement("span", { style: { display: "flex", alignItems: "center", gap: "4px" } }, children);
5049
5810
  }
5050
5811
 
5051
5812
  // src/inspector/useStateInspector.tsx
@@ -5063,7 +5824,7 @@ function useStateInspector({
5063
5824
  colorScheme,
5064
5825
  anchor
5065
5826
  }) {
5066
- const [root, setRoot] = import_react4.default.useState(null);
5827
+ const [root, setRoot] = import_react13.default.useState(null);
5067
5828
  (0, import_react_utils2.useIsomorphicLayoutEffect)(() => {
5068
5829
  if (disabled) return;
5069
5830
  const { host, container } = createShadowRootElement();
@@ -5077,7 +5838,7 @@ function useStateInspector({
5077
5838
  (0, import_react_utils2.useIsomorphicLayoutEffect)(() => {
5078
5839
  if (!root) return;
5079
5840
  root.render(
5080
- /* @__PURE__ */ import_react4.default.createElement(
5841
+ /* @__PURE__ */ import_react13.default.createElement(
5081
5842
  StateInspector,
5082
5843
  {
5083
5844
  colorScheme,
@@ -5091,22 +5852,22 @@ function useStateInspector({
5091
5852
 
5092
5853
  // src/hooks.ts
5093
5854
  function useSyncStateManager(stateManager, path) {
5094
- const getSnapshot = (0, import_react5.useCallback)(
5855
+ const getSnapshot = (0, import_react14.useCallback)(
5095
5856
  () => typeof path === "string" ? stateManager.getState(path) : stateManager.getState(),
5096
5857
  [stateManager, path]
5097
5858
  );
5098
- return (0, import_react5.useSyncExternalStore)(
5859
+ return (0, import_react14.useSyncExternalStore)(
5099
5860
  stateManager.addListener,
5100
5861
  getSnapshot,
5101
5862
  getSnapshot
5102
5863
  );
5103
5864
  }
5104
5865
  function useManagedState(createInitialState, options) {
5105
- const [stateManager] = (0, import_react5.useState)(
5106
- () => new import_state_manager.StateManager(createInitialState(), options)
5866
+ const [stateManager] = (0, import_react14.useState)(
5867
+ () => new import_state_manager2.StateManager(createInitialState(), options)
5107
5868
  );
5108
5869
  const state = useSyncStateManager(stateManager);
5109
- const setState = (0, import_react5.useCallback)(
5870
+ const setState = (0, import_react14.useCallback)(
5110
5871
  (...args) => {
5111
5872
  const [metadata, action] = args.length === 1 ? [void 0, args[0]] : args;
5112
5873
  if (metadata === void 0) {
@@ -5142,7 +5903,7 @@ function useManagedState(createInitialState, options) {
5142
5903
  return [state, setState, stateManager];
5143
5904
  }
5144
5905
  function useManagedHistory(stateManager) {
5145
- return (0, import_react5.useSyncExternalStore)(
5906
+ return (0, import_react14.useSyncExternalStore)(
5146
5907
  stateManager.historyEmittor.addListener,
5147
5908
  stateManager.getHistorySnapshot,
5148
5909
  stateManager.getHistorySnapshot
@@ -5150,18 +5911,18 @@ function useManagedHistory(stateManager) {
5150
5911
  }
5151
5912
  function useMultiplayerState(initialState, options) {
5152
5913
  const {
5153
- sync = (0, import_state_manager.stubSync)(),
5914
+ sync = (0, import_state_manager2.stubSync)(),
5154
5915
  inspector,
5155
5916
  ...rest
5156
5917
  } = options ?? {};
5157
- const [noyaManager] = (0, import_react5.useState)(
5158
- () => new import_state_manager.NoyaManager(initialState, rest)
5918
+ const [noyaManager] = (0, import_react14.useState)(
5919
+ () => new import_state_manager2.NoyaManager(initialState, rest)
5159
5920
  );
5160
5921
  const state = useObservable(
5161
5922
  noyaManager.multiplayerStateManager.optimisticState$
5162
5923
  );
5163
5924
  const assets = useObservable(noyaManager.assetManager.assets$);
5164
- const extras = (0, import_react5.useMemo)(() => {
5925
+ const extras = (0, import_react14.useMemo)(() => {
5165
5926
  return {
5166
5927
  noyaManager,
5167
5928
  taskManager: noyaManager.taskManager,
@@ -5180,8 +5941,8 @@ function useMultiplayerState(initialState, options) {
5180
5941
  assets
5181
5942
  };
5182
5943
  }, [noyaManager, assets]);
5183
- const syncRef = (0, import_react5.useRef)(sync);
5184
- (0, import_react5.useEffect)(() => {
5944
+ const syncRef = (0, import_react14.useRef)(sync);
5945
+ (0, import_react14.useEffect)(() => {
5185
5946
  if (syncRef.current) {
5186
5947
  return syncRef.current({ noyaManager });
5187
5948
  }
@@ -5196,13 +5957,13 @@ function useMultiplayerState(initialState, options) {
5196
5957
  }
5197
5958
  function useErrorOverlay(noyaManager) {
5198
5959
  const unrecoverableError = useObservable(noyaManager.unrecoverableError);
5199
- (0, import_react5.useEffect)(() => {
5960
+ (0, import_react14.useEffect)(() => {
5200
5961
  if (!unrecoverableError) return;
5201
5962
  const el = document.createElement("div");
5202
5963
  el.id = "noya-multiplayer-react-error-overlay";
5203
5964
  document.body.appendChild(el);
5204
5965
  const root = (0, import_client2.createRoot)(el);
5205
- root.render((0, import_react5.createElement)(ErrorOverlay, { error: unrecoverableError }));
5966
+ root.render((0, import_react14.createElement)(ErrorOverlay, { error: unrecoverableError }));
5206
5967
  return () => {
5207
5968
  root.unmount();
5208
5969
  el.remove();
@@ -5220,7 +5981,7 @@ function createDefaultAppData(initialState) {
5220
5981
  };
5221
5982
  }
5222
5983
  function enforceSchema(initialState, schema) {
5223
- return schema ? (0, import_state_manager2.createOrCastValue)({
5984
+ return schema ? (0, import_state_manager3.createOrCastValue)({
5224
5985
  schema,
5225
5986
  value: initialState,
5226
5987
  defs: findAllDefs(schema)
@@ -5250,7 +6011,7 @@ function getAppData(initialState, schema, options) {
5250
6011
  return appData;
5251
6012
  }
5252
6013
  function useNoyaState(...args) {
5253
- 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]];
6014
+ const [initialState, options] = typeof args[0] === "object" && args[0] !== null && "schema" in args[0] && import_state_manager3.TypeGuard.IsSchema(args[0].schema) ? [null, args[0]] : [args[0], args[1]];
5254
6015
  const [
5255
6016
  {
5256
6017
  multiplayerUrl,
@@ -5259,16 +6020,16 @@ function useNoyaState(...args) {
5259
6020
  theme,
5260
6021
  viewType
5261
6022
  }
5262
- ] = (0, import_react6.useState)(() => {
6023
+ ] = (0, import_react15.useState)(() => {
5263
6024
  return getAppData(initialState, options?.schema, {
5264
6025
  overrideExistingState: options?.overrideExistingState
5265
6026
  });
5266
6027
  });
5267
- const sync = (0, import_react6.useMemo)(() => {
5268
- return (0, import_state_manager2.isEmbeddedApp)() ? (0, import_state_manager2.parentFrameSync)({ debug: options?.debug }) : multiplayerUrl ? (0, import_state_manager2.webSocketSync)({
6028
+ const sync = (0, import_react15.useMemo)(() => {
6029
+ return (0, import_state_manager3.isEmbeddedApp)() ? (0, import_state_manager3.parentFrameSync)({ debug: options?.debug }) : multiplayerUrl ? (0, import_state_manager3.webSocketSync)({
5269
6030
  url: multiplayerUrl,
5270
6031
  debug: options?.debug
5271
- }) : options?.offlineStorageKey ? (0, import_state_manager2.localStorageSync)({ key: options.offlineStorageKey }) : (0, import_state_manager2.stubSync)();
6032
+ }) : options?.offlineStorageKey ? (0, import_state_manager3.localStorageSync)({ key: options.offlineStorageKey }) : (0, import_state_manager3.stubSync)();
5272
6033
  }, [multiplayerUrl, options?.offlineStorageKey, options?.debug]);
5273
6034
  const result = useMultiplayerState(noyaAppInitialState, {
5274
6035
  ...options,
@@ -5276,16 +6037,16 @@ function useNoyaState(...args) {
5276
6037
  sync: options?.sync ?? sync
5277
6038
  });
5278
6039
  const [, , extras] = result;
5279
- const mergedExtras = (0, import_react6.useMemo)(() => {
6040
+ const mergedExtras = (0, import_react15.useMemo)(() => {
5280
6041
  return { ...extras, theme, viewType };
5281
6042
  }, [extras, theme, viewType]);
5282
6043
  return [result[0], result[1], mergedExtras];
5283
6044
  }
5284
6045
 
5285
6046
  // src/NoyaStateContext.tsx
5286
- var AnyNoyaStateContext = (0, import_react7.createContext)(void 0);
6047
+ var AnyNoyaStateContext = (0, import_react16.createContext)(void 0);
5287
6048
  function useAnyNoyaStateContext() {
5288
- const value = (0, import_react7.useContext)(AnyNoyaStateContext);
6049
+ const value = (0, import_react16.useContext)(AnyNoyaStateContext);
5289
6050
  if (!value) {
5290
6051
  throw new Error(
5291
6052
  "useNoyaStateContext must be used within a NoyaStateProvider"
@@ -5311,7 +6072,7 @@ function useAssets() {
5311
6072
  }
5312
6073
  function useAsset(id) {
5313
6074
  const { noyaManager } = useAnyNoyaStateContext();
5314
- const observable = (0, import_react7.useMemo)(
6075
+ const observable = (0, import_react16.useMemo)(
5315
6076
  () => noyaManager.assetManager.assets$.map(
5316
6077
  (assets) => assets.find((a) => a.id === id)
5317
6078
  ),
@@ -5322,7 +6083,7 @@ function useAsset(id) {
5322
6083
  function useAssetManager() {
5323
6084
  const { noyaManager } = useAnyNoyaStateContext();
5324
6085
  const isInitialized = useObservable(noyaManager.assetManager.isInitialized$);
5325
- return (0, import_react7.useMemo)(
6086
+ return (0, import_react16.useMemo)(
5326
6087
  () => ({
5327
6088
  create: noyaManager.assetManager.create,
5328
6089
  delete: noyaManager.assetManager.delete,
@@ -5347,7 +6108,7 @@ function useSecret(name) {
5347
6108
  const { noyaManager } = useAnyNoyaStateContext();
5348
6109
  return useObservable(
5349
6110
  noyaManager.secretManager.secrets$,
5350
- (0, import_react7.useCallback)((secrets) => secrets.find((s) => s.name === name), [name])
6111
+ (0, import_react16.useCallback)((secrets) => secrets.find((s) => s.name === name), [name])
5351
6112
  );
5352
6113
  }
5353
6114
  function useInputs() {
@@ -5365,7 +6126,7 @@ function useIOManager() {
5365
6126
  function usePublish(callback) {
5366
6127
  const { noyaManager } = useAnyNoyaStateContext();
5367
6128
  const stableCallback = (0, import_react_utils3.useStableCallback)(callback);
5368
- (0, import_react7.useEffect)(() => {
6129
+ (0, import_react16.useEffect)(() => {
5369
6130
  noyaManager.publishingManager.setPublishingEnabled(true);
5370
6131
  noyaManager.publishingManager.getFilesToPublish = stableCallback;
5371
6132
  return () => {
@@ -5376,7 +6137,7 @@ function usePublish(callback) {
5376
6137
  }
5377
6138
  function useIsInitialized() {
5378
6139
  const { noyaManager, viewType } = useAnyNoyaStateContext();
5379
- const isInitializedObservable = (0, import_react7.useMemo)(
6140
+ const isInitializedObservable = (0, import_react16.useMemo)(
5380
6141
  () => import_observable.Observable.combine(
5381
6142
  [
5382
6143
  ...viewType === "preview" ? [] : [noyaManager.multiplayerStateManager.isInitialized$],
@@ -5393,13 +6154,13 @@ function usePipelineManager() {
5393
6154
  const { noyaManager } = useAnyNoyaStateContext();
5394
6155
  return noyaManager.pipelineManager;
5395
6156
  }
5396
- var ConnectedUsersContext = (0, import_react7.createContext)(void 0);
6157
+ var ConnectedUsersContext = (0, import_react16.createContext)(void 0);
5397
6158
  function useConnectedUsersManager() {
5398
- return (0, import_react7.useContext)(ConnectedUsersContext);
6159
+ return (0, import_react16.useContext)(ConnectedUsersContext);
5399
6160
  }
5400
- var AnyEphemeralUserDataManagerContext = (0, import_react7.createContext)(void 0);
6161
+ var AnyEphemeralUserDataManagerContext = (0, import_react16.createContext)(void 0);
5401
6162
  function useAnyEphemeralUserData() {
5402
- return (0, import_react7.useContext)(AnyEphemeralUserDataManagerContext);
6163
+ return (0, import_react16.useContext)(AnyEphemeralUserDataManagerContext);
5403
6164
  }
5404
6165
  function useCurrentUserId() {
5405
6166
  const connectedUsersManager = useConnectedUsersManager();
@@ -5437,7 +6198,7 @@ function createNoyaContext({
5437
6198
  ...options
5438
6199
  }
5439
6200
  );
5440
- const contextValue = (0, import_react7.useMemo)(
6201
+ const contextValue = (0, import_react16.useMemo)(
5441
6202
  () => ({
5442
6203
  noyaManager,
5443
6204
  theme,
@@ -5445,24 +6206,24 @@ function createNoyaContext({
5445
6206
  }),
5446
6207
  [noyaManager, theme, viewType]
5447
6208
  );
5448
- return /* @__PURE__ */ import_react7.default.createElement(AnyNoyaStateContext.Provider, { value: contextValue }, /* @__PURE__ */ import_react7.default.createElement(
6209
+ return /* @__PURE__ */ import_react16.default.createElement(AnyNoyaStateContext.Provider, { value: contextValue }, /* @__PURE__ */ import_react16.default.createElement(
5449
6210
  ConnectedUsersContext.Provider,
5450
6211
  {
5451
6212
  value: noyaManager.connectedUsersManager
5452
6213
  },
5453
- /* @__PURE__ */ import_react7.default.createElement(
6214
+ /* @__PURE__ */ import_react16.default.createElement(
5454
6215
  EphemeralUserDataManagerContext.Provider,
5455
6216
  {
5456
6217
  value: noyaManager.ephemeralUserDataManager
5457
6218
  },
5458
- options.fallback !== void 0 ? /* @__PURE__ */ import_react7.default.createElement(FallbackUntilInitialized, { fallback: options.fallback }, children) : children
6219
+ options.fallback !== void 0 ? /* @__PURE__ */ import_react16.default.createElement(FallbackUntilInitialized, { fallback: options.fallback }, children) : children
5459
6220
  )
5460
6221
  ));
5461
6222
  }
5462
6223
  function useValue(path, options) {
5463
6224
  const { noyaManager } = useAnyNoyaStateContext();
5464
6225
  let actualPath = typeof path === "function" || !path ? "" : path;
5465
- const mappedObservable = (0, import_react7.useMemo)(() => {
6226
+ const mappedObservable = (0, import_react16.useMemo)(() => {
5466
6227
  if (typeof path === "function") {
5467
6228
  return noyaManager.multiplayerStateManager.optimisticState$.map(path, {
5468
6229
  isEqual: options?.isEqual
@@ -5475,7 +6236,7 @@ function createNoyaContext({
5475
6236
  }
5476
6237
  function useSetValue(path) {
5477
6238
  const { noyaManager } = useAnyNoyaStateContext();
5478
- const setValue = (0, import_react7.useCallback)(
6239
+ const setValue = (0, import_react16.useCallback)(
5479
6240
  (...args) => {
5480
6241
  const [metadata, value] = args.length === 2 ? args : [{}, args[0]];
5481
6242
  noyaManager.multiplayerStateManager.setStateAtPath(
@@ -5499,7 +6260,7 @@ function createNoyaContext({
5499
6260
  return noyaManager.multiplayerStateManager;
5500
6261
  }
5501
6262
  function useEphemeralUserDataManager() {
5502
- const ephemeralUserData = (0, import_react7.useContext)(EphemeralUserDataManagerContext);
6263
+ const ephemeralUserData = (0, import_react16.useContext)(EphemeralUserDataManagerContext);
5503
6264
  if (!ephemeralUserData) {
5504
6265
  throw new Error(
5505
6266
  "useEphemeralUserData must be used within a NoyaStateProvider"
@@ -5516,7 +6277,7 @@ function createNoyaContext({
5516
6277
  }
5517
6278
  function useSetLeftMenuItems(leftMenuItems) {
5518
6279
  const { menuManager } = useNoyaManager();
5519
- (0, import_react7.useEffect)(() => {
6280
+ (0, import_react16.useEffect)(() => {
5520
6281
  if (leftMenuItems) {
5521
6282
  menuManager.setLeftMenuItems(leftMenuItems);
5522
6283
  }
@@ -5528,7 +6289,7 @@ function createNoyaContext({
5528
6289
  }
5529
6290
  function useSetRightMenuItems(rightMenuItems) {
5530
6291
  const { menuManager } = useNoyaManager();
5531
- (0, import_react7.useEffect)(() => {
6292
+ (0, import_react16.useEffect)(() => {
5532
6293
  if (rightMenuItems) {
5533
6294
  menuManager.setRightMenuItems(rightMenuItems);
5534
6295
  }
@@ -5536,19 +6297,19 @@ function createNoyaContext({
5536
6297
  }
5537
6298
  function useHandleMenuItem(callback) {
5538
6299
  const { menuManager } = useNoyaManager();
5539
- (0, import_react7.useEffect)(() => {
6300
+ (0, import_react16.useEffect)(() => {
5540
6301
  return menuManager.addListener(callback);
5541
6302
  }, [menuManager, callback]);
5542
6303
  }
5543
6304
  function useOnSelectMenuItemCallback() {
5544
6305
  const { menuManager } = useNoyaManager();
5545
- return (0, import_react7.useCallback)((type) => menuManager.emit(type), [menuManager]);
6306
+ return (0, import_react16.useCallback)((type) => menuManager.emit(type), [menuManager]);
5546
6307
  }
5547
6308
  function useMenu(options) {
5548
6309
  const { leftMenuItems, rightMenuItems, onSelectMenuItem } = options;
5549
6310
  useSetLeftMenuItems(leftMenuItems);
5550
6311
  useSetRightMenuItems(rightMenuItems);
5551
- const noop = (0, import_react7.useCallback)(() => {
6312
+ const noop = (0, import_react16.useCallback)(() => {
5552
6313
  }, []);
5553
6314
  useHandleMenuItem(onSelectMenuItem ?? noop);
5554
6315
  }
@@ -5574,7 +6335,7 @@ function createNoyaContext({
5574
6335
  // src/ai.ts
5575
6336
  function useRegisterAITool(tool) {
5576
6337
  const aiManager = useAIManager();
5577
- (0, import_react8.useEffect)(() => {
6338
+ (0, import_react17.useEffect)(() => {
5578
6339
  return aiManager.registerTool(tool);
5579
6340
  }, [aiManager, tool]);
5580
6341
  }
@@ -5586,7 +6347,7 @@ function useCallableAITools() {
5586
6347
  // src/components/UserPointersOverlay.tsx
5587
6348
  var import_observable2 = require("@noya-app/observable");
5588
6349
  var import_react_utils4 = require("@noya-app/react-utils");
5589
- var import_react9 = __toESM(require("react"));
6350
+ var import_react18 = __toESM(require("react"));
5590
6351
  function shouldShow(hideAfter, updatedAt) {
5591
6352
  return !!updatedAt && Date.now() - updatedAt < hideAfter;
5592
6353
  }
@@ -5596,7 +6357,7 @@ var UserPointerInternal = (0, import_react_utils4.memoGeneric)(function UserPoin
5596
6357
  hideAfter = 5e3,
5597
6358
  renderUserPointer
5598
6359
  }) {
5599
- const observable = (0, import_react9.useMemo)(() => {
6360
+ const observable = (0, import_react18.useMemo)(() => {
5600
6361
  const metadata$ = ephemeralUserDataManager.metadata$.observePath([user.id]).throttle(50);
5601
6362
  const data$ = ephemeralUserDataManager.data$.observePath([user.id]).throttle(50);
5602
6363
  return import_observable2.Observable.combine([metadata$, data$], ([metadata2, data2]) => {
@@ -5604,10 +6365,10 @@ var UserPointerInternal = (0, import_react_utils4.memoGeneric)(function UserPoin
5604
6365
  });
5605
6366
  }, [ephemeralUserDataManager, user.id]);
5606
6367
  const { metadata, data } = useObservable(observable);
5607
- const [, setForceUpdate] = (0, import_react9.useState)(0);
6368
+ const [, setForceUpdate] = (0, import_react18.useState)(0);
5608
6369
  const updatedAt = metadata?.updatedAt ?? 0;
5609
6370
  const show = shouldShow(hideAfter, updatedAt);
5610
- (0, import_react9.useEffect)(() => {
6371
+ (0, import_react18.useEffect)(() => {
5611
6372
  if (!show) return;
5612
6373
  const timeoutId = setTimeout(() => {
5613
6374
  setForceUpdate((prev) => prev + 1);
@@ -5629,9 +6390,9 @@ var UserPointersOverlay = (0, import_react_utils4.memoGeneric)(function UserPoin
5629
6390
  }) {
5630
6391
  const currentUserId = useObservable(ephemeralUserDataManager.currentUserId$);
5631
6392
  const connectedUsers = useObservable(connectedUsersManager.connectedUsers$);
5632
- return /* @__PURE__ */ import_react9.default.createElement(import_react9.default.Fragment, null, connectedUsers.map((user) => {
6393
+ return /* @__PURE__ */ import_react18.default.createElement(import_react18.default.Fragment, null, connectedUsers.map((user) => {
5633
6394
  if (user.id === currentUserId) return null;
5634
- return /* @__PURE__ */ import_react9.default.createElement(
6395
+ return /* @__PURE__ */ import_react18.default.createElement(
5635
6396
  UserPointerInternal,
5636
6397
  {
5637
6398
  key: user.id,
@@ -5644,17 +6405,17 @@ var UserPointersOverlay = (0, import_react_utils4.memoGeneric)(function UserPoin
5644
6405
  });
5645
6406
 
5646
6407
  // src/WebSocketConnection.ts
5647
- var import_state_manager3 = require("@noya-app/state-manager");
6408
+ var import_state_manager4 = require("@noya-app/state-manager");
5648
6409
  var WebSocketConnection = class {
5649
6410
  constructor(url, options = {}) {
5650
6411
  this.url = url;
5651
6412
  this.options = options;
5652
- this.ws = new import_state_manager3.ReconnectingWebSocket({
6413
+ this.ws = new import_state_manager4.ReconnectingWebSocket({
5653
6414
  debug: options.debug,
5654
6415
  onopen: this.handleOpen,
5655
6416
  onmessage: this.handleMessage,
5656
6417
  onclose: this.handleClose,
5657
- activityDetector: new import_state_manager3.UserActivityDetector()
6418
+ activityDetector: new import_state_manager4.UserActivityDetector()
5658
6419
  });
5659
6420
  }
5660
6421
  ws;
@@ -5731,9 +6492,15 @@ var WebSocketConnection = class {
5731
6492
  WebSocketConnection,
5732
6493
  createDefaultAppData,
5733
6494
  createNoyaContext,
6495
+ decodeAll,
6496
+ encodeAll,
5734
6497
  enforceSchema,
6498
+ exportAll,
6499
+ fetchAssetMap,
5735
6500
  getAppData,
6501
+ importAll,
5736
6502
  parseAppDataParameter,
6503
+ replaceDeep,
5737
6504
  useAIManager,
5738
6505
  useAnyEphemeralUserData,
5739
6506
  useAnyNoyaManager,