@burdenoff/fe-libs 2026.1023.7 → 2026.1023.8

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 (35) hide show
  1. package/dist/shared/graphql/client.d.ts +9 -0
  2. package/dist/shared/graphql/client.js +241 -201
  3. package/dist/shared/graphql/fetch.js +135 -123
  4. package/dist/shared/graphql/index.d.ts +1 -0
  5. package/dist/shared/graphql/workspaceOperationGuard.d.ts +70 -0
  6. package/dist/shared/graphql/workspaceOperationGuard.js +62 -0
  7. package/dist/shared/providers/AppShellProvider.d.ts +16 -0
  8. package/dist/shared/providers/AppShellProvider.js +232 -226
  9. package/dist/shared/providers/shell/AuthProvider.d.ts +14 -1
  10. package/dist/shared/providers/shell/AuthProvider.js +105 -94
  11. package/dist/shared/providers/shell/MultiGatewayProvider.d.ts +8 -1
  12. package/dist/shared/providers/shell/MultiGatewayProvider.js +115 -119
  13. package/dist/shared/providers/shell/ProfileStorageManager.js +1 -1
  14. package/dist/shared/providers/shell/WorkspaceWriteRefusedToastListener.d.ts +4 -0
  15. package/dist/shared/providers/shell/WorkspaceWriteRefusedToastListener.js +23 -0
  16. package/dist/shared/providers/shell/authProvider/identityChange.d.ts +26 -0
  17. package/dist/shared/providers/shell/authProvider/identityChange.js +11 -0
  18. package/dist/shared/providers/shell/authProvider/useAuthActions.d.ts +4 -1
  19. package/dist/shared/providers/shell/authProvider/useAuthActions.js +105 -92
  20. package/dist/shared/providers/shell/authProvider/useBridgeInitialization.d.ts +27 -1
  21. package/dist/shared/providers/shell/authProvider/useBridgeInitialization.js +82 -62
  22. package/dist/shared/providers/shell/authProvider/useRemoteSLO.d.ts +4 -1
  23. package/dist/shared/providers/shell/authProvider/useRemoteSLO.js +16 -14
  24. package/dist/shared/providers/shell/authProvider/useStorageSync.d.ts +4 -1
  25. package/dist/shared/providers/shell/authProvider/useStorageSync.js +19 -14
  26. package/dist/shared/providers/shell/contextSwitchCache.d.ts +4 -0
  27. package/dist/shared/providers/shell/contextSwitchCache.js +17 -0
  28. package/dist/shared/providers/shell/identityQueryReset.d.ts +17 -0
  29. package/dist/shared/providers/shell/identityQueryReset.js +21 -0
  30. package/dist/shared/providers/shell/identityScopedQueryReset.d.ts +16 -0
  31. package/dist/shared/providers/shell/identityScopedQueryReset.js +30 -0
  32. package/dist/shared/providers/shell/index.d.ts +1 -1
  33. package/dist/shared-graphql.js +11 -10
  34. package/dist/shared.js +129 -128
  35. package/package.json +2 -2
@@ -0,0 +1,26 @@
1
+ /**
2
+ * BOFF-9384: the signed-in account, and the announcement every path that
3
+ * changes it makes first (see `AuthProviderProps.onBeforeIdentityChange`).
4
+ */
5
+ /** Which path is about to change the signed-in account. */
6
+ export type IdentityChangeReason = 'login' | 'logout' | 'switch-account' | 'logout-all' | 'remote-slo' | 'bridge-sync' | 'storage-sync';
7
+ /** The account a path is about to make active: profile and user (null = signed out). */
8
+ export interface IdentitySnapshot {
9
+ profileId: string | null;
10
+ userId: string | null;
11
+ }
12
+ export declare const SIGNED_OUT: IdentitySnapshot;
13
+ /**
14
+ * Called BEFORE a path changes React state. The paths AuthProvider drives
15
+ * itself (sign-in, sign-out, account switch, sign-out of every account) call it
16
+ * before they write storage too; the background paths call it once storage
17
+ * already names the next account (remote single-logout after checkSLO cleared
18
+ * it, auth-bridge sync after it wrote the bridge's state, storage sync because
19
+ * a storage change is what woke it). It reaches `onBeforeIdentityChange` only
20
+ * when `next` differs from the account the shell has committed, so a token
21
+ * refresh or a repeated sync never announces.
22
+ */
23
+ export type AnnounceIdentityChange = (reason: IdentityChangeReason, next: IdentitySnapshot) => void;
24
+ export declare function identityKeyOf(profileId: string | null | undefined, userId: string | null | undefined): string;
25
+ /** The identity key of the signed-out state (no profile, no user). */
26
+ export declare const SIGNED_OUT_IDENTITY_KEY: string;
@@ -0,0 +1,11 @@
1
+ //#region src/shared/providers/shell/authProvider/identityChange.ts
2
+ var e = {
3
+ profileId: null,
4
+ userId: null
5
+ };
6
+ function t(e, t) {
7
+ return `${e ?? ""}:${t ?? ""}`;
8
+ }
9
+ var n = t(null, null);
10
+ //#endregion
11
+ export { e as SIGNED_OUT, n as SIGNED_OUT_IDENTITY_KEY, t as identityKeyOf };
@@ -1,5 +1,6 @@
1
1
  import { MutableRefObject } from 'react';
2
2
  import { ProfileUser, AuthTokens } from '../ProfileStorageManager';
3
+ import { AnnounceIdentityChange } from './identityChange';
3
4
  /**
4
5
  * BOFF-9411: the token for the authoritative SignOut request. The caller's
5
6
  * token comes first, then this hook's state, then storage for the active
@@ -31,6 +32,8 @@ export interface AuthActionsDeps {
31
32
  setIsLoading: (loading: boolean) => void;
32
33
  clearAccounts: () => void;
33
34
  refreshAccounts: () => void;
35
+ /** BOFF-9384: called before any storage or state change that switches the account. */
36
+ announceIdentityChange: AnnounceIdentityChange;
34
37
  }
35
38
  export interface LogoutOptions {
36
39
  /**
@@ -68,4 +71,4 @@ export interface AuthActions {
68
71
  addAccount: (user: ProfileUser, accessToken: string, refreshToken?: string) => void;
69
72
  removeAccount: (accountId: string) => void;
70
73
  }
71
- export declare function useAuthActions({ user, tokens, activeId, bridgeSyncInProgress, onRefreshToken, onTokenExpired, setActiveId, setUser, setTokens, setWorkspaceTokenLocal, setMfaRequiredState, setMfaChallengeIdState, setIsLoading, clearAccounts, refreshAccounts, }: AuthActionsDeps): AuthActions;
74
+ export declare function useAuthActions({ user, tokens, activeId, bridgeSyncInProgress, onRefreshToken, onTokenExpired, setActiveId, setUser, setTokens, setWorkspaceTokenLocal, setMfaRequiredState, setMfaChallengeIdState, setIsLoading, clearAccounts, refreshAccounts, announceIdentityChange, }: AuthActionsDeps): AuthActions;
@@ -1,12 +1,13 @@
1
1
  import { resolveGatewayUrls as e } from "../../../config/gatewayUrls.js";
2
- import { addProfile as t, getActiveProfileId as n, getProfileTokens as r, getProfileUser as i, getProfileWorkspaceToken as a, getProfiles as o, loginProfile as s, logoutAllProfiles as c, removeProfile as l, resolveActiveProfileId as u, setProfileTokens as d, setProfileUser as f, setProfileWorkspaceToken as p, switchProfile as m } from "../ProfileStorageManager.js";
3
- import { clearShellSsoCookies as h, setShellSsoCookies as g } from "../../../utils/authCookie.js";
4
- import { getAuthBridge as _ } from "../AuthBridgeClient.js";
5
- import { getCrossOriginLogoutUrl as v } from "./ssoRelay.js";
6
- import { getJwtExpiry as y } from "./jwt.js";
7
- import { useCallback as b } from "react";
2
+ import { addProfile as t, getActiveProfileId as n, getProfileTokens as r, getProfileUser as i, getProfileWorkspaceToken as a, getProfiles as o, getSelectableProfiles as s, loginProfile as c, logoutAllProfiles as l, removeProfile as u, resolveActiveProfileId as d, setProfileTokens as f, setProfileUser as p, setProfileWorkspaceToken as m, switchProfile as h } from "../ProfileStorageManager.js";
3
+ import { clearShellSsoCookies as g, setShellSsoCookies as _ } from "../../../utils/authCookie.js";
4
+ import { getAuthBridge as v } from "../AuthBridgeClient.js";
5
+ import { getCrossOriginLogoutUrl as y } from "./ssoRelay.js";
6
+ import { SIGNED_OUT as b } from "./identityChange.js";
7
+ import { getJwtExpiry as x } from "./jwt.js";
8
+ import { useCallback as S } from "react";
8
9
  //#region src/shared/providers/shell/authProvider/useAuthActions.ts
9
- function x(t) {
10
+ function C(t) {
10
11
  if (t) try {
11
12
  let { globalBaseUrl: n } = e();
12
13
  if (!n) return;
@@ -21,24 +22,29 @@ function x(t) {
21
22
  }).catch(() => {});
22
23
  } catch {}
23
24
  }
24
- function S(e, t, i) {
25
+ function w(e, t, i) {
25
26
  if (e) return e;
26
27
  if (t?.accessToken) return t.accessToken;
27
28
  let a = i ?? n();
28
29
  return (a ? r(a)?.accessToken : void 0) || void 0;
29
30
  }
30
- function C({ user: e, tokens: n, activeId: C, bridgeSyncInProgress: w, onRefreshToken: T, onTokenExpired: E, setActiveId: D, setUser: O, setTokens: k, setWorkspaceTokenLocal: A, setMfaRequiredState: j, setMfaChallengeIdState: M, setIsLoading: N, clearAccounts: P, refreshAccounts: F }) {
31
- let I = b((e, t, n) => {
32
- let r = y(t) ?? Date.now() + 3600 * 1e3, i = {
31
+ function T({ user: e, tokens: n, activeId: T, bridgeSyncInProgress: E, onRefreshToken: D, onTokenExpired: O, setActiveId: k, setUser: A, setTokens: j, setWorkspaceTokenLocal: M, setMfaRequiredState: N, setMfaChallengeIdState: P, setIsLoading: F, clearAccounts: I, refreshAccounts: L, announceIdentityChange: R }) {
32
+ let z = S((e, t, n) => {
33
+ let r = x(t) ?? Date.now() + 3600 * 1e3, i = {
33
34
  accessToken: t,
34
35
  refreshToken: n,
35
36
  expiresAt: r
36
- }, a = s(e, i);
37
- D(a), O(e), k(i), A(null), j(!1), M(null), F();
37
+ };
38
+ R("login", {
39
+ profileId: e.id,
40
+ userId: e.id
41
+ });
42
+ let a = c(e, i);
43
+ k(a), A(e), j(i), M(null), N(!1), P(null), L();
38
44
  try {
39
- g(a, window.location.origin);
45
+ _(a, window.location.origin);
40
46
  } catch {}
41
- w.current || _()?.notifyLogin({
47
+ E.current || v()?.notifyLogin({
42
48
  user: e,
43
49
  tokens: {
44
50
  accessToken: t,
@@ -50,141 +56,148 @@ function C({ user: e, tokens: n, activeId: C, bridgeSyncInProgress: w, onRefresh
50
56
  profiles: o()
51
57
  });
52
58
  }, [
53
- F,
54
- w,
55
- D,
56
- O,
59
+ L,
60
+ E,
57
61
  k,
58
62
  A,
59
63
  j,
60
- M
61
- ]), L = b((e) => {
64
+ M,
65
+ N,
66
+ P,
67
+ R
68
+ ]), B = S((e) => {
62
69
  let t = e?.authoritative !== !1;
63
- t && !w.current && x(S(e?.accessToken, n, C)), C && l(C);
64
- let o = u();
65
- o ? (D(o), O(i(o)), k(r(o)), A(a(o))) : (D(null), O(null), k(null), A(null)), j(!1), M(null), F();
70
+ t && !E.current && C(w(e?.accessToken, n, T)), R("logout", b), T && u(T);
71
+ let o = d();
72
+ o ? (k(o), A(i(o)), j(r(o)), M(a(o))) : (k(null), A(null), j(null), M(null)), N(!1), P(null), L();
66
73
  try {
67
- h();
74
+ g();
68
75
  } catch {}
69
- w.current || _()?.notifyLogout();
70
- let s = t ? v() : null;
71
- s && !w.current && window.location.replace(s);
76
+ E.current || v()?.notifyLogout();
77
+ let s = t ? y() : null;
78
+ s && !E.current && window.location.replace(s);
72
79
  }, [
73
- C,
80
+ T,
74
81
  n,
75
- F,
76
- w,
77
- D,
78
- O,
82
+ L,
83
+ E,
79
84
  k,
80
85
  A,
81
86
  j,
82
- M
83
- ]), R = b((n) => {
84
- if (!e || !C) return;
87
+ M,
88
+ N,
89
+ P,
90
+ R
91
+ ]), V = S((n) => {
92
+ if (!e || !T) return;
85
93
  let r = {
86
94
  ...e,
87
95
  ...n
88
96
  };
89
- O(r), f(C, r), t({
90
- id: C,
97
+ A(r), p(T, r), t({
98
+ id: T,
91
99
  email: r.email,
92
100
  name: r.name ?? `${r.firstName ?? ""} ${r.lastName ?? ""}`.trim(),
93
101
  avatar: r.avatar,
94
102
  lastLogin: (/* @__PURE__ */ new Date()).toISOString()
95
- }), F();
103
+ }), L();
96
104
  }, [
97
105
  e,
98
- C,
99
- F,
100
- O
101
- ]), z = b(async () => {
102
- if (!T || !C) return;
103
- let e = n?.refreshToken ?? r(C)?.refreshToken ?? void 0;
106
+ T,
107
+ L,
108
+ A
109
+ ]), H = S(async () => {
110
+ if (!D || !T) return;
111
+ let e = n?.refreshToken ?? r(T)?.refreshToken ?? void 0;
104
112
  if (e) {
105
- N(!0);
113
+ F(!0);
106
114
  try {
107
- let t = await T(e), n = y(t.accessToken), r = t.expiresAt ?? n ?? Date.now() + 1440 * 60 * 1e3, i = {
115
+ let t = await D(e), n = x(t.accessToken), r = t.expiresAt ?? n ?? Date.now() + 1440 * 60 * 1e3, i = {
108
116
  accessToken: t.accessToken,
109
117
  refreshToken: t.refreshToken ?? e,
110
118
  expiresAt: r
111
119
  };
112
- k(i), d(C, i), w.current || _()?.notifyTokenRefresh({
120
+ j(i), f(T, i), E.current || v()?.notifyTokenRefresh({
113
121
  accessToken: i.accessToken,
114
122
  refreshToken: i.refreshToken,
115
123
  expiresAt: i.expiresAt
116
124
  });
117
125
  } catch (e) {
118
- console.error("Failed to refresh token:", e), n?.expiresAt && n.expiresAt - Date.now() > 0 || (L({ authoritative: !1 }), E?.());
126
+ console.error("Failed to refresh token:", e), n?.expiresAt && n.expiresAt - Date.now() > 0 || (B({ authoritative: !1 }), O?.());
119
127
  } finally {
120
- N(!1);
128
+ F(!1);
121
129
  }
122
130
  }
123
131
  }, [
124
132
  n,
133
+ D,
125
134
  T,
126
- C,
127
- L,
135
+ B,
136
+ O,
128
137
  E,
129
- w,
130
- k,
131
- N
132
- ]), B = b((t) => e?.permissions ? e.permissions.includes(t) || e.permissions.includes("*") : !1, [e]), V = b((e) => {
133
- A(e), C && p(C, e);
134
- }, [C, A]), H = b((e, t) => {
135
- j(e), M(t ?? null);
136
- }, [j, M]), U = b((e) => {
137
- if (!m(e)) {
138
+ j,
139
+ F
140
+ ]), U = S((t) => e?.permissions ? e.permissions.includes(t) || e.permissions.includes("*") : !1, [e]), W = S((e) => {
141
+ M(e), T && m(T, e);
142
+ }, [T, M]), G = S((e, t) => {
143
+ N(e), P(t ?? null);
144
+ }, [N, P]), K = S((e) => {
145
+ if (s().some((t) => t.id === e) && R("switch-account", {
146
+ profileId: e,
147
+ userId: i(e)?.id ?? null
148
+ }), !h(e)) {
138
149
  console.error(`Profile ${e} not found`);
139
150
  return;
140
151
  }
141
- D(e), O(i(e)), k(r(e)), A(a(e)), j(!1), M(null), F(), w.current || _()?.notifyAccountSwitch(e);
152
+ k(e), A(i(e)), j(r(e)), M(a(e)), N(!1), P(null), L(), E.current || v()?.notifyAccountSwitch(e);
142
153
  }, [
143
- F,
144
- w,
145
- D,
146
- O,
154
+ L,
155
+ E,
147
156
  k,
148
157
  A,
149
158
  j,
150
- M
151
- ]), W = I, G = b((e) => {
152
- if (e === C) {
159
+ M,
160
+ N,
161
+ P,
162
+ R
163
+ ]), q = z, J = S((e) => {
164
+ if (e === T) {
153
165
  console.error("Cannot remove active account — logout first");
154
166
  return;
155
167
  }
156
- l(e), F();
157
- }, [C, F]);
168
+ u(e), L();
169
+ }, [T, L]);
158
170
  return {
159
- login: I,
160
- logout: L,
161
- logoutAll: b(() => {
162
- c(), D(null), O(null), k(null), A(null), j(!1), M(null), P();
171
+ login: z,
172
+ logout: B,
173
+ logoutAll: S(() => {
174
+ R("logout-all", b), l(), k(null), A(null), j(null), M(null), N(!1), P(null), I();
163
175
  try {
164
- h();
176
+ g();
165
177
  } catch {}
166
- w.current || _()?.notifyLogoutAll();
167
- let e = v();
168
- e && !w.current && window.location.replace(e);
178
+ E.current || v()?.notifyLogoutAll();
179
+ let e = y();
180
+ e && !E.current && window.location.replace(e);
169
181
  }, [
170
- w,
171
- D,
172
- O,
182
+ E,
173
183
  k,
174
184
  A,
175
185
  j,
176
186
  M,
177
- P
187
+ N,
188
+ P,
189
+ I,
190
+ R
178
191
  ]),
179
- updateUser: R,
180
- refreshAccessToken: z,
181
- hasPermission: B,
182
- setWorkspaceToken: V,
183
- setMfaState: H,
184
- switchAccount: U,
185
- addAccount: W,
186
- removeAccount: G
192
+ updateUser: V,
193
+ refreshAccessToken: H,
194
+ hasPermission: U,
195
+ setWorkspaceToken: W,
196
+ setMfaState: G,
197
+ switchAccount: K,
198
+ addAccount: q,
199
+ removeAccount: J
187
200
  };
188
201
  }
189
202
  //#endregion
190
- export { C as useAuthActions };
203
+ export { T as useAuthActions };
@@ -1,5 +1,7 @@
1
1
  import { MutableRefObject } from 'react';
2
2
  import { ProfileUser, AuthTokens } from '../ProfileStorageManager';
3
+ import { BridgeAuthState } from '../AuthBridgeClient';
4
+ import { AnnounceIdentityChange } from './identityChange';
3
5
  export interface BridgeInitializationDeps {
4
6
  bridgeUrl: string | undefined;
5
7
  bridgeAllowedOrigins: string | undefined;
@@ -13,5 +15,29 @@ export interface BridgeInitializationDeps {
13
15
  setWorkspaceTokenLocal: (token: string | null) => void;
14
16
  clearAccounts: () => void;
15
17
  refreshAccounts: () => void;
18
+ /** BOFF-9384: called before React state moves to another account. */
19
+ announceIdentityChange: AnnounceIdentityChange;
16
20
  }
17
- export declare function useBridgeInitialization({ bridgeUrl, bridgeAllowedOrigins, bridgeDebug, onBridgeReady, bridgeSyncInProgress, setIsLoading, setActiveId, setUser, setTokens, setWorkspaceTokenLocal, clearAccounts, refreshAccounts, }: BridgeInitializationDeps): void;
21
+ /** What `applyBridgeAuthState` writes to: AuthProvider's state setters and callbacks. */
22
+ export interface BridgeAuthStateTarget {
23
+ bridgeUrl: string;
24
+ bridgeSyncInProgress: MutableRefObject<boolean>;
25
+ setActiveId: (id: string | null) => void;
26
+ setUser: (user: ProfileUser | null) => void;
27
+ setTokens: (tokens: AuthTokens | null) => void;
28
+ setWorkspaceTokenLocal: (token: string | null) => void;
29
+ clearAccounts: () => void;
30
+ refreshAccounts: () => void;
31
+ announceIdentityChange: AnnounceIdentityChange;
32
+ markBridgeReady: () => void;
33
+ }
34
+ /**
35
+ * Apply an auth state the bridge delivered (initial state, or a change made in
36
+ * another app shell): sync it into profile storage, then into React state.
37
+ * BOFF-9384: an account change is announced after the profile storage write
38
+ * and before any React state change (like remote single-logout); the write
39
+ * and the announcement run in the same synchronous call, so nothing can read
40
+ * the cache in between.
41
+ */
42
+ export declare function applyBridgeAuthState(state: BridgeAuthState, target: BridgeAuthStateTarget): void;
43
+ export declare function useBridgeInitialization({ bridgeUrl, bridgeAllowedOrigins, bridgeDebug, onBridgeReady, bridgeSyncInProgress, setIsLoading, setActiveId, setUser, setTokens, setWorkspaceTokenLocal, clearAccounts, refreshAccounts, announceIdentityChange, }: BridgeInitializationDeps): void;
@@ -4,84 +4,104 @@ import { isRealNativeOrDesktopShell as o } from "../../../native/platform.js";
4
4
  import { hasRecentSSORedirectAttempt as s, markSSORedirectAttempt as c, shouldSkipSSORedirect as l } from "../../../components/SSORedirectGuard.js";
5
5
  import { getCookieSsoRelayUrl as u } from "./ssoRelay.js";
6
6
  import { syncBridgeStateToProfileStorage as d } from "./bridgeStateSync.js";
7
- import { useEffect as f } from "react";
7
+ import { SIGNED_OUT as f } from "./identityChange.js";
8
+ import { useEffect as p } from "react";
8
9
  //#region src/shared/providers/shell/authProvider/useBridgeInitialization.ts
9
- function p({ bridgeUrl: p, bridgeAllowedOrigins: m, bridgeDebug: h, onBridgeReady: g, bridgeSyncInProgress: _, setIsLoading: v, setActiveId: y, setUser: b, setTokens: x, setWorkspaceTokenLocal: S, clearAccounts: C, refreshAccounts: w }) {
10
- f(() => {
11
- if (!p) return;
10
+ function m(i, a) {
11
+ let { bridgeUrl: p, bridgeSyncInProgress: m, setActiveId: h, setUser: g, setTokens: _, setWorkspaceTokenLocal: v, clearAccounts: y, refreshAccounts: b, announceIdentityChange: x, markBridgeReady: S } = a;
12
+ m.current = !0;
13
+ try {
14
+ if (p) {
15
+ let e = u(p);
16
+ if (e) {
17
+ window.location.replace(e);
18
+ return;
19
+ }
20
+ }
21
+ d(i);
22
+ let a = r();
23
+ if (a) x("bridge-sync", {
24
+ profileId: a,
25
+ userId: t(a)?.id ?? null
26
+ }), h(a), g(t(a)), _(e(a)), v(n(a)), b();
27
+ else {
28
+ if (p && !i.user && !i.tokens) try {
29
+ let e = new URL(p).origin, t = window.location.origin, n = u(p);
30
+ if (n) {
31
+ window.location.replace(n);
32
+ return;
33
+ }
34
+ if (e !== t && !l() && !o()) {
35
+ let t = window.location.href;
36
+ if (s(e, t)) return;
37
+ c(e, t), window.location.replace(`${e}/auth/sso-relay?returnTo=${encodeURIComponent(t)}`);
38
+ return;
39
+ }
40
+ } catch {}
41
+ x("bridge-sync", f), h(null), g(null), _(null), v(null), y();
42
+ }
43
+ } finally {
44
+ m.current = !1, S();
45
+ }
46
+ }
47
+ function h({ bridgeUrl: e, bridgeAllowedOrigins: t, bridgeDebug: n, onBridgeReady: r, bridgeSyncInProgress: o, setIsLoading: s, setActiveId: c, setUser: l, setTokens: u, setWorkspaceTokenLocal: d, clearAccounts: f, refreshAccounts: h, announceIdentityChange: g }) {
48
+ p(() => {
49
+ if (!e) return;
12
50
  try {
13
- let e = new URL(p).pathname;
14
- if (window.location.pathname === e) {
15
- v(!1), g?.();
51
+ let t = new URL(e).pathname;
52
+ if (window.location.pathname === t) {
53
+ s(!1), r?.();
16
54
  return;
17
55
  }
18
56
  } catch {
19
- v(!1), g?.();
57
+ s(!1), r?.();
20
58
  return;
21
59
  }
22
60
  if (a()) {
23
- v(!1), g?.();
61
+ s(!1), r?.();
24
62
  return;
25
63
  }
26
- let f = () => {
27
- v(!1), g?.();
28
- }, T = (i) => {
29
- _.current = !0;
30
- try {
31
- if (p) {
32
- let e = u(p);
33
- if (e) {
34
- window.location.replace(e);
35
- return;
36
- }
37
- }
38
- d(i);
39
- let a = r();
40
- if (a) y(a), b(t(a)), x(e(a)), S(n(a)), w();
41
- else {
42
- if (p && !i.user && !i.tokens) try {
43
- let e = new URL(p).origin, t = window.location.origin, n = u(p);
44
- if (n) {
45
- window.location.replace(n);
46
- return;
47
- }
48
- if (e !== t && !l() && !o()) {
49
- let t = window.location.href;
50
- if (s(e, t)) return;
51
- c(e, t), window.location.replace(`${e}/auth/sso-relay?returnTo=${encodeURIComponent(t)}`);
52
- return;
53
- }
54
- } catch {}
55
- y(null), b(null), x(null), S(null), C();
56
- }
57
- } finally {
58
- _.current = !1, f();
59
- }
60
- }, E = setTimeout(() => {
61
- f();
64
+ let p = () => {
65
+ s(!1), r?.();
66
+ }, _ = (t) => {
67
+ m(t, {
68
+ bridgeUrl: e,
69
+ bridgeSyncInProgress: o,
70
+ setActiveId: c,
71
+ setUser: l,
72
+ setTokens: u,
73
+ setWorkspaceTokenLocal: d,
74
+ clearAccounts: f,
75
+ refreshAccounts: h,
76
+ announceIdentityChange: g,
77
+ markBridgeReady: p
78
+ });
79
+ }, v = setTimeout(() => {
80
+ p();
62
81
  }, 5e3);
63
82
  return i({
64
- bridgeUrl: p,
65
- allowedOrigins: m,
66
- onStateChanged: T,
67
- debug: h ?? !1
83
+ bridgeUrl: e,
84
+ allowedOrigins: t,
85
+ onStateChanged: _,
86
+ debug: n ?? !1
68
87
  }), () => {
69
- clearTimeout(E);
88
+ clearTimeout(v);
70
89
  };
71
90
  }, [
72
- p,
73
- m,
91
+ e,
92
+ t,
93
+ n,
94
+ r,
74
95
  h,
75
- g,
76
- w,
77
- _,
78
- v,
79
- y,
80
- b,
81
- x,
82
- S,
83
- C
96
+ o,
97
+ s,
98
+ c,
99
+ l,
100
+ u,
101
+ d,
102
+ f,
103
+ g
84
104
  ]);
85
105
  }
86
106
  //#endregion
87
- export { p as useBridgeInitialization };
107
+ export { h as useBridgeInitialization };
@@ -1,4 +1,5 @@
1
1
  import { ProfileUser, AuthTokens } from '../ProfileStorageManager';
2
+ import { AnnounceIdentityChange } from './identityChange';
2
3
  export interface RemoteSLODeps {
3
4
  tokens: AuthTokens | null;
4
5
  bridgeUrl: string | undefined;
@@ -10,5 +11,7 @@ export interface RemoteSLODeps {
10
11
  setTokens: (tokens: AuthTokens | null) => void;
11
12
  setWorkspaceTokenLocal: (token: string | null) => void;
12
13
  clearAccounts: () => void;
14
+ /** BOFF-9384: called before React state moves to the signed-out account. */
15
+ announceIdentityChange: AnnounceIdentityChange;
13
16
  }
14
- export declare function useRemoteSLO({ tokens, bridgeUrl, logout, setActiveId, setUser, setTokens, setWorkspaceTokenLocal, clearAccounts, }: RemoteSLODeps): void;
17
+ export declare function useRemoteSLO({ tokens, bridgeUrl, logout, setActiveId, setUser, setTokens, setWorkspaceTokenLocal, clearAccounts, announceIdentityChange, }: RemoteSLODeps): void;
@@ -1,36 +1,38 @@
1
1
  import { resolveGatewayUrls as e } from "../../../config/gatewayUrls.js";
2
2
  import { isSharedSsoCookieDomain as t } from "../../../utils/authCookie.js";
3
3
  import { checkRemoteSLO as n, checkSLO as r } from "../../../components/SSORedirectGuard.js";
4
- import { useEffect as i } from "react";
4
+ import { SIGNED_OUT as i } from "./identityChange.js";
5
+ import { useEffect as a } from "react";
5
6
  //#region src/shared/providers/shell/authProvider/useRemoteSLO.ts
6
- function a({ tokens: a, bridgeUrl: o, logout: s, setActiveId: c, setUser: l, setTokens: u, setWorkspaceTokenLocal: d, clearAccounts: f }) {
7
- i(() => {
8
- if (!a?.accessToken || !o) return;
9
- let i = async () => {
7
+ function o({ tokens: o, bridgeUrl: s, logout: c, setActiveId: l, setUser: u, setTokens: d, setWorkspaceTokenLocal: f, clearAccounts: p, announceIdentityChange: m }) {
8
+ a(() => {
9
+ if (!o?.accessToken || !s) return;
10
+ let a = async () => {
10
11
  if (document.visibilityState === "visible") try {
11
12
  if (r()) {
12
- c(null), l(null), u(null), d(null), f();
13
+ m("remote-slo", i), l(null), u(null), d(null), f(null), p();
13
14
  return;
14
15
  }
15
16
  if (t()) return;
16
- await n(`${e().globalBaseUrl}/global/graphql`, a.accessToken) && s({ authoritative: !1 });
17
+ await n(`${e().globalBaseUrl}/global/graphql`, o.accessToken) && c({ authoritative: !1 });
17
18
  } catch {}
18
19
  };
19
- document.addEventListener("visibilitychange", i);
20
- let p = setInterval(i, 9e4);
20
+ document.addEventListener("visibilitychange", a);
21
+ let h = setInterval(a, 9e4);
21
22
  return () => {
22
- document.removeEventListener("visibilitychange", i), clearInterval(p);
23
+ document.removeEventListener("visibilitychange", a), clearInterval(h);
23
24
  };
24
25
  }, [
25
- a?.accessToken,
26
- o,
26
+ o?.accessToken,
27
27
  s,
28
28
  c,
29
29
  l,
30
30
  u,
31
31
  d,
32
- f
32
+ f,
33
+ p,
34
+ m
33
35
  ]);
34
36
  }
35
37
  //#endregion
36
- export { a as useRemoteSLO };
38
+ export { o as useRemoteSLO };
@@ -1,4 +1,5 @@
1
1
  import { ProfileUser, AuthTokens } from '../ProfileStorageManager';
2
+ import { AnnounceIdentityChange } from './identityChange';
2
3
  export interface StorageSyncDeps {
3
4
  user: ProfileUser | null;
4
5
  tokens: AuthTokens | null;
@@ -10,5 +11,7 @@ export interface StorageSyncDeps {
10
11
  setActiveId: (id: string | null) => void;
11
12
  clearAccounts: () => void;
12
13
  refreshAccounts: () => void;
14
+ /** BOFF-9384: called before React state moves to another account. */
15
+ announceIdentityChange: AnnounceIdentityChange;
13
16
  }
14
- export declare function useStorageSync({ user, tokens, workspaceToken, activeId, setUser, setTokens, setWorkspaceTokenLocal, setActiveId, clearAccounts, refreshAccounts, }: StorageSyncDeps): void;
17
+ export declare function useStorageSync({ user, tokens, workspaceToken, activeId, setUser, setTokens, setWorkspaceTokenLocal, setActiveId, clearAccounts, refreshAccounts, announceIdentityChange, }: StorageSyncDeps): void;