Angular 18 shareable utility library with framework-agnostic core and Angular wrappers for event emitter, authorization, storage, and more
npm install @opensourcekd/ng-common-libsAngular 18 library with Auth0 authentication service and MicroFrontend event bus.
This library features a dual-layer architecture:
- Core Layer (@opensourcekd/ng-common-libs/core): Framework-agnostic event bus using only RxJS. Use in React, Vue, Svelte, or vanilla JavaScript projects.
- Angular Layer (@opensourcekd/ng-common-libs or /angular): Angular-specific services with dependency injection.
- APP_CONFIG: Framework-agnostic configuration utility for all environment variables (Auth0, API URLs)
- EventBusService: MicroFrontend-ready event bus with replay buffer for cross-app communication
- Auth0 Integration: Complete Auth0 authentication service with token management
``bash`
npm install @opensourcekd/ng-common-libs
> Note: mitt and @auth0/auth0-spa-js are bundled with the library. You don't need to install them separately.@opensourcekd/ng-common-libs
>
> Module Federation: Just configure as shared in your webpack config. The bundled dependencies (mitt, @auth0/auth0-spa-js) will be included automatically, ensuring they're loaded only once across all micro-frontends.
If you're using Module Federation with multiple Angular applications (shell + MFEs), you MUST configure the services as singletons using factory functions. This ensures ONE instance is shared across all applications.
In your shell app AND each MFE's app.config.ts (standalone) or app.module.ts (NgModule):
`typescript
import { ApplicationConfig } from '@angular/core';
import {
AuthService,
EventBusService,
getAuthService,
getEventBusService,
configureAuth0
} from '@opensourcekd/ng-common-libs';
import { APP_CONFIG } from '@opensourcekd/ng-common-libs/core';
// Configure Auth0 (do this once in shell or each MFE)
configureAuth0({
domain: APP_CONFIG.auth0Domain,
clientId: APP_CONFIG.auth0ClientId,
audience: APP_CONFIG.apiUrl,
});
export const appConfig: ApplicationConfig = {
providers: [
// REQUIRED: Use factory functions for singleton behavior across MFEs
{ provide: EventBusService, useFactory: getEventBusService },
{ provide: AuthService, useFactory: getAuthService },
// ... your other providers
]
};
`
Why is this needed?
Angular's providedIn: 'root' creates one instance per Angular application. In Module Federation, each MFE is a separate Angular app, so you'd get multiple instances. Factory functions create a JavaScript module-level singleton that's shared across ALL applications.
For NgModule-based apps:
`typescript
import { NgModule } from '@angular/core';
import {
AuthService,
EventBusService,
getAuthService,
getEventBusService
} from '@opensourcekd/ng-common-libs';
@NgModule({
providers: [
{ provide: EventBusService, useFactory: getEventBusService },
{ provide: AuthService, useFactory: getAuthService }
]
})
export class AppModule { }
`
Then use normally in components with inject():`typescript`
export class MyComponent {
private authService = inject(AuthService);
private eventBus = inject(EventBusService);
}
The library provides a framework-agnostic configuration utility with statically configured values from GitHub repository variables:
`typescript
// Import from /core for framework-agnostic usage
import { APP_CONFIG } from '@opensourcekd/ng-common-libs/core';
// Access pre-configured values anywhere in your app
console.log(APP_CONFIG.apiUrl); // Configured during build from GitHub vars
console.log(APP_CONFIG.auth0Domain); // Configured during build from GitHub vars
console.log(APP_CONFIG.auth0ClientId); // Configured during build from GitHub vars
`
Key Features:
- Values are statically baked into the library during build time from GitHub repository variables
- No runtime configuration needed - values are available immediately
- Can be used across any framework: Angular, React, Vue, Svelte, vanilla JS
- Perfect for MicroFrontends (MFEs) and shell applications
Complete Auth0 integration with automatic token management and event emission.
Note: Make sure you've configured the providers as shown in the Module Federation setup above first!
`typescript
import { Component, inject } from '@angular/core';
import { AuthService } from '@opensourcekd/ng-common-libs';
@Component({
selector: 'app-login',
template:
})
export class LoginComponent {
private authService = inject(AuthService);
user = this.authService.getUser(); async login() {
await this.authService.login();
}
async logout() {
await this.authService.logout();
}
}
`See the Auth0 Service Usage Guide for complete integration instructions.
$3
Cross-application event communication for MicroFrontend architectures.
Note: Make sure you've configured the providers as shown in the Module Federation setup above first!
`typescript
import { Component, OnInit, inject } from '@angular/core';
import { EventBusService } from '@opensourcekd/ng-common-libs';@Component({
selector: 'app-event-example',
template:
})
export class EventExampleComponent implements OnInit {
private eventBus = inject(EventBusService); ngOnInit() {
// Subscribe to all events
this.eventBus.onePlusNEvents.subscribe(event => {
console.log('Event received:', event);
});
}
sendEvent() {
// Send structured event
this.eventBus.sendEvent(JSON.stringify({
type: 'user:action',
payload: { userId: '123' },
timestamp: new Date().toISOString()
}));
}
}
`See the EventBus Service Usage Guide for advanced patterns and MicroFrontend examples.
$3
Use the framework-agnostic core event bus:
`typescript
// Import from /core
import { EventBus } from '@opensourcekd/ng-common-libs/core';// Event Bus
const eventBus = new EventBus();
eventBus.emit('user:login', { userId: '123' });
eventBus.on('user:login').subscribe(data => {
console.log('User logged in:', data);
});
`#### React Example
`typescript
import { useEffect } from 'react';
import { EventBus } from '@opensourcekd/ng-common-libs/core';const eventBus = new EventBus();
function MyComponent() {
useEffect(() => {
const subscription = eventBus.on('user:login').subscribe(data => {
console.log('User logged in:', data);
});
return () => subscription.unsubscribe();
}, []);
const handleLogin = () => {
eventBus.emit('user:login', { userId: '123' });
};
return ;
}
`#### Vue Example
`typescript
import { onMounted, onUnmounted } from 'vue';
import { EventBus } from '@opensourcekd/ng-common-libs/core';const eventBus = new EventBus();
export default {
setup() {
let subscription;
onMounted(() => {
subscription = eventBus.on('user:login').subscribe(data => {
console.log('User logged in:', data);
});
});
onUnmounted(() => {
subscription?.unsubscribe();
});
const handleLogin = () => {
eventBus.emit('user:login', { userId: '123' });
};
return { handleLogin };
}
};
`📚 Documentation
- Auth0 Service Usage - Complete Auth0 authentication integration guide
- EventBus Service Usage - Cross-application event communication guide
- Deployment Guide - Publishing, versioning, and consumption
- Microapp Triggering Guide - Automatic build triggering for consuming microapps
- Module Federation Guide - Runtime sharing with Module Federation
📝 API Documentation
$3
-
APP_CONFIG - Read-only application configuration object with values statically configured during build time:
- auth0Domain: string - Auth0 tenant domain (from GitHub var AUTH0_DOMAIN)
- auth0ClientId: string - Auth0 client ID (from GitHub var AUTH0_CLIENT_ID)
- apiUrl: string - API base URL (from GitHub var API_URL)$3
-
configureAuth0(config: Partial - Configure Auth0 settings (domain, clientId, etc.)
- AUTH0_CONFIG - Auth0 configuration object (domain, clientId, redirectUri, etc.)$3
-
login(user?: string, options?: { invitation?: string; organization?: string }): Promise - Initiate Auth0 login with optional user identifier and organization invitation parameters
- logout(): Promise - Logout and clear session
- handleCallback(): Promise<{ success: boolean, appState?: any }> - Handle Auth0 callback and return success status with preserved appState
- getToken(): Promise - Get access token asynchronously (checks storage first, then Auth0)
- getTokenSync(): string | null - Get cached access token synchronously (storage only)
- getUser(): UserInfo | null - Get current user information
- getUserData(): UserData | null - Get simplified user data with role and organization extraction
- isAuthenticated(): Promise - Check authentication status asynchronously (verifies with Auth0)
- isAuthenticatedSync(): boolean - Check authentication status synchronously (storage only)
- user$: Observable - Observable stream of user changes$3
-
sendEvent(event: string): void - Send event to all subscribers
- onePlusNEvents: Observable - Subscribe to all events with replay buffer$3
-
emit - Emit an event
- on - Subscribe to an event
- onMultiple(eventTypes: string[]): Observable - Subscribe to multiple events
- onAll(): Observable - Subscribe to all events🛠️ Development
`bash
Install dependencies
npm installBuild the library
npm run buildRun linter
npm run lint
``MIT
Koustubh Desai
Contributions, issues, and feature requests are welcome!
Give a ⭐️ if this project helped you!