@mohasinac/appkit 4.52.4 → 4.53.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/.build-stamp.json +4 -4
- package/dist/_internal/client/features/sticker-trace/canvas-codec.d.ts +2 -0
- package/dist/_internal/client/features/sticker-trace/canvas-codec.js +148 -0
- package/dist/_internal/server/features/auctions/actions.js +1 -1
- package/dist/_internal/server/features/categories/data.js +23 -7
- package/dist/_internal/server/features/checkout/actions.js +10 -3
- package/dist/_internal/server/features/checkout/data.d.ts +15 -0
- package/dist/_internal/server/features/checkout/data.js +20 -3
- package/dist/_internal/server/features/lottery/actions.js +9 -1
- package/dist/_internal/server/features/lottery/og.d.ts +40 -0
- package/dist/_internal/server/features/lottery/og.js +79 -0
- package/dist/_internal/server/features/messages/actions.js +4 -0
- package/dist/_internal/server/features/offers/adapters.js +17 -3
- package/dist/_internal/server/features/orders/actions.js +7 -2
- package/dist/_internal/server/features/raffle/actions.d.ts +19 -0
- package/dist/_internal/server/features/raffle/actions.js +25 -0
- package/dist/_internal/server/features/reviews/actions.js +1 -1
- package/dist/_internal/server/features/reviews/data.d.ts +1 -1
- package/dist/_internal/server/features/search/index-build/artifact-store.d.ts +89 -0
- package/dist/_internal/server/features/search/index-build/artifact-store.js +208 -0
- package/dist/_internal/server/features/search/index-build/build.d.ts +57 -0
- package/dist/_internal/server/features/search/index-build/build.js +285 -0
- package/dist/_internal/server/features/search/index-build/sources.d.ts +53 -0
- package/dist/_internal/server/features/search/index-build/sources.js +385 -0
- package/dist/_internal/server/features/search/search-sources.d.ts +0 -15
- package/dist/_internal/server/features/search/search-sources.js +142 -7
- package/dist/_internal/server/features/seo/robots.js +21 -1
- package/dist/_internal/server/features/seo/sitemap.js +1 -1
- package/dist/_internal/server/features/shared/listing-data-factory.js +16 -4
- package/dist/_internal/server/features/site-settings/adapters.d.ts +1 -1
- package/dist/_internal/server/features/site-settings/adapters.js +26 -0
- package/dist/_internal/server/features/sticker-trace/actions.d.ts +109 -0
- package/dist/_internal/server/features/sticker-trace/actions.js +172 -0
- package/dist/_internal/server/features/sticker-trace/adapters.d.ts +80 -0
- package/dist/_internal/server/features/sticker-trace/adapters.js +174 -0
- package/dist/_internal/server/features/sticker-trace/build-cut-file.d.ts +26 -0
- package/dist/_internal/server/features/sticker-trace/build-cut-file.js +127 -0
- package/dist/_internal/server/features/sticker-trace/coordinator.d.ts +27 -0
- package/dist/_internal/server/features/sticker-trace/coordinator.js +169 -0
- package/dist/_internal/server/features/sticker-trace/fanout.d.ts +43 -0
- package/dist/_internal/server/features/sticker-trace/fanout.js +180 -0
- package/dist/_internal/server/features/sticker-trace/finalizer.d.ts +25 -0
- package/dist/_internal/server/features/sticker-trace/finalizer.js +123 -0
- package/dist/_internal/server/features/sticker-trace/mosaic-inputs.d.ts +30 -0
- package/dist/_internal/server/features/sticker-trace/mosaic-inputs.js +112 -0
- package/dist/_internal/server/features/sticker-trace/progress.d.ts +81 -0
- package/dist/_internal/server/features/sticker-trace/progress.js +198 -0
- package/dist/_internal/server/features/sticker-trace/promote.d.ts +23 -0
- package/dist/_internal/server/features/sticker-trace/promote.js +193 -0
- package/dist/_internal/server/features/sticker-trace/shard.d.ts +50 -0
- package/dist/_internal/server/features/sticker-trace/shard.js +174 -0
- package/dist/_internal/server/features/sticker-trace/sheet-actions.d.ts +141 -0
- package/dist/_internal/server/features/sticker-trace/sheet-actions.js +279 -0
- package/dist/_internal/server/features/sticker-trace/storage.d.ts +135 -0
- package/dist/_internal/server/features/sticker-trace/storage.js +282 -0
- package/dist/_internal/server/functions/scheduled.d.ts +2 -1
- package/dist/_internal/server/functions/scheduled.js +25 -1
- package/dist/_internal/server/jobs/core/_event-ref.d.ts +51 -0
- package/dist/_internal/server/jobs/core/_event-ref.js +63 -0
- package/dist/_internal/server/jobs/core/assignSpinPrize.d.ts +18 -0
- package/dist/_internal/server/jobs/core/assignSpinPrize.js +77 -16
- package/dist/_internal/server/jobs/core/auctionSettlement.js +13 -4
- package/dist/_internal/server/jobs/core/autoPayoutEligibility.js +44 -15
- package/dist/_internal/server/jobs/core/bundleStockSync.js +3 -4
- package/dist/_internal/server/jobs/core/cleanupRtdbEvents.js +44 -0
- package/dist/_internal/server/jobs/core/event-draw-reasons.d.ts +78 -0
- package/dist/_internal/server/jobs/core/event-draw-reasons.js +133 -0
- package/dist/_internal/server/jobs/core/listingProcessor.js +28 -8
- package/dist/_internal/server/jobs/core/onOrderCreate.js +12 -1
- package/dist/_internal/server/jobs/core/onScamReportCreate.js +13 -2
- package/dist/_internal/server/jobs/core/onScamReportRejected.js +8 -2
- package/dist/_internal/server/jobs/core/onScamReportVerified.js +8 -2
- package/dist/_internal/server/jobs/core/onStoreWrite.js +11 -4
- package/dist/_internal/server/jobs/core/prizeDrawAssignWinner.js +5 -4
- package/dist/_internal/server/jobs/core/prizeDrawExpiryReveal.js +1 -4
- package/dist/_internal/server/jobs/core/prizeDrawSoldOutReveal.js +1 -2
- package/dist/_internal/server/jobs/core/promotions.js +7 -4
- package/dist/_internal/server/jobs/core/searchIndexBuild.d.ts +7 -0
- package/dist/_internal/server/jobs/core/searchIndexBuild.js +211 -0
- package/dist/_internal/server/jobs/core/triggerEventRaffle.d.ts +35 -0
- package/dist/_internal/server/jobs/core/triggerEventRaffle.js +213 -31
- package/dist/_internal/server/jobs/core/weeklyPayoutEligibility.js +20 -14
- package/dist/_internal/server/jobs/handlers/assignSpinPrize.d.ts +8 -0
- package/dist/_internal/server/jobs/handlers/assignSpinPrize.js +15 -15
- package/dist/_internal/server/jobs/handlers/index.d.ts +1 -0
- package/dist/_internal/server/jobs/handlers/index.js +1 -0
- package/dist/_internal/server/jobs/handlers/onCategoryWrite.js +18 -0
- package/dist/_internal/server/jobs/handlers/onProductWrite.js +18 -0
- package/dist/_internal/server/jobs/handlers/onReviewWrite.js +18 -0
- package/dist/_internal/server/jobs/handlers/onScamReportUpdate.js +18 -0
- package/dist/_internal/server/jobs/handlers/onStoreWrite.js +18 -0
- package/dist/_internal/server/jobs/handlers/searchIndexBuild.d.ts +2 -0
- package/dist/_internal/server/jobs/handlers/searchIndexBuild.js +2 -0
- package/dist/_internal/server/jobs/handlers/triggerEventRaffle.d.ts +8 -0
- package/dist/_internal/server/jobs/handlers/triggerEventRaffle.js +15 -6
- package/dist/_internal/shared/actions/action-registry.js +29 -0
- package/dist/_internal/shared/cache/revalidate-targets.d.ts +0 -1
- package/dist/_internal/shared/cache/revalidate-targets.js +10 -8
- package/dist/_internal/shared/features/events/config.d.ts +14 -0
- package/dist/_internal/shared/features/events/config.js +14 -0
- package/dist/_internal/shared/features/notifications/action-url.js +8 -0
- package/dist/_internal/shared/features/site-settings/types.d.ts +11 -0
- package/dist/_internal/shared/features/sticker-trace/codec.d.ts +81 -0
- package/dist/_internal/shared/features/sticker-trace/codec.js +30 -0
- package/dist/_internal/shared/features/sticker-trace/config.d.ts +81 -0
- package/dist/_internal/shared/features/sticker-trace/config.js +177 -0
- package/dist/_internal/shared/features/sticker-trace/cut-contour.d.ts +20 -0
- package/dist/_internal/shared/features/sticker-trace/cut-contour.js +60 -0
- package/dist/_internal/shared/features/sticker-trace/export/build-export-set.d.ts +65 -0
- package/dist/_internal/shared/features/sticker-trace/export/build-export-set.js +176 -0
- package/dist/_internal/shared/features/sticker-trace/export/cut-svg.d.ts +56 -0
- package/dist/_internal/shared/features/sticker-trace/export/cut-svg.js +120 -0
- package/dist/_internal/shared/features/sticker-trace/export/machine-profiles.d.ts +92 -0
- package/dist/_internal/shared/features/sticker-trace/export/machine-profiles.js +153 -0
- package/dist/_internal/shared/features/sticker-trace/export/nesting.d.ts +51 -0
- package/dist/_internal/shared/features/sticker-trace/export/nesting.js +110 -0
- package/dist/_internal/shared/features/sticker-trace/export/page-sizes.d.ts +68 -0
- package/dist/_internal/shared/features/sticker-trace/export/page-sizes.js +223 -0
- package/dist/_internal/shared/features/sticker-trace/export/part-tiling.d.ts +51 -0
- package/dist/_internal/shared/features/sticker-trace/export/part-tiling.js +178 -0
- package/dist/_internal/shared/features/sticker-trace/export/simplify-budget.d.ts +26 -0
- package/dist/_internal/shared/features/sticker-trace/export/simplify-budget.js +134 -0
- package/dist/_internal/shared/features/sticker-trace/export/vectorise-art.d.ts +40 -0
- package/dist/_internal/shared/features/sticker-trace/export/vectorise-art.js +195 -0
- package/dist/_internal/shared/features/sticker-trace/index.d.ts +2 -0
- package/dist/_internal/shared/features/sticker-trace/index.js +59 -0
- package/dist/_internal/shared/features/sticker-trace/math/catmull-rom.d.ts +11 -0
- package/dist/_internal/shared/features/sticker-trace/math/catmull-rom.js +66 -0
- package/dist/_internal/shared/features/sticker-trace/math/edt.d.ts +27 -0
- package/dist/_internal/shared/features/sticker-trace/math/edt.js +165 -0
- package/dist/_internal/shared/features/sticker-trace/math/label.d.ts +15 -0
- package/dist/_internal/shared/features/sticker-trace/math/label.js +156 -0
- package/dist/_internal/shared/features/sticker-trace/math/marching-squares.d.ts +16 -0
- package/dist/_internal/shared/features/sticker-trace/math/marching-squares.js +242 -0
- package/dist/_internal/shared/features/sticker-trace/math/morphology.d.ts +46 -0
- package/dist/_internal/shared/features/sticker-trace/math/morphology.js +168 -0
- package/dist/_internal/shared/features/sticker-trace/math/rasterize-path.d.ts +88 -0
- package/dist/_internal/shared/features/sticker-trace/math/rasterize-path.js +286 -0
- package/dist/_internal/shared/features/sticker-trace/math/rdp.d.ts +10 -0
- package/dist/_internal/shared/features/sticker-trace/math/rdp.js +74 -0
- package/dist/_internal/shared/features/sticker-trace/resume.d.ts +50 -0
- package/dist/_internal/shared/features/sticker-trace/resume.js +160 -0
- package/dist/_internal/shared/features/sticker-trace/trace/cluster.d.ts +20 -0
- package/dist/_internal/shared/features/sticker-trace/trace/cluster.js +132 -0
- package/dist/_internal/shared/features/sticker-trace/trace/cross-profile.d.ts +28 -0
- package/dist/_internal/shared/features/sticker-trace/trace/cross-profile.js +120 -0
- package/dist/_internal/shared/features/sticker-trace/trace/flood.d.ts +21 -0
- package/dist/_internal/shared/features/sticker-trace/trace/flood.js +104 -0
- package/dist/_internal/shared/features/sticker-trace/trace/geometry.d.ts +3 -0
- package/dist/_internal/shared/features/sticker-trace/trace/geometry.js +140 -0
- package/dist/_internal/shared/features/sticker-trace/trace/line-filter.d.ts +15 -0
- package/dist/_internal/shared/features/sticker-trace/trace/line-filter.js +138 -0
- package/dist/_internal/shared/features/sticker-trace/trace/merge.d.ts +27 -0
- package/dist/_internal/shared/features/sticker-trace/trace/merge.js +187 -0
- package/dist/_internal/shared/features/sticker-trace/trace/paper.d.ts +32 -0
- package/dist/_internal/shared/features/sticker-trace/trace/paper.js +147 -0
- package/dist/_internal/shared/features/sticker-trace/trace/prefilter.d.ts +30 -0
- package/dist/_internal/shared/features/sticker-trace/trace/prefilter.js +125 -0
- package/dist/_internal/shared/features/sticker-trace/trace/quantise.d.ts +10 -0
- package/dist/_internal/shared/features/sticker-trace/trace/quantise.js +153 -0
- package/dist/_internal/shared/features/sticker-trace/trace/ridge.d.ts +88 -0
- package/dist/_internal/shared/features/sticker-trace/trace/ridge.js +344 -0
- package/dist/_internal/shared/features/sticker-trace/trace/segment.d.ts +10 -0
- package/dist/_internal/shared/features/sticker-trace/trace/segment.js +251 -0
- package/dist/_internal/shared/features/sticker-trace/types.d.ts +197 -0
- package/dist/_internal/shared/features/sticker-trace/types.js +49 -0
- package/dist/_internal/shared/listing-types/_registry.d.ts +11 -0
- package/dist/_internal/shared/listing-types/art/config.d.ts +1 -0
- package/dist/_internal/shared/listing-types/art/config.js +1 -0
- package/dist/_internal/shared/listing-types/auction/config.d.ts +1 -0
- package/dist/_internal/shared/listing-types/auction/config.js +1 -0
- package/dist/_internal/shared/listing-types/classified/config.d.ts +1 -0
- package/dist/_internal/shared/listing-types/classified/config.js +1 -0
- package/dist/_internal/shared/listing-types/digital-code/config.d.ts +1 -0
- package/dist/_internal/shared/listing-types/digital-code/config.js +1 -0
- package/dist/_internal/shared/listing-types/feature-flags.d.ts +7 -0
- package/dist/_internal/shared/listing-types/feature-flags.js +9 -0
- package/dist/_internal/shared/listing-types/live/config.d.ts +1 -0
- package/dist/_internal/shared/listing-types/live/config.js +1 -0
- package/dist/_internal/shared/listing-types/pre-order/config.d.ts +1 -0
- package/dist/_internal/shared/listing-types/pre-order/config.js +1 -0
- package/dist/_internal/shared/listing-types/prize-draw/config.d.ts +1 -0
- package/dist/_internal/shared/listing-types/prize-draw/config.js +1 -0
- package/dist/_internal/shared/listing-types/standard/config.d.ts +1 -0
- package/dist/_internal/shared/listing-types/standard/config.js +1 -0
- package/dist/_internal/shared/listing-types/stickers/config.d.ts +1 -0
- package/dist/_internal/shared/listing-types/stickers/config.js +1 -0
- package/dist/_internal/shared/media/limits.d.ts +12 -2
- package/dist/_internal/shared/media/limits.js +12 -2
- package/dist/_internal/shared/search/artifact-url.d.ts +35 -0
- package/dist/_internal/shared/search/artifact-url.js +119 -0
- package/dist/_internal/shared/search/index-record.d.ts +68 -0
- package/dist/_internal/shared/search/index-record.js +96 -0
- package/dist/_internal/shared/search/match.d.ts +65 -0
- package/dist/_internal/shared/search/match.js +263 -0
- package/dist/client.d.ts +8 -7
- package/dist/client.js +12 -5
- package/dist/configs/eslint.js +22 -2
- package/dist/constants/api-endpoints.d.ts +68 -0
- package/dist/constants/api-endpoints.js +32 -0
- package/dist/constants/field-names.d.ts +7 -1
- package/dist/constants/field-names.js +36 -1
- package/dist/contracts/repository.d.ts +8 -7
- package/dist/contracts/search.d.ts +2 -2
- package/dist/contracts/table.d.ts +3 -3
- package/dist/contracts/table.js +3 -3
- package/dist/core/contact-submissions.repository.js +2 -2
- package/dist/core/integration-keys.js +7 -1
- package/dist/core/newsletter.repository.js +2 -2
- package/dist/core/site-config.js +1 -1
- package/dist/errors/error-codes.d.ts +30 -0
- package/dist/errors/error-codes.js +30 -0
- package/dist/errors/error-display-map.js +40 -1
- package/dist/features/account/api/[userId]/addresses/route.js +1 -1
- package/dist/features/account/components/UserBidsView.js +1 -1
- package/dist/features/account/components/index.d.ts +0 -8
- package/dist/features/account/components/index.js +0 -4
- package/dist/features/addresses/repository/addresses.repository.d.ts +17 -6
- package/dist/features/addresses/repository/addresses.repository.js +65 -9
- package/dist/features/addresses/schemas/firestore.d.ts +17 -6
- package/dist/features/admin/actions/notification-actions.js +15 -6
- package/dist/features/admin/api/bids/route.js +1 -1
- package/dist/features/admin/api/coupons/route.js +1 -1
- package/dist/features/admin/api/products/route.js +1 -1
- package/dist/features/admin/api/reviews/route.js +1 -1
- package/dist/features/admin/components/AdminAdEditorView.js +19 -5
- package/dist/features/admin/components/AdminAuditLogView.js +1 -1
- package/dist/features/admin/components/AdminBlogEditorView.js +0 -1
- package/dist/features/admin/components/AdminBlogView.js +1 -1
- package/dist/features/admin/components/AdminBrandsView.js +17 -1
- package/dist/features/admin/components/AdminCategoryEditorView.js +0 -1
- package/dist/features/admin/components/AdminContactView.js +1 -1
- package/dist/features/admin/components/AdminEmployeeEditorView.js +1 -3
- package/dist/features/admin/components/AdminNewsletterView.js +1 -1
- package/dist/features/admin/components/AdminOrdersView.js +9 -2
- package/dist/features/admin/components/AdminPayoutsView.js +1 -1
- package/dist/features/admin/components/AdminPrizeDrawsView.js +11 -0
- package/dist/features/admin/components/AdminProductEditorView.d.ts +10 -1
- package/dist/features/admin/components/AdminProductEditorView.js +24 -37
- package/dist/features/admin/components/AdminProductsView.js +10 -3
- package/dist/features/admin/components/AdminScammersView.js +1 -1
- package/dist/features/admin/components/AdminSectionsView.js +21 -5
- package/dist/features/admin/components/AdminSessionsView.js +1 -1
- package/dist/features/admin/components/AdminSublistingCategoriesView.js +22 -1
- package/dist/features/admin/components/AdminTeamView.js +1 -1
- package/dist/features/admin/components/AdminTesterChecklistItemEditorView.js +0 -1
- package/dist/features/admin/components/AdminUsersView.js +1 -1
- package/dist/features/admin/components/DataListingView.d.ts +2 -1
- package/dist/features/admin/components/DataListingView.js +9 -4
- package/dist/features/admin/components/analytics/AdminPageViewsReportView.js +0 -2
- package/dist/features/admin/hooks/useAdminListing.d.ts +1 -1
- package/dist/features/admin/repository/site-settings.repository.js +8 -3
- package/dist/features/admin/schemas/firestore.d.ts +62 -1
- package/dist/features/admin/schemas/firestore.js +32 -0
- package/dist/features/admin/types/index.d.ts +1 -1
- package/dist/features/auctions/actions/bid-actions.d.ts +2 -2
- package/dist/features/auctions/actions/bid-actions.js +16 -4
- package/dist/features/auctions/api/route.js +1 -1
- package/dist/features/auctions/components/AuctionBottomActions.js +4 -0
- package/dist/features/auctions/repository/bid.repository.d.ts +46 -4
- package/dist/features/auctions/repository/bid.repository.js +114 -13
- package/dist/features/auctions/schemas/firestore.d.ts +24 -4
- package/dist/features/auctions/schemas/firestore.js +1 -0
- package/dist/features/auth/actions/profile-actions.js +30 -4
- package/dist/features/auth/components/index.d.ts +0 -1
- package/dist/features/auth/components/index.js +0 -1
- package/dist/features/auth/repository/session.repository.d.ts +17 -3
- package/dist/features/auth/repository/session.repository.js +46 -5
- package/dist/features/auth/repository/token.repository.d.ts +27 -4
- package/dist/features/auth/repository/token.repository.js +65 -11
- package/dist/features/auth/repository/user.repository.d.ts +33 -7
- package/dist/features/auth/repository/user.repository.js +100 -15
- package/dist/features/auth/schemas/firestore.d.ts +63 -12
- package/dist/features/auth/schemas/firestore.js +11 -0
- package/dist/features/before-after/api/route.js +1 -1
- package/dist/features/blog/components/BlogListView.js +16 -3
- package/dist/features/blog/components/BlogPostView.js +1 -1
- package/dist/features/blog/schemas/index.d.ts +2 -2
- package/dist/features/cart/api/route.js +1 -1
- package/dist/features/catalogue/repository/catalogue.repository.d.ts +7 -7
- package/dist/features/catalogue/repository/catalogue.repository.js +28 -10
- package/dist/features/catalogue/schemas/firestore.d.ts +11 -0
- package/dist/features/categories/api/route.js +10 -10
- package/dist/features/categories/components/CategoryDetailPageView.js +35 -5
- package/dist/features/categories/components/CategorySelectorCreate.js +0 -1
- package/dist/features/categories/components/index.d.ts +0 -2
- package/dist/features/categories/components/index.js +0 -1
- package/dist/features/categories/repository/categories.repository.d.ts +1 -0
- package/dist/features/categories/repository/categories.repository.js +31 -1
- package/dist/features/categories/schemas/index.d.ts +2 -2
- package/dist/features/categories/utils/taxonomy-visual.d.ts +21 -0
- package/dist/features/categories/utils/taxonomy-visual.js +58 -0
- package/dist/features/checkout/actions/checkout-value-otp-actions.js +8 -1
- package/dist/features/collections/api/[slug]/route.js +3 -3
- package/dist/features/collections/api/route.js +1 -1
- package/dist/features/consultation/api/route.js +1 -1
- package/dist/features/consultation/repository/consultations.repository.js +1 -1
- package/dist/features/consultation/types/index.d.ts +1 -1
- package/dist/features/contact/components/ContactForm.js +1 -3
- package/dist/features/corporate/api/route.js +1 -1
- package/dist/features/corporate/repository/corporate.repository.js +1 -1
- package/dist/features/corporate/types/index.d.ts +1 -1
- package/dist/features/cron/jobs/auction-expiry.job.js +1 -1
- package/dist/features/cron/jobs/preorder-reminder.job.js +1 -1
- package/dist/features/events/actions/event-actions.d.ts +14 -0
- package/dist/features/events/actions/event-actions.js +82 -3
- package/dist/features/events/api/[id]/route.js +2 -2
- package/dist/features/events/components/AdminEventEditorView.js +22 -3
- package/dist/features/events/components/AdminEventsView.js +32 -8
- package/dist/features/events/components/EventRafflesSection.d.ts +34 -1
- package/dist/features/events/components/EventRafflesSection.js +52 -3
- package/dist/features/events/components/SpinWheelView.d.ts +2 -2
- package/dist/features/events/components/SpinWheelView.js +41 -4
- package/dist/features/events/repository/event-entry.repository.d.ts +14 -2
- package/dist/features/events/repository/event-entry.repository.js +41 -7
- package/dist/features/events/schemas/firestore.d.ts +17 -4
- package/dist/features/events/types/index.d.ts +37 -0
- package/dist/features/faq/repository/faqs.repository.js +1 -1
- package/dist/features/faq/schemas/index.d.ts +5 -2
- package/dist/features/faq/schemas/index.js +6 -0
- package/dist/features/faq/types/index.d.ts +0 -1
- package/dist/features/grouped/components/GroupedListingEditorView.js +17 -2
- package/dist/features/homepage/api/carousel/[id]/route.js +1 -1
- package/dist/features/homepage/api/carousel/route.js +4 -4
- package/dist/features/homepage/api/route.js +2 -2
- package/dist/features/homepage/api/sections/route.js +1 -1
- package/dist/features/homepage/components/AnnouncementBar.d.ts +1 -9
- package/dist/features/homepage/components/AnnouncementBar.js +13 -19
- package/dist/features/homepage/components/MarketplaceHomepageView.js +6 -1
- package/dist/features/homepage/components/index.d.ts +0 -2
- package/dist/features/homepage/components/index.js +0 -1
- package/dist/features/homepage/repository/homepage.repository.js +1 -1
- package/dist/features/homepage/schemas/firestore.d.ts +6 -0
- package/dist/features/homepage/schemas/index.d.ts +10 -10
- package/dist/features/layout/AppLayoutShell.d.ts +12 -3
- package/dist/features/layout/AppLayoutShell.js +65 -13
- package/dist/features/layout/BottomActionsContext.d.ts +16 -0
- package/dist/features/layout/BottomActionsContext.js +5 -0
- package/dist/features/layout/BottomChrome.js +48 -9
- package/dist/features/layout/BottomNavbar.d.ts +14 -0
- package/dist/features/layout/BottomNavbar.js +43 -3
- package/dist/features/layout/MainNavbar.d.ts +11 -0
- package/dist/features/layout/NavbarLayout.d.ts +3 -0
- package/dist/features/layout/NavbarLayout.js +88 -11
- package/dist/features/layout/SideActionDock.d.ts +1 -0
- package/dist/features/layout/SideActionDock.js +219 -0
- package/dist/features/layout/TitleBarLayout.d.ts +1 -3
- package/dist/features/layout/TitleBarLayout.js +3 -4
- package/dist/features/layout/cta-anchor.d.ts +31 -0
- package/dist/features/layout/cta-anchor.js +31 -0
- package/dist/features/layout/hooks/useBottomActions.d.ts +7 -0
- package/dist/features/layout/hooks/useBottomActions.js +6 -1
- package/dist/features/layout/index.d.ts +9 -1
- package/dist/features/layout/index.js +9 -1
- package/dist/features/layout/useCtaReveal.d.ts +24 -0
- package/dist/features/layout/useCtaReveal.js +82 -0
- package/dist/features/layout/useHoldToOpen.d.ts +41 -0
- package/dist/features/layout/useHoldToOpen.js +84 -0
- package/dist/features/lottery/repository/lottery-entry.repository.d.ts +18 -3
- package/dist/features/lottery/repository/lottery-entry.repository.js +48 -6
- package/dist/features/lottery/schemas/firestore.d.ts +33 -5
- package/dist/features/loyalty/api/balance/route.js +1 -1
- package/dist/features/loyalty/api/history/route.js +1 -1
- package/dist/features/media/MediaImage.js +0 -1
- package/dist/features/media/MediaPickerModal.js +7 -1
- package/dist/features/media/modals/ImageEditor.js +5 -1
- package/dist/features/media/modals/VideoThumbnailSelector.js +17 -1
- package/dist/features/media/repository/media-assets.repository.d.ts +19 -0
- package/dist/features/media/upload/CameraCapture.js +16 -1
- package/dist/features/media/upload/ImageUpload.js +42 -4
- package/dist/features/media/upload/MediaUploadField.js +69 -13
- package/dist/features/media/upload/downscale-image.d.ts +56 -0
- package/dist/features/media/upload/downscale-image.js +150 -0
- package/dist/features/messages/components/ConversationThreadView.js +45 -2
- package/dist/features/messages/components/MessageSellerButton.d.ts +15 -1
- package/dist/features/messages/components/MessageSellerButton.js +10 -2
- package/dist/features/messages/schemas/firestore.d.ts +15 -0
- package/dist/features/orders/hooks/useOrders.js +4 -2
- package/dist/features/orders/repository/orders.repository.d.ts +15 -4
- package/dist/features/orders/repository/orders.repository.js +52 -20
- package/dist/features/orders/schemas/firestore.d.ts +15 -4
- package/dist/features/orders/schemas/index.d.ts +8 -8
- package/dist/features/orders/types/index.d.ts +2 -2
- package/dist/features/payments/repository/payments.repository.js +2 -2
- package/dist/features/payments/repository/payout.repository.d.ts +23 -6
- package/dist/features/payments/repository/payout.repository.js +63 -23
- package/dist/features/payments/repository/saved-payment-methods.repository.d.ts +17 -6
- package/dist/features/payments/repository/saved-payment-methods.repository.js +59 -11
- package/dist/features/payments/schemas/firestore.d.ts +14 -3
- package/dist/features/payments/schemas/saved-methods-firestore.d.ts +12 -1
- package/dist/features/pre-orders/api/[slug]/route.js +1 -1
- package/dist/features/pre-orders/api/admin/route.js +1 -1
- package/dist/features/pre-orders/api/route.js +1 -1
- package/dist/features/pre-orders/repository/pre-orders.repository.d.ts +3 -3
- package/dist/features/pre-orders/repository/pre-orders.repository.js +6 -6
- package/dist/features/products/api/[id]/route.js +1 -1
- package/dist/features/products/components/ListingBottomActions.js +4 -0
- package/dist/features/products/components/ProductDetailPageView.js +2 -1
- package/dist/features/products/components/ProductGalleryClient.js +2 -2
- package/dist/features/products/components/ProductGrid.js +12 -1
- package/dist/features/products/components/index.d.ts +0 -2
- package/dist/features/products/components/index.js +0 -1
- package/dist/features/products/config/listing-type-listing-config.d.ts +0 -3
- package/dist/features/products/config/listing-type-listing-config.js +27 -2
- package/dist/features/products/constants/listing-tabs.d.ts +9 -0
- package/dist/features/products/constants/listing-tabs.js +3 -2
- package/dist/features/products/hooks/useProducts.js +2 -2
- package/dist/features/products/repository/products.repository.js +13 -1
- package/dist/features/products/schemas/index.d.ts +2 -2
- package/dist/features/products/types/index.d.ts +1 -1
- package/dist/features/promotions/api/route.js +1 -1
- package/dist/features/reviews/actions/review-actions.d.ts +6 -6
- package/dist/features/reviews/actions/review-actions.js +22 -8
- package/dist/features/reviews/components/ReviewDetailPageView.js +13 -1
- package/dist/features/reviews/components/ReviewsIndexPageView.js +21 -4
- package/dist/features/reviews/repository/reviews.repository.d.ts +19 -7
- package/dist/features/reviews/repository/reviews.repository.js +63 -12
- package/dist/features/reviews/schemas/firestore.d.ts +13 -2
- package/dist/features/reviews/schemas/index.d.ts +2 -2
- package/dist/features/scams/actions/scam-actions.js +16 -4
- package/dist/features/search/components/SearchResultsPageView.js +2 -1
- package/dist/features/search/hooks/useSearchIndex.d.ts +34 -0
- package/dist/features/search/hooks/useSearchIndex.js +172 -0
- package/dist/features/search/repository/search.repository.js +2 -2
- package/dist/features/seller/actions/offer-actions.d.ts +5 -5
- package/dist/features/seller/actions/offer-actions.js +38 -8
- package/dist/features/seller/actions/seller-actions.js +34 -7
- package/dist/features/seller/api/coupons/route.js +1 -1
- package/dist/features/seller/api/products/route.js +1 -1
- package/dist/features/seller/api/store/route.js +1 -1
- package/dist/features/seller/components/SellerBidsView.js +1 -1
- package/dist/features/seller/components/SellerCouponsView.js +1 -1
- package/dist/features/seller/components/SellerListingTypeView.js +9 -1
- package/dist/features/seller/components/SellerOrdersView.js +1 -1
- package/dist/features/seller/components/SellerPayoutSettingsView.js +0 -1
- package/dist/features/seller/components/SellerPayoutsView.js +1 -1
- package/dist/features/seller/components/SellerProductShell.js +0 -1
- package/dist/features/seller/components/SellerProductsView.js +1 -1
- package/dist/features/seller/components/SellerShippingView.js +0 -1
- package/dist/features/seller/components/SellerStorefrontView.js +0 -1
- package/dist/features/seller/components/index.d.ts +0 -4
- package/dist/features/seller/components/index.js +0 -2
- package/dist/features/seller/repository/offer.repository.d.ts +15 -3
- package/dist/features/seller/repository/offer.repository.js +43 -7
- package/dist/features/seller/schemas/firestore.d.ts +14 -3
- package/dist/features/seller/schemas/index.d.ts +4 -4
- package/dist/features/seller/schemas/order-forms.d.ts +39 -0
- package/dist/features/seller/schemas/order-forms.js +37 -0
- package/dist/features/shell/FormShell.js +6 -2
- package/dist/features/shell/QuickFormDrawer.js +15 -1
- package/dist/features/shipments/components/AdminShipmentEditorView.js +0 -1
- package/dist/features/shipments/components/AdminShipmentsView.js +1 -1
- package/dist/features/sticker-trace/components/StickerCommitPanel.d.ts +30 -0
- package/dist/features/sticker-trace/components/StickerCommitPanel.js +93 -0
- package/dist/features/sticker-trace/components/StickerPrintPanel.d.ts +33 -0
- package/dist/features/sticker-trace/components/StickerPrintPanel.js +104 -0
- package/dist/features/sticker-trace/components/StickerRetryPanel.d.ts +20 -0
- package/dist/features/sticker-trace/components/StickerRetryPanel.js +128 -0
- package/dist/features/sticker-trace/components/StickerRunHistoryPanel.d.ts +45 -0
- package/dist/features/sticker-trace/components/StickerRunHistoryPanel.js +84 -0
- package/dist/features/sticker-trace/components/StickerTraceStudio.d.ts +27 -0
- package/dist/features/sticker-trace/components/StickerTraceStudio.js +171 -0
- package/dist/features/sticker-trace/constants/help-content.d.ts +23 -0
- package/dist/features/sticker-trace/constants/help-content.js +172 -0
- package/dist/features/sticker-trace/hooks/useLiveTrace.d.ts +27 -0
- package/dist/features/sticker-trace/hooks/useLiveTrace.js +160 -0
- package/dist/features/sticker-trace/hooks/useStickerTraceProgress.d.ts +22 -0
- package/dist/features/sticker-trace/hooks/useStickerTraceProgress.js +106 -0
- package/dist/features/sticker-trace/repository/sticker-sheets.repository.d.ts +113 -0
- package/dist/features/sticker-trace/repository/sticker-sheets.repository.js +146 -0
- package/dist/features/sticker-trace/repository/sticker-trace-runs.repository.d.ts +132 -0
- package/dist/features/sticker-trace/repository/sticker-trace-runs.repository.js +174 -0
- package/dist/features/sticker-trace/schemas/firestore.d.ts +248 -0
- package/dist/features/sticker-trace/schemas/firestore.js +79 -0
- package/dist/features/sticker-trace/server.d.ts +8 -0
- package/dist/features/sticker-trace/server.js +51 -0
- package/dist/features/stores/actions/store-query-actions.d.ts +2 -2
- package/dist/features/stores/actions/store-query-actions.js +7 -2
- package/dist/features/stores/api/[storeSlug]/auctions/route.js +3 -3
- package/dist/features/stores/api/[storeSlug]/products/route.js +3 -3
- package/dist/features/stores/api/[storeSlug]/reviews/route.js +1 -1
- package/dist/features/stores/api/[storeSlug]/route.js +1 -1
- package/dist/features/stores/components/StoreNavTabs.js +17 -2
- package/dist/features/stores/manifest.js +8 -4
- package/dist/features/support/repository/support.repository.d.ts +14 -3
- package/dist/features/support/repository/support.repository.js +93 -13
- package/dist/features/support/schemas/firestore.d.ts +16 -5
- package/dist/features/tester/seed-data/authored/admin__events-raffles-spin.js +61 -19
- package/dist/features/tester/seed-data/authored/buying__browsing-search.js +19 -3
- 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 +243 -0
- package/dist/features/tester/seed-data/authored/content-discovery__events.js +36 -10
- package/dist/features/tester/seed-data/authored/content-discovery__overflowing-pill-rows.d.ts +2 -0
- package/dist/features/tester/seed-data/authored/content-discovery__overflowing-pill-rows.js +209 -0
- package/dist/features/tester/seed-data/authored/design-ux__header-brand-mark-centring.d.ts +2 -0
- package/dist/features/tester/seed-data/authored/design-ux__header-brand-mark-centring.js +90 -0
- package/dist/features/tester/seed-data/authored/design-ux__header-controls-and-messages.d.ts +2 -0
- package/dist/features/tester/seed-data/authored/design-ux__header-controls-and-messages.js +85 -0
- package/dist/features/tester/seed-data/authored/index.js +10 -0
- package/dist/features/tester/seed-data/authored/selling__media-limits.js +19 -17
- package/dist/features/tester/seed-data/authored/selling__product-upload-details.js +10 -5
- package/dist/features/tester/seed-data/authored/tools__sticker-tracer.d.ts +2 -0
- package/dist/features/tester/seed-data/authored/tools__sticker-tracer.js +283 -0
- package/dist/features/tester/seed-data/tester-checklist-seed-data.js +235 -22
- package/dist/index.d.ts +10 -23
- package/dist/index.js +27 -19
- package/dist/next/api/routeHandler.js +9 -0
- package/dist/next/routing/require-record.d.ts +13 -0
- package/dist/next/routing/require-record.js +62 -0
- package/dist/next/routing/route-map.d.ts +4 -4
- package/dist/next/routing/route-map.js +25 -3
- package/dist/providers/db-firebase/base.d.ts +4 -2
- package/dist/providers/db-firebase/base.js +21 -5
- package/dist/providers/db-firebase/base.repository.d.ts +11 -9
- package/dist/providers/db-firebase/base.repository.js +19 -0
- package/dist/providers/db-firebase/rtdb-paths.d.ts +12 -0
- package/dist/providers/db-firebase/rtdb-paths.js +12 -0
- package/dist/react/ErrorBoundary.js +6 -1
- package/dist/react/hooks/realtime-event-constants.d.ts +1 -0
- package/dist/react/hooks/realtime-event-constants.js +8 -0
- package/dist/react/hooks/useEntityDelete.js +5 -1
- package/dist/react/hooks/useMessage.js +5 -1
- package/dist/repositories/index.d.ts +2 -2
- package/dist/repositories/index.js +6 -1
- package/dist/schemas/registry.d.ts +13 -20
- package/dist/schemas/registry.js +31 -14
- package/dist/schemas/webhooks/google-oauth.d.ts +2 -2
- package/dist/security/encrypted.d.ts +117 -0
- package/dist/security/encrypted.js +100 -0
- package/dist/security/index.d.ts +5 -2
- package/dist/security/index.js +16 -2
- package/dist/security/pii-accessors.d.ts +71 -0
- package/dist/security/pii-accessors.js +150 -0
- package/dist/security/pii-encrypt.d.ts +0 -8
- package/dist/security/pii-encrypt.js +22 -15
- package/dist/security/pii-mask.d.ts +18 -0
- package/dist/security/pii-mask.js +27 -0
- package/dist/seed/_helpers/search-txt-wrappers.d.ts +6 -6
- package/dist/seed/_helpers/search-txt-wrappers.js +22 -0
- package/dist/seed/addresses-seed-data.d.ts +2 -2
- package/dist/seed/authenticity-knowledge-seed-data.d.ts +34 -0
- package/dist/seed/authenticity-knowledge-seed-data.js +1277 -0
- package/dist/seed/bids-seed-data.d.ts +2 -2
- package/dist/seed/bids-seed-data.js +23 -2
- package/dist/seed/events-seed-data.d.ts +2 -2
- package/dist/seed/events-seed-data.js +5 -0
- package/dist/seed/faq-seed-data.js +175 -5
- package/dist/seed/homepage-sections-seed-data.js +39 -23
- package/dist/seed/index.d.ts +1 -0
- package/dist/seed/index.js +1 -0
- package/dist/seed/lottery-entries-seed-data.d.ts +2 -2
- package/dist/seed/offers-seed-data.d.ts +2 -2
- package/dist/seed/offers-seed-data.js +1 -1
- package/dist/seed/orders-seed-data.d.ts +2 -2
- package/dist/seed/payouts-seed-data.d.ts +2 -2
- package/dist/seed/payouts-seed-data.js +1 -1
- package/dist/seed/reviews-seed-data.d.ts +1 -2
- package/dist/seed/seed-purpose.js +7 -0
- package/dist/seed/sessions-seed-data.d.ts +2 -2
- package/dist/seed/sessions-seed-data.js +5 -0
- package/dist/seed/site-settings-seed-data.js +1 -1
- package/dist/seed/support-tickets-seed-data.d.ts +2 -2
- package/dist/seed/support-tickets-seed-data.js +1 -1
- package/dist/seed/users-seed-data.d.ts +2 -2
- package/dist/seed/users-seed-data.js +1 -1
- package/dist/seo/json-ld.js +5 -1
- package/dist/server.d.ts +18 -3
- package/dist/server.js +59 -3
- package/dist/styles.css +237 -1
- package/dist/tailwind-utilities.css +1 -1
- package/dist/ui/components/Button.js +7 -1
- package/dist/ui/components/FilterChipGroup.d.ts +11 -0
- package/dist/ui/components/FilterChipGroup.js +1 -1
- package/dist/ui/components/ImageGallery.js +6 -1
- package/dist/ui/components/ListingLayout.js +14 -8
- package/dist/ui/components/OverflowRow.d.ts +92 -0
- package/dist/ui/components/OverflowRow.js +203 -0
- package/dist/ui/components/OverflowRow.style.css +235 -0
- package/dist/ui/components/RecordDetailModal.js +14 -1
- package/dist/ui/components/RowActionMenu.js +5 -1
- package/dist/ui/components/SideDrawer.js +5 -1
- package/dist/ui/components/SideModal.js +9 -1
- package/dist/ui/components/TabBarShell.d.ts +12 -1
- package/dist/ui/components/TabBarShell.js +3 -2
- package/dist/ui/components/Tabs.js +36 -24
- package/dist/ui/components/Toast.d.ts +3 -24
- package/dist/ui/components/Toast.js +2 -19
- package/dist/ui/components/TopBannerPortal.d.ts +15 -0
- package/dist/ui/components/TopBannerPortal.js +19 -0
- package/dist/ui/components/UnsavedChangesModal.js +5 -1
- package/dist/ui/components/index.style.css +1 -0
- package/dist/ui/components/row-collapse.d.ts +15 -0
- package/dist/ui/components/row-collapse.js +127 -0
- package/dist/ui/components/toast-context.d.ts +63 -0
- package/dist/ui/components/toast-context.js +48 -0
- package/dist/ui/components/top-banner-slot.d.ts +37 -0
- package/dist/ui/components/top-banner-slot.js +45 -0
- package/dist/ui/icons/icon-registry.d.ts +6 -0
- package/dist/ui/icons/icon-registry.js +17 -1
- package/dist/ui/index.d.ts +2 -0
- package/dist/ui/index.js +1 -0
- package/dist/utils/array.helper.d.ts +2 -2
- package/dist/utils/array.helper.js +5 -5
- package/dist/utils/id-generators.d.ts +6 -0
- package/dist/utils/id-generators.js +10 -0
- package/dist/utils/media-url.js +0 -2
- package/dist/utils/search-txt-builders.d.ts +28 -4
- package/dist/utils/search-txt-builders.js +41 -1
- package/dist/validation/schemas.d.ts +8 -8
- package/package.json +6 -2
- package/scripts/seed-cli.mjs +3 -0
- package/dist/features/account/components/UserAddressesView.d.ts +0 -13
- package/dist/features/account/components/UserAddressesView.js +0 -5
- package/dist/features/account/components/UserNotificationsView.d.ts +0 -15
- package/dist/features/account/components/UserNotificationsView.js +0 -12
- package/dist/features/account/components/UserSettingsView.d.ts +0 -16
- package/dist/features/account/components/UserSettingsView.js +0 -13
- package/dist/features/account/components/UserSupportView.d.ts +0 -3
- package/dist/features/account/components/UserSupportView.js +0 -166
- package/dist/features/admin/components/DemoSeedView.d.ts +0 -11
- package/dist/features/admin/components/DemoSeedView.js +0 -5
- package/dist/features/auth/components/AuthStatusPanel.d.ts +0 -10
- package/dist/features/auth/components/AuthStatusPanel.js +0 -22
- package/dist/features/categories/components/CategoryProductsView.d.ts +0 -45
- package/dist/features/categories/components/CategoryProductsView.js +0 -21
- package/dist/features/homepage/components/HowItWorksInfoView.d.ts +0 -36
- package/dist/features/homepage/components/HowItWorksInfoView.js +0 -10
- package/dist/features/layout/BottomActions.d.ts +0 -1
- package/dist/features/layout/BottomActions.js +0 -311
- package/dist/features/products/components/ProductsView.d.ts +0 -6
- package/dist/features/products/components/ProductsView.js +0 -5
- package/dist/features/seller/components/SellerStoreView.d.ts +0 -8
- package/dist/features/seller/components/SellerStoreView.js +0 -8
|
@@ -0,0 +1,119 @@
|
|
|
1
|
+
/*
|
|
2
|
+
* WHY: The browser and the builder must agree on where the search artifact
|
|
3
|
+
* lives, and the obvious URL for a public Storage object is the wrong
|
|
4
|
+
* one.
|
|
5
|
+
* WHAT: The two public URLs — the manifest and a versioned artifact — derived
|
|
6
|
+
* from the bucket name alone, with no Firebase SDK on either side.
|
|
7
|
+
*
|
|
8
|
+
* ## 🛑 The plain `GCS_HOST` URL does NOT work. Measured.
|
|
9
|
+
*
|
|
10
|
+
* It is the first one anyone reaches for and it returns **403**:
|
|
11
|
+
*
|
|
12
|
+
* GET https://{GCS_HOST}/<bucket>/search-index/v3.json -> 403
|
|
13
|
+
* GET https://{FIREBASE_STORAGE_HOST}/v0/b/<bucket>/o/
|
|
14
|
+
* search-index%2Fv3.json?alt=media -> 200
|
|
15
|
+
*
|
|
16
|
+
* (Both hosts are named by their constants rather than spelled out, because
|
|
17
|
+
* `audit-firestore-storage-urls` is strict-zero on the literals and does not
|
|
18
|
+
* strip comments. That is the correct constraint, not a nuisance: the hosts
|
|
19
|
+
* have exactly one declaration, in `utils/media-url.ts`, and this file
|
|
20
|
+
* imports it rather than becoming a second.)
|
|
21
|
+
*
|
|
22
|
+
* `storage.rules`'s `allow read: if true` is a **Firebase Storage** rule. It
|
|
23
|
+
* is evaluated by the Firebase download endpoint and has no bearing on the
|
|
24
|
+
* plain GCS JSON/XML API, which answers to IAM and object ACLs — neither of
|
|
25
|
+
* which grants `allUsers`. So the rule that makes this artifact public only
|
|
26
|
+
* applies on one of the two hosts.
|
|
27
|
+
*
|
|
28
|
+
* ## 🛑 Why this is NOT a `/media/<slug>` reference
|
|
29
|
+
*
|
|
30
|
+
* That audit's stated rule is "every MEDIA reference flows through
|
|
31
|
+
* `/media/<slug>`", and this is not media. Two reasons it must not be routed
|
|
32
|
+
* that way:
|
|
33
|
+
*
|
|
34
|
+
* 1. the proxy resolves a slug through a `mediaAssets/{slug}` Firestore read
|
|
35
|
+
* and then watermarks images — neither of which means anything for a JSON
|
|
36
|
+
* data file;
|
|
37
|
+
* 2. it would put a Vercel function in the path of a 405 KB download for
|
|
38
|
+
* every cold visitor. Root Cause #104 is precisely that bill — 52.52 GB
|
|
39
|
+
* of Fast Origin Transfer against a 10 GB allowance — and the whole point
|
|
40
|
+
* of an immutable version-addressed object is that nothing of ours serves
|
|
41
|
+
* it twice.
|
|
42
|
+
*
|
|
43
|
+
* Verified on the live bucket 2026-10-19, on the second host:
|
|
44
|
+
*
|
|
45
|
+
* Cache-Control: public, max-age=31536000, immutable (passed through)
|
|
46
|
+
* Access-Control-Allow-Origin: https://www.letitrip.in
|
|
47
|
+
* Vary: Origin
|
|
48
|
+
* Content-Length: 418830
|
|
49
|
+
*
|
|
50
|
+
* So the response is cacheable, CORS-readable and non-opaque — which is the
|
|
51
|
+
* whole precondition for the service worker rule and for being able to tell a
|
|
52
|
+
* 404 apart from an empty index.
|
|
53
|
+
*
|
|
54
|
+
* ## 🛑 The tracked CORS config had drifted from the live bucket
|
|
55
|
+
*
|
|
56
|
+
* Found while verifying the above. `appkit/firebase/base/storage-cors.json`
|
|
57
|
+
* is the tracked source of truth and `npm run storage:cors` applies it — but
|
|
58
|
+
* the live bucket had an origin (`letitrip-in-app.vercel.app`), a method
|
|
59
|
+
* (`POST`) and two response headers (`x-goog-resumable`,
|
|
60
|
+
* `x-goog-content-length-range`) the file did not, all of which the
|
|
61
|
+
* resumable-upload path uses. So running the script to "sync" it would have
|
|
62
|
+
* NARROWED the live config and broken uploads, in a repo where that command
|
|
63
|
+
* reads like the safe, idempotent thing to do.
|
|
64
|
+
*
|
|
65
|
+
* The file is now a strict SUPERSET of what was measured live, so applying it
|
|
66
|
+
* can only widen. The config was NOT re-applied as part of this work: GET
|
|
67
|
+
* from the app origins already worked, and re-applying is an upload-path
|
|
68
|
+
* change that has no business riding along with a search feature.
|
|
69
|
+
*
|
|
70
|
+
* ## The path must be percent-encoded WHOLE
|
|
71
|
+
*
|
|
72
|
+
* `/v0/b/<bucket>/o/<object>` takes the object name as ONE path segment, so
|
|
73
|
+
* the `/` inside `search-index/v3.json` has to become `%2F`. `encodeURIComponent`
|
|
74
|
+
* does exactly that; `encodeURI` does not, and would 404 in a way that reads
|
|
75
|
+
* like a missing artifact rather than a malformed URL.
|
|
76
|
+
*
|
|
77
|
+
* @tag domain:search
|
|
78
|
+
* @tag layer:shared
|
|
79
|
+
* @tag pattern:none
|
|
80
|
+
* @tag access:isomorphic
|
|
81
|
+
* @tag consumers:useSearchIndex,artifact-store,verify-search-serving
|
|
82
|
+
* @tag sideEffects:none
|
|
83
|
+
*/
|
|
84
|
+
/*
|
|
85
|
+
* The host comes from its ONE declaration. `utils/media-url.ts` is named in
|
|
86
|
+
* `audit-firestore-storage-urls`'s allowlist as the sole place these strings
|
|
87
|
+
* may appear, with every other module importing from it — so importing is
|
|
88
|
+
* the sanctioned mechanism here, not an exemption carved out for search.
|
|
89
|
+
*/
|
|
90
|
+
import { FIREBASE_STORAGE_HOST } from "../../../utils/media-url.js";
|
|
91
|
+
/** `search-index/v{n}.json` — the version IS the cache key. */
|
|
92
|
+
export const SEARCH_INDEX_PREFIX = "search-index";
|
|
93
|
+
/**
|
|
94
|
+
* The manifest mirror's object name.
|
|
95
|
+
*
|
|
96
|
+
* 🛑 A MIRROR of `searchIndex/manifest` in Firestore, never the source of
|
|
97
|
+
* truth. The build writes Firestore first and this second, because the
|
|
98
|
+
* Firestore document is what the next build reads to decide its mode — a
|
|
99
|
+
* mirror that disagrees costs a stale client for 60 seconds, whereas a
|
|
100
|
+
* manifest the builder cannot trust costs a full rebuild.
|
|
101
|
+
*
|
|
102
|
+
* It exists so the client bootstrap is two plain `fetch`es and no Firebase
|
|
103
|
+
* SDK: pulling in the client SDK to read one small document would cost more
|
|
104
|
+
* bytes than the index it is pointing at.
|
|
105
|
+
*/
|
|
106
|
+
export const SEARCH_MANIFEST_OBJECT = `${SEARCH_INDEX_PREFIX}/manifest.json`;
|
|
107
|
+
export function searchIndexObjectPath(version) {
|
|
108
|
+
return `${SEARCH_INDEX_PREFIX}/v${version}.json`;
|
|
109
|
+
}
|
|
110
|
+
/** Public download URL for any object in the app's Storage bucket. */
|
|
111
|
+
export function firebaseDownloadUrl(bucket, objectPath) {
|
|
112
|
+
return `https://${FIREBASE_STORAGE_HOST}/v0/b/${bucket}/o/${encodeURIComponent(objectPath)}?alt=media`;
|
|
113
|
+
}
|
|
114
|
+
export function searchManifestUrl(bucket) {
|
|
115
|
+
return firebaseDownloadUrl(bucket, SEARCH_MANIFEST_OBJECT);
|
|
116
|
+
}
|
|
117
|
+
export function searchArtifactUrl(bucket, version) {
|
|
118
|
+
return firebaseDownloadUrl(bucket, searchIndexObjectPath(version));
|
|
119
|
+
}
|
|
@@ -0,0 +1,68 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Bumped when the tuple or the envelope changes shape.
|
|
3
|
+
*
|
|
4
|
+
* 🛑 The client REFUSES an artifact whose schema it does not recognise and
|
|
5
|
+
* falls back to the server path, rather than rendering a half-understood one.
|
|
6
|
+
* That is why this is in the envelope and not implied by the URL.
|
|
7
|
+
*/
|
|
8
|
+
export declare const SEARCH_INDEX_SCHEMA_VERSION = 1;
|
|
9
|
+
/**
|
|
10
|
+
* The incremental build's watermark field.
|
|
11
|
+
*
|
|
12
|
+
* 🛑 ONE shared constant for the same reason `SEARCH_TXT_FIELD` is one:
|
|
13
|
+
* `updatedAt` is a CROSS-COLLECTION convention declared on `BaseDocument`, and
|
|
14
|
+
* `field-names.ts` repeats it in four separate per-feature blocks. A builder
|
|
15
|
+
* that queries THIRTEEN collections cannot honestly borrow any single
|
|
16
|
+
* feature's copy — `PRODUCT_FIELDS.UPDATED_AT` naming the field on a `faqs`
|
|
17
|
+
* query is a true string and a false statement.
|
|
18
|
+
*/
|
|
19
|
+
export declare const INDEX_UPDATED_AT_FIELD = "updatedAt";
|
|
20
|
+
/** One searchable kind. The artifact carries the table so the client needs no map. */
|
|
21
|
+
export interface SearchIndexType {
|
|
22
|
+
/** Stable key — `product`, `category`, `part`, … Also the i18n label key. */
|
|
23
|
+
readonly key: string;
|
|
24
|
+
/** `"/products/{s}"` — exactly one substitution, `{s}`, the record's slug. */
|
|
25
|
+
readonly hrefTemplate: string;
|
|
26
|
+
/** The indexable browse page, for the group's "see all" footer. */
|
|
27
|
+
readonly moreHref: string;
|
|
28
|
+
/** Type-level ranking nudge. A product outranks a review for the same score. */
|
|
29
|
+
readonly weight: number;
|
|
30
|
+
}
|
|
31
|
+
/** Tuple positions, named once so no call site indexes by magic number. */
|
|
32
|
+
export declare const REC_TYPE = 0;
|
|
33
|
+
export declare const REC_TITLE = 1;
|
|
34
|
+
export declare const REC_DETAIL = 2;
|
|
35
|
+
export declare const REC_SLUG = 3;
|
|
36
|
+
export declare const REC_FACETS = 4;
|
|
37
|
+
/**
|
|
38
|
+
* `[typeIdx, title, detail, slug, facets?]`
|
|
39
|
+
*
|
|
40
|
+
* `facets` is a compact pipe-joined string (`"lt:auction|br:takara-tomy"`) and
|
|
41
|
+
* is absent rather than empty when a record has none — an omitted trailing
|
|
42
|
+
* element costs two bytes, `""` costs four, times 3,730.
|
|
43
|
+
*/
|
|
44
|
+
export type SearchIndexRecord = readonly [
|
|
45
|
+
number,
|
|
46
|
+
string,
|
|
47
|
+
string,
|
|
48
|
+
string,
|
|
49
|
+
string?
|
|
50
|
+
];
|
|
51
|
+
export interface SearchIndexArtifact {
|
|
52
|
+
readonly schema: number;
|
|
53
|
+
/** Monotonic build number. The artifact is addressed by it and immutable. */
|
|
54
|
+
readonly version: number;
|
|
55
|
+
readonly builtAt: string;
|
|
56
|
+
readonly types: readonly SearchIndexType[];
|
|
57
|
+
readonly r: readonly SearchIndexRecord[];
|
|
58
|
+
}
|
|
59
|
+
/** Resolve a record's destination from the type table. */
|
|
60
|
+
export declare function hrefFor(artifact: Pick<SearchIndexArtifact, "types">, rec: SearchIndexRecord): string;
|
|
61
|
+
/**
|
|
62
|
+
* Parse the compact facet string into pairs.
|
|
63
|
+
*
|
|
64
|
+
* Returns an empty array for an absent or malformed field rather than
|
|
65
|
+
* throwing: a facet is a refinement, and a record whose facets cannot be read
|
|
66
|
+
* is still a record somebody should be able to find.
|
|
67
|
+
*/
|
|
68
|
+
export declare function facetsOf(rec: SearchIndexRecord): ReadonlyArray<readonly [string, string]>;
|
|
@@ -0,0 +1,96 @@
|
|
|
1
|
+
/*
|
|
2
|
+
* WHY: The public search index is one artifact fetched once per visitor and
|
|
3
|
+
* searched in the browser, so its shape is a wire format — every field
|
|
4
|
+
* costs bytes on every download, and every field that can be DERIVED
|
|
5
|
+
* instead of stored should be.
|
|
6
|
+
* WHAT: The record tuple, the type table, and the artifact envelope. Shared by
|
|
7
|
+
* the builder (server) and the matcher (browser) so the two cannot drift.
|
|
8
|
+
*
|
|
9
|
+
* ## 🛑 Why a tuple and not an object
|
|
10
|
+
*
|
|
11
|
+
* 3,730 records. An object repeats its keys on every row; a tuple does not.
|
|
12
|
+
* Measured on the real corpus: 373 KB raw / 63 KB gzip / 46 KB brotli as
|
|
13
|
+
* tuples. The readability cost is paid once, here, by naming the positions.
|
|
14
|
+
*
|
|
15
|
+
* ## What is deliberately ABSENT, and why each
|
|
16
|
+
*
|
|
17
|
+
* href derivable from `types[typeIdx].hrefTemplate`
|
|
18
|
+
* normalised derived once at load with the SAME `normalizeSearchText` the
|
|
19
|
+
* title write path uses — storing it would be a second copy of a
|
|
20
|
+
* string we already ship
|
|
21
|
+
* tokens derived by calling the SAME `aliasVariantsForName` /
|
|
22
|
+
* `partAliasTokens` that are already in the bundle. Shipping
|
|
23
|
+
* them would duplicate a corpus the client already has
|
|
24
|
+
* label 🛑 NOT on the type table. A human-readable group heading baked
|
|
25
|
+
* into the artifact is untranslatable, and this app is
|
|
26
|
+
* `[locale]`-routed with every other UI string going through the
|
|
27
|
+
* label system. The client maps `key` -> label at render time
|
|
28
|
+
* price § Guest price gating is a CLIENT gate; it reaches the rendered
|
|
29
|
+
* DOM and nothing else. This artifact is unauthenticated and
|
|
30
|
+
* immutable-cached, so no gate can reach it — an amount here is
|
|
31
|
+
* published to everyone, permanently, for that version
|
|
32
|
+
* PII same argument, one step worse. Includes blind-index digests: a
|
|
33
|
+
* deterministic per-person identifier is cross-referenceable
|
|
34
|
+
* even unbroken
|
|
35
|
+
*
|
|
36
|
+
* The last two are enforced, not merely documented — see
|
|
37
|
+
* scripts/audit-search-index-artifact.mjs.
|
|
38
|
+
*
|
|
39
|
+
* @tag domain:search
|
|
40
|
+
* @tag layer:shared
|
|
41
|
+
* @tag pattern:none
|
|
42
|
+
* @tag access:isomorphic
|
|
43
|
+
* @tag consumers:index-build,match,verify-search-local
|
|
44
|
+
* @tag sideEffects:none
|
|
45
|
+
*/
|
|
46
|
+
/**
|
|
47
|
+
* Bumped when the tuple or the envelope changes shape.
|
|
48
|
+
*
|
|
49
|
+
* 🛑 The client REFUSES an artifact whose schema it does not recognise and
|
|
50
|
+
* falls back to the server path, rather than rendering a half-understood one.
|
|
51
|
+
* That is why this is in the envelope and not implied by the URL.
|
|
52
|
+
*/
|
|
53
|
+
export const SEARCH_INDEX_SCHEMA_VERSION = 1;
|
|
54
|
+
/**
|
|
55
|
+
* The incremental build's watermark field.
|
|
56
|
+
*
|
|
57
|
+
* 🛑 ONE shared constant for the same reason `SEARCH_TXT_FIELD` is one:
|
|
58
|
+
* `updatedAt` is a CROSS-COLLECTION convention declared on `BaseDocument`, and
|
|
59
|
+
* `field-names.ts` repeats it in four separate per-feature blocks. A builder
|
|
60
|
+
* that queries THIRTEEN collections cannot honestly borrow any single
|
|
61
|
+
* feature's copy — `PRODUCT_FIELDS.UPDATED_AT` naming the field on a `faqs`
|
|
62
|
+
* query is a true string and a false statement.
|
|
63
|
+
*/
|
|
64
|
+
export const INDEX_UPDATED_AT_FIELD = "updatedAt";
|
|
65
|
+
/** Tuple positions, named once so no call site indexes by magic number. */
|
|
66
|
+
export const REC_TYPE = 0;
|
|
67
|
+
export const REC_TITLE = 1;
|
|
68
|
+
export const REC_DETAIL = 2;
|
|
69
|
+
export const REC_SLUG = 3;
|
|
70
|
+
export const REC_FACETS = 4;
|
|
71
|
+
/** Resolve a record's destination from the type table. */
|
|
72
|
+
export function hrefFor(artifact, rec) {
|
|
73
|
+
const type = artifact.types[rec[REC_TYPE]];
|
|
74
|
+
if (!type)
|
|
75
|
+
return "/";
|
|
76
|
+
return type.hrefTemplate.replace("{s}", rec[REC_SLUG]);
|
|
77
|
+
}
|
|
78
|
+
/**
|
|
79
|
+
* Parse the compact facet string into pairs.
|
|
80
|
+
*
|
|
81
|
+
* Returns an empty array for an absent or malformed field rather than
|
|
82
|
+
* throwing: a facet is a refinement, and a record whose facets cannot be read
|
|
83
|
+
* is still a record somebody should be able to find.
|
|
84
|
+
*/
|
|
85
|
+
export function facetsOf(rec) {
|
|
86
|
+
const raw = rec[REC_FACETS];
|
|
87
|
+
if (!raw)
|
|
88
|
+
return [];
|
|
89
|
+
const out = [];
|
|
90
|
+
for (const part of raw.split("|")) {
|
|
91
|
+
const i = part.indexOf(":");
|
|
92
|
+
if (i > 0)
|
|
93
|
+
out.push([part.slice(0, i), part.slice(i + 1)]);
|
|
94
|
+
}
|
|
95
|
+
return out;
|
|
96
|
+
}
|
|
@@ -0,0 +1,65 @@
|
|
|
1
|
+
import { type SearchIndexArtifact, type SearchIndexRecord } from "./index-record";
|
|
2
|
+
export interface ResolvedEntity {
|
|
3
|
+
/** Index into `artifact.types`. */
|
|
4
|
+
readonly typeIdx: number;
|
|
5
|
+
readonly typeKey: string;
|
|
6
|
+
readonly title: string;
|
|
7
|
+
readonly detail: string;
|
|
8
|
+
readonly href: string;
|
|
9
|
+
readonly score: number;
|
|
10
|
+
}
|
|
11
|
+
export interface ResolveOptions {
|
|
12
|
+
readonly limit?: number;
|
|
13
|
+
/** Restrict to these type keys. Empty/absent means every type. */
|
|
14
|
+
readonly types?: readonly string[];
|
|
15
|
+
/** Require every one of these `k:v` facet pairs. */
|
|
16
|
+
readonly facets?: readonly string[];
|
|
17
|
+
}
|
|
18
|
+
/** One record's searchable text, prepared once at load. */
|
|
19
|
+
interface Prepared {
|
|
20
|
+
readonly rec: SearchIndexRecord;
|
|
21
|
+
readonly titleWords: readonly string[];
|
|
22
|
+
readonly titleFlat: string;
|
|
23
|
+
readonly detailWords: readonly string[];
|
|
24
|
+
readonly detailFlat: string;
|
|
25
|
+
/** Alias + misspelling forms of the TITLE. See `prepareIndex`. */
|
|
26
|
+
readonly aliasWords: readonly string[];
|
|
27
|
+
readonly aliasFlat: string;
|
|
28
|
+
}
|
|
29
|
+
/**
|
|
30
|
+
* Prepare an artifact for searching.
|
|
31
|
+
*
|
|
32
|
+
* 🛑 Call this ONCE per artifact, not per query. It normalises every title and
|
|
33
|
+
* detail up front — ~3,700 × 2 `normalizeSearchText` calls, a few milliseconds
|
|
34
|
+
* — so that the per-keystroke path does no allocation beyond the query's own
|
|
35
|
+
* terms. Doing it inside `search` would move that cost onto every keystroke,
|
|
36
|
+
* which is the one thing this design exists to avoid.
|
|
37
|
+
*/
|
|
38
|
+
export declare function prepareIndex(artifact: SearchIndexArtifact): readonly Prepared[];
|
|
39
|
+
/**
|
|
40
|
+
* Search a prepared artifact.
|
|
41
|
+
*
|
|
42
|
+
* Returns a flat, score-ordered list. Grouping by type is the caller's job —
|
|
43
|
+
* the dropdown and the results page group differently, and a tool wants
|
|
44
|
+
* neither.
|
|
45
|
+
*/
|
|
46
|
+
export declare function searchIndex(artifact: SearchIndexArtifact, prepared: readonly Prepared[], query: string, opts?: ResolveOptions): readonly ResolvedEntity[];
|
|
47
|
+
/**
|
|
48
|
+
* The named primitive the tools call.
|
|
49
|
+
*
|
|
50
|
+
* 🛑 `types` is a parameter from day one BECAUSE the tools exist. `/parts`
|
|
51
|
+
* wants parts, the price index wants category leaves, the authenticity
|
|
52
|
+
* typeahead wants canonical models — three consumers, three subsets. Adding
|
|
53
|
+
* the filter later would mean changing every call site that had already been
|
|
54
|
+
* written without it.
|
|
55
|
+
*
|
|
56
|
+
* 🛑 It must NOT be wired into `/tools/authenticity`'s VERDICT path. That
|
|
57
|
+
* engine's fuzzy matching is evidence — a near-miss fires a trademark-evasion
|
|
58
|
+
* warning — and this matcher's alias corpus is built from a counterfeit
|
|
59
|
+
* seller's own spellings. Feeding one into the other would silence the warning
|
|
60
|
+
* by construction. The typeahead may propose a canonical entity; the engine
|
|
61
|
+
* must still analyse what the user actually typed. Enforced by
|
|
62
|
+
* audit-entity-resolver-consumers R2.
|
|
63
|
+
*/
|
|
64
|
+
export declare function resolveEntity(artifact: SearchIndexArtifact, prepared: readonly Prepared[], query: string, opts?: ResolveOptions): readonly ResolvedEntity[];
|
|
65
|
+
export type { Prepared as PreparedIndex };
|
|
@@ -0,0 +1,263 @@
|
|
|
1
|
+
/*
|
|
2
|
+
* WHY: Searching a 3,730-record artifact in the browser, at zero Firestore
|
|
3
|
+
* reads per keystroke. The action-index route already states the
|
|
4
|
+
* doctrine this follows: "One request per session per portal, never per
|
|
5
|
+
* keystroke… a typeahead has to answer in under 16 ms, which a network
|
|
6
|
+
* hop cannot."
|
|
7
|
+
* WHAT: A pure, isomorphic matcher plus `resolveEntity`, the named primitive
|
|
8
|
+
* the /tools surfaces call.
|
|
9
|
+
*
|
|
10
|
+
* ## 🛑 ONE normaliser, and it is imported, not reimplemented
|
|
11
|
+
*
|
|
12
|
+
* `normalizeSearchText` is the same function the write path and the Firestore
|
|
13
|
+
* path use. `audit-search-parity`'s R2 exists because a second tokeniser
|
|
14
|
+
* writes tokens the query side cannot match — "and re-running the backfill
|
|
15
|
+
* does NOT fix it". A library would have brought a third; this file must not
|
|
16
|
+
* grow a local lowercase/NFD pipeline. Enforced by that audit.
|
|
17
|
+
*
|
|
18
|
+
* ## Why hand-rolled rather than MiniSearch
|
|
19
|
+
*
|
|
20
|
+
* Three reasons, in order of weight:
|
|
21
|
+
*
|
|
22
|
+
* 1. the normaliser argument above;
|
|
23
|
+
* 2. typo tolerance is already solved at WRITE time with evidence —
|
|
24
|
+
* `alias-variants` derives its suffix swaps from a crawl of a counterfeit
|
|
25
|
+
* seller's 1,277 titles, which is better grounded than generic edit
|
|
26
|
+
* distance and costs nothing at query time;
|
|
27
|
+
* 3. ~3,700 records is below where an inverted index earns its complexity. A
|
|
28
|
+
* linear scan is a few thousand cheap iterations.
|
|
29
|
+
*
|
|
30
|
+
* 🛑 (3) is a claim with a number attached, and the number is checked —
|
|
31
|
+
* `scripts/verify-search-local.mjs` times it and prints the result. If that
|
|
32
|
+
* ever stops being true, this comment is the thing to come back and delete.
|
|
33
|
+
*
|
|
34
|
+
* ## 🛑 It is NOT BM25 and must not be described as BM25
|
|
35
|
+
*
|
|
36
|
+
* BM25's two moving parts are IDF and length normalisation. Titles here
|
|
37
|
+
* average 20 characters, so length normalisation is degenerate; IDF over one
|
|
38
|
+
* domain mostly re-derives "beyblade is common", which `weight` already
|
|
39
|
+
* encodes. Calling an ordered weight sum "BM25-ish" would be decoration
|
|
40
|
+
* (Root Cause #92). It is a weighted match score, the weights are below, and
|
|
41
|
+
* they are tuned against the verify script.
|
|
42
|
+
*
|
|
43
|
+
* ## What this has that the Firestore path structurally cannot
|
|
44
|
+
*
|
|
45
|
+
* SUBSTRING. `search-txt.ts` states the limit outright: "Word-prefix, not
|
|
46
|
+
* mid-word. 'ariza' will not match 'charizard'." A linear scan gets mid-word
|
|
47
|
+
* for free, which is why Tier 1 is better at its job than Tier 2, not merely
|
|
48
|
+
* cheaper.
|
|
49
|
+
*
|
|
50
|
+
* @tag domain:search
|
|
51
|
+
* @tag layer:shared
|
|
52
|
+
* @tag pattern:none
|
|
53
|
+
* @tag access:isomorphic
|
|
54
|
+
* @tag consumers:useSiteSearch,/parts,/tools/price-index,verify-search-local
|
|
55
|
+
* @tag sideEffects:none
|
|
56
|
+
*/
|
|
57
|
+
import { normalizeSearchText, parseSearchTxtQuery } from "../../../utils/search-txt.js";
|
|
58
|
+
import { aliasVariantsForName } from "./alias-variants.js";
|
|
59
|
+
import { partAliasTokens } from "./part-aliases.js";
|
|
60
|
+
import { facetsOf, hrefFor, REC_DETAIL, REC_TITLE, REC_TYPE, } from "./index-record.js";
|
|
61
|
+
/** Field weights. Title dominates; a detail match is corroboration. */
|
|
62
|
+
const W_TITLE = 3;
|
|
63
|
+
const W_DETAIL = 1;
|
|
64
|
+
/** Match-quality weights, highest first. */
|
|
65
|
+
const S_EXACT = 100;
|
|
66
|
+
const S_PREFIX = 60;
|
|
67
|
+
const S_SUBSTRING = 30;
|
|
68
|
+
const S_ALIAS = 15;
|
|
69
|
+
/** Default cap. A dropdown shows ~6 per group; a page shows more. */
|
|
70
|
+
const DEFAULT_LIMIT = 50;
|
|
71
|
+
/**
|
|
72
|
+
* Prepare an artifact for searching.
|
|
73
|
+
*
|
|
74
|
+
* 🛑 Call this ONCE per artifact, not per query. It normalises every title and
|
|
75
|
+
* detail up front — ~3,700 × 2 `normalizeSearchText` calls, a few milliseconds
|
|
76
|
+
* — so that the per-keystroke path does no allocation beyond the query's own
|
|
77
|
+
* terms. Doing it inside `search` would move that cost onto every keystroke,
|
|
78
|
+
* which is the one thing this design exists to avoid.
|
|
79
|
+
*/
|
|
80
|
+
export function prepareIndex(artifact) {
|
|
81
|
+
return artifact.r.map((rec) => {
|
|
82
|
+
const title = rec[REC_TITLE] ?? "";
|
|
83
|
+
const titleFlat = normalizeSearchText(title);
|
|
84
|
+
const detailFlat = normalizeSearchText(rec[REC_DETAIL] ?? "");
|
|
85
|
+
/*
|
|
86
|
+
* 🛑 The alias corpus is expanded against the DOCUMENT, not the query, and
|
|
87
|
+
* getting this backwards is a real bug I shipped into the first draft.
|
|
88
|
+
*
|
|
89
|
+
* `aliasVariantsForName` is DIRECTIONAL: `doubledLetterVariants` collapses
|
|
90
|
+
* `dragoon -> dragon`, it does not expand `dragon -> dragoon`. The
|
|
91
|
+
* Firestore path works because `buildProductSearchTxt` runs it over the
|
|
92
|
+
* TITLE at write time, so the document carries "dragon" as a token.
|
|
93
|
+
* Expanding the query instead produces nothing for that rule, and the
|
|
94
|
+
* verify script caught it: searching "dragon" found no "Dragoon Storm".
|
|
95
|
+
*
|
|
96
|
+
* So the client does at LOAD what the server does at WRITE — same
|
|
97
|
+
* function, same direction, same result. It also keeps the variants out
|
|
98
|
+
* of the artifact, which is why `index-record.ts` does not carry them.
|
|
99
|
+
*
|
|
100
|
+
* `partAliasTokens` is symmetric (a code <-> name table), so it would have
|
|
101
|
+
* worked either way; it runs here too so there is one rule, not two.
|
|
102
|
+
*/
|
|
103
|
+
const aliasSet = new Set();
|
|
104
|
+
for (const v of aliasVariantsForName(title))
|
|
105
|
+
aliasSet.add(normalizeSearchText(v));
|
|
106
|
+
for (const v of partAliasTokens(`${title} ${rec[REC_DETAIL] ?? ""}`)) {
|
|
107
|
+
aliasSet.add(normalizeSearchText(v));
|
|
108
|
+
}
|
|
109
|
+
aliasSet.delete(titleFlat); // a variant identical to the title adds nothing
|
|
110
|
+
const aliasFlat = [...aliasSet].filter(Boolean).join(" ");
|
|
111
|
+
return {
|
|
112
|
+
rec,
|
|
113
|
+
titleFlat,
|
|
114
|
+
detailFlat,
|
|
115
|
+
aliasFlat,
|
|
116
|
+
titleWords: titleFlat ? titleFlat.split(" ") : [],
|
|
117
|
+
detailWords: detailFlat ? detailFlat.split(" ") : [],
|
|
118
|
+
aliasWords: aliasFlat ? aliasFlat.split(" ") : [],
|
|
119
|
+
};
|
|
120
|
+
});
|
|
121
|
+
}
|
|
122
|
+
/** Best match quality for one term against one field. 0 means no match. */
|
|
123
|
+
function fieldScore(term, words, flat) {
|
|
124
|
+
if (!flat)
|
|
125
|
+
return 0;
|
|
126
|
+
for (const w of words)
|
|
127
|
+
if (w === term)
|
|
128
|
+
return S_EXACT;
|
|
129
|
+
for (const w of words)
|
|
130
|
+
if (w.startsWith(term))
|
|
131
|
+
return S_PREFIX;
|
|
132
|
+
// Mid-word. The capability the token index cannot have.
|
|
133
|
+
if (flat.includes(term))
|
|
134
|
+
return S_SUBSTRING;
|
|
135
|
+
return 0;
|
|
136
|
+
}
|
|
137
|
+
function recordScore(p, terms, typeWeight) {
|
|
138
|
+
let total = 0;
|
|
139
|
+
for (const term of terms) {
|
|
140
|
+
/*
|
|
141
|
+
* An alias match is real but WEAKER than a direct one: `S_ALIAS` is the
|
|
142
|
+
* ceiling for that field, so "Dragoon Storm" still outranks a record that
|
|
143
|
+
* only matched through a generated misspelling.
|
|
144
|
+
*/
|
|
145
|
+
const aliasHit = fieldScore(term, p.aliasWords, p.aliasFlat) > 0 ? S_ALIAS : 0;
|
|
146
|
+
const best = Math.max(fieldScore(term, p.titleWords, p.titleFlat) * W_TITLE, fieldScore(term, p.detailWords, p.detailFlat) * W_DETAIL, aliasHit);
|
|
147
|
+
// AND semantics: a record missing any term is out, regardless of how well
|
|
148
|
+
// it matched the others. "red dranzer" returning everything with "dranzer"
|
|
149
|
+
// is the exact complaint that made search feel broken.
|
|
150
|
+
if (best === 0)
|
|
151
|
+
return 0;
|
|
152
|
+
total += best;
|
|
153
|
+
}
|
|
154
|
+
return total * typeWeight;
|
|
155
|
+
}
|
|
156
|
+
function facetsSatisfied(rec, required) {
|
|
157
|
+
if (required.length === 0)
|
|
158
|
+
return true;
|
|
159
|
+
const have = new Set(facetsOf(rec).map(([k, v]) => `${k}:${v}`));
|
|
160
|
+
return required.every((f) => have.has(f));
|
|
161
|
+
}
|
|
162
|
+
/**
|
|
163
|
+
* Search a prepared artifact.
|
|
164
|
+
*
|
|
165
|
+
* Returns a flat, score-ordered list. Grouping by type is the caller's job —
|
|
166
|
+
* the dropdown and the results page group differently, and a tool wants
|
|
167
|
+
* neither.
|
|
168
|
+
*/
|
|
169
|
+
export function searchIndex(artifact, prepared, query, opts = {}) {
|
|
170
|
+
const terms = parseSearchTxtQuery(query);
|
|
171
|
+
/*
|
|
172
|
+
* 🛑 A query that normalises to nothing returns NOTHING, never everything.
|
|
173
|
+
* "!!!" and "—" have no terms, and treating that as "no filter" is how a
|
|
174
|
+
* punctuation search returns the whole catalogue AS SEARCH RESULTS — the
|
|
175
|
+
* bug A2 fixed on /api/products, and the one `plan.empty` exists for.
|
|
176
|
+
*/
|
|
177
|
+
if (terms.length === 0)
|
|
178
|
+
return [];
|
|
179
|
+
const limit = opts.limit ?? DEFAULT_LIMIT;
|
|
180
|
+
const wantTypes = new Set(opts.types ?? []);
|
|
181
|
+
const facets = opts.facets ?? [];
|
|
182
|
+
const collect = (useTerms, aliasPass) => {
|
|
183
|
+
const hits = [];
|
|
184
|
+
for (const p of prepared) {
|
|
185
|
+
const type = artifact.types[p.rec[REC_TYPE]];
|
|
186
|
+
if (!type)
|
|
187
|
+
continue;
|
|
188
|
+
if (wantTypes.size > 0 && !wantTypes.has(type.key))
|
|
189
|
+
continue;
|
|
190
|
+
if (!facetsSatisfied(p.rec, facets))
|
|
191
|
+
continue;
|
|
192
|
+
const score = recordScore(p, useTerms, type.weight);
|
|
193
|
+
if (score === 0)
|
|
194
|
+
continue;
|
|
195
|
+
hits.push({
|
|
196
|
+
typeIdx: p.rec[REC_TYPE],
|
|
197
|
+
typeKey: type.key,
|
|
198
|
+
title: p.rec[REC_TITLE],
|
|
199
|
+
detail: p.rec[REC_DETAIL],
|
|
200
|
+
href: hrefFor(artifact, p.rec),
|
|
201
|
+
// An alias hit is a weaker signal than a direct one and must not
|
|
202
|
+
// outrank it when both are present in a later, wider query.
|
|
203
|
+
score: aliasPass ? score - S_ALIAS : score,
|
|
204
|
+
});
|
|
205
|
+
}
|
|
206
|
+
return hits;
|
|
207
|
+
};
|
|
208
|
+
/*
|
|
209
|
+
* ONE pass. The alias forms live on the prepared record (see
|
|
210
|
+
* `prepareIndex`), so there is nothing to retry with — an earlier draft had
|
|
211
|
+
* a second query-expansion pass here and it was both redundant and
|
|
212
|
+
* directionally wrong.
|
|
213
|
+
*/
|
|
214
|
+
const hits = collect(terms, false);
|
|
215
|
+
hits.sort((a, b) => b.score - a.score || a.title.localeCompare(b.title));
|
|
216
|
+
/*
|
|
217
|
+
* 🛑 Dedupe by DESTINATION, not by key. Two types can legitimately resolve
|
|
218
|
+
* to the same page: `model` (a composition) and `category` (the model leaf)
|
|
219
|
+
* both render `/categories/{s}`, because a composition has no page of its
|
|
220
|
+
* own. Found running the first real build — 222 model records sit on top of
|
|
221
|
+
* 1,144 categories, so a bey name could return two rows that go to the same
|
|
222
|
+
* place, which reads as a duplicate-results bug rather than as two ways of
|
|
223
|
+
* finding one thing.
|
|
224
|
+
*
|
|
225
|
+
* Keeping the HIGHER-scoring one is what preserves the value of both: the
|
|
226
|
+
* composition's name is often the longer, more specific form ("Aero Knight
|
|
227
|
+
* MS (Aero Knight Metal Sky)" against the category's "Aero Knight MS"), so
|
|
228
|
+
* whichever actually matched the query is the one worth showing.
|
|
229
|
+
*
|
|
230
|
+
* After the sort, so "first seen" is "best scoring".
|
|
231
|
+
*/
|
|
232
|
+
const seen = new Set();
|
|
233
|
+
const deduped = [];
|
|
234
|
+
for (const hit of hits) {
|
|
235
|
+
if (seen.has(hit.href))
|
|
236
|
+
continue;
|
|
237
|
+
seen.add(hit.href);
|
|
238
|
+
deduped.push(hit);
|
|
239
|
+
if (deduped.length >= limit)
|
|
240
|
+
break;
|
|
241
|
+
}
|
|
242
|
+
return deduped;
|
|
243
|
+
}
|
|
244
|
+
/**
|
|
245
|
+
* The named primitive the tools call.
|
|
246
|
+
*
|
|
247
|
+
* 🛑 `types` is a parameter from day one BECAUSE the tools exist. `/parts`
|
|
248
|
+
* wants parts, the price index wants category leaves, the authenticity
|
|
249
|
+
* typeahead wants canonical models — three consumers, three subsets. Adding
|
|
250
|
+
* the filter later would mean changing every call site that had already been
|
|
251
|
+
* written without it.
|
|
252
|
+
*
|
|
253
|
+
* 🛑 It must NOT be wired into `/tools/authenticity`'s VERDICT path. That
|
|
254
|
+
* engine's fuzzy matching is evidence — a near-miss fires a trademark-evasion
|
|
255
|
+
* warning — and this matcher's alias corpus is built from a counterfeit
|
|
256
|
+
* seller's own spellings. Feeding one into the other would silence the warning
|
|
257
|
+
* by construction. The typeahead may propose a canonical entity; the engine
|
|
258
|
+
* must still analyse what the user actually typed. Enforced by
|
|
259
|
+
* audit-entity-resolver-consumers R2.
|
|
260
|
+
*/
|
|
261
|
+
export function resolveEntity(artifact, prepared, query, opts = {}) {
|
|
262
|
+
return searchIndex(artifact, prepared, query, opts);
|
|
263
|
+
}
|
package/dist/client.d.ts
CHANGED
|
@@ -41,6 +41,8 @@ export { Tabs, TabsList, TabsTrigger, TabsContent } from "./ui/components/Tabs";
|
|
|
41
41
|
export type { TabsProps, TabsListProps, TabsTriggerProps, TabsContentProps } from "./ui/components/Tabs";
|
|
42
42
|
export { TabBarShell, TabBarButton, TabsNavSelect } from "./ui/components/TabBarShell";
|
|
43
43
|
export type { TabBarShellProps, TabBarButtonProps, TabsNavSelectProps } from "./ui/components/TabBarShell";
|
|
44
|
+
export { OverflowRow } from "./ui/components/OverflowRow";
|
|
45
|
+
export type { OverflowRowProps, OverflowRowItem, OverflowRowDotTone, OverflowRowLinkProps } from "./ui/components/OverflowRow";
|
|
44
46
|
export { SellerProductsView } from "./features/seller/components/SellerProductsView";
|
|
45
47
|
export { SellerOrderDetailPanel } from "./features/seller/components/SellerOrdersView";
|
|
46
48
|
export { SellerPayoutDetailContent } from "./features/seller/components/SellerPayoutsView";
|
|
@@ -264,7 +266,7 @@ export { buildEventEntryDetailFields } from "./features/events/components/event-
|
|
|
264
266
|
export type { EntryFieldRow } from "./features/events/components/event-entry-detail-fields";
|
|
265
267
|
export type { BidDetailViewer } from "./features/auctions/components/bid-detail-fields";
|
|
266
268
|
export type { AuctionBidsTableProps, AuctionWithBids } from "./features/auctions/components/AuctionBidsTable";
|
|
267
|
-
export { ProtectedRoute,
|
|
269
|
+
export { ProtectedRoute, ForgotPasswordView, LoginForm, RegisterForm, ResetPasswordView, VerifyEmailView } from "./features/auth/index";
|
|
268
270
|
export type { AuthGuardUser, ForgotPasswordViewProps, LoginFormProps, LoginFormValues, RegisterFormProps, RegisterFormValues, ResetPasswordViewProps, VerifyEmailViewProps, } from "./features/auth/index";
|
|
269
271
|
export { useLogout, useLogin, useGoogleLogin, useLinkGoogleAccount, useRegister, useForgotPassword, useResetPassword, useVerifyEmail, useChangeEmail } from "./features/auth/index";
|
|
270
272
|
export type { LoginCredentials, RegisterData, ForgotPasswordData, ResetPasswordData, VerifyEmailData, ChangeEmailData } from "./features/auth/index";
|
|
@@ -284,7 +286,6 @@ export { AddressBook, AddressCard, AddressForm } from "./features/account/index"
|
|
|
284
286
|
export type { AddressCardAddress, AddressCardProps } from "./features/account/index";
|
|
285
287
|
export { useProfile, useUpdateProfile } from "./features/account/index";
|
|
286
288
|
export { updateProfileSchema } from "./features/account/index";
|
|
287
|
-
export { CategoryProductsView } from "./features/categories/index";
|
|
288
289
|
export type { CategoryItem } from "./features/categories/index";
|
|
289
290
|
export { MediaImage } from "./features/media/index";
|
|
290
291
|
export { StoreSidebar } from "./features/seller/components/SellerSidebar";
|
|
@@ -293,8 +294,8 @@ export { StoreProductsView, StoreAboutView } from "./features/stores/index";
|
|
|
293
294
|
export type { StoreProductItem, StoreAboutViewProps, StoreDetail } from "./features/stores/index";
|
|
294
295
|
export { SearchView } from "./features/search/index";
|
|
295
296
|
export type { SearchViewProps } from "./features/search/index";
|
|
296
|
-
export {
|
|
297
|
-
export type {
|
|
297
|
+
export { useSearchIndex, ensureSearchIndex } from "./features/search/hooks/useSearchIndex";
|
|
298
|
+
export type { SearchIndexState, SearchIndexStatus, LoadedSearchIndex, UseSearchIndexOptions, } from "./features/search/hooks/useSearchIndex";
|
|
298
299
|
export { AdSlot } from "./features/homepage/components/AdSlot";
|
|
299
300
|
export { useActiveAd } from "./features/homepage/hooks/useActiveAd";
|
|
300
301
|
export type { ActiveAdRecord, ActiveAdCreative } from "./features/homepage/hooks/useActiveAd";
|
|
@@ -370,8 +371,8 @@ export type { SellerPayoutSettingsViewProps, SellerShippingViewProps, SellerRevi
|
|
|
370
371
|
export { couponDraftToPayload } from "./features/seller/schemas/coupon-form";
|
|
371
372
|
export type { SellerCouponPayload } from "./features/seller/schemas/coupon-form";
|
|
372
373
|
export type { SellerAnalyticsSummary, SellerAnalyticsTopProduct } from "./features/seller/types/index";
|
|
373
|
-
export { UserAccountHubView, UserOrdersView, UserBidsView, OrderDetailView,
|
|
374
|
-
export type { UserAccountHubViewProps, UserAccountHubViewLabels, UserOrdersViewProps, OrderDetailViewProps, OrderDetailViewLabels,
|
|
374
|
+
export { UserAccountHubView, UserOrdersView, UserBidsView, OrderDetailView, UserReturnsView, useNotifications } from "./features/account/index";
|
|
375
|
+
export type { UserAccountHubViewProps, UserAccountHubViewLabels, UserOrdersViewProps, OrderDetailViewProps, OrderDetailViewLabels, UserReturnsViewProps } from "./features/account/index";
|
|
375
376
|
export { useOrders, useOrder, OrdersList } from "./features/orders/index";
|
|
376
377
|
export { OrderStatusTimeline } from "./features/orders/components/OrderStatusTimeline";
|
|
377
378
|
export type { OrderStatusTimelineProps } from "./features/orders/components/OrderStatusTimeline";
|
|
@@ -407,7 +408,7 @@ export type { TrackArgs as TrackHistoryArgs } from "./features/history/hooks/use
|
|
|
407
408
|
export { WISHLIST_MAX, HISTORY_MAX, CART_MAX_ITEMS, } from "./constants/limits";
|
|
408
409
|
export { normalizeListingType, isAuctionListing, isPreOrderListing, isStandardListing, isPrizeDrawListing, isClassifiedListing, isDigitalCodeListing, isLiveListing, isArtListing, isStickersListing, } from "./features/products/utils/listing-type";
|
|
409
410
|
export { isFinalSale, acceptsChangeOfMindReturns, } from "./features/products/constants/final-sale";
|
|
410
|
-
export { isListingTypeEnabled, isCategoryTypeEnabled, enabledListingTypes, enabledCategoryTypes, ALL_LISTING_TYPES, } from "./_internal/shared/listing-types/feature-flags";
|
|
411
|
+
export { isListingTypeEnabled, isCategoryTypeEnabled, enabledListingTypes, enabledCategoryTypes, ALL_LISTING_TYPES, isListingType, } from "./_internal/shared/listing-types/feature-flags";
|
|
411
412
|
export { actionTracker, setActionTrackerSink, resetActionTrackerSink, type ActionEvent, type ActionTrackerSink, } from "./_internal/shared/listing-types/action-tracker";
|
|
412
413
|
export { cartRequiresShipping, cartIsDigitalOnly, cartIsChatOnly, } from "./_internal/shared/listing-types/cart-shipping";
|
|
413
414
|
export { ACTIONS, action, act, canPerformAction, actionsForListingType, actionLabel, type ActionDef, type ActionKind, type ActionResource, type ActionTree, type ActionConfirmation, } from "./_internal/shared/actions/action-registry";
|