@adobe/spacecat-shared-tier-client 1.2.4 → 1.2.5

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/CHANGELOG.md CHANGED
@@ -1,3 +1,10 @@
1
+ # [@adobe/spacecat-shared-tier-client-v1.2.5](https://github.com/adobe/spacecat-shared/compare/@adobe/spacecat-shared-tier-client-v1.2.4...@adobe/spacecat-shared-tier-client-v1.2.5) (2025-11-18)
2
+
3
+
4
+ ### Bug Fixes
5
+
6
+ * adds getAllEnrollment and getFirstEnrolllment for tier client ([#1138](https://github.com/adobe/spacecat-shared/issues/1138)) ([ee8a834](https://github.com/adobe/spacecat-shared/commit/ee8a83414f49887009cad228bdba7d6c7376fe8d))
7
+
1
8
  # [@adobe/spacecat-shared-tier-client-v1.2.4](https://github.com/adobe/spacecat-shared/compare/@adobe/spacecat-shared-tier-client-v1.2.3...@adobe/spacecat-shared-tier-client-v1.2.4) (2025-11-15)
2
9
 
3
10
 
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@adobe/spacecat-shared-tier-client",
3
- "version": "1.2.4",
3
+ "version": "1.2.5",
4
4
  "description": "Shared modules of the Spacecat Services - Tier Client",
5
5
  "type": "module",
6
6
  "engines": {
@@ -220,6 +220,71 @@ class TierClient {
220
220
  throw new Error('Site enrollment not found');
221
221
  }
222
222
  }
223
+
224
+ /**
225
+ * Gets all enrollments based on context, filtered by productCode.
226
+ * - If site is provided: returns site enrollment for the entitlement matching productCode
227
+ * - If org-only: returns all site enrollments for the entitlement matching productCode
228
+ * @returns {Promise<object>} Object with entitlement and enrollments array.
229
+ */
230
+ async getAllEnrollment() {
231
+ try {
232
+ const orgId = this.organization.getId();
233
+ const entitlement = await this.Entitlement
234
+ .findByOrganizationIdAndProductCode(orgId, this.productCode);
235
+
236
+ if (!entitlement) {
237
+ return { entitlement: null, enrollments: [] };
238
+ }
239
+
240
+ const allEnrollments = await this.SiteEnrollment.allByEntitlementId(entitlement.getId());
241
+
242
+ if (this.site) {
243
+ // Return site enrollments matching the entitlement and site
244
+ const siteId = this.site.getId();
245
+ const matchingEnrollments = allEnrollments.filter(
246
+ (se) => se.getSiteId() === siteId,
247
+ );
248
+ return { entitlement, enrollments: matchingEnrollments };
249
+ } else {
250
+ // Return all enrollments for the entitlement
251
+ return { entitlement, enrollments: allEnrollments };
252
+ }
253
+ } catch (error) {
254
+ this.log.error(`Error getting all enrollments: ${error.message}`);
255
+ throw error;
256
+ }
257
+ }
258
+
259
+ /**
260
+ * Gets the first enrollment and its site, filtered by productCode.
261
+ * - If site is provided: returns site enrollment for the entitlement matching productCode
262
+ * - If org-only: returns first site enrollment for the entitlement matching productCode
263
+ * @returns {Promise<object>} Object with entitlement, enrollment, and site.
264
+ */
265
+ async getFirstEnrollment() {
266
+ try {
267
+ const { entitlement, enrollments } = await this.getAllEnrollment();
268
+
269
+ if (!entitlement || !enrollments?.length) {
270
+ return { entitlement: null, enrollment: null, site: null };
271
+ }
272
+
273
+ const firstEnrollment = enrollments[0];
274
+ const enrollmentSiteId = firstEnrollment.getSiteId();
275
+ const site = await this.Site.findById(enrollmentSiteId);
276
+
277
+ if (!site) {
278
+ this.log.warn(`Site not found for enrollment ${firstEnrollment.getId()} with site ID ${enrollmentSiteId}`);
279
+ return { entitlement, enrollment: firstEnrollment, site: null };
280
+ }
281
+
282
+ return { entitlement, enrollment: firstEnrollment, site };
283
+ } catch (error) {
284
+ this.log.error(`Error getting first enrollment: ${error.message}`);
285
+ throw error;
286
+ }
287
+ }
223
288
  }
224
289
 
225
290
  export default TierClient;
@@ -86,6 +86,7 @@ describe('TierClient', () => {
86
86
  info: sandbox.stub(),
87
87
  error: sandbox.stub(),
88
88
  debug: sandbox.stub(),
89
+ warn: sandbox.stub(),
89
90
  },
90
91
  attributes: {
91
92
  authInfo: {
@@ -543,4 +544,272 @@ describe('TierClient', () => {
543
544
  await expect(orgOnlyClient.revokeSiteEnrollment()).to.be.rejectedWith('Site enrollment not found');
544
545
  });
545
546
  });
547
+
548
+ describe('getAllEnrollment', () => {
549
+ beforeEach(() => {
550
+ mockDataAccess.SiteEnrollment.allByEntitlementId = sandbox.stub();
551
+ });
552
+
553
+ it('should return entitlement and enrollments when both exist (org-only)', async () => {
554
+ const tierClientWithoutSite = new TierClient(
555
+ mockContext,
556
+ organizationInstance,
557
+ null,
558
+ productCode,
559
+ );
560
+
561
+ const mockEnrollment2 = {
562
+ getId: () => 'enrollment-456',
563
+ getSiteId: () => '789-site-id',
564
+ getEntitlementId: () => 'entitlement-123',
565
+ };
566
+
567
+ mockDataAccess.Entitlement.findByOrganizationIdAndProductCode.resolves(mockEntitlement);
568
+ mockDataAccess.SiteEnrollment.allByEntitlementId.resolves([
569
+ mockSiteEnrollment,
570
+ mockEnrollment2,
571
+ ]);
572
+
573
+ const result = await tierClientWithoutSite.getAllEnrollment();
574
+
575
+ expect(result).to.deep.equal({
576
+ entitlement: mockEntitlement,
577
+ enrollments: [mockSiteEnrollment, mockEnrollment2],
578
+ });
579
+ expect(mockDataAccess.Entitlement.findByOrganizationIdAndProductCode)
580
+ .to.have.been.calledWith(orgId, productCode);
581
+ expect(mockDataAccess.SiteEnrollment.allByEntitlementId)
582
+ .to.have.been.calledWith('entitlement-123');
583
+ });
584
+
585
+ it('should return filtered enrollments when site is provided', async () => {
586
+ const mockEnrollment2 = {
587
+ getId: () => 'enrollment-456',
588
+ getSiteId: () => 'other-site-id',
589
+ getEntitlementId: () => 'entitlement-123',
590
+ };
591
+
592
+ mockDataAccess.Entitlement.findByOrganizationIdAndProductCode.resolves(mockEntitlement);
593
+ mockDataAccess.SiteEnrollment.allByEntitlementId.resolves([
594
+ mockSiteEnrollment,
595
+ mockEnrollment2,
596
+ ]);
597
+
598
+ const result = await tierClient.getAllEnrollment();
599
+
600
+ expect(result).to.deep.equal({
601
+ entitlement: mockEntitlement,
602
+ enrollments: [mockSiteEnrollment],
603
+ });
604
+ expect(mockDataAccess.SiteEnrollment.allByEntitlementId)
605
+ .to.have.been.calledWith('entitlement-123');
606
+ });
607
+
608
+ it('should return null entitlement and empty enrollments when no entitlement exists', async () => {
609
+ mockDataAccess.Entitlement.findByOrganizationIdAndProductCode.resolves(null);
610
+
611
+ const result = await tierClient.getAllEnrollment();
612
+
613
+ expect(result).to.deep.equal({
614
+ entitlement: null,
615
+ enrollments: [],
616
+ });
617
+ expect(mockDataAccess.SiteEnrollment.allByEntitlementId).to.not.have.been.called;
618
+ });
619
+
620
+ it('should return empty enrollments when entitlement exists but no enrollments', async () => {
621
+ mockDataAccess.Entitlement.findByOrganizationIdAndProductCode.resolves(mockEntitlement);
622
+ mockDataAccess.SiteEnrollment.allByEntitlementId.resolves([]);
623
+
624
+ const result = await tierClient.getAllEnrollment();
625
+
626
+ expect(result).to.deep.equal({
627
+ entitlement: mockEntitlement,
628
+ enrollments: [],
629
+ });
630
+ });
631
+
632
+ it('should handle database errors', async () => {
633
+ mockDataAccess.Entitlement.findByOrganizationIdAndProductCode.rejects(new Error('Database error'));
634
+
635
+ await expect(tierClient.getAllEnrollment()).to.be.rejectedWith('Database error');
636
+ expect(mockContext.log.error).to.have.been.calledWith('Error getting all enrollments: Database error');
637
+ });
638
+
639
+ it('should filter out enrollments not matching site ID', async () => {
640
+ const mockEnrollment2 = {
641
+ getId: () => 'enrollment-456',
642
+ getSiteId: () => 'different-site-id',
643
+ getEntitlementId: () => 'entitlement-123',
644
+ };
645
+
646
+ const mockEnrollment3 = {
647
+ getId: () => 'enrollment-789',
648
+ getSiteId: () => siteId,
649
+ getEntitlementId: () => 'entitlement-123',
650
+ };
651
+
652
+ mockDataAccess.Entitlement.findByOrganizationIdAndProductCode.resolves(mockEntitlement);
653
+ mockDataAccess.SiteEnrollment.allByEntitlementId.resolves([
654
+ mockSiteEnrollment,
655
+ mockEnrollment2,
656
+ mockEnrollment3,
657
+ ]);
658
+
659
+ const result = await tierClient.getAllEnrollment();
660
+
661
+ expect(result.enrollments).to.have.lengthOf(2);
662
+ expect(result.enrollments).to.deep.equal([mockSiteEnrollment, mockEnrollment3]);
663
+ });
664
+ });
665
+
666
+ describe('getFirstEnrollment', () => {
667
+ beforeEach(() => {
668
+ mockDataAccess.SiteEnrollment.allByEntitlementId = sandbox.stub();
669
+ });
670
+
671
+ it('should return entitlement, first enrollment, and site when all exist', async () => {
672
+ const mockSiteObject = {
673
+ getId: () => siteId,
674
+ getName: () => 'Test Site',
675
+ };
676
+
677
+ mockDataAccess.Entitlement.findByOrganizationIdAndProductCode.resolves(mockEntitlement);
678
+ mockDataAccess.SiteEnrollment.allByEntitlementId.resolves([mockSiteEnrollment]);
679
+ mockDataAccess.Site.findById.resolves(mockSiteObject);
680
+
681
+ const tierClientWithoutSite = new TierClient(
682
+ mockContext,
683
+ organizationInstance,
684
+ null,
685
+ productCode,
686
+ );
687
+
688
+ const result = await tierClientWithoutSite.getFirstEnrollment();
689
+
690
+ expect(result).to.deep.equal({
691
+ entitlement: mockEntitlement,
692
+ enrollment: mockSiteEnrollment,
693
+ site: mockSiteObject,
694
+ });
695
+ expect(mockDataAccess.Site.findById).to.have.been.calledWith(siteId);
696
+ });
697
+
698
+ it('should return first enrollment when multiple exist', async () => {
699
+ const mockSiteObject = {
700
+ getId: () => siteId,
701
+ getName: () => 'Test Site',
702
+ };
703
+
704
+ const mockEnrollment2 = {
705
+ getId: () => 'enrollment-456',
706
+ getSiteId: () => 'other-site-id',
707
+ getEntitlementId: () => 'entitlement-123',
708
+ };
709
+
710
+ mockDataAccess.Entitlement.findByOrganizationIdAndProductCode.resolves(mockEntitlement);
711
+ mockDataAccess.SiteEnrollment.allByEntitlementId.resolves([
712
+ mockSiteEnrollment,
713
+ mockEnrollment2,
714
+ ]);
715
+ mockDataAccess.Site.findById.resolves(mockSiteObject);
716
+
717
+ const tierClientWithoutSite = new TierClient(
718
+ mockContext,
719
+ organizationInstance,
720
+ null,
721
+ productCode,
722
+ );
723
+
724
+ const result = await tierClientWithoutSite.getFirstEnrollment();
725
+
726
+ expect(result.enrollment).to.equal(mockSiteEnrollment);
727
+ expect(mockDataAccess.Site.findById).to.have.been.calledWith(siteId);
728
+ });
729
+
730
+ it('should return nulls when no entitlement exists', async () => {
731
+ mockDataAccess.Entitlement.findByOrganizationIdAndProductCode.resolves(null);
732
+
733
+ const result = await tierClient.getFirstEnrollment();
734
+
735
+ expect(result).to.deep.equal({
736
+ entitlement: null,
737
+ enrollment: null,
738
+ site: null,
739
+ });
740
+ expect(mockDataAccess.Site.findById).to.not.have.been.called;
741
+ });
742
+
743
+ it('should return nulls when no enrollments exist', async () => {
744
+ mockDataAccess.Entitlement.findByOrganizationIdAndProductCode.resolves(mockEntitlement);
745
+ mockDataAccess.SiteEnrollment.allByEntitlementId.resolves([]);
746
+
747
+ const result = await tierClient.getFirstEnrollment();
748
+
749
+ expect(result).to.deep.equal({
750
+ entitlement: null,
751
+ enrollment: null,
752
+ site: null,
753
+ });
754
+ expect(mockDataAccess.Site.findById).to.not.have.been.called;
755
+ });
756
+
757
+ it('should return null site when site not found in database', async () => {
758
+ mockDataAccess.Entitlement.findByOrganizationIdAndProductCode.resolves(mockEntitlement);
759
+ mockDataAccess.SiteEnrollment.allByEntitlementId.resolves([mockSiteEnrollment]);
760
+ mockDataAccess.Site.findById.resolves(null);
761
+
762
+ const tierClientWithoutSite = new TierClient(
763
+ mockContext,
764
+ organizationInstance,
765
+ null,
766
+ productCode,
767
+ );
768
+
769
+ const result = await tierClientWithoutSite.getFirstEnrollment();
770
+
771
+ expect(result).to.deep.equal({
772
+ entitlement: mockEntitlement,
773
+ enrollment: mockSiteEnrollment,
774
+ site: null,
775
+ });
776
+ expect(mockContext.log.warn).to.have.been.calledWith(
777
+ `Site not found for enrollment ${mockSiteEnrollment.getId()} with site ID ${siteId}`,
778
+ );
779
+ });
780
+
781
+ it('should handle database errors', async () => {
782
+ mockDataAccess.Entitlement.findByOrganizationIdAndProductCode.rejects(new Error('Database error'));
783
+
784
+ await expect(tierClient.getFirstEnrollment()).to.be.rejectedWith('Database error');
785
+ expect(mockContext.log.error).to.have.been.calledWith('Error getting first enrollment: Database error');
786
+ });
787
+
788
+ it('should work with site-specific client', async () => {
789
+ const mockSiteObject = {
790
+ getId: () => siteId,
791
+ getName: () => 'Test Site',
792
+ };
793
+
794
+ mockDataAccess.Entitlement.findByOrganizationIdAndProductCode.resolves(mockEntitlement);
795
+ mockDataAccess.SiteEnrollment.allByEntitlementId.resolves([mockSiteEnrollment]);
796
+ mockDataAccess.Site.findById.resolves(mockSiteObject);
797
+
798
+ const result = await tierClient.getFirstEnrollment();
799
+
800
+ expect(result).to.deep.equal({
801
+ entitlement: mockEntitlement,
802
+ enrollment: mockSiteEnrollment,
803
+ site: mockSiteObject,
804
+ });
805
+ });
806
+
807
+ it('should handle error when fetching site', async () => {
808
+ mockDataAccess.Entitlement.findByOrganizationIdAndProductCode.resolves(mockEntitlement);
809
+ mockDataAccess.SiteEnrollment.allByEntitlementId.resolves([mockSiteEnrollment]);
810
+ mockDataAccess.Site.findById.rejects(new Error('Site fetch error'));
811
+
812
+ await expect(tierClient.getFirstEnrollment()).to.be.rejectedWith('Site fetch error');
813
+ });
814
+ });
546
815
  });