@modelnex/sdk 0.5.31 → 0.5.33

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
@@ -2766,6 +2766,32 @@ function normalizeDevModeKey(value) {
2766
2766
  const normalized = value.trim();
2767
2767
  return normalized || void 0;
2768
2768
  }
2769
+ function observeInjectedDevModeKey(listener, options) {
2770
+ if (typeof window === "undefined") return () => {
2771
+ };
2772
+ let currentKey = resolveInjectedDevModeKey();
2773
+ const pollIntervalMs = options?.pollIntervalMs ?? 1e3;
2774
+ const syncInjectedDevModeKey = () => {
2775
+ const nextKey = resolveInjectedDevModeKey();
2776
+ if (nextKey === currentKey) return;
2777
+ currentKey = nextKey;
2778
+ listener(nextKey);
2779
+ };
2780
+ const intervalId = window.setInterval(syncInjectedDevModeKey, pollIntervalMs);
2781
+ window.addEventListener("focus", syncInjectedDevModeKey);
2782
+ window.addEventListener("pageshow", syncInjectedDevModeKey);
2783
+ if (typeof document !== "undefined") {
2784
+ document.addEventListener("visibilitychange", syncInjectedDevModeKey);
2785
+ }
2786
+ return () => {
2787
+ window.clearInterval(intervalId);
2788
+ window.removeEventListener("focus", syncInjectedDevModeKey);
2789
+ window.removeEventListener("pageshow", syncInjectedDevModeKey);
2790
+ if (typeof document !== "undefined") {
2791
+ document.removeEventListener("visibilitychange", syncInjectedDevModeKey);
2792
+ }
2793
+ };
2794
+ }
2769
2795
  function resolveInjectedDevModeKey() {
2770
2796
  if (typeof window === "undefined") return void 0;
2771
2797
  const browserWindow = window;
@@ -2806,6 +2832,91 @@ async function validateInjectedDevModeKey(serverUrl, websiteId, devModeKey) {
2806
2832
  return validationPromise;
2807
2833
  }
2808
2834
 
2835
+ // src/utils/recordingPersistence.ts
2836
+ var RECORDING_SESSION_STORAGE_KEY = "modelnex-recording-session";
2837
+ var RESTORABLE_RECORDING_PHASES = /* @__PURE__ */ new Set([
2838
+ "active",
2839
+ "selecting",
2840
+ "configuring",
2841
+ "narrating",
2842
+ "reviewing",
2843
+ "saved",
2844
+ "finishing"
2845
+ ]);
2846
+ var TOUR_STEP_TYPES = /* @__PURE__ */ new Set([
2847
+ "narrate",
2848
+ "act",
2849
+ "input",
2850
+ "ask_and_fill",
2851
+ "user_input",
2852
+ "ask_or_fill",
2853
+ "wait_then_act"
2854
+ ]);
2855
+ function canUseSessionStorage() {
2856
+ return typeof window !== "undefined" && typeof window.sessionStorage !== "undefined";
2857
+ }
2858
+ function isExperienceType(value) {
2859
+ return value === "tour" || value === "onboarding";
2860
+ }
2861
+ function isTourStepType(value) {
2862
+ return typeof value === "string" && TOUR_STEP_TYPES.has(value);
2863
+ }
2864
+ function isPlainObject(value) {
2865
+ return Boolean(value) && typeof value === "object" && !Array.isArray(value);
2866
+ }
2867
+ function sanitizePersistedRecordingSession(raw) {
2868
+ if (!isPlainObject(raw)) return null;
2869
+ if (raw.version !== 1) return null;
2870
+ if (!isExperienceType(raw.experienceType)) return null;
2871
+ if (typeof raw.phase !== "string" || !RESTORABLE_RECORDING_PHASES.has(raw.phase)) return null;
2872
+ if (!Array.isArray(raw.steps) || !Array.isArray(raw.captureEvents) || !Array.isArray(raw.pendingClicks)) return null;
2873
+ if (!isTourStepType(raw.selectedStepType)) return null;
2874
+ return {
2875
+ version: 1,
2876
+ experienceType: raw.experienceType,
2877
+ phase: raw.phase,
2878
+ steps: raw.steps,
2879
+ captureEvents: raw.captureEvents,
2880
+ capturedTranscript: typeof raw.capturedTranscript === "string" ? raw.capturedTranscript : "",
2881
+ pendingClicks: raw.pendingClicks,
2882
+ selectedStepType: raw.selectedStepType
2883
+ };
2884
+ }
2885
+ function readPersistedRecordingSession() {
2886
+ if (!canUseSessionStorage()) return null;
2887
+ try {
2888
+ const raw = window.sessionStorage.getItem(RECORDING_SESSION_STORAGE_KEY);
2889
+ if (!raw) return null;
2890
+ const parsed = sanitizePersistedRecordingSession(JSON.parse(raw));
2891
+ if (parsed) {
2892
+ return parsed;
2893
+ }
2894
+ } catch {
2895
+ }
2896
+ clearPersistedRecordingSession();
2897
+ return null;
2898
+ }
2899
+ function readPersistedRecordingExperienceType() {
2900
+ return readPersistedRecordingSession()?.experienceType ?? null;
2901
+ }
2902
+ function hasPersistedRecordingSession() {
2903
+ return readPersistedRecordingSession() !== null;
2904
+ }
2905
+ function persistRecordingSession(session) {
2906
+ if (!canUseSessionStorage()) return;
2907
+ try {
2908
+ window.sessionStorage.setItem(RECORDING_SESSION_STORAGE_KEY, JSON.stringify(session));
2909
+ } catch {
2910
+ }
2911
+ }
2912
+ function clearPersistedRecordingSession() {
2913
+ if (!canUseSessionStorage()) return;
2914
+ try {
2915
+ window.sessionStorage.removeItem(RECORDING_SESSION_STORAGE_KEY);
2916
+ } catch {
2917
+ }
2918
+ }
2919
+
2809
2920
  // src/hooks/useRunCommand.ts
2810
2921
  var import_react9 = require("react");
2811
2922
  function searchTaggedElementsForQuery(store, query, limit = 8) {
@@ -6742,14 +6853,20 @@ function useRecordingMode({
6742
6853
  onPreview,
6743
6854
  experienceType = "tour"
6744
6855
  }) {
6745
- const [phase, setPhase] = (0, import_react16.useState)("idle");
6746
- const [steps, setSteps] = (0, import_react16.useState)([]);
6856
+ const restoredSessionRef = (0, import_react16.useRef)(void 0);
6857
+ if (restoredSessionRef.current === void 0) {
6858
+ restoredSessionRef.current = readPersistedRecordingSession();
6859
+ }
6860
+ const restoredSession = restoredSessionRef.current;
6861
+ const restoredPhase = restoredSession ? "active" : "idle";
6862
+ const [phase, setPhase] = (0, import_react16.useState)(restoredPhase);
6863
+ const [steps, setSteps] = (0, import_react16.useState)(() => restoredSession?.steps ?? []);
6747
6864
  const [selectedElement, setSelectedElement] = (0, import_react16.useState)(null);
6748
- const [selectedStepType, setSelectedStepType] = (0, import_react16.useState)("ask_or_fill");
6865
+ const [selectedStepType, setSelectedStepType] = (0, import_react16.useState)(() => restoredSession?.selectedStepType ?? "ask_or_fill");
6749
6866
  const [pendingNarration, setPendingNarration] = (0, import_react16.useState)("");
6750
6867
  const [polishedNarration, setPolishedNarration] = (0, import_react16.useState)("");
6751
- const [captureEvents, setCaptureEvents] = (0, import_react16.useState)([]);
6752
- const [capturedTranscript, setCapturedTranscript] = (0, import_react16.useState)("");
6868
+ const [captureEvents, setCaptureEvents] = (0, import_react16.useState)(() => restoredSession?.captureEvents ?? []);
6869
+ const [capturedTranscript, setCapturedTranscript] = (0, import_react16.useState)(() => restoredSession?.capturedTranscript ?? "");
6753
6870
  const [isVoiceCaptureActive, setIsVoiceCaptureActive] = (0, import_react16.useState)(false);
6754
6871
  const stepsRef = (0, import_react16.useRef)([]);
6755
6872
  stepsRef.current = steps;
@@ -6760,7 +6877,7 @@ function useRecordingMode({
6760
6877
  });
6761
6878
  }, [voice]);
6762
6879
  captureEventsRef.current = captureEvents;
6763
- const pendingClicksRef = (0, import_react16.useRef)([]);
6880
+ const pendingClicksRef = (0, import_react16.useRef)(restoredSession?.pendingClicks ?? []);
6764
6881
  const shouldKeepVoiceCaptureRef = (0, import_react16.useRef)(false);
6765
6882
  const resumeVoiceAfterNarrationRef = (0, import_react16.useRef)(false);
6766
6883
  const lastAutoNoteRef = (0, import_react16.useRef)("");
@@ -7335,6 +7452,22 @@ function useRecordingMode({
7335
7452
  }
7336
7453
  }
7337
7454
  }, [isRecording, phase, markStep, undoLastStep, previewSteps, approveNarration, redoNarration]);
7455
+ (0, import_react16.useEffect)(() => {
7456
+ if (!isRecording && steps.length === 0 && captureEvents.length === 0 && !capturedTranscript.trim()) {
7457
+ clearPersistedRecordingSession();
7458
+ return;
7459
+ }
7460
+ persistRecordingSession({
7461
+ version: 1,
7462
+ experienceType,
7463
+ phase,
7464
+ steps,
7465
+ captureEvents,
7466
+ capturedTranscript,
7467
+ pendingClicks: pendingClicksRef.current,
7468
+ selectedStepType
7469
+ });
7470
+ }, [captureEvents, capturedTranscript, experienceType, isRecording, phase, selectedStepType, steps]);
7338
7471
  return {
7339
7472
  phase,
7340
7473
  steps,
@@ -9274,7 +9407,9 @@ function ModelNexChatBubble({
9274
9407
  const [savedDraft, setSavedDraft] = (0, import_react18.useState)(null);
9275
9408
  const [reviewDraft, setReviewDraft] = (0, import_react18.useState)("");
9276
9409
  const [tourLiveTranscript, setTourLiveTranscript] = (0, import_react18.useState)("");
9277
- const [activeRecordingExperienceType, setActiveRecordingExperienceType] = (0, import_react18.useState)(recordingExperienceType);
9410
+ const [activeRecordingExperienceType, setActiveRecordingExperienceType] = (0, import_react18.useState)(
9411
+ () => readPersistedRecordingExperienceType() ?? recordingExperienceType
9412
+ );
9278
9413
  const recording = useRecordingMode({
9279
9414
  serverUrl,
9280
9415
  toursApiBase: ctx?.toursApiBase,
@@ -9284,6 +9419,16 @@ function ModelNexChatBubble({
9284
9419
  });
9285
9420
  const isGeneratingDraft = isRecordingDraftGenerating(recording.phase);
9286
9421
  const showRecordingOverlay = recordingMode && shouldShowRecordingOverlay(recording.phase);
9422
+ (0, import_react18.useEffect)(() => {
9423
+ const shouldBeRecording = recording.phase !== "idle";
9424
+ if (shouldBeRecording && !recordingMode) {
9425
+ setRecordingMode(true);
9426
+ return;
9427
+ }
9428
+ if (!shouldBeRecording && recordingMode && !showStopModal && !savedDraft) {
9429
+ setRecordingMode(false);
9430
+ }
9431
+ }, [recording.phase, recordingMode, savedDraft, setRecordingMode, showStopModal]);
9287
9432
  const playbackController = useExperiencePlaybackController({
9288
9433
  serverUrl,
9289
9434
  commandUrl: ctx?.commandUrl,
@@ -11789,12 +11934,13 @@ var ModelNexProvider = ({
11789
11934
  const [executedFields, setExecutedFields] = (0, import_react21.useState)(/* @__PURE__ */ new Set());
11790
11935
  const [highlightActions, setHighlightActions] = (0, import_react21.useState)(false);
11791
11936
  const [studioMode, setStudioMode] = (0, import_react21.useState)(false);
11792
- const [recordingMode, setRecordingMode] = (0, import_react21.useState)(false);
11937
+ const [recordingMode, setRecordingMode] = (0, import_react21.useState)(() => hasPersistedRecordingSession());
11793
11938
  const [voiceMuted, setVoiceMuted] = (0, import_react21.useState)(false);
11794
11939
  const [socketId, setSocketId] = (0, import_react21.useState)(null);
11795
11940
  const [actions, setActions] = (0, import_react21.useState)(/* @__PURE__ */ new Map());
11796
11941
  const [validatedBrowserDevMode, setValidatedBrowserDevMode] = (0, import_react21.useState)(false);
11797
- const resolvedDevModeKey = (0, import_react21.useMemo)(() => resolveInjectedDevModeKey(), []);
11942
+ const [resolvedDevModeKey, setResolvedDevModeKey] = (0, import_react21.useState)(() => resolveInjectedDevModeKey());
11943
+ (0, import_react21.useEffect)(() => observeInjectedDevModeKey(setResolvedDevModeKey), []);
11798
11944
  (0, import_react21.useEffect)(() => {
11799
11945
  let cancelled = false;
11800
11946
  if (!websiteId || !resolvedDevModeKey) {
package/dist/index.mjs CHANGED
@@ -2557,6 +2557,32 @@ function normalizeDevModeKey(value) {
2557
2557
  const normalized = value.trim();
2558
2558
  return normalized || void 0;
2559
2559
  }
2560
+ function observeInjectedDevModeKey(listener, options) {
2561
+ if (typeof window === "undefined") return () => {
2562
+ };
2563
+ let currentKey = resolveInjectedDevModeKey();
2564
+ const pollIntervalMs = options?.pollIntervalMs ?? 1e3;
2565
+ const syncInjectedDevModeKey = () => {
2566
+ const nextKey = resolveInjectedDevModeKey();
2567
+ if (nextKey === currentKey) return;
2568
+ currentKey = nextKey;
2569
+ listener(nextKey);
2570
+ };
2571
+ const intervalId = window.setInterval(syncInjectedDevModeKey, pollIntervalMs);
2572
+ window.addEventListener("focus", syncInjectedDevModeKey);
2573
+ window.addEventListener("pageshow", syncInjectedDevModeKey);
2574
+ if (typeof document !== "undefined") {
2575
+ document.addEventListener("visibilitychange", syncInjectedDevModeKey);
2576
+ }
2577
+ return () => {
2578
+ window.clearInterval(intervalId);
2579
+ window.removeEventListener("focus", syncInjectedDevModeKey);
2580
+ window.removeEventListener("pageshow", syncInjectedDevModeKey);
2581
+ if (typeof document !== "undefined") {
2582
+ document.removeEventListener("visibilitychange", syncInjectedDevModeKey);
2583
+ }
2584
+ };
2585
+ }
2560
2586
  function resolveInjectedDevModeKey() {
2561
2587
  if (typeof window === "undefined") return void 0;
2562
2588
  const browserWindow = window;
@@ -2597,6 +2623,91 @@ async function validateInjectedDevModeKey(serverUrl, websiteId, devModeKey) {
2597
2623
  return validationPromise;
2598
2624
  }
2599
2625
 
2626
+ // src/utils/recordingPersistence.ts
2627
+ var RECORDING_SESSION_STORAGE_KEY = "modelnex-recording-session";
2628
+ var RESTORABLE_RECORDING_PHASES = /* @__PURE__ */ new Set([
2629
+ "active",
2630
+ "selecting",
2631
+ "configuring",
2632
+ "narrating",
2633
+ "reviewing",
2634
+ "saved",
2635
+ "finishing"
2636
+ ]);
2637
+ var TOUR_STEP_TYPES = /* @__PURE__ */ new Set([
2638
+ "narrate",
2639
+ "act",
2640
+ "input",
2641
+ "ask_and_fill",
2642
+ "user_input",
2643
+ "ask_or_fill",
2644
+ "wait_then_act"
2645
+ ]);
2646
+ function canUseSessionStorage() {
2647
+ return typeof window !== "undefined" && typeof window.sessionStorage !== "undefined";
2648
+ }
2649
+ function isExperienceType(value) {
2650
+ return value === "tour" || value === "onboarding";
2651
+ }
2652
+ function isTourStepType(value) {
2653
+ return typeof value === "string" && TOUR_STEP_TYPES.has(value);
2654
+ }
2655
+ function isPlainObject(value) {
2656
+ return Boolean(value) && typeof value === "object" && !Array.isArray(value);
2657
+ }
2658
+ function sanitizePersistedRecordingSession(raw) {
2659
+ if (!isPlainObject(raw)) return null;
2660
+ if (raw.version !== 1) return null;
2661
+ if (!isExperienceType(raw.experienceType)) return null;
2662
+ if (typeof raw.phase !== "string" || !RESTORABLE_RECORDING_PHASES.has(raw.phase)) return null;
2663
+ if (!Array.isArray(raw.steps) || !Array.isArray(raw.captureEvents) || !Array.isArray(raw.pendingClicks)) return null;
2664
+ if (!isTourStepType(raw.selectedStepType)) return null;
2665
+ return {
2666
+ version: 1,
2667
+ experienceType: raw.experienceType,
2668
+ phase: raw.phase,
2669
+ steps: raw.steps,
2670
+ captureEvents: raw.captureEvents,
2671
+ capturedTranscript: typeof raw.capturedTranscript === "string" ? raw.capturedTranscript : "",
2672
+ pendingClicks: raw.pendingClicks,
2673
+ selectedStepType: raw.selectedStepType
2674
+ };
2675
+ }
2676
+ function readPersistedRecordingSession() {
2677
+ if (!canUseSessionStorage()) return null;
2678
+ try {
2679
+ const raw = window.sessionStorage.getItem(RECORDING_SESSION_STORAGE_KEY);
2680
+ if (!raw) return null;
2681
+ const parsed = sanitizePersistedRecordingSession(JSON.parse(raw));
2682
+ if (parsed) {
2683
+ return parsed;
2684
+ }
2685
+ } catch {
2686
+ }
2687
+ clearPersistedRecordingSession();
2688
+ return null;
2689
+ }
2690
+ function readPersistedRecordingExperienceType() {
2691
+ return readPersistedRecordingSession()?.experienceType ?? null;
2692
+ }
2693
+ function hasPersistedRecordingSession() {
2694
+ return readPersistedRecordingSession() !== null;
2695
+ }
2696
+ function persistRecordingSession(session) {
2697
+ if (!canUseSessionStorage()) return;
2698
+ try {
2699
+ window.sessionStorage.setItem(RECORDING_SESSION_STORAGE_KEY, JSON.stringify(session));
2700
+ } catch {
2701
+ }
2702
+ }
2703
+ function clearPersistedRecordingSession() {
2704
+ if (!canUseSessionStorage()) return;
2705
+ try {
2706
+ window.sessionStorage.removeItem(RECORDING_SESSION_STORAGE_KEY);
2707
+ } catch {
2708
+ }
2709
+ }
2710
+
2600
2711
  // src/hooks/useRunCommand.ts
2601
2712
  import { useCallback as useCallback5, useContext as useContext2 } from "react";
2602
2713
  function searchTaggedElementsForQuery(store, query, limit = 8) {
@@ -6532,14 +6643,20 @@ function useRecordingMode({
6532
6643
  onPreview,
6533
6644
  experienceType = "tour"
6534
6645
  }) {
6535
- const [phase, setPhase] = useState11("idle");
6536
- const [steps, setSteps] = useState11([]);
6646
+ const restoredSessionRef = useRef12(void 0);
6647
+ if (restoredSessionRef.current === void 0) {
6648
+ restoredSessionRef.current = readPersistedRecordingSession();
6649
+ }
6650
+ const restoredSession = restoredSessionRef.current;
6651
+ const restoredPhase = restoredSession ? "active" : "idle";
6652
+ const [phase, setPhase] = useState11(restoredPhase);
6653
+ const [steps, setSteps] = useState11(() => restoredSession?.steps ?? []);
6537
6654
  const [selectedElement, setSelectedElement] = useState11(null);
6538
- const [selectedStepType, setSelectedStepType] = useState11("ask_or_fill");
6655
+ const [selectedStepType, setSelectedStepType] = useState11(() => restoredSession?.selectedStepType ?? "ask_or_fill");
6539
6656
  const [pendingNarration, setPendingNarration] = useState11("");
6540
6657
  const [polishedNarration, setPolishedNarration] = useState11("");
6541
- const [captureEvents, setCaptureEvents] = useState11([]);
6542
- const [capturedTranscript, setCapturedTranscript] = useState11("");
6658
+ const [captureEvents, setCaptureEvents] = useState11(() => restoredSession?.captureEvents ?? []);
6659
+ const [capturedTranscript, setCapturedTranscript] = useState11(() => restoredSession?.capturedTranscript ?? "");
6543
6660
  const [isVoiceCaptureActive, setIsVoiceCaptureActive] = useState11(false);
6544
6661
  const stepsRef = useRef12([]);
6545
6662
  stepsRef.current = steps;
@@ -6550,7 +6667,7 @@ function useRecordingMode({
6550
6667
  });
6551
6668
  }, [voice]);
6552
6669
  captureEventsRef.current = captureEvents;
6553
- const pendingClicksRef = useRef12([]);
6670
+ const pendingClicksRef = useRef12(restoredSession?.pendingClicks ?? []);
6554
6671
  const shouldKeepVoiceCaptureRef = useRef12(false);
6555
6672
  const resumeVoiceAfterNarrationRef = useRef12(false);
6556
6673
  const lastAutoNoteRef = useRef12("");
@@ -7125,6 +7242,22 @@ function useRecordingMode({
7125
7242
  }
7126
7243
  }
7127
7244
  }, [isRecording, phase, markStep, undoLastStep, previewSteps, approveNarration, redoNarration]);
7245
+ useEffect15(() => {
7246
+ if (!isRecording && steps.length === 0 && captureEvents.length === 0 && !capturedTranscript.trim()) {
7247
+ clearPersistedRecordingSession();
7248
+ return;
7249
+ }
7250
+ persistRecordingSession({
7251
+ version: 1,
7252
+ experienceType,
7253
+ phase,
7254
+ steps,
7255
+ captureEvents,
7256
+ capturedTranscript,
7257
+ pendingClicks: pendingClicksRef.current,
7258
+ selectedStepType
7259
+ });
7260
+ }, [captureEvents, capturedTranscript, experienceType, isRecording, phase, selectedStepType, steps]);
7128
7261
  return {
7129
7262
  phase,
7130
7263
  steps,
@@ -9064,7 +9197,9 @@ function ModelNexChatBubble({
9064
9197
  const [savedDraft, setSavedDraft] = useState13(null);
9065
9198
  const [reviewDraft, setReviewDraft] = useState13("");
9066
9199
  const [tourLiveTranscript, setTourLiveTranscript] = useState13("");
9067
- const [activeRecordingExperienceType, setActiveRecordingExperienceType] = useState13(recordingExperienceType);
9200
+ const [activeRecordingExperienceType, setActiveRecordingExperienceType] = useState13(
9201
+ () => readPersistedRecordingExperienceType() ?? recordingExperienceType
9202
+ );
9068
9203
  const recording = useRecordingMode({
9069
9204
  serverUrl,
9070
9205
  toursApiBase: ctx?.toursApiBase,
@@ -9074,6 +9209,16 @@ function ModelNexChatBubble({
9074
9209
  });
9075
9210
  const isGeneratingDraft = isRecordingDraftGenerating(recording.phase);
9076
9211
  const showRecordingOverlay = recordingMode && shouldShowRecordingOverlay(recording.phase);
9212
+ useEffect17(() => {
9213
+ const shouldBeRecording = recording.phase !== "idle";
9214
+ if (shouldBeRecording && !recordingMode) {
9215
+ setRecordingMode(true);
9216
+ return;
9217
+ }
9218
+ if (!shouldBeRecording && recordingMode && !showStopModal && !savedDraft) {
9219
+ setRecordingMode(false);
9220
+ }
9221
+ }, [recording.phase, recordingMode, savedDraft, setRecordingMode, showStopModal]);
9077
9222
  const playbackController = useExperiencePlaybackController({
9078
9223
  serverUrl,
9079
9224
  commandUrl: ctx?.commandUrl,
@@ -11579,12 +11724,13 @@ var ModelNexProvider = ({
11579
11724
  const [executedFields, setExecutedFields] = useState15(/* @__PURE__ */ new Set());
11580
11725
  const [highlightActions, setHighlightActions] = useState15(false);
11581
11726
  const [studioMode, setStudioMode] = useState15(false);
11582
- const [recordingMode, setRecordingMode] = useState15(false);
11727
+ const [recordingMode, setRecordingMode] = useState15(() => hasPersistedRecordingSession());
11583
11728
  const [voiceMuted, setVoiceMuted] = useState15(false);
11584
11729
  const [socketId, setSocketId] = useState15(null);
11585
11730
  const [actions, setActions] = useState15(/* @__PURE__ */ new Map());
11586
11731
  const [validatedBrowserDevMode, setValidatedBrowserDevMode] = useState15(false);
11587
- const resolvedDevModeKey = useMemo5(() => resolveInjectedDevModeKey(), []);
11732
+ const [resolvedDevModeKey, setResolvedDevModeKey] = useState15(() => resolveInjectedDevModeKey());
11733
+ useEffect19(() => observeInjectedDevModeKey(setResolvedDevModeKey), []);
11588
11734
  useEffect19(() => {
11589
11735
  let cancelled = false;
11590
11736
  if (!websiteId || !resolvedDevModeKey) {
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@modelnex/sdk",
3
- "version": "0.5.31",
3
+ "version": "0.5.33",
4
4
  "description": "React SDK for natural language control of web apps via AI agents",
5
5
  "main": "./dist/index.js",
6
6
  "module": "./dist/index.mjs",
@@ -20,15 +20,6 @@
20
20
  "dist",
21
21
  "README.md"
22
22
  ],
23
- "scripts": {
24
- "prepublishOnly": "npm run build",
25
- "build": "npm exec -- tsup src/index.ts --format cjs,esm --dts",
26
- "dev": "npm exec -- tsup src/index.ts --format cjs,esm --watch --dts",
27
- "lint": "eslint src/",
28
- "test": "npm run build && node --test tests/*.test.js",
29
- "test:ci": "npm run test && npm run test:unit",
30
- "test:unit": "node --import tsx --test tests/*.test.ts"
31
- },
32
23
  "peerDependencies": {
33
24
  "react": ">=17.0.0",
34
25
  "react-dom": ">=17.0.0",
@@ -67,5 +58,13 @@
67
58
  "bugs": {
68
59
  "url": "https://github.com/sharunaraksha/modelnex-sdk/issues"
69
60
  },
70
- "homepage": "https://github.com/sharunaraksha/modelnex-sdk#readme"
71
- }
61
+ "homepage": "https://github.com/sharunaraksha/modelnex-sdk#readme",
62
+ "scripts": {
63
+ "build": "npm exec -- tsup src/index.ts --format cjs,esm --dts",
64
+ "dev": "npm exec -- tsup src/index.ts --format cjs,esm --watch --dts",
65
+ "lint": "eslint src/",
66
+ "test": "npm run build && node --test tests/*.test.js",
67
+ "test:ci": "npm run test && npm run test:unit",
68
+ "test:unit": "node --import tsx --test tests/*.test.ts"
69
+ }
70
+ }
@@ -1,55 +0,0 @@
1
- // src/utils/dom-sync.ts
2
- function waitForDomSettle(options = {}) {
3
- const { timeoutMs = 5e3, debounceMs = 400, minWaitMs = 100 } = options;
4
- return new Promise((resolve) => {
5
- let debounceTimer = null;
6
- let resolved = false;
7
- const maxTimer = setTimeout(() => {
8
- if (!resolved) {
9
- resolved = true;
10
- cleanup();
11
- console.log("[DOM Sync] Forced resolution by max timeout");
12
- resolve();
13
- }
14
- }, Math.max(timeoutMs, minWaitMs));
15
- const finish = () => {
16
- if (!resolved) {
17
- resolved = true;
18
- cleanup();
19
- resolve();
20
- }
21
- };
22
- const observer = new MutationObserver((mutations) => {
23
- const hasSignificantMutations = mutations.some((m) => {
24
- if (m.target instanceof HTMLElement) {
25
- if (m.target.hasAttribute("data-modelnex-tour-highlight")) return false;
26
- if (m.target.hasAttribute("data-modelnex-caption")) return false;
27
- if (m.target.closest("#modelnex-studio-root")) return false;
28
- if (m.target.closest("#modelnex-active-agent-root")) return false;
29
- }
30
- return true;
31
- });
32
- if (!hasSignificantMutations) return;
33
- if (debounceTimer) clearTimeout(debounceTimer);
34
- debounceTimer = setTimeout(finish, debounceMs);
35
- });
36
- const cleanup = () => {
37
- observer.disconnect();
38
- if (debounceTimer) clearTimeout(debounceTimer);
39
- clearTimeout(maxTimer);
40
- };
41
- setTimeout(() => {
42
- if (resolved) return;
43
- observer.observe(document.body, {
44
- childList: true,
45
- subtree: true,
46
- attributes: true,
47
- characterData: true
48
- });
49
- debounceTimer = setTimeout(finish, debounceMs);
50
- }, minWaitMs);
51
- });
52
- }
53
- export {
54
- waitForDomSettle
55
- };