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