@mohasinac/appkit 4.42.18 → 4.44.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/_internal/client/features/lottery/LotteryDetailView.js +22 -1
- package/dist/_internal/server/features/categories/adapters.d.ts +47 -0
- package/dist/_internal/server/features/categories/adapters.js +235 -0
- package/dist/_internal/server/features/checkout/actions.js +161 -22
- package/dist/_internal/server/features/checkout/expand-order-items.js +34 -0
- package/dist/_internal/server/features/orders/adapters.js +21 -0
- package/dist/_internal/server/features/products/list-public.d.ts +24 -0
- package/dist/_internal/server/features/products/list-public.js +10 -2
- package/dist/_internal/server/features/refunds/actions.js +1 -1
- package/dist/_internal/server/features/seo/sitemap.js +54 -15
- package/dist/_internal/server/features/stores/adapters.d.ts +1 -1
- package/dist/_internal/server/features/stores/adapters.js +6 -0
- package/dist/_internal/server/functions/scheduled.d.ts +4 -2
- package/dist/_internal/server/functions/scheduled.js +64 -6
- package/dist/_internal/server/jobs/core/adminAnalytics.d.ts +0 -1
- package/dist/_internal/server/jobs/core/adminAnalytics.js +9 -1
- package/dist/_internal/server/jobs/core/analyticsAlertEvaluate.d.ts +47 -0
- package/dist/_internal/server/jobs/core/analyticsAlertEvaluate.js +468 -0
- package/dist/_internal/server/jobs/core/autoPayoutEligibility.js +14 -1
- package/dist/_internal/server/jobs/core/countersReconcile.js +24 -8
- package/dist/_internal/server/jobs/core/onCategoryWrite.js +59 -0
- package/dist/_internal/server/jobs/core/onProductWrite.js +31 -0
- package/dist/_internal/server/jobs/core/onReviewWrite.js +8 -0
- package/dist/_internal/server/jobs/core/onStoreWrite.d.ts +1 -1
- package/dist/_internal/server/jobs/core/onStoreWrite.js +8 -2
- package/dist/_internal/server/jobs/core/priceIndexRollup.d.ts +47 -0
- package/dist/_internal/server/jobs/core/priceIndexRollup.js +234 -0
- package/dist/_internal/server/jobs/core/revalidateNotify.d.ts +28 -0
- package/dist/_internal/server/jobs/core/revalidateNotify.js +125 -0
- package/dist/_internal/server/jobs/core/{testerSandboxCleanup.d.ts → testDataCleanup.d.ts} +3 -3
- package/dist/_internal/server/jobs/core/{testerSandboxCleanup.js → testDataCleanup.js} +3 -3
- package/dist/_internal/server/jobs/core/weeklyPayoutEligibility.js +5 -1
- package/dist/_internal/server/jobs/handlers/analyticsAlertEvaluate.d.ts +2 -0
- package/dist/_internal/server/jobs/handlers/analyticsAlertEvaluate.js +2 -0
- package/dist/_internal/server/jobs/handlers/index.d.ts +3 -1
- package/dist/_internal/server/jobs/handlers/index.js +3 -1
- package/dist/_internal/server/jobs/handlers/messages.d.ts +5 -2
- package/dist/_internal/server/jobs/handlers/messages.js +5 -2
- package/dist/_internal/server/jobs/handlers/priceIndexRollup.d.ts +2 -0
- package/dist/_internal/server/jobs/handlers/priceIndexRollup.js +2 -0
- package/dist/_internal/server/jobs/handlers/testDataCleanup.d.ts +2 -0
- package/dist/_internal/server/jobs/handlers/testDataCleanup.js +2 -0
- package/dist/_internal/shared/actions/action-registry.js +34 -0
- package/dist/_internal/shared/cache/revalidate-targets.d.ts +49 -0
- package/dist/_internal/shared/cache/revalidate-targets.js +157 -0
- package/dist/_internal/shared/checkout/order-math.d.ts +113 -3
- package/dist/_internal/shared/checkout/order-math.js +194 -7
- package/dist/_internal/shared/features/categories/price-guidance.d.ts +110 -0
- package/dist/_internal/shared/features/categories/price-guidance.js +136 -0
- package/dist/_internal/shared/features/site-settings/gst-registration.d.ts +90 -0
- package/dist/_internal/shared/features/site-settings/gst-registration.js +126 -0
- package/dist/_internal/shared/fees/calculator.d.ts +105 -0
- package/dist/_internal/shared/fees/calculator.js +143 -0
- package/dist/_internal/shared/listing-types/art/config.d.ts +0 -6
- package/dist/_internal/shared/listing-types/classified/config.d.ts +0 -6
- package/dist/_internal/shared/listing-types/digital-code/config.d.ts +0 -6
- package/dist/_internal/shared/listing-types/live/config.d.ts +0 -6
- package/dist/_internal/shared/listing-types/standard/config.d.ts +0 -6
- package/dist/_internal/shared/listing-types/stickers/config.d.ts +0 -6
- package/dist/_internal/shared/templating/placeholders.d.ts +70 -0
- package/dist/_internal/shared/templating/placeholders.js +73 -0
- package/dist/client.d.ts +2 -0
- package/dist/client.js +1 -0
- package/dist/constants/api-endpoints.d.ts +42 -0
- package/dist/constants/api-endpoints.js +14 -0
- package/dist/features/admin/actions/admin-actions.d.ts +1 -1
- package/dist/features/admin/actions/admin-actions.js +1 -1
- package/dist/features/admin/components/AdminCategoryEditorView.js +269 -3
- package/dist/features/admin/components/AdminProductEditorView.js +8 -1
- package/dist/features/admin/components/AdminProductsView.js +78 -7
- package/dist/features/admin/components/AdminSiteSettingsView.js +20 -1
- package/dist/features/admin/components/AdminTaxCodeEditorView.d.ts +10 -0
- package/dist/features/admin/components/AdminTaxCodeEditorView.js +160 -0
- package/dist/features/admin/components/AdminTaxCodesView.d.ts +13 -0
- package/dist/features/admin/components/AdminTaxCodesView.js +86 -0
- package/dist/features/admin/components/AdminTesterChecklistView.js +1 -1
- package/dist/features/admin/components/analytics/AdminTopProductsTable.js +1 -1
- package/dist/features/auctions/components/AuctionBottomActions.js +10 -1
- package/dist/features/auctions/components/AuctionDetailPageView.js +2 -1
- package/dist/features/auctions/components/AuctionLiveStatusBadge.d.ts +20 -0
- package/dist/features/auctions/components/AuctionLiveStatusBadge.js +21 -0
- package/dist/features/auctions/components/PlaceBidFormClient.d.ts +1 -1
- package/dist/features/auctions/components/PlaceBidFormClient.js +20 -2
- package/dist/features/auctions/hooks/useIsAuctionEnded.d.ts +41 -0
- package/dist/features/auctions/hooks/useIsAuctionEnded.js +76 -0
- package/dist/features/auth/schemas/firestore.d.ts +0 -1
- package/dist/features/blog/api/route.js +16 -1
- package/dist/features/blog/schemas/firestore.d.ts +2 -2
- package/dist/features/catalogue/components/CatalogueItemEditorView.js +14 -3
- package/dist/features/categories/actions/category-actions.d.ts +2 -2
- package/dist/features/categories/actions/category-actions.js +22 -10
- package/dist/features/categories/api/[id]/description-template/route.d.ts +45 -0
- package/dist/features/categories/api/[id]/description-template/route.js +252 -0
- package/dist/features/categories/api/route.js +156 -11
- package/dist/features/categories/components/CategoriesIndexListing.d.ts +1 -3
- package/dist/features/categories/components/CategoriesIndexListing.js +1 -1
- package/dist/features/categories/components/CategoriesIndexPageView.d.ts +27 -1
- package/dist/features/categories/components/CategoriesIndexPageView.js +24 -33
- package/dist/features/categories/components/CategoryDetailPageView.js +43 -10
- package/dist/features/categories/components/CategoryTemplatePicker.d.ts +65 -0
- package/dist/features/categories/components/CategoryTemplatePicker.js +170 -0
- package/dist/features/categories/constants/listing-categories.d.ts +17 -0
- package/dist/features/categories/constants/listing-categories.js +53 -0
- package/dist/features/categories/hooks/useCategoryTree.js +28 -2
- package/dist/features/categories/repository/categories.repository.d.ts +73 -12
- package/dist/features/categories/repository/categories.repository.js +203 -42
- package/dist/features/categories/repository/price-index.repository.d.ts +115 -0
- package/dist/features/categories/repository/price-index.repository.js +85 -0
- package/dist/features/categories/schemas/category-content.d.ts +206 -0
- package/dist/features/categories/schemas/category-content.js +28 -0
- package/dist/features/categories/schemas/firestore.d.ts +74 -5
- package/dist/features/categories/schemas/firestore.js +74 -3
- package/dist/features/categories/schemas/index.d.ts +1047 -0
- package/dist/features/categories/schemas/index.js +96 -0
- package/dist/features/categories/server.d.ts +1 -0
- package/dist/features/categories/server.js +7 -0
- package/dist/features/categories/types/index.d.ts +9 -0
- package/dist/features/events/schemas/firestore.d.ts +2 -2
- package/dist/features/faq/schemas/firestore.d.ts +2 -1
- package/dist/features/faq/schemas/firestore.js +20 -8
- package/dist/features/faq/utils/getHomepageFaqsCached.d.ts +20 -0
- package/dist/features/faq/utils/getHomepageFaqsCached.js +22 -0
- package/dist/features/homepage/components/MarketplaceHomepageView.js +13 -3
- package/dist/features/homepage/lib/live-stats.js +18 -8
- package/dist/features/media/MediaImage.js +19 -2
- package/dist/features/orders/schemas/firestore.d.ts +70 -0
- package/dist/features/orders/types/index.d.ts +55 -0
- package/dist/features/products/actions/product-actions.d.ts +0 -9
- package/dist/features/products/actions/product-actions.js +25 -0
- package/dist/features/products/columns/index.d.ts +0 -1
- package/dist/features/products/columns/index.js +5 -1
- package/dist/features/products/components/ArtStickersListView.js +7 -1
- package/dist/features/products/components/PrizeDrawsSection.js +5 -0
- package/dist/features/products/components/ProductFilters.d.ts +0 -9
- package/dist/features/products/components/ProductForm.d.ts +27 -1
- package/dist/features/products/components/ProductForm.js +26 -12
- package/dist/features/products/components/ProductsIndexPageView.js +1 -1
- package/dist/features/products/constants/sieve.d.ts +0 -6
- package/dist/features/products/constants/sieve.js +35 -2
- package/dist/features/products/repository/products.repository.d.ts +115 -1
- package/dist/features/products/repository/products.repository.js +491 -39
- package/dist/features/products/schemas/firestore.d.ts +65 -5
- package/dist/features/products/schemas/firestore.js +9 -0
- package/dist/features/products/schemas/product-features.d.ts +140 -2
- package/dist/features/products/schemas/product-features.js +62 -1
- package/dist/features/promotions/repository/coupons.repository.js +6 -1
- package/dist/features/promotions/schemas/firestore.d.ts +44 -1
- package/dist/features/promotions/schemas/firestore.js +76 -2
- package/dist/features/reviews/repository/reviews.repository.d.ts +22 -0
- package/dist/features/reviews/repository/reviews.repository.js +35 -0
- package/dist/features/seller/actions/seller-actions.js +17 -2
- package/dist/features/seller/components/PrintCenterView.d.ts +3 -2
- package/dist/features/seller/components/PrintCenterView.js +3 -2
- package/dist/features/seller/components/SellerAnalyticsAlertsView.js +21 -11
- package/dist/features/seller/components/SellerOrdersView.js +6 -1
- package/dist/features/seller/components/SellerPayoutSettingsView.js +19 -3
- package/dist/features/seller/components/SellerProductShell.d.ts +50 -2
- package/dist/features/seller/components/SellerProductShell.js +101 -9
- package/dist/features/seller/components/SellerProductsFilterDrawer.d.ts +13 -1
- package/dist/features/seller/components/SellerProductsFilterDrawer.js +2 -2
- package/dist/features/seller/components/SellerProductsView.js +108 -3
- package/dist/features/seller/types/index.d.ts +17 -0
- package/dist/features/seller/utils/product-draft-mapping.d.ts +13 -0
- package/dist/features/seller/utils/product-draft-mapping.js +17 -0
- package/dist/features/store-extensions/constants/alert-metrics.d.ts +86 -0
- package/dist/features/store-extensions/constants/alert-metrics.js +142 -0
- package/dist/features/store-extensions/schemas/firestore.d.ts +19 -1
- package/dist/features/stores/schemas/firestore.d.ts +31 -2
- package/dist/features/tax-codes/repository/tax-codes.repository.d.ts +55 -0
- package/dist/features/tax-codes/repository/tax-codes.repository.js +131 -0
- package/dist/features/tax-codes/schemas/firestore.d.ts +125 -0
- package/dist/features/tax-codes/schemas/firestore.js +82 -0
- package/dist/features/tax-codes/schemas/tax-code-form.d.ts +63 -0
- package/dist/features/tax-codes/schemas/tax-code-form.js +152 -0
- package/dist/features/tax-codes/schemas/tax-codes.validators.d.ts +107 -0
- package/dist/features/tax-codes/schemas/tax-codes.validators.js +85 -0
- package/dist/features/tester/actions/index.d.ts +0 -1
- package/dist/features/tester/actions/index.js +0 -1
- package/dist/features/tester/components/AdminTesterFeedbackIssuesView.js +1 -1
- package/dist/features/tester/components/AdminTesterFeedbackListView.js +1 -1
- package/dist/features/tester/components/index.d.ts +0 -4
- package/dist/features/tester/components/index.js +0 -2
- package/dist/features/tester/repository/tester-checklist-item.repository.d.ts +1 -20
- package/dist/features/tester/repository/tester-checklist-item.repository.js +0 -52
- package/dist/features/tester/schemas/firestore.d.ts +0 -6
- package/dist/features/tester/seed-data/authored/admin__admin-detail-round-trips.js +3 -3
- package/dist/features/tester/seed-data/authored/admin__site-system.js +4 -5
- package/dist/features/tester/seed-data/authored/content-discovery__category-counts-and-rollup.js +2 -2
- package/dist/features/tester/seed-data/authored/index.js +0 -2
- package/dist/features/tester/seed-data/authored/page-wiring__reachability.js +0 -19
- package/dist/features/tester/seed-data/tester-checklist-seed-data.js +10 -29
- package/dist/index.d.ts +21 -7
- package/dist/index.js +53 -7
- package/dist/next/routing/route-map.d.ts +2 -4
- package/dist/next/routing/route-map.js +1 -2
- package/dist/repositories/index.d.ts +1 -0
- package/dist/repositories/index.js +1 -0
- package/dist/schemas/registry.d.ts +506 -0
- package/dist/seed/_helpers/brand-rows.d.ts +35 -0
- package/dist/seed/_helpers/brand-rows.js +576 -0
- package/dist/seed/_helpers/category-content.d.ts +39 -0
- package/dist/seed/_helpers/category-content.js +634 -0
- package/dist/seed/_helpers/category-forest.d.ts +2 -0
- package/dist/seed/_helpers/category-forest.js +585 -243
- package/dist/seed/_helpers/category-models.d.ts +5 -0
- package/dist/seed/_helpers/category-models.js +1364 -0
- package/dist/seed/_helpers/category-tree.js +17 -1
- package/dist/seed/_helpers/character-features.d.ts +10 -0
- package/dist/seed/_helpers/character-features.js +118 -0
- package/dist/seed/_helpers/media.d.ts +1 -1
- package/dist/seed/_helpers/media.js +44 -8
- package/dist/seed/_helpers/search-txt-wrappers.d.ts +10 -0
- package/dist/seed/_helpers/search-txt-wrappers.js +12 -1
- package/dist/seed/categories-seed-data.js +147 -169
- package/dist/seed/index.d.ts +1 -0
- package/dist/seed/index.js +1 -0
- package/dist/seed/manifest.d.ts +1 -1
- package/dist/seed/manifest.js +5 -0
- package/dist/seed/orders-seed-data.js +5 -3
- package/dist/seed/product-features-seed-data.d.ts +1 -8
- package/dist/seed/product-features-seed-data.js +358 -154
- package/dist/seed/products-art-seed-data.js +16 -4
- package/dist/seed/products-auctions-seed-data.js +6 -6
- package/dist/seed/products-classifieds-seed-data.js +17 -7
- package/dist/seed/products-digital-codes-seed-data.js +12 -12
- package/dist/seed/products-preorders-seed-data.js +8 -8
- package/dist/seed/products-prize-draws-seed-data.js +25 -8
- package/dist/seed/products-standard-seed-data.js +10 -60
- package/dist/seed/products-stickers-seed-data.js +6 -6
- package/dist/seed/site-settings-seed-data.js +24 -0
- package/dist/seed/store-extensions-seed-data.js +10 -4
- package/dist/seed/tax-codes-seed-data.d.ts +34 -0
- package/dist/seed/tax-codes-seed-data.js +100 -0
- package/dist/seed/test-data-ttl.d.ts +29 -0
- package/dist/seed/test-data-ttl.js +31 -0
- package/dist/server-entry.d.ts +1 -1
- package/dist/server-entry.js +6 -1
- package/dist/server.d.ts +4 -1
- package/dist/server.js +11 -2
- package/dist/styles.css +40 -0
- package/dist/ui/components/PaginatedSelect.d.ts +14 -0
- package/dist/ui/components/PaginatedSelect.js +0 -0
- package/dist/ui/components/PaginatedSelect.style.css +40 -0
- package/dist/utils/media-url.d.ts +26 -0
- package/dist/utils/media-url.js +144 -0
- package/dist/utils/physical-location.d.ts +23 -0
- package/dist/utils/physical-location.js +52 -0
- package/dist/utils/search-txt-builders.d.ts +20 -0
- package/dist/utils/search-txt-builders.js +36 -0
- package/package.json +1 -1
- package/scripts/seed-cli.mjs +4 -1
- package/dist/_internal/server/jobs/handlers/testerSandboxCleanup.d.ts +0 -2
- package/dist/_internal/server/jobs/handlers/testerSandboxCleanup.js +0 -2
- package/dist/features/tester/actions/leaderboard-actions.d.ts +0 -3
- package/dist/features/tester/actions/leaderboard-actions.js +0 -5
- package/dist/features/tester/components/BugHunterLeaderboardView.d.ts +0 -23
- package/dist/features/tester/components/BugHunterLeaderboardView.js +0 -18
- package/dist/features/tester/components/TesterHubView.d.ts +0 -5
- package/dist/features/tester/components/TesterHubView.js +0 -110
- package/dist/features/tester/seed-data/authored/public-pages__bug-hunters.d.ts +0 -2
- package/dist/features/tester/seed-data/authored/public-pages__bug-hunters.js +0 -78
- package/dist/features/tester/seed-data/tester-ttl.d.ts +0 -4
- package/dist/features/tester/seed-data/tester-ttl.js +0 -6
package/dist/server-entry.d.ts
CHANGED
|
@@ -67,7 +67,7 @@ export { getSearchResults, searchAction, type SearchQuery, } from "./_internal/s
|
|
|
67
67
|
export { getCategoryForDetail, listRootCategories, listFeaturedCategories, listMenuCategories, getCategoryTree, listSitemapCategories, CATEGORIES_PAGE_SIZE, CATEGORIES_ROOT_TIER, CATEGORIES_MAX_DEPTH, CATEGORIES_SITEMAP_LIMIT, CATEGORIES_FEATURED_LIMIT, CATEGORIES_MENU_LIMIT, } from "./_internal/server/features/categories/index";
|
|
68
68
|
export { getGroupedListingForDetail, getGroupedListingWithItems, listGroupedListings, listFeaturedGroupedListings, listSitemapGroupedListings, getGroupsForProduct, getGroupsWithItemsForProduct, GROUPED_LISTINGS_PAGE_SIZE, GROUPED_LISTINGS_FEATURED_LIMIT, GROUPED_LISTINGS_SITEMAP_LIMIT, buildGroupedListingMetadata, renderGroupedListingOg, type GroupedListingWithItems, type ListGroupedListingsParams, type SitemapGroupedListing, type GroupedListingMetadataOptions, } from "./_internal/server/features/grouped/index";
|
|
69
69
|
export { createCheckoutOrderAction, attachPaymentAction, verifyAndPlacePhonePeOrderAction, previewCheckoutPricing, resolveShippingCost, formatShippingAddress, CHECKOUT_DEFAULT_COMMISSIONS, CHECKOUT_PAYMENT_METHODS, type CreateCheckoutOrderInput, type VerifyAndPlacePhonePeOrderInput, type CheckoutOrderResult, type CheckoutPaymentMethod, type CheckoutPricingPreviewInput, type CheckoutPricingPreview, } from "./_internal/server/features/checkout/index";
|
|
70
|
-
export { unitPriceFor, lineTotalFor, computePreOrderDepositAmount, } from "./_internal/shared/checkout/order-math";
|
|
70
|
+
export { unitPriceFor, lineTotalFor, sumGroupGst, computePreOrderDepositAmount, type GroupGstSummary, type GstRateSlice, } from "./_internal/shared/checkout/order-math";
|
|
71
71
|
export { processRefundAction, type ProcessRefundInput, } from "./_internal/server/features/refunds/actions";
|
|
72
72
|
export { getSublistingCategoryForDetail } from "./_internal/server/features/sublisting-categories/index";
|
|
73
73
|
export { getStoreForDetail, listStoreProductsInitial, listStoreAuctionsInitial, listStorePreOrdersInitial, listSitemapStores, STORES_PAGE_SIZE, STORES_PRODUCTS_PAGE_SIZE, STORES_SITEMAP_LIMIT, STORES_FEATURED_LIMIT, } from "./_internal/server/features/stores/index";
|
package/dist/server-entry.js
CHANGED
|
@@ -101,7 +101,12 @@ export { createCheckoutOrderAction, attachPaymentAction, verifyAndPlacePhonePeOr
|
|
|
101
101
|
// consumer's Razorpay create-order route needs it: that route used to hand-roll
|
|
102
102
|
// the rule and reproduced only the bundle branch, so it captured the LIST price
|
|
103
103
|
// for an accepted offer. Pure math — no Firestore, no server-only imports.
|
|
104
|
-
|
|
104
|
+
// `sumGroupGst` joins them for exactly the same reason, one defect later: that
|
|
105
|
+
// same create-order route decides what the gateway CAPTURES and omitted product
|
|
106
|
+
// GST entirely, so the buyer was shown the tax, charged without it, and the
|
|
107
|
+
// order recorded none — with the verify-side mismatch guard omitting it too, so
|
|
108
|
+
// the three were consistently wrong and the undercharge was undetectable.
|
|
109
|
+
export { unitPriceFor, lineTotalFor, sumGroupGst, computePreOrderDepositAmount, } from "./_internal/shared/checkout/order-math";
|
|
105
110
|
// S-SBUNI-RULES: refund action
|
|
106
111
|
export { processRefundAction, } from "./_internal/server/features/refunds/actions";
|
|
107
112
|
// S3: sublisting categories data layer
|
package/dist/server.d.ts
CHANGED
|
@@ -231,6 +231,7 @@ export { POST } from "./features/categories/server";
|
|
|
231
231
|
export { categoriesGET } from "./features/categories/server";
|
|
232
232
|
export { categoryItemDELETE } from "./features/categories/server";
|
|
233
233
|
export { categoryItemGET } from "./features/categories/server";
|
|
234
|
+
export { categoryDescriptionTemplateGET } from "./features/categories/server";
|
|
234
235
|
export { categoryItemPATCH } from "./features/categories/server";
|
|
235
236
|
export { createCategory } from "./features/categories/server";
|
|
236
237
|
export { deleteCategory } from "./features/categories/server";
|
|
@@ -267,7 +268,6 @@ export { getEventPollResults } from "./features/events/server";
|
|
|
267
268
|
export type { PollResultEntry, SpinResultEntry } from "./features/events/index";
|
|
268
269
|
export { getEventSpinResults } from "./features/events/server";
|
|
269
270
|
export { getUserSpinResultsForEvent } from "./features/events/server";
|
|
270
|
-
export { getBugHunterLeaderboard } from "./features/tester/server";
|
|
271
271
|
export { getPublicEventById } from "./features/events/server";
|
|
272
272
|
export { listPublicEvents } from "./features/events/server";
|
|
273
273
|
export { getRelatedEvents } from "./features/events/server";
|
|
@@ -427,6 +427,7 @@ export { removeFromWishlist } from "./features/wishlist/server";
|
|
|
427
427
|
export { siteSettingsRepository } from "./repositories/index";
|
|
428
428
|
export { storeRepository } from "./repositories/index";
|
|
429
429
|
export { orderRepository } from "./repositories/index";
|
|
430
|
+
export { taxCodesRepository } from "./repositories/index";
|
|
430
431
|
export type { OrderDocument } from "./features/orders/index";
|
|
431
432
|
export type { OrderDocumentItem } from "./features/orders/index";
|
|
432
433
|
export { serverLogger } from "./monitoring/index";
|
|
@@ -536,6 +537,8 @@ export type { SitemapOptions, RobotsOptions, ManifestOptions, DefaultOgOptions }
|
|
|
536
537
|
export { checkActionAllowed } from "./features/admin/utils/checkActionAllowed";
|
|
537
538
|
export { getDisabledRoutes } from "./features/admin/utils/getDisabledRoutes";
|
|
538
539
|
export { getSiteSettingsGlobal } from "./features/admin/utils/getSiteSettingsGlobal";
|
|
540
|
+
export { getHomepageFaqsCached } from "./features/faq/utils/getHomepageFaqsCached";
|
|
541
|
+
export { revalidateTargetsFor, type RevalidateHints, } from "./_internal/shared/cache/revalidate-targets";
|
|
539
542
|
export { getSiteSettingsSafe } from "./_internal/server/features/site-settings/safe-settings";
|
|
540
543
|
export { toPublicSiteSettings, PUBLIC_SITE_SETTINGS_FIELDS, PRIVATE_SITE_SETTINGS_FIELDS, type ToPublicSiteSettingsOptions, } from "./_internal/server/features/site-settings/adapters";
|
|
541
544
|
export { callFirebaseIdentityToolkit } from "./_internal/server/features/auth/firebase-identity";
|
package/dist/server.js
CHANGED
|
@@ -665,6 +665,8 @@ export { categoryItemDELETE } from "./features/categories/server";
|
|
|
665
665
|
// [SERVER-ONLY]-Server-only — uses Node.js, Next.js server internals, or third-party server SDKs (auth, email, payment, shipping).
|
|
666
666
|
// categoryItemGET - Shared export for category item get.
|
|
667
667
|
export { categoryItemGET } from "./features/categories/server";
|
|
668
|
+
// categoryDescriptionTemplateGET - the seller form's inherited-template read.
|
|
669
|
+
export { categoryDescriptionTemplateGET } from "./features/categories/server";
|
|
668
670
|
// [SERVER-ONLY]-Server-only — uses Node.js, Next.js server internals, or third-party server SDKs (auth, email, payment, shipping).
|
|
669
671
|
// categoryItemPATCH - Shared export for category item patch.
|
|
670
672
|
export { categoryItemPATCH } from "./features/categories/server";
|
|
@@ -780,8 +782,6 @@ export { getEventSpinResults } from "./features/events/server";
|
|
|
780
782
|
// getUserSpinResultsForEvent - The CALLER'S OWN spins for an event, unmasked. Companion to the masked public feed above.
|
|
781
783
|
export { getUserSpinResultsForEvent } from "./features/events/server";
|
|
782
784
|
// [SERVER-ONLY]-Server-only — uses Node.js, Next.js server internals, or third-party server SDKs (auth, email, payment, shipping).
|
|
783
|
-
// getBugHunterLeaderboard - Ranks testers by confirmed-bug count.
|
|
784
|
-
export { getBugHunterLeaderboard } from "./features/tester/server";
|
|
785
785
|
// [SERVER-ONLY]-Server-only — uses Node.js, Next.js server internals, or third-party server SDKs (auth, email, payment, shipping).
|
|
786
786
|
// getPublicEventById - Helper for get public event by id.
|
|
787
787
|
export { getPublicEventById } from "./features/events/server";
|
|
@@ -1248,6 +1248,9 @@ export { siteSettingsRepository } from "./repositories/index";
|
|
|
1248
1248
|
export { storeRepository } from "./repositories/index";
|
|
1249
1249
|
// orderRepository - Shared export for order repository (needed by consumer Firebase Functions, e.g. invoice PDF generation).
|
|
1250
1250
|
export { orderRepository } from "./repositories/index";
|
|
1251
|
+
// taxCodesRepository (B3) — resolved by deriveTaxonomy on every product write
|
|
1252
|
+
// that names a taxonomy field, so it is a server-only read on a hot path.
|
|
1253
|
+
export { taxCodesRepository } from "./repositories/index";
|
|
1251
1254
|
// SB-UNI-V — bundlesRepository deleted; use categoriesRepository with categoryType:"bundle".
|
|
1252
1255
|
// -- Monitoring --------------------------------------------------------------
|
|
1253
1256
|
// serverLogger - Structured server-side logger.
|
|
@@ -1404,6 +1407,12 @@ export { buildSitemap, buildRobots, buildManifest, buildDefaultOgImage, DEFAULT_
|
|
|
1404
1407
|
export { checkActionAllowed } from "./features/admin/utils/checkActionAllowed";
|
|
1405
1408
|
export { getDisabledRoutes } from "./features/admin/utils/getDisabledRoutes";
|
|
1406
1409
|
export { getSiteSettingsGlobal } from "./features/admin/utils/getSiteSettingsGlobal";
|
|
1410
|
+
// Same React.cache dedup, for the FAQ list the homepage reads twice per render
|
|
1411
|
+
// (once for the section, once for its JSON-LD).
|
|
1412
|
+
export { getHomepageFaqsCached } from "./features/faq/utils/getHomepageFaqsCached";
|
|
1413
|
+
// Which PAGE paths a write makes stale — the input to revalidatePath(). Long
|
|
1414
|
+
// detail-route TTLs are only safe because this exists.
|
|
1415
|
+
export { revalidateTargetsFor, } from "./_internal/shared/cache/revalidate-targets";
|
|
1407
1416
|
// Null-safe wrapper — returns null on Firestore failure instead of throwing.
|
|
1408
1417
|
export { getSiteSettingsSafe } from "./_internal/server/features/site-settings/safe-settings";
|
|
1409
1418
|
// Public site-settings allow-list projection — the ONLY sanctioned shape for
|
package/dist/styles.css
CHANGED
|
@@ -7369,6 +7369,46 @@
|
|
|
7369
7369
|
background-color: var(--appkit-color-slate-800);
|
|
7370
7370
|
}
|
|
7371
7371
|
|
|
7372
|
+
/* ── edit the selected option (C2c) ──
|
|
7373
|
+
Absolutely positioned inside `.appkit-ps` (which is `position: relative`)
|
|
7374
|
+
rather than being a flex sibling of the trigger: the trigger is a
|
|
7375
|
+
full-width button and the pencil has to sit ON it visually while remaining
|
|
7376
|
+
OUTSIDE it in the DOM. A button nested inside a button is invalid HTML and
|
|
7377
|
+
the browser's recovery hoists it out, after which which element receives
|
|
7378
|
+
the click is an engine decision — so the pencil would open the dropdown on
|
|
7379
|
+
some browsers and the editor on others.
|
|
7380
|
+
|
|
7381
|
+
`right` clears the ▾ caret. The hover fill uses the theme-inverting
|
|
7382
|
+
surface-hover token, never a named palette tint: `hover:bg-zinc-50` and
|
|
7383
|
+
friends are the SAME near-white in every theme, which is white-on-white
|
|
7384
|
+
under dark ink (Root Cause #79). */
|
|
7385
|
+
.appkit-ps__edit-btn {
|
|
7386
|
+
position: absolute;
|
|
7387
|
+
top: 50%;
|
|
7388
|
+
right: 2rem;
|
|
7389
|
+
transform: translateY(-50%);
|
|
7390
|
+
display: inline-flex;
|
|
7391
|
+
align-items: center;
|
|
7392
|
+
justify-content: center;
|
|
7393
|
+
width: 1.75rem;
|
|
7394
|
+
height: 1.75rem;
|
|
7395
|
+
border-radius: var(--appkit-radius-md, 0.375rem);
|
|
7396
|
+
font-size: 0.875rem;
|
|
7397
|
+
line-height: 1;
|
|
7398
|
+
color: var(--appkit-color-text-muted);
|
|
7399
|
+
transition: background-color 0.1s, color 0.1s;
|
|
7400
|
+
}
|
|
7401
|
+
|
|
7402
|
+
.appkit-ps__edit-btn:hover {
|
|
7403
|
+
background-color: var(--appkit-color-surface-hover);
|
|
7404
|
+
color: var(--appkit-color-primary);
|
|
7405
|
+
}
|
|
7406
|
+
|
|
7407
|
+
.appkit-ps__edit-btn:focus-visible {
|
|
7408
|
+
outline: 2px solid var(--appkit-color-focus-ring);
|
|
7409
|
+
outline-offset: 1px;
|
|
7410
|
+
}
|
|
7411
|
+
|
|
7372
7412
|
/* SideDrawer — accessible slide-in panel with focus trap + unsaved-changes */
|
|
7373
7413
|
|
|
7374
7414
|
.appkit-side-drawer__backdrop {
|
|
@@ -32,6 +32,20 @@ interface BaseProps<V> {
|
|
|
32
32
|
createSchema?: import("zod").ZodType<FormValues> | import("zod").ZodType<unknown>;
|
|
33
33
|
onCreateSubmit?: (values: FormValues) => Promise<PaginatedSelectOption<V>>;
|
|
34
34
|
createSubmitLabel?: string;
|
|
35
|
+
editLabel?: string;
|
|
36
|
+
editDrawerTitle?: string;
|
|
37
|
+
renderEditForm?: (props: {
|
|
38
|
+
value: V;
|
|
39
|
+
option: PaginatedSelectOption<V> | null;
|
|
40
|
+
onEdited: (option: PaginatedSelectOption<V>) => void;
|
|
41
|
+
onCancel: () => void;
|
|
42
|
+
}) => ReactNode;
|
|
43
|
+
editFields?: QuickFieldDef[];
|
|
44
|
+
editSchema?: import("zod").ZodType<FormValues> | import("zod").ZodType<unknown>;
|
|
45
|
+
/** Seed the quick form from the row being edited. */
|
|
46
|
+
onEditLoad?: (value: V) => Promise<FormValues>;
|
|
47
|
+
onEditSubmit?: (value: V, values: FormValues) => Promise<PaginatedSelectOption<V>>;
|
|
48
|
+
editSubmitLabel?: string;
|
|
35
49
|
}
|
|
36
50
|
interface SingleProps<V> extends BaseProps<V> {
|
|
37
51
|
multiple?: false;
|
|
Binary file
|
|
@@ -260,3 +260,43 @@
|
|
|
260
260
|
:is(.dark) .appkit-ps__create-btn:hover {
|
|
261
261
|
background-color: var(--appkit-color-slate-800);
|
|
262
262
|
}
|
|
263
|
+
|
|
264
|
+
/* ── edit the selected option (C2c) ──
|
|
265
|
+
Absolutely positioned inside `.appkit-ps` (which is `position: relative`)
|
|
266
|
+
rather than being a flex sibling of the trigger: the trigger is a
|
|
267
|
+
full-width button and the pencil has to sit ON it visually while remaining
|
|
268
|
+
OUTSIDE it in the DOM. A button nested inside a button is invalid HTML and
|
|
269
|
+
the browser's recovery hoists it out, after which which element receives
|
|
270
|
+
the click is an engine decision — so the pencil would open the dropdown on
|
|
271
|
+
some browsers and the editor on others.
|
|
272
|
+
|
|
273
|
+
`right` clears the ▾ caret. The hover fill uses the theme-inverting
|
|
274
|
+
surface-hover token, never a named palette tint: `hover:bg-zinc-50` and
|
|
275
|
+
friends are the SAME near-white in every theme, which is white-on-white
|
|
276
|
+
under dark ink (Root Cause #79). */
|
|
277
|
+
.appkit-ps__edit-btn {
|
|
278
|
+
position: absolute;
|
|
279
|
+
top: 50%;
|
|
280
|
+
right: 2rem;
|
|
281
|
+
transform: translateY(-50%);
|
|
282
|
+
display: inline-flex;
|
|
283
|
+
align-items: center;
|
|
284
|
+
justify-content: center;
|
|
285
|
+
width: 1.75rem;
|
|
286
|
+
height: 1.75rem;
|
|
287
|
+
border-radius: var(--appkit-radius-md, 0.375rem);
|
|
288
|
+
font-size: 0.875rem;
|
|
289
|
+
line-height: 1;
|
|
290
|
+
color: var(--appkit-color-text-muted);
|
|
291
|
+
transition: background-color 0.1s, color 0.1s;
|
|
292
|
+
}
|
|
293
|
+
|
|
294
|
+
.appkit-ps__edit-btn:hover {
|
|
295
|
+
background-color: var(--appkit-color-surface-hover);
|
|
296
|
+
color: var(--appkit-color-primary);
|
|
297
|
+
}
|
|
298
|
+
|
|
299
|
+
.appkit-ps__edit-btn:focus-visible {
|
|
300
|
+
outline: 2px solid var(--appkit-color-focus-ring);
|
|
301
|
+
outline-offset: 1px;
|
|
302
|
+
}
|
|
@@ -30,6 +30,32 @@ export declare const MEDIA_URL_MAX_LENGTH = 2048;
|
|
|
30
30
|
*/
|
|
31
31
|
export declare const APPROVED_MEDIA_DOMAINS: readonly string[];
|
|
32
32
|
export declare const MEDIA_URL_MESSAGE = "Must be a stored media reference (/media/<slug>) or a URL on an approved CDN domain";
|
|
33
|
+
/**
|
|
34
|
+
* Local, static stand-ins for seed photography. Served straight out of
|
|
35
|
+
* `public/` — no function, no upstream fetch, no sharp pipeline.
|
|
36
|
+
*
|
|
37
|
+
* 🛑 This is the single most load-bearing cost control in the app. Every seed
|
|
38
|
+
* image used to resolve to `/api/media/ext?url=https://placehold.co/…`, i.e. a
|
|
39
|
+
* Node lambda that fetched a third party (up to 2 × 4 s) and ran a full sharp
|
|
40
|
+
* decode/watermark/encode — ONE INVOCATION PER IMAGE. Measured 2026-10-09: the
|
|
41
|
+
* homepage referenced **160** such images at ~49.5 KB each, and
|
|
42
|
+
* `52.52 GB of Fast Origin Transfer ÷ 49.5 KB ≈ 1.06 M` proxy responses in a
|
|
43
|
+
* week. That is what suspended the project (HTTP 402).
|
|
44
|
+
*
|
|
45
|
+
* Six tiles, because the stored URL already encodes which of the six
|
|
46
|
+
* `SEED_PHOTO_COLOURS` it was generated with — so the mapping needs no new
|
|
47
|
+
* data and no migration. The homepage goes 160 images → 6.
|
|
48
|
+
*/
|
|
49
|
+
export declare const SEED_TILE_PREFIX = "/images/seed-tiles/";
|
|
50
|
+
/**
|
|
51
|
+
* A local tile for `absUrl` when it points at a placeholder host, else undefined.
|
|
52
|
+
*
|
|
53
|
+
* placehold.co bakes its colours into the path (`/{w}x{h}/{bg}/{fg}/png`), so the
|
|
54
|
+
* first 6-hex segment IS the background the fixture was generated with — the
|
|
55
|
+
* size segment contains an `x` and cannot match, and the foreground comes after
|
|
56
|
+
* the background, so `.find()` picks the right one.
|
|
57
|
+
*/
|
|
58
|
+
export declare function placeholderTileFor(absUrl: string): string | undefined;
|
|
33
59
|
/**
|
|
34
60
|
* Is `value` something we are willing to PERSIST as a media reference?
|
|
35
61
|
*
|
package/dist/utils/media-url.js
CHANGED
|
@@ -38,6 +38,122 @@ export const APPROVED_MEDIA_DOMAINS = [
|
|
|
38
38
|
"images.unsplash.com",
|
|
39
39
|
];
|
|
40
40
|
export const MEDIA_URL_MESSAGE = "Must be a stored media reference (/media/<slug>) or a URL on an approved CDN domain";
|
|
41
|
+
/* ── Placeholder imagery ─────────────────────────────────────────────────── */
|
|
42
|
+
/**
|
|
43
|
+
* Local, static stand-ins for seed photography. Served straight out of
|
|
44
|
+
* `public/` — no function, no upstream fetch, no sharp pipeline.
|
|
45
|
+
*
|
|
46
|
+
* 🛑 This is the single most load-bearing cost control in the app. Every seed
|
|
47
|
+
* image used to resolve to `/api/media/ext?url=https://placehold.co/…`, i.e. a
|
|
48
|
+
* Node lambda that fetched a third party (up to 2 × 4 s) and ran a full sharp
|
|
49
|
+
* decode/watermark/encode — ONE INVOCATION PER IMAGE. Measured 2026-10-09: the
|
|
50
|
+
* homepage referenced **160** such images at ~49.5 KB each, and
|
|
51
|
+
* `52.52 GB of Fast Origin Transfer ÷ 49.5 KB ≈ 1.06 M` proxy responses in a
|
|
52
|
+
* week. That is what suspended the project (HTTP 402).
|
|
53
|
+
*
|
|
54
|
+
* Six tiles, because the stored URL already encodes which of the six
|
|
55
|
+
* `SEED_PHOTO_COLOURS` it was generated with — so the mapping needs no new
|
|
56
|
+
* data and no migration. The homepage goes 160 images → 6.
|
|
57
|
+
*/
|
|
58
|
+
export const SEED_TILE_PREFIX = "/images/seed-tiles/";
|
|
59
|
+
/**
|
|
60
|
+
* Must stay in lockstep with `SEED_PHOTO_COLOURS` in
|
|
61
|
+
* `appkit/src/seed/_helpers/media.ts`, and with the filenames in
|
|
62
|
+
* `public/images/seed-tiles/`. A colour missing here is not an error — it falls
|
|
63
|
+
* back to a deterministic pick — so the failure mode is "less variety", never a
|
|
64
|
+
* broken image.
|
|
65
|
+
*/
|
|
66
|
+
const SEED_TILE_COLOURS = [
|
|
67
|
+
"1e293b",
|
|
68
|
+
"334155",
|
|
69
|
+
"3f3f46",
|
|
70
|
+
"44403c",
|
|
71
|
+
"312e81",
|
|
72
|
+
"164e63",
|
|
73
|
+
];
|
|
74
|
+
/**
|
|
75
|
+
* Hosts that only ever serve synthetic placeholder imagery.
|
|
76
|
+
*
|
|
77
|
+
* These are the four the seed helper documents having cycled through as each
|
|
78
|
+
* one fell over (picsum 503 on 2026-08-31, placekitten 521, loremflickr too
|
|
79
|
+
* slow for the proxy's 4 s timeout). Watermarking a generated placeholder is
|
|
80
|
+
* pointless, and proxying one costs a function invocation plus full origin
|
|
81
|
+
* transfer for an image we can synthesise locally for free.
|
|
82
|
+
*/
|
|
83
|
+
const PLACEHOLDER_MEDIA_HOSTS = new Set([
|
|
84
|
+
"placehold.co",
|
|
85
|
+
"placeholder.com",
|
|
86
|
+
"via.placeholder.com",
|
|
87
|
+
"picsum.photos",
|
|
88
|
+
"fastly.picsum.photos",
|
|
89
|
+
"placekitten.com",
|
|
90
|
+
"loremflickr.com",
|
|
91
|
+
"dummyimage.com",
|
|
92
|
+
]);
|
|
93
|
+
/** Deterministic 32-bit hash — same input, same tile, every render. */
|
|
94
|
+
function tileHash(input) {
|
|
95
|
+
let h = 2166136261;
|
|
96
|
+
for (let i = 0; i < input.length; i += 1) {
|
|
97
|
+
h ^= input.charCodeAt(i);
|
|
98
|
+
h = Math.imul(h, 16777619);
|
|
99
|
+
}
|
|
100
|
+
return h >>> 0;
|
|
101
|
+
}
|
|
102
|
+
/**
|
|
103
|
+
* The inner `url=` of a stored `/api/media/ext?url=…` value, or null.
|
|
104
|
+
*
|
|
105
|
+
* This is what lets the fix reach data that is ALREADY in Firestore. `seedPhoto`
|
|
106
|
+
* persisted the wrapped form for ~400 assets, and `resolveMediaUrl` used to hand
|
|
107
|
+
* such a value straight back untouched — `new URL()` throws on the relative path
|
|
108
|
+
* and the `catch` returns the input — so the proxy was entered on every render.
|
|
109
|
+
* Unwrapping here fixes every stored row with no migration.
|
|
110
|
+
*/
|
|
111
|
+
function innerExtUrl(value) {
|
|
112
|
+
if (!value.startsWith(MEDIA_ENDPOINTS.EXT))
|
|
113
|
+
return null;
|
|
114
|
+
const q = value.indexOf("?");
|
|
115
|
+
if (q === -1)
|
|
116
|
+
return null;
|
|
117
|
+
try {
|
|
118
|
+
return new URLSearchParams(value.slice(q + 1)).get("url");
|
|
119
|
+
}
|
|
120
|
+
catch (_err) {
|
|
121
|
+
void normalizeError(_err);
|
|
122
|
+
return null;
|
|
123
|
+
}
|
|
124
|
+
}
|
|
125
|
+
/**
|
|
126
|
+
* A local tile for `absUrl` when it points at a placeholder host, else undefined.
|
|
127
|
+
*
|
|
128
|
+
* placehold.co bakes its colours into the path (`/{w}x{h}/{bg}/{fg}/png`), so the
|
|
129
|
+
* first 6-hex segment IS the background the fixture was generated with — the
|
|
130
|
+
* size segment contains an `x` and cannot match, and the foreground comes after
|
|
131
|
+
* the background, so `.find()` picks the right one.
|
|
132
|
+
*/
|
|
133
|
+
export function placeholderTileFor(absUrl) {
|
|
134
|
+
let parsed;
|
|
135
|
+
try {
|
|
136
|
+
parsed = new URL(absUrl);
|
|
137
|
+
}
|
|
138
|
+
catch (_err) {
|
|
139
|
+
void normalizeError(_err);
|
|
140
|
+
return undefined;
|
|
141
|
+
}
|
|
142
|
+
const host = parsed.hostname.replace(/^www\./, "");
|
|
143
|
+
if (!PLACEHOLDER_MEDIA_HOSTS.has(host))
|
|
144
|
+
return undefined;
|
|
145
|
+
const bg = parsed.pathname
|
|
146
|
+
.split("/")
|
|
147
|
+
.find((seg) => /^[0-9a-fA-F]{6}$/.test(seg))
|
|
148
|
+
?.toLowerCase();
|
|
149
|
+
if (bg && SEED_TILE_COLOURS.includes(bg))
|
|
150
|
+
return `${SEED_TILE_PREFIX}${bg}.svg`;
|
|
151
|
+
// Unknown or absent colour (picsum/placekitten carry none) — pick
|
|
152
|
+
// deterministically from the path so the same fixture always gets the same
|
|
153
|
+
// tile and the grid keeps its variety.
|
|
154
|
+
const fallback = SEED_TILE_COLOURS[tileHash(parsed.pathname) % SEED_TILE_COLOURS.length];
|
|
155
|
+
return `${SEED_TILE_PREFIX}${fallback}.svg`;
|
|
156
|
+
}
|
|
41
157
|
/**
|
|
42
158
|
* Is `value` something we are willing to PERSIST as a media reference?
|
|
43
159
|
*
|
|
@@ -95,6 +211,11 @@ export function isStoredMediaRef(value) {
|
|
|
95
211
|
return false;
|
|
96
212
|
if (value.startsWith(MEDIA_PROXY_PREFIX))
|
|
97
213
|
return true;
|
|
214
|
+
// A local seed tile (`/images/seed-tiles/<hex>.svg`). Persistable: it is a
|
|
215
|
+
// static asset we ship, so unlike the `/api/media/ext?url=` form rejected
|
|
216
|
+
// below it is not a render-time transform and does not double-wrap.
|
|
217
|
+
if (value.startsWith(SEED_TILE_PREFIX))
|
|
218
|
+
return true;
|
|
98
219
|
if (value.startsWith("blob:") || value.startsWith("data:"))
|
|
99
220
|
return false;
|
|
100
221
|
if (value.startsWith(MEDIA_ENDPOINTS.EXT))
|
|
@@ -148,6 +269,8 @@ export function resolveMediaUrl(url, opts) {
|
|
|
148
269
|
}
|
|
149
270
|
if (url.startsWith(PROXY_PREFIX))
|
|
150
271
|
return url;
|
|
272
|
+
if (url.startsWith(SEED_TILE_PREFIX))
|
|
273
|
+
return url;
|
|
151
274
|
// A blob:/data: URI is only ever valid in the tab that created it (e.g. a
|
|
152
275
|
// freshly-selected file preview via URL.createObjectURL, or a FileReader
|
|
153
276
|
// data URL fed to a crop modal). Routing it through the external-URL
|
|
@@ -155,8 +278,29 @@ export function resolveMediaUrl(url, opts) {
|
|
|
155
278
|
// rendered directly instead.
|
|
156
279
|
if (url.startsWith("blob:") || url.startsWith("data:"))
|
|
157
280
|
return url;
|
|
281
|
+
/*
|
|
282
|
+
* An ALREADY-WRAPPED `/api/media/ext?url=…` value, which is what the seed
|
|
283
|
+
* catalogue persisted ~400 times. Unwrap and look at what it actually points
|
|
284
|
+
* at: a placeholder host becomes a local tile (no function, no fetch), and
|
|
285
|
+
* anything else falls through to the old behaviour of returning the wrapped
|
|
286
|
+
* value untouched. Without this the branch below is unreachable for stored
|
|
287
|
+
* data, because `new URL()` throws on the relative path.
|
|
288
|
+
*/
|
|
289
|
+
const inner = innerExtUrl(url);
|
|
290
|
+
if (inner) {
|
|
291
|
+
const innerTile = placeholderTileFor(inner);
|
|
292
|
+
if (innerTile)
|
|
293
|
+
return innerTile;
|
|
294
|
+
return url;
|
|
295
|
+
}
|
|
158
296
|
try {
|
|
159
297
|
const parsed = new URL(url);
|
|
298
|
+
// Synthetic placeholder imagery: never worth a function invocation. The
|
|
299
|
+
// placeholder hosts and our own Storage hosts are disjoint sets, so this
|
|
300
|
+
// can sit before the own-bucket branches without shadowing a real asset.
|
|
301
|
+
const tile = placeholderTileFor(url);
|
|
302
|
+
if (tile)
|
|
303
|
+
return tile;
|
|
160
304
|
if (parsed.hostname.endsWith(FIREBASE_STORAGE_HOST)) {
|
|
161
305
|
const m = parsed.pathname.match(/\/o\/([^?]+)/);
|
|
162
306
|
if (m)
|
|
@@ -0,0 +1,23 @@
|
|
|
1
|
+
/** The parts a location can have. All optional — see the blank-parts note. */
|
|
2
|
+
export interface PhysicalLocationParts {
|
|
3
|
+
zone?: string | null;
|
|
4
|
+
shelf?: string | null;
|
|
5
|
+
bin?: string | null;
|
|
6
|
+
}
|
|
7
|
+
/**
|
|
8
|
+
* Render a location as `zone/shelf/bin`, or `undefined` when there is nothing
|
|
9
|
+
* to show.
|
|
10
|
+
*
|
|
11
|
+
* 🛑 Returns `undefined` rather than `"//"` for an all-blank location, and
|
|
12
|
+
* that case is REACHABLE, not defensive: `PhysicalLocationModal` tells the
|
|
13
|
+
* user "All fields are optional" while both bulk-location routes only check
|
|
14
|
+
* `typeof === "string"`, so `{zone:"",shelf:"",bin:""}` saves successfully.
|
|
15
|
+
* Every caller already branches on falsy before rendering, so returning
|
|
16
|
+
* `undefined` makes those rows fall through to their em-dash instead of
|
|
17
|
+
* printing punctuation with no content.
|
|
18
|
+
*
|
|
19
|
+
* Partial locations keep their separators (`A//3`) on purpose — the gap is
|
|
20
|
+
* information, and collapsing it would make "zone A, bin 3" indistinguishable
|
|
21
|
+
* from "zone A, shelf 3".
|
|
22
|
+
*/
|
|
23
|
+
export declare function formatPhysicalLocation(loc: PhysicalLocationParts | null | undefined): string | undefined;
|
|
@@ -0,0 +1,52 @@
|
|
|
1
|
+
/*
|
|
2
|
+
* WHY: `physicalLocation` is a `{zone, shelf, bin}` OBJECT on both
|
|
3
|
+
* `ProductDocument` and `OrderDocument`, and three surfaces render it.
|
|
4
|
+
* Two had hand-written the same `a/b/c` interpolation
|
|
5
|
+
* (`SellerProductsView`, `SellerOrdersView`) and the third —
|
|
6
|
+
* `PrintCenterView` — declared the field as a `string` and rendered the
|
|
7
|
+
* object as a bare React child.
|
|
8
|
+
*
|
|
9
|
+
* 🛑 THAT THIRD ONE IS A CRASH. Rendering an object as a React child throws
|
|
10
|
+
* "Objects are not valid as a React child", so the Print Centre would die
|
|
11
|
+
* the first time any seller used the Set Location bulk action. It is
|
|
12
|
+
* LATENT, not live: measured on production, 0 of 72 products and 0 of 67
|
|
13
|
+
* orders carry the field, so nobody has used that feature yet. It was
|
|
14
|
+
* invisible because BOTH mappers in `PrintCenterPanel` are typed `(p: any)`
|
|
15
|
+
* and the products array is passed `as any` — so neither the wrong
|
|
16
|
+
* declaration nor the wrong value had anything to trip over.
|
|
17
|
+
*
|
|
18
|
+
* WHAT: one formatter. Pure, no imports, structural parameter so a caller can
|
|
19
|
+
* pass a `ProductDocument`'s field, an `OrderDocument`'s, or the
|
|
20
|
+
* `PhysicalLocation` client type without a cast.
|
|
21
|
+
*
|
|
22
|
+
* @tag domain:inventory
|
|
23
|
+
* @tag layer:util
|
|
24
|
+
* @tag access:isomorphic
|
|
25
|
+
* @tag sideEffects:none
|
|
26
|
+
*/
|
|
27
|
+
/**
|
|
28
|
+
* Render a location as `zone/shelf/bin`, or `undefined` when there is nothing
|
|
29
|
+
* to show.
|
|
30
|
+
*
|
|
31
|
+
* 🛑 Returns `undefined` rather than `"//"` for an all-blank location, and
|
|
32
|
+
* that case is REACHABLE, not defensive: `PhysicalLocationModal` tells the
|
|
33
|
+
* user "All fields are optional" while both bulk-location routes only check
|
|
34
|
+
* `typeof === "string"`, so `{zone:"",shelf:"",bin:""}` saves successfully.
|
|
35
|
+
* Every caller already branches on falsy before rendering, so returning
|
|
36
|
+
* `undefined` makes those rows fall through to their em-dash instead of
|
|
37
|
+
* printing punctuation with no content.
|
|
38
|
+
*
|
|
39
|
+
* Partial locations keep their separators (`A//3`) on purpose — the gap is
|
|
40
|
+
* information, and collapsing it would make "zone A, bin 3" indistinguishable
|
|
41
|
+
* from "zone A, shelf 3".
|
|
42
|
+
*/
|
|
43
|
+
export function formatPhysicalLocation(loc) {
|
|
44
|
+
if (!loc)
|
|
45
|
+
return undefined;
|
|
46
|
+
const zone = (loc.zone ?? "").trim();
|
|
47
|
+
const shelf = (loc.shelf ?? "").trim();
|
|
48
|
+
const bin = (loc.bin ?? "").trim();
|
|
49
|
+
if (!zone && !shelf && !bin)
|
|
50
|
+
return undefined;
|
|
51
|
+
return `${zone}/${shelf}/${bin}`;
|
|
52
|
+
}
|
|
@@ -1,4 +1,5 @@
|
|
|
1
1
|
import type { ProductDocument } from "../features/products/schemas/firestore";
|
|
2
|
+
import type { CategoryDocument } from "../features/categories/schemas/firestore";
|
|
2
3
|
import type { ScammerDocument } from "../features/scams/schemas/firestore";
|
|
3
4
|
import type { StoreDocument } from "../features/stores/schemas/firestore";
|
|
4
5
|
import type { EventDocument } from "../features/events/schemas/firestore";
|
|
@@ -9,6 +10,25 @@ import type { CouponDocument } from "../features/promotions/schemas/firestore";
|
|
|
9
10
|
import type { OfferDocument } from "../features/seller/schemas/firestore";
|
|
10
11
|
/** products — title, description, brand, taxonomy, condition, card/grading, specs. */
|
|
11
12
|
export declare function buildProductSearchTxt(p: Partial<ProductDocument>): string[];
|
|
13
|
+
/**
|
|
14
|
+
* categories — name, slug, path, ancestor names, item code, editorial copy.
|
|
15
|
+
*
|
|
16
|
+
* Covers brand and bundle rows too, since they share the collection: hence
|
|
17
|
+
* `brandCountry` and `itemCode`, which only one kind ever carries.
|
|
18
|
+
*
|
|
19
|
+
* 🛑 `ancestors[].name` is in here deliberately, and it is what makes a leaf
|
|
20
|
+
* findable by its lineage — typing "burst" reaches `category-lost-longinus`
|
|
21
|
+
* because Beyblade Burst is one of its ancestors. Without it, the only way to
|
|
22
|
+
* find a tier-4 model is to already know its exact name.
|
|
23
|
+
*
|
|
24
|
+
* `description` is stripped of HTML because `contentBody`-style copy is
|
|
25
|
+
* keyword-rich markup and the tags are not search terms.
|
|
26
|
+
*
|
|
27
|
+
* NOT indexed: `createdBy` (a raw uid), `createdByStoreName` (operator
|
|
28
|
+
* identity), `position`/`subtreeSize` (internal coordinates), and the
|
|
29
|
+
* `metrics` counters (numbers nobody searches by).
|
|
30
|
+
*/
|
|
31
|
+
export declare function buildCategorySearchTxt(c: Partial<CategoryDocument>): string[];
|
|
12
32
|
/** stores — name, description, category. No payout details, no contact. */
|
|
13
33
|
export declare function buildStoreSearchTxt(s: Partial<StoreDocument>): string[];
|
|
14
34
|
/** events — title, description, type, tags. */
|
|
@@ -46,6 +46,42 @@ export function buildProductSearchTxt(p) {
|
|
|
46
46
|
p.specifications?.map((s) => `${s.name} ${s.value}`),
|
|
47
47
|
]);
|
|
48
48
|
}
|
|
49
|
+
/**
|
|
50
|
+
* categories — name, slug, path, ancestor names, item code, editorial copy.
|
|
51
|
+
*
|
|
52
|
+
* Covers brand and bundle rows too, since they share the collection: hence
|
|
53
|
+
* `brandCountry` and `itemCode`, which only one kind ever carries.
|
|
54
|
+
*
|
|
55
|
+
* 🛑 `ancestors[].name` is in here deliberately, and it is what makes a leaf
|
|
56
|
+
* findable by its lineage — typing "burst" reaches `category-lost-longinus`
|
|
57
|
+
* because Beyblade Burst is one of its ancestors. Without it, the only way to
|
|
58
|
+
* find a tier-4 model is to already know its exact name.
|
|
59
|
+
*
|
|
60
|
+
* `description` is stripped of HTML because `contentBody`-style copy is
|
|
61
|
+
* keyword-rich markup and the tags are not search terms.
|
|
62
|
+
*
|
|
63
|
+
* NOT indexed: `createdBy` (a raw uid), `createdByStoreName` (operator
|
|
64
|
+
* identity), `position`/`subtreeSize` (internal coordinates), and the
|
|
65
|
+
* `metrics` counters (numbers nobody searches by).
|
|
66
|
+
*/
|
|
67
|
+
export function buildCategorySearchTxt(c) {
|
|
68
|
+
return buildSearchTxt([
|
|
69
|
+
c.name,
|
|
70
|
+
c.slug,
|
|
71
|
+
stripHtml(c.description),
|
|
72
|
+
c.path,
|
|
73
|
+
c.itemCode,
|
|
74
|
+
c.brandCountry,
|
|
75
|
+
...(c.ancestors ?? []).map((a) => a.name),
|
|
76
|
+
/*
|
|
77
|
+
* B5 — LAST on purpose. `buildSearchTxt` truncates at 600 tokens and does
|
|
78
|
+
* it silently, so whatever sits at the end of this array is what gets
|
|
79
|
+
* dropped first. A model leaf's own name and its lineage must survive
|
|
80
|
+
* ahead of "also known as" spellings.
|
|
81
|
+
*/
|
|
82
|
+
...(c.aliases ?? []),
|
|
83
|
+
]);
|
|
84
|
+
}
|
|
49
85
|
/** stores — name, description, category. No payout details, no contact. */
|
|
50
86
|
export function buildStoreSearchTxt(s) {
|
|
51
87
|
return buildSearchTxt([
|
package/package.json
CHANGED
package/scripts/seed-cli.mjs
CHANGED
|
@@ -195,7 +195,7 @@ const {
|
|
|
195
195
|
siteSettingsSeedData, faqSeedData,
|
|
196
196
|
wishlistsSeedData, historySeedData,
|
|
197
197
|
groupedListingsSeedData,
|
|
198
|
-
scammersSeedData, productFeaturesSeedData,
|
|
198
|
+
scammersSeedData, productFeaturesSeedData, taxCodesSeedData,
|
|
199
199
|
testerChecklistSeedData, testerResponsesSeedData,
|
|
200
200
|
supportTicketsSeedData, catalogueSeedData,
|
|
201
201
|
shipmentsSeedData, shipmentLotsSeedData, shipmentItemsSeedData,
|
|
@@ -210,6 +210,7 @@ const {
|
|
|
210
210
|
CART_COLLECTION,
|
|
211
211
|
GROUPED_LISTINGS_COLLECTION, SCAMMER_COLLECTION,
|
|
212
212
|
WISHLIST_COLLECTION, HISTORY_COLLECTION, PRODUCT_FEATURES_COLLECTION,
|
|
213
|
+
TAX_CODES_COLLECTION,
|
|
213
214
|
TESTER_CHECKLIST_ITEM_COLLECTION,
|
|
214
215
|
TESTER_CHECKLIST_RESPONSE_COLLECTION,
|
|
215
216
|
// PII field/index constants (plain data, still in the main barrel — the
|
|
@@ -285,6 +286,7 @@ const COLLECTION_MAP = {
|
|
|
285
286
|
groupedListings: GROUPED_LISTINGS_COLLECTION,
|
|
286
287
|
scammerProfiles: SCAMMER_COLLECTION,
|
|
287
288
|
productFeatures: PRODUCT_FEATURES_COLLECTION,
|
|
289
|
+
taxCodes: TAX_CODES_COLLECTION,
|
|
288
290
|
testerChecklistItems: TESTER_CHECKLIST_ITEM_COLLECTION,
|
|
289
291
|
/*
|
|
290
292
|
* Tester submissions. DERIVED tier in the tester's own map (wiped at setup so
|
|
@@ -370,6 +372,7 @@ const SEED_DATA_MAP = {
|
|
|
370
372
|
groupedListings: groupedListingsSeedData,
|
|
371
373
|
scammerProfiles: scammersSeedData,
|
|
372
374
|
productFeatures: productFeaturesSeedData,
|
|
375
|
+
taxCodes: taxCodesSeedData,
|
|
373
376
|
testerChecklistItems: testerChecklistSeedData,
|
|
374
377
|
testerChecklistResponses: testerResponsesSeedData,
|
|
375
378
|
};
|
|
@@ -1,5 +0,0 @@
|
|
|
1
|
-
import { testerChecklistItemRepository } from "../repository/tester-checklist-item.repository";
|
|
2
|
-
/** Ranks testers by confirmed-bug count. Mirrors getEventLeaderboard()'s shape. */
|
|
3
|
-
export async function getBugHunterLeaderboard(limit = 50) {
|
|
4
|
-
return testerChecklistItemRepository.getBugHunterLeaderboard(limit);
|
|
5
|
-
}
|