formreader-session-timeout 0.2.4 → 0.2.6

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/index.d.ts CHANGED
@@ -48,7 +48,7 @@ interface SessionConfig {
48
48
  /** Custom function to format the refresh request payload */
49
49
  refreshPayloadFormatter?: (token: string, refreshToken: string) => Record<string, any>;
50
50
  /** Custom function to format the logout request payload */
51
- logoutPayloadFormatter?: (token: string) => Record<string, any>;
51
+ logoutPayloadFormatter?: (token: string, refreshToken?: string) => Record<string, any>;
52
52
  /** Which field in login response contains access token (default: 'access') */
53
53
  accessTokenField?: string;
54
54
  /** Which field in login response contains refresh token (default: 'refresh') */
@@ -59,6 +59,10 @@ interface SessionConfig {
59
59
  refreshRefreshTokenField?: string;
60
60
  /** Whether to store refresh token separately (default: true) */
61
61
  storeRefreshToken?: boolean;
62
+ /** Whether to validate token on page reload/initialization (default: true) */
63
+ validateOnInit?: boolean;
64
+ /** Custom token validation endpoint for server-side validation */
65
+ tokenValidationEndpoint?: string;
62
66
  }
63
67
  interface JWTPayload {
64
68
  exp: number;
@@ -130,9 +134,16 @@ declare class SessionManager {
130
134
  */
131
135
  logout(): Promise<void>;
132
136
  /**
133
- * Check if session is active
137
+ * Check if session is active and token is valid
134
138
  */
135
139
  isActive(): boolean;
140
+ /**
141
+ * Validate current session without initializing
142
+ */
143
+ validateSession(): {
144
+ isValid: boolean;
145
+ reason?: string;
146
+ };
136
147
  /**
137
148
  * Get current state
138
149
  */
@@ -207,6 +218,24 @@ declare function clearToken(): void;
207
218
  */
208
219
  declare function validateToken(token: string): boolean;
209
220
 
221
+ /**
222
+ * Authentication utilities for session validation
223
+ */
224
+ /**
225
+ * Check if user is authenticated with valid token
226
+ * This is the function to use in your App.tsx for page reload validation
227
+ */
228
+ declare function isAuthenticated(): boolean;
229
+ /**
230
+ * Initialize session with token validation on page reload
231
+ * Returns a promise that resolves to authentication status
232
+ */
233
+ declare function initializeAuth(config?: any): Promise<boolean>;
234
+ /**
235
+ * Trigger auth change event for cross-tab synchronization
236
+ */
237
+ declare function triggerAuthChange(): void;
238
+
210
239
  /**
211
240
  * useSessionTimeout Hook
212
241
  * React hook for managing session timeout
@@ -242,4 +271,4 @@ declare function useSessionTimeout(options?: UseSessionTimeoutOptions): {
242
271
  */
243
272
  declare function SessionStatus(): react_jsx_runtime.JSX.Element;
244
273
 
245
- export { DEFAULT_SESSION_CONFIG, JWTPayload, RefreshTokenResponse, SessionConfig, SessionManager, SessionState, SessionStatus, TokenInfo, UseSessionTimeoutOptions, clearToken, getSessionManager, getStoredRefreshToken, getStoredToken, getTimeUntilExpiry, getTokenInfo, isTokenExpired, resetSessionManager, storeRefreshToken, storeToken, useSessionTimeout, validateToken };
274
+ export { DEFAULT_SESSION_CONFIG, JWTPayload, RefreshTokenResponse, SessionConfig, SessionManager, SessionState, SessionStatus, TokenInfo, UseSessionTimeoutOptions, clearToken, getSessionManager, getStoredRefreshToken, getStoredToken, getTimeUntilExpiry, getTokenInfo, initializeAuth, isAuthenticated, isTokenExpired, resetSessionManager, storeRefreshToken, storeToken, triggerAuthChange, useSessionTimeout, validateToken };
package/dist/index.js CHANGED
@@ -28,10 +28,13 @@ __export(session_timeout_exports, {
28
28
  getStoredToken: () => getStoredToken,
29
29
  getTimeUntilExpiry: () => getTimeUntilExpiry,
30
30
  getTokenInfo: () => getTokenInfo,
31
+ initializeAuth: () => initializeAuth,
32
+ isAuthenticated: () => isAuthenticated,
31
33
  isTokenExpired: () => isTokenExpired,
32
34
  resetSessionManager: () => resetSessionManager,
33
35
  storeRefreshToken: () => storeRefreshToken,
34
36
  storeToken: () => storeToken,
37
+ triggerAuthChange: () => triggerAuthChange,
35
38
  useSessionTimeout: () => useSessionTimeout,
36
39
  validateToken: () => validateToken
37
40
  });
@@ -59,7 +62,8 @@ var DEFAULT_SESSION_CONFIG = {
59
62
  refreshTokenField: "refresh",
60
63
  refreshAccessTokenField: "access",
61
64
  refreshRefreshTokenField: "refresh",
62
- storeRefreshToken: true
65
+ storeRefreshToken: true,
66
+ validateOnInit: true
63
67
  };
64
68
 
65
69
  // services/tokenService.ts
@@ -191,6 +195,7 @@ var SessionManager = class {
191
195
  const token = loginResponse ? extractTokenFromResponse(loginResponse, this.config.accessTokenField || "access") : getStoredToken();
192
196
  if (!token) {
193
197
  this.log("No token found, session not initialized");
198
+ this.emit("noToken");
194
199
  return;
195
200
  }
196
201
  storeToken(token);
@@ -206,10 +211,27 @@ var SessionManager = class {
206
211
  }
207
212
  const validation = validateToken(token);
208
213
  if (!validation) {
209
- this.log("Invalid token");
214
+ this.log("Invalid token format");
215
+ this.emit("invalidToken");
210
216
  this.logout();
211
217
  return;
212
218
  }
219
+ if (isTokenExpired(token)) {
220
+ this.log("Token is expired, attempting refresh");
221
+ this.emit("tokenExpired");
222
+ const refreshToken = getStoredRefreshToken();
223
+ if (refreshToken && this.config.autoRefresh) {
224
+ this.refreshToken().then((success) => {
225
+ if (!success) {
226
+ this.logout();
227
+ }
228
+ });
229
+ return;
230
+ } else {
231
+ this.logout();
232
+ return;
233
+ }
234
+ }
213
235
  this.state.isActive = true;
214
236
  this.setupTokenRefresh();
215
237
  this.setupIdleTracking();
@@ -303,7 +325,7 @@ var SessionManager = class {
303
325
  try {
304
326
  this.log(`Refreshing token (attempt ${this.state.refreshAttempts})`);
305
327
  const client = this.config.httpClient || defaultFetchClient();
306
- const refreshPayload = this.config.refreshPayloadFormatter ? this.config.refreshPayloadFormatter(accessToken || "", refreshToken || "") : {
328
+ const refreshPayload = this.config.refreshPayloadFormatter ? this.config.refreshPayloadFormatter(accessToken || "", refreshToken) : {
307
329
  refresh: refreshToken || accessToken,
308
330
  token: accessToken
309
331
  };
@@ -367,7 +389,7 @@ var SessionManager = class {
367
389
  const token = getStoredToken();
368
390
  if (token && this.config.logoutEndpoint) {
369
391
  const client = this.config.httpClient || defaultFetchClient();
370
- const logoutPayload = this.config.logoutPayloadFormatter ? this.config.logoutPayloadFormatter(token) : { token };
392
+ const logoutPayload = this.config.logoutPayloadFormatter ? this.config.logoutPayloadFormatter(token, getStoredRefreshToken()) : { token };
371
393
  await client.post(this.config.logoutEndpoint, logoutPayload, {
372
394
  headers: { Authorization: `Bearer ${token}` }
373
395
  });
@@ -377,15 +399,36 @@ var SessionManager = class {
377
399
  }
378
400
  clearToken();
379
401
  this.state.isActive = false;
380
- this.emit("logout");
402
+ this.emit("loggedOut");
381
403
  (_b = (_a = this.config).onLogout) == null ? void 0 : _b.call(_a);
382
404
  this.cleanup();
383
405
  }
384
406
  /**
385
- * Check if session is active
407
+ * Check if session is active and token is valid
386
408
  */
387
409
  isActive() {
388
- return this.state.isActive;
410
+ if (!this.state.isActive)
411
+ return false;
412
+ const token = getStoredToken();
413
+ if (!token)
414
+ return false;
415
+ return !isTokenExpired(token);
416
+ }
417
+ /**
418
+ * Validate current session without initializing
419
+ */
420
+ validateSession() {
421
+ const token = getStoredToken();
422
+ if (!token) {
423
+ return { isValid: false, reason: "no_token" };
424
+ }
425
+ if (!validateToken(token)) {
426
+ return { isValid: false, reason: "invalid_token" };
427
+ }
428
+ if (isTokenExpired(token)) {
429
+ return { isValid: false, reason: "token_expired" };
430
+ }
431
+ return { isValid: true };
389
432
  }
390
433
  /**
391
434
  * Get current state
@@ -484,6 +527,57 @@ function resetSessionManager() {
484
527
  }
485
528
  }
486
529
 
530
+ // utils/authUtils.ts
531
+ function isAuthenticated() {
532
+ const token = getStoredToken();
533
+ if (!token) {
534
+ return false;
535
+ }
536
+ if (!validateToken(token)) {
537
+ return false;
538
+ }
539
+ if (isTokenExpired(token)) {
540
+ return false;
541
+ }
542
+ return true;
543
+ }
544
+ async function initializeAuth(config) {
545
+ const manager = getSessionManager(config);
546
+ return new Promise((resolve) => {
547
+ const cleanup = [];
548
+ cleanup.push(manager.on("initialized", () => {
549
+ cleanup.forEach((fn) => fn());
550
+ resolve(true);
551
+ }));
552
+ cleanup.push(manager.on("noToken", () => {
553
+ cleanup.forEach((fn) => fn());
554
+ resolve(false);
555
+ }));
556
+ cleanup.push(manager.on("invalidToken", () => {
557
+ cleanup.forEach((fn) => fn());
558
+ resolve(false);
559
+ }));
560
+ cleanup.push(manager.on("tokenExpired", () => {
561
+ setTimeout(() => {
562
+ cleanup.forEach((fn) => fn());
563
+ resolve(manager.isActive());
564
+ }, 1e3);
565
+ }));
566
+ cleanup.push(manager.on("loggedOut", () => {
567
+ cleanup.forEach((fn) => fn());
568
+ resolve(false);
569
+ }));
570
+ manager.init();
571
+ setTimeout(() => {
572
+ cleanup.forEach((fn) => fn());
573
+ resolve(manager.isActive());
574
+ }, 3e3);
575
+ });
576
+ }
577
+ function triggerAuthChange() {
578
+ window.dispatchEvent(new CustomEvent("authChange"));
579
+ }
580
+
487
581
  // hooks/useSessionTimeout.ts
488
582
  var import_react = require("react");
489
583
  function useSessionTimeout(options = {}) {
@@ -633,10 +727,13 @@ function SessionStatus() {
633
727
  getStoredToken,
634
728
  getTimeUntilExpiry,
635
729
  getTokenInfo,
730
+ initializeAuth,
731
+ isAuthenticated,
636
732
  isTokenExpired,
637
733
  resetSessionManager,
638
734
  storeRefreshToken,
639
735
  storeToken,
736
+ triggerAuthChange,
640
737
  useSessionTimeout,
641
738
  validateToken
642
739
  });
package/dist/index.mjs CHANGED
@@ -20,7 +20,8 @@ var DEFAULT_SESSION_CONFIG = {
20
20
  refreshTokenField: "refresh",
21
21
  refreshAccessTokenField: "access",
22
22
  refreshRefreshTokenField: "refresh",
23
- storeRefreshToken: true
23
+ storeRefreshToken: true,
24
+ validateOnInit: true
24
25
  };
25
26
 
26
27
  // services/tokenService.ts
@@ -152,6 +153,7 @@ var SessionManager = class {
152
153
  const token = loginResponse ? extractTokenFromResponse(loginResponse, this.config.accessTokenField || "access") : getStoredToken();
153
154
  if (!token) {
154
155
  this.log("No token found, session not initialized");
156
+ this.emit("noToken");
155
157
  return;
156
158
  }
157
159
  storeToken(token);
@@ -167,10 +169,27 @@ var SessionManager = class {
167
169
  }
168
170
  const validation = validateToken(token);
169
171
  if (!validation) {
170
- this.log("Invalid token");
172
+ this.log("Invalid token format");
173
+ this.emit("invalidToken");
171
174
  this.logout();
172
175
  return;
173
176
  }
177
+ if (isTokenExpired(token)) {
178
+ this.log("Token is expired, attempting refresh");
179
+ this.emit("tokenExpired");
180
+ const refreshToken = getStoredRefreshToken();
181
+ if (refreshToken && this.config.autoRefresh) {
182
+ this.refreshToken().then((success) => {
183
+ if (!success) {
184
+ this.logout();
185
+ }
186
+ });
187
+ return;
188
+ } else {
189
+ this.logout();
190
+ return;
191
+ }
192
+ }
174
193
  this.state.isActive = true;
175
194
  this.setupTokenRefresh();
176
195
  this.setupIdleTracking();
@@ -264,7 +283,7 @@ var SessionManager = class {
264
283
  try {
265
284
  this.log(`Refreshing token (attempt ${this.state.refreshAttempts})`);
266
285
  const client = this.config.httpClient || defaultFetchClient();
267
- const refreshPayload = this.config.refreshPayloadFormatter ? this.config.refreshPayloadFormatter(accessToken || "", refreshToken || "") : {
286
+ const refreshPayload = this.config.refreshPayloadFormatter ? this.config.refreshPayloadFormatter(accessToken || "", refreshToken) : {
268
287
  refresh: refreshToken || accessToken,
269
288
  token: accessToken
270
289
  };
@@ -328,7 +347,7 @@ var SessionManager = class {
328
347
  const token = getStoredToken();
329
348
  if (token && this.config.logoutEndpoint) {
330
349
  const client = this.config.httpClient || defaultFetchClient();
331
- const logoutPayload = this.config.logoutPayloadFormatter ? this.config.logoutPayloadFormatter(token) : { token };
350
+ const logoutPayload = this.config.logoutPayloadFormatter ? this.config.logoutPayloadFormatter(token, getStoredRefreshToken()) : { token };
332
351
  await client.post(this.config.logoutEndpoint, logoutPayload, {
333
352
  headers: { Authorization: `Bearer ${token}` }
334
353
  });
@@ -338,15 +357,36 @@ var SessionManager = class {
338
357
  }
339
358
  clearToken();
340
359
  this.state.isActive = false;
341
- this.emit("logout");
360
+ this.emit("loggedOut");
342
361
  (_b = (_a = this.config).onLogout) == null ? void 0 : _b.call(_a);
343
362
  this.cleanup();
344
363
  }
345
364
  /**
346
- * Check if session is active
365
+ * Check if session is active and token is valid
347
366
  */
348
367
  isActive() {
349
- return this.state.isActive;
368
+ if (!this.state.isActive)
369
+ return false;
370
+ const token = getStoredToken();
371
+ if (!token)
372
+ return false;
373
+ return !isTokenExpired(token);
374
+ }
375
+ /**
376
+ * Validate current session without initializing
377
+ */
378
+ validateSession() {
379
+ const token = getStoredToken();
380
+ if (!token) {
381
+ return { isValid: false, reason: "no_token" };
382
+ }
383
+ if (!validateToken(token)) {
384
+ return { isValid: false, reason: "invalid_token" };
385
+ }
386
+ if (isTokenExpired(token)) {
387
+ return { isValid: false, reason: "token_expired" };
388
+ }
389
+ return { isValid: true };
350
390
  }
351
391
  /**
352
392
  * Get current state
@@ -445,6 +485,57 @@ function resetSessionManager() {
445
485
  }
446
486
  }
447
487
 
488
+ // utils/authUtils.ts
489
+ function isAuthenticated() {
490
+ const token = getStoredToken();
491
+ if (!token) {
492
+ return false;
493
+ }
494
+ if (!validateToken(token)) {
495
+ return false;
496
+ }
497
+ if (isTokenExpired(token)) {
498
+ return false;
499
+ }
500
+ return true;
501
+ }
502
+ async function initializeAuth(config) {
503
+ const manager = getSessionManager(config);
504
+ return new Promise((resolve) => {
505
+ const cleanup = [];
506
+ cleanup.push(manager.on("initialized", () => {
507
+ cleanup.forEach((fn) => fn());
508
+ resolve(true);
509
+ }));
510
+ cleanup.push(manager.on("noToken", () => {
511
+ cleanup.forEach((fn) => fn());
512
+ resolve(false);
513
+ }));
514
+ cleanup.push(manager.on("invalidToken", () => {
515
+ cleanup.forEach((fn) => fn());
516
+ resolve(false);
517
+ }));
518
+ cleanup.push(manager.on("tokenExpired", () => {
519
+ setTimeout(() => {
520
+ cleanup.forEach((fn) => fn());
521
+ resolve(manager.isActive());
522
+ }, 1e3);
523
+ }));
524
+ cleanup.push(manager.on("loggedOut", () => {
525
+ cleanup.forEach((fn) => fn());
526
+ resolve(false);
527
+ }));
528
+ manager.init();
529
+ setTimeout(() => {
530
+ cleanup.forEach((fn) => fn());
531
+ resolve(manager.isActive());
532
+ }, 3e3);
533
+ });
534
+ }
535
+ function triggerAuthChange() {
536
+ window.dispatchEvent(new CustomEvent("authChange"));
537
+ }
538
+
448
539
  // hooks/useSessionTimeout.ts
449
540
  import { useEffect, useState, useCallback, useRef } from "react";
450
541
  function useSessionTimeout(options = {}) {
@@ -593,10 +684,13 @@ export {
593
684
  getStoredToken,
594
685
  getTimeUntilExpiry,
595
686
  getTokenInfo,
687
+ initializeAuth,
688
+ isAuthenticated,
596
689
  isTokenExpired,
597
690
  resetSessionManager,
598
691
  storeRefreshToken,
599
692
  storeToken,
693
+ triggerAuthChange,
600
694
  useSessionTimeout,
601
695
  validateToken
602
696
  };
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "formreader-session-timeout",
3
- "version": "0.2.4",
3
+ "version": "0.2.6",
4
4
  "description": "Session timeout microfrontend: configurable JWT expiry decoding and refresh with idle tracking",
5
5
  "main": "dist/index.js",
6
6
  "module": "dist/index.mjs",