@blotoutio/providers-onescreen-ai-sdk 1.53.1 → 1.55.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.
Files changed (4) hide show
  1. package/index.cjs.js +155 -0
  2. package/index.js +155 -0
  3. package/index.mjs +155 -0
  4. package/package.json +1 -1
package/index.cjs.js CHANGED
@@ -34,6 +34,40 @@ const logger = {
34
34
  },
35
35
  };
36
36
 
37
+ /**
38
+ * Known ad-network click ID query parameters and the human-readable provider
39
+ * label each one maps to. Used by the CDN worker to resolve `inSessionTouch`
40
+ * and by the analytics API to classify paid-media touch sessions.
41
+ *
42
+ * Keep this list in sync with `defaultParams` in queryParams.ts when new
43
+ * click ID providers are added.
44
+ */
45
+ const CLICK_IDS = [
46
+ { param: 'fbclid', label: 'Facebook' }, // Facebook Ads
47
+ { param: 'gclid', label: 'Google' }, // Google Ads (click)
48
+ { param: 'gbraid', label: 'Google' }, // Google Ads (iOS app)
49
+ { param: 'wbraid', label: 'Google' }, // Google Ads (iOS web)
50
+ { param: 'msclkid', label: 'Bing' }, // Microsoft Bing Ads
51
+ { param: 'ttclid', label: 'TikTok' }, // TikTok Ads
52
+ { param: 'ScCid', label: 'Snapchat' }, // Snapchat Ads
53
+ { param: 'epik', label: 'Pinterest' }, // Pinterest Ads
54
+ { param: 'li_fat_id', label: 'LinkedIn' }, // LinkedIn Ads
55
+ { param: 'twclid', label: 'Twitter' }, // X (Twitter) Ads
56
+ { param: 'rdt_cid', label: 'Reddit' }, // Reddit Ads
57
+ { param: 'aleid', label: 'AppLovin' }, // AppLovin
58
+ { param: 'tabclid', label: 'Taboola' }, // Taboola
59
+ { param: 'obclid', label: 'Outbrain' }, // Outbrain
60
+ { param: 'trybe', label: 'Trybe' }, // Trybe
61
+ { param: '_kx', label: 'Klaviyo' }, // Klaviyo email campaigns
62
+ { param: 'mc_eid', label: 'Mailchimp' }, // Mailchimp email campaigns
63
+ { param: 'ttd_id', label: 'The Trade Desk' }, // The Trade Desk programmatic
64
+ { param: 'evsclid', label: 'EvoSearch' }, // EvoSearch
65
+ { param: 'li_did', label: 'Live Intent' }, // LiveIntent device-level ad
66
+ { param: '_raclid', label: 'Rumble' }, // Rumble Ads
67
+ { param: 'ref_id', label: 'StackAdapt' }, // StackAdapt programmatic
68
+ { param: 'duel_a', label: 'Duel' }, // Duel referral/advocacy
69
+ ];
70
+
37
71
  const expand = (str) => str.split(',').flatMap((entry) => {
38
72
  if (!entry.includes('-')) {
39
73
  return entry;
@@ -422,6 +456,127 @@ const wildcardToRegex = (pattern) => {
422
456
  return new RegExp(`^${escaped}$`, 'i'); // Case-insensitive match
423
457
  };
424
458
 
459
+ /**
460
+ * Exact utm_source normalization (lowercase key → canonical name).
461
+ *
462
+ * Use exact match when the key is short, generic, or must not accidentally
463
+ * absorb variant spellings (e.g. "impact" must not match "impact_radius").
464
+ *
465
+ * Ordering: Paid (search/social → ad networks → affiliates) →
466
+ * Organic (AI/discovery) → Retention (email → SMS → push → post-purchase)
467
+ */
468
+ const UTM_SOURCE_EXACT = {
469
+ // ── Paid – Search & Social ────────────────────────────────────────────────
470
+ google: 'Google',
471
+ adwords: 'Google',
472
+ youtube: 'Google',
473
+ yt: 'Google',
474
+ meta: 'Facebook',
475
+ facebook: 'Facebook',
476
+ instagram: 'Facebook',
477
+ ig: 'Facebook',
478
+ igshopping: 'Facebook',
479
+ threads: 'Facebook',
480
+ twitter: 'Twitter',
481
+ snapchat: 'Snapchat',
482
+ pinterest: 'Pinterest',
483
+ bing: 'Bing',
484
+ microsoft: 'Bing',
485
+ tiktok: 'TikTok',
486
+ // ── Paid – Ad Networks ───────────────────────────────────────────────────
487
+ rtbhouse: 'RTB House',
488
+ applovin: 'AppLovin',
489
+ ttd: 'The Trade Desk',
490
+ amazondsp: 'Amazon DSP',
491
+ axon: 'Axon',
492
+ duel: 'Duel',
493
+ // ── Paid – Affiliates ────────────────────────────────────────────────────
494
+ awin: 'Awin',
495
+ 'affiliate-cj': 'CJ Affiliate',
496
+ impact: 'Impact',
497
+ rakuten: 'Rakuten',
498
+ superfiliate: 'Superfiliate',
499
+ // ── Organic – AI & Discovery ─────────────────────────────────────────────
500
+ perplexity: 'Perplexity',
501
+ chatgpt: 'ChatGPT',
502
+ 'chatgpt.com': 'ChatGPT',
503
+ openai: 'ChatGPT',
504
+ 'copilot.com': 'Microsoft Copilot',
505
+ copilot: 'Microsoft Copilot',
506
+ applenews: 'Apple News',
507
+ whatsapp: 'WhatsApp',
508
+ podcast: 'Podcast',
509
+ // ── Retention – Email ────────────────────────────────────────────────────
510
+ mailchimp: 'Mailchimp',
511
+ omnisend: 'Omnisend',
512
+ iterable: 'Iterable',
513
+ listrak: 'Listrak',
514
+ sailthru: 'Sailthru',
515
+ // ── Retention – Push ─────────────────────────────────────────────────────
516
+ pushowl: 'PushOwl',
517
+ // ── Retention – Post-purchase / Payment ──────────────────────────────────
518
+ narvar: 'Narvar',
519
+ shop_app: 'Shop App',
520
+ salesforce: 'Salesforce',
521
+ yotpo: 'Yotpo',
522
+ };
523
+ /**
524
+ * Partial utm_source normalization (startsWith prefix check, lowercase).
525
+ *
526
+ * Checked after exact match so short exact keys (e.g. "ig", "yt") win first.
527
+ */
528
+ const UTM_SOURCE_PARTIAL = [
529
+ // ── Paid – Social ─────────────────────────────────────────────────────────
530
+ { prefix: 'tiktok', name: 'TikTok' },
531
+ // ── Paid – Ad Networks ───────────────────────────────────────────────────
532
+ { prefix: 'criteo', name: 'Criteo' },
533
+ // ── Retention – Email ────────────────────────────────────────────────────
534
+ { prefix: 'klaviyo', name: 'Klaviyo' },
535
+ // ── Retention – SMS ──────────────────────────────────────────────────────
536
+ { prefix: 'attentive', name: 'Attentive' },
537
+ { prefix: 'postscript', name: 'Postscript' },
538
+ // ── Retention – Post-purchase / Payment ──────────────────────────────────
539
+ { prefix: 'afterpay', name: 'Afterpay' },
540
+ { prefix: 'klarna', name: 'Klarna' },
541
+ ];
542
+ const ORGANIC_SEARCH_ENGINES = [
543
+ { match: 'google', name: 'Google' },
544
+ { match: 'bing', name: 'Bing' },
545
+ { match: 'yahoo', name: 'Yahoo' },
546
+ { match: 'duckduckgo', name: 'DuckDuckGo' },
547
+ { match: 'baidu', name: 'Baidu' },
548
+ { match: 'yandex', name: 'Yandex' },
549
+ { match: 'brave', name: 'Brave' },
550
+ ];
551
+ const KNOWN_REFERRAL_PLATFORMS = [
552
+ { match: 'facebook', name: 'Facebook' },
553
+ { match: 'instagram', name: 'Facebook' },
554
+ { match: 'twitter', name: 'Twitter' },
555
+ { match: 'x.com', name: 'Twitter' },
556
+ { match: 'tiktok', name: 'TikTok' },
557
+ { match: 'pinterest', name: 'Pinterest' },
558
+ { match: 'linkedin', name: 'LinkedIn' },
559
+ { match: 'youtube', name: 'YouTube' },
560
+ { match: 'chatgpt', name: 'ChatGPT' },
561
+ { match: 'claude', name: 'Claude' },
562
+ { match: 'perplexity', name: 'Perplexity' },
563
+ { match: 'shop.app', name: 'Shop App' },
564
+ { match: 'amazon', name: 'Amazon' },
565
+ { match: 'attentive', name: 'Attentive' },
566
+ ];
567
+ const OFFLINE_TOUCH = 'Blotout_Offline';
568
+ new Set([
569
+ ...CLICK_IDS.map((c) => c.label),
570
+ ...Object.values(UTM_SOURCE_EXACT),
571
+ ...UTM_SOURCE_PARTIAL.map((e) => e.name),
572
+ ...ORGANIC_SEARCH_ENGINES.map((e) => `Organic Search - ${e.name}`),
573
+ ...KNOWN_REFERRAL_PLATFORMS.map((e) => `Referral - ${e.name}`),
574
+ 'Referral - Other',
575
+ 'Direct Traffic',
576
+ 'Other',
577
+ OFFLINE_TOUCH,
578
+ ]);
579
+
425
580
  const getSourceName = (sourceMapping, url) => {
426
581
  const mapping = tryParse(sourceMapping, []);
427
582
  if (!mapping.length) {
package/index.js CHANGED
@@ -35,6 +35,40 @@ var ProvidersOnescreenAiSdk = (function () {
35
35
  },
36
36
  };
37
37
 
38
+ /**
39
+ * Known ad-network click ID query parameters and the human-readable provider
40
+ * label each one maps to. Used by the CDN worker to resolve `inSessionTouch`
41
+ * and by the analytics API to classify paid-media touch sessions.
42
+ *
43
+ * Keep this list in sync with `defaultParams` in queryParams.ts when new
44
+ * click ID providers are added.
45
+ */
46
+ const CLICK_IDS = [
47
+ { param: 'fbclid', label: 'Facebook' }, // Facebook Ads
48
+ { param: 'gclid', label: 'Google' }, // Google Ads (click)
49
+ { param: 'gbraid', label: 'Google' }, // Google Ads (iOS app)
50
+ { param: 'wbraid', label: 'Google' }, // Google Ads (iOS web)
51
+ { param: 'msclkid', label: 'Bing' }, // Microsoft Bing Ads
52
+ { param: 'ttclid', label: 'TikTok' }, // TikTok Ads
53
+ { param: 'ScCid', label: 'Snapchat' }, // Snapchat Ads
54
+ { param: 'epik', label: 'Pinterest' }, // Pinterest Ads
55
+ { param: 'li_fat_id', label: 'LinkedIn' }, // LinkedIn Ads
56
+ { param: 'twclid', label: 'Twitter' }, // X (Twitter) Ads
57
+ { param: 'rdt_cid', label: 'Reddit' }, // Reddit Ads
58
+ { param: 'aleid', label: 'AppLovin' }, // AppLovin
59
+ { param: 'tabclid', label: 'Taboola' }, // Taboola
60
+ { param: 'obclid', label: 'Outbrain' }, // Outbrain
61
+ { param: 'trybe', label: 'Trybe' }, // Trybe
62
+ { param: '_kx', label: 'Klaviyo' }, // Klaviyo email campaigns
63
+ { param: 'mc_eid', label: 'Mailchimp' }, // Mailchimp email campaigns
64
+ { param: 'ttd_id', label: 'The Trade Desk' }, // The Trade Desk programmatic
65
+ { param: 'evsclid', label: 'EvoSearch' }, // EvoSearch
66
+ { param: 'li_did', label: 'Live Intent' }, // LiveIntent device-level ad
67
+ { param: '_raclid', label: 'Rumble' }, // Rumble Ads
68
+ { param: 'ref_id', label: 'StackAdapt' }, // StackAdapt programmatic
69
+ { param: 'duel_a', label: 'Duel' }, // Duel referral/advocacy
70
+ ];
71
+
38
72
  const expand = (str) => str.split(',').flatMap((entry) => {
39
73
  if (!entry.includes('-')) {
40
74
  return entry;
@@ -423,6 +457,127 @@ var ProvidersOnescreenAiSdk = (function () {
423
457
  return new RegExp(`^${escaped}$`, 'i'); // Case-insensitive match
424
458
  };
425
459
 
460
+ /**
461
+ * Exact utm_source normalization (lowercase key → canonical name).
462
+ *
463
+ * Use exact match when the key is short, generic, or must not accidentally
464
+ * absorb variant spellings (e.g. "impact" must not match "impact_radius").
465
+ *
466
+ * Ordering: Paid (search/social → ad networks → affiliates) →
467
+ * Organic (AI/discovery) → Retention (email → SMS → push → post-purchase)
468
+ */
469
+ const UTM_SOURCE_EXACT = {
470
+ // ── Paid – Search & Social ────────────────────────────────────────────────
471
+ google: 'Google',
472
+ adwords: 'Google',
473
+ youtube: 'Google',
474
+ yt: 'Google',
475
+ meta: 'Facebook',
476
+ facebook: 'Facebook',
477
+ instagram: 'Facebook',
478
+ ig: 'Facebook',
479
+ igshopping: 'Facebook',
480
+ threads: 'Facebook',
481
+ twitter: 'Twitter',
482
+ snapchat: 'Snapchat',
483
+ pinterest: 'Pinterest',
484
+ bing: 'Bing',
485
+ microsoft: 'Bing',
486
+ tiktok: 'TikTok',
487
+ // ── Paid – Ad Networks ───────────────────────────────────────────────────
488
+ rtbhouse: 'RTB House',
489
+ applovin: 'AppLovin',
490
+ ttd: 'The Trade Desk',
491
+ amazondsp: 'Amazon DSP',
492
+ axon: 'Axon',
493
+ duel: 'Duel',
494
+ // ── Paid – Affiliates ────────────────────────────────────────────────────
495
+ awin: 'Awin',
496
+ 'affiliate-cj': 'CJ Affiliate',
497
+ impact: 'Impact',
498
+ rakuten: 'Rakuten',
499
+ superfiliate: 'Superfiliate',
500
+ // ── Organic – AI & Discovery ─────────────────────────────────────────────
501
+ perplexity: 'Perplexity',
502
+ chatgpt: 'ChatGPT',
503
+ 'chatgpt.com': 'ChatGPT',
504
+ openai: 'ChatGPT',
505
+ 'copilot.com': 'Microsoft Copilot',
506
+ copilot: 'Microsoft Copilot',
507
+ applenews: 'Apple News',
508
+ whatsapp: 'WhatsApp',
509
+ podcast: 'Podcast',
510
+ // ── Retention – Email ────────────────────────────────────────────────────
511
+ mailchimp: 'Mailchimp',
512
+ omnisend: 'Omnisend',
513
+ iterable: 'Iterable',
514
+ listrak: 'Listrak',
515
+ sailthru: 'Sailthru',
516
+ // ── Retention – Push ─────────────────────────────────────────────────────
517
+ pushowl: 'PushOwl',
518
+ // ── Retention – Post-purchase / Payment ──────────────────────────────────
519
+ narvar: 'Narvar',
520
+ shop_app: 'Shop App',
521
+ salesforce: 'Salesforce',
522
+ yotpo: 'Yotpo',
523
+ };
524
+ /**
525
+ * Partial utm_source normalization (startsWith prefix check, lowercase).
526
+ *
527
+ * Checked after exact match so short exact keys (e.g. "ig", "yt") win first.
528
+ */
529
+ const UTM_SOURCE_PARTIAL = [
530
+ // ── Paid – Social ─────────────────────────────────────────────────────────
531
+ { prefix: 'tiktok', name: 'TikTok' },
532
+ // ── Paid – Ad Networks ───────────────────────────────────────────────────
533
+ { prefix: 'criteo', name: 'Criteo' },
534
+ // ── Retention – Email ────────────────────────────────────────────────────
535
+ { prefix: 'klaviyo', name: 'Klaviyo' },
536
+ // ── Retention – SMS ──────────────────────────────────────────────────────
537
+ { prefix: 'attentive', name: 'Attentive' },
538
+ { prefix: 'postscript', name: 'Postscript' },
539
+ // ── Retention – Post-purchase / Payment ──────────────────────────────────
540
+ { prefix: 'afterpay', name: 'Afterpay' },
541
+ { prefix: 'klarna', name: 'Klarna' },
542
+ ];
543
+ const ORGANIC_SEARCH_ENGINES = [
544
+ { match: 'google', name: 'Google' },
545
+ { match: 'bing', name: 'Bing' },
546
+ { match: 'yahoo', name: 'Yahoo' },
547
+ { match: 'duckduckgo', name: 'DuckDuckGo' },
548
+ { match: 'baidu', name: 'Baidu' },
549
+ { match: 'yandex', name: 'Yandex' },
550
+ { match: 'brave', name: 'Brave' },
551
+ ];
552
+ const KNOWN_REFERRAL_PLATFORMS = [
553
+ { match: 'facebook', name: 'Facebook' },
554
+ { match: 'instagram', name: 'Facebook' },
555
+ { match: 'twitter', name: 'Twitter' },
556
+ { match: 'x.com', name: 'Twitter' },
557
+ { match: 'tiktok', name: 'TikTok' },
558
+ { match: 'pinterest', name: 'Pinterest' },
559
+ { match: 'linkedin', name: 'LinkedIn' },
560
+ { match: 'youtube', name: 'YouTube' },
561
+ { match: 'chatgpt', name: 'ChatGPT' },
562
+ { match: 'claude', name: 'Claude' },
563
+ { match: 'perplexity', name: 'Perplexity' },
564
+ { match: 'shop.app', name: 'Shop App' },
565
+ { match: 'amazon', name: 'Amazon' },
566
+ { match: 'attentive', name: 'Attentive' },
567
+ ];
568
+ const OFFLINE_TOUCH = 'Blotout_Offline';
569
+ new Set([
570
+ ...CLICK_IDS.map((c) => c.label),
571
+ ...Object.values(UTM_SOURCE_EXACT),
572
+ ...UTM_SOURCE_PARTIAL.map((e) => e.name),
573
+ ...ORGANIC_SEARCH_ENGINES.map((e) => `Organic Search - ${e.name}`),
574
+ ...KNOWN_REFERRAL_PLATFORMS.map((e) => `Referral - ${e.name}`),
575
+ 'Referral - Other',
576
+ 'Direct Traffic',
577
+ 'Other',
578
+ OFFLINE_TOUCH,
579
+ ]);
580
+
426
581
  const getSourceName = (sourceMapping, url) => {
427
582
  const mapping = tryParse(sourceMapping, []);
428
583
  if (!mapping.length) {
package/index.mjs CHANGED
@@ -32,6 +32,40 @@ const logger = {
32
32
  },
33
33
  };
34
34
 
35
+ /**
36
+ * Known ad-network click ID query parameters and the human-readable provider
37
+ * label each one maps to. Used by the CDN worker to resolve `inSessionTouch`
38
+ * and by the analytics API to classify paid-media touch sessions.
39
+ *
40
+ * Keep this list in sync with `defaultParams` in queryParams.ts when new
41
+ * click ID providers are added.
42
+ */
43
+ const CLICK_IDS = [
44
+ { param: 'fbclid', label: 'Facebook' }, // Facebook Ads
45
+ { param: 'gclid', label: 'Google' }, // Google Ads (click)
46
+ { param: 'gbraid', label: 'Google' }, // Google Ads (iOS app)
47
+ { param: 'wbraid', label: 'Google' }, // Google Ads (iOS web)
48
+ { param: 'msclkid', label: 'Bing' }, // Microsoft Bing Ads
49
+ { param: 'ttclid', label: 'TikTok' }, // TikTok Ads
50
+ { param: 'ScCid', label: 'Snapchat' }, // Snapchat Ads
51
+ { param: 'epik', label: 'Pinterest' }, // Pinterest Ads
52
+ { param: 'li_fat_id', label: 'LinkedIn' }, // LinkedIn Ads
53
+ { param: 'twclid', label: 'Twitter' }, // X (Twitter) Ads
54
+ { param: 'rdt_cid', label: 'Reddit' }, // Reddit Ads
55
+ { param: 'aleid', label: 'AppLovin' }, // AppLovin
56
+ { param: 'tabclid', label: 'Taboola' }, // Taboola
57
+ { param: 'obclid', label: 'Outbrain' }, // Outbrain
58
+ { param: 'trybe', label: 'Trybe' }, // Trybe
59
+ { param: '_kx', label: 'Klaviyo' }, // Klaviyo email campaigns
60
+ { param: 'mc_eid', label: 'Mailchimp' }, // Mailchimp email campaigns
61
+ { param: 'ttd_id', label: 'The Trade Desk' }, // The Trade Desk programmatic
62
+ { param: 'evsclid', label: 'EvoSearch' }, // EvoSearch
63
+ { param: 'li_did', label: 'Live Intent' }, // LiveIntent device-level ad
64
+ { param: '_raclid', label: 'Rumble' }, // Rumble Ads
65
+ { param: 'ref_id', label: 'StackAdapt' }, // StackAdapt programmatic
66
+ { param: 'duel_a', label: 'Duel' }, // Duel referral/advocacy
67
+ ];
68
+
35
69
  const expand = (str) => str.split(',').flatMap((entry) => {
36
70
  if (!entry.includes('-')) {
37
71
  return entry;
@@ -420,6 +454,127 @@ const wildcardToRegex = (pattern) => {
420
454
  return new RegExp(`^${escaped}$`, 'i'); // Case-insensitive match
421
455
  };
422
456
 
457
+ /**
458
+ * Exact utm_source normalization (lowercase key → canonical name).
459
+ *
460
+ * Use exact match when the key is short, generic, or must not accidentally
461
+ * absorb variant spellings (e.g. "impact" must not match "impact_radius").
462
+ *
463
+ * Ordering: Paid (search/social → ad networks → affiliates) →
464
+ * Organic (AI/discovery) → Retention (email → SMS → push → post-purchase)
465
+ */
466
+ const UTM_SOURCE_EXACT = {
467
+ // ── Paid – Search & Social ────────────────────────────────────────────────
468
+ google: 'Google',
469
+ adwords: 'Google',
470
+ youtube: 'Google',
471
+ yt: 'Google',
472
+ meta: 'Facebook',
473
+ facebook: 'Facebook',
474
+ instagram: 'Facebook',
475
+ ig: 'Facebook',
476
+ igshopping: 'Facebook',
477
+ threads: 'Facebook',
478
+ twitter: 'Twitter',
479
+ snapchat: 'Snapchat',
480
+ pinterest: 'Pinterest',
481
+ bing: 'Bing',
482
+ microsoft: 'Bing',
483
+ tiktok: 'TikTok',
484
+ // ── Paid – Ad Networks ───────────────────────────────────────────────────
485
+ rtbhouse: 'RTB House',
486
+ applovin: 'AppLovin',
487
+ ttd: 'The Trade Desk',
488
+ amazondsp: 'Amazon DSP',
489
+ axon: 'Axon',
490
+ duel: 'Duel',
491
+ // ── Paid – Affiliates ────────────────────────────────────────────────────
492
+ awin: 'Awin',
493
+ 'affiliate-cj': 'CJ Affiliate',
494
+ impact: 'Impact',
495
+ rakuten: 'Rakuten',
496
+ superfiliate: 'Superfiliate',
497
+ // ── Organic – AI & Discovery ─────────────────────────────────────────────
498
+ perplexity: 'Perplexity',
499
+ chatgpt: 'ChatGPT',
500
+ 'chatgpt.com': 'ChatGPT',
501
+ openai: 'ChatGPT',
502
+ 'copilot.com': 'Microsoft Copilot',
503
+ copilot: 'Microsoft Copilot',
504
+ applenews: 'Apple News',
505
+ whatsapp: 'WhatsApp',
506
+ podcast: 'Podcast',
507
+ // ── Retention – Email ────────────────────────────────────────────────────
508
+ mailchimp: 'Mailchimp',
509
+ omnisend: 'Omnisend',
510
+ iterable: 'Iterable',
511
+ listrak: 'Listrak',
512
+ sailthru: 'Sailthru',
513
+ // ── Retention – Push ─────────────────────────────────────────────────────
514
+ pushowl: 'PushOwl',
515
+ // ── Retention – Post-purchase / Payment ──────────────────────────────────
516
+ narvar: 'Narvar',
517
+ shop_app: 'Shop App',
518
+ salesforce: 'Salesforce',
519
+ yotpo: 'Yotpo',
520
+ };
521
+ /**
522
+ * Partial utm_source normalization (startsWith prefix check, lowercase).
523
+ *
524
+ * Checked after exact match so short exact keys (e.g. "ig", "yt") win first.
525
+ */
526
+ const UTM_SOURCE_PARTIAL = [
527
+ // ── Paid – Social ─────────────────────────────────────────────────────────
528
+ { prefix: 'tiktok', name: 'TikTok' },
529
+ // ── Paid – Ad Networks ───────────────────────────────────────────────────
530
+ { prefix: 'criteo', name: 'Criteo' },
531
+ // ── Retention – Email ────────────────────────────────────────────────────
532
+ { prefix: 'klaviyo', name: 'Klaviyo' },
533
+ // ── Retention – SMS ──────────────────────────────────────────────────────
534
+ { prefix: 'attentive', name: 'Attentive' },
535
+ { prefix: 'postscript', name: 'Postscript' },
536
+ // ── Retention – Post-purchase / Payment ──────────────────────────────────
537
+ { prefix: 'afterpay', name: 'Afterpay' },
538
+ { prefix: 'klarna', name: 'Klarna' },
539
+ ];
540
+ const ORGANIC_SEARCH_ENGINES = [
541
+ { match: 'google', name: 'Google' },
542
+ { match: 'bing', name: 'Bing' },
543
+ { match: 'yahoo', name: 'Yahoo' },
544
+ { match: 'duckduckgo', name: 'DuckDuckGo' },
545
+ { match: 'baidu', name: 'Baidu' },
546
+ { match: 'yandex', name: 'Yandex' },
547
+ { match: 'brave', name: 'Brave' },
548
+ ];
549
+ const KNOWN_REFERRAL_PLATFORMS = [
550
+ { match: 'facebook', name: 'Facebook' },
551
+ { match: 'instagram', name: 'Facebook' },
552
+ { match: 'twitter', name: 'Twitter' },
553
+ { match: 'x.com', name: 'Twitter' },
554
+ { match: 'tiktok', name: 'TikTok' },
555
+ { match: 'pinterest', name: 'Pinterest' },
556
+ { match: 'linkedin', name: 'LinkedIn' },
557
+ { match: 'youtube', name: 'YouTube' },
558
+ { match: 'chatgpt', name: 'ChatGPT' },
559
+ { match: 'claude', name: 'Claude' },
560
+ { match: 'perplexity', name: 'Perplexity' },
561
+ { match: 'shop.app', name: 'Shop App' },
562
+ { match: 'amazon', name: 'Amazon' },
563
+ { match: 'attentive', name: 'Attentive' },
564
+ ];
565
+ const OFFLINE_TOUCH = 'Blotout_Offline';
566
+ new Set([
567
+ ...CLICK_IDS.map((c) => c.label),
568
+ ...Object.values(UTM_SOURCE_EXACT),
569
+ ...UTM_SOURCE_PARTIAL.map((e) => e.name),
570
+ ...ORGANIC_SEARCH_ENGINES.map((e) => `Organic Search - ${e.name}`),
571
+ ...KNOWN_REFERRAL_PLATFORMS.map((e) => `Referral - ${e.name}`),
572
+ 'Referral - Other',
573
+ 'Direct Traffic',
574
+ 'Other',
575
+ OFFLINE_TOUCH,
576
+ ]);
577
+
423
578
  const getSourceName = (sourceMapping, url) => {
424
579
  const mapping = tryParse(sourceMapping, []);
425
580
  if (!mapping.length) {
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@blotoutio/providers-onescreen-ai-sdk",
3
- "version": "1.53.1",
3
+ "version": "1.55.0",
4
4
  "description": "OnescreenAI Browser SDK for EdgeTag",
5
5
  "author": "Blotout",
6
6
  "license": "MIT",