@lime-bundles/widget 3.2.2 → 3.4.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 +19 -0
- package/dist/index.cjs +85 -23
- package/dist/index.cjs.map +1 -1
- package/dist/index.d.cts +88 -7
- package/dist/index.d.ts +88 -7
- package/dist/index.js +88 -25
- package/dist/index.js.map +1 -1
- package/dist/lime-bundle.global.js +18 -18
- package/dist/lime-bundle.global.js.map +1 -1
- package/docs/react-nextjs.md +14 -5
- package/docs/web-component.md +1 -1
- package/package.json +2 -2
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;
|
|
@@ -4246,7 +4294,7 @@ var LimeBundleElement = class extends HTMLElement {
|
|
|
4246
4294
|
const sanitized = (0, import_core8.sanitizeCustomCss)(css.shop.metafield.value);
|
|
4247
4295
|
if (sanitized.ok) this.shopCustomCss = sanitized.css;
|
|
4248
4296
|
}
|
|
4249
|
-
await this.
|
|
4297
|
+
await this.applyLinkGroupVariants();
|
|
4250
4298
|
this.renderBundles();
|
|
4251
4299
|
} catch (err) {
|
|
4252
4300
|
if (controller.signal.aborted) return;
|
|
@@ -4258,40 +4306,54 @@ var LimeBundleElement = class extends HTMLElement {
|
|
|
4258
4306
|
}
|
|
4259
4307
|
}
|
|
4260
4308
|
/**
|
|
4261
|
-
* Resolve the visitor's
|
|
4262
|
-
*
|
|
4263
|
-
*
|
|
4264
|
-
*
|
|
4265
|
-
*
|
|
4266
|
-
* the
|
|
4309
|
+
* Resolve the visitor's assigned variant for every primary bundle in a link
|
|
4310
|
+
* group. Runs in parallel; any assignment failure logs internally and still
|
|
4311
|
+
* renders the primary (safe default). The `getLinkGroupAssignment` helper
|
|
4312
|
+
* persists the bucket via a first-party cookie; variant attribution is
|
|
4313
|
+
* recorded server-side from the cart-line `_lime_bundle_gid` + `_lime_link_group`
|
|
4314
|
+
* attributes the cart-add path stamps when an assignment lands on a non-primary
|
|
4315
|
+
* variant.
|
|
4316
|
+
*
|
|
4317
|
+
* When the assignment points to a non-primary variant the SDK swaps in that
|
|
4318
|
+
* variant's `ParsedBundle` from the primary's `linkGroup.variants` list. The
|
|
4319
|
+
* variant data must already be present in the storefront query response — the
|
|
4320
|
+
* SDK does NOT issue a separate metaobject fetch on the hot path.
|
|
4267
4321
|
*/
|
|
4268
|
-
async
|
|
4322
|
+
async applyLinkGroupVariants() {
|
|
4269
4323
|
if (this.bundles.length === 0) return;
|
|
4324
|
+
const bundleLookupByMetaobjectId = /* @__PURE__ */ new Map();
|
|
4325
|
+
for (const b of this.bundles) {
|
|
4326
|
+
bundleLookupByMetaobjectId.set(b.id, b);
|
|
4327
|
+
}
|
|
4270
4328
|
const results = await Promise.all(
|
|
4271
4329
|
this.bundles.map(async (bundle) => {
|
|
4272
|
-
|
|
4330
|
+
const lg = bundle.linkGroup;
|
|
4331
|
+
if (!lg || !lg.isPrimary || !lg.variants || lg.variants.length < 2) {
|
|
4332
|
+
return bundle;
|
|
4333
|
+
}
|
|
4273
4334
|
try {
|
|
4274
|
-
const assignment = await (0, import_core8.
|
|
4275
|
-
|
|
4276
|
-
|
|
4335
|
+
const assignment = await (0, import_core8.getLinkGroupAssignment)(lg.id, lg.variants);
|
|
4336
|
+
if (!assignment) return bundle;
|
|
4337
|
+
if (assignment.variantMetaobjectId === bundle.id) return bundle;
|
|
4338
|
+
const swap = bundleLookupByMetaobjectId.get(
|
|
4339
|
+
assignment.variantMetaobjectId
|
|
4277
4340
|
);
|
|
4278
|
-
if (
|
|
4279
|
-
|
|
4280
|
-
}
|
|
4341
|
+
if (!swap) return bundle;
|
|
4342
|
+
return swap;
|
|
4281
4343
|
} catch (err) {
|
|
4282
4344
|
console.warn(
|
|
4283
|
-
`[lime-bundle]
|
|
4345
|
+
`[lime-bundle] link-group assignment failed for bundle ${bundle.id}; falling back to primary.`,
|
|
4284
4346
|
err
|
|
4285
4347
|
);
|
|
4348
|
+
return bundle;
|
|
4286
4349
|
}
|
|
4287
|
-
return bundle;
|
|
4288
4350
|
})
|
|
4289
4351
|
);
|
|
4290
4352
|
this.bundles = results;
|
|
4291
4353
|
}
|
|
4292
4354
|
async fetchSingleBundle(client, signal) {
|
|
4293
4355
|
const data = await client.query(
|
|
4294
|
-
import_core8.BUNDLE_METAOBJECT_QUERY,
|
|
4356
|
+
this.wrapQueryForContext(import_core8.BUNDLE_METAOBJECT_QUERY),
|
|
4295
4357
|
{ id: this.bundleGid },
|
|
4296
4358
|
{ signal }
|
|
4297
4359
|
);
|
|
@@ -4303,11 +4365,11 @@ var LimeBundleElement = class extends HTMLElement {
|
|
|
4303
4365
|
data.metaobject.id,
|
|
4304
4366
|
data.metaobject.fields
|
|
4305
4367
|
);
|
|
4306
|
-
this.bundles = parsed ? [parsed] : [];
|
|
4368
|
+
this.bundles = parsed && !this.isMarketHidden(parsed) ? [parsed] : [];
|
|
4307
4369
|
}
|
|
4308
4370
|
async fetchProductBundles(client, signal, productHandle) {
|
|
4309
4371
|
const data = await client.query(
|
|
4310
|
-
import_core8.BUNDLES_FOR_PRODUCT_QUERY,
|
|
4372
|
+
this.wrapQueryForContext(import_core8.BUNDLES_FOR_PRODUCT_QUERY),
|
|
4311
4373
|
{ handle: productHandle },
|
|
4312
4374
|
{ signal }
|
|
4313
4375
|
);
|
|
@@ -4319,7 +4381,7 @@ var LimeBundleElement = class extends HTMLElement {
|
|
|
4319
4381
|
const bundles = [];
|
|
4320
4382
|
for (const ref of refs) {
|
|
4321
4383
|
const parsed = (0, import_core8.parseMetaobjectBundle)(ref.id, ref.fields);
|
|
4322
|
-
if (parsed) bundles.push(parsed);
|
|
4384
|
+
if (parsed && !this.isMarketHidden(parsed)) bundles.push(parsed);
|
|
4323
4385
|
}
|
|
4324
4386
|
this.bundles = bundles;
|
|
4325
4387
|
}
|