@datalyr/web 1.7.3 → 1.7.5
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/dist/datalyr.cjs.js +182 -10
- package/dist/datalyr.cjs.js.map +1 -1
- package/dist/datalyr.esm.js +182 -10
- package/dist/datalyr.esm.js.map +1 -1
- package/dist/datalyr.esm.min.js +1 -1
- package/dist/datalyr.esm.min.js.map +1 -1
- package/dist/datalyr.js +182 -10
- package/dist/datalyr.js.map +1 -1
- package/dist/datalyr.min.js +1 -1
- package/dist/datalyr.min.js.map +1 -1
- package/dist/index.d.ts +27 -0
- package/dist/index.d.ts.map +1 -1
- package/dist/queue.d.ts.map +1 -1
- package/dist/stripe-links.test.d.ts +2 -0
- package/dist/stripe-links.test.d.ts.map +1 -0
- package/dist/types.d.ts +2 -0
- package/dist/types.d.ts.map +1 -1
- package/package.json +1 -1
package/dist/datalyr.js
CHANGED
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
/**
|
|
2
|
-
* @datalyr/web v1.7.
|
|
2
|
+
* @datalyr/web v1.7.5
|
|
3
3
|
* Datalyr Web SDK - Modern attribution tracking for web applications
|
|
4
4
|
* (c) 2026 Datalyr Inc.
|
|
5
5
|
* Released under the MIT License
|
|
@@ -2301,16 +2301,22 @@ var Datalyr = (function (exports) {
|
|
|
2301
2301
|
// so only request it when the body is safely under the cap; oversized batches go via
|
|
2302
2302
|
// a normal fetch (no cap) and succeed.
|
|
2303
2303
|
const useKeepalive = new Blob([body]).size <= 60000;
|
|
2304
|
+
// First-party endpoint (the customer's own tracking host, never *.datalyr.com — set
|
|
2305
|
+
// by the script-origin auto-derive): send the cookie cross-subdomain so the edge can
|
|
2306
|
+
// read/refresh the server-set, ITP-durable visitor_id. Legacy datalyr.com endpoints
|
|
2307
|
+
// stay credential-less — unchanged behavior for every existing install.
|
|
2308
|
+
let firstPartyEndpoint = false;
|
|
2304
2309
|
try {
|
|
2305
|
-
|
|
2306
|
-
|
|
2307
|
-
|
|
2310
|
+
firstPartyEndpoint = !/(^|\.)datalyr\.com$/i.test(new URL(currentEndpoint).hostname);
|
|
2311
|
+
}
|
|
2312
|
+
catch (_a) {
|
|
2313
|
+
/* malformed endpoint — leave false */
|
|
2314
|
+
}
|
|
2315
|
+
try {
|
|
2316
|
+
const response = yield fetch(currentEndpoint, Object.assign({ method: 'POST', headers: {
|
|
2308
2317
|
'Content-Type': 'application/json',
|
|
2309
2318
|
'X-Batch-Size': events.length.toString()
|
|
2310
|
-
},
|
|
2311
|
-
body,
|
|
2312
|
-
keepalive: useKeepalive
|
|
2313
|
-
});
|
|
2319
|
+
}, body, keepalive: useKeepalive }, (firstPartyEndpoint ? { credentials: 'include' } : {})));
|
|
2314
2320
|
if (!response.ok) {
|
|
2315
2321
|
// Handle rate limiting
|
|
2316
2322
|
if (response.status === 429) {
|
|
@@ -4339,7 +4345,7 @@ var Datalyr = (function (exports) {
|
|
|
4339
4345
|
return this.initializationPromise;
|
|
4340
4346
|
}
|
|
4341
4347
|
this.initializationPromise = (() => __awaiter(this, void 0, void 0, function* () {
|
|
4342
|
-
var _a;
|
|
4348
|
+
var _a, _b;
|
|
4343
4349
|
try {
|
|
4344
4350
|
// SEC-03: encryption is for PII-AT-REST only — it must NOT gate event delivery,
|
|
4345
4351
|
// pageviews, or pixels. On a non-secure context (http://) or an old browser,
|
|
@@ -4462,6 +4468,15 @@ var Datalyr = (function (exports) {
|
|
|
4462
4468
|
// opted-out / DNT / GPC visitor's id + click-ids aren't stamped on outbound links.
|
|
4463
4469
|
this.syncOutboundLinkParams(this.config.checkoutChampDomains);
|
|
4464
4470
|
}
|
|
4471
|
+
// Stripe Payment Link auto-decoration (D1, DEFAULT ON): stamp
|
|
4472
|
+
// client_reference_id=<visitor_id> (+ prefilled_email when identified) onto
|
|
4473
|
+
// buy.stripe.com / custom payment-link domain anchors and Stripe embeds, so a
|
|
4474
|
+
// snippet-only merchant's checkout.session.completed webhooks attribute
|
|
4475
|
+
// deterministically with zero server work. Gated on shouldTrack() so
|
|
4476
|
+
// opted-out / DNT / GPC visitors never get an id stamped into outbound links.
|
|
4477
|
+
if (this.config.stripePaymentLinks !== false && this.shouldTrack()) {
|
|
4478
|
+
this.syncStripePaymentLinks((_b = this.config.stripeLinkDomains) !== null && _b !== void 0 ? _b : []);
|
|
4479
|
+
}
|
|
4465
4480
|
// Track initial page view if enabled (AFTER encryption ready)
|
|
4466
4481
|
if (this.config.trackPageViews) {
|
|
4467
4482
|
this.page();
|
|
@@ -5382,6 +5397,159 @@ var Datalyr = (function (exports) {
|
|
|
5382
5397
|
}
|
|
5383
5398
|
this.log("Checkout Champ outbound-link sync active for:", lowerDomains);
|
|
5384
5399
|
}
|
|
5400
|
+
/**
|
|
5401
|
+
* Stripe Payment Link auto-decoration (D1). Structurally mirrors
|
|
5402
|
+
* syncOutboundLinkParams: stampAll on init, debounced MutationObserver for
|
|
5403
|
+
* SPA-rendered anchors, capture-phase click re-stamp + queue flush, disposer
|
|
5404
|
+
* wired into destroy()/pagehide.
|
|
5405
|
+
*
|
|
5406
|
+
* Match: exact-host equality against buy.stripe.com + config.stripeLinkDomains
|
|
5407
|
+
* via the URL API — NEVER substring (a[href*=...] would match
|
|
5408
|
+
* evil.com/buy.stripe.com paths) and NEVER checkout.stripe.com (Checkout
|
|
5409
|
+
* Session URLs ignore these params — the session is already created).
|
|
5410
|
+
*
|
|
5411
|
+
* Stamp (URL API preserves existing query + hash):
|
|
5412
|
+
* - client_reference_id=<visitorId> only if the param is absent (merchant-set
|
|
5413
|
+
* wins) and the id passes the Stripe format guard (Stripe silently DROPS
|
|
5414
|
+
* invalid values — don't write garbage into merchant links).
|
|
5415
|
+
* - prefilled_email=<email> only if identified email exists, the param is
|
|
5416
|
+
* absent, locked_prefilled_email is absent, and privacyMode !== 'strict'.
|
|
5417
|
+
* - <stripe-pricing-table>/<stripe-buy-button>: client-reference-id attribute
|
|
5418
|
+
* if absent.
|
|
5419
|
+
*
|
|
5420
|
+
* The decorated link's checkout.session.completed arrives with
|
|
5421
|
+
* client_reference_id, which stripe-connect.js already reads — zero server
|
|
5422
|
+
* changes. window.open(paymentLink) is not covered (use getVisitorId()
|
|
5423
|
+
* manually); iframe/shadow-DOM links are unreachable from document.
|
|
5424
|
+
*/
|
|
5425
|
+
syncStripePaymentLinks(extraDomains) {
|
|
5426
|
+
if (typeof window === "undefined" || typeof document === "undefined")
|
|
5427
|
+
return;
|
|
5428
|
+
const hosts = new Set(["buy.stripe.com"]);
|
|
5429
|
+
for (const d of extraDomains) {
|
|
5430
|
+
const h = String(d).trim().toLowerCase();
|
|
5431
|
+
if (h)
|
|
5432
|
+
hosts.add(h);
|
|
5433
|
+
}
|
|
5434
|
+
const matchesPaymentLinkHost = (href) => {
|
|
5435
|
+
try {
|
|
5436
|
+
const host = new URL(href, window.location.href).hostname.toLowerCase();
|
|
5437
|
+
return hosts.has(host); // exact-host equality only
|
|
5438
|
+
}
|
|
5439
|
+
catch (_a) {
|
|
5440
|
+
return false;
|
|
5441
|
+
}
|
|
5442
|
+
};
|
|
5443
|
+
// Stripe accepts alphanumeric + `-` + `_`, max 200 chars, and silently drops
|
|
5444
|
+
// invalid values. Legacy/foreign persisted cookie ids are unconstrained —
|
|
5445
|
+
// skip silently rather than stamp a value Stripe would discard.
|
|
5446
|
+
const CLIENT_REFERENCE_ID_RE = /^[A-Za-z0-9_-]{1,200}$/;
|
|
5447
|
+
const getClientReferenceId = () => {
|
|
5448
|
+
const vid = this.identity.getAnonymousId();
|
|
5449
|
+
return vid && CLIENT_REFERENCE_ID_RE.test(vid) ? vid : null;
|
|
5450
|
+
};
|
|
5451
|
+
const getPrefilledEmail = () => {
|
|
5452
|
+
var _a;
|
|
5453
|
+
if (this.config.privacyMode === "strict")
|
|
5454
|
+
return null;
|
|
5455
|
+
const email = (_a = this.userProperties) === null || _a === void 0 ? void 0 : _a.email;
|
|
5456
|
+
return typeof email === "string" && email ? email : null;
|
|
5457
|
+
};
|
|
5458
|
+
const stampLink = (anchor) => {
|
|
5459
|
+
if (!anchor.href || !matchesPaymentLinkHost(anchor.href))
|
|
5460
|
+
return;
|
|
5461
|
+
try {
|
|
5462
|
+
const u = new URL(anchor.href, window.location.href);
|
|
5463
|
+
let mutated = false;
|
|
5464
|
+
const vid = getClientReferenceId();
|
|
5465
|
+
if (vid && !u.searchParams.get("client_reference_id")) {
|
|
5466
|
+
u.searchParams.set("client_reference_id", vid);
|
|
5467
|
+
mutated = true;
|
|
5468
|
+
}
|
|
5469
|
+
const email = getPrefilledEmail();
|
|
5470
|
+
if (email &&
|
|
5471
|
+
!u.searchParams.get("prefilled_email") &&
|
|
5472
|
+
!u.searchParams.get("locked_prefilled_email")) {
|
|
5473
|
+
// URL API percent-encodes automatically.
|
|
5474
|
+
u.searchParams.set("prefilled_email", email);
|
|
5475
|
+
mutated = true;
|
|
5476
|
+
}
|
|
5477
|
+
if (mutated)
|
|
5478
|
+
anchor.href = u.toString();
|
|
5479
|
+
}
|
|
5480
|
+
catch (_a) {
|
|
5481
|
+
// Ignore malformed URLs — don't break the page.
|
|
5482
|
+
}
|
|
5483
|
+
};
|
|
5484
|
+
const stampEmbeds = () => {
|
|
5485
|
+
const vid = getClientReferenceId();
|
|
5486
|
+
if (!vid)
|
|
5487
|
+
return;
|
|
5488
|
+
document.querySelectorAll("stripe-pricing-table, stripe-buy-button").forEach((el) => {
|
|
5489
|
+
if (!el.getAttribute("client-reference-id")) {
|
|
5490
|
+
el.setAttribute("client-reference-id", vid);
|
|
5491
|
+
}
|
|
5492
|
+
});
|
|
5493
|
+
};
|
|
5494
|
+
const stampAll = () => {
|
|
5495
|
+
document.querySelectorAll("a[href]").forEach((el) => stampLink(el));
|
|
5496
|
+
stampEmbeds();
|
|
5497
|
+
};
|
|
5498
|
+
const onClick = (e) => {
|
|
5499
|
+
var _a, _b;
|
|
5500
|
+
const target = (_a = e.target) === null || _a === void 0 ? void 0 : _a.closest("a[href]");
|
|
5501
|
+
if (!target)
|
|
5502
|
+
return;
|
|
5503
|
+
const anchor = target;
|
|
5504
|
+
if (!matchesPaymentLinkHost(anchor.href))
|
|
5505
|
+
return;
|
|
5506
|
+
stampLink(anchor); // re-stamp in case identify() happened since DOMReady
|
|
5507
|
+
try {
|
|
5508
|
+
(_b = this.queue) === null || _b === void 0 ? void 0 : _b.flush();
|
|
5509
|
+
}
|
|
5510
|
+
catch (_c) {
|
|
5511
|
+
// Best-effort — never block navigation.
|
|
5512
|
+
}
|
|
5513
|
+
};
|
|
5514
|
+
stampAll();
|
|
5515
|
+
document.addEventListener("click", onClick, true);
|
|
5516
|
+
try {
|
|
5517
|
+
// Debounce re-stamping (same rationale as the CC sync): a busy SPA can fire
|
|
5518
|
+
// thousands of mutations per second; 150ms is small enough to catch links
|
|
5519
|
+
// before the user can click them, large enough to coalesce bursts. The
|
|
5520
|
+
// click-time re-stamp is the final safety net — no pushState hook needed.
|
|
5521
|
+
let restampTimer = null;
|
|
5522
|
+
const scheduleRestamp = () => {
|
|
5523
|
+
if (restampTimer != null)
|
|
5524
|
+
return;
|
|
5525
|
+
restampTimer = setTimeout(() => {
|
|
5526
|
+
restampTimer = null;
|
|
5527
|
+
stampAll();
|
|
5528
|
+
}, 150);
|
|
5529
|
+
};
|
|
5530
|
+
const observer = new MutationObserver(scheduleRestamp);
|
|
5531
|
+
observer.observe(document.documentElement, { childList: true, subtree: true });
|
|
5532
|
+
// Observer + click listener live for the session; pagehide cleans up on
|
|
5533
|
+
// full-page unload, and destroy() tears them down early via this disposer
|
|
5534
|
+
// (otherwise destroy()+re-init() leaks the observer + capturing listener).
|
|
5535
|
+
this.stripeLinksDisposer = () => {
|
|
5536
|
+
try {
|
|
5537
|
+
observer.disconnect();
|
|
5538
|
+
}
|
|
5539
|
+
catch ( /* idempotent */_a) { /* idempotent */ }
|
|
5540
|
+
if (restampTimer != null) {
|
|
5541
|
+
clearTimeout(restampTimer);
|
|
5542
|
+
restampTimer = null;
|
|
5543
|
+
}
|
|
5544
|
+
document.removeEventListener("click", onClick, true);
|
|
5545
|
+
};
|
|
5546
|
+
window.addEventListener("pagehide", () => { var _a; return (_a = this.stripeLinksDisposer) === null || _a === void 0 ? void 0 : _a.call(this); }, { once: true });
|
|
5547
|
+
}
|
|
5548
|
+
catch (error) {
|
|
5549
|
+
this.log("MutationObserver setup failed (Stripe Payment Link sync):", error);
|
|
5550
|
+
}
|
|
5551
|
+
this.log("Stripe Payment Link auto-decoration active for:", Array.from(hosts));
|
|
5552
|
+
}
|
|
5385
5553
|
/**
|
|
5386
5554
|
* Create event payload
|
|
5387
5555
|
*/
|
|
@@ -5464,7 +5632,7 @@ var Datalyr = (function (exports) {
|
|
|
5464
5632
|
// SDK metadata. MUST stay in sync with package.json "version" — the build guard
|
|
5465
5633
|
// (scripts/check-bundle.js, run by build:check) fails the build if the bundle's
|
|
5466
5634
|
// sdk_version doesn't match package.json. (FSR-103)
|
|
5467
|
-
sdk_version: '1.7.
|
|
5635
|
+
sdk_version: '1.7.4',
|
|
5468
5636
|
sdk_name: 'datalyr-web-sdk'
|
|
5469
5637
|
};
|
|
5470
5638
|
return payload;
|
|
@@ -5685,6 +5853,10 @@ var Datalyr = (function (exports) {
|
|
|
5685
5853
|
this.outboundDisposer();
|
|
5686
5854
|
this.outboundDisposer = undefined;
|
|
5687
5855
|
}
|
|
5856
|
+
if (this.stripeLinksDisposer) {
|
|
5857
|
+
this.stripeLinksDisposer();
|
|
5858
|
+
this.stripeLinksDisposer = undefined;
|
|
5859
|
+
}
|
|
5688
5860
|
// Clean up queue
|
|
5689
5861
|
if (this.queue) {
|
|
5690
5862
|
this.queue.destroy();
|