@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 +155 -9
- package/dist/index.mjs +155 -9
- package/package.json +11 -12
- package/dist/dom-sync-L5KIP45X.mjs +0 -55
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
|
|
6746
|
-
|
|
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)(
|
|
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)(
|
|
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.
|
|
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
|
|
6536
|
-
|
|
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(
|
|
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(
|
|
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 =
|
|
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.
|
|
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
|
-
};
|