http-request-manager 18.7.11 → 18.7.12
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
|
@@ -1,128 +1,44 @@
|
|
|
1
|
-
# Request Manager
|
|
1
|
+
# HTTP Request Manager - Angular Library
|
|
2
2
|
|
|
3
|
-
|
|
3
|
+
[](https://www.typescriptlang.org/)
|
|
4
|
+
[](https://angular.io/)
|
|
5
|
+
[](https://rxjs.dev/)
|
|
4
6
|
|
|
5
|
-
|
|
7
|
+
A comprehensive Angular library providing enterprise-grade HTTP request management, state management, real-time communication, and local data persistence.
|
|
8
|
+
|
|
9
|
+
## 🚀 Features
|
|
6
10
|
|
|
7
11
|
### Core Capabilities
|
|
8
12
|
|
|
9
|
-
|
|
10
|
-
|
|
11
|
-
|
|
12
|
-
|
|
13
|
-
-
|
|
14
|
-
|
|
15
|
-
|
|
16
|
-
|
|
17
|
-
- Built-in error handling with optional toast notifications
|
|
18
|
-
- File download support with progress tracking
|
|
19
|
-
|
|
20
|
-
#### 🔄 State Management
|
|
21
|
-
|
|
22
|
-
- **ComponentStore integration** (`HTTPManagerStateService`) for robust state management
|
|
23
|
-
- Automatic CRUD state updates (Create, Read, Update, Delete)
|
|
24
|
-
- Built-in selectors for data access and filtering
|
|
25
|
-
- Pagination support with state tracking
|
|
26
|
-
- Real-time state synchronization via WebSocket
|
|
27
|
-
- IndexedDB caching for offline-first applications
|
|
28
|
-
- Persistent state with LocalStorage/SessionStorage
|
|
29
|
-
|
|
30
|
-
#### 💬 Real-Time Communication (WebSocket)
|
|
31
|
-
|
|
32
|
-
- **Dual-mode messaging system:**
|
|
33
|
-
- **Messaging (PUB- channels)**: Real-time chat/collaboration
|
|
34
|
-
- **Notifications (MES- channels)**: Database-persisted notifications with date-range queries
|
|
35
|
-
- Automatic reconnection with exponential backoff
|
|
36
|
-
- JWT authentication support
|
|
37
|
-
- Channel-based architecture (STATE, MESSAGE, NOTIFICATION)
|
|
38
|
-
- Subscribe/unsubscribe to channels dynamically
|
|
39
|
-
- Broadcast, channel, and user-specific messaging
|
|
40
|
-
- Connection status monitoring
|
|
41
|
-
- Session persistence across reconnections
|
|
42
|
-
|
|
43
|
-
#### 💾 Data Persistence
|
|
44
|
-
|
|
45
|
-
- **LocalStorage/SessionStorage** with encryption and expiration
|
|
46
|
-
- **IndexedDB** integration via Dexie.js for complex queries
|
|
47
|
-
- Automatic cache invalidation based on time
|
|
48
|
-
- Secure encryption using symmetrical encryption service
|
|
49
|
-
- Reactive storage observables for UI synchronization
|
|
50
|
-
|
|
51
|
-
#### 🎯 Advanced Features
|
|
52
|
-
|
|
53
|
-
- Request interception (credentials, headers, error handling)
|
|
54
|
-
- Automatic loading state management
|
|
55
|
-
- Database-backed notification history with epoch filtering
|
|
56
|
-
- Define and load previous day's notification channels
|
|
57
|
-
- Bulk operations for IndexedDB
|
|
58
|
-
- Model adapters for type safety
|
|
59
|
-
- Configurable global defaults via `forRoot()`
|
|
13
|
+
| Feature | Description | Service |
|
|
14
|
+
|---------|-------------|---------|
|
|
15
|
+
| **🌐 HTTP Request Management** | Observable-based & Signal-based HTTP services with retry logic, polling, and streaming | [`HTTPManagerService`](services/http-manager/README.md) |
|
|
16
|
+
| **🔄 State Management** | ComponentStore integration with automatic CRUD state updates | [`HTTPManagerStateService`](services/http-state/README.md) |
|
|
17
|
+
| **💬 Real-Time Communication** | WebSocket messaging with channel-based architecture | [`WebSocketService`](services/websocket/README.md) |
|
|
18
|
+
| **💾 Data Persistence** | LocalStorage/SessionStorage with encryption & IndexedDB caching | [`LocalStorageManagerService`](services/local-storage/README.md) |
|
|
19
|
+
| **🗄️ Database Management** | IndexedDB integration via Dexie.js with Observable API | [`DatabaseManagerService`](services/database/README.md) |
|
|
20
|
+
| **⚡ Utility Functions** | JSON handling, expiration, conversions, and validation | [`UtilsService`](services/utils/README.md) |
|
|
60
21
|
|
|
61
22
|
### Key Benefits
|
|
62
23
|
|
|
63
|
-
✅ **
|
|
64
|
-
✅ **
|
|
65
|
-
✅ **
|
|
66
|
-
✅ **
|
|
67
|
-
✅ **
|
|
68
|
-
✅ **
|
|
69
|
-
✅ **Flexible** - Works with Observables or Signals based on preference
|
|
70
|
-
✅ **Battle-Tested** - Production-ready with comprehensive error handling
|
|
71
|
-
|
|
72
|
-
### Use Cases
|
|
73
|
-
|
|
74
|
-
| Scenario | Solution |
|
|
75
|
-
|----------|----------|
|
|
76
|
-
| Simple API calls with loading states | `HTTPManagerService` |
|
|
77
|
-
| Modern reactive UI with Signals | `HTTPManagerSignalsService` |
|
|
78
|
-
| CRUD operations with auto state sync | `HTTPManagerStateService` |
|
|
79
|
-
| Real-time chat/collaboration | `HTTPManagerStateService` + WebSocket (PUB- channels) |
|
|
80
|
-
| Persistent notifications/alerts | `HTTPManagerStateService` + WebSocket (MES- channels) |
|
|
81
|
-
| User preferences/settings | `LocalStorageManagerService` |
|
|
82
|
-
| Offline-first data access | `DatabaseManagerService` + `HTTPManagerStateService` |
|
|
83
|
-
| Large local datasets | `DatabaseManagerService` with Dexie.js |
|
|
84
|
-
| Polling for live updates | `HTTPManagerService` with polling |
|
|
85
|
-
| File downloads | `HTTPManagerService.downloadRequest()` |
|
|
86
|
-
|
|
87
|
-
---
|
|
88
|
-
|
|
89
|
-
## Demo Component (`HttpRequestServicesDemoComponent`)
|
|
90
|
-
|
|
91
|
-
The `HttpRequestServicesDemoComponent` is a comprehensive demonstration component that showcases the various services available in the `http-request-manager` library. It allows you to interactively test and visualize the functionality of HTTP services, state management, WebSockets, and local storage.
|
|
92
|
-
|
|
93
|
-
### Usage
|
|
94
|
-
|
|
95
|
-
To use the demo component in your application, simply add the selector to your template and provide the necessary inputs.
|
|
96
|
-
|
|
97
|
-
```html
|
|
98
|
-
<app-http-request-services-demo
|
|
99
|
-
[server]="'http://localhost:8080'"
|
|
100
|
-
[wsServer]="'ws://localhost:8080'"
|
|
101
|
-
[jwtToken]="'your-jwt-token'"
|
|
102
|
-
[adapter]="myAdapterFunction"
|
|
103
|
-
[mapper]="myMapperFunction">
|
|
104
|
-
</app-http-request-services-demo>
|
|
105
|
-
```
|
|
106
|
-
|
|
107
|
-
### Inputs
|
|
108
|
-
|
|
109
|
-
| Input | Type | Description | Default |
|
|
110
|
-
| :--- | :--- | :--- | :--- |
|
|
111
|
-
| `server` | `string` | The base URL for HTTP requests used in the demo. | `'http://localhost:8080'` |
|
|
112
|
-
| `wsServer` | `string` | The WebSocket server URL for testing WS connections. | `'ws://localhost:8080'` |
|
|
113
|
-
| `jwtToken` | `string` | A JWT token used for authenticating WebSocket connections. | `''` |
|
|
114
|
-
| `adapter` | `Function` | An optional adapter function to transform incoming API data. | `undefined` |
|
|
115
|
-
| `mapper` | `Function` | An optional mapper function to transform outgoing request payloads. | `undefined` |
|
|
24
|
+
- ✅ **Type-Safe** - Full TypeScript support with generics
|
|
25
|
+
- ✅ **Offline-First** - Built-in IndexedDB caching
|
|
26
|
+
- ✅ **Real-Time Ready** - Seamless WebSocket integration
|
|
27
|
+
- ✅ **Secure** - Encryption support for sensitive data
|
|
28
|
+
- ✅ **Scalable** - ComponentStore-based architecture
|
|
29
|
+
- ✅ **Flexible** - Works with Observables or Signals
|
|
116
30
|
|
|
117
|
-
|
|
118
|
-
|
|
119
|
-
## Summary
|
|
31
|
+
## 📋 Table of Contents
|
|
120
32
|
|
|
121
|
-
|
|
122
|
-
|
|
123
|
-
|
|
33
|
+
- [Quick Start](#quick-start)
|
|
34
|
+
- [Configuration](#configuration)
|
|
35
|
+
- [Services Overview](#services-overview)
|
|
36
|
+
- [Architecture](#architecture)
|
|
37
|
+
- [Interceptors](#interceptors)
|
|
38
|
+
- [Demo Examples](#demo-examples)
|
|
39
|
+
- [Migration Guide](#migration-guide)
|
|
124
40
|
|
|
125
|
-
## Quick Start
|
|
41
|
+
## 🚀 Quick Start
|
|
126
42
|
|
|
127
43
|
### Installation & Setup (2 minutes)
|
|
128
44
|
|
|
@@ -160,9 +76,9 @@ import { APP_ID } from '@angular/core';
|
|
|
160
76
|
export class AppModule { }
|
|
161
77
|
```
|
|
162
78
|
|
|
163
|
-
###
|
|
79
|
+
### Simple Examples
|
|
164
80
|
|
|
165
|
-
####
|
|
81
|
+
#### Basic HTTP Request
|
|
166
82
|
|
|
167
83
|
```typescript
|
|
168
84
|
import { Component, inject } from '@angular/core';
|
|
@@ -191,18 +107,9 @@ export class UsersComponent {
|
|
|
191
107
|
}
|
|
192
108
|
```
|
|
193
109
|
|
|
194
|
-
####
|
|
110
|
+
#### State Management with CRUD
|
|
195
111
|
|
|
196
112
|
```typescript
|
|
197
|
-
import { Injectable } from '@angular/core';
|
|
198
|
-
import { HTTPManagerStateService, ApiRequest, DataType } from 'http-request-manager';
|
|
199
|
-
|
|
200
|
-
interface User {
|
|
201
|
-
id: number;
|
|
202
|
-
name: string;
|
|
203
|
-
email: string;
|
|
204
|
-
}
|
|
205
|
-
|
|
206
113
|
@Injectable({ providedIn: 'root' })
|
|
207
114
|
export class UsersStore extends HTTPManagerStateService<User> {
|
|
208
115
|
|
|
@@ -239,288 +146,11 @@ export class UsersComponent {
|
|
|
239
146
|
}
|
|
240
147
|
```
|
|
241
148
|
|
|
242
|
-
|
|
243
|
-
|
|
244
|
-
```typescript
|
|
245
|
-
@Injectable({ providedIn: 'root' })
|
|
246
|
-
export class ChatStore extends HTTPManagerStateService<Message> {
|
|
247
|
-
|
|
248
|
-
constructor() {
|
|
249
|
-
super(
|
|
250
|
-
ApiRequest.adapt({
|
|
251
|
-
server: 'http://localhost:8080',
|
|
252
|
-
path: ['messages'],
|
|
253
|
-
ws: {
|
|
254
|
-
id: 'CHAT_WS',
|
|
255
|
-
wsServer: 'ws://localhost:8080',
|
|
256
|
-
jwtToken: '' // Add token if needed
|
|
257
|
-
}
|
|
258
|
-
}),
|
|
259
|
-
DataType.ARRAY
|
|
260
|
-
);
|
|
261
|
-
}
|
|
262
|
-
|
|
263
|
-
joinChat(channel: string) {
|
|
264
|
-
this.createChannel(channel);
|
|
265
|
-
this.subscribeToChannel(channel);
|
|
266
|
-
}
|
|
267
|
-
|
|
268
|
-
sendMessage(channel: string, text: string, user: any) {
|
|
269
|
-
this.wsMessaging(
|
|
270
|
-
ChannelMessage.adapt({
|
|
271
|
-
sessionId: user,
|
|
272
|
-
content: { message: text }
|
|
273
|
-
}),
|
|
274
|
-
[channel]
|
|
275
|
-
);
|
|
276
|
-
}
|
|
277
|
-
}
|
|
278
|
-
|
|
279
|
-
// Component
|
|
280
|
-
@Component({
|
|
281
|
-
template: `
|
|
282
|
-
<div *ngFor="let msg of chatStore.communicationMessages$ | async">
|
|
283
|
-
{{ msg.content.message }}
|
|
284
|
-
</div>
|
|
285
|
-
<input [(ngModel)]="messageText">
|
|
286
|
-
<button (click)="send()">Send</button>
|
|
287
|
-
`
|
|
288
|
-
})
|
|
289
|
-
export class ChatComponent {
|
|
290
|
-
chatStore = inject(ChatStore);
|
|
291
|
-
messageText = '';
|
|
292
|
-
|
|
293
|
-
ngOnInit() {
|
|
294
|
-
this.chatStore.joinChat('general');
|
|
295
|
-
}
|
|
296
|
-
|
|
297
|
-
send() {
|
|
298
|
-
this.chatStore.sendMessage('general', this.messageText, {
|
|
299
|
-
id: 1,
|
|
300
|
-
name: 'John'
|
|
301
|
-
});
|
|
302
|
-
this.messageText = '';
|
|
303
|
-
}
|
|
304
|
-
}
|
|
305
|
-
```
|
|
306
|
-
|
|
307
|
-
#### Example 4: Persistent Notifications with Database
|
|
308
|
-
|
|
309
|
-
```typescript
|
|
310
|
-
@Injectable({ providedIn: 'root' })
|
|
311
|
-
export class NotificationStore extends HTTPManagerStateService<any> {
|
|
312
|
-
|
|
313
|
-
constructor() {
|
|
314
|
-
super(
|
|
315
|
-
ApiRequest.adapt({
|
|
316
|
-
server: 'http://localhost:8080',
|
|
317
|
-
ws: {
|
|
318
|
-
id: 'NOTIFICATIONS',
|
|
319
|
-
wsServer: 'ws://localhost:8080'
|
|
320
|
-
}
|
|
321
|
-
}),
|
|
322
|
-
DataType.ARRAY
|
|
323
|
-
);
|
|
324
|
-
}
|
|
325
|
-
|
|
326
|
-
initNotifications(user: any) {
|
|
327
|
-
// Get today's notification channels
|
|
328
|
-
this.getTodaysNotificationChannels();
|
|
329
|
-
|
|
330
|
-
// Subscribe to alerts with 24h history
|
|
331
|
-
this.subscribeToNotificationChannel('alerts', {
|
|
332
|
-
startEpoch: Math.floor(Date.now() / 1000) - 86400
|
|
333
|
-
}, user);
|
|
334
|
-
}
|
|
335
|
-
|
|
336
|
-
sendAlert(message: string, priority: 'low' | 'high') {
|
|
337
|
-
this.sendNotification('alerts', {
|
|
338
|
-
message,
|
|
339
|
-
priority,
|
|
340
|
-
timestamp: Date.now()
|
|
341
|
-
});
|
|
342
|
-
}
|
|
343
|
-
|
|
344
|
-
loadPreviousDayChannels() {
|
|
345
|
-
this.definePreviousNotificationChannels();
|
|
346
|
-
}
|
|
347
|
-
}
|
|
348
|
-
|
|
349
|
-
// Component
|
|
350
|
-
@Component({
|
|
351
|
-
template: `
|
|
352
|
-
<div *ngFor="let notif of store.notificationMessages$ | async">
|
|
353
|
-
<strong>{{ notif.user_name }}</strong>: {{ notif.content.message }}
|
|
354
|
-
<span>{{ notif.created * 1000 | date:'short' }}</span>
|
|
355
|
-
</div>
|
|
356
|
-
<button (click)="store.loadPreviousDayChannels()">
|
|
357
|
-
Load Previous Day Channels
|
|
358
|
-
</button>
|
|
359
|
-
`
|
|
360
|
-
})
|
|
361
|
-
export class NotificationsComponent {
|
|
362
|
-
store = inject(NotificationStore);
|
|
363
|
-
|
|
364
|
-
ngOnInit() {
|
|
365
|
-
this.store.initNotifications({
|
|
366
|
-
id: 1,
|
|
367
|
-
name: 'John',
|
|
368
|
-
email: 'john@example.com'
|
|
369
|
-
});
|
|
370
|
-
}
|
|
371
|
-
}
|
|
372
|
-
```
|
|
373
|
-
|
|
374
|
-
#### Example 5: Local Storage with Encryption
|
|
375
|
-
|
|
376
|
-
```typescript
|
|
377
|
-
import { Component, inject } from '@angular/core';
|
|
378
|
-
import { LocalStorageManagerService, SettingOptions } from 'http-request-manager';
|
|
379
|
-
|
|
380
|
-
@Component({
|
|
381
|
-
selector: 'app-settings'
|
|
382
|
-
})
|
|
383
|
-
export class SettingsComponent {
|
|
384
|
-
storage = inject(LocalStorageManagerService);
|
|
385
|
-
|
|
386
|
-
saveSettings(settings: any) {
|
|
387
|
-
this.storage.setItem(
|
|
388
|
-
'user-preferences',
|
|
389
|
-
settings,
|
|
390
|
-
SettingOptions.adapt({
|
|
391
|
-
encrypted: true,
|
|
392
|
-
expiresIn: '30d'
|
|
393
|
-
})
|
|
394
|
-
);
|
|
395
|
-
}
|
|
396
|
-
|
|
397
|
-
loadSettings() {
|
|
398
|
-
return this.storage.getItem('user-preferences');
|
|
399
|
-
}
|
|
400
|
-
|
|
401
|
-
clearSettings() {
|
|
402
|
-
this.storage.removeItem('user-preferences');
|
|
403
|
-
}
|
|
404
|
-
}
|
|
405
|
-
```
|
|
406
|
-
|
|
407
|
-
#### Example 6: IndexedDB Caching for Offline-First
|
|
408
|
-
|
|
409
|
-
```typescript
|
|
410
|
-
@Injectable({ providedIn: 'root' })
|
|
411
|
-
export class ProductStore extends HTTPManagerStateService<Product> {
|
|
412
|
-
|
|
413
|
-
constructor() {
|
|
414
|
-
super(
|
|
415
|
-
ApiRequest.adapt({
|
|
416
|
-
server: 'http://localhost:8080',
|
|
417
|
-
path: ['products'],
|
|
418
|
-
adapter: (data: any) => data as Product // Required for DB
|
|
419
|
-
}),
|
|
420
|
-
DataType.ARRAY,
|
|
421
|
-
DatabaseStorage.adapt({
|
|
422
|
-
table: 'products-cache',
|
|
423
|
-
expiresIn: '1d' // Cache for 1 day
|
|
424
|
-
})
|
|
425
|
-
);
|
|
426
|
-
}
|
|
427
|
-
|
|
428
|
-
loadProducts() {
|
|
429
|
-
// First checks IndexedDB cache, then fetches from server if expired
|
|
430
|
-
this.fetchRecords();
|
|
431
|
-
}
|
|
432
|
-
}
|
|
433
|
-
```
|
|
434
|
-
|
|
435
|
-
#### Example 7: Polling for Live Updates
|
|
436
|
-
|
|
437
|
-
```typescript
|
|
438
|
-
export class StatusComponent {
|
|
439
|
-
httpManager = inject(HTTPManagerService);
|
|
440
|
-
|
|
441
|
-
status$ = this.httpManager.data$;
|
|
442
|
-
countdown$ = this.httpManager.countdown$;
|
|
443
|
-
|
|
444
|
-
ngOnInit() {
|
|
445
|
-
this.httpManager.getRequest(
|
|
446
|
-
ApiRequest.adapt({
|
|
447
|
-
path: ['server-status'],
|
|
448
|
-
polling: 10 // Poll every 10 seconds
|
|
449
|
-
})
|
|
450
|
-
).subscribe();
|
|
451
|
-
}
|
|
452
|
-
|
|
453
|
-
ngOnDestroy() {
|
|
454
|
-
this.httpManager.stopPolling();
|
|
455
|
-
}
|
|
456
|
-
}
|
|
457
|
-
```
|
|
458
|
-
|
|
459
|
-
### Common Use Cases
|
|
460
|
-
|
|
461
|
-
| Use Case | Service to Use | Key Features |
|
|
462
|
-
|----------|---------------|--------------|
|
|
463
|
-
| Simple API calls | `HTTPManagerService` | Observables, retry, polling |
|
|
464
|
-
| Modern reactive UI | `HTTPManagerSignalsService` | Angular Signals |
|
|
465
|
-
| CRUD operations | `HTTPManagerStateService` | Auto state updates |
|
|
466
|
-
| Real-time chat | `HTTPManagerStateService` + WS | Messaging channels |
|
|
467
|
-
| Persistent notifications | `HTTPManagerStateService` + WS | Database-backed |
|
|
468
|
-
| User preferences | `LocalStorageManagerService` | Encryption, expiration |
|
|
469
|
-
| Offline-first | `DatabaseManagerService` | IndexedDB |
|
|
470
|
-
| Large local datasets | `DatabaseManagerService` | Querying, indexing |
|
|
471
|
-
|
|
472
|
-
---
|
|
473
|
-
|
|
474
|
-
## Initialization
|
|
475
|
-
|
|
476
|
-
### 1. Module Initialization (`forRoot`)
|
|
477
|
-
|
|
478
|
-
To use the library, import `HttpRequestManagerModule` in your `AppModule` and configure it using the `forRoot` method.
|
|
479
|
-
|
|
480
|
-
#### Configuration Options (`ConfigOptions`)
|
|
481
|
-
|
|
482
|
-
| Option | Type | Description | Default |
|
|
483
|
-
| :--- | :--- | :--- | :--- |
|
|
484
|
-
| `httpRequestOptions` | `ConfigHTTPOptions` | Global configuration for HTTP requests. | `undefined` |
|
|
485
|
-
| `LocalStorageOptions` | `LocalStorageOptions` | Global configuration for Local Storage management. | `undefined` |
|
|
486
|
-
|
|
487
|
-
#### HTTP Options (`ConfigHTTPOptions`)
|
|
488
|
-
|
|
489
|
-
| Option | Type | Description | Default |
|
|
490
|
-
| :--- | :--- | :--- | :--- |
|
|
491
|
-
| `server` | `string` | The base URL for API requests. | `''` |
|
|
492
|
-
| `path` | `any[]` | Default path segments to append to the server URL. | `[]` |
|
|
493
|
-
| `headers` | `any` | Default headers to include in every request. | `{}` |
|
|
494
|
-
| `polling` | `number` | Default polling interval in seconds (0 = disabled). | `0` |
|
|
495
|
-
| `retry` | `RetryOptions` | Default retry configuration. | `{ times: 0, delay: 3 }` |
|
|
496
|
-
| `stream` | `boolean` | Whether to enable streaming by default. | `false` |
|
|
497
|
-
| `displayError` | `boolean` | Whether to display toast notifications for errors by default. | `false` |
|
|
498
|
-
|
|
499
|
-
#### Retry Options (`RetryOptions`)
|
|
500
|
-
|
|
501
|
-
| Option | Type | Description | Default |
|
|
502
|
-
| :--- | :--- | :--- | :--- |
|
|
503
|
-
| `times` | `number` | The number of retry attempts. | `0` |
|
|
504
|
-
| `delay` | `number` | The delay between retries in seconds. | `3` |
|
|
505
|
-
|
|
506
|
-
#### Local Storage Options (`LocalStorageOptions`)
|
|
507
|
-
|
|
508
|
-
| Option | Type | Description | Default |
|
|
509
|
-
| :--- | :--- | :--- | :--- |
|
|
510
|
-
| `storageName` | `string` | The key used to store data in localStorage/sessionStorage. | `'storage'` |
|
|
511
|
-
| `storageSettingsName` | `string` | The key used to store settings metadata. | `'global-storage'` |
|
|
512
|
-
| `options` | `SettingOptions` | Default settings for stored items. | `{ storage: StorageType.GLOBAL, expires: 0, expiresIn: '', encrypted: false }` |
|
|
513
|
-
|
|
514
|
-
#### Setting Options (`SettingOptions`)
|
|
149
|
+
## ⚙️ Configuration
|
|
515
150
|
|
|
516
|
-
|
|
517
|
-
| :--- | :--- | :--- | :--- |
|
|
518
|
-
| `storage` | `StorageType` | The type of storage to use (`StorageType.GLOBAL` or `StorageType.SESSION`). | `StorageType.GLOBAL` |
|
|
519
|
-
| `expires` | `number` | Expiration timestamp (epoch). Usually calculated from `expiresIn`. | `0` |
|
|
520
|
-
| `expiresIn` | `string` | Duration string (e.g., '1d', '2h') for expiration. | `''` |
|
|
521
|
-
| `encrypted` | `boolean` | Whether to encrypt the stored data. | `false` |
|
|
151
|
+
### Module Initialization (`forRoot`)
|
|
522
152
|
|
|
523
|
-
|
|
153
|
+
Configure the library globally using the `forRoot` method:
|
|
524
154
|
|
|
525
155
|
```typescript
|
|
526
156
|
import { HttpRequestManagerModule } from 'http-request-manager';
|
|
@@ -543,943 +173,254 @@ import { HttpRequestManagerModule } from 'http-request-manager';
|
|
|
543
173
|
}
|
|
544
174
|
}
|
|
545
175
|
})
|
|
546
|
-
]
|
|
547
|
-
// ...
|
|
548
|
-
})
|
|
549
|
-
export class AppModule { }
|
|
550
|
-
```
|
|
551
|
-
|
|
552
|
-
### 2. AppService Initialization
|
|
553
|
-
|
|
554
|
-
The `AppService` (used by `LocalStorageManagerService` for encryption) requires a unique `APP_ID` to be provided in your `AppModule`.
|
|
555
|
-
|
|
556
|
-
```typescript
|
|
557
|
-
import { APP_ID } from '@angular/core';
|
|
558
|
-
|
|
559
|
-
@NgModule({
|
|
560
|
-
providers: [
|
|
561
|
-
{
|
|
562
|
-
provide: APP_ID,
|
|
563
|
-
useValue: "your-unique-guid-here", // e.g., "056991ac-3537-43ab-b5b9-83edf6554eff"
|
|
564
|
-
},
|
|
565
|
-
// ...
|
|
566
|
-
],
|
|
567
|
-
// ...
|
|
176
|
+
]
|
|
568
177
|
})
|
|
569
178
|
export class AppModule { }
|
|
570
179
|
```
|
|
571
180
|
|
|
572
|
-
|
|
573
|
-
|
|
574
|
-
### 1. Request Manager Service (`HTTPManagerService`)
|
|
575
|
-
|
|
576
|
-
**Path:** `request-manager-services/http-manager.service.ts`
|
|
577
|
-
|
|
578
|
-
A robust HTTP client service using RxJS `BehaviorSubject` for state management.
|
|
579
|
-
|
|
580
|
-
**What it does:**
|
|
581
|
-
This service acts as a wrapper around Angular's `HttpClient`, providing a centralized way to manage HTTP requests. It handles the entire lifecycle of a request, including loading states, error handling, and data updates, exposing them as Observables.
|
|
582
|
-
|
|
583
|
-
**Features:**
|
|
584
|
-
|
|
585
|
-
- **State Management:** Exposes `data$`, `isPending$`, `error$`, and `countdown$` observables.
|
|
586
|
-
- **Polling:** Supports automatic polling of endpoints with a configurable interval and countdown timer.
|
|
587
|
-
- **Retries:** Automatically retries failed requests based on configuration (number of attempts and delay).
|
|
588
|
-
- **Adapters & Mappers:** Supports `adapter` functions to transform incoming data and `mapper` functions for outgoing payloads.
|
|
589
|
-
- **Streaming:** Handles streaming responses when configured.
|
|
590
|
-
- **Error Handling:** Centralized error handling with optional Toast notifications.
|
|
591
|
-
- **CRUD Support:** Provides methods for `getRequest`, `postRequest`, `putRequest`, `deleteRequest`, and `downloadRequest`.
|
|
592
|
-
|
|
593
|
-
**Usage:**
|
|
594
|
-
Inject `HTTPManagerService` to make API requests. It handles loading state, errors, and data updates via Observables.
|
|
181
|
+
### Configuration Options
|
|
595
182
|
|
|
596
|
-
####
|
|
183
|
+
#### HTTP Options (`ConfigHTTPOptions`)
|
|
597
184
|
|
|
598
185
|
| Option | Type | Description | Default |
|
|
599
|
-
|
|
600
|
-
| `server` | `string` |
|
|
601
|
-
| `path` | `any[]` |
|
|
602
|
-
| `headers` | `any` |
|
|
603
|
-
| `
|
|
604
|
-
| `
|
|
605
|
-
| `
|
|
606
|
-
| `
|
|
607
|
-
| `stream` | `boolean` | Enable streaming response handling. | `false` |
|
|
608
|
-
| `displayError` | `boolean` | Show toast notification on error. | `false` |
|
|
609
|
-
| `saveAs` | `string` | Filename for file downloads. | `undefined` |
|
|
610
|
-
| `ws` | `WSOptions` | WebSocket configuration options. | `undefined` |
|
|
611
|
-
|
|
612
|
-
#### HTTPManagerService Example
|
|
613
|
-
|
|
614
|
-
```typescript
|
|
615
|
-
export class MyComponent {
|
|
616
|
-
httpManager = inject(HTTPManagerService);
|
|
617
|
-
|
|
618
|
-
data$ = this.httpManager.data$;
|
|
619
|
-
isLoading$ = this.httpManager.isPending$;
|
|
620
|
-
error$ = this.httpManager.error$;
|
|
621
|
-
|
|
622
|
-
fetchData() {
|
|
623
|
-
const options = ApiRequest.adapt({
|
|
624
|
-
path: ['users'],
|
|
625
|
-
polling: 5, // Poll every 5 seconds
|
|
626
|
-
retry: { times: 3, delay: 1 },
|
|
627
|
-
adapter: User.adapt // Transform response to User model
|
|
628
|
-
});
|
|
629
|
-
|
|
630
|
-
this.httpManager.getRequest(options).subscribe();
|
|
631
|
-
}
|
|
632
|
-
}
|
|
633
|
-
```
|
|
634
|
-
|
|
635
|
-
#### Advanced Features
|
|
636
|
-
|
|
637
|
-
| Feature | Description | Configuration |
|
|
638
|
-
| :--- | :--- | :--- |
|
|
639
|
-
| **Streaming** | Handle streaming responses (e.g., NDJSON). | Set `stream: true` in `ApiRequest`. |
|
|
640
|
-
| **Polling** | Automatically poll the endpoint at a specified interval. | Set `polling: number` (seconds) in `ApiRequest`. |
|
|
641
|
-
| **Retry** | Automatically retry failed requests. | Configure `retry: { times: 3, delay: 3 }` in `ApiRequest`. |
|
|
642
|
-
| **Adapters** | Transform incoming API response data before it reaches the state. | Use `adapter: (data) => transformedData` in `ApiRequest`. |
|
|
643
|
-
| **Mappers** | Transform outgoing payload data before sending to the API. | Use `mapper: (data) => transformedData` in `ApiRequest`. |
|
|
644
|
-
|
|
645
|
-
```typescript
|
|
646
|
-
const options = ApiRequest.adapt({
|
|
647
|
-
path: ['users'],
|
|
648
|
-
polling: 5, // Poll every 5 seconds
|
|
649
|
-
retry: { times: 3, delay: 1 },
|
|
650
|
-
adapter: User.adapt // Transform response to User model
|
|
651
|
-
});
|
|
652
|
-
```
|
|
653
|
-
|
|
654
|
-
### 2. Request Manager Signal Service (`HTTPManagerSignalsService`)
|
|
655
|
-
|
|
656
|
-
**Path:** `request-manager-services/http-manager-signals.service.ts`
|
|
657
|
-
|
|
658
|
-
A modern alternative to `HTTPManagerService` using Angular Signals for state management.
|
|
659
|
-
|
|
660
|
-
**What it does:**
|
|
661
|
-
This service provides the same functionality as `HTTPManagerService` but exposes state using Angular Signals instead of RxJS Observables. This is ideal for modern Angular applications leveraging fine-grained reactivity.
|
|
662
|
-
|
|
663
|
-
**Features:**
|
|
664
|
-
|
|
665
|
-
- **Signal-Based State:** Exposes `data`, `isPending`, `error`, and `countdown` as Signals.
|
|
666
|
-
- **Feature Parity:** Supports all features of `HTTPManagerService` including polling, retries, adapters, and streaming.
|
|
667
|
-
- **Optimized for Signals:** Designed to work seamlessly with Angular's Signal-based components and templates.
|
|
668
|
-
|
|
669
|
-
**Usage:**
|
|
670
|
-
Ideal for components using Angular Signals.
|
|
671
|
-
|
|
672
|
-
```typescript
|
|
673
|
-
export class MyComponent {
|
|
674
|
-
httpManager = inject(HTTPManagerSignalsService);
|
|
675
|
-
|
|
676
|
-
data = this.httpManager.data; // Signal
|
|
677
|
-
isLoading = this.httpManager.isPending; // Signal
|
|
678
|
-
error = this.httpManager.error; // Signal
|
|
679
|
-
|
|
680
|
-
fetchData() {
|
|
681
|
-
const options = ApiRequest.adapt({ path: ['users'] });
|
|
682
|
-
this.httpManager.getRequest(options).subscribe();
|
|
683
|
-
}
|
|
684
|
-
}
|
|
685
|
-
```
|
|
686
|
-
|
|
687
|
-
### 3. Request Manager State Service (`HTTPManagerStateService`)
|
|
688
|
-
|
|
689
|
-
**Path:** `request-manager-state-service/http-manager-state.store.ts`
|
|
690
|
-
|
|
691
|
-
An extension of `ComponentStore` designed for managing entity state (CRUD) with built-in HTTP request handling and WebSocket integration.
|
|
692
|
-
|
|
693
|
-
**What it does:**
|
|
694
|
-
This service combines HTTP requests with local state management. It automatically updates the local store when CRUD operations succeed, eliminating the need to manually refresh data. It also integrates with WebSockets to keep the state synchronized with server-side changes.
|
|
695
|
-
|
|
696
|
-
**Features:**
|
|
697
|
-
|
|
698
|
-
- **ComponentStore Integration:** Extends NGRX `ComponentStore` for robust state management.
|
|
699
|
-
- **Automatic CRUD Updates:** `createRecord`, `updateRecord`, and `deleteRecord` automatically update the local state upon success.
|
|
700
|
-
- **WebSocket Sync:** Listens for WebSocket messages to update, create, or delete records in real-time.
|
|
701
|
-
- **Database Support:** Can be configured to use IndexedDB for caching (via `DatabaseStorage`).
|
|
702
|
-
- **Selectors:** Provides selectors like `data$` and `selectRecord$(id)` for easy data access.
|
|
703
|
-
- **Pagination Support:** Includes state for pagination (`page$`, `totalPages$`).
|
|
704
|
-
|
|
705
|
-
**Usage:**
|
|
706
|
-
Extend this service to create a store for a specific feature. You must call `super()` with `ApiRequest`, `DataType`, and `DatabaseStorage`.
|
|
707
|
-
|
|
708
|
-
```typescript
|
|
709
|
-
@Injectable()
|
|
710
|
-
export class UsersStore extends HTTPManagerStateService<User> {
|
|
711
|
-
constructor() {
|
|
712
|
-
super(
|
|
713
|
-
ApiRequest.adapt({
|
|
714
|
-
server: 'api',
|
|
715
|
-
path: ['users'],
|
|
716
|
-
adapter: User.adapt // Required for Database Storage
|
|
717
|
-
}),
|
|
718
|
-
DataType.ARRAY,
|
|
719
|
-
DatabaseStorage.adapt({
|
|
720
|
-
table: 'users-cache',
|
|
721
|
-
expiresIn: '1d'
|
|
722
|
-
})
|
|
723
|
-
);
|
|
724
|
-
}
|
|
725
|
-
|
|
726
|
-
// Wrap CRUD methods for cleaner component usage
|
|
727
|
-
getUsers() {
|
|
728
|
-
this.fetchRecords();
|
|
729
|
-
}
|
|
730
|
-
|
|
731
|
-
addUser(user: User) {
|
|
732
|
-
this.createRecord(user);
|
|
733
|
-
}
|
|
734
|
-
}
|
|
735
|
-
```
|
|
736
|
-
|
|
737
|
-
**Features:**
|
|
738
|
-
|
|
739
|
-
- **Automatic State Updates:** `createRecord`, `updateRecord`, and `deleteRecord` automatically update the local state upon success.
|
|
740
|
-
- **Selectors:** `data$`, `selectRecord$(id)`.
|
|
741
|
-
- **WebSocket Integration:** Automatically connects to WS if configured in `ApiRequest`. Syncs state on 'create', 'update', 'delete' events from WS.
|
|
742
|
-
- **Runtime Configuration:** Use `setApiRequestOptions()` to update API or WS settings dynamically.
|
|
743
|
-
|
|
744
|
-
### 4. Request Manager Signal State Service
|
|
745
|
-
|
|
746
|
-
*Note: Currently, the state management service (`HTTPManagerStateService`) is based on `ComponentStore` (RxJS). A dedicated Signal-based state manager is not yet available in this library.*
|
|
747
|
-
|
|
748
|
-
### 5. Local Storage Manager Service (`LocalStorageManagerService`)
|
|
749
|
-
|
|
750
|
-
**Path:** `local-storage-manager-service/local-storage-manager.service.ts`
|
|
751
|
-
|
|
752
|
-
Manages `localStorage` and `sessionStorage` with encryption and expiration support.
|
|
753
|
-
|
|
754
|
-
**What it does:**
|
|
755
|
-
This service provides a secure and managed way to interact with browser storage. It treats storage as a state, allowing you to subscribe to changes. It also handles data encryption and expiration automatically.
|
|
756
|
-
|
|
757
|
-
**Features:**
|
|
186
|
+
|--------|------|-------------|---------|
|
|
187
|
+
| `server` | `string` | Base URL for API requests | `''` |
|
|
188
|
+
| `path` | `any[]` | Default path segments | `[]` |
|
|
189
|
+
| `headers` | `any` | Default headers | `{}` |
|
|
190
|
+
| `polling` | `number` | Default polling interval (seconds) | `0` |
|
|
191
|
+
| `retry` | `RetryOptions` | Default retry configuration | `{ times: 0, delay: 3 }` |
|
|
192
|
+
| `stream` | `boolean` | Enable streaming by default | `false` |
|
|
193
|
+
| `displayError` | `boolean` | Show toast errors by default | `false` |
|
|
758
194
|
|
|
759
|
-
|
|
760
|
-
- **Expiration:** Supports setting an expiration time (`expiresIn`) for stored items. Automatically cleans up expired items.
|
|
761
|
-
- **Storage Types:** Supports both `localStorage` (Global) and `sessionStorage` (Session).
|
|
762
|
-
- **Reactive:** Exposes storage items as Observables, allowing components to react to storage changes.
|
|
763
|
-
- **Metadata Management:** Keeps track of storage settings (encryption, expiration) separately from the data.
|
|
764
|
-
|
|
765
|
-
**Usage:**
|
|
766
|
-
|
|
767
|
-
```typescript
|
|
768
|
-
localStorageManager = inject(LocalStorageManagerService);
|
|
769
|
-
|
|
770
|
-
// Create/Set a store
|
|
771
|
-
this.localStorageManager.setStore({
|
|
772
|
-
name: 'user-settings',
|
|
773
|
-
data: { theme: 'dark' },
|
|
774
|
-
options: {
|
|
775
|
-
storage: StorageType.GLOBAL, // or StorageType.SESSION
|
|
776
|
-
encrypted: true,
|
|
777
|
-
expiresIn: '1d'
|
|
778
|
-
}
|
|
779
|
-
});
|
|
780
|
-
|
|
781
|
-
// Select a store (returns data)
|
|
782
|
-
settings$ = this.localStorageManager.store$('user-settings');
|
|
783
|
-
|
|
784
|
-
// Select store settings (returns metadata)
|
|
785
|
-
meta$ = this.localStorageManager.setting$('user-settings');
|
|
786
|
-
|
|
787
|
-
// Reset all stores
|
|
788
|
-
this.localStorageManager.resetStore();
|
|
789
|
-
```
|
|
790
|
-
|
|
791
|
-
### 6. Store State Manager Service (`StoreStateManagerService`)
|
|
792
|
-
|
|
793
|
-
**Path:** `store-state-manager-service/store-state-manager.service.ts`
|
|
794
|
-
|
|
795
|
-
A service that extends `ComponentStore` to provide persistent state management synchronized with local or session storage.
|
|
796
|
-
|
|
797
|
-
**What it does:**
|
|
798
|
-
This service bridges the gap between in-memory state (ComponentStore) and persistent storage. It ensures that your state is automatically saved to storage when it changes and restored from storage when the service is initialized.
|
|
799
|
-
|
|
800
|
-
**Features:**
|
|
801
|
-
|
|
802
|
-
- **Persistence:** Automatically saves state changes to `localStorage` or `sessionStorage`.
|
|
803
|
-
- **State Restoration:** Restores state from storage on initialization.
|
|
804
|
-
- **Reactivity:** Extends `ComponentStore`, providing all its benefits (selectors, updaters, effects).
|
|
805
|
-
- **Encryption Support:** Leverages `LocalStorageManagerService` for optional encryption.
|
|
806
|
-
- **Model Adaptation:** Supports using a model adapter to ensure state structure.
|
|
807
|
-
|
|
808
|
-
**Usage:**
|
|
809
|
-
Extend this service to create a persistent store.
|
|
810
|
-
|
|
811
|
-
```typescript
|
|
812
|
-
@Injectable({
|
|
813
|
-
providedIn: 'root'
|
|
814
|
-
})
|
|
815
|
-
export class SettingsStateService extends StoreStateManagerService {
|
|
816
|
-
|
|
817
|
-
constructor() {
|
|
818
|
-
super(
|
|
819
|
-
StateStorageOptions.adapt({
|
|
820
|
-
store: 'my-settings-store', // Unique store name
|
|
821
|
-
options: SettingOptions.adapt({
|
|
822
|
-
storage: StorageType.SESSION, // or StorageType.GLOBAL (Local Storage)
|
|
823
|
-
encrypted: false
|
|
824
|
-
}),
|
|
825
|
-
model: Settings.adapt, // Model adapter for initial state
|
|
826
|
-
})
|
|
827
|
-
);
|
|
828
|
-
}
|
|
829
|
-
|
|
830
|
-
// Update specific part of state
|
|
831
|
-
updateSetting(value: any) {
|
|
832
|
-
this.updateData(value);
|
|
833
|
-
}
|
|
834
|
-
|
|
835
|
-
// Select specific part of state
|
|
836
|
-
getSetting(key: string) {
|
|
837
|
-
return this.data$.pipe(map(state => state[key]));
|
|
838
|
-
}
|
|
839
|
-
}
|
|
840
|
-
```
|
|
841
|
-
|
|
842
|
-
**Features:**
|
|
843
|
-
|
|
844
|
-
- **Persistence:** Automatically saves state changes to LocalStorage or SessionStorage.
|
|
845
|
-
- **Reactivity:** Extends `ComponentStore`, providing `data$` selector and `updater` methods.
|
|
846
|
-
- **Encryption:** Supports encrypted storage via `LocalStorageManagerService`.
|
|
847
|
-
|
|
848
|
-
### 7. WebSocket Manager Service (`WebsocketService`)
|
|
849
|
-
|
|
850
|
-
**Path:** `ws-manager-service/services/websocket.service.ts`
|
|
851
|
-
|
|
852
|
-
Handles WebSocket connections, channel subscriptions, and messaging. It is used internally by `HTTPManagerStateService` but can be used standalone.
|
|
853
|
-
|
|
854
|
-
**What it does:**
|
|
855
|
-
This service manages the lifecycle of a WebSocket connection. It handles authentication, connection stability, and message routing. It supports a channel-based architecture for organizing communication.
|
|
856
|
-
|
|
857
|
-
**Features:**
|
|
858
|
-
|
|
859
|
-
- **Connection Management:** Handles connecting, disconnecting, and reconnecting.
|
|
860
|
-
- **Authentication:** Supports JWT-based authentication for secure connections.
|
|
861
|
-
- **Channels:** Allows subscribing and unsubscribing to specific channels.
|
|
862
|
-
- **Channel Management:** Create and delete channels dynamically.
|
|
863
|
-
- **Messaging:** Supports sending messages to specific channels, users, or broadcasting to all.
|
|
864
|
-
- **Observables:** Exposes `messages$`, `connectionStatus$`, and `subscribedChannels$` for reactive integration.
|
|
865
|
-
- **Session Persistence:** Automatically generates and persists session IDs for reconnection scenarios.
|
|
866
|
-
|
|
867
|
-
**Usage:**
|
|
868
|
-
|
|
869
|
-
```typescript
|
|
870
|
-
wsService = inject(WebsocketService);
|
|
871
|
-
|
|
872
|
-
// Connect with options
|
|
873
|
-
this.wsService.connect({
|
|
874
|
-
id: 'my-primary-channel',
|
|
875
|
-
wsServer: 'wss://api.example.com/ws',
|
|
876
|
-
user: { ldap: 'jdoe', name: 'John Doe' },
|
|
877
|
-
channels: ['PUB-notifications', 'PUB-updates']
|
|
878
|
-
}, 'jwt-token');
|
|
879
|
-
|
|
880
|
-
// Subscribe to additional channels
|
|
881
|
-
this.wsService.subscribeToChannel('PUB-my-channel');
|
|
882
|
-
|
|
883
|
-
// Unsubscribe from a channel
|
|
884
|
-
this.wsService.unsubscribeFromChannel('PUB-my-channel');
|
|
885
|
-
|
|
886
|
-
// Listen to messages
|
|
887
|
-
this.wsService.messages$.subscribe(msg => console.log(msg));
|
|
888
|
-
|
|
889
|
-
// Send message to a channel
|
|
890
|
-
this.wsService.sendChannelMessage('PUB-my-channel', { text: 'Hello!' });
|
|
891
|
-
|
|
892
|
-
// Track subscribed channels
|
|
893
|
-
this.wsService.subscribedChannels$.subscribe(channels => console.log([...channels]));
|
|
894
|
-
|
|
895
|
-
// Create/Delete channels
|
|
896
|
-
this.wsService.createChannel('PUB-new-channel');
|
|
897
|
-
this.wsService.deleteChannel('PUB-old-channel');
|
|
898
|
-
|
|
899
|
-
// Get all available channels
|
|
900
|
-
this.wsService.getAllChannels();
|
|
901
|
-
|
|
902
|
-
// Get users in a channel
|
|
903
|
-
this.wsService.getUsersInChannel('PUB-my-channel');
|
|
904
|
-
```
|
|
905
|
-
|
|
906
|
-
#### Channel Naming Conventions
|
|
907
|
-
|
|
908
|
-
The WebSocket service and state manager use a **channel type system** to organize communication. Channel prefixes are managed automatically by the state service.
|
|
909
|
-
|
|
910
|
-
##### Channel Types (`ChannelType` Enum)
|
|
911
|
-
|
|
912
|
-
```typescript
|
|
913
|
-
import { ChannelType, createChannelName } from 'http-request-manager';
|
|
914
|
-
|
|
915
|
-
export enum ChannelType {
|
|
916
|
-
STATE = 'SYS', // Private state synchronization channels
|
|
917
|
-
MESSAGE = 'MES', // Messaging/communication channels (persisted notifications)
|
|
918
|
-
NOTIFICATION = 'PUB' // Public notification/broadcast channels
|
|
919
|
-
}
|
|
920
|
-
|
|
921
|
-
// Utility function to create prefixed channel name
|
|
922
|
-
createChannelName(ChannelType.STATE, 'USERS123'); // Returns 'SYS-USERS123'
|
|
923
|
-
createChannelName(ChannelType.MESSAGE, 'alerts'); // Returns 'MES-alerts'
|
|
924
|
-
createChannelName(ChannelType.NOTIFICATION, 'chat'); // Returns 'PUB-chat'
|
|
925
|
-
```
|
|
926
|
-
|
|
927
|
-
| Channel Type | Prefix | Description | Visibility | Persistence |
|
|
928
|
-
| :--- | :--- | :--- | :--- | :--- |
|
|
929
|
-
| `STATE` | `SYS-` | Private channels for state synchronization (CRUD operations) | Hidden from users | In-memory only |
|
|
930
|
-
| `MESSAGE` | `MES-` | Messaging channels for notifications (persisted to database) | Visible to users | Database persisted |
|
|
931
|
-
| `NOTIFICATION` | `PUB-` | Public channels for real-time messaging/chat | Visible to users | In-memory only |
|
|
932
|
-
|
|
933
|
-
**Important:** When using `HTTPManagerStateService`, channel prefixes are automatically managed. You only need to provide the base channel name.
|
|
934
|
-
|
|
935
|
-
**Example:**
|
|
936
|
-
|
|
937
|
-
```typescript
|
|
938
|
-
// State service automatically adds SYS- prefix for state channels
|
|
939
|
-
// User provides: 'USERS123'
|
|
940
|
-
// State service uses: 'SYS-USERS123'
|
|
941
|
-
|
|
942
|
-
// For messaging channels, use subscribeToMessageChannel()
|
|
943
|
-
stateService.subscribeToMessageChannel('alerts'); // Uses 'MES-alerts'
|
|
195
|
+
#### Local Storage Options (`LocalStorageOptions`)
|
|
944
196
|
|
|
945
|
-
|
|
946
|
-
|
|
947
|
-
|
|
197
|
+
| Option | Type | Description | Default |
|
|
198
|
+
|--------|------|-------------|---------|
|
|
199
|
+
| `storageName` | `string` | Key for storing data | `'storage'` |
|
|
200
|
+
| `storageSettingsName` | `string` | Key for settings metadata | `'global-storage'` |
|
|
201
|
+
| `options` | `SettingOptions` | Default storage settings | `{ storage: StorageType.GLOBAL, expires: 0, expiresIn: '', encrypted: false }` |
|
|
948
202
|
|
|
949
|
-
####
|
|
950
|
-
|
|
951
|
-
| Type | Description | Direction |
|
|
952
|
-
| :--- | :--- | :--- |
|
|
953
|
-
| `subscribe` | Subscribe to a channel | Client → Server |
|
|
954
|
-
| `unsubscribe` | Unsubscribe from a channel | Client → Server |
|
|
955
|
-
| `message` | Send message to channel subscribers | Client → Server |
|
|
956
|
-
| `broadcast` | Broadcast to all connected clients | Client → Server |
|
|
957
|
-
| `userMessage` | Send message to specific user | Client → Server |
|
|
958
|
-
| `createChannel` | Create a new channel | Client → Server |
|
|
959
|
-
| `deleteChannel` | Delete an existing channel | Client → Server |
|
|
960
|
-
| `getChannels` | Request list of all channels | Client → Server |
|
|
961
|
-
| `getUsers` | Get users in a channel | Client → Server |
|
|
962
|
-
| `channelsList` | List of available channels | Server → Client |
|
|
963
|
-
| `subscribed` | Subscription confirmation | Server → Client |
|
|
964
|
-
| `unsubscribed` | Unsubscription confirmation | Server → Client |
|
|
965
|
-
| `incomingMessage` | Message received in a channel | Server → Client |
|
|
966
|
-
|
|
967
|
-
#### WebSocket Options (`WSOptions`)
|
|
203
|
+
#### Retry Options (`RetryOptions`)
|
|
968
204
|
|
|
969
205
|
| Option | Type | Description | Default |
|
|
970
|
-
|
|
971
|
-
| `
|
|
972
|
-
| `
|
|
973
|
-
|
|
974
|
-
|
|
975
|
-
|
|
976
|
-
|
|
|
977
|
-
|
|
206
|
+
|--------|------|-------------|---------|
|
|
207
|
+
| `times` | `number` | Number of retry attempts | `0` |
|
|
208
|
+
| `delay` | `number` | Delay between retries (seconds) | `3` |
|
|
209
|
+
|
|
210
|
+
## 📚 Services Overview
|
|
211
|
+
|
|
212
|
+
| Service | Description | Use Case |
|
|
213
|
+
|---------|-------------|----------|
|
|
214
|
+
| [`HTTPManagerService`](services/http-manager/README.md) | Observable-based HTTP client | Simple API calls with loading states |
|
|
215
|
+
| [`HTTPManagerSignalsService`](services/http-signals/README.md) | Signal-based HTTP client | Modern reactive UI with Angular Signals |
|
|
216
|
+
| [`HTTPManagerStateService`](services/http-state/README.md) | ComponentStore with HTTP & WebSocket | CRUD operations with auto state sync |
|
|
217
|
+
| [`WebsocketService`](services/websocket/README.md) | WebSocket connection management | Real-time messaging and notifications |
|
|
218
|
+
| [`LocalStorageManagerService`](services/local-storage/README.md) | Secure local storage | User preferences, session data |
|
|
219
|
+
| [`DatabaseManagerService`](services/database/README.md) | IndexedDB wrapper | Offline-first data access |
|
|
220
|
+
| [`StoreStateManagerService`](services/store-state-manager/README.md) | Persistent ComponentStore | Application state persistence |
|
|
221
|
+
| [`UtilsService`](services/utils/README.md) | Utility functions | JSON handling, expiration, conversions |
|
|
222
|
+
|
|
223
|
+
### Common Use Cases
|
|
978
224
|
|
|
979
|
-
|
|
225
|
+
| Use Case | Service to Use | Key Features |
|
|
226
|
+
|----------|---------------|--------------|
|
|
227
|
+
| Simple API calls | `HTTPManagerService` | Observables, retry, polling |
|
|
228
|
+
| Modern reactive UI | `HTTPManagerSignalsService` | Angular Signals |
|
|
229
|
+
| CRUD operations | `HTTPManagerStateService` | Auto state updates |
|
|
230
|
+
| Real-time chat | `HTTPManagerStateService` + WebSocket | Messaging channels |
|
|
231
|
+
| Persistent notifications | `HTTPManagerStateService` + WebSocket | Database-backed |
|
|
232
|
+
| User preferences | `LocalStorageManagerService` | Encryption, expiration |
|
|
233
|
+
| Offline-first | `DatabaseManagerService` | IndexedDB |
|
|
234
|
+
| Large local datasets | `DatabaseManagerService` | Querying, indexing |
|
|
980
235
|
|
|
981
|
-
|
|
236
|
+
## 🏗️ Architecture
|
|
237
|
+
|
|
238
|
+
For detailed system architecture, data flows, and design patterns, see:
|
|
239
|
+
|
|
240
|
+
📋 **[Architecture Documentation](architecture/README.md)**
|
|
241
|
+
|
|
242
|
+
### System Overview
|
|
243
|
+
|
|
244
|
+
```
|
|
245
|
+
┌─────────────────────────────────────────────────────────────────┐
|
|
246
|
+
│ Angular Application │
|
|
247
|
+
├─────────────────────────────────────────────────────────────────┤
|
|
248
|
+
│ ┌────────────────┐ ┌────────────────┐ ┌──────────────────┐ │
|
|
249
|
+
│ │ Components │ │ Components │ │ Components │ │
|
|
250
|
+
│ │ (Signals) │ │ (Observables) │ │ (State Store) │ │
|
|
251
|
+
│ └───────┬────────┘ └───────┬────────┘ └────────┬─────────┘ │
|
|
252
|
+
│ │ │ │ │
|
|
253
|
+
│ ▼ ▼ ▼ │
|
|
254
|
+
│ ┌──────────────┐ ┌──────────────┐ ┌──────────────────┐ │
|
|
255
|
+
│ │HTTPManager │ │HTTPManager │ │HTTPManager │ │
|
|
256
|
+
│ │SignalsService│ │Service │ │StateService │ │
|
|
257
|
+
│ └──────┬───────┘ └──────┬───────┘ └────────┬─────────┘ │
|
|
258
|
+
│ │ │ │ │
|
|
259
|
+
│ └───────────────────┴──────────────────────┘ │
|
|
260
|
+
│ │ │
|
|
261
|
+
│ ▼ │
|
|
262
|
+
│ ┌─────────────────┐ │
|
|
263
|
+
│ │ HttpClient │ │
|
|
264
|
+
│ │ (Angular) │ │
|
|
265
|
+
│ └────────┬────────┘ │
|
|
266
|
+
│ │ │
|
|
267
|
+
├─────────────────────────────┼────────────────────────────────────┤
|
|
268
|
+
│ │ │
|
|
269
|
+
│ ┌──────────────────────────┼──────────────────────┐ │
|
|
270
|
+
│ │ Storage Layer │ │
|
|
271
|
+
│ ├──────────────────────────┼──────────────────────┤ │
|
|
272
|
+
│ │ ┌────────────────┐ │ ┌─────────────┐│ │
|
|
273
|
+
│ │ │LocalStorage │ │ │IndexedDB ││ │
|
|
274
|
+
│ │ │Manager Service │ │ │(Dexie.js) ││ │
|
|
275
|
+
│ │ └────────────────┘ │ └─────────────┘│ │
|
|
276
|
+
│ └──────────────────────────┼──────────────────────┘ │
|
|
277
|
+
│ │ │
|
|
278
|
+
│ ┌──────────────────────────┼──────────────────────┐ │
|
|
279
|
+
│ │ WebSocket Layer │ │
|
|
280
|
+
│ ├──────────────────────────┼──────────────────────┤ │
|
|
281
|
+
│ │ ┌─────────────────────────────────────┐ │ │
|
|
282
|
+
│ │ │ WebsocketService │ │ │
|
|
283
|
+
│ │ └─────────────────────────────────────┘ │ │
|
|
284
|
+
│ └─────────────────────────────────────────────────┘ │
|
|
285
|
+
└─────────────────────────────────────────────────────────────────┘
|
|
286
|
+
```
|
|
287
|
+
|
|
288
|
+
## 🔧 Interceptors
|
|
289
|
+
|
|
290
|
+
The library provides several HTTP interceptors that are automatically configured:
|
|
291
|
+
|
|
292
|
+
📋 **[Interceptors Documentation](interceptors/README.md)**
|
|
293
|
+
|
|
294
|
+
### Available Interceptors
|
|
295
|
+
|
|
296
|
+
- **RequestErrorInterceptor** - Handles 400/500 errors with toast notifications
|
|
297
|
+
- **WithCredentialsInterceptor** - Adds `withCredentials: true` to requests
|
|
298
|
+
- **RequestHeadersInterceptor** - Adds common headers (Content-Type, Accept-Language, Current-Date)
|
|
299
|
+
|
|
300
|
+
### Manual Configuration
|
|
982
301
|
|
|
983
302
|
```typescript
|
|
984
|
-
|
|
985
|
-
|
|
986
|
-
|
|
987
|
-
|
|
988
|
-
|
|
989
|
-
|
|
990
|
-
path: ['users'],
|
|
991
|
-
// WebSocket Configuration
|
|
992
|
-
ws: {
|
|
993
|
-
id: 'WS-USERS',
|
|
994
|
-
wsServer: 'wss://api.example.com/ws',
|
|
995
|
-
jwtToken: 'your-token',
|
|
996
|
-
wsChannels: ['allChannels'],
|
|
997
|
-
retry: { times: 3, delay: 5 }
|
|
998
|
-
}
|
|
999
|
-
}),
|
|
1000
|
-
DataType.ARRAY,
|
|
1001
|
-
DatabaseStorage.adapt()
|
|
1002
|
-
);
|
|
1003
|
-
}
|
|
1004
|
-
}
|
|
303
|
+
// app.module.ts
|
|
304
|
+
providers: [
|
|
305
|
+
{ provide: HTTP_INTERCEPTORS, useClass: WithCredentialsInterceptor, multi: true },
|
|
306
|
+
{ provide: HTTP_INTERCEPTORS, useClass: RequestHeadersInterceptor, multi: true },
|
|
307
|
+
{ provide: HTTP_INTERCEPTORS, useClass: RequestErrorInterceptor, multi: true }
|
|
308
|
+
]
|
|
1005
309
|
```
|
|
1006
310
|
|
|
1007
|
-
|
|
1008
|
-
|
|
1009
|
-
## Real-Time Features
|
|
1010
|
-
|
|
1011
|
-
The `http-request-manager` library provides two distinct real-time communication features:
|
|
1012
|
-
|
|
1013
|
-
1. **Messaging (PUB- channels)** - Real-time chat/messaging between users
|
|
1014
|
-
2. **Notifications (MES- channels)** - Persistent notifications stored in database
|
|
1015
|
-
|
|
1016
|
-
Both features integrate seamlessly with `HTTPManagerStateService` and automatically manage channel prefixes.
|
|
1017
|
-
|
|
1018
|
-
### Messaging Feature (PUB- Channels)
|
|
1019
|
-
|
|
1020
|
-
**Purpose:** Real-time messaging/chat functionality for communication between users.
|
|
1021
|
-
|
|
1022
|
-
**Characteristics:**
|
|
1023
|
-
|
|
1024
|
-
- Messages are broadcast in real-time to subscribed users
|
|
1025
|
-
- Messages are stored in-memory only (not persisted to database)
|
|
1026
|
-
- Uses `PUB-` prefix (automatically added)
|
|
1027
|
-
- Ideal for chat applications, live collaboration, etc.
|
|
311
|
+
## 🎮 Demo Examples
|
|
1028
312
|
|
|
1029
|
-
|
|
313
|
+
Comprehensive demo components showcase all library features:
|
|
1030
314
|
|
|
1031
|
-
|
|
1032
|
-
| :--- | :--- | :--- |
|
|
1033
|
-
| `channels$` | `Observable<string[]>` | List of all available channels |
|
|
1034
|
-
| `communicationMessages$` | `Observable<any[]>` | All received messages |
|
|
1035
|
-
| `latestCommunicationMessages$` | `Observable<any>` | Most recent message received |
|
|
1036
|
-
| `connectionStatus$` | `Observable<boolean>` | WebSocket connection status |
|
|
1037
|
-
| `user$` | `Observable<WSUser>` | Current user information |
|
|
315
|
+
📋 **[Demo Examples Documentation](demos/README.md)**
|
|
1038
316
|
|
|
1039
|
-
|
|
317
|
+
### Available Demos
|
|
1040
318
|
|
|
1041
|
-
|
|
1042
|
-
|
|
1043
|
-
|
|
1044
|
-
|
|
1045
|
-
|
|
1046
|
-
|
|
1047
|
-
|
|
1048
|
-
// Unsubscribe from a channel
|
|
1049
|
-
stateService.unsubscribeFromChannel('general-chat');
|
|
1050
|
-
|
|
1051
|
-
// Get all available channels
|
|
1052
|
-
stateService.getAllChannels();
|
|
1053
|
-
|
|
1054
|
-
// Send a message to specific channels
|
|
1055
|
-
stateService.wsMessaging(
|
|
1056
|
-
ChannelMessage.adapt({
|
|
1057
|
-
sessionId: currentUser,
|
|
1058
|
-
content: { message: 'Hello everyone!' }
|
|
1059
|
-
}),
|
|
1060
|
-
['general-chat', 'team-updates'] // Channels (PUB- prefix added automatically)
|
|
1061
|
-
);
|
|
1062
|
-
```
|
|
319
|
+
- **HttpRequestServicesDemoComponent** - Main demo component
|
|
320
|
+
- **RequestManagerDemoComponent** - HTTP service demonstrations
|
|
321
|
+
- **RequestManagerStateDemoComponent** - State management examples
|
|
322
|
+
- **RequestManagerWsDemoComponent** - WebSocket functionality
|
|
323
|
+
- **LocalStorageDemoComponent** - Local storage examples
|
|
324
|
+
- **DatabaseDataDemoComponent** - IndexedDB operations
|
|
1063
325
|
|
|
1064
|
-
|
|
1065
|
-
|
|
1066
|
-
The library includes a demo component showcasing messaging functionality:
|
|
326
|
+
### Usage
|
|
1067
327
|
|
|
1068
328
|
```html
|
|
1069
|
-
<app-
|
|
329
|
+
<app-http-request-services-demo
|
|
1070
330
|
[server]="'http://localhost:8080'"
|
|
1071
331
|
[wsServer]="'ws://localhost:8080'"
|
|
1072
332
|
[jwtToken]="'your-jwt-token'"
|
|
1073
|
-
[
|
|
1074
|
-
|
|
333
|
+
[adapter]="myAdapterFunction"
|
|
334
|
+
[mapper]="myMapperFunction">
|
|
335
|
+
</app-http-request-services-demo>
|
|
1075
336
|
```
|
|
1076
337
|
|
|
1077
|
-
|
|
338
|
+
## 📖 Migration Guide
|
|
1078
339
|
|
|
1079
|
-
|
|
1080
|
-
- Subscribe/unsubscribe to channels
|
|
1081
|
-
- Send messages to multiple channels
|
|
1082
|
-
- View real-time message stream
|
|
1083
|
-
- Toast notifications for incoming messages
|
|
1084
|
-
|
|
1085
|
-
---
|
|
1086
|
-
|
|
1087
|
-
### Notifications Feature (MES- Channels)
|
|
1088
|
-
|
|
1089
|
-
**Purpose:** Persistent notifications that are stored in the database and can be retrieved with date filters.
|
|
1090
|
-
|
|
1091
|
-
**Characteristics:**
|
|
1092
|
-
|
|
1093
|
-
- Notifications are persisted to the server database
|
|
1094
|
-
- Supports date-range queries (startEpoch, endEpoch)
|
|
1095
|
-
- Uses `MES-` prefix (automatically added)
|
|
1096
|
-
- Retrieves historical notifications on subscription
|
|
1097
|
-
- Ideal for announcements, alerts, audit logs, etc.
|
|
1098
|
-
|
|
1099
|
-
#### Notification Observables
|
|
1100
|
-
|
|
1101
|
-
| Observable | Type | Description |
|
|
1102
|
-
| :--- | :--- | :--- |
|
|
1103
|
-
| `notificationChannels$` | `Observable<string[]>` | In-memory notification channels from server |
|
|
1104
|
-
| `todaysNotificationChannels$` | `Observable<string[]>` | Channels with notifications posted today (from DB) |
|
|
1105
|
-
| `notificationMessages$` | `Observable<any[]>` | All notification messages |
|
|
1106
|
-
| `latestNotification$` | `Observable<any>` | Most recent notification received |
|
|
1107
|
-
|
|
1108
|
-
#### Notification Methods
|
|
340
|
+
### From HttpClient to HTTPManagerService
|
|
1109
341
|
|
|
342
|
+
**Before:**
|
|
1110
343
|
```typescript
|
|
1111
|
-
|
|
1112
|
-
|
|
1113
|
-
|
|
1114
|
-
// Get all notification channels (in-memory)
|
|
1115
|
-
stateService.getNotificationChannels();
|
|
1116
|
-
|
|
1117
|
-
// Get today's notification channels (from database)
|
|
1118
|
-
stateService.getTodaysNotificationChannels();
|
|
1119
|
-
|
|
1120
|
-
// Define and load previous day's notification channels
|
|
1121
|
-
// This retrieves channels from the previous day's database records,
|
|
1122
|
-
// creates them in memory if needed, and broadcasts the updated list
|
|
1123
|
-
stateService.definePreviousNotificationChannels();
|
|
1124
|
-
|
|
1125
|
-
// Subscribe to notifications with optional date filter
|
|
1126
|
-
stateService.subscribeToNotificationChannel('alerts', {
|
|
1127
|
-
startEpoch: Math.floor(Date.now() / 1000) - 86400, // Last 24 hours
|
|
1128
|
-
endEpoch: Math.floor(Date.now() / 1000)
|
|
1129
|
-
});
|
|
1130
|
-
|
|
1131
|
-
// Unsubscribe from notifications
|
|
1132
|
-
stateService.unsubscribeFromNotificationChannel('alerts');
|
|
1133
|
-
|
|
1134
|
-
// Send a notification (persisted to database)
|
|
1135
|
-
stateService.sendNotification('alerts', {
|
|
1136
|
-
title: 'System Alert',
|
|
1137
|
-
message: 'Scheduled maintenance at midnight',
|
|
1138
|
-
priority: 'high'
|
|
344
|
+
http.get('api/users').subscribe(users => {
|
|
345
|
+
this.users = users;
|
|
346
|
+
this.loading = false;
|
|
1139
347
|
});
|
|
1140
348
|
```
|
|
1141
349
|
|
|
1142
|
-
|
|
1143
|
-
|
|
350
|
+
**After:**
|
|
1144
351
|
```typescript
|
|
1145
|
-
|
|
1146
|
-
|
|
1147
|
-
|
|
1148
|
-
created: number; // epoch seconds
|
|
1149
|
-
user_name: string; // sender's name
|
|
1150
|
-
sessionId: any; // sender's session info
|
|
1151
|
-
content: any; // notification payload
|
|
1152
|
-
}
|
|
1153
|
-
```
|
|
1154
|
-
|
|
1155
|
-
#### Demo Component: `WsNotificationsComponent`
|
|
352
|
+
httpManager.getRequest(
|
|
353
|
+
ApiRequest.adapt({ path: ['users'] })
|
|
354
|
+
).subscribe();
|
|
1156
355
|
|
|
1157
|
-
|
|
1158
|
-
|
|
1159
|
-
```html
|
|
1160
|
-
<app-ws-notifications
|
|
1161
|
-
[server]="'http://localhost:8080'"
|
|
1162
|
-
[wsServer]="'ws://localhost:8080'"
|
|
1163
|
-
[jwtToken]="'your-jwt-token'"
|
|
1164
|
-
[user]="{ ldap: 'jdoe', name: 'John Doe', email: 'jdoe@example.com' }">
|
|
1165
|
-
</app-ws-notifications>
|
|
356
|
+
data$ = this.httpManager.data$;
|
|
357
|
+
isLoading$ = this.httpManager.isPending$;
|
|
1166
358
|
```
|
|
1167
359
|
|
|
1168
|
-
|
|
1169
|
-
|
|
1170
|
-
- Create notification channels
|
|
1171
|
-
- View today's notification channels (from database)
|
|
1172
|
-
- Define previous day's channels (loads channels from previous day's data)
|
|
1173
|
-
- Subscribe with date range filters
|
|
1174
|
-
- Connect/disconnect from channels
|
|
1175
|
-
- Send notifications (persisted)
|
|
1176
|
-
- View historical notifications in a table
|
|
1177
|
-
|
|
1178
|
-
---
|
|
1179
|
-
|
|
1180
|
-
### Creating a Custom State Service with Messaging & Notifications
|
|
1181
|
-
|
|
1182
|
-
Here's a complete example of a state service that utilizes all real-time features:
|
|
360
|
+
### From Manual State to HTTPManagerStateService
|
|
1183
361
|
|
|
362
|
+
**Before:**
|
|
1184
363
|
```typescript
|
|
1185
|
-
|
|
1186
|
-
|
|
1187
|
-
|
|
1188
|
-
|
|
1189
|
-
|
|
1190
|
-
|
|
1191
|
-
|
|
1192
|
-
|
|
364
|
+
users: User[] = [];
|
|
365
|
+
loading = false;
|
|
366
|
+
|
|
367
|
+
loadUsers() {
|
|
368
|
+
this.loading = true;
|
|
369
|
+
this.http.get('api/users').subscribe(users => {
|
|
370
|
+
this.users = users;
|
|
371
|
+
this.loading = false;
|
|
372
|
+
});
|
|
1193
373
|
}
|
|
1194
374
|
|
|
1195
|
-
|
|
1196
|
-
|
|
1197
|
-
|
|
1198
|
-
|
|
1199
|
-
|
|
1200
|
-
constructor() {
|
|
1201
|
-
super(
|
|
1202
|
-
ApiRequest.adapt({
|
|
1203
|
-
server: 'http://localhost:8080',
|
|
1204
|
-
path: ['api', 'users'],
|
|
1205
|
-
adapter: (data: any) => data as User,
|
|
1206
|
-
ws: {
|
|
1207
|
-
id: 'USERS123', // Base name - automatically becomes SYS-USERS123
|
|
1208
|
-
wsServer: 'ws://localhost:8080',
|
|
1209
|
-
jwtToken: '',
|
|
1210
|
-
retry: { times: 3, delay: 5 }
|
|
1211
|
-
}
|
|
1212
|
-
}),
|
|
1213
|
-
DataType.ARRAY,
|
|
1214
|
-
DatabaseStorage.adapt({ table: 'users-cache', expiresIn: '1d' })
|
|
1215
|
-
);
|
|
1216
|
-
}
|
|
1217
|
-
|
|
1218
|
-
// Initialize connection with user info
|
|
1219
|
-
initializeConnection(wsServer: string, jwtToken: string, user: any) {
|
|
1220
|
-
this.setApiRequestOptions(
|
|
1221
|
-
ApiRequest.adapt({
|
|
1222
|
-
...this.ApiRequestOptions,
|
|
1223
|
-
ws: {
|
|
1224
|
-
...this.ApiRequestOptions.ws,
|
|
1225
|
-
wsServer,
|
|
1226
|
-
jwtToken,
|
|
1227
|
-
user
|
|
1228
|
-
}
|
|
1229
|
-
})
|
|
1230
|
-
);
|
|
1231
|
-
}
|
|
1232
|
-
|
|
1233
|
-
// === MESSAGING (PUB- channels) ===
|
|
1234
|
-
|
|
1235
|
-
createChatRoom(roomName: string) {
|
|
1236
|
-
this.createChannel(roomName); // Creates PUB-{roomName}
|
|
1237
|
-
}
|
|
1238
|
-
|
|
1239
|
-
joinChatRoom(roomName: string) {
|
|
1240
|
-
this.subscribeToChannel(roomName);
|
|
1241
|
-
}
|
|
1242
|
-
|
|
1243
|
-
leaveChatRoom(roomName: string) {
|
|
1244
|
-
this.unsubscribeFromChannel(roomName);
|
|
1245
|
-
}
|
|
1246
|
-
|
|
1247
|
-
sendChatMessage(content: string, rooms: string[]) {
|
|
1248
|
-
this.wsMessaging(
|
|
1249
|
-
{ content: { message: content } },
|
|
1250
|
-
rooms
|
|
1251
|
-
);
|
|
1252
|
-
}
|
|
1253
|
-
|
|
1254
|
-
// === NOTIFICATIONS (MES- channels) ===
|
|
1255
|
-
|
|
1256
|
-
createNotificationStream(streamName: string) {
|
|
1257
|
-
this.createNotificationChannel(streamName); // Creates MES-{streamName}
|
|
1258
|
-
}
|
|
1259
|
-
|
|
1260
|
-
subscribeToAlerts(streamName: string, lastHours: number = 24) {
|
|
1261
|
-
const now = Math.floor(Date.now() / 1000);
|
|
1262
|
-
const startEpoch = now - (lastHours * 3600);
|
|
1263
|
-
|
|
1264
|
-
this.subscribeToNotificationChannel(streamName, {
|
|
1265
|
-
startEpoch,
|
|
1266
|
-
endEpoch: now
|
|
1267
|
-
});
|
|
1268
|
-
}
|
|
1269
|
-
|
|
1270
|
-
sendAlert(streamName: string, alert: { title: string; message: string; priority: string }) {
|
|
1271
|
-
this.sendNotification(streamName, alert);
|
|
1272
|
-
}
|
|
375
|
+
addUser(user: User) {
|
|
376
|
+
this.http.post('api/users', user).subscribe(newUser => {
|
|
377
|
+
this.users = [...this.users, newUser];
|
|
378
|
+
});
|
|
1273
379
|
}
|
|
1274
380
|
```
|
|
1275
381
|
|
|
1276
|
-
**
|
|
1277
|
-
|
|
382
|
+
**After:**
|
|
1278
383
|
```typescript
|
|
1279
|
-
@
|
|
1280
|
-
|
|
1281
|
-
|
|
1282
|
-
|
|
1283
|
-
<!-- Chat Messages -->
|
|
1284
|
-
<div *ngFor="let msg of chatMessages$ | async">
|
|
1285
|
-
{{ msg.content.message }}
|
|
1286
|
-
</div>
|
|
1287
|
-
|
|
1288
|
-
<!-- Notifications -->
|
|
1289
|
-
<div *ngFor="let notification of notifications$ | async">
|
|
1290
|
-
{{ notification.content.title }}: {{ notification.content.message }}
|
|
1291
|
-
</div>
|
|
1292
|
-
</div>
|
|
1293
|
-
`
|
|
1294
|
-
})
|
|
1295
|
-
export class DashboardComponent implements OnInit {
|
|
1296
|
-
userState = inject(UserStateService);
|
|
1297
|
-
|
|
1298
|
-
connectionStatus$ = this.userState.connectionStatus$;
|
|
1299
|
-
chatMessages$ = this.userState.communicationMessages$;
|
|
1300
|
-
notifications$ = this.userState.notificationMessages$;
|
|
1301
|
-
|
|
1302
|
-
ngOnInit() {
|
|
1303
|
-
// Initialize WebSocket connection
|
|
1304
|
-
this.userState.initializeConnection(
|
|
1305
|
-
'ws://localhost:8080',
|
|
1306
|
-
'jwt-token',
|
|
1307
|
-
{ ldap: 'jdoe', name: 'John Doe' }
|
|
1308
|
-
);
|
|
1309
|
-
|
|
1310
|
-
// Join a chat room
|
|
1311
|
-
this.userState.joinChatRoom('general');
|
|
1312
|
-
|
|
1313
|
-
// Subscribe to alerts from last 24 hours
|
|
1314
|
-
this.userState.subscribeToAlerts('system-alerts', 24);
|
|
1315
|
-
}
|
|
1316
|
-
|
|
1317
|
-
sendMessage(text: string) {
|
|
1318
|
-
this.userState.sendChatMessage(text, ['general']);
|
|
1319
|
-
}
|
|
1320
|
-
|
|
1321
|
-
sendAlert() {
|
|
1322
|
-
this.userState.sendAlert('system-alerts', {
|
|
1323
|
-
title: 'Update Available',
|
|
1324
|
-
message: 'A new version is available',
|
|
1325
|
-
priority: 'medium'
|
|
1326
|
-
});
|
|
384
|
+
@Injectable()
|
|
385
|
+
export class UsersStore extends HTTPManagerStateService<User> {
|
|
386
|
+
constructor() {
|
|
387
|
+
super(ApiRequest.adapt({ path: ['users'] }), DataType.ARRAY);
|
|
1327
388
|
}
|
|
389
|
+
|
|
390
|
+
loadUsers() { this.fetchRecords(); }
|
|
391
|
+
addUser(user: User) { this.createRecord(user); }
|
|
1328
392
|
}
|
|
1329
|
-
```
|
|
1330
|
-
|
|
1331
|
-
---
|
|
1332
|
-
|
|
1333
|
-
### 8. Database Manager Service (`DatabaseManagerService`)
|
|
1334
|
-
|
|
1335
|
-
**Path:** `database-manager-service/database.manager.service.ts`
|
|
1336
|
-
|
|
1337
|
-
A wrapper service for Dexie.js to manage IndexedDB interactions using RxJS Observables.
|
|
1338
|
-
|
|
1339
|
-
**What it does:**
|
|
1340
|
-
|
|
1341
|
-
This service simplifies interactions with IndexedDB by providing a clean, Observable-based API. It handles database initialization, table creation, and all standard CRUD operations. It is designed to work seamlessly with the `HTTPManagerStateService` for caching but can also be used independently.
|
|
1342
|
-
|
|
1343
|
-
**Features:**
|
|
1344
|
-
|
|
1345
|
-
- **Table Management:** Create and manage database tables with flexible schemas.
|
|
1346
|
-
- **CRUD Operations:** Full support for Create, Read, Update, and Delete operations on single or multiple records.
|
|
1347
|
-
- **Querying:** Find records by specific column values.
|
|
1348
|
-
- **Bulk Operations:** Optimized methods for creating and deleting multiple records at once.
|
|
1349
|
-
- **Schema Inspection:** Methods to check for table existence and retrieve schema definitions.
|
|
1350
|
-
|
|
1351
|
-
**Usage:**
|
|
1352
|
-
|
|
1353
|
-
```typescript
|
|
1354
|
-
dbManager = inject(DatabaseManagerService);
|
|
1355
|
-
|
|
1356
|
-
// 1. Initialize Table
|
|
1357
|
-
const tableDef = TableSchemaDef.adapt({
|
|
1358
|
-
table: 'users',
|
|
1359
|
-
schema: '++id, name, age' // Dexie.js schema syntax
|
|
1360
|
-
});
|
|
1361
|
-
|
|
1362
|
-
this.dbManager.createDatabaseTable(tableDef).subscribe(() => {
|
|
1363
|
-
console.log('Table initialized');
|
|
1364
|
-
});
|
|
1365
|
-
|
|
1366
|
-
// 2. CRUD Operations
|
|
1367
|
-
// Create
|
|
1368
|
-
this.dbManager.createTableRecord('users', { name: 'John', age: 30 }).subscribe();
|
|
1369
|
-
|
|
1370
|
-
// Read
|
|
1371
|
-
this.dbManager.getTableRecords('users').subscribe(users => console.log(users));
|
|
1372
|
-
this.dbManager.getTableRecord('users', 1).subscribe(user => console.log(user));
|
|
1373
|
-
|
|
1374
|
-
// Update
|
|
1375
|
-
this.dbManager.updateTableRecord('users', { id: 1, name: 'John Doe', age: 31 }).subscribe();
|
|
1376
|
-
|
|
1377
|
-
// Delete
|
|
1378
|
-
this.dbManager.deleteTableRecord('users', 1).subscribe();
|
|
1379
|
-
|
|
1380
|
-
// 3. Bulk Operations
|
|
1381
|
-
const users = [{ name: 'Alice', age: 25 }, { name: 'Bob', age: 28 }];
|
|
1382
|
-
this.dbManager.createTableRecords('users', users).subscribe();
|
|
1383
|
-
|
|
1384
|
-
// 4. Querying
|
|
1385
|
-
this.dbManager.findTableRecords('users', 'age', 25).subscribe(results => console.log(results));
|
|
1386
|
-
|
|
1387
|
-
// 5. Metadata
|
|
1388
|
-
this.dbManager.hasDatabaseTable('users').subscribe(exists => console.log(exists));
|
|
1389
|
-
```
|
|
1390
|
-
|
|
1391
|
-
#### Database Storage Configuration (`DatabaseStorage`)
|
|
1392
|
-
|
|
1393
|
-
When using `HTTPManagerStateService`, you can configure local database caching using `DatabaseStorage.adapt()`.
|
|
1394
393
|
|
|
1395
|
-
|
|
1396
|
-
|
|
1397
|
-
|
|
1398
|
-
| :--- | :--- | :--- | :--- |
|
|
1399
|
-
| `table` | `string` | The name of the table in IndexedDB where records will be stored. | `''` |
|
|
1400
|
-
| `expiresIn` | `string` | The duration for which the data remains valid. Format: `'1d'` (days), `'1h'` (hours), `'30m'` (minutes). | `''` |
|
|
1401
|
-
|
|
1402
|
-
##### Database Storage Example
|
|
1403
|
-
|
|
1404
|
-
```typescript
|
|
1405
|
-
import { DatabaseStorage } from 'http-request-manager';
|
|
1406
|
-
|
|
1407
|
-
const dbConfig = DatabaseStorage.adapt({
|
|
1408
|
-
table: 'my-feature-cache',
|
|
1409
|
-
expiresIn: '6h' // Cache expires in 6 hours
|
|
1410
|
-
});
|
|
394
|
+
// Component
|
|
395
|
+
data$ = this.usersStore.data$;
|
|
396
|
+
isLoading$ = this.usersStore.isPending$;
|
|
1411
397
|
```
|
|
1412
398
|
|
|
1413
|
-
|
|
399
|
+
## 📋 API Reference
|
|
1414
400
|
|
|
1415
|
-
|
|
401
|
+
### Core Models
|
|
1416
402
|
|
|
1417
|
-
|
|
403
|
+
- **ApiRequest** - HTTP request configuration
|
|
404
|
+
- **RetryOptions** - Retry behavior settings
|
|
405
|
+
- **DataType** - Data structure type (ARRAY, OBJECT)
|
|
406
|
+
- **DatabaseStorage** - IndexedDB configuration
|
|
407
|
+
- **SettingOptions** - Storage settings
|
|
408
|
+
- **WSOptions** - WebSocket configuration
|
|
1418
409
|
|
|
1419
|
-
|
|
1420
|
-
A collection of helper functions used throughout the library and available for application use. It simplifies common tasks related to data manipulation, validation, and time calculations.
|
|
410
|
+
### Enums
|
|
1421
411
|
|
|
1422
|
-
**
|
|
412
|
+
- **StreamType** - Streaming response types
|
|
413
|
+
- **StorageType** - Storage scope (GLOBAL, SESSION)
|
|
414
|
+
- **CommunicationType** - WebSocket message types
|
|
1423
415
|
|
|
1424
|
-
|
|
1425
|
-
- **Type Checking:** `isString`, `isObject`, `isJSON`.
|
|
1426
|
-
- **Expiration:** `expires(string)` converts duration strings (e.g., '1d', '2h') to epoch timestamps. `hasExpired(timestamp)` checks if a timestamp has passed.
|
|
1427
|
-
- **Conversions:** `base32ToHex`, `binaryToHex`.
|
|
1428
|
-
- **Object Equality:** `objectsEqual` for deep comparison.
|
|
416
|
+
## 🤝 Contributing
|
|
1429
417
|
|
|
1430
|
-
|
|
418
|
+
This library is designed to be enterprise-ready and production-safe. All features include comprehensive error handling, TypeScript support, and extensive configuration options.
|
|
1431
419
|
|
|
1432
|
-
|
|
1433
|
-
utils = inject(UtilsService);
|
|
1434
|
-
|
|
1435
|
-
// Check expiration
|
|
1436
|
-
const isExpired = this.utils.hasExpired(expiryTimestamp);
|
|
420
|
+
## 📄 License
|
|
1437
421
|
|
|
1438
|
-
|
|
1439
|
-
const json = this.utils.stringToJSON(jsonString);
|
|
1440
|
-
|
|
1441
|
-
// Calculate Expiry
|
|
1442
|
-
const expiryEpoch = this.utils.expires('1d'); // Returns epoch for 1 day from now
|
|
1443
|
-
```
|
|
422
|
+
This project is part of the Angular application library suite.
|
|
1444
423
|
|
|
1445
424
|
---
|
|
1446
425
|
|
|
1447
|
-
|
|
1448
|
-
|
|
1449
|
-
There are 3 interceptors that you can import into your project for api requests.
|
|
1450
|
-
|
|
1451
|
-
You may add these interceptors in your `AppModule` file as providers and import them into as providers.
|
|
1452
|
-
|
|
1453
|
-
```typescript
|
|
1454
|
-
providers: [
|
|
1455
|
-
{ provide: HTTP_INTERCEPTORS, useClass: WithCredentialsInterceptor, multi: true },
|
|
1456
|
-
{ provide: HTTP_INTERCEPTORS, useClass: RequestHeadersInterceptor, multi: true },
|
|
1457
|
-
{ provide: HTTP_INTERCEPTORS, useClass: RequestErrorInterceptor, multi: true }
|
|
1458
|
-
],
|
|
1459
|
-
```
|
|
1460
|
-
|
|
1461
|
-
Or you can use all intercepts above by importing the `HttpRequestManagerModule` in your `AppModule`
|
|
1462
|
-
|
|
1463
|
-
- **RequestErrorInterceptor**
|
|
1464
|
-
|
|
1465
|
-
This interceptor handles errors of type 400 and 500. This interceptor is applicable when you need to display UI for the user to indicate a server or request error has occurred. The Status and Error Text is displayed in a `toast-message` modal.
|
|
1466
|
-
|
|
1467
|
-
- **WithCredentialsInterceptor**
|
|
1468
|
-
|
|
1469
|
-
Adds to your request header
|
|
1470
|
-
|
|
1471
|
-
```json
|
|
1472
|
-
{ credentials: true }
|
|
1473
|
-
```
|
|
1474
|
-
|
|
1475
|
-
- **RequestHeadersInterceptor**
|
|
1476
|
-
|
|
1477
|
-
Adds to your request - current local `language` (i18n) selection and `current date` to every request
|
|
1478
|
-
|
|
1479
|
-
```json
|
|
1480
|
-
{
|
|
1481
|
-
'Content-Type': 'application/json',
|
|
1482
|
-
'Accept-Language': this.language || 'en-CA',
|
|
1483
|
-
'Current-Date': this.currentDate
|
|
1484
|
-
}
|
|
1485
|
-
```
|
|
426
|
+
**Need help?** Check out the detailed documentation for each service, explore the demo examples, or review the architecture documentation for implementation guidance.
|