@corva/chat-core 0.1.5 → 0.1.7

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/dist/index.js CHANGED
@@ -307,7 +307,7 @@ var getUserSecondaryText = (user) => {
307
307
  }
308
308
  if (email) return email;
309
309
  if (titleOrRole) return titleOrRole;
310
- if (user.username) return `@${user.username}`;
310
+ if (user.username && !user.nickname) return `@${user.username}`;
311
311
  return void 0;
312
312
  };
313
313
 
@@ -1649,11 +1649,15 @@ function createGroupsAPI(http) {
1649
1649
  async function getServerMembers(serverId) {
1650
1650
  try {
1651
1651
  const response = await http.request(`/servers/${serverId}/members`);
1652
+ const nicknames = new Map(
1653
+ (response?.members || []).map((m) => [m._id.user, m.nickname || void 0])
1654
+ );
1652
1655
  const users = response?.users || [];
1653
1656
  return users.map((member) => ({
1654
1657
  _id: member._id,
1655
1658
  username: member.username,
1656
1659
  name: member.display_name || member.username,
1660
+ nickname: nicknames.get(member._id),
1657
1661
  status: member.online ? "online" : "offline",
1658
1662
  isBot: !!member.bot
1659
1663
  }));
@@ -2087,7 +2091,7 @@ function createEventRouter(userCache2, sessionToken, autumnUrl, handlers, getMem
2087
2091
  break;
2088
2092
  case "Ready": {
2089
2093
  const readyEvent = message;
2090
- handlers.onReady?.(readyEvent.channels, readyEvent.channel_unreads);
2094
+ handlers.onReady?.(readyEvent.channels, readyEvent.channel_unreads, readyEvent.servers);
2091
2095
  break;
2092
2096
  }
2093
2097
  case "Message":
@@ -2984,7 +2988,7 @@ var ASSET_ID_PARAM = {
2984
2988
  frac_fleet: "frac_fleet_id",
2985
2989
  intervention_unit: "intervention_unit_id"
2986
2990
  };
2987
- async function getAssetChatChannel(assetId, assetType) {
2991
+ async function getAssetChatSession(assetId, assetType) {
2988
2992
  if (!assetId || Number.isNaN(Number(assetId))) {
2989
2993
  throw new Error("Asset ID is required");
2990
2994
  }
@@ -2996,7 +3000,15 @@ async function getAssetChatChannel(assetId, assetType) {
2996
3000
  if (!response?.revolt_channel_id) {
2997
3001
  throw new Error("No revolt_channel_id returned from asset chat API");
2998
3002
  }
2999
- return response.revolt_channel_id;
3003
+ return {
3004
+ channelId: response.revolt_channel_id,
3005
+ serverId: response.revolt_channel_server_id ?? null,
3006
+ companyId: response.revolt_channel_company_id ?? null
3007
+ };
3008
+ }
3009
+ async function getAssetChatChannel(assetId, assetType) {
3010
+ const { channelId } = await getAssetChatSession(assetId, assetType);
3011
+ return channelId;
3000
3012
  }
3001
3013
 
3002
3014
  // src/services/corvaUserService.ts
@@ -3028,6 +3040,9 @@ function createCorvaUserService() {
3028
3040
  enrichUser(user) {
3029
3041
  const corvaUser = revoltToCorva.get(user._id);
3030
3042
  if (!corvaUser) {
3043
+ if (user.nickname) {
3044
+ return { ...user, displayName: user.nickname, displayAvatar: void 0 };
3045
+ }
3031
3046
  return {
3032
3047
  ...user,
3033
3048
  displayName: user.name || user.username || "Unknown User",
@@ -3278,6 +3293,8 @@ var invalidateVisibleUsers = () => {
3278
3293
  visibleUsersGeneration += 1;
3279
3294
  visibleUsersRequest = null;
3280
3295
  };
3296
+ var syncedExternalCompanies = /* @__PURE__ */ new Set();
3297
+ var ownCompanyId = null;
3281
3298
  var seedSocketUsers = (members) => {
3282
3299
  sharedRefs.socket?.seedUsers(members);
3283
3300
  sharedRefs.api?.seedUserCache(members);
@@ -3392,7 +3409,25 @@ var memberStore = createStore()((set, get) => ({
3392
3409
  const { api } = sharedRefs;
3393
3410
  if (!api) return;
3394
3411
  const { serverId } = authStore.getState();
3412
+ const external = getExternalChannel(roomId);
3395
3413
  try {
3414
+ if (external) {
3415
+ const members2 = await api.getServerMembers(external.serverId);
3416
+ get().setMembers(members2, roomId);
3417
+ seedSocketUsers(members2.map((m) => ({ _id: m._id, username: m.username })));
3418
+ const { companyId } = external;
3419
+ if (companyId != null && !syncedExternalCompanies.has(companyId)) {
3420
+ const colleagues = members2.filter((m) => m.nickname);
3421
+ const customers = members2.filter((m) => !m.nickname);
3422
+ const canMapColleagues = colleagues.length === 0 || ownCompanyId != null;
3423
+ if (ownCompanyId != null && ownCompanyId !== companyId && colleagues.length > 0) {
3424
+ await mapCorvaUsers(ownCompanyId, colleagues);
3425
+ }
3426
+ const synced = await mapCorvaUsers(companyId, customers);
3427
+ if (synced && canMapColleagues) syncedExternalCompanies.add(companyId);
3428
+ }
3429
+ return;
3430
+ }
3396
3431
  const useServerMembers = (isAssetChat || roomType === "c") && serverId;
3397
3432
  if (useServerMembers) {
3398
3433
  const { serverMembersCache, serverMembersLoaded } = get();
@@ -3402,9 +3437,10 @@ var memberStore = createStore()((set, get) => ({
3402
3437
  return;
3403
3438
  }
3404
3439
  const members2 = await api.getServerMembers(serverId);
3440
+ set({ serverMembersLoaded: true, serverMembersCache: members2 });
3441
+ if (getExternalChannel(roomId)) return;
3405
3442
  get().setMembers(members2, roomId);
3406
3443
  seedSocketUsers(members2.map((m) => ({ _id: m._id, username: m.username })));
3407
- set({ serverMembersLoaded: true, serverMembersCache: members2 });
3408
3444
  return;
3409
3445
  }
3410
3446
  const channel = await api.getChannel(roomId);
@@ -3430,12 +3466,20 @@ var memberStore = createStore()((set, get) => ({
3430
3466
  },
3431
3467
  searchUsers: async (query) => {
3432
3468
  try {
3433
- const allUsers = await get().getAllVisibleUsers();
3469
+ const currentRoomId = roomStore.getState().currentRoom?._id;
3470
+ const { members, membersRoomId } = get();
3471
+ const external = getExternalChannel(currentRoomId);
3472
+ let allUsers;
3473
+ if (external) allUsers = membersRoomId === currentRoomId ? members : [];
3474
+ else allUsers = await get().getAllVisibleUsers();
3434
3475
  const q = query.trim().toLowerCase();
3435
3476
  if (!q) return allUsers;
3436
- return allUsers.filter(
3437
- (u) => u.username?.toLowerCase().includes(q) || u.name?.toLowerCase().includes(q) || u.displayName?.toLowerCase().includes(q)
3438
- );
3477
+ return allUsers.filter((u) => {
3478
+ if (u.nickname && u.displayName === u.nickname) {
3479
+ return u.nickname.toLowerCase().includes(q);
3480
+ }
3481
+ return u.username?.toLowerCase().includes(q) || u.name?.toLowerCase().includes(q) || u.displayName?.toLowerCase().includes(q);
3482
+ });
3439
3483
  } catch (e) {
3440
3484
  console.error("Failed to search users:", e);
3441
3485
  return [];
@@ -3468,74 +3512,172 @@ var memberStore = createStore()((set, get) => ({
3468
3512
  return visibleUsersRequest;
3469
3513
  },
3470
3514
  syncCorvaUsers: async (companyId) => {
3471
- const { api } = sharedRefs;
3472
- if (!api) return false;
3473
- try {
3474
- const corvaUsersResponse = await getChatHost().corvaApi.get(
3475
- "/v2/users",
3476
- {
3477
- company_id: companyId ?? 1,
3478
- per_page: 500,
3479
- fields: [
3480
- "user.first_name",
3481
- "user.last_name",
3482
- "user.email",
3483
- "user.profile_photo",
3484
- "user.title",
3485
- "user.role",
3486
- "user.company"
3487
- ]
3488
- }
3489
- );
3490
- const corvaUsers = corvaUsersResponse?.data || [];
3491
- const allUsers = await get().getAllVisibleUsers();
3492
- const currentMembers = get().members;
3493
- const userMap = /* @__PURE__ */ new Map();
3494
- allUsers.forEach((u) => userMap.set(u._id, u));
3495
- currentMembers.forEach((u) => {
3515
+ if (!sharedRefs.api) return false;
3516
+ ownCompanyId = companyId ?? 1;
3517
+ const allUsers = await get().getAllVisibleUsers();
3518
+ const userMap = /* @__PURE__ */ new Map();
3519
+ allUsers.forEach((u) => userMap.set(u._id, u));
3520
+ const { members, membersRoomId } = get();
3521
+ if (!getExternalChannel(membersRoomId)) {
3522
+ members.forEach((u) => {
3496
3523
  if (!userMap.has(u._id)) userMap.set(u._id, u);
3497
3524
  });
3498
- const usersToSync = Array.from(userMap.values());
3499
- if (usersToSync.length === 0) return false;
3500
- const corvaUsersByUsername = /* @__PURE__ */ new Map();
3501
- corvaUsers.forEach((corvaUser) => {
3502
- const email = corvaUser.attributes?.email;
3503
- if (email) {
3504
- const username = email.split("@")[0].toLowerCase();
3505
- corvaUsersByUsername.set(username, corvaUser);
3506
- }
3507
- });
3508
- const mappings = [];
3509
- usersToSync.forEach((revoltUser) => {
3510
- if (!revoltUser.username) return;
3511
- const username = revoltUser.username.toLowerCase();
3512
- const corvaUser = corvaUsersByUsername.get(username);
3513
- if (corvaUser) {
3514
- mappings.push({ revoltUserId: revoltUser._id, corvaUser });
3515
- }
3516
- });
3517
- get().bulkSetCorvaUserMappings(mappings);
3518
- mappings.forEach(({ revoltUserId, corvaUser }) => {
3519
- sharedRefs.corvaUserService.setMapping(revoltUserId, corvaUser);
3525
+ }
3526
+ const usersToSync = Array.from(userMap.values());
3527
+ if (usersToSync.length === 0) return false;
3528
+ return mapCorvaUsers(ownCompanyId, usersToSync);
3529
+ }
3530
+ }));
3531
+ var CORVA_USERS_PAGE_SIZE = 500;
3532
+ var CORVA_USERS_MAX_PAGES = 10;
3533
+ async function fetchCompanyCorvaUsers(companyId) {
3534
+ const users = [];
3535
+ for (let page = 1; page <= CORVA_USERS_MAX_PAGES; page += 1) {
3536
+ const response = await getChatHost().corvaApi.get("/v2/users", {
3537
+ company_id: companyId,
3538
+ per_page: CORVA_USERS_PAGE_SIZE,
3539
+ page,
3540
+ fields: [
3541
+ "user.first_name",
3542
+ "user.last_name",
3543
+ "user.email",
3544
+ "user.profile_photo",
3545
+ "user.title",
3546
+ "user.role",
3547
+ "user.company"
3548
+ ]
3549
+ });
3550
+ const data = response?.data || [];
3551
+ users.push(...data);
3552
+ if (data.length < CORVA_USERS_PAGE_SIZE) break;
3553
+ }
3554
+ return users;
3555
+ }
3556
+ var revoltUsernamesForEmail = (email) => {
3557
+ const username = email.split("@")[0].toLowerCase().slice(0, 32);
3558
+ return [username, username.replace(/\+/g, ".")];
3559
+ };
3560
+ async function mapCorvaUsers(companyId, revoltUsers) {
3561
+ try {
3562
+ const corvaUsersByUsername = /* @__PURE__ */ new Map();
3563
+ (await fetchCompanyCorvaUsers(companyId)).forEach((corvaUser) => {
3564
+ const email = corvaUser.attributes?.email;
3565
+ if (!email) return;
3566
+ revoltUsernamesForEmail(email).forEach((username) => {
3567
+ if (!corvaUsersByUsername.has(username)) corvaUsersByUsername.set(username, corvaUser);
3520
3568
  });
3521
- if (mappings.length > 0) {
3522
- const refreshedMembers = get().members;
3523
- const currentRoomId = roomStore.getState().currentRoom?._id;
3524
- get().setMembers(refreshedMembers, currentRoomId);
3525
- set({ allVisibleUsersCache: null });
3526
- invalidateVisibleUsers();
3569
+ });
3570
+ const mappings = [];
3571
+ revoltUsers.forEach((revoltUser) => {
3572
+ if (!revoltUser.username) return;
3573
+ const corvaUser = corvaUsersByUsername.get(revoltUser.username.toLowerCase());
3574
+ if (corvaUser) {
3575
+ mappings.push({ revoltUserId: revoltUser._id, corvaUser });
3527
3576
  }
3528
- return true;
3529
- } catch (error) {
3530
- console.error("Failed to sync Corva users:", error);
3531
- return false;
3577
+ });
3578
+ const store = memberStore.getState();
3579
+ store.bulkSetCorvaUserMappings(mappings);
3580
+ mappings.forEach(({ revoltUserId, corvaUser }) => {
3581
+ sharedRefs.corvaUserService.setMapping(revoltUserId, corvaUser);
3582
+ });
3583
+ if (mappings.length > 0) {
3584
+ const currentRoomId = roomStore.getState().currentRoom?._id;
3585
+ store.setMembers(memberStore.getState().members, currentRoomId);
3586
+ memberStore.setState({ allVisibleUsersCache: null });
3587
+ invalidateVisibleUsers();
3532
3588
  }
3589
+ return true;
3590
+ } catch (error) {
3591
+ console.error("Failed to sync Corva users:", error);
3592
+ return false;
3533
3593
  }
3534
- }));
3594
+ }
3535
3595
  var resetMemberStore = () => {
3596
+ syncedExternalCompanies.clear();
3597
+ ownCompanyId = null;
3536
3598
  invalidateVisibleUsers();
3537
3599
  memberStore.setState(getInitialState());
3538
3600
  };
3601
+
3602
+ // src/store/services/externalChatJoin.ts
3603
+ var ASSET_RESOURCE = {
3604
+ rig: "rigs",
3605
+ frac_fleet: "frac_fleets",
3606
+ intervention_unit: "intervention_units"
3607
+ };
3608
+ var ownerRequests = /* @__PURE__ */ new Map();
3609
+ var joinedThisSession = /* @__PURE__ */ new Set();
3610
+ async function fetchAssetOwnerCompany(assetId, assetType) {
3611
+ const response = await getChatHost().corvaApi.get(
3612
+ `/v2/${ASSET_RESOURCE[assetType]}/${assetId}`,
3613
+ { fields: [`${assetType}.company`, "company.name"], include: "company" }
3614
+ );
3615
+ const companyId = Number(response?.data?.relationships?.company?.data?.id);
3616
+ if (!Number.isFinite(companyId)) throw new Error("Asset company is missing");
3617
+ const company = response?.included?.find(
3618
+ (item) => item.type === "company" && Number(item.id) === companyId
3619
+ );
3620
+ return { id: companyId, name: company?.attributes?.name ?? null };
3621
+ }
3622
+ function getAssetOwnerCompany(assetId, assetType) {
3623
+ const key = `${assetType}:${assetId}`;
3624
+ const cached = ownerRequests.get(key);
3625
+ if (cached) return cached;
3626
+ const request = fetchAssetOwnerCompany(assetId, assetType);
3627
+ request.catch(() => ownerRequests.delete(key));
3628
+ ownerRequests.set(key, request);
3629
+ return request;
3630
+ }
3631
+ var normalizeName = (name) => name.trim().toLowerCase();
3632
+ function isOnCompanyServer(serverNames, companyName) {
3633
+ if (!companyName) return false;
3634
+ const target = normalizeName(companyName);
3635
+ return serverNames.some((name) => normalizeName(name) === target);
3636
+ }
3637
+ var joinedKey = (revoltUserId) => `corva_chat_joined_companies_${revoltUserId}`;
3638
+ function readJoinedCompanies(revoltUserId) {
3639
+ try {
3640
+ const raw = getChatStorage().getItem(joinedKey(revoltUserId));
3641
+ const parsed = raw ? JSON.parse(raw) : [];
3642
+ return Array.isArray(parsed) ? parsed.filter((id) => typeof id === "number") : [];
3643
+ } catch {
3644
+ return [];
3645
+ }
3646
+ }
3647
+ function hasJoinedCompany(revoltUserId, companyId) {
3648
+ return joinedThisSession.has(`${revoltUserId}:${companyId}`) || readJoinedCompanies(revoltUserId).includes(companyId);
3649
+ }
3650
+ function markCompanyJoined(revoltUserId, companyId) {
3651
+ joinedThisSession.add(`${revoltUserId}:${companyId}`);
3652
+ const joined = readJoinedCompanies(revoltUserId);
3653
+ if (joined.includes(companyId)) return;
3654
+ try {
3655
+ getChatStorage().setItem(joinedKey(revoltUserId), JSON.stringify([...joined, companyId]));
3656
+ } catch (error) {
3657
+ console.error("Failed to save joined company:", error);
3658
+ }
3659
+ }
3660
+ function resetAssetOwnerCompanies() {
3661
+ ownerRequests.clear();
3662
+ joinedThisSession.clear();
3663
+ }
3664
+
3665
+ // src/store/stores/assetStore.ts
3666
+ var SERVER_NAMES_WAIT_MS = 5e3;
3667
+ var joinApprovedAssets = /* @__PURE__ */ new Set();
3668
+ async function getJoinRequired(assetId, assetType) {
3669
+ const { corvaCompanyId, user } = authStore.getState();
3670
+ if (!user?._id) return null;
3671
+ if (joinApprovedAssets.has(`${assetType}:${assetId}`)) return null;
3672
+ const owner = await getAssetOwnerCompany(assetId, assetType);
3673
+ if (owner.id === corvaCompanyId || hasJoinedCompany(user._id, owner.id)) return null;
3674
+ const serverNames = await waitForServerNames(SERVER_NAMES_WAIT_MS);
3675
+ if (serverNames && isOnCompanyServer(serverNames, owner.name)) {
3676
+ markCompanyJoined(user._id, owner.id);
3677
+ return null;
3678
+ }
3679
+ return { assetId, assetType, companyId: owner.id, companyName: owner.name };
3680
+ }
3539
3681
  var registerAssetChatChannel = (channelId, assetId, assetType) => {
3540
3682
  const id = Number(assetId);
3541
3683
  if (!Number.isFinite(id)) return;
@@ -3546,6 +3688,15 @@ var registerAssetChatChannel = (channelId, assetId, assetType) => {
3546
3688
  intervention_unit_id: assetType === "intervention_unit" ? id : null
3547
3689
  });
3548
3690
  };
3691
+ var registerChannelServer = ({ channelId, serverId, companyId }) => {
3692
+ const wasExternal = isExternalServerChannel(channelId);
3693
+ authStore.getState().setChannelServer(channelId, serverId, companyId);
3694
+ if (wasExternal === isExternalServerChannel(channelId)) return;
3695
+ const room = roomStore.getState().currentRoom;
3696
+ if (room?._id === channelId) {
3697
+ memberStore.getState().loadRoomMembers(channelId, room.t, true).catch((e) => console.error("Failed to reload asset chat members:", e));
3698
+ }
3699
+ };
3549
3700
  var openRoomLockedAsset = () => {
3550
3701
  const room = roomStore.getState().currentRoom;
3551
3702
  if (!room?._id) return null;
@@ -3565,6 +3716,7 @@ var getInitialState2 = () => ({
3565
3716
  currentAssetStatus: null,
3566
3717
  assetChatId: null,
3567
3718
  assetChatError: null,
3719
+ joinRequired: null,
3568
3720
  knownAssetChatIds: /* @__PURE__ */ new Set(),
3569
3721
  panelSyncedAssetId: null,
3570
3722
  isAssetLocked: false,
@@ -3577,7 +3729,9 @@ var assetStore = createStore()((set, get) => ({
3577
3729
  setAssetContext: async (assetId, assetType, assetName, assetStatus, skipAutoSelect) => {
3578
3730
  const currentState = get();
3579
3731
  const isSameAsset = currentState.currentAssetId === assetId;
3580
- if (isSameAsset && (currentState.assetChatId || currentState.assetChatError)) return;
3732
+ if (isSameAsset && (currentState.assetChatId || currentState.assetChatError || currentState.joinRequired)) {
3733
+ return;
3734
+ }
3581
3735
  const isAssetChanging = !isSameAsset;
3582
3736
  uiStore.setState({ isLoading: true });
3583
3737
  set({
@@ -3586,13 +3740,23 @@ var assetStore = createStore()((set, get) => ({
3586
3740
  currentAssetName: assetName || assetId,
3587
3741
  currentAssetStatus: assetStatus ?? null,
3588
3742
  assetChatError: null,
3743
+ joinRequired: null,
3589
3744
  ...isSameAsset ? {} : { assetChatId: null },
3590
3745
  ...isAssetChanging && { isAssetSwitching: true }
3591
3746
  });
3592
3747
  const isStale = () => get().currentAssetId !== assetId;
3593
3748
  try {
3594
- const chatId = await getAssetChatChannel(assetId, assetType);
3749
+ const joinRequired = await getJoinRequired(assetId, assetType);
3595
3750
  if (isStale()) return;
3751
+ if (joinRequired) {
3752
+ set({ joinRequired });
3753
+ uiStore.setState({ isLoading: false });
3754
+ return;
3755
+ }
3756
+ const session = await getAssetChatSession(assetId, assetType);
3757
+ if (isStale()) return;
3758
+ const chatId = session.channelId;
3759
+ registerChannelServer(session);
3596
3760
  registerAssetChatChannel(chatId, assetId, assetType);
3597
3761
  set({
3598
3762
  assetChatId: chatId,
@@ -3625,7 +3789,8 @@ var assetStore = createStore()((set, get) => ({
3625
3789
  assetChatId: null,
3626
3790
  panelSyncedAssetId: null,
3627
3791
  lockedAsset: null,
3628
- assetChatError: null
3792
+ assetChatError: null,
3793
+ joinRequired: null
3629
3794
  });
3630
3795
  if (currentUser && previousAssetChatId && roomStore.getState().currentRoom?._id === previousAssetChatId) {
3631
3796
  const generalChat = findGeneralRoom(roomStore.getState().subscriptions);
@@ -3634,6 +3799,26 @@ var assetStore = createStore()((set, get) => ({
3634
3799
  }
3635
3800
  }
3636
3801
  },
3802
+ joinAssetChat: async () => {
3803
+ const { joinRequired } = get();
3804
+ const userId = authStore.getState().user?._id;
3805
+ if (!joinRequired || !userId) return;
3806
+ const approvalKey = `${joinRequired.assetType}:${joinRequired.assetId}`;
3807
+ joinApprovedAssets.add(approvalKey);
3808
+ set({ joinRequired: null });
3809
+ const { currentAssetName, currentAssetStatus } = get();
3810
+ try {
3811
+ await get().setAssetContext(
3812
+ joinRequired.assetId,
3813
+ joinRequired.assetType,
3814
+ currentAssetName ?? void 0,
3815
+ currentAssetStatus ?? void 0
3816
+ );
3817
+ if (get().assetChatId) markCompanyJoined(userId, joinRequired.companyId);
3818
+ } finally {
3819
+ joinApprovedAssets.delete(approvalKey);
3820
+ }
3821
+ },
3637
3822
  ensureAssetChatSubscription: async () => {
3638
3823
  const { currentAssetId, currentAssetType } = get();
3639
3824
  if (!currentAssetId || !currentAssetType) return null;
@@ -3644,8 +3829,21 @@ var assetStore = createStore()((set, get) => ({
3644
3829
  try {
3645
3830
  let chatId = get().assetChatId;
3646
3831
  if (!chatId) {
3832
+ let joinRequired;
3833
+ try {
3834
+ joinRequired = await getJoinRequired(currentAssetId, currentAssetType);
3835
+ } catch (e) {
3836
+ console.error("Failed to check asset chat access:", e);
3837
+ return null;
3838
+ }
3839
+ if (joinRequired) {
3840
+ if (get().currentAssetId === currentAssetId) set({ joinRequired });
3841
+ return null;
3842
+ }
3647
3843
  try {
3648
- chatId = await getAssetChatChannel(currentAssetId, currentAssetType);
3844
+ const session = await getAssetChatSession(currentAssetId, currentAssetType);
3845
+ chatId = session.channelId;
3846
+ registerChannelServer(session);
3649
3847
  registerAssetChatChannel(chatId, currentAssetId, currentAssetType);
3650
3848
  set({
3651
3849
  assetChatId: chatId,
@@ -4480,6 +4678,9 @@ onChatStorageConfigured(() => uiStore.setState(loadAttentionBudget()));
4480
4678
  var getInitialState6 = () => ({
4481
4679
  user: null,
4482
4680
  serverId: null,
4681
+ corvaCompanyId: null,
4682
+ externalChannels: {},
4683
+ serverNames: null,
4483
4684
  isConnected: false,
4484
4685
  hasEverConnected: false,
4485
4686
  connectionGaveUp: false,
@@ -4502,6 +4703,14 @@ var authStore = createStore()((set, get) => ({
4502
4703
  channel
4503
4704
  ]
4504
4705
  })),
4706
+ setChannelServer: (channelId, serverId, companyId) => set((state) => {
4707
+ const { [channelId]: previous, ...rest } = state.externalChannels;
4708
+ const isExternal = !!serverId && !!state.serverId && serverId !== state.serverId;
4709
+ if (!isExternal) return previous ? { externalChannels: rest } : state;
4710
+ if (previous?.serverId === serverId && previous.companyId === companyId) return state;
4711
+ return { externalChannels: { ...rest, [channelId]: { serverId, companyId } } };
4712
+ }),
4713
+ setServerNames: (names) => set({ serverNames: names }),
4505
4714
  markChatUsed: () => {
4506
4715
  if (get().chatUsed === true) return;
4507
4716
  set({ chatUsed: true });
@@ -4602,6 +4811,7 @@ var authStore = createStore()((set, get) => ({
4602
4811
  getChatHost().notifier?.onLogout?.();
4603
4812
  resetRoomStore();
4604
4813
  resetAssetStore();
4814
+ resetAssetOwnerCompanies();
4605
4815
  resetMessageStore();
4606
4816
  resetChatAssetPermissionsSnapshot();
4607
4817
  resetUIStore();
@@ -4669,6 +4879,24 @@ var authStore = createStore()((set, get) => ({
4669
4879
  isAuthenticated: () => !!get().user,
4670
4880
  isSocketConnected: () => !!sharedRefs.socket?.isConnected()
4671
4881
  }));
4882
+ var getExternalChannel = (roomId) => roomId && authStore.getState().externalChannels[roomId] || null;
4883
+ var waitForServerNames = (timeoutMs) => {
4884
+ const current = authStore.getState().serverNames;
4885
+ if (current) return Promise.resolve(current);
4886
+ return new Promise((resolve) => {
4887
+ const timer = setTimeout(() => {
4888
+ unsubscribe();
4889
+ resolve(null);
4890
+ }, timeoutMs);
4891
+ const unsubscribe = authStore.subscribe((state) => {
4892
+ if (!state.serverNames) return;
4893
+ clearTimeout(timer);
4894
+ unsubscribe();
4895
+ resolve(state.serverNames);
4896
+ });
4897
+ });
4898
+ };
4899
+ var isExternalServerChannel = (roomId) => !!getExternalChannel(roomId);
4672
4900
  var resetAuthStore = () => authStore.setState(getInitialState6());
4673
4901
 
4674
4902
  // src/store/stores/messageStore.ts
@@ -5143,8 +5371,11 @@ var createSocketEventHandlers = (config) => {
5143
5371
  onDisconnected: () => {
5144
5372
  authStore.setState({ isConnected: false });
5145
5373
  },
5146
- onReady: (channels, channelUnreads) => {
5374
+ onReady: (channels, channelUnreads, servers) => {
5147
5375
  if (!authStore.getState().user?._id) return;
5376
+ authStore.getState().setServerNames(
5377
+ (servers ?? []).map((server) => server.name).filter((name) => !!name)
5378
+ );
5148
5379
  const channelLastMsg = /* @__PURE__ */ new Map();
5149
5380
  channels.forEach((ch) => {
5150
5381
  if (ch.last_message_id) {
@@ -5732,6 +5963,9 @@ async function handleUnauthorized() {
5732
5963
  function ensureChatSession(corvaUser) {
5733
5964
  lastCorvaUser = corvaUser;
5734
5965
  initChat();
5966
+ if (authStore.getState().corvaCompanyId !== corvaUser.company_id) {
5967
+ authStore.setState({ corvaCompanyId: corvaUser.company_id ?? null });
5968
+ }
5735
5969
  sharedRefs.api?.setUnauthorizedHandler(() => {
5736
5970
  handleUnauthorized().catch((error) => console.error("Chat re-authentication failed", error));
5737
5971
  });
@@ -5755,6 +5989,6 @@ function ensureChatSession(corvaUser) {
5755
5989
  return inFlight;
5756
5990
  }
5757
5991
 
5758
- export { ALERT_SEVERITY, ASSET_API_FIELDS, ASSET_CHAT_PREFIXES, ASSET_NOUN, CHANNEL_NAME_MAX_LENGTH, CHANNEL_TYPES, CORVA_MESSAGE_TYPES, CORVA_SYS_PREFIX, DATE_SEPARATOR_LABELS, DEFAULT_CHANNEL_CONTENT_FILTER, DEFAULT_CHANNEL_CONTENT_FILTERS, DEFAULT_CHANNEL_PREFERENCE, DEFAULT_FAVORITE_ROOMS_SETTINGS, DEFAULT_HIDDEN_ROOMS_SETTINGS, DEFAULT_NOTIFICATION_PREFERENCES, DEFAULT_NOTIFICATION_SETTINGS, DEFAULT_ROOM_LIST_ORDER, DIRECT_MESSAGE_PLACEHOLDER, GENERAL_CHAT_NAME, HttpError, MAX_ATTACHMENT_SIZE_BYTES, MAX_ATTACHMENT_SIZE_MB, MAX_NAVIGATION_HISTORY, MENTION_REPLACE_PATTERN, MENTION_SPLIT_PATTERN, MUTE_PRESET_OPTIONS, NOTIFICATION_DESTINATIONS, NOTIFICATION_SETTING_ALL, NOTIFICATION_SETTING_MENTIONS, NOTIFICATION_SETTING_NOTHING, PAUSE_INDEFINITELY, PAUSE_PRESETS, PAUSE_PRESET_OPTIONS, REVOLT_SYSTEM_USER_ID, ROOM_LIST_ORDER, SESSION_STORAGE_KEY, SIDEBAR_SECTIONS, SIDEBAR_TABS, SOFT_DELETE_MARKER, SYSTEM_MESSAGE_TEXTS, SessionManager, WEBSOCKET_CONNECTING, WEBSOCKET_OPEN, addMessage, addOrUpdateSubscription, alertMessageAsText, assetStore, authStore, buildAppCommentMessageContent, buildAskCorvaMessageContent, buildFinalMessage, buildForwardMessageContent, buildGroupChannelName, canDeleteMessage, canEditMessage, channelContentFilterStore, channelToAsset, chatToastStore, clearLastOpenedRoom, compareByActivity, compareByName, compareByRecencyDesc, configureChat, configureChatStorage, createAckScheduler, createCorvaUserService, createDMSubscription, createGroupSubscription, createHttpClient, createLatestWinsQueue, createMemoryStorage, createMessageCache, createRevoltAPI, createRevoltSocket, createRoomTaskQueue, createSocketEventHandlers, createSoftDeletedMessage, createTypingManager, deriveAllowedChatAsset, enrichWithCorvaData, ensureChatSession, extractTimestampFromULID, failOptimisticMessage, favoriteRoomsStore, findGeneralRoom, formatAssetChatName, getAppCommentAttachments, getAssetChatChannel, getAssetTypeFromDisplayName, getChatHost, getChatStorage, getCorvaUserFields, getLastOpenedRoom, getMessageTimestamp, getPauseUntil, getReactionCount, getRoomDisplayName, getSystemMessageWithCorvaNames, getUserDisplayName, getUserSecondaryText, handleUnauthorized, hasReactions, hasUserReacted, initChat, installUnreadWatcher, isAlertMessage, isAppCommentMessage, isAskCorvaMessage, isChannelMuted, isChatAssetTypeAllowed, isChatStorageConfigured, isCurrentRoomSelection, isDeepEqual, isDefaultChannelPreference, isDisallowedAssetChatRoom, isDmGroup, isForwardedMessage, isGeneralRoom, isNotificationsPaused, isPauseActive, isSoftDeletedMessage, isSystemMessage, isUnread, isUserOnline, isValidPausePreset, isVisibleUnread, keepChatUsed, loadUntilFound, memberStore, messageStore, navigationHistoryStore, notificationStore, onChatStorageConfigured, parseCorvaSystemMessage, prepareRoomSelection, removeMessageFromList, removeSubscription, resetAssetStore, resetAuthStore, resetChannelContentFilterStore, resetChatAssetPermissionsSnapshot, resetChatHost, resetFavoriteRoomsStore, resetMemberStore, resetMessageStore, resetNavigationHistoryStore, resetNotificationStore, resetRoomStore, resetUIStore, roomStore, saveLastChatActivity, saveLastOpenedRoom, searchMessages, searchRooms, searchUsers, selectCanGoBack, selectCanGoForward, setAllowedChatAssetTypes, settleOptimisticMessage, sharedRefs, sortChannels, sortDMs, sortMessagesByTime, sortUsersByStatus, stripPlatformMentions, uiStore, updateMessageInList, uploadAndSend, validateChannelName, waitForNextPaint, wasRecentlyActive, withChannelPreferenceDefaults };
5992
+ export { ALERT_SEVERITY, ASSET_API_FIELDS, ASSET_CHAT_PREFIXES, ASSET_NOUN, CHANNEL_NAME_MAX_LENGTH, CHANNEL_TYPES, CORVA_MESSAGE_TYPES, CORVA_SYS_PREFIX, DATE_SEPARATOR_LABELS, DEFAULT_CHANNEL_CONTENT_FILTER, DEFAULT_CHANNEL_CONTENT_FILTERS, DEFAULT_CHANNEL_PREFERENCE, DEFAULT_FAVORITE_ROOMS_SETTINGS, DEFAULT_HIDDEN_ROOMS_SETTINGS, DEFAULT_NOTIFICATION_PREFERENCES, DEFAULT_NOTIFICATION_SETTINGS, DEFAULT_ROOM_LIST_ORDER, DIRECT_MESSAGE_PLACEHOLDER, GENERAL_CHAT_NAME, HttpError, MAX_ATTACHMENT_SIZE_BYTES, MAX_ATTACHMENT_SIZE_MB, MAX_NAVIGATION_HISTORY, MENTION_REPLACE_PATTERN, MENTION_SPLIT_PATTERN, MUTE_PRESET_OPTIONS, NOTIFICATION_DESTINATIONS, NOTIFICATION_SETTING_ALL, NOTIFICATION_SETTING_MENTIONS, NOTIFICATION_SETTING_NOTHING, PAUSE_INDEFINITELY, PAUSE_PRESETS, PAUSE_PRESET_OPTIONS, REVOLT_SYSTEM_USER_ID, ROOM_LIST_ORDER, SESSION_STORAGE_KEY, SIDEBAR_SECTIONS, SIDEBAR_TABS, SOFT_DELETE_MARKER, SYSTEM_MESSAGE_TEXTS, SessionManager, WEBSOCKET_CONNECTING, WEBSOCKET_OPEN, addMessage, addOrUpdateSubscription, alertMessageAsText, assetStore, authStore, buildAppCommentMessageContent, buildAskCorvaMessageContent, buildFinalMessage, buildForwardMessageContent, buildGroupChannelName, canDeleteMessage, canEditMessage, channelContentFilterStore, channelToAsset, chatToastStore, clearLastOpenedRoom, compareByActivity, compareByName, compareByRecencyDesc, configureChat, configureChatStorage, createAckScheduler, createCorvaUserService, createDMSubscription, createGroupSubscription, createHttpClient, createLatestWinsQueue, createMemoryStorage, createMessageCache, createRevoltAPI, createRevoltSocket, createRoomTaskQueue, createSocketEventHandlers, createSoftDeletedMessage, createTypingManager, deriveAllowedChatAsset, enrichWithCorvaData, ensureChatSession, extractTimestampFromULID, failOptimisticMessage, favoriteRoomsStore, findGeneralRoom, formatAssetChatName, getAppCommentAttachments, getAssetChatChannel, getAssetChatSession, getAssetTypeFromDisplayName, getChatHost, getChatStorage, getCorvaUserFields, getExternalChannel, getLastOpenedRoom, getMessageTimestamp, getPauseUntil, getReactionCount, getRoomDisplayName, getSystemMessageWithCorvaNames, getUserDisplayName, getUserSecondaryText, handleUnauthorized, hasReactions, hasUserReacted, initChat, installUnreadWatcher, isAlertMessage, isAppCommentMessage, isAskCorvaMessage, isChannelMuted, isChatAssetTypeAllowed, isChatStorageConfigured, isCurrentRoomSelection, isDeepEqual, isDefaultChannelPreference, isDisallowedAssetChatRoom, isDmGroup, isExternalServerChannel, isForwardedMessage, isGeneralRoom, isNotificationsPaused, isPauseActive, isSoftDeletedMessage, isSystemMessage, isUnread, isUserOnline, isValidPausePreset, isVisibleUnread, keepChatUsed, loadUntilFound, memberStore, messageStore, navigationHistoryStore, notificationStore, onChatStorageConfigured, parseCorvaSystemMessage, prepareRoomSelection, removeMessageFromList, removeSubscription, resetAssetStore, resetAuthStore, resetChannelContentFilterStore, resetChatAssetPermissionsSnapshot, resetChatHost, resetFavoriteRoomsStore, resetMemberStore, resetMessageStore, resetNavigationHistoryStore, resetNotificationStore, resetRoomStore, resetUIStore, roomStore, saveLastChatActivity, saveLastOpenedRoom, searchMessages, searchRooms, searchUsers, selectCanGoBack, selectCanGoForward, setAllowedChatAssetTypes, settleOptimisticMessage, sharedRefs, sortChannels, sortDMs, sortMessagesByTime, sortUsersByStatus, stripPlatformMentions, uiStore, updateMessageInList, uploadAndSend, validateChannelName, waitForNextPaint, waitForServerNames, wasRecentlyActive, withChannelPreferenceDefaults };
5759
5993
  //# sourceMappingURL=index.js.map
5760
5994
  //# sourceMappingURL=index.js.map