@iblai/web-utils 0.3.0 → 1.1.1

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.
Files changed (41) hide show
  1. package/README.md +504 -0
  2. package/dist/data-layer/src/features/chat-files/api-slice.d.ts +185 -0
  3. package/dist/data-layer/src/features/chat-files/types.d.ts +32 -0
  4. package/dist/data-layer/src/features/core/api-slice.d.ts +419 -61
  5. package/dist/data-layer/src/features/core/constants.d.ts +3 -0
  6. package/dist/data-layer/src/features/core/custom-api-slice.d.ts +50 -50
  7. package/dist/data-layer/src/features/core/custom-public-image-asset-api-slice.d.ts +333 -0
  8. package/dist/data-layer/src/features/core/types.d.ts +33 -0
  9. package/dist/data-layer/src/features/credentials/api-slice.d.ts +62 -39
  10. package/dist/data-layer/src/features/mentor/api-slice.d.ts +1028 -188
  11. package/dist/data-layer/src/features/notifications/constants.d.ts +6 -0
  12. package/dist/data-layer/src/features/notifications/custom-api-slice.d.ts +43 -43
  13. package/dist/data-layer/src/features/notifications/types.d.ts +25 -2
  14. package/dist/data-layer/src/features/stripe/api-slice.d.ts +22 -0
  15. package/dist/data-layer/src/index.d.ts +3 -0
  16. package/dist/index.d.ts +447 -83
  17. package/dist/index.esm.js +1137 -196
  18. package/dist/index.esm.js.map +1 -1
  19. package/dist/index.js +1167 -193
  20. package/dist/index.js.map +1 -1
  21. package/dist/package.json +4 -2
  22. package/dist/web-utils/src/constants/chat.d.ts +8 -0
  23. package/dist/web-utils/src/features/files/filesSlice.d.ts +20 -0
  24. package/dist/web-utils/src/features/index.d.ts +1 -0
  25. package/dist/web-utils/src/hooks/chat/use-advanced-chat.d.ts +6 -4
  26. package/dist/web-utils/src/hooks/chat/use-chat-v2.d.ts +11 -1
  27. package/dist/web-utils/src/hooks/use-mentor-settings.d.ts +18 -15
  28. package/dist/web-utils/src/index.d.ts +2 -0
  29. package/dist/web-utils/src/index.web.d.ts +14 -12
  30. package/dist/web-utils/src/providers/auth-provider.d.ts +9 -1
  31. package/dist/web-utils/src/providers/mentor-provider.d.ts +2 -1
  32. package/dist/web-utils/src/providers/tenant-provider.d.ts +3 -1
  33. package/dist/web-utils/src/services/__tests__/file-upload.test.d.ts +1 -0
  34. package/dist/web-utils/src/services/file-upload.d.ts +60 -0
  35. package/dist/web-utils/src/services/index.d.ts +1 -0
  36. package/dist/web-utils/src/types/file-upload.d.ts +62 -0
  37. package/dist/web-utils/src/types/index.d.ts +1 -0
  38. package/dist/web-utils/src/utils/auth.d.ts +180 -0
  39. package/dist/web-utils/src/utils/index.d.ts +1 -0
  40. package/package.json +12 -13
  41. package/dist/web-utils/tsconfig.tsbuildinfo +0 -1
package/dist/index.esm.js CHANGED
@@ -1,7 +1,8 @@
1
1
  import * as React from 'react';
2
2
  import React__default, { useCallback, useDebugValue, useMemo, useState, useEffect, useRef, useLayoutEffect, createContext, useContext } from 'react';
3
- import { OpenAPI, CoreService, ReportsService, AiAnalyticsService, AiMentorService, SearchService, AiPromptService, AiIndexService, CatalogService, SkillsService, AiAccountService, CredentialsService, FeaturesService, CommerceService, NotificationsService } from '@iblai/iblai-api';
4
- import { jsx, Fragment } from 'react/jsx-runtime';
3
+ import { OpenAPI, CoreService, ReportsService, AiAnalyticsService, AiMentorService, SearchService, AiPromptService, AiIndexService, CatalogService, SkillsService, AiAccountService, CredentialsService, FeaturesService, CommerceService, NotificationsService, MentorVisibilityEnum } from '@iblai/iblai-api';
4
+ import { jsx } from 'react/jsx-runtime';
5
+ import axios from 'axios';
5
6
 
6
7
  const SUBSCRIPTION_TRIGGERS = {
7
8
  PRICING_MODAL: "TRIGGER_PRICING_MODAL",
@@ -3380,7 +3381,7 @@ function updateMutationSubstateIfExists(state, id, update) {
3380
3381
  update(substate);
3381
3382
  }
3382
3383
  }
3383
- var initialState$1 = {};
3384
+ var initialState$2 = {};
3384
3385
  function buildSlice({
3385
3386
  reducerPath,
3386
3387
  queryThunk,
@@ -3456,7 +3457,7 @@ function buildSlice({
3456
3457
  }
3457
3458
  const querySlice = createSlice$1({
3458
3459
  name: `${reducerPath}/queries`,
3459
- initialState: initialState$1,
3460
+ initialState: initialState$2,
3460
3461
  reducers: {
3461
3462
  removeQueryResult: {
3462
3463
  reducer(draft, {
@@ -3590,7 +3591,7 @@ function buildSlice({
3590
3591
  });
3591
3592
  const mutationSlice = createSlice$1({
3592
3593
  name: `${reducerPath}/mutations`,
3593
- initialState: initialState$1,
3594
+ initialState: initialState$2,
3594
3595
  reducers: {
3595
3596
  removeMutationResult: {
3596
3597
  reducer(draft, {
@@ -3759,7 +3760,7 @@ function buildSlice({
3759
3760
  }
3760
3761
  const subscriptionSlice = createSlice$1({
3761
3762
  name: `${reducerPath}/subscriptions`,
3762
- initialState: initialState$1,
3763
+ initialState: initialState$2,
3763
3764
  reducers: {
3764
3765
  updateSubscriptionOptions(d, a) {
3765
3766
  },
@@ -3771,7 +3772,7 @@ function buildSlice({
3771
3772
  });
3772
3773
  const internalSubscriptionsSlice = createSlice$1({
3773
3774
  name: `${reducerPath}/internalSubscriptions`,
3774
- initialState: initialState$1,
3775
+ initialState: initialState$2,
3775
3776
  reducers: {
3776
3777
  subscriptionsUpdated: {
3777
3778
  reducer(state, action) {
@@ -6441,6 +6442,25 @@ createApi({
6441
6442
  }),
6442
6443
  });
6443
6444
 
6445
+ createApi({
6446
+ reducerPath: 'chatFilesApiSlice',
6447
+ baseQuery: iblFetchBaseQuery,
6448
+ endpoints: (builder) => ({
6449
+ /**
6450
+ * Get presigned S3 URL for file upload
6451
+ * POST /api/ai-mentor/orgs/{org}/users/{userId}/chat/files/upload-url/
6452
+ */
6453
+ getFileUploadUrl: builder.mutation({
6454
+ query: ({ org, userId, requestBody, }) => ({
6455
+ url: `/api/ai-mentor/orgs/${org}/users/${userId}/chat/files/upload-url/`,
6456
+ method: 'POST',
6457
+ body: requestBody,
6458
+ service: SERVICES.DM,
6459
+ }),
6460
+ }),
6461
+ }),
6462
+ });
6463
+
6444
6464
  createApi({
6445
6465
  reducerPath: 'llmsApiSlice',
6446
6466
  baseQuery: iblFakeBaseQuery,
@@ -6461,6 +6481,7 @@ const mentorApiSlice = createApi({
6461
6481
  'mentorPublicSettings',
6462
6482
  'shareableLinks',
6463
6483
  'publicMentors',
6484
+ 'moderationLogs',
6464
6485
  ],
6465
6486
  endpoints: (builder) => ({
6466
6487
  createMentor: builder.mutation({
@@ -6526,7 +6547,7 @@ const mentorApiSlice = createApi({
6526
6547
  }));
6527
6548
  }
6528
6549
  catch (error) {
6529
- console.error(error);
6550
+ console.error(JSON.stringify(error));
6530
6551
  }
6531
6552
  },
6532
6553
  }),
@@ -6582,9 +6603,17 @@ const mentorApiSlice = createApi({
6582
6603
  ...buildEndpointFromDmService(AiMentorService.aiMentorOrgsUsersMentorsForkCreate),
6583
6604
  invalidatesTags: ['mentors'],
6584
6605
  }),
6606
+ getRecentlyAccessedMentors: builder.query({
6607
+ ...buildEndpointFromDmService(AiMentorService.aiMentorOrgsUsersRecentlyAccessedMentorsList),
6608
+ providesTags: ['mentors'],
6609
+ }),
6610
+ getModerationLogs: builder.query({
6611
+ ...buildEndpointFromDmService(AiMentorService.aiMentorOrgsUsersModerationLogsList),
6612
+ providesTags: ['moderationLogs'],
6613
+ }),
6585
6614
  }),
6586
6615
  });
6587
- const { useLazyGetMentorsQuery, useLazySeedMentorsQuery, useGetMentorSettingsQuery, useGetMentorPublicSettingsQuery, useLazyGetMentorPublicSettingsQuery, useLazyGetFreeUsageCountQuery} = mentorApiSlice;
6616
+ const { useLazyGetMentorsQuery, useLazySeedMentorsQuery, useGetMentorSettingsQuery, useGetMentorPublicSettingsQuery, useLazyGetMentorPublicSettingsQuery, useLazyGetFreeUsageCountQuery, useLazyGetRecentlyAccessedMentorsQuery} = mentorApiSlice;
6588
6617
 
6589
6618
  createApi({
6590
6619
  reducerPath: 'mentorCategoriesApiSlice',
@@ -7051,7 +7080,20 @@ const coreApiSlice = createApi({
7051
7080
  invalidatesTags: ['RbacGroups'],
7052
7081
  }),
7053
7082
  getRbacGroupDetails: builder.query({
7054
- ...buildEndpointFromDmService(CoreService.coreRbacGroupsRetrieve),
7083
+ ...buildEndpointFromService(SERVICES.DM, async (args) => {
7084
+ const url = `${OpenAPI.BASE}/api/core/rbac/groups/${args.id}/`;
7085
+ const response = await fetch(url, {
7086
+ method: 'GET',
7087
+ headers: OpenAPI.HEADERS,
7088
+ });
7089
+ if (!response.ok) {
7090
+ const error = new Error('Failed to fetch RBAC group details');
7091
+ error.status = response.status;
7092
+ error.body = await response.text();
7093
+ throw error;
7094
+ }
7095
+ return response.json();
7096
+ }),
7055
7097
  providesTags: ['RbacGroups'],
7056
7098
  }),
7057
7099
  //RBAC POLICIES
@@ -7072,7 +7114,22 @@ const coreApiSlice = createApi({
7072
7114
  invalidatesTags: ['RbacPolicies'],
7073
7115
  }),
7074
7116
  getRbacPolicyDetails: builder.query({
7075
- ...buildEndpointFromDmService(CoreService.coreRbacPoliciesRetrieve),
7117
+ ...buildEndpointFromService(SERVICES.DM, async (args) => {
7118
+ const queryParams = new URLSearchParams({ platform_key: args.platform_key });
7119
+ const queryString = queryParams.toString();
7120
+ const url = `${OpenAPI.BASE}/api/core/rbac/policies/${args.id}/?${queryString}`;
7121
+ const response = await fetch(url, {
7122
+ method: 'GET',
7123
+ headers: OpenAPI.HEADERS,
7124
+ });
7125
+ if (!response.ok) {
7126
+ const error = new Error('Failed to fetch RBAC policy details');
7127
+ error.status = response.status;
7128
+ error.body = await response.text();
7129
+ throw error;
7130
+ }
7131
+ return response.json();
7132
+ }),
7076
7133
  providesTags: ['RbacPolicies'],
7077
7134
  }),
7078
7135
  //RBAC ROLES
@@ -7097,14 +7154,36 @@ const coreApiSlice = createApi({
7097
7154
  invalidatesTags: ['RbacRoles'],
7098
7155
  }),
7099
7156
  getRbacRoleDetails: builder.query({
7100
- ...buildEndpointFromDmService(CoreService.coreRbacRolesRetrieve),
7157
+ ...buildEndpointFromService(SERVICES.DM, async (args) => {
7158
+ const queryParams = new URLSearchParams({ platform_key: args.platform_key });
7159
+ const queryString = queryParams.toString();
7160
+ const url = `${OpenAPI.BASE}/api/core/rbac/roles/${args.id}/?${queryString}`;
7161
+ const response = await fetch(url, {
7162
+ method: 'GET',
7163
+ headers: OpenAPI.HEADERS,
7164
+ });
7165
+ if (!response.ok) {
7166
+ const error = new Error('Failed to fetch RBAC role details');
7167
+ error.status = response.status;
7168
+ error.body = await response.text();
7169
+ throw error;
7170
+ }
7171
+ return response.json();
7172
+ }),
7101
7173
  providesTags: ['RbacRoles'],
7102
7174
  }),
7175
+ getRbacMentorAccessList: builder.query({
7176
+ ...buildEndpointFromDmService(CoreService.coreRbacMentorAccessList),
7177
+ }),
7178
+ updateRbacMentorAccess: builder.mutation({
7179
+ ...buildEndpointFromDmService(CoreService.coreRbacMentorAccessCreate),
7180
+ }),
7103
7181
  }),
7104
7182
  });
7105
7183
  const { useGetRbacPermissionsMutation} = coreApiSlice;
7106
7184
 
7107
7185
  const CORE_CUSTOM_REDUCER_PATH = 'coreCustomApiSlice';
7186
+ const CORE_FAKE_CUSTOM_REDUCER_PATH = 'coreFakeCustomApiSlice';
7108
7187
  const PLATFORM_MEMBERSHIP_TAG = 'PlatformMembership';
7109
7188
  const CORE_CUSTOM_ENDPOINTS = {
7110
7189
  GET_PLATFORM_MEMBERSHIP: {
@@ -7138,7 +7217,13 @@ const CORE_CUSTOM_ENDPOINTS = {
7138
7217
  DELETE_PLATFORM_IMAGE_ASSET: {
7139
7218
  path: (platform_key, asset_id) => `/api/core/platforms/${platform_key}/public-image-assets/${asset_id}/`,
7140
7219
  service: SERVICES.DM,
7141
- }};
7220
+ },
7221
+ GET_PUBLIC_PLATFORM_IMAGE_ASSET_FILE_URL: {
7222
+ path: (platform_key, asset_id) => `/api/core/platforms/${platform_key}/public-image-assets/${asset_id}/file/`,
7223
+ baseUrl: getServiceUrl(SERVICES.DM),
7224
+ service: SERVICES.DM,
7225
+ },
7226
+ };
7142
7227
 
7143
7228
  createApi({
7144
7229
  // TODO: replace to catalogSlice
@@ -7210,7 +7295,13 @@ createApi({
7210
7295
  ...buildEndpointFromDmService(AiAccountService.aiAccountOrgsIntegrationCredentialPartialUpdate),
7211
7296
  }),
7212
7297
  getConnectedServiceAuthUrl: builder.query({
7213
- ...buildEndpointFromDmService(AiAccountService.aiAccountConnectedServicesOrgsUsersRetrieve),
7298
+ queryFn: async (queryParams, api, extraOptions) => {
7299
+ const url = `/api/ai-account/connected-services/orgs/${queryParams.org}/users/${queryParams.userId}/${queryParams.provider}/${queryParams.service}/`;
7300
+ return iblFetchBaseQuery({
7301
+ url,
7302
+ service: SERVICES.DM,
7303
+ }, api, extraOptions);
7304
+ },
7214
7305
  }),
7215
7306
  connectedServicesCallback: builder.query({
7216
7307
  queryFn: async (queryParams, api, extraOptions) => {
@@ -7304,10 +7395,11 @@ const stripeApiSlice = createApi({
7304
7395
  providesTags: ['stripe-context'],
7305
7396
  }),
7306
7397
  getStripePricingPageSession: builder.query({
7307
- query: ({ platform_key }) => ({
7398
+ query: ({ platform_key, params }) => ({
7308
7399
  url: STRIPE_ENDPOINTS.GET_STRIPE_PRICING_PAGE_SESSION.path(platform_key),
7309
7400
  service: STRIPE_ENDPOINTS.GET_STRIPE_PRICING_PAGE_SESSION.service,
7310
7401
  method: 'GET',
7402
+ params,
7311
7403
  }),
7312
7404
  providesTags: ['stripe-context'],
7313
7405
  }),
@@ -7342,7 +7434,7 @@ const sessionApiSlice = createApi({
7342
7434
  }),
7343
7435
  }),
7344
7436
  });
7345
- const { useCreateSessionIdMutation, useEditSessionMutation, } = sessionApiSlice;
7437
+ const { useCreateSessionIdMutation, useLazyGetSessionIdQuery, useEditSessionMutation, } = sessionApiSlice;
7346
7438
 
7347
7439
  createApi({
7348
7440
  reducerPath: 'datasetsApiSlice',
@@ -8279,6 +8371,12 @@ createApi({
8279
8371
  });
8280
8372
 
8281
8373
  const NOTIFICATIONS_CUSTOM_REDUCER_PATH = 'notificationsCustomApiSlice';
8374
+ const NOTIFICATIONS_CUSTOM_TAGS = {
8375
+ TEMPLATES: 'NOTIFICATIONS_CUSTOM_TEMPLATES',
8376
+ TEMPLATE_DETAILS: 'NOTIFICATIONS_CUSTOM_TEMPLATE_DETAILS',
8377
+ UPDATE_TEMPLATE: 'NOTIFICATIONS_CUSTOM_UPDATE_TEMPLATE',
8378
+ TOGGLE_TEMPLATE: 'NOTIFICATIONS_CUSTOM_TOGGLE_TEMPLATE',
8379
+ };
8282
8380
  const NOTIFICATIONS_CUSTOM_ENDPOINTS = {
8283
8381
  GET_TEMPLATES: {
8284
8382
  service: SERVICES.DM,
@@ -8300,6 +8398,7 @@ const NOTIFICATIONS_CUSTOM_ENDPOINTS = {
8300
8398
 
8301
8399
  createApi({
8302
8400
  reducerPath: NOTIFICATIONS_CUSTOM_REDUCER_PATH,
8401
+ tagTypes: [...Object.values(NOTIFICATIONS_CUSTOM_TAGS)],
8303
8402
  baseQuery: iblFetchBaseQuery,
8304
8403
  endpoints: (builder) => ({
8305
8404
  getTemplates: builder.query({
@@ -8309,6 +8408,7 @@ createApi({
8309
8408
  service: NOTIFICATIONS_CUSTOM_ENDPOINTS.GET_TEMPLATES.service,
8310
8409
  };
8311
8410
  },
8411
+ providesTags: [NOTIFICATIONS_CUSTOM_TAGS.TEMPLATES],
8312
8412
  }),
8313
8413
  getTemplateDetails: builder.query({
8314
8414
  query: (args) => {
@@ -8317,6 +8417,7 @@ createApi({
8317
8417
  service: NOTIFICATIONS_CUSTOM_ENDPOINTS.GET_TEMPLATE_DETAILS.service,
8318
8418
  };
8319
8419
  },
8420
+ providesTags: [NOTIFICATIONS_CUSTOM_TAGS.TEMPLATE_DETAILS],
8320
8421
  }),
8321
8422
  updateTemplate: builder.mutation({
8322
8423
  query: (args) => {
@@ -8327,6 +8428,7 @@ createApi({
8327
8428
  body: args.template,
8328
8429
  };
8329
8430
  },
8431
+ invalidatesTags: [NOTIFICATIONS_CUSTOM_TAGS.TEMPLATE_DETAILS],
8330
8432
  }),
8331
8433
  toggleTemplate: builder.mutation({
8332
8434
  query: (args) => {
@@ -8339,6 +8441,7 @@ createApi({
8339
8441
  },
8340
8442
  };
8341
8443
  },
8444
+ invalidatesTags: [NOTIFICATIONS_CUSTOM_TAGS.TEMPLATES],
8342
8445
  }),
8343
8446
  }),
8344
8447
  });
@@ -8619,7 +8722,7 @@ const CUSTOM_DOMAIN_QUERY_KEYS = {
8619
8722
  CREATE_CUSTOM_DOMAIN: () => ['CREATE_CUSTOM_DOMAIN'],
8620
8723
  };
8621
8724
 
8622
- createApi({
8725
+ const customDomainApiSlice = createApi({
8623
8726
  reducerPath: CUSTOM_DOMAIN_REDUCER_PATH,
8624
8727
  baseQuery: iblFetchBaseQuery,
8625
8728
  tagTypes: [...CUSTOM_DOMAIN_QUERY_KEYS.GET_CUSTOM_DOMAINS()],
@@ -8658,6 +8761,7 @@ createApi({
8658
8761
  }),
8659
8762
  }),
8660
8763
  });
8764
+ const { useGetCustomDomainsQuery} = customDomainApiSlice;
8661
8765
 
8662
8766
  const PLATFORM_CUSTOM_REDUCER_PATH = "platformCustomApiSlice";
8663
8767
  const PLATFORM_CONFIGURATION_TAG = "PlatformConfiguration";
@@ -8720,7 +8824,7 @@ createApi({
8720
8824
  const coreCustomApiSlice = createApi({
8721
8825
  reducerPath: CORE_CUSTOM_REDUCER_PATH,
8722
8826
  baseQuery: iblFetchBaseQuery,
8723
- tagTypes: [PLATFORM_MEMBERSHIP_TAG],
8827
+ tagTypes: [PLATFORM_MEMBERSHIP_TAG, 'PlatformImageAssetFileUrl'],
8724
8828
  endpoints: (builder) => ({
8725
8829
  getPlatformMembership: builder.query({
8726
8830
  query: ({ platform_key }) => ({
@@ -8793,6 +8897,19 @@ const coreCustomApiSlice = createApi({
8793
8897
  });
8794
8898
  const { useJoinTenantMutation} = coreCustomApiSlice;
8795
8899
 
8900
+ createApi({
8901
+ reducerPath: CORE_FAKE_CUSTOM_REDUCER_PATH,
8902
+ baseQuery: iblFakeBaseQuery,
8903
+ endpoints: (builder) => ({
8904
+ getPublicPlatformImageAssetFileUrl: builder.query({
8905
+ ...buildEndpointFromService(SERVICES.DM, async (args) => {
8906
+ const url = `${OpenAPI.BASE}${CORE_CUSTOM_ENDPOINTS.GET_PUBLIC_PLATFORM_IMAGE_ASSET_FILE_URL.path(args.platform_key, args.asset_id)}`;
8907
+ return url;
8908
+ }),
8909
+ }),
8910
+ }),
8911
+ });
8912
+
8796
8913
  const EDX_PROCTORING_ENDPOINTS = {
8797
8914
  GET_EXAM_INFO: {
8798
8915
  service: SERVICES.LMS,
@@ -9715,6 +9832,7 @@ const useSubscriptionHandlerV2 = (subscriptionFlow) => {
9715
9832
  });
9716
9833
  }
9717
9834
  catch (error) {
9835
+ console.error("Error getting user active app:", JSON.stringify(error));
9718
9836
  return null;
9719
9837
  }
9720
9838
  };
@@ -9761,6 +9879,7 @@ const useSubscriptionHandlerV2 = (subscriptionFlow) => {
9761
9879
  return await getUserActiveApp();
9762
9880
  }
9763
9881
  catch (error) {
9882
+ console.error("Error updating trial status:", JSON.stringify(error));
9764
9883
  return null;
9765
9884
  }
9766
9885
  };
@@ -9853,6 +9972,7 @@ const useSubscriptionHandlerV2 = (subscriptionFlow) => {
9853
9972
  return stripeContext.payment_link_url;
9854
9973
  }
9855
9974
  catch (error) {
9975
+ console.error("Error getting top up URL:", JSON.stringify(error));
9856
9976
  return null;
9857
9977
  }
9858
9978
  };
@@ -9926,6 +10046,7 @@ const useSubscriptionHandlerV2 = (subscriptionFlow) => {
9926
10046
  return stripeCustomerPortal === null || stripeCustomerPortal === void 0 ? void 0 : stripeCustomerPortal.url;
9927
10047
  }
9928
10048
  catch (error) {
10049
+ console.error("Error getting billing URL:", JSON.stringify(error));
9929
10050
  return null;
9930
10051
  }
9931
10052
  };
@@ -9971,7 +10092,10 @@ const useSubscriptionHandlerV2 = (subscriptionFlow) => {
9971
10092
  try {
9972
10093
  subscriptionFlow.handleBeforePricingPageDisplayFlow();
9973
10094
  const { data: stripeContext } = await getStripePricingPageSession({
9974
- platform_key: subscriptionFlow.getCurrentTenantKey(),
10095
+ platform_key: subscriptionFlow.getMainTenantKey(),
10096
+ params: {
10097
+ source_platform_key: subscriptionFlow.getCurrentTenantKey(),
10098
+ },
9975
10099
  }, false);
9976
10100
  if (isStripeContextError ||
9977
10101
  !stripeContext ||
@@ -9984,6 +10108,7 @@ const useSubscriptionHandlerV2 = (subscriptionFlow) => {
9984
10108
  }, !hasCredits);
9985
10109
  }
9986
10110
  catch (error) {
10111
+ console.error("Error getting stripe pricing page session:", JSON.stringify(error));
9987
10112
  subscriptionFlow.handleFailureOnPaymentFlow();
9988
10113
  }
9989
10114
  };
@@ -10305,6 +10430,299 @@ const formatRelativeTime = (timestamp) => {
10305
10430
  return `${diffInYears} year${diffInYears === 1 ? "" : "s"} ago`;
10306
10431
  };
10307
10432
 
10433
+ /**
10434
+ * Authentication and Authorization Utilities
10435
+ *
10436
+ * This module provides utility functions for handling authentication flows,
10437
+ * including redirects to auth SPA, cookie management, and session handling.
10438
+ */
10439
+ /**
10440
+ * Check if the current window is inside an iframe
10441
+ * @returns {boolean} True if running in an iframe, false otherwise
10442
+ */
10443
+ function isInIframe() {
10444
+ if (typeof window === "undefined") {
10445
+ return false;
10446
+ }
10447
+ return (window === null || window === void 0 ? void 0 : window.self) !== (window === null || window === void 0 ? void 0 : window.top);
10448
+ }
10449
+ /**
10450
+ * Send a message to the parent website (when in iframe)
10451
+ * @param payload - The data to send to parent window
10452
+ */
10453
+ function sendMessageToParentWebsite(payload) {
10454
+ window.parent.postMessage(payload, "*");
10455
+ }
10456
+ /**
10457
+ * Delete a cookie with specific name, path, and domain
10458
+ * @param name - Cookie name
10459
+ * @param path - Cookie path
10460
+ * @param domain - Cookie domain
10461
+ */
10462
+ function deleteCookie(name, path, domain) {
10463
+ const expires = "expires=Thu, 01 Jan 1970 00:00:00 UTC;";
10464
+ const cookieValue = `${name}=;`;
10465
+ const pathValue = path ? `path=${path};` : "";
10466
+ const domainValue = domain ? `domain=${domain};` : "";
10467
+ document.cookie = cookieValue + expires + pathValue + domainValue;
10468
+ }
10469
+ /**
10470
+ * Get all possible domain parts for cookie deletion
10471
+ * @param domain - The domain to split
10472
+ * @returns Array of domain parts
10473
+ * @example
10474
+ * getDomainParts('app.example.com') // returns ['app.example.com', 'example.com', 'com']
10475
+ */
10476
+ function getDomainParts(domain) {
10477
+ const parts = domain.split(".");
10478
+ const domains = [];
10479
+ for (let i = parts.length - 1; i >= 0; i--) {
10480
+ domains.push(parts.slice(i).join("."));
10481
+ }
10482
+ return domains;
10483
+ }
10484
+ /**
10485
+ * Delete a cookie across all possible domain variations
10486
+ * @param name - Cookie name to delete
10487
+ * @param childDomain - The current domain
10488
+ */
10489
+ function deleteCookieOnAllDomains(name, childDomain) {
10490
+ getDomainParts(childDomain).forEach((domainPart) => {
10491
+ deleteCookie(name, "/", domainPart);
10492
+ deleteCookie(name, "", domainPart);
10493
+ });
10494
+ }
10495
+ /**
10496
+ * Get the parent domain from a given domain
10497
+ * @param domain - The domain to process
10498
+ * @returns The parent domain (e.g., 'app.example.com' → '.example.com')
10499
+ */
10500
+ function getParentDomain(domain) {
10501
+ if (!domain) {
10502
+ return "";
10503
+ }
10504
+ const parts = domain.split(".");
10505
+ return parts.length > 1 ? `.${parts.slice(-2).join(".")}` : domain;
10506
+ }
10507
+ /**
10508
+ * Set a cookie for authentication with cross-domain support
10509
+ * @param name - Cookie name
10510
+ * @param value - Cookie value
10511
+ * @param days - Number of days until expiration (default: 365)
10512
+ */
10513
+ function setCookieForAuth(name, value, days = 365) {
10514
+ const expires = new Date();
10515
+ expires.setTime(expires.getTime() + days * 24 * 60 * 60 * 1000);
10516
+ const hostname = window.location.hostname;
10517
+ let baseDomain = hostname;
10518
+ // Calculate base domain (skip for localhost and IP addresses)
10519
+ if (hostname !== "localhost" && !/^\d+\.\d+\.\d+\.\d+$/.test(hostname)) {
10520
+ const parts = hostname.split(".");
10521
+ if (parts.length > 2) {
10522
+ baseDomain = `.${parts.slice(-2).join(".")}`;
10523
+ }
10524
+ }
10525
+ const domainAttr = baseDomain ? `;domain=${baseDomain}` : "";
10526
+ document.cookie = `${name}=${encodeURIComponent(value)};expires=${expires.toUTCString()};path=/;SameSite=None;Secure${domainAttr}`;
10527
+ }
10528
+ /**
10529
+ * Clear all cookies for the current domain
10530
+ */
10531
+ function clearCookies() {
10532
+ const cookies = document.cookie.split(";");
10533
+ for (let i = 0; i < cookies.length; i++) {
10534
+ const cookie = cookies[i];
10535
+ const eqPos = cookie.indexOf("=");
10536
+ const name = eqPos > -1 ? cookie.substr(0, eqPos) : cookie;
10537
+ deleteCookieOnAllDomains(name, window.location.hostname);
10538
+ document.cookie = `${name}=;expires=Thu, 01 Jan 1970 00:00:00 GMT;path=/;Domain=${getParentDomain(window.location.hostname)}`;
10539
+ }
10540
+ }
10541
+ /**
10542
+ * Check if user is currently logged in
10543
+ * @param tokenKey - The localStorage key for the auth token (default: 'axd_token')
10544
+ * @returns True if logged in, false otherwise
10545
+ */
10546
+ function isLoggedIn(tokenKey = "axd_token") {
10547
+ return !!localStorage.getItem(tokenKey);
10548
+ }
10549
+ /**
10550
+ * Extract platform/tenant key from URL
10551
+ * @param url - The URL to parse
10552
+ * @param pattern - RegExp pattern to match platform key (default matches /platform/[key]/...)
10553
+ * @returns The platform key or null if not found
10554
+ */
10555
+ function getPlatformKey(url, pattern = /\/platform\/([^/]+)/) {
10556
+ const match = url.match(pattern);
10557
+ return match ? match[1] : null;
10558
+ }
10559
+ /**
10560
+ * Redirect to authentication SPA for login/logout
10561
+ *
10562
+ * This function handles the complete authentication flow:
10563
+ * - Clears localStorage and cookies on logout
10564
+ * - Saves redirect path for post-auth return
10565
+ * - Handles iframe scenarios
10566
+ * - Syncs logout across multiple SPAs via cookies
10567
+ *
10568
+ * @param options - Configuration options for the redirect
10569
+ *
10570
+ * @example
10571
+ * ```tsx
10572
+ * // Basic usage
10573
+ * redirectToAuthSpa({
10574
+ * authUrl: 'https://auth.example.com',
10575
+ * appName: 'mentor',
10576
+ * });
10577
+ *
10578
+ * // With logout
10579
+ * redirectToAuthSpa({
10580
+ * authUrl: 'https://auth.example.com',
10581
+ * appName: 'mentor',
10582
+ * logout: true,
10583
+ * platformKey: 'my-tenant',
10584
+ * });
10585
+ *
10586
+ * // With custom redirect
10587
+ * redirectToAuthSpa({
10588
+ * authUrl: 'https://auth.example.com',
10589
+ * appName: 'mentor',
10590
+ * redirectTo: '/dashboard',
10591
+ * platformKey: 'my-tenant',
10592
+ * });
10593
+ * ```
10594
+ */
10595
+ async function redirectToAuthSpa(options) {
10596
+ const { redirectTo, platformKey, logout = false, saveRedirect = true, authUrl, appName, queryParams = {
10597
+ app: "app",
10598
+ redirectTo: "redirect-to",
10599
+ tenant: "tenant",
10600
+ }, redirectPathStorageKey = "redirect_to", cookieNames = {
10601
+ currentTenant: "ibl_current_tenant",
10602
+ userData: "ibl_user_data",
10603
+ tenant: "ibl_tenant",
10604
+ logoutTimestamp: "ibl_logout_timestamp",
10605
+ }, } = options;
10606
+ // Clear localStorage
10607
+ localStorage.clear();
10608
+ if (logout) {
10609
+ // Delete authentication cookies for cross-SPA synchronization
10610
+ const currentDomain = window.location.hostname;
10611
+ if (cookieNames.currentTenant) {
10612
+ deleteCookieOnAllDomains(cookieNames.currentTenant, currentDomain);
10613
+ }
10614
+ if (cookieNames.userData) {
10615
+ deleteCookieOnAllDomains(cookieNames.userData, currentDomain);
10616
+ }
10617
+ if (cookieNames.tenant) {
10618
+ deleteCookieOnAllDomains(cookieNames.tenant, currentDomain);
10619
+ }
10620
+ // Set logout timestamp cookie to trigger logout on other SPAs
10621
+ if (cookieNames.logoutTimestamp) {
10622
+ setCookieForAuth(cookieNames.logoutTimestamp, Date.now().toString());
10623
+ }
10624
+ }
10625
+ // Handle iframe scenario
10626
+ if (isInIframe()) {
10627
+ console.log("[redirectToAuthSpa]: sending authExpired to parent");
10628
+ sendMessageToParentWebsite({ authExpired: true });
10629
+ return;
10630
+ }
10631
+ const redirectPath = redirectTo !== null && redirectTo !== void 0 ? redirectTo : `${window.location.pathname}${window.location.search}`;
10632
+ // Never save sso-login routes as redirect paths
10633
+ if (!redirectPath.startsWith("/sso-login") && saveRedirect) {
10634
+ window.localStorage.setItem(redirectPathStorageKey, redirectPath);
10635
+ }
10636
+ const platform = platformKey !== null && platformKey !== void 0 ? platformKey : getPlatformKey(redirectPath);
10637
+ const redirectToUrl = `${window.location.origin}`;
10638
+ let authRedirectUrl = `${authUrl}/login?${queryParams.app}=${appName}`;
10639
+ authRedirectUrl += `&${queryParams.redirectTo}=${redirectToUrl}`;
10640
+ if (platform) {
10641
+ authRedirectUrl += `&${queryParams.tenant}=${platform}`;
10642
+ }
10643
+ if (logout) {
10644
+ authRedirectUrl += "&logout=1";
10645
+ }
10646
+ // Small delay for any pending operations
10647
+ await new Promise((resolve) => setTimeout(resolve, 100));
10648
+ // Redirect to auth SPA
10649
+ window.location.href = authRedirectUrl;
10650
+ }
10651
+ /**
10652
+ * Get the URL for joining a tenant (sign up flow)
10653
+ * @param authUrl - Auth SPA base URL
10654
+ * @param tenantKey - Tenant to join
10655
+ * @param redirectUrl - URL to redirect to after joining (defaults to current URL)
10656
+ * @returns The join URL
10657
+ */
10658
+ function getAuthSpaJoinUrl(authUrl, tenantKey, redirectUrl) {
10659
+ const resolvedTenant = tenantKey || getPlatformKey(window.location.pathname) || "";
10660
+ if (!resolvedTenant) {
10661
+ return "";
10662
+ }
10663
+ const targetUrl = redirectUrl !== null && redirectUrl !== void 0 ? redirectUrl : window.location.href;
10664
+ const joinUrl = `${authUrl}/join?tenant=${encodeURIComponent(resolvedTenant)}&redirect-to=${encodeURIComponent(targetUrl)}`;
10665
+ return joinUrl;
10666
+ }
10667
+ /**
10668
+ * Redirect to auth SPA's join/signup page for a specific tenant
10669
+ * @param authUrl - Auth SPA base URL
10670
+ * @param tenantKey - Tenant to join
10671
+ * @param redirectUrl - URL to redirect to after joining (defaults to current URL)
10672
+ */
10673
+ function redirectToAuthSpaJoinTenant(authUrl, tenantKey, redirectUrl) {
10674
+ const resolvedTenant = tenantKey || getPlatformKey(window.location.pathname) || "";
10675
+ if (!resolvedTenant) {
10676
+ console.log("[auth-redirect] Missing tenant key for join", {
10677
+ tenantKey,
10678
+ redirectUrl,
10679
+ });
10680
+ redirectToAuthSpa({
10681
+ authUrl,
10682
+ appName: "app", // Will need to be configured
10683
+ redirectTo: redirectUrl,
10684
+ });
10685
+ return;
10686
+ }
10687
+ const targetUrl = redirectUrl !== null && redirectUrl !== void 0 ? redirectUrl : window.location.href;
10688
+ const joinUrl = `${authUrl}/join?tenant=${encodeURIComponent(resolvedTenant)}&redirect-to=${encodeURIComponent(targetUrl)}`;
10689
+ window.location.href = joinUrl;
10690
+ }
10691
+ /**
10692
+ * Handle user logout
10693
+ *
10694
+ * This function:
10695
+ * - Clears localStorage (preserving tenant)
10696
+ * - Sets logout timestamp cookie for cross-SPA sync
10697
+ * - Clears all cookies
10698
+ * - Redirects to auth SPA logout endpoint
10699
+ *
10700
+ * @param options - Logout configuration options
10701
+ *
10702
+ * @example
10703
+ * ```tsx
10704
+ * handleLogout({
10705
+ * authUrl: 'https://auth.example.com',
10706
+ * redirectUrl: 'https://app.example.com',
10707
+ * });
10708
+ * ```
10709
+ */
10710
+ function handleLogout(options) {
10711
+ const { redirectUrl = window.location.origin, authUrl, tenantStorageKey = "tenant", logoutTimestampCookie = "ibl_logout_timestamp", callback, } = options;
10712
+ const tenant = window.localStorage.getItem(tenantStorageKey);
10713
+ window.localStorage.clear();
10714
+ if (tenant) {
10715
+ window.localStorage.setItem(tenantStorageKey, tenant);
10716
+ }
10717
+ // Set logout timestamp cookie to trigger logout on other SPAs
10718
+ setCookieForAuth(logoutTimestampCookie, Date.now().toString());
10719
+ clearCookies();
10720
+ callback === null || callback === void 0 ? void 0 : callback();
10721
+ if (!isInIframe()) {
10722
+ window.location.href = `${authUrl}/logout?redirect-to=${redirectUrl}${tenant ? "&tenant=" + tenant : ""}`;
10723
+ }
10724
+ }
10725
+
10308
10726
  const useExternalPricingPlan = ({ pricingModalData, userEmail, }) => {
10309
10727
  const pricingBoxIframeRef = useRef(null);
10310
10728
  const getIFrameReadyData = async () => {
@@ -10436,6 +10854,8 @@ function jwtDecode(token, options) {
10436
10854
  * - Polls for cookie changes every 2 seconds
10437
10855
  * - Refreshes the page when cross-SPA changes are detected
10438
10856
  * - Listens for storage events to update cookies when localStorage changes
10857
+ * - Monitors logout timestamp cookie to trigger cross-SPA logout
10858
+ * - Automatically logs out when another SPA initiates logout
10439
10859
  *
10440
10860
  * For React Native:
10441
10861
  * - Relies on AsyncStorage only (handled by StorageService)
@@ -10445,7 +10865,7 @@ function jwtDecode(token, options) {
10445
10865
  /**
10446
10866
  * Check if we're running in a web browser environment
10447
10867
  */
10448
- const isWeb = () => {
10868
+ const isWeb$1 = () => {
10449
10869
  return typeof window !== "undefined" && typeof document !== "undefined";
10450
10870
  };
10451
10871
  /**
@@ -10455,6 +10875,7 @@ const COOKIE_KEYS = {
10455
10875
  CURRENT_TENANT: "ibl_current_tenant",
10456
10876
  USER_DATA: "ibl_user_data",
10457
10877
  TENANT: "ibl_tenant",
10878
+ LOGOUT_TIMESTAMP: "ibl_logout_timestamp",
10458
10879
  };
10459
10880
  /**
10460
10881
  * Get the base domain for cookie sharing
@@ -10465,7 +10886,7 @@ const COOKIE_KEYS = {
10465
10886
  */
10466
10887
  const getBaseDomain = () => {
10467
10888
  // Must check for window existence before accessing it
10468
- if (!isWeb())
10889
+ if (!isWeb$1())
10469
10890
  return "";
10470
10891
  const hostname = window.location.hostname;
10471
10892
  // For localhost or IP addresses, use as-is
@@ -10494,7 +10915,7 @@ const CookieUtils = {
10494
10915
  * Uses SameSite=None for cross-subdomain sharing and base domain
10495
10916
  */
10496
10917
  set(name, value, days = 365) {
10497
- if (!isWeb())
10918
+ if (!isWeb$1())
10498
10919
  return;
10499
10920
  const expires = new Date();
10500
10921
  expires.setTime(expires.getTime() + days * 24 * 60 * 60 * 1000);
@@ -10506,7 +10927,7 @@ const CookieUtils = {
10506
10927
  * Get a cookie value by name
10507
10928
  */
10508
10929
  get(name) {
10509
- if (!isWeb())
10930
+ if (!isWeb$1())
10510
10931
  return null;
10511
10932
  const nameEQ = name + "=";
10512
10933
  const cookies = document.cookie.split(";");
@@ -10525,7 +10946,7 @@ const CookieUtils = {
10525
10946
  * Uses same domain logic as set() to ensure proper deletion
10526
10947
  */
10527
10948
  delete(name) {
10528
- if (!isWeb())
10949
+ if (!isWeb$1())
10529
10950
  return;
10530
10951
  const baseDomain = getBaseDomain();
10531
10952
  const domainAttr = baseDomain ? `;domain=${baseDomain}` : "";
@@ -10538,8 +10959,7 @@ const CookieUtils = {
10538
10959
  * On React Native, this is a no-op
10539
10960
  */
10540
10961
  async function syncAuthToCookies(storageService) {
10541
- console.log("##################### syncing auth to cookie");
10542
- if (!isWeb())
10962
+ if (!isWeb$1())
10543
10963
  return;
10544
10964
  try {
10545
10965
  const currentTenant = await storageService.getItem(LOCAL_STORAGE_KEYS.CURRENT_TENANT);
@@ -10568,13 +10988,23 @@ async function syncAuthToCookies(storageService) {
10568
10988
  console.error("[syncAuthToCookies] Error syncing to cookies:", error);
10569
10989
  }
10570
10990
  }
10991
+ /**
10992
+ * Clear current tenant cookie only (web only)
10993
+ * Should be called before tenant switching
10994
+ * On React Native, this is a no-op
10995
+ */
10996
+ function clearCurrentTenantCookie() {
10997
+ if (!isWeb$1())
10998
+ return;
10999
+ CookieUtils.delete(COOKIE_KEYS.CURRENT_TENANT);
11000
+ }
10571
11001
  /**
10572
11002
  * Clear all authentication cookies (web only)
10573
11003
  * Should be called on logout
10574
11004
  * On React Native, this is a no-op
10575
11005
  */
10576
11006
  function clearAuthCookies() {
10577
- if (!isWeb())
11007
+ if (!isWeb$1())
10578
11008
  return;
10579
11009
  CookieUtils.delete(COOKIE_KEYS.CURRENT_TENANT);
10580
11010
  CookieUtils.delete(COOKIE_KEYS.USER_DATA);
@@ -10586,14 +11016,30 @@ function clearAuthCookies() {
10586
11016
  * On React Native, always returns false (no-op)
10587
11017
  */
10588
11018
  async function syncCookiesToLocalStorage(storageService) {
10589
- if (!isWeb())
11019
+ if (!isWeb$1())
10590
11020
  return false;
10591
11021
  try {
10592
11022
  let needsRefresh = false;
10593
11023
  // Check current_tenant
10594
11024
  const cookieCurrentTenant = CookieUtils.get(COOKIE_KEYS.CURRENT_TENANT);
11025
+ console.log("[syncCookiesToLocalStorage] cookieCurrentTenant", cookieCurrentTenant);
10595
11026
  const localCurrentTenant = await storageService.getItem(LOCAL_STORAGE_KEYS.CURRENT_TENANT);
10596
- if (cookieCurrentTenant !== localCurrentTenant) {
11027
+ console.log("[syncCookiesToLocalStorage] localCurrentTenant", localCurrentTenant);
11028
+ // Compare current tenant objects by key field only to avoid false positives from extra fields
11029
+ let currentTenantIsDifferent = false;
11030
+ if (cookieCurrentTenant && localCurrentTenant) {
11031
+ try {
11032
+ const cookieTenant = JSON.parse(cookieCurrentTenant);
11033
+ const localTenant = JSON.parse(localCurrentTenant);
11034
+ // Compare by the tenant key only
11035
+ currentTenantIsDifferent = cookieTenant.key !== localTenant.key;
11036
+ }
11037
+ catch (e) {
11038
+ // If parsing fails, fall back to string comparison
11039
+ currentTenantIsDifferent = cookieCurrentTenant !== localCurrentTenant;
11040
+ }
11041
+ }
11042
+ if (currentTenantIsDifferent) {
10597
11043
  if (cookieCurrentTenant) {
10598
11044
  await storageService.setItem(LOCAL_STORAGE_KEYS.CURRENT_TENANT, cookieCurrentTenant);
10599
11045
  }
@@ -10605,8 +11051,24 @@ async function syncCookiesToLocalStorage(storageService) {
10605
11051
  }
10606
11052
  // Check userData
10607
11053
  const cookieUserData = CookieUtils.get(COOKIE_KEYS.USER_DATA);
11054
+ console.log("[syncCookiesToLocalStorage] cookieUserData", cookieUserData);
10608
11055
  const localUserData = await storageService.getItem(LOCAL_STORAGE_KEYS.USER_DATA);
10609
- if (cookieUserData !== localUserData) {
11056
+ console.log("[syncCookiesToLocalStorage] localUserData", localUserData);
11057
+ // Compare userData objects by user_id to avoid false positives from extra fields
11058
+ let userDataIsDifferent = false;
11059
+ if (cookieUserData && localUserData) {
11060
+ try {
11061
+ const cookieUser = JSON.parse(cookieUserData);
11062
+ const localUser = JSON.parse(localUserData);
11063
+ // Compare by user_id - the primary identifier
11064
+ userDataIsDifferent = cookieUser.user_id !== localUser.user_id;
11065
+ }
11066
+ catch (e) {
11067
+ // If parsing fails, fall back to string comparison
11068
+ userDataIsDifferent = cookieUserData !== localUserData;
11069
+ }
11070
+ }
11071
+ if (userDataIsDifferent) {
10610
11072
  if (cookieUserData) {
10611
11073
  await storageService.setItem(LOCAL_STORAGE_KEYS.USER_DATA, cookieUserData);
10612
11074
  }
@@ -10618,8 +11080,37 @@ async function syncCookiesToLocalStorage(storageService) {
10618
11080
  }
10619
11081
  // Check tenant
10620
11082
  const cookieTenant = CookieUtils.get(COOKIE_KEYS.TENANT);
11083
+ console.log("[syncCookiesToLocalStorage] cookieTenant", cookieTenant);
10621
11084
  const localTenant = await storageService.getItem(LOCAL_STORAGE_KEYS.TENANTS);
10622
- if (cookieTenant !== localTenant) {
11085
+ console.log("[syncCookiesToLocalStorage] localTenant", localTenant);
11086
+ // Compare tenant arrays by checking length and tenant keys
11087
+ let tenantsAreDifferent = false;
11088
+ if (cookieTenant &&
11089
+ localTenant &&
11090
+ cookieTenant !== "[]" &&
11091
+ localTenant !== "[]") {
11092
+ try {
11093
+ const cookieTenantsArray = JSON.parse(cookieTenant);
11094
+ const localTenantsArray = JSON.parse(localTenant);
11095
+ // Check if arrays have same length
11096
+ if (cookieTenantsArray.length !== localTenantsArray.length) {
11097
+ tenantsAreDifferent = true;
11098
+ }
11099
+ else {
11100
+ // Check if all tenant keys match
11101
+ const cookieKeys = new Set(cookieTenantsArray.map((t) => t.key));
11102
+ const localKeys = new Set(localTenantsArray.map((t) => t.key));
11103
+ tenantsAreDifferent =
11104
+ cookieKeys.size !== localKeys.size ||
11105
+ [...cookieKeys].some((key) => !localKeys.has(key));
11106
+ }
11107
+ }
11108
+ catch (e) {
11109
+ // If parsing fails, fall back to string comparison
11110
+ tenantsAreDifferent = cookieTenant !== localTenant;
11111
+ }
11112
+ }
11113
+ if (tenantsAreDifferent) {
10623
11114
  if (cookieTenant) {
10624
11115
  await storageService.setItem(LOCAL_STORAGE_KEYS.TENANTS, cookieTenant);
10625
11116
  }
@@ -10674,6 +11165,7 @@ async function isJwtTokenExpired(storageService) {
10674
11165
  async function validateJwtToken(storageService) {
10675
11166
  try {
10676
11167
  const edxJwtToken = await storageService.getItem(LOCAL_STORAGE_KEYS.EDX_TOKEN_KEY);
11168
+ console.log("[AuthProvider] JWT token ", edxJwtToken);
10677
11169
  const userData = await storageService.getItem(LOCAL_STORAGE_KEYS.USER_DATA);
10678
11170
  if (!edxJwtToken || !userData) {
10679
11171
  return false;
@@ -10696,7 +11188,9 @@ async function validateJwtToken(storageService) {
10696
11188
  function useAuthProvider({ middleware = new Map(), onAuthSuccess, onAuthFailure, redirectToAuthSpa, hasNonExpiredAuthToken, username, pathname, storageService, skipAuthCheck, token, }) {
10697
11189
  const [isAuthenticating, setIsAuthenticating] = useState(true);
10698
11190
  const [userIsAccessingPublicRoute, setUserIsAccessingPublicRoute] = useState(false);
11191
+ const [initialSyncComplete, setInitialSyncComplete] = useState(false);
10699
11192
  const cookieCheckIntervalRef = useRef(null);
11193
+ const lastLogoutTimestampRef = useRef(null);
10700
11194
  // RTK Query hook for refreshing JWT token
10701
11195
  const [refreshJwtToken] = useLazyRefreshJwtTokenQuery();
10702
11196
  /**
@@ -10705,24 +11199,65 @@ function useAuthProvider({ middleware = new Map(), onAuthSuccess, onAuthFailure,
10705
11199
  * On React Native, this is a no-op
10706
11200
  */
10707
11201
  useEffect(() => {
10708
- console.log("################******* useEffect sync auth");
10709
- if (!storageService || !isWeb())
11202
+ if (!storageService || !isWeb$1()) {
11203
+ // If no storage service or not web, mark sync as complete immediately
11204
+ setInitialSyncComplete(true);
10710
11205
  return;
11206
+ }
10711
11207
  // Initial sync on mount
10712
11208
  async function initialSync() {
10713
- const needsRefresh = await syncCookiesToLocalStorage(storageService);
10714
- if (needsRefresh) {
10715
- console.log("[AuthProvider] Cookie sync detected changes, refreshing page...");
10716
- window.location.reload();
11209
+ try {
11210
+ // Initialize last known logout timestamp
11211
+ lastLogoutTimestampRef.current = CookieUtils.get(COOKIE_KEYS.LOGOUT_TIMESTAMP);
11212
+ const needsRefresh = await syncCookiesToLocalStorage(storageService);
11213
+ if (needsRefresh) {
11214
+ console.log("[auth-redirect] Cookie sync detected changes, refreshing page");
11215
+ redirectToAuthSpa(undefined, undefined, false, false);
11216
+ }
11217
+ else {
11218
+ await syncAuthToCookies(storageService);
11219
+ }
11220
+ }
11221
+ finally {
11222
+ // Mark initial sync as complete
11223
+ setInitialSyncComplete(true);
10717
11224
  }
10718
11225
  }
10719
11226
  initialSync();
10720
11227
  // Poll for cookie changes every 2 seconds to detect cross-SPA updates
10721
11228
  cookieCheckIntervalRef.current = setInterval(async () => {
11229
+ // Skip cookie sync checks if user is completing SSO at /sso-login
11230
+ const completingSso = new RegExp("^\/sso-login").test(pathname);
11231
+ if (completingSso) {
11232
+ console.log("[AuthProvider] Skipping cookie sync check for public route");
11233
+ return;
11234
+ }
11235
+ // Check for logout timestamp changes (cross-SPA logout detection)
11236
+ const currentLogoutTimestamp = CookieUtils.get(COOKIE_KEYS.LOGOUT_TIMESTAMP);
11237
+ if (currentLogoutTimestamp &&
11238
+ lastLogoutTimestampRef.current &&
11239
+ currentLogoutTimestamp !== lastLogoutTimestampRef.current) {
11240
+ console.log("[auth-redirect] Logout detected from another SPA", {
11241
+ previousTimestamp: lastLogoutTimestampRef.current,
11242
+ newTimestamp: currentLogoutTimestamp,
11243
+ });
11244
+ lastLogoutTimestampRef.current = currentLogoutTimestamp;
11245
+ redirectToAuthSpa(undefined, undefined, true);
11246
+ return;
11247
+ }
10722
11248
  const needsRefresh = await syncCookiesToLocalStorage(storageService);
10723
11249
  if (needsRefresh) {
10724
- console.log("[AuthProvider] Cookie sync detected changes from another SPA, refreshing page...");
10725
- window.location.reload();
11250
+ console.log("[auth-redirect] Cookie sync detected changes from another SPA, refreshing page");
11251
+ let cookieTenantKey;
11252
+ try {
11253
+ const cookieCurrentTenant = JSON.parse(CookieUtils.get(COOKIE_KEYS.CURRENT_TENANT));
11254
+ cookieTenantKey = cookieCurrentTenant.key;
11255
+ }
11256
+ catch (_a) { }
11257
+ redirectToAuthSpa(undefined, cookieTenantKey, false, false);
11258
+ }
11259
+ else {
11260
+ await syncAuthToCookies(storageService);
10726
11261
  }
10727
11262
  }, 2000);
10728
11263
  // Cleanup interval on unmount
@@ -10731,15 +11266,14 @@ function useAuthProvider({ middleware = new Map(), onAuthSuccess, onAuthFailure,
10731
11266
  clearInterval(cookieCheckIntervalRef.current);
10732
11267
  }
10733
11268
  };
10734
- }, [storageService]);
11269
+ }, [storageService, middleware, pathname]);
10735
11270
  /**
10736
11271
  * Listen for storage events from other tabs/windows (web only)
10737
11272
  * This catches same-SPA changes in different tabs
10738
11273
  * On React Native, this is a no-op
10739
11274
  */
10740
11275
  useEffect(() => {
10741
- console.log("################ useEffect sync auth");
10742
- if (!storageService || !isWeb())
11276
+ if (!storageService || !isWeb$1())
10743
11277
  return;
10744
11278
  const handleStorageChange = async (event) => {
10745
11279
  // Only handle changes to our auth-related keys
@@ -10770,14 +11304,15 @@ function useAuthProvider({ middleware = new Map(), onAuthSuccess, onAuthFailure,
10770
11304
  if (!hasNonExpiredAuthToken()) {
10771
11305
  const reason = "Auth token expired";
10772
11306
  onAuthFailure === null || onAuthFailure === void 0 ? void 0 : onAuthFailure(reason);
10773
- redirectToAuthSpa();
11307
+ console.log("[auth-redirect] Auth token expired");
11308
+ redirectToAuthSpa(undefined, undefined, true);
10774
11309
  return;
10775
11310
  }
10776
11311
  // Check JWT token expiry and force logout for protected routes
10777
11312
  if (isProtectedRoute && storageService) {
10778
11313
  const jwtExpired = await isJwtTokenExpired(storageService);
10779
11314
  if (jwtExpired) {
10780
- console.log("[AuthProvider] JWT token has expired, forcing logout...");
11315
+ console.log("[auth-redirect] JWT token has expired, forcing logout");
10781
11316
  // Clear all auth-related storage keys
10782
11317
  clearAuthCookies();
10783
11318
  const reason = "JWT token expired";
@@ -10799,11 +11334,18 @@ function useAuthProvider({ middleware = new Map(), onAuthSuccess, onAuthFailure,
10799
11334
  console.log("[AuthProvider] JWT token refreshed successfully");
10800
11335
  }
10801
11336
  else if (result.error) {
10802
- console.error("[AuthProvider] Failed to refresh JWT token:", result.error);
11337
+ console.log("[auth-redirect] Failed to refresh JWT token", {
11338
+ error: result.error,
11339
+ });
11340
+ redirectToAuthSpa(undefined, undefined, true);
11341
+ return;
10803
11342
  }
10804
11343
  }
10805
11344
  catch (refreshError) {
10806
- console.error("[AuthProvider] Failed to refresh JWT token:", refreshError);
11345
+ console.log("[auth-redirect] JWT token refresh error", {
11346
+ error: refreshError,
11347
+ });
11348
+ redirectToAuthSpa(undefined, undefined, true);
10807
11349
  // Continue with auth check even if JWT refresh fails
10808
11350
  }
10809
11351
  }
@@ -10815,12 +11357,18 @@ function useAuthProvider({ middleware = new Map(), onAuthSuccess, onAuthFailure,
10815
11357
  setIsAuthenticating(false);
10816
11358
  }
10817
11359
  catch (error) {
11360
+ console.error("[AuthProvider] Error performing auth check:", error);
10818
11361
  const errorMessage = error instanceof Error ? error.message : String(error);
10819
11362
  onAuthFailure === null || onAuthFailure === void 0 ? void 0 : onAuthFailure(`Unexpected error: ${errorMessage}`);
10820
11363
  redirectToAuthSpa();
10821
11364
  }
10822
11365
  }
10823
11366
  useEffect(() => {
11367
+ // Wait for initial sync to complete before performing auth check
11368
+ if (!initialSyncComplete) {
11369
+ console.log("[useAuthProvider] Waiting for initial sync to complete...");
11370
+ return;
11371
+ }
10824
11372
  async function checkAuth() {
10825
11373
  setIsAuthenticating(true);
10826
11374
  const authRequired = (await determineAuthRequired(middleware, pathname)) && !token;
@@ -10841,7 +11389,7 @@ function useAuthProvider({ middleware = new Map(), onAuthSuccess, onAuthFailure,
10841
11389
  }
10842
11390
  console.log("[useAuthProvider] performing auth check for ", username);
10843
11391
  checkAuth();
10844
- }, [username]);
11392
+ }, [username, initialSyncComplete]);
10845
11393
  return {
10846
11394
  isAuthenticating,
10847
11395
  userIsAccessingPublicRoute,
@@ -10909,7 +11457,7 @@ function AuthProvider({ children, fallback, middleware = new Map(), onAuthSucces
10909
11457
  if (isAuthenticating) {
10910
11458
  return fallback;
10911
11459
  }
10912
- return (jsx(AuthContextProvider, { value: { userIsAccessingPublicRoute, setUserIsAccessingPublicRoute }, children: jsx(Fragment, {}) }));
11460
+ return (jsx(AuthContextProvider, { value: { userIsAccessingPublicRoute, setUserIsAccessingPublicRoute }, children: children }));
10913
11461
  }
10914
11462
 
10915
11463
  /**
@@ -10922,6 +11470,12 @@ function AuthProvider({ children, fallback, middleware = new Map(), onAuthSucces
10922
11470
  * - Tenant metadata retrieval
10923
11471
  * - User-tenant relationship verification
10924
11472
  */
11473
+ /**
11474
+ * Check if we're running in a web browser environment
11475
+ */
11476
+ const isWeb = () => {
11477
+ return typeof window !== "undefined" && typeof document !== "undefined";
11478
+ };
10925
11479
  const TenantContext = createContext(undefined);
10926
11480
  /**
10927
11481
  * Context Provider component that wraps children with tenant context
@@ -10942,7 +11496,7 @@ const useTenantContext = () => useContext(TenantContext);
10942
11496
  * 4. Handles tenant-specific domain redirects
10943
11497
  * 5. Maintains tenant access state
10944
11498
  */
10945
- function TenantProvider({ children, fallback, onAuthSuccess, onAuthFailure, currentTenant, requestedTenant, saveCurrentTenant, saveUserTenants, handleTenantSwitch, saveVisitingTenant, removeVisitingTenant, saveUserTokens, saveTenant, onAutoJoinUserToTenant, }) {
11499
+ function TenantProvider({ children, fallback, onAuthSuccess, onAuthFailure, currentTenant, requestedTenant, saveCurrentTenant, saveUserTenants, handleTenantSwitch, saveVisitingTenant, removeVisitingTenant, saveUserTokens, saveTenant, onAutoJoinUserToTenant, redirectToAuthSpa, username, }) {
10946
11500
  const { userIsAccessingPublicRoute, setUserIsAccessingPublicRoute } = useAuthContext();
10947
11501
  const [determineUserPath, setDetermineUserPath] = useState(false);
10948
11502
  const [isLoading, setIsLoading] = React__default.useState(true);
@@ -10953,6 +11507,26 @@ function TenantProvider({ children, fallback, onAuthSuccess, onAuthFailure, curr
10953
11507
  const [getAppToken] = useGetAppTokensMutation();
10954
11508
  const [tenantKey, setTenantKey] = useState(currentTenant);
10955
11509
  const [metadata, setMetadata] = useState({});
11510
+ // Fetch custom domain to get platform_key
11511
+ const currentDomain = typeof window !== "undefined" ? window.location.hostname : "";
11512
+ const { data: customDomainData, isLoading: isLoadingCustomDomain, isError: isCustomDomainError, } = useGetCustomDomainsQuery({ params: { domain: currentDomain } }, { skip: !isWeb() || !currentDomain });
11513
+ // Extract platform_key from custom domain response to use as requestedTenant
11514
+ const customDomainPlatformKey = React__default.useMemo(() => {
11515
+ if (customDomainData &&
11516
+ typeof customDomainData === "object" &&
11517
+ "custom_domains" in customDomainData) {
11518
+ const domains = customDomainData.custom_domains;
11519
+ if (Array.isArray(domains) &&
11520
+ domains.length > 0 &&
11521
+ domains[0].platform_key) {
11522
+ console.log("[TenantProvider] Using platform_key from custom domain:", domains[0].platform_key);
11523
+ return domains[0].platform_key;
11524
+ }
11525
+ }
11526
+ return undefined;
11527
+ }, [customDomainData]);
11528
+ // Use custom domain platform_key as requested tenant if available, otherwise use provided requestedTenant
11529
+ const effectiveRequestedTenant = customDomainPlatformKey || requestedTenant;
10956
11530
  /**
10957
11531
  * Helper function to enhance tenants with platform metadata from user apps
10958
11532
  */
@@ -11012,24 +11586,32 @@ function TenantProvider({ children, fallback, onAuthSuccess, onAuthFailure, curr
11012
11586
  const otherTenant = tenants.find((t) => t.key !== MAIN_TENANT_KEY);
11013
11587
  if (mainTenant &&
11014
11588
  otherTenant &&
11015
- requestedTenant &&
11016
- requestedTenant !== otherTenant.key) {
11589
+ effectiveRequestedTenant &&
11590
+ effectiveRequestedTenant !== otherTenant.key) {
11017
11591
  handleTenantSwitch(otherTenant.key, true);
11018
11592
  console.log("TenantProvider: Triggering tenant switch to newly joined tenant:", otherTenant.key);
11019
11593
  }
11020
11594
  }
11021
- // Enhance tenants with platform metadata
11595
+ // Enhance tenants with platform metadatax
11022
11596
  let enhancedTenants = await enhanceTenants(tenants);
11597
+ // if there is customDomainPlatformKey and user doesn't belong to that tenant, trigger logout
11598
+ if (customDomainPlatformKey) {
11599
+ if (!(enhancedTenants === null || enhancedTenants === void 0 ? void 0 : enhancedTenants.find((tenant) => tenant.key === customDomainPlatformKey))) {
11600
+ redirectToAuthSpa === null || redirectToAuthSpa === void 0 ? void 0 : redirectToAuthSpa(undefined, undefined, true);
11601
+ return;
11602
+ }
11603
+ }
11023
11604
  saveUserTenants(enhancedTenants);
11024
11605
  // Find requested tenant or fallback to current tenant
11025
- console.log("checking requested tenant", { requestedTenant });
11026
- let tenant = enhancedTenants === null || enhancedTenants === void 0 ? void 0 : enhancedTenants.find((tenant) => tenant.key === requestedTenant);
11027
- console.log("requested tenant", { tenant });
11606
+ console.log("checking requested tenant", JSON.stringify({
11607
+ requestedTenant: effectiveRequestedTenant,
11608
+ customDomainPlatformKey,
11609
+ }));
11610
+ let tenant = enhancedTenants === null || enhancedTenants === void 0 ? void 0 : enhancedTenants.find((tenant) => tenant.key === effectiveRequestedTenant);
11611
+ console.log("requested tenant", tenant);
11028
11612
  if (!tenant && !userIsAccessingPublicRoute) {
11029
11613
  setDetermineUserPath(true);
11030
- console.log("no requested tenant, checking current tenant", {
11031
- currentTenant,
11032
- });
11614
+ console.log("no requested tenant, checking current tenant", currentTenant);
11033
11615
  tenant = enhancedTenants === null || enhancedTenants === void 0 ? void 0 : enhancedTenants.find((tenant) => tenant.key === currentTenant);
11034
11616
  console.log("current tenant", { tenant });
11035
11617
  }
@@ -11041,7 +11623,7 @@ function TenantProvider({ children, fallback, onAuthSuccess, onAuthFailure, curr
11041
11623
  tenant = enhancedTenants[0];
11042
11624
  }
11043
11625
  // Fetch and validate tenant metadata
11044
- console.log("fetching tenant metadata", { tenant });
11626
+ console.log("fetching tenant metadata", JSON.stringify(tenant));
11045
11627
  const { data: tenantMetadata } = await fetchTenantMetadata([
11046
11628
  {
11047
11629
  org: (tenant === null || tenant === void 0 ? void 0 : tenant.key) || currentTenant,
@@ -11112,6 +11694,11 @@ function TenantProvider({ children, fallback, onAuthSuccess, onAuthFailure, curr
11112
11694
  platform_name: data.platform_name,
11113
11695
  is_advertising: (_a = data.metadata) === null || _a === void 0 ? void 0 : _a.is_advertising,
11114
11696
  };
11697
+ if (!username) {
11698
+ saveVisitingTenant === null || saveVisitingTenant === void 0 ? void 0 : saveVisitingTenant(newCurrentTenant);
11699
+ // user is not authenticated so we don't need to do anything that concerns an authenticated user
11700
+ return;
11701
+ }
11115
11702
  const { data: tenants } = await fetchUserTenants();
11116
11703
  const enhancedTenants = await enhanceTenants(tenants, data);
11117
11704
  saveUserTenants(enhancedTenants);
@@ -11183,28 +11770,44 @@ function TenantProvider({ children, fallback, onAuthSuccess, onAuthFailure, curr
11183
11770
  }
11184
11771
  // Effect to handle tenant determination when auth state changes
11185
11772
  React__default.useEffect(() => {
11773
+ // Wait for custom domain query to complete (unless skipped or error)
11774
+ const customDomainQuerySkipped = !isWeb() || !currentDomain;
11775
+ if (!customDomainQuerySkipped && isLoadingCustomDomain) {
11776
+ console.log("[TenantProvider] Waiting for custom domain query to complete...");
11777
+ return;
11778
+ }
11779
+ if (isCustomDomainError) {
11780
+ console.warn("[TenantProvider] Custom domain query failed, proceeding without custom domain platform_key");
11781
+ }
11186
11782
  // NOTE: currentTenant comes from local storage.
11187
11783
  // it's the tenant the user is currently signed into.
11188
11784
  console.log("determineWhichTenantToUse", {
11189
11785
  userIsAccessingPublicRoute,
11190
11786
  currentTenant,
11191
11787
  requestedTenant,
11788
+ effectiveRequestedTenant,
11789
+ customDomainPlatformKey,
11192
11790
  });
11193
- if (userIsAccessingPublicRoute && requestedTenant.length === 0) {
11791
+ if (userIsAccessingPublicRoute && effectiveRequestedTenant.length === 0) {
11194
11792
  setIsLoading(false);
11195
11793
  return;
11196
11794
  }
11197
- if (userIsAccessingPublicRoute && requestedTenant.length > 0) {
11795
+ if (userIsAccessingPublicRoute && effectiveRequestedTenant.length > 0) {
11198
11796
  setIsLoading(true);
11199
- setTenantKey(requestedTenant);
11200
- handleLoadTenantMetadata(requestedTenant);
11797
+ setTenantKey(effectiveRequestedTenant);
11798
+ handleLoadTenantMetadata(effectiveRequestedTenant);
11201
11799
  }
11202
11800
  else {
11203
11801
  setIsLoading(true);
11204
11802
  removeVisitingTenant === null || removeVisitingTenant === void 0 ? void 0 : removeVisitingTenant();
11205
11803
  determineWhichTenantToUse();
11206
11804
  }
11207
- }, [userIsAccessingPublicRoute, requestedTenant]);
11805
+ }, [
11806
+ userIsAccessingPublicRoute,
11807
+ effectiveRequestedTenant,
11808
+ isLoadingCustomDomain,
11809
+ isCustomDomainError,
11810
+ ]);
11208
11811
  // Show fallback component during tenant determination
11209
11812
  if (isLoading) {
11210
11813
  return fallback;
@@ -11237,24 +11840,17 @@ function TenantProvider({ children, fallback, onAuthSuccess, onAuthFailure, curr
11237
11840
  * 3. Manages redirection based on mentor availability
11238
11841
  * 4. Integrates with tenant context for access control
11239
11842
  */
11240
- function MentorProvider({ children, fallback, onAuthSuccess, onAuthFailure, redirectToAuthSpa, redirectToMentor, onLoadMentorsPermissions, redirectToNoMentorsPage, redirectToCreateMentor, username, isAdmin, mainTenantKey, requestedMentorId, handleMentorNotFound, forceDetermineMentor = false, }) {
11843
+ function MentorProvider({ children, fallback, onAuthSuccess, onAuthFailure, redirectToAuthSpa, redirectToMentor, onLoadMentorsPermissions, redirectToNoMentorsPage, redirectToCreateMentor, username, isAdmin, mainTenantKey, requestedMentorId, handleMentorNotFound, forceDetermineMentor = false, onComplete, }) {
11241
11844
  const [isLoading, setIsLoading] = useState(true);
11242
11845
  const { userIsAccessingPublicRoute } = useAuthContext();
11243
- const { determineUserPath, tenantKey } = useTenantContext();
11846
+ const { determineUserPath, tenantKey, metadata } = useTenantContext();
11244
11847
  const isMainTenant = tenantKey === mainTenantKey;
11245
- console.log("MentorProvider initialized", {
11246
- username,
11247
- isAdmin,
11248
- tenantKey,
11249
- mainTenantKey,
11250
- isMainTenant,
11251
- requestedMentorId,
11252
- determineUserPath,
11253
- });
11848
+ console.log("MentorProvider initialized", username, isAdmin, tenantKey, mainTenantKey, isMainTenant, requestedMentorId, determineUserPath);
11254
11849
  const [fetchMentors] = useLazyGetMentorsQuery();
11255
11850
  const [fetchSeedMentors] = useLazySeedMentorsQuery();
11256
11851
  const [getMentorPublicSettings] = useLazyGetMentorPublicSettingsQuery();
11257
11852
  const [getRbacPermissions] = useGetRbacPermissionsMutation();
11853
+ const [getRecentlyAccessedMentors] = useLazyGetRecentlyAccessedMentorsQuery();
11258
11854
  const QUERY_LIMIT = 10;
11259
11855
  const loadMentorsPermissions = async (mentorDbId) => {
11260
11856
  try {
@@ -11271,6 +11867,33 @@ function MentorProvider({ children, fallback, onAuthSuccess, onAuthFailure, redi
11271
11867
  }
11272
11868
  catch (_a) { }
11273
11869
  };
11870
+ /**
11871
+ * Gets the mentor database ID from public settings if not available on the mentor object
11872
+ */
11873
+ const getMentorDbId = async (mentor) => {
11874
+ if (mentor === null || mentor === void 0 ? void 0 : mentor.id) {
11875
+ return mentor.id;
11876
+ }
11877
+ if (mentor === null || mentor === void 0 ? void 0 : mentor.unique_id) {
11878
+ try {
11879
+ const response = await getMentorPublicSettings({
11880
+ // @ts-ignore
11881
+ mentor: mentor.unique_id,
11882
+ org: tenantKey,
11883
+ // @ts-ignore
11884
+ userId: username,
11885
+ }).unwrap();
11886
+ return response === null || response === void 0 ? void 0 : response.mentor_id;
11887
+ }
11888
+ catch (error) {
11889
+ console.log("failed to fetch mentor ID from public settings", {
11890
+ error: error instanceof Error ? error.message : String(error),
11891
+ mentorUniqueId: mentor.unique_id,
11892
+ });
11893
+ }
11894
+ }
11895
+ return undefined;
11896
+ };
11274
11897
  /**
11275
11898
  * Determines which mentor to redirect the user to by following this priority:
11276
11899
  * 1. Recently accessed mentors
@@ -11278,24 +11901,60 @@ function MentorProvider({ children, fallback, onAuthSuccess, onAuthFailure, redi
11278
11901
  * 3. Non-featured mentors
11279
11902
  * 4. Seeded mentors (for admin users)
11280
11903
  * 5. Creation flow or no mentors page
11904
+ *
11905
+ * Returns the mentor object if found, undefined otherwise
11281
11906
  */
11282
11907
  async function determineMentorToRedirectTo() {
11283
- var _a, _b, _c, _d, _e, _f, _g, _h, _j, _k, _l, _m, _o, _p, _q, _r, _s;
11284
- console.log("starting mentor determination process", {
11908
+ var _a, _b, _c, _d, _e, _f, _g, _h, _j, _k, _l, _m, _o;
11909
+ console.log("starting mentor determination process", JSON.stringify({
11285
11910
  tenantKey,
11286
11911
  username,
11287
11912
  isAdmin,
11288
11913
  isMainTenant,
11289
- });
11914
+ }));
11915
+ console.log("###################### metadata is ", metadata, typeof metadata);
11290
11916
  setIsLoading(true);
11291
11917
  try {
11292
11918
  // Get the user's recent mentors
11293
- console.log("fetching recent mentors", {
11919
+ console.log("fetching recent mentors", JSON.stringify({
11294
11920
  tenantKey,
11295
11921
  username,
11296
11922
  limit: QUERY_LIMIT,
11297
11923
  orderBy: "recently_accessed_at",
11924
+ }));
11925
+ if (typeof metadata === "object" &&
11926
+ metadata.skills_embedded_mentor_name) {
11927
+ const defaultMentor = JSON.parse(metadata.skills_embedded_mentor_name);
11928
+ if (defaultMentor === null || defaultMentor === void 0 ? void 0 : defaultMentor.unique_id) {
11929
+ return defaultMentor;
11930
+ }
11931
+ }
11932
+ // Check for recently accessed mentors (second choice)
11933
+ console.log("checking recently accessed mentors", JSON.stringify({
11934
+ tenantKey,
11935
+ username,
11936
+ }));
11937
+ const recentlyAccessedResult = await getRecentlyAccessedMentors({
11938
+ org: tenantKey,
11939
+ // @ts-ignore
11940
+ userId: username,
11298
11941
  });
11942
+ // @ts-ignore
11943
+ const recentlyAccessedMentors = recentlyAccessedResult.data;
11944
+ const starredMentors = recentlyAccessedMentors === null || recentlyAccessedMentors === void 0 ? void 0 : recentlyAccessedMentors.starred_mentors;
11945
+ let recentMentors = recentlyAccessedMentors === null || recentlyAccessedMentors === void 0 ? void 0 : recentlyAccessedMentors.recent_mentors;
11946
+ if (starredMentors.length > 0) {
11947
+ const starredMentor = starredMentors[0];
11948
+ if (starredMentor === null || starredMentor === void 0 ? void 0 : starredMentor.unique_id) {
11949
+ return starredMentor;
11950
+ }
11951
+ }
11952
+ if (recentMentors.length > 0) {
11953
+ const recentMentor = recentMentors[0];
11954
+ if (recentMentor === null || recentMentor === void 0 ? void 0 : recentMentor.unique_id) {
11955
+ return recentMentor;
11956
+ }
11957
+ }
11299
11958
  const recentMentorsResult = await fetchMentors({
11300
11959
  // @ts-ignore
11301
11960
  org: tenantKey,
@@ -11303,26 +11962,19 @@ function MentorProvider({ children, fallback, onAuthSuccess, onAuthFailure, redi
11303
11962
  limit: QUERY_LIMIT,
11304
11963
  orderBy: "recently_accessed_at",
11305
11964
  });
11306
- const recentMentors = ((_a = recentMentorsResult.data) === null || _a === void 0 ? void 0 : _a.results) || [];
11307
- console.log("recent mentors fetched", {
11965
+ recentMentors = ((_a = recentMentorsResult.data) === null || _a === void 0 ? void 0 : _a.results) || [];
11966
+ console.log("recent mentors fetched", JSON.stringify({
11308
11967
  count: recentMentors.length,
11309
11968
  mentorIds: recentMentors.map((m) => m === null || m === void 0 ? void 0 : m.unique_id),
11310
- });
11969
+ }));
11311
11970
  // Check if we found recent mentors for the tenant
11312
11971
  if (recentMentors.length > 0) {
11313
- const selectedMentorId = ((_b = recentMentors[0]) === null || _b === void 0 ? void 0 : _b.unique_id) || "";
11314
- const selectedMentorDbId = ((_c = recentMentors[0]) === null || _c === void 0 ? void 0 : _c.id) || "";
11315
- console.log("redirecting to recent mentor", {
11316
- selectedMentorId,
11317
- mentorName: (_d = recentMentors[0]) === null || _d === void 0 ? void 0 : _d.name,
11972
+ console.log("found recent mentor", JSON.stringify({
11973
+ selectedMentorId: (_b = recentMentors[0]) === null || _b === void 0 ? void 0 : _b.unique_id,
11974
+ mentorName: (_c = recentMentors[0]) === null || _c === void 0 ? void 0 : _c.name,
11318
11975
  tenantKey,
11319
- });
11320
- const rbacPermissions = await loadMentorsPermissions(selectedMentorDbId);
11321
- // Select the most recent mentor as current mentor
11322
- onLoadMentorsPermissions === null || onLoadMentorsPermissions === void 0 ? void 0 : onLoadMentorsPermissions(rbacPermissions);
11323
- redirectToMentor(tenantKey, selectedMentorId);
11324
- onAuthSuccess === null || onAuthSuccess === void 0 ? void 0 : onAuthSuccess();
11325
- return;
11976
+ }));
11977
+ return recentMentors[0];
11326
11978
  }
11327
11979
  // If no recent mentors, get featured mentors
11328
11980
  console.log("no recent mentors found, fetching featured mentors", {
@@ -11336,7 +11988,7 @@ function MentorProvider({ children, fallback, onAuthSuccess, onAuthFailure, redi
11336
11988
  limit: QUERY_LIMIT,
11337
11989
  orderBy: "recently_accessed_at",
11338
11990
  });
11339
- const featuredMentors = ((_e = featuredMentorsResult.data) === null || _e === void 0 ? void 0 : _e.results) || [];
11991
+ const featuredMentors = ((_d = featuredMentorsResult.data) === null || _d === void 0 ? void 0 : _d.results) || [];
11340
11992
  console.log("featured mentors fetched", {
11341
11993
  count: featuredMentors.length,
11342
11994
  mentorIds: featuredMentors.map((m) => m === null || m === void 0 ? void 0 : m.unique_id),
@@ -11356,16 +12008,11 @@ function MentorProvider({ children, fallback, onAuthSuccess, onAuthFailure, redi
11356
12008
  const defaultIblMentor = featuredMentors.find((mentor) => { var _a; return ((_a = mentor === null || mentor === void 0 ? void 0 : mentor.metadata) === null || _a === void 0 ? void 0 : _a.default) === true; });
11357
12009
  // Check if found default featured mentor
11358
12010
  if (defaultIblMentor) {
11359
- console.log("redirecting to default IBL mentor", {
12011
+ console.log("found default IBL mentor", {
11360
12012
  mentorId: defaultIblMentor === null || defaultIblMentor === void 0 ? void 0 : defaultIblMentor.unique_id,
11361
12013
  mentorName: defaultIblMentor === null || defaultIblMentor === void 0 ? void 0 : defaultIblMentor.name,
11362
12014
  });
11363
- const defaultIblMentorDbId = (defaultIblMentor === null || defaultIblMentor === void 0 ? void 0 : defaultIblMentor.id) || "";
11364
- const rbacPermissions = await loadMentorsPermissions(defaultIblMentorDbId);
11365
- onLoadMentorsPermissions === null || onLoadMentorsPermissions === void 0 ? void 0 : onLoadMentorsPermissions(rbacPermissions);
11366
- redirectToMentor === null || redirectToMentor === void 0 ? void 0 : redirectToMentor(tenantKey, (defaultIblMentor === null || defaultIblMentor === void 0 ? void 0 : defaultIblMentor.unique_id) || "");
11367
- onAuthSuccess === null || onAuthSuccess === void 0 ? void 0 : onAuthSuccess();
11368
- return;
12015
+ return defaultIblMentor;
11369
12016
  }
11370
12017
  }
11371
12018
  else {
@@ -11376,30 +12023,19 @@ function MentorProvider({ children, fallback, onAuthSuccess, onAuthFailure, redi
11376
12023
  // Check if there's a default featured mentor
11377
12024
  const defaultFeatureMentor = featuredMentors.find((mentor) => { var _a; return ((_a = mentor === null || mentor === void 0 ? void 0 : mentor.metadata) === null || _a === void 0 ? void 0 : _a.default) === true; });
11378
12025
  if (defaultFeatureMentor) {
11379
- console.log("redirecting to default featured mentor", {
12026
+ console.log("found default featured mentor", {
11380
12027
  mentorId: defaultFeatureMentor === null || defaultFeatureMentor === void 0 ? void 0 : defaultFeatureMentor.unique_id,
11381
12028
  mentorName: defaultFeatureMentor === null || defaultFeatureMentor === void 0 ? void 0 : defaultFeatureMentor.name,
11382
12029
  });
11383
- const defaultFeatureMentorDbId = (defaultFeatureMentor === null || defaultFeatureMentor === void 0 ? void 0 : defaultFeatureMentor.id) || "";
11384
- const rbacPermissions = await loadMentorsPermissions(defaultFeatureMentorDbId);
11385
- onLoadMentorsPermissions === null || onLoadMentorsPermissions === void 0 ? void 0 : onLoadMentorsPermissions(rbacPermissions);
11386
- redirectToMentor(tenantKey, (defaultFeatureMentor === null || defaultFeatureMentor === void 0 ? void 0 : defaultFeatureMentor.unique_id) || "");
11387
- onAuthSuccess === null || onAuthSuccess === void 0 ? void 0 : onAuthSuccess();
11388
- return;
12030
+ return defaultFeatureMentor;
11389
12031
  }
11390
12032
  }
11391
12033
  // If no default mentor, select the first featured mentor
11392
- const firstFeaturedMentorId = ((_f = featuredMentors[0]) === null || _f === void 0 ? void 0 : _f.unique_id) || "";
11393
- console.log("redirecting to first featured mentor", {
11394
- mentorId: firstFeaturedMentorId,
11395
- mentorName: (_g = featuredMentors[0]) === null || _g === void 0 ? void 0 : _g.name,
12034
+ console.log("found first featured mentor", {
12035
+ mentorId: (_e = featuredMentors[0]) === null || _e === void 0 ? void 0 : _e.unique_id,
12036
+ mentorName: (_f = featuredMentors[0]) === null || _f === void 0 ? void 0 : _f.name,
11396
12037
  });
11397
- const firstFeaturedMentorDbId = ((_h = featuredMentors[0]) === null || _h === void 0 ? void 0 : _h.id) || "";
11398
- const rbacPermissions = await loadMentorsPermissions(firstFeaturedMentorDbId);
11399
- onLoadMentorsPermissions === null || onLoadMentorsPermissions === void 0 ? void 0 : onLoadMentorsPermissions(rbacPermissions);
11400
- redirectToMentor(tenantKey, firstFeaturedMentorId);
11401
- onAuthSuccess === null || onAuthSuccess === void 0 ? void 0 : onAuthSuccess();
11402
- return;
12038
+ return featuredMentors[0];
11403
12039
  }
11404
12040
  // If no featured mentors, get non-featured mentors
11405
12041
  console.log("no featured mentors found, fetching non-featured mentors", {
@@ -11413,24 +12049,18 @@ function MentorProvider({ children, fallback, onAuthSuccess, onAuthFailure, redi
11413
12049
  limit: QUERY_LIMIT,
11414
12050
  orderBy: "recently_accessed_at",
11415
12051
  });
11416
- const nonFeaturedMentors = ((_j = nonFeaturedMentorsResult.data) === null || _j === void 0 ? void 0 : _j.results) || [];
12052
+ const nonFeaturedMentors = ((_g = nonFeaturedMentorsResult.data) === null || _g === void 0 ? void 0 : _g.results) || [];
11417
12053
  console.log("non-featured mentors fetched", {
11418
12054
  count: nonFeaturedMentors.length,
11419
12055
  mentorIds: nonFeaturedMentors.map((m) => m === null || m === void 0 ? void 0 : m.unique_id),
11420
12056
  });
11421
12057
  // Check if we found non-featured mentors
11422
12058
  if (nonFeaturedMentors.length > 0) {
11423
- const firstNonFeaturedMentorId = ((_k = nonFeaturedMentors[0]) === null || _k === void 0 ? void 0 : _k.unique_id) || "";
11424
- console.log("redirecting to first non-featured mentor", {
11425
- mentorId: firstNonFeaturedMentorId,
11426
- mentorName: (_l = nonFeaturedMentors[0]) === null || _l === void 0 ? void 0 : _l.name,
12059
+ console.log("found first non-featured mentor", {
12060
+ mentorId: (_h = nonFeaturedMentors[0]) === null || _h === void 0 ? void 0 : _h.unique_id,
12061
+ mentorName: (_j = nonFeaturedMentors[0]) === null || _j === void 0 ? void 0 : _j.name,
11427
12062
  });
11428
- const firstNonFeaturedMentorDbId = ((_m = nonFeaturedMentors[0]) === null || _m === void 0 ? void 0 : _m.id) || "";
11429
- const rbacPermissions = await loadMentorsPermissions(firstNonFeaturedMentorDbId);
11430
- onLoadMentorsPermissions === null || onLoadMentorsPermissions === void 0 ? void 0 : onLoadMentorsPermissions(rbacPermissions);
11431
- redirectToMentor(tenantKey, firstNonFeaturedMentorId);
11432
- onAuthSuccess === null || onAuthSuccess === void 0 ? void 0 : onAuthSuccess();
11433
- return;
12063
+ return nonFeaturedMentors[0];
11434
12064
  }
11435
12065
  // If no mentors found, check if user is admin
11436
12066
  console.log("no mentors found, checking admin status", {
@@ -11450,7 +12080,7 @@ function MentorProvider({ children, fallback, onAuthSuccess, onAuthFailure, redi
11450
12080
  // @ts-ignore
11451
12081
  userId: username,
11452
12082
  });
11453
- const seededMentorsDetails = (_o = seedMentorsResult.data) === null || _o === void 0 ? void 0 : _o.detail;
12083
+ const seededMentorsDetails = (_k = seedMentorsResult.data) === null || _k === void 0 ? void 0 : _k.detail;
11454
12084
  console.log("mentor seeding completed", {
11455
12085
  success: !!seededMentorsDetails,
11456
12086
  details: seededMentorsDetails,
@@ -11465,29 +12095,23 @@ function MentorProvider({ children, fallback, onAuthSuccess, onAuthFailure, redi
11465
12095
  username,
11466
12096
  limit: QUERY_LIMIT,
11467
12097
  });
11468
- const featuredMentorsAfterSeed = ((_p = featuredMentorsAfterSeedResult.data) === null || _p === void 0 ? void 0 : _p.results) || [];
12098
+ const featuredMentorsAfterSeed = ((_l = featuredMentorsAfterSeedResult.data) === null || _l === void 0 ? void 0 : _l.results) || [];
11469
12099
  console.log("featured mentors after seeding", {
11470
12100
  count: featuredMentorsAfterSeed.length,
11471
12101
  mentorIds: featuredMentorsAfterSeed.map((m) => m === null || m === void 0 ? void 0 : m.unique_id),
11472
12102
  });
11473
12103
  if (featuredMentorsAfterSeed.length > 0) {
11474
- const seededMentorId = ((_q = featuredMentorsAfterSeed[0]) === null || _q === void 0 ? void 0 : _q.unique_id) || "";
11475
- console.log("redirecting to seeded mentor", {
11476
- mentorId: seededMentorId,
11477
- mentorName: (_r = featuredMentorsAfterSeed[0]) === null || _r === void 0 ? void 0 : _r.name,
12104
+ console.log("found seeded mentor", {
12105
+ mentorId: (_m = featuredMentorsAfterSeed[0]) === null || _m === void 0 ? void 0 : _m.unique_id,
12106
+ mentorName: (_o = featuredMentorsAfterSeed[0]) === null || _o === void 0 ? void 0 : _o.name,
11478
12107
  });
11479
- const seededMentorDbId = ((_s = featuredMentorsAfterSeed[0]) === null || _s === void 0 ? void 0 : _s.id) || "";
11480
- const rbacPermissions = await loadMentorsPermissions(seededMentorDbId);
11481
- onLoadMentorsPermissions === null || onLoadMentorsPermissions === void 0 ? void 0 : onLoadMentorsPermissions(rbacPermissions);
11482
- redirectToMentor(tenantKey, seededMentorId);
11483
- onAuthSuccess === null || onAuthSuccess === void 0 ? void 0 : onAuthSuccess();
11484
- return;
12108
+ return featuredMentorsAfterSeed[0];
11485
12109
  }
11486
12110
  else {
11487
12111
  console.log("no seeded mentors found, redirecting to create mentor");
11488
12112
  redirectToCreateMentor();
11489
12113
  onAuthSuccess === null || onAuthSuccess === void 0 ? void 0 : onAuthSuccess();
11490
- return;
12114
+ return undefined;
11491
12115
  }
11492
12116
  }
11493
12117
  else {
@@ -11495,7 +12119,7 @@ function MentorProvider({ children, fallback, onAuthSuccess, onAuthFailure, redi
11495
12119
  // Prompt the user to create a mentor
11496
12120
  redirectToCreateMentor();
11497
12121
  onAuthSuccess === null || onAuthSuccess === void 0 ? void 0 : onAuthSuccess();
11498
- return;
12122
+ return undefined;
11499
12123
  }
11500
12124
  }
11501
12125
  else {
@@ -11506,7 +12130,7 @@ function MentorProvider({ children, fallback, onAuthSuccess, onAuthFailure, redi
11506
12130
  // Redirect to no mentors page for non-admin users
11507
12131
  redirectToNoMentorsPage();
11508
12132
  onAuthSuccess === null || onAuthSuccess === void 0 ? void 0 : onAuthSuccess();
11509
- return;
12133
+ return undefined;
11510
12134
  }
11511
12135
  }
11512
12136
  catch (error) {
@@ -11518,18 +12142,19 @@ function MentorProvider({ children, fallback, onAuthSuccess, onAuthFailure, redi
11518
12142
  isAdmin,
11519
12143
  });
11520
12144
  onAuthFailure === null || onAuthFailure === void 0 ? void 0 : onAuthFailure(`Unexpected error: ${errorMessage}`);
12145
+ console.log("[auth-redirect] Unexpected error in mentor provider", {
12146
+ error: errorMessage,
12147
+ });
11521
12148
  redirectToAuthSpa();
12149
+ return undefined;
11522
12150
  }
11523
12151
  finally {
11524
12152
  setIsLoading(false);
12153
+ onComplete === null || onComplete === void 0 ? void 0 : onComplete();
11525
12154
  }
11526
12155
  }
11527
12156
  async function mentorExistsInTenant(tenantKey, requestedMentorId) {
11528
- console.log("checking if mentor exists in tenant", {
11529
- tenantKey,
11530
- requestedMentorId,
11531
- username,
11532
- });
12157
+ console.log("checking if mentor exists in tenant", tenantKey, requestedMentorId, username);
11533
12158
  try {
11534
12159
  const response = await getMentorPublicSettings({
11535
12160
  // @ts-ignore
@@ -11558,13 +12183,10 @@ function MentorProvider({ children, fallback, onAuthSuccess, onAuthFailure, redi
11558
12183
  // Effect to handle mentor determination when tenant path is determined
11559
12184
  React__default.useEffect(() => {
11560
12185
  async function checkMentor() {
11561
- console.log("starting mentor check process", {
11562
- determineUserPath,
11563
- requestedMentorId,
11564
- tenantKey,
11565
- });
12186
+ console.log("starting mentor check process", determineUserPath, requestedMentorId, tenantKey);
11566
12187
  if (userIsAccessingPublicRoute && !requestedMentorId) {
11567
12188
  setIsLoading(false);
12189
+ onComplete === null || onComplete === void 0 ? void 0 : onComplete();
11568
12190
  return;
11569
12191
  }
11570
12192
  setIsLoading(true);
@@ -11572,50 +12194,83 @@ function MentorProvider({ children, fallback, onAuthSuccess, onAuthFailure, redi
11572
12194
  // then this mentor provider will redirect the user to the correct mentor.
11573
12195
  if (determineUserPath || forceDetermineMentor) {
11574
12196
  console.log("determine user path is true, starting mentor determination");
11575
- await determineMentorToRedirectTo();
12197
+ const mentor = await determineMentorToRedirectTo();
12198
+ if (mentor === null || mentor === void 0 ? void 0 : mentor.unique_id) {
12199
+ // Get mentor DB ID - use existing ID or fetch from public settings
12200
+ let mentorDbId = mentor === null || mentor === void 0 ? void 0 : mentor.id;
12201
+ if (!mentorDbId) {
12202
+ mentorDbId = await getMentorDbId(mentor);
12203
+ }
12204
+ // Load permissions if we have a mentor DB ID
12205
+ if (mentorDbId) {
12206
+ const rbacPermissions = await loadMentorsPermissions(mentorDbId);
12207
+ onLoadMentorsPermissions === null || onLoadMentorsPermissions === void 0 ? void 0 : onLoadMentorsPermissions(rbacPermissions);
12208
+ }
12209
+ // Redirect to the mentor
12210
+ redirectToMentor(tenantKey, mentor.unique_id);
12211
+ onAuthSuccess === null || onAuthSuccess === void 0 ? void 0 : onAuthSuccess();
12212
+ }
11576
12213
  return;
11577
12214
  }
11578
12215
  else if (requestedMentorId) {
11579
- console.log(" ", {
11580
- requestedMentorId,
11581
- });
11582
12216
  const [mentorExists, requestedMentorDbId] = await mentorExistsInTenant(tenantKey, requestedMentorId);
11583
12217
  // If the mentor does not exist in the tenant, redirect the user to the correct mentor
11584
12218
  if (!mentorExists) {
11585
- console.log("requested mentor not found in tenant", {
12219
+ console.log("requested mentor not found in tenant", JSON.stringify({
11586
12220
  requestedMentorId,
11587
12221
  tenantKey,
11588
12222
  hasCustomHandler: !!handleMentorNotFound,
11589
- });
12223
+ }));
11590
12224
  if (handleMentorNotFound) {
11591
12225
  console.log("calling custom mentor not found handler");
11592
12226
  await handleMentorNotFound();
11593
12227
  }
11594
12228
  else {
11595
12229
  console.log("using default mentor determination fallback");
11596
- await determineMentorToRedirectTo();
12230
+ const mentor = await determineMentorToRedirectTo();
12231
+ if (mentor === null || mentor === void 0 ? void 0 : mentor.unique_id) {
12232
+ // Get mentor DB ID - use existing ID or fetch from public settings
12233
+ let mentorDbId = mentor === null || mentor === void 0 ? void 0 : mentor.id;
12234
+ if (!mentorDbId) {
12235
+ mentorDbId = await getMentorDbId(mentor);
12236
+ }
12237
+ // Load permissions if we have a mentor DB ID
12238
+ if (mentorDbId) {
12239
+ const rbacPermissions = await loadMentorsPermissions(mentorDbId);
12240
+ onLoadMentorsPermissions === null || onLoadMentorsPermissions === void 0 ? void 0 : onLoadMentorsPermissions(rbacPermissions);
12241
+ }
12242
+ // Redirect to the mentor
12243
+ redirectToMentor(tenantKey, mentor.unique_id);
12244
+ onAuthSuccess === null || onAuthSuccess === void 0 ? void 0 : onAuthSuccess();
12245
+ }
11597
12246
  }
11598
12247
  return;
11599
12248
  }
11600
12249
  else {
11601
- console.log("requested mentor exists in tenant, proceeding", {
11602
- requestedMentorId,
11603
- });
12250
+ console.log("requested mentor exists in tenant, proceeding", requestedMentorId);
11604
12251
  if (requestedMentorDbId) {
11605
12252
  const rbacPermissions = await loadMentorsPermissions(requestedMentorDbId);
11606
12253
  onLoadMentorsPermissions === null || onLoadMentorsPermissions === void 0 ? void 0 : onLoadMentorsPermissions(rbacPermissions);
11607
12254
  }
11608
12255
  setIsLoading(false);
12256
+ onComplete === null || onComplete === void 0 ? void 0 : onComplete();
11609
12257
  }
11610
12258
  // If the user is navigating to a specific mentor, check if it exists in the tenant
11611
12259
  }
11612
12260
  else {
11613
12261
  console.log("no specific mentor requested, loading complete");
11614
12262
  setIsLoading(false);
12263
+ onComplete === null || onComplete === void 0 ? void 0 : onComplete();
11615
12264
  }
11616
12265
  }
11617
12266
  checkMentor();
11618
- }, []);
12267
+ }, [
12268
+ requestedMentorId,
12269
+ determineUserPath,
12270
+ forceDetermineMentor,
12271
+ userIsAccessingPublicRoute,
12272
+ tenantKey,
12273
+ ]);
11619
12274
  // Show fallback component during mentor determination
11620
12275
  if (isLoading) {
11621
12276
  console.log("mentor provider showing fallback component");
@@ -12072,7 +12727,7 @@ function formatProdErrorMessage(code) {
12072
12727
 
12073
12728
  const defaultSessionIds = Object.fromEntries(Object.keys(advancedTabsProperties).map((key) => [key, ""]));
12074
12729
  const defaultChatState = Object.fromEntries(Object.keys(advancedTabsProperties).map((key) => [key, []]));
12075
- const initialState = {
12730
+ const initialState$1 = {
12076
12731
  chats: defaultChatState,
12077
12732
  isTyping: false,
12078
12733
  streaming: false,
@@ -12100,7 +12755,7 @@ const initialState = {
12100
12755
  };
12101
12756
  const chatSlice = createSlice({
12102
12757
  name: "chatSliceShared",
12103
- initialState,
12758
+ initialState: initialState$1,
12104
12759
  reducers: {
12105
12760
  setChats: (state, action) => {
12106
12761
  state.chats = action.payload;
@@ -12204,6 +12859,25 @@ const chatSlice = createSlice({
12204
12859
  setShowingSharedChat: (state, action) => {
12205
12860
  state.showingSharedChat = action.payload;
12206
12861
  },
12862
+ updateFileUrlInMessage: (state, action) => {
12863
+ const { fileId, fileUrl } = action.payload;
12864
+ // Update all tabs' messages that have this file
12865
+ Object.keys(state.chats).forEach((tab) => {
12866
+ state.chats[tab] = state.chats[tab].map((message) => {
12867
+ if (message.fileAttachments && message.fileAttachments.length > 0) {
12868
+ const updatedAttachments = message.fileAttachments.map((attachment) => {
12869
+ // Match by fileId
12870
+ if (attachment.fileId === fileId) {
12871
+ return { ...attachment, uploadUrl: fileUrl };
12872
+ }
12873
+ return attachment;
12874
+ });
12875
+ return { ...message, fileAttachments: updatedAttachments };
12876
+ }
12877
+ return message;
12878
+ });
12879
+ });
12880
+ },
12207
12881
  },
12208
12882
  });
12209
12883
  const chatActions = chatSlice.actions;
@@ -12487,6 +13161,61 @@ function useTimeTrackerNative(config) {
12487
13161
  };
12488
13162
  }
12489
13163
 
13164
+ const initialState = {
13165
+ attachedFiles: [],
13166
+ };
13167
+ const filesSlice = createSlice({
13168
+ name: "files",
13169
+ initialState,
13170
+ reducers: {
13171
+ addFiles: (state, action) => {
13172
+ state.attachedFiles = [...state.attachedFiles, ...action.payload];
13173
+ },
13174
+ updateFileProgress: (state, action) => {
13175
+ state.attachedFiles = state.attachedFiles.map((file) => file.id === action.payload.id
13176
+ ? { ...file, uploadProgress: action.payload.progress }
13177
+ : file);
13178
+ },
13179
+ updateFileStatus: (state, action) => {
13180
+ state.attachedFiles = state.attachedFiles.map((file) => file.id === action.payload.id
13181
+ ? { ...file, uploadStatus: action.payload.status }
13182
+ : file);
13183
+ },
13184
+ updateFileUrl: (state, action) => {
13185
+ state.attachedFiles = state.attachedFiles.map((file) => file.id === action.payload.id
13186
+ ? { ...file, uploadUrl: action.payload.uploadUrl }
13187
+ : file);
13188
+ },
13189
+ updateFileMetadata: (state, action) => {
13190
+ state.attachedFiles = state.attachedFiles.map((file) => file.id === action.payload.id
13191
+ ? {
13192
+ ...file,
13193
+ fileKey: action.payload.fileKey,
13194
+ fileId: action.payload.fileId,
13195
+ }
13196
+ : file);
13197
+ },
13198
+ updateFileRetryCount: (state, action) => {
13199
+ state.attachedFiles = state.attachedFiles.map((file) => file.id === action.payload.id
13200
+ ? { ...file, retryCount: action.payload.retryCount }
13201
+ : file);
13202
+ },
13203
+ updateFileUrlFromWebSocket: (state, action) => {
13204
+ state.attachedFiles = state.attachedFiles.map((file) => file.fileId === action.payload.fileId
13205
+ ? { ...file, fileUrl: action.payload.fileUrl }
13206
+ : file);
13207
+ },
13208
+ removeFile: (state, action) => {
13209
+ state.attachedFiles = state.attachedFiles.filter((file) => file.id !== action.payload);
13210
+ },
13211
+ clearFiles: (state) => {
13212
+ state.attachedFiles = [];
13213
+ },
13214
+ },
13215
+ });
13216
+ const { addFiles, removeFile, clearFiles, updateFileProgress, updateFileStatus, updateFileUrl, updateFileMetadata, updateFileRetryCount, updateFileUrlFromWebSocket, } = filesSlice.actions;
13217
+ const filesReducer = filesSlice.reducer;
13218
+
12490
13219
  const useChat = ({ wsUrl, wsToken, flowConfig, sessionId, stopGenerationWsUrl, enableHaptics = false, hapticFeedback, store, errorHandler, onStatusChange, onStreamingChange, onStreamingMessageUpdate, WebSocketImpl = WebSocket, redirectToAuthSpa, sendMessageToParentWebsite, on402Error, }) => {
12491
13220
  const dispatch = useDispatch();
12492
13221
  const isWebSocketPaused = useRef(false);
@@ -12510,7 +13239,7 @@ const useChat = ({ wsUrl, wsToken, flowConfig, sessionId, stopGenerationWsUrl, e
12510
13239
  await hapticFeedback.impactAsync("medium");
12511
13240
  }
12512
13241
  catch (error) {
12513
- console.warn("Haptic feedback failed:", error);
13242
+ errorHandler === null || errorHandler === void 0 ? void 0 : errorHandler("Haptic feedback failed", error);
12514
13243
  }
12515
13244
  }
12516
13245
  }, [enableHaptics, hapticFeedback]);
@@ -12522,8 +13251,8 @@ const useChat = ({ wsUrl, wsToken, flowConfig, sessionId, stopGenerationWsUrl, e
12522
13251
  }
12523
13252
  if (!wsToken) {
12524
13253
  if (!userIsAccessingPublicRoute) {
12525
- console.error("Token is missing for non-anonymous user");
12526
- redirectToAuthSpa();
13254
+ console.log("[auth-redirect] WebSocket token is missing for non-anonymous user");
13255
+ redirectToAuthSpa(undefined, undefined, true);
12527
13256
  return;
12528
13257
  }
12529
13258
  }
@@ -12557,6 +13286,7 @@ const useChat = ({ wsUrl, wsToken, flowConfig, sessionId, stopGenerationWsUrl, e
12557
13286
  onStreamingChange === null || onStreamingChange === void 0 ? void 0 : onStreamingChange(false);
12558
13287
  });
12559
13288
  socket.addEventListener("message", (event) => {
13289
+ var _a, _b, _c;
12560
13290
  if (isWebSocketPaused.current)
12561
13291
  return;
12562
13292
  try {
@@ -12578,6 +13308,16 @@ const useChat = ({ wsUrl, wsToken, flowConfig, sessionId, stopGenerationWsUrl, e
12578
13308
  onStreamingChange(!!messageData.isTyping);
12579
13309
  return;
12580
13310
  }
13311
+ // Handle file processing success
13312
+ if (messageData.type === "file_processing_success") {
13313
+ console.log("🟣 File processing success:", messageData);
13314
+ dispatch(chatActions.updateFileUrlInMessage({
13315
+ fileId: messageData.file_id,
13316
+ fileName: messageData.file_name,
13317
+ fileUrl: messageData.file_url,
13318
+ }));
13319
+ return;
13320
+ }
12581
13321
  // Handle start of new streaming session
12582
13322
  if (messageData.generation_id &&
12583
13323
  !messageData.data &&
@@ -12596,14 +13336,14 @@ const useChat = ({ wsUrl, wsToken, flowConfig, sessionId, stopGenerationWsUrl, e
12596
13336
  if (messageData.data !== undefined || messageData.eos !== undefined) {
12597
13337
  const messageText = messageData.data || "";
12598
13338
  // If we have content to add
12599
- if (messageText) {
13339
+ if (messageText && currentStreamingMessage.current) {
12600
13340
  currentStreamingMessage.current = {
12601
13341
  ...currentStreamingMessage.current,
12602
13342
  content: currentStreamingMessage.current.content + messageText,
12603
13343
  };
12604
13344
  onStreamingMessageUpdate === null || onStreamingMessageUpdate === void 0 ? void 0 : onStreamingMessageUpdate(currentStreamingMessage.current);
12605
13345
  // Update or add message in Redux store
12606
- if (currentStreamingMessage.current.id) {
13346
+ if ((_a = currentStreamingMessage.current) === null || _a === void 0 ? void 0 : _a.id) {
12607
13347
  dispatch(chatActions.appendMessageToActiveTab({
12608
13348
  id: currentStreamingMessage.current.id,
12609
13349
  content: currentStreamingMessage.current.content,
@@ -12613,8 +13353,8 @@ const useChat = ({ wsUrl, wsToken, flowConfig, sessionId, stopGenerationWsUrl, e
12613
13353
  // Handle end of stream
12614
13354
  if (messageData.eos) {
12615
13355
  // Final update to Redux store with complete message
12616
- if (currentStreamingMessage.current.id &&
12617
- currentStreamingMessage.current.content) {
13356
+ if (((_b = currentStreamingMessage.current) === null || _b === void 0 ? void 0 : _b.id) &&
13357
+ ((_c = currentStreamingMessage.current) === null || _c === void 0 ? void 0 : _c.content)) {
12618
13358
  dispatch(chatActions.appendMessageToActiveTab({
12619
13359
  id: currentStreamingMessage.current.id,
12620
13360
  content: currentStreamingMessage.current.content,
@@ -12629,13 +13369,13 @@ const useChat = ({ wsUrl, wsToken, flowConfig, sessionId, stopGenerationWsUrl, e
12629
13369
  }
12630
13370
  }
12631
13371
  catch (error) {
12632
- console.error("Error processing message:", error);
13372
+ errorHandler === null || errorHandler === void 0 ? void 0 : errorHandler("Error processing message", error);
12633
13373
  onStreamingChange === null || onStreamingChange === void 0 ? void 0 : onStreamingChange(false);
12634
13374
  onStatusChange("error");
12635
13375
  }
12636
13376
  });
12637
13377
  socket.addEventListener("error", (error) => {
12638
- console.error("WebSocket error:", error);
13378
+ errorHandler === null || errorHandler === void 0 ? void 0 : errorHandler("WebSocket error", error);
12639
13379
  onStreamingChange === null || onStreamingChange === void 0 ? void 0 : onStreamingChange(false);
12640
13380
  onStatusChange("error");
12641
13381
  });
@@ -12673,19 +13413,31 @@ const useChat = ({ wsUrl, wsToken, flowConfig, sessionId, stopGenerationWsUrl, e
12673
13413
  };
12674
13414
  };
12675
13415
  const sendMessage = useCallback(async (tab, text, options) => {
12676
- var _a;
13416
+ var _a, _b;
12677
13417
  dispatch(chatActions.setShowingSharedChat(false));
12678
- if (!text.trim())
13418
+ // Allow sending if there's text OR file references
13419
+ if (!text.trim() &&
13420
+ (!(options === null || options === void 0 ? void 0 : options.fileReferences) || options.fileReferences.length === 0)) {
12679
13421
  return;
13422
+ }
12680
13423
  onStatusChange("pending");
12681
13424
  isWebSocketPaused.current = false;
12682
13425
  await triggerHapticFeedback();
13426
+ // Create file attachments array from file references if present
13427
+ const fileAttachments = (_a = options === null || options === void 0 ? void 0 : options.fileReferences) === null || _a === void 0 ? void 0 : _a.map((ref) => ({
13428
+ fileName: ref.file_name,
13429
+ fileType: ref.content_type,
13430
+ fileSize: ref.file_size,
13431
+ uploadUrl: ref.upload_url, // Include URL for display
13432
+ fileId: ref.file_id, // Include fileId for matching WebSocket updates
13433
+ }));
12683
13434
  const userMessage = {
12684
13435
  id: `user-${Date.now()}`,
12685
13436
  role: "user",
12686
13437
  content: text,
12687
13438
  timestamp: new Date().toISOString(),
12688
- visible: (_a = options === null || options === void 0 ? void 0 : options.visible) !== null && _a !== void 0 ? _a : true,
13439
+ visible: (_b = options === null || options === void 0 ? void 0 : options.visible) !== null && _b !== void 0 ? _b : true,
13440
+ fileAttachments,
12689
13441
  };
12690
13442
  // Notify parent to add user message
12691
13443
  // onAddUserMessage?.(tab, userMessage);
@@ -12697,8 +13449,14 @@ const useChat = ({ wsUrl, wsToken, flowConfig, sessionId, stopGenerationWsUrl, e
12697
13449
  flow: flowConfig,
12698
13450
  session_id: sessionId,
12699
13451
  token: wsToken,
12700
- prompt: text,
13452
+ prompt: text || "", // Allow empty prompt when sending files
12701
13453
  };
13454
+ if ((options === null || options === void 0 ? void 0 : options.fileReferences) && options.fileReferences.length > 0) {
13455
+ messageData = {
13456
+ ...messageData,
13457
+ file_references: options.fileReferences,
13458
+ };
13459
+ }
12702
13460
  if (iframeContext.pageContent) {
12703
13461
  messageData = {
12704
13462
  ...messageData,
@@ -12768,8 +13526,12 @@ const useChat = ({ wsUrl, wsToken, flowConfig, sessionId, stopGenerationWsUrl, e
12768
13526
  }
12769
13527
  };
12770
13528
  const _initiateServerStopGeneration = () => {
12771
- var _a;
12772
- (_a = stopGenerationSocket === null || stopGenerationSocket === void 0 ? void 0 : stopGenerationSocket.current) === null || _a === void 0 ? void 0 : _a.send(JSON.stringify({
13529
+ var _a, _b;
13530
+ if (!((_a = currentStreamingMessage.current) === null || _a === void 0 ? void 0 : _a.id)) {
13531
+ console.warn("Cannot stop generation: no active generation ID");
13532
+ return;
13533
+ }
13534
+ (_b = stopGenerationSocket === null || stopGenerationSocket === void 0 ? void 0 : stopGenerationSocket.current) === null || _b === void 0 ? void 0 : _b.send(JSON.stringify({
12773
13535
  generation_id: currentStreamingMessage.current.id,
12774
13536
  name: flowConfig.name,
12775
13537
  tenant: flowConfig.tenant,
@@ -12829,7 +13591,7 @@ const useChat = ({ wsUrl, wsToken, flowConfig, sessionId, stopGenerationWsUrl, e
12829
13591
  };
12830
13592
  };
12831
13593
 
12832
- function useMentorSettings({ mentorId, tenantKey, username }) {
13594
+ function useMentorSettings({ mentorId, tenantKey, username, }) {
12833
13595
  var _a, _b, _c, _d;
12834
13596
  const isLoggedIn = username !== ANONYMOUS_USERNAME;
12835
13597
  const { data: mentorSettings } = useGetMentorSettingsQuery({
@@ -12865,6 +13627,9 @@ function useMentorSettings({ mentorId, tenantKey, username }) {
12865
13627
  mentorUniqueId: isLoggedIn
12866
13628
  ? mentorSettings === null || mentorSettings === void 0 ? void 0 : mentorSettings.mentor_unique_id
12867
13629
  : mentorPublicSettings === null || mentorPublicSettings === void 0 ? void 0 : mentorPublicSettings.mentor_unique_id,
13630
+ mentorVisibility: isLoggedIn
13631
+ ? mentorSettings === null || mentorSettings === void 0 ? void 0 : mentorSettings.mentor_visibility
13632
+ : mentorPublicSettings === null || mentorPublicSettings === void 0 ? void 0 : mentorPublicSettings.mentor_visibility,
12868
13633
  mentorName: (_a = mentorSettings === null || mentorSettings === void 0 ? void 0 : mentorSettings.mentor) !== null && _a !== void 0 ? _a : mentorPublicSettings === null || mentorPublicSettings === void 0 ? void 0 : mentorPublicSettings.mentor,
12869
13634
  enableGuidedPrompts: isLoggedIn
12870
13635
  ? mentorSettings === null || mentorSettings === void 0 ? void 0 : mentorSettings.enable_guided_prompts
@@ -12883,8 +13648,8 @@ function useMentorSettings({ mentorId, tenantKey, username }) {
12883
13648
  };
12884
13649
  }
12885
13650
 
12886
- function useAdvancedChat({ tenantKey, mentorId, username = ANONYMOUS_USERNAME, token, wsUrl, stopGenerationWsUrl, redirectToAuthSpa, errorHandler, sendMessageToParentWebsite, isPreviewMode, mentorShareableToken, on402Error, }) {
12887
- var _a, _b, _c, _d;
13651
+ function useAdvancedChat({ tenantKey, mentorId, username = ANONYMOUS_USERNAME, token, wsUrl, stopGenerationWsUrl, redirectToAuthSpa, errorHandler, sendMessageToParentWebsite, isPreviewMode, mentorShareableToken, on402Error, cachedSessionId, onStartNewChat, }) {
13652
+ var _a, _b, _c, _d, _e;
12888
13653
  const dispatch = useDispatch();
12889
13654
  const [createSessionId, { isLoading: isLoadingSessionIds }] = useCreateSessionIdMutation();
12890
13655
  const chats = useSelector(selectChats);
@@ -12922,7 +13687,7 @@ function useAdvancedChat({ tenantKey, mentorId, username = ANONYMOUS_USERNAME, t
12922
13687
  username,
12923
13688
  pathway: mentorId,
12924
13689
  },
12925
- sessionId: sessionIds[activeTab],
13690
+ sessionId: (_a = cachedSessionId === null || cachedSessionId === void 0 ? void 0 : cachedSessionId[mentorId]) !== null && _a !== void 0 ? _a : sessionIds[activeTab],
12926
13691
  activeTab,
12927
13692
  wsToken: token,
12928
13693
  errorHandler,
@@ -12933,6 +13698,56 @@ function useAdvancedChat({ tenantKey, mentorId, username = ANONYMOUS_USERNAME, t
12933
13698
  onStatusChange,
12934
13699
  on402Error,
12935
13700
  });
13701
+ const [getSessionChats, { isError: isErrorGettingSessionChats }] = useLazyGetSessionIdQuery();
13702
+ useEffect(() => {
13703
+ const getChats = async () => {
13704
+ var _a, _b;
13705
+ try {
13706
+ const { data } = await getSessionChats({
13707
+ sessionId: (_a = cachedSessionId === null || cachedSessionId === void 0 ? void 0 : cachedSessionId[mentorId]) !== null && _a !== void 0 ? _a : "",
13708
+ org: tenantKey,
13709
+ share: true,
13710
+ });
13711
+ let previousChats = [];
13712
+ try {
13713
+ previousChats =
13714
+ ((_b = data === null || data === void 0 ? void 0 : data.results) === null || _b === void 0 ? void 0 : _b.map((result) => {
13715
+ return {
13716
+ ...result,
13717
+ role: result.type === "human" ? "user" : "assistant",
13718
+ visible: true,
13719
+ id: new Date().getTime(),
13720
+ content: typeof result.content === "object" &&
13721
+ result.content.length > 0
13722
+ ? result.content[0].text
13723
+ : result.content,
13724
+ };
13725
+ }).reverse()) || [];
13726
+ }
13727
+ catch (error) {
13728
+ console.error(JSON.stringify(error));
13729
+ }
13730
+ // Ensures that the first AI response due to a Proactive prompt
13731
+ // doesn't show up as part of the chats
13732
+ if ((data === null || data === void 0 ? void 0 : data.proactive_prompt) &&
13733
+ previousChats.length > 0 &&
13734
+ previousChats[0].type === "ai") {
13735
+ previousChats.splice(0, 1);
13736
+ }
13737
+ dispatch(chatActions.setNewMessages(previousChats));
13738
+ }
13739
+ catch (error) {
13740
+ console.error(JSON.stringify(error));
13741
+ }
13742
+ };
13743
+ if (cachedSessionId === null || cachedSessionId === void 0 ? void 0 : cachedSessionId[mentorId]) {
13744
+ dispatch(chatActions.updateSessionIds(cachedSessionId === null || cachedSessionId === void 0 ? void 0 : cachedSessionId[mentorId]));
13745
+ getChats();
13746
+ }
13747
+ }, [cachedSessionId]);
13748
+ useEffect(() => {
13749
+ }, [isErrorGettingSessionChats]);
13750
+ useEffect(() => { }, []);
12936
13751
  const startNewChat = React__default.useCallback(async () => {
12937
13752
  // Reset all chat state
12938
13753
  if (!showingSharedChat) {
@@ -12942,6 +13757,7 @@ function useAdvancedChat({ tenantKey, mentorId, username = ANONYMOUS_USERNAME, t
12942
13757
  dispatch(chatActions.setStreaming(false));
12943
13758
  dispatch(chatActions.resetCurrentStreamingMessage(undefined));
12944
13759
  dispatch(chatActions.setTools([]));
13760
+ dispatch(clearFiles(undefined));
12945
13761
  if (isPreviewMode) {
12946
13762
  return;
12947
13763
  }
@@ -12952,6 +13768,7 @@ function useAdvancedChat({ tenantKey, mentorId, username = ANONYMOUS_USERNAME, t
12952
13768
  // @ts-ignore
12953
13769
  requestBody["shareable_link_token"] = mentorShareableToken;
12954
13770
  }
13771
+ console.log("[startNewChat] requestBody", tenantKey, username, JSON.stringify(requestBody));
12955
13772
  const response = await createSessionId({
12956
13773
  org: tenantKey,
12957
13774
  // @ts-ignore
@@ -12959,10 +13776,15 @@ function useAdvancedChat({ tenantKey, mentorId, username = ANONYMOUS_USERNAME, t
12959
13776
  requestBody,
12960
13777
  }).unwrap();
12961
13778
  dispatch(chatActions.updateSessionIds(response.session_id));
12962
- // dispatch(chatActions.setShouldStartNewChat(false));
13779
+ onStartNewChat === null || onStartNewChat === void 0 ? void 0 : onStartNewChat(response.session_id);
12963
13780
  }
12964
13781
  catch (error) {
12965
- errorHandler === null || errorHandler === void 0 ? void 0 : errorHandler("Failed to start new chat");
13782
+ if (mentorSettings.mentorVisibility !==
13783
+ MentorVisibilityEnum.VIEWABLE_BY_ANYONE) {
13784
+ errorHandler === null || errorHandler === void 0 ? void 0 : errorHandler(`Failed to start new chat: ${JSON.stringify(error)}`);
13785
+ console.log("[auth-redirect] Failed to start new chat", JSON.stringify({ error }));
13786
+ redirectToAuthSpa(undefined, undefined, true);
13787
+ }
12966
13788
  }
12967
13789
  }, [
12968
13790
  isPreviewMode,
@@ -12976,7 +13798,8 @@ function useAdvancedChat({ tenantKey, mentorId, username = ANONYMOUS_USERNAME, t
12976
13798
  ]);
12977
13799
  React__default.useEffect(() => {
12978
13800
  if (!showingSharedChat || mentorSettings.allowAnonymous) {
12979
- if (mentorSettings.allowAnonymous !== undefined) {
13801
+ if (mentorSettings.allowAnonymous !== undefined &&
13802
+ !(cachedSessionId === null || cachedSessionId === void 0 ? void 0 : cachedSessionId[mentorId])) {
12980
13803
  startNewChat();
12981
13804
  }
12982
13805
  }
@@ -13028,7 +13851,7 @@ function useAdvancedChat({ tenantKey, mentorId, username = ANONYMOUS_USERNAME, t
13028
13851
  }
13029
13852
  }
13030
13853
  catch (error) {
13031
- errorHandler === null || errorHandler === void 0 ? void 0 : errorHandler("Failed to start new chat");
13854
+ errorHandler === null || errorHandler === void 0 ? void 0 : errorHandler(`Failed to start new chat: ${error}`);
13032
13855
  return;
13033
13856
  }
13034
13857
  }
@@ -13048,9 +13871,9 @@ function useAdvancedChat({ tenantKey, mentorId, username = ANONYMOUS_USERNAME, t
13048
13871
  currentStreamingMessage,
13049
13872
  activeTab,
13050
13873
  uniqueMentorId: mentorId,
13051
- mentorName: (_a = mentorSettings === null || mentorSettings === void 0 ? void 0 : mentorSettings.mentorName) !== null && _a !== void 0 ? _a : "",
13052
- profileImage: (_b = mentorSettings === null || mentorSettings === void 0 ? void 0 : mentorSettings.profileImage) !== null && _b !== void 0 ? _b : "",
13053
- enabledGuidedPrompts: (_c = mentorSettings === null || mentorSettings === void 0 ? void 0 : mentorSettings.enableGuidedPrompts) !== null && _c !== void 0 ? _c : true,
13874
+ mentorName: (_b = mentorSettings === null || mentorSettings === void 0 ? void 0 : mentorSettings.mentorName) !== null && _b !== void 0 ? _b : "",
13875
+ profileImage: (_c = mentorSettings === null || mentorSettings === void 0 ? void 0 : mentorSettings.profileImage) !== null && _c !== void 0 ? _c : "",
13876
+ enabledGuidedPrompts: (_d = mentorSettings === null || mentorSettings === void 0 ? void 0 : mentorSettings.enableGuidedPrompts) !== null && _d !== void 0 ? _d : true,
13054
13877
  sendMessage,
13055
13878
  stopGenerating,
13056
13879
  setMessage,
@@ -13062,7 +13885,7 @@ function useAdvancedChat({ tenantKey, mentorId, username = ANONYMOUS_USERNAME, t
13062
13885
  isConnected,
13063
13886
  messageQueue,
13064
13887
  sessionIds,
13065
- enableSafetyDisclaimer: (_d = mentorSettings === null || mentorSettings === void 0 ? void 0 : mentorSettings.safetyDisclaimer) !== null && _d !== void 0 ? _d : false,
13888
+ enableSafetyDisclaimer: (_e = mentorSettings === null || mentorSettings === void 0 ? void 0 : mentorSettings.safetyDisclaimer) !== null && _e !== void 0 ? _e : false,
13066
13889
  resetConnection,
13067
13890
  };
13068
13891
  }
@@ -17918,5 +18741,123 @@ const tenantSchema = z.object({
17918
18741
  });
17919
18742
  const tenantKeySchema = z.string().min(1);
17920
18743
 
17921
- export { ALPHANUMERIC_32_REGEX, ANONYMOUS_USERNAME, AuthContext, AuthContextProvider, AuthProvider, LOCAL_STORAGE_KEYS, MAX_INITIAL_WEBSOCKET_CONNECTION_ATTEMPTS, MENTOR_CHAT_DOCUMENTS_EXTENSIONS, METADATAS, MentorProvider, SUBSCRIPTION_MESSAGES, SUBSCRIPTION_PACKAGES, SUBSCRIPTION_TRIGGERS, SUBSCRIPTION_V2_TRIGGERS, SubscriptionFlow, SubscriptionFlowV2, TOOLS, TenantContext, TenantContextProvider, TenantProvider, TimeTracker, addProtocolToUrl, advancedTabs, advancedTabsProperties, chatActions, chatSliceReducerShared, clearAuthCookies, defaultSessionIds, formatRelativeTime, getInitials, getTimeAgo, getUserName, isAlphaNumeric32, isJSON, loadMetadataConfig, selectActiveChatMessages, selectActiveTab, selectChats, selectCurrentStreamingMessage, selectDocumentFilter, selectIframeContext, selectIsError, selectIsPending, selectIsStopped, selectIsTyping, selectNumberOfActiveChatMessages, selectSessionId, selectSessionIds, selectShouldStartNewChat, selectShowingSharedChat, selectStatus, selectStreaming, selectToken, selectTokenEnabled, selectTools, syncAuthToCookies, tenantKeySchema, tenantSchema, translatePrompt, useAdvancedChat, useAuthContext, useAuthProvider, useChat, useDayJs, useExternalPricingPlan, useMentorSettings, useMentorTools, useProfileImageUpload, useSubscriptionHandler, useSubscriptionHandlerV2, useTenantContext, useTenantMetadata, useTimeTracker, useTimeTrackerNative, useUserProfileUpdate, userDataSchema };
18744
+ /**
18745
+ * Chat area size constants
18746
+ */
18747
+ const CHAT_AREA_SIZE = {
18748
+ DEFAULT: 672,
18749
+ MIN: 672,
18750
+ MAX: 1024,
18751
+ };
18752
+
18753
+ /**
18754
+ * Extract file information from File object
18755
+ */
18756
+ function getFileInfo(file) {
18757
+ const fileName = file.name;
18758
+ const contentType = file.type || "application/octet-stream";
18759
+ const fileSize = file.size;
18760
+ return {
18761
+ fileName,
18762
+ contentType,
18763
+ fileSize,
18764
+ };
18765
+ }
18766
+ /**
18767
+ * Request presigned S3 URL from backend
18768
+ * Note: This function should be called via the RTK Query mutation hook
18769
+ * This is a helper to show the data flow
18770
+ */
18771
+ async function requestPresignedUrl(sessionId, file, getUploadUrlFn, org, userId) {
18772
+ const { fileName, contentType, fileSize } = getFileInfo(file);
18773
+ return await getUploadUrlFn({
18774
+ org,
18775
+ userId,
18776
+ requestBody: {
18777
+ session_id: sessionId,
18778
+ file_name: fileName,
18779
+ content_type: contentType,
18780
+ file_size: fileSize,
18781
+ },
18782
+ });
18783
+ }
18784
+ /**
18785
+ * Upload file directly to S3 using presigned URL
18786
+ * Uses axios for cross-platform support (web + React Native)
18787
+ */
18788
+ async function uploadToS3(presignedUrl, file, contentType, onProgress) {
18789
+ await axios.put(presignedUrl, file, {
18790
+ headers: {
18791
+ "Content-Type": contentType,
18792
+ },
18793
+ onUploadProgress: (progressEvent) => {
18794
+ if (onProgress && progressEvent.total) {
18795
+ const progress = Math.round((progressEvent.loaded / progressEvent.total) * 100);
18796
+ onProgress(progress);
18797
+ }
18798
+ },
18799
+ });
18800
+ }
18801
+ /**
18802
+ * Complete file upload flow:
18803
+ * 1. Request presigned URL
18804
+ * 2. Upload to S3
18805
+ * 3. Return file reference
18806
+ */
18807
+ async function createFileReference(file, sessionId, getUploadUrlFn, org, userId, onProgress) {
18808
+ // Step 1: Get presigned URL
18809
+ const presignedResponse = await requestPresignedUrl(sessionId, file, getUploadUrlFn, org, userId);
18810
+ // Step 2: Upload to S3
18811
+ const { fileName, contentType, fileSize } = getFileInfo(file);
18812
+ await uploadToS3(presignedResponse.upload_url, file, contentType, onProgress);
18813
+ // Step 3: Return file reference
18814
+ return {
18815
+ file_id: presignedResponse.file_id,
18816
+ file_key: presignedResponse.file_key,
18817
+ file_name: fileName,
18818
+ content_type: contentType,
18819
+ file_size: fileSize,
18820
+ };
18821
+ }
18822
+ /**
18823
+ * Upload multiple files and return their references
18824
+ */
18825
+ async function createMultipleFileReferences(files, sessionId, getUploadUrlFn, org, userId, onFileProgress) {
18826
+ const fileReferences = [];
18827
+ for (let i = 0; i < files.length; i++) {
18828
+ const file = files[i];
18829
+ const onProgress = onFileProgress
18830
+ ? (progress) => onFileProgress(i, progress)
18831
+ : undefined;
18832
+ const fileReference = await createFileReference(file, sessionId, getUploadUrlFn, org, userId, onProgress);
18833
+ fileReferences.push(fileReference);
18834
+ }
18835
+ return fileReferences;
18836
+ }
18837
+ /**
18838
+ * Validate file before upload
18839
+ * Returns error message if invalid, null if valid
18840
+ */
18841
+ function validateFile(file, maxSizeBytes, allowedTypes) {
18842
+ var _a;
18843
+ // Check file size
18844
+ if (maxSizeBytes && file.size > maxSizeBytes) {
18845
+ const maxSizeMB = (maxSizeBytes / (1024 * 1024)).toFixed(2);
18846
+ const fileSizeMB = (file.size / (1024 * 1024)).toFixed(2);
18847
+ return `File size (${fileSizeMB}MB) exceeds maximum allowed size (${maxSizeMB}MB)`;
18848
+ }
18849
+ // Check file type
18850
+ if (allowedTypes && allowedTypes.length > 0) {
18851
+ const fileExtension = (_a = file.name.split(".").pop()) === null || _a === void 0 ? void 0 : _a.toLowerCase();
18852
+ const fileType = file.type.toLowerCase();
18853
+ const isTypeAllowed = allowedTypes.some((allowed) => fileType.includes(allowed.toLowerCase()) ||
18854
+ fileExtension === allowed.toLowerCase().replace(".", ""));
18855
+ if (!isTypeAllowed) {
18856
+ return `File type not allowed. Allowed types: ${allowedTypes.join(", ")}`;
18857
+ }
18858
+ }
18859
+ return null;
18860
+ }
18861
+
18862
+ export { ALPHANUMERIC_32_REGEX, ANONYMOUS_USERNAME, AuthContext, AuthContextProvider, AuthProvider, CHAT_AREA_SIZE, LOCAL_STORAGE_KEYS, MAX_INITIAL_WEBSOCKET_CONNECTION_ATTEMPTS, MENTOR_CHAT_DOCUMENTS_EXTENSIONS, METADATAS, MentorProvider, SUBSCRIPTION_MESSAGES, SUBSCRIPTION_PACKAGES, SUBSCRIPTION_TRIGGERS, SUBSCRIPTION_V2_TRIGGERS, SubscriptionFlow, SubscriptionFlowV2, TOOLS, TenantContext, TenantContextProvider, TenantProvider, TimeTracker, addFiles, addProtocolToUrl, advancedTabs, advancedTabsProperties, chatActions, chatSliceReducerShared, clearAuthCookies, clearCookies, clearCurrentTenantCookie, clearFiles, createFileReference, createMultipleFileReferences, defaultSessionIds, deleteCookie, deleteCookieOnAllDomains, filesReducer, filesSlice, formatRelativeTime, getAuthSpaJoinUrl, getDomainParts, getFileInfo, getInitials, getParentDomain, getPlatformKey, getTimeAgo, getUserName, handleLogout, isAlphaNumeric32, isInIframe, isJSON, isLoggedIn, loadMetadataConfig, redirectToAuthSpa, redirectToAuthSpaJoinTenant, removeFile, requestPresignedUrl, selectActiveChatMessages, selectActiveTab, selectChats, selectCurrentStreamingMessage, selectDocumentFilter, selectIframeContext, selectIsError, selectIsPending, selectIsStopped, selectIsTyping, selectNumberOfActiveChatMessages, selectSessionId, selectSessionIds, selectShouldStartNewChat, selectShowingSharedChat, selectStatus, selectStreaming, selectToken, selectTokenEnabled, selectTools, sendMessageToParentWebsite, setCookieForAuth, syncAuthToCookies, tenantKeySchema, tenantSchema, translatePrompt, updateFileMetadata, updateFileProgress, updateFileRetryCount, updateFileStatus, updateFileUrl, updateFileUrlFromWebSocket, uploadToS3, useAdvancedChat, useAuthContext, useAuthProvider, useChat, useDayJs, useExternalPricingPlan, useMentorSettings, useMentorTools, useProfileImageUpload, useSubscriptionHandler, useSubscriptionHandlerV2, useTenantContext, useTenantMetadata, useTimeTracker, useTimeTrackerNative, useUserProfileUpdate, userDataSchema, validateFile };
17922
18863
  //# sourceMappingURL=index.esm.js.map