• Home
  • Features
  • Pricing
  • Docs
  • Announcements
  • Sign In

prebid / Prebid.js / #304

24 Jun 2025 05:14PM UTC coverage: 90.422% (+0.02%) from 90.403%
#304

push

travis-ci

prebidjs-release
Prebid 9.51.0 release

43346 of 54399 branches covered (79.68%)

64092 of 70881 relevant lines covered (90.42%)

174.66 hits per line

Source File
Press 'n' to go to next uncovered line, 'b' for previous

86.15
/modules/identityLinkIdSystem.js
1
/**
1✔
2
 * This module adds IdentityLink to the User ID module
3
 * The {@link module:modules/userId} module is required
4
 * @module modules/identityLinkSubmodule
5
 * @requires module:modules/userId
6
 */
7

8
import * as utils from '../src/utils.js'
9
import { ajax } from '../src/ajax.js';
10
import { submodule } from '../src/hook.js';
11
import {getStorageManager} from '../src/storageManager.js';
12
import {MODULE_TYPE_UID} from '../src/activities/modules.js';
13

14
/**
15
 * @typedef {import('../modules/userId/index.js').Submodule} Submodule
16
 * @typedef {import('../modules/userId/index.js').SubmoduleConfig} SubmoduleConfig
17
 * @typedef {import('../modules/userId/index.js').ConsentData} ConsentData
18
 * @typedef {import('../modules/userId/index.js').IdResponse} IdResponse
19
 */
20

21
const MODULE_NAME = 'identityLink';
1✔
22

23
export const storage = getStorageManager({moduleType: MODULE_TYPE_UID, moduleName: MODULE_NAME});
1✔
24

25
const liverampEnvelopeName = '_lr_env';
1✔
26

27
/** @type {Submodule} */
28
export const identityLinkSubmodule = {
1✔
29
  /**
30
   * used to link submodule with config
31
   * @type {string}
32
   */
33
  name: MODULE_NAME,
34
  /**
35
   * used to specify vendor id
36
   * @type {number}
37
   */
38
  gvlid: 97,
39
  /**
40
   * decode the stored id value for passing to bid requests
41
   * @function
42
   * @param {string} value
43
   * @returns {{idl_env:string}}
44
   */
45
  decode(value) {
46
    return { 'idl_env': value }
×
47
  },
48
  /**
49
   * performs action to obtain id and return a value in the callback's response argument
50
   * @function
51
   * @param {SubmoduleConfig} [config]
52
   * @param {ConsentData} [consentData]
53
   * @returns {IdResponse|undefined}
54
   */
55
  getId(config, consentData) {
56
    const configParams = (config && config.params) || {};
16!
57
    if (!configParams || typeof configParams.pid !== 'string') {
16✔
58
      utils.logError('identityLink: requires partner id to be defined');
2✔
59
      return;
2✔
60
    }
61
    const {gdpr, gpp: gppData} = consentData ?? {};
14✔
62
    const hasGdpr = (gdpr && typeof gdpr.gdprApplies === 'boolean' && gdpr.gdprApplies) ? 1 : 0;
14✔
63
    const gdprConsentString = hasGdpr ? gdpr.consentString : '';
14✔
64
    // use protocol relative urls for http or https
65
    if (hasGdpr && (!gdprConsentString || gdprConsentString === '')) {
14✔
66
      utils.logInfo('identityLink: Consent string is required to call envelope API.');
2✔
67
      return;
2✔
68
    }
69
    const gppString = gppData && gppData.gppString ? gppData.gppString : false;
12✔
70
    const gppSectionId = gppData && gppData.gppString && gppData.applicableSections.length > 0 && gppData.applicableSections[0] !== -1 ? gppData.applicableSections[0] : false;
12✔
71
    const hasGpp = gppString && gppSectionId;
12✔
72
    const url = `https://api.rlcdn.com/api/identity/envelope?pid=${configParams.pid}${hasGdpr ? '&ct=4&cv=' + gdprConsentString : ''}${hasGpp ? '&gpp=' + gppString + '&gpp_sid=' + gppSectionId : ''}`;
12✔
73
    let resp;
74
    resp = function (callback) {
12✔
75
      // Check ats during callback so it has a chance to initialise.
76
      // If ats library is available, use it to retrieve envelope. If not use standard third party endpoint
77
      if (window.ats && window.ats.retrieveEnvelope) {
12✔
78
        utils.logInfo('identityLink: ATS exists!');
1✔
79
        window.ats.retrieveEnvelope(function (envelope) {
1✔
80
          if (envelope) {
×
81
            utils.logInfo('identityLink: An envelope can be retrieved from ATS!');
×
82
            setEnvelopeSource(true);
×
83
            callback(JSON.parse(envelope).envelope);
×
84
          } else {
85
            getEnvelope(url, callback, configParams);
×
86
          }
87
        });
88
      } else {
89
        // try to get envelope directly from storage if ats lib is not present on a page
90
        let envelope = getEnvelopeFromStorage();
11✔
91
        if (envelope) {
11✔
92
          utils.logInfo('identityLink: LiveRamp envelope successfully retrieved from storage!');
1✔
93
          callback(JSON.parse(envelope).envelope);
1✔
94
        } else {
95
          getEnvelope(url, callback, configParams);
10✔
96
        }
97
      }
98
    };
99

100
    return { callback: resp };
12✔
101
  },
102
  eids: {
103
    'idl_env': {
104
      source: 'liveramp.com',
105
      atype: 3
106
    },
107
  }
108
};
109
// return envelope from third party endpoint
110
function getEnvelope(url, callback, configParams) {
111
  const callbacks = {
10✔
112
    success: response => {
113
      let responseObj;
114
      if (response) {
7✔
115
        try {
5✔
116
          responseObj = JSON.parse(response);
5✔
117
        } catch (error) {
118
          utils.logInfo(error);
×
119
        }
120
      }
121
      callback((responseObj && responseObj.envelope) ? responseObj.envelope : '');
7!
122
    },
123
    error: error => {
124
      utils.logInfo(`identityLink: identityLink: ID fetch encountered an error`, error);
1✔
125
      callback();
1✔
126
    }
127
  };
128

129
  if (!configParams.notUse3P && !storage.getCookie('_lr_retry_request')) {
10✔
130
    setRetryCookie();
8✔
131
    utils.logInfo('identityLink: A 3P retrieval is attempted!');
8✔
132
    setEnvelopeSource(false);
8✔
133
    ajax(url, callbacks, undefined, { method: 'GET', withCredentials: true });
8✔
134
  } else {
135
    callback()
2✔
136
  }
137
}
138

139
function setRetryCookie() {
140
  let now = new Date();
8✔
141
  now.setTime(now.getTime() + 3600000);
8✔
142
  storage.setCookie('_lr_retry_request', 'true', now.toUTCString());
8✔
143
}
144

145
function setEnvelopeSource(src) {
146
  let now = new Date();
8✔
147
  now.setTime(now.getTime() + 2592000000);
8✔
148
  storage.setCookie('_lr_env_src_ats', src, now.toUTCString());
8✔
149
}
150

151
export function getEnvelopeFromStorage() {
152
  let rawEnvelope = storage.getCookie(liverampEnvelopeName) || storage.getDataFromLocalStorage(liverampEnvelopeName);
15✔
153
  if (!rawEnvelope) {
15✔
154
    return undefined;
11✔
155
  }
156
  try {
4✔
157
    return window.atob(rawEnvelope);
4✔
158
  } catch (e) {
159
    try {
1✔
160
      return window.atob(rawEnvelope.replace(/-/g, '+').replace(/_/g, '/'));
1✔
161
    } catch (e2) {
162
      utils.logError('identityLink: invalid envelope format');
×
163
      return undefined;
×
164
    }
165
  }
166
}
167

168
submodule('userId', identityLinkSubmodule);
1✔
STATUS · Troubleshooting · Open an Issue · Sales · Support · CAREERS · ENTERPRISE · START FREE · SCHEDULE DEMO
ANNOUNCEMENTS · TWITTER · TOS & SLA · Supported CI Services · What's a CI service? · Automated Testing

© 2026 Coveralls, Inc