@bidkernel/analytics 0.20.0 → 0.22.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/README.md +19 -1
- package/dist/analytics.global.js +1 -1
- package/dist/index.d.mts +38 -4
- package/dist/index.d.ts +38 -4
- package/dist/index.js +177 -23
- package/dist/index.mjs +175 -23
- package/package.json +1 -1
package/dist/index.js
CHANGED
|
@@ -30,7 +30,9 @@ __export(src_exports, {
|
|
|
30
30
|
getbidkernel: () => getbidkernel,
|
|
31
31
|
hookImaPrototype: () => hookImaPrototype,
|
|
32
32
|
initImaInterception: () => initImaInterception,
|
|
33
|
+
isSessionActive: () => isSessionActive,
|
|
33
34
|
isTrustedEndpoint: () => isTrustedEndpoint,
|
|
35
|
+
onSessionResume: () => onSessionResume,
|
|
34
36
|
registerPrebidAnalytics: () => registerPrebidAnalytics
|
|
35
37
|
});
|
|
36
38
|
module.exports = __toCommonJS(src_exports);
|
|
@@ -354,6 +356,17 @@ var BidderOutcome = {
|
|
|
354
356
|
BIDDER_OUTCOME_NO_RESPONSE: 5,
|
|
355
357
|
UNRECOGNIZED: -1
|
|
356
358
|
};
|
|
359
|
+
var FloorSource = {
|
|
360
|
+
/** FLOOR_SOURCE_UNSPECIFIED - module off, no decision */
|
|
361
|
+
FLOOR_SOURCE_UNSPECIFIED: 0,
|
|
362
|
+
/** FLOOR_SOURCE_STATIC - the publisher's rule, scaled by the treatment */
|
|
363
|
+
FLOOR_SOURCE_STATIC: 1,
|
|
364
|
+
/** FLOOR_SOURCE_POOL - the bid pool's standing bid plus margin */
|
|
365
|
+
FLOOR_SOURCE_POOL: 2,
|
|
366
|
+
/** FLOOR_SOURCE_NONE - module on, but neither term applied */
|
|
367
|
+
FLOOR_SOURCE_NONE: 3,
|
|
368
|
+
UNRECOGNIZED: -1
|
|
369
|
+
};
|
|
357
370
|
function createBaseTraceEventBatch() {
|
|
358
371
|
return {
|
|
359
372
|
propertyId: new Uint8Array(0),
|
|
@@ -756,7 +769,15 @@ var TraceEvent_MetadataEntry = {
|
|
|
756
769
|
}
|
|
757
770
|
};
|
|
758
771
|
function createBaseBidderOutcomeEntry() {
|
|
759
|
-
return {
|
|
772
|
+
return {
|
|
773
|
+
adUnitCode: "",
|
|
774
|
+
outcome: 0,
|
|
775
|
+
bid: void 0,
|
|
776
|
+
refreshIndex: 0,
|
|
777
|
+
floorCents: void 0,
|
|
778
|
+
floorSource: 0,
|
|
779
|
+
floorTreatmentBp: void 0
|
|
780
|
+
};
|
|
760
781
|
}
|
|
761
782
|
var BidderOutcomeEntry = {
|
|
762
783
|
encode(message, writer = new import_wire.BinaryWriter()) {
|
|
@@ -772,6 +793,15 @@ var BidderOutcomeEntry = {
|
|
|
772
793
|
if (message.refreshIndex !== void 0 && message.refreshIndex !== 0) {
|
|
773
794
|
writer.uint32(56).int32(message.refreshIndex);
|
|
774
795
|
}
|
|
796
|
+
if (message.floorCents !== void 0) {
|
|
797
|
+
writer.uint32(64).int32(message.floorCents);
|
|
798
|
+
}
|
|
799
|
+
if (message.floorSource !== void 0 && message.floorSource !== 0) {
|
|
800
|
+
writer.uint32(72).int32(message.floorSource);
|
|
801
|
+
}
|
|
802
|
+
if (message.floorTreatmentBp !== void 0) {
|
|
803
|
+
writer.uint32(80).int32(message.floorTreatmentBp);
|
|
804
|
+
}
|
|
775
805
|
return writer;
|
|
776
806
|
},
|
|
777
807
|
decode(input, length) {
|
|
@@ -809,6 +839,27 @@ var BidderOutcomeEntry = {
|
|
|
809
839
|
message.refreshIndex = reader.int32();
|
|
810
840
|
continue;
|
|
811
841
|
}
|
|
842
|
+
case 8: {
|
|
843
|
+
if (tag !== 64) {
|
|
844
|
+
break;
|
|
845
|
+
}
|
|
846
|
+
message.floorCents = reader.int32();
|
|
847
|
+
continue;
|
|
848
|
+
}
|
|
849
|
+
case 9: {
|
|
850
|
+
if (tag !== 72) {
|
|
851
|
+
break;
|
|
852
|
+
}
|
|
853
|
+
message.floorSource = reader.int32();
|
|
854
|
+
continue;
|
|
855
|
+
}
|
|
856
|
+
case 10: {
|
|
857
|
+
if (tag !== 80) {
|
|
858
|
+
break;
|
|
859
|
+
}
|
|
860
|
+
message.floorTreatmentBp = reader.int32();
|
|
861
|
+
continue;
|
|
862
|
+
}
|
|
812
863
|
}
|
|
813
864
|
if ((tag & 7) === 4 || tag === 0) {
|
|
814
865
|
break;
|
|
@@ -1008,6 +1059,12 @@ var CACHED_BID_TTL_MS = 30 * 60 * 1e3;
|
|
|
1008
1059
|
var MAX_CACHED_BID_KEYS = 200;
|
|
1009
1060
|
var MAX_IMPRESSION_KEYS = 1e3;
|
|
1010
1061
|
var MAX_TRACKED_AUCTIONS = 50;
|
|
1062
|
+
var MAX_FLOOR_DECISIONS = 200;
|
|
1063
|
+
var FLOOR_SOURCE_PROTO = {
|
|
1064
|
+
static: FloorSource.FLOOR_SOURCE_STATIC,
|
|
1065
|
+
pool: FloorSource.FLOOR_SOURCE_POOL,
|
|
1066
|
+
none: FloorSource.FLOOR_SOURCE_NONE
|
|
1067
|
+
};
|
|
1011
1068
|
var CLICK_DEDUP_MS = 1e3;
|
|
1012
1069
|
var SESSION_KEY = "_bidkernel_session";
|
|
1013
1070
|
var SESSION_TS_KEY = "_bidkernel_session_ts";
|
|
@@ -1083,49 +1140,83 @@ function sameEndpointOrigin(a, b) {
|
|
|
1083
1140
|
}
|
|
1084
1141
|
var SESSION_PERSIST_INTERVAL_MS = 60 * 1e3;
|
|
1085
1142
|
var persistedSessionTs = 0;
|
|
1086
|
-
|
|
1143
|
+
var ACTIVITY_EVENTS = ["pointerdown", "pointermove", "keydown", "scroll", "wheel", "touchstart"];
|
|
1144
|
+
var activityListenersBound = false;
|
|
1145
|
+
var sessionResumeListeners = /* @__PURE__ */ new Set();
|
|
1146
|
+
function persistSessionTs(ts) {
|
|
1087
1147
|
try {
|
|
1088
1148
|
if (typeof localStorage !== "undefined") {
|
|
1089
|
-
localStorage.setItem(SESSION_TS_KEY,
|
|
1090
|
-
persistedSessionTs =
|
|
1149
|
+
localStorage.setItem(SESSION_TS_KEY, ts.toString());
|
|
1150
|
+
persistedSessionTs = ts;
|
|
1091
1151
|
}
|
|
1092
1152
|
} catch {
|
|
1093
1153
|
}
|
|
1094
1154
|
}
|
|
1095
|
-
function
|
|
1155
|
+
function isSessionActive(now = Date.now()) {
|
|
1156
|
+
return inMemorySessionTs > 0 && now - inMemorySessionTs <= THIRTY_MINUTES_MS;
|
|
1157
|
+
}
|
|
1158
|
+
function onSessionResume(listener) {
|
|
1159
|
+
bindActivityListeners();
|
|
1160
|
+
sessionResumeListeners.add(listener);
|
|
1161
|
+
return () => {
|
|
1162
|
+
sessionResumeListeners.delete(listener);
|
|
1163
|
+
};
|
|
1164
|
+
}
|
|
1165
|
+
function recordActivity() {
|
|
1096
1166
|
const now = Date.now();
|
|
1167
|
+
const lapsed = !!inMemorySessionId && !isSessionActive(now);
|
|
1097
1168
|
inMemorySessionTs = now;
|
|
1098
|
-
if (
|
|
1169
|
+
if (lapsed) {
|
|
1170
|
+
inMemorySessionId = null;
|
|
1171
|
+
for (const listener of sessionResumeListeners) listener();
|
|
1172
|
+
return;
|
|
1173
|
+
}
|
|
1174
|
+
if (!storageAllowed || !inMemorySessionId || persistedSessionTs === 0) return;
|
|
1099
1175
|
if (now - persistedSessionTs < SESSION_PERSIST_INTERVAL_MS) return;
|
|
1100
1176
|
persistSessionTs(now);
|
|
1101
1177
|
}
|
|
1178
|
+
function sessionNeedsSync() {
|
|
1179
|
+
return !inMemorySessionId || storageAllowed && persistedSessionTs === 0;
|
|
1180
|
+
}
|
|
1181
|
+
function bindActivityListeners() {
|
|
1182
|
+
if (activityListenersBound || typeof window === "undefined") return;
|
|
1183
|
+
activityListenersBound = true;
|
|
1184
|
+
const onActivity = () => recordActivity();
|
|
1185
|
+
for (const name of ACTIVITY_EVENTS) {
|
|
1186
|
+
window.addEventListener(name, onActivity, { passive: true, capture: true });
|
|
1187
|
+
}
|
|
1188
|
+
if (typeof document !== "undefined") {
|
|
1189
|
+
document.addEventListener("visibilitychange", () => {
|
|
1190
|
+
if (document.visibilityState === "visible") recordActivity();
|
|
1191
|
+
});
|
|
1192
|
+
}
|
|
1193
|
+
}
|
|
1102
1194
|
function getOrCreateSessionId() {
|
|
1103
1195
|
const now = Date.now();
|
|
1104
|
-
const memoryFresh = !!inMemorySessionId &&
|
|
1196
|
+
const memoryFresh = !!inMemorySessionId && isSessionActive(now);
|
|
1105
1197
|
try {
|
|
1106
1198
|
if (storageAllowed && typeof localStorage !== "undefined") {
|
|
1107
1199
|
const storedId = localStorage.getItem(SESSION_KEY);
|
|
1108
1200
|
const tsStr = localStorage.getItem(SESSION_TS_KEY);
|
|
1109
1201
|
const storedTs = tsStr ? parseInt(tsStr, 10) || 0 : 0;
|
|
1110
1202
|
if (storedId && storedTs && now - storedTs <= THIRTY_MINUTES_MS) {
|
|
1111
|
-
|
|
1112
|
-
|
|
1113
|
-
|
|
1203
|
+
if (inMemorySessionId !== storedId || inMemorySessionTs < storedTs) {
|
|
1204
|
+
inMemorySessionId = storedId;
|
|
1205
|
+
inMemorySessionTs = Math.max(inMemorySessionTs, storedTs);
|
|
1206
|
+
}
|
|
1207
|
+
if (persistedSessionTs === 0) persistedSessionTs = storedTs;
|
|
1114
1208
|
return storedId;
|
|
1115
1209
|
}
|
|
1116
1210
|
const newId = memoryFresh ? inMemorySessionId : generateUUID();
|
|
1211
|
+
if (!memoryFresh) inMemorySessionTs = now;
|
|
1117
1212
|
localStorage.setItem(SESSION_KEY, newId);
|
|
1118
|
-
persistSessionTs(
|
|
1213
|
+
persistSessionTs(inMemorySessionTs);
|
|
1119
1214
|
inMemorySessionId = newId;
|
|
1120
|
-
inMemorySessionTs = now;
|
|
1121
1215
|
return newId;
|
|
1122
1216
|
}
|
|
1123
1217
|
} catch {
|
|
1124
1218
|
}
|
|
1125
|
-
if (
|
|
1126
|
-
inMemorySessionTs = now;
|
|
1127
|
-
return inMemorySessionId;
|
|
1128
|
-
}
|
|
1219
|
+
if (memoryFresh) return inMemorySessionId;
|
|
1129
1220
|
inMemorySessionId = generateUUID();
|
|
1130
1221
|
inMemorySessionTs = now;
|
|
1131
1222
|
return inMemorySessionId;
|
|
@@ -1284,7 +1375,13 @@ var BidkernelPrebidAnalytics = class _BidkernelPrebidAnalytics {
|
|
|
1284
1375
|
videoDetachCleanups = /* @__PURE__ */ new Set();
|
|
1285
1376
|
// Compacted bidder participation map per auction: auctionId -> Map<`${bidder}:${adUnitCode}`, BidderOutcomeEntry>
|
|
1286
1377
|
auctionBidderOutcomes = /* @__PURE__ */ new Map();
|
|
1378
|
+
// Live Floors decisions: `${auctionId}:${adUnitCode}` -> decision (see recordFloorDecision)
|
|
1379
|
+
floorDecisions = /* @__PURE__ */ new Map();
|
|
1287
1380
|
logger;
|
|
1381
|
+
// True when this instance owns its session id (none was supplied), so the
|
|
1382
|
+
// id follows the page-wide session as it lapses and restarts. An id the
|
|
1383
|
+
// integration supplied is stamped as given.
|
|
1384
|
+
managesSessionId;
|
|
1288
1385
|
constructor(config) {
|
|
1289
1386
|
if (config.storageAllowed !== void 0) {
|
|
1290
1387
|
_BidkernelPrebidAnalytics.setStorageAllowed(config.storageAllowed);
|
|
@@ -1295,7 +1392,7 @@ var BidkernelPrebidAnalytics = class _BidkernelPrebidAnalytics {
|
|
|
1295
1392
|
endpoint,
|
|
1296
1393
|
propertyId: config.propertyId || "",
|
|
1297
1394
|
pageviewId: config.pageviewId || generateUUID(),
|
|
1298
|
-
sessionId: config.sessionId ||
|
|
1395
|
+
sessionId: config.sessionId || "",
|
|
1299
1396
|
userId: config.userId || "",
|
|
1300
1397
|
deviceType: config.deviceType || "desktop",
|
|
1301
1398
|
country: config.country || "",
|
|
@@ -1314,6 +1411,9 @@ var BidkernelPrebidAnalytics = class _BidkernelPrebidAnalytics {
|
|
|
1314
1411
|
prefix: "[bidkernel][prebid-analytics]",
|
|
1315
1412
|
logLevel: this.config.logLevel
|
|
1316
1413
|
});
|
|
1414
|
+
recordActivity();
|
|
1415
|
+
this.managesSessionId = !config.sessionId;
|
|
1416
|
+
if (this.managesSessionId) this.config.sessionId = getOrCreateSessionId();
|
|
1317
1417
|
if (requestedEndpoint && !endpoint) {
|
|
1318
1418
|
this.log(
|
|
1319
1419
|
"ERROR",
|
|
@@ -1362,6 +1462,7 @@ var BidkernelPrebidAnalytics = class _BidkernelPrebidAnalytics {
|
|
|
1362
1462
|
if (typeof document !== "undefined") {
|
|
1363
1463
|
document.addEventListener("visibilitychange", this.boundVisibilityChange);
|
|
1364
1464
|
}
|
|
1465
|
+
bindActivityListeners();
|
|
1365
1466
|
this.flushTimer = setInterval(() => this.flush(), FLUSH_INTERVAL_MS);
|
|
1366
1467
|
this.resendPersistedBatches();
|
|
1367
1468
|
}
|
|
@@ -1471,6 +1572,7 @@ var BidkernelPrebidAnalytics = class _BidkernelPrebidAnalytics {
|
|
|
1471
1572
|
this.slotEmittedImpressionKeys.clear();
|
|
1472
1573
|
this.slotLastAuctionIds.clear();
|
|
1473
1574
|
this.auctionBidderOutcomes.clear();
|
|
1575
|
+
this.floorDecisions.clear();
|
|
1474
1576
|
if (this.flushTimer) {
|
|
1475
1577
|
clearInterval(this.flushTimer);
|
|
1476
1578
|
this.flushTimer = null;
|
|
@@ -2230,15 +2332,44 @@ var BidkernelPrebidAnalytics = class _BidkernelPrebidAnalytics {
|
|
|
2230
2332
|
if (eventType === void 0) return;
|
|
2231
2333
|
this.enqueue(eventType, eventName, data, level);
|
|
2232
2334
|
}
|
|
2335
|
+
/**
|
|
2336
|
+
* Record the wrapper's Live Floors decision for an auction and ad unit,
|
|
2337
|
+
* before the auction runs. The decision is stamped on the auction's
|
|
2338
|
+
* outcome entries for the ad unit at auction end and on the win and
|
|
2339
|
+
* impression rows that follow, so every outcome can be split by floor,
|
|
2340
|
+
* source and treatment without a join. Integrations without the module
|
|
2341
|
+
* never call this and their rows carry no floor fields.
|
|
2342
|
+
*/
|
|
2343
|
+
recordFloorDecision(auctionId, adUnitCode, decision) {
|
|
2344
|
+
if (!auctionId || !adUnitCode) return;
|
|
2345
|
+
const key = `${auctionId}:${adUnitCode}`;
|
|
2346
|
+
this.floorDecisions.delete(key);
|
|
2347
|
+
this.floorDecisions.set(key, {
|
|
2348
|
+
floorCents: decision.floorCents !== void 0 && Number.isFinite(decision.floorCents) ? Math.round(decision.floorCents) : void 0,
|
|
2349
|
+
source: decision.source,
|
|
2350
|
+
treatment: Number.isFinite(decision.treatment) ? decision.treatment : 1
|
|
2351
|
+
});
|
|
2352
|
+
while (this.floorDecisions.size > MAX_FLOOR_DECISIONS) {
|
|
2353
|
+
const oldest = this.floorDecisions.keys().next();
|
|
2354
|
+
if (oldest.done) break;
|
|
2355
|
+
this.floorDecisions.delete(oldest.value);
|
|
2356
|
+
}
|
|
2357
|
+
}
|
|
2358
|
+
floorDecisionFor(auctionId, adUnitCode) {
|
|
2359
|
+
return auctionId && adUnitCode ? this.floorDecisions.get(`${auctionId}:${adUnitCode}`) : void 0;
|
|
2360
|
+
}
|
|
2233
2361
|
setUserId(userId) {
|
|
2234
2362
|
this.config.userId = userId;
|
|
2235
2363
|
}
|
|
2236
2364
|
setSessionId(sessionId) {
|
|
2237
2365
|
this.config.sessionId = sessionId;
|
|
2366
|
+
this.managesSessionId = !sessionId;
|
|
2367
|
+
if (this.managesSessionId) this.config.sessionId = getOrCreateSessionId();
|
|
2238
2368
|
}
|
|
2239
2369
|
navigate(pageviewId, pageUrl) {
|
|
2240
2370
|
this.disable();
|
|
2241
2371
|
this.slotRefreshIndices.clear();
|
|
2372
|
+
this.floorDecisions.clear();
|
|
2242
2373
|
this.pendingThresholdListeners.clear();
|
|
2243
2374
|
this.config.pageviewId = pageviewId || generateUUID();
|
|
2244
2375
|
if (pageUrl) {
|
|
@@ -2252,7 +2383,7 @@ var BidkernelPrebidAnalytics = class _BidkernelPrebidAnalytics {
|
|
|
2252
2383
|
this.pageUrl = "";
|
|
2253
2384
|
}
|
|
2254
2385
|
this.logger.resetTiming();
|
|
2255
|
-
|
|
2386
|
+
recordActivity();
|
|
2256
2387
|
this.enable();
|
|
2257
2388
|
}
|
|
2258
2389
|
handleAuctionInit(data) {
|
|
@@ -2591,7 +2722,9 @@ var BidkernelPrebidAnalytics = class _BidkernelPrebidAnalytics {
|
|
|
2591
2722
|
enqueue(type, eventName, data, level) {
|
|
2592
2723
|
if (!this.isEnabled) return;
|
|
2593
2724
|
if (!this.shouldSample(type, level)) return;
|
|
2594
|
-
|
|
2725
|
+
if (this.managesSessionId && sessionNeedsSync()) {
|
|
2726
|
+
this.config.sessionId = getOrCreateSessionId();
|
|
2727
|
+
}
|
|
2595
2728
|
const protoEvent = {
|
|
2596
2729
|
eventId: idToBytes(generateUUID()),
|
|
2597
2730
|
timestampMs: Date.now(),
|
|
@@ -2626,13 +2759,32 @@ var BidkernelPrebidAnalytics = class _BidkernelPrebidAnalytics {
|
|
|
2626
2759
|
}
|
|
2627
2760
|
if (data.bidderOutcomes && Array.isArray(data.bidderOutcomes)) {
|
|
2628
2761
|
protoEvent.bidderOutcomes = data.bidderOutcomes.map(
|
|
2629
|
-
(entry) =>
|
|
2630
|
-
|
|
2631
|
-
|
|
2632
|
-
|
|
2762
|
+
(entry) => {
|
|
2763
|
+
const floor = this.floorDecisionFor(String(data.auctionId || ""), entry.adUnitCode || "");
|
|
2764
|
+
return {
|
|
2765
|
+
...entry,
|
|
2766
|
+
refreshIndex: entry.refreshIndex ?? this.auctionCycleIndex(entry.adUnitCode || ""),
|
|
2767
|
+
...floor ? {
|
|
2768
|
+
floorCents: floor.floorCents,
|
|
2769
|
+
floorSource: FLOOR_SOURCE_PROTO[floor.source],
|
|
2770
|
+
floorTreatmentBp: Math.round(floor.treatment * 1e4)
|
|
2771
|
+
} : {}
|
|
2772
|
+
};
|
|
2773
|
+
}
|
|
2633
2774
|
);
|
|
2634
2775
|
}
|
|
2635
2776
|
const metadata = { ...data.metadata };
|
|
2777
|
+
if (type === TraceEventType.BID_WIN || type === TraceEventType.IMPRESSION) {
|
|
2778
|
+
const floor = this.floorDecisionFor(
|
|
2779
|
+
String(data.auctionId || ""),
|
|
2780
|
+
protoEvent.adUnitCode || ""
|
|
2781
|
+
);
|
|
2782
|
+
if (floor) {
|
|
2783
|
+
if (floor.floorCents !== void 0) metadata.floor_cents = String(floor.floorCents);
|
|
2784
|
+
metadata.floor_source = floor.source;
|
|
2785
|
+
metadata.floor_treatment = floor.treatment.toFixed(2);
|
|
2786
|
+
}
|
|
2787
|
+
}
|
|
2636
2788
|
if (data.error !== void 0 && data.error !== null) {
|
|
2637
2789
|
metadata.error = typeof data.error === "object" && data.error.message ? String(data.error.message) : String(data.error);
|
|
2638
2790
|
}
|
|
@@ -3841,6 +3993,8 @@ function getbidkernel(alias = "bidkernel") {
|
|
|
3841
3993
|
getbidkernel,
|
|
3842
3994
|
hookImaPrototype,
|
|
3843
3995
|
initImaInterception,
|
|
3996
|
+
isSessionActive,
|
|
3844
3997
|
isTrustedEndpoint,
|
|
3998
|
+
onSessionResume,
|
|
3845
3999
|
registerPrebidAnalytics
|
|
3846
4000
|
});
|