@uxland/primary-shell 7.43.1 → 7.43.2
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/{component-CZHFJbG2.js → component-CU8m_HuW.js} +2 -2
- package/dist/{component-CZHFJbG2.js.map → component-CU8m_HuW.js.map} +1 -1
- package/dist/{index-B0BnyHR2.js → index-B9gGnkza.js} +27 -26
- package/dist/index-B9gGnkza.js.map +1 -0
- package/dist/index.js +1 -1
- package/dist/index.umd.cjs +3 -3
- package/dist/index.umd.cjs.map +1 -1
- package/dist/primary/shell/src/api/session-refresh-timer/session-refresh-timer.d.ts +2 -4
- package/dist/primary/shell/src/api/token-manager/token-manager.d.ts +4 -1
- package/package.json +1 -1
- package/src/api/api.ts +2 -2
- package/src/api/http-client/http-client.test.ts +4 -10
- package/src/api/http-client/http-client.ts +0 -3
- package/src/api/session-refresh-timer/session-refresh-timer.test.ts +5 -54
- package/src/api/session-refresh-timer/session-refresh-timer.ts +2 -6
- package/src/api/token-manager/token-manager.test.ts +36 -12
- package/src/api/token-manager/token-manager.ts +17 -8
- package/dist/index-B0BnyHR2.js.map +0 -1
|
@@ -1,5 +1,4 @@
|
|
|
1
1
|
import { ActivityMonitor } from '../activity-monitor/activity-monitor';
|
|
2
|
-
import { PrimariaBroker } from '../broker/primaria-broker';
|
|
3
2
|
import { TokenManager } from '../token-manager/token-manager';
|
|
4
3
|
export interface SessionRefreshTimer {
|
|
5
4
|
start: () => void;
|
|
@@ -8,13 +7,12 @@ export interface SessionRefreshTimer {
|
|
|
8
7
|
export declare class SessionRefreshTimerImpl implements SessionRefreshTimer {
|
|
9
8
|
private readonly tokenManager;
|
|
10
9
|
private readonly activityMonitor;
|
|
11
|
-
private readonly broker;
|
|
12
10
|
private intervalId;
|
|
13
11
|
private isRefreshing;
|
|
14
|
-
constructor(tokenManager: TokenManager, activityMonitor: ActivityMonitor
|
|
12
|
+
constructor(tokenManager: TokenManager, activityMonitor: ActivityMonitor);
|
|
15
13
|
start: () => void;
|
|
16
14
|
stop: () => void;
|
|
17
15
|
private getTokenExpiry;
|
|
18
16
|
private checkAndRefresh;
|
|
19
17
|
}
|
|
20
|
-
export declare const createSessionRefreshTimer: (tokenManager: TokenManager, activityMonitor: ActivityMonitor
|
|
18
|
+
export declare const createSessionRefreshTimer: (tokenManager: TokenManager, activityMonitor: ActivityMonitor) => SessionRefreshTimer;
|
|
@@ -1,13 +1,16 @@
|
|
|
1
|
+
import { PrimariaBroker } from '../broker/primaria-broker';
|
|
1
2
|
export interface TokenManager {
|
|
2
3
|
setInitialTokens: (access_token: string, refresh_token: string) => void;
|
|
3
4
|
getToken: () => string;
|
|
4
5
|
refreshToken: () => Promise<string>;
|
|
5
6
|
}
|
|
6
7
|
export declare class TokenManagerImpl implements TokenManager {
|
|
8
|
+
private readonly broker;
|
|
9
|
+
constructor(broker: PrimariaBroker);
|
|
7
10
|
getUrlParams: () => URLSearchParams;
|
|
8
11
|
private initToken;
|
|
9
12
|
setInitialTokens: (access_token: string, refresh_token: string) => void;
|
|
10
13
|
getToken: () => string;
|
|
11
14
|
refreshToken: () => Promise<string>;
|
|
12
15
|
}
|
|
13
|
-
export declare const createTokenManager: () => TokenManagerImpl;
|
|
16
|
+
export declare const createTokenManager: (broker: PrimariaBroker) => TokenManagerImpl;
|
package/package.json
CHANGED
package/src/api/api.ts
CHANGED
|
@@ -44,10 +44,10 @@ export interface PrimariaApi extends HarmonixApi {
|
|
|
44
44
|
|
|
45
45
|
const regionManager: RegionManager = createRegionManager("primaria");
|
|
46
46
|
export const PrimariaRegionHost: any = createRegionHost(regionManager as any);
|
|
47
|
-
const tokenManager = createTokenManager();
|
|
47
|
+
const tokenManager = createTokenManager(broker);
|
|
48
48
|
const userManager = createUserManager(tokenManager);
|
|
49
49
|
export const activityMonitor = createActivityMonitor();
|
|
50
|
-
export const sessionRefreshTimer = createSessionRefreshTimer(tokenManager, activityMonitor
|
|
50
|
+
export const sessionRefreshTimer = createSessionRefreshTimer(tokenManager, activityMonitor);
|
|
51
51
|
const globalStateManager: PrimariaGlobalStateManager = createGlobalStateManager(broker);
|
|
52
52
|
const contextManager = createContextManager();
|
|
53
53
|
const pluginBusyManager = new PluginBusyManagerImpl();
|
|
@@ -28,7 +28,7 @@ describe("HTTP Client", () => {
|
|
|
28
28
|
|
|
29
29
|
describe("Without validateMpid", () => {
|
|
30
30
|
beforeEach(() => {
|
|
31
|
-
tokenManager = createTokenManager();
|
|
31
|
+
tokenManager = createTokenManager(broker);
|
|
32
32
|
axiosInstance = createAxiosInstance(tokenManager, broker);
|
|
33
33
|
axiosMockInstance = new AxiosMockAdapter(axiosInstance);
|
|
34
34
|
axiosMockInstance.reset();
|
|
@@ -91,10 +91,7 @@ describe("HTTP Client", () => {
|
|
|
91
91
|
);
|
|
92
92
|
|
|
93
93
|
expect(axiosMockInstance.history.get?.length).toBe(1); // No retry happened
|
|
94
|
-
expect(brokerSpy).toHaveBeenCalledWith(BROKER_EVENTS.shell.refreshTokenFailed,
|
|
95
|
-
expect(brokerSpy).toHaveBeenCalledWith(BROKER_EVENTS.shell.refreshTokenFailed, {
|
|
96
|
-
request: expect.objectContaining({ url: "/api/clinical-course" }),
|
|
97
|
-
});
|
|
94
|
+
expect(brokerSpy).toHaveBeenCalledWith(BROKER_EVENTS.shell.refreshTokenFailed, {});
|
|
98
95
|
});
|
|
99
96
|
|
|
100
97
|
it("should fail request with error != 401 and should not retry", async () => {
|
|
@@ -113,7 +110,7 @@ describe("HTTP Client", () => {
|
|
|
113
110
|
describe.skip("With validateMpid", () => {
|
|
114
111
|
const validTokenHeaders = { "x-catsalut-mpid": "5ec74c7b-5aa5-4a84-b3b4-f02eddfdf6dc" };
|
|
115
112
|
beforeEach(() => {
|
|
116
|
-
tokenManager = createTokenManager();
|
|
113
|
+
tokenManager = createTokenManager(broker);
|
|
117
114
|
axiosInstance = createAxiosInstance(tokenManager, broker, true);
|
|
118
115
|
axiosMockInstance = new AxiosMockAdapter(axiosInstance);
|
|
119
116
|
axiosMockInstance.reset();
|
|
@@ -200,10 +197,7 @@ describe("HTTP Client", () => {
|
|
|
200
197
|
);
|
|
201
198
|
|
|
202
199
|
expect(axiosMockInstance.history.get?.length).toBe(1); // No retry happened
|
|
203
|
-
expect(brokerSpy).toHaveBeenCalledWith(BROKER_EVENTS.shell.refreshTokenFailed,
|
|
204
|
-
expect(brokerSpy).toHaveBeenCalledWith(BROKER_EVENTS.shell.refreshTokenFailed, {
|
|
205
|
-
request: expect.objectContaining({ url: "/api/clinical-course" }),
|
|
206
|
-
});
|
|
200
|
+
expect(brokerSpy).toHaveBeenCalledWith(BROKER_EVENTS.shell.refreshTokenFailed, {});
|
|
207
201
|
});
|
|
208
202
|
|
|
209
203
|
it("should fail request with error != 401 and should not retry", async () => {
|
|
@@ -69,9 +69,6 @@ export const createAxiosInstance = (
|
|
|
69
69
|
return instance(originalRequest);
|
|
70
70
|
} catch (refreshError) {
|
|
71
71
|
console.error("Error refreshing token:", refreshError);
|
|
72
|
-
broker.publish(BROKER_EVENTS.shell.refreshTokenFailed, {
|
|
73
|
-
request: originalRequest,
|
|
74
|
-
});
|
|
75
72
|
return Promise.reject(error);
|
|
76
73
|
}
|
|
77
74
|
}
|
|
@@ -1,5 +1,4 @@
|
|
|
1
1
|
import { afterEach, beforeEach, describe, expect, it, vi } from "vitest";
|
|
2
|
-
import { BROKER_EVENTS } from "../broker/broker-events";
|
|
3
2
|
import { SessionRefreshTimerImpl } from "./session-refresh-timer";
|
|
4
3
|
|
|
5
4
|
const createJwt = (exp: number): string => {
|
|
@@ -23,20 +22,9 @@ const createMockActivityMonitor = (lastActivity = Date.now()) => ({
|
|
|
23
22
|
getLastActivityTimestamp: vi.fn().mockReturnValue(lastActivity),
|
|
24
23
|
});
|
|
25
24
|
|
|
26
|
-
const createMockBroker = () => ({
|
|
27
|
-
publish: vi.fn().mockResolvedValue(undefined),
|
|
28
|
-
subscribe: vi.fn(),
|
|
29
|
-
send: vi.fn(),
|
|
30
|
-
registerRequest: vi.fn(),
|
|
31
|
-
events: BROKER_EVENTS,
|
|
32
|
-
});
|
|
33
|
-
|
|
34
25
|
describe("SessionRefreshTimer", () => {
|
|
35
|
-
let mockBroker: ReturnType<typeof createMockBroker>;
|
|
36
|
-
|
|
37
26
|
beforeEach(() => {
|
|
38
27
|
vi.useFakeTimers();
|
|
39
|
-
mockBroker = createMockBroker();
|
|
40
28
|
});
|
|
41
29
|
|
|
42
30
|
afterEach(() => {
|
|
@@ -48,11 +36,7 @@ describe("SessionRefreshTimer", () => {
|
|
|
48
36
|
const tokenManager = createMockTokenManager({
|
|
49
37
|
getToken: vi.fn().mockReturnValue(createJwt(Math.floor(Date.now() / 1000) + 60)),
|
|
50
38
|
});
|
|
51
|
-
const timer = new SessionRefreshTimerImpl(
|
|
52
|
-
tokenManager,
|
|
53
|
-
createMockActivityMonitor(0),
|
|
54
|
-
mockBroker,
|
|
55
|
-
);
|
|
39
|
+
const timer = new SessionRefreshTimerImpl(tokenManager, createMockActivityMonitor(0));
|
|
56
40
|
|
|
57
41
|
timer.start();
|
|
58
42
|
await vi.advanceTimersByTimeAsync(30_000);
|
|
@@ -64,11 +48,7 @@ describe("SessionRefreshTimer", () => {
|
|
|
64
48
|
const tokenManager = createMockTokenManager({
|
|
65
49
|
getToken: vi.fn().mockReturnValue(createJwt(Math.floor(Date.now() / 1000) + 3600)),
|
|
66
50
|
});
|
|
67
|
-
const timer = new SessionRefreshTimerImpl(
|
|
68
|
-
tokenManager,
|
|
69
|
-
createMockActivityMonitor(),
|
|
70
|
-
mockBroker,
|
|
71
|
-
);
|
|
51
|
+
const timer = new SessionRefreshTimerImpl(tokenManager, createMockActivityMonitor());
|
|
72
52
|
|
|
73
53
|
timer.start();
|
|
74
54
|
await vi.advanceTimersByTimeAsync(30_000);
|
|
@@ -80,11 +60,7 @@ describe("SessionRefreshTimer", () => {
|
|
|
80
60
|
const tokenManager = createMockTokenManager({
|
|
81
61
|
getToken: vi.fn().mockReturnValue(createJwt(Math.floor(Date.now() / 1000) + 60)),
|
|
82
62
|
});
|
|
83
|
-
const timer = new SessionRefreshTimerImpl(
|
|
84
|
-
tokenManager,
|
|
85
|
-
createMockActivityMonitor(),
|
|
86
|
-
mockBroker,
|
|
87
|
-
);
|
|
63
|
+
const timer = new SessionRefreshTimerImpl(tokenManager, createMockActivityMonitor());
|
|
88
64
|
|
|
89
65
|
timer.start();
|
|
90
66
|
await vi.advanceTimersByTimeAsync(30_000);
|
|
@@ -96,11 +72,7 @@ describe("SessionRefreshTimer", () => {
|
|
|
96
72
|
const tokenManager = createMockTokenManager({
|
|
97
73
|
getToken: vi.fn().mockReturnValue(createJwt(Math.floor(Date.now() / 1000) - 60)),
|
|
98
74
|
});
|
|
99
|
-
const timer = new SessionRefreshTimerImpl(
|
|
100
|
-
tokenManager,
|
|
101
|
-
createMockActivityMonitor(),
|
|
102
|
-
mockBroker,
|
|
103
|
-
);
|
|
75
|
+
const timer = new SessionRefreshTimerImpl(tokenManager, createMockActivityMonitor());
|
|
104
76
|
|
|
105
77
|
timer.start();
|
|
106
78
|
await vi.advanceTimersByTimeAsync(30_000);
|
|
@@ -108,23 +80,6 @@ describe("SessionRefreshTimer", () => {
|
|
|
108
80
|
expect(tokenManager.refreshToken).toHaveBeenCalledTimes(1);
|
|
109
81
|
});
|
|
110
82
|
|
|
111
|
-
it("should publish refreshTokenFailed when refresh throws", async () => {
|
|
112
|
-
const tokenManager = createMockTokenManager({
|
|
113
|
-
getToken: vi.fn().mockReturnValue(createJwt(Math.floor(Date.now() / 1000) - 60)),
|
|
114
|
-
refreshToken: vi.fn().mockRejectedValue(new Error("Refresh failed")),
|
|
115
|
-
});
|
|
116
|
-
const timer = new SessionRefreshTimerImpl(
|
|
117
|
-
tokenManager,
|
|
118
|
-
createMockActivityMonitor(),
|
|
119
|
-
mockBroker,
|
|
120
|
-
);
|
|
121
|
-
|
|
122
|
-
timer.start();
|
|
123
|
-
await vi.advanceTimersByTimeAsync(30_000);
|
|
124
|
-
|
|
125
|
-
expect(mockBroker.publish).toHaveBeenCalledWith(BROKER_EVENTS.shell.refreshTokenFailed, {});
|
|
126
|
-
});
|
|
127
|
-
|
|
128
83
|
it("should not trigger concurrent refreshes", async () => {
|
|
129
84
|
let resolveRefresh!: () => void;
|
|
130
85
|
const tokenManager = createMockTokenManager({
|
|
@@ -133,11 +88,7 @@ describe("SessionRefreshTimer", () => {
|
|
|
133
88
|
() => new Promise((resolve) => { resolveRefresh = () => resolve("new_token"); }),
|
|
134
89
|
),
|
|
135
90
|
});
|
|
136
|
-
const timer = new SessionRefreshTimerImpl(
|
|
137
|
-
tokenManager,
|
|
138
|
-
createMockActivityMonitor(),
|
|
139
|
-
mockBroker,
|
|
140
|
-
);
|
|
91
|
+
const timer = new SessionRefreshTimerImpl(tokenManager, createMockActivityMonitor());
|
|
141
92
|
|
|
142
93
|
timer.start();
|
|
143
94
|
await vi.advanceTimersByTimeAsync(30_000);
|
|
@@ -1,7 +1,5 @@
|
|
|
1
1
|
import { jwtDecode } from "jwt-decode";
|
|
2
2
|
import { ActivityMonitor } from "../activity-monitor/activity-monitor";
|
|
3
|
-
import { BROKER_EVENTS } from "../broker/broker-events";
|
|
4
|
-
import { PrimariaBroker } from "../broker/primaria-broker";
|
|
5
3
|
import { TokenManager } from "../token-manager/token-manager";
|
|
6
4
|
|
|
7
5
|
const CHECK_INTERVAL_MS = 30_000;
|
|
@@ -20,7 +18,6 @@ export class SessionRefreshTimerImpl implements SessionRefreshTimer {
|
|
|
20
18
|
constructor(
|
|
21
19
|
private readonly tokenManager: TokenManager,
|
|
22
20
|
private readonly activityMonitor: ActivityMonitor,
|
|
23
|
-
private readonly broker: PrimariaBroker,
|
|
24
21
|
) {}
|
|
25
22
|
|
|
26
23
|
start = () => {
|
|
@@ -64,7 +61,7 @@ export class SessionRefreshTimerImpl implements SessionRefreshTimer {
|
|
|
64
61
|
try {
|
|
65
62
|
await this.tokenManager.refreshToken();
|
|
66
63
|
} catch {
|
|
67
|
-
|
|
64
|
+
// tokenManager.refreshToken() publishes refreshTokenFailed via broker on failure
|
|
68
65
|
} finally {
|
|
69
66
|
this.isRefreshing = false;
|
|
70
67
|
}
|
|
@@ -75,5 +72,4 @@ export class SessionRefreshTimerImpl implements SessionRefreshTimer {
|
|
|
75
72
|
export const createSessionRefreshTimer = (
|
|
76
73
|
tokenManager: TokenManager,
|
|
77
74
|
activityMonitor: ActivityMonitor,
|
|
78
|
-
|
|
79
|
-
): SessionRefreshTimer => new SessionRefreshTimerImpl(tokenManager, activityMonitor, broker);
|
|
75
|
+
): SessionRefreshTimer => new SessionRefreshTimerImpl(tokenManager, activityMonitor);
|
|
@@ -1,5 +1,6 @@
|
|
|
1
1
|
import { afterEach, beforeEach, describe, expect, it, vi } from "vitest";
|
|
2
2
|
import axios from "axios";
|
|
3
|
+
import { BROKER_EVENTS } from "../broker/broker-events";
|
|
3
4
|
|
|
4
5
|
vi.mock("axios");
|
|
5
6
|
|
|
@@ -8,10 +9,19 @@ const refresh_token = "test_refresh_token";
|
|
|
8
9
|
const new_access_token = "new_access_token";
|
|
9
10
|
const new_refresh_token = "new_refresh_token";
|
|
10
11
|
|
|
12
|
+
const createMockBroker = () => ({
|
|
13
|
+
publish: vi.fn().mockResolvedValue(undefined),
|
|
14
|
+
subscribe: vi.fn(),
|
|
15
|
+
send: vi.fn(),
|
|
16
|
+
registerRequest: vi.fn(),
|
|
17
|
+
events: BROKER_EVENTS,
|
|
18
|
+
});
|
|
19
|
+
|
|
11
20
|
describe("TokenManager", () => {
|
|
12
21
|
let mockLocation: Partial<Location>;
|
|
13
22
|
let TokenManagerImpl: any;
|
|
14
23
|
let createTokenManager: any;
|
|
24
|
+
let mockBroker: ReturnType<typeof createMockBroker>;
|
|
15
25
|
|
|
16
26
|
beforeEach(async () => {
|
|
17
27
|
vi.resetModules();
|
|
@@ -19,6 +29,7 @@ describe("TokenManager", () => {
|
|
|
19
29
|
search: `?access_token=${access_token}&refresh_token=${refresh_token}`,
|
|
20
30
|
};
|
|
21
31
|
vi.spyOn(window, "location", "get").mockReturnValue(mockLocation as Location);
|
|
32
|
+
mockBroker = createMockBroker();
|
|
22
33
|
|
|
23
34
|
const module = await import("./token-manager");
|
|
24
35
|
TokenManagerImpl = module.TokenManagerImpl;
|
|
@@ -31,31 +42,31 @@ describe("TokenManager", () => {
|
|
|
31
42
|
|
|
32
43
|
describe("getToken", () => {
|
|
33
44
|
it("should initialize token from URL params on first call", () => {
|
|
34
|
-
const tokenManager = new TokenManagerImpl();
|
|
45
|
+
const tokenManager = new TokenManagerImpl(mockBroker);
|
|
35
46
|
expect(tokenManager.getToken()).toBe(access_token);
|
|
36
47
|
});
|
|
37
48
|
|
|
38
49
|
it("should return empty string if URL params are missing", () => {
|
|
39
50
|
mockLocation.search = "";
|
|
40
|
-
const tokenManager = new TokenManagerImpl();
|
|
51
|
+
const tokenManager = new TokenManagerImpl(mockBroker);
|
|
41
52
|
expect(tokenManager.getToken()).toBe("");
|
|
42
53
|
});
|
|
43
54
|
|
|
44
55
|
it("should return the same token on subsequent calls", () => {
|
|
45
|
-
const tokenManager = new TokenManagerImpl();
|
|
56
|
+
const tokenManager = new TokenManagerImpl(mockBroker);
|
|
46
57
|
expect(tokenManager.getToken()).toBe(tokenManager.getToken());
|
|
47
58
|
});
|
|
48
59
|
});
|
|
49
60
|
|
|
50
61
|
describe("setInitialTokens", () => {
|
|
51
62
|
it("should set tokens manually", () => {
|
|
52
|
-
const tokenManager = new TokenManagerImpl();
|
|
63
|
+
const tokenManager = new TokenManagerImpl(mockBroker);
|
|
53
64
|
tokenManager.setInitialTokens("manual_access", "manual_refresh");
|
|
54
65
|
expect(tokenManager.getToken()).toBe("manual_access");
|
|
55
66
|
});
|
|
56
67
|
|
|
57
68
|
it("should throw error if tokens are already initialized", () => {
|
|
58
|
-
const tokenManager = new TokenManagerImpl();
|
|
69
|
+
const tokenManager = new TokenManagerImpl(mockBroker);
|
|
59
70
|
tokenManager.setInitialTokens("manual_access", "manual_refresh");
|
|
60
71
|
expect(() => tokenManager.setInitialTokens("another_access", "another_refresh")).toThrow(
|
|
61
72
|
"Token already initialized",
|
|
@@ -63,7 +74,7 @@ describe("TokenManager", () => {
|
|
|
63
74
|
});
|
|
64
75
|
|
|
65
76
|
it("should throw error if tokens were already initialized from URL", () => {
|
|
66
|
-
const tokenManager = new TokenManagerImpl();
|
|
77
|
+
const tokenManager = new TokenManagerImpl(mockBroker);
|
|
67
78
|
tokenManager.getToken();
|
|
68
79
|
expect(() => tokenManager.setInitialTokens("manual_access", "manual_refresh")).toThrow(
|
|
69
80
|
"Token already initialized",
|
|
@@ -77,7 +88,7 @@ describe("TokenManager", () => {
|
|
|
77
88
|
data: { access_token: new_access_token, refresh_token: new_refresh_token },
|
|
78
89
|
});
|
|
79
90
|
|
|
80
|
-
const tokenManager = new TokenManagerImpl();
|
|
91
|
+
const tokenManager = new TokenManagerImpl(mockBroker);
|
|
81
92
|
tokenManager.setInitialTokens(access_token, refresh_token);
|
|
82
93
|
|
|
83
94
|
const refreshed = await tokenManager.refreshToken();
|
|
@@ -92,7 +103,7 @@ describe("TokenManager", () => {
|
|
|
92
103
|
data: { access_token: new_access_token, refresh_token: new_refresh_token },
|
|
93
104
|
});
|
|
94
105
|
|
|
95
|
-
const tokenManager = new TokenManagerImpl();
|
|
106
|
+
const tokenManager = new TokenManagerImpl(mockBroker);
|
|
96
107
|
await tokenManager.refreshToken();
|
|
97
108
|
|
|
98
109
|
expect(axios.post).toHaveBeenCalledWith("/api/token/refresh", { token: refresh_token });
|
|
@@ -101,25 +112,38 @@ describe("TokenManager", () => {
|
|
|
101
112
|
it("should throw error if refresh response doesn't contain access_token", async () => {
|
|
102
113
|
vi.mocked(axios.post).mockResolvedValue({ data: {} });
|
|
103
114
|
|
|
104
|
-
const tokenManager = new TokenManagerImpl();
|
|
115
|
+
const tokenManager = new TokenManagerImpl(mockBroker);
|
|
105
116
|
tokenManager.setInitialTokens(access_token, refresh_token);
|
|
106
117
|
|
|
107
118
|
await expect(tokenManager.refreshToken()).rejects.toThrow("Invalid refresh token response");
|
|
108
119
|
});
|
|
109
120
|
|
|
110
|
-
it("should
|
|
121
|
+
it("should publish refreshTokenFailed and rethrow when refresh fails", async () => {
|
|
111
122
|
vi.mocked(axios.post).mockRejectedValue(new Error("Network error"));
|
|
112
123
|
|
|
113
|
-
const tokenManager = new TokenManagerImpl();
|
|
124
|
+
const tokenManager = new TokenManagerImpl(mockBroker);
|
|
114
125
|
tokenManager.setInitialTokens(access_token, refresh_token);
|
|
115
126
|
|
|
116
127
|
await expect(tokenManager.refreshToken()).rejects.toThrow("Network error");
|
|
128
|
+
expect(mockBroker.publish).toHaveBeenCalledWith(BROKER_EVENTS.shell.refreshTokenFailed, {});
|
|
129
|
+
});
|
|
130
|
+
|
|
131
|
+
it("should not publish refreshTokenFailed when refresh succeeds", async () => {
|
|
132
|
+
vi.mocked(axios.post).mockResolvedValue({
|
|
133
|
+
data: { access_token: new_access_token, refresh_token: new_refresh_token },
|
|
134
|
+
});
|
|
135
|
+
|
|
136
|
+
const tokenManager = new TokenManagerImpl(mockBroker);
|
|
137
|
+
tokenManager.setInitialTokens(access_token, refresh_token);
|
|
138
|
+
|
|
139
|
+
await tokenManager.refreshToken();
|
|
140
|
+
expect(mockBroker.publish).not.toHaveBeenCalled();
|
|
117
141
|
});
|
|
118
142
|
});
|
|
119
143
|
|
|
120
144
|
describe("createTokenManager", () => {
|
|
121
145
|
it("should return a singleton instance", () => {
|
|
122
|
-
expect(createTokenManager()).toBe(createTokenManager());
|
|
146
|
+
expect(createTokenManager(mockBroker)).toBe(createTokenManager(mockBroker));
|
|
123
147
|
});
|
|
124
148
|
});
|
|
125
149
|
});
|
|
@@ -1,4 +1,6 @@
|
|
|
1
1
|
import axios from "axios";
|
|
2
|
+
import { BROKER_EVENTS } from "../broker/broker-events";
|
|
3
|
+
import { PrimariaBroker } from "../broker/primaria-broker";
|
|
2
4
|
|
|
3
5
|
export interface TokenManager {
|
|
4
6
|
setInitialTokens: (access_token: string, refresh_token: string) => void;
|
|
@@ -11,6 +13,8 @@ let refreshToken: string;
|
|
|
11
13
|
let tokenInitialized = false;
|
|
12
14
|
|
|
13
15
|
export class TokenManagerImpl implements TokenManager {
|
|
16
|
+
constructor(private readonly broker: PrimariaBroker) {}
|
|
17
|
+
|
|
14
18
|
getUrlParams = (): URLSearchParams => {
|
|
15
19
|
return new URLSearchParams(window.location.search);
|
|
16
20
|
};
|
|
@@ -38,19 +42,24 @@ export class TokenManagerImpl implements TokenManager {
|
|
|
38
42
|
|
|
39
43
|
refreshToken = async () => {
|
|
40
44
|
if (!tokenInitialized) this.initToken();
|
|
41
|
-
|
|
42
|
-
|
|
43
|
-
|
|
44
|
-
|
|
45
|
-
|
|
46
|
-
|
|
45
|
+
try {
|
|
46
|
+
const response = await axios.post("/api/token/refresh", { token: refreshToken });
|
|
47
|
+
const { access_token, refresh_token } = response.data;
|
|
48
|
+
if (!access_token) throw new Error("Invalid refresh token response");
|
|
49
|
+
token = access_token;
|
|
50
|
+
refreshToken = refresh_token;
|
|
51
|
+
return token;
|
|
52
|
+
} catch (error) {
|
|
53
|
+
this.broker.publish(BROKER_EVENTS.shell.refreshTokenFailed, {});
|
|
54
|
+
throw error;
|
|
55
|
+
}
|
|
47
56
|
};
|
|
48
57
|
}
|
|
49
58
|
|
|
50
59
|
let tokenManager: TokenManagerImpl;
|
|
51
60
|
|
|
52
|
-
export const createTokenManager = () => {
|
|
61
|
+
export const createTokenManager = (broker: PrimariaBroker) => {
|
|
53
62
|
if (tokenManager) return tokenManager;
|
|
54
|
-
tokenManager = new TokenManagerImpl();
|
|
63
|
+
tokenManager = new TokenManagerImpl(broker);
|
|
55
64
|
return tokenManager;
|
|
56
65
|
};
|