@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/LICENSE +21 -0
- package/README.md +437 -0
- package/dist/angular/index.cjs +1273 -0
- package/dist/angular/index.cjs.map +1 -0
- package/dist/angular/index.d.ts +691 -0
- package/dist/angular/index.mjs +1255 -0
- package/dist/angular/index.mjs.map +1 -0
- package/dist/core/index.cjs +592 -0
- package/dist/core/index.cjs.map +1 -0
- package/dist/core/index.d.ts +332 -0
- package/dist/core/index.mjs +587 -0
- package/dist/core/index.mjs.map +1 -0
- package/dist/index.cjs +1277 -0
- package/dist/index.cjs.map +1 -0
- package/dist/index.d.ts +691 -0
- package/dist/index.mjs +1255 -0
- package/dist/index.mjs.map +1 -0
- package/package.json +97 -0
package/LICENSE
ADDED
|
@@ -0,0 +1,21 @@
|
|
|
1
|
+
MIT License
|
|
2
|
+
|
|
3
|
+
Copyright (c) 2025 OpensourceKD
|
|
4
|
+
|
|
5
|
+
Permission is hereby granted, free of charge, to any person obtaining a copy
|
|
6
|
+
of this software and associated documentation files (the "Software"), to deal
|
|
7
|
+
in the Software without restriction, including without limitation the rights
|
|
8
|
+
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
|
9
|
+
copies of the Software, and to permit persons to whom the Software is
|
|
10
|
+
furnished to do so, subject to the following conditions:
|
|
11
|
+
|
|
12
|
+
The above copyright notice and this permission notice shall be included in all
|
|
13
|
+
copies or substantial portions of the Software.
|
|
14
|
+
|
|
15
|
+
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
|
16
|
+
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
|
17
|
+
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
|
18
|
+
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
|
19
|
+
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
|
20
|
+
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
|
21
|
+
SOFTWARE.
|
package/README.md
ADDED
|
@@ -0,0 +1,437 @@
|
|
|
1
|
+
# ng-common-libs
|
|
2
|
+
|
|
3
|
+
Angular 18 shareable utility library with framework-agnostic core and Angular wrappers for event handling, authorization, storage management, logging, and HTTP operations.
|
|
4
|
+
|
|
5
|
+
## 🎯 Dual-Layer Architecture
|
|
6
|
+
|
|
7
|
+
This library features a **dual-layer architecture**:
|
|
8
|
+
|
|
9
|
+
- **Core Layer** (`@opensourcekd/ng-common-libs/core`): Framework-agnostic utilities using only RxJS and browser APIs. Use these in React, Vue, Svelte, or vanilla JavaScript projects.
|
|
10
|
+
- **Angular Layer** (`@opensourcekd/ng-common-libs` or `/angular`): Angular-specific wrappers with dependency injection, plus guards and interceptors that require Angular.
|
|
11
|
+
|
|
12
|
+
## 🚀 Features
|
|
13
|
+
|
|
14
|
+
- **Event Bus**: Centralized event communication (framework-agnostic)
|
|
15
|
+
- **Token Manager**: JWT token management and validation (framework-agnostic)
|
|
16
|
+
- **Storage Manager**: Type-safe localStorage/sessionStorage wrapper (framework-agnostic)
|
|
17
|
+
- **Logger**: Configurable logging with multiple levels (framework-agnostic)
|
|
18
|
+
- **Authorization**: Angular guards, interceptors, and permission handling
|
|
19
|
+
- **HTTP Utilities**: Error handling, caching, and retry logic for Angular HTTP requests
|
|
20
|
+
|
|
21
|
+
## 📦 Installation
|
|
22
|
+
|
|
23
|
+
```bash
|
|
24
|
+
npm install @opensourcekd/ng-common-libs
|
|
25
|
+
```
|
|
26
|
+
|
|
27
|
+
## 🔧 Usage
|
|
28
|
+
|
|
29
|
+
### For Angular Projects
|
|
30
|
+
|
|
31
|
+
Use the Angular-specific imports that provide dependency injection:
|
|
32
|
+
|
|
33
|
+
```typescript
|
|
34
|
+
import { Component, OnInit, inject } from '@angular/core';
|
|
35
|
+
import { NgEventEmitter } from '@opensourcekd/ng-common-libs';
|
|
36
|
+
|
|
37
|
+
@Component({
|
|
38
|
+
selector: 'app-example',
|
|
39
|
+
template: `...`
|
|
40
|
+
})
|
|
41
|
+
export class ExampleComponent implements OnInit {
|
|
42
|
+
private eventEmitter = inject(NgEventEmitter);
|
|
43
|
+
|
|
44
|
+
ngOnInit() {
|
|
45
|
+
// Subscribe to events
|
|
46
|
+
this.eventEmitter.on('user:login').subscribe(data => {
|
|
47
|
+
console.log('User logged in:', data);
|
|
48
|
+
});
|
|
49
|
+
}
|
|
50
|
+
|
|
51
|
+
login() {
|
|
52
|
+
// Emit events
|
|
53
|
+
this.eventEmitter.emit('user:login', {
|
|
54
|
+
userId: '123',
|
|
55
|
+
username: 'john'
|
|
56
|
+
});
|
|
57
|
+
}
|
|
58
|
+
}
|
|
59
|
+
```
|
|
60
|
+
|
|
61
|
+
### Authorization
|
|
62
|
+
|
|
63
|
+
#### Token Service
|
|
64
|
+
|
|
65
|
+
Manage authentication tokens with ease:
|
|
66
|
+
|
|
67
|
+
```typescript
|
|
68
|
+
import { inject } from '@angular/core';
|
|
69
|
+
import { TokenService } from '@opensourcekd/ng-common-libs';
|
|
70
|
+
|
|
71
|
+
export class AuthService {
|
|
72
|
+
private tokenService = inject(TokenService);
|
|
73
|
+
|
|
74
|
+
login(token: string) {
|
|
75
|
+
this.tokenService.setToken(token);
|
|
76
|
+
}
|
|
77
|
+
|
|
78
|
+
logout() {
|
|
79
|
+
this.tokenService.clearTokens();
|
|
80
|
+
}
|
|
81
|
+
|
|
82
|
+
isAuthenticated(): boolean {
|
|
83
|
+
return this.tokenService.isAuthenticated();
|
|
84
|
+
}
|
|
85
|
+
|
|
86
|
+
getUserData() {
|
|
87
|
+
return this.tokenService.getUserFromToken();
|
|
88
|
+
}
|
|
89
|
+
}
|
|
90
|
+
```
|
|
91
|
+
|
|
92
|
+
#### Auth Guard
|
|
93
|
+
|
|
94
|
+
Protect routes with authentication guards:
|
|
95
|
+
|
|
96
|
+
```typescript
|
|
97
|
+
import { Routes } from '@angular/router';
|
|
98
|
+
import { authGuard, createRoleGuard } from '@opensourcekd/ng-common-libs';
|
|
99
|
+
|
|
100
|
+
export const routes: Routes = [
|
|
101
|
+
{
|
|
102
|
+
path: 'dashboard',
|
|
103
|
+
component: DashboardComponent,
|
|
104
|
+
canActivate: [authGuard]
|
|
105
|
+
},
|
|
106
|
+
{
|
|
107
|
+
path: 'admin',
|
|
108
|
+
component: AdminComponent,
|
|
109
|
+
canActivate: [createRoleGuard(['admin'], { redirectUrl: '/unauthorized' })]
|
|
110
|
+
}
|
|
111
|
+
];
|
|
112
|
+
```
|
|
113
|
+
|
|
114
|
+
#### Auth Interceptor
|
|
115
|
+
|
|
116
|
+
Automatically add authentication tokens to HTTP requests:
|
|
117
|
+
|
|
118
|
+
```typescript
|
|
119
|
+
import { ApplicationConfig } from '@angular/core';
|
|
120
|
+
import { provideHttpClient, withInterceptors } from '@angular/common/http';
|
|
121
|
+
import { authInterceptor, configureAuthInterceptor } from '@opensourcekd/ng-common-libs';
|
|
122
|
+
|
|
123
|
+
// Configure the interceptor (optional)
|
|
124
|
+
configureAuthInterceptor({
|
|
125
|
+
headerName: 'Authorization',
|
|
126
|
+
tokenPrefix: 'Bearer',
|
|
127
|
+
excludedUrls: ['/auth/login', '/auth/register']
|
|
128
|
+
});
|
|
129
|
+
|
|
130
|
+
export const appConfig: ApplicationConfig = {
|
|
131
|
+
providers: [
|
|
132
|
+
provideHttpClient(
|
|
133
|
+
withInterceptors([authInterceptor])
|
|
134
|
+
)
|
|
135
|
+
]
|
|
136
|
+
};
|
|
137
|
+
```
|
|
138
|
+
|
|
139
|
+
#### Permission Service
|
|
140
|
+
|
|
141
|
+
Check user permissions and roles:
|
|
142
|
+
|
|
143
|
+
```typescript
|
|
144
|
+
import { inject } from '@angular/core';
|
|
145
|
+
import { PermissionService } from '@opensourcekd/ng-common-libs';
|
|
146
|
+
|
|
147
|
+
export class MyComponent {
|
|
148
|
+
private permissionService = inject(PermissionService);
|
|
149
|
+
|
|
150
|
+
canEditPost(): boolean {
|
|
151
|
+
return this.permissionService.hasPermission('posts:edit');
|
|
152
|
+
}
|
|
153
|
+
|
|
154
|
+
isAdmin(): boolean {
|
|
155
|
+
return this.permissionService.hasRole('admin');
|
|
156
|
+
}
|
|
157
|
+
}
|
|
158
|
+
```
|
|
159
|
+
|
|
160
|
+
### Storage Service
|
|
161
|
+
|
|
162
|
+
Type-safe storage operations with JSON serialization:
|
|
163
|
+
|
|
164
|
+
```typescript
|
|
165
|
+
import { inject } from '@angular/core';
|
|
166
|
+
import { StorageService } from '@opensourcekd/ng-common-libs';
|
|
167
|
+
|
|
168
|
+
export class UserPreferencesService {
|
|
169
|
+
private storage = inject(StorageService);
|
|
170
|
+
|
|
171
|
+
savePreferences(prefs: UserPreferences) {
|
|
172
|
+
this.storage.setLocal('user-prefs', prefs);
|
|
173
|
+
}
|
|
174
|
+
|
|
175
|
+
getPreferences(): UserPreferences | null {
|
|
176
|
+
return this.storage.getLocal<UserPreferences>('user-prefs');
|
|
177
|
+
}
|
|
178
|
+
|
|
179
|
+
// With expiration (1 hour)
|
|
180
|
+
saveTempData(data: any) {
|
|
181
|
+
this.storage.setWithExpiration('temp-data', data, 3600000);
|
|
182
|
+
}
|
|
183
|
+
|
|
184
|
+
getTempData() {
|
|
185
|
+
return this.storage.getWithExpiration('temp-data');
|
|
186
|
+
}
|
|
187
|
+
}
|
|
188
|
+
```
|
|
189
|
+
|
|
190
|
+
### Logger Service
|
|
191
|
+
|
|
192
|
+
Centralized logging with configurable levels:
|
|
193
|
+
|
|
194
|
+
```typescript
|
|
195
|
+
import { inject } from '@angular/core';
|
|
196
|
+
import { LoggerService, LogLevel } from '@opensourcekd/ng-common-libs';
|
|
197
|
+
|
|
198
|
+
export class MyService {
|
|
199
|
+
private logger = inject(LoggerService);
|
|
200
|
+
|
|
201
|
+
constructor() {
|
|
202
|
+
// Configure logger
|
|
203
|
+
this.logger.configure({
|
|
204
|
+
level: LogLevel.DEBUG,
|
|
205
|
+
enableTimestamp: true,
|
|
206
|
+
prefix: 'MyApp'
|
|
207
|
+
});
|
|
208
|
+
}
|
|
209
|
+
|
|
210
|
+
doSomething() {
|
|
211
|
+
this.logger.debug('Debug message');
|
|
212
|
+
this.logger.info('Info message');
|
|
213
|
+
this.logger.warn('Warning message');
|
|
214
|
+
this.logger.error('Error message', new Error('Something went wrong'));
|
|
215
|
+
|
|
216
|
+
// Measure execution time
|
|
217
|
+
this.logger.time('fetchData', async () => {
|
|
218
|
+
return await this.fetchData();
|
|
219
|
+
});
|
|
220
|
+
}
|
|
221
|
+
}
|
|
222
|
+
```
|
|
223
|
+
|
|
224
|
+
### HTTP Utilities
|
|
225
|
+
|
|
226
|
+
#### Error Handling Interceptor
|
|
227
|
+
|
|
228
|
+
Handle HTTP errors with automatic retry:
|
|
229
|
+
|
|
230
|
+
```typescript
|
|
231
|
+
import { ApplicationConfig } from '@angular/core';
|
|
232
|
+
import { provideHttpClient, withInterceptors } from '@angular/common/http';
|
|
233
|
+
import { errorHandlingInterceptor, configureErrorHandling } from '@opensourcekd/ng-common-libs';
|
|
234
|
+
|
|
235
|
+
// Configure error handling
|
|
236
|
+
configureErrorHandling({
|
|
237
|
+
enableLogging: true,
|
|
238
|
+
retryAttempts: 3,
|
|
239
|
+
retryDelay: 1000,
|
|
240
|
+
retryStatusCodes: [500, 502, 503, 504]
|
|
241
|
+
});
|
|
242
|
+
|
|
243
|
+
export const appConfig: ApplicationConfig = {
|
|
244
|
+
providers: [
|
|
245
|
+
provideHttpClient(
|
|
246
|
+
withInterceptors([errorHandlingInterceptor])
|
|
247
|
+
)
|
|
248
|
+
]
|
|
249
|
+
};
|
|
250
|
+
```
|
|
251
|
+
|
|
252
|
+
#### Caching Interceptor
|
|
253
|
+
|
|
254
|
+
Cache HTTP responses:
|
|
255
|
+
|
|
256
|
+
```typescript
|
|
257
|
+
import { ApplicationConfig } from '@angular/core';
|
|
258
|
+
import { provideHttpClient, withInterceptors } from '@angular/common/http';
|
|
259
|
+
import { cachingInterceptor, configureCaching } from '@opensourcekd/ng-common-libs';
|
|
260
|
+
|
|
261
|
+
// Configure caching
|
|
262
|
+
configureCaching({
|
|
263
|
+
enabled: true,
|
|
264
|
+
maxAge: 300000, // 5 minutes
|
|
265
|
+
cacheableUrls: ['/api/users', '/api/products']
|
|
266
|
+
});
|
|
267
|
+
|
|
268
|
+
export const appConfig: ApplicationConfig = {
|
|
269
|
+
providers: [
|
|
270
|
+
provideHttpClient(
|
|
271
|
+
withInterceptors([cachingInterceptor])
|
|
272
|
+
)
|
|
273
|
+
]
|
|
274
|
+
};
|
|
275
|
+
```
|
|
276
|
+
|
|
277
|
+
### For Non-Angular Projects (React, Vue, Svelte, Vanilla JS)
|
|
278
|
+
|
|
279
|
+
Use the framework-agnostic core utilities:
|
|
280
|
+
|
|
281
|
+
```typescript
|
|
282
|
+
// Import from /core
|
|
283
|
+
import { EventBus, TokenManager, StorageManager, Logger, LogLevel } from '@opensourcekd/ng-common-libs/core';
|
|
284
|
+
|
|
285
|
+
// Event Bus
|
|
286
|
+
const eventBus = new EventBus();
|
|
287
|
+
eventBus.emit('user:login', { userId: '123' });
|
|
288
|
+
eventBus.on('user:login').subscribe(data => {
|
|
289
|
+
console.log('User logged in:', data);
|
|
290
|
+
});
|
|
291
|
+
|
|
292
|
+
// Token Manager
|
|
293
|
+
const tokenManager = new TokenManager();
|
|
294
|
+
tokenManager.setToken('your-jwt-token');
|
|
295
|
+
if (tokenManager.isAuthenticated()) {
|
|
296
|
+
const user = tokenManager.getUserFromToken();
|
|
297
|
+
}
|
|
298
|
+
|
|
299
|
+
// Storage Manager
|
|
300
|
+
const storage = new StorageManager();
|
|
301
|
+
storage.setLocal('preferences', { theme: 'dark' });
|
|
302
|
+
const prefs = storage.getLocal('preferences');
|
|
303
|
+
|
|
304
|
+
// Logger
|
|
305
|
+
const logger = new Logger();
|
|
306
|
+
logger.configure({ level: LogLevel.DEBUG, prefix: 'MyApp' });
|
|
307
|
+
logger.info('Application started');
|
|
308
|
+
```
|
|
309
|
+
|
|
310
|
+
#### React Example
|
|
311
|
+
|
|
312
|
+
```typescript
|
|
313
|
+
import { useEffect } from 'react';
|
|
314
|
+
import { EventBus } from '@opensourcekd/ng-common-libs/core';
|
|
315
|
+
|
|
316
|
+
const eventBus = new EventBus();
|
|
317
|
+
|
|
318
|
+
function MyComponent() {
|
|
319
|
+
useEffect(() => {
|
|
320
|
+
const subscription = eventBus.on('user:login').subscribe(data => {
|
|
321
|
+
console.log('User logged in:', data);
|
|
322
|
+
});
|
|
323
|
+
return () => subscription.unsubscribe();
|
|
324
|
+
}, []);
|
|
325
|
+
|
|
326
|
+
const handleLogin = () => {
|
|
327
|
+
eventBus.emit('user:login', { userId: '123' });
|
|
328
|
+
};
|
|
329
|
+
|
|
330
|
+
return <button onClick={handleLogin}>Login</button>;
|
|
331
|
+
}
|
|
332
|
+
```
|
|
333
|
+
|
|
334
|
+
#### Vue Example
|
|
335
|
+
|
|
336
|
+
```typescript
|
|
337
|
+
import { onMounted, onUnmounted } from 'vue';
|
|
338
|
+
import { EventBus } from '@opensourcekd/ng-common-libs/core';
|
|
339
|
+
|
|
340
|
+
const eventBus = new EventBus();
|
|
341
|
+
|
|
342
|
+
export default {
|
|
343
|
+
setup() {
|
|
344
|
+
let subscription;
|
|
345
|
+
|
|
346
|
+
onMounted(() => {
|
|
347
|
+
subscription = eventBus.on('user:login').subscribe(data => {
|
|
348
|
+
console.log('User logged in:', data);
|
|
349
|
+
});
|
|
350
|
+
});
|
|
351
|
+
|
|
352
|
+
onUnmounted(() => {
|
|
353
|
+
subscription?.unsubscribe();
|
|
354
|
+
});
|
|
355
|
+
|
|
356
|
+
const handleLogin = () => {
|
|
357
|
+
eventBus.emit('user:login', { userId: '123' });
|
|
358
|
+
};
|
|
359
|
+
|
|
360
|
+
return { handleLogin };
|
|
361
|
+
}
|
|
362
|
+
};
|
|
363
|
+
```
|
|
364
|
+
|
|
365
|
+
## 📚 Documentation
|
|
366
|
+
|
|
367
|
+
- **[Usage Guide](./docs/USAGE.md)** - Complete usage examples for all utilities
|
|
368
|
+
- **[API Reference](./docs/API.md)** - Detailed API documentation
|
|
369
|
+
- **[Deployment Guide](./docs/DEPLOYMENT.md)** - Publishing, versioning, and consumption
|
|
370
|
+
- **[Architecture Decisions](./ARCHITECTURE_DECISIONS.md)** - Detailed architecture and design decisions
|
|
371
|
+
|
|
372
|
+
## 📝 API Documentation
|
|
373
|
+
|
|
374
|
+
### NgEventEmitter
|
|
375
|
+
|
|
376
|
+
- `emit<T>(eventType: string, data?: T): void` - Emit an event
|
|
377
|
+
- `on<T>(eventType: string): Observable<T>` - Subscribe to an event
|
|
378
|
+
- `onMultiple(eventTypes: string[]): Observable<EventPayload>` - Subscribe to multiple events
|
|
379
|
+
- `onAll(): Observable<EventPayload>` - Subscribe to all events
|
|
380
|
+
|
|
381
|
+
### TokenService
|
|
382
|
+
|
|
383
|
+
- `setToken(token: string): void` - Store authentication token
|
|
384
|
+
- `getToken(): string | null` - Retrieve authentication token
|
|
385
|
+
- `removeToken(): void` - Remove authentication token
|
|
386
|
+
- `clearTokens(): void` - Clear all tokens
|
|
387
|
+
- `isAuthenticated(): boolean` - Check if user is authenticated
|
|
388
|
+
- `isTokenExpired(token?: string): boolean` - Check if token is expired
|
|
389
|
+
- `getUserFromToken(token?: string): any` - Extract user data from token
|
|
390
|
+
|
|
391
|
+
### StorageService
|
|
392
|
+
|
|
393
|
+
- `setLocal<T>(key: string, value: T): boolean` - Set item in localStorage
|
|
394
|
+
- `getLocal<T>(key: string, defaultValue?: T): T | null` - Get item from localStorage
|
|
395
|
+
- `removeLocal(key: string): void` - Remove item from localStorage
|
|
396
|
+
- `setSession<T>(key: string, value: T): boolean` - Set item in sessionStorage
|
|
397
|
+
- `getSession<T>(key: string, defaultValue?: T): T | null` - Get item from sessionStorage
|
|
398
|
+
- `setWithExpiration<T>(key, value, expirationMs, useSession?): boolean` - Set item with expiration
|
|
399
|
+
- `getWithExpiration<T>(key, useSession?): T | null` - Get item with expiration check
|
|
400
|
+
|
|
401
|
+
### LoggerService
|
|
402
|
+
|
|
403
|
+
- `debug(message: string, ...args: any[]): void` - Log debug message
|
|
404
|
+
- `info(message: string, ...args: any[]): void` - Log info message
|
|
405
|
+
- `warn(message: string, ...args: any[]): void` - Log warning message
|
|
406
|
+
- `error(message: string, error?: any, ...args: any[]): void` - Log error message
|
|
407
|
+
- `time<T>(label: string, fn: () => Promise<T> | T): Promise<T>` - Measure execution time
|
|
408
|
+
|
|
409
|
+
## 🛠️ Development
|
|
410
|
+
|
|
411
|
+
```bash
|
|
412
|
+
# Install dependencies
|
|
413
|
+
npm install
|
|
414
|
+
|
|
415
|
+
# Build the library
|
|
416
|
+
npm run build
|
|
417
|
+
|
|
418
|
+
# Run linter
|
|
419
|
+
npm run lint
|
|
420
|
+
```
|
|
421
|
+
|
|
422
|
+
## 📄 License
|
|
423
|
+
|
|
424
|
+
MIT
|
|
425
|
+
|
|
426
|
+
## 👤 Author
|
|
427
|
+
|
|
428
|
+
Koustubh Desai <jobs.koustubh@gmail.com>
|
|
429
|
+
|
|
430
|
+
## 🤝 Contributing
|
|
431
|
+
|
|
432
|
+
Contributions, issues, and feature requests are welcome!
|
|
433
|
+
|
|
434
|
+
## ⭐ Show your support
|
|
435
|
+
|
|
436
|
+
Give a ⭐️ if this project helped you!
|
|
437
|
+
|