@zeniai/client-epic-state 4.20.8 → 4.20.9-beta0ND
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/lib/coreEpics.js +2 -1
- package/lib/entity/tenant/SessionManager.d.ts +38 -0
- package/lib/entity/tenant/SessionManager.js +171 -0
- package/lib/entity/tenant/epic/sessionHeartbeatEpic.d.ts +16 -0
- package/lib/entity/tenant/epic/sessionHeartbeatEpic.js +16 -0
- package/lib/entity/tenant/sessionTypes.d.ts +26 -0
- package/lib/entity/tenant/sessionTypes.js +12 -0
- package/lib/entity/tenant/tenantReducer.d.ts +5 -1
- package/lib/entity/tenant/tenantReducer.js +23 -2
- package/lib/entity/tenant/tenantState.d.ts +1 -0
- package/lib/esm/coreEpics.js +2 -1
- package/lib/esm/entity/tenant/SessionManager.js +167 -0
- package/lib/esm/entity/tenant/epic/sessionHeartbeatEpic.js +12 -0
- package/lib/esm/entity/tenant/sessionTypes.js +9 -0
- package/lib/esm/entity/tenant/tenantReducer.js +21 -1
- package/lib/esm/index.js +5 -2
- package/lib/esm/view/expenseAutomationView/selectors/missingReceiptsSelector.js +1 -0
- package/lib/index.d.ts +5 -2
- package/lib/index.js +35 -29
- package/lib/tsconfig.typecheck.tsbuildinfo +1 -1
- package/lib/view/expenseAutomationView/selectorTypes/missingReceiptsSelectorTypes.d.ts +1 -0
- package/lib/view/expenseAutomationView/selectors/missingReceiptsSelector.js +1 -0
- package/package.json +1 -1
package/lib/coreEpics.js
CHANGED
|
@@ -24,6 +24,7 @@ const resendVerifyDeviceOTPEpic_1 = require("./entity/tenant/epic/resendVerifyDe
|
|
|
24
24
|
const saveExternalConnectionEpic_1 = require("./entity/tenant/epic/saveExternalConnectionEpic");
|
|
25
25
|
const sendEmailMagicLinkToUserEpic_1 = require("./entity/tenant/epic/sendEmailMagicLinkToUserEpic");
|
|
26
26
|
const signInUserEpic_1 = require("./entity/tenant/epic/signInUserEpic");
|
|
27
|
+
const sessionHeartbeatEpic_1 = require("./entity/tenant/epic/sessionHeartbeatEpic");
|
|
27
28
|
const signOutUserEpic_1 = require("./entity/tenant/epic/signOutUserEpic");
|
|
28
29
|
const verifyDeviceWithTwoFAEpic_1 = require("./entity/tenant/epic/verifyDeviceWithTwoFAEpic");
|
|
29
30
|
// ── Toast Notification Epic ──────────────────────────────────────────
|
|
@@ -48,7 +49,7 @@ const verifyOtpEpic_1 = require("./view/twoFactorAuthentication/verifyOtpEpic");
|
|
|
48
49
|
// RootActionType is only available in the dynamically imported epic.ts.
|
|
49
50
|
const coreRootEpic = (0, redux_observable_1.combineEpics)(
|
|
50
51
|
// Auth & tenant
|
|
51
|
-
clearAllEpic_1.clearAllEpic, doMagicLinkSignInEpic_1.doMagicLinkSignInEpic, signInUserEpic_1.doSignInEpic, signOutUserEpic_1.doSignOutEpic, fetchActiveTenantEpic_1.fetchActiveTenantEpic, fetchAllTenantsEpic_1.fetchAllTenantsEpic, fetchExcludedResourcesEpic_1.fetchExcludedResourcesEpic, fetchExternalConnectionsEpic_1.fetchExternalConnectionsEpic, fetchSubscriptionSummaryForTenantEpic_1.fetchSubscriptionSummaryForTenantEpic, resendVerifyDeviceOTPEpic_1.resendVerifyDeviceOTPEpic, saveExternalConnectionEpic_1.saveExternalConnectionEpic, sendEmailMagicLinkToUserEpic_1.sendEmailMagicLinkToUserEpic, verifyDeviceWithTwoFAEpic_1.verifyDeviceWithTwoFAEpic,
|
|
52
|
+
clearAllEpic_1.clearAllEpic, doMagicLinkSignInEpic_1.doMagicLinkSignInEpic, signInUserEpic_1.doSignInEpic, signOutUserEpic_1.doSignOutEpic, sessionHeartbeatEpic_1.sessionHeartbeatEpic, fetchActiveTenantEpic_1.fetchActiveTenantEpic, fetchAllTenantsEpic_1.fetchAllTenantsEpic, fetchExcludedResourcesEpic_1.fetchExcludedResourcesEpic, fetchExternalConnectionsEpic_1.fetchExternalConnectionsEpic, fetchSubscriptionSummaryForTenantEpic_1.fetchSubscriptionSummaryForTenantEpic, resendVerifyDeviceOTPEpic_1.resendVerifyDeviceOTPEpic, saveExternalConnectionEpic_1.saveExternalConnectionEpic, sendEmailMagicLinkToUserEpic_1.sendEmailMagicLinkToUserEpic, verifyDeviceWithTwoFAEpic_1.verifyDeviceWithTwoFAEpic,
|
|
52
53
|
// Toast
|
|
53
54
|
pushToastNotificationEpic_1.pushToastNotificationEpic,
|
|
54
55
|
// Collaboration
|
|
@@ -0,0 +1,38 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* SessionManager — Central session lifecycle manager.
|
|
3
|
+
*
|
|
4
|
+
* Responsibilities:
|
|
5
|
+
* 1. Track user activity (mousemove, keydown, click, scroll, touch)
|
|
6
|
+
* 2. Send heartbeat at configurable intervals while user is active
|
|
7
|
+
* 3. Show warning popup after idle timeout
|
|
8
|
+
* 4. Auto-logout after warning countdown expires
|
|
9
|
+
*/
|
|
10
|
+
import { SessionCallbacks, SessionConfig } from './sessionTypes';
|
|
11
|
+
export declare class SessionManager {
|
|
12
|
+
private config;
|
|
13
|
+
private callbacks;
|
|
14
|
+
/** Timestamps and timers */
|
|
15
|
+
private lastActivityTime;
|
|
16
|
+
private idleCheckInterval;
|
|
17
|
+
private heartbeatInterval;
|
|
18
|
+
private countdownInterval;
|
|
19
|
+
private activityDebounceTimer;
|
|
20
|
+
/** State */
|
|
21
|
+
private running;
|
|
22
|
+
private warningActive;
|
|
23
|
+
private secondsRemaining;
|
|
24
|
+
/** Bound handler for event listener cleanup. */
|
|
25
|
+
private boundOnActivity;
|
|
26
|
+
private boundOnVisibilityChange;
|
|
27
|
+
start(config: Partial<SessionConfig> | undefined, callbacks: SessionCallbacks): void;
|
|
28
|
+
stop(): void;
|
|
29
|
+
continueSession(): void;
|
|
30
|
+
isWarningActive(): boolean;
|
|
31
|
+
getSecondsRemaining(): number;
|
|
32
|
+
private onActivity;
|
|
33
|
+
private onVisibilityChange;
|
|
34
|
+
private checkIdle;
|
|
35
|
+
private startWarning;
|
|
36
|
+
private startHeartbeat;
|
|
37
|
+
private clearTimer;
|
|
38
|
+
}
|
|
@@ -0,0 +1,171 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
/**
|
|
3
|
+
* SessionManager — Central session lifecycle manager.
|
|
4
|
+
*
|
|
5
|
+
* Responsibilities:
|
|
6
|
+
* 1. Track user activity (mousemove, keydown, click, scroll, touch)
|
|
7
|
+
* 2. Send heartbeat at configurable intervals while user is active
|
|
8
|
+
* 3. Show warning popup after idle timeout
|
|
9
|
+
* 4. Auto-logout after warning countdown expires
|
|
10
|
+
*/
|
|
11
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
12
|
+
exports.SessionManager = void 0;
|
|
13
|
+
const sessionTypes_1 = require("./sessionTypes");
|
|
14
|
+
/** Events that indicate user activity. */
|
|
15
|
+
const ACTIVITY_EVENTS = [
|
|
16
|
+
'mousemove',
|
|
17
|
+
'mousedown',
|
|
18
|
+
'keydown',
|
|
19
|
+
'scroll',
|
|
20
|
+
'touchstart',
|
|
21
|
+
'click',
|
|
22
|
+
];
|
|
23
|
+
/** Debounce interval for activity events (ms). */
|
|
24
|
+
const ACTIVITY_DEBOUNCE_MS = 1000;
|
|
25
|
+
class SessionManager {
|
|
26
|
+
constructor() {
|
|
27
|
+
this.config = sessionTypes_1.DEFAULT_SESSION_CONFIG;
|
|
28
|
+
this.callbacks = null;
|
|
29
|
+
/** Timestamps and timers */
|
|
30
|
+
this.lastActivityTime = 0;
|
|
31
|
+
this.idleCheckInterval = null;
|
|
32
|
+
this.heartbeatInterval = null;
|
|
33
|
+
this.countdownInterval = null;
|
|
34
|
+
this.activityDebounceTimer = null;
|
|
35
|
+
/** State */
|
|
36
|
+
this.running = false;
|
|
37
|
+
this.warningActive = false;
|
|
38
|
+
this.secondsRemaining = 0;
|
|
39
|
+
/** Bound handler for event listener cleanup. */
|
|
40
|
+
this.boundOnActivity = this.onActivity.bind(this);
|
|
41
|
+
this.boundOnVisibilityChange = this.onVisibilityChange.bind(this);
|
|
42
|
+
}
|
|
43
|
+
// ─── Public API ────────────────────────────────────────────
|
|
44
|
+
start(config = {}, callbacks) {
|
|
45
|
+
if (this.running) {
|
|
46
|
+
this.stop();
|
|
47
|
+
}
|
|
48
|
+
this.config = { ...sessionTypes_1.DEFAULT_SESSION_CONFIG, ...config };
|
|
49
|
+
this.callbacks = callbacks;
|
|
50
|
+
this.running = true;
|
|
51
|
+
this.warningActive = false;
|
|
52
|
+
this.lastActivityTime = Date.now();
|
|
53
|
+
if (!this.config.isAutoLogoutEnabled) {
|
|
54
|
+
return;
|
|
55
|
+
}
|
|
56
|
+
ACTIVITY_EVENTS.forEach((event) => {
|
|
57
|
+
document.addEventListener(event, this.boundOnActivity, {
|
|
58
|
+
capture: true,
|
|
59
|
+
passive: true,
|
|
60
|
+
});
|
|
61
|
+
});
|
|
62
|
+
document.addEventListener('visibilitychange', this.boundOnVisibilityChange);
|
|
63
|
+
this.startHeartbeat();
|
|
64
|
+
this.callbacks?.onHeartbeat();
|
|
65
|
+
this.idleCheckInterval = setInterval(() => this.checkIdle(), 1000);
|
|
66
|
+
}
|
|
67
|
+
stop() {
|
|
68
|
+
this.running = false;
|
|
69
|
+
this.warningActive = false;
|
|
70
|
+
ACTIVITY_EVENTS.forEach((event) => {
|
|
71
|
+
document.removeEventListener(event, this.boundOnActivity, {
|
|
72
|
+
capture: true,
|
|
73
|
+
});
|
|
74
|
+
});
|
|
75
|
+
document.removeEventListener('visibilitychange', this.boundOnVisibilityChange);
|
|
76
|
+
this.clearTimer('idleCheckInterval');
|
|
77
|
+
this.clearTimer('heartbeatInterval');
|
|
78
|
+
this.clearTimer('countdownInterval');
|
|
79
|
+
this.clearTimer('activityDebounceTimer');
|
|
80
|
+
}
|
|
81
|
+
continueSession() {
|
|
82
|
+
if (!this.running) {
|
|
83
|
+
return;
|
|
84
|
+
}
|
|
85
|
+
this.warningActive = false;
|
|
86
|
+
this.secondsRemaining = 0;
|
|
87
|
+
this.lastActivityTime = Date.now();
|
|
88
|
+
this.clearTimer('countdownInterval');
|
|
89
|
+
this.callbacks?.onHeartbeat();
|
|
90
|
+
this.callbacks?.onSessionExtended();
|
|
91
|
+
this.startHeartbeat();
|
|
92
|
+
}
|
|
93
|
+
isWarningActive() {
|
|
94
|
+
return this.warningActive;
|
|
95
|
+
}
|
|
96
|
+
getSecondsRemaining() {
|
|
97
|
+
return this.secondsRemaining;
|
|
98
|
+
}
|
|
99
|
+
// ─── Private ───────────────────────────────────────────────
|
|
100
|
+
onActivity() {
|
|
101
|
+
if (!this.running || this.warningActive) {
|
|
102
|
+
return;
|
|
103
|
+
}
|
|
104
|
+
if (this.activityDebounceTimer != null) {
|
|
105
|
+
return;
|
|
106
|
+
}
|
|
107
|
+
this.lastActivityTime = Date.now();
|
|
108
|
+
this.activityDebounceTimer = setTimeout(() => {
|
|
109
|
+
this.activityDebounceTimer = null;
|
|
110
|
+
}, ACTIVITY_DEBOUNCE_MS);
|
|
111
|
+
}
|
|
112
|
+
onVisibilityChange() {
|
|
113
|
+
if (!this.running) {
|
|
114
|
+
return;
|
|
115
|
+
}
|
|
116
|
+
if (document.visibilityState === 'visible') {
|
|
117
|
+
this.lastActivityTime = Date.now();
|
|
118
|
+
this.checkIdle();
|
|
119
|
+
}
|
|
120
|
+
}
|
|
121
|
+
checkIdle() {
|
|
122
|
+
if (!this.running || this.warningActive) {
|
|
123
|
+
return;
|
|
124
|
+
}
|
|
125
|
+
const idleMs = Date.now() - this.lastActivityTime;
|
|
126
|
+
const idleTimeoutMs = this.config.idleTimeoutMinutes * 60 * 1000;
|
|
127
|
+
if (idleMs >= idleTimeoutMs) {
|
|
128
|
+
this.startWarning();
|
|
129
|
+
}
|
|
130
|
+
}
|
|
131
|
+
startWarning() {
|
|
132
|
+
this.warningActive = true;
|
|
133
|
+
this.secondsRemaining = this.config.warningDurationSeconds;
|
|
134
|
+
this.clearTimer('heartbeatInterval');
|
|
135
|
+
this.callbacks?.onWarningStart(this.secondsRemaining);
|
|
136
|
+
this.countdownInterval = setInterval(() => {
|
|
137
|
+
this.secondsRemaining -= 1;
|
|
138
|
+
if (this.secondsRemaining <= 0) {
|
|
139
|
+
this.clearTimer('countdownInterval');
|
|
140
|
+
this.warningActive = false;
|
|
141
|
+
this.callbacks?.onAutoLogout();
|
|
142
|
+
}
|
|
143
|
+
else {
|
|
144
|
+
this.callbacks?.onWarningTick(this.secondsRemaining);
|
|
145
|
+
}
|
|
146
|
+
}, 1000);
|
|
147
|
+
}
|
|
148
|
+
startHeartbeat() {
|
|
149
|
+
this.clearTimer('heartbeatInterval');
|
|
150
|
+
const intervalMs = this.config.heartbeatIntervalMinutes * 60 * 1000;
|
|
151
|
+
this.heartbeatInterval = setInterval(() => {
|
|
152
|
+
if (!this.running || this.warningActive) {
|
|
153
|
+
return;
|
|
154
|
+
}
|
|
155
|
+
this.callbacks?.onHeartbeat();
|
|
156
|
+
}, intervalMs);
|
|
157
|
+
}
|
|
158
|
+
clearTimer(name) {
|
|
159
|
+
const timer = this[name];
|
|
160
|
+
if (timer != null) {
|
|
161
|
+
if (name === 'activityDebounceTimer') {
|
|
162
|
+
clearTimeout(timer);
|
|
163
|
+
}
|
|
164
|
+
else {
|
|
165
|
+
clearInterval(timer);
|
|
166
|
+
}
|
|
167
|
+
this[name] = null;
|
|
168
|
+
}
|
|
169
|
+
}
|
|
170
|
+
}
|
|
171
|
+
exports.SessionManager = SessionManager;
|
|
@@ -0,0 +1,16 @@
|
|
|
1
|
+
import { ActionsObservable, StateObservable } from 'redux-observable';
|
|
2
|
+
import { RootState } from '../../../reducer';
|
|
3
|
+
import { ZeniAPI } from '../../../zeniAPI';
|
|
4
|
+
import { sendSessionHeartbeat, sessionHeartbeatFailure, sessionHeartbeatSuccess } from '../tenantReducer';
|
|
5
|
+
export type ActionType = ReturnType<typeof sendSessionHeartbeat> | ReturnType<typeof sessionHeartbeatSuccess> | ReturnType<typeof sessionHeartbeatFailure>;
|
|
6
|
+
export declare const sessionHeartbeatEpic: (actions$: ActionsObservable<ActionType>, _: StateObservable<RootState>, zeniAPI: ZeniAPI) => import("rxjs").Observable<{
|
|
7
|
+
payload: {
|
|
8
|
+
expiresAt: string;
|
|
9
|
+
};
|
|
10
|
+
type: "tenant/sessionHeartbeatSuccess";
|
|
11
|
+
} | {
|
|
12
|
+
payload: {
|
|
13
|
+
error: import("../../../responsePayload").ZeniAPIStatus<Record<string, unknown>>;
|
|
14
|
+
};
|
|
15
|
+
type: "tenant/sessionHeartbeatFailure";
|
|
16
|
+
}>;
|
|
@@ -0,0 +1,16 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
+
exports.sessionHeartbeatEpic = void 0;
|
|
4
|
+
const rxjs_1 = require("rxjs");
|
|
5
|
+
const operators_1 = require("rxjs/operators");
|
|
6
|
+
const responsePayload_1 = require("../../../responsePayload");
|
|
7
|
+
const tenantReducer_1 = require("../tenantReducer");
|
|
8
|
+
const sessionHeartbeatEpic = (actions$, _, zeniAPI) => actions$.pipe((0, operators_1.filter)(tenantReducer_1.sendSessionHeartbeat.match), (0, operators_1.switchMap)(() => zeniAPI
|
|
9
|
+
.postAndGetJSON(`${zeniAPI.apiEndPoints.authMicroServiceBaseUrl}/1.0/sessions/heartbeat`)
|
|
10
|
+
.pipe((0, operators_1.mergeMap)((response) => {
|
|
11
|
+
if ((0, responsePayload_1.isSuccessResponse)(response)) {
|
|
12
|
+
return (0, rxjs_1.of)((0, tenantReducer_1.sessionHeartbeatSuccess)(response.data?.expiry ?? ''));
|
|
13
|
+
}
|
|
14
|
+
return (0, rxjs_1.of)((0, tenantReducer_1.sessionHeartbeatFailure)(response.status));
|
|
15
|
+
}), (0, operators_1.catchError)((error) => (0, rxjs_1.of)((0, tenantReducer_1.sessionHeartbeatFailure)((0, responsePayload_1.createZeniAPIStatus)('Heartbeat failed', 'Session heartbeat API call errored: ' + JSON.stringify(error))))))));
|
|
16
|
+
exports.sessionHeartbeatEpic = sessionHeartbeatEpic;
|
|
@@ -0,0 +1,26 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Session management types for idle timeout and heartbeat.
|
|
3
|
+
*/
|
|
4
|
+
export interface SessionConfig {
|
|
5
|
+
/** Minutes between heartbeat API calls while user is active. Default: 10 */
|
|
6
|
+
heartbeatIntervalMinutes: number;
|
|
7
|
+
/** Minutes of inactivity before the warning popup appears. Default: 30 */
|
|
8
|
+
idleTimeoutMinutes: number;
|
|
9
|
+
/** Whether auto-logout is enabled. Default: true */
|
|
10
|
+
isAutoLogoutEnabled: boolean;
|
|
11
|
+
/** Seconds to count down in the warning popup before auto-logout. Default: 60 */
|
|
12
|
+
warningDurationSeconds: number;
|
|
13
|
+
}
|
|
14
|
+
export declare const DEFAULT_SESSION_CONFIG: SessionConfig;
|
|
15
|
+
export interface SessionCallbacks {
|
|
16
|
+
/** Called when the countdown reaches zero — app should sign out. */
|
|
17
|
+
onAutoLogout: () => void;
|
|
18
|
+
/** Called to send a heartbeat API request. */
|
|
19
|
+
onHeartbeat: () => void;
|
|
20
|
+
/** Called when the session is extended (heartbeat success or "Continue Session"). */
|
|
21
|
+
onSessionExtended: () => void;
|
|
22
|
+
/** Called when the warning countdown starts. */
|
|
23
|
+
onWarningStart: (secondsRemaining: number) => void;
|
|
24
|
+
/** Called every second during the countdown. */
|
|
25
|
+
onWarningTick: (secondsRemaining: number) => void;
|
|
26
|
+
}
|
|
@@ -0,0 +1,12 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
/**
|
|
3
|
+
* Session management types for idle timeout and heartbeat.
|
|
4
|
+
*/
|
|
5
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
6
|
+
exports.DEFAULT_SESSION_CONFIG = void 0;
|
|
7
|
+
exports.DEFAULT_SESSION_CONFIG = {
|
|
8
|
+
heartbeatIntervalMinutes: 10,
|
|
9
|
+
idleTimeoutMinutes: 30,
|
|
10
|
+
isAutoLogoutEnabled: true,
|
|
11
|
+
warningDurationSeconds: 60,
|
|
12
|
+
};
|
|
@@ -51,7 +51,11 @@ export declare const updateTenants: import("@reduxjs/toolkit").ActionCreatorWith
|
|
|
51
51
|
accountLockTime?: string;
|
|
52
52
|
accountUnlockTime?: string;
|
|
53
53
|
isAccountLocked?: boolean;
|
|
54
|
-
}, "tenant/sendEmailMagicLinkToUserFailure">, updateSignInState: import("@reduxjs/toolkit").ActionCreatorWithPayload<FetchState, "tenant/updateSignInState">, doSignOut: import("@reduxjs/toolkit").ActionCreatorWithoutPayload<"tenant/doSignOut">, signOutSuccess: import("@reduxjs/toolkit").ActionCreatorWithoutPayload<"tenant/signOutSuccess">,
|
|
54
|
+
}, "tenant/sendEmailMagicLinkToUserFailure">, updateSignInState: import("@reduxjs/toolkit").ActionCreatorWithPayload<FetchState, "tenant/updateSignInState">, doSignOut: import("@reduxjs/toolkit").ActionCreatorWithoutPayload<"tenant/doSignOut">, signOutSuccess: import("@reduxjs/toolkit").ActionCreatorWithoutPayload<"tenant/signOutSuccess">, sendSessionHeartbeat: import("@reduxjs/toolkit").ActionCreatorWithoutPayload<"tenant/sendSessionHeartbeat">, sessionHeartbeatSuccess: import("@reduxjs/toolkit").ActionCreatorWithPreparedPayload<[expiresAt: string], {
|
|
55
|
+
expiresAt: string;
|
|
56
|
+
}, "tenant/sessionHeartbeatSuccess", never, never>, sessionHeartbeatFailure: import("@reduxjs/toolkit").ActionCreatorWithPreparedPayload<[error: ZeniAPIStatus<Record<string, unknown>>], {
|
|
57
|
+
error: ZeniAPIStatus<Record<string, unknown>>;
|
|
58
|
+
}, "tenant/sessionHeartbeatFailure", never, never>, updateLoggedInUser: import("@reduxjs/toolkit").ActionCreatorWithPreparedPayload<[userPayload: LoggedInUserPayload, zeniSessionId: string, authProvider: AuthProvider], {
|
|
55
59
|
userPayload: LoggedInUserPayload;
|
|
56
60
|
zeniSessionId: string;
|
|
57
61
|
authProvider: AuthProvider;
|
|
@@ -4,7 +4,8 @@ var __importDefault = (this && this.__importDefault) || function (mod) {
|
|
|
4
4
|
};
|
|
5
5
|
var _a;
|
|
6
6
|
Object.defineProperty(exports, "__esModule", { value: true });
|
|
7
|
-
exports.
|
|
7
|
+
exports.resendVerifyDeviceOTPFailure = exports.resendVerifyDeviceOTPSuccess = exports.resendVerifyDeviceOTP = exports.verifyDeviceWithTwoFAFailure = exports.verifyDeviceWithTwoFASuccess = exports.verifyDeviceWithTwoFA = exports.updateTenantMasterTOSInfo = exports.trigger2FA = exports.resetSignInState = exports.updateTreasuryVideoViewedForLoggedInUser = exports.updateReferViewedForLoggedInUser = exports.updateTenantReimbursementInfo = exports.removeOnboardingTenant = exports.updateOnboardingTenants = exports.updateSubscriptionSummaryForTenantFailure = exports.updateSubscriptionSummaryForTenantSuccess = exports.fetchSubscriptionSummaryForTenant = exports.clearAll = exports.fetchExternalConnectionsSuccess = exports.fetchExternalConnectionsFailure = exports.saveExternalConnectionFailure = exports.saveExternalConnectionSuccess = exports.saveExternalConnection = exports.fetchExternalConnections = exports.updateLoggedInUser = exports.sessionHeartbeatFailure = exports.sessionHeartbeatSuccess = exports.sendSessionHeartbeat = exports.signOutSuccess = exports.doSignOut = exports.updateSignInState = exports.sendEmailMagicLinkToUserFailure = exports.sendEmailMagicLinkToUserSuccess = exports.sendEmailMagicLinkToUser = exports.magicLinkSignInFailure = exports.magicLinkSignInSuccess = exports.doMagicLinkSignIn = exports.doSignIn = exports.updateExcludedResourcesFailure = exports.updateExcludedResourcesSuccess = exports.fetchExcludedResources = exports.updateCurrentTenant = exports.updateTenantFailure = exports.updateTenantSuccess = exports.fetchActiveTenant = exports.updateTenantsFailure = exports.updateTenantsSuccess = exports.fetchAllTenants = exports.updateTenants = exports.initialState = void 0;
|
|
8
|
+
exports.toConnection = exports.toRoleResource = void 0;
|
|
8
9
|
exports.mapConnectionsPayloadToState = mapConnectionsPayloadToState;
|
|
9
10
|
const toolkit_1 = require("@reduxjs/toolkit");
|
|
10
11
|
const js_base64_1 = require("js-base64");
|
|
@@ -430,6 +431,26 @@ const tenant = (0, toolkit_1.createSlice)({
|
|
|
430
431
|
signOutSuccess(draft) {
|
|
431
432
|
draft.loggedInUser = undefined;
|
|
432
433
|
draft.currentTenantId = undefined;
|
|
434
|
+
draft.sessionExpiresAt = undefined;
|
|
435
|
+
},
|
|
436
|
+
sendSessionHeartbeat() {
|
|
437
|
+
// No state change needed — epic handles the API call
|
|
438
|
+
},
|
|
439
|
+
sessionHeartbeatSuccess: {
|
|
440
|
+
prepare(expiresAt) {
|
|
441
|
+
return { payload: { expiresAt } };
|
|
442
|
+
},
|
|
443
|
+
reducer(draft, action) {
|
|
444
|
+
draft.sessionExpiresAt = action.payload.expiresAt;
|
|
445
|
+
},
|
|
446
|
+
},
|
|
447
|
+
sessionHeartbeatFailure: {
|
|
448
|
+
prepare(error) {
|
|
449
|
+
return { payload: { error } };
|
|
450
|
+
},
|
|
451
|
+
reducer(draft, action) {
|
|
452
|
+
draft.error = action.payload.error;
|
|
453
|
+
},
|
|
433
454
|
},
|
|
434
455
|
fetchSubscriptionSummaryForTenant: {
|
|
435
456
|
prepare(tenantId) {
|
|
@@ -537,7 +558,7 @@ const tenant = (0, toolkit_1.createSlice)({
|
|
|
537
558
|
},
|
|
538
559
|
},
|
|
539
560
|
});
|
|
540
|
-
_a = tenant.actions, exports.updateTenants = _a.updateTenants, exports.fetchAllTenants = _a.fetchAllTenants, exports.updateTenantsSuccess = _a.updateTenantsSuccess, exports.updateTenantsFailure = _a.updateTenantsFailure, exports.fetchActiveTenant = _a.fetchActiveTenant, exports.updateTenantSuccess = _a.updateTenantSuccess, exports.updateTenantFailure = _a.updateTenantFailure, exports.updateCurrentTenant = _a.updateCurrentTenant, exports.fetchExcludedResources = _a.fetchExcludedResources, exports.updateExcludedResourcesSuccess = _a.updateExcludedResourcesSuccess, exports.updateExcludedResourcesFailure = _a.updateExcludedResourcesFailure, exports.doSignIn = _a.doSignIn, exports.doMagicLinkSignIn = _a.doMagicLinkSignIn, exports.magicLinkSignInSuccess = _a.magicLinkSignInSuccess, exports.magicLinkSignInFailure = _a.magicLinkSignInFailure, exports.sendEmailMagicLinkToUser = _a.sendEmailMagicLinkToUser, exports.sendEmailMagicLinkToUserSuccess = _a.sendEmailMagicLinkToUserSuccess, exports.sendEmailMagicLinkToUserFailure = _a.sendEmailMagicLinkToUserFailure, exports.updateSignInState = _a.updateSignInState, exports.doSignOut = _a.doSignOut, exports.signOutSuccess = _a.signOutSuccess, exports.updateLoggedInUser = _a.updateLoggedInUser, exports.fetchExternalConnections = _a.fetchExternalConnections, exports.saveExternalConnection = _a.saveExternalConnection, exports.saveExternalConnectionSuccess = _a.saveExternalConnectionSuccess, exports.saveExternalConnectionFailure = _a.saveExternalConnectionFailure, exports.fetchExternalConnectionsFailure = _a.fetchExternalConnectionsFailure, exports.fetchExternalConnectionsSuccess = _a.fetchExternalConnectionsSuccess, exports.clearAll = _a.clearAll, exports.fetchSubscriptionSummaryForTenant = _a.fetchSubscriptionSummaryForTenant, exports.updateSubscriptionSummaryForTenantSuccess = _a.updateSubscriptionSummaryForTenantSuccess, exports.updateSubscriptionSummaryForTenantFailure = _a.updateSubscriptionSummaryForTenantFailure, exports.updateOnboardingTenants = _a.updateOnboardingTenants, exports.removeOnboardingTenant = _a.removeOnboardingTenant, exports.updateTenantReimbursementInfo = _a.updateTenantReimbursementInfo, exports.updateReferViewedForLoggedInUser = _a.updateReferViewedForLoggedInUser, exports.updateTreasuryVideoViewedForLoggedInUser = _a.updateTreasuryVideoViewedForLoggedInUser, exports.resetSignInState = _a.resetSignInState, exports.trigger2FA = _a.trigger2FA, exports.updateTenantMasterTOSInfo = _a.updateTenantMasterTOSInfo, exports.verifyDeviceWithTwoFA = _a.verifyDeviceWithTwoFA, exports.verifyDeviceWithTwoFASuccess = _a.verifyDeviceWithTwoFASuccess, exports.verifyDeviceWithTwoFAFailure = _a.verifyDeviceWithTwoFAFailure, exports.resendVerifyDeviceOTP = _a.resendVerifyDeviceOTP, exports.resendVerifyDeviceOTPSuccess = _a.resendVerifyDeviceOTPSuccess, exports.resendVerifyDeviceOTPFailure = _a.resendVerifyDeviceOTPFailure;
|
|
561
|
+
_a = tenant.actions, exports.updateTenants = _a.updateTenants, exports.fetchAllTenants = _a.fetchAllTenants, exports.updateTenantsSuccess = _a.updateTenantsSuccess, exports.updateTenantsFailure = _a.updateTenantsFailure, exports.fetchActiveTenant = _a.fetchActiveTenant, exports.updateTenantSuccess = _a.updateTenantSuccess, exports.updateTenantFailure = _a.updateTenantFailure, exports.updateCurrentTenant = _a.updateCurrentTenant, exports.fetchExcludedResources = _a.fetchExcludedResources, exports.updateExcludedResourcesSuccess = _a.updateExcludedResourcesSuccess, exports.updateExcludedResourcesFailure = _a.updateExcludedResourcesFailure, exports.doSignIn = _a.doSignIn, exports.doMagicLinkSignIn = _a.doMagicLinkSignIn, exports.magicLinkSignInSuccess = _a.magicLinkSignInSuccess, exports.magicLinkSignInFailure = _a.magicLinkSignInFailure, exports.sendEmailMagicLinkToUser = _a.sendEmailMagicLinkToUser, exports.sendEmailMagicLinkToUserSuccess = _a.sendEmailMagicLinkToUserSuccess, exports.sendEmailMagicLinkToUserFailure = _a.sendEmailMagicLinkToUserFailure, exports.updateSignInState = _a.updateSignInState, exports.doSignOut = _a.doSignOut, exports.signOutSuccess = _a.signOutSuccess, exports.sendSessionHeartbeat = _a.sendSessionHeartbeat, exports.sessionHeartbeatSuccess = _a.sessionHeartbeatSuccess, exports.sessionHeartbeatFailure = _a.sessionHeartbeatFailure, exports.updateLoggedInUser = _a.updateLoggedInUser, exports.fetchExternalConnections = _a.fetchExternalConnections, exports.saveExternalConnection = _a.saveExternalConnection, exports.saveExternalConnectionSuccess = _a.saveExternalConnectionSuccess, exports.saveExternalConnectionFailure = _a.saveExternalConnectionFailure, exports.fetchExternalConnectionsFailure = _a.fetchExternalConnectionsFailure, exports.fetchExternalConnectionsSuccess = _a.fetchExternalConnectionsSuccess, exports.clearAll = _a.clearAll, exports.fetchSubscriptionSummaryForTenant = _a.fetchSubscriptionSummaryForTenant, exports.updateSubscriptionSummaryForTenantSuccess = _a.updateSubscriptionSummaryForTenantSuccess, exports.updateSubscriptionSummaryForTenantFailure = _a.updateSubscriptionSummaryForTenantFailure, exports.updateOnboardingTenants = _a.updateOnboardingTenants, exports.removeOnboardingTenant = _a.removeOnboardingTenant, exports.updateTenantReimbursementInfo = _a.updateTenantReimbursementInfo, exports.updateReferViewedForLoggedInUser = _a.updateReferViewedForLoggedInUser, exports.updateTreasuryVideoViewedForLoggedInUser = _a.updateTreasuryVideoViewedForLoggedInUser, exports.resetSignInState = _a.resetSignInState, exports.trigger2FA = _a.trigger2FA, exports.updateTenantMasterTOSInfo = _a.updateTenantMasterTOSInfo, exports.verifyDeviceWithTwoFA = _a.verifyDeviceWithTwoFA, exports.verifyDeviceWithTwoFASuccess = _a.verifyDeviceWithTwoFASuccess, exports.verifyDeviceWithTwoFAFailure = _a.verifyDeviceWithTwoFAFailure, exports.resendVerifyDeviceOTP = _a.resendVerifyDeviceOTP, exports.resendVerifyDeviceOTPSuccess = _a.resendVerifyDeviceOTPSuccess, exports.resendVerifyDeviceOTPFailure = _a.resendVerifyDeviceOTPFailure;
|
|
541
562
|
exports.default = tenant.reducer;
|
|
542
563
|
/**
|
|
543
564
|
* Converts tenants payload to Tenant and User State
|
package/lib/esm/coreEpics.js
CHANGED
|
@@ -22,6 +22,7 @@ import { resendVerifyDeviceOTPEpic } from './entity/tenant/epic/resendVerifyDevi
|
|
|
22
22
|
import { saveExternalConnectionEpic } from './entity/tenant/epic/saveExternalConnectionEpic';
|
|
23
23
|
import { sendEmailMagicLinkToUserEpic } from './entity/tenant/epic/sendEmailMagicLinkToUserEpic';
|
|
24
24
|
import { doSignInEpic } from './entity/tenant/epic/signInUserEpic';
|
|
25
|
+
import { sessionHeartbeatEpic } from './entity/tenant/epic/sessionHeartbeatEpic';
|
|
25
26
|
import { doSignOutEpic } from './entity/tenant/epic/signOutUserEpic';
|
|
26
27
|
import { verifyDeviceWithTwoFAEpic } from './entity/tenant/epic/verifyDeviceWithTwoFAEpic';
|
|
27
28
|
// ── Toast Notification Epic ──────────────────────────────────────────
|
|
@@ -46,7 +47,7 @@ import { verifyOtpEpic } from './view/twoFactorAuthentication/verifyOtpEpic';
|
|
|
46
47
|
// RootActionType is only available in the dynamically imported epic.ts.
|
|
47
48
|
const coreRootEpic = combineEpics(
|
|
48
49
|
// Auth & tenant
|
|
49
|
-
clearAllEpic, doMagicLinkSignInEpic, doSignInEpic, doSignOutEpic, fetchActiveTenantEpic, fetchAllTenantsEpic, fetchExcludedResourcesEpic, fetchExternalConnectionsEpic, fetchSubscriptionSummaryForTenantEpic, resendVerifyDeviceOTPEpic, saveExternalConnectionEpic, sendEmailMagicLinkToUserEpic, verifyDeviceWithTwoFAEpic,
|
|
50
|
+
clearAllEpic, doMagicLinkSignInEpic, doSignInEpic, doSignOutEpic, sessionHeartbeatEpic, fetchActiveTenantEpic, fetchAllTenantsEpic, fetchExcludedResourcesEpic, fetchExternalConnectionsEpic, fetchSubscriptionSummaryForTenantEpic, resendVerifyDeviceOTPEpic, saveExternalConnectionEpic, sendEmailMagicLinkToUserEpic, verifyDeviceWithTwoFAEpic,
|
|
50
51
|
// Toast
|
|
51
52
|
pushToastNotificationEpic,
|
|
52
53
|
// Collaboration
|
|
@@ -0,0 +1,167 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* SessionManager — Central session lifecycle manager.
|
|
3
|
+
*
|
|
4
|
+
* Responsibilities:
|
|
5
|
+
* 1. Track user activity (mousemove, keydown, click, scroll, touch)
|
|
6
|
+
* 2. Send heartbeat at configurable intervals while user is active
|
|
7
|
+
* 3. Show warning popup after idle timeout
|
|
8
|
+
* 4. Auto-logout after warning countdown expires
|
|
9
|
+
*/
|
|
10
|
+
import { DEFAULT_SESSION_CONFIG, } from './sessionTypes';
|
|
11
|
+
/** Events that indicate user activity. */
|
|
12
|
+
const ACTIVITY_EVENTS = [
|
|
13
|
+
'mousemove',
|
|
14
|
+
'mousedown',
|
|
15
|
+
'keydown',
|
|
16
|
+
'scroll',
|
|
17
|
+
'touchstart',
|
|
18
|
+
'click',
|
|
19
|
+
];
|
|
20
|
+
/** Debounce interval for activity events (ms). */
|
|
21
|
+
const ACTIVITY_DEBOUNCE_MS = 1000;
|
|
22
|
+
export class SessionManager {
|
|
23
|
+
constructor() {
|
|
24
|
+
this.config = DEFAULT_SESSION_CONFIG;
|
|
25
|
+
this.callbacks = null;
|
|
26
|
+
/** Timestamps and timers */
|
|
27
|
+
this.lastActivityTime = 0;
|
|
28
|
+
this.idleCheckInterval = null;
|
|
29
|
+
this.heartbeatInterval = null;
|
|
30
|
+
this.countdownInterval = null;
|
|
31
|
+
this.activityDebounceTimer = null;
|
|
32
|
+
/** State */
|
|
33
|
+
this.running = false;
|
|
34
|
+
this.warningActive = false;
|
|
35
|
+
this.secondsRemaining = 0;
|
|
36
|
+
/** Bound handler for event listener cleanup. */
|
|
37
|
+
this.boundOnActivity = this.onActivity.bind(this);
|
|
38
|
+
this.boundOnVisibilityChange = this.onVisibilityChange.bind(this);
|
|
39
|
+
}
|
|
40
|
+
// ─── Public API ────────────────────────────────────────────
|
|
41
|
+
start(config = {}, callbacks) {
|
|
42
|
+
if (this.running) {
|
|
43
|
+
this.stop();
|
|
44
|
+
}
|
|
45
|
+
this.config = { ...DEFAULT_SESSION_CONFIG, ...config };
|
|
46
|
+
this.callbacks = callbacks;
|
|
47
|
+
this.running = true;
|
|
48
|
+
this.warningActive = false;
|
|
49
|
+
this.lastActivityTime = Date.now();
|
|
50
|
+
if (!this.config.isAutoLogoutEnabled) {
|
|
51
|
+
return;
|
|
52
|
+
}
|
|
53
|
+
ACTIVITY_EVENTS.forEach((event) => {
|
|
54
|
+
document.addEventListener(event, this.boundOnActivity, {
|
|
55
|
+
capture: true,
|
|
56
|
+
passive: true,
|
|
57
|
+
});
|
|
58
|
+
});
|
|
59
|
+
document.addEventListener('visibilitychange', this.boundOnVisibilityChange);
|
|
60
|
+
this.startHeartbeat();
|
|
61
|
+
this.callbacks?.onHeartbeat();
|
|
62
|
+
this.idleCheckInterval = setInterval(() => this.checkIdle(), 1000);
|
|
63
|
+
}
|
|
64
|
+
stop() {
|
|
65
|
+
this.running = false;
|
|
66
|
+
this.warningActive = false;
|
|
67
|
+
ACTIVITY_EVENTS.forEach((event) => {
|
|
68
|
+
document.removeEventListener(event, this.boundOnActivity, {
|
|
69
|
+
capture: true,
|
|
70
|
+
});
|
|
71
|
+
});
|
|
72
|
+
document.removeEventListener('visibilitychange', this.boundOnVisibilityChange);
|
|
73
|
+
this.clearTimer('idleCheckInterval');
|
|
74
|
+
this.clearTimer('heartbeatInterval');
|
|
75
|
+
this.clearTimer('countdownInterval');
|
|
76
|
+
this.clearTimer('activityDebounceTimer');
|
|
77
|
+
}
|
|
78
|
+
continueSession() {
|
|
79
|
+
if (!this.running) {
|
|
80
|
+
return;
|
|
81
|
+
}
|
|
82
|
+
this.warningActive = false;
|
|
83
|
+
this.secondsRemaining = 0;
|
|
84
|
+
this.lastActivityTime = Date.now();
|
|
85
|
+
this.clearTimer('countdownInterval');
|
|
86
|
+
this.callbacks?.onHeartbeat();
|
|
87
|
+
this.callbacks?.onSessionExtended();
|
|
88
|
+
this.startHeartbeat();
|
|
89
|
+
}
|
|
90
|
+
isWarningActive() {
|
|
91
|
+
return this.warningActive;
|
|
92
|
+
}
|
|
93
|
+
getSecondsRemaining() {
|
|
94
|
+
return this.secondsRemaining;
|
|
95
|
+
}
|
|
96
|
+
// ─── Private ───────────────────────────────────────────────
|
|
97
|
+
onActivity() {
|
|
98
|
+
if (!this.running || this.warningActive) {
|
|
99
|
+
return;
|
|
100
|
+
}
|
|
101
|
+
if (this.activityDebounceTimer != null) {
|
|
102
|
+
return;
|
|
103
|
+
}
|
|
104
|
+
this.lastActivityTime = Date.now();
|
|
105
|
+
this.activityDebounceTimer = setTimeout(() => {
|
|
106
|
+
this.activityDebounceTimer = null;
|
|
107
|
+
}, ACTIVITY_DEBOUNCE_MS);
|
|
108
|
+
}
|
|
109
|
+
onVisibilityChange() {
|
|
110
|
+
if (!this.running) {
|
|
111
|
+
return;
|
|
112
|
+
}
|
|
113
|
+
if (document.visibilityState === 'visible') {
|
|
114
|
+
this.lastActivityTime = Date.now();
|
|
115
|
+
this.checkIdle();
|
|
116
|
+
}
|
|
117
|
+
}
|
|
118
|
+
checkIdle() {
|
|
119
|
+
if (!this.running || this.warningActive) {
|
|
120
|
+
return;
|
|
121
|
+
}
|
|
122
|
+
const idleMs = Date.now() - this.lastActivityTime;
|
|
123
|
+
const idleTimeoutMs = this.config.idleTimeoutMinutes * 60 * 1000;
|
|
124
|
+
if (idleMs >= idleTimeoutMs) {
|
|
125
|
+
this.startWarning();
|
|
126
|
+
}
|
|
127
|
+
}
|
|
128
|
+
startWarning() {
|
|
129
|
+
this.warningActive = true;
|
|
130
|
+
this.secondsRemaining = this.config.warningDurationSeconds;
|
|
131
|
+
this.clearTimer('heartbeatInterval');
|
|
132
|
+
this.callbacks?.onWarningStart(this.secondsRemaining);
|
|
133
|
+
this.countdownInterval = setInterval(() => {
|
|
134
|
+
this.secondsRemaining -= 1;
|
|
135
|
+
if (this.secondsRemaining <= 0) {
|
|
136
|
+
this.clearTimer('countdownInterval');
|
|
137
|
+
this.warningActive = false;
|
|
138
|
+
this.callbacks?.onAutoLogout();
|
|
139
|
+
}
|
|
140
|
+
else {
|
|
141
|
+
this.callbacks?.onWarningTick(this.secondsRemaining);
|
|
142
|
+
}
|
|
143
|
+
}, 1000);
|
|
144
|
+
}
|
|
145
|
+
startHeartbeat() {
|
|
146
|
+
this.clearTimer('heartbeatInterval');
|
|
147
|
+
const intervalMs = this.config.heartbeatIntervalMinutes * 60 * 1000;
|
|
148
|
+
this.heartbeatInterval = setInterval(() => {
|
|
149
|
+
if (!this.running || this.warningActive) {
|
|
150
|
+
return;
|
|
151
|
+
}
|
|
152
|
+
this.callbacks?.onHeartbeat();
|
|
153
|
+
}, intervalMs);
|
|
154
|
+
}
|
|
155
|
+
clearTimer(name) {
|
|
156
|
+
const timer = this[name];
|
|
157
|
+
if (timer != null) {
|
|
158
|
+
if (name === 'activityDebounceTimer') {
|
|
159
|
+
clearTimeout(timer);
|
|
160
|
+
}
|
|
161
|
+
else {
|
|
162
|
+
clearInterval(timer);
|
|
163
|
+
}
|
|
164
|
+
this[name] = null;
|
|
165
|
+
}
|
|
166
|
+
}
|
|
167
|
+
}
|
|
@@ -0,0 +1,12 @@
|
|
|
1
|
+
import { of } from 'rxjs';
|
|
2
|
+
import { catchError, filter, mergeMap, switchMap } from 'rxjs/operators';
|
|
3
|
+
import { createZeniAPIStatus, isSuccessResponse, } from '../../../responsePayload';
|
|
4
|
+
import { sendSessionHeartbeat, sessionHeartbeatFailure, sessionHeartbeatSuccess, } from '../tenantReducer';
|
|
5
|
+
export const sessionHeartbeatEpic = (actions$, _, zeniAPI) => actions$.pipe(filter(sendSessionHeartbeat.match), switchMap(() => zeniAPI
|
|
6
|
+
.postAndGetJSON(`${zeniAPI.apiEndPoints.authMicroServiceBaseUrl}/1.0/sessions/heartbeat`)
|
|
7
|
+
.pipe(mergeMap((response) => {
|
|
8
|
+
if (isSuccessResponse(response)) {
|
|
9
|
+
return of(sessionHeartbeatSuccess(response.data?.expiry ?? ''));
|
|
10
|
+
}
|
|
11
|
+
return of(sessionHeartbeatFailure(response.status));
|
|
12
|
+
}), catchError((error) => of(sessionHeartbeatFailure(createZeniAPIStatus('Heartbeat failed', 'Session heartbeat API call errored: ' + JSON.stringify(error))))))));
|
|
@@ -422,6 +422,26 @@ const tenant = createSlice({
|
|
|
422
422
|
signOutSuccess(draft) {
|
|
423
423
|
draft.loggedInUser = undefined;
|
|
424
424
|
draft.currentTenantId = undefined;
|
|
425
|
+
draft.sessionExpiresAt = undefined;
|
|
426
|
+
},
|
|
427
|
+
sendSessionHeartbeat() {
|
|
428
|
+
// No state change needed — epic handles the API call
|
|
429
|
+
},
|
|
430
|
+
sessionHeartbeatSuccess: {
|
|
431
|
+
prepare(expiresAt) {
|
|
432
|
+
return { payload: { expiresAt } };
|
|
433
|
+
},
|
|
434
|
+
reducer(draft, action) {
|
|
435
|
+
draft.sessionExpiresAt = action.payload.expiresAt;
|
|
436
|
+
},
|
|
437
|
+
},
|
|
438
|
+
sessionHeartbeatFailure: {
|
|
439
|
+
prepare(error) {
|
|
440
|
+
return { payload: { error } };
|
|
441
|
+
},
|
|
442
|
+
reducer(draft, action) {
|
|
443
|
+
draft.error = action.payload.error;
|
|
444
|
+
},
|
|
425
445
|
},
|
|
426
446
|
fetchSubscriptionSummaryForTenant: {
|
|
427
447
|
prepare(tenantId) {
|
|
@@ -529,7 +549,7 @@ const tenant = createSlice({
|
|
|
529
549
|
},
|
|
530
550
|
},
|
|
531
551
|
});
|
|
532
|
-
export const { updateTenants, fetchAllTenants, updateTenantsSuccess, updateTenantsFailure, fetchActiveTenant, updateTenantSuccess, updateTenantFailure, updateCurrentTenant, fetchExcludedResources, updateExcludedResourcesSuccess, updateExcludedResourcesFailure, doSignIn, doMagicLinkSignIn, magicLinkSignInSuccess, magicLinkSignInFailure, sendEmailMagicLinkToUser, sendEmailMagicLinkToUserSuccess, sendEmailMagicLinkToUserFailure, updateSignInState, doSignOut, signOutSuccess, updateLoggedInUser, fetchExternalConnections, saveExternalConnection, saveExternalConnectionSuccess, saveExternalConnectionFailure, fetchExternalConnectionsFailure, fetchExternalConnectionsSuccess, clearAll, fetchSubscriptionSummaryForTenant, updateSubscriptionSummaryForTenantSuccess, updateSubscriptionSummaryForTenantFailure, updateOnboardingTenants, removeOnboardingTenant, updateTenantReimbursementInfo, updateReferViewedForLoggedInUser, updateTreasuryVideoViewedForLoggedInUser, resetSignInState, trigger2FA, updateTenantMasterTOSInfo, verifyDeviceWithTwoFA, verifyDeviceWithTwoFASuccess, verifyDeviceWithTwoFAFailure, resendVerifyDeviceOTP, resendVerifyDeviceOTPSuccess, resendVerifyDeviceOTPFailure, } = tenant.actions;
|
|
552
|
+
export const { updateTenants, fetchAllTenants, updateTenantsSuccess, updateTenantsFailure, fetchActiveTenant, updateTenantSuccess, updateTenantFailure, updateCurrentTenant, fetchExcludedResources, updateExcludedResourcesSuccess, updateExcludedResourcesFailure, doSignIn, doMagicLinkSignIn, magicLinkSignInSuccess, magicLinkSignInFailure, sendEmailMagicLinkToUser, sendEmailMagicLinkToUserSuccess, sendEmailMagicLinkToUserFailure, updateSignInState, doSignOut, signOutSuccess, sendSessionHeartbeat, sessionHeartbeatSuccess, sessionHeartbeatFailure, updateLoggedInUser, fetchExternalConnections, saveExternalConnection, saveExternalConnectionSuccess, saveExternalConnectionFailure, fetchExternalConnectionsFailure, fetchExternalConnectionsSuccess, clearAll, fetchSubscriptionSummaryForTenant, updateSubscriptionSummaryForTenantSuccess, updateSubscriptionSummaryForTenantFailure, updateOnboardingTenants, removeOnboardingTenant, updateTenantReimbursementInfo, updateReferViewedForLoggedInUser, updateTreasuryVideoViewedForLoggedInUser, resetSignInState, trigger2FA, updateTenantMasterTOSInfo, verifyDeviceWithTwoFA, verifyDeviceWithTwoFASuccess, verifyDeviceWithTwoFAFailure, resendVerifyDeviceOTP, resendVerifyDeviceOTPSuccess, resendVerifyDeviceOTPFailure, } = tenant.actions;
|
|
533
553
|
export default tenant.reducer;
|
|
534
554
|
/**
|
|
535
555
|
* Converts tenants payload to Tenant and User State
|