legend-transactional 2.2.2 → 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 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.
@@ -345,6 +351,17 @@ interface EventPayload {
345
351
  'legend_rankings.rankings_finished': {
346
352
  completedRankings: CompletedRanking[];
347
353
  };
354
+ /**
355
+ * Event to deliver intermediate reward (e.g., first game)
356
+ */
357
+ 'legend_rankings.intermediate_reward': {
358
+ userId: string;
359
+ rankingId: number;
360
+ intermediateRewardType: string;
361
+ rewardConfig: Record<string, unknown>;
362
+ templateName: string;
363
+ templateData: Record<string, unknown>;
364
+ };
348
365
  /**
349
366
  * Event to notify when a ranking is created
350
367
  */
@@ -449,6 +466,89 @@ interface EventPayload {
449
466
  bucketName: string;
450
467
  filePaths: string[];
451
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
+ };
452
552
  }
453
553
  /**
454
554
  * Represents the available events in the system.
@@ -456,6 +556,9 @@ interface EventPayload {
456
556
  declare const microserviceEvent: {
457
557
  readonly 'TEST.IMAGE': "test.image";
458
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";
459
562
  readonly 'AUTH.DELETED_USER': "auth.deleted_user";
460
563
  readonly 'AUTH.LOGOUT_USER': "auth.logout_user";
461
564
  readonly 'AUTH.NEW_USER': "auth.new_user";
@@ -472,6 +575,7 @@ declare const microserviceEvent: {
472
575
  readonly 'LEGEND_MISSIONS.SEND_EMAIL_NFT_MISSION_COMPLETED': "legend_missions.send_email_nft_mission_completed";
473
576
  readonly 'LEGEND_RANKINGS.RANKINGS_FINISHED': "legend_rankings.rankings_finished";
474
577
  readonly 'LEGEND_RANKINGS.NEW_RANKING_CREATED': "legend_rankings.new_ranking_created";
578
+ readonly 'LEGEND_RANKINGS.INTERMEDIATE_REWARD': "legend_rankings.intermediate_reward";
475
579
  readonly 'LEGEND_SHOWCASE.PRODUCT_VIRTUAL_DELETED': "legend_showcase.product_virtual_deleted";
476
580
  readonly 'LEGEND_SHOWCASE.UPDATE_ALLOWED_MISSION_SUBSCRIPTION_IDS': "legend_showcase.update_allowed_mission_subscription_ids";
477
581
  readonly 'LEGEND_SHOWCASE.UPDATE_ALLOWED_RANKING_SUBSCRIPTION_IDS': "legend_showcase.update_allowed_ranking_subscription_ids";
@@ -547,7 +651,7 @@ declare abstract class ConsumeChannel {
547
651
  *
548
652
  * @see NACKING_DELAY_MS
549
653
  */
550
- nackWithDelay: (delay?: number, maxRetries?: number) => {
654
+ nackWithDelay(delay?: number, maxRetries?: number): {
551
655
  count: number;
552
656
  delay: number;
553
657
  };
@@ -564,7 +668,7 @@ declare abstract class ConsumeChannel {
564
668
  * - `occurrence`: The current occurrence count for the Fibonacci sequence.
565
669
  * @see MAX_OCCURRENCE
566
670
  */
567
- nackWithFibonacciStrategy: (maxOccurrence?: number, maxRetries?: number) => {
671
+ nackWithFibonacciStrategy(maxOccurrence?: number, maxRetries?: number): {
568
672
  count: number;
569
673
  delay: number;
570
674
  occurrence: number;
@@ -583,14 +687,48 @@ declare abstract class ConsumeChannel {
583
687
 
584
688
  /**
585
689
  * Represents a **_consume_** channel for handling saga events/commands.
586
- * Extends the abstract ConsumeChannel class.
690
+ * Extends the abstract ConsumeChannel class with automatic audit event emission.
587
691
  *
588
692
  */
589
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);
590
712
  /**
591
713
  * Acknowledges the consumed saga event/command.
714
+ * Automatically emits audit.processed event after successful ACK.
592
715
  */
593
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
+ };
594
732
  }
595
733
 
596
734
  /**
@@ -611,6 +749,13 @@ type MicroserviceConsumeEvents<T extends MicroserviceEvent> = {
611
749
  * Represents the names of specific message queues in the RabbitMQ context.
612
750
  */
613
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";
614
759
  /**
615
760
  * Queue used for sending replies in response to saga events.
616
761
  */
@@ -624,6 +769,10 @@ declare const queue: {
624
769
  * Represents the names of exchanges, which act as message routing hubs in the RabbitMQ context.
625
770
  */
626
771
  declare const exchange: {
772
+ /**
773
+ * Audit exchange name for direct routing of audit events
774
+ */
775
+ readonly Audit: "audit_exchange";
627
776
  /**
628
777
  * Exchange dedicated to requeueing messages that require further processing in a saga process
629
778
  */
@@ -681,6 +830,15 @@ declare const authCommands: {
681
830
  */
682
831
  type AuthCommands = (typeof authCommands)[keyof typeof authCommands];
683
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
+
684
842
  /**
685
843
  * Different commands related to the "blockchain" microservice.
686
844
  */
@@ -895,6 +1053,10 @@ interface CommandMap {
895
1053
  * Represents the mapping of "auth" microservice commands.
896
1054
  */
897
1055
  [availableMicroservices.Auth]: AuthCommands;
1056
+ /**
1057
+ * Represents the mapping of "audit-eda" microservice commands.
1058
+ */
1059
+ [availableMicroservices.AuditEda]: AuditEdaCommands;
898
1060
  /**
899
1061
  * Represents the mapping of "blockchain" microservice commands.
900
1062
  */
@@ -1160,6 +1322,24 @@ declare const createConsumers: (consumers: QueueConsumerProps[]) => Promise<void
1160
1322
  */
1161
1323
  declare const createHeaderConsumers: (queueName: string, events: MicroserviceEvent[]) => Promise<void>;
1162
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
+
1163
1343
  declare const sagaTitle: {
1164
1344
  /**
1165
1345
  * Saga used in the flow to purchase resources and deduct coins from the user.
@@ -1745,4 +1925,22 @@ declare const getEventObject: (event: MicroserviceEvent) => {
1745
1925
  [x: string]: MicroserviceEvent;
1746
1926
  };
1747
1927
 
1748
- export { 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, 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 };
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.
@@ -345,6 +351,17 @@ interface EventPayload {
345
351
  'legend_rankings.rankings_finished': {
346
352
  completedRankings: CompletedRanking[];
347
353
  };
354
+ /**
355
+ * Event to deliver intermediate reward (e.g., first game)
356
+ */
357
+ 'legend_rankings.intermediate_reward': {
358
+ userId: string;
359
+ rankingId: number;
360
+ intermediateRewardType: string;
361
+ rewardConfig: Record<string, unknown>;
362
+ templateName: string;
363
+ templateData: Record<string, unknown>;
364
+ };
348
365
  /**
349
366
  * Event to notify when a ranking is created
350
367
  */
@@ -449,6 +466,89 @@ interface EventPayload {
449
466
  bucketName: string;
450
467
  filePaths: string[];
451
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
+ };
452
552
  }
453
553
  /**
454
554
  * Represents the available events in the system.
@@ -456,6 +556,9 @@ interface EventPayload {
456
556
  declare const microserviceEvent: {
457
557
  readonly 'TEST.IMAGE': "test.image";
458
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";
459
562
  readonly 'AUTH.DELETED_USER': "auth.deleted_user";
460
563
  readonly 'AUTH.LOGOUT_USER': "auth.logout_user";
461
564
  readonly 'AUTH.NEW_USER': "auth.new_user";
@@ -472,6 +575,7 @@ declare const microserviceEvent: {
472
575
  readonly 'LEGEND_MISSIONS.SEND_EMAIL_NFT_MISSION_COMPLETED': "legend_missions.send_email_nft_mission_completed";
473
576
  readonly 'LEGEND_RANKINGS.RANKINGS_FINISHED': "legend_rankings.rankings_finished";
474
577
  readonly 'LEGEND_RANKINGS.NEW_RANKING_CREATED': "legend_rankings.new_ranking_created";
578
+ readonly 'LEGEND_RANKINGS.INTERMEDIATE_REWARD': "legend_rankings.intermediate_reward";
475
579
  readonly 'LEGEND_SHOWCASE.PRODUCT_VIRTUAL_DELETED': "legend_showcase.product_virtual_deleted";
476
580
  readonly 'LEGEND_SHOWCASE.UPDATE_ALLOWED_MISSION_SUBSCRIPTION_IDS': "legend_showcase.update_allowed_mission_subscription_ids";
477
581
  readonly 'LEGEND_SHOWCASE.UPDATE_ALLOWED_RANKING_SUBSCRIPTION_IDS': "legend_showcase.update_allowed_ranking_subscription_ids";
@@ -547,7 +651,7 @@ declare abstract class ConsumeChannel {
547
651
  *
548
652
  * @see NACKING_DELAY_MS
549
653
  */
550
- nackWithDelay: (delay?: number, maxRetries?: number) => {
654
+ nackWithDelay(delay?: number, maxRetries?: number): {
551
655
  count: number;
552
656
  delay: number;
553
657
  };
@@ -564,7 +668,7 @@ declare abstract class ConsumeChannel {
564
668
  * - `occurrence`: The current occurrence count for the Fibonacci sequence.
565
669
  * @see MAX_OCCURRENCE
566
670
  */
567
- nackWithFibonacciStrategy: (maxOccurrence?: number, maxRetries?: number) => {
671
+ nackWithFibonacciStrategy(maxOccurrence?: number, maxRetries?: number): {
568
672
  count: number;
569
673
  delay: number;
570
674
  occurrence: number;
@@ -583,14 +687,48 @@ declare abstract class ConsumeChannel {
583
687
 
584
688
  /**
585
689
  * Represents a **_consume_** channel for handling saga events/commands.
586
- * Extends the abstract ConsumeChannel class.
690
+ * Extends the abstract ConsumeChannel class with automatic audit event emission.
587
691
  *
588
692
  */
589
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);
590
712
  /**
591
713
  * Acknowledges the consumed saga event/command.
714
+ * Automatically emits audit.processed event after successful ACK.
592
715
  */
593
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
+ };
594
732
  }
595
733
 
596
734
  /**
@@ -611,6 +749,13 @@ type MicroserviceConsumeEvents<T extends MicroserviceEvent> = {
611
749
  * Represents the names of specific message queues in the RabbitMQ context.
612
750
  */
613
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";
614
759
  /**
615
760
  * Queue used for sending replies in response to saga events.
616
761
  */
@@ -624,6 +769,10 @@ declare const queue: {
624
769
  * Represents the names of exchanges, which act as message routing hubs in the RabbitMQ context.
625
770
  */
626
771
  declare const exchange: {
772
+ /**
773
+ * Audit exchange name for direct routing of audit events
774
+ */
775
+ readonly Audit: "audit_exchange";
627
776
  /**
628
777
  * Exchange dedicated to requeueing messages that require further processing in a saga process
629
778
  */
@@ -681,6 +830,15 @@ declare const authCommands: {
681
830
  */
682
831
  type AuthCommands = (typeof authCommands)[keyof typeof authCommands];
683
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
+
684
842
  /**
685
843
  * Different commands related to the "blockchain" microservice.
686
844
  */
@@ -895,6 +1053,10 @@ interface CommandMap {
895
1053
  * Represents the mapping of "auth" microservice commands.
896
1054
  */
897
1055
  [availableMicroservices.Auth]: AuthCommands;
1056
+ /**
1057
+ * Represents the mapping of "audit-eda" microservice commands.
1058
+ */
1059
+ [availableMicroservices.AuditEda]: AuditEdaCommands;
898
1060
  /**
899
1061
  * Represents the mapping of "blockchain" microservice commands.
900
1062
  */
@@ -1160,6 +1322,24 @@ declare const createConsumers: (consumers: QueueConsumerProps[]) => Promise<void
1160
1322
  */
1161
1323
  declare const createHeaderConsumers: (queueName: string, events: MicroserviceEvent[]) => Promise<void>;
1162
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
+
1163
1343
  declare const sagaTitle: {
1164
1344
  /**
1165
1345
  * Saga used in the flow to purchase resources and deduct coins from the user.
@@ -1745,4 +1925,22 @@ declare const getEventObject: (event: MicroserviceEvent) => {
1745
1925
  [x: string]: MicroserviceEvent;
1746
1926
  };
1747
1927
 
1748
- export { 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, 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 };
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",
@@ -114,6 +125,7 @@ var microserviceEvent = {
114
125
  "LEGEND_MISSIONS.SEND_EMAIL_NFT_MISSION_COMPLETED": "legend_missions.send_email_nft_mission_completed",
115
126
  "LEGEND_RANKINGS.RANKINGS_FINISHED": "legend_rankings.rankings_finished",
116
127
  "LEGEND_RANKINGS.NEW_RANKING_CREATED": "legend_rankings.new_ranking_created",
128
+ "LEGEND_RANKINGS.INTERMEDIATE_REWARD": "legend_rankings.intermediate_reward",
117
129
  "LEGEND_SHOWCASE.PRODUCT_VIRTUAL_DELETED": "legend_showcase.product_virtual_deleted",
118
130
  "LEGEND_SHOWCASE.UPDATE_ALLOWED_MISSION_SUBSCRIPTION_IDS": "legend_showcase.update_allowed_mission_subscription_ids",
119
131
  "LEGEND_SHOWCASE.UPDATE_ALLOWED_RANKING_SUBSCRIPTION_IDS": "legend_showcase.update_allowed_ranking_subscription_ids",
@@ -131,6 +143,13 @@ var microserviceEvent = {
131
143
 
132
144
  // src/@types/rabbit-mq.ts
133
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",
134
153
  /**
135
154
  * Queue used for sending replies in response to saga events.
136
155
  */
@@ -141,6 +160,10 @@ var queue = {
141
160
  CommenceSaga: "commence_saga"
142
161
  };
143
162
  var exchange = {
163
+ /**
164
+ * Audit exchange name for direct routing of audit events
165
+ */
166
+ Audit: "audit_exchange",
144
167
  /**
145
168
  * Exchange dedicated to requeueing messages that require further processing in a saga process
146
169
  */
@@ -175,6 +198,9 @@ var authCommands = {
175
198
  CreateUser: "create_user"
176
199
  };
177
200
 
201
+ // src/@types/saga/commands/audit-eda.ts
202
+ var auditEdaCommands = {};
203
+
178
204
  // src/@types/saga/commands/blockchain.ts
179
205
  var blockchainCommands = {
180
206
  /**
@@ -457,6 +483,11 @@ var getEventObject = (event) => {
457
483
  };
458
484
  };
459
485
 
486
+ // src/utils/extractMicroservice.ts
487
+ function extractMicroserviceFromQueue(queueName) {
488
+ return queueName.replace(/_match_commands$/, "").replace(/_saga_commands$/, "");
489
+ }
490
+
460
491
  // src/Consumer/channels/Consume.ts
461
492
  var ConsumeChannel = class {
462
493
  /**
@@ -496,10 +527,10 @@ var ConsumeChannel = class {
496
527
  *
497
528
  * @see NACKING_DELAY_MS
498
529
  */
499
- nackWithDelay = (delay = NACKING_DELAY_MS, maxRetries) => {
530
+ nackWithDelay(delay = NACKING_DELAY_MS, maxRetries) {
500
531
  const { delay: delayNackRetry, count } = this.nack({ delay, maxRetries });
501
532
  return { count, delay: delayNackRetry };
502
- };
533
+ }
503
534
  /**
504
535
  * Negatively acknowledges (NACKs) the message using a Fibonacci backoff strategy.
505
536
  *
@@ -513,9 +544,9 @@ var ConsumeChannel = class {
513
544
  * - `occurrence`: The current occurrence count for the Fibonacci sequence.
514
545
  * @see MAX_OCCURRENCE
515
546
  */
516
- nackWithFibonacciStrategy = (maxOccurrence = MAX_OCCURRENCE, maxRetries) => {
547
+ nackWithFibonacciStrategy(maxOccurrence = MAX_OCCURRENCE, maxRetries) {
517
548
  return this.nack({ maxOccurrence, maxRetries });
518
- };
549
+ }
519
550
  /**
520
551
  * Private helper function to handle the actual NACK logic.
521
552
  *
@@ -525,11 +556,7 @@ var ConsumeChannel = class {
525
556
  * - `delay` and `maxRetries`: For linear backoff with a fixed delay and retry limit.
526
557
  * - `maxOccurrence`: For Fibonacci backoff with a maximum occurrence count.
527
558
  */
528
- nack = ({
529
- maxRetries,
530
- maxOccurrence,
531
- delay
532
- }) => {
559
+ nack({ maxRetries, maxOccurrence, delay }) {
533
560
  const { msg, queueName, channel } = this;
534
561
  channel.nack(msg, false, false);
535
562
  let count = 0;
@@ -586,7 +613,7 @@ var ConsumeChannel = class {
586
613
  });
587
614
  }
588
615
  return { count, delay: nackDelay, occurrence };
589
- };
616
+ }
590
617
  };
591
618
  var Consume_default = ConsumeChannel;
592
619
 
@@ -618,13 +645,109 @@ var commenceSagaConsumeCallback = (msg, channel, e, queueName) => {
618
645
  e.emit(saga.title, { saga, channel: responseChannel });
619
646
  };
620
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
+
621
672
  // src/Consumer/channels/Events.ts
622
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
+ }
623
696
  /**
624
697
  * Acknowledges the consumed saga event/command.
698
+ * Automatically emits audit.processed event after successful ACK.
625
699
  */
626
700
  ackMessage() {
627
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;
628
751
  }
629
752
  };
630
753
 
@@ -667,7 +790,20 @@ var eventCallback = (msg, channel, e, queueName) => {
667
790
  { headersReceived: headers, eventsDetected: event }
668
791
  );
669
792
  }
670
- const responseChannel = new EventsConsumeChannel(channel, msg, queueName);
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);
671
807
  e.emit(event[0], { payload, channel: responseChannel });
672
808
  };
673
809
 
@@ -834,6 +970,25 @@ var createHeaderConsumers = async (queueName, events) => {
834
970
  }
835
971
  }
836
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
+ };
837
992
  var isReady = false;
838
993
  var prepare = async (url2) => {
839
994
  if (isReady) return;
@@ -893,6 +1048,7 @@ var connectToEvents = async (config) => {
893
1048
  const queueName = `${config.microservice}_match_commands`;
894
1049
  const e = mitt__default.default();
895
1050
  await createHeaderConsumers(queueName, config.events);
1051
+ await createAuditLoggingResources();
896
1052
  void consume(e, queueName, eventCallback);
897
1053
  return e;
898
1054
  };
@@ -978,6 +1134,7 @@ exports.Saga = Saga;
978
1134
  exports.SagaCommenceConsumeChannel = SagaCommenceConsumeChannel;
979
1135
  exports.SagaConsumeChannel = SagaConsumeChannel;
980
1136
  exports.Transactional = Transactional;
1137
+ exports.auditEdaCommands = auditEdaCommands;
981
1138
  exports.authCommands = authCommands;
982
1139
  exports.availableMicroservices = availableMicroservices;
983
1140
  exports.blockchainCommands = blockchainCommands;
@@ -991,10 +1148,12 @@ exports.commenceSagaListener = commenceSagaListener;
991
1148
  exports.connectToEvents = connectToEvents;
992
1149
  exports.connectToSagaCommandEmitter = connectToSagaCommandEmitter;
993
1150
  exports.consume = consume;
1151
+ exports.createAuditLoggingResources = createAuditLoggingResources;
994
1152
  exports.createConsumers = createConsumers;
995
1153
  exports.createHeaderConsumers = createHeaderConsumers;
996
1154
  exports.eventCallback = eventCallback;
997
1155
  exports.exchange = exchange;
1156
+ exports.extractMicroserviceFromQueue = extractMicroserviceFromQueue;
998
1157
  exports.fibonacci = fibonacci;
999
1158
  exports.gender = gender;
1000
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",
@@ -107,6 +118,7 @@ var microserviceEvent = {
107
118
  "LEGEND_MISSIONS.SEND_EMAIL_NFT_MISSION_COMPLETED": "legend_missions.send_email_nft_mission_completed",
108
119
  "LEGEND_RANKINGS.RANKINGS_FINISHED": "legend_rankings.rankings_finished",
109
120
  "LEGEND_RANKINGS.NEW_RANKING_CREATED": "legend_rankings.new_ranking_created",
121
+ "LEGEND_RANKINGS.INTERMEDIATE_REWARD": "legend_rankings.intermediate_reward",
110
122
  "LEGEND_SHOWCASE.PRODUCT_VIRTUAL_DELETED": "legend_showcase.product_virtual_deleted",
111
123
  "LEGEND_SHOWCASE.UPDATE_ALLOWED_MISSION_SUBSCRIPTION_IDS": "legend_showcase.update_allowed_mission_subscription_ids",
112
124
  "LEGEND_SHOWCASE.UPDATE_ALLOWED_RANKING_SUBSCRIPTION_IDS": "legend_showcase.update_allowed_ranking_subscription_ids",
@@ -124,6 +136,13 @@ var microserviceEvent = {
124
136
 
125
137
  // src/@types/rabbit-mq.ts
126
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",
127
146
  /**
128
147
  * Queue used for sending replies in response to saga events.
129
148
  */
@@ -134,6 +153,10 @@ var queue = {
134
153
  CommenceSaga: "commence_saga"
135
154
  };
136
155
  var exchange = {
156
+ /**
157
+ * Audit exchange name for direct routing of audit events
158
+ */
159
+ Audit: "audit_exchange",
137
160
  /**
138
161
  * Exchange dedicated to requeueing messages that require further processing in a saga process
139
162
  */
@@ -168,6 +191,9 @@ var authCommands = {
168
191
  CreateUser: "create_user"
169
192
  };
170
193
 
194
+ // src/@types/saga/commands/audit-eda.ts
195
+ var auditEdaCommands = {};
196
+
171
197
  // src/@types/saga/commands/blockchain.ts
172
198
  var blockchainCommands = {
173
199
  /**
@@ -450,6 +476,11 @@ var getEventObject = (event) => {
450
476
  };
451
477
  };
452
478
 
479
+ // src/utils/extractMicroservice.ts
480
+ function extractMicroserviceFromQueue(queueName) {
481
+ return queueName.replace(/_match_commands$/, "").replace(/_saga_commands$/, "");
482
+ }
483
+
453
484
  // src/Consumer/channels/Consume.ts
454
485
  var ConsumeChannel = class {
455
486
  /**
@@ -489,10 +520,10 @@ var ConsumeChannel = class {
489
520
  *
490
521
  * @see NACKING_DELAY_MS
491
522
  */
492
- nackWithDelay = (delay = NACKING_DELAY_MS, maxRetries) => {
523
+ nackWithDelay(delay = NACKING_DELAY_MS, maxRetries) {
493
524
  const { delay: delayNackRetry, count } = this.nack({ delay, maxRetries });
494
525
  return { count, delay: delayNackRetry };
495
- };
526
+ }
496
527
  /**
497
528
  * Negatively acknowledges (NACKs) the message using a Fibonacci backoff strategy.
498
529
  *
@@ -506,9 +537,9 @@ var ConsumeChannel = class {
506
537
  * - `occurrence`: The current occurrence count for the Fibonacci sequence.
507
538
  * @see MAX_OCCURRENCE
508
539
  */
509
- nackWithFibonacciStrategy = (maxOccurrence = MAX_OCCURRENCE, maxRetries) => {
540
+ nackWithFibonacciStrategy(maxOccurrence = MAX_OCCURRENCE, maxRetries) {
510
541
  return this.nack({ maxOccurrence, maxRetries });
511
- };
542
+ }
512
543
  /**
513
544
  * Private helper function to handle the actual NACK logic.
514
545
  *
@@ -518,11 +549,7 @@ var ConsumeChannel = class {
518
549
  * - `delay` and `maxRetries`: For linear backoff with a fixed delay and retry limit.
519
550
  * - `maxOccurrence`: For Fibonacci backoff with a maximum occurrence count.
520
551
  */
521
- nack = ({
522
- maxRetries,
523
- maxOccurrence,
524
- delay
525
- }) => {
552
+ nack({ maxRetries, maxOccurrence, delay }) {
526
553
  const { msg, queueName, channel } = this;
527
554
  channel.nack(msg, false, false);
528
555
  let count = 0;
@@ -579,7 +606,7 @@ var ConsumeChannel = class {
579
606
  });
580
607
  }
581
608
  return { count, delay: nackDelay, occurrence };
582
- };
609
+ }
583
610
  };
584
611
  var Consume_default = ConsumeChannel;
585
612
 
@@ -611,13 +638,109 @@ var commenceSagaConsumeCallback = (msg, channel, e, queueName) => {
611
638
  e.emit(saga.title, { saga, channel: responseChannel });
612
639
  };
613
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
+
614
665
  // src/Consumer/channels/Events.ts
615
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
+ }
616
689
  /**
617
690
  * Acknowledges the consumed saga event/command.
691
+ * Automatically emits audit.processed event after successful ACK.
618
692
  */
619
693
  ackMessage() {
620
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;
621
744
  }
622
745
  };
623
746
 
@@ -660,7 +783,20 @@ var eventCallback = (msg, channel, e, queueName) => {
660
783
  { headersReceived: headers, eventsDetected: event }
661
784
  );
662
785
  }
663
- const responseChannel = new EventsConsumeChannel(channel, msg, queueName);
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);
664
800
  e.emit(event[0], { payload, channel: responseChannel });
665
801
  };
666
802
 
@@ -827,6 +963,25 @@ var createHeaderConsumers = async (queueName, events) => {
827
963
  }
828
964
  }
829
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
+ };
830
985
  var isReady = false;
831
986
  var prepare = async (url2) => {
832
987
  if (isReady) return;
@@ -886,6 +1041,7 @@ var connectToEvents = async (config) => {
886
1041
  const queueName = `${config.microservice}_match_commands`;
887
1042
  const e = mitt();
888
1043
  await createHeaderConsumers(queueName, config.events);
1044
+ await createAuditLoggingResources();
889
1045
  void consume(e, queueName, eventCallback);
890
1046
  return e;
891
1047
  };
@@ -960,4 +1116,4 @@ var publishEvent = async (msg, event) => {
960
1116
  });
961
1117
  };
962
1118
 
963
- 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.2.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",