@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
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
import { normalizeError } from "../../../errors/normalize.js";
|
|
2
2
|
import { DatabaseError } from "../../../errors/index.js";
|
|
3
3
|
import { BaseRepository } from "../../../providers/db-firebase/index.js";
|
|
4
|
-
import { TOKEN_PII_FIELDS, TOKEN_PII_INDEX_MAP,
|
|
4
|
+
import { TOKEN_PII_FIELDS, TOKEN_PII_INDEX_MAP, maskPii, piiBlindIndex, revealPii, } from "../../../security/index.js";
|
|
5
5
|
import { resolveDate } from "../../../utils/index.js";
|
|
6
6
|
import { EMAIL_VERIFICATION_COLLECTION, PASSWORD_RESET_COLLECTION, TOKEN_FIELDS, } from "../schemas/index.js";
|
|
7
7
|
export class EmailVerificationTokenRepository extends BaseRepository {
|
|
@@ -24,11 +24,38 @@ export class EmailVerificationTokenRepository extends BaseRepository {
|
|
|
24
24
|
this.piiFields = TOKEN_PII_FIELDS;
|
|
25
25
|
this.piiIndexMap = TOKEN_PII_INDEX_MAP;
|
|
26
26
|
}
|
|
27
|
-
|
|
28
|
-
|
|
29
|
-
|
|
30
|
-
|
|
31
|
-
|
|
27
|
+
/*
|
|
28
|
+
* 🛑 `mapDoc` is NOT overridden, and that absence IS the change.
|
|
29
|
+
*
|
|
30
|
+
* It used to decrypt on every read, so ciphertext never left the database
|
|
31
|
+
* and every caller handled plaintext without ever saying so. Following
|
|
32
|
+
* `SiteSettingsRepository`: reads return what Firestore holds, and plaintext
|
|
33
|
+
* requires one of the two named methods below.
|
|
34
|
+
*
|
|
35
|
+
* A convention would not hold this. `EmailVerificationTokenDocument`'s PII fields are
|
|
36
|
+
* `Encrypted<string>`, assignable to nothing that wants a plain `string`, so
|
|
37
|
+
* a reader that skips both accessors is a compile error naming file and line.
|
|
38
|
+
*/
|
|
39
|
+
/** Plaintext PII. **Opt-in and named** — shows up in review and in a grep. */
|
|
40
|
+
revealToken(doc) {
|
|
41
|
+
return revealPii(doc, TOKEN_PII_FIELDS);
|
|
42
|
+
}
|
|
43
|
+
/** As `revealToken`, for a list read. */
|
|
44
|
+
revealTokens(docs) {
|
|
45
|
+
return docs.map((d) => this.revealToken(d));
|
|
46
|
+
}
|
|
47
|
+
/**
|
|
48
|
+
* Masked PII — **the default for any surface that only needs to identify a
|
|
49
|
+
* row to a human.** Decrypts first, then masks: the mask helpers refuse
|
|
50
|
+
* ciphertext by design, so passing a stored field straight in would return
|
|
51
|
+
* "Anonymous" for every row.
|
|
52
|
+
*/
|
|
53
|
+
maskedToken(doc) {
|
|
54
|
+
return maskPii(doc, TOKEN_PII_FIELDS);
|
|
55
|
+
}
|
|
56
|
+
/** As `maskedToken`, for a list read. */
|
|
57
|
+
maskedTokens(docs) {
|
|
58
|
+
return docs.map((d) => this.maskedToken(d));
|
|
32
59
|
}
|
|
33
60
|
async findByToken(token) {
|
|
34
61
|
return this.findOneBy(TOKEN_FIELDS.TOKEN, token);
|
|
@@ -97,11 +124,38 @@ export class PasswordResetTokenRepository extends BaseRepository {
|
|
|
97
124
|
this.piiFields = TOKEN_PII_FIELDS;
|
|
98
125
|
this.piiIndexMap = TOKEN_PII_INDEX_MAP;
|
|
99
126
|
}
|
|
100
|
-
|
|
101
|
-
|
|
102
|
-
|
|
103
|
-
|
|
104
|
-
|
|
127
|
+
/*
|
|
128
|
+
* 🛑 `mapDoc` is NOT overridden, and that absence IS the change.
|
|
129
|
+
*
|
|
130
|
+
* It used to decrypt on every read, so ciphertext never left the database
|
|
131
|
+
* and every caller handled plaintext without ever saying so. Following
|
|
132
|
+
* `SiteSettingsRepository`: reads return what Firestore holds, and plaintext
|
|
133
|
+
* requires one of the two named methods below.
|
|
134
|
+
*
|
|
135
|
+
* A convention would not hold this. `PasswordResetTokenDocument`'s PII fields are
|
|
136
|
+
* `Encrypted<string>`, assignable to nothing that wants a plain `string`, so
|
|
137
|
+
* a reader that skips both accessors is a compile error naming file and line.
|
|
138
|
+
*/
|
|
139
|
+
/** Plaintext PII. **Opt-in and named** — shows up in review and in a grep. */
|
|
140
|
+
revealResetToken(doc) {
|
|
141
|
+
return revealPii(doc, TOKEN_PII_FIELDS);
|
|
142
|
+
}
|
|
143
|
+
/** As `revealResetToken`, for a list read. */
|
|
144
|
+
revealResetTokens(docs) {
|
|
145
|
+
return docs.map((d) => this.revealResetToken(d));
|
|
146
|
+
}
|
|
147
|
+
/**
|
|
148
|
+
* Masked PII — **the default for any surface that only needs to identify a
|
|
149
|
+
* row to a human.** Decrypts first, then masks: the mask helpers refuse
|
|
150
|
+
* ciphertext by design, so passing a stored field straight in would return
|
|
151
|
+
* "Anonymous" for every row.
|
|
152
|
+
*/
|
|
153
|
+
maskedResetToken(doc) {
|
|
154
|
+
return maskPii(doc, TOKEN_PII_FIELDS);
|
|
155
|
+
}
|
|
156
|
+
/** As `maskedResetToken`, for a list read. */
|
|
157
|
+
maskedResetTokens(docs) {
|
|
158
|
+
return docs.map((d) => this.maskedResetToken(d));
|
|
105
159
|
}
|
|
106
160
|
async findByToken(token) {
|
|
107
161
|
return this.findOneBy(TOKEN_FIELDS.TOKEN, token);
|
|
@@ -1,11 +1,38 @@
|
|
|
1
|
-
import type { DocumentSnapshot } from "../../../providers/db-firebase";
|
|
2
1
|
import { BaseRepository, type FirebaseSieveFields, type FirebaseSieveResult, type SieveModel } from "../../../providers/db-firebase";
|
|
3
2
|
import type { UserRole } from "../types";
|
|
4
|
-
import { type UserDocument } from "../schemas";
|
|
3
|
+
import { type UserDocument, type UserPlain } from "../schemas";
|
|
5
4
|
export declare class UserRepository extends BaseRepository<UserDocument> {
|
|
6
5
|
static readonly SIEVE_FIELDS: FirebaseSieveFields;
|
|
7
6
|
constructor();
|
|
8
|
-
|
|
7
|
+
/**
|
|
8
|
+
* Plaintext PII. **Opt-in and named** — for the account's own settings page,
|
|
9
|
+
* the payout run, and any mail that has to reach the person.
|
|
10
|
+
*/
|
|
11
|
+
revealUser(doc: UserDocument): UserPlain;
|
|
12
|
+
/** As `revealUser`, for a list read. */
|
|
13
|
+
revealUsers(docs: readonly UserDocument[]): UserPlain[];
|
|
14
|
+
/**
|
|
15
|
+
* Masked PII — **the default for every admin list and every public
|
|
16
|
+
* surface.** Decrypts first, then masks, because the mask helpers refuse
|
|
17
|
+
* ciphertext by design.
|
|
18
|
+
*
|
|
19
|
+
* `payoutDetails` and `shippingConfig` are decrypted and then masked
|
|
20
|
+
* member-by-member: a UPI handle or account number reaching an admin table
|
|
21
|
+
* unmasked is the most damaging value this document carries.
|
|
22
|
+
*/
|
|
23
|
+
maskedUser(doc: UserDocument): UserPlain;
|
|
24
|
+
/** As `maskedUser`, for a list read. */
|
|
25
|
+
maskedUsers(docs: readonly UserDocument[]): UserPlain[];
|
|
26
|
+
/**
|
|
27
|
+
* Mask every string member of an already-decrypted nested object.
|
|
28
|
+
*
|
|
29
|
+
* The field list is derived from the object rather than hard-coded, because
|
|
30
|
+
* `USER_PII_FIELDS` does not name these members and a second list here would
|
|
31
|
+
* have to be kept in step with `decryptPayoutDetails`'s own (Root Cause #42).
|
|
32
|
+
* Every string in a payout or shipping block is sensitive, so "all of them"
|
|
33
|
+
* is the correct list, not an approximation.
|
|
34
|
+
*/
|
|
35
|
+
private maskNested;
|
|
9
36
|
/**
|
|
10
37
|
* Declared, not hand-rolled.
|
|
11
38
|
*
|
|
@@ -28,9 +55,8 @@ export declare class UserRepository extends BaseRepository<UserDocument> {
|
|
|
28
55
|
* that have to agree — which is what the hand-rolled override was.
|
|
29
56
|
*/
|
|
30
57
|
protected applyWriteHooks<D extends object>(data: D): D;
|
|
31
|
-
|
|
32
|
-
|
|
33
|
-
create(input: Omit<UserDocument, "id" | "createdAt" | "updatedAt">): Promise<UserDocument>;
|
|
58
|
+
createWithId(id: string, data: Partial<UserPlain>): Promise<UserDocument>;
|
|
59
|
+
create(input: Omit<UserPlain, "id" | "createdAt" | "updatedAt">): Promise<UserDocument>;
|
|
34
60
|
findByUid(uid: string): Promise<UserDocument | null>;
|
|
35
61
|
/**
|
|
36
62
|
* Resolve a public profile slug.
|
|
@@ -51,7 +77,7 @@ export declare class UserRepository extends BaseRepository<UserDocument> {
|
|
|
51
77
|
* Permanent bans (`hardBanExpiresAt` null/absent) never match this query.
|
|
52
78
|
*/
|
|
53
79
|
getExpiredHardBans(): Promise<UserDocument[]>;
|
|
54
|
-
update(uid: string, data: Partial<
|
|
80
|
+
update(uid: string, data: Partial<UserPlain>): Promise<UserDocument>;
|
|
55
81
|
markEmailAsVerified(uid: string): Promise<UserDocument>;
|
|
56
82
|
disable(uid: string): Promise<UserDocument>;
|
|
57
83
|
enable(uid: string): Promise<UserDocument>;
|
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
import { normalizeError } from "../../../errors/normalize.js";
|
|
2
2
|
import { DatabaseError } from "../../../errors/index.js";
|
|
3
3
|
import { BaseRepository, getFirestoreCount, prepareForFirestore, parseSieveDateValue, } from "../../../providers/db-firebase/index.js";
|
|
4
|
-
import { USER_PII_FIELDS, USER_PII_INDEX_MAP, decryptPayoutDetails,
|
|
4
|
+
import { USER_PII_FIELDS, USER_PII_INDEX_MAP, decryptPayoutDetails, maskPii, revealPii, decryptShippingConfig, encryptPayoutDetails, encryptShippingConfig, piiBlindIndex, } from "../../../security/index.js";
|
|
5
5
|
import { USER_COLLECTION, USER_FIELDS, } from "../schemas/index.js";
|
|
6
6
|
export class UserRepository extends BaseRepository {
|
|
7
7
|
constructor() {
|
|
@@ -20,15 +20,74 @@ export class UserRepository extends BaseRepository {
|
|
|
20
20
|
this.piiFields = USER_PII_FIELDS;
|
|
21
21
|
this.piiIndexMap = USER_PII_INDEX_MAP;
|
|
22
22
|
}
|
|
23
|
-
|
|
24
|
-
|
|
25
|
-
|
|
26
|
-
|
|
23
|
+
/*
|
|
24
|
+
* 🛑 `mapDoc` no longer decrypts. This is the widest-reaching of the
|
|
25
|
+
* fourteen — 73 files touch this repository — and it is why ciphertext never
|
|
26
|
+
* leaving the database matters most here: `email` and `phoneNumber` belong
|
|
27
|
+
* to every account on the platform.
|
|
28
|
+
*
|
|
29
|
+
* `payoutDetails` and `shippingConfig` are handled inside the accessors
|
|
30
|
+
* rather than by `revealPii`, because each is encrypted by its OWN scheme
|
|
31
|
+
* and not by a `USER_PII_FIELDS` path. An accessor that silently skipped
|
|
32
|
+
* them would hand a caller a UPI id it could not read — worse than refusing,
|
|
33
|
+
* because the value looks present.
|
|
34
|
+
*/
|
|
35
|
+
/**
|
|
36
|
+
* Plaintext PII. **Opt-in and named** — for the account's own settings page,
|
|
37
|
+
* the payout run, and any mail that has to reach the person.
|
|
38
|
+
*/
|
|
39
|
+
revealUser(doc) {
|
|
40
|
+
const revealed = revealPii(doc, USER_PII_FIELDS);
|
|
41
|
+
if (revealed.payoutDetails) {
|
|
42
|
+
revealed.payoutDetails = decryptPayoutDetails(revealed.payoutDetails);
|
|
27
43
|
}
|
|
28
|
-
if (
|
|
29
|
-
|
|
44
|
+
if (revealed.shippingConfig) {
|
|
45
|
+
revealed.shippingConfig = decryptShippingConfig(revealed.shippingConfig);
|
|
30
46
|
}
|
|
31
|
-
return
|
|
47
|
+
return revealed;
|
|
48
|
+
}
|
|
49
|
+
/** As `revealUser`, for a list read. */
|
|
50
|
+
revealUsers(docs) {
|
|
51
|
+
return docs.map((d) => this.revealUser(d));
|
|
52
|
+
}
|
|
53
|
+
/**
|
|
54
|
+
* Masked PII — **the default for every admin list and every public
|
|
55
|
+
* surface.** Decrypts first, then masks, because the mask helpers refuse
|
|
56
|
+
* ciphertext by design.
|
|
57
|
+
*
|
|
58
|
+
* `payoutDetails` and `shippingConfig` are decrypted and then masked
|
|
59
|
+
* member-by-member: a UPI handle or account number reaching an admin table
|
|
60
|
+
* unmasked is the most damaging value this document carries.
|
|
61
|
+
*/
|
|
62
|
+
maskedUser(doc) {
|
|
63
|
+
const masked = maskPii(doc, USER_PII_FIELDS);
|
|
64
|
+
if (masked.payoutDetails) {
|
|
65
|
+
masked.payoutDetails = this.maskNested(decryptPayoutDetails(masked.payoutDetails));
|
|
66
|
+
}
|
|
67
|
+
if (masked.shippingConfig) {
|
|
68
|
+
masked.shippingConfig = this.maskNested(decryptShippingConfig(masked.shippingConfig));
|
|
69
|
+
}
|
|
70
|
+
return masked;
|
|
71
|
+
}
|
|
72
|
+
/** As `maskedUser`, for a list read. */
|
|
73
|
+
maskedUsers(docs) {
|
|
74
|
+
return docs.map((d) => this.maskedUser(d));
|
|
75
|
+
}
|
|
76
|
+
/**
|
|
77
|
+
* Mask every string member of an already-decrypted nested object.
|
|
78
|
+
*
|
|
79
|
+
* The field list is derived from the object rather than hard-coded, because
|
|
80
|
+
* `USER_PII_FIELDS` does not name these members and a second list here would
|
|
81
|
+
* have to be kept in step with `decryptPayoutDetails`'s own (Root Cause #42).
|
|
82
|
+
* Every string in a payout or shipping block is sensitive, so "all of them"
|
|
83
|
+
* is the correct list, not an approximation.
|
|
84
|
+
*/
|
|
85
|
+
maskNested(value) {
|
|
86
|
+
if (!value)
|
|
87
|
+
return undefined;
|
|
88
|
+
return maskPii(value, Object.entries(value)
|
|
89
|
+
.filter(([, v]) => typeof v === "string")
|
|
90
|
+
.map(([k]) => k));
|
|
32
91
|
}
|
|
33
92
|
/**
|
|
34
93
|
* The base hook, plus the nested objects it cannot see.
|
|
@@ -47,10 +106,11 @@ export class UserRepository extends BaseRepository {
|
|
|
47
106
|
access.shippingConfig = encryptShippingConfig(access.shippingConfig);
|
|
48
107
|
return out;
|
|
49
108
|
}
|
|
50
|
-
|
|
51
|
-
|
|
52
|
-
|
|
53
|
-
|
|
109
|
+
/*
|
|
110
|
+
* Takes PLAINTEXT, like the base it overrides — the three real signup paths
|
|
111
|
+
* hand over the email Firebase just gave them, and `applyWriteHooks` below
|
|
112
|
+
* is what encrypts it.
|
|
113
|
+
*/
|
|
54
114
|
async createWithId(id, data) {
|
|
55
115
|
// `uid` is a required UserDocument field read directly off the mapped
|
|
56
116
|
// object (SessionUser.uid, getServerPermissions(uid), etc.) — mapDoc()
|
|
@@ -76,6 +136,7 @@ export class UserRepository extends BaseRepository {
|
|
|
76
136
|
// request an O(1) lookup). The readable public identifier is `slug`, minted
|
|
77
137
|
// by `reserveUserSlug` from displayName only.
|
|
78
138
|
const id = this.db.collection(this.collection).doc().id;
|
|
139
|
+
// Plain in, ciphertext out — `applyWriteHooks` encrypts below.
|
|
79
140
|
const userData = {
|
|
80
141
|
...input,
|
|
81
142
|
createdAt: new Date(),
|
|
@@ -86,7 +147,15 @@ export class UserRepository extends BaseRepository {
|
|
|
86
147
|
.collection(this.collection)
|
|
87
148
|
.doc(id)
|
|
88
149
|
.set(prepareForFirestore(encrypted));
|
|
89
|
-
|
|
150
|
+
/*
|
|
151
|
+
* Returns what was PERSISTED, not the plaintext input.
|
|
152
|
+
*
|
|
153
|
+
* `encrypted` is the exact object just written, so this is both honest and
|
|
154
|
+
* assignable to the base's `Promise<UserDocument>` — the declaration
|
|
155
|
+
* previously said `UserDocument` while returning `userData`, the plaintext.
|
|
156
|
+
* No re-read, so no extra Firestore read (Rule #6).
|
|
157
|
+
*/
|
|
158
|
+
return { id, ...encrypted };
|
|
90
159
|
}
|
|
91
160
|
async findByUid(uid) {
|
|
92
161
|
return this.findOneBy(USER_FIELDS.UID, uid);
|
|
@@ -157,6 +226,11 @@ export class UserRepository extends BaseRepository {
|
|
|
157
226
|
throw new DatabaseError("Failed to fetch expired hard bans", error);
|
|
158
227
|
}
|
|
159
228
|
}
|
|
229
|
+
/*
|
|
230
|
+
* Takes PLAINTEXT, like the base it overrides — this method is the thing
|
|
231
|
+
* that encrypts (`applyWriteHooks`), so demanding ciphertext from callers
|
|
232
|
+
* inverted its own contract.
|
|
233
|
+
*/
|
|
160
234
|
async update(uid, data) {
|
|
161
235
|
const encrypted = this.applyWriteHooks(data);
|
|
162
236
|
return super.update(uid, encrypted);
|
|
@@ -181,11 +255,22 @@ export class UserRepository extends BaseRepository {
|
|
|
181
255
|
if (!currentUser) {
|
|
182
256
|
throw new DatabaseError(`User not found: ${uid}`);
|
|
183
257
|
}
|
|
258
|
+
/*
|
|
259
|
+
* Plain in, ciphertext out — `this.update` encrypts via the write hook.
|
|
260
|
+
*
|
|
261
|
+
* 🛑 The comparison below (`data.email !== currentUser.email`) now
|
|
262
|
+
* compares PLAINTEXT to CIPHERTEXT, so it is always true and
|
|
263
|
+
* `emailVerified` is cleared on every profile save that includes an
|
|
264
|
+
* email — even an unchanged one. `currentUser` comes from `findById`,
|
|
265
|
+
* which no longer decrypts. Fixed by comparing against the revealed
|
|
266
|
+
* value, which is the one place in this method that needs plaintext.
|
|
267
|
+
*/
|
|
184
268
|
const updateData = { ...data };
|
|
185
|
-
|
|
269
|
+
const current = this.revealUser(currentUser);
|
|
270
|
+
if (data.email && data.email !== current.email) {
|
|
186
271
|
updateData.emailVerified = false;
|
|
187
272
|
}
|
|
188
|
-
if (data.phoneNumber && data.phoneNumber !==
|
|
273
|
+
if (data.phoneNumber && data.phoneNumber !== current.phoneNumber) {
|
|
189
274
|
updateData.phoneVerified = false;
|
|
190
275
|
}
|
|
191
276
|
return this.update(uid, updateData);
|
|
@@ -7,6 +7,7 @@
|
|
|
7
7
|
import type { UserRole } from "../types";
|
|
8
8
|
import type { BannedAction, EmployeeGroup, Permission } from "../permissions/constants";
|
|
9
9
|
import type { BaseDocument } from "../../../_internal/shared/types/base-document";
|
|
10
|
+
import type { Encrypted, Plaintext } from "../../../security/encrypted";
|
|
10
11
|
/**
|
|
11
12
|
* Generic schema defaults for user-related data.
|
|
12
13
|
* Consumer-specific values (admin email, currency) belong in SiteConfig, not here.
|
|
@@ -31,6 +32,16 @@ export interface AvatarMetadata {
|
|
|
31
32
|
};
|
|
32
33
|
zoom: number;
|
|
33
34
|
}
|
|
35
|
+
/**
|
|
36
|
+
* `UserDocument` with its PII as plain `string` — what the named repository
|
|
37
|
+
* accessors return, and what a WRITE path accepts (the repository encrypts).
|
|
38
|
+
*
|
|
39
|
+
* `Plaintext<T>` is the one definition of this shape; see `security/encrypted.ts`.
|
|
40
|
+
* It is deliberately NOT distinguishable from a MASKED value — `maskPii`
|
|
41
|
+
* returns plain strings too, and no type can express "these characters are
|
|
42
|
+
* asterisks". The distinction is which named method you called.
|
|
43
|
+
*/
|
|
44
|
+
export type UserPlain = Plaintext<UserDocument>;
|
|
34
45
|
export interface UserDocument extends BaseDocument {
|
|
35
46
|
uid: string;
|
|
36
47
|
/**
|
|
@@ -52,8 +63,14 @@ export interface UserDocument extends BaseDocument {
|
|
|
52
63
|
* profile resolution falls back to id and then uid.
|
|
53
64
|
*/
|
|
54
65
|
slug?: string;
|
|
55
|
-
|
|
56
|
-
|
|
66
|
+
/**
|
|
67
|
+
* PII — CIPHERTEXT at rest, kept true by `UserRepository` no longer
|
|
68
|
+
* decrypting in `mapDoc`. Readers call `userRepository.maskedUser(doc)` (the
|
|
69
|
+
* default) or `revealUser(doc)` (opt-in, named, greppable).
|
|
70
|
+
*/
|
|
71
|
+
email: Encrypted<string> | null;
|
|
72
|
+
/** PII — ciphertext at rest; see `email`. */
|
|
73
|
+
phoneNumber: Encrypted<string> | null;
|
|
57
74
|
phoneVerified?: boolean;
|
|
58
75
|
displayName: string | null;
|
|
59
76
|
photoURL: string | null;
|
|
@@ -133,7 +150,8 @@ export interface UserDocument extends BaseDocument {
|
|
|
133
150
|
* exchange rather than the client SDK's linkWithCredential(). */
|
|
134
151
|
googleLinked?: boolean;
|
|
135
152
|
/** The Google account email this profile is linked to, once linked. */
|
|
136
|
-
|
|
153
|
+
/** PII — ciphertext at rest; see `email`. */
|
|
154
|
+
googleLinkedEmail?: Encrypted<string> | null;
|
|
137
155
|
uiPreferences?: {
|
|
138
156
|
/** IDs of collapsible dashboard sections currently collapsed, flat across
|
|
139
157
|
* every page (IDs are page-prefixed, e.g. "admin-dashboard:alerts", to
|
|
@@ -216,13 +234,13 @@ export interface SellerPayoutDetails {
|
|
|
216
234
|
isConfigured: boolean;
|
|
217
235
|
}
|
|
218
236
|
export declare const USER_COLLECTION: "users";
|
|
219
|
-
export declare const DEFAULT_USER_DATA: Partial<
|
|
237
|
+
export declare const DEFAULT_USER_DATA: Partial<UserPlain>;
|
|
220
238
|
export declare const USER_INDEXED_FIELDS: readonly ["email", "emailIndex", "phoneNumber", "phoneIndex", "role", "disabled", "emailVerified", "phoneVerified", "storeSlug", "storeStatus", "isTester", "slug"];
|
|
221
239
|
export declare const USER_PUBLIC_FIELDS: readonly ["uid", "displayName", "photoURL", "avatarMetadata", "role", "createdAt", "storeSlug", "publicProfile", "stats"];
|
|
222
240
|
export declare const USER_UPDATABLE_FIELDS: readonly ["displayName", "photoURL"];
|
|
223
241
|
export type UserCreateInput = Omit<UserDocument, "uid" | "id" | "createdAt" | "updatedAt">;
|
|
224
242
|
export type UserUpdateInput = Partial<Pick<UserDocument, "displayName" | "photoURL">>;
|
|
225
|
-
export type UserAdminUpdateInput = Partial<Omit<
|
|
243
|
+
export type UserAdminUpdateInput = Partial<Omit<UserPlain, "uid" | "id" | "createdAt">>;
|
|
226
244
|
export interface UserQueryFilter {
|
|
227
245
|
email?: string;
|
|
228
246
|
phoneNumber?: string;
|
|
@@ -308,18 +326,38 @@ export declare const USER_FIELDS: {
|
|
|
308
326
|
readonly LOGIN_COUNT: "metadata.loginCount";
|
|
309
327
|
};
|
|
310
328
|
};
|
|
329
|
+
/**
|
|
330
|
+
* `EmailVerificationTokenDocument` with its PII as plain `string` — what the named repository
|
|
331
|
+
* accessors return, and what a WRITE path accepts (the repository encrypts).
|
|
332
|
+
*
|
|
333
|
+
* `Plaintext<T>` is the one definition of this shape; see `security/encrypted.ts`.
|
|
334
|
+
* It is deliberately NOT distinguishable from a MASKED value — `maskPii`
|
|
335
|
+
* returns plain strings too, and no type can express "these characters are
|
|
336
|
+
* asterisks". The distinction is which named method you called.
|
|
337
|
+
*/
|
|
338
|
+
export type EmailVerificationTokenPlain = Plaintext<EmailVerificationTokenDocument>;
|
|
311
339
|
export type EmailVerificationTokenDocument = {
|
|
312
340
|
id?: string;
|
|
313
341
|
userId: string;
|
|
314
|
-
email: string
|
|
342
|
+
email: Encrypted<string>;
|
|
315
343
|
token: string;
|
|
316
344
|
expiresAt: Date;
|
|
317
345
|
createdAt: Date;
|
|
318
346
|
};
|
|
347
|
+
/**
|
|
348
|
+
* `PasswordResetTokenDocument` with its PII as plain `string` — what the named repository
|
|
349
|
+
* accessors return, and what a WRITE path accepts (the repository encrypts).
|
|
350
|
+
*
|
|
351
|
+
* `Plaintext<T>` is the one definition of this shape; see `security/encrypted.ts`.
|
|
352
|
+
* It is deliberately NOT distinguishable from a MASKED value — `maskPii`
|
|
353
|
+
* returns plain strings too, and no type can express "these characters are
|
|
354
|
+
* asterisks". The distinction is which named method you called.
|
|
355
|
+
*/
|
|
356
|
+
export type PasswordResetTokenPlain = Plaintext<PasswordResetTokenDocument>;
|
|
319
357
|
export type PasswordResetTokenDocument = {
|
|
320
358
|
id?: string;
|
|
321
359
|
userId: string;
|
|
322
|
-
email: string
|
|
360
|
+
email: Encrypted<string>;
|
|
323
361
|
token: string;
|
|
324
362
|
expiresAt: Date;
|
|
325
363
|
createdAt: Date;
|
|
@@ -353,19 +391,32 @@ export declare const TOKEN_FIELDS: {
|
|
|
353
391
|
readonly USED: "used";
|
|
354
392
|
readonly USED_AT: "usedAt";
|
|
355
393
|
};
|
|
394
|
+
/**
|
|
395
|
+
* The session shape with its PII as plain `string`.
|
|
396
|
+
*
|
|
397
|
+
* Was a hand-written twin, because `Plaintext<T>` un-branded top-level members
|
|
398
|
+
* only and all three of this document's PII fields are NESTED. Making the
|
|
399
|
+
* generic recurse removed the twin — which is the better outcome: a
|
|
400
|
+
* hand-written copy of a derived shape is the drift this whole file's
|
|
401
|
+
* `*Plain` convention exists to avoid.
|
|
402
|
+
*/
|
|
403
|
+
export type SessionPlain = Plaintext<SessionDocument>;
|
|
356
404
|
export type SessionDocument = {
|
|
357
405
|
id: string;
|
|
358
406
|
userId: string;
|
|
359
407
|
deviceInfo?: {
|
|
360
|
-
|
|
408
|
+
/** PII — ciphertext at rest. See `SessionRepository.revealSession`. */
|
|
409
|
+
userAgent?: Encrypted<string>;
|
|
361
410
|
browser?: string;
|
|
362
411
|
os?: string;
|
|
363
412
|
device?: string;
|
|
364
|
-
|
|
413
|
+
/** PII — ciphertext at rest. */
|
|
414
|
+
ip?: Encrypted<string>;
|
|
365
415
|
};
|
|
366
416
|
location?: {
|
|
367
417
|
country?: string;
|
|
368
|
-
|
|
418
|
+
/** PII — ciphertext at rest. */
|
|
419
|
+
city?: Encrypted<string>;
|
|
369
420
|
};
|
|
370
421
|
createdAt: Date;
|
|
371
422
|
lastActivity: Date;
|
|
@@ -382,7 +433,7 @@ export declare const SESSION_PUBLIC_FIELDS: readonly ["id", "deviceInfo", "locat
|
|
|
382
433
|
export declare const SESSION_EXPIRATION_MS: number;
|
|
383
434
|
/** 30 days — auto-cleanup threshold */
|
|
384
435
|
export declare const SESSION_CLEANUP_AFTER_MS: number;
|
|
385
|
-
export type SessionCreateInput = Omit<
|
|
436
|
+
export type SessionCreateInput = Omit<SessionPlain, "id" | "createdAt" | "lastActivity">;
|
|
386
437
|
export type SessionUpdateInput = {
|
|
387
438
|
lastActivity: Date;
|
|
388
439
|
location?: SessionDocument["location"];
|
|
@@ -400,7 +451,7 @@ export declare const sessionQueryHelpers: {
|
|
|
400
451
|
readonly notExpired: () => readonly ["expiresAt", ">=", Date];
|
|
401
452
|
readonly recentActivity: (since: Date) => readonly ["lastActivity", ">=", Date];
|
|
402
453
|
};
|
|
403
|
-
export declare function parseUserAgent(userAgent: string):
|
|
454
|
+
export declare function parseUserAgent(userAgent: string): SessionPlain["deviceInfo"];
|
|
404
455
|
export declare const SESSION_FIELDS: {
|
|
405
456
|
readonly ID: "id";
|
|
406
457
|
readonly USER_ID: "userId";
|
|
@@ -24,6 +24,12 @@ export const UserSchemaDefaults = {
|
|
|
24
24
|
UNKNOWN_USER_AGENT: "Unknown",
|
|
25
25
|
};
|
|
26
26
|
export const USER_COLLECTION = "users";
|
|
27
|
+
/*
|
|
28
|
+
* The PLAIN shape: this is spread into a brand-new account's payload at
|
|
29
|
+
* signup, where every value is plaintext and `createWithId` encrypts. Typed
|
|
30
|
+
* as the document it would have demanded `Encrypted<string>` from all three
|
|
31
|
+
* signup routes.
|
|
32
|
+
*/
|
|
27
33
|
export const DEFAULT_USER_DATA = {
|
|
28
34
|
role: "user",
|
|
29
35
|
emailVerified: false,
|
|
@@ -215,6 +221,11 @@ export const sessionQueryHelpers = {
|
|
|
215
221
|
notExpired: () => ["expiresAt", ">=", new Date()],
|
|
216
222
|
recentActivity: (since) => ["lastActivity", ">=", since],
|
|
217
223
|
};
|
|
224
|
+
/*
|
|
225
|
+
* Returns the PLAIN device shape: it parses a raw UA header, so everything it
|
|
226
|
+
* produces is plaintext and the repository's write hook encrypts it. Declaring
|
|
227
|
+
* `SessionDocument["deviceInfo"]` claimed the parser emitted ciphertext.
|
|
228
|
+
*/
|
|
218
229
|
export function parseUserAgent(userAgent) {
|
|
219
230
|
const ua = userAgent.toLowerCase();
|
|
220
231
|
const BROWSER_TOKENS = [
|
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
import { jsx as _jsx, jsxs as _jsxs, Fragment as _Fragment } from "react/jsx-runtime";
|
|
2
2
|
import React from "react";
|
|
3
3
|
import Link from "next/link.js";
|
|
4
|
-
import { Article,
|
|
4
|
+
import { Article, Div, Grid, Heading, OverflowRow, Pagination, Row, Span, Stack, Text } from "../../../ui/index.js";
|
|
5
5
|
import { MediaImage } from "../../media/MediaImage.js";
|
|
6
6
|
import { getDefaultLocale } from "../../../core/baseline-resolver.js";
|
|
7
7
|
import { getMediaUrl } from "../../media/types/index.js";
|
|
@@ -11,7 +11,6 @@ const __P = {
|
|
|
11
11
|
};
|
|
12
12
|
const __O = {
|
|
13
13
|
hidden: "overflow-hidden",
|
|
14
|
-
xAuto: "overflow-x-auto",
|
|
15
14
|
};
|
|
16
15
|
const CLS_FEATURED_BADGE = "rounded-full bg-warning-surface px-[var(--appkit-space-2)] py-[var(--appkit-space-0-5)] text-warning dark:bg-warning-surface dark:text-warning";
|
|
17
16
|
export function BlogCard({ post, href, onClick, className = "" }) {
|
|
@@ -33,7 +32,21 @@ export function BlogCard({ post, href, onClick, className = "" }) {
|
|
|
33
32
|
return card;
|
|
34
33
|
}
|
|
35
34
|
export function BlogCategoryTabs({ categories, active, onSelect, labels = {}, }) {
|
|
36
|
-
|
|
35
|
+
/*
|
|
36
|
+
* `ALL_ID` is a sentinel, not a category. It cannot be `""` because that is
|
|
37
|
+
* also `OverflowRow`'s "nothing selected" state, which would leave the
|
|
38
|
+
* collapsed trigger showing the placeholder instead of "All".
|
|
39
|
+
*/
|
|
40
|
+
const ALL_ID = "__all__";
|
|
41
|
+
const items = [
|
|
42
|
+
{ id: ALL_ID, label: labels.all ?? "All", onSelect: () => onSelect(null) },
|
|
43
|
+
...categories.map((cat) => ({
|
|
44
|
+
id: cat,
|
|
45
|
+
label: labels[cat] ?? cat,
|
|
46
|
+
onSelect: () => onSelect(cat),
|
|
47
|
+
})),
|
|
48
|
+
];
|
|
49
|
+
return (_jsx(OverflowRow, { items: items, ariaLabel: "Blog categories", activeId: active ?? ALL_ID, searchPlaceholder: "Search categories\u2026", noResultsText: "No matching category" }));
|
|
37
50
|
}
|
|
38
51
|
export function BlogListView({ posts, isLoading, totalPages = 1, currentPage = 1, total = 0, onPageChange, onPostClick, emptyLabel = "No posts found", slots, }) {
|
|
39
52
|
if (isLoading) {
|
|
@@ -55,5 +55,5 @@ export function BlogPostView({ slug, initialData, labels = {}, renderImage, rend
|
|
|
55
55
|
})
|
|
56
56
|
: "";
|
|
57
57
|
const coverImageUrl = getMediaUrl(post.coverImage);
|
|
58
|
-
return (_jsxs(Div, { className: `min-h-screen ${className}`, children: [coverImageUrl && (_jsxs(Div, { className: `relative h-72 md:h-96 ${__O.hidden}`, children: [renderImage ? (renderImage(post)) : (_jsx(MediaImage, { src: coverImageUrl, alt: post.title, size: "hero" })), _jsx(Scrim, { direction: "bottom-up", intensity: "subtle", className: "absolute inset-0" })] })), _jsxs(Div, { className: "max-w-3xl mx-auto", paddingY: "y-3xl", paddingX: "x-md", children: [renderBlogPostHeader(post, date, labels), post.youtubeId && /^[A-Za-z0-9_-]{6,20}$/.test(post.youtubeId) && (_jsx(Div, { className: "mb-8", children: _jsx(Iframe, { src: `https://www.youtube-nocookie.com/embed/${post.youtubeId}`, title: `${post.title} — video`, aspect: "video", rounded: "lg" }) })), post.tags && post.tags.length > 0 && (_jsx(Row, { wrap: true, gap: "sm", className: "mb-8", children: post.tags.map((tag) => (_jsxs(Link, { href: `${String(ROUTES.
|
|
58
|
+
return (_jsxs(Div, { className: `min-h-screen ${className}`, children: [coverImageUrl && (_jsxs(Div, { className: `relative h-72 md:h-96 ${__O.hidden}`, children: [renderImage ? (renderImage(post)) : (_jsx(MediaImage, { src: coverImageUrl, alt: post.title, size: "hero" })), _jsx(Scrim, { direction: "bottom-up", intensity: "subtle", className: "absolute inset-0" })] })), _jsxs(Div, { className: "max-w-3xl mx-auto", paddingY: "y-3xl", paddingX: "x-md", children: [renderBlogPostHeader(post, date, labels), post.youtubeId && /^[A-Za-z0-9_-]{6,20}$/.test(post.youtubeId) && (_jsx(Div, { className: "mb-8", children: _jsx(Iframe, { src: `https://www.youtube-nocookie.com/embed/${post.youtubeId}`, title: `${post.title} — video`, aspect: "video", rounded: "lg" }) })), post.tags && post.tags.length > 0 && (_jsx(Row, { wrap: true, gap: "sm", className: "mb-8", children: post.tags.map((tag) => (_jsxs(Link, { href: `${String(ROUTES.BLOG.LIST)}?tags=${encodeURIComponent(tag)}`, className: "inline-block px-[var(--appkit-space-3)] py-[var(--appkit-space-1)] rounded-full bg-[var(--appkit-color-surface)] bg-[var(--appkit-color-surface-elevated)] hover:bg-primary/10 text-[var(--appkit-color-text-muted)] hover:text-primary text-[length:var(--appkit-text-xs)] font-medium transition-colors", children: ["#", tag] }, tag))) })), renderAuthorBio && _jsx(Div, { className: "mb-6", children: renderAuthorBio(post) }), _jsx(Div, { surface: "card", padding: "xl", className: "mb-12", children: renderContent ? renderContent(post) : (_jsx(RichText, { html: normalizeRichTextHtml(post.content ?? ""), proseClass: "prose max-w-none dark:prose-invert" })) }), _jsxs(Stack, { gap: "xl", children: [renderBlogPostRelated(related, labels?.relatedTitle ?? "Related Posts", renderRelatedCard), renderBlogPostRelated(relatedByTags, labels?.relatedByTagsTitle ?? "You might also like", renderRelatedCard), renderBlogPostRelated(relatedByAuthor, labels?.relatedByAuthorTitle ?? `More from ${post.authorName}`, renderRelatedCard)] }), renderBackButton && _jsx(Div, { border: "default", className: "mt-10 border-t", padding: "t-xl", children: renderBackButton() })] })] }));
|
|
59
59
|
}
|
|
@@ -467,18 +467,18 @@ export declare const blogListParamsSchema: z.ZodObject<{
|
|
|
467
467
|
sort?: string | undefined;
|
|
468
468
|
page?: number | undefined;
|
|
469
469
|
q?: string | undefined;
|
|
470
|
-
perPage?: number | undefined;
|
|
471
470
|
pageSize?: number | undefined;
|
|
472
471
|
category?: "news" | "tips" | "guides" | "updates" | "community" | undefined;
|
|
473
472
|
featured?: boolean | undefined;
|
|
474
473
|
tags?: string | undefined;
|
|
474
|
+
perPage?: number | undefined;
|
|
475
475
|
}, {
|
|
476
476
|
sort?: string | undefined;
|
|
477
477
|
page?: number | undefined;
|
|
478
478
|
q?: string | undefined;
|
|
479
|
-
perPage?: number | undefined;
|
|
480
479
|
pageSize?: number | undefined;
|
|
481
480
|
category?: "news" | "tips" | "guides" | "updates" | "community" | undefined;
|
|
482
481
|
featured?: boolean | undefined;
|
|
483
482
|
tags?: string | undefined;
|
|
483
|
+
perPage?: number | undefined;
|
|
484
484
|
}>;
|
|
@@ -1,4 +1,3 @@
|
|
|
1
|
-
import type { DocumentSnapshot } from "firebase-admin/firestore";
|
|
2
1
|
/**
|
|
3
2
|
* Personal Catalogue Repository (Feature B).
|
|
4
3
|
*/
|
|
@@ -14,16 +13,17 @@ export interface CatalogueWriteContext {
|
|
|
14
13
|
}
|
|
15
14
|
export declare class CatalogueRepository extends BaseRepository<CatalogueItemDocument> {
|
|
16
15
|
/**
|
|
17
|
-
* `
|
|
16
|
+
* 🛑 DEAD as written: `CatalogueItemDocument` has no `ownerEmail`.
|
|
18
17
|
*
|
|
19
|
-
*
|
|
20
|
-
*
|
|
21
|
-
*
|
|
22
|
-
*
|
|
18
|
+
* Kept rather than deleted because it is the declaration that would start
|
|
19
|
+
* working the moment an owner email is added to the document, and deleting
|
|
20
|
+
* it would hand that future field plaintext storage by default. The reasoning
|
|
21
|
+
* it used to carry — "`ownerEmail` only, NOT `ownerName`, because D1 keeps
|
|
22
|
+
* names searchable" — described a choice between two fields that neither
|
|
23
|
+
* exist nor can arrive through `CatalogueItemCreateInput`.
|
|
23
24
|
*/
|
|
24
25
|
protected piiFields: readonly ["ownerEmail"];
|
|
25
26
|
/** Decrypt on read so callers see the shape they wrote. */
|
|
26
|
-
protected mapDoc<D = CatalogueItemDocument>(snap: DocumentSnapshot): D;
|
|
27
27
|
constructor();
|
|
28
28
|
create(input: CatalogueItemCreateInput): Promise<CatalogueItemDocument>;
|
|
29
29
|
/**
|