@opensourcekd/ng-common-libs 2.0.5 → 2.0.7
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/README.md +6 -0
- package/dist/index.cjs +273 -1
- package/dist/index.cjs.map +1 -1
- package/dist/index.d.ts +249 -3
- package/dist/index.mjs +273 -2
- package/dist/index.mjs.map +1 -1
- package/package.json +1 -1
package/README.md
CHANGED
|
@@ -23,6 +23,7 @@ import {
|
|
|
23
23
|
|
|
24
24
|
- **AuthService**: Complete Auth0 authentication with token management (Pure TypeScript - no Angular dependency)
|
|
25
25
|
- **EventBus**: Framework-agnostic event bus using RxJS
|
|
26
|
+
- **Logger**: OpenTelemetry-compliant structured logging with observable log streams
|
|
26
27
|
- **Works with any framework**: Angular, React, Vue, Svelte, vanilla JS
|
|
27
28
|
- **Module Federation Support**: Singleton pattern works across shell + MFEs
|
|
28
29
|
- **Zero Framework Lock-in**: Core services are pure TypeScript classes
|
|
@@ -94,6 +95,7 @@ import {
|
|
|
94
95
|
// Services
|
|
95
96
|
AuthService,
|
|
96
97
|
EventBus,
|
|
98
|
+
Logger,
|
|
97
99
|
|
|
98
100
|
// Helper Functions
|
|
99
101
|
configureAuth0,
|
|
@@ -121,6 +123,10 @@ import {
|
|
|
121
123
|
AppState,
|
|
122
124
|
AuthorizationParams,
|
|
123
125
|
CallbackResult,
|
|
126
|
+
LogRecord,
|
|
127
|
+
LogAttributes,
|
|
128
|
+
LogSeverity,
|
|
129
|
+
LoggerOptions,
|
|
124
130
|
} from '@opensourcekd/ng-common-libs';
|
|
125
131
|
```
|
|
126
132
|
|
package/dist/index.cjs
CHANGED
|
@@ -12,6 +12,9 @@ var operators = require('rxjs/operators');
|
|
|
12
12
|
* // Create an instance
|
|
13
13
|
* const eventBus = new EventBus();
|
|
14
14
|
*
|
|
15
|
+
* // Create an instance with an identifier
|
|
16
|
+
* const eventBus = new EventBus({ id: 'MFE' });
|
|
17
|
+
*
|
|
15
18
|
* // Emit an event
|
|
16
19
|
* eventBus.emit('user:login', { userId: '123', username: 'john' });
|
|
17
20
|
*
|
|
@@ -19,10 +22,28 @@ var operators = require('rxjs/operators');
|
|
|
19
22
|
* eventBus.on('user:login').subscribe(data => {
|
|
20
23
|
* console.log('User logged in:', data);
|
|
21
24
|
* });
|
|
25
|
+
*
|
|
26
|
+
* // Get the identifier
|
|
27
|
+
* const id = eventBus.getId(); // 'MFE' or undefined
|
|
22
28
|
* ```
|
|
23
29
|
*/
|
|
24
30
|
class EventBus {
|
|
25
31
|
eventSubject = new rxjs.Subject();
|
|
32
|
+
id;
|
|
33
|
+
/**
|
|
34
|
+
* Create a new EventBus instance
|
|
35
|
+
* @param options - Optional configuration with an id to identify the instance
|
|
36
|
+
*/
|
|
37
|
+
constructor(options) {
|
|
38
|
+
this.id = options?.id;
|
|
39
|
+
}
|
|
40
|
+
/**
|
|
41
|
+
* Get the identifier of this EventBus instance
|
|
42
|
+
* @returns The id if provided during initialization, undefined otherwise
|
|
43
|
+
*/
|
|
44
|
+
getId() {
|
|
45
|
+
return this.id;
|
|
46
|
+
}
|
|
26
47
|
/**
|
|
27
48
|
* Emit an event with optional data
|
|
28
49
|
* @param eventType - The type/name of the event
|
|
@@ -245,10 +266,16 @@ function removeStorageItem(key, storageType = 'sessionStorage') {
|
|
|
245
266
|
* };
|
|
246
267
|
* const authService = new AuthService(authConfig, eventBus);
|
|
247
268
|
*
|
|
269
|
+
* // Or create with an identifier
|
|
270
|
+
* const authService = new AuthService(authConfig, eventBus, undefined, undefined, { id: 'MFE' });
|
|
271
|
+
*
|
|
248
272
|
* // Use the service
|
|
249
273
|
* await authService.login();
|
|
250
274
|
* const user = authService.getUser();
|
|
251
275
|
* const token = await authService.getToken();
|
|
276
|
+
*
|
|
277
|
+
* // Get the identifier
|
|
278
|
+
* const id = authService.getId(); // 'MFE' or undefined
|
|
252
279
|
* ```
|
|
253
280
|
*/
|
|
254
281
|
class AuthService {
|
|
@@ -267,12 +294,14 @@ class AuthService {
|
|
|
267
294
|
storageConfig;
|
|
268
295
|
storageKeys;
|
|
269
296
|
eventBus;
|
|
297
|
+
id;
|
|
270
298
|
/**
|
|
271
299
|
* Create a new AuthService instance
|
|
272
300
|
* @param config - Auth0 configuration
|
|
273
301
|
* @param eventBus - EventBus instance for emitting auth events
|
|
274
302
|
* @param storageConfig - Storage configuration (optional, defaults to sessionStorage)
|
|
275
303
|
* @param storageKeys - Storage keys (optional, defaults to standard keys)
|
|
304
|
+
* @param options - Optional configuration with an id to identify the instance
|
|
276
305
|
*/
|
|
277
306
|
constructor(config, eventBus, storageConfig = {
|
|
278
307
|
TOKEN_STORAGE: 'sessionStorage',
|
|
@@ -280,16 +309,24 @@ class AuthService {
|
|
|
280
309
|
}, storageKeys = {
|
|
281
310
|
ACCESS_TOKEN: 'auth0_access_token',
|
|
282
311
|
USER_INFO: 'auth0_user_info'
|
|
283
|
-
}) {
|
|
312
|
+
}, options) {
|
|
284
313
|
this.config = config;
|
|
285
314
|
this.eventBus = eventBus;
|
|
286
315
|
this.storageConfig = storageConfig;
|
|
287
316
|
this.storageKeys = storageKeys;
|
|
317
|
+
this.id = options?.id;
|
|
288
318
|
this.userSubject = new rxjs.BehaviorSubject(this.getUserInfoFromStorage());
|
|
289
319
|
this.user$ = this.userSubject.asObservable();
|
|
290
320
|
console.log("[AuthService] AuthService instance created (Auth0 client will be initialized on first use)");
|
|
291
321
|
// Lazy initialization - Auth0 client will be initialized in ensureInitialized() on first use
|
|
292
322
|
}
|
|
323
|
+
/**
|
|
324
|
+
* Get the identifier of this AuthService instance
|
|
325
|
+
* @returns The id if provided during initialization, undefined otherwise
|
|
326
|
+
*/
|
|
327
|
+
getId() {
|
|
328
|
+
return this.id;
|
|
329
|
+
}
|
|
293
330
|
/**
|
|
294
331
|
* Initialize Auth0 client
|
|
295
332
|
*/
|
|
@@ -406,6 +443,8 @@ class AuthService {
|
|
|
406
443
|
}
|
|
407
444
|
const token = await this.auth0Client.getTokenSilently();
|
|
408
445
|
this.setToken(token);
|
|
446
|
+
// Clean up OAuth callback parameters from URL
|
|
447
|
+
this.cleanupCallbackUrl();
|
|
409
448
|
console.log("[AuthService] Authentication successful");
|
|
410
449
|
this.emitAuthEvent('login_success', { user, appState: result.appState });
|
|
411
450
|
return { success: true, appState: result.appState };
|
|
@@ -628,6 +667,34 @@ class AuthService {
|
|
|
628
667
|
this.eventBus.emit(event.type, event);
|
|
629
668
|
console.log('[AuthService] Auth event emitted:', event.type);
|
|
630
669
|
}
|
|
670
|
+
/**
|
|
671
|
+
* Clean up OAuth callback parameters from URL after successful authentication
|
|
672
|
+
* Removes 'code' and 'state' parameters while preserving other query parameters
|
|
673
|
+
*/
|
|
674
|
+
cleanupCallbackUrl() {
|
|
675
|
+
try {
|
|
676
|
+
const url = new URL(window.location.href);
|
|
677
|
+
const params = new URLSearchParams(url.search);
|
|
678
|
+
// Check if OAuth params exist
|
|
679
|
+
const hasCode = params.has('code');
|
|
680
|
+
const hasState = params.has('state');
|
|
681
|
+
if (hasCode || hasState) {
|
|
682
|
+
// Remove OAuth callback parameters
|
|
683
|
+
params.delete('code');
|
|
684
|
+
params.delete('state');
|
|
685
|
+
// Construct new URL without OAuth params
|
|
686
|
+
const newSearch = params.toString();
|
|
687
|
+
const newUrl = `${url.pathname}${newSearch ? '?' + newSearch : ''}${url.hash}`;
|
|
688
|
+
// Replace URL without adding to browser history
|
|
689
|
+
window.history.replaceState({}, '', newUrl);
|
|
690
|
+
console.log('[AuthService] OAuth callback parameters cleaned from URL');
|
|
691
|
+
}
|
|
692
|
+
}
|
|
693
|
+
catch (error) {
|
|
694
|
+
console.warn('[AuthService] Failed to clean up callback URL:', error);
|
|
695
|
+
// Don't throw - URL cleanup is not critical for auth functionality
|
|
696
|
+
}
|
|
697
|
+
}
|
|
631
698
|
}
|
|
632
699
|
/**
|
|
633
700
|
* Create AuthService instance using AUTH0_CONFIG
|
|
@@ -667,10 +734,215 @@ function createAuthService(eventBus) {
|
|
|
667
734
|
return new AuthService(auth0Config, eventBus, STORAGE_CONFIG, STORAGE_KEYS);
|
|
668
735
|
}
|
|
669
736
|
|
|
737
|
+
/**
|
|
738
|
+
* OpenTelemetry severity levels
|
|
739
|
+
* Based on OpenTelemetry log data model
|
|
740
|
+
* @see https://opentelemetry.io/docs/specs/otel/logs/data-model/
|
|
741
|
+
*/
|
|
742
|
+
exports.LogSeverity = void 0;
|
|
743
|
+
(function (LogSeverity) {
|
|
744
|
+
LogSeverity[LogSeverity["TRACE"] = 1] = "TRACE";
|
|
745
|
+
LogSeverity[LogSeverity["DEBUG"] = 5] = "DEBUG";
|
|
746
|
+
LogSeverity[LogSeverity["INFO"] = 9] = "INFO";
|
|
747
|
+
LogSeverity[LogSeverity["WARN"] = 13] = "WARN";
|
|
748
|
+
LogSeverity[LogSeverity["ERROR"] = 17] = "ERROR";
|
|
749
|
+
LogSeverity[LogSeverity["FATAL"] = 21] = "FATAL";
|
|
750
|
+
})(exports.LogSeverity || (exports.LogSeverity = {}));
|
|
751
|
+
/**
|
|
752
|
+
* Logger - OpenTelemetry-compliant structured logging
|
|
753
|
+
* Framework-agnostic implementation using RxJS for observability
|
|
754
|
+
*
|
|
755
|
+
* Conforms to OpenTelemetry log data model:
|
|
756
|
+
* - Structured logging with severity levels
|
|
757
|
+
* - Timestamp in milliseconds
|
|
758
|
+
* - Support for attributes and resource context
|
|
759
|
+
* - Observable log stream for integration with OTel exporters
|
|
760
|
+
*
|
|
761
|
+
* @example
|
|
762
|
+
* ```typescript
|
|
763
|
+
* // Create a logger instance
|
|
764
|
+
* const logger = new Logger({
|
|
765
|
+
* name: 'MyService',
|
|
766
|
+
* minSeverity: LogSeverity.INFO,
|
|
767
|
+
* resource: {
|
|
768
|
+
* 'service.name': 'my-app',
|
|
769
|
+
* 'deployment.environment': 'production'
|
|
770
|
+
* }
|
|
771
|
+
* });
|
|
772
|
+
*
|
|
773
|
+
* // Simple logging
|
|
774
|
+
* logger.info('User logged in');
|
|
775
|
+
* logger.error('Failed to fetch data');
|
|
776
|
+
*
|
|
777
|
+
* // Structured logging with attributes
|
|
778
|
+
* logger.info('User action', {
|
|
779
|
+
* userId: '123',
|
|
780
|
+
* action: 'purchase',
|
|
781
|
+
* amount: 99.99
|
|
782
|
+
* });
|
|
783
|
+
*
|
|
784
|
+
* // Subscribe to log stream (e.g., for sending to OTel collector)
|
|
785
|
+
* logger.getLogStream().subscribe(logRecord => {
|
|
786
|
+
* // Send to OTel exporter, custom backend, etc.
|
|
787
|
+
* console.log(JSON.stringify(logRecord));
|
|
788
|
+
* });
|
|
789
|
+
*
|
|
790
|
+
* // Log with trace correlation
|
|
791
|
+
* logger.info('Processing request',
|
|
792
|
+
* { requestId: 'abc-123' },
|
|
793
|
+
* { traceId: '1234...', spanId: '5678...' }
|
|
794
|
+
* );
|
|
795
|
+
* ```
|
|
796
|
+
*/
|
|
797
|
+
class Logger {
|
|
798
|
+
logSubject = new rxjs.Subject();
|
|
799
|
+
name;
|
|
800
|
+
minSeverity;
|
|
801
|
+
resource;
|
|
802
|
+
consoleOutput;
|
|
803
|
+
/**
|
|
804
|
+
* Create a new Logger instance
|
|
805
|
+
* @param options - Optional configuration for the logger
|
|
806
|
+
*/
|
|
807
|
+
constructor(options) {
|
|
808
|
+
this.name = options?.name;
|
|
809
|
+
this.minSeverity = options?.minSeverity ?? exports.LogSeverity.TRACE;
|
|
810
|
+
this.resource = options?.resource;
|
|
811
|
+
this.consoleOutput = options?.consoleOutput ?? true;
|
|
812
|
+
}
|
|
813
|
+
/**
|
|
814
|
+
* Get the logger name
|
|
815
|
+
* @returns The logger name if provided during initialization
|
|
816
|
+
*/
|
|
817
|
+
getName() {
|
|
818
|
+
return this.name;
|
|
819
|
+
}
|
|
820
|
+
/**
|
|
821
|
+
* Get the observable log stream
|
|
822
|
+
* Subscribe to this to receive all log records emitted by this logger
|
|
823
|
+
* @returns Observable that emits LogRecord objects
|
|
824
|
+
*/
|
|
825
|
+
getLogStream() {
|
|
826
|
+
return this.logSubject.asObservable();
|
|
827
|
+
}
|
|
828
|
+
/**
|
|
829
|
+
* Emit a log record
|
|
830
|
+
* @param severity - Severity level
|
|
831
|
+
* @param severityText - Severity level text
|
|
832
|
+
* @param body - Log message
|
|
833
|
+
* @param attributes - Optional structured attributes
|
|
834
|
+
* @param context - Optional trace context (traceId, spanId)
|
|
835
|
+
*/
|
|
836
|
+
log(severity, severityText, body, attributes, context) {
|
|
837
|
+
// Check if we should log based on minimum severity
|
|
838
|
+
if (severity < this.minSeverity) {
|
|
839
|
+
return;
|
|
840
|
+
}
|
|
841
|
+
const logRecord = {
|
|
842
|
+
timestamp: Date.now(),
|
|
843
|
+
severityNumber: severity,
|
|
844
|
+
severityText,
|
|
845
|
+
body,
|
|
846
|
+
attributes,
|
|
847
|
+
traceId: context?.traceId,
|
|
848
|
+
spanId: context?.spanId,
|
|
849
|
+
resource: this.resource
|
|
850
|
+
};
|
|
851
|
+
// Emit to observable stream
|
|
852
|
+
this.logSubject.next(logRecord);
|
|
853
|
+
// Console output if enabled
|
|
854
|
+
if (this.consoleOutput) {
|
|
855
|
+
this.outputToConsole(logRecord);
|
|
856
|
+
}
|
|
857
|
+
}
|
|
858
|
+
/**
|
|
859
|
+
* Output log to console
|
|
860
|
+
* @param logRecord - The log record to output
|
|
861
|
+
*/
|
|
862
|
+
outputToConsole(logRecord) {
|
|
863
|
+
const prefix = this.name ? `[${this.name}]` : '';
|
|
864
|
+
const message = `${prefix} ${logRecord.body}`;
|
|
865
|
+
const meta = logRecord.attributes;
|
|
866
|
+
switch (logRecord.severityNumber) {
|
|
867
|
+
case exports.LogSeverity.TRACE:
|
|
868
|
+
case exports.LogSeverity.DEBUG:
|
|
869
|
+
console.debug(message, meta);
|
|
870
|
+
break;
|
|
871
|
+
case exports.LogSeverity.INFO:
|
|
872
|
+
console.info(message, meta);
|
|
873
|
+
break;
|
|
874
|
+
case exports.LogSeverity.WARN:
|
|
875
|
+
console.warn(message, meta);
|
|
876
|
+
break;
|
|
877
|
+
case exports.LogSeverity.ERROR:
|
|
878
|
+
case exports.LogSeverity.FATAL:
|
|
879
|
+
console.error(message, meta);
|
|
880
|
+
break;
|
|
881
|
+
default:
|
|
882
|
+
console.log(message, meta);
|
|
883
|
+
}
|
|
884
|
+
}
|
|
885
|
+
/**
|
|
886
|
+
* Log a TRACE level message
|
|
887
|
+
* @param body - Log message
|
|
888
|
+
* @param attributes - Optional structured attributes
|
|
889
|
+
* @param context - Optional trace context
|
|
890
|
+
*/
|
|
891
|
+
trace(body, attributes, context) {
|
|
892
|
+
this.log(exports.LogSeverity.TRACE, 'TRACE', body, attributes, context);
|
|
893
|
+
}
|
|
894
|
+
/**
|
|
895
|
+
* Log a DEBUG level message
|
|
896
|
+
* @param body - Log message
|
|
897
|
+
* @param attributes - Optional structured attributes
|
|
898
|
+
* @param context - Optional trace context
|
|
899
|
+
*/
|
|
900
|
+
debug(body, attributes, context) {
|
|
901
|
+
this.log(exports.LogSeverity.DEBUG, 'DEBUG', body, attributes, context);
|
|
902
|
+
}
|
|
903
|
+
/**
|
|
904
|
+
* Log an INFO level message
|
|
905
|
+
* @param body - Log message
|
|
906
|
+
* @param attributes - Optional structured attributes
|
|
907
|
+
* @param context - Optional trace context
|
|
908
|
+
*/
|
|
909
|
+
info(body, attributes, context) {
|
|
910
|
+
this.log(exports.LogSeverity.INFO, 'INFO', body, attributes, context);
|
|
911
|
+
}
|
|
912
|
+
/**
|
|
913
|
+
* Log a WARN level message
|
|
914
|
+
* @param body - Log message
|
|
915
|
+
* @param attributes - Optional structured attributes
|
|
916
|
+
* @param context - Optional trace context
|
|
917
|
+
*/
|
|
918
|
+
warn(body, attributes, context) {
|
|
919
|
+
this.log(exports.LogSeverity.WARN, 'WARN', body, attributes, context);
|
|
920
|
+
}
|
|
921
|
+
/**
|
|
922
|
+
* Log an ERROR level message
|
|
923
|
+
* @param body - Log message
|
|
924
|
+
* @param attributes - Optional structured attributes
|
|
925
|
+
* @param context - Optional trace context
|
|
926
|
+
*/
|
|
927
|
+
error(body, attributes, context) {
|
|
928
|
+
this.log(exports.LogSeverity.ERROR, 'ERROR', body, attributes, context);
|
|
929
|
+
}
|
|
930
|
+
/**
|
|
931
|
+
* Log a FATAL level message
|
|
932
|
+
* @param body - Log message
|
|
933
|
+
* @param attributes - Optional structured attributes
|
|
934
|
+
* @param context - Optional trace context
|
|
935
|
+
*/
|
|
936
|
+
fatal(body, attributes, context) {
|
|
937
|
+
this.log(exports.LogSeverity.FATAL, 'FATAL', body, attributes, context);
|
|
938
|
+
}
|
|
939
|
+
}
|
|
940
|
+
|
|
670
941
|
exports.APP_CONFIG = APP_CONFIG;
|
|
671
942
|
exports.AUTH0_CONFIG = AUTH0_CONFIG;
|
|
672
943
|
exports.AuthService = AuthService;
|
|
673
944
|
exports.EventBus = EventBus;
|
|
945
|
+
exports.Logger = Logger;
|
|
674
946
|
exports.STORAGE_CONFIG = STORAGE_CONFIG;
|
|
675
947
|
exports.STORAGE_KEYS = STORAGE_KEYS;
|
|
676
948
|
exports.configureAuth0 = configureAuth0;
|