@cross-deck/web 1.5.7 → 1.6.2
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 +72 -0
- package/README.md +6 -4
- package/dist/contracts.json +58 -12
- package/dist/crossdeck.umd.min.js +2 -2
- package/dist/crossdeck.umd.min.js.map +1 -1
- package/dist/error-codes.json +1 -1
- package/dist/index.cjs +594 -238
- package/dist/index.cjs.map +1 -1
- package/dist/index.d.mts +55 -5
- package/dist/index.d.ts +55 -5
- package/dist/index.mjs +594 -238
- package/dist/index.mjs.map +1 -1
- package/dist/react.cjs +529 -24
- package/dist/react.cjs.map +1 -1
- package/dist/react.mjs +529 -24
- package/dist/react.mjs.map +1 -1
- package/dist/vue.cjs +529 -24
- package/dist/vue.cjs.map +1 -1
- package/dist/vue.mjs +529 -24
- package/dist/vue.mjs.map +1 -1
- package/package.json +1 -1
package/CHANGELOG.md
CHANGED
|
@@ -2,6 +2,78 @@
|
|
|
2
2
|
|
|
3
3
|
All notable changes to `@cross-deck/web` will be documented here. The format follows [Keep a Changelog](https://keepachangelog.com/en/1.1.0/) and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0.html).
|
|
4
4
|
|
|
5
|
+
## [1.6.2] — 2026-05-31
|
|
6
|
+
|
|
7
|
+
Patch — session-boundary correctness. A stored session could span a gap
|
|
8
|
+
longer than the 30-minute inactivity window in two cases the resume logic
|
|
9
|
+
missed, fragmenting journey grouping. Both are now fixed. No public API
|
|
10
|
+
change; `session.ended` emission timing changes as described, so read
|
|
11
|
+
before upgrading if you have downstream logic keyed on it.
|
|
12
|
+
|
|
13
|
+
**A tab left open and idle, then used again, no longer stretches one
|
|
14
|
+
session across the gap.** `markActivity()` now rolls to a new session when
|
|
15
|
+
an event lands after the 30-minute window has lapsed — covering the case
|
|
16
|
+
the page-load and tab-return resume checks miss entirely (a tab kept open
|
|
17
|
+
and idle, then interacted with, with no visibility transition). A single
|
|
18
|
+
stored session can no longer contain a >30-minute gap.
|
|
19
|
+
|
|
20
|
+
**Returning to a long-idle tab no longer back-dates `session.ended`.** The
|
|
21
|
+
visibility-resume path emitted `session.ended` at the moment of return —
|
|
22
|
+
more than 30 minutes after the session's last real event — which itself
|
|
23
|
+
opened an intra-session gap. The prior session now ends implicitly (its
|
|
24
|
+
end inferred from its last event), consistent with the page-load resume
|
|
25
|
+
path. If you key downstream logic on `session.ended`, note it no longer
|
|
26
|
+
fires on a >30-minute tab-return.
|
|
27
|
+
|
|
28
|
+
## [1.6.1] — 2026-05-30
|
|
29
|
+
|
|
30
|
+
Minor — two autocapture fidelity fixes, plus a repair to the release
|
|
31
|
+
pipeline itself. (1.6.0 carried the same two fixes but never reached npm:
|
|
32
|
+
its automated publish hit a pre-existing broken test gate — a schema-lock
|
|
33
|
+
test that loaded a contract via a monorepo-only path that doesn't exist
|
|
34
|
+
in the published package. Fixed by reading the contract from the copy
|
|
35
|
+
bundled into the SDK, so this is the first build of these changes to
|
|
36
|
+
ship.) No public API change; event emission behaviour changes as
|
|
37
|
+
described, so read before upgrading if you have downstream logic keyed on
|
|
38
|
+
`session.ended` timing.
|
|
39
|
+
|
|
40
|
+
**Sessions now survive full-page navigations.** Session state was
|
|
41
|
+
in-memory only, so on a multi-page site (where the SDK re-installs on
|
|
42
|
+
every navigation) one visit was split into a separate session per page —
|
|
43
|
+
each `session.ended` on `pagehide` landing at the same instant the next
|
|
44
|
+
page's `session.started` fired. Sessions are now persisted (id, start,
|
|
45
|
+
last-activity, first-touch acquisition) to the same storage adapter as
|
|
46
|
+
identity and **resumed** across page loads within a rolling 30-minute
|
|
47
|
+
inactivity window.
|
|
48
|
+
|
|
49
|
+
- `session.started` no longer fires on a resumed page load — only on a
|
|
50
|
+
genuinely new session (first visit, or first load after >30 min idle).
|
|
51
|
+
- `session.ended` no longer fires on `pagehide` / `beforeunload` (a
|
|
52
|
+
navigation is not a session end). It fires only on real 30-min
|
|
53
|
+
inactivity or an explicit `Crossdeck.stop()`.
|
|
54
|
+
- The inactivity window is bumped by every tracked event (auto or
|
|
55
|
+
custom), not just pageviews/clicks.
|
|
56
|
+
- Honours consent posture: with `persistIdentity: false` or a
|
|
57
|
+
`MemoryStorage` adapter, the session is in-memory only (per-page, the
|
|
58
|
+
prior behaviour).
|
|
59
|
+
- Continuity is same-origin (localStorage); cross-subdomain stitching is
|
|
60
|
+
not yet handled.
|
|
61
|
+
|
|
62
|
+
**Click autocapture no longer mashes labels.** A click on a control that
|
|
63
|
+
wraps other controls or a content block (a card around several buttons, a
|
|
64
|
+
hero `<a>` around a heading + paragraph) used to collapse the whole
|
|
65
|
+
subtree into one string — `"Log inContinue with GoogleContinue with
|
|
66
|
+
Apple…"`, `"Tudo que você é,em um só link.Portfolio…"`. The resolver now
|
|
67
|
+
returns the control's own label (word boundaries preserved, decorative
|
|
68
|
+
`svg`/`style`/`script` skipped), or for a wrapper its direct label / the
|
|
69
|
+
first heading inside it, falling through to the selector rather than a
|
|
70
|
+
concatenation. Attribute precedence (`data-*` → aria → value → text →
|
|
71
|
+
title → img/svg) is unchanged.
|
|
72
|
+
|
|
73
|
+
Bundle-size budget for the core bundles raised 55 → 58 KB gzipped (ESM +
|
|
74
|
+
CJS) to fit the ~1 KB of new code; react/vue/UMD bundles unchanged and
|
|
75
|
+
still under budget.
|
|
76
|
+
|
|
5
77
|
## [1.5.1] — 2026-05-27
|
|
6
78
|
|
|
7
79
|
`crossdeck.contract_failed` is now single-fire to a dedicated
|
package/README.md
CHANGED
|
@@ -86,13 +86,15 @@ That's the full happy path.
|
|
|
86
86
|
|
|
87
87
|
| Event | When |
|
|
88
88
|
|---|---|
|
|
89
|
-
| `session.started` |
|
|
90
|
-
| `session.ended` | On
|
|
89
|
+
| `session.started` | When a **new** session begins — first visit, or the first page load after >30 min of inactivity. A session resumed across a page navigation does **not** re-fire it. Carries `sessionId`. |
|
|
90
|
+
| `session.ended` | On a real session end only: >30 min of inactivity, or an explicit `Crossdeck.stop()`. Carries `sessionId` and `durationMs`. |
|
|
91
91
|
| `page.viewed` | On initial load + every SPA navigation (`history.pushState`, `replaceState`, `popstate`). Carries `path`, `url`, `search`, `hash`, `title`, `referrer`. |
|
|
92
92
|
|
|
93
|
-
Every event — auto-tracked and developer-emitted — is enriched with the device-info payload below.
|
|
93
|
+
Every event — auto-tracked and developer-emitted — is enriched with the device-info payload below.
|
|
94
94
|
|
|
95
|
-
**
|
|
95
|
+
**Sessions survive page loads (v1.6.0+).** A session is a *visit*, not a page. The SDK persists the session (id, start time, last-activity time, first-touch acquisition) to the same storage as identity, so a full-page navigation on a multi-page site **resumes the same session** rather than starting a new one. The window is a rolling 30-minute inactivity timer bumped by every tracked event (auto or custom); only real 30-min inactivity or `Crossdeck.stop()` ends it. A page unload (`pagehide`/`beforeunload`) is treated as a navigation, not an end. Quick tab switches (Cmd-Tab) likewise don't end the session — matching GA4's session-window convention. Continuity is same-origin; cross-subdomain stitching is on the roadmap. With `persistIdentity: false` (or a `MemoryStorage` adapter) the session is in-memory only and resets per page.
|
|
96
|
+
|
|
97
|
+
**Per-session acquisition (v0.6.0+):** when a session starts the SDK reads `window.location.search` and `document.referrer` and captures `utm_source`, `utm_medium`, `utm_campaign`, `utm_content`, `utm_term`, plus `referrer`. Non-empty values are auto-attached to every subsequent event of that session — first-touch attribution stays pinned to the entry URL even after SPA route changes strip the params away, and now stays pinned across full-page navigations within the session too. A new session (>30 min idle) re-reads the URL.
|
|
96
98
|
|
|
97
99
|
## Auto-attached device info
|
|
98
100
|
|
package/dist/contracts.json
CHANGED
|
@@ -1,10 +1,10 @@
|
|
|
1
1
|
{
|
|
2
2
|
"$schema": "https://json-schema.org/draft/2020-12/schema",
|
|
3
|
-
"generatedAt": "2026-
|
|
3
|
+
"generatedAt": "2026-06-01T05:25:25.624Z",
|
|
4
4
|
"sdk": "@cross-deck/web",
|
|
5
|
-
"sdkVersion": "1.
|
|
6
|
-
"bundledIn": "@cross-deck/web@1.
|
|
7
|
-
"count":
|
|
5
|
+
"sdkVersion": "1.6.2",
|
|
6
|
+
"bundledIn": "@cross-deck/web@1.6.2",
|
|
7
|
+
"count": 9,
|
|
8
8
|
"contracts": [
|
|
9
9
|
{
|
|
10
10
|
"id": "contract-failed-payload-schema-lock",
|
|
@@ -126,7 +126,7 @@
|
|
|
126
126
|
"legal/security/index.html#diagnostic",
|
|
127
127
|
"legal/sdk-data/index.html#b-diagnostic"
|
|
128
128
|
],
|
|
129
|
-
"bundledIn": "@cross-deck/web@1.
|
|
129
|
+
"bundledIn": "@cross-deck/web@1.6.2"
|
|
130
130
|
},
|
|
131
131
|
{
|
|
132
132
|
"id": "error-envelope-shape",
|
|
@@ -165,7 +165,7 @@
|
|
|
165
165
|
],
|
|
166
166
|
"registeredAt": "2026-05-26",
|
|
167
167
|
"firstRegisteredIn": "bank-grade reconciliation v1.4.0 — phase 8 (codifies existing contract)",
|
|
168
|
-
"bundledIn": "@cross-deck/web@1.
|
|
168
|
+
"bundledIn": "@cross-deck/web@1.6.2"
|
|
169
169
|
},
|
|
170
170
|
{
|
|
171
171
|
"id": "flush-interval-parity",
|
|
@@ -210,7 +210,7 @@
|
|
|
210
210
|
],
|
|
211
211
|
"registeredAt": "2026-05-26",
|
|
212
212
|
"firstRegisteredIn": "bank-grade reconciliation v1.4.0 — phase 3.3",
|
|
213
|
-
"bundledIn": "@cross-deck/web@1.
|
|
213
|
+
"bundledIn": "@cross-deck/web@1.6.2"
|
|
214
214
|
},
|
|
215
215
|
{
|
|
216
216
|
"id": "idempotency-key-deterministic",
|
|
@@ -315,7 +315,7 @@
|
|
|
315
315
|
],
|
|
316
316
|
"registeredAt": "2026-05-26",
|
|
317
317
|
"firstRegisteredIn": "bank-grade reconciliation v1.4.0 — phase 2.2.a + 2.2.b + 2.2.c",
|
|
318
|
-
"bundledIn": "@cross-deck/web@1.
|
|
318
|
+
"bundledIn": "@cross-deck/web@1.6.2"
|
|
319
319
|
},
|
|
320
320
|
{
|
|
321
321
|
"id": "init-reentry-drains-prior-queue",
|
|
@@ -342,7 +342,7 @@
|
|
|
342
342
|
],
|
|
343
343
|
"registeredAt": "2026-05-26",
|
|
344
344
|
"firstRegisteredIn": "bank-grade reconciliation v1.4.0 — phase 5.5",
|
|
345
|
-
"bundledIn": "@cross-deck/web@1.
|
|
345
|
+
"bundledIn": "@cross-deck/web@1.6.2"
|
|
346
346
|
},
|
|
347
347
|
{
|
|
348
348
|
"id": "per-user-cache-isolation",
|
|
@@ -421,7 +421,7 @@
|
|
|
421
421
|
],
|
|
422
422
|
"registeredAt": "2026-05-26",
|
|
423
423
|
"firstRegisteredIn": "bank-grade reconciliation v1.4.0 — phase 1.3 (web/RN) + dogfood-gap fix (swift + android)",
|
|
424
|
-
"bundledIn": "@cross-deck/web@1.
|
|
424
|
+
"bundledIn": "@cross-deck/web@1.6.2"
|
|
425
425
|
},
|
|
426
426
|
{
|
|
427
427
|
"id": "sdk-error-codes-catalogue",
|
|
@@ -435,9 +435,14 @@
|
|
|
435
435
|
"codeRef": [
|
|
436
436
|
"sdks/web/src/error-codes.ts",
|
|
437
437
|
"sdks/node/src/error-codes.ts",
|
|
438
|
+
"sdks/web/src/_contract-verifiers.ts",
|
|
438
439
|
"backend/src/api/v1-errors.ts"
|
|
439
440
|
],
|
|
440
441
|
"testRef": [
|
|
442
|
+
{
|
|
443
|
+
"file": "sdks/web/tests/contract-verifiers.test.ts",
|
|
444
|
+
"name": "sdk-error-codes-catalogue covers every backend wire code with remediation"
|
|
445
|
+
},
|
|
441
446
|
{
|
|
442
447
|
"file": "sdks/web/tests/error-codes-backfill.test.ts",
|
|
443
448
|
"name": "includes backend code"
|
|
@@ -461,7 +466,48 @@
|
|
|
461
466
|
],
|
|
462
467
|
"registeredAt": "2026-05-26",
|
|
463
468
|
"firstRegisteredIn": "bank-grade reconciliation v1.4.0 — phase 6.2",
|
|
464
|
-
"bundledIn": "@cross-deck/web@1.
|
|
469
|
+
"bundledIn": "@cross-deck/web@1.6.2"
|
|
470
|
+
},
|
|
471
|
+
{
|
|
472
|
+
"id": "super-property-merge-precedence",
|
|
473
|
+
"pillar": "analytics",
|
|
474
|
+
"status": "enforced",
|
|
475
|
+
"claim": "Every Crossdeck SDK merges event properties with the precedence device < super < caller (caller-supplied values win over registered super-properties, which win over auto-attached device info). Pre-v1.4.0 Swift had it INVERTED (super < device < caller — device clobbered super), so a `register('plan', 'pro')` super-property was silently overridden by auto-attached device fields whenever keys collided. Cross-SDK funnel queries on super-property keys returned different answers per platform.",
|
|
476
|
+
"appliesTo": [
|
|
477
|
+
"web",
|
|
478
|
+
"swift"
|
|
479
|
+
],
|
|
480
|
+
"codeRef": [
|
|
481
|
+
"sdks/web/src/super-properties.ts",
|
|
482
|
+
"sdks/web/src/_contract-verifiers.ts",
|
|
483
|
+
"sdks/swift/Sources/Crossdeck/EventPropertyMerge.swift",
|
|
484
|
+
"sdks/swift/Sources/Crossdeck/Crossdeck.swift"
|
|
485
|
+
],
|
|
486
|
+
"testRef": [
|
|
487
|
+
{
|
|
488
|
+
"file": "sdks/web/tests/contract-verifiers.test.ts",
|
|
489
|
+
"name": "super-property-merge-precedence verifies caller > super > device"
|
|
490
|
+
},
|
|
491
|
+
{
|
|
492
|
+
"file": "sdks/swift/Tests/CrossdeckTests/EventPropertyMergeTests.swift",
|
|
493
|
+
"name": "test_super_overrides_device"
|
|
494
|
+
},
|
|
495
|
+
{
|
|
496
|
+
"file": "sdks/swift/Tests/CrossdeckTests/EventPropertyMergeTests.swift",
|
|
497
|
+
"name": "test_caller_overrides_super"
|
|
498
|
+
},
|
|
499
|
+
{
|
|
500
|
+
"file": "sdks/swift/Tests/CrossdeckTests/EventPropertyMergeTests.swift",
|
|
501
|
+
"name": "test_full_precedence_chain"
|
|
502
|
+
},
|
|
503
|
+
{
|
|
504
|
+
"file": "sdks/swift/Tests/CrossdeckTests/EventPropertyMergeTests.swift",
|
|
505
|
+
"name": "test_matchesWebNodeRNPrecedence"
|
|
506
|
+
}
|
|
507
|
+
],
|
|
508
|
+
"registeredAt": "2026-05-26",
|
|
509
|
+
"firstRegisteredIn": "bank-grade reconciliation v1.4.0 — phase 3.2",
|
|
510
|
+
"bundledIn": "@cross-deck/web@1.6.2"
|
|
465
511
|
},
|
|
466
512
|
{
|
|
467
513
|
"id": "sync-purchases-funnel-parity",
|
|
@@ -494,7 +540,7 @@
|
|
|
494
540
|
],
|
|
495
541
|
"registeredAt": "2026-05-26",
|
|
496
542
|
"firstRegisteredIn": "bank-grade reconciliation v1.4.0 — phase 3.5",
|
|
497
|
-
"bundledIn": "@cross-deck/web@1.
|
|
543
|
+
"bundledIn": "@cross-deck/web@1.6.2"
|
|
498
544
|
}
|
|
499
545
|
]
|
|
500
546
|
}
|