@mohasinac/appkit 4.45.0 → 4.46.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/server/features/categories/live-counts.d.ts +41 -0
- package/dist/_internal/server/features/categories/live-counts.js +72 -0
- package/dist/_internal/server/features/checkout/expand-order-items.js +17 -0
- package/dist/_internal/server/features/orders/adapters.js +29 -0
- package/dist/_internal/server/features/parts/assembly.d.ts +126 -0
- package/dist/_internal/server/features/parts/assembly.js +246 -0
- package/dist/_internal/server/features/parts/data.d.ts +65 -0
- package/dist/_internal/server/features/parts/data.js +170 -0
- package/dist/_internal/server/features/parts/og.d.ts +34 -0
- package/dist/_internal/server/features/parts/og.js +66 -0
- package/dist/_internal/server/features/search/search-everything.d.ts +75 -0
- package/dist/_internal/server/features/search/search-everything.js +120 -0
- package/dist/_internal/server/features/search/search-sources.d.ts +17 -0
- package/dist/_internal/server/features/search/search-sources.js +138 -0
- package/dist/_internal/server/jobs/core/categoryTaxonomyBackfill.d.ts +70 -0
- package/dist/_internal/server/jobs/core/categoryTaxonomyBackfill.js +302 -0
- package/dist/_internal/server/jobs/core/countersReconcile.js +128 -19
- package/dist/_internal/server/jobs/core/jobRunners.js +12 -0
- package/dist/_internal/server/jobs/core/onCategoryWrite.js +73 -3
- package/dist/_internal/server/jobs/core/onProductWrite.js +93 -43
- package/dist/_internal/server/jobs/core/productViewWindows.d.ts +2 -0
- package/dist/_internal/server/jobs/core/productViewWindows.js +173 -0
- package/dist/_internal/server/jobs/core/testDataCleanup.d.ts +1 -1
- package/dist/_internal/server/jobs/core/testDataCleanup.js +27 -1
- package/dist/_internal/server/jobs/handlers/pageViewRollup.d.ts +20 -0
- package/dist/_internal/server/jobs/handlers/pageViewRollup.js +25 -1
- package/dist/_internal/shared/actions/action-registry.js +36 -0
- package/dist/_internal/shared/features/promotions/schema.d.ts +2 -2
- package/dist/_internal/shared/features/shipping/protections.d.ts +93 -1
- package/dist/_internal/shared/features/shipping/protections.js +127 -0
- package/dist/_internal/shared/search/part-aliases.d.ts +44 -0
- package/dist/_internal/shared/search/part-aliases.js +104 -0
- package/dist/constants/api-endpoints.d.ts +18 -12
- package/dist/constants/api-endpoints.js +6 -8
- package/dist/constants/field-names.d.ts +0 -2
- package/dist/constants/field-names.js +0 -2
- package/dist/constants/index.d.ts +1 -1
- package/dist/constants/index.js +1 -1
- package/dist/core/index.d.ts +0 -3
- package/dist/core/index.js +0 -2
- package/dist/errors/messages.d.ts +0 -7
- package/dist/errors/messages.js +0 -8
- package/dist/features/admin/components/AdminSectionsView.js +83 -32
- package/dist/features/admin/components/AdminSiteSettingsView.js +6 -2
- package/dist/features/admin/components/sections/sectionTemplates.d.ts +117 -0
- package/dist/features/admin/components/sections/sectionTemplates.js +213 -0
- package/dist/features/admin/schemas/firestore.d.ts +15 -0
- package/dist/features/admin/types/index.d.ts +0 -1
- package/dist/features/auth/permissions/constants.d.ts +1 -1
- package/dist/features/auth/permissions/constants.js +0 -2
- package/dist/features/categories/api/[id]/description-template/route.js +40 -1
- package/dist/features/categories/components/BrandDetailPageView.js +14 -3
- package/dist/features/categories/components/CategoryDetailPageView.js +89 -14
- package/dist/features/categories/components/CategoryTemplatePicker.js +9 -1
- package/dist/features/categories/repository/categories.repository.d.ts +65 -0
- package/dist/features/categories/repository/categories.repository.js +168 -22
- package/dist/features/categories/repository/category-counts.d.ts +143 -0
- package/dist/features/categories/repository/category-counts.js +224 -0
- package/dist/features/categories/schemas/category-counts.d.ts +155 -0
- package/dist/features/categories/schemas/category-counts.js +116 -0
- package/dist/features/categories/schemas/firestore.d.ts +0 -2
- package/dist/features/categories/schemas/firestore.js +0 -1
- package/dist/features/categories/utils/breadcrumb-chain.d.ts +194 -0
- package/dist/features/categories/utils/breadcrumb-chain.js +202 -0
- package/dist/features/corporate/schemas/index.d.ts +4 -4
- package/dist/features/orders/schemas/firestore.d.ts +13 -0
- package/dist/features/orders/types/index.d.ts +30 -0
- package/dist/features/parts/components/AssemblyDrawer.d.ts +107 -0
- package/dist/features/parts/components/AssemblyDrawer.js +250 -0
- package/dist/features/parts/components/ModelCompositionPanel.d.ts +37 -0
- package/dist/features/parts/components/ModelCompositionPanel.js +34 -0
- package/dist/features/parts/components/PartDetailPageView.d.ts +48 -0
- package/dist/features/parts/components/PartDetailPageView.js +20 -0
- package/dist/features/parts/components/PartsIndexPageView.d.ts +33 -0
- package/dist/features/parts/components/PartsIndexPageView.js +17 -0
- package/dist/features/parts/schemas/firestore.d.ts +257 -0
- package/dist/features/parts/schemas/firestore.js +181 -0
- package/dist/features/parts/utils/colourway-match.d.ts +62 -0
- package/dist/features/parts/utils/colourway-match.js +98 -0
- package/dist/features/parts/utils/part-breakdown.d.ts +53 -0
- package/dist/features/parts/utils/part-breakdown.js +77 -0
- package/dist/features/products/components/ProductDetailPageView.d.ts +14 -1
- package/dist/features/products/components/ProductDetailPageView.js +22 -3
- package/dist/features/products/components/ProductTabsShell.d.ts +3 -1
- package/dist/features/products/components/ProductTabsShell.js +4 -1
- package/dist/features/products/repository/category-assignment.d.ts +132 -0
- package/dist/features/products/repository/category-assignment.js +304 -0
- package/dist/features/products/repository/products.repository.d.ts +58 -1
- package/dist/features/products/repository/products.repository.js +255 -28
- package/dist/features/products/schemas/firestore.d.ts +147 -6
- package/dist/features/products/schemas/firestore.js +49 -0
- package/dist/features/search/components/SearchResultsPageView.d.ts +33 -0
- package/dist/features/search/components/SearchResultsPageView.js +21 -0
- package/dist/features/seller/components/SellerProductsView.js +129 -3
- package/dist/features/tester/seed-data/authored/admin__site-system.js +0 -15
- package/dist/features/tester/seed-data/authored/content-discovery__parts-database.d.ts +2 -0
- package/dist/features/tester/seed-data/authored/content-discovery__parts-database.js +166 -0
- package/dist/features/tester/seed-data/authored/index.js +2 -0
- package/dist/features/tester/seed-data/tester-checklist-seed-data.js +28 -1
- package/dist/index.d.ts +11 -16
- package/dist/index.js +26 -18
- package/dist/next/routing/route-map.d.ts +6 -2
- package/dist/next/routing/route-map.js +14 -1
- package/dist/providers/db-firebase/base.repository.d.ts +31 -0
- package/dist/providers/db-firebase/base.repository.js +31 -0
- package/dist/repositories/index.d.ts +1 -2
- package/dist/repositories/index.js +0 -1
- package/dist/seed/_helpers/category-content.d.ts +29 -0
- package/dist/seed/_helpers/category-content.js +98 -1
- package/dist/seed/_helpers/category-forest.js +104 -24
- package/dist/seed/_helpers/category-parts.d.ts +9 -0
- package/dist/seed/_helpers/category-parts.js +4594 -0
- package/dist/seed/carousel-slides-seed-data.js +81 -8
- package/dist/seed/categories-seed-data.js +44 -6
- package/dist/seed/homepage-sections-seed-data.js +170 -9
- package/dist/seed/index.d.ts +2 -0
- package/dist/seed/index.js +13 -0
- package/dist/seed/model-composition-seed-data.d.ts +15 -0
- package/dist/seed/model-composition-seed-data.js +8918 -0
- package/dist/seed/part-glossary-seed-data.d.ts +15 -0
- package/dist/seed/part-glossary-seed-data.js +10729 -0
- package/dist/seed/products-standard-seed-data.js +52 -0
- package/dist/seed/seed-purpose.d.ts +103 -4
- package/dist/seed/seed-purpose.js +162 -11
- package/dist/seo/json-ld.d.ts +10 -1
- package/dist/seo/json-ld.js +9 -1
- package/dist/server.d.ts +7 -0
- package/dist/server.js +11 -0
- package/dist/styles.css +1 -1
- package/dist/tailwind-utilities.css +1 -1
- package/dist/utils/id-generators.d.ts +30 -0
- package/dist/utils/id-generators.js +31 -1
- package/dist/utils/search-txt-builders.js +22 -0
- package/dist/utils/search-txt.d.ts +22 -0
- package/dist/utils/search-txt.js +17 -0
- package/dist/values/success-messages.d.ts +0 -4
- package/dist/values/success-messages.js +0 -5
- package/package.json +1 -1
- package/scripts/seed-cli.mjs +292 -16
- package/dist/core/copilot-log.repository.d.ts +0 -44
- package/dist/core/copilot-log.repository.js +0 -61
- package/dist/features/copilot/components/AdminCopilotView.d.ts +0 -21
- package/dist/features/copilot/components/AdminCopilotView.js +0 -51
- package/dist/features/copilot/components/index.d.ts +0 -2
- package/dist/features/copilot/components/index.js +0 -1
- package/dist/features/copilot/hooks/useCopilotChat.d.ts +0 -25
- package/dist/features/copilot/hooks/useCopilotChat.js +0 -65
- package/dist/features/copilot/hooks/useCopilotFeedback.d.ts +0 -15
- package/dist/features/copilot/hooks/useCopilotFeedback.js +0 -15
- package/dist/features/copilot/index.d.ts +0 -3
- package/dist/features/copilot/index.js +0 -3
package/dist/index.js
CHANGED
|
@@ -649,17 +649,11 @@ export { mergeFeatureMessages } from "./cli/index.js";
|
|
|
649
649
|
export { withFeatures } from "./cli/index.js";
|
|
650
650
|
// ./core/index
|
|
651
651
|
// [CLIENT-SSR]-Runs in both SSR and browser â€" React component or hook that does not depend on browser-only APIs.
|
|
652
|
-
// COPILOT_LOGS_COLLECTION - Constant used across modules.
|
|
653
|
-
export { COPILOT_LOGS_COLLECTION } from "./core/index.js";
|
|
654
652
|
// [CLIENT-SSR]-Runs in both SSR and browser â€" React component or hook that does not depend on browser-only APIs.
|
|
655
|
-
// COPILOT_LOGS_INDEXED_FIELDS - Constant used across modules.
|
|
656
|
-
export { COPILOT_LOGS_INDEXED_FIELDS } from "./core/index.js";
|
|
657
653
|
// [CLIENT-SSR]-Runs in both SSR and browser â€" React component or hook that does not depend on browser-only APIs.
|
|
658
654
|
// CacheManager - Shared export for cache manager.
|
|
659
655
|
export { CacheManager } from "./core/index.js";
|
|
660
656
|
// [DB]-Database layer â€" uses firebase-admin or another server-side DB SDK; can only run in a trusted server environment.
|
|
661
|
-
// CopilotLogRepository - Shared export for copilot log repository.
|
|
662
|
-
export { CopilotLogRepository } from "./core/index.js";
|
|
663
657
|
// [CLIENT-SSR]-Runs in both SSR and browser â€" React component or hook that does not depend on browser-only APIs.
|
|
664
658
|
// EventBus - Shared export for event bus.
|
|
665
659
|
export { EventBus } from "./core/index.js";
|
|
@@ -698,11 +692,7 @@ export { cacheManager } from "./core/index.js";
|
|
|
698
692
|
// configureMarketDefaults - Shared export for configure market defaults.
|
|
699
693
|
export { configureMarketDefaults } from "./core/index.js";
|
|
700
694
|
// [CLIENT-SSR]-Runs in both SSR and browser â€" React component or hook that does not depend on browser-only APIs.
|
|
701
|
-
// copilotLogQueryHelpers - Shared export for copilot log query helpers.
|
|
702
|
-
export { copilotLogQueryHelpers } from "./core/index.js";
|
|
703
695
|
// [DB]-Database layer â€" uses firebase-admin or another server-side DB SDK; can only run in a trusted server environment.
|
|
704
|
-
// copilotLogRepository - Shared export for copilot log repository.
|
|
705
|
-
export { copilotLogRepository } from "./core/index.js";
|
|
706
696
|
// [CLIENT-SSR]-Runs in both SSR and browser â€" React component or hook that does not depend on browser-only APIs.
|
|
707
697
|
// createServerAction - Helper for create server action.
|
|
708
698
|
export { createServerAction } from "./core/index.js";
|
|
@@ -1321,6 +1311,7 @@ export { catalogueSeedData } from "./seed/index.js";
|
|
|
1321
1311
|
// [SERVER-ONLY]-Server-only â€" uses Node.js, Next.js server internals, or third-party server SDKs (auth, email, payment, shipping).
|
|
1322
1312
|
// productsStandardSeedData - Seed data for standard (buy-now) product listings.
|
|
1323
1313
|
export { productsStandardSeedData } from "./seed/index.js";
|
|
1314
|
+
// 1,173-node taxonomy has a catalogue in it (967 of 968 leaves were empty).
|
|
1324
1315
|
// [SERVER-ONLY]-Server-only â€" uses Node.js, Next.js server internals, or third-party server SDKs (auth, email, payment, shipping).
|
|
1325
1316
|
// productsAuctionsSeedData - Seed data for auction product listings.
|
|
1326
1317
|
export { productsAuctionsSeedData } from "./seed/index.js";
|
|
@@ -3093,16 +3084,13 @@ export { ContactPageView } from "./features/contact/index.js";
|
|
|
3093
3084
|
// [CLIENT-SSR]-Runs in both SSR and browser â€" React component or hook that does not depend on browser-only APIs.
|
|
3094
3085
|
// useContactSubmit - React hook for use contact submit.
|
|
3095
3086
|
export { useContactSubmit } from "./features/contact/index.js";
|
|
3096
|
-
// ./features/copilot/index
|
|
3097
3087
|
// [CLIENT-SSR]-Runs in both SSR and browser â€" React component or hook that does not depend on browser-only APIs.
|
|
3098
|
-
// AdminCopilotView - Component for admin copilot view.
|
|
3099
|
-
export { AdminCopilotView } from "./features/copilot/index.js";
|
|
3100
3088
|
// [CLIENT-SSR]-Runs in both SSR and browser â€" React component or hook that does not depend on browser-only APIs.
|
|
3101
|
-
// useCopilotChat - React hook for use copilot chat.
|
|
3102
|
-
export { useCopilotChat } from "./features/copilot/index.js";
|
|
3103
3089
|
// [CLIENT-SSR]-Runs in both SSR and browser â€" React component or hook that does not depend on browser-only APIs.
|
|
3104
|
-
//
|
|
3105
|
-
export
|
|
3090
|
+
// [TYPE]-TypeScript type-only export â€" erased at compile time, zero runtime cost.
|
|
3091
|
+
// [TYPE]-TypeScript type-only export â€" erased at compile time, zero runtime cost.
|
|
3092
|
+
// [TYPE]-TypeScript type-only export â€" erased at compile time, zero runtime cost.
|
|
3093
|
+
// [TYPE]-TypeScript type-only export â€" erased at compile time, zero runtime cost.
|
|
3106
3094
|
// ./features/corporate/index
|
|
3107
3095
|
// [CLIENT-SSR]-Runs in both SSR and browser â€" React component or hook that does not depend on browser-only APIs.
|
|
3108
3096
|
// CorporateInquiryForm - Component for corporate inquiry form.
|
|
@@ -5355,7 +5343,7 @@ export { Ol } from "./ui/index.js";
|
|
|
5355
5343
|
export { LoginRequiredModal } from "./ui/components/LoginRequiredModal.js";
|
|
5356
5344
|
export { isAuthError } from "./utils/auth-error.js";
|
|
5357
5345
|
// -- Missing constants ----------------------------------------------------------
|
|
5358
|
-
export { API_ENDPOINTS, API_ROUTES, LOGS_ENDPOINTS, AUTH_ENDPOINTS, ACCOUNT_ENDPOINTS, NOTIFICATIONS_ENDPOINTS, ADMIN_ENDPOINTS, AUCTION_ENDPOINTS, BID_ENDPOINTS, CART_ENDPOINTS, CATEGORY_ENDPOINTS, CHECKOUT_ENDPOINTS,
|
|
5346
|
+
export { API_ENDPOINTS, API_ROUTES, LOGS_ENDPOINTS, AUTH_ENDPOINTS, ACCOUNT_ENDPOINTS, NOTIFICATIONS_ENDPOINTS, ADMIN_ENDPOINTS, AUCTION_ENDPOINTS, BID_ENDPOINTS, CART_ENDPOINTS, CATEGORY_ENDPOINTS, CHECKOUT_ENDPOINTS, FAQ_ENDPOINTS, HOMEPAGE_ENDPOINTS, LOYALTY_ENDPOINTS, ANALYTICS_ENDPOINTS, MEDIA_ENDPOINTS, ORDER_ENDPOINTS, PREORDER_ENDPOINTS, PRODUCT_ENDPOINTS, REVIEW_ENDPOINTS, SEARCH_ENDPOINTS, SELLER_ENDPOINTS, BLOG_ENDPOINTS, WISHLIST_ENDPOINTS, COLLECTION_CACHE_PATHS, resolveEndpoint, resolveEndpointFn, ROUTES, PUBLIC_ROUTES, PROTECTED_ROUTES, AUTH_ROUTES, WISHLIST_MAX, HISTORY_MAX, CART_MAX_ITEMS, WISHLIST_DOC_ID, HISTORY_DOC_ID, WISHLIST_COLLECTION, HISTORY_COLLECTION, } from "./constants/index.js";
|
|
5359
5347
|
// Wishlist server errors (server-only via tree-shake â€" class only, no firebase-admin at module scope)
|
|
5360
5348
|
export { WishlistFullError } from "./features/wishlist/server.js";
|
|
5361
5349
|
// History â€" client hook + guest util are safe in main barrel; repository is server-only
|
|
@@ -5460,6 +5448,26 @@ export { productFeaturesSeedData } from "./seed/index.js";
|
|
|
5460
5448
|
* had no data, which is indistinguishable from an empty fixture set.
|
|
5461
5449
|
*/
|
|
5462
5450
|
export { taxCodesSeedData } from "./seed/index.js";
|
|
5451
|
+
/*
|
|
5452
|
+
* E4/D12 — generated from the extracted corpus research.
|
|
5453
|
+
*
|
|
5454
|
+
* 🛑 Exported from the MAIN barrel, because `seed-cli.mjs` destructures all of
|
|
5455
|
+
* its seed data from `appkit` (not from `/server`, which is what I assumed
|
|
5456
|
+
* first). Adding a collection to `seed/index.ts` and `COLLECTION_MAP` alone
|
|
5457
|
+
* leaves the loader reading `undefined` — and `appkit-seed status` then reports
|
|
5458
|
+
* "0 seed rows", i.e. a collection that looks registered and loads nothing.
|
|
5459
|
+
* That is Root Cause #90 exactly: the PII half was wired and the LOADING half
|
|
5460
|
+
* was not, so every grep found real hits while the collection stayed empty.
|
|
5461
|
+
*/
|
|
5462
|
+
// E4/D12 — the collection constants and types.
|
|
5463
|
+
export { PART_GLOSSARY_COLLECTION, MODEL_COMPOSITION_COLLECTION, PART_SLOT_VALUES, PART_SLOT_LABEL, ALL_PART_SLOTS, LISTING_TYPE_HAS_COMPOSITION, partSlotFromSegment, partGlossaryId, } from "./features/parts/schemas/firestore.js";
|
|
5464
|
+
export { partGlossarySeedData } from "./seed/index.js";
|
|
5465
|
+
export { modelCompositionSeedData } from "./seed/index.js";
|
|
5466
|
+
// D12 — the public part surfaces.
|
|
5467
|
+
export { ModelCompositionPanel } from "./features/parts/components/ModelCompositionPanel.js";
|
|
5468
|
+
export { PartsIndexPageView, PartClassificationPageView, } from "./features/parts/components/PartsIndexPageView.js";
|
|
5469
|
+
export { PartDetailPageView } from "./features/parts/components/PartDetailPageView.js";
|
|
5470
|
+
export { AssemblyDrawer } from "./features/parts/components/AssemblyDrawer.js";
|
|
5463
5471
|
// Scam registry â€" schema types and constants
|
|
5464
5472
|
export { SCAMMER_COLLECTION, SCAMMER_ID_PREFIX, SCAMMER_MATCH_FIELDS, SCAMMER_INDEXED_FIELDS, SCAMMER_FIELDS, SCAMMER_INCIDENTS_SUBCOLLECTION, SCAMMER_COMMENTS_SUBCOLLECTION, SCAMMER_CONTESTS_SUBCOLLECTION, MAX_COMMENT_BODY_LENGTH, MAX_PENDING_SCAMMER_REPORTS_PER_USER, ScammerStatusValues, ScamPlatformValues, SocialPlatformValues, ContestTypeValues, ContestStatusValues, SCAM_PLATFORM_LABELS, SOCIAL_PLATFORM_LABELS, SCAMMER_STATUS_LABELS, CONTEST_TYPE_LABELS, CONTEST_STATUS_LABELS, DEFAULT_SCAMMER_DATA, DEFAULT_SCAMMER_INCIDENT_DATA, DEFAULT_SCAMMER_COMMENT_DATA, DEFAULT_SCAMMER_CONTEST_DATA, } from "./features/scams/schemas/firestore.js";
|
|
5465
5473
|
// Scam registry â€" scam type definitions
|
|
@@ -106,6 +106,9 @@ export declare const DEFAULT_ROUTE_MAP: {
|
|
|
106
106
|
readonly ITEM_REQUESTS_NEW: "/item-requests/new";
|
|
107
107
|
readonly TOOLS: "/tools";
|
|
108
108
|
readonly TOOL_PRICE_INDEX: "/tools/price-index";
|
|
109
|
+
readonly PARTS: "/parts";
|
|
110
|
+
readonly PART_CLASSIFICATION: (classification: string) => string;
|
|
111
|
+
readonly PART_DETAIL: (classification: string, code: string) => string;
|
|
109
112
|
readonly SCAM_TYPES: "/scams/types";
|
|
110
113
|
readonly SCAM_FAQS: "/scams/faqs";
|
|
111
114
|
readonly CLASSIFIED: "/classified";
|
|
@@ -335,7 +338,6 @@ export declare const DEFAULT_ROUTE_MAP: {
|
|
|
335
338
|
readonly EVENT_ENTRIES: (id: string) => string;
|
|
336
339
|
readonly STORES: "/admin/stores";
|
|
337
340
|
readonly STORE_DETAIL: (id: string) => string;
|
|
338
|
-
readonly COPILOT: "/admin/copilot";
|
|
339
341
|
readonly ADS: "/admin/ads";
|
|
340
342
|
readonly ADS_NEW: "/admin/ads/new";
|
|
341
343
|
readonly ADS_EDIT: (id: string) => string;
|
|
@@ -511,6 +513,9 @@ export declare const ROUTES: {
|
|
|
511
513
|
readonly ITEM_REQUESTS_NEW: "/item-requests/new";
|
|
512
514
|
readonly TOOLS: "/tools";
|
|
513
515
|
readonly TOOL_PRICE_INDEX: "/tools/price-index";
|
|
516
|
+
readonly PARTS: "/parts";
|
|
517
|
+
readonly PART_CLASSIFICATION: (classification: string) => string;
|
|
518
|
+
readonly PART_DETAIL: (classification: string, code: string) => string;
|
|
514
519
|
readonly SCAM_TYPES: "/scams/types";
|
|
515
520
|
readonly SCAM_FAQS: "/scams/faqs";
|
|
516
521
|
readonly CLASSIFIED: "/classified";
|
|
@@ -740,7 +745,6 @@ export declare const ROUTES: {
|
|
|
740
745
|
readonly EVENT_ENTRIES: (id: string) => string;
|
|
741
746
|
readonly STORES: "/admin/stores";
|
|
742
747
|
readonly STORE_DETAIL: (id: string) => string;
|
|
743
|
-
readonly COPILOT: "/admin/copilot";
|
|
744
748
|
readonly ADS: "/admin/ads";
|
|
745
749
|
readonly ADS_NEW: "/admin/ads/new";
|
|
746
750
|
readonly ADS_EDIT: (id: string) => string;
|
|
@@ -106,6 +106,20 @@ export const DEFAULT_ROUTE_MAP = {
|
|
|
106
106
|
*/
|
|
107
107
|
TOOLS: "/tools",
|
|
108
108
|
TOOL_PRICE_INDEX: "/tools/price-index",
|
|
109
|
+
/*
|
|
110
|
+
* The PARTS database. A reference surface, so it lives beside the other
|
|
111
|
+
* two things that answer a question rather than sell you something.
|
|
112
|
+
*
|
|
113
|
+
* 🛑 `/parts/{classification}/{code}` — the classification is REQUIRED in
|
|
114
|
+
* the path, because a code alone is ambiguous: `105` is a Metal Fight
|
|
115
|
+
* spin-track height, a bare number in Burst is a disc, and `1-60` is a
|
|
116
|
+
* Beyblade X ratchet. The two segments together are the document id
|
|
117
|
+
* (`${slot}--${tail}`), so the page is a direct doc read with no query
|
|
118
|
+
* and no index.
|
|
119
|
+
*/
|
|
120
|
+
PARTS: "/parts",
|
|
121
|
+
PART_CLASSIFICATION: (classification) => `/parts/${classification}`,
|
|
122
|
+
PART_DETAIL: (classification, code) => `/parts/${classification}/${code}`,
|
|
109
123
|
SCAM_TYPES: "/scams/types",
|
|
110
124
|
SCAM_FAQS: "/scams/faqs",
|
|
111
125
|
CLASSIFIED: "/classified",
|
|
@@ -364,7 +378,6 @@ export const DEFAULT_ROUTE_MAP = {
|
|
|
364
378
|
EVENT_ENTRIES: (id) => `/admin/events/${id}/entries`,
|
|
365
379
|
STORES: "/admin/stores",
|
|
366
380
|
STORE_DETAIL: (id) => `/admin/stores/${id}/view`,
|
|
367
|
-
COPILOT: "/admin/copilot",
|
|
368
381
|
ADS: "/admin/ads",
|
|
369
382
|
ADS_NEW: "/admin/ads/new",
|
|
370
383
|
ADS_EDIT: (id) => `/admin/ads/${id}/edit`,
|
|
@@ -112,6 +112,37 @@ export declare abstract class BaseRepository<T extends DocumentData> {
|
|
|
112
112
|
patch: Partial<T>;
|
|
113
113
|
}>): Promise<number>;
|
|
114
114
|
create(data: Partial<T> | FirestoreDocument): Promise<T>;
|
|
115
|
+
/**
|
|
116
|
+
* Write a document at a CALLER-CHOSEN id.
|
|
117
|
+
*
|
|
118
|
+
* 🛑 **This OVERWRITES. It is an upsert, not a create**, despite the name —
|
|
119
|
+
* `.set()` with no merge option replaces the whole document, and there is no
|
|
120
|
+
* existence check. Writing an id that already exists silently discards
|
|
121
|
+
* everything that was there and returns a success.
|
|
122
|
+
*
|
|
123
|
+
* That is **deliberate and load-bearing for most of its 28 callers**, which
|
|
124
|
+
* are genuine upserts keyed on a deterministic id:
|
|
125
|
+
*
|
|
126
|
+
* - `testerChecklistResponses` — one doc per (tester, case), re-answered
|
|
127
|
+
* every time a verdict changes. CLAUDE.md records that this upsert is
|
|
128
|
+
* *"what makes Yes/No answers + comments + screenshots survive a page
|
|
129
|
+
* reload"*, so a create-only variant here would break verdict recording.
|
|
130
|
+
* - `sessions`, analytics rollups, `priceIndex` — all rewritten by design.
|
|
131
|
+
*
|
|
132
|
+
* 🛑 **So do NOT "fix" this to `.create()`.** I was about to: the plan carried
|
|
133
|
+
* it as a severity-1 silent-overwrite risk for products, on the reasoning that
|
|
134
|
+
* two physical units of one model would derive the same slug and the second
|
|
135
|
+
* would destroy the first. **Measured, that is false** —
|
|
136
|
+
* `ProductRepository.create` OVERRIDES this method and runs `generateUniqueId`
|
|
137
|
+
* with a real `findById` probe, so units get `-1`, `-2`, … and never collide.
|
|
138
|
+
* A blanket `.create()` would have broken the tester harness to fix a defect
|
|
139
|
+
* products do not have.
|
|
140
|
+
*
|
|
141
|
+
* **A caller that needs create-only semantics must probe first**, the way
|
|
142
|
+
* `ProductRepository.create` does. The hazard this docstring removes is the
|
|
143
|
+
* NAME: `createWithId` reads as "create" and behaves as "replace", and that
|
|
144
|
+
* gap is what made the wrong conclusion so easy to reach.
|
|
145
|
+
*/
|
|
115
146
|
createWithId(id: string, data: Partial<T>): Promise<T>;
|
|
116
147
|
update(id: string, data: Partial<T>): Promise<T>;
|
|
117
148
|
delete(id: string): Promise<void>;
|
|
@@ -284,6 +284,37 @@ export class BaseRepository {
|
|
|
284
284
|
throw new DatabaseError(`Failed to create document: ${detailOf(error)}`, error);
|
|
285
285
|
}
|
|
286
286
|
}
|
|
287
|
+
/**
|
|
288
|
+
* Write a document at a CALLER-CHOSEN id.
|
|
289
|
+
*
|
|
290
|
+
* 🛑 **This OVERWRITES. It is an upsert, not a create**, despite the name —
|
|
291
|
+
* `.set()` with no merge option replaces the whole document, and there is no
|
|
292
|
+
* existence check. Writing an id that already exists silently discards
|
|
293
|
+
* everything that was there and returns a success.
|
|
294
|
+
*
|
|
295
|
+
* That is **deliberate and load-bearing for most of its 28 callers**, which
|
|
296
|
+
* are genuine upserts keyed on a deterministic id:
|
|
297
|
+
*
|
|
298
|
+
* - `testerChecklistResponses` — one doc per (tester, case), re-answered
|
|
299
|
+
* every time a verdict changes. CLAUDE.md records that this upsert is
|
|
300
|
+
* *"what makes Yes/No answers + comments + screenshots survive a page
|
|
301
|
+
* reload"*, so a create-only variant here would break verdict recording.
|
|
302
|
+
* - `sessions`, analytics rollups, `priceIndex` — all rewritten by design.
|
|
303
|
+
*
|
|
304
|
+
* 🛑 **So do NOT "fix" this to `.create()`.** I was about to: the plan carried
|
|
305
|
+
* it as a severity-1 silent-overwrite risk for products, on the reasoning that
|
|
306
|
+
* two physical units of one model would derive the same slug and the second
|
|
307
|
+
* would destroy the first. **Measured, that is false** —
|
|
308
|
+
* `ProductRepository.create` OVERRIDES this method and runs `generateUniqueId`
|
|
309
|
+
* with a real `findById` probe, so units get `-1`, `-2`, … and never collide.
|
|
310
|
+
* A blanket `.create()` would have broken the tester harness to fix a defect
|
|
311
|
+
* products do not have.
|
|
312
|
+
*
|
|
313
|
+
* **A caller that needs create-only semantics must probe first**, the way
|
|
314
|
+
* `ProductRepository.create` does. The hazard this docstring removes is the
|
|
315
|
+
* NAME: `createWithId` reads as "create" and behaves as "replace", and that
|
|
316
|
+
* gap is what made the wrong conclusion so easy to reach.
|
|
317
|
+
*/
|
|
287
318
|
async createWithId(id, data) {
|
|
288
319
|
try {
|
|
289
320
|
const now = new Date();
|
|
@@ -49,8 +49,7 @@ export { EventRepository, EventsRepository, eventRepository, } from "../features
|
|
|
49
49
|
export { EventEntryRepository, EventEntriesRepository, eventEntryRepository, } from "../features/events/repository/event-entry.repository";
|
|
50
50
|
export { NewsletterRepository, newsletterRepository, } from "../core/newsletter.repository";
|
|
51
51
|
export type { NewsletterSubscriberDocument, NewsletterSubscriberCreateInput, NewsletterSubscriberUpdateInput, NewsletterListModel, } from "../core/newsletter.repository";
|
|
52
|
-
export {
|
|
53
|
-
export type { CopilotFeedback, CopilotLogDocument, CopilotLogCreateInput, } from "../core";
|
|
52
|
+
export type {} from "../core";
|
|
54
53
|
export { ScammerRepository, scammerRepository, } from "../features/scams/repository/scammer.repository";
|
|
55
54
|
export { SupportRepository, supportRepository, } from "../features/support/repository/support.repository";
|
|
56
55
|
export type { SupportTicketDocument, SupportTicketCreateInput, SupportTicketUpdateInput, TicketMessage, TicketCategory, TicketStatus, TicketPriority, } from "../features/support/schemas/firestore";
|
|
@@ -61,7 +61,6 @@ export { historyRepository, } from "../features/history/repository/user-history.
|
|
|
61
61
|
export { EventRepository, EventsRepository, eventRepository, } from "../features/events/repository/events.repository.js";
|
|
62
62
|
export { EventEntryRepository, EventEntriesRepository, eventEntryRepository, } from "../features/events/repository/event-entry.repository.js";
|
|
63
63
|
export { NewsletterRepository, newsletterRepository, } from "../core/newsletter.repository.js";
|
|
64
|
-
export { CopilotLogRepository, copilotLogRepository } from "../core/index.js";
|
|
65
64
|
export { ScammerRepository, scammerRepository, } from "../features/scams/repository/scammer.repository.js";
|
|
66
65
|
export { SupportRepository, supportRepository, } from "../features/support/repository/support.repository.js";
|
|
67
66
|
// SB-UNI-B — SublistingCategoriesRepository deleted; sublistings now live on
|
|
@@ -15,6 +15,7 @@ export declare const CRAWL_AS_OF: Date;
|
|
|
15
15
|
* description containing a literal `{{series}}`.
|
|
16
16
|
*/
|
|
17
17
|
export declare const TEMPLATES: Record<CategoryTemplateVariant, CategoryDescriptionTemplate>;
|
|
18
|
+
export declare const BEY_TEMPLATES: CategoryDescriptionTemplate[];
|
|
18
19
|
/** The set a normal collectible category offers. */
|
|
19
20
|
export declare const COLLECTIBLE_TEMPLATES: CategoryDescriptionTemplate[];
|
|
20
21
|
/** Parts and small accessories arrive carded or loose, not boxed. */
|
|
@@ -25,6 +26,34 @@ export declare function templateSet(...variants: CategoryTemplateVariant[]): Cat
|
|
|
25
26
|
export declare function marketBand(leafId: string): CategoryPriceGuidance | undefined;
|
|
26
27
|
/** Every leaf id this map claims a band for — the seed asserts they all exist. */
|
|
27
28
|
export declare const MARKET_BAND_LEAF_IDS: string[];
|
|
29
|
+
/**
|
|
30
|
+
* B6 — the ROOT-LEVEL tax fallback, one per root.
|
|
31
|
+
*
|
|
32
|
+
* 🛑 Measured 2026-10-12: the tax code sat on tiers 1–3 only (t1=4, t2=47,
|
|
33
|
+
* t3=71) and on NO root, so **3 of 70 live products resolved no tax code at
|
|
34
|
+
* all** and would have fallen to `DEFAULT_GST_RATE` — a listing filed at
|
|
35
|
+
* `category-spinning-tops`, `category-burst-tops` or `category-x-tops`.
|
|
36
|
+
*
|
|
37
|
+
* C0c's own rule is that reaching that constant is a TRIAGE SIGNAL, not a
|
|
38
|
+
* feature: "a listing reaching step 3 at all means its category has no tax
|
|
39
|
+
* code — and that, not the constant, is the defect to fix. The measure of
|
|
40
|
+
* success is that step 3 fires for nothing."
|
|
41
|
+
*
|
|
42
|
+
* Putting it at the root is what makes that true for every branch, including
|
|
43
|
+
* branches nobody has filed under yet — `resolveCategoryDefaults` walks the
|
|
44
|
+
* chain nearest-first, so a tier-2 or tier-3 entry still WINS as a
|
|
45
|
+
* more-specific override. This is a floor, not a replacement.
|
|
46
|
+
*
|
|
47
|
+
* 🛑 Deliberately NOT a single shared constant. Each root is a different HSN
|
|
48
|
+
* question and a wrong HSN on a real invoice is worse than an absent one —
|
|
49
|
+
* printed cards are chapter 4911, not 9503, and a live plant is exempt. Only
|
|
50
|
+
* 9503 was verified (section 3.2); the three non-9503 roots therefore take the
|
|
51
|
+
* closest VERIFIED code rather than an unverified guess, and say so.
|
|
52
|
+
*/
|
|
53
|
+
export declare const ROOT_AUTHENTICITY_DEFAULT: "unverified";
|
|
54
|
+
export declare const ROOT_TAX_DEFAULTS: Record<string, {
|
|
55
|
+
taxCodeId: string;
|
|
56
|
+
}>;
|
|
28
57
|
/** A complete top. */
|
|
29
58
|
export declare function beyDefaults(leafId: string, series: string, system: string): CategoryProductDefaults;
|
|
30
59
|
/** A loose component. */
|
|
@@ -144,6 +144,36 @@ export const TEMPLATES = {
|
|
|
144
144
|
version: 1,
|
|
145
145
|
},
|
|
146
146
|
};
|
|
147
|
+
/**
|
|
148
|
+
* ── D12: the BEYBLADE bodies, which are the only ones that state PARTS ─────
|
|
149
|
+
*
|
|
150
|
+
* 🛑 A separate set rather than adding the slot to the shared bodies, and the
|
|
151
|
+
* reason is mechanical: `COLLECTIBLE_TEMPLATES` is also what every figure,
|
|
152
|
+
* Hot Wheels and TCG category uses, and a `{{partBreakdown}}` on a Marvel
|
|
153
|
+
* Legends listing resolves to nothing. The endpoint strips the line when
|
|
154
|
+
* there is no composition, so the artifact would be invisible rather than
|
|
155
|
+
* wrong — but it would also be a read attempted on four roots that can never
|
|
156
|
+
* satisfy it, on an endpoint the seller form hits on every category change.
|
|
157
|
+
*
|
|
158
|
+
* Assigned to the 21 `line(...)` nodes, which are Beyblade generation lines
|
|
159
|
+
* and nothing else — their children are `MODEL_LEAVES`. A model leaf carries
|
|
160
|
+
* no body of its own and INHERITS this one, while the slot resolves against
|
|
161
|
+
* the leaf's OWN composition. That is the whole design: one body per
|
|
162
|
+
* generation, 216 models' worth of parts.
|
|
163
|
+
*/
|
|
164
|
+
const BEY_PARTS_LINE = ` <li><strong>Parts:</strong> {{partBreakdown}}</li>`;
|
|
165
|
+
/** The slot sits on its own source line, because the strip is line-based. */
|
|
166
|
+
function withPartsLine(body) {
|
|
167
|
+
return body.replace("</ul>", `${BEY_PARTS_LINE}
|
|
168
|
+
</ul>`);
|
|
169
|
+
}
|
|
170
|
+
const BEY_TEMPLATE_VARIANTS = [
|
|
171
|
+
"new_in_box",
|
|
172
|
+
"pre_owned",
|
|
173
|
+
"replica",
|
|
174
|
+
"default",
|
|
175
|
+
];
|
|
176
|
+
export const BEY_TEMPLATES = BEY_TEMPLATE_VARIANTS.map((v) => ({ ...TEMPLATES[v], body: withPartsLine(TEMPLATES[v].body) }));
|
|
147
177
|
/** The set a normal collectible category offers. */
|
|
148
178
|
export const COLLECTIBLE_TEMPLATES = [
|
|
149
179
|
TEMPLATES.new_in_box,
|
|
@@ -357,6 +387,54 @@ export const MARKET_BAND_LEAF_IDS = Object.keys(MARKET_BANDS);
|
|
|
357
387
|
const TAX_TOY = "tax-hsn-95030020"; // non-electronic toys incl. spinning tops — 5%
|
|
358
388
|
const TAX_TOY_OTHER = "tax-hsn-95030099"; // other toys — 5%
|
|
359
389
|
const TAX_EXEMPT = "tax-exempt-0";
|
|
390
|
+
/**
|
|
391
|
+
* B6 — the ROOT-LEVEL tax fallback, one per root.
|
|
392
|
+
*
|
|
393
|
+
* 🛑 Measured 2026-10-12: the tax code sat on tiers 1–3 only (t1=4, t2=47,
|
|
394
|
+
* t3=71) and on NO root, so **3 of 70 live products resolved no tax code at
|
|
395
|
+
* all** and would have fallen to `DEFAULT_GST_RATE` — a listing filed at
|
|
396
|
+
* `category-spinning-tops`, `category-burst-tops` or `category-x-tops`.
|
|
397
|
+
*
|
|
398
|
+
* C0c's own rule is that reaching that constant is a TRIAGE SIGNAL, not a
|
|
399
|
+
* feature: "a listing reaching step 3 at all means its category has no tax
|
|
400
|
+
* code — and that, not the constant, is the defect to fix. The measure of
|
|
401
|
+
* success is that step 3 fires for nothing."
|
|
402
|
+
*
|
|
403
|
+
* Putting it at the root is what makes that true for every branch, including
|
|
404
|
+
* branches nobody has filed under yet — `resolveCategoryDefaults` walks the
|
|
405
|
+
* chain nearest-first, so a tier-2 or tier-3 entry still WINS as a
|
|
406
|
+
* more-specific override. This is a floor, not a replacement.
|
|
407
|
+
*
|
|
408
|
+
* 🛑 Deliberately NOT a single shared constant. Each root is a different HSN
|
|
409
|
+
* question and a wrong HSN on a real invoice is worse than an absent one —
|
|
410
|
+
* printed cards are chapter 4911, not 9503, and a live plant is exempt. Only
|
|
411
|
+
* 9503 was verified (section 3.2); the three non-9503 roots therefore take the
|
|
412
|
+
* closest VERIFIED code rather than an unverified guess, and say so.
|
|
413
|
+
*/
|
|
414
|
+
export const ROOT_AUTHENTICITY_DEFAULT = "unverified";
|
|
415
|
+
export const ROOT_TAX_DEFAULTS = {
|
|
416
|
+
// Verified: HSN 9503 0020 — non-electronic toys including spinning tops, 5%.
|
|
417
|
+
"category-spinning-tops": { taxCodeId: TAX_TOY },
|
|
418
|
+
// Verified: HSN 9503 0099 — "other toys", 5%. A built model kit and a
|
|
419
|
+
// die-cast car are both toys under 9503; neither is a spinning top.
|
|
420
|
+
"category-hot-wheels": { taxCodeId: TAX_TOY_OTHER },
|
|
421
|
+
"category-model-kits": { taxCodeId: TAX_TOY_OTHER },
|
|
422
|
+
"category-collectible-figures": { taxCodeId: TAX_TOY_OTHER },
|
|
423
|
+
/*
|
|
424
|
+
* 🛑 Trading cards are chapter 4911 (printed matter) or 9504 (playing cards)
|
|
425
|
+
* and NEITHER was verified — section 3.2 confirmed 9503 only, and § "Still
|
|
426
|
+
* open" records "verify each before seeding; 9503 is the only one I
|
|
427
|
+
* confirmed". `9503 0099` is used as the floor because a TCG single sold as
|
|
428
|
+
* a collectible is a toy-chapter good at the same 5% rate, so the RATE is
|
|
429
|
+
* right even where the chapter may not be. It must be re-chaptered before
|
|
430
|
+
* the first real TCG invoice, and that is a data task with a source, not a
|
|
431
|
+
* guess to make here.
|
|
432
|
+
*/
|
|
433
|
+
"category-trading-cards": { taxCodeId: TAX_TOY_OTHER },
|
|
434
|
+
// A live plant or animal is nil-rated — a deliberate exemption, which is
|
|
435
|
+
// exactly why `gstRate: 0` must survive derivation rather than be "corrected".
|
|
436
|
+
"category-living-collectibles": { taxCodeId: TAX_EXEMPT },
|
|
437
|
+
};
|
|
360
438
|
/** Shared across every Beyblade-family node. */
|
|
361
439
|
const BEY_FAQ_TEMPLATES = [
|
|
362
440
|
{
|
|
@@ -591,9 +669,28 @@ export function diecastDefaults(leafId, line) {
|
|
|
591
669
|
],
|
|
592
670
|
};
|
|
593
671
|
}
|
|
672
|
+
const TAX_TOY_ELECTRONIC = "tax-hsn-95030010"; // electronic toys — 18%
|
|
673
|
+
/**
|
|
674
|
+
* 🛑 THE ONLY 18% BRANCH IN THE CATALOGUE, and it is derived rather than
|
|
675
|
+
* hand-written on a product.
|
|
676
|
+
*
|
|
677
|
+
* `tax-hsn-95030010` (electronic toys, 18%) has existed as a `taxCodes` row
|
|
678
|
+
* since B3 with **nothing referencing it** — so the 18% arm of `calculateGst`
|
|
679
|
+
* and every mixed-rate path (C0c defect 4's `gstByRate`, the per-rate invoice
|
|
680
|
+
* table, the blended-rate payout) had no data that could exercise it. A code
|
|
681
|
+
* with no referrer is the vocabulary-with-no-rows shape of Root Cause #90.
|
|
682
|
+
*
|
|
683
|
+
* Counters and BeyPointers are battery-powered scoring devices, which is what
|
|
684
|
+
* 9503 0010 covers — so this is the honest home for it, not a flag planted on
|
|
685
|
+
* an arbitrary row. Putting it on the CATEGORY rather than on a product means
|
|
686
|
+
* the 18% is proven through `deriveTaxonomy`, i.e. through the mechanism that
|
|
687
|
+
* will actually carry it in production, instead of through a literal that
|
|
688
|
+
* would pass while the derivation stayed untested.
|
|
689
|
+
*/
|
|
690
|
+
const ELECTRONIC_ACCESSORY_LEAVES = new Set(["category-accessory-counters"]);
|
|
594
691
|
export function accessoryDefaults(leafId, kind) {
|
|
595
692
|
return {
|
|
596
|
-
taxCodeId: TAX_TOY_OTHER,
|
|
693
|
+
taxCodeId: ELECTRONIC_ACCESSORY_LEAVES.has(leafId) ? TAX_TOY_ELECTRONIC : TAX_TOY_OTHER,
|
|
597
694
|
specifications: [SPEC("Accessory type", kind)],
|
|
598
695
|
defaultAuthenticity: "unverified",
|
|
599
696
|
priceGuidance: marketBand(leafId),
|