@iblai/web-utils 0.2.1 → 1.0.0

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 (38) 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 +980 -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/index.d.ts +3 -0
  15. package/dist/index.d.ts +425 -66
  16. package/dist/index.esm.js +999 -109
  17. package/dist/index.esm.js.map +1 -1
  18. package/dist/index.js +1030 -107
  19. package/dist/index.js.map +1 -1
  20. package/dist/package.json +4 -2
  21. package/dist/web-utils/src/constants/chat.d.ts +8 -0
  22. package/dist/web-utils/src/features/files/filesSlice.d.ts +20 -0
  23. package/dist/web-utils/src/features/index.d.ts +1 -0
  24. package/dist/web-utils/src/hooks/chat/use-advanced-chat.d.ts +6 -4
  25. package/dist/web-utils/src/hooks/chat/use-chat-v2.d.ts +11 -1
  26. package/dist/web-utils/src/index.d.ts +2 -0
  27. package/dist/web-utils/src/index.web.d.ts +14 -12
  28. package/dist/web-utils/src/providers/auth-provider.d.ts +9 -1
  29. package/dist/web-utils/src/providers/tenant-provider.d.ts +2 -1
  30. package/dist/web-utils/src/services/__tests__/file-upload.test.d.ts +1 -0
  31. package/dist/web-utils/src/services/file-upload.d.ts +60 -0
  32. package/dist/web-utils/src/services/index.d.ts +1 -0
  33. package/dist/web-utils/src/types/file-upload.d.ts +62 -0
  34. package/dist/web-utils/src/types/index.d.ts +1 -0
  35. package/dist/web-utils/src/utils/auth.d.ts +180 -0
  36. package/dist/web-utils/src/utils/index.d.ts +1 -0
  37. package/dist/web-utils/tsconfig.tsbuildinfo +1 -1
  38. package/package.json +3 -3
package/dist/index.js CHANGED
@@ -3,6 +3,7 @@
3
3
  var React = require('react');
4
4
  var iblaiApi = require('@iblai/iblai-api');
5
5
  var jsxRuntime = require('react/jsx-runtime');
6
+ var axios = require('axios');
6
7
 
7
8
  function _interopNamespaceDefault(e) {
8
9
  var n = Object.create(null);
@@ -3400,7 +3401,7 @@ function updateMutationSubstateIfExists(state, id, update) {
3400
3401
  update(substate);
3401
3402
  }
3402
3403
  }
3403
- var initialState$1 = {};
3404
+ var initialState$2 = {};
3404
3405
  function buildSlice({
3405
3406
  reducerPath,
3406
3407
  queryThunk,
@@ -3476,7 +3477,7 @@ function buildSlice({
3476
3477
  }
3477
3478
  const querySlice = createSlice$1({
3478
3479
  name: `${reducerPath}/queries`,
3479
- initialState: initialState$1,
3480
+ initialState: initialState$2,
3480
3481
  reducers: {
3481
3482
  removeQueryResult: {
3482
3483
  reducer(draft, {
@@ -3610,7 +3611,7 @@ function buildSlice({
3610
3611
  });
3611
3612
  const mutationSlice = createSlice$1({
3612
3613
  name: `${reducerPath}/mutations`,
3613
- initialState: initialState$1,
3614
+ initialState: initialState$2,
3614
3615
  reducers: {
3615
3616
  removeMutationResult: {
3616
3617
  reducer(draft, {
@@ -3779,7 +3780,7 @@ function buildSlice({
3779
3780
  }
3780
3781
  const subscriptionSlice = createSlice$1({
3781
3782
  name: `${reducerPath}/subscriptions`,
3782
- initialState: initialState$1,
3783
+ initialState: initialState$2,
3783
3784
  reducers: {
3784
3785
  updateSubscriptionOptions(d, a) {
3785
3786
  },
@@ -3791,7 +3792,7 @@ function buildSlice({
3791
3792
  });
3792
3793
  const internalSubscriptionsSlice = createSlice$1({
3793
3794
  name: `${reducerPath}/internalSubscriptions`,
3794
- initialState: initialState$1,
3795
+ initialState: initialState$2,
3795
3796
  reducers: {
3796
3797
  subscriptionsUpdated: {
3797
3798
  reducer(state, action) {
@@ -6461,6 +6462,25 @@ createApi({
6461
6462
  }),
6462
6463
  });
6463
6464
 
6465
+ createApi({
6466
+ reducerPath: 'chatFilesApiSlice',
6467
+ baseQuery: iblFetchBaseQuery,
6468
+ endpoints: (builder) => ({
6469
+ /**
6470
+ * Get presigned S3 URL for file upload
6471
+ * POST /api/ai-mentor/orgs/{org}/users/{userId}/chat/files/upload-url/
6472
+ */
6473
+ getFileUploadUrl: builder.mutation({
6474
+ query: ({ org, userId, requestBody, }) => ({
6475
+ url: `/api/ai-mentor/orgs/${org}/users/${userId}/chat/files/upload-url/`,
6476
+ method: 'POST',
6477
+ body: requestBody,
6478
+ service: SERVICES.DM,
6479
+ }),
6480
+ }),
6481
+ }),
6482
+ });
6483
+
6464
6484
  createApi({
6465
6485
  reducerPath: 'llmsApiSlice',
6466
6486
  baseQuery: iblFakeBaseQuery,
@@ -6481,6 +6501,7 @@ const mentorApiSlice = createApi({
6481
6501
  'mentorPublicSettings',
6482
6502
  'shareableLinks',
6483
6503
  'publicMentors',
6504
+ 'moderationLogs',
6484
6505
  ],
6485
6506
  endpoints: (builder) => ({
6486
6507
  createMentor: builder.mutation({
@@ -6546,7 +6567,7 @@ const mentorApiSlice = createApi({
6546
6567
  }));
6547
6568
  }
6548
6569
  catch (error) {
6549
- console.error(error);
6570
+ console.error(JSON.stringify(error));
6550
6571
  }
6551
6572
  },
6552
6573
  }),
@@ -6602,9 +6623,17 @@ const mentorApiSlice = createApi({
6602
6623
  ...buildEndpointFromDmService(iblaiApi.AiMentorService.aiMentorOrgsUsersMentorsForkCreate),
6603
6624
  invalidatesTags: ['mentors'],
6604
6625
  }),
6626
+ getRecentlyAccessedMentors: builder.query({
6627
+ ...buildEndpointFromDmService(iblaiApi.AiMentorService.aiMentorOrgsUsersRecentlyAccessedMentorsList),
6628
+ providesTags: ['mentors'],
6629
+ }),
6630
+ getModerationLogs: builder.query({
6631
+ ...buildEndpointFromDmService(iblaiApi.AiMentorService.aiMentorOrgsUsersModerationLogsList),
6632
+ providesTags: ['moderationLogs'],
6633
+ }),
6605
6634
  }),
6606
6635
  });
6607
- const { useLazyGetMentorsQuery, useLazySeedMentorsQuery, useGetMentorSettingsQuery, useGetMentorPublicSettingsQuery, useLazyGetMentorPublicSettingsQuery, useLazyGetFreeUsageCountQuery} = mentorApiSlice;
6636
+ const { useLazyGetMentorsQuery, useLazySeedMentorsQuery, useGetMentorSettingsQuery, useGetMentorPublicSettingsQuery, useLazyGetMentorPublicSettingsQuery, useLazyGetFreeUsageCountQuery, useLazyGetRecentlyAccessedMentorsQuery} = mentorApiSlice;
6608
6637
 
6609
6638
  createApi({
6610
6639
  reducerPath: 'mentorCategoriesApiSlice',
@@ -7071,7 +7100,20 @@ const coreApiSlice = createApi({
7071
7100
  invalidatesTags: ['RbacGroups'],
7072
7101
  }),
7073
7102
  getRbacGroupDetails: builder.query({
7074
- ...buildEndpointFromDmService(iblaiApi.CoreService.coreRbacGroupsRetrieve),
7103
+ ...buildEndpointFromService(SERVICES.DM, async (args) => {
7104
+ const url = `${iblaiApi.OpenAPI.BASE}/api/core/rbac/groups/${args.id}/`;
7105
+ const response = await fetch(url, {
7106
+ method: 'GET',
7107
+ headers: iblaiApi.OpenAPI.HEADERS,
7108
+ });
7109
+ if (!response.ok) {
7110
+ const error = new Error('Failed to fetch RBAC group details');
7111
+ error.status = response.status;
7112
+ error.body = await response.text();
7113
+ throw error;
7114
+ }
7115
+ return response.json();
7116
+ }),
7075
7117
  providesTags: ['RbacGroups'],
7076
7118
  }),
7077
7119
  //RBAC POLICIES
@@ -7092,7 +7134,22 @@ const coreApiSlice = createApi({
7092
7134
  invalidatesTags: ['RbacPolicies'],
7093
7135
  }),
7094
7136
  getRbacPolicyDetails: builder.query({
7095
- ...buildEndpointFromDmService(iblaiApi.CoreService.coreRbacPoliciesRetrieve),
7137
+ ...buildEndpointFromService(SERVICES.DM, async (args) => {
7138
+ const queryParams = new URLSearchParams({ platform_key: args.platform_key });
7139
+ const queryString = queryParams.toString();
7140
+ const url = `${iblaiApi.OpenAPI.BASE}/api/core/rbac/policies/${args.id}/?${queryString}`;
7141
+ const response = await fetch(url, {
7142
+ method: 'GET',
7143
+ headers: iblaiApi.OpenAPI.HEADERS,
7144
+ });
7145
+ if (!response.ok) {
7146
+ const error = new Error('Failed to fetch RBAC policy details');
7147
+ error.status = response.status;
7148
+ error.body = await response.text();
7149
+ throw error;
7150
+ }
7151
+ return response.json();
7152
+ }),
7096
7153
  providesTags: ['RbacPolicies'],
7097
7154
  }),
7098
7155
  //RBAC ROLES
@@ -7117,14 +7174,36 @@ const coreApiSlice = createApi({
7117
7174
  invalidatesTags: ['RbacRoles'],
7118
7175
  }),
7119
7176
  getRbacRoleDetails: builder.query({
7120
- ...buildEndpointFromDmService(iblaiApi.CoreService.coreRbacRolesRetrieve),
7177
+ ...buildEndpointFromService(SERVICES.DM, async (args) => {
7178
+ const queryParams = new URLSearchParams({ platform_key: args.platform_key });
7179
+ const queryString = queryParams.toString();
7180
+ const url = `${iblaiApi.OpenAPI.BASE}/api/core/rbac/roles/${args.id}/?${queryString}`;
7181
+ const response = await fetch(url, {
7182
+ method: 'GET',
7183
+ headers: iblaiApi.OpenAPI.HEADERS,
7184
+ });
7185
+ if (!response.ok) {
7186
+ const error = new Error('Failed to fetch RBAC role details');
7187
+ error.status = response.status;
7188
+ error.body = await response.text();
7189
+ throw error;
7190
+ }
7191
+ return response.json();
7192
+ }),
7121
7193
  providesTags: ['RbacRoles'],
7122
7194
  }),
7195
+ getRbacMentorAccessList: builder.query({
7196
+ ...buildEndpointFromDmService(iblaiApi.CoreService.coreRbacMentorAccessList),
7197
+ }),
7198
+ updateRbacMentorAccess: builder.mutation({
7199
+ ...buildEndpointFromDmService(iblaiApi.CoreService.coreRbacMentorAccessCreate),
7200
+ }),
7123
7201
  }),
7124
7202
  });
7125
7203
  const { useGetRbacPermissionsMutation} = coreApiSlice;
7126
7204
 
7127
7205
  const CORE_CUSTOM_REDUCER_PATH = 'coreCustomApiSlice';
7206
+ const CORE_FAKE_CUSTOM_REDUCER_PATH = 'coreFakeCustomApiSlice';
7128
7207
  const PLATFORM_MEMBERSHIP_TAG = 'PlatformMembership';
7129
7208
  const CORE_CUSTOM_ENDPOINTS = {
7130
7209
  GET_PLATFORM_MEMBERSHIP: {
@@ -7158,7 +7237,13 @@ const CORE_CUSTOM_ENDPOINTS = {
7158
7237
  DELETE_PLATFORM_IMAGE_ASSET: {
7159
7238
  path: (platform_key, asset_id) => `/api/core/platforms/${platform_key}/public-image-assets/${asset_id}/`,
7160
7239
  service: SERVICES.DM,
7161
- }};
7240
+ },
7241
+ GET_PUBLIC_PLATFORM_IMAGE_ASSET_FILE_URL: {
7242
+ path: (platform_key, asset_id) => `/api/core/platforms/${platform_key}/public-image-assets/${asset_id}/file/`,
7243
+ baseUrl: getServiceUrl(SERVICES.DM),
7244
+ service: SERVICES.DM,
7245
+ },
7246
+ };
7162
7247
 
7163
7248
  createApi({
7164
7249
  // TODO: replace to catalogSlice
@@ -7230,7 +7315,13 @@ createApi({
7230
7315
  ...buildEndpointFromDmService(iblaiApi.AiAccountService.aiAccountOrgsIntegrationCredentialPartialUpdate),
7231
7316
  }),
7232
7317
  getConnectedServiceAuthUrl: builder.query({
7233
- ...buildEndpointFromDmService(iblaiApi.AiAccountService.aiAccountConnectedServicesOrgsUsersRetrieve),
7318
+ queryFn: async (queryParams, api, extraOptions) => {
7319
+ const url = `/api/ai-account/connected-services/orgs/${queryParams.org}/users/${queryParams.userId}/${queryParams.provider}/${queryParams.service}/`;
7320
+ return iblFetchBaseQuery({
7321
+ url,
7322
+ service: SERVICES.DM,
7323
+ }, api, extraOptions);
7324
+ },
7234
7325
  }),
7235
7326
  connectedServicesCallback: builder.query({
7236
7327
  queryFn: async (queryParams, api, extraOptions) => {
@@ -7362,7 +7453,7 @@ const sessionApiSlice = createApi({
7362
7453
  }),
7363
7454
  }),
7364
7455
  });
7365
- const { useCreateSessionIdMutation, useEditSessionMutation, } = sessionApiSlice;
7456
+ const { useCreateSessionIdMutation, useLazyGetSessionIdQuery, useEditSessionMutation, } = sessionApiSlice;
7366
7457
 
7367
7458
  createApi({
7368
7459
  reducerPath: 'datasetsApiSlice',
@@ -8299,6 +8390,12 @@ createApi({
8299
8390
  });
8300
8391
 
8301
8392
  const NOTIFICATIONS_CUSTOM_REDUCER_PATH = 'notificationsCustomApiSlice';
8393
+ const NOTIFICATIONS_CUSTOM_TAGS = {
8394
+ TEMPLATES: 'NOTIFICATIONS_CUSTOM_TEMPLATES',
8395
+ TEMPLATE_DETAILS: 'NOTIFICATIONS_CUSTOM_TEMPLATE_DETAILS',
8396
+ UPDATE_TEMPLATE: 'NOTIFICATIONS_CUSTOM_UPDATE_TEMPLATE',
8397
+ TOGGLE_TEMPLATE: 'NOTIFICATIONS_CUSTOM_TOGGLE_TEMPLATE',
8398
+ };
8302
8399
  const NOTIFICATIONS_CUSTOM_ENDPOINTS = {
8303
8400
  GET_TEMPLATES: {
8304
8401
  service: SERVICES.DM,
@@ -8320,6 +8417,7 @@ const NOTIFICATIONS_CUSTOM_ENDPOINTS = {
8320
8417
 
8321
8418
  createApi({
8322
8419
  reducerPath: NOTIFICATIONS_CUSTOM_REDUCER_PATH,
8420
+ tagTypes: [...Object.values(NOTIFICATIONS_CUSTOM_TAGS)],
8323
8421
  baseQuery: iblFetchBaseQuery,
8324
8422
  endpoints: (builder) => ({
8325
8423
  getTemplates: builder.query({
@@ -8329,6 +8427,7 @@ createApi({
8329
8427
  service: NOTIFICATIONS_CUSTOM_ENDPOINTS.GET_TEMPLATES.service,
8330
8428
  };
8331
8429
  },
8430
+ providesTags: [NOTIFICATIONS_CUSTOM_TAGS.TEMPLATES],
8332
8431
  }),
8333
8432
  getTemplateDetails: builder.query({
8334
8433
  query: (args) => {
@@ -8337,6 +8436,7 @@ createApi({
8337
8436
  service: NOTIFICATIONS_CUSTOM_ENDPOINTS.GET_TEMPLATE_DETAILS.service,
8338
8437
  };
8339
8438
  },
8439
+ providesTags: [NOTIFICATIONS_CUSTOM_TAGS.TEMPLATE_DETAILS],
8340
8440
  }),
8341
8441
  updateTemplate: builder.mutation({
8342
8442
  query: (args) => {
@@ -8347,6 +8447,7 @@ createApi({
8347
8447
  body: args.template,
8348
8448
  };
8349
8449
  },
8450
+ invalidatesTags: [NOTIFICATIONS_CUSTOM_TAGS.TEMPLATE_DETAILS],
8350
8451
  }),
8351
8452
  toggleTemplate: builder.mutation({
8352
8453
  query: (args) => {
@@ -8359,6 +8460,7 @@ createApi({
8359
8460
  },
8360
8461
  };
8361
8462
  },
8463
+ invalidatesTags: [NOTIFICATIONS_CUSTOM_TAGS.TEMPLATES],
8362
8464
  }),
8363
8465
  }),
8364
8466
  });
@@ -8639,7 +8741,7 @@ const CUSTOM_DOMAIN_QUERY_KEYS = {
8639
8741
  CREATE_CUSTOM_DOMAIN: () => ['CREATE_CUSTOM_DOMAIN'],
8640
8742
  };
8641
8743
 
8642
- createApi({
8744
+ const customDomainApiSlice = createApi({
8643
8745
  reducerPath: CUSTOM_DOMAIN_REDUCER_PATH,
8644
8746
  baseQuery: iblFetchBaseQuery,
8645
8747
  tagTypes: [...CUSTOM_DOMAIN_QUERY_KEYS.GET_CUSTOM_DOMAINS()],
@@ -8678,6 +8780,7 @@ createApi({
8678
8780
  }),
8679
8781
  }),
8680
8782
  });
8783
+ const { useGetCustomDomainsQuery} = customDomainApiSlice;
8681
8784
 
8682
8785
  const PLATFORM_CUSTOM_REDUCER_PATH = "platformCustomApiSlice";
8683
8786
  const PLATFORM_CONFIGURATION_TAG = "PlatformConfiguration";
@@ -8740,7 +8843,7 @@ createApi({
8740
8843
  const coreCustomApiSlice = createApi({
8741
8844
  reducerPath: CORE_CUSTOM_REDUCER_PATH,
8742
8845
  baseQuery: iblFetchBaseQuery,
8743
- tagTypes: [PLATFORM_MEMBERSHIP_TAG],
8846
+ tagTypes: [PLATFORM_MEMBERSHIP_TAG, 'PlatformImageAssetFileUrl'],
8744
8847
  endpoints: (builder) => ({
8745
8848
  getPlatformMembership: builder.query({
8746
8849
  query: ({ platform_key }) => ({
@@ -8813,6 +8916,19 @@ const coreCustomApiSlice = createApi({
8813
8916
  });
8814
8917
  const { useJoinTenantMutation} = coreCustomApiSlice;
8815
8918
 
8919
+ createApi({
8920
+ reducerPath: CORE_FAKE_CUSTOM_REDUCER_PATH,
8921
+ baseQuery: iblFakeBaseQuery,
8922
+ endpoints: (builder) => ({
8923
+ getPublicPlatformImageAssetFileUrl: builder.query({
8924
+ ...buildEndpointFromService(SERVICES.DM, async (args) => {
8925
+ const url = `${iblaiApi.OpenAPI.BASE}${CORE_CUSTOM_ENDPOINTS.GET_PUBLIC_PLATFORM_IMAGE_ASSET_FILE_URL.path(args.platform_key, args.asset_id)}`;
8926
+ return url;
8927
+ }),
8928
+ }),
8929
+ }),
8930
+ });
8931
+
8816
8932
  const EDX_PROCTORING_ENDPOINTS = {
8817
8933
  GET_EXAM_INFO: {
8818
8934
  service: SERVICES.LMS,
@@ -10325,6 +10441,299 @@ const formatRelativeTime = (timestamp) => {
10325
10441
  return `${diffInYears} year${diffInYears === 1 ? "" : "s"} ago`;
10326
10442
  };
10327
10443
 
10444
+ /**
10445
+ * Authentication and Authorization Utilities
10446
+ *
10447
+ * This module provides utility functions for handling authentication flows,
10448
+ * including redirects to auth SPA, cookie management, and session handling.
10449
+ */
10450
+ /**
10451
+ * Check if the current window is inside an iframe
10452
+ * @returns {boolean} True if running in an iframe, false otherwise
10453
+ */
10454
+ function isInIframe() {
10455
+ if (typeof window === "undefined") {
10456
+ return false;
10457
+ }
10458
+ return (window === null || window === void 0 ? void 0 : window.self) !== (window === null || window === void 0 ? void 0 : window.top);
10459
+ }
10460
+ /**
10461
+ * Send a message to the parent website (when in iframe)
10462
+ * @param payload - The data to send to parent window
10463
+ */
10464
+ function sendMessageToParentWebsite(payload) {
10465
+ window.parent.postMessage(payload, "*");
10466
+ }
10467
+ /**
10468
+ * Delete a cookie with specific name, path, and domain
10469
+ * @param name - Cookie name
10470
+ * @param path - Cookie path
10471
+ * @param domain - Cookie domain
10472
+ */
10473
+ function deleteCookie(name, path, domain) {
10474
+ const expires = "expires=Thu, 01 Jan 1970 00:00:00 UTC;";
10475
+ const cookieValue = `${name}=;`;
10476
+ const pathValue = path ? `path=${path};` : "";
10477
+ const domainValue = domain ? `domain=${domain};` : "";
10478
+ document.cookie = cookieValue + expires + pathValue + domainValue;
10479
+ }
10480
+ /**
10481
+ * Get all possible domain parts for cookie deletion
10482
+ * @param domain - The domain to split
10483
+ * @returns Array of domain parts
10484
+ * @example
10485
+ * getDomainParts('app.example.com') // returns ['app.example.com', 'example.com', 'com']
10486
+ */
10487
+ function getDomainParts(domain) {
10488
+ const parts = domain.split(".");
10489
+ const domains = [];
10490
+ for (let i = parts.length - 1; i >= 0; i--) {
10491
+ domains.push(parts.slice(i).join("."));
10492
+ }
10493
+ return domains;
10494
+ }
10495
+ /**
10496
+ * Delete a cookie across all possible domain variations
10497
+ * @param name - Cookie name to delete
10498
+ * @param childDomain - The current domain
10499
+ */
10500
+ function deleteCookieOnAllDomains(name, childDomain) {
10501
+ getDomainParts(childDomain).forEach((domainPart) => {
10502
+ deleteCookie(name, "/", domainPart);
10503
+ deleteCookie(name, "", domainPart);
10504
+ });
10505
+ }
10506
+ /**
10507
+ * Get the parent domain from a given domain
10508
+ * @param domain - The domain to process
10509
+ * @returns The parent domain (e.g., 'app.example.com' → '.example.com')
10510
+ */
10511
+ function getParentDomain(domain) {
10512
+ if (!domain) {
10513
+ return "";
10514
+ }
10515
+ const parts = domain.split(".");
10516
+ return parts.length > 1 ? `.${parts.slice(-2).join(".")}` : domain;
10517
+ }
10518
+ /**
10519
+ * Set a cookie for authentication with cross-domain support
10520
+ * @param name - Cookie name
10521
+ * @param value - Cookie value
10522
+ * @param days - Number of days until expiration (default: 365)
10523
+ */
10524
+ function setCookieForAuth(name, value, days = 365) {
10525
+ const expires = new Date();
10526
+ expires.setTime(expires.getTime() + days * 24 * 60 * 60 * 1000);
10527
+ const hostname = window.location.hostname;
10528
+ let baseDomain = hostname;
10529
+ // Calculate base domain (skip for localhost and IP addresses)
10530
+ if (hostname !== "localhost" && !/^\d+\.\d+\.\d+\.\d+$/.test(hostname)) {
10531
+ const parts = hostname.split(".");
10532
+ if (parts.length > 2) {
10533
+ baseDomain = `.${parts.slice(-2).join(".")}`;
10534
+ }
10535
+ }
10536
+ const domainAttr = baseDomain ? `;domain=${baseDomain}` : "";
10537
+ document.cookie = `${name}=${encodeURIComponent(value)};expires=${expires.toUTCString()};path=/;SameSite=None;Secure${domainAttr}`;
10538
+ }
10539
+ /**
10540
+ * Clear all cookies for the current domain
10541
+ */
10542
+ function clearCookies() {
10543
+ const cookies = document.cookie.split(";");
10544
+ for (let i = 0; i < cookies.length; i++) {
10545
+ const cookie = cookies[i];
10546
+ const eqPos = cookie.indexOf("=");
10547
+ const name = eqPos > -1 ? cookie.substr(0, eqPos) : cookie;
10548
+ deleteCookieOnAllDomains(name, window.location.hostname);
10549
+ document.cookie = `${name}=;expires=Thu, 01 Jan 1970 00:00:00 GMT;path=/;Domain=${getParentDomain(window.location.hostname)}`;
10550
+ }
10551
+ }
10552
+ /**
10553
+ * Check if user is currently logged in
10554
+ * @param tokenKey - The localStorage key for the auth token (default: 'axd_token')
10555
+ * @returns True if logged in, false otherwise
10556
+ */
10557
+ function isLoggedIn(tokenKey = "axd_token") {
10558
+ return !!localStorage.getItem(tokenKey);
10559
+ }
10560
+ /**
10561
+ * Extract platform/tenant key from URL
10562
+ * @param url - The URL to parse
10563
+ * @param pattern - RegExp pattern to match platform key (default matches /platform/[key]/...)
10564
+ * @returns The platform key or null if not found
10565
+ */
10566
+ function getPlatformKey(url, pattern = /\/platform\/([^/]+)/) {
10567
+ const match = url.match(pattern);
10568
+ return match ? match[1] : null;
10569
+ }
10570
+ /**
10571
+ * Redirect to authentication SPA for login/logout
10572
+ *
10573
+ * This function handles the complete authentication flow:
10574
+ * - Clears localStorage and cookies on logout
10575
+ * - Saves redirect path for post-auth return
10576
+ * - Handles iframe scenarios
10577
+ * - Syncs logout across multiple SPAs via cookies
10578
+ *
10579
+ * @param options - Configuration options for the redirect
10580
+ *
10581
+ * @example
10582
+ * ```tsx
10583
+ * // Basic usage
10584
+ * redirectToAuthSpa({
10585
+ * authUrl: 'https://auth.example.com',
10586
+ * appName: 'mentor',
10587
+ * });
10588
+ *
10589
+ * // With logout
10590
+ * redirectToAuthSpa({
10591
+ * authUrl: 'https://auth.example.com',
10592
+ * appName: 'mentor',
10593
+ * logout: true,
10594
+ * platformKey: 'my-tenant',
10595
+ * });
10596
+ *
10597
+ * // With custom redirect
10598
+ * redirectToAuthSpa({
10599
+ * authUrl: 'https://auth.example.com',
10600
+ * appName: 'mentor',
10601
+ * redirectTo: '/dashboard',
10602
+ * platformKey: 'my-tenant',
10603
+ * });
10604
+ * ```
10605
+ */
10606
+ async function redirectToAuthSpa(options) {
10607
+ const { redirectTo, platformKey, logout = false, saveRedirect = true, authUrl, appName, queryParams = {
10608
+ app: "app",
10609
+ redirectTo: "redirect-to",
10610
+ tenant: "tenant",
10611
+ }, redirectPathStorageKey = "redirect_to", cookieNames = {
10612
+ currentTenant: "ibl_current_tenant",
10613
+ userData: "ibl_user_data",
10614
+ tenant: "ibl_tenant",
10615
+ logoutTimestamp: "ibl_logout_timestamp",
10616
+ }, } = options;
10617
+ // Clear localStorage
10618
+ localStorage.clear();
10619
+ if (logout) {
10620
+ // Delete authentication cookies for cross-SPA synchronization
10621
+ const currentDomain = window.location.hostname;
10622
+ if (cookieNames.currentTenant) {
10623
+ deleteCookieOnAllDomains(cookieNames.currentTenant, currentDomain);
10624
+ }
10625
+ if (cookieNames.userData) {
10626
+ deleteCookieOnAllDomains(cookieNames.userData, currentDomain);
10627
+ }
10628
+ if (cookieNames.tenant) {
10629
+ deleteCookieOnAllDomains(cookieNames.tenant, currentDomain);
10630
+ }
10631
+ // Set logout timestamp cookie to trigger logout on other SPAs
10632
+ if (cookieNames.logoutTimestamp) {
10633
+ setCookieForAuth(cookieNames.logoutTimestamp, Date.now().toString());
10634
+ }
10635
+ }
10636
+ // Handle iframe scenario
10637
+ if (isInIframe()) {
10638
+ console.log("[redirectToAuthSpa]: sending authExpired to parent");
10639
+ sendMessageToParentWebsite({ authExpired: true });
10640
+ return;
10641
+ }
10642
+ const redirectPath = redirectTo !== null && redirectTo !== void 0 ? redirectTo : `${window.location.pathname}${window.location.search}`;
10643
+ // Never save sso-login routes as redirect paths
10644
+ if (!redirectPath.startsWith("/sso-login") && saveRedirect) {
10645
+ window.localStorage.setItem(redirectPathStorageKey, redirectPath);
10646
+ }
10647
+ const platform = platformKey !== null && platformKey !== void 0 ? platformKey : getPlatformKey(redirectPath);
10648
+ const redirectToUrl = `${window.location.origin}`;
10649
+ let authRedirectUrl = `${authUrl}/login?${queryParams.app}=${appName}`;
10650
+ authRedirectUrl += `&${queryParams.redirectTo}=${redirectToUrl}`;
10651
+ if (platform) {
10652
+ authRedirectUrl += `&${queryParams.tenant}=${platform}`;
10653
+ }
10654
+ if (logout) {
10655
+ authRedirectUrl += "&logout=1";
10656
+ }
10657
+ // Small delay for any pending operations
10658
+ await new Promise((resolve) => setTimeout(resolve, 100));
10659
+ // Redirect to auth SPA
10660
+ window.location.href = authRedirectUrl;
10661
+ }
10662
+ /**
10663
+ * Get the URL for joining a tenant (sign up flow)
10664
+ * @param authUrl - Auth SPA base URL
10665
+ * @param tenantKey - Tenant to join
10666
+ * @param redirectUrl - URL to redirect to after joining (defaults to current URL)
10667
+ * @returns The join URL
10668
+ */
10669
+ function getAuthSpaJoinUrl(authUrl, tenantKey, redirectUrl) {
10670
+ const resolvedTenant = tenantKey || getPlatformKey(window.location.pathname) || "";
10671
+ if (!resolvedTenant) {
10672
+ return "";
10673
+ }
10674
+ const targetUrl = redirectUrl !== null && redirectUrl !== void 0 ? redirectUrl : window.location.href;
10675
+ const joinUrl = `${authUrl}/join?tenant=${encodeURIComponent(resolvedTenant)}&redirect-to=${encodeURIComponent(targetUrl)}`;
10676
+ return joinUrl;
10677
+ }
10678
+ /**
10679
+ * Redirect to auth SPA's join/signup page for a specific tenant
10680
+ * @param authUrl - Auth SPA base URL
10681
+ * @param tenantKey - Tenant to join
10682
+ * @param redirectUrl - URL to redirect to after joining (defaults to current URL)
10683
+ */
10684
+ function redirectToAuthSpaJoinTenant(authUrl, tenantKey, redirectUrl) {
10685
+ const resolvedTenant = tenantKey || getPlatformKey(window.location.pathname) || "";
10686
+ if (!resolvedTenant) {
10687
+ console.log("[auth-redirect] Missing tenant key for join", {
10688
+ tenantKey,
10689
+ redirectUrl,
10690
+ });
10691
+ redirectToAuthSpa({
10692
+ authUrl,
10693
+ appName: "app", // Will need to be configured
10694
+ redirectTo: redirectUrl,
10695
+ });
10696
+ return;
10697
+ }
10698
+ const targetUrl = redirectUrl !== null && redirectUrl !== void 0 ? redirectUrl : window.location.href;
10699
+ const joinUrl = `${authUrl}/join?tenant=${encodeURIComponent(resolvedTenant)}&redirect-to=${encodeURIComponent(targetUrl)}`;
10700
+ window.location.href = joinUrl;
10701
+ }
10702
+ /**
10703
+ * Handle user logout
10704
+ *
10705
+ * This function:
10706
+ * - Clears localStorage (preserving tenant)
10707
+ * - Sets logout timestamp cookie for cross-SPA sync
10708
+ * - Clears all cookies
10709
+ * - Redirects to auth SPA logout endpoint
10710
+ *
10711
+ * @param options - Logout configuration options
10712
+ *
10713
+ * @example
10714
+ * ```tsx
10715
+ * handleLogout({
10716
+ * authUrl: 'https://auth.example.com',
10717
+ * redirectUrl: 'https://app.example.com',
10718
+ * });
10719
+ * ```
10720
+ */
10721
+ function handleLogout(options) {
10722
+ const { redirectUrl = window.location.origin, authUrl, tenantStorageKey = "tenant", logoutTimestampCookie = "ibl_logout_timestamp", callback, } = options;
10723
+ const tenant = window.localStorage.getItem(tenantStorageKey);
10724
+ window.localStorage.clear();
10725
+ if (tenant) {
10726
+ window.localStorage.setItem(tenantStorageKey, tenant);
10727
+ }
10728
+ // Set logout timestamp cookie to trigger logout on other SPAs
10729
+ setCookieForAuth(logoutTimestampCookie, Date.now().toString());
10730
+ clearCookies();
10731
+ callback === null || callback === void 0 ? void 0 : callback();
10732
+ if (!isInIframe()) {
10733
+ window.location.href = `${authUrl}/logout?redirect-to=${redirectUrl}${tenant ? "&tenant=" + tenant : ""}`;
10734
+ }
10735
+ }
10736
+
10328
10737
  const useExternalPricingPlan = ({ pricingModalData, userEmail, }) => {
10329
10738
  const pricingBoxIframeRef = React.useRef(null);
10330
10739
  const getIFrameReadyData = async () => {
@@ -10456,6 +10865,8 @@ function jwtDecode(token, options) {
10456
10865
  * - Polls for cookie changes every 2 seconds
10457
10866
  * - Refreshes the page when cross-SPA changes are detected
10458
10867
  * - Listens for storage events to update cookies when localStorage changes
10868
+ * - Monitors logout timestamp cookie to trigger cross-SPA logout
10869
+ * - Automatically logs out when another SPA initiates logout
10459
10870
  *
10460
10871
  * For React Native:
10461
10872
  * - Relies on AsyncStorage only (handled by StorageService)
@@ -10465,7 +10876,7 @@ function jwtDecode(token, options) {
10465
10876
  /**
10466
10877
  * Check if we're running in a web browser environment
10467
10878
  */
10468
- const isWeb = () => {
10879
+ const isWeb$1 = () => {
10469
10880
  return typeof window !== "undefined" && typeof document !== "undefined";
10470
10881
  };
10471
10882
  /**
@@ -10475,6 +10886,7 @@ const COOKIE_KEYS = {
10475
10886
  CURRENT_TENANT: "ibl_current_tenant",
10476
10887
  USER_DATA: "ibl_user_data",
10477
10888
  TENANT: "ibl_tenant",
10889
+ LOGOUT_TIMESTAMP: "ibl_logout_timestamp",
10478
10890
  };
10479
10891
  /**
10480
10892
  * Get the base domain for cookie sharing
@@ -10485,7 +10897,7 @@ const COOKIE_KEYS = {
10485
10897
  */
10486
10898
  const getBaseDomain = () => {
10487
10899
  // Must check for window existence before accessing it
10488
- if (!isWeb())
10900
+ if (!isWeb$1())
10489
10901
  return "";
10490
10902
  const hostname = window.location.hostname;
10491
10903
  // For localhost or IP addresses, use as-is
@@ -10514,7 +10926,7 @@ const CookieUtils = {
10514
10926
  * Uses SameSite=None for cross-subdomain sharing and base domain
10515
10927
  */
10516
10928
  set(name, value, days = 365) {
10517
- if (!isWeb())
10929
+ if (!isWeb$1())
10518
10930
  return;
10519
10931
  const expires = new Date();
10520
10932
  expires.setTime(expires.getTime() + days * 24 * 60 * 60 * 1000);
@@ -10526,7 +10938,7 @@ const CookieUtils = {
10526
10938
  * Get a cookie value by name
10527
10939
  */
10528
10940
  get(name) {
10529
- if (!isWeb())
10941
+ if (!isWeb$1())
10530
10942
  return null;
10531
10943
  const nameEQ = name + "=";
10532
10944
  const cookies = document.cookie.split(";");
@@ -10545,7 +10957,7 @@ const CookieUtils = {
10545
10957
  * Uses same domain logic as set() to ensure proper deletion
10546
10958
  */
10547
10959
  delete(name) {
10548
- if (!isWeb())
10960
+ if (!isWeb$1())
10549
10961
  return;
10550
10962
  const baseDomain = getBaseDomain();
10551
10963
  const domainAttr = baseDomain ? `;domain=${baseDomain}` : "";
@@ -10558,8 +10970,7 @@ const CookieUtils = {
10558
10970
  * On React Native, this is a no-op
10559
10971
  */
10560
10972
  async function syncAuthToCookies(storageService) {
10561
- console.log("##################### syncing auth to cookie");
10562
- if (!isWeb())
10973
+ if (!isWeb$1())
10563
10974
  return;
10564
10975
  try {
10565
10976
  const currentTenant = await storageService.getItem(LOCAL_STORAGE_KEYS.CURRENT_TENANT);
@@ -10588,13 +10999,23 @@ async function syncAuthToCookies(storageService) {
10588
10999
  console.error("[syncAuthToCookies] Error syncing to cookies:", error);
10589
11000
  }
10590
11001
  }
11002
+ /**
11003
+ * Clear current tenant cookie only (web only)
11004
+ * Should be called before tenant switching
11005
+ * On React Native, this is a no-op
11006
+ */
11007
+ function clearCurrentTenantCookie() {
11008
+ if (!isWeb$1())
11009
+ return;
11010
+ CookieUtils.delete(COOKIE_KEYS.CURRENT_TENANT);
11011
+ }
10591
11012
  /**
10592
11013
  * Clear all authentication cookies (web only)
10593
11014
  * Should be called on logout
10594
11015
  * On React Native, this is a no-op
10595
11016
  */
10596
11017
  function clearAuthCookies() {
10597
- if (!isWeb())
11018
+ if (!isWeb$1())
10598
11019
  return;
10599
11020
  CookieUtils.delete(COOKIE_KEYS.CURRENT_TENANT);
10600
11021
  CookieUtils.delete(COOKIE_KEYS.USER_DATA);
@@ -10606,14 +11027,30 @@ function clearAuthCookies() {
10606
11027
  * On React Native, always returns false (no-op)
10607
11028
  */
10608
11029
  async function syncCookiesToLocalStorage(storageService) {
10609
- if (!isWeb())
11030
+ if (!isWeb$1())
10610
11031
  return false;
10611
11032
  try {
10612
11033
  let needsRefresh = false;
10613
11034
  // Check current_tenant
10614
11035
  const cookieCurrentTenant = CookieUtils.get(COOKIE_KEYS.CURRENT_TENANT);
11036
+ console.log("[syncCookiesToLocalStorage] cookieCurrentTenant", cookieCurrentTenant);
10615
11037
  const localCurrentTenant = await storageService.getItem(LOCAL_STORAGE_KEYS.CURRENT_TENANT);
10616
- if (cookieCurrentTenant !== localCurrentTenant) {
11038
+ console.log("[syncCookiesToLocalStorage] localCurrentTenant", localCurrentTenant);
11039
+ // Compare current tenant objects by key field only to avoid false positives from extra fields
11040
+ let currentTenantIsDifferent = false;
11041
+ if (cookieCurrentTenant && localCurrentTenant) {
11042
+ try {
11043
+ const cookieTenant = JSON.parse(cookieCurrentTenant);
11044
+ const localTenant = JSON.parse(localCurrentTenant);
11045
+ // Compare by the tenant key only
11046
+ currentTenantIsDifferent = cookieTenant.key !== localTenant.key;
11047
+ }
11048
+ catch (e) {
11049
+ // If parsing fails, fall back to string comparison
11050
+ currentTenantIsDifferent = cookieCurrentTenant !== localCurrentTenant;
11051
+ }
11052
+ }
11053
+ if (currentTenantIsDifferent) {
10617
11054
  if (cookieCurrentTenant) {
10618
11055
  await storageService.setItem(LOCAL_STORAGE_KEYS.CURRENT_TENANT, cookieCurrentTenant);
10619
11056
  }
@@ -10625,8 +11062,24 @@ async function syncCookiesToLocalStorage(storageService) {
10625
11062
  }
10626
11063
  // Check userData
10627
11064
  const cookieUserData = CookieUtils.get(COOKIE_KEYS.USER_DATA);
11065
+ console.log("[syncCookiesToLocalStorage] cookieUserData", cookieUserData);
10628
11066
  const localUserData = await storageService.getItem(LOCAL_STORAGE_KEYS.USER_DATA);
10629
- if (cookieUserData !== localUserData) {
11067
+ console.log("[syncCookiesToLocalStorage] localUserData", localUserData);
11068
+ // Compare userData objects by user_id to avoid false positives from extra fields
11069
+ let userDataIsDifferent = false;
11070
+ if (cookieUserData && localUserData) {
11071
+ try {
11072
+ const cookieUser = JSON.parse(cookieUserData);
11073
+ const localUser = JSON.parse(localUserData);
11074
+ // Compare by user_id - the primary identifier
11075
+ userDataIsDifferent = cookieUser.user_id !== localUser.user_id;
11076
+ }
11077
+ catch (e) {
11078
+ // If parsing fails, fall back to string comparison
11079
+ userDataIsDifferent = cookieUserData !== localUserData;
11080
+ }
11081
+ }
11082
+ if (userDataIsDifferent) {
10630
11083
  if (cookieUserData) {
10631
11084
  await storageService.setItem(LOCAL_STORAGE_KEYS.USER_DATA, cookieUserData);
10632
11085
  }
@@ -10638,8 +11091,37 @@ async function syncCookiesToLocalStorage(storageService) {
10638
11091
  }
10639
11092
  // Check tenant
10640
11093
  const cookieTenant = CookieUtils.get(COOKIE_KEYS.TENANT);
11094
+ console.log("[syncCookiesToLocalStorage] cookieTenant", cookieTenant);
10641
11095
  const localTenant = await storageService.getItem(LOCAL_STORAGE_KEYS.TENANTS);
10642
- if (cookieTenant !== localTenant) {
11096
+ console.log("[syncCookiesToLocalStorage] localTenant", localTenant);
11097
+ // Compare tenant arrays by checking length and tenant keys
11098
+ let tenantsAreDifferent = false;
11099
+ if (cookieTenant &&
11100
+ localTenant &&
11101
+ cookieTenant !== "[]" &&
11102
+ localTenant !== "[]") {
11103
+ try {
11104
+ const cookieTenantsArray = JSON.parse(cookieTenant);
11105
+ const localTenantsArray = JSON.parse(localTenant);
11106
+ // Check if arrays have same length
11107
+ if (cookieTenantsArray.length !== localTenantsArray.length) {
11108
+ tenantsAreDifferent = true;
11109
+ }
11110
+ else {
11111
+ // Check if all tenant keys match
11112
+ const cookieKeys = new Set(cookieTenantsArray.map((t) => t.key));
11113
+ const localKeys = new Set(localTenantsArray.map((t) => t.key));
11114
+ tenantsAreDifferent =
11115
+ cookieKeys.size !== localKeys.size ||
11116
+ [...cookieKeys].some((key) => !localKeys.has(key));
11117
+ }
11118
+ }
11119
+ catch (e) {
11120
+ // If parsing fails, fall back to string comparison
11121
+ tenantsAreDifferent = cookieTenant !== localTenant;
11122
+ }
11123
+ }
11124
+ if (tenantsAreDifferent) {
10643
11125
  if (cookieTenant) {
10644
11126
  await storageService.setItem(LOCAL_STORAGE_KEYS.TENANTS, cookieTenant);
10645
11127
  }
@@ -10694,6 +11176,7 @@ async function isJwtTokenExpired(storageService) {
10694
11176
  async function validateJwtToken(storageService) {
10695
11177
  try {
10696
11178
  const edxJwtToken = await storageService.getItem(LOCAL_STORAGE_KEYS.EDX_TOKEN_KEY);
11179
+ console.log("[AuthProvider] JWT token ", edxJwtToken);
10697
11180
  const userData = await storageService.getItem(LOCAL_STORAGE_KEYS.USER_DATA);
10698
11181
  if (!edxJwtToken || !userData) {
10699
11182
  return false;
@@ -10716,7 +11199,9 @@ async function validateJwtToken(storageService) {
10716
11199
  function useAuthProvider({ middleware = new Map(), onAuthSuccess, onAuthFailure, redirectToAuthSpa, hasNonExpiredAuthToken, username, pathname, storageService, skipAuthCheck, token, }) {
10717
11200
  const [isAuthenticating, setIsAuthenticating] = React.useState(true);
10718
11201
  const [userIsAccessingPublicRoute, setUserIsAccessingPublicRoute] = React.useState(false);
11202
+ const [initialSyncComplete, setInitialSyncComplete] = React.useState(false);
10719
11203
  const cookieCheckIntervalRef = React.useRef(null);
11204
+ const lastLogoutTimestampRef = React.useRef(null);
10720
11205
  // RTK Query hook for refreshing JWT token
10721
11206
  const [refreshJwtToken] = useLazyRefreshJwtTokenQuery();
10722
11207
  /**
@@ -10725,24 +11210,65 @@ function useAuthProvider({ middleware = new Map(), onAuthSuccess, onAuthFailure,
10725
11210
  * On React Native, this is a no-op
10726
11211
  */
10727
11212
  React.useEffect(() => {
10728
- console.log("################******* useEffect sync auth");
10729
- if (!storageService || !isWeb())
11213
+ if (!storageService || !isWeb$1()) {
11214
+ // If no storage service or not web, mark sync as complete immediately
11215
+ setInitialSyncComplete(true);
10730
11216
  return;
11217
+ }
10731
11218
  // Initial sync on mount
10732
11219
  async function initialSync() {
10733
- const needsRefresh = await syncCookiesToLocalStorage(storageService);
10734
- if (needsRefresh) {
10735
- console.log("[AuthProvider] Cookie sync detected changes, refreshing page...");
10736
- window.location.reload();
11220
+ try {
11221
+ // Initialize last known logout timestamp
11222
+ lastLogoutTimestampRef.current = CookieUtils.get(COOKIE_KEYS.LOGOUT_TIMESTAMP);
11223
+ const needsRefresh = await syncCookiesToLocalStorage(storageService);
11224
+ if (needsRefresh) {
11225
+ console.log("[auth-redirect] Cookie sync detected changes, refreshing page");
11226
+ redirectToAuthSpa(undefined, undefined, false, false);
11227
+ }
11228
+ else {
11229
+ await syncAuthToCookies(storageService);
11230
+ }
11231
+ }
11232
+ finally {
11233
+ // Mark initial sync as complete
11234
+ setInitialSyncComplete(true);
10737
11235
  }
10738
11236
  }
10739
11237
  initialSync();
10740
11238
  // Poll for cookie changes every 2 seconds to detect cross-SPA updates
10741
11239
  cookieCheckIntervalRef.current = setInterval(async () => {
11240
+ // Skip cookie sync checks if user is completing SSO at /sso-login
11241
+ const completingSso = new RegExp("^\/sso-login").test(pathname);
11242
+ if (completingSso) {
11243
+ console.log("[AuthProvider] Skipping cookie sync check for public route");
11244
+ return;
11245
+ }
11246
+ // Check for logout timestamp changes (cross-SPA logout detection)
11247
+ const currentLogoutTimestamp = CookieUtils.get(COOKIE_KEYS.LOGOUT_TIMESTAMP);
11248
+ if (currentLogoutTimestamp &&
11249
+ lastLogoutTimestampRef.current &&
11250
+ currentLogoutTimestamp !== lastLogoutTimestampRef.current) {
11251
+ console.log("[auth-redirect] Logout detected from another SPA", {
11252
+ previousTimestamp: lastLogoutTimestampRef.current,
11253
+ newTimestamp: currentLogoutTimestamp,
11254
+ });
11255
+ lastLogoutTimestampRef.current = currentLogoutTimestamp;
11256
+ redirectToAuthSpa(undefined, undefined, true);
11257
+ return;
11258
+ }
10742
11259
  const needsRefresh = await syncCookiesToLocalStorage(storageService);
10743
11260
  if (needsRefresh) {
10744
- console.log("[AuthProvider] Cookie sync detected changes from another SPA, refreshing page...");
10745
- window.location.reload();
11261
+ console.log("[auth-redirect] Cookie sync detected changes from another SPA, refreshing page");
11262
+ let cookieTenantKey;
11263
+ try {
11264
+ const cookieCurrentTenant = JSON.parse(CookieUtils.get(COOKIE_KEYS.CURRENT_TENANT));
11265
+ cookieTenantKey = cookieCurrentTenant.key;
11266
+ }
11267
+ catch (_a) { }
11268
+ redirectToAuthSpa(undefined, cookieTenantKey, false, false);
11269
+ }
11270
+ else {
11271
+ await syncAuthToCookies(storageService);
10746
11272
  }
10747
11273
  }, 2000);
10748
11274
  // Cleanup interval on unmount
@@ -10751,15 +11277,14 @@ function useAuthProvider({ middleware = new Map(), onAuthSuccess, onAuthFailure,
10751
11277
  clearInterval(cookieCheckIntervalRef.current);
10752
11278
  }
10753
11279
  };
10754
- }, [storageService]);
11280
+ }, [storageService, middleware, pathname]);
10755
11281
  /**
10756
11282
  * Listen for storage events from other tabs/windows (web only)
10757
11283
  * This catches same-SPA changes in different tabs
10758
11284
  * On React Native, this is a no-op
10759
11285
  */
10760
11286
  React.useEffect(() => {
10761
- console.log("################ useEffect sync auth");
10762
- if (!storageService || !isWeb())
11287
+ if (!storageService || !isWeb$1())
10763
11288
  return;
10764
11289
  const handleStorageChange = async (event) => {
10765
11290
  // Only handle changes to our auth-related keys
@@ -10790,14 +11315,15 @@ function useAuthProvider({ middleware = new Map(), onAuthSuccess, onAuthFailure,
10790
11315
  if (!hasNonExpiredAuthToken()) {
10791
11316
  const reason = "Auth token expired";
10792
11317
  onAuthFailure === null || onAuthFailure === void 0 ? void 0 : onAuthFailure(reason);
10793
- redirectToAuthSpa();
11318
+ console.log("[auth-redirect] Auth token expired");
11319
+ redirectToAuthSpa(undefined, undefined, true);
10794
11320
  return;
10795
11321
  }
10796
11322
  // Check JWT token expiry and force logout for protected routes
10797
11323
  if (isProtectedRoute && storageService) {
10798
11324
  const jwtExpired = await isJwtTokenExpired(storageService);
10799
11325
  if (jwtExpired) {
10800
- console.log("[AuthProvider] JWT token has expired, forcing logout...");
11326
+ console.log("[auth-redirect] JWT token has expired, forcing logout");
10801
11327
  // Clear all auth-related storage keys
10802
11328
  clearAuthCookies();
10803
11329
  const reason = "JWT token expired";
@@ -10819,11 +11345,18 @@ function useAuthProvider({ middleware = new Map(), onAuthSuccess, onAuthFailure,
10819
11345
  console.log("[AuthProvider] JWT token refreshed successfully");
10820
11346
  }
10821
11347
  else if (result.error) {
10822
- console.error("[AuthProvider] Failed to refresh JWT token:", result.error);
11348
+ console.log("[auth-redirect] Failed to refresh JWT token", {
11349
+ error: result.error,
11350
+ });
11351
+ redirectToAuthSpa(undefined, undefined, true);
11352
+ return;
10823
11353
  }
10824
11354
  }
10825
11355
  catch (refreshError) {
10826
- console.error("[AuthProvider] Failed to refresh JWT token:", refreshError);
11356
+ console.log("[auth-redirect] JWT token refresh error", {
11357
+ error: refreshError,
11358
+ });
11359
+ redirectToAuthSpa(undefined, undefined, true);
10827
11360
  // Continue with auth check even if JWT refresh fails
10828
11361
  }
10829
11362
  }
@@ -10835,12 +11368,18 @@ function useAuthProvider({ middleware = new Map(), onAuthSuccess, onAuthFailure,
10835
11368
  setIsAuthenticating(false);
10836
11369
  }
10837
11370
  catch (error) {
11371
+ console.error("[AuthProvider] Error performing auth check:", error);
10838
11372
  const errorMessage = error instanceof Error ? error.message : String(error);
10839
11373
  onAuthFailure === null || onAuthFailure === void 0 ? void 0 : onAuthFailure(`Unexpected error: ${errorMessage}`);
10840
11374
  redirectToAuthSpa();
10841
11375
  }
10842
11376
  }
10843
11377
  React.useEffect(() => {
11378
+ // Wait for initial sync to complete before performing auth check
11379
+ if (!initialSyncComplete) {
11380
+ console.log("[useAuthProvider] Waiting for initial sync to complete...");
11381
+ return;
11382
+ }
10844
11383
  async function checkAuth() {
10845
11384
  setIsAuthenticating(true);
10846
11385
  const authRequired = (await determineAuthRequired(middleware, pathname)) && !token;
@@ -10861,7 +11400,7 @@ function useAuthProvider({ middleware = new Map(), onAuthSuccess, onAuthFailure,
10861
11400
  }
10862
11401
  console.log("[useAuthProvider] performing auth check for ", username);
10863
11402
  checkAuth();
10864
- }, [username]);
11403
+ }, [username, initialSyncComplete]);
10865
11404
  return {
10866
11405
  isAuthenticating,
10867
11406
  userIsAccessingPublicRoute,
@@ -10929,7 +11468,7 @@ function AuthProvider({ children, fallback, middleware = new Map(), onAuthSucces
10929
11468
  if (isAuthenticating) {
10930
11469
  return fallback;
10931
11470
  }
10932
- return (jsxRuntime.jsx(AuthContextProvider, { value: { userIsAccessingPublicRoute, setUserIsAccessingPublicRoute }, children: jsxRuntime.jsx(jsxRuntime.Fragment, {}) }));
11471
+ return (jsxRuntime.jsx(AuthContextProvider, { value: { userIsAccessingPublicRoute, setUserIsAccessingPublicRoute }, children: children }));
10933
11472
  }
10934
11473
 
10935
11474
  /**
@@ -10942,6 +11481,12 @@ function AuthProvider({ children, fallback, middleware = new Map(), onAuthSucces
10942
11481
  * - Tenant metadata retrieval
10943
11482
  * - User-tenant relationship verification
10944
11483
  */
11484
+ /**
11485
+ * Check if we're running in a web browser environment
11486
+ */
11487
+ const isWeb = () => {
11488
+ return typeof window !== "undefined" && typeof document !== "undefined";
11489
+ };
10945
11490
  const TenantContext = React.createContext(undefined);
10946
11491
  /**
10947
11492
  * Context Provider component that wraps children with tenant context
@@ -10962,7 +11507,7 @@ const useTenantContext = () => React.useContext(TenantContext);
10962
11507
  * 4. Handles tenant-specific domain redirects
10963
11508
  * 5. Maintains tenant access state
10964
11509
  */
10965
- function TenantProvider({ children, fallback, onAuthSuccess, onAuthFailure, currentTenant, requestedTenant, saveCurrentTenant, saveUserTenants, handleTenantSwitch, saveVisitingTenant, removeVisitingTenant, saveUserTokens, saveTenant, onAutoJoinUserToTenant, }) {
11510
+ function TenantProvider({ children, fallback, onAuthSuccess, onAuthFailure, currentTenant, requestedTenant, saveCurrentTenant, saveUserTenants, handleTenantSwitch, saveVisitingTenant, removeVisitingTenant, saveUserTokens, saveTenant, onAutoJoinUserToTenant, redirectToAuthSpa, }) {
10966
11511
  const { userIsAccessingPublicRoute, setUserIsAccessingPublicRoute } = useAuthContext();
10967
11512
  const [determineUserPath, setDetermineUserPath] = React.useState(false);
10968
11513
  const [isLoading, setIsLoading] = React.useState(true);
@@ -10973,6 +11518,26 @@ function TenantProvider({ children, fallback, onAuthSuccess, onAuthFailure, curr
10973
11518
  const [getAppToken] = useGetAppTokensMutation();
10974
11519
  const [tenantKey, setTenantKey] = React.useState(currentTenant);
10975
11520
  const [metadata, setMetadata] = React.useState({});
11521
+ // Fetch custom domain to get platform_key
11522
+ const currentDomain = typeof window !== "undefined" ? window.location.hostname : "";
11523
+ const { data: customDomainData, isLoading: isLoadingCustomDomain, isError: isCustomDomainError, } = useGetCustomDomainsQuery({ params: { domain: currentDomain } }, { skip: !isWeb() || !currentDomain });
11524
+ // Extract platform_key from custom domain response to use as requestedTenant
11525
+ const customDomainPlatformKey = React.useMemo(() => {
11526
+ if (customDomainData &&
11527
+ typeof customDomainData === "object" &&
11528
+ "custom_domains" in customDomainData) {
11529
+ const domains = customDomainData.custom_domains;
11530
+ if (Array.isArray(domains) &&
11531
+ domains.length > 0 &&
11532
+ domains[0].platform_key) {
11533
+ console.log("[TenantProvider] Using platform_key from custom domain:", domains[0].platform_key);
11534
+ return domains[0].platform_key;
11535
+ }
11536
+ }
11537
+ return undefined;
11538
+ }, [customDomainData]);
11539
+ // Use custom domain platform_key as requested tenant if available, otherwise use provided requestedTenant
11540
+ const effectiveRequestedTenant = customDomainPlatformKey || requestedTenant;
10976
11541
  /**
10977
11542
  * Helper function to enhance tenants with platform metadata from user apps
10978
11543
  */
@@ -11032,24 +11597,32 @@ function TenantProvider({ children, fallback, onAuthSuccess, onAuthFailure, curr
11032
11597
  const otherTenant = tenants.find((t) => t.key !== MAIN_TENANT_KEY);
11033
11598
  if (mainTenant &&
11034
11599
  otherTenant &&
11035
- requestedTenant &&
11036
- requestedTenant !== otherTenant.key) {
11600
+ effectiveRequestedTenant &&
11601
+ effectiveRequestedTenant !== otherTenant.key) {
11037
11602
  handleTenantSwitch(otherTenant.key, true);
11038
11603
  console.log("TenantProvider: Triggering tenant switch to newly joined tenant:", otherTenant.key);
11039
11604
  }
11040
11605
  }
11041
- // Enhance tenants with platform metadata
11606
+ // Enhance tenants with platform metadatax
11042
11607
  let enhancedTenants = await enhanceTenants(tenants);
11608
+ // if there is customDomainPlatformKey and user doesn't belong to that tenant, trigger logout
11609
+ if (customDomainPlatformKey) {
11610
+ if (!(enhancedTenants === null || enhancedTenants === void 0 ? void 0 : enhancedTenants.find((tenant) => tenant.key === customDomainPlatformKey))) {
11611
+ redirectToAuthSpa === null || redirectToAuthSpa === void 0 ? void 0 : redirectToAuthSpa(undefined, undefined, true);
11612
+ return;
11613
+ }
11614
+ }
11043
11615
  saveUserTenants(enhancedTenants);
11044
11616
  // Find requested tenant or fallback to current tenant
11045
- console.log("checking requested tenant", { requestedTenant });
11046
- let tenant = enhancedTenants === null || enhancedTenants === void 0 ? void 0 : enhancedTenants.find((tenant) => tenant.key === requestedTenant);
11047
- console.log("requested tenant", { tenant });
11617
+ console.log("checking requested tenant", JSON.stringify({
11618
+ requestedTenant: effectiveRequestedTenant,
11619
+ customDomainPlatformKey,
11620
+ }));
11621
+ let tenant = enhancedTenants === null || enhancedTenants === void 0 ? void 0 : enhancedTenants.find((tenant) => tenant.key === effectiveRequestedTenant);
11622
+ console.log("requested tenant", tenant);
11048
11623
  if (!tenant && !userIsAccessingPublicRoute) {
11049
11624
  setDetermineUserPath(true);
11050
- console.log("no requested tenant, checking current tenant", {
11051
- currentTenant,
11052
- });
11625
+ console.log("no requested tenant, checking current tenant", currentTenant);
11053
11626
  tenant = enhancedTenants === null || enhancedTenants === void 0 ? void 0 : enhancedTenants.find((tenant) => tenant.key === currentTenant);
11054
11627
  console.log("current tenant", { tenant });
11055
11628
  }
@@ -11061,7 +11634,7 @@ function TenantProvider({ children, fallback, onAuthSuccess, onAuthFailure, curr
11061
11634
  tenant = enhancedTenants[0];
11062
11635
  }
11063
11636
  // Fetch and validate tenant metadata
11064
- console.log("fetching tenant metadata", { tenant });
11637
+ console.log("fetching tenant metadata", JSON.stringify(tenant));
11065
11638
  const { data: tenantMetadata } = await fetchTenantMetadata([
11066
11639
  {
11067
11640
  org: (tenant === null || tenant === void 0 ? void 0 : tenant.key) || currentTenant,
@@ -11203,28 +11776,44 @@ function TenantProvider({ children, fallback, onAuthSuccess, onAuthFailure, curr
11203
11776
  }
11204
11777
  // Effect to handle tenant determination when auth state changes
11205
11778
  React.useEffect(() => {
11779
+ // Wait for custom domain query to complete (unless skipped or error)
11780
+ const customDomainQuerySkipped = !isWeb() || !currentDomain;
11781
+ if (!customDomainQuerySkipped && isLoadingCustomDomain) {
11782
+ console.log("[TenantProvider] Waiting for custom domain query to complete...");
11783
+ return;
11784
+ }
11785
+ if (isCustomDomainError) {
11786
+ console.warn("[TenantProvider] Custom domain query failed, proceeding without custom domain platform_key");
11787
+ }
11206
11788
  // NOTE: currentTenant comes from local storage.
11207
11789
  // it's the tenant the user is currently signed into.
11208
11790
  console.log("determineWhichTenantToUse", {
11209
11791
  userIsAccessingPublicRoute,
11210
11792
  currentTenant,
11211
11793
  requestedTenant,
11794
+ effectiveRequestedTenant,
11795
+ customDomainPlatformKey,
11212
11796
  });
11213
- if (userIsAccessingPublicRoute && requestedTenant.length === 0) {
11797
+ if (userIsAccessingPublicRoute && effectiveRequestedTenant.length === 0) {
11214
11798
  setIsLoading(false);
11215
11799
  return;
11216
11800
  }
11217
- if (userIsAccessingPublicRoute && requestedTenant.length > 0) {
11801
+ if (userIsAccessingPublicRoute && effectiveRequestedTenant.length > 0) {
11218
11802
  setIsLoading(true);
11219
- setTenantKey(requestedTenant);
11220
- handleLoadTenantMetadata(requestedTenant);
11803
+ setTenantKey(effectiveRequestedTenant);
11804
+ handleLoadTenantMetadata(effectiveRequestedTenant);
11221
11805
  }
11222
11806
  else {
11223
11807
  setIsLoading(true);
11224
11808
  removeVisitingTenant === null || removeVisitingTenant === void 0 ? void 0 : removeVisitingTenant();
11225
11809
  determineWhichTenantToUse();
11226
11810
  }
11227
- }, [userIsAccessingPublicRoute, requestedTenant]);
11811
+ }, [
11812
+ userIsAccessingPublicRoute,
11813
+ effectiveRequestedTenant,
11814
+ isLoadingCustomDomain,
11815
+ isCustomDomainError,
11816
+ ]);
11228
11817
  // Show fallback component during tenant determination
11229
11818
  if (isLoading) {
11230
11819
  return fallback;
@@ -11260,21 +11849,14 @@ function TenantProvider({ children, fallback, onAuthSuccess, onAuthFailure, curr
11260
11849
  function MentorProvider({ children, fallback, onAuthSuccess, onAuthFailure, redirectToAuthSpa, redirectToMentor, onLoadMentorsPermissions, redirectToNoMentorsPage, redirectToCreateMentor, username, isAdmin, mainTenantKey, requestedMentorId, handleMentorNotFound, forceDetermineMentor = false, }) {
11261
11850
  const [isLoading, setIsLoading] = React.useState(true);
11262
11851
  const { userIsAccessingPublicRoute } = useAuthContext();
11263
- const { determineUserPath, tenantKey } = useTenantContext();
11852
+ const { determineUserPath, tenantKey, metadata } = useTenantContext();
11264
11853
  const isMainTenant = tenantKey === mainTenantKey;
11265
- console.log("MentorProvider initialized", {
11266
- username,
11267
- isAdmin,
11268
- tenantKey,
11269
- mainTenantKey,
11270
- isMainTenant,
11271
- requestedMentorId,
11272
- determineUserPath,
11273
- });
11854
+ console.log("MentorProvider initialized", username, isAdmin, tenantKey, mainTenantKey, isMainTenant, requestedMentorId, determineUserPath);
11274
11855
  const [fetchMentors] = useLazyGetMentorsQuery();
11275
11856
  const [fetchSeedMentors] = useLazySeedMentorsQuery();
11276
11857
  const [getMentorPublicSettings] = useLazyGetMentorPublicSettingsQuery();
11277
11858
  const [getRbacPermissions] = useGetRbacPermissionsMutation();
11859
+ const [getRecentlyAccessedMentors] = useLazyGetRecentlyAccessedMentorsQuery();
11278
11860
  const QUERY_LIMIT = 10;
11279
11861
  const loadMentorsPermissions = async (mentorDbId) => {
11280
11862
  try {
@@ -11301,21 +11883,69 @@ function MentorProvider({ children, fallback, onAuthSuccess, onAuthFailure, redi
11301
11883
  */
11302
11884
  async function determineMentorToRedirectTo() {
11303
11885
  var _a, _b, _c, _d, _e, _f, _g, _h, _j, _k, _l, _m, _o, _p, _q, _r, _s;
11304
- console.log("starting mentor determination process", {
11886
+ console.log("starting mentor determination process", JSON.stringify({
11305
11887
  tenantKey,
11306
11888
  username,
11307
11889
  isAdmin,
11308
11890
  isMainTenant,
11309
- });
11891
+ }));
11892
+ console.log("###################### metadata is ", metadata, typeof metadata);
11310
11893
  setIsLoading(true);
11311
11894
  try {
11312
11895
  // Get the user's recent mentors
11313
- console.log("fetching recent mentors", {
11896
+ console.log("fetching recent mentors", JSON.stringify({
11314
11897
  tenantKey,
11315
11898
  username,
11316
11899
  limit: QUERY_LIMIT,
11317
11900
  orderBy: "recently_accessed_at",
11901
+ }));
11902
+ if (typeof metadata === "object" &&
11903
+ metadata.skills_embedded_mentor_name) {
11904
+ const defaultMentor = JSON.parse(metadata.skills_embedded_mentor_name);
11905
+ if (defaultMentor === null || defaultMentor === void 0 ? void 0 : defaultMentor.unique_id) {
11906
+ if (defaultMentor === null || defaultMentor === void 0 ? void 0 : defaultMentor.id) {
11907
+ const rbacPermissions = await loadMentorsPermissions(defaultMentor === null || defaultMentor === void 0 ? void 0 : defaultMentor.id);
11908
+ onLoadMentorsPermissions === null || onLoadMentorsPermissions === void 0 ? void 0 : onLoadMentorsPermissions(rbacPermissions);
11909
+ }
11910
+ redirectToMentor(tenantKey, defaultMentor.unique_id);
11911
+ onAuthSuccess === null || onAuthSuccess === void 0 ? void 0 : onAuthSuccess();
11912
+ return;
11913
+ }
11914
+ }
11915
+ // Check for recently accessed mentors (second choice)
11916
+ console.log("checking recently accessed mentors", JSON.stringify({
11917
+ tenantKey,
11918
+ username,
11919
+ }));
11920
+ const recentlyAccessedResult = await getRecentlyAccessedMentors({
11921
+ org: tenantKey,
11922
+ // @ts-ignore
11923
+ userId: username,
11318
11924
  });
11925
+ // @ts-ignore
11926
+ const recentlyAccessedMentors = recentlyAccessedResult.data;
11927
+ const starredMentors = recentlyAccessedMentors === null || recentlyAccessedMentors === void 0 ? void 0 : recentlyAccessedMentors.starred_mentors;
11928
+ let recentMentors = recentlyAccessedMentors === null || recentlyAccessedMentors === void 0 ? void 0 : recentlyAccessedMentors.recent_mentors;
11929
+ if (starredMentors.length > 0) {
11930
+ const starredMentor = starredMentors[0];
11931
+ if (starredMentor === null || starredMentor === void 0 ? void 0 : starredMentor.unique_id) {
11932
+ const rbacPermissions = await loadMentorsPermissions(starredMentor === null || starredMentor === void 0 ? void 0 : starredMentor.id);
11933
+ onLoadMentorsPermissions === null || onLoadMentorsPermissions === void 0 ? void 0 : onLoadMentorsPermissions(rbacPermissions);
11934
+ redirectToMentor(tenantKey, starredMentor.unique_id);
11935
+ onAuthSuccess === null || onAuthSuccess === void 0 ? void 0 : onAuthSuccess();
11936
+ return;
11937
+ }
11938
+ }
11939
+ if (recentMentors.length > 0) {
11940
+ const recentMentor = recentMentors[0];
11941
+ if (recentMentor === null || recentMentor === void 0 ? void 0 : recentMentor.unique_id) {
11942
+ const rbacPermissions = await loadMentorsPermissions(recentMentor === null || recentMentor === void 0 ? void 0 : recentMentor.id);
11943
+ onLoadMentorsPermissions === null || onLoadMentorsPermissions === void 0 ? void 0 : onLoadMentorsPermissions(rbacPermissions);
11944
+ redirectToMentor(tenantKey, recentMentor.unique_id);
11945
+ onAuthSuccess === null || onAuthSuccess === void 0 ? void 0 : onAuthSuccess();
11946
+ return;
11947
+ }
11948
+ }
11319
11949
  const recentMentorsResult = await fetchMentors({
11320
11950
  // @ts-ignore
11321
11951
  org: tenantKey,
@@ -11323,20 +11953,20 @@ function MentorProvider({ children, fallback, onAuthSuccess, onAuthFailure, redi
11323
11953
  limit: QUERY_LIMIT,
11324
11954
  orderBy: "recently_accessed_at",
11325
11955
  });
11326
- const recentMentors = ((_a = recentMentorsResult.data) === null || _a === void 0 ? void 0 : _a.results) || [];
11327
- console.log("recent mentors fetched", {
11956
+ recentMentors = ((_a = recentMentorsResult.data) === null || _a === void 0 ? void 0 : _a.results) || [];
11957
+ console.log("recent mentors fetched", JSON.stringify({
11328
11958
  count: recentMentors.length,
11329
11959
  mentorIds: recentMentors.map((m) => m === null || m === void 0 ? void 0 : m.unique_id),
11330
- });
11960
+ }));
11331
11961
  // Check if we found recent mentors for the tenant
11332
11962
  if (recentMentors.length > 0) {
11333
11963
  const selectedMentorId = ((_b = recentMentors[0]) === null || _b === void 0 ? void 0 : _b.unique_id) || "";
11334
11964
  const selectedMentorDbId = ((_c = recentMentors[0]) === null || _c === void 0 ? void 0 : _c.id) || "";
11335
- console.log("redirecting to recent mentor", {
11965
+ console.log("redirecting to recent mentor", JSON.stringify({
11336
11966
  selectedMentorId,
11337
11967
  mentorName: (_d = recentMentors[0]) === null || _d === void 0 ? void 0 : _d.name,
11338
11968
  tenantKey,
11339
- });
11969
+ }));
11340
11970
  const rbacPermissions = await loadMentorsPermissions(selectedMentorDbId);
11341
11971
  // Select the most recent mentor as current mentor
11342
11972
  onLoadMentorsPermissions === null || onLoadMentorsPermissions === void 0 ? void 0 : onLoadMentorsPermissions(rbacPermissions);
@@ -11538,6 +12168,9 @@ function MentorProvider({ children, fallback, onAuthSuccess, onAuthFailure, redi
11538
12168
  isAdmin,
11539
12169
  });
11540
12170
  onAuthFailure === null || onAuthFailure === void 0 ? void 0 : onAuthFailure(`Unexpected error: ${errorMessage}`);
12171
+ console.log("[auth-redirect] Unexpected error in mentor provider", {
12172
+ error: errorMessage,
12173
+ });
11541
12174
  redirectToAuthSpa();
11542
12175
  }
11543
12176
  finally {
@@ -11545,11 +12178,7 @@ function MentorProvider({ children, fallback, onAuthSuccess, onAuthFailure, redi
11545
12178
  }
11546
12179
  }
11547
12180
  async function mentorExistsInTenant(tenantKey, requestedMentorId) {
11548
- console.log("checking if mentor exists in tenant", {
11549
- tenantKey,
11550
- requestedMentorId,
11551
- username,
11552
- });
12181
+ console.log("checking if mentor exists in tenant", tenantKey, requestedMentorId, username);
11553
12182
  try {
11554
12183
  const response = await getMentorPublicSettings({
11555
12184
  // @ts-ignore
@@ -11578,11 +12207,7 @@ function MentorProvider({ children, fallback, onAuthSuccess, onAuthFailure, redi
11578
12207
  // Effect to handle mentor determination when tenant path is determined
11579
12208
  React.useEffect(() => {
11580
12209
  async function checkMentor() {
11581
- console.log("starting mentor check process", {
11582
- determineUserPath,
11583
- requestedMentorId,
11584
- tenantKey,
11585
- });
12210
+ console.log("starting mentor check process", determineUserPath, requestedMentorId, tenantKey);
11586
12211
  if (userIsAccessingPublicRoute && !requestedMentorId) {
11587
12212
  setIsLoading(false);
11588
12213
  return;
@@ -11602,11 +12227,11 @@ function MentorProvider({ children, fallback, onAuthSuccess, onAuthFailure, redi
11602
12227
  const [mentorExists, requestedMentorDbId] = await mentorExistsInTenant(tenantKey, requestedMentorId);
11603
12228
  // If the mentor does not exist in the tenant, redirect the user to the correct mentor
11604
12229
  if (!mentorExists) {
11605
- console.log("requested mentor not found in tenant", {
12230
+ console.log("requested mentor not found in tenant", JSON.stringify({
11606
12231
  requestedMentorId,
11607
12232
  tenantKey,
11608
12233
  hasCustomHandler: !!handleMentorNotFound,
11609
- });
12234
+ }));
11610
12235
  if (handleMentorNotFound) {
11611
12236
  console.log("calling custom mentor not found handler");
11612
12237
  await handleMentorNotFound();
@@ -11618,9 +12243,7 @@ function MentorProvider({ children, fallback, onAuthSuccess, onAuthFailure, redi
11618
12243
  return;
11619
12244
  }
11620
12245
  else {
11621
- console.log("requested mentor exists in tenant, proceeding", {
11622
- requestedMentorId,
11623
- });
12246
+ console.log("requested mentor exists in tenant, proceeding", requestedMentorId);
11624
12247
  if (requestedMentorDbId) {
11625
12248
  const rbacPermissions = await loadMentorsPermissions(requestedMentorDbId);
11626
12249
  onLoadMentorsPermissions === null || onLoadMentorsPermissions === void 0 ? void 0 : onLoadMentorsPermissions(rbacPermissions);
@@ -12092,7 +12715,7 @@ function formatProdErrorMessage(code) {
12092
12715
 
12093
12716
  const defaultSessionIds = Object.fromEntries(Object.keys(advancedTabsProperties).map((key) => [key, ""]));
12094
12717
  const defaultChatState = Object.fromEntries(Object.keys(advancedTabsProperties).map((key) => [key, []]));
12095
- const initialState = {
12718
+ const initialState$1 = {
12096
12719
  chats: defaultChatState,
12097
12720
  isTyping: false,
12098
12721
  streaming: false,
@@ -12120,7 +12743,7 @@ const initialState = {
12120
12743
  };
12121
12744
  const chatSlice = createSlice({
12122
12745
  name: "chatSliceShared",
12123
- initialState,
12746
+ initialState: initialState$1,
12124
12747
  reducers: {
12125
12748
  setChats: (state, action) => {
12126
12749
  state.chats = action.payload;
@@ -12224,6 +12847,25 @@ const chatSlice = createSlice({
12224
12847
  setShowingSharedChat: (state, action) => {
12225
12848
  state.showingSharedChat = action.payload;
12226
12849
  },
12850
+ updateFileUrlInMessage: (state, action) => {
12851
+ const { fileId, fileUrl } = action.payload;
12852
+ // Update all tabs' messages that have this file
12853
+ Object.keys(state.chats).forEach((tab) => {
12854
+ state.chats[tab] = state.chats[tab].map((message) => {
12855
+ if (message.fileAttachments && message.fileAttachments.length > 0) {
12856
+ const updatedAttachments = message.fileAttachments.map((attachment) => {
12857
+ // Match by fileId
12858
+ if (attachment.fileId === fileId) {
12859
+ return { ...attachment, uploadUrl: fileUrl };
12860
+ }
12861
+ return attachment;
12862
+ });
12863
+ return { ...message, fileAttachments: updatedAttachments };
12864
+ }
12865
+ return message;
12866
+ });
12867
+ });
12868
+ },
12227
12869
  },
12228
12870
  });
12229
12871
  const chatActions = chatSlice.actions;
@@ -12507,6 +13149,61 @@ function useTimeTrackerNative(config) {
12507
13149
  };
12508
13150
  }
12509
13151
 
13152
+ const initialState = {
13153
+ attachedFiles: [],
13154
+ };
13155
+ const filesSlice = createSlice({
13156
+ name: "files",
13157
+ initialState,
13158
+ reducers: {
13159
+ addFiles: (state, action) => {
13160
+ state.attachedFiles = [...state.attachedFiles, ...action.payload];
13161
+ },
13162
+ updateFileProgress: (state, action) => {
13163
+ state.attachedFiles = state.attachedFiles.map((file) => file.id === action.payload.id
13164
+ ? { ...file, uploadProgress: action.payload.progress }
13165
+ : file);
13166
+ },
13167
+ updateFileStatus: (state, action) => {
13168
+ state.attachedFiles = state.attachedFiles.map((file) => file.id === action.payload.id
13169
+ ? { ...file, uploadStatus: action.payload.status }
13170
+ : file);
13171
+ },
13172
+ updateFileUrl: (state, action) => {
13173
+ state.attachedFiles = state.attachedFiles.map((file) => file.id === action.payload.id
13174
+ ? { ...file, uploadUrl: action.payload.uploadUrl }
13175
+ : file);
13176
+ },
13177
+ updateFileMetadata: (state, action) => {
13178
+ state.attachedFiles = state.attachedFiles.map((file) => file.id === action.payload.id
13179
+ ? {
13180
+ ...file,
13181
+ fileKey: action.payload.fileKey,
13182
+ fileId: action.payload.fileId,
13183
+ }
13184
+ : file);
13185
+ },
13186
+ updateFileRetryCount: (state, action) => {
13187
+ state.attachedFiles = state.attachedFiles.map((file) => file.id === action.payload.id
13188
+ ? { ...file, retryCount: action.payload.retryCount }
13189
+ : file);
13190
+ },
13191
+ updateFileUrlFromWebSocket: (state, action) => {
13192
+ state.attachedFiles = state.attachedFiles.map((file) => file.fileId === action.payload.fileId
13193
+ ? { ...file, fileUrl: action.payload.fileUrl }
13194
+ : file);
13195
+ },
13196
+ removeFile: (state, action) => {
13197
+ state.attachedFiles = state.attachedFiles.filter((file) => file.id !== action.payload);
13198
+ },
13199
+ clearFiles: (state) => {
13200
+ state.attachedFiles = [];
13201
+ },
13202
+ },
13203
+ });
13204
+ const { addFiles, removeFile, clearFiles, updateFileProgress, updateFileStatus, updateFileUrl, updateFileMetadata, updateFileRetryCount, updateFileUrlFromWebSocket, } = filesSlice.actions;
13205
+ const filesReducer = filesSlice.reducer;
13206
+
12510
13207
  const useChat = ({ wsUrl, wsToken, flowConfig, sessionId, stopGenerationWsUrl, enableHaptics = false, hapticFeedback, store, errorHandler, onStatusChange, onStreamingChange, onStreamingMessageUpdate, WebSocketImpl = WebSocket, redirectToAuthSpa, sendMessageToParentWebsite, on402Error, }) => {
12511
13208
  const dispatch = useDispatch();
12512
13209
  const isWebSocketPaused = React.useRef(false);
@@ -12542,8 +13239,8 @@ const useChat = ({ wsUrl, wsToken, flowConfig, sessionId, stopGenerationWsUrl, e
12542
13239
  }
12543
13240
  if (!wsToken) {
12544
13241
  if (!userIsAccessingPublicRoute) {
12545
- console.error("Token is missing for non-anonymous user");
12546
- redirectToAuthSpa();
13242
+ console.log("[auth-redirect] WebSocket token is missing for non-anonymous user");
13243
+ redirectToAuthSpa(undefined, undefined, true);
12547
13244
  return;
12548
13245
  }
12549
13246
  }
@@ -12598,6 +13295,16 @@ const useChat = ({ wsUrl, wsToken, flowConfig, sessionId, stopGenerationWsUrl, e
12598
13295
  onStreamingChange(!!messageData.isTyping);
12599
13296
  return;
12600
13297
  }
13298
+ // Handle file processing success
13299
+ if (messageData.type === "file_processing_success") {
13300
+ console.log("🟣 File processing success:", messageData);
13301
+ dispatch(chatActions.updateFileUrlInMessage({
13302
+ fileId: messageData.file_id,
13303
+ fileName: messageData.file_name,
13304
+ fileUrl: messageData.file_url,
13305
+ }));
13306
+ return;
13307
+ }
12601
13308
  // Handle start of new streaming session
12602
13309
  if (messageData.generation_id &&
12603
13310
  !messageData.data &&
@@ -12693,19 +13400,31 @@ const useChat = ({ wsUrl, wsToken, flowConfig, sessionId, stopGenerationWsUrl, e
12693
13400
  };
12694
13401
  };
12695
13402
  const sendMessage = React.useCallback(async (tab, text, options) => {
12696
- var _a;
13403
+ var _a, _b;
12697
13404
  dispatch(chatActions.setShowingSharedChat(false));
12698
- if (!text.trim())
13405
+ // Allow sending if there's text OR file references
13406
+ if (!text.trim() &&
13407
+ (!(options === null || options === void 0 ? void 0 : options.fileReferences) || options.fileReferences.length === 0)) {
12699
13408
  return;
13409
+ }
12700
13410
  onStatusChange("pending");
12701
13411
  isWebSocketPaused.current = false;
12702
13412
  await triggerHapticFeedback();
13413
+ // Create file attachments array from file references if present
13414
+ const fileAttachments = (_a = options === null || options === void 0 ? void 0 : options.fileReferences) === null || _a === void 0 ? void 0 : _a.map((ref) => ({
13415
+ fileName: ref.file_name,
13416
+ fileType: ref.content_type,
13417
+ fileSize: ref.file_size,
13418
+ uploadUrl: ref.upload_url, // Include URL for display
13419
+ fileId: ref.file_id, // Include fileId for matching WebSocket updates
13420
+ }));
12703
13421
  const userMessage = {
12704
13422
  id: `user-${Date.now()}`,
12705
13423
  role: "user",
12706
13424
  content: text,
12707
13425
  timestamp: new Date().toISOString(),
12708
- visible: (_a = options === null || options === void 0 ? void 0 : options.visible) !== null && _a !== void 0 ? _a : true,
13426
+ visible: (_b = options === null || options === void 0 ? void 0 : options.visible) !== null && _b !== void 0 ? _b : true,
13427
+ fileAttachments,
12709
13428
  };
12710
13429
  // Notify parent to add user message
12711
13430
  // onAddUserMessage?.(tab, userMessage);
@@ -12717,8 +13436,14 @@ const useChat = ({ wsUrl, wsToken, flowConfig, sessionId, stopGenerationWsUrl, e
12717
13436
  flow: flowConfig,
12718
13437
  session_id: sessionId,
12719
13438
  token: wsToken,
12720
- prompt: text,
13439
+ prompt: text || "", // Allow empty prompt when sending files
12721
13440
  };
13441
+ if ((options === null || options === void 0 ? void 0 : options.fileReferences) && options.fileReferences.length > 0) {
13442
+ messageData = {
13443
+ ...messageData,
13444
+ file_references: options.fileReferences,
13445
+ };
13446
+ }
12722
13447
  if (iframeContext.pageContent) {
12723
13448
  messageData = {
12724
13449
  ...messageData,
@@ -12903,7 +13628,7 @@ function useMentorSettings({ mentorId, tenantKey, username }) {
12903
13628
  };
12904
13629
  }
12905
13630
 
12906
- function useAdvancedChat({ tenantKey, mentorId, username = ANONYMOUS_USERNAME, token, wsUrl, stopGenerationWsUrl, redirectToAuthSpa, errorHandler, sendMessageToParentWebsite, isPreviewMode, mentorShareableToken, on402Error, }) {
13631
+ function useAdvancedChat({ tenantKey, mentorId, username = ANONYMOUS_USERNAME, token, wsUrl, stopGenerationWsUrl, redirectToAuthSpa, errorHandler, sendMessageToParentWebsite, isPreviewMode, mentorShareableToken, on402Error, cachedSessionId, onStartNewChat, }) {
12907
13632
  var _a, _b, _c, _d;
12908
13633
  const dispatch = useDispatch();
12909
13634
  const [createSessionId, { isLoading: isLoadingSessionIds }] = useCreateSessionIdMutation();
@@ -12942,7 +13667,7 @@ function useAdvancedChat({ tenantKey, mentorId, username = ANONYMOUS_USERNAME, t
12942
13667
  username,
12943
13668
  pathway: mentorId,
12944
13669
  },
12945
- sessionId: sessionIds[activeTab],
13670
+ sessionId: cachedSessionId !== null && cachedSessionId !== void 0 ? cachedSessionId : sessionIds[activeTab],
12946
13671
  activeTab,
12947
13672
  wsToken: token,
12948
13673
  errorHandler,
@@ -12953,6 +13678,49 @@ function useAdvancedChat({ tenantKey, mentorId, username = ANONYMOUS_USERNAME, t
12953
13678
  onStatusChange,
12954
13679
  on402Error,
12955
13680
  });
13681
+ const [getSessionChats, { isError: isErrorGettingSessionChats }] = useLazyGetSessionIdQuery();
13682
+ React.useEffect(() => {
13683
+ const getChats = async () => {
13684
+ var _a;
13685
+ try {
13686
+ const { data } = await getSessionChats({
13687
+ sessionId: cachedSessionId !== null && cachedSessionId !== void 0 ? cachedSessionId : "",
13688
+ org: tenantKey,
13689
+ share: true,
13690
+ });
13691
+ let previousChats = [];
13692
+ try {
13693
+ previousChats =
13694
+ ((_a = data === null || data === void 0 ? void 0 : data.results) === null || _a === void 0 ? void 0 : _a.map((result) => {
13695
+ return {
13696
+ ...result,
13697
+ role: result.type === "human" ? "user" : "assistant",
13698
+ visible: true,
13699
+ id: new Date().getTime(),
13700
+ content: typeof result.content === "object" &&
13701
+ result.content.length > 0
13702
+ ? result.content[0].text
13703
+ : result.content,
13704
+ };
13705
+ }).reverse()) || [];
13706
+ }
13707
+ catch (error) {
13708
+ console.error(JSON.stringify(error));
13709
+ }
13710
+ dispatch(chatActions.setNewMessages(previousChats));
13711
+ }
13712
+ catch (error) {
13713
+ console.error(JSON.stringify(error));
13714
+ }
13715
+ };
13716
+ if (cachedSessionId) {
13717
+ dispatch(chatActions.updateSessionIds(cachedSessionId));
13718
+ getChats();
13719
+ }
13720
+ }, [cachedSessionId]);
13721
+ React.useEffect(() => {
13722
+ }, [isErrorGettingSessionChats]);
13723
+ React.useEffect(() => { }, []);
12956
13724
  const startNewChat = React.useCallback(async () => {
12957
13725
  // Reset all chat state
12958
13726
  if (!showingSharedChat) {
@@ -12962,6 +13730,7 @@ function useAdvancedChat({ tenantKey, mentorId, username = ANONYMOUS_USERNAME, t
12962
13730
  dispatch(chatActions.setStreaming(false));
12963
13731
  dispatch(chatActions.resetCurrentStreamingMessage(undefined));
12964
13732
  dispatch(chatActions.setTools([]));
13733
+ dispatch(clearFiles(undefined));
12965
13734
  if (isPreviewMode) {
12966
13735
  return;
12967
13736
  }
@@ -12972,6 +13741,7 @@ function useAdvancedChat({ tenantKey, mentorId, username = ANONYMOUS_USERNAME, t
12972
13741
  // @ts-ignore
12973
13742
  requestBody["shareable_link_token"] = mentorShareableToken;
12974
13743
  }
13744
+ console.log("[startNewChat] requestBody", tenantKey, username, JSON.stringify(requestBody));
12975
13745
  const response = await createSessionId({
12976
13746
  org: tenantKey,
12977
13747
  // @ts-ignore
@@ -12979,10 +13749,12 @@ function useAdvancedChat({ tenantKey, mentorId, username = ANONYMOUS_USERNAME, t
12979
13749
  requestBody,
12980
13750
  }).unwrap();
12981
13751
  dispatch(chatActions.updateSessionIds(response.session_id));
12982
- // dispatch(chatActions.setShouldStartNewChat(false));
13752
+ onStartNewChat === null || onStartNewChat === void 0 ? void 0 : onStartNewChat(response.session_id);
12983
13753
  }
12984
13754
  catch (error) {
12985
- errorHandler === null || errorHandler === void 0 ? void 0 : errorHandler("Failed to start new chat");
13755
+ errorHandler === null || errorHandler === void 0 ? void 0 : errorHandler(`Failed to start new chat: ${JSON.stringify(error)}`);
13756
+ console.log("[auth-redirect] Failed to start new chat", JSON.stringify({ error }));
13757
+ redirectToAuthSpa(undefined, undefined, true);
12986
13758
  }
12987
13759
  }, [
12988
13760
  isPreviewMode,
@@ -12996,7 +13768,7 @@ function useAdvancedChat({ tenantKey, mentorId, username = ANONYMOUS_USERNAME, t
12996
13768
  ]);
12997
13769
  React.useEffect(() => {
12998
13770
  if (!showingSharedChat || mentorSettings.allowAnonymous) {
12999
- if (mentorSettings.allowAnonymous !== undefined) {
13771
+ if (mentorSettings.allowAnonymous !== undefined && !cachedSessionId) {
13000
13772
  startNewChat();
13001
13773
  }
13002
13774
  }
@@ -13048,7 +13820,7 @@ function useAdvancedChat({ tenantKey, mentorId, username = ANONYMOUS_USERNAME, t
13048
13820
  }
13049
13821
  }
13050
13822
  catch (error) {
13051
- errorHandler === null || errorHandler === void 0 ? void 0 : errorHandler("Failed to start new chat");
13823
+ errorHandler === null || errorHandler === void 0 ? void 0 : errorHandler(`Failed to start new chat: ${error}`);
13052
13824
  return;
13053
13825
  }
13054
13826
  }
@@ -17938,11 +18710,130 @@ const tenantSchema = z.object({
17938
18710
  });
17939
18711
  const tenantKeySchema = z.string().min(1);
17940
18712
 
18713
+ /**
18714
+ * Chat area size constants
18715
+ */
18716
+ const CHAT_AREA_SIZE = {
18717
+ DEFAULT: 672,
18718
+ MIN: 672,
18719
+ MAX: 1024,
18720
+ };
18721
+
18722
+ /**
18723
+ * Extract file information from File object
18724
+ */
18725
+ function getFileInfo(file) {
18726
+ const fileName = file.name;
18727
+ const contentType = file.type || "application/octet-stream";
18728
+ const fileSize = file.size;
18729
+ return {
18730
+ fileName,
18731
+ contentType,
18732
+ fileSize,
18733
+ };
18734
+ }
18735
+ /**
18736
+ * Request presigned S3 URL from backend
18737
+ * Note: This function should be called via the RTK Query mutation hook
18738
+ * This is a helper to show the data flow
18739
+ */
18740
+ async function requestPresignedUrl(sessionId, file, getUploadUrlFn, org, userId) {
18741
+ const { fileName, contentType, fileSize } = getFileInfo(file);
18742
+ return await getUploadUrlFn({
18743
+ org,
18744
+ userId,
18745
+ requestBody: {
18746
+ session_id: sessionId,
18747
+ file_name: fileName,
18748
+ content_type: contentType,
18749
+ file_size: fileSize,
18750
+ },
18751
+ });
18752
+ }
18753
+ /**
18754
+ * Upload file directly to S3 using presigned URL
18755
+ * Uses axios for cross-platform support (web + React Native)
18756
+ */
18757
+ async function uploadToS3(presignedUrl, file, contentType, onProgress) {
18758
+ await axios.put(presignedUrl, file, {
18759
+ headers: {
18760
+ "Content-Type": contentType,
18761
+ },
18762
+ onUploadProgress: (progressEvent) => {
18763
+ if (onProgress && progressEvent.total) {
18764
+ const progress = Math.round((progressEvent.loaded / progressEvent.total) * 100);
18765
+ onProgress(progress);
18766
+ }
18767
+ },
18768
+ });
18769
+ }
18770
+ /**
18771
+ * Complete file upload flow:
18772
+ * 1. Request presigned URL
18773
+ * 2. Upload to S3
18774
+ * 3. Return file reference
18775
+ */
18776
+ async function createFileReference(file, sessionId, getUploadUrlFn, org, userId, onProgress) {
18777
+ // Step 1: Get presigned URL
18778
+ const presignedResponse = await requestPresignedUrl(sessionId, file, getUploadUrlFn, org, userId);
18779
+ // Step 2: Upload to S3
18780
+ const { fileName, contentType, fileSize } = getFileInfo(file);
18781
+ await uploadToS3(presignedResponse.upload_url, file, contentType, onProgress);
18782
+ // Step 3: Return file reference
18783
+ return {
18784
+ file_id: presignedResponse.file_id,
18785
+ file_key: presignedResponse.file_key,
18786
+ file_name: fileName,
18787
+ content_type: contentType,
18788
+ file_size: fileSize,
18789
+ };
18790
+ }
18791
+ /**
18792
+ * Upload multiple files and return their references
18793
+ */
18794
+ async function createMultipleFileReferences(files, sessionId, getUploadUrlFn, org, userId, onFileProgress) {
18795
+ const fileReferences = [];
18796
+ for (let i = 0; i < files.length; i++) {
18797
+ const file = files[i];
18798
+ const onProgress = onFileProgress
18799
+ ? (progress) => onFileProgress(i, progress)
18800
+ : undefined;
18801
+ const fileReference = await createFileReference(file, sessionId, getUploadUrlFn, org, userId, onProgress);
18802
+ fileReferences.push(fileReference);
18803
+ }
18804
+ return fileReferences;
18805
+ }
18806
+ /**
18807
+ * Validate file before upload
18808
+ * Returns error message if invalid, null if valid
18809
+ */
18810
+ function validateFile(file, maxSizeBytes, allowedTypes) {
18811
+ var _a;
18812
+ // Check file size
18813
+ if (maxSizeBytes && file.size > maxSizeBytes) {
18814
+ const maxSizeMB = (maxSizeBytes / (1024 * 1024)).toFixed(2);
18815
+ const fileSizeMB = (file.size / (1024 * 1024)).toFixed(2);
18816
+ return `File size (${fileSizeMB}MB) exceeds maximum allowed size (${maxSizeMB}MB)`;
18817
+ }
18818
+ // Check file type
18819
+ if (allowedTypes && allowedTypes.length > 0) {
18820
+ const fileExtension = (_a = file.name.split(".").pop()) === null || _a === void 0 ? void 0 : _a.toLowerCase();
18821
+ const fileType = file.type.toLowerCase();
18822
+ const isTypeAllowed = allowedTypes.some((allowed) => fileType.includes(allowed.toLowerCase()) ||
18823
+ fileExtension === allowed.toLowerCase().replace(".", ""));
18824
+ if (!isTypeAllowed) {
18825
+ return `File type not allowed. Allowed types: ${allowedTypes.join(", ")}`;
18826
+ }
18827
+ }
18828
+ return null;
18829
+ }
18830
+
17941
18831
  exports.ALPHANUMERIC_32_REGEX = ALPHANUMERIC_32_REGEX;
17942
18832
  exports.ANONYMOUS_USERNAME = ANONYMOUS_USERNAME;
17943
18833
  exports.AuthContext = AuthContext;
17944
18834
  exports.AuthContextProvider = AuthContextProvider;
17945
18835
  exports.AuthProvider = AuthProvider;
18836
+ exports.CHAT_AREA_SIZE = CHAT_AREA_SIZE;
17946
18837
  exports.LOCAL_STORAGE_KEYS = LOCAL_STORAGE_KEYS;
17947
18838
  exports.MAX_INITIAL_WEBSOCKET_CONNECTION_ATTEMPTS = MAX_INITIAL_WEBSOCKET_CONNECTION_ATTEMPTS;
17948
18839
  exports.MENTOR_CHAT_DOCUMENTS_EXTENSIONS = MENTOR_CHAT_DOCUMENTS_EXTENSIONS;
@@ -17959,20 +18850,42 @@ exports.TenantContext = TenantContext;
17959
18850
  exports.TenantContextProvider = TenantContextProvider;
17960
18851
  exports.TenantProvider = TenantProvider;
17961
18852
  exports.TimeTracker = TimeTracker;
18853
+ exports.addFiles = addFiles;
17962
18854
  exports.addProtocolToUrl = addProtocolToUrl;
17963
18855
  exports.advancedTabs = advancedTabs;
17964
18856
  exports.advancedTabsProperties = advancedTabsProperties;
17965
18857
  exports.chatActions = chatActions;
17966
18858
  exports.chatSliceReducerShared = chatSliceReducerShared;
17967
18859
  exports.clearAuthCookies = clearAuthCookies;
18860
+ exports.clearCookies = clearCookies;
18861
+ exports.clearCurrentTenantCookie = clearCurrentTenantCookie;
18862
+ exports.clearFiles = clearFiles;
18863
+ exports.createFileReference = createFileReference;
18864
+ exports.createMultipleFileReferences = createMultipleFileReferences;
17968
18865
  exports.defaultSessionIds = defaultSessionIds;
18866
+ exports.deleteCookie = deleteCookie;
18867
+ exports.deleteCookieOnAllDomains = deleteCookieOnAllDomains;
18868
+ exports.filesReducer = filesReducer;
18869
+ exports.filesSlice = filesSlice;
17969
18870
  exports.formatRelativeTime = formatRelativeTime;
18871
+ exports.getAuthSpaJoinUrl = getAuthSpaJoinUrl;
18872
+ exports.getDomainParts = getDomainParts;
18873
+ exports.getFileInfo = getFileInfo;
17970
18874
  exports.getInitials = getInitials;
18875
+ exports.getParentDomain = getParentDomain;
18876
+ exports.getPlatformKey = getPlatformKey;
17971
18877
  exports.getTimeAgo = getTimeAgo;
17972
18878
  exports.getUserName = getUserName;
18879
+ exports.handleLogout = handleLogout;
17973
18880
  exports.isAlphaNumeric32 = isAlphaNumeric32;
18881
+ exports.isInIframe = isInIframe;
17974
18882
  exports.isJSON = isJSON;
18883
+ exports.isLoggedIn = isLoggedIn;
17975
18884
  exports.loadMetadataConfig = loadMetadataConfig;
18885
+ exports.redirectToAuthSpa = redirectToAuthSpa;
18886
+ exports.redirectToAuthSpaJoinTenant = redirectToAuthSpaJoinTenant;
18887
+ exports.removeFile = removeFile;
18888
+ exports.requestPresignedUrl = requestPresignedUrl;
17976
18889
  exports.selectActiveChatMessages = selectActiveChatMessages;
17977
18890
  exports.selectActiveTab = selectActiveTab;
17978
18891
  exports.selectChats = selectChats;
@@ -17993,10 +18906,19 @@ exports.selectStreaming = selectStreaming;
17993
18906
  exports.selectToken = selectToken;
17994
18907
  exports.selectTokenEnabled = selectTokenEnabled;
17995
18908
  exports.selectTools = selectTools;
18909
+ exports.sendMessageToParentWebsite = sendMessageToParentWebsite;
18910
+ exports.setCookieForAuth = setCookieForAuth;
17996
18911
  exports.syncAuthToCookies = syncAuthToCookies;
17997
18912
  exports.tenantKeySchema = tenantKeySchema;
17998
18913
  exports.tenantSchema = tenantSchema;
17999
18914
  exports.translatePrompt = translatePrompt;
18915
+ exports.updateFileMetadata = updateFileMetadata;
18916
+ exports.updateFileProgress = updateFileProgress;
18917
+ exports.updateFileRetryCount = updateFileRetryCount;
18918
+ exports.updateFileStatus = updateFileStatus;
18919
+ exports.updateFileUrl = updateFileUrl;
18920
+ exports.updateFileUrlFromWebSocket = updateFileUrlFromWebSocket;
18921
+ exports.uploadToS3 = uploadToS3;
18000
18922
  exports.useAdvancedChat = useAdvancedChat;
18001
18923
  exports.useAuthContext = useAuthContext;
18002
18924
  exports.useAuthProvider = useAuthProvider;
@@ -18014,4 +18936,5 @@ exports.useTimeTracker = useTimeTracker;
18014
18936
  exports.useTimeTrackerNative = useTimeTrackerNative;
18015
18937
  exports.useUserProfileUpdate = useUserProfileUpdate;
18016
18938
  exports.userDataSchema = userDataSchema;
18939
+ exports.validateFile = validateFile;
18017
18940
  //# sourceMappingURL=index.js.map