@opensourcekd/ng-common-libs 2.0.6 → 2.0.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/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
@@ -317,7 +317,7 @@ class AuthService {
317
317
  this.id = options?.id;
318
318
  this.userSubject = new rxjs.BehaviorSubject(this.getUserInfoFromStorage());
319
319
  this.user$ = this.userSubject.asObservable();
320
- console.log("[AuthService] AuthService instance created (Auth0 client will be initialized on first use)");
320
+ console.log("[AuthService] AuthService instance created (Auth0 client will be initialized on first use, kd)");
321
321
  // Lazy initialization - Auth0 client will be initialized in ensureInitialized() on first use
322
322
  }
323
323
  /**
@@ -443,6 +443,8 @@ class AuthService {
443
443
  }
444
444
  const token = await this.auth0Client.getTokenSilently();
445
445
  this.setToken(token);
446
+ // Clean up OAuth callback parameters from URL
447
+ this.cleanupCallbackUrl();
446
448
  console.log("[AuthService] Authentication successful");
447
449
  this.emitAuthEvent('login_success', { user, appState: result.appState });
448
450
  return { success: true, appState: result.appState };
@@ -665,6 +667,34 @@ class AuthService {
665
667
  this.eventBus.emit(event.type, event);
666
668
  console.log('[AuthService] Auth event emitted:', event.type);
667
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
+ }
668
698
  }
669
699
  /**
670
700
  * Create AuthService instance using AUTH0_CONFIG
@@ -704,10 +734,215 @@ function createAuthService(eventBus) {
704
734
  return new AuthService(auth0Config, eventBus, STORAGE_CONFIG, STORAGE_KEYS);
705
735
  }
706
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
+
707
941
  exports.APP_CONFIG = APP_CONFIG;
708
942
  exports.AUTH0_CONFIG = AUTH0_CONFIG;
709
943
  exports.AuthService = AuthService;
710
944
  exports.EventBus = EventBus;
945
+ exports.Logger = Logger;
711
946
  exports.STORAGE_CONFIG = STORAGE_CONFIG;
712
947
  exports.STORAGE_KEYS = STORAGE_KEYS;
713
948
  exports.configureAuth0 = configureAuth0;