8
8
import { getGlobal } from '../src/prebidGlobal.js' ;
9
9
import { submodule } from '../src/hook.js' ;
10
10
import { getStorageManager } from '../src/storageManager.js' ;
11
- import { deepAccess , deepSetValue , isFn , logError , mergeDeep , isPlainObject , safeJSONParse } from '../src/utils.js' ;
11
+ import { deepAccess , deepSetValue , isFn , logError , mergeDeep , isPlainObject , safeJSONParse , prefixLog } from '../src/utils.js' ;
12
12
import { includes } from '../src/polyfill.js' ;
13
13
14
14
const MODULE_NAME = 'permutive'
15
15
16
+ const logger = prefixLog ( '[PermutiveRTD]' )
17
+
16
18
export const PERMUTIVE_SUBMODULE_CONFIG_KEY = 'permutive-prebid-rtd'
19
+ export const PERMUTIVE_STANDARD_KEYWORD = 'p_standard'
20
+ export const PERMUTIVE_CUSTOM_COHORTS_KEYWORD = 'permutive'
17
21
export const PERMUTIVE_STANDARD_AUD_KEYWORD = 'p_standard_aud'
18
22
19
23
export const storage = getStorageManager ( { gvlid : null , moduleName : MODULE_NAME } )
@@ -24,30 +28,6 @@ function init(moduleConfig, userConsent) {
24
28
return true
25
29
}
26
30
27
- /**
28
- * Set segment targeting from cache and then try to wait for Permutive
29
- * to initialise to get realtime segment targeting
30
- * @param {Object } reqBidsConfigObj
31
- * @param {function } callback - Called when submodule is done
32
- * @param {customModuleConfig } reqBidsConfigObj - Publisher config for module
33
- */
34
- export function initSegments ( reqBidsConfigObj , callback , customModuleConfig ) {
35
- const permutiveOnPage = isPermutiveOnPage ( )
36
- const moduleConfig = getModuleConfig ( customModuleConfig )
37
- const segmentData = getSegments ( moduleConfig . params . maxSegs )
38
-
39
- setSegments ( reqBidsConfigObj , moduleConfig , segmentData )
40
-
41
- if ( moduleConfig . waitForIt && permutiveOnPage ) {
42
- window . permutive . ready ( function ( ) {
43
- setSegments ( reqBidsConfigObj , moduleConfig , segmentData )
44
- callback ( )
45
- } , 'realtime' )
46
- } else {
47
- callback ( )
48
- }
49
- }
50
-
51
31
function liftIntoParams ( params ) {
52
32
return isPlainObject ( params ) ? { params } : { }
53
33
}
@@ -109,15 +89,13 @@ export function getModuleConfig(customModuleConfig) {
109
89
110
90
/**
111
91
* Sets ortb2 config for ac bidders
112
- * @param {Object } bidderOrtb2
92
+ * @param {Object } bidderOrtb2 - The ortb2 object for the all bidders
113
93
* @param {Object } customModuleConfig - Publisher config for module
114
94
*/
115
- export function setBidderRtb ( bidderOrtb2 , customModuleConfig ) {
116
- const moduleConfig = getModuleConfig ( customModuleConfig )
95
+ export function setBidderRtb ( bidderOrtb2 , moduleConfig , segmentData ) {
117
96
const acBidders = deepAccess ( moduleConfig , 'params.acBidders' )
118
97
const maxSegs = deepAccess ( moduleConfig , 'params.maxSegs' )
119
98
const transformationConfigs = deepAccess ( moduleConfig , 'params.transformations' ) || [ ]
120
- const segmentData = getSegments ( maxSegs )
121
99
122
100
const ssps = segmentData ?. ssp ?. ssps ?? [ ]
123
101
const sspCohorts = segmentData ?. ssp ?. cohorts ?? [ ]
@@ -126,28 +104,37 @@ export function setBidderRtb (bidderOrtb2, customModuleConfig) {
126
104
bidders . forEach ( function ( bidder ) {
127
105
const currConfig = { ortb2 : bidderOrtb2 [ bidder ] || { } }
128
106
107
+ let cohorts = [ ]
108
+
129
109
const isAcBidder = acBidders . indexOf ( bidder ) > - 1
130
- const isSspBidder = ssps . indexOf ( bidder ) > - 1
110
+ if ( isAcBidder ) {
111
+ cohorts = segmentData . ac
112
+ }
131
113
132
- let cohorts = [ ]
133
- if ( isAcBidder ) cohorts = segmentData . ac
134
- if ( isSspBidder ) cohorts = [ ...new Set ( [ ...cohorts , ...sspCohorts ] ) ] . slice ( 0 , maxSegs )
114
+ const isSspBidder = ssps . indexOf ( bidder ) > - 1
115
+ if ( isSspBidder ) {
116
+ cohorts = [ ...new Set ( [ ...cohorts , ...sspCohorts ] ) ] . slice ( 0 , maxSegs )
117
+ }
135
118
136
- const nextConfig = updateOrtbConfig ( currConfig , cohorts , sspCohorts , transformationConfigs )
137
- bidderOrtb2 [ bidder ] = nextConfig . ortb2 ;
119
+ const nextConfig = updateOrtbConfig ( bidder , currConfig , cohorts , sspCohorts , transformationConfigs , segmentData )
120
+ bidderOrtb2 [ bidder ] = nextConfig . ortb2
138
121
} )
139
122
}
140
123
141
124
/**
142
125
* Updates `user.data` object in existing bidder config with Permutive segments
126
+ * @param string bidder - The bidder
143
127
* @param {Object } currConfig - Current bidder config
144
128
* @param {Object[] } transformationConfigs - array of objects with `id` and `config` properties, used to determine
145
129
* the transformations on user data to include the ORTB2 object
146
130
* @param {string[] } segmentIDs - Permutive segment IDs
147
131
* @param {string[] } sspSegmentIDs - Permutive SSP segment IDs
132
+ * @param {Object } segmentData - The segments available for targeting
148
133
* @return {Object } Merged ortb2 object
149
134
*/
150
- function updateOrtbConfig ( currConfig , segmentIDs , sspSegmentIDs , transformationConfigs ) {
135
+ function updateOrtbConfig ( bidder , currConfig , segmentIDs , sspSegmentIDs , transformationConfigs , segmentData ) {
136
+ const customCohortsData = deepAccess ( segmentData , bidder ) || [ ]
137
+
151
138
const name = 'permutive.com'
152
139
153
140
const permutiveUserData = {
@@ -174,6 +161,19 @@ function updateOrtbConfig (currConfig, segmentIDs, sspSegmentIDs, transformation
174
161
const updatedUserKeywords = ( currentUserKeywords === '' ) ? keywords : `${ currentUserKeywords } ,${ keywords } `
175
162
deepSetValue ( ortbConfig , 'ortb2.user.keywords' , updatedUserKeywords )
176
163
164
+ // Set user extensions
165
+ if ( segmentIDs . length > 0 ) {
166
+ deepSetValue ( ortbConfig , `ortb2.user.ext.data.${ PERMUTIVE_STANDARD_KEYWORD } ` , segmentIDs )
167
+ logger . logInfo ( `Extending ortb2.user.ext.data with "${ PERMUTIVE_STANDARD_KEYWORD } "` , segmentIDs )
168
+ }
169
+
170
+ if ( customCohortsData . length > 0 ) {
171
+ deepSetValue ( ortbConfig , `ortb2.user.ext.data.${ PERMUTIVE_CUSTOM_COHORTS_KEYWORD } ` , customCohortsData . map ( String ) )
172
+ logger . logInfo ( `Extending ortb2.user.ext.data with "${ PERMUTIVE_CUSTOM_COHORTS_KEYWORD } "` , customCohortsData )
173
+ }
174
+
175
+ logger . logInfo ( `Updating ortb2 config for ${ bidder } ` , ortbConfig )
176
+
177
177
return ortbConfig
178
178
}
179
179
@@ -262,17 +262,6 @@ function getDefaultBidderFn (bidder) {
262
262
263
263
return bid
264
264
} ,
265
- rubicon : function ( bid , data , acEnabled ) {
266
- if ( isPStandardTargetingEnabled ( data , acEnabled ) ) {
267
- const segments = pStandardTargeting ( data , acEnabled )
268
- deepSetValue ( bid , 'params.visitor.p_standard' , segments )
269
- }
270
- if ( data . rubicon && data . rubicon . length ) {
271
- deepSetValue ( bid , 'params.visitor.permutive' , data . rubicon . map ( String ) )
272
- }
273
-
274
- return bid
275
- } ,
276
265
ozone : function ( bid , data , acEnabled ) {
277
266
if ( isPStandardTargetingEnabled ( data , acEnabled ) ) {
278
267
const segments = pStandardTargeting ( data , acEnabled )
@@ -283,7 +272,12 @@ function getDefaultBidderFn (bidder) {
283
272
}
284
273
}
285
274
286
- return bidderMap [ bidder ]
275
+ // On no default bidder just return the same bid as passed in
276
+ function bidIdentity ( bid ) {
277
+ return bid
278
+ }
279
+
280
+ return bidderMap [ bidder ] || bidIdentity
287
281
}
288
282
289
283
/**
@@ -383,17 +377,55 @@ function iabSegmentId(permutiveSegmentId, iabIds) {
383
377
return iabIds [ permutiveSegmentId ] || unknownIabSegmentId
384
378
}
385
379
380
+ /**
381
+ * Pull the latest configuration and cohort information and update accordingly.
382
+ *
383
+ * @param reqBidsConfigObj - Bidder provided config for request
384
+ * @param customModuleConfig - Publisher provide config
385
+ */
386
+ export function readAndSetCohorts ( reqBidsConfigObj , moduleConfig ) {
387
+ const segmentData = getSegments ( deepAccess ( moduleConfig , 'params.maxSegs' ) )
388
+
389
+ makeSafe ( function ( ) {
390
+ // Legacy route with custom parameters
391
+ // ACK policy violation, in process of removing
392
+ setSegments ( reqBidsConfigObj , moduleConfig , segmentData )
393
+ } ) ;
394
+
395
+ makeSafe ( function ( ) {
396
+ // Route for bidders supporting ORTB2
397
+ setBidderRtb ( reqBidsConfigObj . ortb2Fragments ?. bidder , moduleConfig , segmentData )
398
+ } )
399
+ }
400
+
401
+ let permutiveSDKInRealTime = false
402
+
386
403
/** @type {RtdSubmodule } */
387
404
export const permutiveSubmodule = {
388
405
name : MODULE_NAME ,
389
406
getBidRequestData : function ( reqBidsConfigObj , callback , customModuleConfig ) {
407
+ const completeBidRequestData = ( ) => {
408
+ logger . logInfo ( `Request data updated` )
409
+ callback ( )
410
+ }
411
+
412
+ const moduleConfig = getModuleConfig ( customModuleConfig )
413
+
414
+ readAndSetCohorts ( reqBidsConfigObj , moduleConfig )
415
+
390
416
makeSafe ( function ( ) {
391
- // Legacy route with custom parameters
392
- initSegments ( reqBidsConfigObj , callback , customModuleConfig )
393
- } ) ;
394
- makeSafe ( function ( ) {
395
- // Route for bidders supporting ORTB2
396
- setBidderRtb ( reqBidsConfigObj . ortb2Fragments ?. bidder , customModuleConfig )
417
+ if ( permutiveSDKInRealTime || ! ( moduleConfig . waitForIt && isPermutiveOnPage ( ) ) ) {
418
+ return completeBidRequestData ( )
419
+ }
420
+
421
+ window . permutive . ready ( function ( ) {
422
+ logger . logInfo ( `SDK is realtime, updating cohorts` )
423
+ permutiveSDKInRealTime = true
424
+ readAndSetCohorts ( reqBidsConfigObj , getModuleConfig ( customModuleConfig ) )
425
+ completeBidRequestData ( )
426
+ } , 'realtime' )
427
+
428
+ logger . logInfo ( `Registered cohort update when SDK is realtime` )
397
429
} )
398
430
} ,
399
431
init : init
0 commit comments