@opensourcekd/ng-common-libs 1.1.8

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.cjs ADDED
@@ -0,0 +1,1277 @@
1
+ 'use strict';
2
+
3
+ var rxjs = require('rxjs');
4
+ var operators = require('rxjs/operators');
5
+ var core = require('@angular/core');
6
+ var router = require('@angular/router');
7
+ var http = require('@angular/common/http');
8
+
9
+ /**
10
+ * EventBus - A centralized event bus for application-wide communication
11
+ * Framework-agnostic implementation using only RxJS
12
+ *
13
+ * @example
14
+ * ```typescript
15
+ * // Create an instance
16
+ * const eventBus = new EventBus();
17
+ *
18
+ * // Emit an event
19
+ * eventBus.emit('user:login', { userId: '123', username: 'john' });
20
+ *
21
+ * // Subscribe to an event
22
+ * eventBus.on('user:login').subscribe(data => {
23
+ * console.log('User logged in:', data);
24
+ * });
25
+ * ```
26
+ */
27
+ class EventBus {
28
+ eventSubject = new rxjs.Subject();
29
+ /**
30
+ * Emit an event with optional data
31
+ * @param eventType - The type/name of the event
32
+ * @param data - Optional data to send with the event
33
+ */
34
+ emit(eventType, data) {
35
+ this.eventSubject.next({
36
+ type: eventType,
37
+ data,
38
+ timestamp: Date.now()
39
+ });
40
+ }
41
+ /**
42
+ * Subscribe to a specific event type
43
+ * @param eventType - The type/name of the event to listen for
44
+ * @returns Observable that emits the event data
45
+ */
46
+ on(eventType) {
47
+ return this.eventSubject.asObservable().pipe(operators.filter(event => event.type === eventType), operators.map(event => event.data));
48
+ }
49
+ /**
50
+ * Subscribe to multiple event types
51
+ * @param eventTypes - Array of event types to listen for
52
+ * @returns Observable that emits the full event payload
53
+ */
54
+ onMultiple(eventTypes) {
55
+ return this.eventSubject.asObservable().pipe(operators.filter(event => eventTypes.includes(event.type)));
56
+ }
57
+ /**
58
+ * Subscribe to all events
59
+ * @returns Observable that emits all event payloads
60
+ */
61
+ onAll() {
62
+ return this.eventSubject.asObservable();
63
+ }
64
+ }
65
+
66
+ /**
67
+ * TokenManager - Manages authentication tokens
68
+ * Framework-agnostic implementation using browser storage APIs
69
+ * Handles storage, retrieval, and validation of JWT tokens
70
+ *
71
+ * @example
72
+ * ```typescript
73
+ * const tokenManager = new TokenManager();
74
+ *
75
+ * // Store a token
76
+ * tokenManager.setToken('your-jwt-token');
77
+ *
78
+ * // Check if authenticated
79
+ * if (tokenManager.isAuthenticated()) {
80
+ * const userData = tokenManager.getUserFromToken();
81
+ * }
82
+ * ```
83
+ */
84
+ class TokenManager {
85
+ TOKEN_KEY = 'auth_token';
86
+ REFRESH_TOKEN_KEY = 'refresh_token';
87
+ useSessionStorage = false;
88
+ /**
89
+ * Configure token manager
90
+ */
91
+ configure(config) {
92
+ if (config.tokenKey) {
93
+ this.TOKEN_KEY = config.tokenKey;
94
+ }
95
+ if (config.refreshTokenKey) {
96
+ this.REFRESH_TOKEN_KEY = config.refreshTokenKey;
97
+ }
98
+ if (config.useSessionStorage !== undefined) {
99
+ this.useSessionStorage = config.useSessionStorage;
100
+ }
101
+ }
102
+ /**
103
+ * Get the storage mechanism based on configuration
104
+ */
105
+ getStorage() {
106
+ return this.useSessionStorage ? sessionStorage : localStorage;
107
+ }
108
+ /**
109
+ * Set authentication token
110
+ */
111
+ setToken(token) {
112
+ this.getStorage().setItem(this.TOKEN_KEY, token);
113
+ }
114
+ /**
115
+ * Get authentication token
116
+ */
117
+ getToken() {
118
+ return this.getStorage().getItem(this.TOKEN_KEY);
119
+ }
120
+ /**
121
+ * Remove authentication token
122
+ */
123
+ removeToken() {
124
+ this.getStorage().removeItem(this.TOKEN_KEY);
125
+ }
126
+ /**
127
+ * Set refresh token
128
+ */
129
+ setRefreshToken(token) {
130
+ this.getStorage().setItem(this.REFRESH_TOKEN_KEY, token);
131
+ }
132
+ /**
133
+ * Get refresh token
134
+ */
135
+ getRefreshToken() {
136
+ return this.getStorage().getItem(this.REFRESH_TOKEN_KEY);
137
+ }
138
+ /**
139
+ * Remove refresh token
140
+ */
141
+ removeRefreshToken() {
142
+ this.getStorage().removeItem(this.REFRESH_TOKEN_KEY);
143
+ }
144
+ /**
145
+ * Clear all tokens
146
+ */
147
+ clearTokens() {
148
+ this.removeToken();
149
+ this.removeRefreshToken();
150
+ }
151
+ /**
152
+ * Check if token exists
153
+ */
154
+ hasToken() {
155
+ return !!this.getToken();
156
+ }
157
+ /**
158
+ * Decode JWT token (without verification)
159
+ * @param token - JWT token to decode
160
+ * @returns Decoded token payload or null if invalid
161
+ */
162
+ decodeToken(token) {
163
+ const tokenToDecode = token || this.getToken();
164
+ if (!tokenToDecode)
165
+ return null;
166
+ try {
167
+ const parts = tokenToDecode.split('.');
168
+ if (parts.length !== 3)
169
+ return null;
170
+ const payload = parts[1];
171
+ const decoded = JSON.parse(atob(payload.replace(/-/g, '+').replace(/_/g, '/')));
172
+ return decoded;
173
+ }
174
+ catch (error) {
175
+ console.error('Error decoding token:', error);
176
+ return null;
177
+ }
178
+ }
179
+ /**
180
+ * Check if token is expired
181
+ * @param token - Optional token to check (defaults to stored token)
182
+ * @returns true if token is expired or invalid
183
+ */
184
+ isTokenExpired(token) {
185
+ const decoded = this.decodeToken(token);
186
+ if (!decoded || !decoded.exp)
187
+ return true;
188
+ const expirationDate = new Date(decoded.exp * 1000);
189
+ return expirationDate <= new Date();
190
+ }
191
+ /**
192
+ * Check if user is authenticated (has valid, non-expired token)
193
+ */
194
+ isAuthenticated() {
195
+ return this.hasToken() && !this.isTokenExpired();
196
+ }
197
+ /**
198
+ * Get token expiration date
199
+ */
200
+ getTokenExpirationDate(token) {
201
+ const decoded = this.decodeToken(token);
202
+ if (!decoded || !decoded.exp)
203
+ return null;
204
+ return new Date(decoded.exp * 1000);
205
+ }
206
+ /**
207
+ * Get user data from token
208
+ */
209
+ getUserFromToken(token) {
210
+ return this.decodeToken(token);
211
+ }
212
+ }
213
+
214
+ /**
215
+ * StorageManager - Type-safe wrapper for browser storage
216
+ * Framework-agnostic implementation using browser storage APIs
217
+ * Provides JSON serialization/deserialization and error handling
218
+ *
219
+ * @example
220
+ * ```typescript
221
+ * const storage = new StorageManager();
222
+ *
223
+ * // Store data
224
+ * storage.setLocal('user-prefs', { theme: 'dark', lang: 'en' });
225
+ *
226
+ * // Retrieve data
227
+ * const prefs = storage.getLocal('user-prefs');
228
+ *
229
+ * // With expiration
230
+ * storage.setWithExpiration('temp-data', someData, 3600000); // 1 hour
231
+ * ```
232
+ */
233
+ class StorageManager {
234
+ /**
235
+ * Set item in localStorage with JSON serialization
236
+ */
237
+ setLocal(key, value) {
238
+ try {
239
+ const serialized = JSON.stringify(value);
240
+ localStorage.setItem(key, serialized);
241
+ return true;
242
+ }
243
+ catch (error) {
244
+ console.error('Error setting localStorage item:', error);
245
+ return false;
246
+ }
247
+ }
248
+ /**
249
+ * Get item from localStorage with JSON deserialization
250
+ */
251
+ getLocal(key, defaultValue) {
252
+ try {
253
+ const item = localStorage.getItem(key);
254
+ if (item === null) {
255
+ return defaultValue !== undefined ? defaultValue : null;
256
+ }
257
+ return JSON.parse(item);
258
+ }
259
+ catch (error) {
260
+ console.error('Error getting localStorage item:', error);
261
+ return defaultValue !== undefined ? defaultValue : null;
262
+ }
263
+ }
264
+ /**
265
+ * Remove item from localStorage
266
+ */
267
+ removeLocal(key) {
268
+ try {
269
+ localStorage.removeItem(key);
270
+ }
271
+ catch (error) {
272
+ console.error('Error removing localStorage item:', error);
273
+ }
274
+ }
275
+ /**
276
+ * Clear all localStorage items
277
+ */
278
+ clearLocal() {
279
+ try {
280
+ localStorage.clear();
281
+ }
282
+ catch (error) {
283
+ console.error('Error clearing localStorage:', error);
284
+ }
285
+ }
286
+ /**
287
+ * Check if key exists in localStorage
288
+ */
289
+ hasLocal(key) {
290
+ try {
291
+ return localStorage.getItem(key) !== null;
292
+ }
293
+ catch (error) {
294
+ console.error('Error checking localStorage key:', error);
295
+ return false;
296
+ }
297
+ }
298
+ /**
299
+ * Get all localStorage keys
300
+ */
301
+ getLocalKeys() {
302
+ try {
303
+ return Object.keys(localStorage);
304
+ }
305
+ catch (error) {
306
+ console.error('Error getting localStorage keys:', error);
307
+ return [];
308
+ }
309
+ }
310
+ /**
311
+ * Set item in sessionStorage with JSON serialization
312
+ */
313
+ setSession(key, value) {
314
+ try {
315
+ const serialized = JSON.stringify(value);
316
+ sessionStorage.setItem(key, serialized);
317
+ return true;
318
+ }
319
+ catch (error) {
320
+ console.error('Error setting sessionStorage item:', error);
321
+ return false;
322
+ }
323
+ }
324
+ /**
325
+ * Get item from sessionStorage with JSON deserialization
326
+ */
327
+ getSession(key, defaultValue) {
328
+ try {
329
+ const item = sessionStorage.getItem(key);
330
+ if (item === null) {
331
+ return defaultValue !== undefined ? defaultValue : null;
332
+ }
333
+ return JSON.parse(item);
334
+ }
335
+ catch (error) {
336
+ console.error('Error getting sessionStorage item:', error);
337
+ return defaultValue !== undefined ? defaultValue : null;
338
+ }
339
+ }
340
+ /**
341
+ * Remove item from sessionStorage
342
+ */
343
+ removeSession(key) {
344
+ try {
345
+ sessionStorage.removeItem(key);
346
+ }
347
+ catch (error) {
348
+ console.error('Error removing sessionStorage item:', error);
349
+ }
350
+ }
351
+ /**
352
+ * Clear all sessionStorage items
353
+ */
354
+ clearSession() {
355
+ try {
356
+ sessionStorage.clear();
357
+ }
358
+ catch (error) {
359
+ console.error('Error clearing sessionStorage:', error);
360
+ }
361
+ }
362
+ /**
363
+ * Check if key exists in sessionStorage
364
+ */
365
+ hasSession(key) {
366
+ try {
367
+ return sessionStorage.getItem(key) !== null;
368
+ }
369
+ catch (error) {
370
+ console.error('Error checking sessionStorage key:', error);
371
+ return false;
372
+ }
373
+ }
374
+ /**
375
+ * Get all sessionStorage keys
376
+ */
377
+ getSessionKeys() {
378
+ try {
379
+ return Object.keys(sessionStorage);
380
+ }
381
+ catch (error) {
382
+ console.error('Error getting sessionStorage keys:', error);
383
+ return [];
384
+ }
385
+ }
386
+ /**
387
+ * Set item with expiration time
388
+ * @param key - Storage key
389
+ * @param value - Value to store
390
+ * @param expirationMs - Expiration time in milliseconds
391
+ * @param useSession - Use sessionStorage instead of localStorage
392
+ */
393
+ setWithExpiration(key, value, expirationMs, useSession = false) {
394
+ const item = {
395
+ value,
396
+ expiration: Date.now() + expirationMs
397
+ };
398
+ return useSession
399
+ ? this.setSession(key, item)
400
+ : this.setLocal(key, item);
401
+ }
402
+ /**
403
+ * Get item with expiration check
404
+ * Returns null if item is expired
405
+ */
406
+ getWithExpiration(key, useSession = false) {
407
+ const item = useSession
408
+ ? this.getSession(key)
409
+ : this.getLocal(key);
410
+ if (!item)
411
+ return null;
412
+ if (Date.now() > item.expiration) {
413
+ // Item expired, remove it
414
+ if (useSession) {
415
+ this.removeSession(key);
416
+ }
417
+ else {
418
+ this.removeLocal(key);
419
+ }
420
+ return null;
421
+ }
422
+ return item.value;
423
+ }
424
+ }
425
+
426
+ /**
427
+ * Log level enum
428
+ */
429
+ exports.LogLevel = void 0;
430
+ (function (LogLevel) {
431
+ LogLevel[LogLevel["DEBUG"] = 0] = "DEBUG";
432
+ LogLevel[LogLevel["INFO"] = 1] = "INFO";
433
+ LogLevel[LogLevel["WARN"] = 2] = "WARN";
434
+ LogLevel[LogLevel["ERROR"] = 3] = "ERROR";
435
+ LogLevel[LogLevel["NONE"] = 4] = "NONE";
436
+ })(exports.LogLevel || (exports.LogLevel = {}));
437
+ /**
438
+ * Logger - Centralized logging utility
439
+ * Framework-agnostic implementation using browser console APIs
440
+ * Supports different log levels and can be configured globally
441
+ *
442
+ * @example
443
+ * ```typescript
444
+ * const logger = new Logger();
445
+ *
446
+ * // Configure
447
+ * logger.configure({
448
+ * level: LogLevel.DEBUG,
449
+ * enableTimestamp: true,
450
+ * prefix: 'MyApp'
451
+ * });
452
+ *
453
+ * // Use
454
+ * logger.info('User logged in', { userId: '123' });
455
+ * logger.error('Failed to load data', error);
456
+ * ```
457
+ */
458
+ class Logger {
459
+ config = {
460
+ level: exports.LogLevel.INFO,
461
+ enableTimestamp: true,
462
+ enableStackTrace: false,
463
+ prefix: ''
464
+ };
465
+ /**
466
+ * Configure the logger
467
+ */
468
+ configure(config) {
469
+ this.config = { ...this.config, ...config };
470
+ }
471
+ /**
472
+ * Set log level
473
+ */
474
+ setLevel(level) {
475
+ this.config.level = level;
476
+ }
477
+ /**
478
+ * Get current log level
479
+ */
480
+ getLevel() {
481
+ return this.config.level;
482
+ }
483
+ /**
484
+ * Format log message with timestamp and prefix
485
+ */
486
+ formatMessage(message, level) {
487
+ const parts = [];
488
+ if (this.config.enableTimestamp) {
489
+ parts.push(`[${new Date().toISOString()}]`);
490
+ }
491
+ if (this.config.prefix) {
492
+ parts.push(`[${this.config.prefix}]`);
493
+ }
494
+ parts.push(`[${level}]`);
495
+ parts.push(message);
496
+ return parts.join(' ');
497
+ }
498
+ /**
499
+ * Check if log level should be logged
500
+ */
501
+ shouldLog(level) {
502
+ return level >= this.config.level;
503
+ }
504
+ /**
505
+ * Log debug message
506
+ */
507
+ debug(message, ...args) {
508
+ if (this.shouldLog(exports.LogLevel.DEBUG)) {
509
+ console.debug(this.formatMessage(message, 'DEBUG'), ...args);
510
+ }
511
+ }
512
+ /**
513
+ * Log info message
514
+ */
515
+ info(message, ...args) {
516
+ if (this.shouldLog(exports.LogLevel.INFO)) {
517
+ console.info(this.formatMessage(message, 'INFO'), ...args);
518
+ }
519
+ }
520
+ /**
521
+ * Log warning message
522
+ */
523
+ warn(message, ...args) {
524
+ if (this.shouldLog(exports.LogLevel.WARN)) {
525
+ console.warn(this.formatMessage(message, 'WARN'), ...args);
526
+ }
527
+ }
528
+ /**
529
+ * Log error message
530
+ */
531
+ error(message, error, ...args) {
532
+ if (this.shouldLog(exports.LogLevel.ERROR)) {
533
+ console.error(this.formatMessage(message, 'ERROR'), ...args);
534
+ if (error) {
535
+ console.error(error);
536
+ if (this.config.enableStackTrace && error?.stack) {
537
+ console.error('Stack trace:', error.stack);
538
+ }
539
+ }
540
+ }
541
+ }
542
+ /**
543
+ * Log a group of messages
544
+ */
545
+ group(label, callback) {
546
+ if (this.shouldLog(exports.LogLevel.INFO)) {
547
+ console.group(this.formatMessage(label, 'GROUP'));
548
+ callback();
549
+ console.groupEnd();
550
+ }
551
+ }
552
+ /**
553
+ * Log a collapsed group of messages
554
+ */
555
+ groupCollapsed(label, callback) {
556
+ if (this.shouldLog(exports.LogLevel.INFO)) {
557
+ console.groupCollapsed(this.formatMessage(label, 'GROUP'));
558
+ callback();
559
+ console.groupEnd();
560
+ }
561
+ }
562
+ /**
563
+ * Log a table (useful for arrays of objects)
564
+ */
565
+ table(data, columns) {
566
+ if (this.shouldLog(exports.LogLevel.INFO)) {
567
+ console.table(data, columns);
568
+ }
569
+ }
570
+ /**
571
+ * Log execution time of a function
572
+ */
573
+ async time(label, fn) {
574
+ const start = performance.now();
575
+ try {
576
+ const result = await fn();
577
+ const end = performance.now();
578
+ const duration = (end - start).toFixed(2);
579
+ this.info(`${label} completed in ${duration}ms`);
580
+ return result;
581
+ }
582
+ catch (error) {
583
+ const end = performance.now();
584
+ const duration = (end - start).toFixed(2);
585
+ this.error(`${label} failed after ${duration}ms`, error);
586
+ throw error;
587
+ }
588
+ }
589
+ }
590
+
591
+ /******************************************************************************
592
+ Copyright (c) Microsoft Corporation.
593
+
594
+ Permission to use, copy, modify, and/or distribute this software for any
595
+ purpose with or without fee is hereby granted.
596
+
597
+ THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES WITH
598
+ REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY
599
+ AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY SPECIAL, DIRECT,
600
+ INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM
601
+ LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR
602
+ OTHER TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR
603
+ PERFORMANCE OF THIS SOFTWARE.
604
+ ***************************************************************************** */
605
+ /* global Reflect, Promise, SuppressedError, Symbol, Iterator */
606
+
607
+
608
+ function __decorate(decorators, target, key, desc) {
609
+ var c = arguments.length, r = c < 3 ? target : desc === null ? desc = Object.getOwnPropertyDescriptor(target, key) : desc, d;
610
+ if (typeof Reflect === "object" && typeof Reflect.decorate === "function") r = Reflect.decorate(decorators, target, key, desc);
611
+ else for (var i = decorators.length - 1; i >= 0; i--) if (d = decorators[i]) r = (c < 3 ? d(r) : c > 3 ? d(target, key, r) : d(target, key)) || r;
612
+ return c > 3 && r && Object.defineProperty(target, key, r), r;
613
+ }
614
+
615
+ function __metadata(metadataKey, metadataValue) {
616
+ if (typeof Reflect === "object" && typeof Reflect.metadata === "function") return Reflect.metadata(metadataKey, metadataValue);
617
+ }
618
+
619
+ typeof SuppressedError === "function" ? SuppressedError : function (error, suppressed, message) {
620
+ var e = new Error(message);
621
+ return e.name = "SuppressedError", e.error = error, e.suppressed = suppressed, e;
622
+ };
623
+
624
+ /**
625
+ * NgEventEmitter - Angular service wrapper for EventBus
626
+ * Provides Angular dependency injection support for the framework-agnostic EventBus
627
+ *
628
+ * @example
629
+ * ```typescript
630
+ * import { Component, inject } from '@angular/core';
631
+ * import { NgEventEmitter } from 'common-libs';
632
+ *
633
+ * @Component({
634
+ * selector: 'app-example',
635
+ * template: '...'
636
+ * })
637
+ * export class ExampleComponent {
638
+ * private eventEmitter = inject(NgEventEmitter);
639
+ *
640
+ * ngOnInit() {
641
+ * this.eventEmitter.on('user:login').subscribe(data => {
642
+ * console.log('User logged in:', data);
643
+ * });
644
+ * }
645
+ *
646
+ * login() {
647
+ * this.eventEmitter.emit('user:login', { userId: '123' });
648
+ * }
649
+ * }
650
+ * ```
651
+ */
652
+ exports.NgEventEmitter = class NgEventEmitter extends EventBus {
653
+ constructor() {
654
+ super();
655
+ }
656
+ };
657
+ exports.NgEventEmitter = __decorate([
658
+ core.Injectable({
659
+ providedIn: 'root'
660
+ }),
661
+ __metadata("design:paramtypes", [])
662
+ ], exports.NgEventEmitter);
663
+
664
+ /**
665
+ * TokenService - Angular service wrapper for TokenManager
666
+ * Provides Angular dependency injection support for the framework-agnostic TokenManager
667
+ *
668
+ * @example
669
+ * ```typescript
670
+ * import { Component, inject } from '@angular/core';
671
+ * import { TokenService } from 'common-libs';
672
+ *
673
+ * export class AuthService {
674
+ * private tokenService = inject(TokenService);
675
+ *
676
+ * login(token: string) {
677
+ * this.tokenService.setToken(token);
678
+ * }
679
+ *
680
+ * isAuthenticated(): boolean {
681
+ * return this.tokenService.isAuthenticated();
682
+ * }
683
+ * }
684
+ * ```
685
+ */
686
+ exports.TokenService = class TokenService extends TokenManager {
687
+ constructor() {
688
+ console.log("Hey Jude in TokenService of common-libs");
689
+ super();
690
+ }
691
+ };
692
+ exports.TokenService = __decorate([
693
+ core.Injectable({
694
+ providedIn: 'root'
695
+ }),
696
+ __metadata("design:paramtypes", [])
697
+ ], exports.TokenService);
698
+
699
+ /**
700
+ * StorageService - Angular service wrapper for StorageManager
701
+ * Provides Angular dependency injection support for the framework-agnostic StorageManager
702
+ *
703
+ * @example
704
+ * ```typescript
705
+ * import { Component, inject } from '@angular/core';
706
+ * import { StorageService } from 'common-libs';
707
+ *
708
+ * export class UserPreferencesService {
709
+ * private storage = inject(StorageService);
710
+ *
711
+ * savePreferences(prefs: any) {
712
+ * this.storage.setLocal('user-prefs', prefs);
713
+ * }
714
+ *
715
+ * getPreferences() {
716
+ * return this.storage.getLocal('user-prefs');
717
+ * }
718
+ * }
719
+ * ```
720
+ */
721
+ exports.StorageService = class StorageService extends StorageManager {
722
+ constructor() {
723
+ super();
724
+ }
725
+ };
726
+ exports.StorageService = __decorate([
727
+ core.Injectable({
728
+ providedIn: 'root'
729
+ }),
730
+ __metadata("design:paramtypes", [])
731
+ ], exports.StorageService);
732
+
733
+ /**
734
+ * LoggerService - Angular service wrapper for Logger
735
+ * Provides Angular dependency injection support for the framework-agnostic Logger
736
+ *
737
+ * @example
738
+ * ```typescript
739
+ * import { Component, inject } from '@angular/core';
740
+ * import { LoggerService, LogLevel } from 'common-libs';
741
+ *
742
+ * export class MyService {
743
+ * private logger = inject(LoggerService);
744
+ *
745
+ * constructor() {
746
+ * this.logger.configure({
747
+ * level: LogLevel.DEBUG,
748
+ * prefix: 'MyApp'
749
+ * });
750
+ * }
751
+ *
752
+ * doSomething() {
753
+ * this.logger.info('Doing something');
754
+ * }
755
+ * }
756
+ * ```
757
+ */
758
+ exports.LoggerService = class LoggerService extends Logger {
759
+ constructor() {
760
+ super();
761
+ }
762
+ };
763
+ exports.LoggerService = __decorate([
764
+ core.Injectable({
765
+ providedIn: 'root'
766
+ }),
767
+ __metadata("design:paramtypes", [])
768
+ ], exports.LoggerService);
769
+
770
+ /**
771
+ * PermissionService - Manages user permissions and roles
772
+ */
773
+ exports.PermissionService = class PermissionService {
774
+ tokenService = core.inject(exports.TokenService);
775
+ /**
776
+ * Check if user has a specific permission
777
+ */
778
+ hasPermission(permission) {
779
+ const user = this.tokenService.getUserFromToken();
780
+ const permissions = user?.permissions || [];
781
+ return permissions.includes(permission);
782
+ }
783
+ /**
784
+ * Check if user has any of the specified permissions
785
+ */
786
+ hasAnyPermission(permissions) {
787
+ return permissions.some(permission => this.hasPermission(permission));
788
+ }
789
+ /**
790
+ * Check if user has all of the specified permissions
791
+ */
792
+ hasAllPermissions(permissions) {
793
+ return permissions.every(permission => this.hasPermission(permission));
794
+ }
795
+ /**
796
+ * Check if user has a specific role
797
+ */
798
+ hasRole(role) {
799
+ const user = this.tokenService.getUserFromToken();
800
+ const roles = user?.roles || [];
801
+ return roles.includes(role);
802
+ }
803
+ /**
804
+ * Check if user has any of the specified roles
805
+ */
806
+ hasAnyRole(roles) {
807
+ return roles.some(role => this.hasRole(role));
808
+ }
809
+ /**
810
+ * Check if user has all of the specified roles
811
+ */
812
+ hasAllRoles(roles) {
813
+ return roles.every(role => this.hasRole(role));
814
+ }
815
+ /**
816
+ * Get all user permissions
817
+ */
818
+ getPermissions() {
819
+ const user = this.tokenService.getUserFromToken();
820
+ return user?.permissions || [];
821
+ }
822
+ /**
823
+ * Get all user roles
824
+ */
825
+ getRoles() {
826
+ const user = this.tokenService.getUserFromToken();
827
+ return user?.roles || [];
828
+ }
829
+ /**
830
+ * Get user ID from token
831
+ */
832
+ getUserId() {
833
+ const user = this.tokenService.getUserFromToken();
834
+ return user?.sub || user?.id || user?.userId || null;
835
+ }
836
+ /**
837
+ * Get username from token
838
+ */
839
+ getUsername() {
840
+ const user = this.tokenService.getUserFromToken();
841
+ return user?.username || user?.name || user?.email || null;
842
+ }
843
+ /**
844
+ * Get user email from token
845
+ */
846
+ getUserEmail() {
847
+ const user = this.tokenService.getUserFromToken();
848
+ return user?.email || null;
849
+ }
850
+ };
851
+ exports.PermissionService = __decorate([
852
+ core.Injectable({
853
+ providedIn: 'root'
854
+ })
855
+ ], exports.PermissionService);
856
+
857
+ /**
858
+ * Factory function to create an auth guard with configuration
859
+ *
860
+ * @example
861
+ * ```typescript
862
+ * // In routes
863
+ * {
864
+ * path: 'dashboard',
865
+ * component: DashboardComponent,
866
+ * canActivate: [createAuthGuard({ redirectUrl: '/login' })]
867
+ * }
868
+ * ```
869
+ */
870
+ function createAuthGuard(config = {}) {
871
+ return (route, state) => {
872
+ const tokenService = core.inject(exports.TokenService);
873
+ const router$1 = core.inject(router.Router);
874
+ const redirectUrl = config.redirectUrl || '/login';
875
+ const checkExpiration = config.checkExpiration !== false;
876
+ const hasToken = tokenService.hasToken();
877
+ const isExpired = checkExpiration ? tokenService.isTokenExpired() : false;
878
+ if (hasToken && !isExpired) {
879
+ return true;
880
+ }
881
+ // Store the attempted URL for redirecting after login
882
+ const returnUrl = state.url;
883
+ router$1.navigate([redirectUrl], {
884
+ queryParams: { returnUrl },
885
+ queryParamsHandling: 'merge'
886
+ });
887
+ return false;
888
+ };
889
+ }
890
+ /**
891
+ * Default auth guard - redirects to '/login' if not authenticated
892
+ */
893
+ const authGuard = createAuthGuard();
894
+ /**
895
+ * Permission-based guard factory
896
+ * Checks if user has required permissions from token
897
+ *
898
+ * @example
899
+ * ```typescript
900
+ * {
901
+ * path: 'admin',
902
+ * component: AdminComponent,
903
+ * canActivate: [createPermissionGuard(['admin', 'editor'])]
904
+ * }
905
+ * ```
906
+ */
907
+ function createPermissionGuard(requiredPermissions, config = {}) {
908
+ return (route, state) => {
909
+ const tokenService = core.inject(exports.TokenService);
910
+ const router$1 = core.inject(router.Router);
911
+ const redirectUrl = config.redirectUrl || '/unauthorized';
912
+ // First check authentication
913
+ if (!tokenService.isAuthenticated()) {
914
+ router$1.navigate(['/login'], {
915
+ queryParams: { returnUrl: state.url }
916
+ });
917
+ return false;
918
+ }
919
+ // Check permissions
920
+ const user = tokenService.getUserFromToken();
921
+ const userPermissions = user?.permissions || user?.roles || [];
922
+ const hasPermission = requiredPermissions.some(permission => userPermissions.includes(permission));
923
+ if (!hasPermission) {
924
+ router$1.navigate([redirectUrl]);
925
+ return false;
926
+ }
927
+ return true;
928
+ };
929
+ }
930
+ /**
931
+ * Role-based guard factory
932
+ * Checks if user has required role from token
933
+ *
934
+ * @example
935
+ * ```typescript
936
+ * {
937
+ * path: 'admin',
938
+ * component: AdminComponent,
939
+ * canActivate: [createRoleGuard(['admin'])]
940
+ * }
941
+ * ```
942
+ */
943
+ function createRoleGuard(requiredRoles, config = {}) {
944
+ return createPermissionGuard(requiredRoles, config);
945
+ }
946
+
947
+ const defaultConfig$1 = {
948
+ headerName: 'Authorization',
949
+ tokenPrefix: 'Bearer',
950
+ excludedUrls: []
951
+ };
952
+ let interceptorConfig = { ...defaultConfig$1 };
953
+ /**
954
+ * Configure the auth interceptor
955
+ */
956
+ function configureAuthInterceptor(config) {
957
+ interceptorConfig = { ...defaultConfig$1, ...config };
958
+ }
959
+ /**
960
+ * Auth Interceptor - Automatically adds authentication token to HTTP requests
961
+ *
962
+ * @example
963
+ * ```typescript
964
+ * // In app.config.ts
965
+ * export const appConfig: ApplicationConfig = {
966
+ * providers: [
967
+ * provideHttpClient(
968
+ * withInterceptors([authInterceptor])
969
+ * )
970
+ * ]
971
+ * };
972
+ * ```
973
+ */
974
+ const authInterceptor = (req, next) => {
975
+ const tokenService = core.inject(exports.TokenService);
976
+ const config = interceptorConfig;
977
+ // Check if URL should be excluded
978
+ const isExcluded = config.excludedUrls?.some(url => req.url.includes(url));
979
+ if (isExcluded) {
980
+ return next(req);
981
+ }
982
+ // Get token and add to request if available
983
+ const token = tokenService.getToken();
984
+ if (token) {
985
+ const authReq = req.clone({
986
+ setHeaders: {
987
+ [config.headerName]: `${config.tokenPrefix} ${token}`
988
+ }
989
+ });
990
+ return next(authReq);
991
+ }
992
+ return next(req);
993
+ };
994
+
995
+ const defaultConfig = {
996
+ enableLogging: true,
997
+ retryAttempts: 0,
998
+ retryDelay: 1000,
999
+ retryStatusCodes: [408, 429, 500, 502, 503, 504],
1000
+ excludedUrls: []
1001
+ };
1002
+ let errorConfig = { ...defaultConfig };
1003
+ /**
1004
+ * Configure the error handling interceptor
1005
+ */
1006
+ function configureErrorHandling(config) {
1007
+ errorConfig = { ...defaultConfig, ...config };
1008
+ }
1009
+ /**
1010
+ * Error handling interceptor - Handles HTTP errors and retries
1011
+ *
1012
+ * @example
1013
+ * ```typescript
1014
+ * // In app.config.ts
1015
+ * export const appConfig: ApplicationConfig = {
1016
+ * providers: [
1017
+ * provideHttpClient(
1018
+ * withInterceptors([errorHandlingInterceptor])
1019
+ * )
1020
+ * ]
1021
+ * };
1022
+ *
1023
+ * // Configure retry behavior
1024
+ * configureErrorHandling({
1025
+ * retryAttempts: 3,
1026
+ * retryDelay: 2000,
1027
+ * retryStatusCodes: [500, 502, 503]
1028
+ * });
1029
+ * ```
1030
+ */
1031
+ const errorHandlingInterceptor = (req, next) => {
1032
+ const logger = core.inject(exports.LoggerService);
1033
+ const config = errorConfig;
1034
+ // Check if URL should be excluded
1035
+ const isExcluded = config.excludedUrls?.some(url => req.url.includes(url));
1036
+ if (isExcluded) {
1037
+ return next(req);
1038
+ }
1039
+ return next(req).pipe(
1040
+ // Retry logic with exponential backoff
1041
+ operators.retry({
1042
+ count: config.retryAttempts,
1043
+ delay: (error, retryCount) => {
1044
+ // Only retry for specific status codes
1045
+ if (!config.retryStatusCodes?.includes(error.status)) {
1046
+ return rxjs.throwError(() => error);
1047
+ }
1048
+ const delay = config.retryDelay * Math.pow(2, retryCount - 1);
1049
+ if (config.enableLogging) {
1050
+ logger.warn(`Retrying request (attempt ${retryCount}) after ${delay}ms`, { url: req.url, status: error.status });
1051
+ }
1052
+ return rxjs.timer(delay);
1053
+ }
1054
+ }),
1055
+ // Error handling
1056
+ operators.catchError((error) => {
1057
+ if (config.enableLogging) {
1058
+ logger.error('HTTP request failed', error, {
1059
+ url: req.url,
1060
+ status: error.status,
1061
+ message: error.message
1062
+ });
1063
+ }
1064
+ return rxjs.throwError(() => error);
1065
+ }));
1066
+ };
1067
+ /**
1068
+ * HTTP Error class with additional context
1069
+ */
1070
+ class HttpError extends Error {
1071
+ status;
1072
+ statusText;
1073
+ url;
1074
+ originalError;
1075
+ constructor(status, statusText, url, originalError) {
1076
+ super(`HTTP ${status} ${statusText}: ${url}`);
1077
+ this.status = status;
1078
+ this.statusText = statusText;
1079
+ this.url = url;
1080
+ this.originalError = originalError;
1081
+ this.name = 'HttpError';
1082
+ }
1083
+ }
1084
+ /**
1085
+ * Parse HTTP error and return user-friendly message
1086
+ */
1087
+ function parseHttpError(error) {
1088
+ if (error.error instanceof ErrorEvent) {
1089
+ // Client-side error
1090
+ return `Network error: ${error.error.message}`;
1091
+ }
1092
+ else {
1093
+ // Server-side error
1094
+ const errorMessage = error.error?.message || error.message || 'Unknown error';
1095
+ return `Server error (${error.status}): ${errorMessage}`;
1096
+ }
1097
+ }
1098
+ /**
1099
+ * Check if error is a network error
1100
+ */
1101
+ function isNetworkError(error) {
1102
+ return error.error instanceof ErrorEvent || error.status === 0;
1103
+ }
1104
+ /**
1105
+ * Check if error is a server error (5xx)
1106
+ */
1107
+ function isServerError(error) {
1108
+ return error.status >= 500 && error.status < 600;
1109
+ }
1110
+ /**
1111
+ * Check if error is a client error (4xx)
1112
+ */
1113
+ function isClientError(error) {
1114
+ return error.status >= 400 && error.status < 500;
1115
+ }
1116
+
1117
+ const defaultCacheConfig = {
1118
+ enabled: true,
1119
+ maxAge: 60000, // 1 minute
1120
+ excludedUrls: [],
1121
+ cacheableUrls: [],
1122
+ cacheMethods: ['GET']
1123
+ };
1124
+ let cacheConfig = { ...defaultCacheConfig };
1125
+ const cache = new Map();
1126
+ const MAX_CACHE_SIZE = 100; // Maximum number of cached entries
1127
+ /**
1128
+ * Configure the caching interceptor
1129
+ */
1130
+ function configureCaching(config) {
1131
+ cacheConfig = { ...defaultCacheConfig, ...config };
1132
+ }
1133
+ /**
1134
+ * Clean up expired cache entries
1135
+ */
1136
+ function cleanupCache() {
1137
+ const now = Date.now();
1138
+ const keysToDelete = [];
1139
+ cache.forEach((entry, key) => {
1140
+ const age = now - entry.timestamp;
1141
+ if (age >= cacheConfig.maxAge) {
1142
+ keysToDelete.push(key);
1143
+ }
1144
+ });
1145
+ keysToDelete.forEach(key => cache.delete(key));
1146
+ }
1147
+ /**
1148
+ * Evict oldest cache entry if cache is full
1149
+ */
1150
+ function evictOldestIfFull() {
1151
+ if (cache.size >= MAX_CACHE_SIZE) {
1152
+ let oldestKey = null;
1153
+ let oldestTimestamp = Infinity;
1154
+ cache.forEach((entry, key) => {
1155
+ if (entry.timestamp < oldestTimestamp) {
1156
+ oldestTimestamp = entry.timestamp;
1157
+ oldestKey = key;
1158
+ }
1159
+ });
1160
+ if (oldestKey) {
1161
+ cache.delete(oldestKey);
1162
+ }
1163
+ }
1164
+ }
1165
+ /**
1166
+ * Clear all cached entries
1167
+ */
1168
+ function clearCache() {
1169
+ cache.clear();
1170
+ }
1171
+ /**
1172
+ * Clear cache entry for specific URL
1173
+ */
1174
+ function clearCacheEntry(url) {
1175
+ cache.delete(url);
1176
+ }
1177
+ /**
1178
+ * Caching interceptor - Caches HTTP GET requests
1179
+ *
1180
+ * @example
1181
+ * ```typescript
1182
+ * // In app.config.ts
1183
+ * export const appConfig: ApplicationConfig = {
1184
+ * providers: [
1185
+ * provideHttpClient(
1186
+ * withInterceptors([cachingInterceptor])
1187
+ * )
1188
+ * ]
1189
+ * };
1190
+ *
1191
+ * // Configure caching
1192
+ * configureCaching({
1193
+ * enabled: true,
1194
+ * maxAge: 300000, // 5 minutes
1195
+ * cacheableUrls: ['/api/users', '/api/products']
1196
+ * });
1197
+ * ```
1198
+ */
1199
+ const cachingInterceptor = (req, next) => {
1200
+ const logger = core.inject(exports.LoggerService);
1201
+ const config = cacheConfig;
1202
+ // Only cache if enabled
1203
+ if (!config.enabled) {
1204
+ return next(req);
1205
+ }
1206
+ // Only cache specific methods (default: GET)
1207
+ if (!config.cacheMethods?.includes(req.method)) {
1208
+ return next(req);
1209
+ }
1210
+ // Check if URL should be excluded
1211
+ const isExcluded = config.excludedUrls?.some(url => req.url.includes(url));
1212
+ if (isExcluded) {
1213
+ return next(req);
1214
+ }
1215
+ // Check if URL is explicitly cacheable (if list is provided)
1216
+ if (config.cacheableUrls && config.cacheableUrls.length > 0) {
1217
+ const isCacheable = config.cacheableUrls.some(url => req.url.includes(url));
1218
+ if (!isCacheable) {
1219
+ return next(req);
1220
+ }
1221
+ }
1222
+ const cacheKey = req.urlWithParams;
1223
+ // Check cache
1224
+ const cached = cache.get(cacheKey);
1225
+ if (cached) {
1226
+ const age = Date.now() - cached.timestamp;
1227
+ if (age < config.maxAge) {
1228
+ logger.debug(`Cache hit for ${cacheKey}`, { age });
1229
+ return new rxjs.Observable(observer => {
1230
+ observer.next(cached.response.clone());
1231
+ observer.complete();
1232
+ });
1233
+ }
1234
+ else {
1235
+ // Cache expired
1236
+ cache.delete(cacheKey);
1237
+ }
1238
+ }
1239
+ // Clean up expired entries periodically
1240
+ if (Math.random() < 0.1) { // 10% chance on each request
1241
+ cleanupCache();
1242
+ }
1243
+ // Make request and cache response
1244
+ return next(req).pipe(operators.tap(event => {
1245
+ if (event instanceof http.HttpResponse) {
1246
+ evictOldestIfFull();
1247
+ cache.set(cacheKey, {
1248
+ response: event.clone(),
1249
+ timestamp: Date.now()
1250
+ });
1251
+ logger.debug(`Cached response for ${cacheKey}`);
1252
+ }
1253
+ }));
1254
+ };
1255
+
1256
+ exports.EventBus = EventBus;
1257
+ exports.HttpError = HttpError;
1258
+ exports.Logger = Logger;
1259
+ exports.StorageManager = StorageManager;
1260
+ exports.TokenManager = TokenManager;
1261
+ exports.authGuard = authGuard;
1262
+ exports.authInterceptor = authInterceptor;
1263
+ exports.cachingInterceptor = cachingInterceptor;
1264
+ exports.clearCache = clearCache;
1265
+ exports.clearCacheEntry = clearCacheEntry;
1266
+ exports.configureAuthInterceptor = configureAuthInterceptor;
1267
+ exports.configureCaching = configureCaching;
1268
+ exports.configureErrorHandling = configureErrorHandling;
1269
+ exports.createAuthGuard = createAuthGuard;
1270
+ exports.createPermissionGuard = createPermissionGuard;
1271
+ exports.createRoleGuard = createRoleGuard;
1272
+ exports.errorHandlingInterceptor = errorHandlingInterceptor;
1273
+ exports.isClientError = isClientError;
1274
+ exports.isNetworkError = isNetworkError;
1275
+ exports.isServerError = isServerError;
1276
+ exports.parseHttpError = parseHttpError;
1277
+ //# sourceMappingURL=index.cjs.map