@modelnex/sdk 0.5.14 → 0.5.15

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.d.mts CHANGED
@@ -228,7 +228,7 @@ interface RecordingStep {
228
228
  }
229
229
 
230
230
  /** Default ModelNex server when `serverUrl` is omitted or React context is unavailable. */
231
- declare const DEFAULT_MODELNEX_SERVER_URL = "https://modelnex-server-production.up.railway.app";
231
+ declare const DEFAULT_MODELNEX_SERVER_URL = "https://api.modelnex.com";
232
232
 
233
233
  /**
234
234
  * Automatic DOM element extraction with stable fingerprinting.
@@ -822,7 +822,7 @@ declare function clearActiveDraftPreview(experienceType?: ExperienceType): void;
822
822
  interface ModelNexProviderProps {
823
823
  children?: unknown;
824
824
  /**
825
- * ModelNex Server URL (e.g. https://xxx.up.railway.app).
825
+ * ModelNex Server URL (e.g. https://api.modelnex.com).
826
826
  * When omitted, {@link DEFAULT_MODELNEX_SERVER_URL} is used.
827
827
  */
828
828
  serverUrl?: string;
package/dist/index.d.ts CHANGED
@@ -228,7 +228,7 @@ interface RecordingStep {
228
228
  }
229
229
 
230
230
  /** Default ModelNex server when `serverUrl` is omitted or React context is unavailable. */
231
- declare const DEFAULT_MODELNEX_SERVER_URL = "https://modelnex-server-production.up.railway.app";
231
+ declare const DEFAULT_MODELNEX_SERVER_URL = "https://api.modelnex.com";
232
232
 
233
233
  /**
234
234
  * Automatic DOM element extraction with stable fingerprinting.
@@ -822,7 +822,7 @@ declare function clearActiveDraftPreview(experienceType?: ExperienceType): void;
822
822
  interface ModelNexProviderProps {
823
823
  children?: unknown;
824
824
  /**
825
- * ModelNex Server URL (e.g. https://xxx.up.railway.app).
825
+ * ModelNex Server URL (e.g. https://api.modelnex.com).
826
826
  * When omitted, {@link DEFAULT_MODELNEX_SERVER_URL} is used.
827
827
  */
828
828
  serverUrl?: string;
package/dist/index.js CHANGED
@@ -2324,7 +2324,7 @@ function useBuiltinActions(registerAction, unregisterAction, tagStore, serverUrl
2324
2324
  }
2325
2325
 
2326
2326
  // src/constants.ts
2327
- var DEFAULT_MODELNEX_SERVER_URL = "https://modelnex-server-production.up.railway.app";
2327
+ var DEFAULT_MODELNEX_SERVER_URL = "https://api.modelnex.com";
2328
2328
 
2329
2329
  // src/hooks/useRunCommand.ts
2330
2330
  var import_react9 = require("react");
@@ -3154,6 +3154,12 @@ function useTourPlayback({
3154
3154
  const [serverState, setServerState] = (0, import_react12.useState)(null);
3155
3155
  const ctx = (0, import_react12.useContext)(ModelNexContext);
3156
3156
  const devMode = ctx?.devMode;
3157
+ const devModeRef = (0, import_react12.useRef)(devMode);
3158
+ devModeRef.current = devMode;
3159
+ const userProfileRef = (0, import_react12.useRef)(userProfile);
3160
+ userProfileRef.current = userProfile;
3161
+ const experienceTypeRef = (0, import_react12.useRef)(experienceType);
3162
+ experienceTypeRef.current = experienceType;
3157
3163
  const tourRef = (0, import_react12.useRef)(null);
3158
3164
  const stepIndexRef = (0, import_react12.useRef)(0);
3159
3165
  const skipRequestedRef = (0, import_react12.useRef)(false);
@@ -3193,18 +3199,27 @@ function useTourPlayback({
3193
3199
  (0, import_react12.useEffect)(() => {
3194
3200
  if (disabled) return;
3195
3201
  if (typeof window === "undefined") return;
3202
+ let cancelled = false;
3203
+ let createdSocket = null;
3196
3204
  import("socket.io-client").then((ioModule) => {
3205
+ if (cancelled) return;
3197
3206
  const io2 = ioModule.default || ioModule;
3198
3207
  const socket = io2(serverUrl, {
3199
3208
  path: "/socket.io",
3200
3209
  // standard
3201
3210
  transports: resolveSocketIoTransports(serverUrl, "polling-first")
3202
3211
  });
3212
+ if (cancelled) {
3213
+ socket.disconnect();
3214
+ return;
3215
+ }
3216
+ createdSocket = socket;
3203
3217
  socketRef.current = socket;
3204
3218
  socket.on("connect", () => {
3205
3219
  console.log("[TourClient] Connected to tour agent server:", socket.id);
3206
- if (websiteId && userProfile) {
3207
- socket.emit("tour:init", { websiteId, userId: userProfile.userId, userType: userProfile.type });
3220
+ const profile = userProfileRef.current;
3221
+ if (websiteId && profile?.userId) {
3222
+ socket.emit("tour:init", { websiteId, userId: profile.userId, userType: profile.type });
3208
3223
  }
3209
3224
  });
3210
3225
  socket.on("tour:server_state", (payload) => {
@@ -3229,6 +3244,11 @@ function useTourPlayback({
3229
3244
  }
3230
3245
  });
3231
3246
  socket.on("tour:command", async (payload) => {
3247
+ const emitIfOpen = (ev, data) => {
3248
+ if (socketRef.current !== socket) return;
3249
+ if (!socket.connected) return;
3250
+ socket.emit(ev, data);
3251
+ };
3232
3252
  console.log("[TourClient] Received command batch:", payload.stepIndex, payload.commands);
3233
3253
  runCleanup(pendingManualWaitCleanupRef.current);
3234
3254
  pendingManualWaitCleanupRef.current = null;
@@ -3287,7 +3307,7 @@ function useTourPlayback({
3287
3307
  if (!payload.commands || !Array.isArray(payload.commands)) {
3288
3308
  console.warn("[TourClient] Payload commands is not an array:", payload);
3289
3309
  commandInFlightRef.current = false;
3290
- socket.emit("tour:action_result", {
3310
+ emitIfOpen("tour:action_result", {
3291
3311
  success: false,
3292
3312
  reason: "invalid_commands",
3293
3313
  commandBatchId,
@@ -3566,7 +3586,7 @@ function useTourPlayback({
3566
3586
  currentStepOrder: stepIndexRef.current
3567
3587
  });
3568
3588
  }
3569
- socket.emit("tour:action_result", {
3589
+ emitIfOpen("tour:action_result", {
3570
3590
  success: true,
3571
3591
  interrupted: true,
3572
3592
  results,
@@ -3591,7 +3611,7 @@ function useTourPlayback({
3591
3611
  currentStepOrder: stepIndexRef.current
3592
3612
  });
3593
3613
  }
3594
- socket.emit("tour:action_result", {
3614
+ emitIfOpen("tour:action_result", {
3595
3615
  success: false,
3596
3616
  reason: "execution_error",
3597
3617
  error: String(err),
@@ -3660,7 +3680,7 @@ function useTourPlayback({
3660
3680
  currentStepOrder: stepIndexRef.current
3661
3681
  });
3662
3682
  }
3663
- socket.emit("tour:action_result", {
3683
+ emitIfOpen("tour:action_result", {
3664
3684
  success: true,
3665
3685
  waitingForInput: true,
3666
3686
  results,
@@ -3693,7 +3713,7 @@ function useTourPlayback({
3693
3713
  const { waitForDomSettle: waitForDomSettle2 } = await Promise.resolve().then(() => (init_dom_sync(), dom_sync_exports));
3694
3714
  await waitForDomSettle2({ timeoutMs: 1500, debounceMs: 200 });
3695
3715
  await syncAOM();
3696
- socket.emit("tour:user_input", {
3716
+ emitIfOpen("tour:user_input", {
3697
3717
  transcript,
3698
3718
  runId: runIdRef.current,
3699
3719
  turnId: turnIdRef.current
@@ -3712,7 +3732,7 @@ function useTourPlayback({
3712
3732
  currentStepOrder: stepIndexRef.current
3713
3733
  });
3714
3734
  }
3715
- socket.emit("tour:action_result", {
3735
+ emitIfOpen("tour:action_result", {
3716
3736
  success: true,
3717
3737
  results,
3718
3738
  commandBatchId,
@@ -3725,8 +3745,9 @@ function useTourPlayback({
3725
3745
  if (isActiveRef.current) return;
3726
3746
  runIdRef.current = typeof tourData.runId === "number" ? tourData.runId : runIdRef.current;
3727
3747
  const tour = tourData.tourContext ?? tourRef.current;
3728
- if (tour?.type && tour.type !== experienceType) {
3729
- console.log(`[TourClient] Ignoring ${tour.type} start (this hook is for ${experienceType})`);
3748
+ const expType = experienceTypeRef.current;
3749
+ if (tour?.type && tour.type !== expType) {
3750
+ console.log(`[TourClient] Ignoring ${tour.type} start (this hook is for ${expType})`);
3730
3751
  return;
3731
3752
  }
3732
3753
  skipRequestedRef.current = false;
@@ -3753,11 +3774,13 @@ function useTourPlayback({
3753
3774
  try {
3754
3775
  const { generateMinifiedAOM: generateMinifiedAOM2 } = await Promise.resolve().then(() => (init_aom(), aom_exports));
3755
3776
  const aom = generateMinifiedAOM2();
3756
- socket.emit("tour:sync_dom", {
3757
- url: window.location.pathname + window.location.search + window.location.hash,
3758
- aom: aom.nodes,
3759
- domSummary: captureDomSummary()
3760
- });
3777
+ if (socketRef.current === socket && socket.connected) {
3778
+ socket.emit("tour:sync_dom", {
3779
+ url: window.location.pathname + window.location.search + window.location.hash,
3780
+ aom: aom.nodes,
3781
+ domSummary: captureDomSummary()
3782
+ });
3783
+ }
3761
3784
  } catch (e) {
3762
3785
  console.warn("[TourClient] Initial DOM sync failed:", e);
3763
3786
  }
@@ -3785,7 +3808,7 @@ function useTourPlayback({
3785
3808
  handleTourEnd();
3786
3809
  });
3787
3810
  socket.on("tour:debug_log", (entry) => {
3788
- const isDev = devMode || process.env.NODE_ENV === "development" || typeof window !== "undefined" && window.MODELNEX_DEBUG;
3811
+ const isDev = devModeRef.current || process.env.NODE_ENV === "development" || typeof window !== "undefined" && window.MODELNEX_DEBUG;
3789
3812
  if (isDev) {
3790
3813
  console.log(`%c[ModelNex Tour] ${entry.type}`, "color: #3b82f6; font-weight: bold", entry);
3791
3814
  if (typeof window !== "undefined") {
@@ -3795,18 +3818,28 @@ function useTourPlayback({
3795
3818
  }
3796
3819
  }
3797
3820
  });
3798
- console.log("[ModelNex SDK] Tour playback initialized. Debug logs enabled:", devMode || process.env.NODE_ENV === "development");
3821
+ console.log("[ModelNex SDK] Tour playback initialized. Debug logs enabled:", devModeRef.current || process.env.NODE_ENV === "development");
3799
3822
  });
3800
3823
  return () => {
3801
- if (socketRef.current) {
3802
- socketRef.current.disconnect();
3803
- socketRef.current = null;
3824
+ cancelled = true;
3825
+ const toClose = createdSocket ?? socketRef.current;
3826
+ if (toClose) {
3827
+ toClose.disconnect();
3804
3828
  }
3829
+ createdSocket = null;
3830
+ socketRef.current = null;
3805
3831
  setServerState(null);
3806
3832
  runIdRef.current = null;
3807
3833
  turnIdRef.current = null;
3808
3834
  };
3809
- }, [serverUrl, websiteId, userProfile, disabled, devMode, experienceType]);
3835
+ }, [serverUrl, websiteId, disabled]);
3836
+ (0, import_react12.useEffect)(() => {
3837
+ if (disabled) return;
3838
+ const s = socketRef.current;
3839
+ const profile = userProfile;
3840
+ if (!s?.connected || !websiteId || !profile?.userId) return;
3841
+ s.emit("tour:init", { websiteId, userId: profile.userId, userType: profile.type });
3842
+ }, [disabled, websiteId, userProfile?.userId, userProfile?.type]);
3810
3843
  (0, import_react12.useEffect)(() => {
3811
3844
  if (!showCaptions || !isReviewMode) {
3812
3845
  removeCaption();
package/dist/index.mjs CHANGED
@@ -2114,7 +2114,7 @@ function useBuiltinActions(registerAction, unregisterAction, tagStore, serverUrl
2114
2114
  }
2115
2115
 
2116
2116
  // src/constants.ts
2117
- var DEFAULT_MODELNEX_SERVER_URL = "https://modelnex-server-production.up.railway.app";
2117
+ var DEFAULT_MODELNEX_SERVER_URL = "https://api.modelnex.com";
2118
2118
 
2119
2119
  // src/hooks/useRunCommand.ts
2120
2120
  import { useCallback as useCallback5, useContext as useContext2 } from "react";
@@ -2944,6 +2944,12 @@ function useTourPlayback({
2944
2944
  const [serverState, setServerState] = useState7(null);
2945
2945
  const ctx = useContext4(ModelNexContext);
2946
2946
  const devMode = ctx?.devMode;
2947
+ const devModeRef = useRef8(devMode);
2948
+ devModeRef.current = devMode;
2949
+ const userProfileRef = useRef8(userProfile);
2950
+ userProfileRef.current = userProfile;
2951
+ const experienceTypeRef = useRef8(experienceType);
2952
+ experienceTypeRef.current = experienceType;
2947
2953
  const tourRef = useRef8(null);
2948
2954
  const stepIndexRef = useRef8(0);
2949
2955
  const skipRequestedRef = useRef8(false);
@@ -2983,18 +2989,27 @@ function useTourPlayback({
2983
2989
  useEffect11(() => {
2984
2990
  if (disabled) return;
2985
2991
  if (typeof window === "undefined") return;
2992
+ let cancelled = false;
2993
+ let createdSocket = null;
2986
2994
  import("socket.io-client").then((ioModule) => {
2995
+ if (cancelled) return;
2987
2996
  const io2 = ioModule.default || ioModule;
2988
2997
  const socket = io2(serverUrl, {
2989
2998
  path: "/socket.io",
2990
2999
  // standard
2991
3000
  transports: resolveSocketIoTransports(serverUrl, "polling-first")
2992
3001
  });
3002
+ if (cancelled) {
3003
+ socket.disconnect();
3004
+ return;
3005
+ }
3006
+ createdSocket = socket;
2993
3007
  socketRef.current = socket;
2994
3008
  socket.on("connect", () => {
2995
3009
  console.log("[TourClient] Connected to tour agent server:", socket.id);
2996
- if (websiteId && userProfile) {
2997
- socket.emit("tour:init", { websiteId, userId: userProfile.userId, userType: userProfile.type });
3010
+ const profile = userProfileRef.current;
3011
+ if (websiteId && profile?.userId) {
3012
+ socket.emit("tour:init", { websiteId, userId: profile.userId, userType: profile.type });
2998
3013
  }
2999
3014
  });
3000
3015
  socket.on("tour:server_state", (payload) => {
@@ -3019,6 +3034,11 @@ function useTourPlayback({
3019
3034
  }
3020
3035
  });
3021
3036
  socket.on("tour:command", async (payload) => {
3037
+ const emitIfOpen = (ev, data) => {
3038
+ if (socketRef.current !== socket) return;
3039
+ if (!socket.connected) return;
3040
+ socket.emit(ev, data);
3041
+ };
3022
3042
  console.log("[TourClient] Received command batch:", payload.stepIndex, payload.commands);
3023
3043
  runCleanup(pendingManualWaitCleanupRef.current);
3024
3044
  pendingManualWaitCleanupRef.current = null;
@@ -3077,7 +3097,7 @@ function useTourPlayback({
3077
3097
  if (!payload.commands || !Array.isArray(payload.commands)) {
3078
3098
  console.warn("[TourClient] Payload commands is not an array:", payload);
3079
3099
  commandInFlightRef.current = false;
3080
- socket.emit("tour:action_result", {
3100
+ emitIfOpen("tour:action_result", {
3081
3101
  success: false,
3082
3102
  reason: "invalid_commands",
3083
3103
  commandBatchId,
@@ -3356,7 +3376,7 @@ function useTourPlayback({
3356
3376
  currentStepOrder: stepIndexRef.current
3357
3377
  });
3358
3378
  }
3359
- socket.emit("tour:action_result", {
3379
+ emitIfOpen("tour:action_result", {
3360
3380
  success: true,
3361
3381
  interrupted: true,
3362
3382
  results,
@@ -3381,7 +3401,7 @@ function useTourPlayback({
3381
3401
  currentStepOrder: stepIndexRef.current
3382
3402
  });
3383
3403
  }
3384
- socket.emit("tour:action_result", {
3404
+ emitIfOpen("tour:action_result", {
3385
3405
  success: false,
3386
3406
  reason: "execution_error",
3387
3407
  error: String(err),
@@ -3450,7 +3470,7 @@ function useTourPlayback({
3450
3470
  currentStepOrder: stepIndexRef.current
3451
3471
  });
3452
3472
  }
3453
- socket.emit("tour:action_result", {
3473
+ emitIfOpen("tour:action_result", {
3454
3474
  success: true,
3455
3475
  waitingForInput: true,
3456
3476
  results,
@@ -3483,7 +3503,7 @@ function useTourPlayback({
3483
3503
  const { waitForDomSettle } = await import("./dom-sync-L5KIP45X.mjs");
3484
3504
  await waitForDomSettle({ timeoutMs: 1500, debounceMs: 200 });
3485
3505
  await syncAOM();
3486
- socket.emit("tour:user_input", {
3506
+ emitIfOpen("tour:user_input", {
3487
3507
  transcript,
3488
3508
  runId: runIdRef.current,
3489
3509
  turnId: turnIdRef.current
@@ -3502,7 +3522,7 @@ function useTourPlayback({
3502
3522
  currentStepOrder: stepIndexRef.current
3503
3523
  });
3504
3524
  }
3505
- socket.emit("tour:action_result", {
3525
+ emitIfOpen("tour:action_result", {
3506
3526
  success: true,
3507
3527
  results,
3508
3528
  commandBatchId,
@@ -3515,8 +3535,9 @@ function useTourPlayback({
3515
3535
  if (isActiveRef.current) return;
3516
3536
  runIdRef.current = typeof tourData.runId === "number" ? tourData.runId : runIdRef.current;
3517
3537
  const tour = tourData.tourContext ?? tourRef.current;
3518
- if (tour?.type && tour.type !== experienceType) {
3519
- console.log(`[TourClient] Ignoring ${tour.type} start (this hook is for ${experienceType})`);
3538
+ const expType = experienceTypeRef.current;
3539
+ if (tour?.type && tour.type !== expType) {
3540
+ console.log(`[TourClient] Ignoring ${tour.type} start (this hook is for ${expType})`);
3520
3541
  return;
3521
3542
  }
3522
3543
  skipRequestedRef.current = false;
@@ -3543,11 +3564,13 @@ function useTourPlayback({
3543
3564
  try {
3544
3565
  const { generateMinifiedAOM: generateMinifiedAOM2 } = await import("./aom-HDYNCIOY.mjs");
3545
3566
  const aom = generateMinifiedAOM2();
3546
- socket.emit("tour:sync_dom", {
3547
- url: window.location.pathname + window.location.search + window.location.hash,
3548
- aom: aom.nodes,
3549
- domSummary: captureDomSummary()
3550
- });
3567
+ if (socketRef.current === socket && socket.connected) {
3568
+ socket.emit("tour:sync_dom", {
3569
+ url: window.location.pathname + window.location.search + window.location.hash,
3570
+ aom: aom.nodes,
3571
+ domSummary: captureDomSummary()
3572
+ });
3573
+ }
3551
3574
  } catch (e) {
3552
3575
  console.warn("[TourClient] Initial DOM sync failed:", e);
3553
3576
  }
@@ -3575,7 +3598,7 @@ function useTourPlayback({
3575
3598
  handleTourEnd();
3576
3599
  });
3577
3600
  socket.on("tour:debug_log", (entry) => {
3578
- const isDev = devMode || process.env.NODE_ENV === "development" || typeof window !== "undefined" && window.MODELNEX_DEBUG;
3601
+ const isDev = devModeRef.current || process.env.NODE_ENV === "development" || typeof window !== "undefined" && window.MODELNEX_DEBUG;
3579
3602
  if (isDev) {
3580
3603
  console.log(`%c[ModelNex Tour] ${entry.type}`, "color: #3b82f6; font-weight: bold", entry);
3581
3604
  if (typeof window !== "undefined") {
@@ -3585,18 +3608,28 @@ function useTourPlayback({
3585
3608
  }
3586
3609
  }
3587
3610
  });
3588
- console.log("[ModelNex SDK] Tour playback initialized. Debug logs enabled:", devMode || process.env.NODE_ENV === "development");
3611
+ console.log("[ModelNex SDK] Tour playback initialized. Debug logs enabled:", devModeRef.current || process.env.NODE_ENV === "development");
3589
3612
  });
3590
3613
  return () => {
3591
- if (socketRef.current) {
3592
- socketRef.current.disconnect();
3593
- socketRef.current = null;
3614
+ cancelled = true;
3615
+ const toClose = createdSocket ?? socketRef.current;
3616
+ if (toClose) {
3617
+ toClose.disconnect();
3594
3618
  }
3619
+ createdSocket = null;
3620
+ socketRef.current = null;
3595
3621
  setServerState(null);
3596
3622
  runIdRef.current = null;
3597
3623
  turnIdRef.current = null;
3598
3624
  };
3599
- }, [serverUrl, websiteId, userProfile, disabled, devMode, experienceType]);
3625
+ }, [serverUrl, websiteId, disabled]);
3626
+ useEffect11(() => {
3627
+ if (disabled) return;
3628
+ const s = socketRef.current;
3629
+ const profile = userProfile;
3630
+ if (!s?.connected || !websiteId || !profile?.userId) return;
3631
+ s.emit("tour:init", { websiteId, userId: profile.userId, userType: profile.type });
3632
+ }, [disabled, websiteId, userProfile?.userId, userProfile?.type]);
3600
3633
  useEffect11(() => {
3601
3634
  if (!showCaptions || !isReviewMode) {
3602
3635
  removeCaption();
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@modelnex/sdk",
3
- "version": "0.5.14",
3
+ "version": "0.5.15",
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",