@adaas/a-utils 0.1.12 → 0.1.14

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.
@@ -0,0 +1,864 @@
1
+ # A-Channel
2
+
3
+ A powerful, extensible communication channel component that provides structured messaging patterns with lifecycle management, error handling, and type safety for TypeScript applications.
4
+
5
+ ## Table of Contents
6
+
7
+ - [Overview](#overview)
8
+ - [Key Features](#key-features)
9
+ - [Installation](#installation)
10
+ - [Basic Usage](#basic-usage)
11
+ - [Advanced Usage](#advanced-usage)
12
+ - [Channel Lifecycle](#channel-lifecycle)
13
+ - [Request Processing](#request-processing)
14
+ - [Send Operations](#send-operations)
15
+ - [Error Handling](#error-handling)
16
+ - [Type Safety](#type-safety)
17
+ - [Extension and Customization](#extension-and-customization)
18
+ - [API Reference](#api-reference)
19
+ - [Examples](#examples)
20
+
21
+ ## Overview
22
+
23
+ A-Channel implements communication patterns that allow you to encapsulate messaging operations as structured, extensible components. It provides a foundation for building various types of communication channels (HTTP, WebSocket, Message Queues, etc.) with consistent lifecycle management and error handling.
24
+
25
+ ## Key Features
26
+
27
+ - 🔄 **Lifecycle Management** - Complete connection and processing lifecycle with hooks
28
+ - 📡 **Multiple Communication Patterns** - Request/Response and Fire-and-Forget messaging
29
+ - 🛡️ **Error Handling** - Comprehensive error capture and management
30
+ - 🎯 **Type Safety** - Full TypeScript support with generic types
31
+ - 🔧 **Extensible** - Component-based architecture for custom behavior
32
+ - ⚡ **Concurrent Processing** - Handle multiple requests simultaneously
33
+ - 📊 **Processing State** - Built-in state tracking and management
34
+ - 🏗️ **Dependency Injection** - Integration with A-Context for scope management
35
+
36
+ ## Installation
37
+
38
+ ```bash
39
+ npm install @adaas/a-utils
40
+ ```
41
+
42
+ ## Basic Usage
43
+
44
+ ### Simple Channel Creation
45
+
46
+ ```typescript
47
+ import { A_Channel } from '@adaas/a-utils/lib/A-Channel/A-Channel.component';
48
+ import { A_Context } from '@adaas/a-concept';
49
+
50
+ // Create a basic channel
51
+ const channel = new A_Channel();
52
+ A_Context.root.register(channel);
53
+
54
+ // Initialize the channel
55
+ await channel.initialize;
56
+
57
+ console.log(`Channel ready, processing: ${channel.processing}`);
58
+ ```
59
+
60
+ ### Basic Request/Response
61
+
62
+ ```typescript
63
+ // Send a request and get response
64
+ const response = await channel.request({
65
+ action: 'getUserData',
66
+ userId: '12345'
67
+ });
68
+
69
+ console.log('Request params:', response.params);
70
+ console.log('Response data:', response.data);
71
+ console.log('Request status:', response.status);
72
+ ```
73
+
74
+ ### Fire-and-Forget Messaging
75
+
76
+ ```typescript
77
+ // Send a message without waiting for response
78
+ await channel.send({
79
+ type: 'notification',
80
+ message: 'User logged in',
81
+ timestamp: new Date().toISOString()
82
+ });
83
+
84
+ console.log('Message sent successfully');
85
+ ```
86
+
87
+ ## Advanced Usage
88
+
89
+ ### Custom Channel with Business Logic
90
+
91
+ ```typescript
92
+ import { A_Component, A_Feature, A_Inject } from '@adaas/a-concept';
93
+ import { A_ChannelFeatures } from '@adaas/a-utils/lib/A-Channel/A-Channel.constants';
94
+ import { A_ChannelRequestContext } from '@adaas/a-utils/lib/A-Channel/A-ChannelRequest.context';
95
+
96
+ // Define typed interfaces
97
+ interface UserRequest {
98
+ action: 'create' | 'update' | 'delete';
99
+ userId: string;
100
+ userData?: any;
101
+ }
102
+
103
+ interface UserResponse {
104
+ success: boolean;
105
+ userId: string;
106
+ message: string;
107
+ timestamp: string;
108
+ }
109
+
110
+ // Create custom channel
111
+ class UserManagementChannel extends A_Channel {}
112
+
113
+ // Create custom processor
114
+ class UserProcessor extends A_Component {
115
+
116
+ @A_Feature.Extend({ scope: [UserManagementChannel] })
117
+ async [A_ChannelFeatures.onConnect]() {
118
+ console.log('User management channel connected');
119
+ // Initialize database connections, validate configuration, etc.
120
+ }
121
+
122
+ @A_Feature.Extend({ scope: [UserManagementChannel] })
123
+ async [A_ChannelFeatures.onBeforeRequest](
124
+ @A_Inject(A_ChannelRequestContext) context: A_ChannelRequestContext<UserRequest>
125
+ ) {
126
+ // Validate request
127
+ const { action, userId } = context.params;
128
+ if (!userId) {
129
+ throw new Error('User ID is required');
130
+ }
131
+ console.log(`Processing ${action} for user ${userId}`);
132
+ }
133
+
134
+ @A_Feature.Extend({ scope: [UserManagementChannel] })
135
+ async [A_ChannelFeatures.onRequest](
136
+ @A_Inject(A_ChannelRequestContext) context: A_ChannelRequestContext<UserRequest, UserResponse>
137
+ ) {
138
+ const { action, userId, userData } = context.params;
139
+
140
+ // Simulate business logic
141
+ let message = '';
142
+ switch (action) {
143
+ case 'create':
144
+ message = `User ${userId} created successfully`;
145
+ break;
146
+ case 'update':
147
+ message = `User ${userId} updated successfully`;
148
+ break;
149
+ case 'delete':
150
+ message = `User ${userId} deleted successfully`;
151
+ break;
152
+ }
153
+
154
+ // Set response data
155
+ (context as any)._result = {
156
+ success: true,
157
+ userId,
158
+ message,
159
+ timestamp: new Date().toISOString()
160
+ };
161
+ }
162
+
163
+ @A_Feature.Extend({ scope: [UserManagementChannel] })
164
+ async [A_ChannelFeatures.onAfterRequest](
165
+ @A_Inject(A_ChannelRequestContext) context: A_ChannelRequestContext<UserRequest, UserResponse>
166
+ ) {
167
+ // Log successful completion
168
+ console.log(`Request completed: ${context.data?.message}`);
169
+ }
170
+
171
+ @A_Feature.Extend({ scope: [UserManagementChannel] })
172
+ async [A_ChannelFeatures.onError](
173
+ @A_Inject(A_ChannelRequestContext) context: A_ChannelRequestContext<UserRequest>
174
+ ) {
175
+ console.error(`Request failed for action: ${context.params.action}`);
176
+ // Log error, send alerts, etc.
177
+ }
178
+ }
179
+
180
+ // Usage
181
+ A_Context.reset();
182
+ A_Context.root.register(UserProcessor);
183
+
184
+ const userChannel = new UserManagementChannel();
185
+ A_Context.root.register(userChannel);
186
+
187
+ // Process user requests
188
+ const createResponse = await userChannel.request<UserRequest, UserResponse>({
189
+ action: 'create',
190
+ userId: 'user-123',
191
+ userData: { name: 'John Doe', email: 'john@example.com' }
192
+ });
193
+
194
+ console.log('User created:', createResponse.data);
195
+ ```
196
+
197
+ ## Channel Lifecycle
198
+
199
+ A-Channel follows a structured lifecycle with multiple extension points:
200
+
201
+ ### Connection Lifecycle
202
+
203
+ ```typescript
204
+ class LifecycleChannel extends A_Channel {}
205
+
206
+ class LifecycleProcessor extends A_Component {
207
+
208
+ @A_Feature.Extend({ scope: [LifecycleChannel] })
209
+ async [A_ChannelFeatures.onConnect]() {
210
+ console.log('1. Channel connecting...');
211
+ // Initialize connections, load configuration, validate environment
212
+ }
213
+
214
+ @A_Feature.Extend({ scope: [LifecycleChannel] })
215
+ async [A_ChannelFeatures.onDisconnect]() {
216
+ console.log('6. Channel disconnecting...');
217
+ // Cleanup resources, close connections, save state
218
+ }
219
+ }
220
+
221
+ const channel = new LifecycleChannel();
222
+ A_Context.root.register(LifecycleProcessor);
223
+ A_Context.root.register(channel);
224
+
225
+ // Initialize (calls onConnect)
226
+ await channel.initialize;
227
+
228
+ // Use channel for requests...
229
+
230
+ // Cleanup (calls onDisconnect)
231
+ await channel.disconnect();
232
+ ```
233
+
234
+ ### Request Lifecycle
235
+
236
+ ```typescript
237
+ class RequestLifecycleProcessor extends A_Component {
238
+
239
+ @A_Feature.Extend({ scope: [LifecycleChannel] })
240
+ async [A_ChannelFeatures.onBeforeRequest](
241
+ @A_Inject(A_ChannelRequestContext) context: A_ChannelRequestContext
242
+ ) {
243
+ console.log('2. Pre-processing request...');
244
+ // Validate input, authenticate, rate limiting
245
+ }
246
+
247
+ @A_Feature.Extend({ scope: [LifecycleChannel] })
248
+ async [A_ChannelFeatures.onRequest](
249
+ @A_Inject(A_ChannelRequestContext) context: A_ChannelRequestContext
250
+ ) {
251
+ console.log('3. Processing request...');
252
+ // Main business logic
253
+ }
254
+
255
+ @A_Feature.Extend({ scope: [LifecycleChannel] })
256
+ async [A_ChannelFeatures.onAfterRequest](
257
+ @A_Inject(A_ChannelRequestContext) context: A_ChannelRequestContext
258
+ ) {
259
+ console.log('4. Post-processing request...');
260
+ // Logging, analytics, cleanup
261
+ }
262
+
263
+ @A_Feature.Extend({ scope: [LifecycleChannel] })
264
+ async [A_ChannelFeatures.onError](
265
+ @A_Inject(A_ChannelRequestContext) context: A_ChannelRequestContext
266
+ ) {
267
+ console.log('5. Handling error...');
268
+ // Error logging, alerts, recovery
269
+ }
270
+ }
271
+ ```
272
+
273
+ ## Request Processing
274
+
275
+ ### Synchronous Request/Response
276
+
277
+ ```typescript
278
+ class APIChannel extends A_Channel {}
279
+
280
+ class APIProcessor extends A_Component {
281
+
282
+ @A_Feature.Extend({ scope: [APIChannel] })
283
+ async [A_ChannelFeatures.onRequest](
284
+ @A_Inject(A_ChannelRequestContext) context: A_ChannelRequestContext
285
+ ) {
286
+ const { endpoint, method, body } = context.params;
287
+
288
+ // Simulate API call
289
+ const response = await fetch(endpoint, {
290
+ method,
291
+ body: JSON.stringify(body),
292
+ headers: { 'Content-Type': 'application/json' }
293
+ });
294
+
295
+ const data = await response.json();
296
+ (context as any)._result = {
297
+ status: response.status,
298
+ data,
299
+ headers: Object.fromEntries(response.headers.entries())
300
+ };
301
+ }
302
+ }
303
+
304
+ A_Context.root.register(APIProcessor);
305
+
306
+ const apiChannel = new APIChannel();
307
+ A_Context.root.register(apiChannel);
308
+
309
+ const response = await apiChannel.request({
310
+ endpoint: 'https://api.example.com/users',
311
+ method: 'GET'
312
+ });
313
+
314
+ console.log('API Response:', response.data);
315
+ ```
316
+
317
+ ### Concurrent Request Processing
318
+
319
+ ```typescript
320
+ // Process multiple requests concurrently
321
+ const requests = [
322
+ apiChannel.request({ endpoint: '/users/1', method: 'GET' }),
323
+ apiChannel.request({ endpoint: '/users/2', method: 'GET' }),
324
+ apiChannel.request({ endpoint: '/users/3', method: 'GET' })
325
+ ];
326
+
327
+ const responses = await Promise.all(requests);
328
+ responses.forEach((response, index) => {
329
+ console.log(`User ${index + 1}:`, response.data);
330
+ });
331
+ ```
332
+
333
+ ## Send Operations
334
+
335
+ ### Event Broadcasting
336
+
337
+ ```typescript
338
+ class EventChannel extends A_Channel {}
339
+
340
+ class EventBroadcaster extends A_Component {
341
+
342
+ @A_Feature.Extend({ scope: [EventChannel] })
343
+ async [A_ChannelFeatures.onSend](
344
+ @A_Inject(A_ChannelRequestContext) context: A_ChannelRequestContext
345
+ ) {
346
+ const { eventType, payload, recipients } = context.params;
347
+
348
+ console.log(`Broadcasting ${eventType} to ${recipients.length} recipients`);
349
+
350
+ // Simulate broadcasting
351
+ for (const recipient of recipients) {
352
+ console.log(`Sending to ${recipient}:`, payload);
353
+ // Send to message queue, WebSocket, email service, etc.
354
+ }
355
+ }
356
+ }
357
+
358
+ A_Context.root.register(EventBroadcaster);
359
+
360
+ const eventChannel = new EventChannel();
361
+ A_Context.root.register(eventChannel);
362
+
363
+ // Send notification to multiple users
364
+ await eventChannel.send({
365
+ eventType: 'user.login',
366
+ payload: { userId: '123', timestamp: new Date() },
367
+ recipients: ['admin@example.com', 'user@example.com']
368
+ });
369
+ ```
370
+
371
+ ### Message Queuing
372
+
373
+ ```typescript
374
+ class QueueChannel extends A_Channel {}
375
+
376
+ class MessageQueue extends A_Component {
377
+ private queue: any[] = [];
378
+
379
+ @A_Feature.Extend({ scope: [QueueChannel] })
380
+ async [A_ChannelFeatures.onSend](
381
+ @A_Inject(A_ChannelRequestContext) context: A_ChannelRequestContext
382
+ ) {
383
+ const message = {
384
+ id: Date.now(),
385
+ payload: context.params,
386
+ timestamp: new Date(),
387
+ retries: 0
388
+ };
389
+
390
+ this.queue.push(message);
391
+ console.log(`Queued message ${message.id}, queue size: ${this.queue.length}`);
392
+
393
+ // Process queue asynchronously
394
+ setImmediate(() => this.processQueue());
395
+ }
396
+
397
+ private async processQueue() {
398
+ while (this.queue.length > 0) {
399
+ const message = this.queue.shift();
400
+ try {
401
+ await this.processMessage(message);
402
+ console.log(`Processed message ${message.id}`);
403
+ } catch (error) {
404
+ console.error(`Failed to process message ${message.id}:`, error);
405
+ // Implement retry logic
406
+ }
407
+ }
408
+ }
409
+
410
+ private async processMessage(message: any) {
411
+ // Simulate message processing
412
+ await new Promise(resolve => setTimeout(resolve, 100));
413
+ }
414
+ }
415
+
416
+ A_Context.root.register(MessageQueue);
417
+
418
+ const queueChannel = new QueueChannel();
419
+ A_Context.root.register(queueChannel);
420
+
421
+ // Send messages to queue
422
+ await queueChannel.send({ type: 'email', to: 'user@example.com' });
423
+ await queueChannel.send({ type: 'sms', to: '+1234567890' });
424
+ ```
425
+
426
+ ## Error Handling
427
+
428
+ ### Comprehensive Error Management
429
+
430
+ ```typescript
431
+ import { A_ChannelError } from '@adaas/a-utils/lib/A-Channel/A-Channel.error';
432
+
433
+ class RobustChannel extends A_Channel {}
434
+
435
+ class ErrorHandler extends A_Component {
436
+
437
+ @A_Feature.Extend({ scope: [RobustChannel] })
438
+ async [A_ChannelFeatures.onRequest](
439
+ @A_Inject(A_ChannelRequestContext) context: A_ChannelRequestContext
440
+ ) {
441
+ const { operation } = context.params;
442
+
443
+ switch (operation) {
444
+ case 'network_error':
445
+ throw new Error('Network connection failed');
446
+ case 'validation_error':
447
+ throw new Error('Invalid input data');
448
+ case 'timeout_error':
449
+ throw new Error('Operation timed out');
450
+ case 'success':
451
+ (context as any)._result = { success: true };
452
+ break;
453
+ default:
454
+ throw new Error('Unknown operation');
455
+ }
456
+ }
457
+
458
+ @A_Feature.Extend({ scope: [RobustChannel] })
459
+ async [A_ChannelFeatures.onError](
460
+ @A_Inject(A_ChannelRequestContext) context: A_ChannelRequestContext
461
+ ) {
462
+ console.log('Error details:', {
463
+ operation: context.params.operation,
464
+ failed: context.failed,
465
+ status: context.status
466
+ });
467
+
468
+ // Implement error recovery, alerting, logging
469
+ if (context.params.operation === 'network_error') {
470
+ console.log('Implementing network retry logic...');
471
+ }
472
+ }
473
+ }
474
+
475
+ A_Context.root.register(ErrorHandler);
476
+
477
+ const robustChannel = new RobustChannel();
478
+ A_Context.root.register(robustChannel);
479
+
480
+ // Test error handling
481
+ const operations = ['success', 'network_error', 'validation_error'];
482
+
483
+ for (const operation of operations) {
484
+ const result = await robustChannel.request({ operation });
485
+
486
+ if (result.failed) {
487
+ console.log(`Operation ${operation} failed as expected`);
488
+ } else {
489
+ console.log(`Operation ${operation} succeeded:`, result.data);
490
+ }
491
+ }
492
+ ```
493
+
494
+ ## Type Safety
495
+
496
+ ### Strongly Typed Channels
497
+
498
+ ```typescript
499
+ // Define strict interfaces
500
+ interface DatabaseQuery {
501
+ table: string;
502
+ operation: 'SELECT' | 'INSERT' | 'UPDATE' | 'DELETE';
503
+ where?: Record<string, any>;
504
+ data?: Record<string, any>;
505
+ }
506
+
507
+ interface DatabaseResult {
508
+ success: boolean;
509
+ rowsAffected: number;
510
+ data?: any[];
511
+ insertId?: number;
512
+ }
513
+
514
+ class DatabaseChannel extends A_Channel {}
515
+
516
+ class DatabaseProcessor extends A_Component {
517
+
518
+ @A_Feature.Extend({ scope: [DatabaseChannel] })
519
+ async [A_ChannelFeatures.onRequest](
520
+ @A_Inject(A_ChannelRequestContext) context: A_ChannelRequestContext<DatabaseQuery, DatabaseResult>
521
+ ) {
522
+ const { table, operation, where, data } = context.params;
523
+
524
+ // Type-safe access to parameters
525
+ console.log(`Executing ${operation} on table ${table}`);
526
+
527
+ // Simulate database operation
528
+ let result: DatabaseResult;
529
+
530
+ switch (operation) {
531
+ case 'SELECT':
532
+ result = {
533
+ success: true,
534
+ rowsAffected: 0,
535
+ data: [{ id: 1, name: 'Test' }]
536
+ };
537
+ break;
538
+ case 'INSERT':
539
+ result = {
540
+ success: true,
541
+ rowsAffected: 1,
542
+ insertId: 123
543
+ };
544
+ break;
545
+ default:
546
+ result = {
547
+ success: true,
548
+ rowsAffected: 1
549
+ };
550
+ }
551
+
552
+ (context as any)._result = result;
553
+ }
554
+ }
555
+
556
+ A_Context.root.register(DatabaseProcessor);
557
+
558
+ const dbChannel = new DatabaseChannel();
559
+ A_Context.root.register(dbChannel);
560
+
561
+ // Type-safe requests
562
+ const selectResult = await dbChannel.request<DatabaseQuery, DatabaseResult>({
563
+ table: 'users',
564
+ operation: 'SELECT',
565
+ where: { active: true }
566
+ });
567
+
568
+ // TypeScript provides full intellisense and type checking
569
+ if (selectResult.data?.success) {
570
+ console.log('Selected rows:', selectResult.data.data?.length);
571
+ }
572
+
573
+ const insertResult = await dbChannel.request<DatabaseQuery, DatabaseResult>({
574
+ table: 'users',
575
+ operation: 'INSERT',
576
+ data: { name: 'John Doe', email: 'john@example.com' }
577
+ });
578
+
579
+ if (insertResult.data?.success) {
580
+ console.log('Inserted user with ID:', insertResult.data.insertId);
581
+ }
582
+ ```
583
+
584
+ ## Extension and Customization
585
+
586
+ ### Multi-Feature Channel
587
+
588
+ ```typescript
589
+ class AdvancedChannel extends A_Channel {
590
+ private metrics = { requests: 0, errors: 0, totalTime: 0 };
591
+
592
+ getMetrics() {
593
+ return { ...this.metrics };
594
+ }
595
+
596
+ resetMetrics() {
597
+ this.metrics = { requests: 0, errors: 0, totalTime: 0 };
598
+ }
599
+ }
600
+
601
+ class MetricsCollector extends A_Component {
602
+
603
+ @A_Feature.Extend({ scope: [AdvancedChannel] })
604
+ async [A_ChannelFeatures.onBeforeRequest](
605
+ @A_Inject(A_ChannelRequestContext) context: A_ChannelRequestContext
606
+ ) {
607
+ (context as any)._startTime = Date.now();
608
+ }
609
+
610
+ @A_Feature.Extend({ scope: [AdvancedChannel] })
611
+ async [A_ChannelFeatures.onAfterRequest](
612
+ @A_Inject(A_ChannelRequestContext) context: A_ChannelRequestContext
613
+ ) {
614
+ const channel = A_Context.scope(this).resolve(AdvancedChannel);
615
+ const duration = Date.now() - (context as any)._startTime;
616
+
617
+ channel['metrics'].requests++;
618
+ channel['metrics'].totalTime += duration;
619
+ }
620
+
621
+ @A_Feature.Extend({ scope: [AdvancedChannel] })
622
+ async [A_ChannelFeatures.onError](
623
+ @A_Inject(A_ChannelRequestContext) context: A_ChannelRequestContext
624
+ ) {
625
+ const channel = A_Context.scope(this).resolve(AdvancedChannel);
626
+ channel['metrics'].errors++;
627
+ }
628
+ }
629
+
630
+ class CacheLayer extends A_Component {
631
+ private cache = new Map<string, any>();
632
+
633
+ @A_Feature.Extend({ scope: [AdvancedChannel] })
634
+ async [A_ChannelFeatures.onBeforeRequest](
635
+ @A_Inject(A_ChannelRequestContext) context: A_ChannelRequestContext
636
+ ) {
637
+ const cacheKey = JSON.stringify(context.params);
638
+
639
+ if (this.cache.has(cacheKey)) {
640
+ console.log('Cache hit!');
641
+ (context as any)._result = this.cache.get(cacheKey);
642
+ (context as any)._cached = true;
643
+ }
644
+ }
645
+
646
+ @A_Feature.Extend({ scope: [AdvancedChannel] })
647
+ async [A_ChannelFeatures.onAfterRequest](
648
+ @A_Inject(A_ChannelRequestContext) context: A_ChannelRequestContext
649
+ ) {
650
+ if (!(context as any)._cached && context.data) {
651
+ const cacheKey = JSON.stringify(context.params);
652
+ this.cache.set(cacheKey, context.data);
653
+ console.log('Cached result');
654
+ }
655
+ }
656
+ }
657
+
658
+ // Register multiple processors
659
+ A_Context.root.register(MetricsCollector);
660
+ A_Context.root.register(CacheLayer);
661
+
662
+ const advancedChannel = new AdvancedChannel();
663
+ A_Context.root.register(advancedChannel);
664
+
665
+ // Use channel with metrics and caching
666
+ await advancedChannel.request({ action: 'getData', id: 1 });
667
+ await advancedChannel.request({ action: 'getData', id: 1 }); // Cache hit
668
+ await advancedChannel.request({ action: 'getData', id: 2 });
669
+
670
+ console.log('Metrics:', advancedChannel.getMetrics());
671
+ ```
672
+
673
+ ## API Reference
674
+
675
+ ### A_Channel Class
676
+
677
+ #### Properties
678
+ - `processing: boolean` - Indicates if channel is currently processing requests
679
+ - `initialize: Promise<void>` - Promise that resolves when channel is initialized
680
+
681
+ #### Methods
682
+
683
+ ##### Connection Management
684
+ - `async connect(): Promise<void>` - Initialize the channel
685
+ - `async disconnect(): Promise<void>` - Cleanup and disconnect the channel
686
+
687
+ ##### Communication
688
+ - `async request<T, R>(params: T): Promise<A_ChannelRequestContext<T, R>>` - Send request and wait for response
689
+ - `async send<T>(message: T): Promise<void>` - Send fire-and-forget message
690
+
691
+ #### Lifecycle Hooks (Extensible via A_Feature)
692
+ - `onConnect` - Called during channel initialization
693
+ - `onDisconnect` - Called during channel cleanup
694
+ - `onBeforeRequest` - Called before processing request
695
+ - `onRequest` - Called to process request
696
+ - `onAfterRequest` - Called after processing request
697
+ - `onSend` - Called to process send operation
698
+ - `onError` - Called when any operation fails
699
+
700
+ ### A_ChannelRequestContext Class
701
+
702
+ #### Properties
703
+ - `params: T` - Request parameters
704
+ - `data: R` - Response data (after processing)
705
+ - `status: A_ChannelRequestStatuses` - Request status (PENDING, SUCCESS, FAILED)
706
+ - `failed: boolean` - Whether the request failed
707
+
708
+ #### Methods
709
+ - `fail(error: Error): void` - Mark request as failed
710
+
711
+ ### Constants
712
+
713
+ #### A_ChannelRequestStatuses
714
+ ```typescript
715
+ enum A_ChannelRequestStatuses {
716
+ PENDING = 'PENDING',
717
+ SUCCESS = 'SUCCESS',
718
+ FAILED = 'FAILED'
719
+ }
720
+ ```
721
+
722
+ ## Examples
723
+
724
+ ### HTTP Client Channel
725
+
726
+ ```typescript
727
+ class HttpChannel extends A_Channel {
728
+ constructor(private baseUrl: string, private defaultHeaders: Record<string, string> = {}) {
729
+ super();
730
+ }
731
+
732
+ async get(path: string, headers?: Record<string, string>) {
733
+ return this.request({
734
+ method: 'GET',
735
+ url: `${this.baseUrl}${path}`,
736
+ headers: { ...this.defaultHeaders, ...headers }
737
+ });
738
+ }
739
+
740
+ async post(path: string, body: any, headers?: Record<string, string>) {
741
+ return this.request({
742
+ method: 'POST',
743
+ url: `${this.baseUrl}${path}`,
744
+ body,
745
+ headers: { ...this.defaultHeaders, ...headers }
746
+ });
747
+ }
748
+ }
749
+
750
+ class HttpProcessor extends A_Component {
751
+ @A_Feature.Extend({ scope: [HttpChannel] })
752
+ async [A_ChannelFeatures.onRequest](
753
+ @A_Inject(A_ChannelRequestContext) context: A_ChannelRequestContext
754
+ ) {
755
+ const { method, url, body, headers } = context.params;
756
+
757
+ const response = await fetch(url, {
758
+ method,
759
+ body: body ? JSON.stringify(body) : undefined,
760
+ headers: {
761
+ 'Content-Type': 'application/json',
762
+ ...headers
763
+ }
764
+ });
765
+
766
+ const data = await response.json();
767
+
768
+ (context as any)._result = {
769
+ status: response.status,
770
+ statusText: response.statusText,
771
+ data,
772
+ headers: Object.fromEntries(response.headers.entries())
773
+ };
774
+ }
775
+ }
776
+
777
+ // Usage
778
+ A_Context.root.register(HttpProcessor);
779
+
780
+ const httpClient = new HttpChannel('https://api.example.com', {
781
+ 'Authorization': 'Bearer token123'
782
+ });
783
+ A_Context.root.register(httpClient);
784
+
785
+ const userResponse = await httpClient.get('/users/123');
786
+ console.log('User data:', userResponse.data);
787
+
788
+ const createResponse = await httpClient.post('/users', {
789
+ name: 'John Doe',
790
+ email: 'john@example.com'
791
+ });
792
+ console.log('Created user:', createResponse.data);
793
+ ```
794
+
795
+ ### WebSocket Channel
796
+
797
+ ```typescript
798
+ class WebSocketChannel extends A_Channel {
799
+ private ws?: WebSocket;
800
+
801
+ async connectWebSocket(url: string) {
802
+ return new Promise<void>((resolve, reject) => {
803
+ this.ws = new WebSocket(url);
804
+ this.ws.onopen = () => resolve();
805
+ this.ws.onerror = (error) => reject(error);
806
+ });
807
+ }
808
+ }
809
+
810
+ class WebSocketProcessor extends A_Component {
811
+
812
+ @A_Feature.Extend({ scope: [WebSocketChannel] })
813
+ async [A_ChannelFeatures.onConnect]() {
814
+ const channel = A_Context.scope(this).resolve(WebSocketChannel);
815
+ await channel.connectWebSocket('ws://localhost:8080');
816
+ console.log('WebSocket connected');
817
+ }
818
+
819
+ @A_Feature.Extend({ scope: [WebSocketChannel] })
820
+ async [A_ChannelFeatures.onSend](
821
+ @A_Inject(A_ChannelRequestContext) context: A_ChannelRequestContext
822
+ ) {
823
+ const channel = A_Context.scope(this).resolve(WebSocketChannel);
824
+ const message = JSON.stringify(context.params);
825
+
826
+ if (channel['ws']?.readyState === WebSocket.OPEN) {
827
+ channel['ws'].send(message);
828
+ console.log('Message sent via WebSocket');
829
+ } else {
830
+ throw new Error('WebSocket not connected');
831
+ }
832
+ }
833
+ }
834
+
835
+ // Usage
836
+ A_Context.root.register(WebSocketProcessor);
837
+
838
+ const wsChannel = new WebSocketChannel();
839
+ A_Context.root.register(wsChannel);
840
+
841
+ await wsChannel.initialize;
842
+
843
+ await wsChannel.send({
844
+ type: 'chat',
845
+ message: 'Hello WebSocket!',
846
+ timestamp: new Date().toISOString()
847
+ });
848
+ ```
849
+
850
+ ---
851
+
852
+ ## Contributing
853
+
854
+ When extending A-Channel functionality, please ensure:
855
+
856
+ 1. All new features include comprehensive tests
857
+ 2. TypeScript types are properly defined and exported
858
+ 3. Documentation is updated for new APIs
859
+ 4. Examples are provided for complex features
860
+ 5. Backward compatibility is maintained
861
+
862
+ ## License
863
+
864
+ This project is licensed under the MIT License - see the LICENSE file for details.