@crelora/mark 0.2.2 → 0.3.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/dist/node.es.js CHANGED
@@ -1,4 +1,4 @@
1
- const _ = "https://ingest.onelence.com";
1
+ const m = "https://ingest.onelence.com";
2
2
  class f extends Error {
3
3
  status;
4
4
  retryAfterMs;
@@ -6,10 +6,10 @@ class f extends Error {
6
6
  super(t), this.name = "TransportError", this.status = e.status, this.retryAfterMs = e.retryAfterMs;
7
7
  }
8
8
  }
9
- function m(a) {
9
+ function y(a) {
10
10
  return !(typeof a != "number" || a < 400 || a >= 500 || a === 408 || a === 429);
11
11
  }
12
- function y(a) {
12
+ function w(a) {
13
13
  if (!a) return;
14
14
  const t = a.trim();
15
15
  if (!t) return;
@@ -22,20 +22,20 @@ function y(a) {
22
22
  return i > 0 ? i : 0;
23
23
  }
24
24
  }
25
- const w = 5, I = 300, b = 15e3, k = 2880 * 60 * 1e3;
26
- class v {
25
+ const I = 5, v = 300, b = 15e3, k = 2880 * 60 * 1e3;
26
+ class M {
27
27
  constructor(t, e = {}) {
28
- this.transport = t, this.maxAttempts = e.maxAttempts ?? w, this.baseBackoffMs = e.baseBackoffMs ?? I, this.maxBackoffMs = e.maxBackoffMs ?? b, this.maxItemAgeMs = e.maxItemAgeMs ?? k, this.debug = e.debug ?? !1, this.loadPersisted = e.loadPersisted, this.savePersisted = e.savePersisted, this.onError = e.onError;
28
+ this.transport = t, this.maxAttempts = e.maxAttempts ?? I, this.baseBackoffMs = e.baseBackoffMs ?? v, this.maxBackoffMs = e.maxBackoffMs ?? b, this.maxItemAgeMs = e.maxItemAgeMs ?? k, this.debug = e.debug ?? !1, this.loadPersisted = e.loadPersisted, this.savePersisted = e.savePersisted, this.onError = e.onError;
29
29
  const s = this.loadPersisted?.() ?? [];
30
30
  if (s.length > 0) {
31
31
  const i = Date.now();
32
- for (const o of s) {
33
- const n = o.enqueuedAt ?? i;
34
- if (i - n > this.maxItemAgeMs) {
32
+ for (const n of s) {
33
+ const r = n.enqueuedAt ?? i;
34
+ if (i - r > this.maxItemAgeMs) {
35
35
  this.dropped += 1;
36
36
  continue;
37
37
  }
38
- this.queue.push({ ...o, enqueuedAt: n });
38
+ this.queue.push({ ...n, enqueuedAt: r });
39
39
  }
40
40
  this.persist();
41
41
  }
@@ -118,7 +118,7 @@ class v {
118
118
  } catch (s) {
119
119
  this.failed += 1, this.onError?.(s, e.data);
120
120
  const i = s instanceof f ? s.status : void 0;
121
- if (m(i)) {
121
+ if (y(i)) {
122
122
  this.queue.shift(), this.dropped += 1, this.persist(), this.debug && console.error("[Mark] Dropping event after non-retriable status", i, e.path);
123
123
  continue;
124
124
  }
@@ -126,18 +126,18 @@ class v {
126
126
  this.queue.shift(), this.dropped += 1, this.persist(), this.debug && console.error("[Mark] Dropping event after max retries", e.path, s);
127
127
  continue;
128
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));
129
+ const n = s instanceof f ? s.retryAfterMs : void 0;
130
+ let r;
131
+ if (typeof n == "number")
132
+ r = Math.min(this.maxBackoffMs, Math.max(0, n));
133
133
  else {
134
- const r = Math.random() * this.baseBackoffMs;
135
- n = Math.min(
134
+ const o = Math.random() * this.baseBackoffMs;
135
+ r = Math.min(
136
136
  this.maxBackoffMs,
137
- this.baseBackoffMs * 2 ** (e.attempts - 1) + r
137
+ this.baseBackoffMs * 2 ** (e.attempts - 1) + o
138
138
  );
139
139
  }
140
- e.nextAttemptAt = Date.now() + n, this.persist();
140
+ e.nextAttemptAt = Date.now() + r, this.persist();
141
141
  break;
142
142
  }
143
143
  }
@@ -147,7 +147,15 @@ class v {
147
147
  }
148
148
  }
149
149
  }
150
- const M = /* @__PURE__ */ new Set(["event_name", "user_id", "consent_state", "source", "is_conversion"]), A = /* @__PURE__ */ new Set([
150
+ const A = 256;
151
+ function p(a) {
152
+ if (typeof a != "string")
153
+ return;
154
+ const t = a.trim();
155
+ if (!(!t || t.length > A) && !t.includes("@") && !/\s/.test(t))
156
+ return t;
157
+ }
158
+ const S = /* @__PURE__ */ new Set(["event_name", "user_id", "consent_state", "source", "is_conversion"]), q = /* @__PURE__ */ new Set([
151
159
  "user_id",
152
160
  "visitor_id",
153
161
  "click_id",
@@ -156,13 +164,13 @@ const M = /* @__PURE__ */ new Set(["event_name", "user_id", "consent_state", "so
156
164
  "consent_state",
157
165
  "source"
158
166
  ]);
159
- class q {
167
+ class D {
160
168
  constructor(t, e) {
161
169
  this.deps = e, this.validateConfig(t), this.config = {
162
- endpoint: t.endpoint ?? _,
170
+ endpoint: t.endpoint ?? m,
163
171
  ...t,
164
172
  include_page_context: t.include_page_context ?? !0
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 v(this.deps.transport, {
173
+ }, 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
174
  debug: this.config.debug,
167
175
  loadPersisted: () => this.deps.storage.getOutbox?.() ?? [],
168
176
  savePersisted: (s) => this.deps.storage.setOutbox?.(s),
@@ -204,19 +212,19 @@ class q {
204
212
  return this.config.debug && console.warn("[Mark] Tracking blocked due to consent requirement."), !1;
205
213
  if (!s && !this.shouldSampleTrack())
206
214
  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 = {
215
+ const n = this.sanitizeTrackData(e), r = { ...n };
216
+ "query" in r && delete r.query, "site_id" in r && delete r.site_id, "site_host" in r && delete r.site_host;
217
+ const o = {
210
218
  event_name: t,
211
219
  message_id: this.createMessageId(),
212
- ...this.getIdentityFields(o),
213
- ...n
220
+ ...this.getIdentityFields(n),
221
+ ...r
214
222
  };
215
- s && (r.is_conversion = !0);
216
- const h = o.site_id ?? this.siteId, u = o.site_host ?? this.siteHost;
217
- h && (r.site_id = h), u && (r.site_host = u), this.config.include_page_context && typeof window < "u" && (this.applyPageContext(r), !u && r.site && (r.site_host = r.site)), this.applyInternalFlag(r, o.is_internal);
218
- const c = this.config.before_send ? this.config.before_send(r) : r;
219
- return c ? (this.ensureSession(), this.applySessionFields(c), this.config.batching?.enabled && !s && !i?.preferBeacon ? (this.enqueueBatch(c), !0) : (this.queue.enqueue("/event", { ...c, __prefer_beacon: i?.preferBeacon === !0 }), !0)) : !0;
223
+ s && (o.is_conversion = !0);
224
+ const h = n.site_id ?? this.siteId, u = n.site_host ?? this.siteHost;
225
+ h && (o.site_id = h), u && (o.site_host = u), this.config.include_page_context && typeof window < "u" && (this.applyPageContext(o), !u && o.site && (o.site_host = o.site)), this.applyInternalFlag(o, n.is_internal);
226
+ const d = this.config.before_send ? this.config.before_send(o) : o;
227
+ return d ? (this.ensureSession(), this.applySessionFields(d), this.config.batching?.enabled && !s && !i?.preferBeacon ? (this.enqueueBatch(d), !0) : (this.queue.enqueue("/event", { ...d, __prefer_beacon: i?.preferBeacon === !0 }), !0)) : !0;
220
228
  }
221
229
  identify(t, e = {}) {
222
230
  if (!t) {
@@ -251,6 +259,15 @@ class q {
251
259
  getVisitorId() {
252
260
  return this.deps.storage.getVisitorId();
253
261
  }
262
+ /**
263
+ * Adopts or replaces the stored visitor id with a trusted first-party value.
264
+ * Use when an external anonymous id (for example a platform client id) arrives
265
+ * after init. Returns false when the id is invalid.
266
+ */
267
+ setVisitorId(t) {
268
+ const e = p(t);
269
+ return e ? this.deps.storage.setVisitorId ? this.deps.storage.setVisitorId(e) : (this.deps.storage.getVisitorId() === e || this.deps.storage.update({ visitor_id: e }), !0) : (this.config.debug && console.warn("[Mark] setVisitorId called with an invalid visitor id."), !1);
270
+ }
254
271
  setConsent(t) {
255
272
  const e = this.deps.storage.getConsentStatus();
256
273
  this.deps.storage.setConsentStatus(t), t === "denied" ? (this.deps.storage.clearAttribution?.(), this.deps.storage.clearCookieVisitorId?.(), this.deps.storage.setInternal?.(!1)) : t === "granted" && e === "denied" && this.config.rotate_visitor_on_consent_change && this.deps.storage.rotateVisitorId?.();
@@ -318,10 +335,10 @@ class q {
318
335
  e === !0 || s ? t.is_internal = !0 : delete t.is_internal;
319
336
  }
320
337
  getIdentityFields(t) {
321
- 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 ?? {}, u = { ...r, ...h }, c = {};
322
- e && (c.visitor_id = e), s && (c.user_id = s), i && (c.click_id = i), o && (c.campaign_id = o), n && (c.session_id = n);
338
+ 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(), n = t?.campaign_id ?? this.deps.storage.getCampaignId(), r = t?.session_id ?? this.deps.storage.getSessionId?.(), o = this.deps.storage.getQueryParams() ?? {}, h = t?.query ?? {}, u = { ...o, ...h }, d = {};
339
+ e && (d.visitor_id = e), s && (d.user_id = s), i && (d.click_id = i), n && (d.campaign_id = n), r && (d.session_id = r);
323
340
  const l = this.deps.storage.getSessionStartedAt?.();
324
- return n && l && (c.session_started_at = l, c.session_elapsed_ms = Date.now() - Date.parse(l)), Object.keys(u).length > 0 && (c.query = u), c;
341
+ return r && l && (d.session_started_at = l, d.session_elapsed_ms = Date.now() - Date.parse(l)), Object.keys(u).length > 0 && (d.query = u), d;
325
342
  }
326
343
  /**
327
344
  * Patches session fields after ensureSession when the first event in a session was built
@@ -346,13 +363,13 @@ class q {
346
363
  sanitizeTrackData(t) {
347
364
  const e = {};
348
365
  for (const [s, i] of Object.entries(t))
349
- M.has(s) || (e[s] = i);
366
+ S.has(s) || (e[s] = i);
350
367
  return e;
351
368
  }
352
369
  sanitizeIdentifyTraits(t) {
353
370
  const e = {};
354
371
  for (const [s, i] of Object.entries(t))
355
- A.has(s) || (e[s] = i);
372
+ q.has(s) || (e[s] = i);
356
373
  return e;
357
374
  }
358
375
  validateConfig(t) {
@@ -368,6 +385,8 @@ class q {
368
385
  throw new Error("[Mark] `site_id` cannot be an empty string.");
369
386
  if (typeof t.site_host == "string" && !t.site_host.trim())
370
387
  throw new Error("[Mark] `site_host` cannot be an empty string.");
388
+ if (t.visitor_id !== void 0 && !p(t.visitor_id))
389
+ throw new Error("[Mark] `visitor_id` must be a non-empty string (max 256 characters).");
371
390
  }
372
391
  applyPageContext(t) {
373
392
  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)));
@@ -397,11 +416,11 @@ class q {
397
416
  ensureSession() {
398
417
  const t = Date.now(), e = this.deps.storage.getSessionId?.(), s = this.deps.storage.getLastActivityAt?.(), i = s ? Date.parse(s) : 0;
399
418
  if (!e || !i || t - i >= this.sessionTimeoutMs || this.crossedUtcDay(i, t)) {
400
- const n = this.createMessageId(), r = new Date(t).toISOString();
419
+ const r = this.createMessageId(), o = new Date(t).toISOString();
401
420
  this.deps.storage.update({
402
- session_id: n,
403
- session_started_at: r,
404
- last_activity_at: r
421
+ session_id: r,
422
+ session_started_at: o,
423
+ last_activity_at: o
405
424
  });
406
425
  return;
407
426
  }
@@ -447,21 +466,21 @@ class q {
447
466
  if (t?.type !== "tcf" || typeof window > "u") return;
448
467
  const e = t.purposes, s = (i) => {
449
468
  try {
450
- const o = window;
451
- if (typeof o.__tcfapi != "function") {
469
+ const n = window;
470
+ if (typeof n.__tcfapi != "function") {
452
471
  i > 0 && setTimeout(() => s(i - 1), 200);
453
472
  return;
454
473
  }
455
- o.__tcfapi("addEventListener", 2, (n, r) => {
456
- if (!r || !n) {
474
+ n.__tcfapi("addEventListener", 2, (r, o) => {
475
+ if (!o || !r) {
457
476
  this.tcfCachedAllowed = !1;
458
477
  return;
459
478
  }
460
- if (n.gdprApplies === !1) {
479
+ if (r.gdprApplies === !1) {
461
480
  this.tcfCachedAllowed = !0;
462
481
  return;
463
482
  }
464
- const h = n.purpose?.consents ?? {};
483
+ const h = r.purpose?.consents ?? {};
465
484
  this.tcfCachedAllowed = e.every((u) => h[String(u)] === !0);
466
485
  });
467
486
  } catch {
@@ -471,12 +490,12 @@ class q {
471
490
  s(10);
472
491
  }
473
492
  }
474
- class S {
493
+ class T {
475
494
  config;
476
495
  endpoint;
477
496
  pending = /* @__PURE__ */ new Set();
478
497
  constructor(t) {
479
- this.config = t, this.endpoint = t.endpoint ?? _;
498
+ this.config = t, this.endpoint = t.endpoint ?? m;
480
499
  }
481
500
  async send(t, e, s) {
482
501
  const i = this.sendInternal(t, e, s);
@@ -491,51 +510,51 @@ class S {
491
510
  this.pending.size !== 0 && await Promise.allSettled(Array.from(this.pending));
492
511
  }
493
512
  async sendInternal(t, e, s) {
494
- const i = this.joinUrl(this.endpoint, t), o = this.config.key, n = {
513
+ const i = this.joinUrl(this.endpoint, t), n = this.config.key, r = {
495
514
  "Content-Type": "application/json",
496
- [o.startsWith("sk_") ? "x-secret-key" : "x-publishable-key"]: o
515
+ [n.startsWith("sk_") ? "x-secret-key" : "x-publishable-key"]: n
497
516
  };
498
517
  this.config.debug && console.log("[Mark] Sending", i, e);
499
- const r = JSON.stringify(e);
518
+ const o = JSON.stringify(e);
500
519
  if (s?.preferBeacon && typeof navigator < "u" && typeof navigator.sendBeacon == "function") {
501
- const d = new Blob([r], { type: "application/json" });
502
- if (navigator.sendBeacon(i, d))
520
+ const c = new Blob([o], { type: "application/json" });
521
+ if (navigator.sendBeacon(i, c))
503
522
  return;
504
523
  }
505
524
  if (typeof fetch != "function")
506
525
  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.");
507
526
  const h = this.config.request_timeout_ms ?? 1e4, u = new AbortController();
508
- let c = !1;
527
+ let d = !1;
509
528
  const l = setTimeout(() => {
510
- c = !0, u.abort();
529
+ d = !0, u.abort();
511
530
  }, h);
512
531
  try {
513
- const d = await fetch(i, {
532
+ const c = await fetch(i, {
514
533
  method: "POST",
515
- headers: n,
516
- body: r,
534
+ headers: r,
535
+ body: o,
517
536
  keepalive: !0,
518
537
  signal: u.signal
519
538
  });
520
- if (!d.ok) {
521
- const g = await this.readErrorSnippet(d), p = y(d.headers.get("Retry-After"));
539
+ if (!c.ok) {
540
+ const g = await this.readErrorSnippet(c), _ = w(c.headers.get("Retry-After"));
522
541
  throw this.config.debug && console.error("[Mark] Request rejected", {
523
542
  url: i,
524
- status: d.status,
525
- statusText: d.statusText,
543
+ status: c.status,
544
+ statusText: c.statusText,
526
545
  body: g,
527
- retryAfterMs: p
546
+ retryAfterMs: _
528
547
  }), new f(
529
- `[Mark] Request rejected with status ${d.status}: ${g}`,
530
- { status: d.status, retryAfterMs: p }
548
+ `[Mark] Request rejected with status ${c.status}: ${g}`,
549
+ { status: c.status, retryAfterMs: _ }
531
550
  );
532
551
  }
533
- } catch (d) {
534
- if (this.config.debug && console.error("[Mark] Failed to send", i, d), d instanceof f)
535
- throw d;
536
- if (c)
552
+ } catch (c) {
553
+ if (this.config.debug && console.error("[Mark] Failed to send", i, c), c instanceof f)
554
+ throw c;
555
+ if (d)
537
556
  throw new f(`[Mark] Request timed out after ${h}ms`, { status: 408 });
538
- const g = d instanceof Error ? d.message : String(d);
557
+ const g = c instanceof Error ? c.message : String(c);
539
558
  throw new f(`[Mark] Network error: ${g}`);
540
559
  } finally {
541
560
  clearTimeout(l);
@@ -553,7 +572,7 @@ class S {
553
572
  }
554
573
  }
555
574
  }
556
- class D {
575
+ class E {
557
576
  constructor(t = {}) {
558
577
  this.defaults = t;
559
578
  }
@@ -594,6 +613,10 @@ class D {
594
613
  }
595
614
  rotateVisitorId() {
596
615
  }
616
+ setVisitorId(t) {
617
+ const e = p(t);
618
+ return e ? (this.defaults.visitor_id = e, !0) : !1;
619
+ }
597
620
  getInternal() {
598
621
  return this.defaults.is_internal;
599
622
  }
@@ -601,7 +624,7 @@ class D {
601
624
  this.defaults.is_internal = t ? !0 : void 0;
602
625
  }
603
626
  }
604
- class T {
627
+ class x {
605
628
  constructor(t) {
606
629
  this.client = t;
607
630
  }
@@ -634,6 +657,14 @@ class T {
634
657
  getVisitorId() {
635
658
  return this.client.getVisitorId();
636
659
  }
660
+ /**
661
+ * Adopts or replaces the visitor id for this NodeMark instance.
662
+ * With default StatelessStorage, updates the in-memory defaults used by
663
+ * subsequent track/identify calls.
664
+ */
665
+ setVisitorId(t) {
666
+ return this.client.setVisitorId(t);
667
+ }
637
668
  /**
638
669
  * Marks the current request/visitor as internal traffic. When using the
639
670
  * default StatelessStorage, the flag is scoped to this NodeMark instance.
@@ -645,9 +676,9 @@ class T {
645
676
  return this.client.getInternal();
646
677
  }
647
678
  }
648
- const E = (a, t = {}) => {
649
- const e = t.storage ?? new D({
650
- visitor_id: t.storageDefaults?.visitor_id,
679
+ const C = (a, t = {}) => {
680
+ const e = p(a.visitor_id), s = t.storage ?? new E({
681
+ visitor_id: t.storageDefaults?.visitor_id ?? e,
651
682
  user_id: t.storageDefaults?.user_id,
652
683
  session_id: t.storageDefaults?.session_id,
653
684
  session_started_at: t.storageDefaults?.session_started_at,
@@ -657,12 +688,12 @@ const E = (a, t = {}) => {
657
688
  query_params: t.storageDefaults?.query_params,
658
689
  consent_status: t.storageDefaults?.consent_status,
659
690
  is_internal: t.storageDefaults?.is_internal
660
- }), s = t.transport ?? new S(a), i = new q(a, { storage: e, transport: s });
661
- return new T(i);
691
+ }), i = t.transport ?? new T(a), n = new D(a, { storage: s, transport: i });
692
+ return new x(n);
662
693
  };
663
694
  export {
664
- T as NodeMark,
665
- D as StatelessStorage,
666
- E as createNodeMark
695
+ x as NodeMark,
696
+ E as StatelessStorage,
697
+ C as createNodeMark
667
698
  };
668
699
  //# sourceMappingURL=node.es.js.map