@lime-bundles/widget 4.5.1 → 4.6.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/README.md CHANGED
@@ -62,9 +62,12 @@ document.querySelector("lime-bundle").addEventListener(
62
62
  | `app-url` | | Enables impression + add-to-cart analytics when set. |
63
63
  | `analytics` | | `"false"` suppresses analytics even when `app-url` is set. |
64
64
  | `locale` | | BCP-47 tag forwarded to the Storefront API. |
65
- | `country` | | ISO-3166 alpha-2 (e.g. `"US"`). Adds `@inContext(country:)` to Storefront queries — Markets pricing + currency. |
65
+ | `country` | | ISO-3166 alpha-2 (e.g. `"US"`). Adds `@inContext(country:)` to Storefront queries — Markets pricing + currency — and matches market-restricted bundles' projected country codes. |
66
66
  | `language` | | ISO-639-1 (e.g. `"EN"`). Adds `@inContext(language:)`. |
67
- | `market-id` | | Current visitor's Market GID. Hides market-restricted bundles whose allow-list doesn't include this market. |
67
+ | `market-id` | | Current visitor's Market GID. Legacy market-gate signal; prefer `country` (retail) and the `buyer` property (B2B) — a B2B buyer's company-location market has no storefront market context. |
68
+ | `currency-rate` | | Store→presentment currency rate. Merchant-configured amounts (fixed-amount discounts, flat prices, volume tier amounts) are stored in the shop's store currency; on a "local currencies" market, pass the buyer's rate (on a Liquid-adjacent page, `window.Shopify.currency.rate`) so quoted sale prices match what checkout charges. Defaults to `1` (no conversion); invalid or non-positive values also fall back to `1`. Percentages are unaffected. |
69
+
70
+ A market-restricted bundle renders when any signal matches: `country` vs the bundle's projected country codes, the resolved `buyer` property's `companyLocationId` vs its projected company locations, or `market-id` vs its market allow-list.
68
71
 
69
72
  **Product resolution** (when `bundle-gid` is absent): explicit `product-handle` → `<meta name="shopify:product-handle">` → `/products/<handle>` URL segment.
70
73
 
package/dist/index.cjs CHANGED
@@ -7212,7 +7212,8 @@ var LimeBundleElement = class extends HTMLElement {
7212
7212
  "locale",
7213
7213
  "country",
7214
7214
  "language",
7215
- "market-id"
7215
+ "market-id",
7216
+ "currency-rate"
7216
7217
  ];
7217
7218
  /**
7218
7219
  * B2B buyer identity. Set programmatically — `element.buyer = {...}` or
@@ -7267,7 +7268,7 @@ var LimeBundleElement = class extends HTMLElement {
7267
7268
  }
7268
7269
  attributeChangedCallback(name, oldValue, newValue) {
7269
7270
  if (oldValue === newValue || !this.isConnected) return;
7270
- if (name === "bundle-gid" || name === "product-handle" || name === "product-id" || name === "shop-domain" || name === "storefront-token") {
7271
+ if (name === "bundle-gid" || name === "product-handle" || name === "product-id" || name === "shop-domain" || name === "storefront-token" || name === "currency-rate") {
7271
7272
  if (this.shopDomain && this.storefrontToken) {
7272
7273
  this.fetchBundle();
7273
7274
  }
@@ -7310,6 +7311,17 @@ var LimeBundleElement = class extends HTMLElement {
7310
7311
  get marketId() {
7311
7312
  return this.getAttribute("market-id") ?? void 0;
7312
7313
  }
7314
+ /**
7315
+ * Store→presentment currency rate. Merchant-configured amounts
7316
+ * (fixed_amount / flat_price values, volume tier amounts) are stored in
7317
+ * the shop's store currency; set this to the buyer's currency rate so
7318
+ * quoted sale prices match what the checkout's discount function
7319
+ * charges. Anything unparseable or non-positive falls back to 1 —
7320
+ * no conversion — via `normalizeCurrencyRate`.
7321
+ */
7322
+ get currencyRate() {
7323
+ return this.getAttribute("currency-rate") ?? void 0;
7324
+ }
7313
7325
  /**
7314
7326
  * Returns the @inContext-wrapped query when any context field is set;
7315
7327
  * otherwise the plain query. Keeps responses publicly cacheable when
@@ -7324,14 +7336,23 @@ var LimeBundleElement = class extends HTMLElement {
7324
7336
  buyer: this.buyer
7325
7337
  }) ? (0, import_core6.withInContext)(query) : query;
7326
7338
  }
7339
+ /** Buyer resolved once per fetch so the market gate can read the
7340
+ * company location without invoking a callback resolver twice. */
7341
+ resolvedBuyer = void 0;
7327
7342
  /**
7328
- * Returns true if this bundle should be hidden for the current market.
7343
+ * Returns true if this bundle should be hidden for the current buyer.
7329
7344
  * For "all" bundles, always returns false (visible). For "specific"
7330
- * bundles, returns true when no marketId was set or when the bundle's
7331
- * marketIds doesn't include the configured market.
7345
+ * bundles, visibility needs a matching signal: the `country` attribute
7346
+ * against the bundle's projected country codes (retail markets), the
7347
+ * resolved buyer's companyLocationId against its projected company
7348
+ * locations (B2B markets), or a legacy `market-id` match.
7332
7349
  */
7333
7350
  isMarketHidden(bundle) {
7334
- return !(0, import_core6.isVisibleInMarket)(bundle, this.marketId);
7351
+ return !(0, import_core6.isVisibleToBuyer)(bundle, {
7352
+ marketId: this.marketId,
7353
+ countryCode: this.country,
7354
+ companyLocationId: this.resolvedBuyer?.companyLocationId
7355
+ });
7335
7356
  }
7336
7357
  async fetchBundle() {
7337
7358
  if (!this.shopDomain || !this.storefrontToken) {
@@ -7344,12 +7365,17 @@ var LimeBundleElement = class extends HTMLElement {
7344
7365
  const controller = new AbortController();
7345
7366
  this.abortController = controller;
7346
7367
  this.renderLoading();
7368
+ try {
7369
+ this.resolvedBuyer = typeof this.buyer === "function" ? await this.buyer() : this.buyer;
7370
+ } catch {
7371
+ this.resolvedBuyer = void 0;
7372
+ }
7347
7373
  const client = (0, import_core6.createStorefrontClient)({
7348
7374
  shopDomain: this.shopDomain,
7349
7375
  accessToken: this.storefrontToken,
7350
7376
  country: this.country,
7351
7377
  language: this.language,
7352
- buyer: this.buyer
7378
+ buyer: this.resolvedBuyer
7353
7379
  });
7354
7380
  try {
7355
7381
  let bundlePromise;
@@ -7414,7 +7440,7 @@ var LimeBundleElement = class extends HTMLElement {
7414
7440
  data.metaobject.id,
7415
7441
  data.metaobject.fields
7416
7442
  );
7417
- this.bundles = parsed && !this.isMarketHidden(parsed) ? [parsed] : [];
7443
+ this.bundles = parsed && !this.isMarketHidden(parsed) ? [(0, import_core6.convertBundleToPresentment)(parsed, this.currencyRate)] : [];
7418
7444
  }
7419
7445
  async fetchProductBundles(client, signal, productHandle) {
7420
7446
  const data = await client.query(
@@ -7430,7 +7456,9 @@ var LimeBundleElement = class extends HTMLElement {
7430
7456
  const bundles = [];
7431
7457
  for (const ref of refs) {
7432
7458
  const parsed = (0, import_core6.parseMetaobjectBundle)(ref.id, ref.fields);
7433
- if (parsed && !this.isMarketHidden(parsed)) bundles.push(parsed);
7459
+ if (parsed && !this.isMarketHidden(parsed)) {
7460
+ bundles.push((0, import_core6.convertBundleToPresentment)(parsed, this.currencyRate));
7461
+ }
7434
7462
  }
7435
7463
  this.bundles = (0, import_core6.resolveAbTests)(bundles, (0, import_core6.getVisitorId)());
7436
7464
  }
package/dist/index.d.cts CHANGED
@@ -109,17 +109,31 @@ declare class LimeBundleElement extends HTMLElement {
109
109
  private get country();
110
110
  private get language();
111
111
  private get marketId();
112
+ /**
113
+ * Store→presentment currency rate. Merchant-configured amounts
114
+ * (fixed_amount / flat_price values, volume tier amounts) are stored in
115
+ * the shop's store currency; set this to the buyer's currency rate so
116
+ * quoted sale prices match what the checkout's discount function
117
+ * charges. Anything unparseable or non-positive falls back to 1 —
118
+ * no conversion — via `normalizeCurrencyRate`.
119
+ */
120
+ private get currencyRate();
112
121
  /**
113
122
  * Returns the @inContext-wrapped query when any context field is set;
114
123
  * otherwise the plain query. Keeps responses publicly cacheable when
115
124
  * no buyer/country/language is set.
116
125
  */
117
126
  private wrapQueryForContext;
127
+ /** Buyer resolved once per fetch so the market gate can read the
128
+ * company location without invoking a callback resolver twice. */
129
+ private resolvedBuyer;
118
130
  /**
119
- * Returns true if this bundle should be hidden for the current market.
131
+ * Returns true if this bundle should be hidden for the current buyer.
120
132
  * For "all" bundles, always returns false (visible). For "specific"
121
- * bundles, returns true when no marketId was set or when the bundle's
122
- * marketIds doesn't include the configured market.
133
+ * bundles, visibility needs a matching signal: the `country` attribute
134
+ * against the bundle's projected country codes (retail markets), the
135
+ * resolved buyer's companyLocationId against its projected company
136
+ * locations (B2B markets), or a legacy `market-id` match.
123
137
  */
124
138
  private isMarketHidden;
125
139
  private fetchBundle;
package/dist/index.d.ts CHANGED
@@ -109,17 +109,31 @@ declare class LimeBundleElement extends HTMLElement {
109
109
  private get country();
110
110
  private get language();
111
111
  private get marketId();
112
+ /**
113
+ * Store→presentment currency rate. Merchant-configured amounts
114
+ * (fixed_amount / flat_price values, volume tier amounts) are stored in
115
+ * the shop's store currency; set this to the buyer's currency rate so
116
+ * quoted sale prices match what the checkout's discount function
117
+ * charges. Anything unparseable or non-positive falls back to 1 —
118
+ * no conversion — via `normalizeCurrencyRate`.
119
+ */
120
+ private get currencyRate();
112
121
  /**
113
122
  * Returns the @inContext-wrapped query when any context field is set;
114
123
  * otherwise the plain query. Keeps responses publicly cacheable when
115
124
  * no buyer/country/language is set.
116
125
  */
117
126
  private wrapQueryForContext;
127
+ /** Buyer resolved once per fetch so the market gate can read the
128
+ * company location without invoking a callback resolver twice. */
129
+ private resolvedBuyer;
118
130
  /**
119
- * Returns true if this bundle should be hidden for the current market.
131
+ * Returns true if this bundle should be hidden for the current buyer.
120
132
  * For "all" bundles, always returns false (visible). For "specific"
121
- * bundles, returns true when no marketId was set or when the bundle's
122
- * marketIds doesn't include the configured market.
133
+ * bundles, visibility needs a matching signal: the `country` attribute
134
+ * against the bundle's projected country codes (retail markets), the
135
+ * resolved buyer's companyLocationId against its projected company
136
+ * locations (B2B markets), or a legacy `market-id` match.
123
137
  */
124
138
  private isMarketHidden;
125
139
  private fetchBundle;
package/dist/index.js CHANGED
@@ -9,6 +9,7 @@ import {
9
9
  CART_LINES_REMOVE_MUTATION,
10
10
  SHOP_SETTINGS_QUERY,
11
11
  parseMetaobjectBundle,
12
+ convertBundleToPresentment,
12
13
  observeImpression,
13
14
  reportImpression,
14
15
  reportAddToCart,
@@ -16,7 +17,7 @@ import {
16
17
  sanitizeCustomCss,
17
18
  hasInContext,
18
19
  withInContext,
19
- isVisibleInMarket,
20
+ isVisibleToBuyer,
20
21
  getVisitorId,
21
22
  resolveAbTests
22
23
  } from "@lime-bundles/core";
@@ -7220,7 +7221,8 @@ var LimeBundleElement = class extends HTMLElement {
7220
7221
  "locale",
7221
7222
  "country",
7222
7223
  "language",
7223
- "market-id"
7224
+ "market-id",
7225
+ "currency-rate"
7224
7226
  ];
7225
7227
  /**
7226
7228
  * B2B buyer identity. Set programmatically — `element.buyer = {...}` or
@@ -7275,7 +7277,7 @@ var LimeBundleElement = class extends HTMLElement {
7275
7277
  }
7276
7278
  attributeChangedCallback(name, oldValue, newValue) {
7277
7279
  if (oldValue === newValue || !this.isConnected) return;
7278
- if (name === "bundle-gid" || name === "product-handle" || name === "product-id" || name === "shop-domain" || name === "storefront-token") {
7280
+ if (name === "bundle-gid" || name === "product-handle" || name === "product-id" || name === "shop-domain" || name === "storefront-token" || name === "currency-rate") {
7279
7281
  if (this.shopDomain && this.storefrontToken) {
7280
7282
  this.fetchBundle();
7281
7283
  }
@@ -7318,6 +7320,17 @@ var LimeBundleElement = class extends HTMLElement {
7318
7320
  get marketId() {
7319
7321
  return this.getAttribute("market-id") ?? void 0;
7320
7322
  }
7323
+ /**
7324
+ * Store→presentment currency rate. Merchant-configured amounts
7325
+ * (fixed_amount / flat_price values, volume tier amounts) are stored in
7326
+ * the shop's store currency; set this to the buyer's currency rate so
7327
+ * quoted sale prices match what the checkout's discount function
7328
+ * charges. Anything unparseable or non-positive falls back to 1 —
7329
+ * no conversion — via `normalizeCurrencyRate`.
7330
+ */
7331
+ get currencyRate() {
7332
+ return this.getAttribute("currency-rate") ?? void 0;
7333
+ }
7321
7334
  /**
7322
7335
  * Returns the @inContext-wrapped query when any context field is set;
7323
7336
  * otherwise the plain query. Keeps responses publicly cacheable when
@@ -7332,14 +7345,23 @@ var LimeBundleElement = class extends HTMLElement {
7332
7345
  buyer: this.buyer
7333
7346
  }) ? withInContext(query) : query;
7334
7347
  }
7348
+ /** Buyer resolved once per fetch so the market gate can read the
7349
+ * company location without invoking a callback resolver twice. */
7350
+ resolvedBuyer = void 0;
7335
7351
  /**
7336
- * Returns true if this bundle should be hidden for the current market.
7352
+ * Returns true if this bundle should be hidden for the current buyer.
7337
7353
  * For "all" bundles, always returns false (visible). For "specific"
7338
- * bundles, returns true when no marketId was set or when the bundle's
7339
- * marketIds doesn't include the configured market.
7354
+ * bundles, visibility needs a matching signal: the `country` attribute
7355
+ * against the bundle's projected country codes (retail markets), the
7356
+ * resolved buyer's companyLocationId against its projected company
7357
+ * locations (B2B markets), or a legacy `market-id` match.
7340
7358
  */
7341
7359
  isMarketHidden(bundle) {
7342
- return !isVisibleInMarket(bundle, this.marketId);
7360
+ return !isVisibleToBuyer(bundle, {
7361
+ marketId: this.marketId,
7362
+ countryCode: this.country,
7363
+ companyLocationId: this.resolvedBuyer?.companyLocationId
7364
+ });
7343
7365
  }
7344
7366
  async fetchBundle() {
7345
7367
  if (!this.shopDomain || !this.storefrontToken) {
@@ -7352,12 +7374,17 @@ var LimeBundleElement = class extends HTMLElement {
7352
7374
  const controller = new AbortController();
7353
7375
  this.abortController = controller;
7354
7376
  this.renderLoading();
7377
+ try {
7378
+ this.resolvedBuyer = typeof this.buyer === "function" ? await this.buyer() : this.buyer;
7379
+ } catch {
7380
+ this.resolvedBuyer = void 0;
7381
+ }
7355
7382
  const client = createStorefrontClient({
7356
7383
  shopDomain: this.shopDomain,
7357
7384
  accessToken: this.storefrontToken,
7358
7385
  country: this.country,
7359
7386
  language: this.language,
7360
- buyer: this.buyer
7387
+ buyer: this.resolvedBuyer
7361
7388
  });
7362
7389
  try {
7363
7390
  let bundlePromise;
@@ -7422,7 +7449,7 @@ var LimeBundleElement = class extends HTMLElement {
7422
7449
  data.metaobject.id,
7423
7450
  data.metaobject.fields
7424
7451
  );
7425
- this.bundles = parsed && !this.isMarketHidden(parsed) ? [parsed] : [];
7452
+ this.bundles = parsed && !this.isMarketHidden(parsed) ? [convertBundleToPresentment(parsed, this.currencyRate)] : [];
7426
7453
  }
7427
7454
  async fetchProductBundles(client, signal, productHandle) {
7428
7455
  const data = await client.query(
@@ -7438,7 +7465,9 @@ var LimeBundleElement = class extends HTMLElement {
7438
7465
  const bundles = [];
7439
7466
  for (const ref of refs) {
7440
7467
  const parsed = parseMetaobjectBundle(ref.id, ref.fields);
7441
- if (parsed && !this.isMarketHidden(parsed)) bundles.push(parsed);
7468
+ if (parsed && !this.isMarketHidden(parsed)) {
7469
+ bundles.push(convertBundleToPresentment(parsed, this.currencyRate));
7470
+ }
7442
7471
  }
7443
7472
  this.bundles = resolveAbTests(bundles, getVisitorId());
7444
7473
  }