legend-transactional 2.2.3 → 2.3.0
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/dist/index.d.mts +190 -4
- package/dist/index.d.ts +190 -4
- package/dist/index.js +170 -12
- package/dist/index.mjs +168 -13
- package/package.json +1 -1
package/dist/index.d.mts
CHANGED
|
@@ -72,6 +72,12 @@ declare const availableMicroservices: {
|
|
|
72
72
|
* Represents the "legend-storage" microservice.
|
|
73
73
|
*/
|
|
74
74
|
readonly Storage: "legend-storage";
|
|
75
|
+
/**
|
|
76
|
+
* Represents the "audit-eda" microservice for event-driven architecture auditing.
|
|
77
|
+
* This microservice consumes audit events (audit.received, audit.processed, audit.dead_letter)
|
|
78
|
+
* to track event lifecycle and debugging purposes.
|
|
79
|
+
*/
|
|
80
|
+
readonly AuditEda: "audit-eda";
|
|
75
81
|
};
|
|
76
82
|
/**
|
|
77
83
|
* Type of available microservices in the system.
|
|
@@ -460,6 +466,89 @@ interface EventPayload {
|
|
|
460
466
|
bucketName: string;
|
|
461
467
|
filePaths: string[];
|
|
462
468
|
};
|
|
469
|
+
/**
|
|
470
|
+
* Emitted when an event is received by a microservice before processing starts (audit tracking)
|
|
471
|
+
*/
|
|
472
|
+
'audit.received': {
|
|
473
|
+
/**
|
|
474
|
+
* The microservice that received the event
|
|
475
|
+
*/
|
|
476
|
+
microservice: string;
|
|
477
|
+
/**
|
|
478
|
+
* The event that was received
|
|
479
|
+
*/
|
|
480
|
+
receivedEvent: string;
|
|
481
|
+
/**
|
|
482
|
+
* Timestamp when the event was received (UNIX timestamp in seconds)
|
|
483
|
+
*/
|
|
484
|
+
receivedAt: number;
|
|
485
|
+
/**
|
|
486
|
+
* The queue name from which the event was consumed
|
|
487
|
+
*/
|
|
488
|
+
queueName: string;
|
|
489
|
+
/**
|
|
490
|
+
* Optional event identifier for tracking
|
|
491
|
+
*/
|
|
492
|
+
eventId?: string;
|
|
493
|
+
};
|
|
494
|
+
/**
|
|
495
|
+
* Emitted when an event is successfully processed by a microservice for audit tracking
|
|
496
|
+
*/
|
|
497
|
+
'audit.processed': {
|
|
498
|
+
/**
|
|
499
|
+
* The microservice that processed the event
|
|
500
|
+
*/
|
|
501
|
+
microservice: string;
|
|
502
|
+
/**
|
|
503
|
+
* The original event that was processed
|
|
504
|
+
*/
|
|
505
|
+
processedEvent: string;
|
|
506
|
+
/**
|
|
507
|
+
* Timestamp when the event was processed (UNIX timestamp in seconds)
|
|
508
|
+
*/
|
|
509
|
+
processedAt: number;
|
|
510
|
+
/**
|
|
511
|
+
* The queue name where the event was consumed
|
|
512
|
+
*/
|
|
513
|
+
queueName: string;
|
|
514
|
+
/**
|
|
515
|
+
* Optional event identifier for tracking
|
|
516
|
+
*/
|
|
517
|
+
eventId?: string;
|
|
518
|
+
};
|
|
519
|
+
/**
|
|
520
|
+
* Emitted when a message is rejected/nacked and sent to dead letter queue
|
|
521
|
+
*/
|
|
522
|
+
'audit.dead_letter': {
|
|
523
|
+
/**
|
|
524
|
+
* The microservice that rejected the event
|
|
525
|
+
*/
|
|
526
|
+
microservice: string;
|
|
527
|
+
/**
|
|
528
|
+
* The original event that was rejected
|
|
529
|
+
*/
|
|
530
|
+
rejectedEvent: string;
|
|
531
|
+
/**
|
|
532
|
+
* Timestamp when the event was rejected (UNIX timestamp in seconds)
|
|
533
|
+
*/
|
|
534
|
+
rejectedAt: number;
|
|
535
|
+
/**
|
|
536
|
+
* The queue name where the event was rejected from
|
|
537
|
+
*/
|
|
538
|
+
queueName: string;
|
|
539
|
+
/**
|
|
540
|
+
* Reason for rejection (delay, fibonacci_strategy, etc.)
|
|
541
|
+
*/
|
|
542
|
+
rejectionReason: 'delay' | 'fibonacci_strategy';
|
|
543
|
+
/**
|
|
544
|
+
* Optional retry count
|
|
545
|
+
*/
|
|
546
|
+
retryCount?: number;
|
|
547
|
+
/**
|
|
548
|
+
* Optional event identifier for tracking
|
|
549
|
+
*/
|
|
550
|
+
eventId?: string;
|
|
551
|
+
};
|
|
463
552
|
}
|
|
464
553
|
/**
|
|
465
554
|
* Represents the available events in the system.
|
|
@@ -467,6 +556,9 @@ interface EventPayload {
|
|
|
467
556
|
declare const microserviceEvent: {
|
|
468
557
|
readonly 'TEST.IMAGE': "test.image";
|
|
469
558
|
readonly 'TEST.MINT': "test.mint";
|
|
559
|
+
readonly 'AUDIT.RECEIVED': "audit.received";
|
|
560
|
+
readonly 'AUDIT.PROCESSED': "audit.processed";
|
|
561
|
+
readonly 'AUDIT.DEAD_LETTER': "audit.dead_letter";
|
|
470
562
|
readonly 'AUTH.DELETED_USER': "auth.deleted_user";
|
|
471
563
|
readonly 'AUTH.LOGOUT_USER': "auth.logout_user";
|
|
472
564
|
readonly 'AUTH.NEW_USER': "auth.new_user";
|
|
@@ -559,7 +651,7 @@ declare abstract class ConsumeChannel {
|
|
|
559
651
|
*
|
|
560
652
|
* @see NACKING_DELAY_MS
|
|
561
653
|
*/
|
|
562
|
-
nackWithDelay
|
|
654
|
+
nackWithDelay(delay?: number, maxRetries?: number): {
|
|
563
655
|
count: number;
|
|
564
656
|
delay: number;
|
|
565
657
|
};
|
|
@@ -576,7 +668,7 @@ declare abstract class ConsumeChannel {
|
|
|
576
668
|
* - `occurrence`: The current occurrence count for the Fibonacci sequence.
|
|
577
669
|
* @see MAX_OCCURRENCE
|
|
578
670
|
*/
|
|
579
|
-
nackWithFibonacciStrategy
|
|
671
|
+
nackWithFibonacciStrategy(maxOccurrence?: number, maxRetries?: number): {
|
|
580
672
|
count: number;
|
|
581
673
|
delay: number;
|
|
582
674
|
occurrence: number;
|
|
@@ -595,14 +687,48 @@ declare abstract class ConsumeChannel {
|
|
|
595
687
|
|
|
596
688
|
/**
|
|
597
689
|
* Represents a **_consume_** channel for handling saga events/commands.
|
|
598
|
-
* Extends the abstract ConsumeChannel class.
|
|
690
|
+
* Extends the abstract ConsumeChannel class with automatic audit event emission.
|
|
599
691
|
*
|
|
600
692
|
*/
|
|
601
693
|
declare class EventsConsumeChannel extends ConsumeChannel {
|
|
694
|
+
/**
|
|
695
|
+
* The microservice name that is processing the event
|
|
696
|
+
*/
|
|
697
|
+
private readonly microservice;
|
|
698
|
+
/**
|
|
699
|
+
* The original event that was received
|
|
700
|
+
*/
|
|
701
|
+
private readonly processedEvent;
|
|
702
|
+
/**
|
|
703
|
+
* Creates a new EventsConsumeChannel instance
|
|
704
|
+
*
|
|
705
|
+
* @param channel - The AMQP Channel
|
|
706
|
+
* @param msg - The consumed message
|
|
707
|
+
* @param queueName - The queue name
|
|
708
|
+
* @param microservice - The microservice name processing the event
|
|
709
|
+
* @param processedEvent - The event type being processed
|
|
710
|
+
*/
|
|
711
|
+
constructor(channel: Channel, msg: ConsumeMessage, queueName: string, microservice: string, processedEvent: string);
|
|
602
712
|
/**
|
|
603
713
|
* Acknowledges the consumed saga event/command.
|
|
714
|
+
* Automatically emits audit.processed event after successful ACK.
|
|
604
715
|
*/
|
|
605
716
|
ackMessage(): void;
|
|
717
|
+
/**
|
|
718
|
+
* Override nackWithDelay to emit audit.dead_letter event
|
|
719
|
+
*/
|
|
720
|
+
nackWithDelay(delay?: number, maxRetries?: number): {
|
|
721
|
+
count: number;
|
|
722
|
+
delay: number;
|
|
723
|
+
};
|
|
724
|
+
/**
|
|
725
|
+
* Override nackWithFibonacciStrategy to emit audit.dead_letter event
|
|
726
|
+
*/
|
|
727
|
+
nackWithFibonacciStrategy(maxOccurrence?: number, maxRetries?: number): {
|
|
728
|
+
count: number;
|
|
729
|
+
delay: number;
|
|
730
|
+
occurrence: number;
|
|
731
|
+
};
|
|
606
732
|
}
|
|
607
733
|
|
|
608
734
|
/**
|
|
@@ -623,6 +749,13 @@ type MicroserviceConsumeEvents<T extends MicroserviceEvent> = {
|
|
|
623
749
|
* Represents the names of specific message queues in the RabbitMQ context.
|
|
624
750
|
*/
|
|
625
751
|
declare const queue: {
|
|
752
|
+
/**
|
|
753
|
+
* Audit queue names for separate audit event types
|
|
754
|
+
* @constant
|
|
755
|
+
*/
|
|
756
|
+
readonly AuditReceived: "audit_received_commands";
|
|
757
|
+
readonly AuditProcessed: "audit_processed_commands";
|
|
758
|
+
readonly AuditDeadLetter: "audit_dead_letter_commands";
|
|
626
759
|
/**
|
|
627
760
|
* Queue used for sending replies in response to saga events.
|
|
628
761
|
*/
|
|
@@ -636,6 +769,10 @@ declare const queue: {
|
|
|
636
769
|
* Represents the names of exchanges, which act as message routing hubs in the RabbitMQ context.
|
|
637
770
|
*/
|
|
638
771
|
declare const exchange: {
|
|
772
|
+
/**
|
|
773
|
+
* Audit exchange name for direct routing of audit events
|
|
774
|
+
*/
|
|
775
|
+
readonly Audit: "audit_exchange";
|
|
639
776
|
/**
|
|
640
777
|
* Exchange dedicated to requeueing messages that require further processing in a saga process
|
|
641
778
|
*/
|
|
@@ -693,6 +830,15 @@ declare const authCommands: {
|
|
|
693
830
|
*/
|
|
694
831
|
type AuthCommands = (typeof authCommands)[keyof typeof authCommands];
|
|
695
832
|
|
|
833
|
+
/**
|
|
834
|
+
* Different commands related to the "audit-eda" microservice.
|
|
835
|
+
*/
|
|
836
|
+
declare const auditEdaCommands: {};
|
|
837
|
+
/**
|
|
838
|
+
* Available commands for the "audit-eda" microservice.
|
|
839
|
+
*/
|
|
840
|
+
type AuditEdaCommands = (typeof auditEdaCommands)[keyof typeof auditEdaCommands];
|
|
841
|
+
|
|
696
842
|
/**
|
|
697
843
|
* Different commands related to the "blockchain" microservice.
|
|
698
844
|
*/
|
|
@@ -907,6 +1053,10 @@ interface CommandMap {
|
|
|
907
1053
|
* Represents the mapping of "auth" microservice commands.
|
|
908
1054
|
*/
|
|
909
1055
|
[availableMicroservices.Auth]: AuthCommands;
|
|
1056
|
+
/**
|
|
1057
|
+
* Represents the mapping of "audit-eda" microservice commands.
|
|
1058
|
+
*/
|
|
1059
|
+
[availableMicroservices.AuditEda]: AuditEdaCommands;
|
|
910
1060
|
/**
|
|
911
1061
|
* Represents the mapping of "blockchain" microservice commands.
|
|
912
1062
|
*/
|
|
@@ -1172,6 +1322,24 @@ declare const createConsumers: (consumers: QueueConsumerProps[]) => Promise<void
|
|
|
1172
1322
|
*/
|
|
1173
1323
|
declare const createHeaderConsumers: (queueName: string, events: MicroserviceEvent[]) => Promise<void>;
|
|
1174
1324
|
|
|
1325
|
+
/**
|
|
1326
|
+
* Creates audit logging infrastructure with direct exchange and separate queues
|
|
1327
|
+
* Uses direct exchange for efficient single-consumer delivery to audit microservice
|
|
1328
|
+
*
|
|
1329
|
+
* This function sets up the RabbitMQ infrastructure needed for audit event tracking:
|
|
1330
|
+
* - Creates a direct exchange for audit events
|
|
1331
|
+
* - Creates 3 separate queues (audit.received, audit.processed, audit.dead_letter)
|
|
1332
|
+
* - Binds each queue to the audit exchange with appropriate routing keys
|
|
1333
|
+
*
|
|
1334
|
+
* The direct exchange strategy ensures that:
|
|
1335
|
+
* - Only the audit microservice consumes audit events
|
|
1336
|
+
* - Routing is efficient (no pattern matching needed)
|
|
1337
|
+
* - Each audit event type has its own queue for isolation
|
|
1338
|
+
*
|
|
1339
|
+
* @internal This is called automatically when connecting to events
|
|
1340
|
+
*/
|
|
1341
|
+
declare const createAuditLoggingResources: () => Promise<void>;
|
|
1342
|
+
|
|
1175
1343
|
declare const sagaTitle: {
|
|
1176
1344
|
/**
|
|
1177
1345
|
* Saga used in the flow to purchase resources and deduct coins from the user.
|
|
@@ -1757,4 +1925,22 @@ declare const getEventObject: (event: MicroserviceEvent) => {
|
|
|
1757
1925
|
[x: string]: MicroserviceEvent;
|
|
1758
1926
|
};
|
|
1759
1927
|
|
|
1760
|
-
|
|
1928
|
+
/**
|
|
1929
|
+
* Extracts the microservice name from a queue name
|
|
1930
|
+
*
|
|
1931
|
+
* Queue names follow the pattern: `{microservice}_match_commands` or `{microservice}_saga_commands`
|
|
1932
|
+
* This utility extracts the microservice part from the queue name.
|
|
1933
|
+
*
|
|
1934
|
+
* @param queueName - The queue name (e.g., 'auth_match_commands', 'coins_saga_commands')
|
|
1935
|
+
* @returns The microservice name (e.g., 'auth', 'coins')
|
|
1936
|
+
*
|
|
1937
|
+
* @example
|
|
1938
|
+
* ```typescript
|
|
1939
|
+
* extractMicroserviceFromQueue('auth_match_commands'); // Returns: 'auth'
|
|
1940
|
+
* extractMicroserviceFromQueue('coins_saga_commands'); // Returns: 'coins'
|
|
1941
|
+
* extractMicroserviceFromQueue('audit-eda_match_commands'); // Returns: 'audit-eda'
|
|
1942
|
+
* ```
|
|
1943
|
+
*/
|
|
1944
|
+
declare function extractMicroserviceFromQueue(queueName: string): string;
|
|
1945
|
+
|
|
1946
|
+
export { type AuditEdaCommands, type AuthCommands, type AvailableMicroservices, type BlockchainCommands, type CoinsCommands, type CommandMap, type CommenceSaga, type CommenceSagaEvents, type CommenceSagaHandler, type CompletedRanking, type EventPayload, EventsConsumeChannel, type EventsHandler, type Exchange, type Gender, MAX_NACK_RETRIES, MAX_OCCURRENCE, type MicroserviceCommand, MicroserviceConsumeChannel, type MicroserviceConsumeEvents, type MicroserviceConsumeSagaEvents, type MicroserviceEvent, type MicroserviceHandler, NACKING_DELAY_MS, type Nack, type PaymentEmailType, PaymentEmailTypes, type QueueConsumerProps, type RankingWinners, type RankingsCommands, type RapidMessagingCommands, type Room, type RoomCreatorCommands, type RoomInventoryCommands, type RoomSnapshotCommands, type RoomType, RoomTypes, Saga, SagaCommenceConsumeChannel, type SagaCommencePayload, SagaConsumeChannel, type SagaConsumeSagaEvents, type SagaHandler, type SagaStep, type SagaStepDefaults, type SagaTitle, type SendEmailCommands, type ShowcaseCommands, type SocialCommands, type SocialMediaRoomsCommands, type SocialUser, type Status, type StorageCommands, type TestImageCommands, type TestMintCommands, Transactional, type TransactionalConfig, type UserLocation, auditEdaCommands, authCommands, availableMicroservices, blockchainCommands, closeConsumeChannel, closeRabbitMQConn, closeSendChannel, coinsCommands, commenceSaga, commenceSagaConsumeCallback, commenceSagaListener, connectToEvents, connectToSagaCommandEmitter, consume, createAuditLoggingResources, createConsumers, createHeaderConsumers, eventCallback, exchange, extractMicroserviceFromQueue, fibonacci, gender, getConsumeChannel, getEventKey, getEventObject, getQueueConsumer, getQueueName, getRabbitMQConn, getSendChannel, isConnectionHealthy, microserviceEvent, nodeDataDefaults, publishEvent, queue, rankingsCommands, rapidMessagingCommands, roomCreatorCommands, roomInventoryCommands, roomSnapshotCommands, sagaConsumeCallback, sagaStepCallback, sagaTitle, saveQueueForHealthCheck, saveUri, sendEmailCommands, sendToQueue, showcaseCommands, socialCommands, socialMediaRoomsCommands, startGlobalSagaStepListener, status, stopRabbitMQ, storageCommands, testImageCommands, testMintCommands };
|
package/dist/index.d.ts
CHANGED
|
@@ -72,6 +72,12 @@ declare const availableMicroservices: {
|
|
|
72
72
|
* Represents the "legend-storage" microservice.
|
|
73
73
|
*/
|
|
74
74
|
readonly Storage: "legend-storage";
|
|
75
|
+
/**
|
|
76
|
+
* Represents the "audit-eda" microservice for event-driven architecture auditing.
|
|
77
|
+
* This microservice consumes audit events (audit.received, audit.processed, audit.dead_letter)
|
|
78
|
+
* to track event lifecycle and debugging purposes.
|
|
79
|
+
*/
|
|
80
|
+
readonly AuditEda: "audit-eda";
|
|
75
81
|
};
|
|
76
82
|
/**
|
|
77
83
|
* Type of available microservices in the system.
|
|
@@ -460,6 +466,89 @@ interface EventPayload {
|
|
|
460
466
|
bucketName: string;
|
|
461
467
|
filePaths: string[];
|
|
462
468
|
};
|
|
469
|
+
/**
|
|
470
|
+
* Emitted when an event is received by a microservice before processing starts (audit tracking)
|
|
471
|
+
*/
|
|
472
|
+
'audit.received': {
|
|
473
|
+
/**
|
|
474
|
+
* The microservice that received the event
|
|
475
|
+
*/
|
|
476
|
+
microservice: string;
|
|
477
|
+
/**
|
|
478
|
+
* The event that was received
|
|
479
|
+
*/
|
|
480
|
+
receivedEvent: string;
|
|
481
|
+
/**
|
|
482
|
+
* Timestamp when the event was received (UNIX timestamp in seconds)
|
|
483
|
+
*/
|
|
484
|
+
receivedAt: number;
|
|
485
|
+
/**
|
|
486
|
+
* The queue name from which the event was consumed
|
|
487
|
+
*/
|
|
488
|
+
queueName: string;
|
|
489
|
+
/**
|
|
490
|
+
* Optional event identifier for tracking
|
|
491
|
+
*/
|
|
492
|
+
eventId?: string;
|
|
493
|
+
};
|
|
494
|
+
/**
|
|
495
|
+
* Emitted when an event is successfully processed by a microservice for audit tracking
|
|
496
|
+
*/
|
|
497
|
+
'audit.processed': {
|
|
498
|
+
/**
|
|
499
|
+
* The microservice that processed the event
|
|
500
|
+
*/
|
|
501
|
+
microservice: string;
|
|
502
|
+
/**
|
|
503
|
+
* The original event that was processed
|
|
504
|
+
*/
|
|
505
|
+
processedEvent: string;
|
|
506
|
+
/**
|
|
507
|
+
* Timestamp when the event was processed (UNIX timestamp in seconds)
|
|
508
|
+
*/
|
|
509
|
+
processedAt: number;
|
|
510
|
+
/**
|
|
511
|
+
* The queue name where the event was consumed
|
|
512
|
+
*/
|
|
513
|
+
queueName: string;
|
|
514
|
+
/**
|
|
515
|
+
* Optional event identifier for tracking
|
|
516
|
+
*/
|
|
517
|
+
eventId?: string;
|
|
518
|
+
};
|
|
519
|
+
/**
|
|
520
|
+
* Emitted when a message is rejected/nacked and sent to dead letter queue
|
|
521
|
+
*/
|
|
522
|
+
'audit.dead_letter': {
|
|
523
|
+
/**
|
|
524
|
+
* The microservice that rejected the event
|
|
525
|
+
*/
|
|
526
|
+
microservice: string;
|
|
527
|
+
/**
|
|
528
|
+
* The original event that was rejected
|
|
529
|
+
*/
|
|
530
|
+
rejectedEvent: string;
|
|
531
|
+
/**
|
|
532
|
+
* Timestamp when the event was rejected (UNIX timestamp in seconds)
|
|
533
|
+
*/
|
|
534
|
+
rejectedAt: number;
|
|
535
|
+
/**
|
|
536
|
+
* The queue name where the event was rejected from
|
|
537
|
+
*/
|
|
538
|
+
queueName: string;
|
|
539
|
+
/**
|
|
540
|
+
* Reason for rejection (delay, fibonacci_strategy, etc.)
|
|
541
|
+
*/
|
|
542
|
+
rejectionReason: 'delay' | 'fibonacci_strategy';
|
|
543
|
+
/**
|
|
544
|
+
* Optional retry count
|
|
545
|
+
*/
|
|
546
|
+
retryCount?: number;
|
|
547
|
+
/**
|
|
548
|
+
* Optional event identifier for tracking
|
|
549
|
+
*/
|
|
550
|
+
eventId?: string;
|
|
551
|
+
};
|
|
463
552
|
}
|
|
464
553
|
/**
|
|
465
554
|
* Represents the available events in the system.
|
|
@@ -467,6 +556,9 @@ interface EventPayload {
|
|
|
467
556
|
declare const microserviceEvent: {
|
|
468
557
|
readonly 'TEST.IMAGE': "test.image";
|
|
469
558
|
readonly 'TEST.MINT': "test.mint";
|
|
559
|
+
readonly 'AUDIT.RECEIVED': "audit.received";
|
|
560
|
+
readonly 'AUDIT.PROCESSED': "audit.processed";
|
|
561
|
+
readonly 'AUDIT.DEAD_LETTER': "audit.dead_letter";
|
|
470
562
|
readonly 'AUTH.DELETED_USER': "auth.deleted_user";
|
|
471
563
|
readonly 'AUTH.LOGOUT_USER': "auth.logout_user";
|
|
472
564
|
readonly 'AUTH.NEW_USER': "auth.new_user";
|
|
@@ -559,7 +651,7 @@ declare abstract class ConsumeChannel {
|
|
|
559
651
|
*
|
|
560
652
|
* @see NACKING_DELAY_MS
|
|
561
653
|
*/
|
|
562
|
-
nackWithDelay
|
|
654
|
+
nackWithDelay(delay?: number, maxRetries?: number): {
|
|
563
655
|
count: number;
|
|
564
656
|
delay: number;
|
|
565
657
|
};
|
|
@@ -576,7 +668,7 @@ declare abstract class ConsumeChannel {
|
|
|
576
668
|
* - `occurrence`: The current occurrence count for the Fibonacci sequence.
|
|
577
669
|
* @see MAX_OCCURRENCE
|
|
578
670
|
*/
|
|
579
|
-
nackWithFibonacciStrategy
|
|
671
|
+
nackWithFibonacciStrategy(maxOccurrence?: number, maxRetries?: number): {
|
|
580
672
|
count: number;
|
|
581
673
|
delay: number;
|
|
582
674
|
occurrence: number;
|
|
@@ -595,14 +687,48 @@ declare abstract class ConsumeChannel {
|
|
|
595
687
|
|
|
596
688
|
/**
|
|
597
689
|
* Represents a **_consume_** channel for handling saga events/commands.
|
|
598
|
-
* Extends the abstract ConsumeChannel class.
|
|
690
|
+
* Extends the abstract ConsumeChannel class with automatic audit event emission.
|
|
599
691
|
*
|
|
600
692
|
*/
|
|
601
693
|
declare class EventsConsumeChannel extends ConsumeChannel {
|
|
694
|
+
/**
|
|
695
|
+
* The microservice name that is processing the event
|
|
696
|
+
*/
|
|
697
|
+
private readonly microservice;
|
|
698
|
+
/**
|
|
699
|
+
* The original event that was received
|
|
700
|
+
*/
|
|
701
|
+
private readonly processedEvent;
|
|
702
|
+
/**
|
|
703
|
+
* Creates a new EventsConsumeChannel instance
|
|
704
|
+
*
|
|
705
|
+
* @param channel - The AMQP Channel
|
|
706
|
+
* @param msg - The consumed message
|
|
707
|
+
* @param queueName - The queue name
|
|
708
|
+
* @param microservice - The microservice name processing the event
|
|
709
|
+
* @param processedEvent - The event type being processed
|
|
710
|
+
*/
|
|
711
|
+
constructor(channel: Channel, msg: ConsumeMessage, queueName: string, microservice: string, processedEvent: string);
|
|
602
712
|
/**
|
|
603
713
|
* Acknowledges the consumed saga event/command.
|
|
714
|
+
* Automatically emits audit.processed event after successful ACK.
|
|
604
715
|
*/
|
|
605
716
|
ackMessage(): void;
|
|
717
|
+
/**
|
|
718
|
+
* Override nackWithDelay to emit audit.dead_letter event
|
|
719
|
+
*/
|
|
720
|
+
nackWithDelay(delay?: number, maxRetries?: number): {
|
|
721
|
+
count: number;
|
|
722
|
+
delay: number;
|
|
723
|
+
};
|
|
724
|
+
/**
|
|
725
|
+
* Override nackWithFibonacciStrategy to emit audit.dead_letter event
|
|
726
|
+
*/
|
|
727
|
+
nackWithFibonacciStrategy(maxOccurrence?: number, maxRetries?: number): {
|
|
728
|
+
count: number;
|
|
729
|
+
delay: number;
|
|
730
|
+
occurrence: number;
|
|
731
|
+
};
|
|
606
732
|
}
|
|
607
733
|
|
|
608
734
|
/**
|
|
@@ -623,6 +749,13 @@ type MicroserviceConsumeEvents<T extends MicroserviceEvent> = {
|
|
|
623
749
|
* Represents the names of specific message queues in the RabbitMQ context.
|
|
624
750
|
*/
|
|
625
751
|
declare const queue: {
|
|
752
|
+
/**
|
|
753
|
+
* Audit queue names for separate audit event types
|
|
754
|
+
* @constant
|
|
755
|
+
*/
|
|
756
|
+
readonly AuditReceived: "audit_received_commands";
|
|
757
|
+
readonly AuditProcessed: "audit_processed_commands";
|
|
758
|
+
readonly AuditDeadLetter: "audit_dead_letter_commands";
|
|
626
759
|
/**
|
|
627
760
|
* Queue used for sending replies in response to saga events.
|
|
628
761
|
*/
|
|
@@ -636,6 +769,10 @@ declare const queue: {
|
|
|
636
769
|
* Represents the names of exchanges, which act as message routing hubs in the RabbitMQ context.
|
|
637
770
|
*/
|
|
638
771
|
declare const exchange: {
|
|
772
|
+
/**
|
|
773
|
+
* Audit exchange name for direct routing of audit events
|
|
774
|
+
*/
|
|
775
|
+
readonly Audit: "audit_exchange";
|
|
639
776
|
/**
|
|
640
777
|
* Exchange dedicated to requeueing messages that require further processing in a saga process
|
|
641
778
|
*/
|
|
@@ -693,6 +830,15 @@ declare const authCommands: {
|
|
|
693
830
|
*/
|
|
694
831
|
type AuthCommands = (typeof authCommands)[keyof typeof authCommands];
|
|
695
832
|
|
|
833
|
+
/**
|
|
834
|
+
* Different commands related to the "audit-eda" microservice.
|
|
835
|
+
*/
|
|
836
|
+
declare const auditEdaCommands: {};
|
|
837
|
+
/**
|
|
838
|
+
* Available commands for the "audit-eda" microservice.
|
|
839
|
+
*/
|
|
840
|
+
type AuditEdaCommands = (typeof auditEdaCommands)[keyof typeof auditEdaCommands];
|
|
841
|
+
|
|
696
842
|
/**
|
|
697
843
|
* Different commands related to the "blockchain" microservice.
|
|
698
844
|
*/
|
|
@@ -907,6 +1053,10 @@ interface CommandMap {
|
|
|
907
1053
|
* Represents the mapping of "auth" microservice commands.
|
|
908
1054
|
*/
|
|
909
1055
|
[availableMicroservices.Auth]: AuthCommands;
|
|
1056
|
+
/**
|
|
1057
|
+
* Represents the mapping of "audit-eda" microservice commands.
|
|
1058
|
+
*/
|
|
1059
|
+
[availableMicroservices.AuditEda]: AuditEdaCommands;
|
|
910
1060
|
/**
|
|
911
1061
|
* Represents the mapping of "blockchain" microservice commands.
|
|
912
1062
|
*/
|
|
@@ -1172,6 +1322,24 @@ declare const createConsumers: (consumers: QueueConsumerProps[]) => Promise<void
|
|
|
1172
1322
|
*/
|
|
1173
1323
|
declare const createHeaderConsumers: (queueName: string, events: MicroserviceEvent[]) => Promise<void>;
|
|
1174
1324
|
|
|
1325
|
+
/**
|
|
1326
|
+
* Creates audit logging infrastructure with direct exchange and separate queues
|
|
1327
|
+
* Uses direct exchange for efficient single-consumer delivery to audit microservice
|
|
1328
|
+
*
|
|
1329
|
+
* This function sets up the RabbitMQ infrastructure needed for audit event tracking:
|
|
1330
|
+
* - Creates a direct exchange for audit events
|
|
1331
|
+
* - Creates 3 separate queues (audit.received, audit.processed, audit.dead_letter)
|
|
1332
|
+
* - Binds each queue to the audit exchange with appropriate routing keys
|
|
1333
|
+
*
|
|
1334
|
+
* The direct exchange strategy ensures that:
|
|
1335
|
+
* - Only the audit microservice consumes audit events
|
|
1336
|
+
* - Routing is efficient (no pattern matching needed)
|
|
1337
|
+
* - Each audit event type has its own queue for isolation
|
|
1338
|
+
*
|
|
1339
|
+
* @internal This is called automatically when connecting to events
|
|
1340
|
+
*/
|
|
1341
|
+
declare const createAuditLoggingResources: () => Promise<void>;
|
|
1342
|
+
|
|
1175
1343
|
declare const sagaTitle: {
|
|
1176
1344
|
/**
|
|
1177
1345
|
* Saga used in the flow to purchase resources and deduct coins from the user.
|
|
@@ -1757,4 +1925,22 @@ declare const getEventObject: (event: MicroserviceEvent) => {
|
|
|
1757
1925
|
[x: string]: MicroserviceEvent;
|
|
1758
1926
|
};
|
|
1759
1927
|
|
|
1760
|
-
|
|
1928
|
+
/**
|
|
1929
|
+
* Extracts the microservice name from a queue name
|
|
1930
|
+
*
|
|
1931
|
+
* Queue names follow the pattern: `{microservice}_match_commands` or `{microservice}_saga_commands`
|
|
1932
|
+
* This utility extracts the microservice part from the queue name.
|
|
1933
|
+
*
|
|
1934
|
+
* @param queueName - The queue name (e.g., 'auth_match_commands', 'coins_saga_commands')
|
|
1935
|
+
* @returns The microservice name (e.g., 'auth', 'coins')
|
|
1936
|
+
*
|
|
1937
|
+
* @example
|
|
1938
|
+
* ```typescript
|
|
1939
|
+
* extractMicroserviceFromQueue('auth_match_commands'); // Returns: 'auth'
|
|
1940
|
+
* extractMicroserviceFromQueue('coins_saga_commands'); // Returns: 'coins'
|
|
1941
|
+
* extractMicroserviceFromQueue('audit-eda_match_commands'); // Returns: 'audit-eda'
|
|
1942
|
+
* ```
|
|
1943
|
+
*/
|
|
1944
|
+
declare function extractMicroserviceFromQueue(queueName: string): string;
|
|
1945
|
+
|
|
1946
|
+
export { type AuditEdaCommands, type AuthCommands, type AvailableMicroservices, type BlockchainCommands, type CoinsCommands, type CommandMap, type CommenceSaga, type CommenceSagaEvents, type CommenceSagaHandler, type CompletedRanking, type EventPayload, EventsConsumeChannel, type EventsHandler, type Exchange, type Gender, MAX_NACK_RETRIES, MAX_OCCURRENCE, type MicroserviceCommand, MicroserviceConsumeChannel, type MicroserviceConsumeEvents, type MicroserviceConsumeSagaEvents, type MicroserviceEvent, type MicroserviceHandler, NACKING_DELAY_MS, type Nack, type PaymentEmailType, PaymentEmailTypes, type QueueConsumerProps, type RankingWinners, type RankingsCommands, type RapidMessagingCommands, type Room, type RoomCreatorCommands, type RoomInventoryCommands, type RoomSnapshotCommands, type RoomType, RoomTypes, Saga, SagaCommenceConsumeChannel, type SagaCommencePayload, SagaConsumeChannel, type SagaConsumeSagaEvents, type SagaHandler, type SagaStep, type SagaStepDefaults, type SagaTitle, type SendEmailCommands, type ShowcaseCommands, type SocialCommands, type SocialMediaRoomsCommands, type SocialUser, type Status, type StorageCommands, type TestImageCommands, type TestMintCommands, Transactional, type TransactionalConfig, type UserLocation, auditEdaCommands, authCommands, availableMicroservices, blockchainCommands, closeConsumeChannel, closeRabbitMQConn, closeSendChannel, coinsCommands, commenceSaga, commenceSagaConsumeCallback, commenceSagaListener, connectToEvents, connectToSagaCommandEmitter, consume, createAuditLoggingResources, createConsumers, createHeaderConsumers, eventCallback, exchange, extractMicroserviceFromQueue, fibonacci, gender, getConsumeChannel, getEventKey, getEventObject, getQueueConsumer, getQueueName, getRabbitMQConn, getSendChannel, isConnectionHealthy, microserviceEvent, nodeDataDefaults, publishEvent, queue, rankingsCommands, rapidMessagingCommands, roomCreatorCommands, roomInventoryCommands, roomSnapshotCommands, sagaConsumeCallback, sagaStepCallback, sagaTitle, saveQueueForHealthCheck, saveUri, sendEmailCommands, sendToQueue, showcaseCommands, socialCommands, socialMediaRoomsCommands, startGlobalSagaStepListener, status, stopRabbitMQ, storageCommands, testImageCommands, testMintCommands };
|
package/dist/index.js
CHANGED
|
@@ -75,7 +75,13 @@ var availableMicroservices = {
|
|
|
75
75
|
/**
|
|
76
76
|
* Represents the "legend-storage" microservice.
|
|
77
77
|
*/
|
|
78
|
-
Storage: "legend-storage"
|
|
78
|
+
Storage: "legend-storage",
|
|
79
|
+
/**
|
|
80
|
+
* Represents the "audit-eda" microservice for event-driven architecture auditing.
|
|
81
|
+
* This microservice consumes audit events (audit.received, audit.processed, audit.dead_letter)
|
|
82
|
+
* to track event lifecycle and debugging purposes.
|
|
83
|
+
*/
|
|
84
|
+
AuditEda: "audit-eda"
|
|
79
85
|
};
|
|
80
86
|
|
|
81
87
|
// src/@types/event/events.ts
|
|
@@ -98,6 +104,11 @@ var microserviceEvent = {
|
|
|
98
104
|
"TEST.IMAGE": "test.image",
|
|
99
105
|
"TEST.MINT": "test.mint",
|
|
100
106
|
///////////////////////////
|
|
107
|
+
// AUDIT EVENTS - For tracking event lifecycle
|
|
108
|
+
"AUDIT.RECEIVED": "audit.received",
|
|
109
|
+
"AUDIT.PROCESSED": "audit.processed",
|
|
110
|
+
"AUDIT.DEAD_LETTER": "audit.dead_letter",
|
|
111
|
+
///////////////////////////
|
|
101
112
|
"AUTH.DELETED_USER": "auth.deleted_user",
|
|
102
113
|
"AUTH.LOGOUT_USER": "auth.logout_user",
|
|
103
114
|
"AUTH.NEW_USER": "auth.new_user",
|
|
@@ -132,6 +143,13 @@ var microserviceEvent = {
|
|
|
132
143
|
|
|
133
144
|
// src/@types/rabbit-mq.ts
|
|
134
145
|
var queue = {
|
|
146
|
+
/**
|
|
147
|
+
* Audit queue names for separate audit event types
|
|
148
|
+
* @constant
|
|
149
|
+
*/
|
|
150
|
+
AuditReceived: "audit_received_commands",
|
|
151
|
+
AuditProcessed: "audit_processed_commands",
|
|
152
|
+
AuditDeadLetter: "audit_dead_letter_commands",
|
|
135
153
|
/**
|
|
136
154
|
* Queue used for sending replies in response to saga events.
|
|
137
155
|
*/
|
|
@@ -142,6 +160,10 @@ var queue = {
|
|
|
142
160
|
CommenceSaga: "commence_saga"
|
|
143
161
|
};
|
|
144
162
|
var exchange = {
|
|
163
|
+
/**
|
|
164
|
+
* Audit exchange name for direct routing of audit events
|
|
165
|
+
*/
|
|
166
|
+
Audit: "audit_exchange",
|
|
145
167
|
/**
|
|
146
168
|
* Exchange dedicated to requeueing messages that require further processing in a saga process
|
|
147
169
|
*/
|
|
@@ -176,6 +198,9 @@ var authCommands = {
|
|
|
176
198
|
CreateUser: "create_user"
|
|
177
199
|
};
|
|
178
200
|
|
|
201
|
+
// src/@types/saga/commands/audit-eda.ts
|
|
202
|
+
var auditEdaCommands = {};
|
|
203
|
+
|
|
179
204
|
// src/@types/saga/commands/blockchain.ts
|
|
180
205
|
var blockchainCommands = {
|
|
181
206
|
/**
|
|
@@ -458,6 +483,11 @@ var getEventObject = (event) => {
|
|
|
458
483
|
};
|
|
459
484
|
};
|
|
460
485
|
|
|
486
|
+
// src/utils/extractMicroservice.ts
|
|
487
|
+
function extractMicroserviceFromQueue(queueName) {
|
|
488
|
+
return queueName.replace(/_match_commands$/, "").replace(/_saga_commands$/, "");
|
|
489
|
+
}
|
|
490
|
+
|
|
461
491
|
// src/Consumer/channels/Consume.ts
|
|
462
492
|
var ConsumeChannel = class {
|
|
463
493
|
/**
|
|
@@ -497,10 +527,10 @@ var ConsumeChannel = class {
|
|
|
497
527
|
*
|
|
498
528
|
* @see NACKING_DELAY_MS
|
|
499
529
|
*/
|
|
500
|
-
nackWithDelay
|
|
530
|
+
nackWithDelay(delay = NACKING_DELAY_MS, maxRetries) {
|
|
501
531
|
const { delay: delayNackRetry, count } = this.nack({ delay, maxRetries });
|
|
502
532
|
return { count, delay: delayNackRetry };
|
|
503
|
-
}
|
|
533
|
+
}
|
|
504
534
|
/**
|
|
505
535
|
* Negatively acknowledges (NACKs) the message using a Fibonacci backoff strategy.
|
|
506
536
|
*
|
|
@@ -514,9 +544,9 @@ var ConsumeChannel = class {
|
|
|
514
544
|
* - `occurrence`: The current occurrence count for the Fibonacci sequence.
|
|
515
545
|
* @see MAX_OCCURRENCE
|
|
516
546
|
*/
|
|
517
|
-
nackWithFibonacciStrategy
|
|
547
|
+
nackWithFibonacciStrategy(maxOccurrence = MAX_OCCURRENCE, maxRetries) {
|
|
518
548
|
return this.nack({ maxOccurrence, maxRetries });
|
|
519
|
-
}
|
|
549
|
+
}
|
|
520
550
|
/**
|
|
521
551
|
* Private helper function to handle the actual NACK logic.
|
|
522
552
|
*
|
|
@@ -526,11 +556,7 @@ var ConsumeChannel = class {
|
|
|
526
556
|
* - `delay` and `maxRetries`: For linear backoff with a fixed delay and retry limit.
|
|
527
557
|
* - `maxOccurrence`: For Fibonacci backoff with a maximum occurrence count.
|
|
528
558
|
*/
|
|
529
|
-
nack
|
|
530
|
-
maxRetries,
|
|
531
|
-
maxOccurrence,
|
|
532
|
-
delay
|
|
533
|
-
}) => {
|
|
559
|
+
nack({ maxRetries, maxOccurrence, delay }) {
|
|
534
560
|
const { msg, queueName, channel } = this;
|
|
535
561
|
channel.nack(msg, false, false);
|
|
536
562
|
let count = 0;
|
|
@@ -587,7 +613,7 @@ var ConsumeChannel = class {
|
|
|
587
613
|
});
|
|
588
614
|
}
|
|
589
615
|
return { count, delay: nackDelay, occurrence };
|
|
590
|
-
}
|
|
616
|
+
}
|
|
591
617
|
};
|
|
592
618
|
var Consume_default = ConsumeChannel;
|
|
593
619
|
|
|
@@ -619,13 +645,109 @@ var commenceSagaConsumeCallback = (msg, channel, e, queueName) => {
|
|
|
619
645
|
e.emit(saga.title, { saga, channel: responseChannel });
|
|
620
646
|
};
|
|
621
647
|
|
|
648
|
+
// src/Broker/PublishAuditEvent.ts
|
|
649
|
+
async function publishAuditEvent(channel, eventType, payload) {
|
|
650
|
+
try {
|
|
651
|
+
const routingKey = eventType;
|
|
652
|
+
const messageBuffer = Buffer.from(JSON.stringify(payload));
|
|
653
|
+
channel.publish(exchange.Audit, routingKey, messageBuffer, {
|
|
654
|
+
contentType: "application/json",
|
|
655
|
+
deliveryMode: 2
|
|
656
|
+
// persistent
|
|
657
|
+
});
|
|
658
|
+
} catch (error) {
|
|
659
|
+
console.error(`Failed to publish audit event ${eventType}:`, error);
|
|
660
|
+
}
|
|
661
|
+
}
|
|
662
|
+
async function publishAuditReceived(channel, payload) {
|
|
663
|
+
await publishAuditEvent(channel, "audit.received", payload);
|
|
664
|
+
}
|
|
665
|
+
async function publishAuditProcessed(channel, payload) {
|
|
666
|
+
await publishAuditEvent(channel, "audit.processed", payload);
|
|
667
|
+
}
|
|
668
|
+
async function publishAuditDeadLetter(channel, payload) {
|
|
669
|
+
await publishAuditEvent(channel, "audit.dead_letter", payload);
|
|
670
|
+
}
|
|
671
|
+
|
|
622
672
|
// src/Consumer/channels/Events.ts
|
|
623
673
|
var EventsConsumeChannel = class extends Consume_default {
|
|
674
|
+
/**
|
|
675
|
+
* The microservice name that is processing the event
|
|
676
|
+
*/
|
|
677
|
+
microservice;
|
|
678
|
+
/**
|
|
679
|
+
* The original event that was received
|
|
680
|
+
*/
|
|
681
|
+
processedEvent;
|
|
682
|
+
/**
|
|
683
|
+
* Creates a new EventsConsumeChannel instance
|
|
684
|
+
*
|
|
685
|
+
* @param channel - The AMQP Channel
|
|
686
|
+
* @param msg - The consumed message
|
|
687
|
+
* @param queueName - The queue name
|
|
688
|
+
* @param microservice - The microservice name processing the event
|
|
689
|
+
* @param processedEvent - The event type being processed
|
|
690
|
+
*/
|
|
691
|
+
constructor(channel, msg, queueName, microservice, processedEvent) {
|
|
692
|
+
super(channel, msg, queueName);
|
|
693
|
+
this.microservice = microservice;
|
|
694
|
+
this.processedEvent = processedEvent;
|
|
695
|
+
}
|
|
624
696
|
/**
|
|
625
697
|
* Acknowledges the consumed saga event/command.
|
|
698
|
+
* Automatically emits audit.processed event after successful ACK.
|
|
626
699
|
*/
|
|
627
700
|
ackMessage() {
|
|
628
701
|
this.channel.ack(this.msg, false);
|
|
702
|
+
const timestamp = Math.floor(Date.now() / 1e3);
|
|
703
|
+
publishAuditProcessed(this.channel, {
|
|
704
|
+
microservice: this.microservice,
|
|
705
|
+
processedEvent: this.processedEvent,
|
|
706
|
+
processedAt: timestamp,
|
|
707
|
+
queueName: this.queueName,
|
|
708
|
+
eventId: void 0
|
|
709
|
+
// Optional: can be enhanced later
|
|
710
|
+
}).catch((error) => {
|
|
711
|
+
console.error("Failed to emit audit.processed event:", error);
|
|
712
|
+
});
|
|
713
|
+
}
|
|
714
|
+
/**
|
|
715
|
+
* Override nackWithDelay to emit audit.dead_letter event
|
|
716
|
+
*/
|
|
717
|
+
nackWithDelay(delay = NACKING_DELAY_MS, maxRetries) {
|
|
718
|
+
const parentNack = super.nackWithDelay(delay, maxRetries);
|
|
719
|
+
const timestamp = Math.floor(Date.now() / 1e3);
|
|
720
|
+
publishAuditDeadLetter(this.channel, {
|
|
721
|
+
microservice: this.microservice,
|
|
722
|
+
rejectedEvent: this.processedEvent,
|
|
723
|
+
rejectedAt: timestamp,
|
|
724
|
+
queueName: this.queueName,
|
|
725
|
+
rejectionReason: "delay",
|
|
726
|
+
retryCount: parentNack.count,
|
|
727
|
+
eventId: void 0
|
|
728
|
+
}).catch((error) => {
|
|
729
|
+
console.error("Failed to emit audit.dead_letter event:", error);
|
|
730
|
+
});
|
|
731
|
+
return parentNack;
|
|
732
|
+
}
|
|
733
|
+
/**
|
|
734
|
+
* Override nackWithFibonacciStrategy to emit audit.dead_letter event
|
|
735
|
+
*/
|
|
736
|
+
nackWithFibonacciStrategy(maxOccurrence = MAX_OCCURRENCE, maxRetries) {
|
|
737
|
+
const parentNack = super.nackWithFibonacciStrategy(maxOccurrence, maxRetries);
|
|
738
|
+
const timestamp = Math.floor(Date.now() / 1e3);
|
|
739
|
+
publishAuditDeadLetter(this.channel, {
|
|
740
|
+
microservice: this.microservice,
|
|
741
|
+
rejectedEvent: this.processedEvent,
|
|
742
|
+
rejectedAt: timestamp,
|
|
743
|
+
queueName: this.queueName,
|
|
744
|
+
rejectionReason: "fibonacci_strategy",
|
|
745
|
+
retryCount: parentNack.count,
|
|
746
|
+
eventId: void 0
|
|
747
|
+
}).catch((error) => {
|
|
748
|
+
console.error("Failed to emit audit.dead_letter event:", error);
|
|
749
|
+
});
|
|
750
|
+
return parentNack;
|
|
629
751
|
}
|
|
630
752
|
};
|
|
631
753
|
|
|
@@ -668,7 +790,20 @@ var eventCallback = (msg, channel, e, queueName) => {
|
|
|
668
790
|
{ headersReceived: headers, eventsDetected: event }
|
|
669
791
|
);
|
|
670
792
|
}
|
|
671
|
-
const
|
|
793
|
+
const microservice = extractMicroserviceFromQueue(queueName);
|
|
794
|
+
const receivedEvent = event[0];
|
|
795
|
+
const timestamp = Math.floor(Date.now() / 1e3);
|
|
796
|
+
publishAuditReceived(channel, {
|
|
797
|
+
microservice,
|
|
798
|
+
receivedEvent,
|
|
799
|
+
receivedAt: timestamp,
|
|
800
|
+
queueName,
|
|
801
|
+
eventId: void 0
|
|
802
|
+
// Optional: can be enhanced later with message ID tracking
|
|
803
|
+
}).catch((error) => {
|
|
804
|
+
console.error("Failed to emit audit.received event:", error);
|
|
805
|
+
});
|
|
806
|
+
const responseChannel = new EventsConsumeChannel(channel, msg, queueName, microservice, receivedEvent);
|
|
672
807
|
e.emit(event[0], { payload, channel: responseChannel });
|
|
673
808
|
};
|
|
674
809
|
|
|
@@ -835,6 +970,25 @@ var createHeaderConsumers = async (queueName, events) => {
|
|
|
835
970
|
}
|
|
836
971
|
}
|
|
837
972
|
};
|
|
973
|
+
|
|
974
|
+
// src/Consumer/auditInfrastructure.ts
|
|
975
|
+
var createAuditLoggingResources = async () => {
|
|
976
|
+
const channel = await getConsumeChannel();
|
|
977
|
+
await Promise.all([
|
|
978
|
+
// Create direct exchange for audit events
|
|
979
|
+
channel.assertExchange(exchange.Audit, "direct", { durable: true }),
|
|
980
|
+
// Create queues for audit events
|
|
981
|
+
channel.assertQueue(queue.AuditReceived, { durable: true }),
|
|
982
|
+
channel.assertQueue(queue.AuditProcessed, { durable: true }),
|
|
983
|
+
channel.assertQueue(queue.AuditDeadLetter, { durable: true })
|
|
984
|
+
]);
|
|
985
|
+
await Promise.all([
|
|
986
|
+
// Bind each queue to its specific routing key
|
|
987
|
+
channel.bindQueue(queue.AuditReceived, exchange.Audit, "audit.received"),
|
|
988
|
+
channel.bindQueue(queue.AuditProcessed, exchange.Audit, "audit.processed"),
|
|
989
|
+
channel.bindQueue(queue.AuditDeadLetter, exchange.Audit, "audit.dead_letter")
|
|
990
|
+
]);
|
|
991
|
+
};
|
|
838
992
|
var isReady = false;
|
|
839
993
|
var prepare = async (url2) => {
|
|
840
994
|
if (isReady) return;
|
|
@@ -894,6 +1048,7 @@ var connectToEvents = async (config) => {
|
|
|
894
1048
|
const queueName = `${config.microservice}_match_commands`;
|
|
895
1049
|
const e = mitt__default.default();
|
|
896
1050
|
await createHeaderConsumers(queueName, config.events);
|
|
1051
|
+
await createAuditLoggingResources();
|
|
897
1052
|
void consume(e, queueName, eventCallback);
|
|
898
1053
|
return e;
|
|
899
1054
|
};
|
|
@@ -979,6 +1134,7 @@ exports.Saga = Saga;
|
|
|
979
1134
|
exports.SagaCommenceConsumeChannel = SagaCommenceConsumeChannel;
|
|
980
1135
|
exports.SagaConsumeChannel = SagaConsumeChannel;
|
|
981
1136
|
exports.Transactional = Transactional;
|
|
1137
|
+
exports.auditEdaCommands = auditEdaCommands;
|
|
982
1138
|
exports.authCommands = authCommands;
|
|
983
1139
|
exports.availableMicroservices = availableMicroservices;
|
|
984
1140
|
exports.blockchainCommands = blockchainCommands;
|
|
@@ -992,10 +1148,12 @@ exports.commenceSagaListener = commenceSagaListener;
|
|
|
992
1148
|
exports.connectToEvents = connectToEvents;
|
|
993
1149
|
exports.connectToSagaCommandEmitter = connectToSagaCommandEmitter;
|
|
994
1150
|
exports.consume = consume;
|
|
1151
|
+
exports.createAuditLoggingResources = createAuditLoggingResources;
|
|
995
1152
|
exports.createConsumers = createConsumers;
|
|
996
1153
|
exports.createHeaderConsumers = createHeaderConsumers;
|
|
997
1154
|
exports.eventCallback = eventCallback;
|
|
998
1155
|
exports.exchange = exchange;
|
|
1156
|
+
exports.extractMicroserviceFromQueue = extractMicroserviceFromQueue;
|
|
999
1157
|
exports.fibonacci = fibonacci;
|
|
1000
1158
|
exports.gender = gender;
|
|
1001
1159
|
exports.getConsumeChannel = getConsumeChannel;
|
package/dist/index.mjs
CHANGED
|
@@ -68,7 +68,13 @@ var availableMicroservices = {
|
|
|
68
68
|
/**
|
|
69
69
|
* Represents the "legend-storage" microservice.
|
|
70
70
|
*/
|
|
71
|
-
Storage: "legend-storage"
|
|
71
|
+
Storage: "legend-storage",
|
|
72
|
+
/**
|
|
73
|
+
* Represents the "audit-eda" microservice for event-driven architecture auditing.
|
|
74
|
+
* This microservice consumes audit events (audit.received, audit.processed, audit.dead_letter)
|
|
75
|
+
* to track event lifecycle and debugging purposes.
|
|
76
|
+
*/
|
|
77
|
+
AuditEda: "audit-eda"
|
|
72
78
|
};
|
|
73
79
|
|
|
74
80
|
// src/@types/event/events.ts
|
|
@@ -91,6 +97,11 @@ var microserviceEvent = {
|
|
|
91
97
|
"TEST.IMAGE": "test.image",
|
|
92
98
|
"TEST.MINT": "test.mint",
|
|
93
99
|
///////////////////////////
|
|
100
|
+
// AUDIT EVENTS - For tracking event lifecycle
|
|
101
|
+
"AUDIT.RECEIVED": "audit.received",
|
|
102
|
+
"AUDIT.PROCESSED": "audit.processed",
|
|
103
|
+
"AUDIT.DEAD_LETTER": "audit.dead_letter",
|
|
104
|
+
///////////////////////////
|
|
94
105
|
"AUTH.DELETED_USER": "auth.deleted_user",
|
|
95
106
|
"AUTH.LOGOUT_USER": "auth.logout_user",
|
|
96
107
|
"AUTH.NEW_USER": "auth.new_user",
|
|
@@ -125,6 +136,13 @@ var microserviceEvent = {
|
|
|
125
136
|
|
|
126
137
|
// src/@types/rabbit-mq.ts
|
|
127
138
|
var queue = {
|
|
139
|
+
/**
|
|
140
|
+
* Audit queue names for separate audit event types
|
|
141
|
+
* @constant
|
|
142
|
+
*/
|
|
143
|
+
AuditReceived: "audit_received_commands",
|
|
144
|
+
AuditProcessed: "audit_processed_commands",
|
|
145
|
+
AuditDeadLetter: "audit_dead_letter_commands",
|
|
128
146
|
/**
|
|
129
147
|
* Queue used for sending replies in response to saga events.
|
|
130
148
|
*/
|
|
@@ -135,6 +153,10 @@ var queue = {
|
|
|
135
153
|
CommenceSaga: "commence_saga"
|
|
136
154
|
};
|
|
137
155
|
var exchange = {
|
|
156
|
+
/**
|
|
157
|
+
* Audit exchange name for direct routing of audit events
|
|
158
|
+
*/
|
|
159
|
+
Audit: "audit_exchange",
|
|
138
160
|
/**
|
|
139
161
|
* Exchange dedicated to requeueing messages that require further processing in a saga process
|
|
140
162
|
*/
|
|
@@ -169,6 +191,9 @@ var authCommands = {
|
|
|
169
191
|
CreateUser: "create_user"
|
|
170
192
|
};
|
|
171
193
|
|
|
194
|
+
// src/@types/saga/commands/audit-eda.ts
|
|
195
|
+
var auditEdaCommands = {};
|
|
196
|
+
|
|
172
197
|
// src/@types/saga/commands/blockchain.ts
|
|
173
198
|
var blockchainCommands = {
|
|
174
199
|
/**
|
|
@@ -451,6 +476,11 @@ var getEventObject = (event) => {
|
|
|
451
476
|
};
|
|
452
477
|
};
|
|
453
478
|
|
|
479
|
+
// src/utils/extractMicroservice.ts
|
|
480
|
+
function extractMicroserviceFromQueue(queueName) {
|
|
481
|
+
return queueName.replace(/_match_commands$/, "").replace(/_saga_commands$/, "");
|
|
482
|
+
}
|
|
483
|
+
|
|
454
484
|
// src/Consumer/channels/Consume.ts
|
|
455
485
|
var ConsumeChannel = class {
|
|
456
486
|
/**
|
|
@@ -490,10 +520,10 @@ var ConsumeChannel = class {
|
|
|
490
520
|
*
|
|
491
521
|
* @see NACKING_DELAY_MS
|
|
492
522
|
*/
|
|
493
|
-
nackWithDelay
|
|
523
|
+
nackWithDelay(delay = NACKING_DELAY_MS, maxRetries) {
|
|
494
524
|
const { delay: delayNackRetry, count } = this.nack({ delay, maxRetries });
|
|
495
525
|
return { count, delay: delayNackRetry };
|
|
496
|
-
}
|
|
526
|
+
}
|
|
497
527
|
/**
|
|
498
528
|
* Negatively acknowledges (NACKs) the message using a Fibonacci backoff strategy.
|
|
499
529
|
*
|
|
@@ -507,9 +537,9 @@ var ConsumeChannel = class {
|
|
|
507
537
|
* - `occurrence`: The current occurrence count for the Fibonacci sequence.
|
|
508
538
|
* @see MAX_OCCURRENCE
|
|
509
539
|
*/
|
|
510
|
-
nackWithFibonacciStrategy
|
|
540
|
+
nackWithFibonacciStrategy(maxOccurrence = MAX_OCCURRENCE, maxRetries) {
|
|
511
541
|
return this.nack({ maxOccurrence, maxRetries });
|
|
512
|
-
}
|
|
542
|
+
}
|
|
513
543
|
/**
|
|
514
544
|
* Private helper function to handle the actual NACK logic.
|
|
515
545
|
*
|
|
@@ -519,11 +549,7 @@ var ConsumeChannel = class {
|
|
|
519
549
|
* - `delay` and `maxRetries`: For linear backoff with a fixed delay and retry limit.
|
|
520
550
|
* - `maxOccurrence`: For Fibonacci backoff with a maximum occurrence count.
|
|
521
551
|
*/
|
|
522
|
-
nack
|
|
523
|
-
maxRetries,
|
|
524
|
-
maxOccurrence,
|
|
525
|
-
delay
|
|
526
|
-
}) => {
|
|
552
|
+
nack({ maxRetries, maxOccurrence, delay }) {
|
|
527
553
|
const { msg, queueName, channel } = this;
|
|
528
554
|
channel.nack(msg, false, false);
|
|
529
555
|
let count = 0;
|
|
@@ -580,7 +606,7 @@ var ConsumeChannel = class {
|
|
|
580
606
|
});
|
|
581
607
|
}
|
|
582
608
|
return { count, delay: nackDelay, occurrence };
|
|
583
|
-
}
|
|
609
|
+
}
|
|
584
610
|
};
|
|
585
611
|
var Consume_default = ConsumeChannel;
|
|
586
612
|
|
|
@@ -612,13 +638,109 @@ var commenceSagaConsumeCallback = (msg, channel, e, queueName) => {
|
|
|
612
638
|
e.emit(saga.title, { saga, channel: responseChannel });
|
|
613
639
|
};
|
|
614
640
|
|
|
641
|
+
// src/Broker/PublishAuditEvent.ts
|
|
642
|
+
async function publishAuditEvent(channel, eventType, payload) {
|
|
643
|
+
try {
|
|
644
|
+
const routingKey = eventType;
|
|
645
|
+
const messageBuffer = Buffer.from(JSON.stringify(payload));
|
|
646
|
+
channel.publish(exchange.Audit, routingKey, messageBuffer, {
|
|
647
|
+
contentType: "application/json",
|
|
648
|
+
deliveryMode: 2
|
|
649
|
+
// persistent
|
|
650
|
+
});
|
|
651
|
+
} catch (error) {
|
|
652
|
+
console.error(`Failed to publish audit event ${eventType}:`, error);
|
|
653
|
+
}
|
|
654
|
+
}
|
|
655
|
+
async function publishAuditReceived(channel, payload) {
|
|
656
|
+
await publishAuditEvent(channel, "audit.received", payload);
|
|
657
|
+
}
|
|
658
|
+
async function publishAuditProcessed(channel, payload) {
|
|
659
|
+
await publishAuditEvent(channel, "audit.processed", payload);
|
|
660
|
+
}
|
|
661
|
+
async function publishAuditDeadLetter(channel, payload) {
|
|
662
|
+
await publishAuditEvent(channel, "audit.dead_letter", payload);
|
|
663
|
+
}
|
|
664
|
+
|
|
615
665
|
// src/Consumer/channels/Events.ts
|
|
616
666
|
var EventsConsumeChannel = class extends Consume_default {
|
|
667
|
+
/**
|
|
668
|
+
* The microservice name that is processing the event
|
|
669
|
+
*/
|
|
670
|
+
microservice;
|
|
671
|
+
/**
|
|
672
|
+
* The original event that was received
|
|
673
|
+
*/
|
|
674
|
+
processedEvent;
|
|
675
|
+
/**
|
|
676
|
+
* Creates a new EventsConsumeChannel instance
|
|
677
|
+
*
|
|
678
|
+
* @param channel - The AMQP Channel
|
|
679
|
+
* @param msg - The consumed message
|
|
680
|
+
* @param queueName - The queue name
|
|
681
|
+
* @param microservice - The microservice name processing the event
|
|
682
|
+
* @param processedEvent - The event type being processed
|
|
683
|
+
*/
|
|
684
|
+
constructor(channel, msg, queueName, microservice, processedEvent) {
|
|
685
|
+
super(channel, msg, queueName);
|
|
686
|
+
this.microservice = microservice;
|
|
687
|
+
this.processedEvent = processedEvent;
|
|
688
|
+
}
|
|
617
689
|
/**
|
|
618
690
|
* Acknowledges the consumed saga event/command.
|
|
691
|
+
* Automatically emits audit.processed event after successful ACK.
|
|
619
692
|
*/
|
|
620
693
|
ackMessage() {
|
|
621
694
|
this.channel.ack(this.msg, false);
|
|
695
|
+
const timestamp = Math.floor(Date.now() / 1e3);
|
|
696
|
+
publishAuditProcessed(this.channel, {
|
|
697
|
+
microservice: this.microservice,
|
|
698
|
+
processedEvent: this.processedEvent,
|
|
699
|
+
processedAt: timestamp,
|
|
700
|
+
queueName: this.queueName,
|
|
701
|
+
eventId: void 0
|
|
702
|
+
// Optional: can be enhanced later
|
|
703
|
+
}).catch((error) => {
|
|
704
|
+
console.error("Failed to emit audit.processed event:", error);
|
|
705
|
+
});
|
|
706
|
+
}
|
|
707
|
+
/**
|
|
708
|
+
* Override nackWithDelay to emit audit.dead_letter event
|
|
709
|
+
*/
|
|
710
|
+
nackWithDelay(delay = NACKING_DELAY_MS, maxRetries) {
|
|
711
|
+
const parentNack = super.nackWithDelay(delay, maxRetries);
|
|
712
|
+
const timestamp = Math.floor(Date.now() / 1e3);
|
|
713
|
+
publishAuditDeadLetter(this.channel, {
|
|
714
|
+
microservice: this.microservice,
|
|
715
|
+
rejectedEvent: this.processedEvent,
|
|
716
|
+
rejectedAt: timestamp,
|
|
717
|
+
queueName: this.queueName,
|
|
718
|
+
rejectionReason: "delay",
|
|
719
|
+
retryCount: parentNack.count,
|
|
720
|
+
eventId: void 0
|
|
721
|
+
}).catch((error) => {
|
|
722
|
+
console.error("Failed to emit audit.dead_letter event:", error);
|
|
723
|
+
});
|
|
724
|
+
return parentNack;
|
|
725
|
+
}
|
|
726
|
+
/**
|
|
727
|
+
* Override nackWithFibonacciStrategy to emit audit.dead_letter event
|
|
728
|
+
*/
|
|
729
|
+
nackWithFibonacciStrategy(maxOccurrence = MAX_OCCURRENCE, maxRetries) {
|
|
730
|
+
const parentNack = super.nackWithFibonacciStrategy(maxOccurrence, maxRetries);
|
|
731
|
+
const timestamp = Math.floor(Date.now() / 1e3);
|
|
732
|
+
publishAuditDeadLetter(this.channel, {
|
|
733
|
+
microservice: this.microservice,
|
|
734
|
+
rejectedEvent: this.processedEvent,
|
|
735
|
+
rejectedAt: timestamp,
|
|
736
|
+
queueName: this.queueName,
|
|
737
|
+
rejectionReason: "fibonacci_strategy",
|
|
738
|
+
retryCount: parentNack.count,
|
|
739
|
+
eventId: void 0
|
|
740
|
+
}).catch((error) => {
|
|
741
|
+
console.error("Failed to emit audit.dead_letter event:", error);
|
|
742
|
+
});
|
|
743
|
+
return parentNack;
|
|
622
744
|
}
|
|
623
745
|
};
|
|
624
746
|
|
|
@@ -661,7 +783,20 @@ var eventCallback = (msg, channel, e, queueName) => {
|
|
|
661
783
|
{ headersReceived: headers, eventsDetected: event }
|
|
662
784
|
);
|
|
663
785
|
}
|
|
664
|
-
const
|
|
786
|
+
const microservice = extractMicroserviceFromQueue(queueName);
|
|
787
|
+
const receivedEvent = event[0];
|
|
788
|
+
const timestamp = Math.floor(Date.now() / 1e3);
|
|
789
|
+
publishAuditReceived(channel, {
|
|
790
|
+
microservice,
|
|
791
|
+
receivedEvent,
|
|
792
|
+
receivedAt: timestamp,
|
|
793
|
+
queueName,
|
|
794
|
+
eventId: void 0
|
|
795
|
+
// Optional: can be enhanced later with message ID tracking
|
|
796
|
+
}).catch((error) => {
|
|
797
|
+
console.error("Failed to emit audit.received event:", error);
|
|
798
|
+
});
|
|
799
|
+
const responseChannel = new EventsConsumeChannel(channel, msg, queueName, microservice, receivedEvent);
|
|
665
800
|
e.emit(event[0], { payload, channel: responseChannel });
|
|
666
801
|
};
|
|
667
802
|
|
|
@@ -828,6 +963,25 @@ var createHeaderConsumers = async (queueName, events) => {
|
|
|
828
963
|
}
|
|
829
964
|
}
|
|
830
965
|
};
|
|
966
|
+
|
|
967
|
+
// src/Consumer/auditInfrastructure.ts
|
|
968
|
+
var createAuditLoggingResources = async () => {
|
|
969
|
+
const channel = await getConsumeChannel();
|
|
970
|
+
await Promise.all([
|
|
971
|
+
// Create direct exchange for audit events
|
|
972
|
+
channel.assertExchange(exchange.Audit, "direct", { durable: true }),
|
|
973
|
+
// Create queues for audit events
|
|
974
|
+
channel.assertQueue(queue.AuditReceived, { durable: true }),
|
|
975
|
+
channel.assertQueue(queue.AuditProcessed, { durable: true }),
|
|
976
|
+
channel.assertQueue(queue.AuditDeadLetter, { durable: true })
|
|
977
|
+
]);
|
|
978
|
+
await Promise.all([
|
|
979
|
+
// Bind each queue to its specific routing key
|
|
980
|
+
channel.bindQueue(queue.AuditReceived, exchange.Audit, "audit.received"),
|
|
981
|
+
channel.bindQueue(queue.AuditProcessed, exchange.Audit, "audit.processed"),
|
|
982
|
+
channel.bindQueue(queue.AuditDeadLetter, exchange.Audit, "audit.dead_letter")
|
|
983
|
+
]);
|
|
984
|
+
};
|
|
831
985
|
var isReady = false;
|
|
832
986
|
var prepare = async (url2) => {
|
|
833
987
|
if (isReady) return;
|
|
@@ -887,6 +1041,7 @@ var connectToEvents = async (config) => {
|
|
|
887
1041
|
const queueName = `${config.microservice}_match_commands`;
|
|
888
1042
|
const e = mitt();
|
|
889
1043
|
await createHeaderConsumers(queueName, config.events);
|
|
1044
|
+
await createAuditLoggingResources();
|
|
890
1045
|
void consume(e, queueName, eventCallback);
|
|
891
1046
|
return e;
|
|
892
1047
|
};
|
|
@@ -961,4 +1116,4 @@ var publishEvent = async (msg, event) => {
|
|
|
961
1116
|
});
|
|
962
1117
|
};
|
|
963
1118
|
|
|
964
|
-
export { EventsConsumeChannel, MAX_NACK_RETRIES, MAX_OCCURRENCE, MicroserviceConsumeChannel, NACKING_DELAY_MS, PaymentEmailTypes, RoomTypes, Saga, SagaCommenceConsumeChannel, SagaConsumeChannel, Transactional, authCommands, availableMicroservices, blockchainCommands, closeConsumeChannel, closeRabbitMQConn, closeSendChannel, coinsCommands, commenceSaga, commenceSagaConsumeCallback, commenceSagaListener, connectToEvents, connectToSagaCommandEmitter, consume, createConsumers, createHeaderConsumers, eventCallback, exchange, fibonacci, gender, getConsumeChannel, getEventKey, getEventObject, getQueueConsumer, getQueueName, getRabbitMQConn, getSendChannel, isConnectionHealthy, microserviceEvent, nodeDataDefaults, publishEvent, queue, rankingsCommands, rapidMessagingCommands, roomCreatorCommands, roomInventoryCommands, roomSnapshotCommands, sagaConsumeCallback, sagaStepCallback, sagaTitle, saveQueueForHealthCheck, saveUri, sendEmailCommands, sendToQueue, showcaseCommands, socialCommands, socialMediaRoomsCommands, startGlobalSagaStepListener, status, stopRabbitMQ, storageCommands, testImageCommands, testMintCommands };
|
|
1119
|
+
export { EventsConsumeChannel, MAX_NACK_RETRIES, MAX_OCCURRENCE, MicroserviceConsumeChannel, NACKING_DELAY_MS, PaymentEmailTypes, RoomTypes, Saga, SagaCommenceConsumeChannel, SagaConsumeChannel, Transactional, auditEdaCommands, authCommands, availableMicroservices, blockchainCommands, closeConsumeChannel, closeRabbitMQConn, closeSendChannel, coinsCommands, commenceSaga, commenceSagaConsumeCallback, commenceSagaListener, connectToEvents, connectToSagaCommandEmitter, consume, createAuditLoggingResources, createConsumers, createHeaderConsumers, eventCallback, exchange, extractMicroserviceFromQueue, fibonacci, gender, getConsumeChannel, getEventKey, getEventObject, getQueueConsumer, getQueueName, getRabbitMQConn, getSendChannel, isConnectionHealthy, microserviceEvent, nodeDataDefaults, publishEvent, queue, rankingsCommands, rapidMessagingCommands, roomCreatorCommands, roomInventoryCommands, roomSnapshotCommands, sagaConsumeCallback, sagaStepCallback, sagaTitle, saveQueueForHealthCheck, saveUri, sendEmailCommands, sendToQueue, showcaseCommands, socialCommands, socialMediaRoomsCommands, startGlobalSagaStepListener, status, stopRabbitMQ, storageCommands, testImageCommands, testMintCommands };
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "legend-transactional",
|
|
3
|
-
"version": "2.
|
|
3
|
+
"version": "2.3.0",
|
|
4
4
|
"description": "A simple transactional, event-driven communication framework for microservices using RabbitMQ",
|
|
5
5
|
"author": "Jorge Clavijo <jym272@gmail.com> (https://github.com/jym272)",
|
|
6
6
|
"license": "MIT",
|