@lime-bundles/react 4.0.0 → 5.0.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/index.d.cts CHANGED
@@ -1,6 +1,6 @@
1
1
  import * as react_jsx_runtime from 'react/jsx-runtime';
2
- import { CartLineInput, ProductVariant, ParsedBundle, WidgetConfig } from '@lime-bundles/core';
3
- export { ABVariantOverrides, BUNDLES_FOR_PRODUCT_QUERY, BUNDLE_METAOBJECT_QUERY, BundleParseError, BundleType, CartLineInput, CountdownConfig, CtaConfig, DiscountConfig, FixedBundleData, FixedBundlePricing, HeaderConfig, ImageTransform, LayoutConfig, MixMatchBundleData, ParsedBundle, PopularBadgeConfig, PricingConfig, PricingRow, Product, ProductListConfig, ProductVariant, SHOP_CUSTOM_CSS_QUERY, SavingsBarConfig, StorefrontApiError, ThumbnailRatio, VolumeBundleData, VolumeTier, WIDGET_CONFIG_DEFAULTS, WidgetConfig, applyABVariantB, applyWidgetConfigVars, calculateDiscount, calculateTierSavings, computeBundleSaleCents, computeFixedPricing, createStorefrontClient, fetchBundlesForProduct, formatCents, formatCountdown, formatMoney, formatUnitPrice, getABTestAssignment, getActiveTier, hasConsent, injectCustomCss, mergeWidgetConfig, observeImpression, parseCents, parseMetaobjectBundle, parseMetaobjectBundleStrict, percentageDiscountUnit, reportAddToCart, reportImpression, sanitizeCustomCss, setConsent, thumbnailRatioVars, transformImageUrl, validateQuantity } from '@lime-bundles/core';
2
+ import { CartLineInput, BuyerResolver, ProductVariant, ParsedBundle, WidgetConfig } from '@lime-bundles/core';
3
+ export { ABVariantOverrides, BUNDLES_FOR_PRODUCT_QUERY, BUNDLE_METAOBJECT_QUERY, BundleParseError, BundleType, CartLineInput, CountdownConfig, CtaConfig, DiscountConfig, FixedBundleData, FixedBundlePricing, HeaderConfig, ImageTransform, LayoutConfig, MixMatchBundleData, ParsedBundle, PopularBadgeConfig, PricingConfig, PricingRow, Product, ProductListConfig, ProductVariant, SHOP_CUSTOM_CSS_QUERY, SavingsBarConfig, StorefrontApiError, ThumbnailRatio, VolumeBundleData, VolumeTier, WIDGET_CONFIG_DEFAULTS, WidgetConfig, applyWidgetConfigVars, calculateDiscount, calculateTierSavings, computeBundleSaleCents, computeFixedPricing, createStorefrontClient, fetchBundlesForProduct, fnv1a, formatCents, formatCountdown, formatMoney, formatUnitPrice, getActiveTier, getLinkGroupAssignment, hasConsent, injectCustomCss, mergeWidgetConfig, observeImpression, parseCents, parseMetaobjectBundle, parseMetaobjectBundleStrict, percentageDiscountUnit, pickVariantFromWeights, reportAddToCart, reportImpression, sanitizeCustomCss, setConsent, thumbnailRatioVars, transformImageUrl, validateQuantity } from '@lime-bundles/core';
4
4
 
5
5
  /**
6
6
  * Shared props for bundle components.
@@ -32,6 +32,25 @@ interface BundleComponentProps {
32
32
  analyticsEnabled?: boolean;
33
33
  /** Called with the thrown `Error` from fetchBundleData or onAddToCart. */
34
34
  onError?: (error: Error) => void;
35
+ /**
36
+ * ISO-3166 alpha-2 country code, passed as Storefront `@inContext(country:)`.
37
+ * Drives Markets pricing and currency. Omit for shop default.
38
+ */
39
+ country?: string;
40
+ /** ISO-639-1 language code, passed as `@inContext(language:)`. */
41
+ language?: string;
42
+ /**
43
+ * B2B buyer identity. Prefer the callback form (`() => Promise<BuyerInput>`)
44
+ * so the customer access token doesn't live in static prop trees. See
45
+ * the package README ("Markets & B2B") for the security threat model.
46
+ */
47
+ buyer?: BuyerResolver;
48
+ /**
49
+ * Current visitor's Shopify Market GID. When set and the bundle's
50
+ * `marketVisibility === "specific"`, the bundle is hidden if its
51
+ * `marketIds` doesn't include this market.
52
+ */
53
+ marketId?: string;
35
54
  }
36
55
 
37
56
  declare function FixedBundle(props: BundleComponentProps): react_jsx_runtime.JSX.Element | null;
@@ -116,6 +135,26 @@ interface FetchBundleDataOptions {
116
135
  signal?: AbortSignal;
117
136
  /** Override the Storefront API version pinned in `createStorefrontClient`. */
118
137
  apiVersion?: string;
138
+ /**
139
+ * ISO-3166 alpha-2 country code passed as `@inContext(country: ...)`.
140
+ * Drives Shopify Markets pricing, currency, and availability.
141
+ */
142
+ country?: string;
143
+ /** ISO-639-1 language code passed as `@inContext(language: ...)`. */
144
+ language?: string;
145
+ /**
146
+ * B2B buyer identity. Prefer the callback form for security — it lets
147
+ * you fetch the customer access token just-in-time so it doesn't sit
148
+ * in static prop trees. See packages/*\/README.md → "Markets & B2B".
149
+ */
150
+ buyer?: BuyerResolver;
151
+ /**
152
+ * Shopify Market GID for the current visitor. When set and the bundle's
153
+ * `marketVisibility === "specific"`, the bundle is filtered out if its
154
+ * `marketIds` doesn't include this market. Returned to the caller via
155
+ * `BundleVisibilityWarning[]` for surfacing.
156
+ */
157
+ marketId?: string;
119
158
  }
120
159
  declare function fetchBundleData(options: FetchBundleDataOptions): Promise<ParsedBundle>;
121
160
 
@@ -131,6 +170,14 @@ interface UseBundleDataOptions {
131
170
  shopDomain: string;
132
171
  storefrontAccessToken: string;
133
172
  bundleGid: string;
173
+ /** ISO-3166 alpha-2 country, passed as Storefront `@inContext(country:)`. */
174
+ country?: string;
175
+ /** ISO-639-1 language, passed as `@inContext(language:)`. */
176
+ language?: string;
177
+ /** B2B buyer identity. Prefer the callback form to keep tokens off prop trees. */
178
+ buyer?: BuyerResolver;
179
+ /** Current visitor's Market GID — filters market-restricted bundles client-side. */
180
+ marketId?: string;
134
181
  }
135
182
  type UseBundleDataResult = {
136
183
  status: "loading";
@@ -175,8 +222,13 @@ interface UseAnalyticsOptions {
175
222
  bundleGid: string;
176
223
  bundleType: string;
177
224
  enabled?: boolean;
178
- abTestId?: string;
179
- abVariant?: string;
225
+ /**
226
+ * Link-group UUID when the rendered bundle is part of an A/B test. Replaces
227
+ * the prior abTestId/abVariant pair — each variant is its own bundle row
228
+ * under the duplicate-bundle model so `bundleGid` already identifies the
229
+ * variant; `linkGroupId` is the convenience join key for analytics.
230
+ */
231
+ linkGroupId?: string;
180
232
  }
181
233
  declare function useAnalytics(options: UseAnalyticsOptions): {
182
234
  elementRef: (el: HTMLElement | null) => void;
package/dist/index.d.ts CHANGED
@@ -1,6 +1,6 @@
1
1
  import * as react_jsx_runtime from 'react/jsx-runtime';
2
- import { CartLineInput, ProductVariant, ParsedBundle, WidgetConfig } from '@lime-bundles/core';
3
- export { ABVariantOverrides, BUNDLES_FOR_PRODUCT_QUERY, BUNDLE_METAOBJECT_QUERY, BundleParseError, BundleType, CartLineInput, CountdownConfig, CtaConfig, DiscountConfig, FixedBundleData, FixedBundlePricing, HeaderConfig, ImageTransform, LayoutConfig, MixMatchBundleData, ParsedBundle, PopularBadgeConfig, PricingConfig, PricingRow, Product, ProductListConfig, ProductVariant, SHOP_CUSTOM_CSS_QUERY, SavingsBarConfig, StorefrontApiError, ThumbnailRatio, VolumeBundleData, VolumeTier, WIDGET_CONFIG_DEFAULTS, WidgetConfig, applyABVariantB, applyWidgetConfigVars, calculateDiscount, calculateTierSavings, computeBundleSaleCents, computeFixedPricing, createStorefrontClient, fetchBundlesForProduct, formatCents, formatCountdown, formatMoney, formatUnitPrice, getABTestAssignment, getActiveTier, hasConsent, injectCustomCss, mergeWidgetConfig, observeImpression, parseCents, parseMetaobjectBundle, parseMetaobjectBundleStrict, percentageDiscountUnit, reportAddToCart, reportImpression, sanitizeCustomCss, setConsent, thumbnailRatioVars, transformImageUrl, validateQuantity } from '@lime-bundles/core';
2
+ import { CartLineInput, BuyerResolver, ProductVariant, ParsedBundle, WidgetConfig } from '@lime-bundles/core';
3
+ export { ABVariantOverrides, BUNDLES_FOR_PRODUCT_QUERY, BUNDLE_METAOBJECT_QUERY, BundleParseError, BundleType, CartLineInput, CountdownConfig, CtaConfig, DiscountConfig, FixedBundleData, FixedBundlePricing, HeaderConfig, ImageTransform, LayoutConfig, MixMatchBundleData, ParsedBundle, PopularBadgeConfig, PricingConfig, PricingRow, Product, ProductListConfig, ProductVariant, SHOP_CUSTOM_CSS_QUERY, SavingsBarConfig, StorefrontApiError, ThumbnailRatio, VolumeBundleData, VolumeTier, WIDGET_CONFIG_DEFAULTS, WidgetConfig, applyWidgetConfigVars, calculateDiscount, calculateTierSavings, computeBundleSaleCents, computeFixedPricing, createStorefrontClient, fetchBundlesForProduct, fnv1a, formatCents, formatCountdown, formatMoney, formatUnitPrice, getActiveTier, getLinkGroupAssignment, hasConsent, injectCustomCss, mergeWidgetConfig, observeImpression, parseCents, parseMetaobjectBundle, parseMetaobjectBundleStrict, percentageDiscountUnit, pickVariantFromWeights, reportAddToCart, reportImpression, sanitizeCustomCss, setConsent, thumbnailRatioVars, transformImageUrl, validateQuantity } from '@lime-bundles/core';
4
4
 
5
5
  /**
6
6
  * Shared props for bundle components.
@@ -32,6 +32,25 @@ interface BundleComponentProps {
32
32
  analyticsEnabled?: boolean;
33
33
  /** Called with the thrown `Error` from fetchBundleData or onAddToCart. */
34
34
  onError?: (error: Error) => void;
35
+ /**
36
+ * ISO-3166 alpha-2 country code, passed as Storefront `@inContext(country:)`.
37
+ * Drives Markets pricing and currency. Omit for shop default.
38
+ */
39
+ country?: string;
40
+ /** ISO-639-1 language code, passed as `@inContext(language:)`. */
41
+ language?: string;
42
+ /**
43
+ * B2B buyer identity. Prefer the callback form (`() => Promise<BuyerInput>`)
44
+ * so the customer access token doesn't live in static prop trees. See
45
+ * the package README ("Markets & B2B") for the security threat model.
46
+ */
47
+ buyer?: BuyerResolver;
48
+ /**
49
+ * Current visitor's Shopify Market GID. When set and the bundle's
50
+ * `marketVisibility === "specific"`, the bundle is hidden if its
51
+ * `marketIds` doesn't include this market.
52
+ */
53
+ marketId?: string;
35
54
  }
36
55
 
37
56
  declare function FixedBundle(props: BundleComponentProps): react_jsx_runtime.JSX.Element | null;
@@ -116,6 +135,26 @@ interface FetchBundleDataOptions {
116
135
  signal?: AbortSignal;
117
136
  /** Override the Storefront API version pinned in `createStorefrontClient`. */
118
137
  apiVersion?: string;
138
+ /**
139
+ * ISO-3166 alpha-2 country code passed as `@inContext(country: ...)`.
140
+ * Drives Shopify Markets pricing, currency, and availability.
141
+ */
142
+ country?: string;
143
+ /** ISO-639-1 language code passed as `@inContext(language: ...)`. */
144
+ language?: string;
145
+ /**
146
+ * B2B buyer identity. Prefer the callback form for security — it lets
147
+ * you fetch the customer access token just-in-time so it doesn't sit
148
+ * in static prop trees. See packages/*\/README.md → "Markets & B2B".
149
+ */
150
+ buyer?: BuyerResolver;
151
+ /**
152
+ * Shopify Market GID for the current visitor. When set and the bundle's
153
+ * `marketVisibility === "specific"`, the bundle is filtered out if its
154
+ * `marketIds` doesn't include this market. Returned to the caller via
155
+ * `BundleVisibilityWarning[]` for surfacing.
156
+ */
157
+ marketId?: string;
119
158
  }
120
159
  declare function fetchBundleData(options: FetchBundleDataOptions): Promise<ParsedBundle>;
121
160
 
@@ -131,6 +170,14 @@ interface UseBundleDataOptions {
131
170
  shopDomain: string;
132
171
  storefrontAccessToken: string;
133
172
  bundleGid: string;
173
+ /** ISO-3166 alpha-2 country, passed as Storefront `@inContext(country:)`. */
174
+ country?: string;
175
+ /** ISO-639-1 language, passed as `@inContext(language:)`. */
176
+ language?: string;
177
+ /** B2B buyer identity. Prefer the callback form to keep tokens off prop trees. */
178
+ buyer?: BuyerResolver;
179
+ /** Current visitor's Market GID — filters market-restricted bundles client-side. */
180
+ marketId?: string;
134
181
  }
135
182
  type UseBundleDataResult = {
136
183
  status: "loading";
@@ -175,8 +222,13 @@ interface UseAnalyticsOptions {
175
222
  bundleGid: string;
176
223
  bundleType: string;
177
224
  enabled?: boolean;
178
- abTestId?: string;
179
- abVariant?: string;
225
+ /**
226
+ * Link-group UUID when the rendered bundle is part of an A/B test. Replaces
227
+ * the prior abTestId/abVariant pair — each variant is its own bundle row
228
+ * under the duplicate-bundle model so `bundleGid` already identifies the
229
+ * variant; `linkGroupId` is the convenience join key for analytics.
230
+ */
231
+ linkGroupId?: string;
180
232
  }
181
233
  declare function useAnalytics(options: UseAnalyticsOptions): {
182
234
  elementRef: (el: HTMLElement | null) => void;
package/dist/index.js CHANGED
@@ -11,24 +11,43 @@ import {
11
11
 
12
12
  // src/hooks/useBundleData.ts
13
13
  import { useState, useEffect } from "react";
14
- import { injectCustomCss } from "@lime-bundles/core";
14
+ import {
15
+ injectCustomCss
16
+ } from "@lime-bundles/core";
15
17
 
16
18
  // src/fetchBundleData.ts
17
19
  import {
18
20
  createStorefrontClient,
21
+ hasInContext,
19
22
  BUNDLE_METAOBJECT_QUERY,
23
+ withInContext,
20
24
  parseMetaobjectBundleStrict,
21
25
  BundleParseError
22
26
  } from "@lime-bundles/core";
23
27
  async function fetchBundleData(options) {
24
- const client = createStorefrontClient({
28
+ const result = await fetchBundleDataWithWarnings(options);
29
+ if (!result.bundle) {
30
+ throw new BundleParseError(
31
+ `Bundle hidden by market gate: ${options.bundleGid}`,
32
+ "not_found"
33
+ );
34
+ }
35
+ return result.bundle;
36
+ }
37
+ async function fetchBundleDataWithWarnings(options) {
38
+ const config = {
25
39
  shopDomain: options.shopDomain,
26
40
  accessToken: options.storefrontAccessToken,
27
41
  buyerIp: options.buyerIp,
28
- apiVersion: options.apiVersion
29
- });
42
+ apiVersion: options.apiVersion,
43
+ country: options.country,
44
+ language: options.language,
45
+ buyer: options.buyer
46
+ };
47
+ const client = createStorefrontClient(config);
48
+ const query = hasInContext(config) ? withInContext(BUNDLE_METAOBJECT_QUERY) : BUNDLE_METAOBJECT_QUERY;
30
49
  const data = await client.query(
31
- BUNDLE_METAOBJECT_QUERY,
50
+ query,
32
51
  { id: options.bundleGid },
33
52
  { signal: options.signal }
34
53
  );
@@ -38,10 +57,24 @@ async function fetchBundleData(options) {
38
57
  "not_found"
39
58
  );
40
59
  }
41
- return parseMetaobjectBundleStrict(
60
+ const bundle = parseMetaobjectBundleStrict(
42
61
  data.metaobject.id,
43
62
  data.metaobject.fields
44
63
  );
64
+ if (bundle.marketVisibility === "specific" && (!options.marketId || !bundle.marketIds.includes(options.marketId))) {
65
+ return {
66
+ bundle: null,
67
+ warnings: [
68
+ {
69
+ bundleGid: options.bundleGid,
70
+ reason: "market_mismatch",
71
+ currentMarketId: options.marketId ?? null,
72
+ allowedMarketIds: bundle.marketIds
73
+ }
74
+ ]
75
+ };
76
+ }
77
+ return { bundle, warnings: [] };
45
78
  }
46
79
 
47
80
  // src/fetchShopCustomCss.ts
@@ -90,7 +123,11 @@ function useBundleData(options) {
90
123
  shopDomain: options.shopDomain,
91
124
  storefrontAccessToken: options.storefrontAccessToken,
92
125
  bundleGid: options.bundleGid,
93
- signal: controller.signal
126
+ signal: controller.signal,
127
+ country: options.country,
128
+ language: options.language,
129
+ buyer: options.buyer,
130
+ marketId: options.marketId
94
131
  }).then((bundle) => {
95
132
  if (controller.signal.aborted) return;
96
133
  setState({ status: "success", bundle, error: null });
@@ -117,7 +154,11 @@ function useBundleData(options) {
117
154
  }, [
118
155
  options.shopDomain,
119
156
  options.storefrontAccessToken,
120
- options.bundleGid
157
+ options.bundleGid,
158
+ options.country,
159
+ options.language,
160
+ options.buyer,
161
+ options.marketId
121
162
  ]);
122
163
  return state;
123
164
  }
@@ -141,7 +182,7 @@ function useAnalytics(options) {
141
182
  );
142
183
  useEffect2(() => {
143
184
  impressionFiredRef.current = false;
144
- }, [options.bundleGid, options.abVariant]);
185
+ }, [options.bundleGid]);
145
186
  useEffect2(() => {
146
187
  if (options.enabled === false) return;
147
188
  if (impressionFiredRef.current) return;
@@ -152,8 +193,7 @@ function useAnalytics(options) {
152
193
  reportImpression(config, {
153
194
  bundleGid: options.bundleGid,
154
195
  bundleType: options.bundleType,
155
- abTestId: options.abTestId,
156
- abVariant: options.abVariant
196
+ linkGroupId: options.linkGroupId
157
197
  });
158
198
  });
159
199
  return cleanup;
@@ -163,8 +203,7 @@ function useAnalytics(options) {
163
203
  options.enabled,
164
204
  options.bundleGid,
165
205
  options.bundleType,
166
- options.abTestId,
167
- options.abVariant
206
+ options.linkGroupId
168
207
  ]);
169
208
  const trackAddToCart = useCallback(
170
209
  (event) => {
@@ -175,8 +214,7 @@ function useAnalytics(options) {
175
214
  productId: event.productId,
176
215
  quantity: event.quantity,
177
216
  totalPrice: event.totalPrice,
178
- abTestId: options.abTestId,
179
- abVariant: options.abVariant
217
+ linkGroupId: options.linkGroupId
180
218
  });
181
219
  },
182
220
  [
@@ -184,8 +222,7 @@ function useAnalytics(options) {
184
222
  options.enabled,
185
223
  options.bundleGid,
186
224
  options.bundleType,
187
- options.abTestId,
188
- options.abVariant
225
+ options.linkGroupId
189
226
  ]
190
227
  );
191
228
  return { elementRef, trackAddToCart };
@@ -1479,7 +1516,6 @@ import {
1479
1516
  mergeWidgetConfig,
1480
1517
  applyWidgetConfigVars as applyWidgetConfigVars2,
1481
1518
  thumbnailRatioVars,
1482
- applyABVariantB,
1483
1519
  parseCents,
1484
1520
  formatCents,
1485
1521
  percentageDiscountUnit,
@@ -1496,7 +1532,9 @@ import {
1496
1532
  reportImpression as reportImpression2,
1497
1533
  reportAddToCart as reportAddToCart2,
1498
1534
  observeImpression as observeImpression2,
1499
- getABTestAssignment,
1535
+ getLinkGroupAssignment,
1536
+ pickVariantFromWeights,
1537
+ fnv1a,
1500
1538
  setConsent,
1501
1539
  hasConsent,
1502
1540
  injectCustomCss as injectCustomCss3,
@@ -1520,7 +1558,6 @@ export {
1520
1558
  VariantDropdown,
1521
1559
  VolumeBundle,
1522
1560
  WIDGET_CONFIG_DEFAULTS,
1523
- applyABVariantB,
1524
1561
  applyWidgetConfigVars2 as applyWidgetConfigVars,
1525
1562
  calculateDiscount2 as calculateDiscount,
1526
1563
  calculateTierSavings2 as calculateTierSavings,
@@ -1530,12 +1567,13 @@ export {
1530
1567
  fetchBundleData,
1531
1568
  fetchBundlesForProduct2 as fetchBundlesForProduct,
1532
1569
  fetchShopCustomCss,
1570
+ fnv1a,
1533
1571
  formatCents,
1534
1572
  formatCountdown,
1535
1573
  formatMoney4 as formatMoney,
1536
1574
  formatUnitPrice4 as formatUnitPrice,
1537
- getABTestAssignment,
1538
1575
  getActiveTier2 as getActiveTier,
1576
+ getLinkGroupAssignment,
1539
1577
  hasConsent,
1540
1578
  injectCustomCss3 as injectCustomCss,
1541
1579
  mergeWidgetConfig,
@@ -1544,6 +1582,7 @@ export {
1544
1582
  parseMetaobjectBundle,
1545
1583
  parseMetaobjectBundleStrict2 as parseMetaobjectBundleStrict,
1546
1584
  percentageDiscountUnit,
1585
+ pickVariantFromWeights,
1547
1586
  reportAddToCart2 as reportAddToCart,
1548
1587
  reportImpression2 as reportImpression,
1549
1588
  sanitizeCustomCss,