@iblai/web-utils 1.1.10 → 1.1.12

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.
@@ -0,0 +1,165 @@
1
+ import { SelfRetireResponse } from './types';
2
+ export declare const retirementApiSlice: import("@reduxjs/toolkit/query").Api<import("@reduxjs/toolkit/query").BaseQueryFn<import("@data-layer/features/utils").CustomQueryArgs, unknown, import("@data-layer/features/utils").ExtendedFetchBaseQueryError, Record<string, unknown>, import("@reduxjs/toolkit/query").FetchBaseQueryMeta>, {
3
+ selfRetire: import("@reduxjs/toolkit/query").MutationDefinition<void, import("@reduxjs/toolkit/query").BaseQueryFn<import("@data-layer/features/utils").CustomQueryArgs, unknown, import("@data-layer/features/utils").ExtendedFetchBaseQueryError, Record<string, unknown>, import("@reduxjs/toolkit/query").FetchBaseQueryMeta>, never, SelfRetireResponse, "retirementApiSlice", unknown>;
4
+ }, "retirementApiSlice", never, typeof import("@reduxjs/toolkit/query").coreModuleName | typeof import("@reduxjs/toolkit/dist/query/react").reactHooksModuleName>;
5
+ export declare const useSelfRetireMutation: <R extends Record<string, any> = ({
6
+ requestId?: undefined;
7
+ status: import("@reduxjs/toolkit/query").QueryStatus.uninitialized;
8
+ data?: undefined;
9
+ error?: undefined;
10
+ endpointName?: string;
11
+ startedTimeStamp?: undefined;
12
+ fulfilledTimeStamp?: undefined;
13
+ } & {
14
+ status: import("@reduxjs/toolkit/query").QueryStatus.uninitialized;
15
+ isUninitialized: true;
16
+ isLoading: false;
17
+ isSuccess: false;
18
+ isError: false;
19
+ }) | ({
20
+ status: import("@reduxjs/toolkit/query").QueryStatus.fulfilled;
21
+ } & Omit<{
22
+ requestId: string;
23
+ data?: SelfRetireResponse | undefined;
24
+ error?: import("@data-layer/features/utils").ExtendedFetchBaseQueryError | import("@reduxjs/toolkit").SerializedError | undefined;
25
+ endpointName: string;
26
+ startedTimeStamp: number;
27
+ fulfilledTimeStamp?: number;
28
+ }, "data" | "fulfilledTimeStamp"> & Required<Pick<{
29
+ requestId: string;
30
+ data?: SelfRetireResponse | undefined;
31
+ error?: import("@data-layer/features/utils").ExtendedFetchBaseQueryError | import("@reduxjs/toolkit").SerializedError | undefined;
32
+ endpointName: string;
33
+ startedTimeStamp: number;
34
+ fulfilledTimeStamp?: number;
35
+ }, "data" | "fulfilledTimeStamp">> & {
36
+ error: undefined;
37
+ } & {
38
+ status: import("@reduxjs/toolkit/query").QueryStatus.fulfilled;
39
+ isUninitialized: false;
40
+ isLoading: false;
41
+ isSuccess: true;
42
+ isError: false;
43
+ }) | ({
44
+ status: import("@reduxjs/toolkit/query").QueryStatus.pending;
45
+ } & {
46
+ requestId: string;
47
+ data?: SelfRetireResponse | undefined;
48
+ error?: import("@data-layer/features/utils").ExtendedFetchBaseQueryError | import("@reduxjs/toolkit").SerializedError | undefined;
49
+ endpointName: string;
50
+ startedTimeStamp: number;
51
+ fulfilledTimeStamp?: number;
52
+ } & {
53
+ data?: undefined;
54
+ } & {
55
+ status: import("@reduxjs/toolkit/query").QueryStatus.pending;
56
+ isUninitialized: false;
57
+ isLoading: true;
58
+ isSuccess: false;
59
+ isError: false;
60
+ }) | ({
61
+ status: import("@reduxjs/toolkit/query").QueryStatus.rejected;
62
+ } & Omit<{
63
+ requestId: string;
64
+ data?: SelfRetireResponse | undefined;
65
+ error?: import("@data-layer/features/utils").ExtendedFetchBaseQueryError | import("@reduxjs/toolkit").SerializedError | undefined;
66
+ endpointName: string;
67
+ startedTimeStamp: number;
68
+ fulfilledTimeStamp?: number;
69
+ }, "error"> & Required<Pick<{
70
+ requestId: string;
71
+ data?: SelfRetireResponse | undefined;
72
+ error?: import("@data-layer/features/utils").ExtendedFetchBaseQueryError | import("@reduxjs/toolkit").SerializedError | undefined;
73
+ endpointName: string;
74
+ startedTimeStamp: number;
75
+ fulfilledTimeStamp?: number;
76
+ }, "error">> & {
77
+ status: import("@reduxjs/toolkit/query").QueryStatus.rejected;
78
+ isUninitialized: false;
79
+ isLoading: false;
80
+ isSuccess: false;
81
+ isError: true;
82
+ })>(options?: {
83
+ selectFromResult?: ((state: ({
84
+ requestId?: undefined;
85
+ status: import("@reduxjs/toolkit/query").QueryStatus.uninitialized;
86
+ data?: undefined;
87
+ error?: undefined;
88
+ endpointName?: string;
89
+ startedTimeStamp?: undefined;
90
+ fulfilledTimeStamp?: undefined;
91
+ } & {
92
+ status: import("@reduxjs/toolkit/query").QueryStatus.uninitialized;
93
+ isUninitialized: true;
94
+ isLoading: false;
95
+ isSuccess: false;
96
+ isError: false;
97
+ }) | ({
98
+ status: import("@reduxjs/toolkit/query").QueryStatus.fulfilled;
99
+ } & Omit<{
100
+ requestId: string;
101
+ data?: SelfRetireResponse | undefined;
102
+ error?: import("@data-layer/features/utils").ExtendedFetchBaseQueryError | import("@reduxjs/toolkit").SerializedError | undefined;
103
+ endpointName: string;
104
+ startedTimeStamp: number;
105
+ fulfilledTimeStamp?: number;
106
+ }, "data" | "fulfilledTimeStamp"> & Required<Pick<{
107
+ requestId: string;
108
+ data?: SelfRetireResponse | undefined;
109
+ error?: import("@data-layer/features/utils").ExtendedFetchBaseQueryError | import("@reduxjs/toolkit").SerializedError | undefined;
110
+ endpointName: string;
111
+ startedTimeStamp: number;
112
+ fulfilledTimeStamp?: number;
113
+ }, "data" | "fulfilledTimeStamp">> & {
114
+ error: undefined;
115
+ } & {
116
+ status: import("@reduxjs/toolkit/query").QueryStatus.fulfilled;
117
+ isUninitialized: false;
118
+ isLoading: false;
119
+ isSuccess: true;
120
+ isError: false;
121
+ }) | ({
122
+ status: import("@reduxjs/toolkit/query").QueryStatus.pending;
123
+ } & {
124
+ requestId: string;
125
+ data?: SelfRetireResponse | undefined;
126
+ error?: import("@data-layer/features/utils").ExtendedFetchBaseQueryError | import("@reduxjs/toolkit").SerializedError | undefined;
127
+ endpointName: string;
128
+ startedTimeStamp: number;
129
+ fulfilledTimeStamp?: number;
130
+ } & {
131
+ data?: undefined;
132
+ } & {
133
+ status: import("@reduxjs/toolkit/query").QueryStatus.pending;
134
+ isUninitialized: false;
135
+ isLoading: true;
136
+ isSuccess: false;
137
+ isError: false;
138
+ }) | ({
139
+ status: import("@reduxjs/toolkit/query").QueryStatus.rejected;
140
+ } & Omit<{
141
+ requestId: string;
142
+ data?: SelfRetireResponse | undefined;
143
+ error?: import("@data-layer/features/utils").ExtendedFetchBaseQueryError | import("@reduxjs/toolkit").SerializedError | undefined;
144
+ endpointName: string;
145
+ startedTimeStamp: number;
146
+ fulfilledTimeStamp?: number;
147
+ }, "error"> & Required<Pick<{
148
+ requestId: string;
149
+ data?: SelfRetireResponse | undefined;
150
+ error?: import("@data-layer/features/utils").ExtendedFetchBaseQueryError | import("@reduxjs/toolkit").SerializedError | undefined;
151
+ endpointName: string;
152
+ startedTimeStamp: number;
153
+ fulfilledTimeStamp?: number;
154
+ }, "error">> & {
155
+ status: import("@reduxjs/toolkit/query").QueryStatus.rejected;
156
+ isUninitialized: false;
157
+ isLoading: false;
158
+ isSuccess: false;
159
+ isError: true;
160
+ })) => R) | undefined;
161
+ fixedCacheKey?: string;
162
+ } | undefined) => readonly [(arg: void) => import("@reduxjs/toolkit/query").MutationActionCreatorResult<import("@reduxjs/toolkit/query").MutationDefinition<void, import("@reduxjs/toolkit/query").BaseQueryFn<import("@data-layer/features/utils").CustomQueryArgs, unknown, import("@data-layer/features/utils").ExtendedFetchBaseQueryError, Record<string, unknown>, import("@reduxjs/toolkit/query").FetchBaseQueryMeta>, never, SelfRetireResponse, "retirementApiSlice", unknown>>, import("@reduxjs/toolkit/query").TSHelpersNoInfer<R> & {
163
+ originalArgs?: void | undefined;
164
+ reset: () => void;
165
+ }];
@@ -0,0 +1,7 @@
1
+ import { SERVICES } from '@data-layer/constants';
2
+ export declare const RETIREMENT_ENDPOINTS: {
3
+ SELF_RETIRE: {
4
+ service: SERVICES;
5
+ path: () => string;
6
+ };
7
+ };
@@ -0,0 +1,3 @@
1
+ export interface SelfRetireResponse {
2
+ message?: string;
3
+ }
@@ -74,6 +74,9 @@ export * from './features/core/custom-public-image-asset-api-slice';
74
74
  export * from './features/edx-proctoring/api-slice';
75
75
  export * from './features/edx-proctoring/constants';
76
76
  export * from './features/edx-proctoring/types';
77
+ export * from './features/retirement/api-slice';
78
+ export * from './features/retirement/constants';
79
+ export * from './features/retirement/types';
77
80
  export * from './features/disclaimers/api-slice';
78
81
  export * from './features/disclaimers/constants';
79
82
  export * from './features/disclaimers/types';
package/dist/index.esm.js CHANGED
@@ -6954,6 +6954,10 @@ const useChat = ({ wsUrl, wsToken, flowConfig, sessionId, stopGenerationWsUrl, e
6954
6954
  const ws = useRef(null);
6955
6955
  const isConnected = useRef(false);
6956
6956
  const messageQueue = useRef([]);
6957
+ // Keep sessionId in a ref so sendMessage always reads the latest value,
6958
+ // avoiding stale closures when Redux updates sessionIds between renders.
6959
+ const sessionIdRef = useRef(sessionId);
6960
+ sessionIdRef.current = sessionId;
6957
6961
  const currentStreamingMessage = useRef({
6958
6962
  id: null,
6959
6963
  content: "",
@@ -7066,21 +7070,30 @@ const useChat = ({ wsUrl, wsToken, flowConfig, sessionId, stopGenerationWsUrl, e
7066
7070
  connectionAttempts.current >
7067
7071
  MAX_INITIAL_WEBSOCKET_CONNECTION_ATTEMPTS;
7068
7072
  if (shouldShowError) {
7069
- console.error(JSON.stringify({
7073
+ console.error("[ws-error] WebSocket connection error exceeded max attempts", {
7074
+ error,
7075
+ wsUrl,
7070
7076
  tenant: flowConfig === null || flowConfig === void 0 ? void 0 : flowConfig.tenant,
7071
7077
  mentorId: flowConfig === null || flowConfig === void 0 ? void 0 : flowConfig.name,
7072
7078
  username: flowConfig === null || flowConfig === void 0 ? void 0 : flowConfig.username,
7079
+ sessionId: sessionIdRef.current,
7080
+ isInitialConnection: isInitialConnection.current,
7073
7081
  connectionAttempts: connectionAttempts.current,
7074
7082
  maxAttempts: MAX_INITIAL_WEBSOCKET_CONNECTION_ATTEMPTS,
7075
- shouldShowError,
7076
- error,
7077
- }));
7078
- errorHandler === null || errorHandler === void 0 ? void 0 : errorHandler("Failed to connect to the mentor", error);
7083
+ readyState: socket.readyState,
7084
+ timestamp: new Date().toISOString(),
7085
+ });
7079
7086
  onStatusChange("error");
7080
7087
  reject(error);
7081
7088
  }
7082
7089
  else {
7083
- console.warn("Initial connection attempt failed, will retry...");
7090
+ console.warn(`[ws-error] Initial connection attempt ${connectionAttempts.current}/${MAX_INITIAL_WEBSOCKET_CONNECTION_ATTEMPTS} failed, will retry...`, {
7091
+ wsUrl,
7092
+ tenant: flowConfig === null || flowConfig === void 0 ? void 0 : flowConfig.tenant,
7093
+ mentorId: flowConfig === null || flowConfig === void 0 ? void 0 : flowConfig.name,
7094
+ readyState: socket.readyState,
7095
+ timestamp: new Date().toISOString(),
7096
+ });
7084
7097
  }
7085
7098
  onStreamingChange === null || onStreamingChange === void 0 ? void 0 : onStreamingChange(false);
7086
7099
  });
@@ -7760,7 +7773,19 @@ const useChat = ({ wsUrl, wsToken, flowConfig, sessionId, stopGenerationWsUrl, e
7760
7773
  onStreamingChange === null || onStreamingChange === void 0 ? void 0 : onStreamingChange(false);
7761
7774
  return;
7762
7775
  }
7763
- errorHandler === null || errorHandler === void 0 ? void 0 : errorHandler("WebSocket error", error);
7776
+ console.error("[ws-error] WebSocket error on active connection", {
7777
+ error,
7778
+ wsUrl,
7779
+ tenant: flowConfig === null || flowConfig === void 0 ? void 0 : flowConfig.tenant,
7780
+ mentorId: flowConfig === null || flowConfig === void 0 ? void 0 : flowConfig.name,
7781
+ username: flowConfig === null || flowConfig === void 0 ? void 0 : flowConfig.username,
7782
+ sessionId: sessionIdRef.current,
7783
+ isInitialConnection: isInitialConnection.current,
7784
+ connectionAttempts: connectionAttempts.current,
7785
+ readyState: socket.readyState,
7786
+ isConnected: isConnected.current,
7787
+ timestamp: new Date().toISOString(),
7788
+ });
7764
7789
  onStreamingChange === null || onStreamingChange === void 0 ? void 0 : onStreamingChange(false);
7765
7790
  onStatusChange("error");
7766
7791
  });
@@ -7793,7 +7818,16 @@ const useChat = ({ wsUrl, wsToken, flowConfig, sessionId, stopGenerationWsUrl, e
7793
7818
  if (isInitialConnection.current &&
7794
7819
  connectionAttempts.current >=
7795
7820
  MAX_INITIAL_WEBSOCKET_CONNECTION_ATTEMPTS) {
7796
- errorHandler === null || errorHandler === void 0 ? void 0 : errorHandler("Failed to connect to the mentor after multiple attempts");
7821
+ console.error("[ws-close] Failed to connect to the mentor after multiple attempts", {
7822
+ wsUrl,
7823
+ tenant: flowConfig === null || flowConfig === void 0 ? void 0 : flowConfig.tenant,
7824
+ mentorId: flowConfig === null || flowConfig === void 0 ? void 0 : flowConfig.name,
7825
+ username: flowConfig === null || flowConfig === void 0 ? void 0 : flowConfig.username,
7826
+ sessionId: sessionIdRef.current,
7827
+ connectionAttempts: connectionAttempts.current,
7828
+ maxAttempts: MAX_INITIAL_WEBSOCKET_CONNECTION_ATTEMPTS,
7829
+ timestamp: new Date().toISOString(),
7830
+ });
7797
7831
  onStatusChange("error");
7798
7832
  isInitialConnection.current = false;
7799
7833
  }
@@ -7894,9 +7928,19 @@ const useChat = ({ wsUrl, wsToken, flowConfig, sessionId, stopGenerationWsUrl, e
7894
7928
  onStatusChange("error");
7895
7929
  return;
7896
7930
  }
7931
+ // Guard against sending messages without a session ID.
7932
+ // This can happen due to race conditions (e.g., user sends before
7933
+ // createSessionId API returns, or stale closure after tab change).
7934
+ const currentSessionId = sessionIdRef.current;
7935
+ if (!currentSessionId) {
7936
+ console.warn("[sendMessage] No session ID available, cannot send message");
7937
+ onStatusChange("error");
7938
+ errorHandler === null || errorHandler === void 0 ? void 0 : errorHandler("Chat session not ready. Please try again.");
7939
+ return;
7940
+ }
7897
7941
  let messageData = {
7898
7942
  flow: flowConfig,
7899
- session_id: sessionId,
7943
+ session_id: currentSessionId,
7900
7944
  token: wsToken,
7901
7945
  prompt: text || "", // Allow empty prompt when sending files
7902
7946
  };
@@ -7969,7 +8013,6 @@ const useChat = ({ wsUrl, wsToken, flowConfig, sessionId, stopGenerationWsUrl, e
7969
8013
  }
7970
8014
  }, [
7971
8015
  flowConfig,
7972
- sessionId,
7973
8016
  wsToken,
7974
8017
  store,
7975
8018
  triggerHapticFeedback,
@@ -13956,7 +13999,7 @@ const mentorApiSlice = createApi({
13956
13999
  dispatch(mentorApiSlice.util.updateQueryData('getShareableLink', {
13957
14000
  mentor: updateData.mentor,
13958
14001
  org: updateData.org,
13959
- // @ts-ignore
14002
+ // @ts-expect-error userId may not be in the type
13960
14003
  userId: updateData.userId,
13961
14004
  }, (draft) => {
13962
14005
  var _a;
@@ -17088,6 +17131,28 @@ createApi({
17088
17131
  }),
17089
17132
  });
17090
17133
 
17134
+ const RETIREMENT_ENDPOINTS = {
17135
+ SELF_RETIRE: {
17136
+ service: SERVICES.LMS,
17137
+ path: () => `/api/ibl/retirements/self_retire/`,
17138
+ },
17139
+ };
17140
+
17141
+ createApi({
17142
+ reducerPath: 'retirementApiSlice',
17143
+ baseQuery: iblFetchBaseQuery,
17144
+ endpoints: (builder) => ({
17145
+ selfRetire: builder.mutation({
17146
+ query: () => ({
17147
+ url: RETIREMENT_ENDPOINTS.SELF_RETIRE.path(),
17148
+ service: RETIREMENT_ENDPOINTS.SELF_RETIRE.service,
17149
+ method: 'POST',
17150
+ isJson: true,
17151
+ }),
17152
+ }),
17153
+ }),
17154
+ });
17155
+
17091
17156
  const DISCLAIMERS_REDUCER_PATH = 'disclaimersApiSlice';
17092
17157
  const DISCLAIMERS_ENDPOINTS = {
17093
17158
  GET_DISCLAIMERS: {