@vio-live/web-sdk 0.23.0 → 0.23.1

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
@@ -137,8 +137,13 @@ In order:
137
137
  carousel's id). `vio-slot-name` is its optional human label for the dashboard.
138
138
  2. Otherwise an **auto id**: `${scope}-${kind}-${ordinal + 1}` — `carousel-1`,
139
139
  `card-3`, `detail-1`, `article-123-carousel-1` — counted among the same kind of
140
- element **with the same scope**, in document order, when the element connects.
141
- Its label is `Carousel 1` (` · Title` when the scope has a label).
140
+ element **with the same scope**: on a fresh load elements connect in document
141
+ order, so the number is the document position; in a dynamic DOM a later element
142
+ takes the first free number and a removed element's number is reused — two live
143
+ elements never share an id. Its label is `Carousel 1` (` · Title` when the
144
+ scope has a label). Every id is capped at 100 characters (a long scope is cut,
145
+ the kind and number are kept), and the capped id is what gets declared,
146
+ exposed and sent.
142
147
 
143
148
  The attribute is **`vio-slot`** (property `vioSlot`, React prop `vioSlot`) — **not
144
149
  `slot`**, which is HTML's own attribute for shadow DOM slotting and stays untouched.
@@ -177,11 +182,15 @@ template that wants slots shared across articles simply sets no scope.
177
182
  Every mounted element registers its id (and label); after the first successful
178
183
  `Vio.bootstrap()` the SDK sends **one** manifest for the whole page
179
184
  (`POST /v2/mobile/components/manifest`, `mode: 'merge'`, so one page never
180
- deprecates another page's slots) and again whenever a new id or label appears. The
181
- same set is not re-sent from the same browser for **24 h** (remembered in
182
- `localStorage` under the platform and a hash of the key — never the key itself;
183
- without storage it simply posts each load). Best-effort, never throws. By hand,
184
- e.g. from an editor:
185
+ deprecates another page's slots) and again whenever a new id or label appears.
186
+ The browser remembers **each id (under its label) for 24 h** in `localStorage`
187
+ (under the platform and a hash of the key — never the key itself), so a
188
+ multi-page site posts only the ids a page adds, a revisit posts nothing, a
189
+ renamed block posts again; without storage it simply posts each load. A failed
190
+ attempt (or a server that ignored `merge`) is not retried for 1 h; a declaration
191
+ sends at most 100 locations and a page load at most 3 manifests (each cap warns
192
+ once). Best-effort, never throws. By hand, e.g. from an editor (`force` re-sends
193
+ everything and ignores the per-load cap):
185
194
 
186
195
  ```ts
187
196
  await Vio.declareSlots(['hero', { id: 'sidebar', displayName: 'Sidebar' }], { force: true })
@@ -196,7 +205,9 @@ several, the default campaign, else the first listed. No assignment → the defa
196
205
  campaign. `Vio.campaignForSlot('hero')` answers from the last bootstrap (`null`
197
206
  before it); the pure `resolveSlotCampaign(boot, slot, now?, platform?)` is exported
198
207
  from `/core`. A carousel or card **without a `sponsor-id`** uses the primary sponsor
199
- of its slot's campaign; an explicit `sponsor-id` still wins.
208
+ of its slot's campaign (the default campaign's when the slot has none), and the
209
+ detail opened by such a card does the same — before 0.23 a sponsorless card did
210
+ nothing. An explicit `sponsor-id` still wins.
200
211
 
201
212
  ## Attribution — the slot, the campaign, the article
202
213
 
@@ -205,26 +216,36 @@ and so do the Vev blocks and the Replit site:
205
216
 
206
217
  ```ts
207
218
  Vio.attribution('hero')
208
- // → { slot: 'hero', campaignId: 12, sponsorId: 7, contentId: 'https://host/sport/42', contentTitle: 'Why the lamp matters' }
219
+ // → { slot: 'hero', campaignId: 12, sponsorId: 7, contentId: 'article-42', contentTitle: 'Why the lamp matters' }
209
220
  ```
210
221
 
211
222
  `campaignId`/`sponsorId` are the slot's campaign and its primary sponsor (`{}` before
212
223
  the bootstrap); `contentId`/`contentTitle` are the **content** (the article) the page
213
224
  is. The place is the slot, the article is the content — both automatic.
214
225
 
215
- **Article (content) attribution.** `Vio.content()` resolves it once per page and
216
- every analytics event carries it as `content_id` / `content_title`: id from
217
- `Vio.init({ contentId })` → `?vio_content=` → `<meta name="vio:content-id">` →
226
+ **Article (content) attribution.** `Vio.content()` resolves it **live** (a few
227
+ `querySelector`s, so an SPA route change or a new title is seen on the next event)
228
+ and every analytics event carries it as `content_id` / `content_title`: id from
229
+ `Vio.init({ contentId })` → `?vio_content=` (honored by design — a page may be
230
+ told which article it is) → `<meta name="vio:content-id">` →
218
231
  `<link rel="canonical">` / `og:url` (without query and hash) → `location.pathname`;
219
232
  title from `Vio.init({ contentTitle })` → `?vio_content_title=` →
220
- `<meta name="vio:content-title">` → `og:title` → `document.title`. Per element,
233
+ `<meta name="vio:content-title">` → `og:title` → `document.title`. The collector
234
+ rejects a whole event over an id of 128 chars or a title of 255, so a candidate id
235
+ that does not fit is skipped for the next one (and omitted when none fits) and
236
+ titles are cut — in one place, before anything is sent. Per element,
221
237
  `vio-content-id` / `vio-content-title` override it (a teaser for another article).
222
238
 
223
239
  **What analytics gets.** Every event an element emits (`vio:product-click`,
224
240
  `vio:product-add`, `vio:added-to-cart`, `vio:checkout-open`, …) and every event it
225
241
  tracks carries `slot` (the effective id), `location_id` (= the slot), `content_id`
226
- and `content_title`. `campaign_id` resolves as explicit `campaignId` → the slot's
227
- assigned campaign → the sponsor's campaign → the default.
242
+ and `content_title`. `campaign_id` resolves as explicit `campaignId` (the element's
243
+ own attribution travels in its event detail and is honored as such) → the slot's
244
+ assigned campaign → the sponsor's campaign → the default. Two things changed from
245
+ 0.22 for carousels: a carousel's impressions and `view_item_list` report
246
+ `location_id` as its slot id (`carousel-1`, or the `vio-slot`) instead of its
247
+ `label`, and every event now carries `content_id` / `content_title` — including
248
+ the single-campaign `begin_checkout` / `purchase`.
228
249
 
229
250
  ### Cart origins and the purchase per campaign
230
251
 
@@ -246,9 +267,21 @@ They persist with the cart; carts from before origins read as one empty origin.
246
267
  At checkout and purchase the cart is **split per campaign**: `begin_checkout` and
247
268
  `purchase` go out **once per campaign in the cart**, each with that campaign's
248
269
  items (quantities from the origins; units without one fall into the campaign the
249
- current rule resolves), its own `value`, the same `order_id`, and the slice's
250
- `slot` / `content_id` when they are unique in it. A cart with a single campaign
251
- behaves exactly as before: one event.
270
+ current rule resolves), its own `value` (two decimals), the same `order_id`, the
271
+ slice's `slot` / `content_id` only when they are unique in it, and
272
+ `props: { slice, slices }` so the collector can count the order once. A cart with a
273
+ single campaign is one event, as before; when its origins name the campaign, the
274
+ event names it too (plus the unique slot / content). A cart without origins
275
+ (0.22) reports exactly as it did.
276
+
277
+ The split is public, so a host with its own analytics sink (Vev) applies the same
278
+ rule instead of its own:
279
+
280
+ ```ts
281
+ Vio.cartSlices() // over the live cart; Vio.cartSlices(sponsorId) for one sponsor
282
+ Vio.cartSlices(undefined, { items }) // pure, over a snapshot of lines
283
+ // → CartSlice[]: { campaignId?, sponsorId?, slot?, contentId?, items: VioItem[], value, currency?, slice, slices }
284
+ ```
252
285
 
253
286
  ## Theming
254
287
 
@@ -0,0 +1,3 @@
1
+
2
+ //# sourceMappingURL=chunk-45YKS5UG.js.map
3
+ //# sourceMappingURL=chunk-45YKS5UG.js.map
@@ -1 +1 @@
1
- {"version":3,"sources":[],"names":[],"mappings":"","file":"chunk-25QECQDS.js"}
1
+ {"version":3,"sources":[],"names":[],"mappings":"","file":"chunk-45YKS5UG.js"}