@bidkernel/analytics 0.10.0 → 0.12.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/dist/index.js CHANGED
@@ -31,6 +31,292 @@ __export(src_exports, {
31
31
  });
32
32
  module.exports = __toCommonJS(src_exports);
33
33
 
34
+ // ../logger/src/index.ts
35
+ var LogLevel = {
36
+ DEBUG: "DEBUG",
37
+ INFO: "INFO",
38
+ WARN: "WARN",
39
+ ERROR: "ERROR"
40
+ };
41
+ var LOG_LEVEL_MAP = {
42
+ [LogLevel.DEBUG]: 10,
43
+ [LogLevel.INFO]: 20,
44
+ [LogLevel.WARN]: 30,
45
+ [LogLevel.ERROR]: 40
46
+ };
47
+ var COLORS = {
48
+ badge: "color: #2dd4bf; font-weight: bold",
49
+ // teal - [ads] badge
50
+ badgeWarn: "background: #f59e0b; color: #fff; padding: 2px 4px; border-radius: 3px; font-weight: bold",
51
+ // amber - [ads] badge (warning)
52
+ badgeError: "background: #ef4444; color: #fff; padding: 2px 4px; border-radius: 3px; font-weight: bold",
53
+ // red - [ads] badge (error)
54
+ dim: "color: #6b7280",
55
+ // gray - timestamp
56
+ event: "color: #38bdf8; font-weight: bold",
57
+ // blue - event name
58
+ eventWarn: "color: #f59e0b; font-weight: bold",
59
+ // amber - event name (warning)
60
+ eventError: "color: #ef4444; font-weight: bold",
61
+ // red - event name (error)
62
+ reset: "color: inherit"
63
+ // back to default
64
+ };
65
+ var logCounter = 0;
66
+ var localGlobalListeners = /* @__PURE__ */ new Set();
67
+ function getGlobalListeners() {
68
+ if (typeof window !== "undefined") {
69
+ const win = window;
70
+ if (!win.__bidkernelLogListeners) {
71
+ win.__bidkernelLogListeners = /* @__PURE__ */ new Set();
72
+ }
73
+ return win.__bidkernelLogListeners;
74
+ }
75
+ return localGlobalListeners;
76
+ }
77
+ function formatTime(ms) {
78
+ if (ms < 0 || !Number.isFinite(ms)) ms = 0;
79
+ if (ms < 1e3) return `${ms.toFixed(2)}ms`;
80
+ const s = ms / 1e3;
81
+ if (s < 60) return `${s.toFixed(2)}s`;
82
+ const m = Math.floor(s / 60);
83
+ if (m < 60) return `${m}m ${(s % 60).toFixed(2)}s`;
84
+ const h = Math.floor(m / 60);
85
+ return `${h}h ${m % 60}m ${(s % 60).toFixed(2)}s`;
86
+ }
87
+ function normalizeLogLevel(level) {
88
+ if (typeof level === "string") {
89
+ const upper = level.toUpperCase();
90
+ if (upper === "DEBUG" || upper === "INFO" || upper === "WARN" || upper === "ERROR") {
91
+ return upper;
92
+ }
93
+ }
94
+ return LogLevel.INFO;
95
+ }
96
+ var Logger = class _Logger {
97
+ _prefix;
98
+ _level;
99
+ _loadedAt;
100
+ _now;
101
+ _console;
102
+ _customFormatTime;
103
+ _listeners = /* @__PURE__ */ new Set();
104
+ constructor(options = {}) {
105
+ this._prefix = options.prefix ?? "[bidkernel]";
106
+ this._level = normalizeLogLevel(options.logLevel ?? LogLevel.INFO);
107
+ this._now = options.now;
108
+ this._console = options.console;
109
+ this._customFormatTime = options.formatTime;
110
+ if (options.onLog) {
111
+ this._listeners.add(options.onLog);
112
+ }
113
+ this._loadedAt = options.loadedAt ?? (this._now ? this._now() : typeof performance !== "undefined" && typeof performance.now === "function" ? performance.now() : Date.now());
114
+ }
115
+ get prefix() {
116
+ return this._prefix;
117
+ }
118
+ set prefix(val) {
119
+ this._prefix = val;
120
+ }
121
+ get logLevel() {
122
+ return this._level;
123
+ }
124
+ set logLevel(val) {
125
+ this._level = normalizeLogLevel(val);
126
+ }
127
+ getLevel() {
128
+ return this._level;
129
+ }
130
+ setLevel(level) {
131
+ this._level = normalizeLogLevel(level);
132
+ }
133
+ getPrefix() {
134
+ return this._prefix;
135
+ }
136
+ setPrefix(prefix) {
137
+ this._prefix = prefix;
138
+ }
139
+ resetTiming(loadedAt) {
140
+ this._loadedAt = loadedAt ?? (this._now ? this._now() : typeof performance !== "undefined" && typeof performance.now === "function" ? performance.now() : Date.now());
141
+ }
142
+ getLoadedAt() {
143
+ return this._loadedAt;
144
+ }
145
+ addListener(listener) {
146
+ this._listeners.add(listener);
147
+ return () => {
148
+ this._listeners.delete(listener);
149
+ };
150
+ }
151
+ removeListener(listener) {
152
+ this._listeners.delete(listener);
153
+ }
154
+ isEnabled(level) {
155
+ const target = normalizeLogLevel(level);
156
+ return (LOG_LEVEL_MAP[target] ?? 20) >= (LOG_LEVEL_MAP[this._level] ?? 20);
157
+ }
158
+ formatTime(ms) {
159
+ if (this._customFormatTime) {
160
+ return this._customFormatTime(ms);
161
+ }
162
+ return formatTime(ms);
163
+ }
164
+ _getConsole() {
165
+ if (this._console) return this._console;
166
+ if (typeof console !== "undefined") return console;
167
+ return void 0;
168
+ }
169
+ _getElapsed() {
170
+ const current = this._now ? this._now() : typeof performance !== "undefined" && typeof performance.now === "function" ? performance.now() : Date.now();
171
+ return Math.max(0, current - this._loadedAt);
172
+ }
173
+ _dispatchRecord(record) {
174
+ for (const l of this._listeners) {
175
+ try {
176
+ l(record);
177
+ } catch {
178
+ }
179
+ }
180
+ const globalListeners = getGlobalListeners();
181
+ for (const gl of globalListeners) {
182
+ if (!this._listeners.has(gl)) {
183
+ try {
184
+ gl(record);
185
+ } catch {
186
+ }
187
+ }
188
+ }
189
+ if (typeof window !== "undefined" && typeof window.dispatchEvent === "function") {
190
+ try {
191
+ window.dispatchEvent(new CustomEvent("__bidkernel_log__", { detail: record }));
192
+ } catch {
193
+ }
194
+ }
195
+ }
196
+ log(level, nameOrMsg, ...args) {
197
+ const normLevel = normalizeLogLevel(level);
198
+ if (!this.isEnabled(normLevel)) {
199
+ return;
200
+ }
201
+ const elapsed = this._getElapsed();
202
+ const formattedTimeStr = this.formatTime(elapsed);
203
+ const nowEpoch = Date.now();
204
+ const recordId = `bk_log_${nowEpoch}_${++logCounter}`;
205
+ const record = {
206
+ id: recordId,
207
+ timestamp: nowEpoch,
208
+ elapsedMs: elapsed,
209
+ level: normLevel,
210
+ prefix: this._prefix,
211
+ message: nameOrMsg,
212
+ args,
213
+ data: args.length === 1 ? args[0] : args.length > 1 ? args : void 0
214
+ };
215
+ this._dispatchRecord(record);
216
+ const c = this._getConsole();
217
+ if (!c) return;
218
+ let badgeStyle = COLORS.badge;
219
+ let eventStyle = COLORS.event;
220
+ if (normLevel === LogLevel.WARN) {
221
+ badgeStyle = COLORS.badgeWarn;
222
+ eventStyle = COLORS.eventWarn;
223
+ } else if (normLevel === LogLevel.ERROR) {
224
+ badgeStyle = COLORS.badgeError;
225
+ eventStyle = COLORS.eventError;
226
+ }
227
+ const fmt = `%c${this._prefix}%c ${formattedTimeStr} %c${nameOrMsg}%c`;
228
+ const styles = [badgeStyle, COLORS.dim, eventStyle, COLORS.reset];
229
+ const callArgs = [fmt, ...styles];
230
+ if (args.length > 0) {
231
+ callArgs.push(...args);
232
+ }
233
+ switch (normLevel) {
234
+ case LogLevel.DEBUG:
235
+ if (typeof c.log === "function") {
236
+ c.log(...callArgs);
237
+ } else if (typeof c.debug === "function") {
238
+ c.debug(...callArgs);
239
+ }
240
+ break;
241
+ case LogLevel.INFO:
242
+ if (typeof c.info === "function") {
243
+ c.info(...callArgs);
244
+ } else if (typeof c.log === "function") {
245
+ c.log(...callArgs);
246
+ }
247
+ break;
248
+ case LogLevel.WARN:
249
+ if (typeof c.warn === "function") {
250
+ c.warn(...callArgs);
251
+ } else if (typeof c.log === "function") {
252
+ c.log(...callArgs);
253
+ }
254
+ break;
255
+ case LogLevel.ERROR:
256
+ if (typeof c.error === "function") {
257
+ c.error(...callArgs);
258
+ } else if (typeof c.log === "function") {
259
+ c.log(...callArgs);
260
+ }
261
+ break;
262
+ default:
263
+ if (typeof c.log === "function") {
264
+ c.log(...callArgs);
265
+ }
266
+ break;
267
+ }
268
+ }
269
+ debug(nameOrMsg, ...args) {
270
+ this.log(LogLevel.DEBUG, nameOrMsg, ...args);
271
+ }
272
+ info(nameOrMsg, ...args) {
273
+ this.log(LogLevel.INFO, nameOrMsg, ...args);
274
+ }
275
+ warn(nameOrMsg, ...args) {
276
+ this.log(LogLevel.WARN, nameOrMsg, ...args);
277
+ }
278
+ error(nameOrMsg, ...args) {
279
+ this.log(LogLevel.ERROR, nameOrMsg, ...args);
280
+ }
281
+ logEvent(event) {
282
+ if (!event) return;
283
+ if (event.data !== void 0) {
284
+ this.log(event.level, event.eventName, event.data);
285
+ } else {
286
+ this.log(event.level, event.eventName);
287
+ }
288
+ }
289
+ child(subNamespace, options = {}) {
290
+ let childPrefix = this._prefix;
291
+ if (subNamespace) {
292
+ const formattedSub = subNamespace.startsWith("[") && subNamespace.endsWith("]") ? subNamespace : `[${subNamespace}]`;
293
+ childPrefix = `${this._prefix}${formattedSub}`;
294
+ }
295
+ return new _Logger({
296
+ prefix: childPrefix,
297
+ logLevel: options.logLevel ?? this._level,
298
+ loadedAt: options.loadedAt ?? this._loadedAt,
299
+ now: options.now ?? this._now,
300
+ console: options.console ?? this._console,
301
+ formatTime: options.formatTime ?? this._customFormatTime,
302
+ ...options
303
+ });
304
+ }
305
+ withPrefix(prefix) {
306
+ return new _Logger({
307
+ prefix,
308
+ logLevel: this._level,
309
+ loadedAt: this._loadedAt,
310
+ now: this._now,
311
+ console: this._console,
312
+ formatTime: this._customFormatTime
313
+ });
314
+ }
315
+ };
316
+ function createLogger(options) {
317
+ return new Logger(options);
318
+ }
319
+
34
320
  // ../../protogen/trace_event.ts
35
321
  var import_wire = require("@bufbuild/protobuf/wire");
36
322
  var TraceEventType = {
@@ -789,7 +1075,8 @@ var EVENT_NAME_TO_TYPE = {
789
1075
  timeInView: TraceEventType.TIME_IN_VIEW,
790
1076
  viewable: TraceEventType.VIEWABLE
791
1077
  };
792
- var IMMEDIATE_FLUSH_TYPES = /* @__PURE__ */ new Set([
1078
+ var REVENUE_FLUSH_DELAY_MS = 3e3;
1079
+ var REVENUE_FLUSH_TYPES = /* @__PURE__ */ new Set([
793
1080
  TraceEventType.IMPRESSION,
794
1081
  TraceEventType.BID_WIN,
795
1082
  TraceEventType.CLICK
@@ -1273,7 +1560,7 @@ var BidkernelPrebidAnalytics = class _BidkernelPrebidAnalytics {
1273
1560
  consecutiveSendFailures = 0;
1274
1561
  nextSendAllowedAt = 0;
1275
1562
  replayedEventCount = 0;
1276
- immediateFlushScheduled = false;
1563
+ revenueFlushTimer = null;
1277
1564
  // localStorage keys of exit batches this instance persisted, so a page that
1278
1565
  // survives its own pagehide/hidden (bfcache restore, tab re-focus) can
1279
1566
  // remove them instead of leaving them for a duplicate resend.
@@ -1294,6 +1581,7 @@ var BidkernelPrebidAnalytics = class _BidkernelPrebidAnalytics {
1294
1581
  videoDetachCleanups = /* @__PURE__ */ new Set();
1295
1582
  // Compacted bidder participation map per auction: auctionId -> Map<`${bidder}:${adUnitCode}`, BidderOutcomeEntry>
1296
1583
  auctionBidderOutcomes = /* @__PURE__ */ new Map();
1584
+ logger;
1297
1585
  constructor(config) {
1298
1586
  const requestedEndpoint = config.endpoint || "";
1299
1587
  const endpoint = !requestedEndpoint || isTrustedEndpoint(requestedEndpoint) ? requestedEndpoint : "";
@@ -1312,8 +1600,13 @@ var BidkernelPrebidAnalytics = class _BidkernelPrebidAnalytics {
1312
1600
  viewabilityEnabled: config.viewabilityEnabled ?? true,
1313
1601
  logLevel: config.logLevel || "INFO",
1314
1602
  pbjsGlobalName: config.pbjsGlobalName || "pbjs",
1315
- attachPbjsListeners: config.attachPbjsListeners ?? true
1603
+ attachPbjsListeners: config.attachPbjsListeners ?? true,
1604
+ revenueFlushDelayMs: Number.isFinite(config.revenueFlushDelayMs) && config.revenueFlushDelayMs >= 0 ? config.revenueFlushDelayMs : REVENUE_FLUSH_DELAY_MS
1316
1605
  };
1606
+ this.logger = createLogger({
1607
+ prefix: "[bidkernel][prebid-analytics]",
1608
+ logLevel: this.config.logLevel
1609
+ });
1317
1610
  if (requestedEndpoint && !endpoint) {
1318
1611
  this.log(
1319
1612
  "ERROR",
@@ -1330,6 +1623,7 @@ var BidkernelPrebidAnalytics = class _BidkernelPrebidAnalytics {
1330
1623
  if (this.isEnabled) return;
1331
1624
  this.isEnabled = true;
1332
1625
  _BidkernelPrebidAnalytics.activeInstances.add(this);
1626
+ this.logger.setLevel(this.config.logLevel);
1333
1627
  if (!this.config.endpoint) {
1334
1628
  this.log("WARN", "Endpoint is empty. Analytics events will not be transmitted.");
1335
1629
  }
@@ -1466,6 +1760,10 @@ var BidkernelPrebidAnalytics = class _BidkernelPrebidAnalytics {
1466
1760
  clearInterval(this.flushTimer);
1467
1761
  this.flushTimer = null;
1468
1762
  }
1763
+ if (this.revenueFlushTimer) {
1764
+ clearTimeout(this.revenueFlushTimer);
1765
+ this.revenueFlushTimer = null;
1766
+ }
1469
1767
  if (this.persistedCleanupTimer) {
1470
1768
  clearTimeout(this.persistedCleanupTimer);
1471
1769
  this.persistedCleanupTimer = null;
@@ -2615,6 +2913,7 @@ var BidkernelPrebidAnalytics = class _BidkernelPrebidAnalytics {
2615
2913
  } else {
2616
2914
  this.pageUrl = "";
2617
2915
  }
2916
+ this.logger.resetTiming();
2618
2917
  extendSession();
2619
2918
  this.enable();
2620
2919
  }
@@ -3029,12 +3328,11 @@ var BidkernelPrebidAnalytics = class _BidkernelPrebidAnalytics {
3029
3328
  }
3030
3329
  if (this.queue.length >= BATCH_SIZE) {
3031
3330
  this.flush();
3032
- } else if (IMMEDIATE_FLUSH_TYPES.has(type) && !this.immediateFlushScheduled) {
3033
- this.immediateFlushScheduled = true;
3034
- setTimeout(() => {
3035
- this.immediateFlushScheduled = false;
3331
+ } else if (REVENUE_FLUSH_TYPES.has(type) && this.revenueFlushTimer === null) {
3332
+ this.revenueFlushTimer = setTimeout(() => {
3333
+ this.revenueFlushTimer = null;
3036
3334
  this.flush();
3037
- }, 0);
3335
+ }, this.config.revenueFlushDelayMs);
3038
3336
  }
3039
3337
  }
3040
3338
  shouldSample(type, level) {
@@ -3294,25 +3592,13 @@ var BidkernelPrebidAnalytics = class _BidkernelPrebidAnalytics {
3294
3592
  }
3295
3593
  }
3296
3594
  log(level, msg, ...args) {
3297
- const levels = { DEBUG: 10, INFO: 20, WARN: 30, ERROR: 40 };
3298
- if (levels[level] < levels[this.config.logLevel]) return;
3299
- const prefix = `[bidkernel][prebid-analytics][${level}]`;
3300
- switch (level) {
3301
- case "DEBUG":
3302
- console.debug(prefix, msg, ...args);
3303
- break;
3304
- case "INFO":
3305
- console.info(prefix, msg, ...args);
3306
- break;
3307
- case "WARN":
3308
- console.warn(prefix, msg, ...args);
3309
- break;
3310
- case "ERROR":
3311
- console.error(prefix, msg, ...args);
3312
- break;
3313
- }
3595
+ this.logger.log(level, msg, ...args);
3314
3596
  }
3315
3597
  };
3598
+ var defaultLogger = createLogger({
3599
+ prefix: "[bidkernel]",
3600
+ logLevel: "INFO"
3601
+ });
3316
3602
  function extractAnalyticsOptions(config, allowProviderless = true) {
3317
3603
  if (!config) return null;
3318
3604
  if (Array.isArray(config)) {
@@ -3369,8 +3655,8 @@ function registerPrebidAnalytics(pbjsGlobalName = "pbjs", defaults) {
3369
3655
  ...options
3370
3656
  };
3371
3657
  if (pinnedEndpoint && !sameEndpointOrigin(merged.endpoint || "", pinnedEndpoint)) {
3372
- console.warn(
3373
- `[bidkernel] Ignoring analytics endpoint change to ${merged.endpoint || "(empty)"}: this page is pinned to ${pinnedEndpoint}. Reload to change the ingest endpoint.`
3658
+ defaultLogger.warn(
3659
+ `Ignoring analytics endpoint change to ${merged.endpoint || "(empty)"}: this page is pinned to ${pinnedEndpoint}. Reload to change the ingest endpoint.`
3374
3660
  );
3375
3661
  merged.endpoint = pinnedEndpoint;
3376
3662
  }
@@ -3378,7 +3664,7 @@ function registerPrebidAnalytics(pbjsGlobalName = "pbjs", defaults) {
3378
3664
  try {
3379
3665
  previous.disable();
3380
3666
  } catch (e) {
3381
- console.warn("[bidkernel] Failed to disable previous analytics instance:", e);
3667
+ defaultLogger.warn("Failed to disable previous analytics instance:", e);
3382
3668
  }
3383
3669
  }
3384
3670
  const analytics = new BidkernelPrebidAnalytics(merged);
@@ -3411,7 +3697,7 @@ function registerPrebidAnalytics(pbjsGlobalName = "pbjs", defaults) {
3411
3697
  enableInstance(stashed);
3412
3698
  }
3413
3699
  } catch (e) {
3414
- console.warn("[bidkernel] Failed to register standard Prebid analytics adapter:", e);
3700
+ defaultLogger.warn("Failed to register standard Prebid analytics adapter:", e);
3415
3701
  }
3416
3702
  };
3417
3703
  if (pbjs.adapterManager && typeof pbjs.adapterManager.registerAnalyticsAdapter === "function") {