@lime-bundles/widget 3.2.2 → 3.3.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
@@ -61,11 +61,30 @@ document.querySelector("lime-bundle").addEventListener(
61
61
  | `app-url` | | Enables impression + add-to-cart analytics when set. |
62
62
  | `analytics` | | `"false"` suppresses analytics even when `app-url` is set. |
63
63
  | `locale` | | BCP-47 tag forwarded to the Storefront API. |
64
+ | `country` | | ISO-3166 alpha-2 (e.g. `"US"`). Adds `@inContext(country:)` to Storefront queries — Markets pricing + currency. |
65
+ | `language` | | ISO-639-1 (e.g. `"EN"`). Adds `@inContext(language:)`. |
66
+ | `market-id` | | Current visitor's Market GID. Hides market-restricted bundles whose allow-list doesn't include this market. |
64
67
 
65
68
  **Product resolution** (when `bundle-gid` is absent): explicit `product-handle` → `<meta name="shopify:product-handle">` → `/products/<handle>` URL segment.
66
69
 
67
70
  Changing any attribute at runtime re-fetches and re-renders.
68
71
 
72
+ ### B2B buyer identity (programmatic property only)
73
+
74
+ `buyer` is **not** an HTML attribute. Set it on the element after creation so the customer access token never lands in DOM-snapshot tools (Sentry, analytics, browser extensions) or Referer headers:
75
+
76
+ ```js
77
+ const el = document.querySelector("lime-bundle");
78
+ el.buyer = async () => {
79
+ // Resolved per request — no token in static markup
80
+ return { customerAccessToken: await fetchToken(), companyLocationId: "gid://shopify/CompanyLocation/9" };
81
+ };
82
+ ```
83
+
84
+ The Customer Account API PKCE flow is the canonical token source. See https://shopify.dev/docs/api/customer/latest.
85
+
86
+ Buyer-contextual Storefront responses MUST be `Cache-Control: private` — never share across users.
87
+
69
88
  ## Events
70
89
 
71
90
  All events bubble and pierce shadow-DOM boundaries (`composed: true`), so you can listen on any ancestor.
package/dist/index.cjs CHANGED
@@ -4130,8 +4130,19 @@ var LimeBundleElement = class extends HTMLElement {
4130
4130
  "product-handle",
4131
4131
  "app-url",
4132
4132
  "analytics",
4133
- "locale"
4133
+ "locale",
4134
+ "country",
4135
+ "language",
4136
+ "market-id"
4134
4137
  ];
4138
+ /**
4139
+ * B2B buyer identity. Set programmatically — `element.buyer = {...}` or
4140
+ * `element.buyer = () => fetchToken()`. NEVER expose as an HTML attribute
4141
+ * because the customer access token would land in DOM snapshots (Sentry,
4142
+ * analytics, browser extensions) and Referer headers. See the package
4143
+ * README ("Markets & B2B").
4144
+ */
4145
+ buyer = void 0;
4135
4146
  shadow;
4136
4147
  bundles = [];
4137
4148
  abortController = null;
@@ -4194,6 +4205,40 @@ var LimeBundleElement = class extends HTMLElement {
4194
4205
  get analyticsEnabled() {
4195
4206
  return this.getAttribute("analytics") !== "false";
4196
4207
  }
4208
+ get country() {
4209
+ return this.getAttribute("country") ?? void 0;
4210
+ }
4211
+ get language() {
4212
+ return this.getAttribute("language") ?? void 0;
4213
+ }
4214
+ get marketId() {
4215
+ return this.getAttribute("market-id") ?? void 0;
4216
+ }
4217
+ /**
4218
+ * Returns the @inContext-wrapped query when any context field is set;
4219
+ * otherwise the plain query. Keeps responses publicly cacheable when
4220
+ * no buyer/country/language is set.
4221
+ */
4222
+ wrapQueryForContext(query) {
4223
+ return (0, import_core8.hasInContext)({
4224
+ shopDomain: this.shopDomain,
4225
+ accessToken: this.storefrontToken,
4226
+ country: this.country,
4227
+ language: this.language,
4228
+ buyer: this.buyer
4229
+ }) ? (0, import_core8.withInContext)(query) : query;
4230
+ }
4231
+ /**
4232
+ * Returns true if this bundle should be hidden for the current market.
4233
+ * For "all" bundles, always returns false (visible). For "specific"
4234
+ * bundles, returns true when no marketId was set or when the bundle's
4235
+ * marketIds doesn't include the configured market.
4236
+ */
4237
+ isMarketHidden(bundle) {
4238
+ if (bundle.marketVisibility !== "specific") return false;
4239
+ if (!this.marketId) return true;
4240
+ return !bundle.marketIds.includes(this.marketId);
4241
+ }
4197
4242
  async fetchBundle() {
4198
4243
  if (!this.shopDomain || !this.storefrontToken) {
4199
4244
  this.renderError(
@@ -4207,7 +4252,10 @@ var LimeBundleElement = class extends HTMLElement {
4207
4252
  this.renderLoading();
4208
4253
  const client = (0, import_core8.createStorefrontClient)({
4209
4254
  shopDomain: this.shopDomain,
4210
- accessToken: this.storefrontToken
4255
+ accessToken: this.storefrontToken,
4256
+ country: this.country,
4257
+ language: this.language,
4258
+ buyer: this.buyer
4211
4259
  });
4212
4260
  try {
4213
4261
  let bundlePromise;
@@ -4291,7 +4339,7 @@ var LimeBundleElement = class extends HTMLElement {
4291
4339
  }
4292
4340
  async fetchSingleBundle(client, signal) {
4293
4341
  const data = await client.query(
4294
- import_core8.BUNDLE_METAOBJECT_QUERY,
4342
+ this.wrapQueryForContext(import_core8.BUNDLE_METAOBJECT_QUERY),
4295
4343
  { id: this.bundleGid },
4296
4344
  { signal }
4297
4345
  );
@@ -4303,11 +4351,11 @@ var LimeBundleElement = class extends HTMLElement {
4303
4351
  data.metaobject.id,
4304
4352
  data.metaobject.fields
4305
4353
  );
4306
- this.bundles = parsed ? [parsed] : [];
4354
+ this.bundles = parsed && !this.isMarketHidden(parsed) ? [parsed] : [];
4307
4355
  }
4308
4356
  async fetchProductBundles(client, signal, productHandle) {
4309
4357
  const data = await client.query(
4310
- import_core8.BUNDLES_FOR_PRODUCT_QUERY,
4358
+ this.wrapQueryForContext(import_core8.BUNDLES_FOR_PRODUCT_QUERY),
4311
4359
  { handle: productHandle },
4312
4360
  { signal }
4313
4361
  );
@@ -4319,7 +4367,7 @@ var LimeBundleElement = class extends HTMLElement {
4319
4367
  const bundles = [];
4320
4368
  for (const ref of refs) {
4321
4369
  const parsed = (0, import_core8.parseMetaobjectBundle)(ref.id, ref.fields);
4322
- if (parsed) bundles.push(parsed);
4370
+ if (parsed && !this.isMarketHidden(parsed)) bundles.push(parsed);
4323
4371
  }
4324
4372
  this.bundles = bundles;
4325
4373
  }