@drivemetadata-ai/sdk 0.1.1-beta.4 → 0.1.1

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.
@@ -224,6 +224,15 @@ var sensitiveKeys = /* @__PURE__ */ new Set([
224
224
  "session",
225
225
  "cookie"
226
226
  ]);
227
+ function redactUrl(url, allowQueryKeys = ["utm_source", "utm_medium", "utm_campaign", "utm_term", "utm_content"]) {
228
+ const parsed = new URL(url, "https://placeholder.local");
229
+ for (const key of Array.from(parsed.searchParams.keys())) {
230
+ if (!allowQueryKeys.includes(key)) {
231
+ parsed.searchParams.set(key, "[REDACTED]");
232
+ }
233
+ }
234
+ return url.startsWith("http") ? parsed.toString() : `${parsed.pathname}${parsed.search}`;
235
+ }
227
236
  function sanitizeValue(value, allow, path = []) {
228
237
  if (Array.isArray(value)) {
229
238
  return value.map((item) => sanitizeValue(item, allow, path));
@@ -245,6 +254,127 @@ function sanitizeProperties(input, allowRawKeys = []) {
245
254
  return sanitizeValue(input, allow);
246
255
  }
247
256
 
257
+ // src/browser/core/attribute-persistence.ts
258
+ var DMD_ATTRIBUTES_STORAGE_KEY = "dmd_attributes";
259
+ var SESSION_STORAGE_KEY = "sessionData";
260
+ var SESSION_ID_KEY = "sessionId";
261
+ var SESSION_TIMESTAMP_KEY = "timestamp";
262
+ function isBlankValue(value) {
263
+ return value === null || value === void 0 || typeof value === "string" && value.trim() === "";
264
+ }
265
+ function readAttributes(base) {
266
+ const raw = base.getItem(DMD_ATTRIBUTES_STORAGE_KEY);
267
+ if (!raw) return {};
268
+ try {
269
+ const parsed = JSON.parse(raw);
270
+ return parsed && typeof parsed === "object" && !Array.isArray(parsed) ? parsed : {};
271
+ } catch {
272
+ base.removeItem(DMD_ATTRIBUTES_STORAGE_KEY);
273
+ return {};
274
+ }
275
+ }
276
+ function sanitizeAttributes(attributes) {
277
+ return Object.fromEntries(Object.entries(attributes).filter(([, value]) => !isBlankValue(value)));
278
+ }
279
+ function writeAttributes(base, attributes) {
280
+ const sanitized = sanitizeAttributes(attributes);
281
+ if (Object.keys(sanitized).length === 0) {
282
+ base.removeItem(DMD_ATTRIBUTES_STORAGE_KEY);
283
+ return;
284
+ }
285
+ base.setItem(DMD_ATTRIBUTES_STORAGE_KEY, JSON.stringify(sanitized));
286
+ }
287
+ function parseSessionData(value) {
288
+ try {
289
+ const parsed = JSON.parse(value);
290
+ const sessionData = {};
291
+ const sessionId = typeof parsed.sessionId === "string" && parsed.sessionId.trim() !== "" ? parsed.sessionId : void 0;
292
+ const timestamp = typeof parsed.timestamp === "number" ? parsed.timestamp : void 0;
293
+ if (sessionId !== void 0) sessionData.sessionId = sessionId;
294
+ if (timestamp !== void 0) sessionData.timestamp = timestamp;
295
+ return sessionData;
296
+ } catch {
297
+ return {};
298
+ }
299
+ }
300
+ function getAggregateValue(attributes, key) {
301
+ if (key === SESSION_STORAGE_KEY) {
302
+ const sessionId = attributes[SESSION_ID_KEY];
303
+ const timestamp = attributes[SESSION_TIMESTAMP_KEY];
304
+ if (typeof sessionId === "string" && !isBlankValue(sessionId) && typeof timestamp === "number") {
305
+ return JSON.stringify({ sessionId, timestamp });
306
+ }
307
+ return null;
308
+ }
309
+ const value = attributes[key];
310
+ if (isBlankValue(value)) return null;
311
+ return typeof value === "string" ? value : JSON.stringify(value);
312
+ }
313
+ function setAggregateValue(attributes, key, value) {
314
+ if (key === SESSION_STORAGE_KEY) {
315
+ const sessionData = parseSessionData(value);
316
+ if (sessionData.sessionId === void 0 || sessionData.timestamp === void 0) {
317
+ delete attributes[SESSION_ID_KEY];
318
+ delete attributes[SESSION_TIMESTAMP_KEY];
319
+ return;
320
+ }
321
+ attributes[SESSION_ID_KEY] = sessionData.sessionId;
322
+ attributes[SESSION_TIMESTAMP_KEY] = sessionData.timestamp;
323
+ return;
324
+ }
325
+ attributes[key] = value;
326
+ }
327
+ function removeAggregateValue(attributes, key) {
328
+ if (key === SESSION_STORAGE_KEY) {
329
+ delete attributes[SESSION_ID_KEY];
330
+ delete attributes[SESSION_TIMESTAMP_KEY];
331
+ return;
332
+ }
333
+ delete attributes[key];
334
+ }
335
+ function createDmdAttributesPersistence(base) {
336
+ return {
337
+ getItem(key) {
338
+ if (key === DMD_ATTRIBUTES_STORAGE_KEY) return base.getItem(key);
339
+ const attributes = readAttributes(base);
340
+ const aggregateValue = getAggregateValue(attributes, key);
341
+ if (aggregateValue !== null) return aggregateValue;
342
+ const legacyValue = base.getItem(key);
343
+ if (isBlankValue(legacyValue)) return null;
344
+ setAggregateValue(attributes, key, String(legacyValue));
345
+ writeAttributes(base, attributes);
346
+ return legacyValue;
347
+ },
348
+ setItem(key, value) {
349
+ if (key === DMD_ATTRIBUTES_STORAGE_KEY) return base.setItem(key, value);
350
+ const attributes = readAttributes(base);
351
+ if (isBlankValue(value)) {
352
+ removeAggregateValue(attributes, key);
353
+ writeAttributes(base, attributes);
354
+ base.removeItem(key);
355
+ return true;
356
+ }
357
+ setAggregateValue(attributes, key, value);
358
+ writeAttributes(base, attributes);
359
+ base.setItem(key, value);
360
+ return true;
361
+ },
362
+ removeItem(key) {
363
+ if (key === DMD_ATTRIBUTES_STORAGE_KEY) {
364
+ base.removeItem(key);
365
+ return;
366
+ }
367
+ const attributes = readAttributes(base);
368
+ removeAggregateValue(attributes, key);
369
+ writeAttributes(base, attributes);
370
+ base.removeItem(key);
371
+ },
372
+ getHealth() {
373
+ return base.getHealth();
374
+ }
375
+ };
376
+ }
377
+
248
378
  // src/core/attribution.ts
249
379
  var dmdUtmKeys = [
250
380
  "utm_source",
@@ -281,6 +411,10 @@ function mergeAttributionRecords(explicitProperties, stored) {
281
411
  }
282
412
 
283
413
  // src/browser/core/attribution.ts
414
+ var DMD_CLICK_ID_QUERY_KEY = "click_id";
415
+ var DMD_CLICK_ID_LEGACY_QUERY_KEY = "dmd_click_id";
416
+ var DMD_CLICK_ID_STORAGE_KEY = "dmd_click_id";
417
+ var DMD_CLICK_ID_ATTRIBUTE_KEY = "click_id";
284
418
  function getCurrentUrl() {
285
419
  return getBrowserWindow()?.location?.href;
286
420
  }
@@ -299,6 +433,9 @@ function setIfPresent(persistence, key, value) {
299
433
  persistence.setItem(key, value);
300
434
  }
301
435
  }
436
+ function getClickIdParam(params) {
437
+ return params.get(DMD_CLICK_ID_LEGACY_QUERY_KEY) || params.get(DMD_CLICK_ID_QUERY_KEY);
438
+ }
302
439
  function getStoredString(persistence, key) {
303
440
  const value = persistence.getItem(key);
304
441
  return value === null || value === "" ? void 0 : value;
@@ -318,6 +455,9 @@ function captureAttributionFromUrl(persistence, url = getCurrentUrl()) {
318
455
  for (const key of dmdCampaignKeys) {
319
456
  setIfPresent(persistence, key, params.get(key));
320
457
  }
458
+ const clickId = getClickIdParam(params);
459
+ setIfPresent(persistence, DMD_CLICK_ID_ATTRIBUTE_KEY, clickId);
460
+ setIfPresent(persistence, DMD_CLICK_ID_STORAGE_KEY, clickId);
321
461
  for (const [param, sdkPubId] of dmdClickIdSources) {
322
462
  const value = params.get(param);
323
463
  if (value) {
@@ -333,7 +473,8 @@ function getStoredAttributionData(persistence) {
333
473
  fbc: getStoredString(persistence, "fbc") ?? getCookie("_fbc"),
334
474
  fbp: getStoredString(persistence, "fbp") ?? getCookie("_fbp"),
335
475
  campaign_id: getStoredString(persistence, "campaign_id"),
336
- ad_id: getStoredString(persistence, "ad_id")
476
+ ad_id: getStoredString(persistence, "ad_id"),
477
+ click_id: getStoredString(persistence, DMD_CLICK_ID_STORAGE_KEY) ?? getStoredString(persistence, DMD_CLICK_ID_ATTRIBUTE_KEY)
337
478
  });
338
479
  }
339
480
  function getStoredUtmParameter(persistence) {
@@ -852,6 +993,24 @@ function resetAnonymousId(persistence) {
852
993
  return anonymousId;
853
994
  }
854
995
 
996
+ // src/browser/core/page-context.ts
997
+ function redactSearch(search) {
998
+ const redacted = redactUrl(search);
999
+ return redacted.startsWith("/?") ? redacted.slice(1) : redacted;
1000
+ }
1001
+ function getBrowserPageContext() {
1002
+ const browserWindow = getBrowserWindow();
1003
+ const documentRef = browserWindow?.document ?? globalThis.document;
1004
+ const location = browserWindow?.location;
1005
+ const page2 = {};
1006
+ if (location?.href) page2.url = location.href;
1007
+ if (location?.pathname) page2.path = location.pathname;
1008
+ if (location?.search) page2.search = redactSearch(location.search);
1009
+ if (documentRef?.title) page2.title = documentRef.title;
1010
+ if (documentRef?.referrer) page2.referrer = redactUrl(documentRef.referrer);
1011
+ return page2;
1012
+ }
1013
+
855
1014
  // src/browser/core/persistence.ts
856
1015
  function createPersistenceHealth(requested) {
857
1016
  return {
@@ -1018,7 +1177,7 @@ function createBrowserPersistence(mode = "localStorage+cookie") {
1018
1177
  }
1019
1178
 
1020
1179
  // src/browser/core/session.ts
1021
- var SESSION_STORAGE_KEY = "sessionData";
1180
+ var SESSION_STORAGE_KEY2 = "sessionData";
1022
1181
  function getUrlParam2(name) {
1023
1182
  const href = getBrowserWindow()?.location?.href;
1024
1183
  if (!href) return null;
@@ -1029,7 +1188,7 @@ function getUrlParam2(name) {
1029
1188
  }
1030
1189
  }
1031
1190
  function readStoredSession(persistence) {
1032
- const rawSession = persistence.getItem(SESSION_STORAGE_KEY);
1191
+ const rawSession = persistence.getItem(SESSION_STORAGE_KEY2);
1033
1192
  if (!rawSession) return void 0;
1034
1193
  try {
1035
1194
  const parsed = JSON.parse(rawSession);
@@ -1040,12 +1199,12 @@ function readStoredSession(persistence) {
1040
1199
  };
1041
1200
  }
1042
1201
  } catch {
1043
- persistence.removeItem(SESSION_STORAGE_KEY);
1202
+ persistence.removeItem(SESSION_STORAGE_KEY2);
1044
1203
  }
1045
1204
  return void 0;
1046
1205
  }
1047
1206
  function writeStoredSession(persistence, sessionId, timestamp) {
1048
- persistence.setItem(SESSION_STORAGE_KEY, JSON.stringify({ sessionId, timestamp }));
1207
+ persistence.setItem(SESSION_STORAGE_KEY2, JSON.stringify({ sessionId, timestamp }));
1049
1208
  }
1050
1209
  function createSessionManager(persistence, idleTimeoutSeconds = 30 * 60) {
1051
1210
  function resolveSessionId() {
@@ -1099,11 +1258,12 @@ var DriveMetaDataSDK = class {
1099
1258
  requireConfigString(config.writeKey || config.token, "writeKey or token");
1100
1259
  this.config = config;
1101
1260
  this.endpoint = endpointFromConfig(config);
1102
- this.persistence = createBrowserPersistence(config.persistence);
1261
+ const storagePersistence = createBrowserPersistence(config.persistence);
1262
+ this.persistence = createDmdAttributesPersistence(storagePersistence);
1103
1263
  this.session = createSessionManager(this.persistence, config.sessionIdleTimeoutSeconds);
1104
1264
  const deliveryConfig = {
1105
1265
  endpoint: this.endpoint,
1106
- storage: this.persistence
1266
+ storage: storagePersistence
1107
1267
  };
1108
1268
  if (config.delivery?.maxQueueSize !== void 0) deliveryConfig.maxQueueSize = config.delivery.maxQueueSize;
1109
1269
  if (config.delivery?.queueTtlMs !== void 0) deliveryConfig.queueTtlMs = config.delivery.queueTtlMs;
@@ -1348,6 +1508,7 @@ var DriveMetaDataSDK = class {
1348
1508
  }
1349
1509
  toCollectorPayload(prepared) {
1350
1510
  const browserWindow = getBrowserWindow();
1511
+ const pageContext = getBrowserPageContext();
1351
1512
  return createBackendCollectorPayload({
1352
1513
  requestId: prepared.messageId,
1353
1514
  timestamp: prepared.timestamp,
@@ -1359,9 +1520,13 @@ var DriveMetaDataSDK = class {
1359
1520
  sessionId: prepared.sessionId,
1360
1521
  ua: browserWindow?.navigator?.userAgent,
1361
1522
  appId: prepared.appId,
1362
- pageUrl: browserWindow?.location?.href,
1523
+ pageUrl: pageContext.url ?? browserWindow?.location?.href,
1363
1524
  eventData: mergeStoredAttribution({
1364
1525
  ...prepared.properties,
1526
+ page: {
1527
+ ...pageContext,
1528
+ ...prepared.properties.page && typeof prepared.properties.page === "object" ? prepared.properties.page : {}
1529
+ },
1365
1530
  anonymousId: prepared.anonymousId,
1366
1531
  sessionId: prepared.sessionId,
1367
1532
  timestamp: prepared.timestamp,