@mohasinac/appkit 4.45.0 → 4.47.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/BreadcrumbTrail.d.ts +24 -1
- package/dist/features/categories/components/BreadcrumbTrail.js +45 -4
- 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/CategoryInlineSelect.d.ts +17 -1
- package/dist/features/seller/components/CategoryInlineSelect.js +14 -3
- package/dist/features/seller/components/SellerProductShell.d.ts +26 -1
- package/dist/features/seller/components/SellerProductShell.js +30 -1
- 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-generated.d.ts +24 -0
- package/dist/seed/_helpers/category-content-generated.js +1837 -0
- 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
|
@@ -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),
|
|
@@ -49,7 +49,8 @@
|
|
|
49
49
|
* @tag sideEffects:none
|
|
50
50
|
*/
|
|
51
51
|
import { MODEL_LEAVES } from "./category-models.js";
|
|
52
|
-
import {
|
|
52
|
+
import { PART_LEAVES } from "./category-parts.js";
|
|
53
|
+
import { BEY_TEMPLATES, COLLECTIBLE_TEMPLATES, PART_TEMPLATES, SEALED_TEMPLATES, accessoryDefaults, beyDefaults, diecastDefaults, figureDefaults, launcherDefaults, livingDefaults, marketBand, partDefaults, stadiumDefaults, tcgDefaults, ROOT_TAX_DEFAULTS, ROOT_AUTHENTICITY_DEFAULT, } from "./category-content.js";
|
|
53
54
|
import { seedPhoto } from "./media.js";
|
|
54
55
|
const cover = (slug) => seedPhoto(`category-image-${slug}-20260101`, 1200, 600);
|
|
55
56
|
/**
|
|
@@ -78,12 +79,27 @@ function node(id, name, description, defaults, templates, children) {
|
|
|
78
79
|
extra.productDefaults = defaults;
|
|
79
80
|
if (templates)
|
|
80
81
|
extra.descriptionTemplates = templates;
|
|
82
|
+
/*
|
|
83
|
+
* 🛑 D13 — a part-type node's children are its PART LEAVES, threaded here
|
|
84
|
+
* rather than at the 20 call sites.
|
|
85
|
+
*
|
|
86
|
+
* Same shape as `line()` and `MODEL_LEAVES`: the generated map is keyed by
|
|
87
|
+
* parent id, so a node with no entry gets `[]` and is unchanged. Doing it in
|
|
88
|
+
* the helper means adding a part classification is a generator run plus one
|
|
89
|
+
* `node(...)` line, not an edit in two places that must agree.
|
|
90
|
+
*
|
|
91
|
+
* An explicit `children` argument still wins, so a node that hand-authors
|
|
92
|
+
* its children is not silently overwritten — there is none today, and the
|
|
93
|
+
* precedence has to be decided rather than discovered.
|
|
94
|
+
*/
|
|
95
|
+
const generated = PART_LEAVES[id];
|
|
96
|
+
const kids = children ?? generated;
|
|
81
97
|
return {
|
|
82
98
|
id,
|
|
83
99
|
name,
|
|
84
100
|
description,
|
|
85
101
|
...(Object.keys(extra).length ? { extra } : {}),
|
|
86
|
-
...(
|
|
102
|
+
...(kids && kids.length ? { children: kids } : {}),
|
|
87
103
|
};
|
|
88
104
|
}
|
|
89
105
|
/** A branch node — grouping only, no products file directly under it. */
|
|
@@ -115,16 +131,27 @@ const BEYBLADE_ORIGINAL = {
|
|
|
115
131
|
},
|
|
116
132
|
children: [
|
|
117
133
|
branch("category-original-tops", "Original Tops", "Complete original-series Beyblades, from the first Spin Gear releases through HMS.", [
|
|
118
|
-
line("category-original-plastic-gen", "Plastic Generation", "The earliest 1999–2000 plastic-series releases, before the Spin Gear system was formalised.", beyDefaults("category-original-plastic-gen", "Beyblade (Original)", "Plastic Generation"),
|
|
119
|
-
line("category-original-spin-gear", "Spin Gear System", "The 2000–2001 Spin Gear releases — the system that set the Attack Ring / Weight Disk / Blade Base template.", beyDefaults("category-original-spin-gear", "Beyblade (Original)", "Spin Gear System"),
|
|
120
|
-
line("category-original-magnacore", "Magnacore System", "The 2002 V-Force Magnacore line, with magnets in the base that pull a top toward or away from the stadium centre.", beyDefaults("category-original-magnacore", "Beyblade V-Force", "Magnacore System"),
|
|
121
|
-
line("category-original-engine-gear", "Engine Gear System", "The 2003 G-Revolution Engine Gear line — a wound spring inside the top that releases mid-battle.", beyDefaults("category-original-engine-gear", "Beyblade G-Revolution", "Engine Gear System"),
|
|
122
|
-
line("category-original-hms", "Heavy Metal System", "The 2003 HMS line — metal throughout, the last and heaviest of the original generation, and the highest-value tier here.", beyDefaults("category-original-hms", "Beyblade HMS", "Heavy Metal System"),
|
|
134
|
+
line("category-original-plastic-gen", "Plastic Generation", "The earliest 1999–2000 plastic-series releases, before the Spin Gear system was formalised.", beyDefaults("category-original-plastic-gen", "Beyblade (Original)", "Plastic Generation"), BEY_TEMPLATES),
|
|
135
|
+
line("category-original-spin-gear", "Spin Gear System", "The 2000–2001 Spin Gear releases — the system that set the Attack Ring / Weight Disk / Blade Base template.", beyDefaults("category-original-spin-gear", "Beyblade (Original)", "Spin Gear System"), BEY_TEMPLATES),
|
|
136
|
+
line("category-original-magnacore", "Magnacore System", "The 2002 V-Force Magnacore line, with magnets in the base that pull a top toward or away from the stadium centre.", beyDefaults("category-original-magnacore", "Beyblade V-Force", "Magnacore System"), BEY_TEMPLATES),
|
|
137
|
+
line("category-original-engine-gear", "Engine Gear System", "The 2003 G-Revolution Engine Gear line — a wound spring inside the top that releases mid-battle.", beyDefaults("category-original-engine-gear", "Beyblade G-Revolution", "Engine Gear System"), BEY_TEMPLATES),
|
|
138
|
+
line("category-original-hms", "Heavy Metal System", "The 2003 HMS line — metal throughout, the last and heaviest of the original generation, and the highest-value tier here.", beyDefaults("category-original-hms", "Beyblade HMS", "Heavy Metal System"), BEY_TEMPLATES),
|
|
123
139
|
]),
|
|
124
140
|
branch("category-original-parts", "Original Parts", "Loose Attack Rings, Weight Disks and Blade Bases for rebuilding an original-era combo.", [
|
|
125
141
|
node("category-original-attack-rings", "Attack Rings", "The upper contact ring — what actually strikes an opponent, and the part that decides a combo's attack profile.", partDefaults("category-original-attack-rings", "Attack Ring"), PART_TEMPLATES),
|
|
126
142
|
node("category-original-weight-disks", "Weight Disks", "The metal disk between ring and base. Heavier disks buy stamina; lighter ones buy speed.", partDefaults("category-original-weight-disks", "Weight Disk"), PART_TEMPLATES),
|
|
127
143
|
node("category-original-blade-bases", "Blade Bases", "The bottom assembly — tip shape, spin gear housing and, on later systems, the magnet or engine.", partDefaults("category-original-blade-bases", "Blade Base"), PART_TEMPLATES),
|
|
144
|
+
/*
|
|
145
|
+
* D13 — five part-type nodes the forest was missing, so every one of the
|
|
146
|
+
* 20 part classifications has a home. Measured before adding: 135 of 753
|
|
147
|
+
* parts (bit chips 66, running cores 25, chrome wheels 25, spin gears 14,
|
|
148
|
+
* engine gears 5) had no node to be filed under, and a part leaf with no
|
|
149
|
+
* parent is a tier-0 orphan.
|
|
150
|
+
*/
|
|
151
|
+
node("category-original-bit-chips", "Bit Chips", "The small chip at the centre of a Plastic-Gen Attack Ring, carrying the beast art. Collected in its own right and routinely swapped.", partDefaults("category-original-bit-chips", "Bit Chip"), PART_TEMPLATES),
|
|
152
|
+
node("category-original-spin-gears", "Spin Gears", "The 2000–2001 Spin Gear module that sets spin direction and locks the Blade Base to the Weight Disk.", partDefaults("category-original-spin-gears", "Spin Gear"), PART_TEMPLATES),
|
|
153
|
+
node("category-original-engine-gears", "Engine Gears", "The G-Revolution wound-spring module that releases mid-battle. Only a handful of releases used one.", partDefaults("category-original-engine-gears", "Engine Gear"), PART_TEMPLATES),
|
|
154
|
+
node("category-original-running-cores", "Running Cores", "HMS combines the Spin Gear and Blade Base into one moulded Running Core, which is why an HMS breakdown has fewer slots than a Plastic-Gen one.", partDefaults("category-original-running-cores", "Running Core"), PART_TEMPLATES),
|
|
128
155
|
]),
|
|
129
156
|
branch("category-original-launchers", "Original Launchers", "Ripcord launchers, grips and winders for original-series tops.", [
|
|
130
157
|
node("category-original-ripcord-launchers", "Ripcord Launchers", "The classic pull-cord launchers used across the original series.", launcherDefaults("category-original-ripcord-launchers", "Beyblade (Original)"), PART_TEMPLATES),
|
|
@@ -158,11 +185,11 @@ const BEYBLADE_METAL = {
|
|
|
158
185
|
},
|
|
159
186
|
children: [
|
|
160
187
|
branch("category-metal-tops", "Metal Fight Tops", "Complete Metal Fight Beyblades across all five sub-generations.", [
|
|
161
|
-
line("category-metal-phws", "Metal System", "The 2008 debut system that preceded the Hybrid Wheel System — the first metal-weighted tops.", beyDefaults("category-metal-phws", "Beyblade: Metal Fusion", "Metal System"),
|
|
162
|
-
line("category-metal-fusion", "Metal Fusion", "The Hybrid Wheel System wave that defined the era — Face Bolt, Energy Ring, Fusion Wheel, Spin Track, Tip.", beyDefaults("category-metal-fusion", "Beyblade: Metal Fusion", "Hybrid Wheel System"),
|
|
163
|
-
line("category-metal-masters", "Metal Masters", "Later Hybrid Wheel releases with heavier wheels and tighter tolerances.", beyDefaults("category-metal-masters", "Beyblade: Metal Masters", "Hybrid Wheel System"),
|
|
164
|
-
line("category-metal-fury-4d", "Metal Fury (4D)", "The 4D System wave — multi-mode wheels and switchable bottoms, and the heaviest tops of the era.", beyDefaults("category-metal-fury-4d", "Beyblade: Metal Fury", "4D System"),
|
|
165
|
-
line("category-metal-shogun-steel", "Shogun Steel / Zero-G", "The 2012–2013 Zero-G line, built for the rocking Zero-G stadium rather than a static dish.", beyDefaults("category-metal-shogun-steel", "Beyblade: Shogun Steel", "Synchrom System"),
|
|
188
|
+
line("category-metal-phws", "Metal System", "The 2008 debut system that preceded the Hybrid Wheel System — the first metal-weighted tops.", beyDefaults("category-metal-phws", "Beyblade: Metal Fusion", "Metal System"), BEY_TEMPLATES),
|
|
189
|
+
line("category-metal-fusion", "Metal Fusion", "The Hybrid Wheel System wave that defined the era — Face Bolt, Energy Ring, Fusion Wheel, Spin Track, Tip.", beyDefaults("category-metal-fusion", "Beyblade: Metal Fusion", "Hybrid Wheel System"), BEY_TEMPLATES),
|
|
190
|
+
line("category-metal-masters", "Metal Masters", "Later Hybrid Wheel releases with heavier wheels and tighter tolerances.", beyDefaults("category-metal-masters", "Beyblade: Metal Masters", "Hybrid Wheel System"), BEY_TEMPLATES),
|
|
191
|
+
line("category-metal-fury-4d", "Metal Fury (4D)", "The 4D System wave — multi-mode wheels and switchable bottoms, and the heaviest tops of the era.", beyDefaults("category-metal-fury-4d", "Beyblade: Metal Fury", "4D System"), BEY_TEMPLATES),
|
|
192
|
+
line("category-metal-shogun-steel", "Shogun Steel / Zero-G", "The 2012–2013 Zero-G line, built for the rocking Zero-G stadium rather than a static dish.", beyDefaults("category-metal-shogun-steel", "Beyblade: Shogun Steel", "Synchrom System"), BEY_TEMPLATES),
|
|
166
193
|
]),
|
|
167
194
|
branch("category-metal-parts", "Metal Fight Parts", "The four-part system sold loose — this is where a custom Metal Fight combo gets built.", [
|
|
168
195
|
node("category-metal-face-bolts", "Face Bolts", "The screw and face sticker at the top. Mostly cosmetic, occasionally a weight tweak.", partDefaults("category-metal-face-bolts", "Face Bolt"), PART_TEMPLATES),
|
|
@@ -170,6 +197,7 @@ const BEYBLADE_METAL = {
|
|
|
170
197
|
node("category-metal-fusion-wheels", "Fusion Wheels", "The metal mass of the top — the single part that most decides whether a combo attacks or endures.", partDefaults("category-metal-fusion-wheels", "Fusion Wheel"), PART_TEMPLATES),
|
|
171
198
|
node("category-metal-spin-tracks", "Spin Tracks", "The height component. 85, 100, 105, 125, 145, 230 — taller clears a dish's slope, lower sits under an opponent.", partDefaults("category-metal-spin-tracks", "Spin Track"), PART_TEMPLATES),
|
|
172
199
|
node("category-metal-performance-tips", "Performance Tips", "The floor contact: Rubber Flat, Wide Defense, Eternal Sharp, Metal Ball and the rest of the bottom vocabulary.", partDefaults("category-metal-performance-tips", "Performance Tip"), PART_TEMPLATES),
|
|
200
|
+
node("category-metal-chrome-wheels", "Chrome Wheels", "The 4D System's upper metal wheel, sold loose and the heaviest single part in the generation.", partDefaults("category-metal-chrome-wheels", "Chrome Wheel"), PART_TEMPLATES),
|
|
173
201
|
]),
|
|
174
202
|
branch("category-metal-launchers", "Metal Fight Launchers", "String launchers, ripcord launchers and grips for the Metal Fight era.", [
|
|
175
203
|
node("category-metal-string-launchers", "String Launchers", "The pull-string launchers that replaced ripcords, giving far more consistent launch power.", launcherDefaults("category-metal-string-launchers", "Beyblade: Metal Fight"), PART_TEMPLATES),
|
|
@@ -206,13 +234,13 @@ const BEYBLADE_BURST = {
|
|
|
206
234
|
},
|
|
207
235
|
children: [
|
|
208
236
|
branch("category-burst-tops", "Burst Tops", "Complete Burst-system Beyblades across every wave.", [
|
|
209
|
-
line("category-burst-classic", "Burst Classic", "The original 2015–2017 single- and dual-layer waves, before any metal entered the Layer.", beyDefaults("category-burst-classic", "Beyblade Burst", "Burst System"),
|
|
210
|
-
line("category-burst-god", "Burst God", "The God Layer wave, which added spring-loaded Layers and the first real burst-resistance tuning.", beyDefaults("category-burst-god", "Beyblade Burst God", "God Layer System"),
|
|
211
|
-
line("category-burst-cho-z", "Cho-Z", "The metal-layer wave — heavier Layers and roughly double the burst resistance of what came before.", beyDefaults("category-burst-cho-z", "Beyblade Burst Cho-Z", "Cho-Z Layer System"),
|
|
212
|
-
line("category-burst-gt", "GT", "The Gatinko wave, with a swappable chip inside the Layer for a third tuning axis.", beyDefaults("category-burst-gt", "Beyblade Burst GT", "Gatinko Layer System"),
|
|
213
|
-
line("category-burst-superking", "Superking", "The Sparking / Superking wave and its five-sided ratchet, which changed launch dynamics entirely.", beyDefaults("category-burst-superking", "Beyblade Burst Superking", "Sparking Layer System"),
|
|
214
|
-
line("category-burst-db", "Dynamite Battle", "The DB wave — Armour Tips and the heaviest Layers Burst had shipped to that point.", beyDefaults("category-burst-db", "Beyblade Burst Dynamite Battle", "Dynamite Battle Layer System"),
|
|
215
|
-
line("category-burst-bu", "Burst Ultimate", "The final Burst wave, closing the line in 2023 before Beyblade X replaced it.", beyDefaults("category-burst-bu", "Beyblade Burst Ultimate", "Burst Ultimate Layer System"),
|
|
237
|
+
line("category-burst-classic", "Burst Classic", "The original 2015–2017 single- and dual-layer waves, before any metal entered the Layer.", beyDefaults("category-burst-classic", "Beyblade Burst", "Burst System"), BEY_TEMPLATES),
|
|
238
|
+
line("category-burst-god", "Burst God", "The God Layer wave, which added spring-loaded Layers and the first real burst-resistance tuning.", beyDefaults("category-burst-god", "Beyblade Burst God", "God Layer System"), BEY_TEMPLATES),
|
|
239
|
+
line("category-burst-cho-z", "Cho-Z", "The metal-layer wave — heavier Layers and roughly double the burst resistance of what came before.", beyDefaults("category-burst-cho-z", "Beyblade Burst Cho-Z", "Cho-Z Layer System"), BEY_TEMPLATES),
|
|
240
|
+
line("category-burst-gt", "GT", "The Gatinko wave, with a swappable chip inside the Layer for a third tuning axis.", beyDefaults("category-burst-gt", "Beyblade Burst GT", "Gatinko Layer System"), BEY_TEMPLATES),
|
|
241
|
+
line("category-burst-superking", "Superking", "The Sparking / Superking wave and its five-sided ratchet, which changed launch dynamics entirely.", beyDefaults("category-burst-superking", "Beyblade Burst Superking", "Sparking Layer System"), BEY_TEMPLATES),
|
|
242
|
+
line("category-burst-db", "Dynamite Battle", "The DB wave — Armour Tips and the heaviest Layers Burst had shipped to that point.", beyDefaults("category-burst-db", "Beyblade Burst Dynamite Battle", "Dynamite Battle Layer System"), BEY_TEMPLATES),
|
|
243
|
+
line("category-burst-bu", "Burst Ultimate", "The final Burst wave, closing the line in 2023 before Beyblade X replaced it.", beyDefaults("category-burst-bu", "Beyblade Burst Ultimate", "Burst Ultimate Layer System"), BEY_TEMPLATES),
|
|
216
244
|
]),
|
|
217
245
|
branch("category-burst-parts", "Burst Parts", "Layers, Discs, Drivers and the chips and armour that bolt onto them.", [
|
|
218
246
|
node("category-burst-layers", "Layers", "The top piece — attack profile and burst resistance. The most expensive part of a Burst build.", partDefaults("category-burst-layers", "Layer"), PART_TEMPLATES),
|
|
@@ -255,10 +283,10 @@ const BEYBLADE_X = {
|
|
|
255
283
|
},
|
|
256
284
|
children: [
|
|
257
285
|
branch("category-x-tops", "Beyblade X Tops", "Complete Beyblade X tops — starters, boosters and the X-Over reissues.", [
|
|
258
|
-
line("category-x-basic", "Basic Line", "Standard three-part X tops. The entry point into the format and the bulk of its catalogue.", beyDefaults("category-x-basic", "Beyblade X", "Xtreme Gear (Basic Line)"),
|
|
259
|
-
line("category-x-unique-ux", "Unique Line (UX)", "UX releases, each Blade carrying a mechanical gimmick the Basic Line does not have.", beyDefaults("category-x-unique-ux", "Beyblade X", "Xtreme Gear (Unique Line)"),
|
|
260
|
-
line("category-x-custom-cx", "Custom Line (CX)", "CX releases, whose Blade splits into a Lock Chip, a Main Blade and an Assist Blade.", beyDefaults("category-x-custom-cx", "Beyblade X", "Xtreme Gear (Custom Line)"),
|
|
261
|
-
line("category-x-over", "X-Over Project", "Classic designs from earlier generations reissued on Beyblade X hardware.", beyDefaults("category-x-over", "Beyblade X", "Xtreme Gear (X-Over)"),
|
|
286
|
+
line("category-x-basic", "Basic Line", "Standard three-part X tops. The entry point into the format and the bulk of its catalogue.", beyDefaults("category-x-basic", "Beyblade X", "Xtreme Gear (Basic Line)"), BEY_TEMPLATES),
|
|
287
|
+
line("category-x-unique-ux", "Unique Line (UX)", "UX releases, each Blade carrying a mechanical gimmick the Basic Line does not have.", beyDefaults("category-x-unique-ux", "Beyblade X", "Xtreme Gear (Unique Line)"), BEY_TEMPLATES),
|
|
288
|
+
line("category-x-custom-cx", "Custom Line (CX)", "CX releases, whose Blade splits into a Lock Chip, a Main Blade and an Assist Blade.", beyDefaults("category-x-custom-cx", "Beyblade X", "Xtreme Gear (Custom Line)"), BEY_TEMPLATES),
|
|
289
|
+
line("category-x-over", "X-Over Project", "Classic designs from earlier generations reissued on Beyblade X hardware.", beyDefaults("category-x-over", "Beyblade X", "Xtreme Gear (X-Over)"), BEY_TEMPLATES),
|
|
262
290
|
]),
|
|
263
291
|
branch("category-x-parts", "Beyblade X Parts", "Blades, Ratchets and Bits sold loose for custom X builds.", [
|
|
264
292
|
node("category-x-blades", "Blades", "The upper piece that defines an X combo's attack shape and its ability to hold the rail.", partDefaults("category-x-blades", "Blade"), PART_TEMPLATES),
|
|
@@ -635,6 +663,58 @@ const LIVING_COLLECTIBLES = {
|
|
|
635
663
|
]),
|
|
636
664
|
],
|
|
637
665
|
};
|
|
666
|
+
/**
|
|
667
|
+
* B6 — attach each root's tax floor HERE rather than inside six `extra` blocks.
|
|
668
|
+
*
|
|
669
|
+
* 🛑 One place, because the failure mode is an OMISSION. Six hand-edited
|
|
670
|
+
* blocks is six chances to add a seventh root with no tax code, and the symptom
|
|
671
|
+
* would be three products silently resolving `DEFAULT_GST_RATE` — exactly what
|
|
672
|
+
* was measured before this (3 of 70, at `category-spinning-tops`,
|
|
673
|
+
* `category-burst-tops` and `category-x-tops`). Here, a root missing from
|
|
674
|
+
* `ROOT_TAX_DEFAULTS` is a THROW at seed time, which is a visible failure
|
|
675
|
+
* rather than a wrong rate on an invoice.
|
|
676
|
+
*
|
|
677
|
+
* It MERGES rather than overwrites: a root that already declares
|
|
678
|
+
* `productDefaults` (none does today) keeps everything it has, and a
|
|
679
|
+
* `taxCodeId` it declared itself wins. The root value is a floor.
|
|
680
|
+
*/
|
|
681
|
+
function withRootTax(root) {
|
|
682
|
+
const tax = ROOT_TAX_DEFAULTS[root.id];
|
|
683
|
+
if (!tax) {
|
|
684
|
+
throw new Error(`category-forest: root "${root.id}" has no entry in ROOT_TAX_DEFAULTS. ` +
|
|
685
|
+
"Every root needs a tax floor, or products under it resolve DEFAULT_GST_RATE " +
|
|
686
|
+
"— which C0c defines as a triage signal, not a feature.");
|
|
687
|
+
}
|
|
688
|
+
const extra = (root.extra ?? {});
|
|
689
|
+
return {
|
|
690
|
+
...root,
|
|
691
|
+
extra: {
|
|
692
|
+
...extra,
|
|
693
|
+
productDefaults: {
|
|
694
|
+
...tax,
|
|
695
|
+
/*
|
|
696
|
+
* 🛑 `unverified` AS THE ROOT FLOOR, and the value choice is the whole
|
|
697
|
+
* point. 43 of 381 listing nodes resolved NO `defaultAuthenticity` —
|
|
698
|
+
* tier 0, tier 1 and several tier-2 branches — so a product filed
|
|
699
|
+
* there got nothing.
|
|
700
|
+
*
|
|
701
|
+
* `unverified` exists precisely for this: `ProductAuthenticity`'s own
|
|
702
|
+
* docstring records that "without it, an honest seller who does not
|
|
703
|
+
* know would have to pick 'original', and silence would be
|
|
704
|
+
* indistinguishable from a genuine claim." Defaulting to `original`
|
|
705
|
+
* would have the platform make an authenticity claim nobody checked,
|
|
706
|
+
* on a marketplace whose differentiator is that it does not do that.
|
|
707
|
+
*
|
|
708
|
+
* A more specific category still WINS — `resolveCategoryDefaults`
|
|
709
|
+
* walks nearest-first, and the 6 nodes that legitimately declare
|
|
710
|
+
* `original` keep it.
|
|
711
|
+
*/
|
|
712
|
+
defaultAuthenticity: ROOT_AUTHENTICITY_DEFAULT,
|
|
713
|
+
...(extra.productDefaults ?? {}),
|
|
714
|
+
},
|
|
715
|
+
},
|
|
716
|
+
};
|
|
717
|
+
}
|
|
638
718
|
export const CATEGORY_FOREST = [
|
|
639
719
|
SPINNING_TOPS,
|
|
640
720
|
TRADING_CARDS,
|
|
@@ -642,7 +722,7 @@ export const CATEGORY_FOREST = [
|
|
|
642
722
|
HOT_WHEELS,
|
|
643
723
|
MODEL_KITS,
|
|
644
724
|
LIVING_COLLECTIBLES,
|
|
645
|
-
];
|
|
725
|
+
].map(withRootTax);
|
|
646
726
|
/*
|
|
647
727
|
* Keeps `marketBand` honest: a band keyed on a leaf id that no longer exists is
|
|
648
728
|
* dead weight that reads as coverage. Asserted by the seed, not here, because
|
|
@@ -0,0 +1,9 @@
|
|
|
1
|
+
import type { CategoryTreeNode } from "./category-tree";
|
|
2
|
+
/** Part leaves, keyed by the part-type node they belong under. */
|
|
3
|
+
export declare const PART_LEAVES: Record<string, CategoryTreeNode[]>;
|
|
4
|
+
/**
|
|
5
|
+
* The part leaf id for a `partGlossary` row id, and vice versa — they are the
|
|
6
|
+
* SAME string by construction, so this map exists only to let a reader see that
|
|
7
|
+
* stated rather than inferred.
|
|
8
|
+
*/
|
|
9
|
+
export declare const PART_LEAF_COUNT = 752;
|