@burdenoff/fe-libs 2026.1017.11 → 2026.1018.1

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
@@ -75,6 +75,13 @@ var e = {
75
75
  showFooter: !1,
76
76
  showBreadcrumb: !1
77
77
  },
78
+ {
79
+ pattern: "/auth/sso-deposit",
80
+ showHeader: !1,
81
+ showSidebar: !1,
82
+ showFooter: !1,
83
+ showBreadcrumb: !1
84
+ },
78
85
  {
79
86
  pattern: "/workspaces/invite",
80
87
  showHeader: !1,
@@ -1,5 +1,16 @@
1
1
  import { MutableRefObject } from 'react';
2
2
  import { ProfileUser, AuthTokens } from '../ProfileStorageManager';
3
+ /**
4
+ * BOFF-9411: the token for the authoritative SignOut request. The caller's
5
+ * token comes first, then this hook's state, then storage for the active
6
+ * profile. Storage is read at call time because this hook's state can still be
7
+ * empty after an in-tab sign-in that another auth store wrote. Without an
8
+ * active profile in state, only this tab's own active-profile pointer is used,
9
+ * never `resolveActiveProfileId()`: once the signing-out profile has been
10
+ * cleared, that falls back to another signed-in account, and SignOut would
11
+ * revoke that account's sessions.
12
+ */
13
+ export declare function resolveSignOutAccessToken(callerToken: string | null | undefined, tokens: AuthTokens | null, activeId: string | null): string | undefined;
3
14
  export interface AuthActionsDeps {
4
15
  user: ProfileUser | null;
5
16
  tokens: AuthTokens | null;
@@ -35,6 +46,14 @@ export interface LogoutOptions {
35
46
  * remote-SLO poll.
36
47
  */
37
48
  authoritative?: boolean;
49
+ /**
50
+ * BOFF-9411: the caller's current access token, used only for the
51
+ * authoritative SignOut request. An app with its own auth store may clear
52
+ * that store's copy of the profile before calling logout(), and this hook's
53
+ * state can lag an in-tab sign-in written by that store, so without it the
54
+ * request could find no token and was skipped.
55
+ */
56
+ accessToken?: string | null;
38
57
  }
39
58
  export interface AuthActions {
40
59
  login: (user: ProfileUser, accessToken: string, refreshToken?: string) => void;
@@ -1,12 +1,12 @@
1
1
  import { resolveGatewayUrls as e } from "../../../config/gatewayUrls.js";
2
- import { addProfile as t, getProfileTokens as n, getProfileUser as r, getProfileWorkspaceToken as i, getProfiles as a, loginProfile as o, logoutAllProfiles as s, removeProfile as c, resolveActiveProfileId as l, setProfileTokens as u, setProfileUser as d, setProfileWorkspaceToken as f, switchProfile as p } from "../ProfileStorageManager.js";
3
- import { clearShellSsoCookies as m, setShellSsoCookies as h } from "../../../utils/authCookie.js";
4
- import { getAuthBridge as g } from "../AuthBridgeClient.js";
5
- import { getCrossOriginLogoutUrl as _ } from "./ssoRelay.js";
6
- import { getJwtExpiry as v } from "./jwt.js";
7
- import { useCallback as y } from "react";
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";
8
8
  //#region src/shared/providers/shell/authProvider/useAuthActions.ts
9
- function b(t) {
9
+ function x(t) {
10
10
  if (t) try {
11
11
  let { globalBaseUrl: n } = e();
12
12
  if (!n) return;
@@ -21,164 +21,170 @@ function b(t) {
21
21
  }).catch(() => {});
22
22
  } catch {}
23
23
  }
24
- function x({ user: e, tokens: x, activeId: S, bridgeSyncInProgress: C, onRefreshToken: w, onTokenExpired: T, setActiveId: E, setUser: D, setTokens: O, setWorkspaceTokenLocal: k, setMfaRequiredState: A, setMfaChallengeIdState: j, setIsLoading: M, clearAccounts: N, refreshAccounts: P }) {
25
- let F = y((e, t, n) => {
26
- let r = v(t) ?? Date.now() + 3600 * 1e3, i = {
24
+ function S(e, t, i) {
25
+ if (e) return e;
26
+ if (t?.accessToken) return t.accessToken;
27
+ let a = i ?? n();
28
+ return (a ? r(a)?.accessToken : void 0) || void 0;
29
+ }
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 = {
27
33
  accessToken: t,
28
34
  refreshToken: n,
29
35
  expiresAt: r
30
- }, s = o(e, i);
31
- E(s), D(e), O(i), k(null), A(!1), j(null), P();
36
+ }, a = s(e, i);
37
+ D(a), O(e), k(i), A(null), j(!1), M(null), F();
32
38
  try {
33
- h(s, window.location.origin);
39
+ g(a, window.location.origin);
34
40
  } catch {}
35
- C.current || g()?.notifyLogin({
41
+ w.current || _()?.notifyLogin({
36
42
  user: e,
37
43
  tokens: {
38
44
  accessToken: t,
39
45
  refreshToken: n,
40
46
  expiresAt: r
41
47
  },
42
- activeAccountId: s,
43
- activeProfileId: s,
44
- profiles: a()
48
+ activeAccountId: a,
49
+ activeProfileId: a,
50
+ profiles: o()
45
51
  });
46
52
  }, [
47
- P,
48
- C,
49
- E,
53
+ F,
54
+ w,
50
55
  D,
51
56
  O,
52
57
  k,
53
58
  A,
54
- j
55
- ]), I = y((e) => {
59
+ j,
60
+ M
61
+ ]), L = b((e) => {
56
62
  let t = e?.authoritative !== !1;
57
- t && !C.current && b(x?.accessToken ?? (S ? n(S)?.accessToken : void 0)), S && c(S);
58
- let a = l();
59
- a ? (E(a), D(r(a)), O(n(a)), k(i(a))) : (E(null), D(null), O(null), k(null)), A(!1), j(null), P();
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();
60
66
  try {
61
- m();
67
+ h();
62
68
  } catch {}
63
- C.current || g()?.notifyLogout();
64
- let o = t ? _() : null;
65
- o && !C.current && window.location.replace(o);
69
+ w.current || _()?.notifyLogout();
70
+ let s = t ? v() : null;
71
+ s && !w.current && window.location.replace(s);
66
72
  }, [
67
- S,
68
- x,
69
- P,
70
73
  C,
71
- E,
74
+ n,
75
+ F,
76
+ w,
72
77
  D,
73
78
  O,
74
79
  k,
75
80
  A,
76
- j
77
- ]), L = y((n) => {
78
- if (!e || !S) return;
81
+ j,
82
+ M
83
+ ]), R = b((n) => {
84
+ if (!e || !C) return;
79
85
  let r = {
80
86
  ...e,
81
87
  ...n
82
88
  };
83
- D(r), d(S, r), t({
84
- id: S,
89
+ O(r), f(C, r), t({
90
+ id: C,
85
91
  email: r.email,
86
92
  name: r.name ?? `${r.firstName ?? ""} ${r.lastName ?? ""}`.trim(),
87
93
  avatar: r.avatar,
88
94
  lastLogin: (/* @__PURE__ */ new Date()).toISOString()
89
- }), P();
95
+ }), F();
90
96
  }, [
91
97
  e,
92
- S,
93
- P,
94
- D
95
- ]), R = y(async () => {
96
- if (!w || !S) return;
97
- let e = x?.refreshToken ?? n(S)?.refreshToken ?? void 0;
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;
98
104
  if (e) {
99
- M(!0);
105
+ N(!0);
100
106
  try {
101
- let t = await w(e), n = v(t.accessToken), r = t.expiresAt ?? n ?? Date.now() + 1440 * 60 * 1e3, i = {
107
+ let t = await T(e), n = y(t.accessToken), r = t.expiresAt ?? n ?? Date.now() + 1440 * 60 * 1e3, i = {
102
108
  accessToken: t.accessToken,
103
109
  refreshToken: t.refreshToken ?? e,
104
110
  expiresAt: r
105
111
  };
106
- O(i), u(S, i), C.current || g()?.notifyTokenRefresh({
112
+ k(i), d(C, i), w.current || _()?.notifyTokenRefresh({
107
113
  accessToken: i.accessToken,
108
114
  refreshToken: i.refreshToken,
109
115
  expiresAt: i.expiresAt
110
116
  });
111
117
  } catch (e) {
112
- console.error("Failed to refresh token:", e), x?.expiresAt && x.expiresAt - Date.now() > 0 || (I({ authoritative: !1 }), T?.());
118
+ console.error("Failed to refresh token:", e), n?.expiresAt && n.expiresAt - Date.now() > 0 || (L({ authoritative: !1 }), E?.());
113
119
  } finally {
114
- M(!1);
120
+ N(!1);
115
121
  }
116
122
  }
117
123
  }, [
118
- x,
119
- w,
120
- S,
121
- I,
124
+ n,
122
125
  T,
123
126
  C,
124
- O,
125
- M
126
- ]), z = y((t) => e?.permissions ? e.permissions.includes(t) || e.permissions.includes("*") : !1, [e]), B = y((e) => {
127
- k(e), S && f(S, e);
128
- }, [S, k]), V = y((e, t) => {
129
- A(e), j(t ?? null);
130
- }, [A, j]), H = y((e) => {
131
- if (!p(e)) {
127
+ L,
128
+ 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)) {
132
138
  console.error(`Profile ${e} not found`);
133
139
  return;
134
140
  }
135
- E(e), D(r(e)), O(n(e)), k(i(e)), A(!1), j(null), P(), C.current || g()?.notifyAccountSwitch(e);
141
+ D(e), O(i(e)), k(r(e)), A(a(e)), j(!1), M(null), F(), w.current || _()?.notifyAccountSwitch(e);
136
142
  }, [
137
- P,
138
- C,
139
- E,
143
+ F,
144
+ w,
140
145
  D,
141
146
  O,
142
147
  k,
143
148
  A,
144
- j
145
- ]), U = F, W = y((e) => {
146
- if (e === S) {
149
+ j,
150
+ M
151
+ ]), W = I, G = b((e) => {
152
+ if (e === C) {
147
153
  console.error("Cannot remove active account — logout first");
148
154
  return;
149
155
  }
150
- c(e), P();
151
- }, [S, P]);
156
+ l(e), F();
157
+ }, [C, F]);
152
158
  return {
153
- login: F,
154
- logout: I,
155
- logoutAll: y(() => {
156
- s(), E(null), D(null), O(null), k(null), A(!1), j(null), N();
159
+ login: I,
160
+ logout: L,
161
+ logoutAll: b(() => {
162
+ c(), D(null), O(null), k(null), A(null), j(!1), M(null), P();
157
163
  try {
158
- m();
164
+ h();
159
165
  } catch {}
160
- C.current || g()?.notifyLogoutAll();
161
- let e = _();
162
- e && !C.current && window.location.replace(e);
166
+ w.current || _()?.notifyLogoutAll();
167
+ let e = v();
168
+ e && !w.current && window.location.replace(e);
163
169
  }, [
164
- C,
165
- E,
170
+ w,
166
171
  D,
167
172
  O,
168
173
  k,
169
174
  A,
170
175
  j,
171
- N
176
+ M,
177
+ P
172
178
  ]),
173
- updateUser: L,
174
- refreshAccessToken: R,
175
- hasPermission: z,
176
- setWorkspaceToken: B,
177
- setMfaState: V,
178
- switchAccount: H,
179
- addAccount: U,
180
- removeAccount: W
179
+ updateUser: R,
180
+ refreshAccessToken: z,
181
+ hasPermission: B,
182
+ setWorkspaceToken: V,
183
+ setMfaState: H,
184
+ switchAccount: U,
185
+ addAccount: W,
186
+ removeAccount: G
181
187
  };
182
188
  }
183
189
  //#endregion
184
- export { x as useAuthActions };
190
+ export { C as useAuthActions };
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@burdenoff/fe-libs",
3
- "version": "2026.1017.11",
3
+ "version": "2026.1018.1",
4
4
  "description": "Burdenoff frontend primitives and domain libraries",
5
5
  "type": "module",
6
6
  "bin": {
@@ -311,7 +311,7 @@
311
311
  "test:package-livekit-optional": "node scripts/validate-livekit-optional.mjs",
312
312
  "verify:package": "node scripts/verify-package-contents.mjs",
313
313
  "test:handsfree-browser": "node scripts/handsfree-browser-run.mjs",
314
- "test": "bun test scripts/graphql-schema-drift/__tests__ scripts/a11y-audit/__tests__ src/credentials src/connections src/storage src/shared/assistant src/shared/components src/shared/graphql/links/sse-link.test.ts src/shared/graphql/fetch.test.ts src/shared/graphql/prepareWorkspaceRequest.test.ts src/shared/graphql/client.test.ts src/shared/utils/apollo.test.ts src/shared/graphql/tourWorkspaceAuth.test.ts src/shared/config/gatewayUrls.test.ts src/shared/config/authBridgeUrls.test.ts src/shared/config/gatewayFallback.test.ts scripts/__tests__ src/shared/config/products.test.ts src/shared/config/productSlug.test.ts src/shared/hooks/shell/useProducts.test.ts src/shared/providers/shell/brandAttribute.test.ts src/chrome/ProductSwitcher.test.ts src/shared/utils/gatewayFetchRewrite.test.ts src/shared/utils/authCookie.test.ts src/shared/providers/shell/ProfileStorageManager.test.ts src/shared/providers/AppShellProvider.test.ts src/shared/providers/shell/interpolate.test.ts src/shared/providers/shell/resolveTranslation.test.ts src/shared/providers/shell/I18nProvider.render.test.tsx src/shared/providers/shell/I18nProvider.client.test.tsx src/shared/providers/shell/translationStore.test.ts src/shared/providers/shell/translationLayers.test.ts src/shared/providers/shell/directionMode.test.ts src/shared/providers/shell/authProvider/ssoRelay.test.ts src/shared/providers/shell/personaSurfaceRemote.test.ts src/shared/providers/shell/workspaceSwitch.client.test.tsx src/shared/events/sinks/RybbitSink.test.ts src/shell-native src/shared/native src/shared/navigation src/shared/tours src/chrome/__tests__ src/ui/__tests__",
314
+ "test": "bun test scripts/graphql-schema-drift/__tests__ scripts/a11y-audit/__tests__ src/credentials src/connections src/storage src/shared/assistant src/shared/components src/shared/graphql/links/sse-link.test.ts src/shared/graphql/fetch.test.ts src/shared/graphql/prepareWorkspaceRequest.test.ts src/shared/graphql/client.test.ts src/shared/utils/apollo.test.ts src/shared/graphql/tourWorkspaceAuth.test.ts src/shared/config/gatewayUrls.test.ts src/shared/config/authBridgeUrls.test.ts src/shared/config/shellRoutes.test.ts src/shared/config/gatewayFallback.test.ts scripts/__tests__ src/shared/config/products.test.ts src/shared/config/productSlug.test.ts src/shared/hooks/shell/useProducts.test.ts src/shared/providers/shell/brandAttribute.test.ts src/chrome/ProductSwitcher.test.ts src/shared/utils/gatewayFetchRewrite.test.ts src/shared/utils/authCookie.test.ts src/shared/providers/shell/ProfileStorageManager.test.ts src/shared/providers/AppShellProvider.test.ts src/shared/providers/shell/interpolate.test.ts src/shared/providers/shell/resolveTranslation.test.ts src/shared/providers/shell/I18nProvider.render.test.tsx src/shared/providers/shell/I18nProvider.client.test.tsx src/shared/providers/shell/translationStore.test.ts src/shared/providers/shell/translationLayers.test.ts src/shared/providers/shell/directionMode.test.ts src/shared/providers/shell/authProvider/ssoRelay.test.ts src/shared/providers/shell/authProvider/useAuthActions.signOut.test.tsx src/shared/providers/shell/personaSurfaceRemote.test.ts src/shared/providers/shell/workspaceSwitch.client.test.tsx src/shared/events/sinks/RybbitSink.test.ts src/shell-native src/shared/native src/shared/navigation src/shared/tours src/chrome/__tests__ src/ui/__tests__",
315
315
  "sanity": "bash scripts/build-limits.sh --gate bash -c 'bun run lint:sanity && bun run format && bun run type:check && bun run test && bun run build && bun run verify:package'",
316
316
  "switch:status": "bun scripts/deps-mode.ts status",
317
317
  "switch:remote": "bun scripts/deps-mode.ts remote",