@runwell/shopify-toolkit 0.18.0 → 0.23.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.
Files changed (37) hide show
  1. package/bin/runwell-shopify +10 -1
  2. package/lib/init.js +13 -2
  3. package/lib/list.js +22 -9
  4. package/lib/qa-bundles.js +117 -0
  5. package/lib/qa.js +147 -13
  6. package/modules/INDEX.md +14 -5
  7. package/modules/bundle-builder/README.md +6 -1
  8. package/modules/bundle-builder/module.json +5 -1
  9. package/modules/cart-cross-sell/snippets/runwell-cart-xsell.liquid +16 -0
  10. package/modules/runwell-bundle-system/README.md +35 -0
  11. package/modules/runwell-bundle-system/admin-metafields.json +55 -0
  12. package/modules/runwell-bundle-system/assets/runwell-bundle-system.css +1107 -0
  13. package/modules/runwell-bundle-system/assets/runwell-bundle-system.js +444 -0
  14. package/modules/runwell-bundle-system/module.json +137 -0
  15. package/modules/runwell-bundle-system/qa/mobile-checklist.md +105 -0
  16. package/modules/runwell-bundle-system/qa/v1.5-mobile-qa-checklist.md +103 -0
  17. package/modules/runwell-bundle-system/sections/runwell-bundle-cart-xsell.liquid +59 -0
  18. package/modules/runwell-bundle-system/sections/runwell-bundle-collection.liquid +121 -0
  19. package/modules/runwell-bundle-system/sections/runwell-bundle-home-stacks.liquid +77 -0
  20. package/modules/runwell-bundle-system/sections/runwell-bundle-pdp-banner.liquid +50 -0
  21. package/modules/runwell-bundle-system/sections/runwell-bundle-pdp-pairs-with.liquid +72 -0
  22. package/modules/runwell-bundle-system/sections/runwell-bundle-pdp.liquid +117 -0
  23. package/modules/runwell-bundle-system/settings.json +25 -0
  24. package/modules/runwell-bundle-system/snippets/runwell-bundle-byob-picker-accordion.liquid +84 -0
  25. package/modules/runwell-bundle-system/snippets/runwell-bundle-byob-picker-grid.liquid +72 -0
  26. package/modules/runwell-bundle-system/snippets/runwell-bundle-byob-picker-radio.liquid +77 -0
  27. package/modules/runwell-bundle-system/snippets/runwell-bundle-byob-picker.liquid +71 -0
  28. package/modules/runwell-bundle-system/snippets/runwell-bundle-byob-summary.liquid +39 -0
  29. package/modules/runwell-bundle-system/snippets/runwell-bundle-card.liquid +70 -0
  30. package/modules/runwell-bundle-system/snippets/runwell-bundle-cross-supplier.liquid +18 -0
  31. package/modules/runwell-bundle-system/snippets/runwell-bundle-data.liquid +75 -0
  32. package/modules/runwell-bundle-system/snippets/runwell-bundle-fomo.liquid +32 -0
  33. package/modules/runwell-bundle-system/snippets/runwell-bundle-free-gift.liquid +34 -0
  34. package/modules/runwell-bundle-system/snippets/runwell-bundle-multi-product.liquid +86 -0
  35. package/modules/runwell-bundle-system/snippets/runwell-bundle-pricing.liquid +30 -0
  36. package/modules/runwell-bundle-system/snippets/runwell-bundle-quantity-tiers.liquid +73 -0
  37. package/package.json +1 -1
@@ -0,0 +1,55 @@
1
+ {
2
+ "$comment": "Source of truth for runwell.bundle_* product metafield definitions. Mirrors spec.md section 2.1. Read by runwell-shopify provision-metafields (when implemented) and by admin-guide.md for manual setup.",
3
+ "spec_ref": "_clients/capital-v/lushi/specs/bundle-system/spec.md#21-per-bundle-product-metafields",
4
+ "product_metafields": {
5
+ "namespace": "runwell",
6
+ "owner_type": "PRODUCT",
7
+ "definitions": [
8
+ { "key": "bundle_mode", "name": "Bundle mode", "type": "single_line_text_field", "validations": [{ "name": "choices", "value": "[\"quantity_tiers\",\"multi_product\",\"mix_match\",\"byob\",\"subscription\"]" }] },
9
+ { "key": "bundle_pricing_model", "name": "Bundle pricing model", "type": "single_line_text_field", "validations": [{ "name": "choices", "value": "[\"tier_quantity\",\"fixed_price\",\"fixed_bundle_price\",\"percent_off_subtotal\",\"dollar_off_subtotal\"]" }] },
10
+ { "key": "bundle_pricing_value", "name": "Bundle pricing value (JSON)", "type": "json", "description": "Shape varies by pricing_model. See spec.md section 2.2." },
11
+ { "key": "bundle_components", "name": "Bundle components (JSON)", "type": "json", "description": "Required for multi_product / mix_match. Array of {product_handle, qty}." },
12
+ { "key": "bundle_quantity_tiers", "name": "Bundle quantity tiers (JSON)", "type": "json", "description": "Required for quantity_tiers. Array of {qty, discount_pct}. Mirrors quantity_breaks schema." },
13
+ { "key": "bundle_show_in_catalog", "name": "Show in main catalog", "type": "boolean", "default": true },
14
+ { "key": "bundle_surfaces_enabled", "name": "Surfaces enabled (JSON)", "type": "json", "description": "Per-bundle surface allowlist. Array of 1..6. Absent = all enabled at tenant level." },
15
+ { "key": "bundle_copy", "name": "Per-surface copy (JSON)", "type": "json", "description": "Per-surface eyebrow/heading/cta overrides." },
16
+ { "key": "bundle_free_gift_enabled", "name": "Free gift enabled", "type": "boolean", "default": false },
17
+ { "key": "bundle_free_gift_handle", "name": "Free gift product handle", "type": "single_line_text_field" },
18
+ { "key": "bundle_fomo_mode", "name": "FOMO mode", "type": "single_line_text_field", "validations": [{ "name": "choices", "value": "[\"none\",\"discount\",\"scarcity\",\"both\"]" }] },
19
+ { "key": "bundle_fomo_cycle_days", "name": "FOMO cycle (days)", "type": "number_integer" },
20
+ { "key": "bundle_fomo_stock_count", "name": "FOMO stock count", "type": "number_integer" },
21
+ { "key": "bundle_cross_supplier", "name": "Cross-supplier", "type": "boolean", "default": false },
22
+ { "key": "bundle_supplier_count", "name": "Supplier count", "type": "number_integer" },
23
+ { "key": "bundle_savings_pct", "name": "Computed savings percent", "type": "number_decimal", "description": "Precomputed for fast banner / card render. Recomputed by runwell-shopify rebuild-bundle-index." },
24
+ { "key": "bundle_byob_candidates", "name": "BYOB candidates", "type": "list.product_reference", "description": "Mode C only. Pool of candidate products the customer can pick from.", "v1_5": true },
25
+ { "key": "bundle_byob_min_picks", "name": "BYOB min picks", "type": "number_integer", "description": "Mode C only. Minimum required selections before ATC enables.", "v1_5": true },
26
+ { "key": "bundle_byob_max_picks", "name": "BYOB max picks", "type": "number_integer", "description": "Mode C only. Maximum allowed selections.", "v1_5": true },
27
+ { "key": "bundle_byob_layout", "name": "BYOB picker layout", "type": "single_line_text_field", "validations": [{ "name": "choices", "value": "[\"grid\",\"accordion\",\"radio\"]" }], "description": "Mode C only. Default grid.", "v1_5": true },
28
+ { "key": "bundle_byob_categories", "name": "BYOB categories", "type": "json", "description": "Mode C only. Optional. Array of {label, handles: [product_handle]} to group candidates.", "v1_5": true },
29
+ { "key": "bundle_byob_required_handles", "name": "BYOB required handles", "type": "list.product_reference", "description": "Mode C only. Pre-selected, not deselectable.", "v1_5": true },
30
+ { "key": "subscription_enabled", "name": "Subscription enabled (v2)", "type": "boolean", "default": false, "v2_only": true },
31
+ { "key": "subscription_interval", "name": "Subscription interval (JSON, v2)", "type": "json", "v2_only": true },
32
+ { "key": "subscription_discount_pct", "name": "Subscription discount percent (v2)", "type": "number_decimal", "v2_only": true },
33
+ { "key": "subscription_badge_copy", "name": "Subscription badge copy (v2)", "type": "single_line_text_field", "v2_only": true }
34
+ ]
35
+ },
36
+ "shop_metaobjects": [
37
+ {
38
+ "type": "bundle_index",
39
+ "name": "Bundle index",
40
+ "description": "Forward map (bundles -> components) and reverse map (products -> bundles) used by surfaces 2/4 to avoid N+1 reads. Single instance per shop. Rebuilt by runwell-shopify rebuild-bundle-index or by Shopify Flow on bundle product create/update.",
41
+ "field_definitions": [
42
+ { "key": "entries", "name": "Entries", "type": "json", "description": "{products: {handle: [bundle_handles]}, bundles: {handle: {components: {handle: qty}}}}" }
43
+ ]
44
+ }
45
+ ],
46
+ "cross_field_validation": [
47
+ { "rule": "bundle_quantity_tiers required when bundle_mode == 'quantity_tiers'", "enforced_by": "runwell-shopify qa --bundles" },
48
+ { "rule": "bundle_components required when bundle_mode in ['multi_product','mix_match']", "enforced_by": "runwell-shopify qa --bundles" },
49
+ { "rule": "bundle_byob_candidates + bundle_byob_min_picks + bundle_byob_max_picks required when bundle_mode == 'byob'", "enforced_by": "runwell-shopify qa --bundles" },
50
+ { "rule": "bundle_byob_min_picks <= bundle_byob_max_picks", "enforced_by": "runwell-shopify qa --bundles" },
51
+ { "rule": "bundle_byob_layout == 'radio' requires bundle_byob_categories", "enforced_by": "runwell-shopify qa --bundles" },
52
+ { "rule": "bundle_pricing_value shape matches bundle_pricing_model (see spec.md section 2.2)", "enforced_by": "runwell-shopify qa --bundles" },
53
+ { "rule": "bundle_free_gift_handle required when bundle_free_gift_enabled == true", "enforced_by": "runwell-shopify qa --bundles" }
54
+ ]
55
+ }