@mohasinac/appkit 4.53.0 → 4.53.2
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/.build-stamp.json +3 -3
- package/dist/_internal/client/scaffolds/AppShell.js +1 -1
- package/dist/_internal/client/theme/ThemeProvider.js +15 -1
- package/dist/_internal/server/features/auctions/og.d.ts +3 -1
- package/dist/_internal/server/features/auctions/og.js +3 -1
- package/dist/_internal/server/features/bundles/actions.js +1 -1
- package/dist/_internal/server/features/business-documents/download.d.ts +41 -0
- package/dist/_internal/server/features/business-documents/download.js +91 -0
- package/dist/_internal/server/features/categories/adapters.d.ts +1 -1
- package/dist/_internal/server/features/categories/adapters.js +10 -0
- package/dist/_internal/server/features/categories/price-guidance-resolve.d.ts +66 -0
- package/dist/_internal/server/features/categories/price-guidance-resolve.js +138 -0
- package/dist/_internal/server/features/checkout/actions.d.ts +14 -0
- package/dist/_internal/server/features/checkout/actions.js +106 -12
- package/dist/_internal/server/features/checkout/bundle-expansion.js +17 -0
- package/dist/_internal/server/features/checkout/data.d.ts +22 -0
- package/dist/_internal/server/features/checkout/group-rule-revalidation.d.ts +34 -0
- package/dist/_internal/server/features/checkout/group-rule-revalidation.js +124 -0
- package/dist/_internal/server/features/checkout/supplier-identity.d.ts +55 -0
- package/dist/_internal/server/features/checkout/supplier-identity.js +81 -0
- package/dist/_internal/server/features/classified/metadata.js +1 -1
- package/dist/_internal/server/features/classified/og.d.ts +3 -1
- package/dist/_internal/server/features/classified/og.js +3 -1
- package/dist/_internal/server/features/digital-code/metadata.js +1 -1
- package/dist/_internal/server/features/digital-code/og.d.ts +3 -1
- package/dist/_internal/server/features/digital-code/og.js +3 -1
- package/dist/_internal/server/features/digital-code/pool.d.ts +19 -4
- package/dist/_internal/server/features/digital-code/pool.js +19 -4
- package/dist/_internal/server/features/live/metadata.js +1 -1
- package/dist/_internal/server/features/live/og.d.ts +3 -1
- package/dist/_internal/server/features/live/og.js +3 -1
- package/dist/_internal/server/features/messages/actions.js +1 -1
- package/dist/_internal/server/features/parts/og.js +1 -1
- package/dist/_internal/server/features/pre-orders/og.d.ts +3 -1
- package/dist/_internal/server/features/pre-orders/og.js +3 -1
- package/dist/_internal/server/features/price-index/market.d.ts +57 -0
- package/dist/_internal/server/features/price-index/market.js +120 -0
- package/dist/_internal/server/features/price-index/search.d.ts +18 -0
- package/dist/_internal/server/features/price-index/search.js +47 -7
- package/dist/_internal/server/features/prize-draws/og.d.ts +3 -1
- package/dist/_internal/server/features/prize-draws/og.js +3 -1
- package/dist/_internal/server/features/products/group-members.d.ts +26 -0
- package/dist/_internal/server/features/products/group-members.js +7 -1
- package/dist/_internal/server/features/products/list-public.d.ts +12 -0
- package/dist/_internal/server/features/products/list-public.js +10 -1
- package/dist/_internal/server/features/products/listing-tab-counts.d.ts +25 -1
- package/dist/_internal/server/features/products/listing-tab-counts.js +128 -10
- package/dist/_internal/server/features/products/og.d.ts +3 -1
- package/dist/_internal/server/features/products/og.js +3 -1
- package/dist/_internal/server/features/search/scoped-sources.d.ts +26 -0
- package/dist/_internal/server/features/search/scoped-sources.js +252 -0
- package/dist/_internal/server/features/search/search-everything.d.ts +57 -0
- package/dist/_internal/server/features/search/search-everything.js +70 -20
- package/dist/_internal/server/features/seo/sitemap.js +6 -0
- package/dist/_internal/server/features/shared/listing-adapters.js +4 -2
- package/dist/_internal/server/features/sticker-trace/adapters.d.ts +11 -0
- package/dist/_internal/server/features/sticker-trace/adapters.js +1 -0
- package/dist/_internal/server/features/sticker-trace/promote-to-listings.d.ts +26 -0
- package/dist/_internal/server/features/sticker-trace/promote-to-listings.js +264 -0
- package/dist/_internal/server/features/sticker-trace/sheet-actions.d.ts +3 -1
- package/dist/_internal/server/features/sticker-trace/sheet-actions.js +32 -0
- package/dist/_internal/server/features/sticker-trace/storage.d.ts +20 -1
- package/dist/_internal/server/features/sticker-trace/storage.js +20 -1
- package/dist/_internal/server/features/stores/adapters.d.ts +1 -1
- package/dist/_internal/server/features/stores/adapters.js +16 -0
- package/dist/_internal/server/features/stores/index.d.ts +1 -0
- package/dist/_internal/server/features/stores/index.js +1 -0
- package/dist/_internal/server/features/stores/tabs.d.ts +30 -0
- package/dist/_internal/server/features/stores/tabs.js +124 -0
- package/dist/_internal/shared/checkout/rules/_defaults.js +0 -2
- package/dist/_internal/shared/checkout/rules/_limits.d.ts +14 -1
- package/dist/_internal/shared/checkout/rules/_limits.js +14 -1
- package/dist/_internal/shared/checkout/rules/_registry.js +2 -0
- package/dist/_internal/shared/checkout/rules/auction.rule.js +9 -1
- package/dist/_internal/shared/checkout/rules/bundle.rule.js +13 -0
- package/dist/_internal/shared/checkout/rules/index.d.ts +2 -0
- package/dist/_internal/shared/checkout/rules/index.js +9 -0
- package/dist/_internal/shared/checkout/rules/offer.rule.js +0 -1
- package/dist/_internal/shared/checkout/rules/payment-gate.d.ts +26 -0
- package/dist/_internal/shared/checkout/rules/payment-gate.js +133 -0
- package/dist/_internal/shared/checkout/rules/prize-draw.rule.js +29 -8
- package/dist/_internal/shared/checkout/rules/spares.rule.d.ts +16 -0
- package/dist/_internal/shared/checkout/rules/spares.rule.js +5 -0
- package/dist/_internal/shared/checkout/rules/types.d.ts +26 -2
- package/dist/_internal/shared/config/schema.d.ts +122 -0
- package/dist/_internal/shared/features/cart/schema.js +3 -2
- package/dist/_internal/shared/features/products/group-rules.d.ts +75 -0
- package/dist/_internal/shared/features/products/group-rules.js +142 -0
- package/dist/_internal/shared/listing-types/_registry.d.ts +24 -0
- package/dist/_internal/shared/listing-types/_registry.js +39 -1
- package/dist/_internal/shared/listing-types/art/config.d.ts +1 -0
- package/dist/_internal/shared/listing-types/art/config.js +2 -0
- package/dist/_internal/shared/listing-types/auction/config.d.ts +1 -0
- package/dist/_internal/shared/listing-types/auction/config.js +2 -0
- package/dist/_internal/shared/listing-types/availability.js +48 -0
- package/dist/_internal/shared/listing-types/capabilities.js +19 -0
- package/dist/_internal/shared/listing-types/classified/config.d.ts +1 -0
- package/dist/_internal/shared/listing-types/classified/config.js +2 -0
- package/dist/_internal/shared/listing-types/digital-code/config.d.ts +1 -0
- package/dist/_internal/shared/listing-types/digital-code/config.js +2 -0
- package/dist/_internal/shared/listing-types/feature-flags.js +1 -0
- package/dist/_internal/shared/listing-types/live/config.d.ts +1 -0
- package/dist/_internal/shared/listing-types/live/config.js +2 -0
- package/dist/_internal/shared/listing-types/pre-order/config.d.ts +1 -0
- package/dist/_internal/shared/listing-types/pre-order/config.js +2 -0
- package/dist/_internal/shared/listing-types/prize-draw/config.d.ts +1 -0
- package/dist/_internal/shared/listing-types/prize-draw/config.js +2 -0
- package/dist/_internal/shared/listing-types/spares/config.d.ts +74 -0
- package/dist/_internal/shared/listing-types/spares/config.js +60 -0
- package/dist/_internal/shared/listing-types/spares/ctas.d.ts +1 -0
- package/dist/_internal/shared/listing-types/spares/ctas.js +4 -0
- package/dist/_internal/shared/listing-types/spares/og.js +1 -0
- package/dist/_internal/shared/listing-types/spares/schema.d.ts +2 -0
- package/dist/_internal/shared/listing-types/spares/schema.js +3 -0
- package/dist/_internal/shared/listing-types/spares/seed-factory.d.ts +1 -0
- package/dist/_internal/shared/listing-types/spares/seed-factory.js +1 -0
- package/dist/_internal/shared/listing-types/standard/config.d.ts +1 -0
- package/dist/_internal/shared/listing-types/standard/config.js +2 -0
- package/dist/_internal/shared/listing-types/stickers/config.d.ts +1 -0
- package/dist/_internal/shared/listing-types/stickers/config.js +2 -0
- package/dist/_internal/shared/search/match.d.ts +11 -0
- package/dist/_internal/shared/search/match.js +30 -3
- package/dist/_internal/shared/search/to-groups.d.ts +52 -0
- package/dist/_internal/shared/search/to-groups.js +141 -0
- package/dist/client.d.ts +8 -2
- package/dist/client.js +4 -1
- package/dist/constants/api-endpoints.d.ts +46 -15
- package/dist/constants/api-endpoints.js +35 -5
- package/dist/constants/cache-invalidation.js +3 -1
- package/dist/constants/field-names.d.ts +6 -0
- package/dist/constants/field-names.js +6 -0
- package/dist/features/about/components/PolicyPageView.d.ts +22 -2
- package/dist/features/about/components/PolicyPageView.js +14 -2
- package/dist/features/about/components/PublicProfileView.js +2 -1
- package/dist/features/about/components/ShippingPolicyView.js +42 -2
- package/dist/features/account/components/NotificationBell.js +1 -1
- package/dist/features/account/hooks/useProfileStats.js +5 -1
- package/dist/features/addresses/repository/addresses.repository.d.ts +16 -0
- package/dist/features/addresses/repository/addresses.repository.js +21 -0
- package/dist/features/admin/actions/admin-actions.js +16 -1
- package/dist/features/admin/components/AdminCategoryEditorView.js +19 -2
- package/dist/features/admin/components/AdminNavigationView.js +1 -1
- package/dist/features/admin/components/AdminPageHeader.js +1 -1
- package/dist/features/admin/components/AdminProductEditorView.js +17 -2
- package/dist/features/admin/components/AdminSidebar.js +1 -1
- package/dist/features/admin/components/AdminSiteSettingsView.js +39 -8
- package/dist/features/admin/components/AdminSparesView.d.ts +12 -0
- package/dist/features/admin/components/AdminSparesView.js +30 -0
- package/dist/features/admin/components/AdminUsersView.js +9 -7
- package/dist/features/admin/components/index.d.ts +2 -0
- package/dist/features/admin/components/index.js +1 -0
- package/dist/features/admin/components/sections/adminSectionsTypes.js +7 -0
- package/dist/features/admin/constants/filter-tabs.d.ts +3 -0
- package/dist/features/admin/constants/filter-tabs.js +1 -0
- package/dist/features/admin/schemas/firestore.d.ts +26 -2
- package/dist/features/auctions/components/AuctionDetailPageView.js +12 -18
- package/dist/features/auth/repository/user.repository.d.ts +13 -0
- package/dist/features/auth/repository/user.repository.js +28 -0
- package/dist/features/auth/schemas/firestore.d.ts +2 -0
- package/dist/features/auth/schemas/firestore.js +2 -0
- package/dist/features/business-documents/repository/business-documents.repository.d.ts +58 -0
- package/dist/features/business-documents/repository/business-documents.repository.js +54 -0
- package/dist/features/business-documents/schemas/firestore.d.ts +105 -0
- package/dist/features/business-documents/schemas/firestore.js +75 -0
- package/dist/features/cart/actions/cart-actions.js +83 -6
- package/dist/features/cart/repository/cart.repository.js +32 -4
- package/dist/features/cart/schemas/firestore.d.ts +20 -0
- package/dist/features/cart/schemas/index.d.ts +2 -2
- package/dist/features/catalogue/components/PublicCatalogueItemDetailView.js +1 -1
- package/dist/features/categories/api/[id]/price-guidance/route.d.ts +42 -0
- package/dist/features/categories/api/[id]/price-guidance/route.js +90 -0
- package/dist/features/categories/components/BrandDetailPageView.js +32 -8
- package/dist/features/categories/components/BrandDetailTabs.d.ts +7 -1
- package/dist/features/categories/components/BrandDetailTabs.js +28 -3
- package/dist/features/categories/components/BundleCollage.js +3 -2
- package/dist/features/categories/components/BundleItemsPicker.js +3 -4
- package/dist/features/categories/components/CategoriesIndexListing.js +23 -8
- package/dist/features/categories/components/CategoryDetailPageView.js +157 -20
- package/dist/features/categories/components/CategoryDetailTabs.d.ts +7 -1
- package/dist/features/categories/components/CategoryDetailTabs.js +41 -7
- package/dist/features/categories/components/CategoryGrid.js +10 -1
- package/dist/features/categories/components/PriceGuidanceHint.d.ts +29 -0
- package/dist/features/categories/components/PriceGuidanceHint.js +61 -0
- package/dist/features/categories/components/SubcategoryCardRow.d.ts +27 -0
- package/dist/features/categories/components/SubcategoryCardRow.js +98 -0
- package/dist/features/categories/constants/category-tabs.d.ts +20 -25
- package/dist/features/categories/constants/category-tabs.js +22 -39
- package/dist/features/categories/repository/categories.repository.d.ts +12 -0
- package/dist/features/categories/repository/categories.repository.js +20 -0
- package/dist/features/categories/schemas/firestore.d.ts +22 -1
- package/dist/features/categories/schemas/firestore.js +10 -0
- package/dist/features/categories/schemas/index.d.ts +6 -0
- package/dist/features/categories/schemas/index.js +2 -0
- package/dist/features/categories/types/index.d.ts +8 -0
- package/dist/features/categories/utils/taxonomy-visual.d.ts +16 -3
- package/dist/features/categories/utils/taxonomy-visual.js +26 -10
- package/dist/features/classified/components/ClassifiedDetailPageView.js +14 -10
- package/dist/features/contact/components/ContactPageView.d.ts +33 -1
- package/dist/features/contact/components/ContactPageView.js +58 -28
- package/dist/features/digital-codes/components/DigitalCodeDetailPageView.js +14 -10
- package/dist/features/grouped/components/GroupedListingDetailView.js +9 -1
- package/dist/features/grouped/schemas/firestore.d.ts +5 -0
- package/dist/features/homepage/actions/homepage-section-actions.d.ts +3 -3
- package/dist/features/homepage/components/CollectionCardsSection.d.ts +28 -6
- package/dist/features/homepage/components/CollectionCardsSection.js +43 -8
- package/dist/features/homepage/components/HowItWorksSection.d.ts +23 -6
- package/dist/features/homepage/components/HowItWorksSection.js +4 -4
- package/dist/features/homepage/components/PromoGrid.d.ts +31 -2
- package/dist/features/homepage/components/PromoGrid.js +12 -3
- package/dist/features/homepage/components/TestimonialsCarousel.d.ts +34 -2
- package/dist/features/homepage/components/TestimonialsCarousel.js +1 -1
- package/dist/features/homepage/components/index.d.ts +0 -20
- package/dist/features/homepage/components/index.js +0 -11
- package/dist/features/homepage/index.d.ts +0 -2
- package/dist/features/homepage/index.js +0 -2
- package/dist/features/homepage/lib/section-renderer.d.ts +9 -0
- package/dist/features/homepage/lib/section-renderer.js +202 -58
- package/dist/features/homepage/repository/homepage-sections.repository.d.ts +35 -3
- package/dist/features/homepage/repository/homepage-sections.repository.js +58 -8
- package/dist/features/homepage/schemas/firestore.d.ts +106 -3
- package/dist/features/homepage/schemas/firestore.js +32 -2
- package/dist/features/homepage/schemas/index.d.ts +36 -7
- package/dist/features/homepage/schemas/index.js +39 -27
- package/dist/features/homepage/server.d.ts +0 -3
- package/dist/features/homepage/server.js +0 -3
- package/dist/features/homepage/types/index.d.ts +0 -47
- package/dist/features/homepage/types/index.js +49 -0
- package/dist/features/layout/AppLayoutShell.js +1 -1
- package/dist/features/layout/BottomNavItem.js +1 -1
- package/dist/features/layout/BottomSheet.js +1 -1
- package/dist/features/layout/TitleBarLayout.js +1 -1
- package/dist/features/live/components/LiveItemDetailPageView.js +14 -10
- package/dist/features/media/hooks/useMedia.js +17 -0
- package/dist/features/media/repository/media-assets.repository.d.ts +46 -0
- package/dist/features/media/repository/media-assets.repository.js +31 -0
- package/dist/features/media/trust-signals.d.ts +85 -0
- package/dist/features/media/trust-signals.js +126 -0
- package/dist/features/parts/components/PartDetailPageView.d.ts +14 -1
- package/dist/features/parts/components/PartDetailPageView.js +2 -2
- package/dist/features/parts/components/PartsIndexPageView.d.ts +11 -2
- package/dist/features/parts/components/PartsIndexPageView.js +2 -2
- package/dist/features/parts/components/PartsSearchBox.d.ts +9 -0
- package/dist/features/parts/components/PartsSearchBox.js +57 -0
- package/dist/features/parts/schemas/firestore.d.ts +149 -3
- package/dist/features/parts/schemas/firestore.js +184 -0
- package/dist/features/payments/repository/payout.repository.d.ts +15 -0
- package/dist/features/payments/repository/payout.repository.js +21 -0
- package/dist/features/pre-orders/components/PreOrderDetailPageView.js +12 -18
- package/dist/features/pre-orders/components/PreOrdersIndexListing.js +1 -1
- package/dist/features/price-index/components/PriceIndexToolView.d.ts +24 -1
- package/dist/features/price-index/components/PriceIndexToolView.js +299 -17
- package/dist/features/price-index/lookup-target.d.ts +48 -0
- package/dist/features/price-index/lookup-target.js +107 -0
- package/dist/features/products/components/AvailabilityScopeHint.d.ts +22 -0
- package/dist/features/products/components/AvailabilityScopeHint.js +27 -0
- package/dist/features/products/components/CompareOverlay.d.ts +20 -2
- package/dist/features/products/components/CompareOverlay.js +23 -3
- package/dist/features/products/components/CustomSectionTabContent.d.ts +31 -0
- package/dist/features/products/components/CustomSectionTabContent.js +29 -3
- package/dist/features/products/components/GroupMemberPicker.d.ts +19 -1
- package/dist/features/products/components/GroupMemberPicker.js +46 -8
- package/dist/features/products/components/GroupSettingsPanel.d.ts +11 -1
- package/dist/features/products/components/GroupSettingsPanel.js +92 -3
- package/dist/features/products/components/PrizeDrawDetailPageView.js +1 -1
- package/dist/features/products/components/PrizeDrawEntryActions.d.ts +15 -1
- package/dist/features/products/components/PrizeDrawEntryActions.js +70 -8
- package/dist/features/products/components/ProductDetailPageView.js +81 -17
- package/dist/features/products/components/ProductForm.d.ts +13 -1
- package/dist/features/products/components/ProductForm.js +16 -2
- package/dist/features/products/components/ProductsIndexListing.d.ts +16 -1
- package/dist/features/products/components/ProductsIndexListing.js +3 -3
- package/dist/features/products/components/ShowGroupSection.js +15 -2
- package/dist/features/products/components/SparesListView.d.ts +7 -0
- package/dist/features/products/components/SparesListView.js +39 -0
- package/dist/features/products/components/SublistingCarouselSection.js +2 -1
- package/dist/features/products/constants/action-defs.d.ts +1 -0
- package/dist/features/products/constants/action-defs.js +1 -0
- package/dist/features/products/repository/products.repository.d.ts +99 -0
- package/dist/features/products/repository/products.repository.js +240 -18
- package/dist/features/products/schemas/firestore.d.ts +97 -4
- package/dist/features/products/schemas/firestore.js +104 -0
- package/dist/features/products/schemas/index.d.ts +10 -19
- package/dist/features/products/schemas/index.js +23 -6
- package/dist/features/products/types/index.d.ts +45 -1
- package/dist/features/products/utils/group-member-image.d.ts +46 -0
- package/dist/features/products/utils/group-member-image.js +4 -0
- package/dist/features/products/utils/listing-badge-variant.js +4 -0
- package/dist/features/reviews/components/ReviewsList.js +1 -1
- package/dist/features/scams/components/ScamProfileView.js +1 -1
- package/dist/features/search/components/EntityTypeahead.d.ts +44 -0
- package/dist/features/search/components/EntityTypeahead.js +92 -0
- package/dist/features/search/components/Search.d.ts +12 -1
- package/dist/features/search/components/Search.js +47 -3
- package/dist/features/search/components/SearchFacetRail.d.ts +11 -0
- package/dist/features/search/components/SearchFacetRail.js +92 -0
- package/dist/features/search/components/SearchResultsClient.d.ts +33 -0
- package/dist/features/search/components/SearchResultsClient.js +103 -0
- package/dist/features/search/components/SearchResultsPageView.d.ts +15 -1
- package/dist/features/search/components/SearchResultsPageView.js +2 -2
- package/dist/features/search/components/index.d.ts +0 -6
- package/dist/features/search/components/index.js +0 -3
- package/dist/features/search/hooks/useNavSuggestions.d.ts +13 -0
- package/dist/features/search/hooks/useScopedSearch.d.ts +34 -0
- package/dist/features/search/hooks/useScopedSearch.js +114 -0
- package/dist/features/search/hooks/useSiteSearch.d.ts +26 -0
- package/dist/features/search/hooks/useSiteSearch.js +149 -0
- package/dist/features/search/index.d.ts +0 -4
- package/dist/features/search/index.js +0 -4
- package/dist/features/search/manifest.d.ts +12 -0
- package/dist/features/search/manifest.js +17 -2
- package/dist/features/search/server.d.ts +0 -3
- package/dist/features/search/server.js +0 -3
- package/dist/features/seller/components/SellerListingTypeView.d.ts +1 -1
- package/dist/features/seller/components/SellerListingTypeView.js +20 -0
- package/dist/features/seller/components/SellerPayoutSettingsView.js +35 -14
- package/dist/features/seller/components/SellerProductShell.d.ts +1 -1
- package/dist/features/seller/components/SellerProductShell.js +2 -1
- package/dist/features/seller/components/SellerProductsView.js +3 -2
- package/dist/features/seller/components/SellerSidebar.js +1 -1
- package/dist/features/seller/components/SellerSparesView.d.ts +17 -0
- package/dist/features/seller/components/SellerSparesView.js +6 -0
- package/dist/features/seller/components/index.d.ts +2 -0
- package/dist/features/seller/components/index.js +1 -0
- package/dist/features/shell/CommandPalette.js +1 -1
- package/dist/features/sticker-trace/schemas/firestore.d.ts +19 -0
- package/dist/features/stores/components/StoreAuctionsListing.js +2 -1
- package/dist/features/stores/components/StoreDetailLayoutView.d.ts +1 -1
- package/dist/features/stores/components/StoreDetailLayoutView.js +7 -82
- package/dist/features/stores/components/StoreHeader.js +1 -2
- package/dist/features/stores/components/StoreSparesPageView.d.ts +27 -0
- package/dist/features/stores/components/StoreSparesPageView.js +48 -0
- package/dist/features/stores/schemas/firestore.d.ts +19 -0
- package/dist/features/tester/seed-data/authored/buying__spares-and-groups.d.ts +2 -0
- package/dist/features/tester/seed-data/authored/buying__spares-and-groups.js +96 -0
- package/dist/features/tester/seed-data/authored/content-discovery__authenticity-checker.d.ts +2 -0
- package/dist/features/tester/seed-data/authored/content-discovery__authenticity-checker.js +392 -45
- package/dist/features/tester/seed-data/authored/content-discovery__category-tabs-franchise-bundles.js +54 -32
- package/dist/features/tester/seed-data/authored/content-discovery__parts-database.js +3 -2
- package/dist/features/tester/seed-data/authored/content-discovery__price-index-and-compare.d.ts +2 -0
- package/dist/features/tester/seed-data/authored/content-discovery__price-index-and-compare.js +73 -0
- package/dist/features/tester/seed-data/authored/content-discovery__site-wide-index.d.ts +2 -0
- package/dist/features/tester/seed-data/authored/content-discovery__site-wide-index.js +340 -0
- package/dist/features/tester/seed-data/authored/index.js +16 -0
- package/dist/features/tester/seed-data/authored/search-and-nav__header-search.d.ts +1 -0
- package/dist/features/tester/seed-data/authored/search-and-nav__header-search.js +57 -0
- package/dist/features/tester/seed-data/authored/selling__spares-and-group-editing.d.ts +2 -0
- package/dist/features/tester/seed-data/authored/selling__spares-and-group-editing.js +77 -0
- package/dist/features/tester/seed-data/authored/tools__sticker-promote-to-listings.d.ts +2 -0
- package/dist/features/tester/seed-data/authored/tools__sticker-promote-to-listings.js +58 -0
- package/dist/features/tester/seed-data/authored/tools__sticker-tracer.js +5 -4
- package/dist/features/tester/seed-data/tester-checklist-seed-data.js +384 -18
- package/dist/index.d.ts +17 -57
- package/dist/index.js +35 -96
- package/dist/next/routing/route-map.d.ts +42 -1
- package/dist/next/routing/route-map.js +45 -0
- package/dist/providers/db-firebase/base.repository.d.ts +22 -0
- package/dist/providers/db-firebase/base.repository.js +36 -0
- package/dist/schemas/registry.d.ts +15 -6
- package/dist/security/blind-index-tokens.d.ts +54 -0
- package/dist/security/blind-index-tokens.js +152 -0
- package/dist/security/index.d.ts +1 -1
- package/dist/security/index.js +1 -1
- package/dist/security/settings-encryption.d.ts +35 -0
- package/dist/security/settings-encryption.js +91 -0
- package/dist/seed/_helpers/brand-rows.js +38 -14
- package/dist/seed/_helpers/category-forest.js +73 -7
- package/dist/seed/_helpers/category-images-generated.d.ts +25 -6
- package/dist/seed/_helpers/category-images-generated.js +81 -6
- package/dist/seed/_helpers/category-models.d.ts +1 -1
- package/dist/seed/_helpers/category-models.js +7 -1
- package/dist/seed/_helpers/category-parts-glossary-map.js +8 -0
- package/dist/seed/_helpers/category-parts.d.ts +1 -1
- package/dist/seed/_helpers/category-parts.js +50 -2
- package/dist/seed/_helpers/character-features.d.ts +1 -1
- package/dist/seed/_helpers/character-features.js +2 -1
- package/dist/seed/_helpers/franchise-rows.js +10 -2
- package/dist/seed/_helpers/media.d.ts +47 -0
- package/dist/seed/_helpers/media.js +34 -0
- package/dist/seed/authenticity-knowledge-seed-data.d.ts +49 -5
- package/dist/seed/authenticity-knowledge-seed-data.js +10001 -549
- package/dist/seed/categories-seed-data.js +124 -20
- package/dist/seed/grouped-listings-seed-data.js +16 -0
- package/dist/seed/homepage-sections-seed-data.js +94 -5
- package/dist/seed/index.d.ts +2 -3
- package/dist/seed/index.js +2 -2
- package/dist/seed/manifest.js +3 -0
- package/dist/seed/media-assets-seed-data.d.ts +1 -1
- package/dist/seed/media-assets-seed-data.js +746 -196
- package/dist/seed/model-composition-seed-data.js +122 -6
- package/dist/seed/part-glossary-seed-data.d.ts +1 -1
- package/dist/seed/part-glossary-seed-data.js +37219 -463
- package/dist/seed/products-art-seed-data.js +7 -18
- package/dist/seed/products-auctions-seed-data.js +56 -47
- package/dist/seed/products-beyblade-x-seed-data.d.ts +2 -0
- package/dist/seed/products-beyblade-x-seed-data.js +476 -0
- package/dist/seed/products-catalogue-seed-data.d.ts +5 -5
- package/dist/seed/products-catalogue-seed-data.js +1500 -1240
- package/dist/seed/products-classifieds-seed-data.js +9 -27
- package/dist/seed/products-digital-codes-seed-data.js +9 -18
- package/dist/seed/products-live-items-seed-data.js +5 -13
- package/dist/seed/products-preorders-seed-data.js +67 -33
- package/dist/seed/products-prize-draws-seed-data.js +8 -17
- package/dist/seed/products-spares-seed-data.d.ts +2 -0
- package/dist/seed/products-spares-seed-data.js +368 -0
- package/dist/seed/products-standard-seed-data.js +39 -126
- package/dist/seed/products-stickers-seed-data.js +59 -15
- package/dist/seed/site-settings-seed-data.js +8 -0
- package/dist/seo/json-ld.d.ts +25 -0
- package/dist/seo/json-ld.js +28 -0
- package/dist/server-entry.d.ts +3 -1
- package/dist/server-entry.js +2 -2
- package/dist/server.d.ts +11 -9
- package/dist/server.js +35 -25
- package/dist/styles.css +202 -1
- package/dist/tailwind-input.css +31 -17
- package/dist/tailwind-utilities.css +1 -1
- package/dist/ui/components/Accordion.js +1 -1
- package/dist/ui/components/Breadcrumb.js +1 -1
- package/dist/ui/components/DetailPageGallery.js +0 -2
- package/dist/ui/components/DetailPageHero.js +0 -1
- package/dist/ui/components/DetailPageTabs.js +1 -1
- package/dist/ui/components/Divider.js +3 -3
- package/dist/ui/components/GatedPrice.js +5 -1
- package/dist/ui/components/HorizontalScroller.js +1 -1
- package/dist/ui/components/ListingLayout.js +3 -3
- package/dist/ui/components/MediaTabs.style.css +81 -0
- package/dist/ui/components/Pagination.js +1 -1
- package/dist/ui/components/PendingValue.d.ts +45 -0
- package/dist/ui/components/PendingValue.js +7 -0
- package/dist/ui/components/Radio.style.css +119 -0
- package/dist/ui/components/RatingDisplay.js +2 -2
- package/dist/ui/components/SettingsSection.js +0 -2
- package/dist/ui/components/SiteLogo.js +3 -0
- package/dist/ui/components/SiteMark.js +3 -0
- package/dist/ui/components/SortDropdown.js +1 -1
- package/dist/ui/components/SpecTable.d.ts +58 -0
- package/dist/ui/components/SpecTable.js +8 -0
- package/dist/ui/components/StarRating.js +1 -3
- package/dist/ui/components/SummaryCard.js +1 -1
- package/dist/ui/components/index.style.css +1 -0
- package/dist/ui/icons/icon-registry.d.ts +1 -0
- package/dist/ui/icons/icon-registry.js +9 -1
- package/dist/ui/index.d.ts +4 -0
- package/dist/ui/index.js +2 -0
- package/dist/utils/search-txt-query.d.ts +12 -0
- package/dist/utils/search-txt-query.js +12 -0
- package/package.json +1 -1
- package/scripts/dedupe-peer-deps.mjs +18 -0
- package/scripts/seed-cli.mjs +250 -35
- package/scripts/verify-css-build.mjs +118 -37
- package/dist/_internal/server/features/search/actions.d.ts +0 -7
- package/dist/_internal/server/features/search/actions.js +0 -21
- package/dist/_internal/server/features/search/data.d.ts +0 -15
- package/dist/_internal/server/features/search/data.js +0 -18
- package/dist/_internal/server/features/search/index.d.ts +0 -3
- package/dist/_internal/server/features/search/index.js +0 -2
- package/dist/features/homepage/api/[id]/route.d.ts +0 -23
- package/dist/features/homepage/api/[id]/route.js +0 -103
- package/dist/features/homepage/api/route.d.ts +0 -14
- package/dist/features/homepage/api/route.js +0 -140
- package/dist/features/homepage/api/sections/[id]/route.d.ts +0 -26
- package/dist/features/homepage/api/sections/[id]/route.js +0 -95
- package/dist/features/homepage/api/sections/route.d.ts +0 -13
- package/dist/features/homepage/api/sections/route.js +0 -82
- package/dist/features/homepage/components/AdvertisementBanner.d.ts +0 -14
- package/dist/features/homepage/components/AdvertisementBanner.js +0 -35
- package/dist/features/homepage/components/BeforeAfterCard.d.ts +0 -9
- package/dist/features/homepage/components/BeforeAfterCard.js +0 -73
- package/dist/features/homepage/components/FeaturedResultsSection.d.ts +0 -17
- package/dist/features/homepage/components/FeaturedResultsSection.js +0 -17
- package/dist/features/homepage/components/HeroBanner.d.ts +0 -7
- package/dist/features/homepage/components/HeroBanner.js +0 -43
- package/dist/features/homepage/components/HeroSection.d.ts +0 -7
- package/dist/features/homepage/components/HeroSection.js +0 -6
- package/dist/features/homepage/components/HomepageSkeleton.d.ts +0 -2
- package/dist/features/homepage/components/HomepageSkeleton.js +0 -21
- package/dist/features/homepage/components/HomepageView.d.ts +0 -25
- package/dist/features/homepage/components/HomepageView.js +0 -5
- package/dist/features/homepage/components/NewsletterBanner.d.ts +0 -23
- package/dist/features/homepage/components/NewsletterBanner.js +0 -37
- package/dist/features/homepage/components/SiteFeaturesSection.d.ts +0 -14
- package/dist/features/homepage/components/SiteFeaturesSection.js +0 -11
- package/dist/features/homepage/components/TrustBadges.d.ts +0 -6
- package/dist/features/homepage/components/TrustBadges.js +0 -46
- package/dist/features/homepage/components/TrustIndicatorsSection.d.ts +0 -12
- package/dist/features/homepage/components/TrustIndicatorsSection.js +0 -11
- package/dist/features/homepage/hooks/useHomepage.d.ts +0 -11
- package/dist/features/homepage/hooks/useHomepage.js +0 -17
- package/dist/features/homepage/hooks/useHomepageSections.d.ts +0 -2
- package/dist/features/homepage/hooks/useHomepageSections.js +0 -10
- package/dist/features/homepage/repository/homepage.repository.d.ts +0 -11
- package/dist/features/homepage/repository/homepage.repository.js +0 -25
- package/dist/features/search/actions/index.d.ts +0 -1
- package/dist/features/search/actions/index.js +0 -1
- package/dist/features/search/actions/search-actions.d.ts +0 -18
- package/dist/features/search/actions/search-actions.js +0 -43
- package/dist/features/search/api/route.d.ts +0 -22
- package/dist/features/search/api/route.js +0 -128
- package/dist/features/search/columns/index.d.ts +0 -17
- package/dist/features/search/columns/index.js +0 -49
- package/dist/features/search/components/SearchFiltersRow.d.ts +0 -22
- package/dist/features/search/components/SearchFiltersRow.js +0 -21
- package/dist/features/search/components/SearchResultsSection.d.ts +0 -53
- package/dist/features/search/components/SearchResultsSection.js +0 -35
- package/dist/features/search/components/SearchView.d.ts +0 -27
- package/dist/features/search/components/SearchView.js +0 -8
- package/dist/features/search/hooks/useSearch.d.ts +0 -21
- package/dist/features/search/hooks/useSearch.js +0 -33
- package/dist/features/search/repository/search.repository.d.ts +0 -14
- package/dist/features/search/repository/search.repository.js +0 -59
- package/dist/features/search/schemas/index.d.ts +0 -70
- package/dist/features/search/schemas/index.js +0 -36
- package/dist/features/search/types/index.d.ts +0 -48
- package/dist/features/stores/components/StoreScopedSearch.d.ts +0 -17
- package/dist/features/stores/components/StoreScopedSearch.js +0 -27
- package/dist/seed/defaults/homepage-sections.d.ts +0 -2
- package/dist/seed/defaults/homepage-sections.js +0 -60
- package/dist/seed/factories/homepage-section.factory.d.ts +0 -10
- package/dist/seed/factories/homepage-section.factory.js +0 -13
- /package/dist/{features/search/types/index.js → _internal/shared/listing-types/spares/og.d.ts} +0 -0
|
@@ -50,6 +50,7 @@ export declare const DEFAULT_ROUTE_MAP: {
|
|
|
50
50
|
readonly STORE_DIGITAL_CODES: (storeSlug: string) => string;
|
|
51
51
|
readonly STORE_LIVE: (storeSlug: string) => string;
|
|
52
52
|
readonly STORE_ART: (storeSlug: string) => string;
|
|
53
|
+
readonly STORE_SPARES: (storeSlug: string) => string;
|
|
53
54
|
readonly CATEGORIES: "/categories";
|
|
54
55
|
readonly CATEGORY_DETAIL: (slug: string) => string;
|
|
55
56
|
readonly BRANDS: "/brands";
|
|
@@ -78,6 +79,19 @@ export declare const DEFAULT_ROUTE_MAP: {
|
|
|
78
79
|
readonly COOKIE_POLICY: "/cookies";
|
|
79
80
|
readonly REFUND_POLICY: "/refund-policy";
|
|
80
81
|
readonly SHIPPING_POLICY: "/shipping-policy";
|
|
82
|
+
/**
|
|
83
|
+
* Cancellation policy. Distinct from the refund policy, which already
|
|
84
|
+
* covers cancellation in passing — PhonePe's merchant review asks for it
|
|
85
|
+
* by name, and so does the Consumer Protection (E-Commerce) Rules 2020
|
|
86
|
+
* disclosure list.
|
|
87
|
+
*/
|
|
88
|
+
readonly CANCELLATION_POLICY: "/cancellation-policy";
|
|
89
|
+
/**
|
|
90
|
+
* Grievance officer. A MANDATORY published disclosure under the Consumer
|
|
91
|
+
* Protection (E-Commerce) Rules 2020 and the IT Rules 2021 — name,
|
|
92
|
+
* designation, contact and a response commitment.
|
|
93
|
+
*/
|
|
94
|
+
readonly GRIEVANCE: "/grievance";
|
|
81
95
|
readonly HOW_AUCTIONS_WORK: "/how-auctions-work";
|
|
82
96
|
readonly HOW_PRE_ORDERS_WORK: "/how-pre-orders-work";
|
|
83
97
|
readonly HOW_OFFERS_WORK: "/how-offers-work";
|
|
@@ -124,6 +138,7 @@ export declare const DEFAULT_ROUTE_MAP: {
|
|
|
124
138
|
readonly LIVE: "/live";
|
|
125
139
|
readonly LIVE_DETAIL: (slug: string) => string;
|
|
126
140
|
readonly ART: "/art";
|
|
141
|
+
readonly SPARES: "/spares";
|
|
127
142
|
readonly CATALOGUE_ITEM_DETAIL: (ownerSlug: string, itemId: string) => string;
|
|
128
143
|
};
|
|
129
144
|
readonly ERRORS: {
|
|
@@ -246,6 +261,9 @@ export declare const DEFAULT_ROUTE_MAP: {
|
|
|
246
261
|
readonly STICKERS: "/store/stickers";
|
|
247
262
|
readonly STICKERS_NEW: "/store/stickers/new";
|
|
248
263
|
readonly STICKERS_EDIT: (id: string) => string;
|
|
264
|
+
readonly SPARES: "/store/spares";
|
|
265
|
+
readonly SPARES_NEW: "/store/spares/new";
|
|
266
|
+
readonly SPARES_EDIT: (id: string) => string;
|
|
249
267
|
readonly PRINT_CENTER: "/store/print-center";
|
|
250
268
|
readonly FULFILLMENT: "/store/fulfillment";
|
|
251
269
|
readonly PAYOUT_METHODS: "/store/payout-methods";
|
|
@@ -324,6 +342,7 @@ export declare const DEFAULT_ROUTE_MAP: {
|
|
|
324
342
|
readonly LIVE: "/admin/live";
|
|
325
343
|
readonly ART: "/admin/art";
|
|
326
344
|
readonly STICKERS: "/admin/stickers";
|
|
345
|
+
readonly SPARES: "/admin/spares";
|
|
327
346
|
readonly GROUPED_LISTINGS: "/admin/grouped-listings";
|
|
328
347
|
readonly GROUPED_LISTINGS_NEW: "/admin/grouped-listings/new";
|
|
329
348
|
readonly GROUPED_LISTINGS_EDIT: (id: string) => string;
|
|
@@ -466,6 +485,7 @@ export declare const ROUTES: {
|
|
|
466
485
|
readonly STORE_DIGITAL_CODES: (storeSlug: string) => string;
|
|
467
486
|
readonly STORE_LIVE: (storeSlug: string) => string;
|
|
468
487
|
readonly STORE_ART: (storeSlug: string) => string;
|
|
488
|
+
readonly STORE_SPARES: (storeSlug: string) => string;
|
|
469
489
|
readonly CATEGORIES: "/categories";
|
|
470
490
|
readonly CATEGORY_DETAIL: (slug: string) => string;
|
|
471
491
|
readonly BRANDS: "/brands";
|
|
@@ -494,6 +514,19 @@ export declare const ROUTES: {
|
|
|
494
514
|
readonly COOKIE_POLICY: "/cookies";
|
|
495
515
|
readonly REFUND_POLICY: "/refund-policy";
|
|
496
516
|
readonly SHIPPING_POLICY: "/shipping-policy";
|
|
517
|
+
/**
|
|
518
|
+
* Cancellation policy. Distinct from the refund policy, which already
|
|
519
|
+
* covers cancellation in passing — PhonePe's merchant review asks for it
|
|
520
|
+
* by name, and so does the Consumer Protection (E-Commerce) Rules 2020
|
|
521
|
+
* disclosure list.
|
|
522
|
+
*/
|
|
523
|
+
readonly CANCELLATION_POLICY: "/cancellation-policy";
|
|
524
|
+
/**
|
|
525
|
+
* Grievance officer. A MANDATORY published disclosure under the Consumer
|
|
526
|
+
* Protection (E-Commerce) Rules 2020 and the IT Rules 2021 — name,
|
|
527
|
+
* designation, contact and a response commitment.
|
|
528
|
+
*/
|
|
529
|
+
readonly GRIEVANCE: "/grievance";
|
|
497
530
|
readonly HOW_AUCTIONS_WORK: "/how-auctions-work";
|
|
498
531
|
readonly HOW_PRE_ORDERS_WORK: "/how-pre-orders-work";
|
|
499
532
|
readonly HOW_OFFERS_WORK: "/how-offers-work";
|
|
@@ -540,6 +573,7 @@ export declare const ROUTES: {
|
|
|
540
573
|
readonly LIVE: "/live";
|
|
541
574
|
readonly LIVE_DETAIL: (slug: string) => string;
|
|
542
575
|
readonly ART: "/art";
|
|
576
|
+
readonly SPARES: "/spares";
|
|
543
577
|
readonly CATALOGUE_ITEM_DETAIL: (ownerSlug: string, itemId: string) => string;
|
|
544
578
|
};
|
|
545
579
|
readonly ERRORS: {
|
|
@@ -662,6 +696,9 @@ export declare const ROUTES: {
|
|
|
662
696
|
readonly STICKERS: "/store/stickers";
|
|
663
697
|
readonly STICKERS_NEW: "/store/stickers/new";
|
|
664
698
|
readonly STICKERS_EDIT: (id: string) => string;
|
|
699
|
+
readonly SPARES: "/store/spares";
|
|
700
|
+
readonly SPARES_NEW: "/store/spares/new";
|
|
701
|
+
readonly SPARES_EDIT: (id: string) => string;
|
|
665
702
|
readonly PRINT_CENTER: "/store/print-center";
|
|
666
703
|
readonly FULFILLMENT: "/store/fulfillment";
|
|
667
704
|
readonly PAYOUT_METHODS: "/store/payout-methods";
|
|
@@ -740,6 +777,7 @@ export declare const ROUTES: {
|
|
|
740
777
|
readonly LIVE: "/admin/live";
|
|
741
778
|
readonly ART: "/admin/art";
|
|
742
779
|
readonly STICKERS: "/admin/stickers";
|
|
780
|
+
readonly SPARES: "/admin/spares";
|
|
743
781
|
readonly GROUPED_LISTINGS: "/admin/grouped-listings";
|
|
744
782
|
readonly GROUPED_LISTINGS_NEW: "/admin/grouped-listings/new";
|
|
745
783
|
readonly GROUPED_LISTINGS_EDIT: (id: string) => string;
|
|
@@ -903,6 +941,9 @@ export declare const SELLER_ROUTES: {
|
|
|
903
941
|
readonly STICKERS: "/store/stickers";
|
|
904
942
|
readonly STICKERS_NEW: "/store/stickers/new";
|
|
905
943
|
readonly STICKERS_EDIT: (id: string) => string;
|
|
944
|
+
readonly SPARES: "/store/spares";
|
|
945
|
+
readonly SPARES_NEW: "/store/spares/new";
|
|
946
|
+
readonly SPARES_EDIT: (id: string) => string;
|
|
906
947
|
readonly PRINT_CENTER: "/store/print-center";
|
|
907
948
|
readonly FULFILLMENT: "/store/fulfillment";
|
|
908
949
|
readonly PAYOUT_METHODS: "/store/payout-methods";
|
|
@@ -931,6 +972,6 @@ export declare const SELLER_ROUTES: {
|
|
|
931
972
|
readonly GUIDE_SETTINGS: "/store/guide/settings";
|
|
932
973
|
readonly GUIDE_WHATSAPP: "/store/guide/whatsapp";
|
|
933
974
|
};
|
|
934
|
-
export declare const PUBLIC_ROUTES: readonly ["/", string, string, string, string, string, string, string, string, string, string, string, string, string, string, string, string, string, "/unauthorized", "/auth/login", "/auth/register", "/auth/forgot-password", "/auth/reset-password", "/auth/verify-email"];
|
|
975
|
+
export declare const PUBLIC_ROUTES: readonly ["/", string, string, string, string, string, string, string, string, string, string, string, string, string, string, string, string, string, string, string, "/unauthorized", "/auth/login", "/auth/register", "/auth/forgot-password", "/auth/reset-password", "/auth/verify-email"];
|
|
935
976
|
export declare const PROTECTED_ROUTES: readonly [string, string, string, string, string, string, string];
|
|
936
977
|
export declare const AUTH_ROUTES: readonly ["/auth/login", "/auth/register"];
|
|
@@ -43,6 +43,13 @@ export const DEFAULT_ROUTE_MAP = {
|
|
|
43
43
|
// `standard` — so the tab showed a real non-zero count and then landed on
|
|
44
44
|
// a page containing none of those items.
|
|
45
45
|
STORE_ART: (storeSlug) => `/stores/${storeSlug}/art`,
|
|
46
|
+
/*
|
|
47
|
+
* 🛑 `STORE_PAGE_TABS` is DERIVED from the plugin registry, so this tab
|
|
48
|
+
* appears the moment the plugin exists — and a missing
|
|
49
|
+
* `stores/[storeSlug]/spares/page.tsx` is then a clickable 404 that no
|
|
50
|
+
* audit covers. The folder lands in the same commit as this key.
|
|
51
|
+
*/
|
|
52
|
+
STORE_SPARES: (storeSlug) => `/stores/${storeSlug}/spares`,
|
|
46
53
|
CATEGORIES: "/categories",
|
|
47
54
|
CATEGORY_DETAIL: (slug) => `/categories/${slug}`,
|
|
48
55
|
BRANDS: "/brands",
|
|
@@ -86,6 +93,19 @@ export const DEFAULT_ROUTE_MAP = {
|
|
|
86
93
|
COOKIE_POLICY: "/cookies",
|
|
87
94
|
REFUND_POLICY: "/refund-policy",
|
|
88
95
|
SHIPPING_POLICY: "/shipping-policy",
|
|
96
|
+
/**
|
|
97
|
+
* Cancellation policy. Distinct from the refund policy, which already
|
|
98
|
+
* covers cancellation in passing — PhonePe's merchant review asks for it
|
|
99
|
+
* by name, and so does the Consumer Protection (E-Commerce) Rules 2020
|
|
100
|
+
* disclosure list.
|
|
101
|
+
*/
|
|
102
|
+
CANCELLATION_POLICY: "/cancellation-policy",
|
|
103
|
+
/**
|
|
104
|
+
* Grievance officer. A MANDATORY published disclosure under the Consumer
|
|
105
|
+
* Protection (E-Commerce) Rules 2020 and the IT Rules 2021 — name,
|
|
106
|
+
* designation, contact and a response commitment.
|
|
107
|
+
*/
|
|
108
|
+
GRIEVANCE: "/grievance",
|
|
89
109
|
HOW_AUCTIONS_WORK: "/how-auctions-work",
|
|
90
110
|
HOW_PRE_ORDERS_WORK: "/how-pre-orders-work",
|
|
91
111
|
HOW_OFFERS_WORK: "/how-offers-work",
|
|
@@ -188,6 +208,21 @@ export const DEFAULT_ROUTE_MAP = {
|
|
|
188
208
|
// detail page stays PRODUCT_DETAIL (`/products/{slug}`), already wired in
|
|
189
209
|
// `_internal/shared/listing-types/{art,stickers}/config.ts`.
|
|
190
210
|
ART: "/art",
|
|
211
|
+
/*
|
|
212
|
+
* Part Two — loose components off disassembled items.
|
|
213
|
+
*
|
|
214
|
+
* 🛑 A REAL page, not a redirect shim like `/live`. Its plugin sets
|
|
215
|
+
* `inGeneralCatalogue: false`, and the rule for that flag is nav
|
|
216
|
+
* reachability: a type kept out of `/products` must own a page that
|
|
217
|
+
* `MAIN_NAV_ITEMS` links, or it is reachable from nowhere at all (Root
|
|
218
|
+
* Cause #61). A shim pointing back at `/products` would re-open exactly
|
|
219
|
+
* that hole while looking like it had closed it.
|
|
220
|
+
*
|
|
221
|
+
* Detail route stays `PRODUCT_DETAIL` — a spare checks out like any
|
|
222
|
+
* standard item, so it needs no bespoke detail page, same reasoning as
|
|
223
|
+
* art/stickers above.
|
|
224
|
+
*/
|
|
225
|
+
SPARES: "/spares",
|
|
191
226
|
// Personal catalogue (Feature B) — a user's own photo inventory of owned
|
|
192
227
|
// items, distinct from marketplace listings. Public when the owner sets
|
|
193
228
|
// an item's visibility to "public". The owner's full catalogue listing
|
|
@@ -319,6 +354,10 @@ export const DEFAULT_ROUTE_MAP = {
|
|
|
319
354
|
STICKERS: "/store/stickers",
|
|
320
355
|
STICKERS_NEW: "/store/stickers/new",
|
|
321
356
|
STICKERS_EDIT: (id) => `/store/stickers/${id}/edit`,
|
|
357
|
+
// Part Two — spares
|
|
358
|
+
SPARES: "/store/spares",
|
|
359
|
+
SPARES_NEW: "/store/spares/new",
|
|
360
|
+
SPARES_EDIT: (id) => `/store/spares/${id}/edit`,
|
|
322
361
|
PRINT_CENTER: "/store/print-center",
|
|
323
362
|
FULFILLMENT: "/store/fulfillment",
|
|
324
363
|
// S-STORE Tier — new extension routes
|
|
@@ -412,6 +451,8 @@ export const DEFAULT_ROUTE_MAP = {
|
|
|
412
451
|
// EMI/art-stickers session — art / stickers
|
|
413
452
|
ART: "/admin/art",
|
|
414
453
|
STICKERS: "/admin/stickers",
|
|
454
|
+
// Part Two — spares
|
|
455
|
+
SPARES: "/admin/spares",
|
|
415
456
|
GROUPED_LISTINGS: "/admin/grouped-listings",
|
|
416
457
|
GROUPED_LISTINGS_NEW: "/admin/grouped-listings/new",
|
|
417
458
|
GROUPED_LISTINGS_EDIT: (id) => `/admin/grouped-listings/${id}/edit`,
|
|
@@ -580,6 +621,10 @@ export const PUBLIC_ROUTES = [
|
|
|
580
621
|
ROUTES.PUBLIC.PRIVACY,
|
|
581
622
|
ROUTES.PUBLIC.ETHICS,
|
|
582
623
|
ROUTES.PUBLIC.CODE_OF_CONDUCT,
|
|
624
|
+
ROUTES.PUBLIC.CANCELLATION_POLICY,
|
|
625
|
+
// Public by necessity: a grievance officer a complainant must sign in to
|
|
626
|
+
// find is not a published disclosure.
|
|
627
|
+
ROUTES.PUBLIC.GRIEVANCE,
|
|
583
628
|
ROUTES.ERRORS.UNAUTHORIZED,
|
|
584
629
|
ROUTES.AUTH.LOGIN,
|
|
585
630
|
ROUTES.AUTH.REGISTER,
|
|
@@ -49,6 +49,28 @@ export declare abstract class BaseRepository<T extends DocumentData> {
|
|
|
49
49
|
* text, so indexing an encrypted field would undo the encryption.
|
|
50
50
|
*/
|
|
51
51
|
protected buildSearchTxtFor(_data: Record<string, JsonValue>): string[] | null;
|
|
52
|
+
/**
|
|
53
|
+
* Build this document's `*TokensIndex` fields — whole-word HMAC digests
|
|
54
|
+
* over PII, for admin search without decryption. Return `null` to leave
|
|
55
|
+
* the document alone (the default).
|
|
56
|
+
*
|
|
57
|
+
* Mirrors `buildSearchTxtFor`'s shape exactly, and for the reason that
|
|
58
|
+
* shape exists: a hook run from `applyWriteHooks` reaches EVERY write path
|
|
59
|
+
* — create, createWithId, update, the `*InTx`/`*InBatch` family, and a
|
|
60
|
+
* seed load, which goes through the same repository methods. A one-off
|
|
61
|
+
* backfill script cannot reach any of those; it only catches documents
|
|
62
|
+
* that already existed when it ran.
|
|
63
|
+
*
|
|
64
|
+
* 🛑 This is NOT `buildSearchTxtFor`'s inverse rule. `searchTxt` must never
|
|
65
|
+
* carry PII; this hook exists FOR PII, and runs in the only place that
|
|
66
|
+
* sees the plaintext before `encryptPiiFields` replaces it. See
|
|
67
|
+
* `security/blind-index-tokens.ts` for why the tokens are whole-word only.
|
|
68
|
+
*
|
|
69
|
+
* Return shape is `{ fieldName: digests[] }` rather than a single array,
|
|
70
|
+
* because a document can carry more than one token field (a payout has
|
|
71
|
+
* `sellerTokensIndex`, nothing else does yet, but the hook is general).
|
|
72
|
+
*/
|
|
73
|
+
protected buildTokensIndexFor(_data: Record<string, JsonValue>): Record<string, string[]> | null;
|
|
52
74
|
/**
|
|
53
75
|
* The one place writes are transformed. Every write path routes through here
|
|
54
76
|
* so a new method cannot silently skip encryption.
|
|
@@ -5,6 +5,7 @@ import { applySieveToFirestore, countSieveMatches, } from "./sieve.js";
|
|
|
5
5
|
import { deserializeTimestamps, prepareForFirestore } from "./helpers.js";
|
|
6
6
|
import { getAdminDb } from "./admin.js";
|
|
7
7
|
import { encryptPiiFields, piiIndicesFor } from "../../security/pii-encrypt.js";
|
|
8
|
+
import { BLIND_INDEX_KEY_VERSION_FIELD, CURRENT_BLIND_INDEX_KEY_VERSION, } from "../../security/blind-index-tokens.js";
|
|
8
9
|
/**
|
|
9
10
|
* The underlying failure's message, for interpolation into a DatabaseError.
|
|
10
11
|
*
|
|
@@ -133,6 +134,30 @@ export class BaseRepository {
|
|
|
133
134
|
buildSearchTxtFor(_data) {
|
|
134
135
|
return null;
|
|
135
136
|
}
|
|
137
|
+
/**
|
|
138
|
+
* Build this document's `*TokensIndex` fields — whole-word HMAC digests
|
|
139
|
+
* over PII, for admin search without decryption. Return `null` to leave
|
|
140
|
+
* the document alone (the default).
|
|
141
|
+
*
|
|
142
|
+
* Mirrors `buildSearchTxtFor`'s shape exactly, and for the reason that
|
|
143
|
+
* shape exists: a hook run from `applyWriteHooks` reaches EVERY write path
|
|
144
|
+
* — create, createWithId, update, the `*InTx`/`*InBatch` family, and a
|
|
145
|
+
* seed load, which goes through the same repository methods. A one-off
|
|
146
|
+
* backfill script cannot reach any of those; it only catches documents
|
|
147
|
+
* that already existed when it ran.
|
|
148
|
+
*
|
|
149
|
+
* 🛑 This is NOT `buildSearchTxtFor`'s inverse rule. `searchTxt` must never
|
|
150
|
+
* carry PII; this hook exists FOR PII, and runs in the only place that
|
|
151
|
+
* sees the plaintext before `encryptPiiFields` replaces it. See
|
|
152
|
+
* `security/blind-index-tokens.ts` for why the tokens are whole-word only.
|
|
153
|
+
*
|
|
154
|
+
* Return shape is `{ fieldName: digests[] }` rather than a single array,
|
|
155
|
+
* because a document can carry more than one token field (a payout has
|
|
156
|
+
* `sellerTokensIndex`, nothing else does yet, but the hook is general).
|
|
157
|
+
*/
|
|
158
|
+
buildTokensIndexFor(_data) {
|
|
159
|
+
return null;
|
|
160
|
+
}
|
|
136
161
|
/**
|
|
137
162
|
* The one place writes are transformed. Every write path routes through here
|
|
138
163
|
* so a new method cannot silently skip encryption.
|
|
@@ -154,6 +179,17 @@ export class BaseRepository {
|
|
|
154
179
|
const searchTxt = this.buildSearchTxtFor(out);
|
|
155
180
|
if (searchTxt)
|
|
156
181
|
out.searchTxt = searchTxt;
|
|
182
|
+
/*
|
|
183
|
+
* `data`, not `out` — the plaintext source, same as `piiIndicesFor`
|
|
184
|
+
* above. By this point `out` may already hold ciphertext, and hashing
|
|
185
|
+
* ciphertext would make the index meaningless.
|
|
186
|
+
*/
|
|
187
|
+
const tokensIndex = this.buildTokensIndexFor(data);
|
|
188
|
+
if (tokensIndex) {
|
|
189
|
+
Object.assign(out, tokensIndex, {
|
|
190
|
+
[BLIND_INDEX_KEY_VERSION_FIELD]: CURRENT_BLIND_INDEX_KEY_VERSION,
|
|
191
|
+
});
|
|
192
|
+
}
|
|
157
193
|
return out;
|
|
158
194
|
}
|
|
159
195
|
/**
|
|
@@ -1011,6 +1011,8 @@ export declare const SCHEMAS: {
|
|
|
1011
1011
|
brandWebsite: import("zod").ZodOptional<import("zod").ZodString>;
|
|
1012
1012
|
brandCountry: import("zod").ZodOptional<import("zod").ZodString>;
|
|
1013
1013
|
brandFounded: import("zod").ZodOptional<import("zod").ZodNumber>;
|
|
1014
|
+
hasbroName: import("zod").ZodOptional<import("zod").ZodString>;
|
|
1015
|
+
hasbroCoverImage: import("zod").ZodOptional<import("zod").ZodString>;
|
|
1014
1016
|
highlights: import("zod").ZodOptional<import("zod").ZodArray<import("zod").ZodString, "many">>;
|
|
1015
1017
|
faqs: import("zod").ZodOptional<import("zod").ZodArray<import("zod").ZodObject<{
|
|
1016
1018
|
question: import("zod").ZodString;
|
|
@@ -1604,6 +1606,8 @@ export declare const SCHEMAS: {
|
|
|
1604
1606
|
brandWebsite?: string | undefined;
|
|
1605
1607
|
brandCountry?: string | undefined;
|
|
1606
1608
|
brandFounded?: number | undefined;
|
|
1609
|
+
hasbroName?: string | undefined;
|
|
1610
|
+
hasbroCoverImage?: string | undefined;
|
|
1607
1611
|
highlights?: string[] | undefined;
|
|
1608
1612
|
contentBody?: string | undefined;
|
|
1609
1613
|
descriptionTemplates?: {
|
|
@@ -1775,6 +1779,8 @@ export declare const SCHEMAS: {
|
|
|
1775
1779
|
brandWebsite?: string | undefined;
|
|
1776
1780
|
brandCountry?: string | undefined;
|
|
1777
1781
|
brandFounded?: number | undefined;
|
|
1782
|
+
hasbroName?: string | undefined;
|
|
1783
|
+
hasbroCoverImage?: string | undefined;
|
|
1778
1784
|
highlights?: string[] | undefined;
|
|
1779
1785
|
contentBody?: string | undefined;
|
|
1780
1786
|
descriptionTemplates?: {
|
|
@@ -2605,12 +2611,12 @@ export declare const SCHEMAS: {
|
|
|
2605
2611
|
toDate: import("zod").ZodFunction<import("zod").ZodTuple<[], import("zod").ZodUnknown>, import("zod").ZodDate>;
|
|
2606
2612
|
}, import("zod").ZodTypeAny, "passthrough">>]>;
|
|
2607
2613
|
id: import("zod").ZodString;
|
|
2608
|
-
type: import("zod").ZodEnum<["
|
|
2614
|
+
type: import("zod").ZodEnum<[import("..").SectionType, ...import("..").SectionType[]]>;
|
|
2609
2615
|
order: import("zod").ZodNumber;
|
|
2610
2616
|
enabled: import("zod").ZodBoolean;
|
|
2611
2617
|
config: import("zod").ZodRecord<import("zod").ZodString, import("zod").ZodType<import("./types").JsonValue, import("zod").ZodTypeDef, import("./types").JsonValue>>;
|
|
2612
2618
|
}, "strip", import("zod").ZodTypeAny, {
|
|
2613
|
-
type: "
|
|
2619
|
+
type: import("..").SectionType;
|
|
2614
2620
|
id: string;
|
|
2615
2621
|
createdAt: string | Date | import("zod").objectOutputType<{
|
|
2616
2622
|
toDate: import("zod").ZodFunction<import("zod").ZodTuple<[], import("zod").ZodUnknown>, import("zod").ZodDate>;
|
|
@@ -2622,7 +2628,7 @@ export declare const SCHEMAS: {
|
|
|
2622
2628
|
order: number;
|
|
2623
2629
|
config: Record<string, import("./types").JsonValue>;
|
|
2624
2630
|
}, {
|
|
2625
|
-
type: "
|
|
2631
|
+
type: import("..").SectionType;
|
|
2626
2632
|
id: string;
|
|
2627
2633
|
createdAt: string | Date | import("zod").objectInputType<{
|
|
2628
2634
|
toDate: import("zod").ZodFunction<import("zod").ZodTuple<[], import("zod").ZodUnknown>, import("zod").ZodDate>;
|
|
@@ -5501,18 +5507,21 @@ export declare const SCHEMAS: {
|
|
|
5501
5507
|
audienceUserIds?: string[] | undefined;
|
|
5502
5508
|
}>;
|
|
5503
5509
|
readonly homepageSection: import("zod").ZodObject<{
|
|
5504
|
-
type: import("zod").ZodEnum<["
|
|
5510
|
+
type: import("zod").ZodEnum<[import("..").SectionType, ...import("..").SectionType[]]>;
|
|
5505
5511
|
enabled: import("zod").ZodDefault<import("zod").ZodOptional<import("zod").ZodBoolean>>;
|
|
5506
5512
|
order: import("zod").ZodOptional<import("zod").ZodNumber>;
|
|
5513
|
+
surface: import("zod").ZodOptional<import("zod").ZodEnum<["homepage", "category", "brand", "product", "store"]>>;
|
|
5507
5514
|
config: import("zod").ZodRecord<import("zod").ZodString, import("zod").ZodType<import("./types").JsonValue, import("zod").ZodTypeDef, import("./types").JsonValue>>;
|
|
5508
5515
|
}, "strip", import("zod").ZodTypeAny, {
|
|
5509
|
-
type: "
|
|
5516
|
+
type: import("..").SectionType;
|
|
5510
5517
|
enabled: boolean;
|
|
5511
5518
|
config: Record<string, import("./types").JsonValue>;
|
|
5519
|
+
surface?: "brand" | "category" | "store" | "product" | "homepage" | undefined;
|
|
5512
5520
|
order?: number | undefined;
|
|
5513
5521
|
}, {
|
|
5514
|
-
type: "
|
|
5522
|
+
type: import("..").SectionType;
|
|
5515
5523
|
config: Record<string, import("./types").JsonValue>;
|
|
5524
|
+
surface?: "brand" | "category" | "store" | "product" | "homepage" | undefined;
|
|
5516
5525
|
enabled?: boolean | undefined;
|
|
5517
5526
|
order?: number | undefined;
|
|
5518
5527
|
}>;
|
|
@@ -0,0 +1,54 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* The shortest token worth indexing.
|
|
3
|
+
*
|
|
4
|
+
* 🛑 Three, matching the frequency argument in the header. Two-character
|
|
5
|
+
* tokens are both uninformative as a search ("find everyone with 'li' in
|
|
6
|
+
* their name") and the regime where counting starts to work.
|
|
7
|
+
*/
|
|
8
|
+
export declare const BLIND_INDEX_MIN_TOKEN = 3;
|
|
9
|
+
/** Tokens per field. A bound, so one pathological value cannot bloat a document. */
|
|
10
|
+
export declare const BLIND_INDEX_MAX_TOKENS = 24;
|
|
11
|
+
/** Split a value into whole, normalised, long-enough words. */
|
|
12
|
+
export declare function tokensOf(value: string): string[];
|
|
13
|
+
/**
|
|
14
|
+
* Build a `*TokensIndex` from one or more plaintext values.
|
|
15
|
+
*
|
|
16
|
+
* Returns `[]` rather than undefined for an empty input, so the field is
|
|
17
|
+
* always present and `array-contains` behaves predictably. An ABSENT array
|
|
18
|
+
* field and an empty one are the same to `array-contains`, but they are not
|
|
19
|
+
* the same to a human reading the document and wondering whether the
|
|
20
|
+
* backfill ran.
|
|
21
|
+
*/
|
|
22
|
+
export declare function buildTokensIndex(...values: readonly (string | null | undefined)[]): string[];
|
|
23
|
+
/**
|
|
24
|
+
* The digest to pass to `array-contains` for one search term.
|
|
25
|
+
*
|
|
26
|
+
* Returns null when the term is too short to have been indexed — the caller
|
|
27
|
+
* must then return NOTHING rather than fall back to an unfiltered query.
|
|
28
|
+
* A two-character admin search that quietly listed every user would be the
|
|
29
|
+
* `plan.empty` bug (a query that normalises away matching everything) on
|
|
30
|
+
* the one surface where the result set is people.
|
|
31
|
+
*/
|
|
32
|
+
export declare function tokensIndexQueryValue(term: string): string | null;
|
|
33
|
+
/**
|
|
34
|
+
* Which key version wrote a given index.
|
|
35
|
+
*
|
|
36
|
+
* 🛑 Rotating `PII_HMAC_KEY` invalidates every digest written before it, and
|
|
37
|
+
* the failure is silent: searches simply stop matching, which reads as "no
|
|
38
|
+
* such user" rather than as a broken index. Recording the version means a
|
|
39
|
+
* backfill can tell what it still has to rewrite instead of rewriting
|
|
40
|
+
* everything, and a mismatch is detectable rather than invisible.
|
|
41
|
+
*/
|
|
42
|
+
export declare const BLIND_INDEX_KEY_VERSION_FIELD = "blindIndexKeyVersion";
|
|
43
|
+
/**
|
|
44
|
+
* The version every NEW write stamps. Bump by hand when `PII_HMAC_KEY`
|
|
45
|
+
* rotates — never computed, because a value derived from the key itself
|
|
46
|
+
* would be constant across every rotation and the whole point is to tell
|
|
47
|
+
* two rotations apart.
|
|
48
|
+
*
|
|
49
|
+
* Read from `PII_HMAC_KEY_VERSION` so the repository write path (which runs
|
|
50
|
+
* inside the Next.js/Functions runtime) and `backfill-blind-index.mjs`
|
|
51
|
+
* (which runs as a standalone script before `appkit/dist` is necessarily
|
|
52
|
+
* current) agree without importing from each other.
|
|
53
|
+
*/
|
|
54
|
+
export declare const CURRENT_BLIND_INDEX_KEY_VERSION: number;
|
|
@@ -0,0 +1,152 @@
|
|
|
1
|
+
/*
|
|
2
|
+
* WHY: An admin needs to find a person by name without anything on the
|
|
3
|
+
* server being able to read that name, and without the index itself
|
|
4
|
+
* becoming the leak.
|
|
5
|
+
* WHAT: `*TokensIndex` — a whole-word HMAC token array, and the ONE
|
|
6
|
+
* normaliser both sides must use.
|
|
7
|
+
*
|
|
8
|
+
* ## 🛑 WHOLE WORDS ONLY, 3 characters minimum. This is the security
|
|
9
|
+
* boundary, not a tuning preference.
|
|
10
|
+
*
|
|
11
|
+
* The edge-n-gram expansion that makes `searchTxt` good is exactly what
|
|
12
|
+
* would make a blind index leak. An attacker with read access cannot
|
|
13
|
+
* compute HMACs without the key — but they can COUNT them. A 1-character
|
|
14
|
+
* prefix has 36 possible hashes and a 2-character one roughly 1,300, so the
|
|
15
|
+
* most frequent hash in the column is `a`, the second is `e`, and the
|
|
16
|
+
* distribution unpicks from there by ordinary frequency analysis. Whole
|
|
17
|
+
* tokens keep the space uninteresting, and "type a full first or last name"
|
|
18
|
+
* is what admin people-search actually needs.
|
|
19
|
+
*
|
|
20
|
+
* So: never call `buildSearchTxt` to build one of these, never add a prefix
|
|
21
|
+
* loop, and never derive one field from the other. `audit-blind-index-tokens`
|
|
22
|
+
* R1 blocks all three.
|
|
23
|
+
*
|
|
24
|
+
* ## 🛑 `hmacBlindIndex` does NOT normalise — it hashes the raw string
|
|
25
|
+
*
|
|
26
|
+
* `Mohasin` and `mohasin` therefore produce different digests. Both sides
|
|
27
|
+
* must run the same normaliser BEFORE hashing, and if they ever diverge a
|
|
28
|
+
* backfill does not fix it: you must first discover the divergence, and the
|
|
29
|
+
* symptom is "search returns nothing", which reads as "no such user".
|
|
30
|
+
*
|
|
31
|
+
* That is why `buildTokensIndex` and `tokensIndexQueryValue` live in one
|
|
32
|
+
* file and share `normaliseToken` — the write side and the query side
|
|
33
|
+
* cannot be edited independently.
|
|
34
|
+
*
|
|
35
|
+
* ## Why this is a DIFFERENT field from `searchTxt`, not an extension
|
|
36
|
+
*
|
|
37
|
+
* Different properties, deliberately: hashed not plaintext, whole-word not
|
|
38
|
+
* prefix-expanded, admin-only not public. `searchTxt` still never carries
|
|
39
|
+
* PII, and that rule is untouched. Keeping them visibly distinct is what
|
|
40
|
+
* stops someone "simplifying" one into the other.
|
|
41
|
+
*
|
|
42
|
+
* @tag domain:security
|
|
43
|
+
* @tag layer:shared
|
|
44
|
+
* @tag pattern:none
|
|
45
|
+
* @tag access:server
|
|
46
|
+
* @tag consumers:UserRepository,PayoutRepository,AddressesRepository,backfill-blind-index
|
|
47
|
+
* @tag sideEffects:none
|
|
48
|
+
*/
|
|
49
|
+
import { hmacBlindIndex } from "./pii-encrypt.js";
|
|
50
|
+
/**
|
|
51
|
+
* The shortest token worth indexing.
|
|
52
|
+
*
|
|
53
|
+
* 🛑 Three, matching the frequency argument in the header. Two-character
|
|
54
|
+
* tokens are both uninformative as a search ("find everyone with 'li' in
|
|
55
|
+
* their name") and the regime where counting starts to work.
|
|
56
|
+
*/
|
|
57
|
+
export const BLIND_INDEX_MIN_TOKEN = 3;
|
|
58
|
+
/** Tokens per field. A bound, so one pathological value cannot bloat a document. */
|
|
59
|
+
export const BLIND_INDEX_MAX_TOKENS = 24;
|
|
60
|
+
/**
|
|
61
|
+
* The ONE normaliser for this path.
|
|
62
|
+
*
|
|
63
|
+
* Deliberately NOT `normalizeSearchText`: that one exists to make the
|
|
64
|
+
* public write path and the Firestore token query agree, and it is tuned
|
|
65
|
+
* for product titles. Reusing it here would couple two schemes that must be
|
|
66
|
+
* able to change independently — and a change made for search reasons would
|
|
67
|
+
* silently invalidate every stored digest.
|
|
68
|
+
*
|
|
69
|
+
* Lower-case, strip diacritics, drop everything that is not a letter or a
|
|
70
|
+
* digit. An email is split on its punctuation too, so `mohsin0502@gmail.com`
|
|
71
|
+
* yields `mohsin0502`, `gmail`, `com` — the local part being the useful one.
|
|
72
|
+
*/
|
|
73
|
+
function normaliseToken(raw) {
|
|
74
|
+
return raw
|
|
75
|
+
.normalize("NFD")
|
|
76
|
+
.replace(/[̀-ͯ]/g, "")
|
|
77
|
+
.toLowerCase()
|
|
78
|
+
.replace(/[^a-z0-9]/g, "");
|
|
79
|
+
}
|
|
80
|
+
/** Split a value into whole, normalised, long-enough words. */
|
|
81
|
+
export function tokensOf(value) {
|
|
82
|
+
const out = [];
|
|
83
|
+
const seen = new Set();
|
|
84
|
+
for (const part of value.split(/[\s.@_\-+/\\,;:()[\]]+/)) {
|
|
85
|
+
const t = normaliseToken(part);
|
|
86
|
+
if (t.length < BLIND_INDEX_MIN_TOKEN)
|
|
87
|
+
continue;
|
|
88
|
+
if (seen.has(t))
|
|
89
|
+
continue;
|
|
90
|
+
seen.add(t);
|
|
91
|
+
out.push(t);
|
|
92
|
+
if (out.length >= BLIND_INDEX_MAX_TOKENS)
|
|
93
|
+
break;
|
|
94
|
+
}
|
|
95
|
+
return out;
|
|
96
|
+
}
|
|
97
|
+
/**
|
|
98
|
+
* Build a `*TokensIndex` from one or more plaintext values.
|
|
99
|
+
*
|
|
100
|
+
* Returns `[]` rather than undefined for an empty input, so the field is
|
|
101
|
+
* always present and `array-contains` behaves predictably. An ABSENT array
|
|
102
|
+
* field and an empty one are the same to `array-contains`, but they are not
|
|
103
|
+
* the same to a human reading the document and wondering whether the
|
|
104
|
+
* backfill ran.
|
|
105
|
+
*/
|
|
106
|
+
export function buildTokensIndex(...values) {
|
|
107
|
+
const tokens = new Set();
|
|
108
|
+
for (const v of values) {
|
|
109
|
+
if (!v)
|
|
110
|
+
continue;
|
|
111
|
+
for (const t of tokensOf(v))
|
|
112
|
+
tokens.add(t);
|
|
113
|
+
}
|
|
114
|
+
return [...tokens].slice(0, BLIND_INDEX_MAX_TOKENS).map((t) => hmacBlindIndex(t));
|
|
115
|
+
}
|
|
116
|
+
/**
|
|
117
|
+
* The digest to pass to `array-contains` for one search term.
|
|
118
|
+
*
|
|
119
|
+
* Returns null when the term is too short to have been indexed — the caller
|
|
120
|
+
* must then return NOTHING rather than fall back to an unfiltered query.
|
|
121
|
+
* A two-character admin search that quietly listed every user would be the
|
|
122
|
+
* `plan.empty` bug (a query that normalises away matching everything) on
|
|
123
|
+
* the one surface where the result set is people.
|
|
124
|
+
*/
|
|
125
|
+
export function tokensIndexQueryValue(term) {
|
|
126
|
+
const t = normaliseToken(term);
|
|
127
|
+
if (t.length < BLIND_INDEX_MIN_TOKEN)
|
|
128
|
+
return null;
|
|
129
|
+
return hmacBlindIndex(t);
|
|
130
|
+
}
|
|
131
|
+
/**
|
|
132
|
+
* Which key version wrote a given index.
|
|
133
|
+
*
|
|
134
|
+
* 🛑 Rotating `PII_HMAC_KEY` invalidates every digest written before it, and
|
|
135
|
+
* the failure is silent: searches simply stop matching, which reads as "no
|
|
136
|
+
* such user" rather than as a broken index. Recording the version means a
|
|
137
|
+
* backfill can tell what it still has to rewrite instead of rewriting
|
|
138
|
+
* everything, and a mismatch is detectable rather than invisible.
|
|
139
|
+
*/
|
|
140
|
+
export const BLIND_INDEX_KEY_VERSION_FIELD = "blindIndexKeyVersion";
|
|
141
|
+
/**
|
|
142
|
+
* The version every NEW write stamps. Bump by hand when `PII_HMAC_KEY`
|
|
143
|
+
* rotates — never computed, because a value derived from the key itself
|
|
144
|
+
* would be constant across every rotation and the whole point is to tell
|
|
145
|
+
* two rotations apart.
|
|
146
|
+
*
|
|
147
|
+
* Read from `PII_HMAC_KEY_VERSION` so the repository write path (which runs
|
|
148
|
+
* inside the Next.js/Functions runtime) and `backfill-blind-index.mjs`
|
|
149
|
+
* (which runs as a standalone script before `appkit/dist` is necessarily
|
|
150
|
+
* current) agree without importing from each other.
|
|
151
|
+
*/
|
|
152
|
+
export const CURRENT_BLIND_INDEX_KEY_VERSION = Number((typeof process !== "undefined" ? process.env?.PII_HMAC_KEY_VERSION : undefined) ?? "1");
|
package/dist/security/index.d.ts
CHANGED
|
@@ -10,4 +10,4 @@ export { encryptValue, decryptValue, hmacBlindIndex, encryptPiiFields, decryptPi
|
|
|
10
10
|
export { revealPii, maskPii, revealPiiAll, maskPiiAll } from "./pii-accessors";
|
|
11
11
|
export { isPiiEncrypted, maskName, maskEmail, maskPhone, maskPublicReview, maskPublicBid, maskPublicEventEntry, maskOfferForSeller, ENC_PREFIX, HMAC_PREFIX, } from "./pii-mask";
|
|
12
12
|
export { USER_PII_FIELDS, USER_PII_INDEX_MAP, ADDRESS_PII_FIELDS, ORDER_PII_FIELDS, PAYOUT_PII_FIELDS, PAYOUT_PII_INDEX_MAP, BID_PII_FIELDS, TOKEN_PII_FIELDS, TOKEN_PII_INDEX_MAP, REVIEW_PII_FIELDS, REVIEW_PII_INDEX_MAP, OFFER_PII_FIELDS, EVENT_ENTRY_PII_FIELDS, LOTTERY_ENTRY_PII_FIELDS, PAYMENT_METHOD_PII_FIELDS, CONVERSATION_PII_FIELDS, MESSAGE_PII_FIELDS, } from "./pii-schemas";
|
|
13
|
-
export { encryptSecret, decryptSecret, isSecretEncrypted, maskSecret, } from "./settings-encryption";
|
|
13
|
+
export { encryptSecret, decryptSecret, isSecretEncrypted, maskSecret, encryptBuffer, decryptBuffer, isBufferEncrypted, } from "./settings-encryption";
|
package/dist/security/index.js
CHANGED
|
@@ -22,7 +22,7 @@ export { revealPii, maskPii, revealPiiAll, maskPiiAll } from "./pii-accessors.js
|
|
|
22
22
|
// universal client+server index.ts. See pii-mask.ts's header comment.
|
|
23
23
|
export { isPiiEncrypted, maskName, maskEmail, maskPhone, maskPublicReview, maskPublicBid, maskPublicEventEntry, maskOfferForSeller, ENC_PREFIX, HMAC_PREFIX, } from "./pii-mask.js";
|
|
24
24
|
export { USER_PII_FIELDS, USER_PII_INDEX_MAP, ADDRESS_PII_FIELDS, ORDER_PII_FIELDS, PAYOUT_PII_FIELDS, PAYOUT_PII_INDEX_MAP, BID_PII_FIELDS, TOKEN_PII_FIELDS, TOKEN_PII_INDEX_MAP, REVIEW_PII_FIELDS, REVIEW_PII_INDEX_MAP, OFFER_PII_FIELDS, EVENT_ENTRY_PII_FIELDS, LOTTERY_ENTRY_PII_FIELDS, PAYMENT_METHOD_PII_FIELDS, CONVERSATION_PII_FIELDS, MESSAGE_PII_FIELDS, } from "./pii-schemas.js";
|
|
25
|
-
export { encryptSecret, decryptSecret, isSecretEncrypted, maskSecret, } from "./settings-encryption.js";
|
|
25
|
+
export { encryptSecret, decryptSecret, isSecretEncrypted, maskSecret, encryptBuffer, decryptBuffer, isBufferEncrypted, } from "./settings-encryption.js";
|
|
26
26
|
// RBAC system — DELETED 2026-08-29.
|
|
27
27
|
//
|
|
28
28
|
// `security/rbac/**` was a complete second permission system: DEFAULT_ROLES,
|
|
@@ -1,4 +1,39 @@
|
|
|
1
1
|
export declare function encryptSecret(plaintext: string): string;
|
|
2
2
|
export declare function decryptSecret(encrypted: string): string;
|
|
3
3
|
export declare function isSecretEncrypted(value: string): boolean;
|
|
4
|
+
/**
|
|
5
|
+
* AES-256-GCM a file's bytes under `SETTINGS_ENCRYPTION_KEY`.
|
|
6
|
+
*
|
|
7
|
+
* Throws when the key is unset — deliberately, and identically to
|
|
8
|
+
* `encryptSecret`. A document store that silently writes plaintext when
|
|
9
|
+
* misconfigured is worse than one that refuses, because nothing downstream can
|
|
10
|
+
* tell the two apart afterwards.
|
|
11
|
+
*/
|
|
12
|
+
export declare function encryptBuffer(plaintext: Buffer): Buffer;
|
|
13
|
+
/**
|
|
14
|
+
* Reverse `encryptBuffer`.
|
|
15
|
+
*
|
|
16
|
+
* 🛑 Unlike `decryptSecret`, a buffer with no `enc:v1:` prefix is REJECTED
|
|
17
|
+
* rather than passed through. That asymmetry is intentional. `decryptSecret`
|
|
18
|
+
* tolerates plaintext because the settings collection genuinely holds
|
|
19
|
+
* unencrypted placeholders that predate encryption, so passing them through is
|
|
20
|
+
* the migration path. Here there is no such legacy: every object this reads was
|
|
21
|
+
* written by `encryptBuffer`, so an unprefixed buffer means the wrong object,
|
|
22
|
+
* a truncated download, or an upload that bypassed encryption — and returning
|
|
23
|
+
* it verbatim would serve one of those to an admin as though it were fine.
|
|
24
|
+
*
|
|
25
|
+
* GCM authentication also means `final()` throws on any tampering or on the
|
|
26
|
+
* wrong key, so a corrupted object fails loudly instead of yielding garbage.
|
|
27
|
+
*/
|
|
28
|
+
export declare function decryptBuffer(encrypted: Buffer): Buffer;
|
|
29
|
+
/**
|
|
30
|
+
* True when `buf` carries the binary envelope AND is long enough to hold a
|
|
31
|
+
* complete one.
|
|
32
|
+
*
|
|
33
|
+
* The length check is not pedantry: without it a 7-byte buffer containing only
|
|
34
|
+
* the prefix passes, and `decryptBuffer` then hands `createDecipheriv` a
|
|
35
|
+
* zero-length IV, which throws `Invalid initialization vector` — an error that
|
|
36
|
+
* describes the crypto call rather than the truncated download that caused it.
|
|
37
|
+
*/
|
|
38
|
+
export declare function isBufferEncrypted(buf: Buffer): boolean;
|
|
4
39
|
export declare function maskSecret(value: string): string;
|