win-portal-auth-sdk 1.3.0 → 1.4.0

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.
Files changed (45) hide show
  1. package/README.md +80 -7
  2. package/dist/client/auth-client.d.ts +97 -2
  3. package/dist/client/auth-client.d.ts.map +1 -1
  4. package/dist/client/auth-client.js +276 -30
  5. package/dist/client/index.d.ts +1 -1
  6. package/dist/client/index.d.ts.map +1 -1
  7. package/dist/index.d.ts +7 -1
  8. package/dist/index.d.ts.map +1 -1
  9. package/dist/index.js +14 -2
  10. package/dist/nestjs/decorators/current-token.decorator.d.ts +29 -0
  11. package/dist/nestjs/decorators/current-token.decorator.d.ts.map +1 -0
  12. package/dist/nestjs/decorators/current-token.decorator.js +36 -0
  13. package/dist/nestjs/decorators/current-user.decorator.d.ts +26 -0
  14. package/dist/nestjs/decorators/current-user.decorator.d.ts.map +1 -0
  15. package/dist/nestjs/decorators/current-user.decorator.js +33 -0
  16. package/dist/nestjs/decorators/index.d.ts +9 -0
  17. package/dist/nestjs/decorators/index.d.ts.map +1 -0
  18. package/dist/nestjs/decorators/index.js +15 -0
  19. package/dist/nestjs/decorators/public.decorator.d.ts +31 -0
  20. package/dist/nestjs/decorators/public.decorator.d.ts.map +1 -0
  21. package/dist/nestjs/decorators/public.decorator.js +36 -0
  22. package/dist/nestjs/guards/index.d.ts +7 -0
  23. package/dist/nestjs/guards/index.d.ts.map +1 -0
  24. package/dist/nestjs/guards/index.js +11 -0
  25. package/dist/nestjs/guards/oauth-auth.guard.d.ts +139 -0
  26. package/dist/nestjs/guards/oauth-auth.guard.d.ts.map +1 -0
  27. package/dist/nestjs/guards/oauth-auth.guard.js +257 -0
  28. package/dist/nestjs/index.d.ts +28 -0
  29. package/dist/nestjs/index.d.ts.map +1 -0
  30. package/dist/nestjs/index.js +47 -0
  31. package/dist/nestjs/middleware/index.d.ts +7 -0
  32. package/dist/nestjs/middleware/index.d.ts.map +1 -0
  33. package/dist/nestjs/middleware/index.js +11 -0
  34. package/dist/nestjs/middleware/request-context.middleware.d.ts +62 -0
  35. package/dist/nestjs/middleware/request-context.middleware.d.ts.map +1 -0
  36. package/dist/nestjs/middleware/request-context.middleware.js +122 -0
  37. package/dist/nestjs/types/request-context.types.d.ts +69 -0
  38. package/dist/nestjs/types/request-context.types.d.ts.map +1 -0
  39. package/dist/nestjs/types/request-context.types.js +33 -0
  40. package/dist/types/index.d.ts +18 -0
  41. package/dist/types/index.d.ts.map +1 -1
  42. package/dist/utils/logger.d.ts +23 -0
  43. package/dist/utils/logger.d.ts.map +1 -0
  44. package/dist/utils/logger.js +49 -0
  45. package/package.json +41 -3
@@ -14,6 +14,17 @@ exports.AuthClient = void 0;
14
14
  const axios_1 = __importDefault(require("axios"));
15
15
  const api_1 = require("./api");
16
16
  const token_utils_1 = require("../utils/token-utils");
17
+ const logger_1 = require("../utils/logger");
18
+ // Constants - Default values
19
+ const DEFAULT_INACTIVITY_TIMEOUT_SECONDS = 30 * 60; // 30 minutes
20
+ const DEFAULT_WARNING_SECONDS = 5 * 60; // 5 minutes
21
+ const DEFAULT_SESSION_CHECK_INTERVAL_SECONDS = 30; // 30 seconds
22
+ // Internal constants - Rate limiting (ไม่ควรให้ customize)
23
+ const REFRESH_COOLDOWN_MS = 30 * 1000; // 30 seconds - rate limiting for refresh
24
+ const WARNING_COOLDOWN_MS = 60 * 1000; // 1 minute - rate limiting for warnings
25
+ // Internal constants - Performance tuning (สามารถ customize ได้ผ่าน advanced config)
26
+ const DEFAULT_ACTIVITY_THROTTLE_MS = 1000; // 1 second - throttle activity handler
27
+ const DEFAULT_REFRESH_TIMEOUT_MS = 5000; // 5 seconds - refresh timeout
17
28
  class AuthClient {
18
29
  constructor(config) {
19
30
  this.token = null;
@@ -25,21 +36,38 @@ class AuthClient {
25
36
  this.automaticRefreshEnabled = null;
26
37
  this.lastRefreshAttempt = 0;
27
38
  this.refreshPromise = null;
28
- this.REFRESH_COOLDOWN_MS = 30 * 1000; // 30 seconds cooldown
29
39
  // Session expiration monitoring
30
40
  this.sessionExpirationCallbacks = null;
31
41
  this.sessionManagementConfig = null;
32
42
  this.sessionManagementConfigPromise = null;
33
43
  this.sessionExpirationCheckInterval = null;
34
- this.sessionExpirationCheckIntervalSeconds = 30;
44
+ this.sessionExpirationCheckIntervalSeconds = DEFAULT_SESSION_CHECK_INTERVAL_SECONDS;
35
45
  this.lastWarningTime = 0;
36
- this.WARNING_COOLDOWN_MS = 60 * 1000; // 1 minute cooldown between warnings
46
+ // Inactivity detection
47
+ this.inactivityCallbacks = null;
48
+ this.inactivityTimeout = null;
49
+ this.inactivityWarningTimeout = null;
50
+ this.lastActivityTime = 0;
51
+ this.inactivityDetectionEnabled = false;
52
+ this.inactivityTimeoutSeconds = 0;
53
+ this.inactivityWarningSeconds = 0;
54
+ this.activityEvents = [];
55
+ this.activityHandler = null;
56
+ this.activityThrottleTimeout = null;
57
+ this.activityThrottleMs = DEFAULT_ACTIVITY_THROTTLE_MS;
58
+ this.refreshTimeoutMs = DEFAULT_REFRESH_TIMEOUT_MS;
37
59
  this.apiKey = config.apiKey;
38
60
  this.apiKeyHeader = config.apiKeyHeader || 'X-API-Key';
39
- console.log('[AuthClient] Initializing with config:', {
61
+ // Apply advanced config if provided
62
+ if (config.advanced) {
63
+ this.activityThrottleMs = config.advanced.activityThrottleMs ?? DEFAULT_ACTIVITY_THROTTLE_MS;
64
+ this.refreshTimeoutMs = config.advanced.refreshTimeoutMs ?? DEFAULT_REFRESH_TIMEOUT_MS;
65
+ }
66
+ logger_1.logger.debug('Initializing with config:', {
40
67
  baseURL: config.baseURL,
41
68
  timeout: config.timeout,
42
69
  apiKeyHeader: this.apiKeyHeader,
70
+ advanced: config.advanced,
43
71
  });
44
72
  this.client = axios_1.default.create({
45
73
  baseURL: config.baseURL,
@@ -67,29 +95,28 @@ class AuthClient {
67
95
  const isCritical = remainingMinutes !== null && remainingMinutes <= 1;
68
96
  const now = Date.now();
69
97
  const timeSinceLastRefresh = now - this.lastRefreshAttempt;
70
- if (timeSinceLastRefresh >= this.REFRESH_COOLDOWN_MS &&
71
- !this.refreshPromise) {
72
- console.log(`[AuthClient] Token near expiration (${remainingMinutes} min remaining), refreshing...`);
98
+ if (timeSinceLastRefresh >= REFRESH_COOLDOWN_MS && !this.refreshPromise) {
99
+ logger_1.logger.debug(`Token near expiration (${remainingMinutes} min remaining), refreshing...`);
73
100
  this.lastRefreshAttempt = now;
74
101
  if (isCritical) {
75
102
  // Critical: await refresh
76
103
  try {
77
104
  const newToken = await Promise.race([
78
105
  this.performRefresh(),
79
- new Promise((_, reject) => setTimeout(() => reject(new Error('Refresh timeout')), 5000)),
106
+ new Promise((_, reject) => setTimeout(() => reject(new Error('Refresh timeout')), this.refreshTimeoutMs)),
80
107
  ]);
81
108
  this.token = newToken;
82
109
  requestConfig.headers['Authorization'] = `Bearer ${newToken}`;
83
- console.log('[AuthClient] Token refreshed successfully (critical)');
110
+ logger_1.logger.info('Token refreshed successfully (critical)');
84
111
  }
85
112
  catch (error) {
86
- console.error('[AuthClient] Critical token refresh failed:', error);
113
+ logger_1.logger.error('Critical token refresh failed:', error);
87
114
  }
88
115
  }
89
116
  else {
90
117
  // Background refresh
91
118
  this.performRefresh().catch((error) => {
92
- console.error('[AuthClient] Background token refresh failed:', error);
119
+ logger_1.logger.error('Background token refresh failed:', error);
93
120
  });
94
121
  }
95
122
  }
@@ -107,7 +134,7 @@ class AuthClient {
107
134
  // Handle 401 errors - try refresh token before failing
108
135
  if (error.response?.status === 401 && originalRequest && this.refreshTokenCallbacks) {
109
136
  if (originalRequest._retry) {
110
- console.warn('[AuthClient] 401 Unauthorized after retry - refresh failed');
137
+ logger_1.logger.warn('401 Unauthorized after retry - refresh failed');
111
138
  if (this.refreshTokenCallbacks.onRefreshFailure) {
112
139
  await this.refreshTokenCallbacks.onRefreshFailure();
113
140
  }
@@ -115,7 +142,7 @@ class AuthClient {
115
142
  }
116
143
  // Skip refresh for refresh endpoint itself
117
144
  if (originalRequest.url?.includes('/auth/refresh') || originalRequest.url?.includes('/auth/refresh-token')) {
118
- console.error('[AuthClient] Refresh endpoint failed - session expired');
145
+ logger_1.logger.error('Refresh endpoint failed - session expired');
119
146
  if (this.refreshTokenCallbacks.onRefreshFailure) {
120
147
  await this.refreshTokenCallbacks.onRefreshFailure();
121
148
  }
@@ -124,15 +151,15 @@ class AuthClient {
124
151
  // Try to refresh token
125
152
  try {
126
153
  originalRequest._retry = true;
127
- console.log('[AuthClient] 401 detected, attempting token refresh...');
154
+ logger_1.logger.debug('401 detected, attempting token refresh...');
128
155
  const newToken = await this.performRefresh();
129
156
  originalRequest.headers = originalRequest.headers || {};
130
157
  originalRequest.headers.Authorization = `Bearer ${newToken}`;
131
- console.log('[AuthClient] Token refreshed, retrying original request...');
158
+ logger_1.logger.debug('Token refreshed, retrying original request...');
132
159
  return this.client(originalRequest);
133
160
  }
134
161
  catch (refreshError) {
135
- console.error('[AuthClient] Token refresh failed:', refreshError);
162
+ logger_1.logger.error('Token refresh failed:', refreshError);
136
163
  if (this.refreshTokenCallbacks.onRefreshFailure) {
137
164
  await this.refreshTokenCallbacks.onRefreshFailure();
138
165
  }
@@ -141,10 +168,10 @@ class AuthClient {
141
168
  }
142
169
  // Handle other errors
143
170
  if (error.response?.status === 401) {
144
- console.error('[AuthClient] API Key authentication failed');
171
+ logger_1.logger.error('API Key authentication failed');
145
172
  }
146
173
  else if (error.response?.status === 429) {
147
- console.error('[AuthClient] Rate limit exceeded');
174
+ logger_1.logger.error('Rate limit exceeded');
148
175
  }
149
176
  return Promise.reject(error);
150
177
  });
@@ -170,7 +197,7 @@ class AuthClient {
170
197
  * ```
171
198
  */
172
199
  initializeOAuth(config) {
173
- console.log('[AuthClient] Initializing OAuth with:', {
200
+ logger_1.logger.debug('Initializing OAuth with:', {
174
201
  clientId: config.clientId,
175
202
  redirectUri: config.redirectUri,
176
203
  scope: config.scope,
@@ -244,7 +271,7 @@ class AuthClient {
244
271
  setToken(token, type = 'jwt') {
245
272
  this.token = token;
246
273
  this.authType = type;
247
- console.log(`[AuthClient] Token set with type: ${type}`);
274
+ logger_1.logger.debug(`Token set with type: ${type}`);
248
275
  // Reset warning time when token changes
249
276
  this.lastWarningTime = 0;
250
277
  // If session expiration monitoring is enabled, check immediately
@@ -265,7 +292,7 @@ class AuthClient {
265
292
  */
266
293
  setAuthType(type) {
267
294
  this.authType = type;
268
- console.log(`[AuthClient] Auth type changed to: ${type}`);
295
+ logger_1.logger.debug(`Auth type changed to: ${type}`);
269
296
  }
270
297
  /**
271
298
  * Get current token (masked)
@@ -379,10 +406,10 @@ class AuthClient {
379
406
  const config = await this.systemConfig.getSecurityJwtConfig();
380
407
  this.refreshThresholdMinutes = config.refresh_threshold_minutes;
381
408
  this.automaticRefreshEnabled = config.automatic_refresh ?? true;
382
- console.log(`[AuthClient] JWT config loaded: refresh_threshold_minutes=${this.refreshThresholdMinutes} minutes, automatic_refresh=${this.automaticRefreshEnabled}`);
409
+ logger_1.logger.debug(`JWT config loaded: refresh_threshold_minutes=${this.refreshThresholdMinutes} minutes, automatic_refresh=${this.automaticRefreshEnabled}`);
383
410
  }
384
411
  catch (error) {
385
- console.error('[AuthClient] Failed to load JWT config:', error);
412
+ logger_1.logger.error('Failed to load JWT config:', error);
386
413
  // Reset to allow retry
387
414
  this.jwtConfigPromise = null;
388
415
  throw error;
@@ -429,7 +456,7 @@ class AuthClient {
429
456
  if (session.refresh_token) {
430
457
  await this.refreshTokenCallbacks.setRefreshToken(session.refresh_token);
431
458
  }
432
- console.log('[AuthClient] Token refreshed successfully');
459
+ logger_1.logger.debug('Token refreshed successfully');
433
460
  return newAccessToken;
434
461
  }
435
462
  catch (error) {
@@ -442,11 +469,11 @@ class AuthClient {
442
469
  if (tokens.refresh_token) {
443
470
  await this.refreshTokenCallbacks.setRefreshToken(tokens.refresh_token);
444
471
  }
445
- console.log('[AuthClient] Token refreshed successfully (fallback)');
472
+ logger_1.logger.debug('Token refreshed successfully (fallback)');
446
473
  return newAccessToken;
447
474
  }
448
475
  catch (fallbackError) {
449
- console.error('[AuthClient] Fallback refresh also failed:', fallbackError);
476
+ logger_1.logger.error('Fallback refresh also failed:', fallbackError);
450
477
  throw fallbackError;
451
478
  }
452
479
  }
@@ -487,7 +514,7 @@ class AuthClient {
487
514
  */
488
515
  async enableSessionExpirationMonitoring(options) {
489
516
  this.sessionExpirationCallbacks = options.callbacks;
490
- this.sessionExpirationCheckIntervalSeconds = options.checkIntervalSeconds ?? 30;
517
+ this.sessionExpirationCheckIntervalSeconds = options.checkIntervalSeconds ?? DEFAULT_SESSION_CHECK_INTERVAL_SECONDS;
491
518
  // Load session management config
492
519
  await this.loadSessionManagementConfig();
493
520
  // Start monitoring
@@ -519,7 +546,7 @@ class AuthClient {
519
546
  try {
520
547
  const config = await this.systemConfig.getSessionManagement();
521
548
  this.sessionManagementConfig = config;
522
- console.log('[AuthClient] Session management config loaded:', {
549
+ logger_1.logger.debug('Session management config loaded:', {
523
550
  inactivityEnabled: config.inactivity.enabled,
524
551
  inactivityTimeout: `${config.inactivity.timeout_duration} ${config.inactivity.timeout_unit}`,
525
552
  inactivityWarningMinutes: config.inactivity.warning_minutes,
@@ -528,7 +555,7 @@ class AuthClient {
528
555
  });
529
556
  }
530
557
  catch (error) {
531
- console.error('[AuthClient] Failed to load session management config:', error);
558
+ logger_1.logger.error('Failed to load session management config:', error);
532
559
  // Reset to allow retry
533
560
  this.sessionManagementConfigPromise = null;
534
561
  throw error;
@@ -628,7 +655,7 @@ class AuthClient {
628
655
  // Check cooldown to avoid spam
629
656
  const now = Date.now();
630
657
  const timeSinceLastWarning = now - this.lastWarningTime;
631
- if (timeSinceLastWarning >= this.WARNING_COOLDOWN_MS) {
658
+ if (timeSinceLastWarning >= WARNING_COOLDOWN_MS) {
632
659
  this.lastWarningTime = now;
633
660
  this.sessionExpirationCallbacks.onSessionExpiring(remainingMinutes, expirationType);
634
661
  }
@@ -641,5 +668,224 @@ class AuthClient {
641
668
  this.sessionManagementConfig = null;
642
669
  await this.loadSessionManagementConfig();
643
670
  }
671
+ /**
672
+ * Enable inactivity detection
673
+ * จับ user activity (mouse/keyboard/touch/scroll) และ trigger callback เมื่อ inactivity timeout
674
+ *
675
+ * @param options - Options for inactivity detection
676
+ *
677
+ * @example
678
+ * ```typescript
679
+ * await authClient.enableInactivityDetection({
680
+ * callbacks: {
681
+ * onInactivityWarning: (remainingSeconds) => {
682
+ * console.log(`Inactivity warning: ${remainingSeconds} seconds remaining`);
683
+ * // แสดง notification หรือ dialog
684
+ * },
685
+ * onInactivityTimeout: () => {
686
+ * console.log('Inactivity timeout');
687
+ * // Redirect to login หรือ logout
688
+ * authClient.clearToken();
689
+ * window.location.href = '/login';
690
+ * }
691
+ * },
692
+ * timeoutSeconds: 1800, // 30 minutes (optional, default: จาก session management config)
693
+ * warningSeconds: 300, // 5 minutes warning (optional, default: จาก session management config)
694
+ * events: ['mousemove', 'keydown', 'touchstart', 'scroll'] // (optional, default: ทั้งหมด)
695
+ * });
696
+ * ```
697
+ */
698
+ async enableInactivityDetection(options) {
699
+ // Disable existing detection if any
700
+ this.disableInactivityDetection();
701
+ this.inactivityCallbacks = options.callbacks;
702
+ // Load session management config if not loaded
703
+ if (!this.sessionManagementConfig) {
704
+ await this.loadSessionManagementConfig();
705
+ }
706
+ // Determine timeout and warning seconds
707
+ if (options.timeoutSeconds !== undefined) {
708
+ this.inactivityTimeoutSeconds = options.timeoutSeconds;
709
+ }
710
+ else if (this.sessionManagementConfig?.inactivity.enabled) {
711
+ // Use session management config
712
+ this.inactivityTimeoutSeconds =
713
+ (0, token_utils_1.convertDurationToMinutes)(this.sessionManagementConfig.inactivity.timeout_duration, this.sessionManagementConfig.inactivity.timeout_unit) * 60; // Convert to seconds
714
+ }
715
+ else {
716
+ // Default: 30 minutes
717
+ this.inactivityTimeoutSeconds = DEFAULT_INACTIVITY_TIMEOUT_SECONDS;
718
+ }
719
+ if (options.warningSeconds !== undefined) {
720
+ this.inactivityWarningSeconds = options.warningSeconds;
721
+ }
722
+ else if (this.sessionManagementConfig?.inactivity.warning_minutes) {
723
+ // Use session management config (convert minutes to seconds)
724
+ this.inactivityWarningSeconds = this.sessionManagementConfig.inactivity.warning_minutes * 60;
725
+ }
726
+ else {
727
+ // Default: 5 minutes
728
+ this.inactivityWarningSeconds = DEFAULT_WARNING_SECONDS;
729
+ }
730
+ // Determine events to listen
731
+ this.activityEvents = options.events || ['mousemove', 'keydown', 'touchstart', 'scroll'];
732
+ // Initialize last activity time
733
+ this.lastActivityTime = Date.now();
734
+ // Enable detection
735
+ this.inactivityDetectionEnabled = true;
736
+ // Setup event listeners
737
+ this.setupActivityListeners();
738
+ // Start timer
739
+ this.resetInactivityTimer();
740
+ logger_1.logger.debug('Inactivity detection enabled:', {
741
+ timeoutSeconds: this.inactivityTimeoutSeconds,
742
+ warningSeconds: this.inactivityWarningSeconds,
743
+ events: this.activityEvents,
744
+ });
745
+ }
746
+ /**
747
+ * Disable inactivity detection
748
+ */
749
+ disableInactivityDetection() {
750
+ this.inactivityDetectionEnabled = false;
751
+ // Clear throttle timeout
752
+ if (this.activityThrottleTimeout) {
753
+ clearTimeout(this.activityThrottleTimeout);
754
+ this.activityThrottleTimeout = null;
755
+ }
756
+ // Clear timeouts
757
+ this.clearInactivityTimeouts();
758
+ // Remove event listeners
759
+ this.removeActivityListeners();
760
+ // Reset state
761
+ this.inactivityCallbacks = null;
762
+ this.lastActivityTime = 0;
763
+ this.inactivityTimeoutSeconds = 0;
764
+ this.inactivityWarningSeconds = 0;
765
+ this.activityEvents = [];
766
+ logger_1.logger.debug('Inactivity detection disabled');
767
+ }
768
+ /**
769
+ * Handle user activity - reset inactivity timer with throttle
770
+ */
771
+ handleUserActivity() {
772
+ if (!this.inactivityDetectionEnabled) {
773
+ return;
774
+ }
775
+ // Throttle: reset timer สูงสุดทุก 1 วินาที เพื่อลด CPU usage
776
+ if (this.activityThrottleTimeout) {
777
+ return;
778
+ }
779
+ this.lastActivityTime = Date.now();
780
+ this.resetInactivityTimer();
781
+ this.activityThrottleTimeout = setTimeout(() => {
782
+ this.activityThrottleTimeout = null;
783
+ }, this.activityThrottleMs);
784
+ }
785
+ /**
786
+ * Setup activity event listeners
787
+ */
788
+ setupActivityListeners() {
789
+ if (typeof window === 'undefined') {
790
+ logger_1.logger.warn('Cannot setup activity listeners: window is undefined (SSR)');
791
+ return;
792
+ }
793
+ // Remove existing listeners if any
794
+ this.removeActivityListeners();
795
+ // Create handler
796
+ const handler = () => {
797
+ this.handleUserActivity();
798
+ };
799
+ this.activityHandler = handler;
800
+ // Setup listeners for each event type
801
+ this.activityEvents.forEach((eventType) => {
802
+ window.addEventListener(eventType, handler, { passive: true });
803
+ });
804
+ logger_1.logger.debug('Activity listeners setup:', this.activityEvents);
805
+ }
806
+ /**
807
+ * Remove activity event listeners
808
+ */
809
+ removeActivityListeners() {
810
+ if (typeof window === 'undefined' || !this.activityHandler) {
811
+ return;
812
+ }
813
+ const handler = this.activityHandler;
814
+ this.activityEvents.forEach((eventType) => {
815
+ window.removeEventListener(eventType, handler);
816
+ });
817
+ this.activityHandler = null;
818
+ logger_1.logger.debug('Activity listeners removed');
819
+ }
820
+ /**
821
+ * Clear inactivity timeouts (helper method)
822
+ */
823
+ clearInactivityTimeouts() {
824
+ if (this.inactivityWarningTimeout) {
825
+ clearTimeout(this.inactivityWarningTimeout);
826
+ this.inactivityWarningTimeout = null;
827
+ }
828
+ if (this.inactivityTimeout) {
829
+ clearTimeout(this.inactivityTimeout);
830
+ this.inactivityTimeout = null;
831
+ }
832
+ }
833
+ /**
834
+ * Reset inactivity timer
835
+ */
836
+ resetInactivityTimer() {
837
+ // Clear existing timeouts
838
+ this.clearInactivityTimeouts();
839
+ if (!this.inactivityDetectionEnabled || !this.inactivityCallbacks) {
840
+ return;
841
+ }
842
+ const now = Date.now();
843
+ this.lastActivityTime = now;
844
+ // Setup warning timeout
845
+ if (this.inactivityWarningSeconds > 0 && this.inactivityCallbacks.onInactivityWarning) {
846
+ const warningTime = this.inactivityTimeoutSeconds - this.inactivityWarningSeconds;
847
+ if (warningTime > 0) {
848
+ const timerStartTime = now; // Capture start time for this timer
849
+ this.inactivityWarningTimeout = setTimeout(() => {
850
+ // Calculate remaining seconds based on when timer was set
851
+ const elapsedSeconds = (Date.now() - timerStartTime) / 1000;
852
+ const remainingSeconds = this.inactivityTimeoutSeconds - elapsedSeconds;
853
+ if (this.inactivityCallbacks?.onInactivityWarning && remainingSeconds > 0) {
854
+ this.inactivityCallbacks.onInactivityWarning(Math.floor(remainingSeconds));
855
+ }
856
+ }, warningTime * 1000);
857
+ }
858
+ }
859
+ // Setup timeout
860
+ this.inactivityTimeout = setTimeout(() => {
861
+ if (this.inactivityCallbacks?.onInactivityTimeout) {
862
+ this.inactivityCallbacks.onInactivityTimeout();
863
+ }
864
+ }, this.inactivityTimeoutSeconds * 1000);
865
+ }
866
+ /**
867
+ * Check inactivity timeout and trigger callbacks if needed
868
+ */
869
+ checkInactivityTimeout() {
870
+ if (!this.inactivityDetectionEnabled || !this.inactivityCallbacks) {
871
+ return;
872
+ }
873
+ const now = Date.now();
874
+ const inactiveSeconds = (now - this.lastActivityTime) / 1000;
875
+ // Check if timeout reached
876
+ if (inactiveSeconds >= this.inactivityTimeoutSeconds) {
877
+ if (this.inactivityCallbacks.onInactivityTimeout) {
878
+ this.inactivityCallbacks.onInactivityTimeout();
879
+ }
880
+ return;
881
+ }
882
+ // Check if warning should be triggered
883
+ const remainingSeconds = this.inactivityTimeoutSeconds - inactiveSeconds;
884
+ if (remainingSeconds <= this.inactivityWarningSeconds &&
885
+ remainingSeconds > 0 &&
886
+ this.inactivityCallbacks.onInactivityWarning) {
887
+ this.inactivityCallbacks.onInactivityWarning(Math.floor(remainingSeconds));
888
+ }
889
+ }
644
890
  }
645
891
  exports.AuthClient = AuthClient;
@@ -2,6 +2,6 @@
2
2
  * Client exports for frontend applications
3
3
  */
4
4
  export { AuthClient } from './auth-client';
5
- export type { RefreshTokenCallbacks, AutomaticRefreshOptions, SessionExpirationCallbacks, SessionExpirationOptions, } from './auth-client';
5
+ export type { RefreshTokenCallbacks, AutomaticRefreshOptions, SessionExpirationCallbacks, SessionExpirationOptions, InactivityCallbacks, InactivityDetectionOptions, } from './auth-client';
6
6
  export * from './api';
7
7
  //# sourceMappingURL=index.d.ts.map
@@ -1 +1 @@
1
- {"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../src/client/index.ts"],"names":[],"mappings":"AAAA;;GAEG;AAEH,OAAO,EAAE,UAAU,EAAE,MAAM,eAAe,CAAC;AAC3C,YAAY,EACV,qBAAqB,EACrB,uBAAuB,EACvB,0BAA0B,EAC1B,wBAAwB,GACzB,MAAM,eAAe,CAAC;AACvB,cAAc,OAAO,CAAC"}
1
+ {"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../src/client/index.ts"],"names":[],"mappings":"AAAA;;GAEG;AAEH,OAAO,EAAE,UAAU,EAAE,MAAM,eAAe,CAAC;AAC3C,YAAY,EACV,qBAAqB,EACrB,uBAAuB,EACvB,0BAA0B,EAC1B,wBAAwB,EACxB,mBAAmB,EACnB,0BAA0B,GAC3B,MAAM,eAAe,CAAC;AACvB,cAAc,OAAO,CAAC"}
package/dist/index.d.ts CHANGED
@@ -3,9 +3,15 @@
3
3
  *
4
4
  * Authentication SDK for Win Portal applications
5
5
  * Provides HTTP client with automatic API key injection
6
+ *
7
+ * Core exports - ใช้ได้ทุกที่ (Frontend & Backend)
8
+ *
9
+ * สำหรับ Backend-specific features:
10
+ * - Express Middleware: import from 'win-portal-auth-sdk/middleware'
11
+ * - NestJS Components: import from 'win-portal-auth-sdk/nestjs'
6
12
  */
7
13
  export * from './types';
8
14
  export * from './client';
9
- export * from './middleware';
10
15
  export * from './utils/token-utils';
16
+ export { logger } from './utils/logger';
11
17
  //# sourceMappingURL=index.d.ts.map
@@ -1 +1 @@
1
- {"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"AAAA;;;;;GAKG;AAGH,cAAc,SAAS,CAAC;AAGxB,cAAc,UAAU,CAAC;AAGzB,cAAc,cAAc,CAAC;AAG7B,cAAc,qBAAqB,CAAC"}
1
+ {"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;GAWG;AAGH,cAAc,SAAS,CAAC;AAGxB,cAAc,UAAU,CAAC;AAGzB,cAAc,qBAAqB,CAAC;AACpC,OAAO,EAAE,MAAM,EAAE,MAAM,gBAAgB,CAAC"}
package/dist/index.js CHANGED
@@ -4,6 +4,12 @@
4
4
  *
5
5
  * Authentication SDK for Win Portal applications
6
6
  * Provides HTTP client with automatic API key injection
7
+ *
8
+ * Core exports - ใช้ได้ทุกที่ (Frontend & Backend)
9
+ *
10
+ * สำหรับ Backend-specific features:
11
+ * - Express Middleware: import from 'win-portal-auth-sdk/middleware'
12
+ * - NestJS Components: import from 'win-portal-auth-sdk/nestjs'
7
13
  */
8
14
  var __createBinding = (this && this.__createBinding) || (Object.create ? (function(o, m, k, k2) {
9
15
  if (k2 === undefined) k2 = k;
@@ -20,11 +26,17 @@ var __exportStar = (this && this.__exportStar) || function(m, exports) {
20
26
  for (var p in m) if (p !== "default" && !Object.prototype.hasOwnProperty.call(exports, p)) __createBinding(exports, m, p);
21
27
  };
22
28
  Object.defineProperty(exports, "__esModule", { value: true });
29
+ exports.logger = void 0;
23
30
  // Types
24
31
  __exportStar(require("./types"), exports);
25
32
  // Client (Frontend & Backend)
26
33
  __exportStar(require("./client"), exports);
27
- // Middleware (Backend only - Express & NestJS)
28
- __exportStar(require("./middleware"), exports);
29
34
  // Utils
30
35
  __exportStar(require("./utils/token-utils"), exports);
36
+ var logger_1 = require("./utils/logger");
37
+ Object.defineProperty(exports, "logger", { enumerable: true, get: function () { return logger_1.logger; } });
38
+ // Note: Middleware และ NestJS components ไม่ได้ export จาก root
39
+ // เพื่อป้องกันการ bundle backend code ใน frontend applications
40
+ // ใช้ subpath exports แทน:
41
+ // - 'win-portal-auth-sdk/middleware' สำหรับ Express middleware
42
+ // - 'win-portal-auth-sdk/nestjs' สำหรับ NestJS components
@@ -0,0 +1,29 @@
1
+ /**
2
+ * Current Token Decorator
3
+ *
4
+ * Parameter decorator to extract the current authentication token from the request.
5
+ * Requires that a guard has set request.token (e.g., OAuthAuthGuard).
6
+ */
7
+ /**
8
+ * Current Token Decorator
9
+ *
10
+ * Extracts the authentication token from request.token.
11
+ * Returns null if no token is available.
12
+ *
13
+ * @example
14
+ * ```typescript
15
+ * @Controller('api')
16
+ * @UseGuards(OAuthAuthGuard)
17
+ * export class ApiController {
18
+ * @Get('token-info')
19
+ * getTokenInfo(@CurrentToken() token: string) {
20
+ * return {
21
+ * token: token.substring(0, 20) + '...',
22
+ * length: token.length,
23
+ * };
24
+ * }
25
+ * }
26
+ * ```
27
+ */
28
+ export declare const CurrentToken: any;
29
+ //# sourceMappingURL=current-token.decorator.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"current-token.decorator.d.ts","sourceRoot":"","sources":["../../../src/nestjs/decorators/current-token.decorator.ts"],"names":[],"mappings":"AAAA;;;;;GAKG;AAKH;;;;;;;;;;;;;;;;;;;;GAoBG;AACH,eAAO,MAAM,YAAY,KAGvB,CAAC"}
@@ -0,0 +1,36 @@
1
+ "use strict";
2
+ /**
3
+ * Current Token Decorator
4
+ *
5
+ * Parameter decorator to extract the current authentication token from the request.
6
+ * Requires that a guard has set request.token (e.g., OAuthAuthGuard).
7
+ */
8
+ Object.defineProperty(exports, "__esModule", { value: true });
9
+ exports.CurrentToken = void 0;
10
+ // @ts-expect-error - @nestjs/common is a peer dependency, will be available at runtime in NestJS apps
11
+ const common_1 = require("@nestjs/common");
12
+ /**
13
+ * Current Token Decorator
14
+ *
15
+ * Extracts the authentication token from request.token.
16
+ * Returns null if no token is available.
17
+ *
18
+ * @example
19
+ * ```typescript
20
+ * @Controller('api')
21
+ * @UseGuards(OAuthAuthGuard)
22
+ * export class ApiController {
23
+ * @Get('token-info')
24
+ * getTokenInfo(@CurrentToken() token: string) {
25
+ * return {
26
+ * token: token.substring(0, 20) + '...',
27
+ * length: token.length,
28
+ * };
29
+ * }
30
+ * }
31
+ * ```
32
+ */
33
+ exports.CurrentToken = (0, common_1.createParamDecorator)((data, ctx) => {
34
+ const request = ctx.switchToHttp().getRequest();
35
+ return request.token || null;
36
+ });
@@ -0,0 +1,26 @@
1
+ /**
2
+ * Current User Decorator
3
+ *
4
+ * Parameter decorator to extract the current authenticated user from the request.
5
+ * Requires that a guard has set request.user (e.g., OAuthAuthGuard).
6
+ */
7
+ /**
8
+ * Current User Decorator
9
+ *
10
+ * Extracts the authenticated user from request.user.
11
+ * Returns null if no user is authenticated.
12
+ *
13
+ * @example
14
+ * ```typescript
15
+ * @Controller('users')
16
+ * @UseGuards(OAuthAuthGuard)
17
+ * export class UsersController {
18
+ * @Get('profile')
19
+ * getProfile(@CurrentUser() user: User) {
20
+ * return user;
21
+ * }
22
+ * }
23
+ * ```
24
+ */
25
+ export declare const CurrentUser: any;
26
+ //# sourceMappingURL=current-user.decorator.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"current-user.decorator.d.ts","sourceRoot":"","sources":["../../../src/nestjs/decorators/current-user.decorator.ts"],"names":[],"mappings":"AAAA;;;;;GAKG;AAMH;;;;;;;;;;;;;;;;;GAiBG;AACH,eAAO,MAAM,WAAW,KAKvB,CAAC"}