win-portal-auth-sdk 1.6.2 → 1.6.5
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/client/auth-client.d.ts +44 -18
- package/dist/client/auth-client.d.ts.map +1 -1
- package/dist/client/auth-client.js +110 -19
- package/dist/client/index.d.ts +1 -0
- package/dist/client/index.d.ts.map +1 -1
- package/dist/client/index.js +3 -1
- package/dist/client/session-socket.d.ts +89 -0
- package/dist/client/session-socket.d.ts.map +1 -0
- package/dist/client/session-socket.js +195 -0
- package/dist/middleware/express.middleware.d.ts +18 -5
- package/dist/middleware/express.middleware.d.ts.map +1 -1
- package/dist/middleware/express.middleware.js +18 -5
- package/dist/middleware/nestjs.guard.d.ts +30 -6
- package/dist/middleware/nestjs.guard.d.ts.map +1 -1
- package/dist/middleware/nestjs.guard.js +30 -6
- package/package.json +9 -1
|
@@ -128,6 +128,9 @@ export declare class AuthClient {
|
|
|
128
128
|
private activityThrottleTimeout;
|
|
129
129
|
private activityThrottleMs;
|
|
130
130
|
private refreshTimeoutMs;
|
|
131
|
+
private lastActivityRefreshTime;
|
|
132
|
+
private ACTIVITY_REFRESH_INTERVAL_MS;
|
|
133
|
+
private sessionSocket;
|
|
131
134
|
readonly auth: AuthAPI;
|
|
132
135
|
readonly health: HealthAPI;
|
|
133
136
|
readonly systemConfig: SystemConfigAPI;
|
|
@@ -188,22 +191,32 @@ export declare class AuthClient {
|
|
|
188
191
|
/**
|
|
189
192
|
* Set JWT token for authenticated requests
|
|
190
193
|
*
|
|
194
|
+
* @platform **Frontend only** - สำหรับ React/Next.js applications
|
|
195
|
+
* @platform **Backend**: ไม่ต้องใช้ - Backend ใช้ `createAuthGuard()` หรือ `authMiddleware()` แทน (ไม่ต้อง setToken)
|
|
196
|
+
*
|
|
191
197
|
* @param token - JWT access token
|
|
192
198
|
* @param type - Token type: 'jwt' (default), 'oauth', or 'hybrid'
|
|
193
199
|
*
|
|
194
200
|
* @example
|
|
195
201
|
* ```typescript
|
|
196
|
-
* // JWT token from /auth/login
|
|
202
|
+
* // Frontend: JWT token from /auth/login
|
|
197
203
|
* authClient.setToken(session.token, 'jwt');
|
|
198
204
|
*
|
|
199
|
-
* // OAuth access token
|
|
205
|
+
* // Frontend: OAuth access token
|
|
200
206
|
* authClient.setToken(oauthToken, 'oauth');
|
|
201
207
|
*
|
|
202
|
-
* //
|
|
203
|
-
*
|
|
208
|
+
* // Backend: ไม่ต้องใช้ - ใช้ createAuthGuard() แทน
|
|
209
|
+
* // @UseGuards(AuthGuard)
|
|
204
210
|
* ```
|
|
205
211
|
*/
|
|
206
212
|
setToken(token: string, type?: 'jwt' | 'oauth' | 'hybrid'): void;
|
|
213
|
+
/**
|
|
214
|
+
* Update session socket token if real-time monitoring is enabled
|
|
215
|
+
*
|
|
216
|
+
* @private
|
|
217
|
+
* @param token - New JWT token to update
|
|
218
|
+
*/
|
|
219
|
+
private updateSessionSocketToken;
|
|
207
220
|
/**
|
|
208
221
|
* Get current token type
|
|
209
222
|
*/
|
|
@@ -228,33 +241,30 @@ export declare class AuthClient {
|
|
|
228
241
|
getAxiosInstance(): AxiosInstance;
|
|
229
242
|
/**
|
|
230
243
|
* Enable automatic token refresh
|
|
231
|
-
*
|
|
244
|
+
*
|
|
245
|
+
* @platform **Frontend only** - สำหรับ React/Next.js applications
|
|
246
|
+
* @platform **Backend**: ไม่ต้องใช้ - Backend ไม่ได้ถือ token, Frontend เป็นคน refresh และส่ง token ใหม่มาใน request ถัดไป
|
|
247
|
+
*
|
|
248
|
+
* Call this after user is authenticated to enable automatic refresh.
|
|
249
|
+
* SDK จะ refresh token อัตโนมัติก่อนหมดอายุผ่าน axios interceptor.
|
|
232
250
|
*
|
|
233
251
|
* @param options - Options for automatic refresh (optional - SDK will use session-based refresh if not provided)
|
|
234
252
|
*
|
|
235
253
|
* @example
|
|
236
254
|
* ```typescript
|
|
237
|
-
* //
|
|
238
|
-
* // Works when login only returns access_token
|
|
255
|
+
* // Frontend: Session-based refresh (default - no refresh token needed)
|
|
239
256
|
* await authClient.enableAutomaticRefresh({
|
|
240
257
|
* onRefreshFailure: () => window.location.href = '/login'
|
|
241
258
|
* });
|
|
242
259
|
*
|
|
243
|
-
* //
|
|
260
|
+
* // Frontend: With refresh token (if login returns refresh_token)
|
|
244
261
|
* await authClient.enableAutomaticRefresh({
|
|
245
262
|
* refreshTokenKey: 'refresh_token',
|
|
246
263
|
* onRefreshFailure: () => window.location.href = '/login'
|
|
247
264
|
* });
|
|
248
265
|
*
|
|
249
|
-
* //
|
|
250
|
-
*
|
|
251
|
-
* callbacks: {
|
|
252
|
-
* getRefreshToken: () => customStorage.get('refresh_token'),
|
|
253
|
-
* setRefreshToken: (token) => customStorage.set('refresh_token', token),
|
|
254
|
-
* clearRefreshToken: () => customStorage.remove('refresh_token'),
|
|
255
|
-
* onRefreshFailure: () => window.location.href = '/login'
|
|
256
|
-
* }
|
|
257
|
-
* });
|
|
266
|
+
* // Backend: ไม่ต้องใช้ - ใช้ createAuthGuard() แทน
|
|
267
|
+
* // @UseGuards(AuthGuard) // Guard จะ validate token อัตโนมัติ
|
|
258
268
|
* ```
|
|
259
269
|
*/
|
|
260
270
|
enableAutomaticRefresh(options?: AutomaticRefreshOptions): Promise<void>;
|
|
@@ -285,12 +295,17 @@ export declare class AuthClient {
|
|
|
285
295
|
reloadJwtConfig(): Promise<void>;
|
|
286
296
|
/**
|
|
287
297
|
* Enable session expiration monitoring
|
|
298
|
+
*
|
|
299
|
+
* @platform **Frontend only** - สำหรับ React/Next.js applications
|
|
300
|
+
* @platform **Backend**: ไม่ต้องใช้ - Backend ไม่ได้ track session expiration, Frontend เป็นคนจัดการ
|
|
301
|
+
*
|
|
288
302
|
* จะตรวจสอบ session expiration ตาม config จาก settings/sessions และเรียก callback เมื่อใกล้หมดอายุ
|
|
289
303
|
*
|
|
290
304
|
* @param options - Options for session expiration monitoring
|
|
291
305
|
*
|
|
292
306
|
* @example
|
|
293
307
|
* ```typescript
|
|
308
|
+
* // Frontend: Monitor session expiration
|
|
294
309
|
* await authClient.enableSessionExpirationMonitoring({
|
|
295
310
|
* callbacks: {
|
|
296
311
|
* onSessionExpiring: (remainingMinutes, expirationType) => {
|
|
@@ -304,6 +319,8 @@ export declare class AuthClient {
|
|
|
304
319
|
* },
|
|
305
320
|
* checkIntervalSeconds: 30 // ตรวจสอบทุก 30 วินาที
|
|
306
321
|
* });
|
|
322
|
+
*
|
|
323
|
+
* // Backend: ไม่ต้องใช้ - ใช้ createAuthGuard() แทน
|
|
307
324
|
* ```
|
|
308
325
|
*/
|
|
309
326
|
enableSessionExpirationMonitoring(options: SessionExpirationOptions): Promise<void>;
|
|
@@ -345,12 +362,18 @@ export declare class AuthClient {
|
|
|
345
362
|
reloadSessionManagementConfig(): Promise<void>;
|
|
346
363
|
/**
|
|
347
364
|
* Enable inactivity detection
|
|
348
|
-
*
|
|
365
|
+
*
|
|
366
|
+
* @platform **Frontend only** - สำหรับ React/Next.js applications
|
|
367
|
+
* @platform **Backend**: ไม่ต้องใช้ - Backend ไม่ได้ track user activity, Frontend เป็นคนจัดการ
|
|
368
|
+
*
|
|
369
|
+
* จับ user activity (mouse/keyboard/touch/scroll) และ trigger callback เมื่อ inactivity timeout.
|
|
370
|
+
* เมื่อมี activity จะ trigger token refresh เพื่อ update server-side `last_access_at`.
|
|
349
371
|
*
|
|
350
372
|
* @param options - Options for inactivity detection
|
|
351
373
|
*
|
|
352
374
|
* @example
|
|
353
375
|
* ```typescript
|
|
376
|
+
* // Frontend: Track user activity and trigger token refresh
|
|
354
377
|
* await authClient.enableInactivityDetection({
|
|
355
378
|
* callbacks: {
|
|
356
379
|
* onInactivityWarning: (remainingSeconds) => {
|
|
@@ -368,6 +391,8 @@ export declare class AuthClient {
|
|
|
368
391
|
* warningSeconds: 300, // 5 minutes warning (optional, default: จาก session management config)
|
|
369
392
|
* events: ['mousemove', 'keydown', 'touchstart', 'scroll'] // (optional, default: ทั้งหมด)
|
|
370
393
|
* });
|
|
394
|
+
*
|
|
395
|
+
* // Backend: ไม่ต้องใช้ - Server-side inactivity enforcement ทำงานอัตโนมัติ
|
|
371
396
|
* ```
|
|
372
397
|
*/
|
|
373
398
|
enableInactivityDetection(options: InactivityDetectionOptions): Promise<void>;
|
|
@@ -377,6 +402,7 @@ export declare class AuthClient {
|
|
|
377
402
|
disableInactivityDetection(): void;
|
|
378
403
|
/**
|
|
379
404
|
* Handle user activity - reset inactivity timer with throttle
|
|
405
|
+
* Also trigger token refresh to update server-side last_access_at (if auto-refresh enabled)
|
|
380
406
|
*/
|
|
381
407
|
private handleUserActivity;
|
|
382
408
|
/**
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"auth-client.d.ts","sourceRoot":"","sources":["../../src/client/auth-client.ts"],"names":[],"mappings":"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
|
|
1
|
+
{"version":3,"file":"auth-client.d.ts","sourceRoot":"","sources":["../../src/client/auth-client.ts"],"names":[],"mappings":"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"}
|
|
@@ -56,6 +56,10 @@ class AuthClient {
|
|
|
56
56
|
this.activityThrottleTimeout = null;
|
|
57
57
|
this.activityThrottleMs = DEFAULT_ACTIVITY_THROTTLE_MS;
|
|
58
58
|
this.refreshTimeoutMs = DEFAULT_REFRESH_TIMEOUT_MS;
|
|
59
|
+
this.lastActivityRefreshTime = 0; // Track last time we refreshed due to activity
|
|
60
|
+
this.ACTIVITY_REFRESH_INTERVAL_MS = 5 * 60 * 1000; // Refresh every 5 minutes when active (keep-alive)
|
|
61
|
+
// Real-time session monitoring (Socket.IO)
|
|
62
|
+
this.sessionSocket = null; // SessionSocket instance
|
|
59
63
|
this.apiKey = config.apiKey;
|
|
60
64
|
this.apiKeyHeader = config.apiKeyHeader || 'X-API-Key';
|
|
61
65
|
// Apply advanced config if provided
|
|
@@ -107,6 +111,8 @@ class AuthClient {
|
|
|
107
111
|
]);
|
|
108
112
|
this.token = newToken;
|
|
109
113
|
requestConfig.headers['Authorization'] = `Bearer ${newToken}`;
|
|
114
|
+
// Update session socket token if real-time monitoring is enabled
|
|
115
|
+
this.updateSessionSocketToken(newToken);
|
|
110
116
|
logger_1.logger.info('Token refreshed successfully (critical)');
|
|
111
117
|
}
|
|
112
118
|
catch (error) {
|
|
@@ -261,24 +267,29 @@ class AuthClient {
|
|
|
261
267
|
/**
|
|
262
268
|
* Set JWT token for authenticated requests
|
|
263
269
|
*
|
|
270
|
+
* @platform **Frontend only** - สำหรับ React/Next.js applications
|
|
271
|
+
* @platform **Backend**: ไม่ต้องใช้ - Backend ใช้ `createAuthGuard()` หรือ `authMiddleware()` แทน (ไม่ต้อง setToken)
|
|
272
|
+
*
|
|
264
273
|
* @param token - JWT access token
|
|
265
274
|
* @param type - Token type: 'jwt' (default), 'oauth', or 'hybrid'
|
|
266
275
|
*
|
|
267
276
|
* @example
|
|
268
277
|
* ```typescript
|
|
269
|
-
* // JWT token from /auth/login
|
|
278
|
+
* // Frontend: JWT token from /auth/login
|
|
270
279
|
* authClient.setToken(session.token, 'jwt');
|
|
271
280
|
*
|
|
272
|
-
* // OAuth access token
|
|
281
|
+
* // Frontend: OAuth access token
|
|
273
282
|
* authClient.setToken(oauthToken, 'oauth');
|
|
274
283
|
*
|
|
275
|
-
* //
|
|
276
|
-
*
|
|
284
|
+
* // Backend: ไม่ต้องใช้ - ใช้ createAuthGuard() แทน
|
|
285
|
+
* // @UseGuards(AuthGuard)
|
|
277
286
|
* ```
|
|
278
287
|
*/
|
|
279
288
|
setToken(token, type = 'jwt') {
|
|
280
289
|
this.token = token;
|
|
281
290
|
this.authType = type;
|
|
291
|
+
// Update session socket token if real-time monitoring is enabled
|
|
292
|
+
this.updateSessionSocketToken(token);
|
|
282
293
|
logger_1.logger.debug(`Token set with type: ${type}`);
|
|
283
294
|
// Reset warning time when token changes
|
|
284
295
|
this.lastWarningTime = 0;
|
|
@@ -287,6 +298,18 @@ class AuthClient {
|
|
|
287
298
|
this.checkSessionExpiration();
|
|
288
299
|
}
|
|
289
300
|
}
|
|
301
|
+
/**
|
|
302
|
+
* Update session socket token if real-time monitoring is enabled
|
|
303
|
+
*
|
|
304
|
+
* @private
|
|
305
|
+
* @param token - New JWT token to update
|
|
306
|
+
*/
|
|
307
|
+
updateSessionSocketToken(token) {
|
|
308
|
+
if (this.sessionSocket && typeof this.sessionSocket.updateToken === 'function') {
|
|
309
|
+
this.sessionSocket.updateToken(token);
|
|
310
|
+
logger_1.logger.debug('Session socket token updated');
|
|
311
|
+
}
|
|
312
|
+
}
|
|
290
313
|
/**
|
|
291
314
|
* Get current token type
|
|
292
315
|
*/
|
|
@@ -329,33 +352,30 @@ class AuthClient {
|
|
|
329
352
|
}
|
|
330
353
|
/**
|
|
331
354
|
* Enable automatic token refresh
|
|
332
|
-
*
|
|
355
|
+
*
|
|
356
|
+
* @platform **Frontend only** - สำหรับ React/Next.js applications
|
|
357
|
+
* @platform **Backend**: ไม่ต้องใช้ - Backend ไม่ได้ถือ token, Frontend เป็นคน refresh และส่ง token ใหม่มาใน request ถัดไป
|
|
358
|
+
*
|
|
359
|
+
* Call this after user is authenticated to enable automatic refresh.
|
|
360
|
+
* SDK จะ refresh token อัตโนมัติก่อนหมดอายุผ่าน axios interceptor.
|
|
333
361
|
*
|
|
334
362
|
* @param options - Options for automatic refresh (optional - SDK will use session-based refresh if not provided)
|
|
335
363
|
*
|
|
336
364
|
* @example
|
|
337
365
|
* ```typescript
|
|
338
|
-
* //
|
|
339
|
-
* // Works when login only returns access_token
|
|
366
|
+
* // Frontend: Session-based refresh (default - no refresh token needed)
|
|
340
367
|
* await authClient.enableAutomaticRefresh({
|
|
341
368
|
* onRefreshFailure: () => window.location.href = '/login'
|
|
342
369
|
* });
|
|
343
370
|
*
|
|
344
|
-
* //
|
|
371
|
+
* // Frontend: With refresh token (if login returns refresh_token)
|
|
345
372
|
* await authClient.enableAutomaticRefresh({
|
|
346
373
|
* refreshTokenKey: 'refresh_token',
|
|
347
374
|
* onRefreshFailure: () => window.location.href = '/login'
|
|
348
375
|
* });
|
|
349
376
|
*
|
|
350
|
-
* //
|
|
351
|
-
*
|
|
352
|
-
* callbacks: {
|
|
353
|
-
* getRefreshToken: () => customStorage.get('refresh_token'),
|
|
354
|
-
* setRefreshToken: (token) => customStorage.set('refresh_token', token),
|
|
355
|
-
* clearRefreshToken: () => customStorage.remove('refresh_token'),
|
|
356
|
-
* onRefreshFailure: () => window.location.href = '/login'
|
|
357
|
-
* }
|
|
358
|
-
* });
|
|
377
|
+
* // Backend: ไม่ต้องใช้ - ใช้ createAuthGuard() แทน
|
|
378
|
+
* // @UseGuards(AuthGuard) // Guard จะ validate token อัตโนมัติ
|
|
359
379
|
* ```
|
|
360
380
|
*/
|
|
361
381
|
async enableAutomaticRefresh(options) {
|
|
@@ -432,7 +452,35 @@ class AuthClient {
|
|
|
432
452
|
*/
|
|
433
453
|
async performJwtConfigLoad() {
|
|
434
454
|
try {
|
|
435
|
-
|
|
455
|
+
let config;
|
|
456
|
+
try {
|
|
457
|
+
// Try to get specific JWT config (SystemConfig format with .value)
|
|
458
|
+
const result = await this.systemConfig.get('security', 'jwt');
|
|
459
|
+
logger_1.logger.debug('JWT config result:', { result });
|
|
460
|
+
// Handle SystemConfig format - has .value property
|
|
461
|
+
if ('value' in result && result.value) {
|
|
462
|
+
config = result.value;
|
|
463
|
+
}
|
|
464
|
+
else {
|
|
465
|
+
throw new Error('JWT config value not found in SystemConfig response');
|
|
466
|
+
}
|
|
467
|
+
}
|
|
468
|
+
catch (error) {
|
|
469
|
+
// Fallback: Try to get all security configs and extract jwt
|
|
470
|
+
logger_1.logger.debug('Failed to get JWT config by key, trying category fallback:', error);
|
|
471
|
+
const categoryResult = await this.systemConfig.get('security');
|
|
472
|
+
// Handle SystemConfigByCategory format - jwt is a direct key
|
|
473
|
+
if (categoryResult && typeof categoryResult === 'object' && 'jwt' in categoryResult) {
|
|
474
|
+
config = categoryResult.jwt;
|
|
475
|
+
}
|
|
476
|
+
else {
|
|
477
|
+
throw new Error('JWT config not found in security category');
|
|
478
|
+
}
|
|
479
|
+
}
|
|
480
|
+
// Validate config has required fields
|
|
481
|
+
if (!config || typeof config.refresh_threshold_minutes !== 'number') {
|
|
482
|
+
throw new Error('Invalid JWT config: refresh_threshold_minutes is missing or invalid');
|
|
483
|
+
}
|
|
436
484
|
this.refreshThresholdMinutes = config.refresh_threshold_minutes;
|
|
437
485
|
this.automaticRefreshEnabled = config.automatic_refresh ?? true;
|
|
438
486
|
logger_1.logger.debug(`JWT config loaded: refresh_threshold_minutes=${this.refreshThresholdMinutes} minutes, automatic_refresh=${this.automaticRefreshEnabled}`);
|
|
@@ -478,6 +526,8 @@ class AuthClient {
|
|
|
478
526
|
const newAccessToken = result.token;
|
|
479
527
|
// Update token in client
|
|
480
528
|
this.token = newAccessToken;
|
|
529
|
+
// Update session socket token if real-time monitoring is enabled
|
|
530
|
+
this.updateSessionSocketToken(newAccessToken);
|
|
481
531
|
logger_1.logger.debug('Token refreshed successfully (session-based)');
|
|
482
532
|
return newAccessToken;
|
|
483
533
|
}
|
|
@@ -499,6 +549,8 @@ class AuthClient {
|
|
|
499
549
|
const newAccessToken = session.access_token;
|
|
500
550
|
// Update token in client
|
|
501
551
|
this.token = newAccessToken;
|
|
552
|
+
// Update session socket token if real-time monitoring is enabled
|
|
553
|
+
this.updateSessionSocketToken(newAccessToken);
|
|
502
554
|
// Save new refresh token if rotated
|
|
503
555
|
if (session.refresh_token) {
|
|
504
556
|
await this.refreshTokenCallbacks.setRefreshToken(session.refresh_token);
|
|
@@ -526,12 +578,17 @@ class AuthClient {
|
|
|
526
578
|
}
|
|
527
579
|
/**
|
|
528
580
|
* Enable session expiration monitoring
|
|
581
|
+
*
|
|
582
|
+
* @platform **Frontend only** - สำหรับ React/Next.js applications
|
|
583
|
+
* @platform **Backend**: ไม่ต้องใช้ - Backend ไม่ได้ track session expiration, Frontend เป็นคนจัดการ
|
|
584
|
+
*
|
|
529
585
|
* จะตรวจสอบ session expiration ตาม config จาก settings/sessions และเรียก callback เมื่อใกล้หมดอายุ
|
|
530
586
|
*
|
|
531
587
|
* @param options - Options for session expiration monitoring
|
|
532
588
|
*
|
|
533
589
|
* @example
|
|
534
590
|
* ```typescript
|
|
591
|
+
* // Frontend: Monitor session expiration
|
|
535
592
|
* await authClient.enableSessionExpirationMonitoring({
|
|
536
593
|
* callbacks: {
|
|
537
594
|
* onSessionExpiring: (remainingMinutes, expirationType) => {
|
|
@@ -545,6 +602,8 @@ class AuthClient {
|
|
|
545
602
|
* },
|
|
546
603
|
* checkIntervalSeconds: 30 // ตรวจสอบทุก 30 วินาที
|
|
547
604
|
* });
|
|
605
|
+
*
|
|
606
|
+
* // Backend: ไม่ต้องใช้ - ใช้ createAuthGuard() แทน
|
|
548
607
|
* ```
|
|
549
608
|
*/
|
|
550
609
|
async enableSessionExpirationMonitoring(options) {
|
|
@@ -703,12 +762,18 @@ class AuthClient {
|
|
|
703
762
|
}
|
|
704
763
|
/**
|
|
705
764
|
* Enable inactivity detection
|
|
706
|
-
*
|
|
765
|
+
*
|
|
766
|
+
* @platform **Frontend only** - สำหรับ React/Next.js applications
|
|
767
|
+
* @platform **Backend**: ไม่ต้องใช้ - Backend ไม่ได้ track user activity, Frontend เป็นคนจัดการ
|
|
768
|
+
*
|
|
769
|
+
* จับ user activity (mouse/keyboard/touch/scroll) และ trigger callback เมื่อ inactivity timeout.
|
|
770
|
+
* เมื่อมี activity จะ trigger token refresh เพื่อ update server-side `last_access_at`.
|
|
707
771
|
*
|
|
708
772
|
* @param options - Options for inactivity detection
|
|
709
773
|
*
|
|
710
774
|
* @example
|
|
711
775
|
* ```typescript
|
|
776
|
+
* // Frontend: Track user activity and trigger token refresh
|
|
712
777
|
* await authClient.enableInactivityDetection({
|
|
713
778
|
* callbacks: {
|
|
714
779
|
* onInactivityWarning: (remainingSeconds) => {
|
|
@@ -726,6 +791,8 @@ class AuthClient {
|
|
|
726
791
|
* warningSeconds: 300, // 5 minutes warning (optional, default: จาก session management config)
|
|
727
792
|
* events: ['mousemove', 'keydown', 'touchstart', 'scroll'] // (optional, default: ทั้งหมด)
|
|
728
793
|
* });
|
|
794
|
+
*
|
|
795
|
+
* // Backend: ไม่ต้องใช้ - Server-side inactivity enforcement ทำงานอัตโนมัติ
|
|
729
796
|
* ```
|
|
730
797
|
*/
|
|
731
798
|
async enableInactivityDetection(options) {
|
|
@@ -799,6 +866,7 @@ class AuthClient {
|
|
|
799
866
|
}
|
|
800
867
|
/**
|
|
801
868
|
* Handle user activity - reset inactivity timer with throttle
|
|
869
|
+
* Also trigger token refresh to update server-side last_access_at (if auto-refresh enabled)
|
|
802
870
|
*/
|
|
803
871
|
handleUserActivity() {
|
|
804
872
|
if (!this.inactivityDetectionEnabled) {
|
|
@@ -810,6 +878,29 @@ class AuthClient {
|
|
|
810
878
|
}
|
|
811
879
|
this.lastActivityTime = Date.now();
|
|
812
880
|
this.resetInactivityTimer();
|
|
881
|
+
// ✅ Connect inactivity detection with auto-refresh: trigger refresh to update server-side last_access_at
|
|
882
|
+
// This ensures server knows user is active even if no API calls are made
|
|
883
|
+
if (this.automaticRefreshEnabled &&
|
|
884
|
+
this.refreshTokenCallbacks &&
|
|
885
|
+
this.token &&
|
|
886
|
+
(0, token_utils_1.isTokenValid)(this.token)) {
|
|
887
|
+
const now = Date.now();
|
|
888
|
+
const timeSinceLastActivityRefresh = now - this.lastActivityRefreshTime;
|
|
889
|
+
// Refresh token if:
|
|
890
|
+
// 1. Token is near expiration (use refresh_threshold_minutes)
|
|
891
|
+
// 2. OR it's been 5 minutes since last activity refresh (keep-alive)
|
|
892
|
+
const shouldRefresh = (this.refreshThresholdMinutes !== null &&
|
|
893
|
+
(0, token_utils_1.isTokenNearExpiration)(this.token, this.refreshThresholdMinutes)) ||
|
|
894
|
+
timeSinceLastActivityRefresh >= this.ACTIVITY_REFRESH_INTERVAL_MS;
|
|
895
|
+
if (shouldRefresh && !this.refreshPromise) {
|
|
896
|
+
this.lastActivityRefreshTime = now;
|
|
897
|
+
// Trigger background refresh (non-blocking)
|
|
898
|
+
this.performRefresh().catch((error) => {
|
|
899
|
+
logger_1.logger.debug('Activity-triggered token refresh failed:', error);
|
|
900
|
+
// Don't call onRefreshFailure here - this is just a keep-alive, not critical
|
|
901
|
+
});
|
|
902
|
+
}
|
|
903
|
+
}
|
|
813
904
|
this.activityThrottleTimeout = setTimeout(() => {
|
|
814
905
|
this.activityThrottleTimeout = null;
|
|
815
906
|
}, this.activityThrottleMs);
|
package/dist/client/index.d.ts
CHANGED
|
@@ -2,6 +2,7 @@
|
|
|
2
2
|
* Client exports for frontend applications
|
|
3
3
|
*/
|
|
4
4
|
export { AuthClient } from './auth-client';
|
|
5
|
+
export { SessionSocket, type SessionSocketOptions, type SessionEventData } from './session-socket';
|
|
5
6
|
export type { RefreshTokenCallbacks, AutomaticRefreshOptions, SessionExpirationCallbacks, SessionExpirationOptions, InactivityCallbacks, InactivityDetectionOptions, } from './auth-client';
|
|
6
7
|
export * from './api';
|
|
7
8
|
//# 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,EACxB,mBAAmB,EACnB,0BAA0B,GAC3B,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,OAAO,EAAE,aAAa,EAAE,KAAK,oBAAoB,EAAE,KAAK,gBAAgB,EAAE,MAAM,kBAAkB,CAAC;AACnG,YAAY,EACV,qBAAqB,EACrB,uBAAuB,EACvB,0BAA0B,EAC1B,wBAAwB,EACxB,mBAAmB,EACnB,0BAA0B,GAC3B,MAAM,eAAe,CAAC;AACvB,cAAc,OAAO,CAAC"}
|
package/dist/client/index.js
CHANGED
|
@@ -17,7 +17,9 @@ var __exportStar = (this && this.__exportStar) || function(m, exports) {
|
|
|
17
17
|
for (var p in m) if (p !== "default" && !Object.prototype.hasOwnProperty.call(exports, p)) __createBinding(exports, m, p);
|
|
18
18
|
};
|
|
19
19
|
Object.defineProperty(exports, "__esModule", { value: true });
|
|
20
|
-
exports.AuthClient = void 0;
|
|
20
|
+
exports.SessionSocket = exports.AuthClient = void 0;
|
|
21
21
|
var auth_client_1 = require("./auth-client");
|
|
22
22
|
Object.defineProperty(exports, "AuthClient", { enumerable: true, get: function () { return auth_client_1.AuthClient; } });
|
|
23
|
+
var session_socket_1 = require("./session-socket");
|
|
24
|
+
Object.defineProperty(exports, "SessionSocket", { enumerable: true, get: function () { return session_socket_1.SessionSocket; } });
|
|
23
25
|
__exportStar(require("./api"), exports);
|
|
@@ -0,0 +1,89 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Session Socket Options
|
|
3
|
+
*/
|
|
4
|
+
export interface SessionSocketOptions {
|
|
5
|
+
/** Portal API URL (same as AuthClient baseURL) */
|
|
6
|
+
baseURL: string;
|
|
7
|
+
/** JWT token for authentication */
|
|
8
|
+
token: string;
|
|
9
|
+
/** Namespace (default: /app-sessions) */
|
|
10
|
+
namespace?: string;
|
|
11
|
+
/** Callbacks */
|
|
12
|
+
onSessionExpired?: (data: SessionEventData) => void;
|
|
13
|
+
onSessionRevoked?: (data: SessionEventData) => void;
|
|
14
|
+
onSessionExpiring?: (data: {
|
|
15
|
+
remaining_seconds: number;
|
|
16
|
+
reason: string;
|
|
17
|
+
}) => void;
|
|
18
|
+
onConnectionChange?: (connected: boolean) => void;
|
|
19
|
+
/** Auto-reconnect (default: true) */
|
|
20
|
+
autoReconnect?: boolean;
|
|
21
|
+
/** Reconnect attempts (default: 5) */
|
|
22
|
+
reconnectAttempts?: number;
|
|
23
|
+
/** Reconnect delay in ms (default: 1000) */
|
|
24
|
+
reconnectDelay?: number;
|
|
25
|
+
}
|
|
26
|
+
/**
|
|
27
|
+
* Session Event Data
|
|
28
|
+
*/
|
|
29
|
+
export interface SessionEventData {
|
|
30
|
+
session_id: string;
|
|
31
|
+
reason: string;
|
|
32
|
+
expired_at?: string;
|
|
33
|
+
last_access_at?: string;
|
|
34
|
+
revoked_by?: string;
|
|
35
|
+
revoked_at?: string;
|
|
36
|
+
}
|
|
37
|
+
/**
|
|
38
|
+
* Session Socket Client
|
|
39
|
+
*
|
|
40
|
+
* @description Socket.IO client wrapper for real-time session events
|
|
41
|
+
* Requires socket.io-client as peer dependency
|
|
42
|
+
*
|
|
43
|
+
* @example
|
|
44
|
+
* ```typescript
|
|
45
|
+
* const socket = new SessionSocket({
|
|
46
|
+
* baseURL: 'https://portal.example.com',
|
|
47
|
+
* token: 'jwt-token',
|
|
48
|
+
* onSessionExpired: (data) => {
|
|
49
|
+
* console.log('Session expired:', data);
|
|
50
|
+
* window.location.href = '/login';
|
|
51
|
+
* },
|
|
52
|
+
* });
|
|
53
|
+
*
|
|
54
|
+
* socket.connect();
|
|
55
|
+
* ```
|
|
56
|
+
*/
|
|
57
|
+
export declare class SessionSocket {
|
|
58
|
+
private socket;
|
|
59
|
+
private options;
|
|
60
|
+
private reconnectAttempts;
|
|
61
|
+
private reconnectTimeout;
|
|
62
|
+
private isConnecting;
|
|
63
|
+
constructor(options: SessionSocketOptions);
|
|
64
|
+
/**
|
|
65
|
+
* Connect to Socket.IO server
|
|
66
|
+
*/
|
|
67
|
+
connect(): Promise<void>;
|
|
68
|
+
/**
|
|
69
|
+
* Disconnect from Socket.IO server
|
|
70
|
+
*/
|
|
71
|
+
disconnect(): void;
|
|
72
|
+
/**
|
|
73
|
+
* Check if socket is connected
|
|
74
|
+
*/
|
|
75
|
+
isConnected(): boolean;
|
|
76
|
+
/**
|
|
77
|
+
* Update JWT token (useful when token is refreshed)
|
|
78
|
+
*/
|
|
79
|
+
updateToken(token: string): void;
|
|
80
|
+
/**
|
|
81
|
+
* Setup Socket.IO event listeners
|
|
82
|
+
*/
|
|
83
|
+
private setupEventListeners;
|
|
84
|
+
/**
|
|
85
|
+
* Schedule reconnection attempt
|
|
86
|
+
*/
|
|
87
|
+
private scheduleReconnect;
|
|
88
|
+
}
|
|
89
|
+
//# sourceMappingURL=session-socket.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"session-socket.d.ts","sourceRoot":"","sources":["../../src/client/session-socket.ts"],"names":[],"mappings":"AAEA;;GAEG;AACH,MAAM,WAAW,oBAAoB;IACnC,kDAAkD;IAClD,OAAO,EAAE,MAAM,CAAC;IAChB,mCAAmC;IACnC,KAAK,EAAE,MAAM,CAAC;IACd,yCAAyC;IACzC,SAAS,CAAC,EAAE,MAAM,CAAC;IACnB,gBAAgB;IAChB,gBAAgB,CAAC,EAAE,CAAC,IAAI,EAAE,gBAAgB,KAAK,IAAI,CAAC;IACpD,gBAAgB,CAAC,EAAE,CAAC,IAAI,EAAE,gBAAgB,KAAK,IAAI,CAAC;IACpD,iBAAiB,CAAC,EAAE,CAAC,IAAI,EAAE;QAAE,iBAAiB,EAAE,MAAM,CAAC;QAAC,MAAM,EAAE,MAAM,CAAA;KAAE,KAAK,IAAI,CAAC;IAClF,kBAAkB,CAAC,EAAE,CAAC,SAAS,EAAE,OAAO,KAAK,IAAI,CAAC;IAClD,qCAAqC;IACrC,aAAa,CAAC,EAAE,OAAO,CAAC;IACxB,sCAAsC;IACtC,iBAAiB,CAAC,EAAE,MAAM,CAAC;IAC3B,4CAA4C;IAC5C,cAAc,CAAC,EAAE,MAAM,CAAC;CACzB;AAED;;GAEG;AACH,MAAM,WAAW,gBAAgB;IAC/B,UAAU,EAAE,MAAM,CAAC;IACnB,MAAM,EAAE,MAAM,CAAC;IACf,UAAU,CAAC,EAAE,MAAM,CAAC;IACpB,cAAc,CAAC,EAAE,MAAM,CAAC;IACxB,UAAU,CAAC,EAAE,MAAM,CAAC;IACpB,UAAU,CAAC,EAAE,MAAM,CAAC;CACrB;AAED;;;;;;;;;;;;;;;;;;;GAmBG;AACH,qBAAa,aAAa;IACxB,OAAO,CAAC,MAAM,CAAa;IAC3B,OAAO,CAAC,OAAO,CAAuB;IACtC,OAAO,CAAC,iBAAiB,CAAK;IAC9B,OAAO,CAAC,gBAAgB,CAA+B;IACvD,OAAO,CAAC,YAAY,CAAS;gBAEjB,OAAO,EAAE,oBAAoB;IAUzC;;OAEG;IACG,OAAO,IAAI,OAAO,CAAC,IAAI,CAAC;IAuC9B;;OAEG;IACH,UAAU,IAAI,IAAI;IAgBlB;;OAEG;IACH,WAAW,IAAI,OAAO;IAItB;;OAEG;IACH,WAAW,CAAC,KAAK,EAAE,MAAM,GAAG,IAAI;IAYhC;;OAEG;IACH,OAAO,CAAC,mBAAmB;IAiD3B;;OAEG;IACH,OAAO,CAAC,iBAAiB;CAiB1B"}
|
|
@@ -0,0 +1,195 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
var __createBinding = (this && this.__createBinding) || (Object.create ? (function(o, m, k, k2) {
|
|
3
|
+
if (k2 === undefined) k2 = k;
|
|
4
|
+
var desc = Object.getOwnPropertyDescriptor(m, k);
|
|
5
|
+
if (!desc || ("get" in desc ? !m.__esModule : desc.writable || desc.configurable)) {
|
|
6
|
+
desc = { enumerable: true, get: function() { return m[k]; } };
|
|
7
|
+
}
|
|
8
|
+
Object.defineProperty(o, k2, desc);
|
|
9
|
+
}) : (function(o, m, k, k2) {
|
|
10
|
+
if (k2 === undefined) k2 = k;
|
|
11
|
+
o[k2] = m[k];
|
|
12
|
+
}));
|
|
13
|
+
var __setModuleDefault = (this && this.__setModuleDefault) || (Object.create ? (function(o, v) {
|
|
14
|
+
Object.defineProperty(o, "default", { enumerable: true, value: v });
|
|
15
|
+
}) : function(o, v) {
|
|
16
|
+
o["default"] = v;
|
|
17
|
+
});
|
|
18
|
+
var __importStar = (this && this.__importStar) || function (mod) {
|
|
19
|
+
if (mod && mod.__esModule) return mod;
|
|
20
|
+
var result = {};
|
|
21
|
+
if (mod != null) for (var k in mod) if (k !== "default" && Object.prototype.hasOwnProperty.call(mod, k)) __createBinding(result, mod, k);
|
|
22
|
+
__setModuleDefault(result, mod);
|
|
23
|
+
return result;
|
|
24
|
+
};
|
|
25
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
26
|
+
exports.SessionSocket = void 0;
|
|
27
|
+
const logger_1 = require("../utils/logger");
|
|
28
|
+
/**
|
|
29
|
+
* Session Socket Client
|
|
30
|
+
*
|
|
31
|
+
* @description Socket.IO client wrapper for real-time session events
|
|
32
|
+
* Requires socket.io-client as peer dependency
|
|
33
|
+
*
|
|
34
|
+
* @example
|
|
35
|
+
* ```typescript
|
|
36
|
+
* const socket = new SessionSocket({
|
|
37
|
+
* baseURL: 'https://portal.example.com',
|
|
38
|
+
* token: 'jwt-token',
|
|
39
|
+
* onSessionExpired: (data) => {
|
|
40
|
+
* console.log('Session expired:', data);
|
|
41
|
+
* window.location.href = '/login';
|
|
42
|
+
* },
|
|
43
|
+
* });
|
|
44
|
+
*
|
|
45
|
+
* socket.connect();
|
|
46
|
+
* ```
|
|
47
|
+
*/
|
|
48
|
+
class SessionSocket {
|
|
49
|
+
constructor(options) {
|
|
50
|
+
this.socket = null; // socket.io-client Socket
|
|
51
|
+
this.reconnectAttempts = 0;
|
|
52
|
+
this.reconnectTimeout = null;
|
|
53
|
+
this.isConnecting = false;
|
|
54
|
+
this.options = {
|
|
55
|
+
namespace: '/app-sessions',
|
|
56
|
+
autoReconnect: true,
|
|
57
|
+
reconnectAttempts: 5,
|
|
58
|
+
reconnectDelay: 1000,
|
|
59
|
+
...options,
|
|
60
|
+
};
|
|
61
|
+
}
|
|
62
|
+
/**
|
|
63
|
+
* Connect to Socket.IO server
|
|
64
|
+
*/
|
|
65
|
+
async connect() {
|
|
66
|
+
if (this.isConnecting || this.isConnected()) {
|
|
67
|
+
return;
|
|
68
|
+
}
|
|
69
|
+
try {
|
|
70
|
+
// Dynamic import socket.io-client
|
|
71
|
+
const { io } = await Promise.resolve().then(() => __importStar(require('socket.io-client')));
|
|
72
|
+
this.isConnecting = true;
|
|
73
|
+
const url = `${this.options.baseURL}${this.options.namespace}`;
|
|
74
|
+
this.socket = io(url, {
|
|
75
|
+
auth: {
|
|
76
|
+
token: this.options.token,
|
|
77
|
+
},
|
|
78
|
+
transports: ['websocket', 'polling'],
|
|
79
|
+
reconnection: this.options.autoReconnect,
|
|
80
|
+
reconnectionAttempts: this.options.reconnectAttempts,
|
|
81
|
+
reconnectionDelay: this.options.reconnectDelay,
|
|
82
|
+
});
|
|
83
|
+
// Setup event listeners
|
|
84
|
+
this.setupEventListeners();
|
|
85
|
+
logger_1.logger.debug('SessionSocket connecting...', { url, namespace: this.options.namespace });
|
|
86
|
+
}
|
|
87
|
+
catch (error) {
|
|
88
|
+
this.isConnecting = false;
|
|
89
|
+
if (error.message?.includes('Cannot find module') || error.message?.includes('socket.io-client')) {
|
|
90
|
+
logger_1.logger.warn('socket.io-client not installed. Install it to enable real-time session monitoring: npm install socket.io-client');
|
|
91
|
+
}
|
|
92
|
+
else {
|
|
93
|
+
logger_1.logger.error('Failed to connect SessionSocket:', error);
|
|
94
|
+
}
|
|
95
|
+
throw error;
|
|
96
|
+
}
|
|
97
|
+
}
|
|
98
|
+
/**
|
|
99
|
+
* Disconnect from Socket.IO server
|
|
100
|
+
*/
|
|
101
|
+
disconnect() {
|
|
102
|
+
if (this.socket) {
|
|
103
|
+
this.socket.disconnect();
|
|
104
|
+
this.socket = null;
|
|
105
|
+
}
|
|
106
|
+
if (this.reconnectTimeout) {
|
|
107
|
+
clearTimeout(this.reconnectTimeout);
|
|
108
|
+
this.reconnectTimeout = null;
|
|
109
|
+
}
|
|
110
|
+
this.reconnectAttempts = 0;
|
|
111
|
+
this.isConnecting = false;
|
|
112
|
+
logger_1.logger.debug('SessionSocket disconnected');
|
|
113
|
+
}
|
|
114
|
+
/**
|
|
115
|
+
* Check if socket is connected
|
|
116
|
+
*/
|
|
117
|
+
isConnected() {
|
|
118
|
+
return this.socket?.connected === true;
|
|
119
|
+
}
|
|
120
|
+
/**
|
|
121
|
+
* Update JWT token (useful when token is refreshed)
|
|
122
|
+
*/
|
|
123
|
+
updateToken(token) {
|
|
124
|
+
this.options.token = token;
|
|
125
|
+
if (this.socket) {
|
|
126
|
+
this.socket.auth = { token };
|
|
127
|
+
// Reconnect with new token
|
|
128
|
+
if (this.isConnected()) {
|
|
129
|
+
this.disconnect();
|
|
130
|
+
this.connect();
|
|
131
|
+
}
|
|
132
|
+
}
|
|
133
|
+
}
|
|
134
|
+
/**
|
|
135
|
+
* Setup Socket.IO event listeners
|
|
136
|
+
*/
|
|
137
|
+
setupEventListeners() {
|
|
138
|
+
if (!this.socket) {
|
|
139
|
+
return;
|
|
140
|
+
}
|
|
141
|
+
// Connection events
|
|
142
|
+
this.socket.on('connect', () => {
|
|
143
|
+
this.isConnecting = false;
|
|
144
|
+
this.reconnectAttempts = 0;
|
|
145
|
+
logger_1.logger.debug('SessionSocket connected');
|
|
146
|
+
this.options.onConnectionChange?.(true);
|
|
147
|
+
});
|
|
148
|
+
this.socket.on('disconnect', (reason) => {
|
|
149
|
+
logger_1.logger.debug('SessionSocket disconnected:', reason);
|
|
150
|
+
this.options.onConnectionChange?.(false);
|
|
151
|
+
// Auto-reconnect if enabled and not manually disconnected
|
|
152
|
+
if (this.options.autoReconnect && reason !== 'io client disconnect') {
|
|
153
|
+
this.scheduleReconnect();
|
|
154
|
+
}
|
|
155
|
+
});
|
|
156
|
+
this.socket.on('connect_error', (error) => {
|
|
157
|
+
logger_1.logger.warn('SessionSocket connection error:', error.message);
|
|
158
|
+
this.isConnecting = false;
|
|
159
|
+
});
|
|
160
|
+
// Session events
|
|
161
|
+
this.socket.on('session_expired', (data) => {
|
|
162
|
+
logger_1.logger.debug('Session expired event received:', data);
|
|
163
|
+
this.options.onSessionExpired?.(data);
|
|
164
|
+
});
|
|
165
|
+
this.socket.on('session_revoked', (data) => {
|
|
166
|
+
logger_1.logger.debug('Session revoked event received:', data);
|
|
167
|
+
this.options.onSessionRevoked?.(data);
|
|
168
|
+
});
|
|
169
|
+
this.socket.on('session_expiring', (data) => {
|
|
170
|
+
logger_1.logger.debug('Session expiring event received:', data);
|
|
171
|
+
this.options.onSessionExpiring?.(data);
|
|
172
|
+
});
|
|
173
|
+
this.socket.on('connection_status', (data) => {
|
|
174
|
+
logger_1.logger.debug('Connection status:', data);
|
|
175
|
+
});
|
|
176
|
+
}
|
|
177
|
+
/**
|
|
178
|
+
* Schedule reconnection attempt
|
|
179
|
+
*/
|
|
180
|
+
scheduleReconnect() {
|
|
181
|
+
if (this.reconnectAttempts >= (this.options.reconnectAttempts || 5)) {
|
|
182
|
+
logger_1.logger.warn('Max reconnection attempts reached');
|
|
183
|
+
return;
|
|
184
|
+
}
|
|
185
|
+
this.reconnectAttempts++;
|
|
186
|
+
const delay = (this.options.reconnectDelay || 1000) * this.reconnectAttempts; // Exponential backoff
|
|
187
|
+
logger_1.logger.debug(`Scheduling reconnect attempt ${this.reconnectAttempts} in ${delay}ms`);
|
|
188
|
+
this.reconnectTimeout = setTimeout(() => {
|
|
189
|
+
this.connect().catch((error) => {
|
|
190
|
+
logger_1.logger.error('Reconnection failed:', error);
|
|
191
|
+
});
|
|
192
|
+
}, delay);
|
|
193
|
+
}
|
|
194
|
+
}
|
|
195
|
+
exports.SessionSocket = SessionSocket;
|
|
@@ -9,21 +9,34 @@ import './express.types';
|
|
|
9
9
|
/**
|
|
10
10
|
* Create Express middleware
|
|
11
11
|
*
|
|
12
|
+
* @platform **Backend only** - สำหรับ Express applications
|
|
13
|
+
* @platform **Frontend**: ไม่ต้องใช้ - Frontend ใช้ `AuthClient` แทน
|
|
14
|
+
*
|
|
15
|
+
* Validate token จาก request header และ attach user profile ลง `req.user`.
|
|
16
|
+
* Backend ไม่ต้อง refresh token - Frontend เป็นคน refresh และส่ง token ใหม่มาใน request ถัดไป.
|
|
17
|
+
*
|
|
18
|
+
* @param config - Configuration สำหรับ auth middleware
|
|
19
|
+
* @returns Express middleware function
|
|
20
|
+
*
|
|
12
21
|
* @example
|
|
13
22
|
* ```typescript
|
|
23
|
+
* // Backend: Express middleware
|
|
14
24
|
* import { authMiddleware } from 'win-portal-auth-sdk';
|
|
15
25
|
*
|
|
16
|
-
* // Express
|
|
17
26
|
* app.use(authMiddleware({
|
|
18
|
-
* baseURL:
|
|
19
|
-
* apiKey:
|
|
27
|
+
* baseURL: process.env.PORTAL_API_URL!,
|
|
28
|
+
* apiKey: process.env.PORTAL_API_KEY!,
|
|
29
|
+
* cacheTimeout: 300, // Cache user profile 5 นาที (default)
|
|
20
30
|
* }));
|
|
21
31
|
*
|
|
22
32
|
* // In routes
|
|
23
33
|
* app.get('/profile', (req, res) => {
|
|
24
|
-
* const user = req.user; //
|
|
25
|
-
* const token = req.token;
|
|
34
|
+
* const user = req.user; // UserProfileResponseDto from Portal
|
|
35
|
+
* const token = req.token; // JWT token
|
|
36
|
+
* res.json({ user });
|
|
26
37
|
* });
|
|
38
|
+
*
|
|
39
|
+
* // Frontend: ไม่ต้องใช้ - ใช้ AuthClient แทน
|
|
27
40
|
* ```
|
|
28
41
|
*/
|
|
29
42
|
export declare function authMiddleware(config: MiddlewareConfig): (req: any, res: any, next: any) => Promise<any>;
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"express.middleware.d.ts","sourceRoot":"","sources":["../../src/middleware/express.middleware.ts"],"names":[],"mappings":"AAAA;;;;GAIG;AAEH,OAAO,EAAE,IAAI,EAAE,MAAM,UAAU,CAAC;AAChC,OAAO,EAAE,gBAAgB,EAAE,WAAW,EAAE,MAAM,SAAS,CAAC;AAMxD,OAAO,iBAAiB,CAAC;AAEzB
|
|
1
|
+
{"version":3,"file":"express.middleware.d.ts","sourceRoot":"","sources":["../../src/middleware/express.middleware.ts"],"names":[],"mappings":"AAAA;;;;GAIG;AAEH,OAAO,EAAE,IAAI,EAAE,MAAM,UAAU,CAAC;AAChC,OAAO,EAAE,gBAAgB,EAAE,WAAW,EAAE,MAAM,SAAS,CAAC;AAMxD,OAAO,iBAAiB,CAAC;AAEzB;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;GAgCG;AACH,wBAAgB,cAAc,CAAC,MAAM,EAAE,gBAAgB,SAGlC,GAAG,OAAO,GAAG,QAAQ,GAAG,kBA4B5C;AAED;;;;;;;;;;GAUG;AACH,wBAAgB,OAAO,CAAC,GAAG,EAAE,GAAG,GAAG,WAAW,CAK7C;AAED;;;;;;;;;;;GAWG;AACH,wBAAgB,WAAW,CAAC,GAAG,EAAE,GAAG,GAAG;IACrC,IAAI,EAAE,IAAI,CAAC;IACX,KAAK,EAAE,MAAM,CAAC;CACf,CASA;AAED;;GAEG;AACH,wBAAgB,cAAc,CAAC,KAAK,CAAC,EAAE,MAAM,QAM5C"}
|
|
@@ -14,21 +14,34 @@ require("./express.types");
|
|
|
14
14
|
/**
|
|
15
15
|
* Create Express middleware
|
|
16
16
|
*
|
|
17
|
+
* @platform **Backend only** - สำหรับ Express applications
|
|
18
|
+
* @platform **Frontend**: ไม่ต้องใช้ - Frontend ใช้ `AuthClient` แทน
|
|
19
|
+
*
|
|
20
|
+
* Validate token จาก request header และ attach user profile ลง `req.user`.
|
|
21
|
+
* Backend ไม่ต้อง refresh token - Frontend เป็นคน refresh และส่ง token ใหม่มาใน request ถัดไป.
|
|
22
|
+
*
|
|
23
|
+
* @param config - Configuration สำหรับ auth middleware
|
|
24
|
+
* @returns Express middleware function
|
|
25
|
+
*
|
|
17
26
|
* @example
|
|
18
27
|
* ```typescript
|
|
28
|
+
* // Backend: Express middleware
|
|
19
29
|
* import { authMiddleware } from 'win-portal-auth-sdk';
|
|
20
30
|
*
|
|
21
|
-
* // Express
|
|
22
31
|
* app.use(authMiddleware({
|
|
23
|
-
* baseURL:
|
|
24
|
-
* apiKey:
|
|
32
|
+
* baseURL: process.env.PORTAL_API_URL!,
|
|
33
|
+
* apiKey: process.env.PORTAL_API_KEY!,
|
|
34
|
+
* cacheTimeout: 300, // Cache user profile 5 นาที (default)
|
|
25
35
|
* }));
|
|
26
36
|
*
|
|
27
37
|
* // In routes
|
|
28
38
|
* app.get('/profile', (req, res) => {
|
|
29
|
-
* const user = req.user; //
|
|
30
|
-
* const token = req.token;
|
|
39
|
+
* const user = req.user; // UserProfileResponseDto from Portal
|
|
40
|
+
* const token = req.token; // JWT token
|
|
41
|
+
* res.json({ user });
|
|
31
42
|
* });
|
|
43
|
+
*
|
|
44
|
+
* // Frontend: ไม่ต้องใช้ - ใช้ AuthClient แทน
|
|
32
45
|
* ```
|
|
33
46
|
*/
|
|
34
47
|
function authMiddleware(config) {
|
|
@@ -7,22 +7,34 @@ import { MiddlewareConfig } from './types';
|
|
|
7
7
|
/**
|
|
8
8
|
* NestJS Auth Guard
|
|
9
9
|
*
|
|
10
|
+
* @platform **Backend only** - สำหรับ NestJS applications
|
|
11
|
+
* @platform **Frontend**: ไม่ต้องใช้ - Frontend ใช้ `AuthClient` แทน
|
|
12
|
+
*
|
|
13
|
+
* Validate token จาก request header และ attach user profile ลง `request.user`.
|
|
14
|
+
* Backend ไม่ต้อง refresh token - Frontend เป็นคน refresh และส่ง token ใหม่มาใน request ถัดไป.
|
|
15
|
+
*
|
|
16
|
+
* @param config - Configuration สำหรับ auth guard
|
|
17
|
+
* @returns NestJS Guard class ที่สามารถใช้กับ `@UseGuards()` decorator
|
|
18
|
+
*
|
|
10
19
|
* @example
|
|
11
20
|
* ```typescript
|
|
12
|
-
* // In your auth.guard.ts
|
|
21
|
+
* // Backend: In your auth.guard.ts
|
|
13
22
|
* import { createAuthGuard } from 'win-portal-auth-sdk';
|
|
14
23
|
*
|
|
15
24
|
* export const AuthGuard = createAuthGuard({
|
|
16
|
-
* baseURL: process.env.
|
|
17
|
-
* apiKey: process.env.
|
|
25
|
+
* baseURL: process.env.PORTAL_API_URL!,
|
|
26
|
+
* apiKey: process.env.PORTAL_API_KEY!,
|
|
27
|
+
* cacheTimeout: 300, // Cache user profile 5 นาที (default)
|
|
18
28
|
* });
|
|
19
29
|
*
|
|
20
30
|
* // In your controller
|
|
21
31
|
* @UseGuards(AuthGuard)
|
|
22
32
|
* @Get('profile')
|
|
23
|
-
* getProfile(@CurrentUser() user:
|
|
24
|
-
* return user;
|
|
33
|
+
* getProfile(@CurrentUser() user: UserProfileResponseDto) {
|
|
34
|
+
* return user; // user มาจาก Portal API (ผ่าน Guard validation)
|
|
25
35
|
* }
|
|
36
|
+
*
|
|
37
|
+
* // Frontend: ไม่ต้องใช้ - ใช้ AuthClient แทน
|
|
26
38
|
* ```
|
|
27
39
|
*/
|
|
28
40
|
export declare function createAuthGuard(config: Omit<MiddlewareConfig, 'optional'>): {
|
|
@@ -33,14 +45,26 @@ export declare function createAuthGuard(config: Omit<MiddlewareConfig, 'optional
|
|
|
33
45
|
/**
|
|
34
46
|
* Optional Auth Guard - Does not block if no token
|
|
35
47
|
*
|
|
48
|
+
* @platform **Backend only** - สำหรับ NestJS applications
|
|
49
|
+
* @platform **Frontend**: ไม่ต้องใช้ - Frontend ใช้ `AuthClient` แทน
|
|
50
|
+
*
|
|
51
|
+
* Similar to `createAuthGuard()` แต่ไม่ block request ถ้าไม่มี token.
|
|
52
|
+
* ใช้สำหรับ routes ที่ต้องการ user ถ้ามี แต่ยังทำงานได้ถ้าไม่มี.
|
|
53
|
+
*
|
|
54
|
+
* @param config - Configuration สำหรับ auth guard
|
|
55
|
+
* @returns NestJS Guard class ที่สามารถใช้กับ `@UseGuards()` decorator
|
|
56
|
+
*
|
|
36
57
|
* @example
|
|
37
58
|
* ```typescript
|
|
59
|
+
* // Backend: Optional auth guard
|
|
38
60
|
* @UseGuards(OptionalAuthGuard)
|
|
39
61
|
* @Get('posts')
|
|
40
|
-
* getPosts(@CurrentUser() user:
|
|
62
|
+
* getPosts(@CurrentUser() user: UserProfileResponseDto | null) {
|
|
41
63
|
* // user may be null
|
|
42
64
|
* return user ? 'Your posts' : 'Public posts';
|
|
43
65
|
* }
|
|
66
|
+
*
|
|
67
|
+
* // Frontend: ไม่ต้องใช้ - ใช้ AuthClient แทน
|
|
44
68
|
* ```
|
|
45
69
|
*/
|
|
46
70
|
export declare function createOptionalAuthGuard(config: Omit<MiddlewareConfig, 'optional'>): {
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"nestjs.guard.d.ts","sourceRoot":"","sources":["../../src/middleware/nestjs.guard.ts"],"names":[],"mappings":"AAAA;;;;GAIG;AAEH,OAAO,EAAE,gBAAgB,EAAE,MAAM,SAAS,CAAC;AAI3C
|
|
1
|
+
{"version":3,"file":"nestjs.guard.d.ts","sourceRoot":"","sources":["../../src/middleware/nestjs.guard.ts"],"names":[],"mappings":"AAAA;;;;GAIG;AAEH,OAAO,EAAE,gBAAgB,EAAE,MAAM,SAAS,CAAC;AAI3C;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;GAgCG;AACH,wBAAgB,eAAe,CAAC,MAAM,EAAE,IAAI,CAAC,gBAAgB,EAAE,UAAU,CAAC;;6BAO3C,GAAG,GAAG,QAAQ,OAAO,CAAC;;EAoBpD;AAED;;;;;;;;;;;;;;;;;;;;;;;;GAwBG;AACH,wBAAgB,uBAAuB,CAAC,MAAM,EAAE,IAAI,CAAC,gBAAgB,EAAE,UAAU,CAAC;;6BAOnD,GAAG,GAAG,QAAQ,OAAO,CAAC;;EAepD;AAED;;GAEG;AACH,wBAAgB,kBAAkB,CAAC,KAAK,CAAC,EAAE,MAAM,QAMhD"}
|
|
@@ -11,22 +11,34 @@ const user_cache_1 = require("./shared/user-cache");
|
|
|
11
11
|
/**
|
|
12
12
|
* NestJS Auth Guard
|
|
13
13
|
*
|
|
14
|
+
* @platform **Backend only** - สำหรับ NestJS applications
|
|
15
|
+
* @platform **Frontend**: ไม่ต้องใช้ - Frontend ใช้ `AuthClient` แทน
|
|
16
|
+
*
|
|
17
|
+
* Validate token จาก request header และ attach user profile ลง `request.user`.
|
|
18
|
+
* Backend ไม่ต้อง refresh token - Frontend เป็นคน refresh และส่ง token ใหม่มาใน request ถัดไป.
|
|
19
|
+
*
|
|
20
|
+
* @param config - Configuration สำหรับ auth guard
|
|
21
|
+
* @returns NestJS Guard class ที่สามารถใช้กับ `@UseGuards()` decorator
|
|
22
|
+
*
|
|
14
23
|
* @example
|
|
15
24
|
* ```typescript
|
|
16
|
-
* // In your auth.guard.ts
|
|
25
|
+
* // Backend: In your auth.guard.ts
|
|
17
26
|
* import { createAuthGuard } from 'win-portal-auth-sdk';
|
|
18
27
|
*
|
|
19
28
|
* export const AuthGuard = createAuthGuard({
|
|
20
|
-
* baseURL: process.env.
|
|
21
|
-
* apiKey: process.env.
|
|
29
|
+
* baseURL: process.env.PORTAL_API_URL!,
|
|
30
|
+
* apiKey: process.env.PORTAL_API_KEY!,
|
|
31
|
+
* cacheTimeout: 300, // Cache user profile 5 นาที (default)
|
|
22
32
|
* });
|
|
23
33
|
*
|
|
24
34
|
* // In your controller
|
|
25
35
|
* @UseGuards(AuthGuard)
|
|
26
36
|
* @Get('profile')
|
|
27
|
-
* getProfile(@CurrentUser() user:
|
|
28
|
-
* return user;
|
|
37
|
+
* getProfile(@CurrentUser() user: UserProfileResponseDto) {
|
|
38
|
+
* return user; // user มาจาก Portal API (ผ่าน Guard validation)
|
|
29
39
|
* }
|
|
40
|
+
*
|
|
41
|
+
* // Frontend: ไม่ต้องใช้ - ใช้ AuthClient แทน
|
|
30
42
|
* ```
|
|
31
43
|
*/
|
|
32
44
|
function createAuthGuard(config) {
|
|
@@ -55,14 +67,26 @@ exports.createAuthGuard = createAuthGuard;
|
|
|
55
67
|
/**
|
|
56
68
|
* Optional Auth Guard - Does not block if no token
|
|
57
69
|
*
|
|
70
|
+
* @platform **Backend only** - สำหรับ NestJS applications
|
|
71
|
+
* @platform **Frontend**: ไม่ต้องใช้ - Frontend ใช้ `AuthClient` แทน
|
|
72
|
+
*
|
|
73
|
+
* Similar to `createAuthGuard()` แต่ไม่ block request ถ้าไม่มี token.
|
|
74
|
+
* ใช้สำหรับ routes ที่ต้องการ user ถ้ามี แต่ยังทำงานได้ถ้าไม่มี.
|
|
75
|
+
*
|
|
76
|
+
* @param config - Configuration สำหรับ auth guard
|
|
77
|
+
* @returns NestJS Guard class ที่สามารถใช้กับ `@UseGuards()` decorator
|
|
78
|
+
*
|
|
58
79
|
* @example
|
|
59
80
|
* ```typescript
|
|
81
|
+
* // Backend: Optional auth guard
|
|
60
82
|
* @UseGuards(OptionalAuthGuard)
|
|
61
83
|
* @Get('posts')
|
|
62
|
-
* getPosts(@CurrentUser() user:
|
|
84
|
+
* getPosts(@CurrentUser() user: UserProfileResponseDto | null) {
|
|
63
85
|
* // user may be null
|
|
64
86
|
* return user ? 'Your posts' : 'Public posts';
|
|
65
87
|
* }
|
|
88
|
+
*
|
|
89
|
+
* // Frontend: ไม่ต้องใช้ - ใช้ AuthClient แทน
|
|
66
90
|
* ```
|
|
67
91
|
*/
|
|
68
92
|
function createOptionalAuthGuard(config) {
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "win-portal-auth-sdk",
|
|
3
|
-
"version": "1.6.
|
|
3
|
+
"version": "1.6.5",
|
|
4
4
|
"description": "Shared authentication SDK for Win Portal applications with JWT and OAuth support",
|
|
5
5
|
"main": "dist/index.js",
|
|
6
6
|
"types": "dist/index.d.ts",
|
|
@@ -47,6 +47,14 @@
|
|
|
47
47
|
"dependencies": {
|
|
48
48
|
"axios": "^1.6.0"
|
|
49
49
|
},
|
|
50
|
+
"peerDependencies": {
|
|
51
|
+
"socket.io-client": "^4.0.0"
|
|
52
|
+
},
|
|
53
|
+
"peerDependenciesMeta": {
|
|
54
|
+
"socket.io-client": {
|
|
55
|
+
"optional": true
|
|
56
|
+
}
|
|
57
|
+
},
|
|
50
58
|
"devDependencies": {
|
|
51
59
|
"@types/node": "^20.0.0",
|
|
52
60
|
"typescript": "^5.3.0"
|