@lime-bundles/widget 4.6.6 → 4.6.8

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/index.cjs CHANGED
@@ -52,6 +52,121 @@ function bundleLineAttributes(bundleGid, bundleType) {
52
52
  ];
53
53
  }
54
54
 
55
+ // ../render/src/cart.ts
56
+ var CART_STOCK_WARNING_CODES = [
57
+ "MERCHANDISE_NOT_ENOUGH_STOCK",
58
+ "MERCHANDISE_OUT_OF_STOCK"
59
+ ];
60
+ function isStockWarning(warning) {
61
+ return !!warning.code && CART_STOCK_WARNING_CODES.indexOf(warning.code) !== -1;
62
+ }
63
+ function hasStockWarning(warnings) {
64
+ const list = warnings || [];
65
+ for (let i = 0; i < list.length; i++) {
66
+ if (isStockWarning(list[i])) return true;
67
+ }
68
+ return false;
69
+ }
70
+ function stockWarningMessage(warnings) {
71
+ const list = warnings || [];
72
+ for (let i = 0; i < list.length; i++) {
73
+ const warning = list[i];
74
+ if (isStockWarning(warning) && warning.message) return warning.message;
75
+ }
76
+ return void 0;
77
+ }
78
+ function totalPerVariant(lines) {
79
+ const totals = /* @__PURE__ */ Object.create(null);
80
+ for (let i = 0; i < lines.length; i++) {
81
+ const line = lines[i];
82
+ totals[line.variantId] = (totals[line.variantId] || 0) + (line.quantity || 0);
83
+ }
84
+ return totals;
85
+ }
86
+ function bundleAddFellShort(requested, before, after) {
87
+ const wanted = totalPerVariant(requested);
88
+ const had = totalPerVariant(before);
89
+ const has = totalPerVariant(after);
90
+ for (const variantId in wanted) {
91
+ if ((has[variantId] || 0) - (had[variantId] || 0) < wanted[variantId]) {
92
+ return true;
93
+ }
94
+ }
95
+ return false;
96
+ }
97
+
98
+ // ../render/src/strings.ts
99
+ var DEFAULT_STRINGS = {
100
+ locale: "en",
101
+ addItem: "Add",
102
+ addedItem: "Added",
103
+ removeItem: "Remove",
104
+ swapItem: "Swap",
105
+ required: "Required",
106
+ soldOut: "Sold out",
107
+ outOfStock: "Out of stock",
108
+ itemsOutOfStock: {
109
+ one: "__COUNT__ item out of stock",
110
+ other: "__COUNT__ items out of stock"
111
+ },
112
+ cartStockError: "We couldn't add this bundle to your cart. __MESSAGE__",
113
+ quantity: "Quantity",
114
+ increaseQuantity: "Increase quantity",
115
+ decreaseQuantity: "Decrease quantity",
116
+ allTypes: "All",
117
+ editSelection: "Edit selection",
118
+ addToCart: "Add to cart",
119
+ bundlePrice: "Bundle total",
120
+ save: "Save",
121
+ complete: "Complete",
122
+ ofSelected: "__COUNT__ of __TOTAL__ added",
123
+ moreToGo: "__COUNT__ more to go",
124
+ nProductsShown: "__COUNT__ products shown",
125
+ bundleComplete: "Your bundle is complete",
126
+ chooseMoreUnlock: "Choose __COUNT__ more to unlock __PCT__% off",
127
+ chooseMoreComplete: "Choose __COUNT__ more to complete your bundle",
128
+ stepOf: "Step __STEP__ of __TOTAL__",
129
+ stepsCompleted: "__COUNT__ of __TOTAL__ steps completed",
130
+ doorChoose: "Choose your products",
131
+ doorContinue: "Continue building",
132
+ doorQuickSteps: {
133
+ one: "__COUNT__ quick step",
134
+ other: "__COUNT__ quick steps"
135
+ },
136
+ doorStepsToGo: {
137
+ one: "__COUNT__ step to go",
138
+ other: "__COUNT__ steps to go"
139
+ },
140
+ each: " each",
141
+ buyQty: "Buy __COUNT__",
142
+ itemCount: {
143
+ one: "__COUNT__ item",
144
+ other: "__COUNT__ items"
145
+ },
146
+ needsSpots: {
147
+ one: "Needs __COUNT__ spot",
148
+ other: "Needs __COUNT__ spots"
149
+ }
150
+ };
151
+ function formatItemsOutOfStock(t, count) {
152
+ const raw = t.itemsOutOfStock;
153
+ let tpl;
154
+ if (raw && typeof raw === "object") {
155
+ const form = new Intl.PluralRules(t.locale || "en").select(count);
156
+ tpl = raw[form] || raw.other;
157
+ } else {
158
+ tpl = raw;
159
+ }
160
+ return (tpl || "__COUNT__ items out of stock").split("__COUNT__").join(String(count));
161
+ }
162
+ var CART_STOCK_ERROR_FALLBACK = "We couldn't add this bundle to your cart. __MESSAGE__";
163
+ function formatCartStockError(template, message) {
164
+ const tpl = (template || "").trim() || CART_STOCK_ERROR_FALLBACK;
165
+ const warning = (message || "").trim();
166
+ const composed = tpl.indexOf("__MESSAGE__") === -1 ? tpl + " " + warning : tpl.split("__MESSAGE__").join(warning);
167
+ return composed.replace(/\s+/g, " ").trim();
168
+ }
169
+
55
170
  // ../render/src/adapt.ts
56
171
  var import_core = require("@lime-bundles/core");
57
172
  function numericId(gid) {
@@ -803,70 +918,6 @@ function initCountdown(container) {
803
918
  }
804
919
  }
805
920
 
806
- // ../render/src/strings.ts
807
- var DEFAULT_STRINGS = {
808
- locale: "en",
809
- addItem: "Add",
810
- addedItem: "Added",
811
- removeItem: "Remove",
812
- swapItem: "Swap",
813
- required: "Required",
814
- soldOut: "Sold out",
815
- outOfStock: "Out of stock",
816
- itemsOutOfStock: {
817
- one: "__COUNT__ item out of stock",
818
- other: "__COUNT__ items out of stock"
819
- },
820
- quantity: "Quantity",
821
- increaseQuantity: "Increase quantity",
822
- decreaseQuantity: "Decrease quantity",
823
- allTypes: "All",
824
- editSelection: "Edit selection",
825
- addToCart: "Add to cart",
826
- bundlePrice: "Bundle total",
827
- save: "Save",
828
- complete: "Complete",
829
- ofSelected: "__COUNT__ of __TOTAL__ added",
830
- moreToGo: "__COUNT__ more to go",
831
- nProductsShown: "__COUNT__ products shown",
832
- bundleComplete: "Your bundle is complete",
833
- chooseMoreUnlock: "Choose __COUNT__ more to unlock __PCT__% off",
834
- chooseMoreComplete: "Choose __COUNT__ more to complete your bundle",
835
- stepOf: "Step __STEP__ of __TOTAL__",
836
- stepsCompleted: "__COUNT__ of __TOTAL__ steps completed",
837
- doorChoose: "Choose your products",
838
- doorContinue: "Continue building",
839
- doorQuickSteps: {
840
- one: "__COUNT__ quick step",
841
- other: "__COUNT__ quick steps"
842
- },
843
- doorStepsToGo: {
844
- one: "__COUNT__ step to go",
845
- other: "__COUNT__ steps to go"
846
- },
847
- each: " each",
848
- buyQty: "Buy __COUNT__",
849
- itemCount: {
850
- one: "__COUNT__ item",
851
- other: "__COUNT__ items"
852
- },
853
- needsSpots: {
854
- one: "Needs __COUNT__ spot",
855
- other: "Needs __COUNT__ spots"
856
- }
857
- };
858
- function formatItemsOutOfStock(t, count) {
859
- const raw = t.itemsOutOfStock;
860
- let tpl;
861
- if (raw && typeof raw === "object") {
862
- const form = new Intl.PluralRules(t.locale || "en").select(count);
863
- tpl = raw[form] || raw.other;
864
- } else {
865
- tpl = raw;
866
- }
867
- return (tpl || "__COUNT__ items out of stock").split("__COUNT__").join(String(count));
868
- }
869
-
870
921
  // ../render/src/dropdown/bind.ts
871
922
  var import_core2 = require("@lime-bundles/core");
872
923
 
@@ -6612,14 +6663,14 @@ var BUNDLE_BOGO_CSS = `/* Lime Bundles \u2014 BOGO (Buy X Get Y) bundle styles *
6612
6663
  opacity: 0.6;
6613
6664
  }
6614
6665
 
6615
- /* The reward row's struck original is emitted empty and filled on hydration,
6616
- so anything sharing its line moves when it appears. The count is the only
6617
- such thing, and it is a count, not part of the price phrase: pinning it to
6618
- the row's right edge makes its position independent of the price text \u2014 the
6619
- same right-slot treatment the fixed widget gives its quantity chip. */
6620
- .lb-bogo .lb-bundle-qty-inline {
6621
- margin-left: auto;
6622
- }
6666
+ /* The count sits beside the price, like every other inline-quantity widget
6667
+ (mix & match, multi-step). It used to be pinned to the row's right edge:
6668
+ this row's prices are emitted empty and filled on hydration, so a
6669
+ server-rendered count was painted and then shoved sideways when the price
6670
+ landed beside it. Pinning bought zero layout shift at the cost of a number
6671
+ floating in space, unattached to the figure it multiplies. The count is now
6672
+ emitted empty and filled with the rest of the price line, so it has no
6673
+ first-paint position to be moved from and needs no pinning. */
6623
6674
  `;
6624
6675
  var BUNDLE_MULTI_STEP_CSS = `/**
6625
6676
  * Lime Bundles \u2014 Multi-step bundle widget styles (wizard chrome ONLY).
@@ -7656,7 +7707,33 @@ var LimeBundleElement = class extends HTMLElement {
7656
7707
  const key = cartStorageKey(this.shopDomain);
7657
7708
  let cartId = storage?.getItem(key) ?? null;
7658
7709
  const isStaleCartError = (errors) => errors.length > 0 && errors.every((e) => (e.field ?? []).includes("cartId"));
7659
- const stockCapped = (warnings) => (warnings ?? []).some((w) => w.code === "MERCHANDISE_NOT_ENOUGH_STOCK");
7710
+ const requested = lines.map((line) => ({
7711
+ variantId: line.merchandiseId,
7712
+ quantity: line.quantity
7713
+ }));
7714
+ const bundleLinesOf = (payload) => {
7715
+ const nodes = payload?.cart?.lines?.nodes;
7716
+ if (!nodes) return null;
7717
+ const found = [];
7718
+ for (const node of nodes) {
7719
+ if (!node.attributes.some((a) => a.key === BUNDLE_GID_ATTRIBUTE)) {
7720
+ continue;
7721
+ }
7722
+ const variantId = node.merchandise?.id;
7723
+ if (!variantId) continue;
7724
+ found.push({ variantId, quantity: node.quantity });
7725
+ }
7726
+ return found;
7727
+ };
7728
+ const fellShort = (payload) => {
7729
+ const after = bundleLinesOf(payload);
7730
+ if (!after) return hasStockWarning(payload?.warnings);
7731
+ return bundleAddFellShort(requested, [], after);
7732
+ };
7733
+ const stockError = (payload) => formatCartStockError(
7734
+ DEFAULT_STRINGS.cartStockError,
7735
+ stockWarningMessage(payload?.warnings)
7736
+ );
7660
7737
  const fail = (message) => {
7661
7738
  this.dispatchEvent(
7662
7739
  new CustomEvent("lime-bundle:error", {
@@ -7687,8 +7764,8 @@ var LimeBundleElement = class extends HTMLElement {
7687
7764
  return;
7688
7765
  }
7689
7766
  storage?.removeItem(key);
7690
- } else if (stockCapped(payload?.warnings)) {
7691
- fail("Some items in this bundle are out of stock.");
7767
+ } else if (fellShort(payload)) {
7768
+ fail(stockError(payload));
7692
7769
  return;
7693
7770
  } else if (payload?.cart) {
7694
7771
  checkoutUrl = payload.cart.checkoutUrl;
@@ -7704,8 +7781,8 @@ var LimeBundleElement = class extends HTMLElement {
7704
7781
  fail(payload.userErrors[0].message);
7705
7782
  return;
7706
7783
  }
7707
- if (stockCapped(payload?.warnings)) {
7708
- fail("Some items in this bundle are out of stock.");
7784
+ if (fellShort(payload)) {
7785
+ fail(stockError(payload));
7709
7786
  return;
7710
7787
  }
7711
7788
  if (payload?.cart) {
package/dist/index.js CHANGED
@@ -46,6 +46,121 @@ function bundleLineAttributes(bundleGid, bundleType) {
46
46
  ];
47
47
  }
48
48
 
49
+ // ../render/src/cart.ts
50
+ var CART_STOCK_WARNING_CODES = [
51
+ "MERCHANDISE_NOT_ENOUGH_STOCK",
52
+ "MERCHANDISE_OUT_OF_STOCK"
53
+ ];
54
+ function isStockWarning(warning) {
55
+ return !!warning.code && CART_STOCK_WARNING_CODES.indexOf(warning.code) !== -1;
56
+ }
57
+ function hasStockWarning(warnings) {
58
+ const list = warnings || [];
59
+ for (let i = 0; i < list.length; i++) {
60
+ if (isStockWarning(list[i])) return true;
61
+ }
62
+ return false;
63
+ }
64
+ function stockWarningMessage(warnings) {
65
+ const list = warnings || [];
66
+ for (let i = 0; i < list.length; i++) {
67
+ const warning = list[i];
68
+ if (isStockWarning(warning) && warning.message) return warning.message;
69
+ }
70
+ return void 0;
71
+ }
72
+ function totalPerVariant(lines) {
73
+ const totals = /* @__PURE__ */ Object.create(null);
74
+ for (let i = 0; i < lines.length; i++) {
75
+ const line = lines[i];
76
+ totals[line.variantId] = (totals[line.variantId] || 0) + (line.quantity || 0);
77
+ }
78
+ return totals;
79
+ }
80
+ function bundleAddFellShort(requested, before, after) {
81
+ const wanted = totalPerVariant(requested);
82
+ const had = totalPerVariant(before);
83
+ const has = totalPerVariant(after);
84
+ for (const variantId in wanted) {
85
+ if ((has[variantId] || 0) - (had[variantId] || 0) < wanted[variantId]) {
86
+ return true;
87
+ }
88
+ }
89
+ return false;
90
+ }
91
+
92
+ // ../render/src/strings.ts
93
+ var DEFAULT_STRINGS = {
94
+ locale: "en",
95
+ addItem: "Add",
96
+ addedItem: "Added",
97
+ removeItem: "Remove",
98
+ swapItem: "Swap",
99
+ required: "Required",
100
+ soldOut: "Sold out",
101
+ outOfStock: "Out of stock",
102
+ itemsOutOfStock: {
103
+ one: "__COUNT__ item out of stock",
104
+ other: "__COUNT__ items out of stock"
105
+ },
106
+ cartStockError: "We couldn't add this bundle to your cart. __MESSAGE__",
107
+ quantity: "Quantity",
108
+ increaseQuantity: "Increase quantity",
109
+ decreaseQuantity: "Decrease quantity",
110
+ allTypes: "All",
111
+ editSelection: "Edit selection",
112
+ addToCart: "Add to cart",
113
+ bundlePrice: "Bundle total",
114
+ save: "Save",
115
+ complete: "Complete",
116
+ ofSelected: "__COUNT__ of __TOTAL__ added",
117
+ moreToGo: "__COUNT__ more to go",
118
+ nProductsShown: "__COUNT__ products shown",
119
+ bundleComplete: "Your bundle is complete",
120
+ chooseMoreUnlock: "Choose __COUNT__ more to unlock __PCT__% off",
121
+ chooseMoreComplete: "Choose __COUNT__ more to complete your bundle",
122
+ stepOf: "Step __STEP__ of __TOTAL__",
123
+ stepsCompleted: "__COUNT__ of __TOTAL__ steps completed",
124
+ doorChoose: "Choose your products",
125
+ doorContinue: "Continue building",
126
+ doorQuickSteps: {
127
+ one: "__COUNT__ quick step",
128
+ other: "__COUNT__ quick steps"
129
+ },
130
+ doorStepsToGo: {
131
+ one: "__COUNT__ step to go",
132
+ other: "__COUNT__ steps to go"
133
+ },
134
+ each: " each",
135
+ buyQty: "Buy __COUNT__",
136
+ itemCount: {
137
+ one: "__COUNT__ item",
138
+ other: "__COUNT__ items"
139
+ },
140
+ needsSpots: {
141
+ one: "Needs __COUNT__ spot",
142
+ other: "Needs __COUNT__ spots"
143
+ }
144
+ };
145
+ function formatItemsOutOfStock(t, count) {
146
+ const raw = t.itemsOutOfStock;
147
+ let tpl;
148
+ if (raw && typeof raw === "object") {
149
+ const form = new Intl.PluralRules(t.locale || "en").select(count);
150
+ tpl = raw[form] || raw.other;
151
+ } else {
152
+ tpl = raw;
153
+ }
154
+ return (tpl || "__COUNT__ items out of stock").split("__COUNT__").join(String(count));
155
+ }
156
+ var CART_STOCK_ERROR_FALLBACK = "We couldn't add this bundle to your cart. __MESSAGE__";
157
+ function formatCartStockError(template, message) {
158
+ const tpl = (template || "").trim() || CART_STOCK_ERROR_FALLBACK;
159
+ const warning = (message || "").trim();
160
+ const composed = tpl.indexOf("__MESSAGE__") === -1 ? tpl + " " + warning : tpl.split("__MESSAGE__").join(warning);
161
+ return composed.replace(/\s+/g, " ").trim();
162
+ }
163
+
49
164
  // ../render/src/adapt.ts
50
165
  import {
51
166
  formatUnitPrice,
@@ -802,70 +917,6 @@ function initCountdown(container) {
802
917
  }
803
918
  }
804
919
 
805
- // ../render/src/strings.ts
806
- var DEFAULT_STRINGS = {
807
- locale: "en",
808
- addItem: "Add",
809
- addedItem: "Added",
810
- removeItem: "Remove",
811
- swapItem: "Swap",
812
- required: "Required",
813
- soldOut: "Sold out",
814
- outOfStock: "Out of stock",
815
- itemsOutOfStock: {
816
- one: "__COUNT__ item out of stock",
817
- other: "__COUNT__ items out of stock"
818
- },
819
- quantity: "Quantity",
820
- increaseQuantity: "Increase quantity",
821
- decreaseQuantity: "Decrease quantity",
822
- allTypes: "All",
823
- editSelection: "Edit selection",
824
- addToCart: "Add to cart",
825
- bundlePrice: "Bundle total",
826
- save: "Save",
827
- complete: "Complete",
828
- ofSelected: "__COUNT__ of __TOTAL__ added",
829
- moreToGo: "__COUNT__ more to go",
830
- nProductsShown: "__COUNT__ products shown",
831
- bundleComplete: "Your bundle is complete",
832
- chooseMoreUnlock: "Choose __COUNT__ more to unlock __PCT__% off",
833
- chooseMoreComplete: "Choose __COUNT__ more to complete your bundle",
834
- stepOf: "Step __STEP__ of __TOTAL__",
835
- stepsCompleted: "__COUNT__ of __TOTAL__ steps completed",
836
- doorChoose: "Choose your products",
837
- doorContinue: "Continue building",
838
- doorQuickSteps: {
839
- one: "__COUNT__ quick step",
840
- other: "__COUNT__ quick steps"
841
- },
842
- doorStepsToGo: {
843
- one: "__COUNT__ step to go",
844
- other: "__COUNT__ steps to go"
845
- },
846
- each: " each",
847
- buyQty: "Buy __COUNT__",
848
- itemCount: {
849
- one: "__COUNT__ item",
850
- other: "__COUNT__ items"
851
- },
852
- needsSpots: {
853
- one: "Needs __COUNT__ spot",
854
- other: "Needs __COUNT__ spots"
855
- }
856
- };
857
- function formatItemsOutOfStock(t, count) {
858
- const raw = t.itemsOutOfStock;
859
- let tpl;
860
- if (raw && typeof raw === "object") {
861
- const form = new Intl.PluralRules(t.locale || "en").select(count);
862
- tpl = raw[form] || raw.other;
863
- } else {
864
- tpl = raw;
865
- }
866
- return (tpl || "__COUNT__ items out of stock").split("__COUNT__").join(String(count));
867
- }
868
-
869
920
  // ../render/src/dropdown/bind.ts
870
921
  import { dropdown } from "@lime-bundles/core";
871
922
 
@@ -6622,14 +6673,14 @@ var BUNDLE_BOGO_CSS = `/* Lime Bundles \u2014 BOGO (Buy X Get Y) bundle styles *
6622
6673
  opacity: 0.6;
6623
6674
  }
6624
6675
 
6625
- /* The reward row's struck original is emitted empty and filled on hydration,
6626
- so anything sharing its line moves when it appears. The count is the only
6627
- such thing, and it is a count, not part of the price phrase: pinning it to
6628
- the row's right edge makes its position independent of the price text \u2014 the
6629
- same right-slot treatment the fixed widget gives its quantity chip. */
6630
- .lb-bogo .lb-bundle-qty-inline {
6631
- margin-left: auto;
6632
- }
6676
+ /* The count sits beside the price, like every other inline-quantity widget
6677
+ (mix & match, multi-step). It used to be pinned to the row's right edge:
6678
+ this row's prices are emitted empty and filled on hydration, so a
6679
+ server-rendered count was painted and then shoved sideways when the price
6680
+ landed beside it. Pinning bought zero layout shift at the cost of a number
6681
+ floating in space, unattached to the figure it multiplies. The count is now
6682
+ emitted empty and filled with the rest of the price line, so it has no
6683
+ first-paint position to be moved from and needs no pinning. */
6633
6684
  `;
6634
6685
  var BUNDLE_MULTI_STEP_CSS = `/**
6635
6686
  * Lime Bundles \u2014 Multi-step bundle widget styles (wizard chrome ONLY).
@@ -7666,7 +7717,33 @@ var LimeBundleElement = class extends HTMLElement {
7666
7717
  const key = cartStorageKey(this.shopDomain);
7667
7718
  let cartId = storage?.getItem(key) ?? null;
7668
7719
  const isStaleCartError = (errors) => errors.length > 0 && errors.every((e) => (e.field ?? []).includes("cartId"));
7669
- const stockCapped = (warnings) => (warnings ?? []).some((w) => w.code === "MERCHANDISE_NOT_ENOUGH_STOCK");
7720
+ const requested = lines.map((line) => ({
7721
+ variantId: line.merchandiseId,
7722
+ quantity: line.quantity
7723
+ }));
7724
+ const bundleLinesOf = (payload) => {
7725
+ const nodes = payload?.cart?.lines?.nodes;
7726
+ if (!nodes) return null;
7727
+ const found = [];
7728
+ for (const node of nodes) {
7729
+ if (!node.attributes.some((a) => a.key === BUNDLE_GID_ATTRIBUTE)) {
7730
+ continue;
7731
+ }
7732
+ const variantId = node.merchandise?.id;
7733
+ if (!variantId) continue;
7734
+ found.push({ variantId, quantity: node.quantity });
7735
+ }
7736
+ return found;
7737
+ };
7738
+ const fellShort = (payload) => {
7739
+ const after = bundleLinesOf(payload);
7740
+ if (!after) return hasStockWarning(payload?.warnings);
7741
+ return bundleAddFellShort(requested, [], after);
7742
+ };
7743
+ const stockError = (payload) => formatCartStockError(
7744
+ DEFAULT_STRINGS.cartStockError,
7745
+ stockWarningMessage(payload?.warnings)
7746
+ );
7670
7747
  const fail = (message) => {
7671
7748
  this.dispatchEvent(
7672
7749
  new CustomEvent("lime-bundle:error", {
@@ -7697,8 +7774,8 @@ var LimeBundleElement = class extends HTMLElement {
7697
7774
  return;
7698
7775
  }
7699
7776
  storage?.removeItem(key);
7700
- } else if (stockCapped(payload?.warnings)) {
7701
- fail("Some items in this bundle are out of stock.");
7777
+ } else if (fellShort(payload)) {
7778
+ fail(stockError(payload));
7702
7779
  return;
7703
7780
  } else if (payload?.cart) {
7704
7781
  checkoutUrl = payload.cart.checkoutUrl;
@@ -7714,8 +7791,8 @@ var LimeBundleElement = class extends HTMLElement {
7714
7791
  fail(payload.userErrors[0].message);
7715
7792
  return;
7716
7793
  }
7717
- if (stockCapped(payload?.warnings)) {
7718
- fail("Some items in this bundle are out of stock.");
7794
+ if (fellShort(payload)) {
7795
+ fail(stockError(payload));
7719
7796
  return;
7720
7797
  }
7721
7798
  if (payload?.cart) {