@mohasinac/appkit 2.7.50 → 2.7.52

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.
Files changed (143) hide show
  1. package/dist/_internal/server/jobs/core/__tests__/couponExpiry.test.d.ts +1 -0
  2. package/dist/_internal/server/jobs/core/__tests__/couponExpiry.test.js +65 -0
  3. package/dist/_internal/server/jobs/core/__tests__/listingProcessor.test.d.ts +1 -0
  4. package/dist/_internal/server/jobs/core/__tests__/listingProcessor.test.js +163 -0
  5. package/dist/_internal/server/jobs/core/__tests__/mediaTmpCleanup.test.d.ts +1 -0
  6. package/dist/_internal/server/jobs/core/__tests__/mediaTmpCleanup.test.js +115 -0
  7. package/dist/_internal/server/jobs/core/__tests__/pendingOrderTimeout.test.d.ts +1 -0
  8. package/dist/_internal/server/jobs/core/__tests__/pendingOrderTimeout.test.js +96 -0
  9. package/dist/client.d.ts +29 -6
  10. package/dist/client.js +16 -4
  11. package/dist/constants/api-endpoints.d.ts +42 -0
  12. package/dist/constants/api-endpoints.js +14 -0
  13. package/dist/features/_guide-cls.d.ts +13 -0
  14. package/dist/features/_guide-cls.js +14 -0
  15. package/dist/features/about/components/HelpPageView.js +29 -26
  16. package/dist/features/account/components/BuyerAccountGuideView.d.ts +1 -0
  17. package/dist/features/account/components/BuyerAccountGuideView.js +39 -0
  18. package/dist/features/account/components/BuyerAuctionsGuideView.d.ts +1 -0
  19. package/dist/features/account/components/BuyerAuctionsGuideView.js +38 -0
  20. package/dist/features/account/components/BuyerOrdersGuideView.d.ts +1 -0
  21. package/dist/features/account/components/BuyerOrdersGuideView.js +48 -0
  22. package/dist/features/account/components/BuyerShoppingGuideView.d.ts +1 -0
  23. package/dist/features/account/components/BuyerShoppingGuideView.js +38 -0
  24. package/dist/features/admin/components/AdminAnalyticsGuideView.d.ts +1 -0
  25. package/dist/features/admin/components/AdminAnalyticsGuideView.js +24 -0
  26. package/dist/features/admin/components/AdminBlogEditorView.js +100 -77
  27. package/dist/features/admin/components/AdminBundleEditorView.js +20 -14
  28. package/dist/features/admin/components/AdminBundlesView.d.ts +1 -3
  29. package/dist/features/admin/components/AdminBundlesView.js +173 -52
  30. package/dist/features/admin/components/AdminCatalogGuideView.d.ts +1 -0
  31. package/dist/features/admin/components/AdminCatalogGuideView.js +28 -0
  32. package/dist/features/admin/components/AdminContentGuideView.d.ts +1 -0
  33. package/dist/features/admin/components/AdminContentGuideView.js +36 -0
  34. package/dist/features/admin/components/AdminCouponEditorView.js +1 -1
  35. package/dist/features/admin/components/AdminGuideHubView.d.ts +5 -0
  36. package/dist/features/admin/components/AdminGuideHubView.js +79 -0
  37. package/dist/features/admin/components/AdminOrdersGuideView.d.ts +1 -0
  38. package/dist/features/admin/components/AdminOrdersGuideView.js +44 -0
  39. package/dist/features/admin/components/AdminProductsView.js +8 -3
  40. package/dist/features/admin/components/AdminSiteConfigGuideView.d.ts +1 -0
  41. package/dist/features/admin/components/AdminSiteConfigGuideView.js +21 -0
  42. package/dist/features/admin/components/AdminStoresGuideView.d.ts +1 -0
  43. package/dist/features/admin/components/AdminStoresGuideView.js +32 -0
  44. package/dist/features/admin/components/AdminTeamGuideView.d.ts +1 -0
  45. package/dist/features/admin/components/AdminTeamGuideView.js +33 -0
  46. package/dist/features/admin/components/AdminTrustGuideView.d.ts +1 -0
  47. package/dist/features/admin/components/AdminTrustGuideView.js +40 -0
  48. package/dist/features/admin/components/AdminUsersGuideView.d.ts +1 -0
  49. package/dist/features/admin/components/AdminUsersGuideView.js +38 -0
  50. package/dist/features/categories/components/CategoryBundlesListing.js +3 -33
  51. package/dist/features/categories/components/index.d.ts +0 -2
  52. package/dist/features/categories/components/index.js +0 -1
  53. package/dist/features/events/components/AdminEventEditorView.js +223 -269
  54. package/dist/features/grouped/repository/grouped-listings.repository.d.ts +9 -0
  55. package/dist/features/grouped/repository/grouped-listings.repository.js +12 -0
  56. package/dist/features/media/upload/MediaUploadField.js +1 -1
  57. package/dist/features/pre-orders/components/PreOrdersIndexListing.js +3 -1
  58. package/dist/features/products/components/AuctionsIndexListing.js +3 -1
  59. package/dist/features/products/components/MarketplaceBundleCard.d.ts +21 -0
  60. package/dist/features/products/components/MarketplaceBundleCard.js +56 -0
  61. package/dist/features/products/components/ProductsIndexListing.js +3 -1
  62. package/dist/features/products/components/index.d.ts +2 -4
  63. package/dist/features/products/components/index.js +1 -2
  64. package/dist/features/promotions/schemas/firestore.js +1 -1
  65. package/dist/features/reviews/components/index.d.ts +0 -2
  66. package/dist/features/reviews/components/index.js +0 -1
  67. package/dist/features/seller/components/BrandInlineSelect.js +23 -3
  68. package/dist/features/seller/components/CategoryInlineSelect.js +20 -3
  69. package/dist/features/seller/components/SellerAnalyticsAlertsView.d.ts +6 -0
  70. package/dist/features/seller/components/SellerAnalyticsAlertsView.js +124 -0
  71. package/dist/features/seller/components/SellerAnalyticsView.d.ts +2 -0
  72. package/dist/features/seller/components/SellerAnalyticsView.js +17 -9
  73. package/dist/features/seller/components/SellerBundlesView.d.ts +5 -0
  74. package/dist/features/seller/components/SellerBundlesView.js +104 -0
  75. package/dist/features/seller/components/SellerClassifiedView.d.ts +5 -0
  76. package/dist/features/seller/components/SellerClassifiedView.js +113 -0
  77. package/dist/features/seller/components/SellerDashboardView.js +19 -7
  78. package/dist/features/seller/components/SellerDigitalCodesView.d.ts +5 -0
  79. package/dist/features/seller/components/SellerDigitalCodesView.js +115 -0
  80. package/dist/features/seller/components/SellerGoogleReviewsView.d.ts +14 -0
  81. package/dist/features/seller/components/SellerGoogleReviewsView.js +95 -0
  82. package/dist/features/seller/components/SellerGroupedListingsView.d.ts +6 -0
  83. package/dist/features/seller/components/SellerGroupedListingsView.js +112 -0
  84. package/dist/features/seller/components/SellerLiveView.d.ts +5 -0
  85. package/dist/features/seller/components/SellerLiveView.js +113 -0
  86. package/dist/features/seller/components/SellerOrdersView.js +18 -2
  87. package/dist/features/seller/components/SellerPayoutMethodsView.d.ts +7 -0
  88. package/dist/features/seller/components/SellerPayoutMethodsView.js +120 -0
  89. package/dist/features/seller/components/SellerPayoutSettingsView.js +50 -12
  90. package/dist/features/seller/components/SellerProductShell.d.ts +1 -1
  91. package/dist/features/seller/components/SellerProductShell.js +9 -7
  92. package/dist/features/seller/components/SellerProductsFilterDrawer.js +3 -1
  93. package/dist/features/seller/components/SellerProductsView.js +48 -54
  94. package/dist/features/seller/components/SellerShippingConfigsView.d.ts +7 -0
  95. package/dist/features/seller/components/SellerShippingConfigsView.js +149 -0
  96. package/dist/features/seller/components/SellerShippingView.js +37 -10
  97. package/dist/features/seller/components/SellerStoreCategoriesView.d.ts +9 -0
  98. package/dist/features/seller/components/SellerStoreCategoriesView.js +122 -0
  99. package/dist/features/seller/components/SellerStorefrontView.d.ts +0 -7
  100. package/dist/features/seller/components/SellerStorefrontView.js +26 -29
  101. package/dist/features/seller/components/SellerTemplatesView.d.ts +10 -0
  102. package/dist/features/seller/components/SellerTemplatesView.js +265 -0
  103. package/dist/features/seller/components/index.d.ts +26 -0
  104. package/dist/features/seller/components/index.js +13 -0
  105. package/dist/features/stores/api/[storeSlug]/reviews/route.js +49 -7
  106. package/dist/features/stores/components/StoreCapabilitiesGuideView.d.ts +3 -0
  107. package/dist/features/stores/components/StoreCapabilitiesGuideView.js +101 -0
  108. package/dist/features/stores/components/StoreFinanceGuideView.d.ts +3 -0
  109. package/dist/features/stores/components/StoreFinanceGuideView.js +79 -0
  110. package/dist/features/stores/components/StoreGuideHubView.d.ts +5 -0
  111. package/dist/features/stores/components/StoreGuideHubView.js +89 -0
  112. package/dist/features/stores/components/StoreListingsGuideView.d.ts +3 -0
  113. package/dist/features/stores/components/StoreListingsGuideView.js +151 -0
  114. package/dist/features/stores/components/StoreOrdersGuideView.d.ts +3 -0
  115. package/dist/features/stores/components/StoreOrdersGuideView.js +122 -0
  116. package/dist/features/stores/components/StoreReviewsListing.js +100 -23
  117. package/dist/features/stores/components/StoreSettingsGuideView.d.ts +3 -0
  118. package/dist/features/stores/components/StoreSettingsGuideView.js +56 -0
  119. package/dist/features/stores/components/index.d.ts +12 -1
  120. package/dist/features/stores/components/index.js +6 -1
  121. package/dist/features/stores/hooks/useStores.d.ts +5 -0
  122. package/dist/features/stores/hooks/useStores.js +10 -0
  123. package/dist/features/stores/manifest.js +1 -1
  124. package/dist/features/whatsapp-bot/components/SellerWhatsAppSettingsView.js +13 -2
  125. package/dist/index.d.ts +54 -9
  126. package/dist/index.js +58 -15
  127. package/dist/next/routing/route-map.d.ts +55 -0
  128. package/dist/next/routing/route-map.js +25 -0
  129. package/dist/providers/db-firebase/__tests__/filter-aliases.test.d.ts +1 -0
  130. package/dist/providers/db-firebase/__tests__/filter-aliases.test.js +93 -0
  131. package/dist/providers/db-firebase/sieve.d.ts +49 -0
  132. package/dist/providers/db-firebase/sieve.js +61 -8
  133. package/dist/repositories/index.d.ts +1 -0
  134. package/dist/repositories/index.js +2 -0
  135. package/dist/tailwind-utilities.css +1 -1
  136. package/dist/ui/components/ListingToolbar.d.ts +8 -1
  137. package/dist/ui/components/ListingToolbar.js +4 -2
  138. package/dist/ui/components/__tests__/BulkActionBar.test.d.ts +1 -0
  139. package/dist/ui/components/__tests__/BulkActionBar.test.js +96 -0
  140. package/dist/ui/components/__tests__/ListingToolbar.test.d.ts +1 -0
  141. package/dist/ui/components/__tests__/ListingToolbar.test.js +125 -0
  142. package/dist/ui/index.d.ts +1 -1
  143. package/package.json +8 -2
@@ -0,0 +1,65 @@
1
+ import { describe, it, expect, vi, beforeEach } from "vitest";
2
+ vi.mock("../../../../../repositories", () => ({
3
+ couponsRepository: {
4
+ getExpiredActiveRefs: vi.fn(),
5
+ deactivateInBatch: vi.fn(),
6
+ },
7
+ }));
8
+ import { runCouponExpiry } from "../couponExpiry";
9
+ import { couponsRepository } from "../../../../../repositories";
10
+ function makeBatch() {
11
+ return { commit: vi.fn().mockResolvedValue(undefined) };
12
+ }
13
+ function makeCtx(batchOverride) {
14
+ const batch = batchOverride ?? makeBatch();
15
+ return {
16
+ job: "coupon-expiry",
17
+ db: { batch: vi.fn(() => batch) },
18
+ logger: { info: vi.fn(), warn: vi.fn(), error: vi.fn() },
19
+ env: vi.fn(),
20
+ now: new Date("2026-01-15T12:00:00Z"),
21
+ };
22
+ }
23
+ beforeEach(() => {
24
+ vi.clearAllMocks();
25
+ });
26
+ describe("runCouponExpiry", () => {
27
+ it("returns early and does not commit when no expired coupons", async () => {
28
+ couponsRepository.getExpiredActiveRefs.mockResolvedValue([]);
29
+ const ctx = makeCtx();
30
+ await runCouponExpiry(ctx);
31
+ expect(ctx.db.batch).not.toHaveBeenCalled();
32
+ });
33
+ it("calls getExpiredActiveRefs with ctx.now", async () => {
34
+ couponsRepository.getExpiredActiveRefs.mockResolvedValue([]);
35
+ const ctx = makeCtx();
36
+ await runCouponExpiry(ctx);
37
+ expect(couponsRepository.getExpiredActiveRefs).toHaveBeenCalledWith(ctx.now);
38
+ });
39
+ it("deactivates each expired coupon in the batch", async () => {
40
+ const refs = [{ id: "coupon-1" }, { id: "coupon-2" }];
41
+ couponsRepository.getExpiredActiveRefs.mockResolvedValue(refs);
42
+ const batch = makeBatch();
43
+ const ctx = makeCtx(batch);
44
+ await runCouponExpiry(ctx);
45
+ expect(couponsRepository.deactivateInBatch).toHaveBeenCalledTimes(2);
46
+ expect(couponsRepository.deactivateInBatch).toHaveBeenCalledWith(batch, refs[0]);
47
+ expect(couponsRepository.deactivateInBatch).toHaveBeenCalledWith(batch, refs[1]);
48
+ });
49
+ it("commits the batch when there are expired coupons", async () => {
50
+ const refs = [{ id: "coupon-1" }];
51
+ couponsRepository.getExpiredActiveRefs.mockResolvedValue(refs);
52
+ const batch = makeBatch();
53
+ const ctx = makeCtx(batch);
54
+ await runCouponExpiry(ctx);
55
+ expect(batch.commit).toHaveBeenCalledOnce();
56
+ });
57
+ it("does not deactivate or commit when refs is empty", async () => {
58
+ couponsRepository.getExpiredActiveRefs.mockResolvedValue([]);
59
+ const batch = makeBatch();
60
+ const ctx = makeCtx(batch);
61
+ await runCouponExpiry(ctx);
62
+ expect(couponsRepository.deactivateInBatch).not.toHaveBeenCalled();
63
+ expect(batch.commit).not.toHaveBeenCalled();
64
+ });
65
+ });
@@ -0,0 +1,163 @@
1
+ import { describe, it, expect, vi, beforeEach } from "vitest";
2
+ // Mock all repository imports before importing the module under test.
3
+ vi.mock("../../../../../repositories", () => ({
4
+ productRepository: { list: vi.fn() },
5
+ blogRepository: { listAll: vi.fn() },
6
+ eventRepository: { list: vi.fn() },
7
+ couponsRepository: { list: vi.fn() },
8
+ storeRepository: { listStores: vi.fn() },
9
+ categoriesRepository: { list: vi.fn() },
10
+ bidRepository: { list: vi.fn() },
11
+ payoutRepository: { list: vi.fn() },
12
+ orderRepository: { listAll: vi.fn() },
13
+ reviewRepository: { listAll: vi.fn() },
14
+ faqsRepository: { list: vi.fn() },
15
+ notificationRepository: { list: vi.fn() },
16
+ scammerRepository: { listAll: vi.fn() },
17
+ productFeaturesRepository: { list: vi.fn() },
18
+ homepageSectionsRepository: { list: vi.fn() },
19
+ userRepository: { list: vi.fn() },
20
+ eventEntryRepository: { listForEvent: vi.fn() },
21
+ productTemplateRepository: { listByStore: vi.fn() },
22
+ }));
23
+ import { runListingProcessor } from "../listingProcessor";
24
+ import { productRepository, blogRepository, eventRepository, couponsRepository, storeRepository, } from "../../../../../repositories";
25
+ function makeCtx() {
26
+ return {
27
+ job: "test",
28
+ db: {},
29
+ logger: { info: vi.fn(), warn: vi.fn(), error: vi.fn() },
30
+ env: vi.fn(),
31
+ now: new Date(),
32
+ };
33
+ }
34
+ const EMPTY_RESULT = {
35
+ items: [],
36
+ total: 0,
37
+ page: 1,
38
+ pageSize: 20,
39
+ totalPages: 0,
40
+ hasMore: false,
41
+ };
42
+ beforeEach(() => {
43
+ vi.clearAllMocks();
44
+ productRepository.list.mockResolvedValue(EMPTY_RESULT);
45
+ blogRepository.listAll.mockResolvedValue(EMPTY_RESULT);
46
+ eventRepository.list.mockResolvedValue(EMPTY_RESULT);
47
+ couponsRepository.list.mockResolvedValue(EMPTY_RESULT);
48
+ storeRepository.listStores.mockResolvedValue(EMPTY_RESULT);
49
+ });
50
+ describe("runListingProcessor", () => {
51
+ it("throws 400 when body is missing collection", async () => {
52
+ const ctx = makeCtx();
53
+ await expect(runListingProcessor({}, ctx)).rejects.toMatchObject({ httpStatus: 400, message: "Missing collection" });
54
+ });
55
+ it("throws 400 for an unsupported collection name", async () => {
56
+ const ctx = makeCtx();
57
+ await expect(runListingProcessor({ collection: "nonexistent" }, ctx)).rejects.toMatchObject({ httpStatus: 400 });
58
+ });
59
+ it("calls the correct lister for 'products'", async () => {
60
+ const ctx = makeCtx();
61
+ await runListingProcessor({ collection: "products", f: "status==published" }, ctx);
62
+ expect(productRepository.list).toHaveBeenCalledWith(expect.objectContaining({ filters: "status==published" }), {});
63
+ });
64
+ it("calls blogRepository for 'blogPosts'", async () => {
65
+ const ctx = makeCtx();
66
+ await runListingProcessor({ collection: "blogPosts" }, ctx);
67
+ expect(blogRepository.listAll).toHaveBeenCalled();
68
+ });
69
+ it("calls eventRepository for 'events'", async () => {
70
+ const ctx = makeCtx();
71
+ await runListingProcessor({ collection: "events" }, ctx);
72
+ expect(eventRepository.list).toHaveBeenCalled();
73
+ });
74
+ it("passes filters and sorts to the lister", async () => {
75
+ const ctx = makeCtx();
76
+ await runListingProcessor({
77
+ collection: "products",
78
+ f: "brand==hasbro",
79
+ s: "-price",
80
+ }, ctx);
81
+ expect(productRepository.list).toHaveBeenCalledWith(expect.objectContaining({ filters: "brand==hasbro", sorts: "-price" }), {});
82
+ });
83
+ it("uses default sort when s is absent", async () => {
84
+ const ctx = makeCtx();
85
+ await runListingProcessor({ collection: "products" }, ctx);
86
+ expect(productRepository.list).toHaveBeenCalledWith(expect.objectContaining({ sorts: "-createdAt" }), {});
87
+ });
88
+ it("clamps pageSize to MAX_PAGE_SIZE (100)", async () => {
89
+ const ctx = makeCtx();
90
+ await runListingProcessor({ collection: "products", ps: 999 }, ctx);
91
+ expect(productRepository.list).toHaveBeenCalledWith(expect.objectContaining({ pageSize: "100" }), {});
92
+ });
93
+ it("uses DEFAULT_PAGE_SIZE when ps is 0", async () => {
94
+ const ctx = makeCtx();
95
+ await runListingProcessor({ collection: "products", ps: 0 }, ctx);
96
+ expect(productRepository.list).toHaveBeenCalledWith(expect.objectContaining({ pageSize: "20" }), {});
97
+ });
98
+ it("uses DEFAULT_PAGE_SIZE when ps is negative", async () => {
99
+ const ctx = makeCtx();
100
+ await runListingProcessor({ collection: "products", ps: -5 }, ctx);
101
+ expect(productRepository.list).toHaveBeenCalledWith(expect.objectContaining({ pageSize: "20" }), {});
102
+ });
103
+ it("reads page from p param", async () => {
104
+ const ctx = makeCtx();
105
+ await runListingProcessor({ collection: "products", p: 3 }, ctx);
106
+ expect(productRepository.list).toHaveBeenCalledWith(expect.objectContaining({ page: "3" }), {});
107
+ });
108
+ it("decodes a valid cursor and uses its page over p", async () => {
109
+ // Encode page=5 as a cursor
110
+ const cursor = Buffer.from(JSON.stringify({ page: 5 }), "utf8").toString("base64");
111
+ const ctx = makeCtx();
112
+ await runListingProcessor({ collection: "products", cursor, p: 1 }, ctx);
113
+ expect(productRepository.list).toHaveBeenCalledWith(expect.objectContaining({ page: "5" }), {});
114
+ });
115
+ it("falls back to p when cursor is invalid base64 JSON", async () => {
116
+ const ctx = makeCtx();
117
+ await runListingProcessor({ collection: "products", cursor: "!!!notbase64!!!", p: 2 }, ctx);
118
+ expect(productRepository.list).toHaveBeenCalledWith(expect.objectContaining({ page: "2" }), {});
119
+ });
120
+ it("encodes the next cursor when hasMore is true", async () => {
121
+ productRepository.list.mockResolvedValue({
122
+ ...EMPTY_RESULT,
123
+ hasMore: true,
124
+ page: 1,
125
+ });
126
+ const ctx = makeCtx();
127
+ const result = await runListingProcessor({ collection: "products", p: 1 }, ctx);
128
+ expect(result.cursor).not.toBeNull();
129
+ // Decode and verify it points to page 2
130
+ const decoded = JSON.parse(Buffer.from(result.cursor, "base64").toString("utf8"));
131
+ expect(decoded.page).toBe(2);
132
+ });
133
+ it("returns null cursor when hasMore is false", async () => {
134
+ const ctx = makeCtx();
135
+ const result = await runListingProcessor({ collection: "products" }, ctx);
136
+ expect(result.cursor).toBeNull();
137
+ });
138
+ it("passes baseOpts to the lister", async () => {
139
+ const ctx = makeCtx();
140
+ await runListingProcessor({
141
+ collection: "products",
142
+ baseOpts: { storeId: "store-abc" },
143
+ }, ctx);
144
+ expect(productRepository.list).toHaveBeenCalledWith(expect.any(Object), { storeId: "store-abc" });
145
+ });
146
+ it("calls stores lister with activeOnly=true by default", async () => {
147
+ const ctx = makeCtx();
148
+ await runListingProcessor({ collection: "stores" }, ctx);
149
+ expect(storeRepository.listStores).toHaveBeenCalledWith(expect.any(Object), true);
150
+ });
151
+ it("returns the items from the lister result", async () => {
152
+ const items = [{ id: "p1" }, { id: "p2" }];
153
+ productRepository.list.mockResolvedValue({
154
+ ...EMPTY_RESULT,
155
+ items,
156
+ total: 2,
157
+ });
158
+ const ctx = makeCtx();
159
+ const result = await runListingProcessor({ collection: "products" }, ctx);
160
+ expect(result.items).toEqual(items);
161
+ expect(result.total).toBe(2);
162
+ });
163
+ });
@@ -0,0 +1,115 @@
1
+ import { describe, it, expect, vi, beforeEach } from "vitest";
2
+ vi.mock("../../../../../providers/db-firebase/admin-storage-lite", () => ({
3
+ getAdminStorageLite: vi.fn(),
4
+ }));
5
+ import { runMediaTmpCleanup } from "../mediaTmpCleanup";
6
+ import { getAdminStorageLite } from "../../../../../providers/db-firebase/admin-storage-lite";
7
+ function makeCtx(envOverrides = {}) {
8
+ return {
9
+ job: "media-tmp-cleanup",
10
+ db: {},
11
+ logger: { info: vi.fn(), warn: vi.fn(), error: vi.fn() },
12
+ env: (key) => envOverrides[key],
13
+ now: new Date("2026-01-15T12:00:00Z"),
14
+ };
15
+ }
16
+ function makeFile(name, updatedOffset, cutoffBase) {
17
+ const updated = new Date(cutoffBase.getTime() + updatedOffset).toISOString();
18
+ return {
19
+ name,
20
+ getMetadata: vi.fn().mockResolvedValue([{ updated }]),
21
+ delete: vi.fn().mockResolvedValue(undefined),
22
+ };
23
+ }
24
+ function setupBucket(files) {
25
+ const bucket = {
26
+ getFiles: vi.fn().mockResolvedValue([files]),
27
+ };
28
+ getAdminStorageLite.mockReturnValue({
29
+ bucket: vi.fn(() => bucket),
30
+ });
31
+ return bucket;
32
+ }
33
+ beforeEach(() => {
34
+ vi.clearAllMocks();
35
+ delete process.env.FIREBASE_ADMIN_STORAGE_BUCKET;
36
+ delete process.env.NEXT_PUBLIC_FIREBASE_STORAGE_BUCKET;
37
+ });
38
+ describe("runMediaTmpCleanup", () => {
39
+ it("does nothing when no files exist under tmp/", async () => {
40
+ setupBucket([]);
41
+ const ctx = makeCtx();
42
+ await runMediaTmpCleanup(ctx);
43
+ // Should complete without error
44
+ });
45
+ it("skips files newer than the TTL cutoff", async () => {
46
+ // cutoff = now - 24h; file updated 1ms AFTER cutoff → not stale
47
+ const ctx = makeCtx();
48
+ const cutoff = new Date(Date.now() - 24 * 60 * 60 * 1000);
49
+ const newFile = makeFile("tmp/new-file.jpg", 1000, cutoff); // updated after cutoff
50
+ setupBucket([newFile]);
51
+ await runMediaTmpCleanup(ctx);
52
+ expect(newFile.delete).not.toHaveBeenCalled();
53
+ });
54
+ it("deletes files older than the TTL cutoff", async () => {
55
+ const ctx = makeCtx();
56
+ const cutoff = new Date(Date.now() - 24 * 60 * 60 * 1000);
57
+ const oldFile = makeFile("tmp/old-file.jpg", -1000, cutoff); // updated before cutoff
58
+ setupBucket([oldFile]);
59
+ await runMediaTmpCleanup(ctx);
60
+ expect(oldFile.delete).toHaveBeenCalledOnce();
61
+ });
62
+ it("uses MEDIA_TMP_TTL_HOURS env var to override default TTL", async () => {
63
+ const ctx = makeCtx({ MEDIA_TMP_TTL_HOURS: "1" });
64
+ // With 1h TTL, cutoff = now - 1h
65
+ // A file updated 2h ago should be deleted
66
+ const cutoff = new Date(Date.now() - 1 * 60 * 60 * 1000);
67
+ const twoHourOldFile = makeFile("tmp/old.jpg", -60 * 60 * 1000, cutoff);
68
+ setupBucket([twoHourOldFile]);
69
+ await runMediaTmpCleanup(ctx);
70
+ expect(twoHourOldFile.delete).toHaveBeenCalledOnce();
71
+ });
72
+ it("swallows 404 errors without logging them as errors", async () => {
73
+ const ctx = makeCtx();
74
+ const cutoff = new Date(Date.now() - 24 * 60 * 60 * 1000);
75
+ const staleFile = makeFile("tmp/gone.jpg", -1000, cutoff);
76
+ const notFoundErr = Object.assign(new Error("Not found"), { code: 404 });
77
+ staleFile.delete.mockRejectedValue(notFoundErr);
78
+ setupBucket([staleFile]);
79
+ await expect(runMediaTmpCleanup(ctx)).resolves.toBeUndefined();
80
+ expect(ctx.logger.error).not.toHaveBeenCalledWith("Failed to delete tmp file", expect.anything(), expect.anything());
81
+ });
82
+ it("logs a non-404 delete error but continues processing", async () => {
83
+ const ctx = makeCtx();
84
+ const cutoff = new Date(Date.now() - 24 * 60 * 60 * 1000);
85
+ const failFile = makeFile("tmp/fail.jpg", -1000, cutoff);
86
+ const okFile = makeFile("tmp/ok.jpg", -2000, cutoff);
87
+ const genericErr = Object.assign(new Error("Permission denied"), { code: 403 });
88
+ failFile.delete.mockRejectedValue(genericErr);
89
+ setupBucket([failFile, okFile]);
90
+ await runMediaTmpCleanup(ctx);
91
+ expect(ctx.logger.error).toHaveBeenCalledWith("Failed to delete tmp file", genericErr, expect.any(Object));
92
+ expect(okFile.delete).toHaveBeenCalledOnce();
93
+ });
94
+ it("skips files missing updated/timeCreated metadata", async () => {
95
+ const ctx = makeCtx();
96
+ const noMetaFile = {
97
+ name: "tmp/no-meta.jpg",
98
+ getMetadata: vi.fn().mockResolvedValue([{}]),
99
+ delete: vi.fn(),
100
+ };
101
+ setupBucket([noMetaFile]);
102
+ await runMediaTmpCleanup(ctx);
103
+ expect(noMetaFile.delete).not.toHaveBeenCalled();
104
+ });
105
+ it("throws when bucket.getFiles itself fails", async () => {
106
+ const bucket = {
107
+ getFiles: vi.fn().mockRejectedValue(new Error("Storage unavailable")),
108
+ };
109
+ getAdminStorageLite.mockReturnValue({
110
+ bucket: vi.fn(() => bucket),
111
+ });
112
+ const ctx = makeCtx();
113
+ await expect(runMediaTmpCleanup(ctx)).rejects.toThrow("Storage unavailable");
114
+ });
115
+ });
@@ -0,0 +1,96 @@
1
+ import { describe, it, expect, vi, beforeEach } from "vitest";
2
+ vi.mock("../../../../../repositories", () => ({
3
+ orderRepository: {
4
+ getTimedOutPending: vi.fn(),
5
+ cancelInBatch: vi.fn(),
6
+ },
7
+ }));
8
+ vi.mock("../../../../../features/admin/actions/notification-actions", () => ({
9
+ sendNotification: vi.fn().mockResolvedValue(undefined),
10
+ }));
11
+ vi.mock("../../handlers/messages", () => ({
12
+ ORDER_MESSAGES: {
13
+ CANCELLED_TITLE: "Order cancelled",
14
+ CANCELLED_TIMEOUT_MESSAGE: (title, hours) => `${title} cancelled after ${hours}h`,
15
+ },
16
+ }));
17
+ import { runPendingOrderTimeout } from "../pendingOrderTimeout";
18
+ import { orderRepository } from "../../../../../repositories";
19
+ import { sendNotification } from "../../../../../features/admin/actions/notification-actions";
20
+ function makeBatch() {
21
+ return { commit: vi.fn().mockResolvedValue(undefined) };
22
+ }
23
+ function makeCtxWithBatch(envOverrides = {}) {
24
+ const batch = makeBatch();
25
+ const ctx = {
26
+ job: "pending-order-timeout",
27
+ db: { batch: vi.fn(() => batch) },
28
+ logger: { info: vi.fn(), warn: vi.fn(), error: vi.fn() },
29
+ env: (key) => envOverrides[key],
30
+ now: new Date("2026-01-15T12:00:00Z"),
31
+ };
32
+ return { ctx, batch };
33
+ }
34
+ function makeCtx(envOverrides = {}) {
35
+ return makeCtxWithBatch(envOverrides).ctx;
36
+ }
37
+ beforeEach(() => {
38
+ vi.clearAllMocks();
39
+ sendNotification.mockResolvedValue(undefined);
40
+ });
41
+ describe("runPendingOrderTimeout", () => {
42
+ it("returns early when no timed-out orders exist", async () => {
43
+ orderRepository.getTimedOutPending.mockResolvedValue([]);
44
+ const ctx = makeCtx();
45
+ await runPendingOrderTimeout(ctx);
46
+ expect(ctx.db.batch).not.toHaveBeenCalled();
47
+ expect(sendNotification).not.toHaveBeenCalled();
48
+ });
49
+ it("uses DEFAULT_TIMEOUT_HOURS (24) when env var is unset", async () => {
50
+ orderRepository.getTimedOutPending.mockResolvedValue([]);
51
+ const ctx = makeCtx();
52
+ await runPendingOrderTimeout(ctx);
53
+ expect(orderRepository.getTimedOutPending).toHaveBeenCalledWith(24);
54
+ });
55
+ it("uses ORDER_TIMEOUT_HOURS from env when set", async () => {
56
+ orderRepository.getTimedOutPending.mockResolvedValue([]);
57
+ const ctx = makeCtx({ ORDER_TIMEOUT_HOURS: "48" });
58
+ await runPendingOrderTimeout(ctx);
59
+ expect(orderRepository.getTimedOutPending).toHaveBeenCalledWith(48);
60
+ });
61
+ it("cancels timed-out orders in the batch", async () => {
62
+ const ref1 = { id: "order-ref-1" };
63
+ const ref2 = { id: "order-ref-2" };
64
+ const timedOut = [
65
+ { ref: ref1, data: { userId: "u1", productTitle: "Charizard", id: "order-1" } },
66
+ { ref: ref2, data: { userId: "u2", productTitle: "Blastoise", id: "order-2" } },
67
+ ];
68
+ orderRepository.getTimedOutPending.mockResolvedValue(timedOut);
69
+ const { ctx, batch } = makeCtxWithBatch();
70
+ await runPendingOrderTimeout(ctx);
71
+ expect(orderRepository.cancelInBatch).toHaveBeenCalledTimes(2);
72
+ expect(orderRepository.cancelInBatch).toHaveBeenCalledWith(batch, ref1);
73
+ expect(orderRepository.cancelInBatch).toHaveBeenCalledWith(batch, ref2);
74
+ expect(batch.commit).toHaveBeenCalledOnce();
75
+ });
76
+ it("sends a notification for each cancelled order", async () => {
77
+ const timedOut = [
78
+ { ref: {}, data: { userId: "u1", productTitle: "Charizard", id: "order-1" } },
79
+ { ref: {}, data: { userId: "u2", productTitle: "Blastoise", id: "order-2" } },
80
+ ];
81
+ orderRepository.getTimedOutPending.mockResolvedValue(timedOut);
82
+ const ctx = makeCtx();
83
+ await runPendingOrderTimeout(ctx);
84
+ expect(sendNotification).toHaveBeenCalledTimes(2);
85
+ expect(sendNotification).toHaveBeenCalledWith(expect.objectContaining({ userId: "u1", type: "order_cancelled", relatedId: "order-1" }));
86
+ });
87
+ it("does not throw when a notification fails (Promise.allSettled)", async () => {
88
+ const timedOut = [
89
+ { ref: {}, data: { userId: "u1", productTitle: "Pikachu", id: "order-x" } },
90
+ ];
91
+ orderRepository.getTimedOutPending.mockResolvedValue(timedOut);
92
+ sendNotification.mockRejectedValue(new Error("Notification failed"));
93
+ const ctx = makeCtx();
94
+ await expect(runPendingOrderTimeout(ctx)).resolves.toBeUndefined();
95
+ });
96
+ });
package/dist/client.d.ts CHANGED
@@ -57,6 +57,8 @@ export type { SessionProviderProps } from "./react/contexts/SessionContext";
57
57
  export { ThemeProvider } from "./react/contexts/ThemeContext";
58
58
  export { useUrlTable } from "./react/hooks/useUrlTable";
59
59
  export type { UseUrlTableOptions } from "./react/hooks/useUrlTable";
60
+ export { useBulkSelection } from "./react/hooks/useBulkSelection";
61
+ export type { UseBulkSelectionOptions, UseBulkSelectionReturn } from "./react/hooks/useBulkSelection";
60
62
  export { ROUTES, PUBLIC_ROUTES, PROTECTED_ROUTES, AUTH_ROUTES } from "./constants/index";
61
63
  export { Container, Grid, Row, Stack } from "./ui/components/Layout";
62
64
  export { Div } from "./ui/components/Div";
@@ -99,9 +101,11 @@ export { ZodSetup } from "./validation/ZodSetup";
99
101
  export type { ZodSetupProps } from "./validation/ZodSetup";
100
102
  export { AdminSidebar } from "./features/admin/components/AdminSidebar";
101
103
  export type { AdminSidebarProps, AdminNavItem, AdminNavGroup } from "./features/admin/components/AdminSidebar";
102
- export { AdminDashboardView, AdminAnalyticsView, AdminListingScaffold, AdminPrizeDrawsView, useAdminListingData, toRecordArray, toStringValue, toRelativeDate, toRupees } from "./features/admin/index";
103
- export type { AdminDashboardViewProps, AdminAnalyticsViewProps, AdminAnalyticsViewLabels, AdminPrizeDrawsViewProps } from "./features/admin/index";
104
+ export { AdminDashboardView, AdminAnalyticsView, AdminListingScaffold, AdminPrizeDrawsView, AdminCarouselView, AdminSublistingCategoriesView, DataTable, useAdminListingData, toRecordArray, toStringValue, toRelativeDate, toRupees } from "./features/admin/index";
105
+ export type { AdminDashboardViewProps, AdminAnalyticsViewProps, AdminAnalyticsViewLabels, AdminPrizeDrawsViewProps, AdminCarouselViewProps } from "./features/admin/index";
106
+ export type { BulkActionItem } from "./ui/components/BulkActionBar";
104
107
  export { ADMIN_ENDPOINTS } from "./constants/index";
108
+ export { apiClient, ApiClientError } from "./http/index";
105
109
  export { UserSidebar } from "./features/account/components/UserSidebar";
106
110
  export type { UserSidebarProps, UserNavItem, UserNavGroup } from "./features/account/components/UserSidebar";
107
111
  export { CouponsIndexListing } from "./features/promotions/components/CouponsIndexListing";
@@ -122,10 +126,9 @@ export type { Address, AddressFormData } from "./features/account/index";
122
126
  export { AddressBook, AddressCard, AddressForm } from "./features/account/index";
123
127
  export type { AddressCardAddress, AddressCardProps } from "./features/account/index";
124
128
  export { useProfile, useUpdateProfile } from "./features/account/index";
125
- export { CategoryProductsView, CategoriesListView } from "./features/categories/index";
129
+ export { CategoryProductsView } from "./features/categories/index";
126
130
  export type { CategoryItem } from "./features/categories/index";
127
131
  export { MediaImage } from "./features/media/index";
128
- export { ReviewsListView } from "./features/reviews/index";
129
132
  export { StoreSidebar, SellerSidebar } from "./features/seller/components/SellerSidebar";
130
133
  export type { StoreNavItem, StoreNavGroup, SellerNavItem } from "./features/seller/components/SellerSidebar";
131
134
  export { StoreProductsView, StoreAboutView } from "./features/stores/index";
@@ -147,6 +150,8 @@ export type { WishlistCapEventDetail } from "./features/wishlist/hooks/useWishli
147
150
  export { getGuestWishlistItems, addToGuestWishlist, removeFromGuestWishlist, isInGuestWishlist, clearGuestWishlist, getGuestWishlistCount, getGuestWishlistByType, } from "./features/wishlist/utils/guest-wishlist";
148
151
  export { InteractiveProductCard } from "./features/products/index";
149
152
  export type { InteractiveProductCardProps } from "./features/products/index";
153
+ export { MarketplaceBundleCard } from "./features/products/components/MarketplaceBundleCard";
154
+ export type { MarketplaceBundleCardProps, MarketplaceBundleCardData, MarketplaceBundleCardLabels, } from "./features/products/components/MarketplaceBundleCard";
150
155
  export { CompareOverlay } from "./features/products/components/CompareOverlay";
151
156
  export type { CompareOverlayProps, CompareOverlayLabels, CompareProductLike, } from "./features/products/components/CompareOverlay";
152
157
  export { COMPARE_MAX_ITEMS } from "./features/products/constants/action-defs";
@@ -189,8 +194,8 @@ export { UserOffersPanel } from "./features/account/components/UserOffersPanel";
189
194
  export type { UserOffersPanelProps } from "./features/account/components/UserOffersPanel";
190
195
  export { SellerDashboardView as StoreDashboardView, SellerDashboardView, useSellerDashboard as useStoreDashboard, useSellerDashboard } from "./features/seller/index";
191
196
  export type { SellerDashboardViewProps as StoreDashboardViewProps, SellerDashboardViewProps } from "./features/seller/index";
192
- export { SellerPayoutSettingsView, SellerShippingView, SellerReviewsView, SellerPayoutRequestView, SellerAnalyticsStats, SellerTopProducts, SellerAnalyticsView, SellerPayoutsView, SellerCouponEditorView, SellerBidsView, SellerAddressesView, SellerPreOrdersView, SellerPrizeDrawsView, PrintCenterView } from "./features/seller/components/index";
193
- export type { SellerPayoutSettingsViewProps, SellerShippingViewProps, SellerReviewsViewProps, SellerPayoutRequestViewProps, SellerAnalyticsViewProps, SellerPayoutsViewProps, SellerCouponEditorViewProps, CouponEditorDraft, SellerBidsViewProps, SellerAddressesViewProps, SellerPreOrdersViewProps, SellerPrizeDrawsViewProps } from "./features/seller/components/index";
197
+ export { SellerPayoutSettingsView, SellerShippingView, SellerReviewsView, SellerPayoutRequestView, SellerAnalyticsStats, SellerTopProducts, SellerAnalyticsView, SellerPayoutsView, SellerCouponEditorView, SellerBidsView, SellerAddressesView, SellerPreOrdersView, SellerPrizeDrawsView, PrintCenterView, SellerOffersView, SellerGroupedListingsView, StoreGroupedListingsView, SellerAnalyticsAlertsView, StoreAnalyticsAlertsView } from "./features/seller/components/index";
198
+ export type { SellerPayoutSettingsViewProps, SellerShippingViewProps, SellerReviewsViewProps, SellerPayoutRequestViewProps, SellerAnalyticsViewProps, SellerPayoutsViewProps, SellerCouponEditorViewProps, CouponEditorDraft, SellerBidsViewProps, SellerAddressesViewProps, SellerPreOrdersViewProps, SellerPrizeDrawsViewProps, SellerOffersViewProps, SellerGroupedListingsViewProps, SellerAnalyticsAlertsViewProps } from "./features/seller/components/index";
194
199
  export type { SellerAnalyticsSummary, SellerAnalyticsTopProduct } from "./features/seller/types/index";
195
200
  export { UserAccountHubView, UserOrdersView, OrderDetailView, UserNotificationsView, UserReturnsView, UserSupportView, useNotifications } from "./features/account/index";
196
201
  export type { UserAccountHubViewProps, UserAccountHubViewLabels, UserOrdersViewProps, UserOrdersViewLabels, OrderDetailViewProps, OrderDetailViewLabels, UserNotificationsViewProps, UserNotificationsViewLabels, UserReturnsViewProps, UserReturnsViewLabels, UserSupportViewProps } from "./features/account/index";
@@ -248,3 +253,21 @@ export { PhysicalLocationModal } from "./features/seller/components/PhysicalLoca
248
253
  export type { PhysicalLocation } from "./features/seller/components/PhysicalLocationModal";
249
254
  export { Toggle } from "./ui/components/Toggle";
250
255
  export type { ToggleProps } from "./ui/components/Toggle";
256
+ export { SellerStoreCategoriesView } from "./features/seller/components/SellerStoreCategoriesView";
257
+ export type { SellerStoreCategoriesViewProps } from "./features/seller/components/SellerStoreCategoriesView";
258
+ export { SellerTemplatesView } from "./features/seller/components/SellerTemplatesView";
259
+ export type { SellerTemplatesViewProps } from "./features/seller/components/SellerTemplatesView";
260
+ export { SellerPayoutMethodsView } from "./features/seller/components/SellerPayoutMethodsView";
261
+ export type { SellerPayoutMethodsViewProps } from "./features/seller/components/SellerPayoutMethodsView";
262
+ export { SellerShippingConfigsView } from "./features/seller/components/SellerShippingConfigsView";
263
+ export type { SellerShippingConfigsViewProps } from "./features/seller/components/SellerShippingConfigsView";
264
+ export { SellerGoogleReviewsView } from "./features/seller/components/SellerGoogleReviewsView";
265
+ export type { SellerGoogleReviewsViewProps } from "./features/seller/components/SellerGoogleReviewsView";
266
+ export { SellerBundlesView } from "./features/seller/components/SellerBundlesView";
267
+ export type { SellerBundlesViewProps } from "./features/seller/components/SellerBundlesView";
268
+ export { SellerClassifiedView } from "./features/seller/components/SellerClassifiedView";
269
+ export type { SellerClassifiedViewProps } from "./features/seller/components/SellerClassifiedView";
270
+ export { SellerDigitalCodesView } from "./features/seller/components/SellerDigitalCodesView";
271
+ export type { SellerDigitalCodesViewProps } from "./features/seller/components/SellerDigitalCodesView";
272
+ export { SellerLiveView } from "./features/seller/components/SellerLiveView";
273
+ export type { SellerLiveViewProps } from "./features/seller/components/SellerLiveView";
package/dist/client.js CHANGED
@@ -121,6 +121,7 @@ export { useMediaUpload } from "./features/media/index";
121
121
  export { SessionProvider, useSession } from "./react/contexts/SessionContext";
122
122
  export { ThemeProvider } from "./react/contexts/ThemeContext";
123
123
  export { useUrlTable } from "./react/hooks/useUrlTable";
124
+ export { useBulkSelection } from "./react/hooks/useBulkSelection";
124
125
  // Client-safe constants, UI primitives, and views
125
126
  export { ROUTES, PUBLIC_ROUTES, PROTECTED_ROUTES, AUTH_ROUTES } from "./constants/index";
126
127
  export { Container, Grid, Row, Stack } from "./ui/components/Layout";
@@ -149,8 +150,9 @@ export { Search } from "./features/search/components";
149
150
  export { ToastProvider, SkipToMain, NavigationLoader } from "./ui/index";
150
151
  export { ZodSetup } from "./validation/ZodSetup";
151
152
  export { AdminSidebar } from "./features/admin/components/AdminSidebar";
152
- export { AdminDashboardView, AdminAnalyticsView, AdminListingScaffold, AdminPrizeDrawsView, useAdminListingData, toRecordArray, toStringValue, toRelativeDate, toRupees } from "./features/admin/index";
153
+ export { AdminDashboardView, AdminAnalyticsView, AdminListingScaffold, AdminPrizeDrawsView, AdminCarouselView, AdminSublistingCategoriesView, DataTable, useAdminListingData, toRecordArray, toStringValue, toRelativeDate, toRupees } from "./features/admin/index";
153
154
  export { ADMIN_ENDPOINTS } from "./constants/index";
155
+ export { apiClient, ApiClientError } from "./http/index";
154
156
  export { UserSidebar } from "./features/account/components/UserSidebar";
155
157
  export { CouponsIndexListing } from "./features/promotions/components/CouponsIndexListing";
156
158
  export { NotificationBell } from "./features/account/components/NotificationBell";
@@ -162,9 +164,8 @@ export { CartView, CartItemRow, CartSummary, CartDrawer, CheckoutView, CheckoutS
162
164
  export { useAddresses, useCreateAddress, useUpdateAddress, useDeleteAddress, useSetDefaultAddress, useAddress } from "./features/account/index";
163
165
  export { AddressBook, AddressCard, AddressForm } from "./features/account/index";
164
166
  export { useProfile, useUpdateProfile } from "./features/account/index";
165
- export { CategoryProductsView, CategoriesListView } from "./features/categories/index";
167
+ export { CategoryProductsView } from "./features/categories/index";
166
168
  export { MediaImage } from "./features/media/index";
167
- export { ReviewsListView } from "./features/reviews/index";
168
169
  export { StoreSidebar, SellerSidebar } from "./features/seller/components/SellerSidebar";
169
170
  export { StoreProductsView, StoreAboutView } from "./features/stores/index";
170
171
  export { SearchView } from "./features/search/index";
@@ -177,6 +178,7 @@ export { WishlistCapWatcher } from "./features/wishlist/components/WishlistCapWa
177
178
  export { useWishlistCount, useWishlistCountWithLimit, WISHLIST_CAP_EVENT } from "./features/wishlist/hooks/useWishlistCount";
178
179
  export { getGuestWishlistItems, addToGuestWishlist, removeFromGuestWishlist, isInGuestWishlist, clearGuestWishlist, getGuestWishlistCount, getGuestWishlistByType, } from "./features/wishlist/utils/guest-wishlist";
179
180
  export { InteractiveProductCard } from "./features/products/index";
181
+ export { MarketplaceBundleCard } from "./features/products/components/MarketplaceBundleCard";
180
182
  export { CompareOverlay } from "./features/products/components/CompareOverlay";
181
183
  export { COMPARE_MAX_ITEMS } from "./features/products/constants/action-defs";
182
184
  // Messages — RTDB-pinged Firestore conversations (D5 + VC7)
@@ -208,7 +210,7 @@ export { FeatureBadge, FeatureBadgeList } from "./features/products/components/F
208
210
  export { SellerOffersPanel } from "./features/seller/components/SellerOffersPanel";
209
211
  export { UserOffersPanel } from "./features/account/components/UserOffersPanel";
210
212
  export { SellerDashboardView as StoreDashboardView, SellerDashboardView, useSellerDashboard as useStoreDashboard, useSellerDashboard } from "./features/seller/index";
211
- export { SellerPayoutSettingsView, SellerShippingView, SellerReviewsView, SellerPayoutRequestView, SellerAnalyticsStats, SellerTopProducts, SellerAnalyticsView, SellerPayoutsView, SellerCouponEditorView, SellerBidsView, SellerAddressesView, SellerPreOrdersView, SellerPrizeDrawsView, PrintCenterView } from "./features/seller/components/index";
213
+ export { SellerPayoutSettingsView, SellerShippingView, SellerReviewsView, SellerPayoutRequestView, SellerAnalyticsStats, SellerTopProducts, SellerAnalyticsView, SellerPayoutsView, SellerCouponEditorView, SellerBidsView, SellerAddressesView, SellerPreOrdersView, SellerPrizeDrawsView, PrintCenterView, SellerOffersView, SellerGroupedListingsView, StoreGroupedListingsView, SellerAnalyticsAlertsView, StoreAnalyticsAlertsView } from "./features/seller/components/index";
212
214
  export { UserAccountHubView, UserOrdersView, OrderDetailView, UserNotificationsView, UserReturnsView, UserSupportView, useNotifications } from "./features/account/index";
213
215
  export { useOrders, useOrder, OrdersList } from "./features/orders/index";
214
216
  export { useCouponValidate } from "./features/promotions/hooks/useCouponValidate";
@@ -258,3 +260,13 @@ export { LiveItemDetailView } from "./_internal/client/features/live/LiveItemDet
258
260
  export { PhysicalLocationModal } from "./features/seller/components/PhysicalLocationModal";
259
261
  // [CLIENT-ONLY] — Toggle switch primitive.
260
262
  export { Toggle } from "./ui/components/Toggle";
263
+ // [CLIENT] Wave 4 seller management views.
264
+ export { SellerStoreCategoriesView } from "./features/seller/components/SellerStoreCategoriesView";
265
+ export { SellerTemplatesView } from "./features/seller/components/SellerTemplatesView";
266
+ export { SellerPayoutMethodsView } from "./features/seller/components/SellerPayoutMethodsView";
267
+ export { SellerShippingConfigsView } from "./features/seller/components/SellerShippingConfigsView";
268
+ export { SellerGoogleReviewsView } from "./features/seller/components/SellerGoogleReviewsView";
269
+ export { SellerBundlesView } from "./features/seller/components/SellerBundlesView";
270
+ export { SellerClassifiedView } from "./features/seller/components/SellerClassifiedView";
271
+ export { SellerDigitalCodesView } from "./features/seller/components/SellerDigitalCodesView";
272
+ export { SellerLiveView } from "./features/seller/components/SellerLiveView";