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

prebid / Prebid.js / 16197995703

10 Jul 2025 02:32PM UTC coverage: 96.232% (+0.003%) from 96.229%
16197995703

push

github

web-flow
Linting: remove exception (#13518)

* bump coveralls

* remove exceptions

* results

* eslint fix

* Update package-lock.json

* Update package-lock.json

* Core: remove codex comments and unused lint rule (#13520)

---------

Co-authored-by: Demetrio Girardi <dgirardi@prebid.org>

39174 of 48116 branches covered (81.42%)

9842 of 9975 new or added lines in 861 files covered. (98.67%)

15 existing lines in 8 files now uncovered.

192483 of 200020 relevant lines covered (96.23%)

88.4 hits per line

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

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

8
import { logInfo, logError, logWarn } from '../src/utils.js';
9
import * as ajaxLib 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 = 'merkleId';
1✔
22
const ID_URL = 'https://prebid.sv.rkdms.com/identity/';
1✔
23
const DEFAULT_REFRESH = 7 * 3600;
1✔
24
const SESSION_COOKIE_NAME = '_svsid';
1✔
25

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

28
function getSession(configParams) {
29
  let session = null;
4✔
30
  if (typeof configParams.sv_session === 'string') {
4!
31
    session = configParams.sv_session;
4✔
32
  } else {
33
    session = storage.getCookie(SESSION_COOKIE_NAME);
×
34
  }
35
  return session;
4✔
36
}
37

38
function setCookie(name, value, expires) {
NEW
39
  const expTime = new Date();
×
40
  expTime.setTime(expTime.getTime() + expires * 1000 * 60);
×
41
  storage.setCookie(name, value, expTime.toUTCString(), 'Lax');
×
42
}
43

44
function setSession(storage, response) {
45
  logInfo('Merkle setting ' + `${SESSION_COOKIE_NAME}`);
4✔
46
  if (response && response[SESSION_COOKIE_NAME] && typeof response[SESSION_COOKIE_NAME] === 'string') {
4!
47
    setCookie(SESSION_COOKIE_NAME, response[SESSION_COOKIE_NAME], storage.expires);
×
48
  }
49
}
50

51
function constructUrl(configParams) {
52
  const session = getSession(configParams);
4✔
53
  let url = configParams.endpoint + `?sv_domain=${configParams.sv_domain}&sv_pubid=${configParams.sv_pubid}&ssp_ids=${configParams.ssp_ids.join()}`;
4✔
54
  if (session) {
4✔
55
    url = `${url}&sv_session=${session}`;
4✔
56
  }
57
  logInfo('Merkle url :' + url);
4✔
58
  return url;
4✔
59
}
60

61
function generateId(configParams, configStorage) {
62
  const url = constructUrl(configParams);
4✔
63

64
  const resp = function (callback) {
4✔
65
    ajaxLib.ajaxBuilder()(
4✔
66
      url,
67
      response => {
68
        let responseObj;
69
        if (response) {
4✔
70
          try {
4✔
71
            responseObj = JSON.parse(response);
4✔
72
            setSession(configStorage, responseObj)
4✔
73
            logInfo('Merkle responseObj ' + JSON.stringify(responseObj));
4✔
74
          } catch (error) {
75
            logError(error);
×
76
          }
77
        }
78

79
        const date = new Date().toUTCString();
4✔
80
        responseObj.date = date;
4✔
81
        logInfo('Merkle responseObj with date ' + JSON.stringify(responseObj));
4✔
82
        callback(responseObj);
4✔
83
      },
84
      error => {
85
        logError(`${MODULE_NAME}: merkleId fetch encountered an error`, error);
×
86
        callback();
×
87
      },
88
      {method: 'GET', withCredentials: true}
89
    );
90
  };
91
  return resp;
4✔
92
}
93

94
/** @type {Submodule} */
95
export const merkleIdSubmodule = {
1✔
96
  /**
97
   * used to link submodule with config
98
   * @type {string}
99
   */
100
  name: MODULE_NAME,
101

102
  /**
103
   * decode the stored id value for passing to bid requests
104
   * @function
105
   * @param {string} value
106
   * @returns {{eids:Array}}
107
   */
108
  decode(value) {
109
    // Legacy support for a single id
110
    const id = (value && value.pam_id && typeof value.pam_id.id === 'string') ? value.pam_id : undefined;
3✔
111
    logInfo('Merkle id ' + JSON.stringify(id));
3✔
112

113
    if (id) {
3✔
114
      return {'merkleId': id}
1✔
115
    }
116

117
    // Supports multiple IDs for different SSPs
118
    const merkleIds = (value && value?.merkleId && Array.isArray(value.merkleId)) ? value.merkleId : undefined;
2✔
119
    logInfo('merkleIds: ' + JSON.stringify(merkleIds));
2✔
120

121
    return merkleIds ? {'merkleId': merkleIds} : undefined;
2✔
122
  },
123

124
  /**
125
   * performs action to obtain id and return a value in the callback's response argument
126
   * @function
127
   * @param {SubmoduleConfig} [config]
128
   * @param {ConsentData} [consentData]
129
   * @returns {IdResponse|undefined}
130
   */
131
  getId(config, consentData) {
132
    logInfo('User ID - merkleId generating id');
5✔
133

134
    const configParams = (config && config.params) || {};
5!
135

136
    if (typeof configParams.sv_pubid !== 'string') {
5✔
137
      logError('User ID - merkleId submodule requires a valid sv_pubid string to be defined');
1✔
138
      return;
1✔
139
    }
140

141
    if (!Array.isArray(configParams.ssp_ids)) {
4✔
142
      logError('User ID - merkleId submodule requires a valid ssp_ids array to be defined');
1✔
143
      return;
1✔
144
    }
145

146
    if (consentData?.gdpr?.gdprApplies === true) {
3✔
147
      logError('User ID - merkleId submodule does not currently handle consent strings');
1✔
148
      return;
1✔
149
    }
150

151
    if (typeof configParams.endpoint !== 'string') {
2✔
152
      logWarn('User ID - merkleId submodule endpoint string is not defined');
2✔
153
      configParams.endpoint = ID_URL
2✔
154
    }
155

156
    if (typeof configParams.sv_domain !== 'string') {
2!
157
      configParams.sv_domain = merkleIdSubmodule.findRootDomain();
×
158
    }
159

160
    const configStorage = (config && config.storage) || {};
2!
161
    const resp = generateId(configParams, configStorage)
2✔
162
    return {callback: resp};
2✔
163
  },
164
  extendId: function (config = {}, consentData, storedId) {
4!
165
    logInfo('User ID - stored id ' + storedId);
4✔
166
    const configParams = (config && config.params) || {};
4!
167

168
    if (typeof configParams.endpoint !== 'string') {
4✔
169
      logWarn('User ID - merkleId submodule endpoint string is not defined');
1✔
170
      configParams.endpoint = ID_URL;
1✔
171
    }
172

173
    if (consentData && typeof consentData.gdprApplies === 'boolean' && consentData.gdprApplies) {
4!
174
      logError('User ID - merkleId submodule does not currently handle consent strings');
×
175
      return;
×
176
    }
177

178
    if (typeof configParams.sv_domain !== 'string') {
4!
179
      configParams.sv_domain = merkleIdSubmodule.findRootDomain();
×
180
    }
181

182
    const configStorage = (config && config.storage) || {};
4✔
183
    if (configStorage && configStorage.refreshInSeconds && typeof configParams.refreshInSeconds === 'number') {
4✔
184
      return {id: storedId};
1✔
185
    }
186

187
    let refreshInSeconds = DEFAULT_REFRESH;
3✔
188
    if (configParams && configParams.refreshInSeconds && typeof configParams.refreshInSeconds === 'number') {
3✔
189
      refreshInSeconds = configParams.refreshInSeconds;
1✔
190
      logInfo('User ID - merkleId param refreshInSeconds' + refreshInSeconds);
1✔
191
    }
192

193
    const storedDate = new Date(storedId.date);
3✔
194
    let refreshNeeded = false;
3✔
195
    if (storedDate) {
3✔
196
      refreshNeeded = storedDate && (Date.now() - storedDate.getTime() > refreshInSeconds * 1000);
3✔
197
      if (refreshNeeded) {
3✔
198
        logInfo('User ID - merkleId needs refreshing id');
2✔
199
        const resp = generateId(configParams, configStorage);
2✔
200
        return {callback: resp};
2✔
201
      }
202
    }
203

204
    logInfo('User ID - merkleId not refreshed');
1✔
205
    return {id: storedId};
1✔
206
  },
207
  eids: {
208
    'merkleId': {
209
      atype: 3,
210
      getSource: function(data) {
211
        if (data?.ext?.ssp) {
3✔
212
          return `${data.ext.ssp}.merkleinc.com`
2✔
213
        }
214
        return 'merkleinc.com'
1✔
215
      },
216
      getValue: function(data) {
217
        return data.id;
3✔
218
      },
219
      getUidExt: function(data) {
220
        if (data.keyID) {
3✔
221
          return {
1✔
222
            keyID: data.keyID
223
          }
224
        }
225
        if (data.ext) {
2✔
226
          return data.ext;
2✔
227
        }
228
      }
229
    },
230
  }
231

232
};
233

234
submodule('userId', merkleIdSubmodule);
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