@drivemetadata-ai/sdk 0.1.1-beta.2 → 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.
- package/README.md +152 -21
- package/dist/angular/index.cjs +946 -95
- package/dist/angular/index.cjs.map +1 -1
- package/dist/angular/index.d.cts +2 -2
- package/dist/angular/index.d.ts +2 -2
- package/dist/angular/index.js +946 -95
- package/dist/angular/index.js.map +1 -1
- package/dist/browser/index.cjs +947 -96
- package/dist/browser/index.cjs.map +1 -1
- package/dist/browser/index.d.cts +2 -2
- package/dist/browser/index.d.ts +2 -2
- package/dist/browser/index.js +947 -96
- package/dist/browser/index.js.map +1 -1
- package/dist/next/index.cjs +946 -95
- package/dist/next/index.cjs.map +1 -1
- package/dist/next/index.d.cts +1 -1
- package/dist/next/index.d.ts +1 -1
- package/dist/next/index.js +946 -95
- package/dist/next/index.js.map +1 -1
- package/dist/node/index.cjs +81 -9
- package/dist/node/index.cjs.map +1 -1
- package/dist/node/index.js +81 -9
- package/dist/node/index.js.map +1 -1
- package/dist/react/index.cjs +946 -95
- package/dist/react/index.cjs.map +1 -1
- package/dist/react/index.d.cts +2 -2
- package/dist/react/index.d.ts +2 -2
- package/dist/react/index.js +946 -95
- package/dist/react/index.js.map +1 -1
- package/dist/{types--V8TVIqT.d.cts → types-mgbdL1V7.d.cts} +17 -4
- package/dist/{types--V8TVIqT.d.ts → types-mgbdL1V7.d.ts} +17 -4
- package/docs/architecture.md +109 -0
- package/docs/index.md +1 -0
- package/docs/integration.md +203 -5
- package/docs/npm-browser-sdk.md +4 -0
- package/package.json +4 -2
package/dist/next/index.cjs
CHANGED
|
@@ -45,12 +45,62 @@ module.exports = __toCommonJS(next_exports);
|
|
|
45
45
|
// src/react/DmdProvider.tsx
|
|
46
46
|
var import_react = __toESM(require("react"), 1);
|
|
47
47
|
|
|
48
|
+
// src/browser/core/browser-config.ts
|
|
49
|
+
function setIfDefined(target, key, value) {
|
|
50
|
+
if (value !== void 0) {
|
|
51
|
+
target[key] = value;
|
|
52
|
+
}
|
|
53
|
+
}
|
|
54
|
+
function normalizeBrowserConfig(input) {
|
|
55
|
+
const normalized = {
|
|
56
|
+
...input,
|
|
57
|
+
clientId: input.clientId ?? "",
|
|
58
|
+
workspaceId: input.workspaceId ?? "",
|
|
59
|
+
appId: input.appId ?? ""
|
|
60
|
+
};
|
|
61
|
+
setIfDefined(normalized, "apiHost", input.apiHost);
|
|
62
|
+
setIfDefined(normalized, "capturePageview", input.capturePageview);
|
|
63
|
+
setIfDefined(normalized, "capturePageleave", input.capturePageleave);
|
|
64
|
+
setIfDefined(normalized, "captureDeadClicks", input.captureDeadClicks);
|
|
65
|
+
setIfDefined(normalized, "crossSubdomainCookie", input.crossSubdomainCookie);
|
|
66
|
+
setIfDefined(normalized, "sessionIdleTimeoutSeconds", input.sessionIdleTimeoutSeconds);
|
|
67
|
+
setIfDefined(normalized, "schemaValidation", input.schemaValidation);
|
|
68
|
+
setIfDefined(normalized, "beforeSend", input.beforeSend);
|
|
69
|
+
setIfDefined(normalized, "persistence", input.disablePersistence === true ? "none" : input.persistence);
|
|
70
|
+
return normalized;
|
|
71
|
+
}
|
|
72
|
+
|
|
73
|
+
// src/core/uuid.ts
|
|
74
|
+
function createUuid() {
|
|
75
|
+
const cryptoApi = globalThis.crypto;
|
|
76
|
+
if (typeof cryptoApi?.randomUUID === "function") {
|
|
77
|
+
return cryptoApi.randomUUID();
|
|
78
|
+
}
|
|
79
|
+
const bytes = new Uint8Array(16);
|
|
80
|
+
if (typeof cryptoApi?.getRandomValues === "function") {
|
|
81
|
+
cryptoApi.getRandomValues(bytes);
|
|
82
|
+
} else {
|
|
83
|
+
for (let index = 0; index < bytes.length; index += 1) {
|
|
84
|
+
bytes[index] = Math.floor(Math.random() * 256);
|
|
85
|
+
}
|
|
86
|
+
}
|
|
87
|
+
bytes[6] = (bytes[6] ?? 0) & 15 | 64;
|
|
88
|
+
bytes[8] = (bytes[8] ?? 0) & 63 | 128;
|
|
89
|
+
const hex = Array.from(bytes, (byte) => byte.toString(16).padStart(2, "0")).join("");
|
|
90
|
+
return `${hex.slice(0, 8)}-${hex.slice(8, 12)}-${hex.slice(12, 16)}-${hex.slice(16, 20)}-${hex.slice(20)}`;
|
|
91
|
+
}
|
|
92
|
+
function isUuid(value) {
|
|
93
|
+
return typeof value === "string" && /^[0-9a-f]{8}-[0-9a-f]{4}-[1-8][0-9a-f]{3}-[89ab][0-9a-f]{3}-[0-9a-f]{12}$/i.test(value);
|
|
94
|
+
}
|
|
95
|
+
function ensureUuid(value) {
|
|
96
|
+
return isUuid(value) ? value : createUuid();
|
|
97
|
+
}
|
|
98
|
+
|
|
48
99
|
// src/core/backend-payload.ts
|
|
49
100
|
function formatUtcTimestamp(value) {
|
|
50
|
-
|
|
51
|
-
const
|
|
52
|
-
|
|
53
|
-
return date.toISOString().replace("T", " ").slice(0, 19);
|
|
101
|
+
const date = typeof value === "string" || typeof value === "number" || value instanceof Date ? new Date(value) : /* @__PURE__ */ new Date();
|
|
102
|
+
const safeDate = Number.isNaN(date.getTime()) ? /* @__PURE__ */ new Date() : date;
|
|
103
|
+
return safeDate.toISOString().replace("T", " ").slice(0, 19);
|
|
54
104
|
}
|
|
55
105
|
function cleanObject(value) {
|
|
56
106
|
if (Array.isArray(value)) {
|
|
@@ -81,15 +131,19 @@ function createBackendCollectorPayload(input) {
|
|
|
81
131
|
};
|
|
82
132
|
const metaData = {
|
|
83
133
|
...normalizedEventData,
|
|
84
|
-
requestId: input.requestId,
|
|
134
|
+
requestId: ensureUuid(typeof input.requestId === "string" ? input.requestId : void 0),
|
|
85
135
|
timestamp,
|
|
86
136
|
eventType: input.eventType,
|
|
87
137
|
requestFrom: input.requestFrom ?? "3",
|
|
88
138
|
clientId: input.clientId,
|
|
89
139
|
workspaceId: input.workspaceId,
|
|
90
140
|
token: input.token,
|
|
91
|
-
anonymousId:
|
|
92
|
-
|
|
141
|
+
anonymousId: ensureUuid(
|
|
142
|
+
typeof eventData.anonymousId === "string" ? eventData.anonymousId : typeof input.anonymousId === "string" ? input.anonymousId : void 0
|
|
143
|
+
),
|
|
144
|
+
sessionId: ensureUuid(
|
|
145
|
+
typeof eventData.sessionId === "string" ? eventData.sessionId : typeof input.sessionId === "string" ? input.sessionId : void 0
|
|
146
|
+
),
|
|
93
147
|
ua: input.ua,
|
|
94
148
|
appDetails: { app_id: input.appId },
|
|
95
149
|
page: { ...page2, url: page2.url ?? input.pageUrl },
|
|
@@ -100,12 +154,45 @@ function createBackendCollectorPayload(input) {
|
|
|
100
154
|
return cleanObject(payload);
|
|
101
155
|
}
|
|
102
156
|
|
|
103
|
-
// src/core/
|
|
104
|
-
|
|
105
|
-
|
|
157
|
+
// src/core/backend-schema.ts
|
|
158
|
+
var requiredMetaDataFields = [
|
|
159
|
+
"requestId",
|
|
160
|
+
"timestamp",
|
|
161
|
+
"eventType",
|
|
162
|
+
"requestFrom",
|
|
163
|
+
"clientId",
|
|
164
|
+
"workspaceId",
|
|
165
|
+
"anonymousId",
|
|
166
|
+
"sessionId"
|
|
167
|
+
];
|
|
168
|
+
function isPresent(value) {
|
|
169
|
+
return value !== null && value !== void 0 && value !== "";
|
|
170
|
+
}
|
|
171
|
+
function validateBackendCollectorPayload(payload) {
|
|
172
|
+
const errors = [];
|
|
173
|
+
const metaData = payload.metaData;
|
|
174
|
+
if (!metaData || typeof metaData !== "object" || Array.isArray(metaData)) {
|
|
175
|
+
return {
|
|
176
|
+
ok: false,
|
|
177
|
+
errors: ["metaData is required"]
|
|
178
|
+
};
|
|
179
|
+
}
|
|
180
|
+
const metadataRecord = metaData;
|
|
181
|
+
for (const field of requiredMetaDataFields) {
|
|
182
|
+
if (!isPresent(metadataRecord[field])) {
|
|
183
|
+
errors.push(`metaData.${field} is required`);
|
|
184
|
+
}
|
|
185
|
+
}
|
|
186
|
+
if (isPresent(metadataRecord.eventType) && typeof metadataRecord.eventType !== "string") {
|
|
187
|
+
errors.push("metaData.eventType must be a string");
|
|
188
|
+
}
|
|
189
|
+
return {
|
|
190
|
+
ok: errors.length === 0,
|
|
191
|
+
errors
|
|
192
|
+
};
|
|
106
193
|
}
|
|
107
194
|
|
|
108
|
-
// src/
|
|
195
|
+
// src/core/consent.ts
|
|
109
196
|
var purposes = [
|
|
110
197
|
"analytics",
|
|
111
198
|
"advertising",
|
|
@@ -145,6 +232,476 @@ function canCollectPurpose(consent, purpose) {
|
|
|
145
232
|
return consent[purpose] === "granted";
|
|
146
233
|
}
|
|
147
234
|
|
|
235
|
+
// src/core/event-schema.ts
|
|
236
|
+
var reservedKeys = /* @__PURE__ */ new Set(["messageId", "timestamp", "type", "event", "anonymousId", "userId", "context"]);
|
|
237
|
+
function validateEventEnvelope(envelope, options = {}) {
|
|
238
|
+
if (options.mode === "off") return { ok: true, errors: [] };
|
|
239
|
+
const errors = [];
|
|
240
|
+
if (typeof envelope.type !== "string") errors.push("type must be a string");
|
|
241
|
+
if (envelope.type === "track" && typeof envelope.event !== "string") {
|
|
242
|
+
errors.push("track event must include event name");
|
|
243
|
+
}
|
|
244
|
+
if (typeof envelope.messageId !== "string") errors.push("messageId must be a string");
|
|
245
|
+
if (typeof envelope.timestamp !== "string") errors.push("timestamp must be an ISO string");
|
|
246
|
+
for (const key of Object.keys(envelope.properties ?? {})) {
|
|
247
|
+
if (reservedKeys.has(key)) errors.push(`properties.${key} is reserved`);
|
|
248
|
+
}
|
|
249
|
+
return { ok: errors.length === 0, errors };
|
|
250
|
+
}
|
|
251
|
+
|
|
252
|
+
// src/core/environment.ts
|
|
253
|
+
function getBrowserWindow() {
|
|
254
|
+
return typeof window === "undefined" ? void 0 : window;
|
|
255
|
+
}
|
|
256
|
+
|
|
257
|
+
// src/core/privacy.ts
|
|
258
|
+
var sensitiveKeys = /* @__PURE__ */ new Set([
|
|
259
|
+
"email",
|
|
260
|
+
"phone",
|
|
261
|
+
"mobile",
|
|
262
|
+
"address",
|
|
263
|
+
"address1",
|
|
264
|
+
"address2",
|
|
265
|
+
"first_name",
|
|
266
|
+
"last_name",
|
|
267
|
+
"name",
|
|
268
|
+
"token",
|
|
269
|
+
"secret",
|
|
270
|
+
"password",
|
|
271
|
+
"session",
|
|
272
|
+
"cookie"
|
|
273
|
+
]);
|
|
274
|
+
function redactUrl(url, allowQueryKeys = ["utm_source", "utm_medium", "utm_campaign", "utm_term", "utm_content"]) {
|
|
275
|
+
const parsed = new URL(url, "https://placeholder.local");
|
|
276
|
+
for (const key of Array.from(parsed.searchParams.keys())) {
|
|
277
|
+
if (!allowQueryKeys.includes(key)) {
|
|
278
|
+
parsed.searchParams.set(key, "[REDACTED]");
|
|
279
|
+
}
|
|
280
|
+
}
|
|
281
|
+
return url.startsWith("http") ? parsed.toString() : `${parsed.pathname}${parsed.search}`;
|
|
282
|
+
}
|
|
283
|
+
function sanitizeValue(value, allow, path = []) {
|
|
284
|
+
if (Array.isArray(value)) {
|
|
285
|
+
return value.map((item) => sanitizeValue(item, allow, path));
|
|
286
|
+
}
|
|
287
|
+
if (value && typeof value === "object") {
|
|
288
|
+
return Object.fromEntries(
|
|
289
|
+
Object.entries(value).filter(([key]) => {
|
|
290
|
+
const lowerKey = key.toLowerCase();
|
|
291
|
+
const lowerPath = path.map((item) => item.toLowerCase());
|
|
292
|
+
const isEcommerceItemName = lowerKey === "name" && lowerPath.includes("ecommerce") && lowerPath.includes("items");
|
|
293
|
+
return isEcommerceItemName || !sensitiveKeys.has(lowerKey) || allow.has(lowerKey);
|
|
294
|
+
}).map(([key, nestedValue]) => [key, sanitizeValue(nestedValue, allow, [...path, key])])
|
|
295
|
+
);
|
|
296
|
+
}
|
|
297
|
+
return value;
|
|
298
|
+
}
|
|
299
|
+
function sanitizeProperties(input, allowRawKeys = []) {
|
|
300
|
+
const allow = new Set(allowRawKeys.map((key) => key.toLowerCase()));
|
|
301
|
+
return sanitizeValue(input, allow);
|
|
302
|
+
}
|
|
303
|
+
|
|
304
|
+
// src/browser/core/attribute-persistence.ts
|
|
305
|
+
var DMD_ATTRIBUTES_STORAGE_KEY = "dmd_attributes";
|
|
306
|
+
var SESSION_STORAGE_KEY = "sessionData";
|
|
307
|
+
var SESSION_ID_KEY = "sessionId";
|
|
308
|
+
var SESSION_TIMESTAMP_KEY = "timestamp";
|
|
309
|
+
function isBlankValue(value) {
|
|
310
|
+
return value === null || value === void 0 || typeof value === "string" && value.trim() === "";
|
|
311
|
+
}
|
|
312
|
+
function readAttributes(base) {
|
|
313
|
+
const raw = base.getItem(DMD_ATTRIBUTES_STORAGE_KEY);
|
|
314
|
+
if (!raw) return {};
|
|
315
|
+
try {
|
|
316
|
+
const parsed = JSON.parse(raw);
|
|
317
|
+
return parsed && typeof parsed === "object" && !Array.isArray(parsed) ? parsed : {};
|
|
318
|
+
} catch {
|
|
319
|
+
base.removeItem(DMD_ATTRIBUTES_STORAGE_KEY);
|
|
320
|
+
return {};
|
|
321
|
+
}
|
|
322
|
+
}
|
|
323
|
+
function sanitizeAttributes(attributes) {
|
|
324
|
+
return Object.fromEntries(Object.entries(attributes).filter(([, value]) => !isBlankValue(value)));
|
|
325
|
+
}
|
|
326
|
+
function writeAttributes(base, attributes) {
|
|
327
|
+
const sanitized = sanitizeAttributes(attributes);
|
|
328
|
+
if (Object.keys(sanitized).length === 0) {
|
|
329
|
+
base.removeItem(DMD_ATTRIBUTES_STORAGE_KEY);
|
|
330
|
+
return;
|
|
331
|
+
}
|
|
332
|
+
base.setItem(DMD_ATTRIBUTES_STORAGE_KEY, JSON.stringify(sanitized));
|
|
333
|
+
}
|
|
334
|
+
function parseSessionData(value) {
|
|
335
|
+
try {
|
|
336
|
+
const parsed = JSON.parse(value);
|
|
337
|
+
const sessionData = {};
|
|
338
|
+
const sessionId = typeof parsed.sessionId === "string" && parsed.sessionId.trim() !== "" ? parsed.sessionId : void 0;
|
|
339
|
+
const timestamp = typeof parsed.timestamp === "number" ? parsed.timestamp : void 0;
|
|
340
|
+
if (sessionId !== void 0) sessionData.sessionId = sessionId;
|
|
341
|
+
if (timestamp !== void 0) sessionData.timestamp = timestamp;
|
|
342
|
+
return sessionData;
|
|
343
|
+
} catch {
|
|
344
|
+
return {};
|
|
345
|
+
}
|
|
346
|
+
}
|
|
347
|
+
function getAggregateValue(attributes, key) {
|
|
348
|
+
if (key === SESSION_STORAGE_KEY) {
|
|
349
|
+
const sessionId = attributes[SESSION_ID_KEY];
|
|
350
|
+
const timestamp = attributes[SESSION_TIMESTAMP_KEY];
|
|
351
|
+
if (typeof sessionId === "string" && !isBlankValue(sessionId) && typeof timestamp === "number") {
|
|
352
|
+
return JSON.stringify({ sessionId, timestamp });
|
|
353
|
+
}
|
|
354
|
+
return null;
|
|
355
|
+
}
|
|
356
|
+
const value = attributes[key];
|
|
357
|
+
if (isBlankValue(value)) return null;
|
|
358
|
+
return typeof value === "string" ? value : JSON.stringify(value);
|
|
359
|
+
}
|
|
360
|
+
function setAggregateValue(attributes, key, value) {
|
|
361
|
+
if (key === SESSION_STORAGE_KEY) {
|
|
362
|
+
const sessionData = parseSessionData(value);
|
|
363
|
+
if (sessionData.sessionId === void 0 || sessionData.timestamp === void 0) {
|
|
364
|
+
delete attributes[SESSION_ID_KEY];
|
|
365
|
+
delete attributes[SESSION_TIMESTAMP_KEY];
|
|
366
|
+
return;
|
|
367
|
+
}
|
|
368
|
+
attributes[SESSION_ID_KEY] = sessionData.sessionId;
|
|
369
|
+
attributes[SESSION_TIMESTAMP_KEY] = sessionData.timestamp;
|
|
370
|
+
return;
|
|
371
|
+
}
|
|
372
|
+
attributes[key] = value;
|
|
373
|
+
}
|
|
374
|
+
function removeAggregateValue(attributes, key) {
|
|
375
|
+
if (key === SESSION_STORAGE_KEY) {
|
|
376
|
+
delete attributes[SESSION_ID_KEY];
|
|
377
|
+
delete attributes[SESSION_TIMESTAMP_KEY];
|
|
378
|
+
return;
|
|
379
|
+
}
|
|
380
|
+
delete attributes[key];
|
|
381
|
+
}
|
|
382
|
+
function createDmdAttributesPersistence(base) {
|
|
383
|
+
return {
|
|
384
|
+
getItem(key) {
|
|
385
|
+
if (key === DMD_ATTRIBUTES_STORAGE_KEY) return base.getItem(key);
|
|
386
|
+
const attributes = readAttributes(base);
|
|
387
|
+
const aggregateValue = getAggregateValue(attributes, key);
|
|
388
|
+
if (aggregateValue !== null) return aggregateValue;
|
|
389
|
+
const legacyValue = base.getItem(key);
|
|
390
|
+
if (isBlankValue(legacyValue)) return null;
|
|
391
|
+
setAggregateValue(attributes, key, String(legacyValue));
|
|
392
|
+
writeAttributes(base, attributes);
|
|
393
|
+
return legacyValue;
|
|
394
|
+
},
|
|
395
|
+
setItem(key, value) {
|
|
396
|
+
if (key === DMD_ATTRIBUTES_STORAGE_KEY) return base.setItem(key, value);
|
|
397
|
+
const attributes = readAttributes(base);
|
|
398
|
+
if (isBlankValue(value)) {
|
|
399
|
+
removeAggregateValue(attributes, key);
|
|
400
|
+
writeAttributes(base, attributes);
|
|
401
|
+
base.removeItem(key);
|
|
402
|
+
return true;
|
|
403
|
+
}
|
|
404
|
+
setAggregateValue(attributes, key, value);
|
|
405
|
+
writeAttributes(base, attributes);
|
|
406
|
+
base.setItem(key, value);
|
|
407
|
+
return true;
|
|
408
|
+
},
|
|
409
|
+
removeItem(key) {
|
|
410
|
+
if (key === DMD_ATTRIBUTES_STORAGE_KEY) {
|
|
411
|
+
base.removeItem(key);
|
|
412
|
+
return;
|
|
413
|
+
}
|
|
414
|
+
const attributes = readAttributes(base);
|
|
415
|
+
removeAggregateValue(attributes, key);
|
|
416
|
+
writeAttributes(base, attributes);
|
|
417
|
+
base.removeItem(key);
|
|
418
|
+
},
|
|
419
|
+
getHealth() {
|
|
420
|
+
return base.getHealth();
|
|
421
|
+
}
|
|
422
|
+
};
|
|
423
|
+
}
|
|
424
|
+
|
|
425
|
+
// src/core/attribution.ts
|
|
426
|
+
var dmdUtmKeys = [
|
|
427
|
+
"utm_source",
|
|
428
|
+
"utm_medium",
|
|
429
|
+
"utm_campaign",
|
|
430
|
+
"utm_term",
|
|
431
|
+
"utm_content",
|
|
432
|
+
"utm_id"
|
|
433
|
+
];
|
|
434
|
+
var dmdCampaignKeys = ["campaign_id", "ad_id"];
|
|
435
|
+
var dmdClickIdSources = [
|
|
436
|
+
["gclid", 2],
|
|
437
|
+
["fbclid", 3],
|
|
438
|
+
["ScCid", 1],
|
|
439
|
+
["li_fat_id", 4]
|
|
440
|
+
];
|
|
441
|
+
function cleanAttributionRecord(record) {
|
|
442
|
+
const cleaned = Object.fromEntries(
|
|
443
|
+
Object.entries(record).filter(([, value]) => value !== null && value !== void 0 && value !== "")
|
|
444
|
+
);
|
|
445
|
+
return Object.keys(cleaned).length > 0 ? cleaned : void 0;
|
|
446
|
+
}
|
|
447
|
+
function objectValue(value) {
|
|
448
|
+
return value && typeof value === "object" && !Array.isArray(value) ? value : void 0;
|
|
449
|
+
}
|
|
450
|
+
function mergeAttributionRecords(explicitProperties, stored) {
|
|
451
|
+
const attributionData = objectValue(explicitProperties.attributionData);
|
|
452
|
+
const utmParameter = objectValue(explicitProperties.utmParameter);
|
|
453
|
+
return {
|
|
454
|
+
...explicitProperties,
|
|
455
|
+
...stored.attributionData || attributionData ? { attributionData: { ...stored.attributionData ?? {}, ...attributionData ?? {} } } : {},
|
|
456
|
+
...stored.utmParameter || utmParameter ? { utmParameter: { ...stored.utmParameter ?? {}, ...utmParameter ?? {} } } : {}
|
|
457
|
+
};
|
|
458
|
+
}
|
|
459
|
+
|
|
460
|
+
// src/browser/core/attribution.ts
|
|
461
|
+
var DMD_CLICK_ID_QUERY_KEY = "click_id";
|
|
462
|
+
var DMD_CLICK_ID_LEGACY_QUERY_KEY = "dmd_click_id";
|
|
463
|
+
var DMD_CLICK_ID_STORAGE_KEY = "dmd_click_id";
|
|
464
|
+
var DMD_CLICK_ID_ATTRIBUTE_KEY = "click_id";
|
|
465
|
+
function getCurrentUrl() {
|
|
466
|
+
return getBrowserWindow()?.location?.href;
|
|
467
|
+
}
|
|
468
|
+
function getCookie(name) {
|
|
469
|
+
const cookie = getBrowserWindow()?.document?.cookie;
|
|
470
|
+
if (!cookie) return void 0;
|
|
471
|
+
const escapedName = name.replace(/[.*+?^${}()|[\]\\]/g, "\\$&");
|
|
472
|
+
const match = new RegExp(`(?:^|; )${escapedName}=([^;]*)`).exec(cookie);
|
|
473
|
+
return match ? decodeURIComponent(match[1] ?? "") : void 0;
|
|
474
|
+
}
|
|
475
|
+
function getParams(url) {
|
|
476
|
+
return new URL(url, "https://placeholder.local").searchParams;
|
|
477
|
+
}
|
|
478
|
+
function setIfPresent(persistence, key, value) {
|
|
479
|
+
if (value !== null && value !== "") {
|
|
480
|
+
persistence.setItem(key, value);
|
|
481
|
+
}
|
|
482
|
+
}
|
|
483
|
+
function getClickIdParam(params) {
|
|
484
|
+
return params.get(DMD_CLICK_ID_LEGACY_QUERY_KEY) || params.get(DMD_CLICK_ID_QUERY_KEY);
|
|
485
|
+
}
|
|
486
|
+
function getStoredString(persistence, key) {
|
|
487
|
+
const value = persistence.getItem(key);
|
|
488
|
+
return value === null || value === "" ? void 0 : value;
|
|
489
|
+
}
|
|
490
|
+
function getStoredNumberOrString(persistence, key) {
|
|
491
|
+
const value = getStoredString(persistence, key);
|
|
492
|
+
if (value === void 0) return void 0;
|
|
493
|
+
const parsed = Number.parseInt(value, 10);
|
|
494
|
+
return Number.isNaN(parsed) ? value : parsed;
|
|
495
|
+
}
|
|
496
|
+
function captureAttributionFromUrl(persistence, url = getCurrentUrl()) {
|
|
497
|
+
if (!url) return;
|
|
498
|
+
const params = getParams(url);
|
|
499
|
+
for (const key of dmdUtmKeys) {
|
|
500
|
+
setIfPresent(persistence, key, params.get(key));
|
|
501
|
+
}
|
|
502
|
+
for (const key of dmdCampaignKeys) {
|
|
503
|
+
setIfPresent(persistence, key, params.get(key));
|
|
504
|
+
}
|
|
505
|
+
const clickId = getClickIdParam(params);
|
|
506
|
+
setIfPresent(persistence, DMD_CLICK_ID_ATTRIBUTE_KEY, clickId);
|
|
507
|
+
setIfPresent(persistence, DMD_CLICK_ID_STORAGE_KEY, clickId);
|
|
508
|
+
for (const [param, sdkPubId] of dmdClickIdSources) {
|
|
509
|
+
const value = params.get(param);
|
|
510
|
+
if (value) {
|
|
511
|
+
persistence.setItem("unique_id", value);
|
|
512
|
+
persistence.setItem("sdk_pub_id", String(sdkPubId));
|
|
513
|
+
}
|
|
514
|
+
}
|
|
515
|
+
}
|
|
516
|
+
function getStoredAttributionData(persistence) {
|
|
517
|
+
return cleanAttributionRecord({
|
|
518
|
+
unique_id: getStoredString(persistence, "unique_id"),
|
|
519
|
+
sdk_pub_id: getStoredNumberOrString(persistence, "sdk_pub_id"),
|
|
520
|
+
fbc: getStoredString(persistence, "fbc") ?? getCookie("_fbc"),
|
|
521
|
+
fbp: getStoredString(persistence, "fbp") ?? getCookie("_fbp"),
|
|
522
|
+
campaign_id: getStoredString(persistence, "campaign_id"),
|
|
523
|
+
ad_id: getStoredString(persistence, "ad_id"),
|
|
524
|
+
click_id: getStoredString(persistence, DMD_CLICK_ID_STORAGE_KEY) ?? getStoredString(persistence, DMD_CLICK_ID_ATTRIBUTE_KEY)
|
|
525
|
+
});
|
|
526
|
+
}
|
|
527
|
+
function getStoredUtmParameter(persistence) {
|
|
528
|
+
return cleanAttributionRecord(Object.fromEntries(dmdUtmKeys.map((key) => [key, getStoredString(persistence, key)])));
|
|
529
|
+
}
|
|
530
|
+
function mergeStoredAttribution(properties, persistence) {
|
|
531
|
+
const stored = {};
|
|
532
|
+
const attributionData = getStoredAttributionData(persistence);
|
|
533
|
+
const utmParameter = getStoredUtmParameter(persistence);
|
|
534
|
+
if (attributionData !== void 0) stored.attributionData = attributionData;
|
|
535
|
+
if (utmParameter !== void 0) stored.utmParameter = utmParameter;
|
|
536
|
+
return mergeAttributionRecords(properties, stored);
|
|
537
|
+
}
|
|
538
|
+
|
|
539
|
+
// src/browser/core/autocapture.ts
|
|
540
|
+
function installAutocapture(config) {
|
|
541
|
+
const trackedPageUrls = /* @__PURE__ */ new Set();
|
|
542
|
+
const timers = /* @__PURE__ */ new Set();
|
|
543
|
+
const pageviewDelayMs = config.pageviewDelayMs ?? 500;
|
|
544
|
+
const history = config.browserWindow.history;
|
|
545
|
+
const originalPushState = history?.pushState;
|
|
546
|
+
const originalReplaceState = history?.replaceState;
|
|
547
|
+
function clearTimer(timer) {
|
|
548
|
+
timers.delete(timer);
|
|
549
|
+
clearTimeout(timer);
|
|
550
|
+
}
|
|
551
|
+
function canonicalUrl() {
|
|
552
|
+
return config.browserWindow.location.href;
|
|
553
|
+
}
|
|
554
|
+
function trackCurrentPageview() {
|
|
555
|
+
if (!config.capturePageview) return;
|
|
556
|
+
const url = canonicalUrl();
|
|
557
|
+
if (trackedPageUrls.has(url)) return;
|
|
558
|
+
trackedPageUrls.add(url);
|
|
559
|
+
config.onPageView();
|
|
560
|
+
}
|
|
561
|
+
function schedulePageview(delayMs) {
|
|
562
|
+
if (!config.capturePageview) return;
|
|
563
|
+
const timer = setTimeout(() => {
|
|
564
|
+
timers.delete(timer);
|
|
565
|
+
trackCurrentPageview();
|
|
566
|
+
}, delayMs);
|
|
567
|
+
timers.add(timer);
|
|
568
|
+
}
|
|
569
|
+
function handleRouteChange() {
|
|
570
|
+
config.onRouteChange?.();
|
|
571
|
+
trackCurrentPageview();
|
|
572
|
+
}
|
|
573
|
+
function wrapHistoryMethod(method) {
|
|
574
|
+
if (!history) return;
|
|
575
|
+
const original = history[method];
|
|
576
|
+
if (typeof original !== "function") return;
|
|
577
|
+
history[method] = function wrappedHistoryMethod(...args) {
|
|
578
|
+
const result = original.apply(this, args);
|
|
579
|
+
const timer = setTimeout(() => {
|
|
580
|
+
timers.delete(timer);
|
|
581
|
+
handleRouteChange();
|
|
582
|
+
}, 0);
|
|
583
|
+
timers.add(timer);
|
|
584
|
+
return result;
|
|
585
|
+
};
|
|
586
|
+
}
|
|
587
|
+
function handlePopOrHashChange() {
|
|
588
|
+
handleRouteChange();
|
|
589
|
+
}
|
|
590
|
+
function handlePageLeave() {
|
|
591
|
+
if (config.capturePageleave) {
|
|
592
|
+
config.onPageLeave();
|
|
593
|
+
}
|
|
594
|
+
}
|
|
595
|
+
schedulePageview(pageviewDelayMs);
|
|
596
|
+
wrapHistoryMethod("pushState");
|
|
597
|
+
wrapHistoryMethod("replaceState");
|
|
598
|
+
const canListen = typeof config.browserWindow.addEventListener === "function" && typeof config.browserWindow.removeEventListener === "function";
|
|
599
|
+
if (canListen) {
|
|
600
|
+
config.browserWindow.addEventListener("popstate", handlePopOrHashChange);
|
|
601
|
+
config.browserWindow.addEventListener("hashchange", handlePopOrHashChange);
|
|
602
|
+
config.browserWindow.addEventListener("beforeunload", handlePageLeave);
|
|
603
|
+
}
|
|
604
|
+
return {
|
|
605
|
+
cleanup() {
|
|
606
|
+
for (const timer of Array.from(timers)) {
|
|
607
|
+
clearTimer(timer);
|
|
608
|
+
}
|
|
609
|
+
if (history && originalPushState) history.pushState = originalPushState;
|
|
610
|
+
if (history && originalReplaceState) history.replaceState = originalReplaceState;
|
|
611
|
+
if (canListen) {
|
|
612
|
+
config.browserWindow.removeEventListener("popstate", handlePopOrHashChange);
|
|
613
|
+
config.browserWindow.removeEventListener("hashchange", handlePopOrHashChange);
|
|
614
|
+
config.browserWindow.removeEventListener("beforeunload", handlePageLeave);
|
|
615
|
+
}
|
|
616
|
+
}
|
|
617
|
+
};
|
|
618
|
+
}
|
|
619
|
+
|
|
620
|
+
// src/core/payload-size.ts
|
|
621
|
+
var preserveStringKeys = /* @__PURE__ */ new Set([
|
|
622
|
+
"requestId",
|
|
623
|
+
"eventType",
|
|
624
|
+
"requestFrom",
|
|
625
|
+
"clientId",
|
|
626
|
+
"workspaceId",
|
|
627
|
+
"anonymousId",
|
|
628
|
+
"sessionId",
|
|
629
|
+
"token"
|
|
630
|
+
]);
|
|
631
|
+
function payloadByteLength(payload) {
|
|
632
|
+
const serialized = JSON.stringify(payload);
|
|
633
|
+
if (typeof TextEncoder !== "undefined") {
|
|
634
|
+
return new TextEncoder().encode(serialized).length;
|
|
635
|
+
}
|
|
636
|
+
return serialized.length;
|
|
637
|
+
}
|
|
638
|
+
function clonePayload(payload) {
|
|
639
|
+
try {
|
|
640
|
+
return JSON.parse(JSON.stringify(payload));
|
|
641
|
+
} catch {
|
|
642
|
+
return void 0;
|
|
643
|
+
}
|
|
644
|
+
}
|
|
645
|
+
function truncateValue(value, truncateStringLength, key) {
|
|
646
|
+
if (typeof value === "string") {
|
|
647
|
+
if (key && preserveStringKeys.has(key)) return value;
|
|
648
|
+
if (value.length <= truncateStringLength) return value;
|
|
649
|
+
return `${value.slice(0, truncateStringLength)}...[TRUNCATED]`;
|
|
650
|
+
}
|
|
651
|
+
if (Array.isArray(value)) {
|
|
652
|
+
return value.map((item) => truncateValue(item, truncateStringLength));
|
|
653
|
+
}
|
|
654
|
+
if (value && typeof value === "object") {
|
|
655
|
+
return Object.fromEntries(
|
|
656
|
+
Object.entries(value).map(([childKey, childValue]) => [
|
|
657
|
+
childKey,
|
|
658
|
+
truncateValue(childValue, truncateStringLength, childKey)
|
|
659
|
+
])
|
|
660
|
+
);
|
|
661
|
+
}
|
|
662
|
+
return value;
|
|
663
|
+
}
|
|
664
|
+
function markPayloadTruncated(payload) {
|
|
665
|
+
if (payload.metaData && typeof payload.metaData === "object" && !Array.isArray(payload.metaData)) {
|
|
666
|
+
return {
|
|
667
|
+
...payload,
|
|
668
|
+
metaData: {
|
|
669
|
+
...payload.metaData,
|
|
670
|
+
payloadTruncated: true
|
|
671
|
+
}
|
|
672
|
+
};
|
|
673
|
+
}
|
|
674
|
+
return {
|
|
675
|
+
...payload,
|
|
676
|
+
payloadTruncated: true
|
|
677
|
+
};
|
|
678
|
+
}
|
|
679
|
+
function truncatePayload(payload, truncateStringLength) {
|
|
680
|
+
const cloned = clonePayload(payload);
|
|
681
|
+
if (!cloned) return void 0;
|
|
682
|
+
return markPayloadTruncated(truncateValue(cloned, truncateStringLength));
|
|
683
|
+
}
|
|
684
|
+
function getPayloadMessageId(payload) {
|
|
685
|
+
const value = payload.metaData?.requestId ?? payload.messageId;
|
|
686
|
+
return value === void 0 ? void 0 : String(value);
|
|
687
|
+
}
|
|
688
|
+
function preparePayloadForSizePolicy(payload, options = {}) {
|
|
689
|
+
const maxPayloadBytes = options.maxPayloadBytes ?? 64e3;
|
|
690
|
+
const payloadSizePolicy = options.payloadSizePolicy ?? "drop";
|
|
691
|
+
const payloadTruncateStringLength = options.payloadTruncateStringLength ?? 1024;
|
|
692
|
+
if (payloadByteLength(payload) <= maxPayloadBytes) {
|
|
693
|
+
return { ok: true, payload, truncated: false };
|
|
694
|
+
}
|
|
695
|
+
if (payloadSizePolicy === "truncate") {
|
|
696
|
+
const truncatedPayload = truncatePayload(payload, payloadTruncateStringLength);
|
|
697
|
+
if (truncatedPayload && payloadByteLength(truncatedPayload) <= maxPayloadBytes) {
|
|
698
|
+
return { ok: true, payload: truncatedPayload, truncated: true };
|
|
699
|
+
}
|
|
700
|
+
}
|
|
701
|
+
const messageId = getPayloadMessageId(payload);
|
|
702
|
+
return messageId === void 0 ? { ok: false, reason: "payload_too_large" } : { ok: false, reason: "payload_too_large", messageId };
|
|
703
|
+
}
|
|
704
|
+
|
|
148
705
|
// src/browser/core/delivery.ts
|
|
149
706
|
function createId(prefix) {
|
|
150
707
|
return `${prefix}_${Math.random().toString(36).slice(2)}${Date.now().toString(36)}`;
|
|
@@ -176,7 +733,6 @@ function createDeliveryManager(config) {
|
|
|
176
733
|
const lockTtlMs = config.lockTtlMs ?? 5e3;
|
|
177
734
|
const tabId = config.tabId ?? createId("tab");
|
|
178
735
|
const batchSize = config.batchSize ?? 25;
|
|
179
|
-
const maxPayloadBytes = config.maxPayloadBytes ?? 64e3;
|
|
180
736
|
function recordDrop(event) {
|
|
181
737
|
diagnostics.dropped.push(event);
|
|
182
738
|
config.onDrop?.(event);
|
|
@@ -185,12 +741,22 @@ function createDeliveryManager(config) {
|
|
|
185
741
|
diagnostics.lastError = error.message;
|
|
186
742
|
config.onError?.(error);
|
|
187
743
|
}
|
|
188
|
-
function
|
|
189
|
-
const
|
|
190
|
-
if (
|
|
191
|
-
|
|
744
|
+
function preparePayloadForSend(payload) {
|
|
745
|
+
const sizePolicyOptions = {};
|
|
746
|
+
if (config.maxPayloadBytes !== void 0) sizePolicyOptions.maxPayloadBytes = config.maxPayloadBytes;
|
|
747
|
+
if (config.payloadSizePolicy !== void 0) sizePolicyOptions.payloadSizePolicy = config.payloadSizePolicy;
|
|
748
|
+
if (config.payloadTruncateStringLength !== void 0) {
|
|
749
|
+
sizePolicyOptions.payloadTruncateStringLength = config.payloadTruncateStringLength;
|
|
192
750
|
}
|
|
193
|
-
|
|
751
|
+
const prepared = preparePayloadForSizePolicy(payload, sizePolicyOptions);
|
|
752
|
+
if (prepared.ok) return prepared.payload;
|
|
753
|
+
const diagnostic = {
|
|
754
|
+
reason: prepared.reason,
|
|
755
|
+
timestamp: (/* @__PURE__ */ new Date()).toISOString()
|
|
756
|
+
};
|
|
757
|
+
if (prepared.messageId !== void 0) diagnostic.messageId = prepared.messageId;
|
|
758
|
+
recordDrop(diagnostic);
|
|
759
|
+
return void 0;
|
|
194
760
|
}
|
|
195
761
|
function recordStorageUnavailable() {
|
|
196
762
|
recordDrop({
|
|
@@ -280,7 +846,19 @@ function createDeliveryManager(config) {
|
|
|
280
846
|
idempotencyKey: String(payload.idempotencyKey ?? createIdempotencyKey(payload, messageId))
|
|
281
847
|
};
|
|
282
848
|
}
|
|
849
|
+
function tryBeacon(body) {
|
|
850
|
+
if (!config.useBeacon) return false;
|
|
851
|
+
const sendBeacon = globalThis.navigator?.sendBeacon;
|
|
852
|
+
if (typeof sendBeacon !== "function") return false;
|
|
853
|
+
try {
|
|
854
|
+
const blob = new Blob([JSON.stringify(body)], { type: "application/json" });
|
|
855
|
+
return sendBeacon.call(globalThis.navigator, config.endpoint, blob);
|
|
856
|
+
} catch {
|
|
857
|
+
return false;
|
|
858
|
+
}
|
|
859
|
+
}
|
|
283
860
|
async function deliver(body) {
|
|
861
|
+
if (tryBeacon(body)) return;
|
|
284
862
|
const fetchImpl = config.fetch ?? globalThis.fetch;
|
|
285
863
|
if (typeof fetchImpl !== "function") {
|
|
286
864
|
throw new Error("fetch_unavailable");
|
|
@@ -297,26 +875,22 @@ function createDeliveryManager(config) {
|
|
|
297
875
|
return {
|
|
298
876
|
async send(payload) {
|
|
299
877
|
const body = withEnvelope(payload);
|
|
300
|
-
|
|
301
|
-
|
|
302
|
-
messageId: String(body.metaData?.requestId ?? body.messageId),
|
|
303
|
-
reason: "payload_too_large",
|
|
304
|
-
timestamp: (/* @__PURE__ */ new Date()).toISOString()
|
|
305
|
-
});
|
|
878
|
+
const preparedBody = preparePayloadForSend(body);
|
|
879
|
+
if (!preparedBody) {
|
|
306
880
|
return;
|
|
307
881
|
}
|
|
308
882
|
diagnostics.inFlight += 1;
|
|
309
883
|
try {
|
|
310
|
-
await deliver(
|
|
884
|
+
await deliver(preparedBody);
|
|
311
885
|
} catch (error) {
|
|
312
886
|
const deliveryError = error instanceof Error ? error : new Error(String(error));
|
|
313
887
|
recordError(deliveryError);
|
|
314
888
|
enqueue({
|
|
315
|
-
messageId: String(body
|
|
889
|
+
messageId: String(getPayloadMessageId(body)),
|
|
316
890
|
savedAt: Date.now(),
|
|
317
891
|
attempts: 1,
|
|
318
892
|
lastError: deliveryError.message,
|
|
319
|
-
payload:
|
|
893
|
+
payload: preparedBody
|
|
320
894
|
});
|
|
321
895
|
} finally {
|
|
322
896
|
diagnostics.inFlight -= 1;
|
|
@@ -429,60 +1003,286 @@ function createDeliveryManager(config) {
|
|
|
429
1003
|
};
|
|
430
1004
|
}
|
|
431
1005
|
|
|
432
|
-
// src/browser/core/
|
|
433
|
-
var
|
|
434
|
-
|
|
435
|
-
|
|
436
|
-
|
|
437
|
-
|
|
438
|
-
|
|
439
|
-
|
|
440
|
-
|
|
441
|
-
|
|
442
|
-
"name",
|
|
443
|
-
"token",
|
|
444
|
-
"secret",
|
|
445
|
-
"password",
|
|
446
|
-
"session",
|
|
447
|
-
"cookie"
|
|
448
|
-
]);
|
|
449
|
-
function sanitizeValue(value, allow) {
|
|
450
|
-
if (Array.isArray(value)) {
|
|
451
|
-
return value.map((item) => sanitizeValue(item, allow));
|
|
1006
|
+
// src/browser/core/identity.ts
|
|
1007
|
+
var ANONYMOUS_ID_STORAGE_KEY = "dmd_anonymous_id";
|
|
1008
|
+
var LEGACY_ANONYMOUS_ID_STORAGE_KEY = "anonymousId";
|
|
1009
|
+
function getUrlParam(name) {
|
|
1010
|
+
const href = getBrowserWindow()?.location?.href;
|
|
1011
|
+
if (!href) return null;
|
|
1012
|
+
try {
|
|
1013
|
+
return new URL(href).searchParams.get(name);
|
|
1014
|
+
} catch {
|
|
1015
|
+
return null;
|
|
452
1016
|
}
|
|
453
|
-
|
|
454
|
-
|
|
455
|
-
|
|
456
|
-
|
|
1017
|
+
}
|
|
1018
|
+
function resolveAnonymousId(persistence) {
|
|
1019
|
+
const urlAnonymousId = getUrlParam("aid");
|
|
1020
|
+
if (isUuid(urlAnonymousId)) {
|
|
1021
|
+
persistence.setItem(ANONYMOUS_ID_STORAGE_KEY, urlAnonymousId);
|
|
1022
|
+
return urlAnonymousId;
|
|
457
1023
|
}
|
|
458
|
-
|
|
1024
|
+
const storedAnonymousId = persistence.getItem(ANONYMOUS_ID_STORAGE_KEY);
|
|
1025
|
+
if (isUuid(storedAnonymousId)) {
|
|
1026
|
+
return storedAnonymousId;
|
|
1027
|
+
}
|
|
1028
|
+
const legacyAnonymousId = persistence.getItem(LEGACY_ANONYMOUS_ID_STORAGE_KEY);
|
|
1029
|
+
if (isUuid(legacyAnonymousId)) {
|
|
1030
|
+
persistence.setItem(ANONYMOUS_ID_STORAGE_KEY, legacyAnonymousId);
|
|
1031
|
+
return legacyAnonymousId;
|
|
1032
|
+
}
|
|
1033
|
+
const anonymousId = createUuid();
|
|
1034
|
+
persistence.setItem(ANONYMOUS_ID_STORAGE_KEY, anonymousId);
|
|
1035
|
+
return anonymousId;
|
|
459
1036
|
}
|
|
460
|
-
function
|
|
461
|
-
const
|
|
462
|
-
|
|
1037
|
+
function resetAnonymousId(persistence) {
|
|
1038
|
+
const anonymousId = createUuid();
|
|
1039
|
+
persistence.setItem(ANONYMOUS_ID_STORAGE_KEY, anonymousId);
|
|
1040
|
+
return anonymousId;
|
|
463
1041
|
}
|
|
464
1042
|
|
|
465
|
-
// src/browser/core/
|
|
466
|
-
|
|
467
|
-
|
|
468
|
-
|
|
469
|
-
|
|
470
|
-
|
|
471
|
-
|
|
472
|
-
|
|
1043
|
+
// src/browser/core/page-context.ts
|
|
1044
|
+
function redactSearch(search) {
|
|
1045
|
+
const redacted = redactUrl(search);
|
|
1046
|
+
return redacted.startsWith("/?") ? redacted.slice(1) : redacted;
|
|
1047
|
+
}
|
|
1048
|
+
function getBrowserPageContext() {
|
|
1049
|
+
const browserWindow = getBrowserWindow();
|
|
1050
|
+
const documentRef = browserWindow?.document ?? globalThis.document;
|
|
1051
|
+
const location = browserWindow?.location;
|
|
1052
|
+
const page2 = {};
|
|
1053
|
+
if (location?.href) page2.url = location.href;
|
|
1054
|
+
if (location?.pathname) page2.path = location.pathname;
|
|
1055
|
+
if (location?.search) page2.search = redactSearch(location.search);
|
|
1056
|
+
if (documentRef?.title) page2.title = documentRef.title;
|
|
1057
|
+
if (documentRef?.referrer) page2.referrer = redactUrl(documentRef.referrer);
|
|
1058
|
+
return page2;
|
|
1059
|
+
}
|
|
1060
|
+
|
|
1061
|
+
// src/browser/core/persistence.ts
|
|
1062
|
+
function createPersistenceHealth(requested) {
|
|
1063
|
+
return {
|
|
1064
|
+
requested,
|
|
1065
|
+
cookieFallbackUsed: false,
|
|
1066
|
+
memoryFallbackUsed: requested === "memory",
|
|
1067
|
+
failures: []
|
|
1068
|
+
};
|
|
1069
|
+
}
|
|
1070
|
+
function recordFailure(health, backend, operation, error) {
|
|
1071
|
+
health.failures.push({
|
|
1072
|
+
backend,
|
|
1073
|
+
operation,
|
|
1074
|
+
message: error instanceof Error ? error.message : String(error)
|
|
1075
|
+
});
|
|
1076
|
+
if (health.failures.length > 25) {
|
|
1077
|
+
health.failures.shift();
|
|
473
1078
|
}
|
|
474
|
-
|
|
475
|
-
|
|
476
|
-
|
|
477
|
-
|
|
1079
|
+
}
|
|
1080
|
+
function createMemoryPersistence(health = createPersistenceHealth("memory")) {
|
|
1081
|
+
const memory = {};
|
|
1082
|
+
return {
|
|
1083
|
+
getItem(key) {
|
|
1084
|
+
return Object.prototype.hasOwnProperty.call(memory, key) ? memory[key] ?? null : null;
|
|
1085
|
+
},
|
|
1086
|
+
setItem(key, value) {
|
|
1087
|
+
memory[key] = value;
|
|
1088
|
+
return true;
|
|
1089
|
+
},
|
|
1090
|
+
removeItem(key) {
|
|
1091
|
+
delete memory[key];
|
|
1092
|
+
},
|
|
1093
|
+
getHealth() {
|
|
1094
|
+
return {
|
|
1095
|
+
...health,
|
|
1096
|
+
failures: health.failures.map((failure) => ({ ...failure }))
|
|
1097
|
+
};
|
|
1098
|
+
}
|
|
1099
|
+
};
|
|
1100
|
+
}
|
|
1101
|
+
function getCookie2(name) {
|
|
1102
|
+
const browserWindow = getBrowserWindow();
|
|
1103
|
+
const cookie = browserWindow?.document?.cookie;
|
|
1104
|
+
if (!cookie) return null;
|
|
1105
|
+
const escapedName = name.replace(/[.*+?^${}()|[\]\\]/g, "\\$&");
|
|
1106
|
+
const match = new RegExp(`(?:^|; )${escapedName}=([^;]*)`).exec(cookie);
|
|
1107
|
+
return match ? decodeURIComponent(match[1] ?? "") : null;
|
|
1108
|
+
}
|
|
1109
|
+
function setCookie(name, value) {
|
|
1110
|
+
const browserWindow = getBrowserWindow();
|
|
1111
|
+
if (!browserWindow?.document) return false;
|
|
1112
|
+
try {
|
|
1113
|
+
const expires = new Date(Date.now() + 365 * 24 * 60 * 60 * 1e3).toUTCString();
|
|
1114
|
+
const secure = browserWindow.location?.protocol === "https:" ? "; Secure" : "";
|
|
1115
|
+
browserWindow.document.cookie = `${name}=${encodeURIComponent(value)}; expires=${expires}; path=/${secure}; SameSite=Lax`;
|
|
1116
|
+
return true;
|
|
1117
|
+
} catch {
|
|
1118
|
+
return false;
|
|
478
1119
|
}
|
|
479
|
-
|
|
1120
|
+
}
|
|
1121
|
+
function removeCookie(name) {
|
|
1122
|
+
const browserWindow = getBrowserWindow();
|
|
1123
|
+
if (!browserWindow?.document) return;
|
|
1124
|
+
browserWindow.document.cookie = `${name}=; expires=Thu, 01 Jan 1970 00:00:00 GMT; path=/`;
|
|
1125
|
+
}
|
|
1126
|
+
function getLocalStorage() {
|
|
1127
|
+
const browserWindow = getBrowserWindow();
|
|
1128
|
+
try {
|
|
1129
|
+
return browserWindow?.localStorage;
|
|
1130
|
+
} catch {
|
|
1131
|
+
return void 0;
|
|
1132
|
+
}
|
|
1133
|
+
}
|
|
1134
|
+
function getSessionStorage() {
|
|
1135
|
+
const browserWindow = getBrowserWindow();
|
|
1136
|
+
try {
|
|
1137
|
+
return browserWindow?.sessionStorage;
|
|
1138
|
+
} catch {
|
|
1139
|
+
return void 0;
|
|
1140
|
+
}
|
|
1141
|
+
}
|
|
1142
|
+
function createBrowserPersistence(mode = "localStorage+cookie") {
|
|
1143
|
+
const health = createPersistenceHealth(mode);
|
|
1144
|
+
const memory = createMemoryPersistence(health);
|
|
1145
|
+
if (mode === "none") {
|
|
1146
|
+
return {
|
|
1147
|
+
getItem() {
|
|
1148
|
+
return null;
|
|
1149
|
+
},
|
|
1150
|
+
setItem() {
|
|
1151
|
+
return false;
|
|
1152
|
+
},
|
|
1153
|
+
removeItem() {
|
|
1154
|
+
},
|
|
1155
|
+
getHealth() {
|
|
1156
|
+
return {
|
|
1157
|
+
...health,
|
|
1158
|
+
failures: health.failures.map((failure) => ({ ...failure }))
|
|
1159
|
+
};
|
|
1160
|
+
}
|
|
1161
|
+
};
|
|
1162
|
+
}
|
|
1163
|
+
if (mode === "memory") return memory;
|
|
1164
|
+
const primary = mode === "sessionStorage" ? getSessionStorage() : getLocalStorage();
|
|
1165
|
+
const useCookie = mode === "cookie" || mode === "localStorage+cookie" || !primary;
|
|
1166
|
+
return {
|
|
1167
|
+
getItem(key) {
|
|
1168
|
+
try {
|
|
1169
|
+
const stored = primary?.getItem(key);
|
|
1170
|
+
if (stored) return stored;
|
|
1171
|
+
} catch (error) {
|
|
1172
|
+
recordFailure(health, mode === "sessionStorage" ? "sessionStorage" : "localStorage", "get", error);
|
|
1173
|
+
}
|
|
1174
|
+
if (useCookie) {
|
|
1175
|
+
const cookie = getCookie2(key);
|
|
1176
|
+
if (cookie) {
|
|
1177
|
+
health.cookieFallbackUsed = true;
|
|
1178
|
+
return cookie;
|
|
1179
|
+
}
|
|
1180
|
+
}
|
|
1181
|
+
const value = memory.getItem(key);
|
|
1182
|
+
if (value !== null) health.memoryFallbackUsed = true;
|
|
1183
|
+
return value;
|
|
1184
|
+
},
|
|
1185
|
+
setItem(key, value) {
|
|
1186
|
+
let wrote = false;
|
|
1187
|
+
try {
|
|
1188
|
+
primary?.setItem(key, value);
|
|
1189
|
+
wrote = primary !== void 0;
|
|
1190
|
+
} catch (error) {
|
|
1191
|
+
recordFailure(health, mode === "sessionStorage" ? "sessionStorage" : "localStorage", "set", error);
|
|
1192
|
+
wrote = false;
|
|
1193
|
+
}
|
|
1194
|
+
if (useCookie) {
|
|
1195
|
+
const cookieWrote = setCookie(key, value);
|
|
1196
|
+
if (cookieWrote) health.cookieFallbackUsed = true;
|
|
1197
|
+
wrote = cookieWrote || wrote;
|
|
1198
|
+
}
|
|
1199
|
+
if (!wrote) {
|
|
1200
|
+
health.memoryFallbackUsed = true;
|
|
1201
|
+
return memory.setItem(key, value);
|
|
1202
|
+
}
|
|
1203
|
+
if (mode === "localStorage+cookie") {
|
|
1204
|
+
memory.setItem(key, value);
|
|
1205
|
+
}
|
|
1206
|
+
return true;
|
|
1207
|
+
},
|
|
1208
|
+
removeItem(key) {
|
|
1209
|
+
try {
|
|
1210
|
+
primary?.removeItem(key);
|
|
1211
|
+
} catch (error) {
|
|
1212
|
+
recordFailure(health, mode === "sessionStorage" ? "sessionStorage" : "localStorage", "remove", error);
|
|
1213
|
+
}
|
|
1214
|
+
if (useCookie) removeCookie(key);
|
|
1215
|
+
memory.removeItem(key);
|
|
1216
|
+
},
|
|
1217
|
+
getHealth() {
|
|
1218
|
+
return {
|
|
1219
|
+
...health,
|
|
1220
|
+
failures: health.failures.map((failure) => ({ ...failure }))
|
|
1221
|
+
};
|
|
1222
|
+
}
|
|
1223
|
+
};
|
|
480
1224
|
}
|
|
481
1225
|
|
|
482
|
-
// src/browser/core/
|
|
483
|
-
|
|
484
|
-
|
|
1226
|
+
// src/browser/core/session.ts
|
|
1227
|
+
var SESSION_STORAGE_KEY2 = "sessionData";
|
|
1228
|
+
function getUrlParam2(name) {
|
|
1229
|
+
const href = getBrowserWindow()?.location?.href;
|
|
1230
|
+
if (!href) return null;
|
|
1231
|
+
try {
|
|
1232
|
+
return new URL(href).searchParams.get(name);
|
|
1233
|
+
} catch {
|
|
1234
|
+
return null;
|
|
1235
|
+
}
|
|
485
1236
|
}
|
|
1237
|
+
function readStoredSession(persistence) {
|
|
1238
|
+
const rawSession = persistence.getItem(SESSION_STORAGE_KEY2);
|
|
1239
|
+
if (!rawSession) return void 0;
|
|
1240
|
+
try {
|
|
1241
|
+
const parsed = JSON.parse(rawSession);
|
|
1242
|
+
if (isUuid(parsed.sessionId) && typeof parsed.timestamp === "number") {
|
|
1243
|
+
return {
|
|
1244
|
+
sessionId: parsed.sessionId,
|
|
1245
|
+
timestamp: parsed.timestamp
|
|
1246
|
+
};
|
|
1247
|
+
}
|
|
1248
|
+
} catch {
|
|
1249
|
+
persistence.removeItem(SESSION_STORAGE_KEY2);
|
|
1250
|
+
}
|
|
1251
|
+
return void 0;
|
|
1252
|
+
}
|
|
1253
|
+
function writeStoredSession(persistence, sessionId, timestamp) {
|
|
1254
|
+
persistence.setItem(SESSION_STORAGE_KEY2, JSON.stringify({ sessionId, timestamp }));
|
|
1255
|
+
}
|
|
1256
|
+
function createSessionManager(persistence, idleTimeoutSeconds = 30 * 60) {
|
|
1257
|
+
function resolveSessionId() {
|
|
1258
|
+
const now = Date.now();
|
|
1259
|
+
const urlSessionId = getUrlParam2("sid") ?? getUrlParam2("session_id");
|
|
1260
|
+
if (isUuid(urlSessionId)) {
|
|
1261
|
+
writeStoredSession(persistence, urlSessionId, now);
|
|
1262
|
+
return urlSessionId;
|
|
1263
|
+
}
|
|
1264
|
+
const storedSession = readStoredSession(persistence);
|
|
1265
|
+
if (storedSession && now - storedSession.timestamp <= idleTimeoutSeconds * 1e3) {
|
|
1266
|
+
writeStoredSession(persistence, storedSession.sessionId, now);
|
|
1267
|
+
return storedSession.sessionId;
|
|
1268
|
+
}
|
|
1269
|
+
const sessionId = createUuid();
|
|
1270
|
+
writeStoredSession(persistence, sessionId, now);
|
|
1271
|
+
return sessionId;
|
|
1272
|
+
}
|
|
1273
|
+
return {
|
|
1274
|
+
getSessionId() {
|
|
1275
|
+
return resolveSessionId();
|
|
1276
|
+
},
|
|
1277
|
+
reset() {
|
|
1278
|
+
const sessionId = createUuid();
|
|
1279
|
+
writeStoredSession(persistence, sessionId, Date.now());
|
|
1280
|
+
return sessionId;
|
|
1281
|
+
}
|
|
1282
|
+
};
|
|
1283
|
+
}
|
|
1284
|
+
|
|
1285
|
+
// src/browser/core/DriveMetaDataSDK.ts
|
|
486
1286
|
function endpointFromConfig(config) {
|
|
487
1287
|
const host = config.apiHost ?? "https://sdk.drivemetadata.com/v2";
|
|
488
1288
|
return `${host.replace(/\/$/, "")}/data-collector`;
|
|
@@ -493,14 +1293,6 @@ function requireConfigString(value, field) {
|
|
|
493
1293
|
}
|
|
494
1294
|
return value;
|
|
495
1295
|
}
|
|
496
|
-
function getBrowserStorage() {
|
|
497
|
-
const browserWindow = getBrowserWindow();
|
|
498
|
-
try {
|
|
499
|
-
return browserWindow?.localStorage;
|
|
500
|
-
} catch {
|
|
501
|
-
return void 0;
|
|
502
|
-
}
|
|
503
|
-
}
|
|
504
1296
|
var DriveMetaDataSDK = class {
|
|
505
1297
|
constructor(config) {
|
|
506
1298
|
this.initialized = true;
|
|
@@ -513,30 +1305,36 @@ var DriveMetaDataSDK = class {
|
|
|
513
1305
|
requireConfigString(config.writeKey || config.token, "writeKey or token");
|
|
514
1306
|
this.config = config;
|
|
515
1307
|
this.endpoint = endpointFromConfig(config);
|
|
516
|
-
const
|
|
1308
|
+
const storagePersistence = createBrowserPersistence(config.persistence);
|
|
1309
|
+
this.persistence = createDmdAttributesPersistence(storagePersistence);
|
|
1310
|
+
this.session = createSessionManager(this.persistence, config.sessionIdleTimeoutSeconds);
|
|
517
1311
|
const deliveryConfig = {
|
|
518
|
-
endpoint: this.endpoint
|
|
1312
|
+
endpoint: this.endpoint,
|
|
1313
|
+
storage: storagePersistence
|
|
519
1314
|
};
|
|
520
1315
|
if (config.delivery?.maxQueueSize !== void 0) deliveryConfig.maxQueueSize = config.delivery.maxQueueSize;
|
|
521
1316
|
if (config.delivery?.queueTtlMs !== void 0) deliveryConfig.queueTtlMs = config.delivery.queueTtlMs;
|
|
522
1317
|
if (config.delivery?.retryDelayMs !== void 0) deliveryConfig.retryDelayMs = config.delivery.retryDelayMs;
|
|
523
1318
|
if (config.delivery?.maxRetryDelayMs !== void 0) deliveryConfig.maxRetryDelayMs = config.delivery.maxRetryDelayMs;
|
|
524
1319
|
if (config.delivery?.maxPayloadBytes !== void 0) deliveryConfig.maxPayloadBytes = config.delivery.maxPayloadBytes;
|
|
1320
|
+
if (config.delivery?.payloadSizePolicy !== void 0) deliveryConfig.payloadSizePolicy = config.delivery.payloadSizePolicy;
|
|
1321
|
+
if (config.delivery?.payloadTruncateStringLength !== void 0) {
|
|
1322
|
+
deliveryConfig.payloadTruncateStringLength = config.delivery.payloadTruncateStringLength;
|
|
1323
|
+
}
|
|
1324
|
+
if (config.delivery?.useBeacon !== void 0) deliveryConfig.useBeacon = config.delivery.useBeacon;
|
|
525
1325
|
if (config.delivery?.batchSize !== void 0) deliveryConfig.batchSize = config.delivery.batchSize;
|
|
526
1326
|
if (config.onDrop !== void 0) deliveryConfig.onDrop = config.onDrop;
|
|
527
1327
|
if (config.onError !== void 0) deliveryConfig.onError = config.onError;
|
|
528
|
-
this.delivery = createDeliveryManager(
|
|
529
|
-
...deliveryConfig,
|
|
530
|
-
storage
|
|
531
|
-
} : deliveryConfig);
|
|
1328
|
+
this.delivery = createDeliveryManager(deliveryConfig);
|
|
532
1329
|
this.initialRetryDelayMs = config.delivery?.retryDelayMs ?? 1e3;
|
|
533
1330
|
this.retryDelayMs = this.initialRetryDelayMs;
|
|
534
1331
|
this.maxRetryDelayMs = config.delivery?.maxRetryDelayMs ?? 3e4;
|
|
535
1332
|
this.writeKey = config.writeKey || config.token || "";
|
|
536
|
-
this.identity = { anonymousId:
|
|
537
|
-
this.
|
|
1333
|
+
this.identity = { anonymousId: resolveAnonymousId(this.persistence) };
|
|
1334
|
+
captureAttributionFromUrl(this.persistence);
|
|
538
1335
|
this.consentState = normalizeConsent(config.gdprConsent ?? config.consent);
|
|
539
1336
|
this.gdprConsent = this.consentState.analytics;
|
|
1337
|
+
this.installAutocapture();
|
|
540
1338
|
if (!config.delivery?.disableLifecycleFlush) {
|
|
541
1339
|
this.installLifecycleFlush();
|
|
542
1340
|
}
|
|
@@ -576,7 +1374,8 @@ var DriveMetaDataSDK = class {
|
|
|
576
1374
|
}
|
|
577
1375
|
}
|
|
578
1376
|
reset() {
|
|
579
|
-
this.identity = { anonymousId:
|
|
1377
|
+
this.identity = { anonymousId: resetAnonymousId(this.persistence) };
|
|
1378
|
+
this.session.reset();
|
|
580
1379
|
this.queue = [];
|
|
581
1380
|
this.offline = false;
|
|
582
1381
|
if (this.retryTimer !== void 0) {
|
|
@@ -585,8 +1384,20 @@ var DriveMetaDataSDK = class {
|
|
|
585
1384
|
}
|
|
586
1385
|
this.lifecycleCleanup?.();
|
|
587
1386
|
this.lifecycleCleanup = void 0;
|
|
1387
|
+
this.autocaptureCleanup?.();
|
|
1388
|
+
this.autocaptureCleanup = void 0;
|
|
588
1389
|
this.delivery.clearQueue("manual_clear");
|
|
589
1390
|
}
|
|
1391
|
+
disposeForTests() {
|
|
1392
|
+
if (this.retryTimer !== void 0) {
|
|
1393
|
+
clearTimeout(this.retryTimer);
|
|
1394
|
+
this.retryTimer = void 0;
|
|
1395
|
+
}
|
|
1396
|
+
this.lifecycleCleanup?.();
|
|
1397
|
+
this.lifecycleCleanup = void 0;
|
|
1398
|
+
this.autocaptureCleanup?.();
|
|
1399
|
+
this.autocaptureCleanup = void 0;
|
|
1400
|
+
}
|
|
590
1401
|
setConsent(consent) {
|
|
591
1402
|
this.consentState = typeof consent === "object" ? mergeConsent(this.consentState, consent) : normalizeConsent(consent);
|
|
592
1403
|
this.gdprConsent = this.consentState.analytics;
|
|
@@ -601,6 +1412,7 @@ var DriveMetaDataSDK = class {
|
|
|
601
1412
|
initialized: this.initialized,
|
|
602
1413
|
consent: this.gdprConsent,
|
|
603
1414
|
consentPurposes: this.consentState,
|
|
1415
|
+
persistence: this.persistence.getHealth(),
|
|
604
1416
|
queueSize: deliveryDiagnostics.queued,
|
|
605
1417
|
offline: this.offline || deliveryDiagnostics.queued > 0,
|
|
606
1418
|
droppedEvents: this.droppedEvents + deliveryDiagnostics.dropped.length,
|
|
@@ -615,7 +1427,9 @@ var DriveMetaDataSDK = class {
|
|
|
615
1427
|
void this.delivery.send(payload).then(() => {
|
|
616
1428
|
const diagnostics = this.delivery.getDiagnostics();
|
|
617
1429
|
this.offline = diagnostics.queued > 0;
|
|
618
|
-
|
|
1430
|
+
if (diagnostics.lastError !== void 0) {
|
|
1431
|
+
this.lastError = diagnostics.lastError;
|
|
1432
|
+
}
|
|
619
1433
|
if (diagnostics.queued > 0) {
|
|
620
1434
|
this.scheduleRetryFlush();
|
|
621
1435
|
}
|
|
@@ -647,6 +1461,28 @@ var DriveMetaDataSDK = class {
|
|
|
647
1461
|
}
|
|
648
1462
|
};
|
|
649
1463
|
}
|
|
1464
|
+
installAutocapture() {
|
|
1465
|
+
const browserWindow = getBrowserWindow();
|
|
1466
|
+
if (!browserWindow) return;
|
|
1467
|
+
if (this.config.autocapture === false) return;
|
|
1468
|
+
const capturePageview = this.config.capturePageview !== false;
|
|
1469
|
+
const capturePageleave = this.config.capturePageleave !== false;
|
|
1470
|
+
const controller = installAutocapture({
|
|
1471
|
+
browserWindow,
|
|
1472
|
+
capturePageview,
|
|
1473
|
+
capturePageleave,
|
|
1474
|
+
onPageView: () => {
|
|
1475
|
+
this.page();
|
|
1476
|
+
},
|
|
1477
|
+
onPageLeave: () => {
|
|
1478
|
+
this.trackEvent("page_leave", { url: browserWindow.location.href });
|
|
1479
|
+
},
|
|
1480
|
+
onRouteChange: () => {
|
|
1481
|
+
captureAttributionFromUrl(this.persistence);
|
|
1482
|
+
}
|
|
1483
|
+
});
|
|
1484
|
+
this.autocaptureCleanup = controller.cleanup;
|
|
1485
|
+
}
|
|
650
1486
|
scheduleRetryFlush() {
|
|
651
1487
|
if (this.retryTimer !== void 0) return;
|
|
652
1488
|
const delay = Math.min(this.retryDelayMs, this.maxRetryDelayMs);
|
|
@@ -672,7 +1508,7 @@ var DriveMetaDataSDK = class {
|
|
|
672
1508
|
type,
|
|
673
1509
|
event,
|
|
674
1510
|
properties: sanitizeProperties(properties),
|
|
675
|
-
messageId: options.messageId
|
|
1511
|
+
messageId: ensureUuid(options.messageId),
|
|
676
1512
|
timestamp: options.timestamp ?? (/* @__PURE__ */ new Date()).toISOString(),
|
|
677
1513
|
context: options.context ?? {},
|
|
678
1514
|
anonymousId: this.identity.anonymousId,
|
|
@@ -681,7 +1517,7 @@ var DriveMetaDataSDK = class {
|
|
|
681
1517
|
appId: this.config.appId,
|
|
682
1518
|
writeKey: this.writeKey,
|
|
683
1519
|
consent: this.consentState,
|
|
684
|
-
sessionId: this.
|
|
1520
|
+
sessionId: this.session.getSessionId()
|
|
685
1521
|
};
|
|
686
1522
|
if (this.identity.userId !== void 0) prepared.userId = this.identity.userId;
|
|
687
1523
|
if (this.identity.groupId !== void 0) prepared.groupId = this.identity.groupId;
|
|
@@ -705,10 +1541,21 @@ var DriveMetaDataSDK = class {
|
|
|
705
1541
|
if (!validation.ok) {
|
|
706
1542
|
this.lastError = `DMD SDK schema warning: ${validation.errors.join(", ")}`;
|
|
707
1543
|
}
|
|
708
|
-
this.
|
|
1544
|
+
const collectorPayload = this.toCollectorPayload(prepared);
|
|
1545
|
+
const backendValidation = validateBackendCollectorPayload(collectorPayload);
|
|
1546
|
+
if (!backendValidation.ok && this.config.schemaValidation === "strict") {
|
|
1547
|
+
this.lastError = `DMD SDK backend schema warning: ${backendValidation.errors.join(", ")}`;
|
|
1548
|
+
this.recordDrop(type, "invalid_payload", event);
|
|
1549
|
+
return;
|
|
1550
|
+
}
|
|
1551
|
+
if (!backendValidation.ok) {
|
|
1552
|
+
this.lastError = `DMD SDK backend schema warning: ${backendValidation.errors.join(", ")}`;
|
|
1553
|
+
}
|
|
1554
|
+
this.sendEvent(collectorPayload);
|
|
709
1555
|
}
|
|
710
1556
|
toCollectorPayload(prepared) {
|
|
711
1557
|
const browserWindow = getBrowserWindow();
|
|
1558
|
+
const pageContext = getBrowserPageContext();
|
|
712
1559
|
return createBackendCollectorPayload({
|
|
713
1560
|
requestId: prepared.messageId,
|
|
714
1561
|
timestamp: prepared.timestamp,
|
|
@@ -720,15 +1567,19 @@ var DriveMetaDataSDK = class {
|
|
|
720
1567
|
sessionId: prepared.sessionId,
|
|
721
1568
|
ua: browserWindow?.navigator?.userAgent,
|
|
722
1569
|
appId: prepared.appId,
|
|
723
|
-
pageUrl: browserWindow?.location?.href,
|
|
724
|
-
eventData: {
|
|
1570
|
+
pageUrl: pageContext.url ?? browserWindow?.location?.href,
|
|
1571
|
+
eventData: mergeStoredAttribution({
|
|
725
1572
|
...prepared.properties,
|
|
1573
|
+
page: {
|
|
1574
|
+
...pageContext,
|
|
1575
|
+
...prepared.properties.page && typeof prepared.properties.page === "object" ? prepared.properties.page : {}
|
|
1576
|
+
},
|
|
726
1577
|
anonymousId: prepared.anonymousId,
|
|
727
1578
|
sessionId: prepared.sessionId,
|
|
728
1579
|
timestamp: prepared.timestamp,
|
|
729
1580
|
requestSentAt: prepared.timestamp,
|
|
730
1581
|
requestReceivedAt: prepared.timestamp
|
|
731
|
-
}
|
|
1582
|
+
}, this.persistence)
|
|
732
1583
|
});
|
|
733
1584
|
}
|
|
734
1585
|
recordDrop(type, reason, event) {
|
|
@@ -804,7 +1655,7 @@ function initDmdSDK(config) {
|
|
|
804
1655
|
return publicSingleton;
|
|
805
1656
|
}
|
|
806
1657
|
try {
|
|
807
|
-
const instance = new DriveMetaDataSDK(config);
|
|
1658
|
+
const instance = new DriveMetaDataSDK(normalizeBrowserConfig(config));
|
|
808
1659
|
return setSingleton(instance);
|
|
809
1660
|
} catch (error) {
|
|
810
1661
|
lastError = error instanceof Error ? error.message : String(error);
|