@crelora/mark 0.0.18 → 0.1.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 +38 -11
- package/dist/browser.es.js +618 -124
- package/dist/browser.es.js.map +1 -0
- package/dist/browser.umd.js +2 -1
- package/dist/browser.umd.js.map +1 -0
- package/dist/node.cjs +2 -1
- package/dist/node.cjs.map +1 -0
- package/dist/node.es.js +431 -66
- package/dist/node.es.js.map +1 -0
- package/dist/types/browser/BrowserStorage.d.ts +12 -0
- package/dist/types/browser/Mark.d.ts +18 -0
- package/dist/types/core/DeliveryQueue.d.ts +57 -0
- package/dist/types/core/HttpTransport.d.ts +6 -2
- package/dist/types/core/MarkCore.d.ts +46 -2
- package/dist/types/core/TransportError.d.ts +15 -0
- package/dist/types/core/adapters.d.ts +14 -1
- package/dist/types/node/StatelessStorage.d.ts +7 -0
- package/dist/types/node/index.d.ts +8 -0
- package/dist/types/types.d.ts +37 -0
- package/dist/web-vitals-CrnTllyu.js +221 -0
- package/dist/web-vitals-CrnTllyu.js.map +1 -0
- package/package.json +18 -2
package/dist/node.es.js
CHANGED
|
@@ -1,4 +1,153 @@
|
|
|
1
|
-
const
|
|
1
|
+
const p = "https://ingest.onelence.com";
|
|
2
|
+
class f extends Error {
|
|
3
|
+
status;
|
|
4
|
+
retryAfterMs;
|
|
5
|
+
constructor(t, e = {}) {
|
|
6
|
+
super(t), this.name = "TransportError", this.status = e.status, this.retryAfterMs = e.retryAfterMs;
|
|
7
|
+
}
|
|
8
|
+
}
|
|
9
|
+
function m(a) {
|
|
10
|
+
return !(typeof a != "number" || a < 400 || a >= 500 || a === 408 || a === 429);
|
|
11
|
+
}
|
|
12
|
+
function y(a) {
|
|
13
|
+
if (!a) return;
|
|
14
|
+
const t = a.trim();
|
|
15
|
+
if (!t) return;
|
|
16
|
+
const e = Number(t);
|
|
17
|
+
if (Number.isFinite(e) && e >= 0)
|
|
18
|
+
return Math.floor(e * 1e3);
|
|
19
|
+
const s = Date.parse(t);
|
|
20
|
+
if (Number.isFinite(s)) {
|
|
21
|
+
const i = s - Date.now();
|
|
22
|
+
return i > 0 ? i : 0;
|
|
23
|
+
}
|
|
24
|
+
}
|
|
25
|
+
const w = 5, b = 300, k = 15e3, v = 2880 * 60 * 1e3;
|
|
26
|
+
class M {
|
|
27
|
+
constructor(t, e = {}) {
|
|
28
|
+
this.transport = t, this.maxAttempts = e.maxAttempts ?? w, this.baseBackoffMs = e.baseBackoffMs ?? b, this.maxBackoffMs = e.maxBackoffMs ?? k, this.maxItemAgeMs = e.maxItemAgeMs ?? v, this.debug = e.debug ?? !1, this.loadPersisted = e.loadPersisted, this.savePersisted = e.savePersisted, this.onError = e.onError;
|
|
29
|
+
const s = this.loadPersisted?.() ?? [];
|
|
30
|
+
if (s.length > 0) {
|
|
31
|
+
const i = Date.now();
|
|
32
|
+
for (const o of s) {
|
|
33
|
+
const n = o.enqueuedAt ?? i;
|
|
34
|
+
if (i - n > this.maxItemAgeMs) {
|
|
35
|
+
this.dropped += 1;
|
|
36
|
+
continue;
|
|
37
|
+
}
|
|
38
|
+
this.queue.push({ ...o, enqueuedAt: n });
|
|
39
|
+
}
|
|
40
|
+
this.persist();
|
|
41
|
+
}
|
|
42
|
+
}
|
|
43
|
+
queue = [];
|
|
44
|
+
flushing = !1;
|
|
45
|
+
sent = 0;
|
|
46
|
+
failed = 0;
|
|
47
|
+
dropped = 0;
|
|
48
|
+
maxAttempts;
|
|
49
|
+
baseBackoffMs;
|
|
50
|
+
maxBackoffMs;
|
|
51
|
+
maxItemAgeMs;
|
|
52
|
+
debug;
|
|
53
|
+
loadPersisted;
|
|
54
|
+
savePersisted;
|
|
55
|
+
onError;
|
|
56
|
+
enqueue(t, e) {
|
|
57
|
+
this.queue.push({
|
|
58
|
+
path: t,
|
|
59
|
+
data: e,
|
|
60
|
+
attempts: 0,
|
|
61
|
+
nextAttemptAt: Date.now(),
|
|
62
|
+
enqueuedAt: Date.now()
|
|
63
|
+
}), this.persist(), this.process();
|
|
64
|
+
}
|
|
65
|
+
async flush() {
|
|
66
|
+
await this.process(!0), await this.transport.flush?.();
|
|
67
|
+
}
|
|
68
|
+
/**
|
|
69
|
+
* Best-effort synchronous drain using sendBeacon. Intended for page unload;
|
|
70
|
+
* errors are swallowed because the tab is going away.
|
|
71
|
+
*/
|
|
72
|
+
drainViaBeacon() {
|
|
73
|
+
if (this.queue.length === 0) return;
|
|
74
|
+
const t = this.queue.splice(0, this.queue.length);
|
|
75
|
+
this.persist();
|
|
76
|
+
for (const e of t) {
|
|
77
|
+
const s = { ...e.data };
|
|
78
|
+
delete s.__prefer_beacon;
|
|
79
|
+
try {
|
|
80
|
+
this.transport.send(e.path, s, { preferBeacon: !0 });
|
|
81
|
+
} catch {
|
|
82
|
+
}
|
|
83
|
+
}
|
|
84
|
+
}
|
|
85
|
+
getStats() {
|
|
86
|
+
return {
|
|
87
|
+
queued: this.queue.length,
|
|
88
|
+
sent: this.sent,
|
|
89
|
+
failed: this.failed,
|
|
90
|
+
dropped: this.dropped
|
|
91
|
+
};
|
|
92
|
+
}
|
|
93
|
+
clear() {
|
|
94
|
+
this.queue.splice(0, this.queue.length), this.persist();
|
|
95
|
+
}
|
|
96
|
+
persist() {
|
|
97
|
+
this.savePersisted?.(this.queue);
|
|
98
|
+
}
|
|
99
|
+
evictExpired() {
|
|
100
|
+
if (this.queue.length === 0) return;
|
|
101
|
+
const e = Date.now() - this.maxItemAgeMs;
|
|
102
|
+
let s = 0;
|
|
103
|
+
for (let i = this.queue.length - 1; i >= 0; i -= 1)
|
|
104
|
+
this.queue[i].enqueuedAt <= e && (this.queue.splice(i, 1), this.dropped += 1, s += 1);
|
|
105
|
+
s > 0 && this.persist();
|
|
106
|
+
}
|
|
107
|
+
async process(t = !1) {
|
|
108
|
+
if (!this.flushing) {
|
|
109
|
+
this.flushing = !0;
|
|
110
|
+
try {
|
|
111
|
+
for (this.evictExpired(); this.queue.length > 0; ) {
|
|
112
|
+
const e = this.queue[0];
|
|
113
|
+
if (!t && e.nextAttemptAt > Date.now())
|
|
114
|
+
break;
|
|
115
|
+
try {
|
|
116
|
+
const s = { ...e.data }, i = s.__prefer_beacon === !0;
|
|
117
|
+
delete s.__prefer_beacon, await this.transport.send(e.path, s, { preferBeacon: i }), this.queue.shift(), this.sent += 1, this.persist();
|
|
118
|
+
} catch (s) {
|
|
119
|
+
this.failed += 1, this.onError?.(s, e.data);
|
|
120
|
+
const i = s instanceof f ? s.status : void 0;
|
|
121
|
+
if (m(i)) {
|
|
122
|
+
this.queue.shift(), this.dropped += 1, this.persist(), this.debug && console.error("[Mark] Dropping event after non-retriable status", i, e.path);
|
|
123
|
+
continue;
|
|
124
|
+
}
|
|
125
|
+
if (e.attempts += 1, e.attempts >= this.maxAttempts) {
|
|
126
|
+
this.queue.shift(), this.dropped += 1, this.persist(), this.debug && console.error("[Mark] Dropping event after max retries", e.path, s);
|
|
127
|
+
continue;
|
|
128
|
+
}
|
|
129
|
+
const o = s instanceof f ? s.retryAfterMs : void 0;
|
|
130
|
+
let n;
|
|
131
|
+
if (typeof o == "number")
|
|
132
|
+
n = Math.min(this.maxBackoffMs, Math.max(0, o));
|
|
133
|
+
else {
|
|
134
|
+
const r = Math.random() * this.baseBackoffMs;
|
|
135
|
+
n = Math.min(
|
|
136
|
+
this.maxBackoffMs,
|
|
137
|
+
this.baseBackoffMs * 2 ** (e.attempts - 1) + r
|
|
138
|
+
);
|
|
139
|
+
}
|
|
140
|
+
e.nextAttemptAt = Date.now() + n, this.persist();
|
|
141
|
+
break;
|
|
142
|
+
}
|
|
143
|
+
}
|
|
144
|
+
} finally {
|
|
145
|
+
this.flushing = !1;
|
|
146
|
+
}
|
|
147
|
+
}
|
|
148
|
+
}
|
|
149
|
+
}
|
|
150
|
+
const I = /* @__PURE__ */ new Set(["event_name", "user_id", "consent_state", "source", "is_conversion"]), q = /* @__PURE__ */ new Set([
|
|
2
151
|
"user_id",
|
|
3
152
|
"visitor_id",
|
|
4
153
|
"click_id",
|
|
@@ -7,56 +156,94 @@ const d = "https://ingest.onelence.com", u = /* @__PURE__ */ new Set(["event_nam
|
|
|
7
156
|
"consent_state",
|
|
8
157
|
"source"
|
|
9
158
|
]);
|
|
10
|
-
class
|
|
159
|
+
class A {
|
|
11
160
|
constructor(t, e) {
|
|
12
161
|
this.deps = e, this.validateConfig(t), this.config = {
|
|
13
|
-
endpoint: t.endpoint ??
|
|
162
|
+
endpoint: t.endpoint ?? p,
|
|
14
163
|
...t,
|
|
15
164
|
include_page_context: t.include_page_context ?? !0
|
|
16
|
-
}, this.consentRequirement = t.require_consent ?? !1, this.siteId = t.site_id, this.siteHost = t.site_host
|
|
165
|
+
}, this.consentRequirement = t.require_consent ?? !1, this.siteId = t.site_id, this.siteHost = t.site_host, this.sessionTimeoutMs = t.session_timeout_ms ?? 1800 * 1e3, this.queue = new M(this.deps.transport, {
|
|
166
|
+
debug: this.config.debug,
|
|
167
|
+
loadPersisted: () => this.deps.storage.getOutbox?.() ?? [],
|
|
168
|
+
savePersisted: (s) => this.deps.storage.setOutbox?.(s),
|
|
169
|
+
onError: (s, i) => this.config.on_error?.(s, i)
|
|
170
|
+
}), this.warnMisconfiguredSiteHost(), this.subscribeTcf();
|
|
17
171
|
}
|
|
18
172
|
config;
|
|
19
173
|
consentRequirement;
|
|
20
174
|
siteId;
|
|
21
175
|
siteHost;
|
|
176
|
+
queue;
|
|
177
|
+
sessionTimeoutMs;
|
|
178
|
+
batchTimer = null;
|
|
179
|
+
batchedEvents = [];
|
|
180
|
+
tcfCachedAllowed = !1;
|
|
181
|
+
/**
|
|
182
|
+
* Best-effort synchronous drain that dispatches all queued events via
|
|
183
|
+
* sendBeacon. Intended for use on page unload (visibilitychange=hidden,
|
|
184
|
+
* pagehide) where async fetch may be cancelled by the browser.
|
|
185
|
+
*/
|
|
186
|
+
drainViaBeacon() {
|
|
187
|
+
this.flushBatch(), this.queue.drainViaBeacon();
|
|
188
|
+
}
|
|
189
|
+
/**
|
|
190
|
+
* Kicks the queue to retry any pending items now. Safe to call repeatedly;
|
|
191
|
+
* used by the browser wrapper in response to `online` events or periodic
|
|
192
|
+
* timers.
|
|
193
|
+
*/
|
|
194
|
+
kickQueue() {
|
|
195
|
+
this.queue.flush();
|
|
196
|
+
}
|
|
22
197
|
track(t, e = {}) {
|
|
23
198
|
return this.trackInternal(t, e, !1);
|
|
24
199
|
}
|
|
25
|
-
trackInternal(t, e = {}, s = !1) {
|
|
200
|
+
trackInternal(t, e = {}, s = !1, i) {
|
|
26
201
|
if (!t)
|
|
27
202
|
return this.config.debug && console.warn("[Mark] track called without event name"), !1;
|
|
28
|
-
if (!this.hasConsent())
|
|
203
|
+
if (!this.hasConsent() || this.isDntBlocked())
|
|
29
204
|
return this.config.debug && console.warn("[Mark] Tracking blocked due to consent requirement."), !1;
|
|
30
|
-
|
|
31
|
-
|
|
32
|
-
const n = {
|
|
205
|
+
if (!s && !this.shouldSampleTrack())
|
|
206
|
+
return !0;
|
|
207
|
+
const o = this.sanitizeTrackData(e), n = { ...o };
|
|
208
|
+
"query" in n && delete n.query, "site_id" in n && delete n.site_id, "site_host" in n && delete n.site_host;
|
|
209
|
+
const r = {
|
|
33
210
|
event_name: t,
|
|
34
|
-
|
|
35
|
-
...
|
|
211
|
+
message_id: this.createMessageId(),
|
|
212
|
+
...this.getIdentityFields(o),
|
|
213
|
+
...n
|
|
36
214
|
};
|
|
37
|
-
s && (
|
|
38
|
-
const
|
|
39
|
-
|
|
215
|
+
s && (r.is_conversion = !0);
|
|
216
|
+
const h = o.site_id ?? this.siteId, d = o.site_host ?? this.siteHost;
|
|
217
|
+
h && (r.site_id = h), d && (r.site_host = d), this.config.include_page_context && typeof window < "u" && (this.applyPageContext(r), !d && r.site && (r.site_host = r.site));
|
|
218
|
+
const u = this.config.before_send ? this.config.before_send(r) : r;
|
|
219
|
+
return u ? (this.ensureSession(), this.config.batching?.enabled && !s && !i?.preferBeacon ? (this.enqueueBatch(u), !0) : (this.queue.enqueue("/event", { ...u, __prefer_beacon: i?.preferBeacon === !0 }), !0)) : !0;
|
|
40
220
|
}
|
|
41
221
|
identify(t, e = {}) {
|
|
42
222
|
if (!t) {
|
|
43
223
|
this.config.debug && console.warn("[Mark] identify called without userId");
|
|
44
224
|
return;
|
|
45
225
|
}
|
|
46
|
-
if (!this.hasConsent()) {
|
|
226
|
+
if (!this.hasConsent() || this.isDntBlocked()) {
|
|
47
227
|
this.config.debug && console.warn("[Mark] Identify blocked due to consent requirement.");
|
|
48
228
|
return;
|
|
49
229
|
}
|
|
230
|
+
this.deps.storage.update({ user_id: t });
|
|
50
231
|
const s = {
|
|
51
232
|
user_id: t,
|
|
233
|
+
message_id: this.createMessageId(),
|
|
52
234
|
...this.sanitizeIdentifyTraits(e),
|
|
53
235
|
...this.getIdentityFields()
|
|
54
236
|
};
|
|
55
|
-
this.siteId && (s.site_id = this.siteId), this.siteHost && (s.site_host = this.siteHost)
|
|
237
|
+
this.siteId && (s.site_id = this.siteId), this.siteHost && (s.site_host = this.siteHost);
|
|
238
|
+
const i = this.config.before_send ? this.config.before_send(s) : s;
|
|
239
|
+
i && this.queue.enqueue("/identify", i);
|
|
56
240
|
}
|
|
57
241
|
conversion(t, e = {}) {
|
|
58
242
|
return this.trackInternal(t, e, !0);
|
|
59
243
|
}
|
|
244
|
+
trackWithOptions(t, e = {}, s) {
|
|
245
|
+
return this.trackInternal(t, e, !1, s);
|
|
246
|
+
}
|
|
60
247
|
/**
|
|
61
248
|
* Returns the current visitor ID from storage, if any.
|
|
62
249
|
* Used by browser/Node wrappers to expose a stable pseudonymous ID for server-side attribution.
|
|
@@ -65,19 +252,42 @@ class l {
|
|
|
65
252
|
return this.deps.storage.getVisitorId();
|
|
66
253
|
}
|
|
67
254
|
setConsent(t) {
|
|
68
|
-
this.deps.storage.
|
|
69
|
-
|
|
255
|
+
const e = this.deps.storage.getConsentStatus();
|
|
256
|
+
this.deps.storage.setConsentStatus(t), t === "denied" ? (this.deps.storage.clearAttribution?.(), this.deps.storage.clearCookieVisitorId?.()) : t === "granted" && e === "denied" && this.config.rotate_visitor_on_consent_change && this.deps.storage.rotateVisitorId?.();
|
|
257
|
+
const s = {
|
|
70
258
|
visitor_id: this.deps.storage.getVisitorId(),
|
|
71
259
|
consent_state: t,
|
|
72
|
-
source: "sdk"
|
|
260
|
+
source: "sdk",
|
|
261
|
+
message_id: this.createMessageId()
|
|
73
262
|
};
|
|
74
|
-
this.siteId && (
|
|
263
|
+
this.siteId && (s.site_id = this.siteId), this.siteHost && (s.site_host = this.siteHost);
|
|
264
|
+
const i = this.config.before_send ? this.config.before_send(s) : s;
|
|
265
|
+
i && this.queue.enqueue("/consent", i);
|
|
266
|
+
}
|
|
267
|
+
reset() {
|
|
268
|
+
this.deps.storage.update({
|
|
269
|
+
user_id: void 0,
|
|
270
|
+
last_click_id: void 0,
|
|
271
|
+
campaign_id: void 0,
|
|
272
|
+
query_params: void 0,
|
|
273
|
+
session_id: void 0,
|
|
274
|
+
session_started_at: void 0,
|
|
275
|
+
last_activity_at: void 0
|
|
276
|
+
}), this.deps.storage.rotateVisitorId?.();
|
|
277
|
+
}
|
|
278
|
+
flush() {
|
|
279
|
+
return this.flushBatch(), this.queue.flush();
|
|
280
|
+
}
|
|
281
|
+
getStats() {
|
|
282
|
+
return this.queue.getStats();
|
|
75
283
|
}
|
|
76
284
|
getIdentityFields(t) {
|
|
77
|
-
const e = t?.visitor_id ?? this.deps.storage.getVisitorId(), s = t?.click_id ?? this.deps.storage.getLastClickId(),
|
|
78
|
-
return e && (
|
|
285
|
+
const e = t?.visitor_id ?? this.deps.storage.getVisitorId(), s = t?.user_id ?? this.deps.storage.getUserId?.(), i = t?.click_id ?? this.deps.storage.getLastClickId(), o = t?.campaign_id ?? this.deps.storage.getCampaignId(), n = t?.session_id ?? this.deps.storage.getSessionId?.(), r = this.deps.storage.getQueryParams() ?? {}, h = t?.query ?? {}, d = { ...r, ...h }, u = {};
|
|
286
|
+
return e && (u.visitor_id = e), s && (u.user_id = s), i && (u.click_id = i), o && (u.campaign_id = o), n && (u.session_id = n), Object.keys(d).length > 0 && (u.query = d), u;
|
|
79
287
|
}
|
|
80
288
|
hasConsent() {
|
|
289
|
+
if (this.config.consent_source?.type === "tcf" && typeof window < "u" && !this.tcfCachedAllowed)
|
|
290
|
+
return !1;
|
|
81
291
|
if (!this.consentRequirement)
|
|
82
292
|
return !0;
|
|
83
293
|
const e = this.deps.storage.getConsentStatus();
|
|
@@ -86,13 +296,13 @@ class l {
|
|
|
86
296
|
sanitizeTrackData(t) {
|
|
87
297
|
const e = {};
|
|
88
298
|
for (const [s, i] of Object.entries(t))
|
|
89
|
-
|
|
299
|
+
I.has(s) || (e[s] = i);
|
|
90
300
|
return e;
|
|
91
301
|
}
|
|
92
302
|
sanitizeIdentifyTraits(t) {
|
|
93
303
|
const e = {};
|
|
94
304
|
for (const [s, i] of Object.entries(t))
|
|
95
|
-
|
|
305
|
+
q.has(s) || (e[s] = i);
|
|
96
306
|
return e;
|
|
97
307
|
}
|
|
98
308
|
validateConfig(t) {
|
|
@@ -110,42 +320,175 @@ class l {
|
|
|
110
320
|
throw new Error("[Mark] `site_host` cannot be an empty string.");
|
|
111
321
|
}
|
|
112
322
|
applyPageContext(t) {
|
|
113
|
-
|
|
323
|
+
typeof document > "u" || (t.site || (t.site = window.location.host), t.page || (t.page = window.location.pathname), t.title || (t.title = document.title), !t.referrer && document.referrer && (t.referrer = this.scrubReferrer(document.referrer)));
|
|
324
|
+
}
|
|
325
|
+
enqueueBatch(t) {
|
|
326
|
+
this.batchedEvents.push(t);
|
|
327
|
+
const e = this.config.batching?.max_size ?? 20;
|
|
328
|
+
if (this.batchedEvents.length >= e) {
|
|
329
|
+
this.flushBatch();
|
|
330
|
+
return;
|
|
331
|
+
}
|
|
332
|
+
if (!this.batchTimer) {
|
|
333
|
+
const s = this.config.batching?.flush_interval_ms ?? 2e3;
|
|
334
|
+
this.batchTimer = setTimeout(() => {
|
|
335
|
+
this.batchTimer = null, this.flushBatch();
|
|
336
|
+
}, s);
|
|
337
|
+
}
|
|
338
|
+
}
|
|
339
|
+
flushBatch() {
|
|
340
|
+
if (this.batchedEvents.length === 0) return;
|
|
341
|
+
const t = this.config.batching?.endpoint_path ?? "/events", e = this.batchedEvents.splice(0, this.batchedEvents.length);
|
|
342
|
+
this.queue.enqueue(t, { events: e, message_id: this.createMessageId() });
|
|
343
|
+
}
|
|
344
|
+
createMessageId() {
|
|
345
|
+
return typeof crypto < "u" && typeof crypto.randomUUID == "function" ? crypto.randomUUID() : `msg_${Date.now()}_${Math.random().toString(16).slice(2)}`;
|
|
346
|
+
}
|
|
347
|
+
ensureSession() {
|
|
348
|
+
const t = Date.now(), e = this.deps.storage.getSessionId?.(), s = this.deps.storage.getLastActivityAt?.(), i = s ? Date.parse(s) : 0;
|
|
349
|
+
if (!e || !i || t - i >= this.sessionTimeoutMs || this.crossedUtcDay(i, t)) {
|
|
350
|
+
const n = this.createMessageId(), r = new Date(t).toISOString();
|
|
351
|
+
this.deps.storage.update({
|
|
352
|
+
session_id: n,
|
|
353
|
+
session_started_at: r,
|
|
354
|
+
last_activity_at: r
|
|
355
|
+
});
|
|
356
|
+
return;
|
|
357
|
+
}
|
|
358
|
+
this.deps.storage.update({ last_activity_at: new Date(t).toISOString() });
|
|
359
|
+
}
|
|
360
|
+
crossedUtcDay(t, e) {
|
|
361
|
+
const s = new Date(t), i = new Date(e);
|
|
362
|
+
return s.getUTCFullYear() !== i.getUTCFullYear() || s.getUTCMonth() !== i.getUTCMonth() || s.getUTCDate() !== i.getUTCDate();
|
|
363
|
+
}
|
|
364
|
+
shouldSampleTrack() {
|
|
365
|
+
return typeof this.config.sample_rate != "number" ? !0 : this.config.sample_rate <= 0 ? !1 : this.config.sample_rate >= 1 ? !0 : Math.random() <= this.config.sample_rate;
|
|
366
|
+
}
|
|
367
|
+
isDntBlocked() {
|
|
368
|
+
if (!this.config.honor_dnt || typeof navigator > "u")
|
|
369
|
+
return !1;
|
|
370
|
+
const t = navigator.doNotTrack, e = navigator.globalPrivacyControl;
|
|
371
|
+
return t === "1" || e === !0;
|
|
372
|
+
}
|
|
373
|
+
scrubReferrer(t) {
|
|
374
|
+
try {
|
|
375
|
+
const e = new URL(t);
|
|
376
|
+
if (typeof window > "u") return t;
|
|
377
|
+
const s = new URL(window.location.href);
|
|
378
|
+
return e.origin !== s.origin ? (e.search = "", e.toString()) : t;
|
|
379
|
+
} catch {
|
|
380
|
+
return t;
|
|
381
|
+
}
|
|
382
|
+
}
|
|
383
|
+
warnMisconfiguredSiteHost() {
|
|
384
|
+
!this.config.debug || !this.siteHost || typeof window > "u" || (window.location.host !== this.siteHost && console.warn("[Mark] config.site_host does not match current host", {
|
|
385
|
+
expected: this.siteHost,
|
|
386
|
+
actual: window.location.host
|
|
387
|
+
}), this.siteId && !/^[0-9a-f]{8}-[0-9a-f]{4}-[1-5][0-9a-f]{3}-[89ab][0-9a-f]{3}-[0-9a-f]{12}$/i.test(this.siteId) && console.warn("[Mark] config.site_id does not look like UUID v4", this.siteId));
|
|
388
|
+
}
|
|
389
|
+
/**
|
|
390
|
+
* Subscribes to the IAB TCF v2 CMP via `__tcfapi('addEventListener', ...)`.
|
|
391
|
+
* Result is cached in `tcfCachedAllowed` so the synchronous `hasConsent()`
|
|
392
|
+
* path does not need to await the CMP. If the CMP is not yet present, we
|
|
393
|
+
* poll briefly (CMPs commonly load asynchronously) and give up after ~2s.
|
|
394
|
+
*/
|
|
395
|
+
subscribeTcf() {
|
|
396
|
+
const t = this.config.consent_source;
|
|
397
|
+
if (t?.type !== "tcf" || typeof window > "u") return;
|
|
398
|
+
const e = t.purposes, s = (i) => {
|
|
399
|
+
try {
|
|
400
|
+
const o = window;
|
|
401
|
+
if (typeof o.__tcfapi != "function") {
|
|
402
|
+
i > 0 && setTimeout(() => s(i - 1), 200);
|
|
403
|
+
return;
|
|
404
|
+
}
|
|
405
|
+
o.__tcfapi("addEventListener", 2, (n, r) => {
|
|
406
|
+
if (!r || !n) {
|
|
407
|
+
this.tcfCachedAllowed = !1;
|
|
408
|
+
return;
|
|
409
|
+
}
|
|
410
|
+
if (n.gdprApplies === !1) {
|
|
411
|
+
this.tcfCachedAllowed = !0;
|
|
412
|
+
return;
|
|
413
|
+
}
|
|
414
|
+
const h = n.purpose?.consents ?? {};
|
|
415
|
+
this.tcfCachedAllowed = e.every((d) => h[String(d)] === !0);
|
|
416
|
+
});
|
|
417
|
+
} catch {
|
|
418
|
+
this.tcfCachedAllowed = !1;
|
|
419
|
+
}
|
|
420
|
+
};
|
|
421
|
+
s(10);
|
|
114
422
|
}
|
|
115
423
|
}
|
|
116
|
-
class
|
|
424
|
+
class D {
|
|
117
425
|
config;
|
|
118
426
|
endpoint;
|
|
427
|
+
pending = /* @__PURE__ */ new Set();
|
|
119
428
|
constructor(t) {
|
|
120
|
-
this.
|
|
429
|
+
this.config = t, this.endpoint = t.endpoint ?? p;
|
|
121
430
|
}
|
|
122
|
-
async send(t, e) {
|
|
123
|
-
const
|
|
431
|
+
async send(t, e, s) {
|
|
432
|
+
const i = this.sendInternal(t, e, s);
|
|
433
|
+
this.pending.add(i);
|
|
434
|
+
try {
|
|
435
|
+
await i;
|
|
436
|
+
} finally {
|
|
437
|
+
this.pending.delete(i);
|
|
438
|
+
}
|
|
439
|
+
}
|
|
440
|
+
async flush() {
|
|
441
|
+
this.pending.size !== 0 && await Promise.allSettled(Array.from(this.pending));
|
|
442
|
+
}
|
|
443
|
+
async sendInternal(t, e, s) {
|
|
444
|
+
const i = this.joinUrl(this.endpoint, t), o = this.config.key, n = {
|
|
124
445
|
"Content-Type": "application/json",
|
|
125
|
-
[
|
|
446
|
+
[o.startsWith("sk_") ? "x-secret-key" : "x-publishable-key"]: o
|
|
126
447
|
};
|
|
127
|
-
|
|
128
|
-
|
|
129
|
-
|
|
448
|
+
this.config.debug && console.log("[Mark] Sending", i, e);
|
|
449
|
+
const r = JSON.stringify(e);
|
|
450
|
+
if (s?.preferBeacon && typeof navigator < "u" && typeof navigator.sendBeacon == "function") {
|
|
451
|
+
const c = new Blob([r], { type: "application/json" });
|
|
452
|
+
if (navigator.sendBeacon(i, c))
|
|
453
|
+
return;
|
|
130
454
|
}
|
|
455
|
+
if (typeof fetch != "function")
|
|
456
|
+
throw this.config.debug && console.error("[Mark] Global fetch is not available in this runtime."), new f("[Mark] Global fetch is not available in this runtime.");
|
|
457
|
+
const h = this.config.request_timeout_ms ?? 1e4, d = new AbortController();
|
|
458
|
+
let u = !1;
|
|
459
|
+
const _ = setTimeout(() => {
|
|
460
|
+
u = !0, d.abort();
|
|
461
|
+
}, h);
|
|
131
462
|
try {
|
|
132
|
-
const
|
|
463
|
+
const c = await fetch(i, {
|
|
133
464
|
method: "POST",
|
|
134
|
-
headers:
|
|
135
|
-
body:
|
|
136
|
-
keepalive: !0
|
|
465
|
+
headers: n,
|
|
466
|
+
body: r,
|
|
467
|
+
keepalive: !0,
|
|
468
|
+
signal: d.signal
|
|
137
469
|
});
|
|
138
|
-
if (!
|
|
139
|
-
const
|
|
140
|
-
console.error("[Mark] Request rejected", {
|
|
141
|
-
url:
|
|
142
|
-
status:
|
|
143
|
-
statusText:
|
|
144
|
-
body:
|
|
145
|
-
|
|
470
|
+
if (!c.ok) {
|
|
471
|
+
const l = await this.readErrorSnippet(c), g = y(c.headers.get("Retry-After"));
|
|
472
|
+
throw this.config.debug && console.error("[Mark] Request rejected", {
|
|
473
|
+
url: i,
|
|
474
|
+
status: c.status,
|
|
475
|
+
statusText: c.statusText,
|
|
476
|
+
body: l,
|
|
477
|
+
retryAfterMs: g
|
|
478
|
+
}), new f(
|
|
479
|
+
`[Mark] Request rejected with status ${c.status}: ${l}`,
|
|
480
|
+
{ status: c.status, retryAfterMs: g }
|
|
481
|
+
);
|
|
146
482
|
}
|
|
147
|
-
} catch (
|
|
148
|
-
this.config.debug && console.error("[Mark] Failed to send",
|
|
483
|
+
} catch (c) {
|
|
484
|
+
if (this.config.debug && console.error("[Mark] Failed to send", i, c), c instanceof f)
|
|
485
|
+
throw c;
|
|
486
|
+
if (u)
|
|
487
|
+
throw new f(`[Mark] Request timed out after ${h}ms`, { status: 408 });
|
|
488
|
+
const l = c instanceof Error ? c.message : String(c);
|
|
489
|
+
throw new f(`[Mark] Network error: ${l}`);
|
|
490
|
+
} finally {
|
|
491
|
+
clearTimeout(_);
|
|
149
492
|
}
|
|
150
493
|
}
|
|
151
494
|
joinUrl(t, e) {
|
|
@@ -159,18 +502,8 @@ class f {
|
|
|
159
502
|
return "";
|
|
160
503
|
}
|
|
161
504
|
}
|
|
162
|
-
validateConfig(t) {
|
|
163
|
-
if (!t.key || !t.key.trim())
|
|
164
|
-
throw new Error("[Mark] `key` must be a non-empty string.");
|
|
165
|
-
if (t.endpoint)
|
|
166
|
-
try {
|
|
167
|
-
new URL(t.endpoint);
|
|
168
|
-
} catch {
|
|
169
|
-
throw new Error("[Mark] `endpoint` must be a valid absolute URL.");
|
|
170
|
-
}
|
|
171
|
-
}
|
|
172
505
|
}
|
|
173
|
-
class
|
|
506
|
+
class S {
|
|
174
507
|
constructor(t = {}) {
|
|
175
508
|
this.defaults = t;
|
|
176
509
|
}
|
|
@@ -186,6 +519,18 @@ class _ {
|
|
|
186
519
|
getQueryParams() {
|
|
187
520
|
return this.defaults.query_params;
|
|
188
521
|
}
|
|
522
|
+
getUserId() {
|
|
523
|
+
return this.defaults.user_id;
|
|
524
|
+
}
|
|
525
|
+
getSessionId() {
|
|
526
|
+
return this.defaults.session_id;
|
|
527
|
+
}
|
|
528
|
+
getSessionStartedAt() {
|
|
529
|
+
return this.defaults.session_started_at;
|
|
530
|
+
}
|
|
531
|
+
getLastActivityAt() {
|
|
532
|
+
return this.defaults.last_activity_at;
|
|
533
|
+
}
|
|
189
534
|
getConsentStatus() {
|
|
190
535
|
return this.defaults.consent_status;
|
|
191
536
|
}
|
|
@@ -193,8 +538,14 @@ class _ {
|
|
|
193
538
|
}
|
|
194
539
|
setConsentStatus() {
|
|
195
540
|
}
|
|
541
|
+
clearAttribution() {
|
|
542
|
+
}
|
|
543
|
+
clearCookieVisitorId() {
|
|
544
|
+
}
|
|
545
|
+
rotateVisitorId() {
|
|
546
|
+
}
|
|
196
547
|
}
|
|
197
|
-
class
|
|
548
|
+
class T {
|
|
198
549
|
constructor(t) {
|
|
199
550
|
this.client = t;
|
|
200
551
|
}
|
|
@@ -210,6 +561,15 @@ class g {
|
|
|
210
561
|
setConsent(t) {
|
|
211
562
|
this.client.setConsent(t);
|
|
212
563
|
}
|
|
564
|
+
flush() {
|
|
565
|
+
return this.client.flush();
|
|
566
|
+
}
|
|
567
|
+
reset() {
|
|
568
|
+
this.client.reset();
|
|
569
|
+
}
|
|
570
|
+
getStats() {
|
|
571
|
+
return this.client.getStats();
|
|
572
|
+
}
|
|
213
573
|
/**
|
|
214
574
|
* Returns the visitor ID from the configured storage, if any.
|
|
215
575
|
* With default StatelessStorage, this is the value passed via `storageDefaults.visitor_id` when creating the client.
|
|
@@ -219,18 +579,23 @@ class g {
|
|
|
219
579
|
return this.client.getVisitorId();
|
|
220
580
|
}
|
|
221
581
|
}
|
|
222
|
-
const
|
|
223
|
-
const e = t.storage ?? new
|
|
582
|
+
const E = (a, t = {}) => {
|
|
583
|
+
const e = t.storage ?? new S({
|
|
224
584
|
visitor_id: t.storageDefaults?.visitor_id,
|
|
585
|
+
user_id: t.storageDefaults?.user_id,
|
|
586
|
+
session_id: t.storageDefaults?.session_id,
|
|
587
|
+
session_started_at: t.storageDefaults?.session_started_at,
|
|
588
|
+
last_activity_at: t.storageDefaults?.last_activity_at,
|
|
225
589
|
last_click_id: t.storageDefaults?.last_click_id,
|
|
226
590
|
campaign_id: t.storageDefaults?.campaign_id,
|
|
227
591
|
query_params: t.storageDefaults?.query_params,
|
|
228
592
|
consent_status: t.storageDefaults?.consent_status
|
|
229
|
-
}), s = t.transport ?? new
|
|
230
|
-
return new
|
|
593
|
+
}), s = t.transport ?? new D(a), i = new A(a, { storage: e, transport: s });
|
|
594
|
+
return new T(i);
|
|
231
595
|
};
|
|
232
596
|
export {
|
|
233
|
-
|
|
234
|
-
|
|
235
|
-
|
|
597
|
+
T as NodeMark,
|
|
598
|
+
S as StatelessStorage,
|
|
599
|
+
E as createNodeMark
|
|
236
600
|
};
|
|
601
|
+
//# sourceMappingURL=node.es.js.map
|