@burdenoff/fe-libs 2026.1017.12 → 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.
|
@@ -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,
|
|
3
|
-
import { clearShellSsoCookies as
|
|
4
|
-
import { getAuthBridge as
|
|
5
|
-
import { getCrossOriginLogoutUrl as
|
|
6
|
-
import { getJwtExpiry as
|
|
7
|
-
import { useCallback as
|
|
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
|
|
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
|
|
25
|
-
|
|
26
|
-
|
|
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
|
-
},
|
|
31
|
-
|
|
36
|
+
}, a = s(e, i);
|
|
37
|
+
D(a), O(e), k(i), A(null), j(!1), M(null), F();
|
|
32
38
|
try {
|
|
33
|
-
|
|
39
|
+
g(a, window.location.origin);
|
|
34
40
|
} catch {}
|
|
35
|
-
|
|
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:
|
|
43
|
-
activeProfileId:
|
|
44
|
-
profiles:
|
|
48
|
+
activeAccountId: a,
|
|
49
|
+
activeProfileId: a,
|
|
50
|
+
profiles: o()
|
|
45
51
|
});
|
|
46
52
|
}, [
|
|
47
|
-
|
|
48
|
-
|
|
49
|
-
E,
|
|
53
|
+
F,
|
|
54
|
+
w,
|
|
50
55
|
D,
|
|
51
56
|
O,
|
|
52
57
|
k,
|
|
53
58
|
A,
|
|
54
|
-
j
|
|
55
|
-
|
|
59
|
+
j,
|
|
60
|
+
M
|
|
61
|
+
]), L = b((e) => {
|
|
56
62
|
let t = e?.authoritative !== !1;
|
|
57
|
-
t && !
|
|
58
|
-
let
|
|
59
|
-
|
|
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
|
-
|
|
67
|
+
h();
|
|
62
68
|
} catch {}
|
|
63
|
-
|
|
64
|
-
let
|
|
65
|
-
|
|
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
|
-
|
|
74
|
+
n,
|
|
75
|
+
F,
|
|
76
|
+
w,
|
|
72
77
|
D,
|
|
73
78
|
O,
|
|
74
79
|
k,
|
|
75
80
|
A,
|
|
76
|
-
j
|
|
77
|
-
|
|
78
|
-
|
|
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
|
-
|
|
84
|
-
id:
|
|
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
|
-
}),
|
|
95
|
+
}), F();
|
|
90
96
|
}, [
|
|
91
97
|
e,
|
|
92
|
-
|
|
93
|
-
|
|
94
|
-
|
|
95
|
-
]),
|
|
96
|
-
if (!
|
|
97
|
-
let 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;
|
|
98
104
|
if (e) {
|
|
99
|
-
|
|
105
|
+
N(!0);
|
|
100
106
|
try {
|
|
101
|
-
let t = await
|
|
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
|
-
|
|
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),
|
|
118
|
+
console.error("Failed to refresh token:", e), n?.expiresAt && n.expiresAt - Date.now() > 0 || (L({ authoritative: !1 }), E?.());
|
|
113
119
|
} finally {
|
|
114
|
-
|
|
120
|
+
N(!1);
|
|
115
121
|
}
|
|
116
122
|
}
|
|
117
123
|
}, [
|
|
118
|
-
|
|
119
|
-
w,
|
|
120
|
-
S,
|
|
121
|
-
I,
|
|
124
|
+
n,
|
|
122
125
|
T,
|
|
123
126
|
C,
|
|
124
|
-
|
|
125
|
-
|
|
126
|
-
|
|
127
|
-
k
|
|
128
|
-
|
|
129
|
-
|
|
130
|
-
|
|
131
|
-
|
|
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
|
-
|
|
141
|
+
D(e), O(i(e)), k(r(e)), A(a(e)), j(!1), M(null), F(), w.current || _()?.notifyAccountSwitch(e);
|
|
136
142
|
}, [
|
|
137
|
-
|
|
138
|
-
|
|
139
|
-
E,
|
|
143
|
+
F,
|
|
144
|
+
w,
|
|
140
145
|
D,
|
|
141
146
|
O,
|
|
142
147
|
k,
|
|
143
148
|
A,
|
|
144
|
-
j
|
|
145
|
-
|
|
146
|
-
|
|
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
|
-
|
|
151
|
-
}, [
|
|
156
|
+
l(e), F();
|
|
157
|
+
}, [C, F]);
|
|
152
158
|
return {
|
|
153
|
-
login:
|
|
154
|
-
logout:
|
|
155
|
-
logoutAll:
|
|
156
|
-
|
|
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
|
-
|
|
164
|
+
h();
|
|
159
165
|
} catch {}
|
|
160
|
-
|
|
161
|
-
let e =
|
|
162
|
-
e && !
|
|
166
|
+
w.current || _()?.notifyLogoutAll();
|
|
167
|
+
let e = v();
|
|
168
|
+
e && !w.current && window.location.replace(e);
|
|
163
169
|
}, [
|
|
164
|
-
|
|
165
|
-
E,
|
|
170
|
+
w,
|
|
166
171
|
D,
|
|
167
172
|
O,
|
|
168
173
|
k,
|
|
169
174
|
A,
|
|
170
175
|
j,
|
|
171
|
-
|
|
176
|
+
M,
|
|
177
|
+
P
|
|
172
178
|
]),
|
|
173
|
-
updateUser:
|
|
174
|
-
refreshAccessToken:
|
|
175
|
-
hasPermission:
|
|
176
|
-
setWorkspaceToken:
|
|
177
|
-
setMfaState:
|
|
178
|
-
switchAccount:
|
|
179
|
-
addAccount:
|
|
180
|
-
removeAccount:
|
|
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 {
|
|
190
|
+
export { C as useAuthActions };
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@burdenoff/fe-libs",
|
|
3
|
-
"version": "2026.
|
|
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/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/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",
|