@vio-live/web-sdk 0.32.0 → 0.33.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/CHANGELOG.md +48 -0
- package/README.md +19 -4
- package/dist/{chunk-C5Q6W4B2.js → chunk-T5B74YBQ.js} +46 -8
- package/dist/chunk-T5B74YBQ.js.map +1 -0
- package/dist/{chunk-IR4XYTZL.js → chunk-ZORYG4W3.js} +668 -98
- package/dist/chunk-ZORYG4W3.js.map +1 -0
- package/dist/core/index.d.ts +759 -568
- package/dist/core/index.js +1 -1
- package/dist/index.js +1 -1
- package/dist/react/index.d.ts +2 -2
- package/dist/react/index.js +3 -3
- package/dist/{tokens-D1DCVzOf.d.ts → tokens-B7GVA_qB.d.ts} +14 -0
- package/dist/ui/index.d.ts +1 -1
- package/dist/ui/index.js +3 -3
- package/package.json +1 -1
- package/dist/chunk-C5Q6W4B2.js.map +0 -1
- package/dist/chunk-IR4XYTZL.js.map +0 -1
package/CHANGELOG.md
CHANGED
|
@@ -14,6 +14,54 @@ How to keep this file: see [CONTRIBUTING → Changelog](CONTRIBUTING.md#changelo
|
|
|
14
14
|
The details of each feature live in the [README](README.md); this file says *what*
|
|
15
15
|
and *when*, and links there.
|
|
16
16
|
|
|
17
|
+
## 0.33.0 — 2026-10-28
|
|
18
|
+
|
|
19
|
+
### Fixed
|
|
20
|
+
- **One cart per connection.** Every connection of a site (environment + key) shared one stored
|
|
21
|
+
cart, and every tab adopted what the others wrote: two tabs on two connections (Staging and Prod
|
|
22
|
+
side by side) could take each other's cart for a moment. Each connection now keeps its own
|
|
23
|
+
(`vio.cart.v1:<environment>:<hash of the key>` — never the key itself), a tab only listens to
|
|
24
|
+
its own, and `Vio.init` with another key switches `Vio.cart` to that connection's carts (the
|
|
25
|
+
first one's come back if the page switches back). An answer that arrives for the connection the
|
|
26
|
+
page left lands in that connection's cart, silently — never in the new one.
|
|
27
|
+
- **The commerce key is the channel of the article's campaign, not the sponsor's first block.**
|
|
28
|
+
With two campaigns of one sponsor on a surface (Careless: campaign 2 on channel 482, an internal
|
|
29
|
+
test campaign 1 on channel 480), products, carts and checkouts used the default campaign's
|
|
30
|
+
channel even for an article of the other. The key now follows the campaign in context (the
|
|
31
|
+
click's `campaignId`, `vio-campaign`, `data-vio-campaign`, `Vio.init`'s), among the sponsor's
|
|
32
|
+
blocks (a block with `commerce: null` is skipped instead of throwing). `Vio.commerceFor(sponsorId)`
|
|
33
|
+
still works and takes an optional `{ campaignId?, channelId? }`; commerce clients are kept per
|
|
34
|
+
sponsor and key. New: `Vio.sponsorCommerce(sponsorId, ctx?)`.
|
|
35
|
+
- **A cart remembers its channel.** `SponsorCartState.channelId` is stored when the backend cart is
|
|
36
|
+
created, and every later cart and checkout call for it (also the return from Vipps / Stripe,
|
|
37
|
+
through the per-checkout memory) uses that channel's key. If the bootstrap no longer lists the
|
|
38
|
+
channel, the stale `cartId` is dropped and the cart is created again on the current channel with
|
|
39
|
+
its lines — never a call with another channel's key. Carts from before keep the sponsor's first
|
|
40
|
+
block, as when they were created.
|
|
41
|
+
- **The order's campaign belongs to the cart's sponsor.** `attribution.campaign_id` on the checkout
|
|
42
|
+
and `campaignId` on `vio:checkout-created` (→ `add_payment_info`) took the page's campaign even
|
|
43
|
+
when it was another sponsor's. Now: the campaign the cart's lines were added from, else the
|
|
44
|
+
page's (`data-vio-campaign` / `vio-campaign` on the page, then `Vio.init`'s) only when the sponsor
|
|
45
|
+
takes part in it, else the slices' rule — only campaigns of that sponsor.
|
|
46
|
+
- **The bootstrap no longer lives for the whole page.** When the tab becomes visible again and the
|
|
47
|
+
cached bootstrap is older than 5 minutes, it is fetched again (the old one stays until the new
|
|
48
|
+
one arrives, and if the refresh fails). Carts keep their lines; an open checkout keeps paying
|
|
49
|
+
with its channel's key.
|
|
50
|
+
- **«Frakt & retur» no longer shows filler as the delivery time.** A rate's description equal to
|
|
51
|
+
its own name (dashboard-created rates copied it), `By Outshifter` or `Default Shipping Method`
|
|
52
|
+
(products' defaults) is no description in `getShippingRates`; the detail also drops one equal
|
|
53
|
+
to the product's title or the brand / seller name.
|
|
54
|
+
|
|
55
|
+
### ⚠️ Upgrade notes
|
|
56
|
+
- **Hosts with several articles (Replit, Vev):** pass `sponsorId` **and** `campaignId` on
|
|
57
|
+
`vio:product-click`, set `data-vio-campaign` on each article's wrapper, and do **not** set a
|
|
58
|
+
site-wide `Vio.init({ campaignId })` — the campaign in context decides which channel sells.
|
|
59
|
+
- The carts kept in the old shared entry move, once, to the first connection that opens with none
|
|
60
|
+
of its own. Nothing to do.
|
|
61
|
+
- `Vio.cart` is the same object for the whole page, so listeners added to it keep working across a
|
|
62
|
+
re-init. A host that archived and restored carts per connection itself (Replit's
|
|
63
|
+
`vioCartConnections`) can rely on this instead.
|
|
64
|
+
|
|
17
65
|
## 0.32.0 — 2026-10-28
|
|
18
66
|
|
|
19
67
|
> First version published to npm since 0.29.0: **0.30.0 and 0.31.0 were never published on their own** — their
|
package/README.md
CHANGED
|
@@ -226,7 +226,7 @@ a campaign to a slot. But an editorial page — a Vev article, a Replit article
|
|
|
226
226
|
often *is* part of one campaign, and the page can say so:
|
|
227
227
|
|
|
228
228
|
```ts
|
|
229
|
-
Vio.init({ apiKey: '…', campaignId: 12 }) // the whole page
|
|
229
|
+
Vio.init({ apiKey: '…', campaignId: 12 }) // the whole page — only on a page of ONE campaign
|
|
230
230
|
```
|
|
231
231
|
|
|
232
232
|
```html
|
|
@@ -243,6 +243,19 @@ ancestors. On web/Replit a **per-article** campaign needs a per-article scope to
|
|
|
243
243
|
same `carousel-1`, and the articles' campaigns would overwrite one another's
|
|
244
244
|
assignment; Vev ids are per block, so it does not apply there. What it does:
|
|
245
245
|
|
|
246
|
+
- **Which channel sells.** One article = one campaign = one channel = one
|
|
247
|
+
sponsor, and one sponsor may run several campaigns on a surface, each on its own
|
|
248
|
+
commerce channel. The SDK reads products, creates the cart and pays with the key
|
|
249
|
+
of the channel of the **campaign in context** — the click's `campaignId`, the
|
|
250
|
+
element's `vio-campaign`, an ancestor's `data-vio-campaign`, then `Vio.init`'s —
|
|
251
|
+
among the blocks of that sponsor (`Vio.sponsorCommerce(sponsorId, { campaignId })`,
|
|
252
|
+
`Vio.commerceFor(sponsorId, { campaignId })`); without one, the sponsor's first
|
|
253
|
+
block, as before. A cart remembers the channel it was created on (`channelId`)
|
|
254
|
+
and every later cart and checkout call uses that channel's key; if the bootstrap
|
|
255
|
+
no longer lists that channel, the cart is created again on the current one with
|
|
256
|
+
its lines. So on a site with several articles (Replit, Vev), **set
|
|
257
|
+
`data-vio-campaign` per article and pass `sponsorId` and `campaignId` on
|
|
258
|
+
`vio:product-click`; do not set a site-wide `Vio.init({ campaignId })`.**
|
|
246
259
|
- **Declaration.** The manifest carries the page's campaign (top-level) and an
|
|
247
260
|
element's own campaign per location when it differs. The campaigns service
|
|
248
261
|
(campaigns micro PR #16) turns that into assignments of the page's slots
|
|
@@ -372,9 +385,11 @@ Since 0.26 the origins do not stay in the browser: **Commerce receives them**
|
|
|
372
385
|
- **Per checkout.** `CreateCheckout` and the `UpdateCheckout` right before paying
|
|
373
386
|
carry `attribution`: `surface_key` (the SDK key — the gateway sets it from
|
|
374
387
|
`X-API-Key` anyway, and shopcart checks it against the cart's channel, so a page
|
|
375
|
-
cannot credit a sale to another surface), `campaign_id` (
|
|
376
|
-
|
|
377
|
-
the
|
|
388
|
+
cannot credit a sale to another surface), `campaign_id` (always a campaign the
|
|
389
|
+
cart's sponsor takes part in: the campaign the cart's lines were added from, else
|
|
390
|
+
the page's — `data-vio-campaign` / `vio-campaign` on the page, then `Vio.init`'s —
|
|
391
|
+
else the campaign that explains most units of the cart under the same rule
|
|
392
|
+
`purchase` is split by), `content_url` / `content_title` (the page at
|
|
378
393
|
pay time) and `entry` (`{ referrer, utm_source, utm_medium, utm_campaign,
|
|
379
394
|
landing_url }`: the landing the session **remembers** — the same memory the
|
|
380
395
|
`client` block reads, which now keeps the landing page too — never the page the
|
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import { Vio, __decorateClass, primaryImageUrl, displayPrice, toCampaignId, getGlobalCurrency, ensureVippsButton, formatPrice, buyerRefOf, nexiReturnPaymentId, readNexiPending, kustomReturnOutcome, KUSTOM_RETURN_QUERY_KEYS, storageGet, ADYEN_RETURN_METHOD, adyenReturnParams, ADYEN_RETURN_QUERY_KEYS, adyenReturnOutcome, getGlobalCountryCode, isValidPhone, gatewayHasBuyerRef, rememberedCheckoutSponsor, checkoutSponsorOf, AdyenOriginError, normalizeSlotId, autoSlotDisplayName, autoSlotId, sponsorIdentityFrom, Configuration, normalizeScope, campaignCandidates } from './chunk-
|
|
1
|
+
import { Vio, __decorateClass, primaryImageUrl, displayPrice, toCampaignId, getGlobalCurrency, ensureVippsButton, formatPrice, shippingDescriptionOf, buyerRefOf, nexiReturnPaymentId, readNexiPending, kustomReturnOutcome, KUSTOM_RETURN_QUERY_KEYS, storageGet, ADYEN_RETURN_METHOD, adyenReturnParams, ADYEN_RETURN_QUERY_KEYS, adyenReturnOutcome, getGlobalCountryCode, isValidPhone, gatewayHasBuyerRef, rememberedCheckoutSponsor, checkoutSponsorOf, AdyenOriginError, normalizeSlotId, autoSlotDisplayName, autoSlotId, sponsorIdentityFrom, Configuration, normalizeScope, campaignCandidates } from './chunk-ZORYG4W3.js';
|
|
2
2
|
import { LitElement, css, html, nothing } from 'lit';
|
|
3
3
|
import { property, state, query } from 'lit/decorators.js';
|
|
4
4
|
|
|
@@ -1151,6 +1151,21 @@ var VioProductCarousel = class extends LitElement {
|
|
|
1151
1151
|
* sponsor of the campaign the slot shows (ADR-0034 — "the campaign of the
|
|
1152
1152
|
* block is its sponsor"), else 0 (unknown).
|
|
1153
1153
|
*/
|
|
1154
|
+
/**
|
|
1155
|
+
* The campaign whose channel sells a sponsor's products here (one article =
|
|
1156
|
+
* one campaign = one channel): the campaign this slot credits for that
|
|
1157
|
+
* sponsor (`Vio.attribution`), then the element's own (`vio-campaign`, an
|
|
1158
|
+
* ancestor's `data-vio-campaign`).
|
|
1159
|
+
*/
|
|
1160
|
+
commerceCampaigns(sponsorId) {
|
|
1161
|
+
const own = this.slotRegistration.campaignHint;
|
|
1162
|
+
try {
|
|
1163
|
+
const resolved = typeof Vio.attribution === "function" ? Vio.attribution(this.effectiveSlot || null, { sponsorId, campaignId: own }).campaignId : void 0;
|
|
1164
|
+
return resolved !== void 0 ? [resolved, ...own] : own;
|
|
1165
|
+
} catch {
|
|
1166
|
+
return own;
|
|
1167
|
+
}
|
|
1168
|
+
}
|
|
1154
1169
|
effectiveSponsorId() {
|
|
1155
1170
|
if (this.sponsorId > 0) return this.sponsorId;
|
|
1156
1171
|
const fromSlot = typeof Vio.campaignForSlot === "function" ? Number(Vio.campaignForSlot(this.effectiveSlot || null, { campaignId: this.slotRegistration.campaignHint })?.primarySponsor?.id) : NaN;
|
|
@@ -1188,7 +1203,7 @@ var VioProductCarousel = class extends LitElement {
|
|
|
1188
1203
|
}
|
|
1189
1204
|
const fetched = await Promise.all(
|
|
1190
1205
|
Array.from(bySponsor.entries()).map(async ([sponsorId2, ids]) => {
|
|
1191
|
-
const commerce = this.commerceKey && this.productRefs.trim() === "" ? Vio.commerceWithKey(this.commerceKey) : Vio.commerceFor(sponsorId2);
|
|
1206
|
+
const commerce = this.commerceKey && this.productRefs.trim() === "" ? Vio.commerceWithKey(this.commerceKey) : Vio.commerceFor(sponsorId2, { campaignId: this.commerceCampaigns(sponsorId2) });
|
|
1192
1207
|
const products = await commerce.channel.product.getByIds({
|
|
1193
1208
|
product_ids: ids,
|
|
1194
1209
|
currency: this.currency,
|
|
@@ -2204,6 +2219,21 @@ var VioProductDetail = class extends LitElement {
|
|
|
2204
2219
|
const own = this.slotRegistration.campaignHint;
|
|
2205
2220
|
return this.fromCard && this.eventCampaignId !== void 0 ? [this.eventCampaignId, ...own] : own;
|
|
2206
2221
|
}
|
|
2222
|
+
/**
|
|
2223
|
+
* The campaign whose channel sells the open product (one article = one
|
|
2224
|
+
* campaign = one channel): the campaign its events credit, then the opening
|
|
2225
|
+
* click's and this element's own — so the product, its rates and its
|
|
2226
|
+
* seller are read with that channel's key, the one the cart is created on.
|
|
2227
|
+
*/
|
|
2228
|
+
commerceCampaigns() {
|
|
2229
|
+
const hint = this.activeCampaignHint;
|
|
2230
|
+
try {
|
|
2231
|
+
const resolved = this.attribution().campaignId;
|
|
2232
|
+
return typeof resolved === "number" ? [resolved, ...hint] : hint;
|
|
2233
|
+
} catch {
|
|
2234
|
+
return hint;
|
|
2235
|
+
}
|
|
2236
|
+
}
|
|
2207
2237
|
slotAttributes() {
|
|
2208
2238
|
return {
|
|
2209
2239
|
vioSlot: this.vioSlot,
|
|
@@ -3319,7 +3349,7 @@ var VioProductDetail = class extends LitElement {
|
|
|
3319
3349
|
try {
|
|
3320
3350
|
const activeCurrency = getGlobalCurrency() || this.currency;
|
|
3321
3351
|
this.currency = activeCurrency;
|
|
3322
|
-
const commerce = Vio.commerceFor(this.sponsorId);
|
|
3352
|
+
const commerce = Vio.commerceFor(this.sponsorId, { campaignId: this.commerceCampaigns() });
|
|
3323
3353
|
products = await commerce.channel.product.getByIds({
|
|
3324
3354
|
product_ids: [productIdNum],
|
|
3325
3355
|
currency: activeCurrency,
|
|
@@ -4019,7 +4049,7 @@ var VioProductDetail = class extends LitElement {
|
|
|
4019
4049
|
async loadShippingFrom(productId, seq) {
|
|
4020
4050
|
let rates = null;
|
|
4021
4051
|
try {
|
|
4022
|
-
const product = Vio.commerceFor(this.sponsorId).channel.product;
|
|
4052
|
+
const product = Vio.commerceFor(this.sponsorId, { campaignId: this.commerceCampaigns() }).channel.product;
|
|
4023
4053
|
rates = typeof product.getShippingRates === "function" ? await product.getShippingRates(productId, { currency: this.currency }) : null;
|
|
4024
4054
|
} catch {
|
|
4025
4055
|
rates = null;
|
|
@@ -4135,7 +4165,12 @@ var VioProductDetail = class extends LitElement {
|
|
|
4135
4165
|
*/
|
|
4136
4166
|
renderShippingReturns() {
|
|
4137
4167
|
const identity = resolveSponsorIdentity(this.sponsorId);
|
|
4138
|
-
const rates = this.shippingRates
|
|
4168
|
+
const rates = shippingRatesShown(this.shippingRates, [
|
|
4169
|
+
this.product?.title,
|
|
4170
|
+
this.product?.brand,
|
|
4171
|
+
this.sellerName,
|
|
4172
|
+
identity?.name
|
|
4173
|
+
]);
|
|
4139
4174
|
const times = [...new Set(rates.map((r) => r.description).filter(Boolean))];
|
|
4140
4175
|
const perRateTime = times.length > 1;
|
|
4141
4176
|
const sharedTime = times.length === 1 ? times[0] : times.length === 0 && this.deliveryTime.trim() ? `Leveringstid: ${this.deliveryTime.trim()}` : "";
|
|
@@ -4188,7 +4223,7 @@ var VioProductDetail = class extends LitElement {
|
|
|
4188
4223
|
async loadSeller(productId, seq) {
|
|
4189
4224
|
let name = null;
|
|
4190
4225
|
try {
|
|
4191
|
-
name = await Vio.commerceFor(this.sponsorId).channel.product.getSellerCompany(productId);
|
|
4226
|
+
name = await Vio.commerceFor(this.sponsorId, { campaignId: this.commerceCampaigns() }).channel.product.getSellerCompany(productId);
|
|
4192
4227
|
} catch {
|
|
4193
4228
|
name = null;
|
|
4194
4229
|
}
|
|
@@ -4657,6 +4692,9 @@ function normalizeValues(raw) {
|
|
|
4657
4692
|
}
|
|
4658
4693
|
return [];
|
|
4659
4694
|
}
|
|
4695
|
+
function shippingRatesShown(rates, repeats = []) {
|
|
4696
|
+
return rates.map((r) => ({ ...r, description: shippingDescriptionOf(r.description, [r.name, ...repeats]) }));
|
|
4697
|
+
}
|
|
4660
4698
|
function splitRateName(name) {
|
|
4661
4699
|
const text = String(name ?? "").trim();
|
|
4662
4700
|
const m = text.match(/^(.+?)\s+[-–—]\s+(.+)$/);
|
|
@@ -9353,5 +9391,5 @@ function registerVioElements() {
|
|
|
9353
9391
|
}
|
|
9354
9392
|
|
|
9355
9393
|
export { VioCart, VioCheckout, VioProduct, VioProductCarousel, VioProductDetail, VioTokens, applyVioTheme, registerVioElements };
|
|
9356
|
-
//# sourceMappingURL=chunk-
|
|
9357
|
-
//# sourceMappingURL=chunk-
|
|
9394
|
+
//# sourceMappingURL=chunk-T5B74YBQ.js.map
|
|
9395
|
+
//# sourceMappingURL=chunk-T5B74YBQ.js.map
|