@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/browser/index.js
CHANGED
|
@@ -1,9 +1,59 @@
|
|
|
1
|
+
// src/browser/core/browser-config.ts
|
|
2
|
+
function setIfDefined(target, key, value) {
|
|
3
|
+
if (value !== void 0) {
|
|
4
|
+
target[key] = value;
|
|
5
|
+
}
|
|
6
|
+
}
|
|
7
|
+
function normalizeBrowserConfig(input) {
|
|
8
|
+
const normalized = {
|
|
9
|
+
...input,
|
|
10
|
+
clientId: input.clientId ?? "",
|
|
11
|
+
workspaceId: input.workspaceId ?? "",
|
|
12
|
+
appId: input.appId ?? ""
|
|
13
|
+
};
|
|
14
|
+
setIfDefined(normalized, "apiHost", input.apiHost);
|
|
15
|
+
setIfDefined(normalized, "capturePageview", input.capturePageview);
|
|
16
|
+
setIfDefined(normalized, "capturePageleave", input.capturePageleave);
|
|
17
|
+
setIfDefined(normalized, "captureDeadClicks", input.captureDeadClicks);
|
|
18
|
+
setIfDefined(normalized, "crossSubdomainCookie", input.crossSubdomainCookie);
|
|
19
|
+
setIfDefined(normalized, "sessionIdleTimeoutSeconds", input.sessionIdleTimeoutSeconds);
|
|
20
|
+
setIfDefined(normalized, "schemaValidation", input.schemaValidation);
|
|
21
|
+
setIfDefined(normalized, "beforeSend", input.beforeSend);
|
|
22
|
+
setIfDefined(normalized, "persistence", input.disablePersistence === true ? "none" : input.persistence);
|
|
23
|
+
return normalized;
|
|
24
|
+
}
|
|
25
|
+
|
|
26
|
+
// src/core/uuid.ts
|
|
27
|
+
function createUuid() {
|
|
28
|
+
const cryptoApi = globalThis.crypto;
|
|
29
|
+
if (typeof cryptoApi?.randomUUID === "function") {
|
|
30
|
+
return cryptoApi.randomUUID();
|
|
31
|
+
}
|
|
32
|
+
const bytes = new Uint8Array(16);
|
|
33
|
+
if (typeof cryptoApi?.getRandomValues === "function") {
|
|
34
|
+
cryptoApi.getRandomValues(bytes);
|
|
35
|
+
} else {
|
|
36
|
+
for (let index = 0; index < bytes.length; index += 1) {
|
|
37
|
+
bytes[index] = Math.floor(Math.random() * 256);
|
|
38
|
+
}
|
|
39
|
+
}
|
|
40
|
+
bytes[6] = (bytes[6] ?? 0) & 15 | 64;
|
|
41
|
+
bytes[8] = (bytes[8] ?? 0) & 63 | 128;
|
|
42
|
+
const hex = Array.from(bytes, (byte) => byte.toString(16).padStart(2, "0")).join("");
|
|
43
|
+
return `${hex.slice(0, 8)}-${hex.slice(8, 12)}-${hex.slice(12, 16)}-${hex.slice(16, 20)}-${hex.slice(20)}`;
|
|
44
|
+
}
|
|
45
|
+
function isUuid(value) {
|
|
46
|
+
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);
|
|
47
|
+
}
|
|
48
|
+
function ensureUuid(value) {
|
|
49
|
+
return isUuid(value) ? value : createUuid();
|
|
50
|
+
}
|
|
51
|
+
|
|
1
52
|
// src/core/backend-payload.ts
|
|
2
53
|
function formatUtcTimestamp(value) {
|
|
3
|
-
|
|
4
|
-
const
|
|
5
|
-
|
|
6
|
-
return date.toISOString().replace("T", " ").slice(0, 19);
|
|
54
|
+
const date = typeof value === "string" || typeof value === "number" || value instanceof Date ? new Date(value) : /* @__PURE__ */ new Date();
|
|
55
|
+
const safeDate = Number.isNaN(date.getTime()) ? /* @__PURE__ */ new Date() : date;
|
|
56
|
+
return safeDate.toISOString().replace("T", " ").slice(0, 19);
|
|
7
57
|
}
|
|
8
58
|
function cleanObject(value) {
|
|
9
59
|
if (Array.isArray(value)) {
|
|
@@ -34,15 +84,19 @@ function createBackendCollectorPayload(input) {
|
|
|
34
84
|
};
|
|
35
85
|
const metaData = {
|
|
36
86
|
...normalizedEventData,
|
|
37
|
-
requestId: input.requestId,
|
|
87
|
+
requestId: ensureUuid(typeof input.requestId === "string" ? input.requestId : void 0),
|
|
38
88
|
timestamp,
|
|
39
89
|
eventType: input.eventType,
|
|
40
90
|
requestFrom: input.requestFrom ?? "3",
|
|
41
91
|
clientId: input.clientId,
|
|
42
92
|
workspaceId: input.workspaceId,
|
|
43
93
|
token: input.token,
|
|
44
|
-
anonymousId:
|
|
45
|
-
|
|
94
|
+
anonymousId: ensureUuid(
|
|
95
|
+
typeof eventData.anonymousId === "string" ? eventData.anonymousId : typeof input.anonymousId === "string" ? input.anonymousId : void 0
|
|
96
|
+
),
|
|
97
|
+
sessionId: ensureUuid(
|
|
98
|
+
typeof eventData.sessionId === "string" ? eventData.sessionId : typeof input.sessionId === "string" ? input.sessionId : void 0
|
|
99
|
+
),
|
|
46
100
|
ua: input.ua,
|
|
47
101
|
appDetails: { app_id: input.appId },
|
|
48
102
|
page: { ...page2, url: page2.url ?? input.pageUrl },
|
|
@@ -53,12 +107,45 @@ function createBackendCollectorPayload(input) {
|
|
|
53
107
|
return cleanObject(payload);
|
|
54
108
|
}
|
|
55
109
|
|
|
56
|
-
// src/core/
|
|
57
|
-
|
|
58
|
-
|
|
110
|
+
// src/core/backend-schema.ts
|
|
111
|
+
var requiredMetaDataFields = [
|
|
112
|
+
"requestId",
|
|
113
|
+
"timestamp",
|
|
114
|
+
"eventType",
|
|
115
|
+
"requestFrom",
|
|
116
|
+
"clientId",
|
|
117
|
+
"workspaceId",
|
|
118
|
+
"anonymousId",
|
|
119
|
+
"sessionId"
|
|
120
|
+
];
|
|
121
|
+
function isPresent(value) {
|
|
122
|
+
return value !== null && value !== void 0 && value !== "";
|
|
123
|
+
}
|
|
124
|
+
function validateBackendCollectorPayload(payload) {
|
|
125
|
+
const errors = [];
|
|
126
|
+
const metaData = payload.metaData;
|
|
127
|
+
if (!metaData || typeof metaData !== "object" || Array.isArray(metaData)) {
|
|
128
|
+
return {
|
|
129
|
+
ok: false,
|
|
130
|
+
errors: ["metaData is required"]
|
|
131
|
+
};
|
|
132
|
+
}
|
|
133
|
+
const metadataRecord = metaData;
|
|
134
|
+
for (const field of requiredMetaDataFields) {
|
|
135
|
+
if (!isPresent(metadataRecord[field])) {
|
|
136
|
+
errors.push(`metaData.${field} is required`);
|
|
137
|
+
}
|
|
138
|
+
}
|
|
139
|
+
if (isPresent(metadataRecord.eventType) && typeof metadataRecord.eventType !== "string") {
|
|
140
|
+
errors.push("metaData.eventType must be a string");
|
|
141
|
+
}
|
|
142
|
+
return {
|
|
143
|
+
ok: errors.length === 0,
|
|
144
|
+
errors
|
|
145
|
+
};
|
|
59
146
|
}
|
|
60
147
|
|
|
61
|
-
// src/
|
|
148
|
+
// src/core/consent.ts
|
|
62
149
|
var purposes = [
|
|
63
150
|
"analytics",
|
|
64
151
|
"advertising",
|
|
@@ -98,6 +185,476 @@ function canCollectPurpose(consent2, purpose) {
|
|
|
98
185
|
return consent2[purpose] === "granted";
|
|
99
186
|
}
|
|
100
187
|
|
|
188
|
+
// src/core/event-schema.ts
|
|
189
|
+
var reservedKeys = /* @__PURE__ */ new Set(["messageId", "timestamp", "type", "event", "anonymousId", "userId", "context"]);
|
|
190
|
+
function validateEventEnvelope(envelope, options = {}) {
|
|
191
|
+
if (options.mode === "off") return { ok: true, errors: [] };
|
|
192
|
+
const errors = [];
|
|
193
|
+
if (typeof envelope.type !== "string") errors.push("type must be a string");
|
|
194
|
+
if (envelope.type === "track" && typeof envelope.event !== "string") {
|
|
195
|
+
errors.push("track event must include event name");
|
|
196
|
+
}
|
|
197
|
+
if (typeof envelope.messageId !== "string") errors.push("messageId must be a string");
|
|
198
|
+
if (typeof envelope.timestamp !== "string") errors.push("timestamp must be an ISO string");
|
|
199
|
+
for (const key of Object.keys(envelope.properties ?? {})) {
|
|
200
|
+
if (reservedKeys.has(key)) errors.push(`properties.${key} is reserved`);
|
|
201
|
+
}
|
|
202
|
+
return { ok: errors.length === 0, errors };
|
|
203
|
+
}
|
|
204
|
+
|
|
205
|
+
// src/core/environment.ts
|
|
206
|
+
function getBrowserWindow() {
|
|
207
|
+
return typeof window === "undefined" ? void 0 : window;
|
|
208
|
+
}
|
|
209
|
+
|
|
210
|
+
// src/core/privacy.ts
|
|
211
|
+
var sensitiveKeys = /* @__PURE__ */ new Set([
|
|
212
|
+
"email",
|
|
213
|
+
"phone",
|
|
214
|
+
"mobile",
|
|
215
|
+
"address",
|
|
216
|
+
"address1",
|
|
217
|
+
"address2",
|
|
218
|
+
"first_name",
|
|
219
|
+
"last_name",
|
|
220
|
+
"name",
|
|
221
|
+
"token",
|
|
222
|
+
"secret",
|
|
223
|
+
"password",
|
|
224
|
+
"session",
|
|
225
|
+
"cookie"
|
|
226
|
+
]);
|
|
227
|
+
function redactUrl(url, allowQueryKeys = ["utm_source", "utm_medium", "utm_campaign", "utm_term", "utm_content"]) {
|
|
228
|
+
const parsed = new URL(url, "https://placeholder.local");
|
|
229
|
+
for (const key of Array.from(parsed.searchParams.keys())) {
|
|
230
|
+
if (!allowQueryKeys.includes(key)) {
|
|
231
|
+
parsed.searchParams.set(key, "[REDACTED]");
|
|
232
|
+
}
|
|
233
|
+
}
|
|
234
|
+
return url.startsWith("http") ? parsed.toString() : `${parsed.pathname}${parsed.search}`;
|
|
235
|
+
}
|
|
236
|
+
function sanitizeValue(value, allow, path = []) {
|
|
237
|
+
if (Array.isArray(value)) {
|
|
238
|
+
return value.map((item) => sanitizeValue(item, allow, path));
|
|
239
|
+
}
|
|
240
|
+
if (value && typeof value === "object") {
|
|
241
|
+
return Object.fromEntries(
|
|
242
|
+
Object.entries(value).filter(([key]) => {
|
|
243
|
+
const lowerKey = key.toLowerCase();
|
|
244
|
+
const lowerPath = path.map((item) => item.toLowerCase());
|
|
245
|
+
const isEcommerceItemName = lowerKey === "name" && lowerPath.includes("ecommerce") && lowerPath.includes("items");
|
|
246
|
+
return isEcommerceItemName || !sensitiveKeys.has(lowerKey) || allow.has(lowerKey);
|
|
247
|
+
}).map(([key, nestedValue]) => [key, sanitizeValue(nestedValue, allow, [...path, key])])
|
|
248
|
+
);
|
|
249
|
+
}
|
|
250
|
+
return value;
|
|
251
|
+
}
|
|
252
|
+
function sanitizeProperties(input, allowRawKeys = []) {
|
|
253
|
+
const allow = new Set(allowRawKeys.map((key) => key.toLowerCase()));
|
|
254
|
+
return sanitizeValue(input, allow);
|
|
255
|
+
}
|
|
256
|
+
|
|
257
|
+
// src/browser/core/attribute-persistence.ts
|
|
258
|
+
var DMD_ATTRIBUTES_STORAGE_KEY = "dmd_attributes";
|
|
259
|
+
var SESSION_STORAGE_KEY = "sessionData";
|
|
260
|
+
var SESSION_ID_KEY = "sessionId";
|
|
261
|
+
var SESSION_TIMESTAMP_KEY = "timestamp";
|
|
262
|
+
function isBlankValue(value) {
|
|
263
|
+
return value === null || value === void 0 || typeof value === "string" && value.trim() === "";
|
|
264
|
+
}
|
|
265
|
+
function readAttributes(base) {
|
|
266
|
+
const raw = base.getItem(DMD_ATTRIBUTES_STORAGE_KEY);
|
|
267
|
+
if (!raw) return {};
|
|
268
|
+
try {
|
|
269
|
+
const parsed = JSON.parse(raw);
|
|
270
|
+
return parsed && typeof parsed === "object" && !Array.isArray(parsed) ? parsed : {};
|
|
271
|
+
} catch {
|
|
272
|
+
base.removeItem(DMD_ATTRIBUTES_STORAGE_KEY);
|
|
273
|
+
return {};
|
|
274
|
+
}
|
|
275
|
+
}
|
|
276
|
+
function sanitizeAttributes(attributes) {
|
|
277
|
+
return Object.fromEntries(Object.entries(attributes).filter(([, value]) => !isBlankValue(value)));
|
|
278
|
+
}
|
|
279
|
+
function writeAttributes(base, attributes) {
|
|
280
|
+
const sanitized = sanitizeAttributes(attributes);
|
|
281
|
+
if (Object.keys(sanitized).length === 0) {
|
|
282
|
+
base.removeItem(DMD_ATTRIBUTES_STORAGE_KEY);
|
|
283
|
+
return;
|
|
284
|
+
}
|
|
285
|
+
base.setItem(DMD_ATTRIBUTES_STORAGE_KEY, JSON.stringify(sanitized));
|
|
286
|
+
}
|
|
287
|
+
function parseSessionData(value) {
|
|
288
|
+
try {
|
|
289
|
+
const parsed = JSON.parse(value);
|
|
290
|
+
const sessionData = {};
|
|
291
|
+
const sessionId = typeof parsed.sessionId === "string" && parsed.sessionId.trim() !== "" ? parsed.sessionId : void 0;
|
|
292
|
+
const timestamp = typeof parsed.timestamp === "number" ? parsed.timestamp : void 0;
|
|
293
|
+
if (sessionId !== void 0) sessionData.sessionId = sessionId;
|
|
294
|
+
if (timestamp !== void 0) sessionData.timestamp = timestamp;
|
|
295
|
+
return sessionData;
|
|
296
|
+
} catch {
|
|
297
|
+
return {};
|
|
298
|
+
}
|
|
299
|
+
}
|
|
300
|
+
function getAggregateValue(attributes, key) {
|
|
301
|
+
if (key === SESSION_STORAGE_KEY) {
|
|
302
|
+
const sessionId = attributes[SESSION_ID_KEY];
|
|
303
|
+
const timestamp = attributes[SESSION_TIMESTAMP_KEY];
|
|
304
|
+
if (typeof sessionId === "string" && !isBlankValue(sessionId) && typeof timestamp === "number") {
|
|
305
|
+
return JSON.stringify({ sessionId, timestamp });
|
|
306
|
+
}
|
|
307
|
+
return null;
|
|
308
|
+
}
|
|
309
|
+
const value = attributes[key];
|
|
310
|
+
if (isBlankValue(value)) return null;
|
|
311
|
+
return typeof value === "string" ? value : JSON.stringify(value);
|
|
312
|
+
}
|
|
313
|
+
function setAggregateValue(attributes, key, value) {
|
|
314
|
+
if (key === SESSION_STORAGE_KEY) {
|
|
315
|
+
const sessionData = parseSessionData(value);
|
|
316
|
+
if (sessionData.sessionId === void 0 || sessionData.timestamp === void 0) {
|
|
317
|
+
delete attributes[SESSION_ID_KEY];
|
|
318
|
+
delete attributes[SESSION_TIMESTAMP_KEY];
|
|
319
|
+
return;
|
|
320
|
+
}
|
|
321
|
+
attributes[SESSION_ID_KEY] = sessionData.sessionId;
|
|
322
|
+
attributes[SESSION_TIMESTAMP_KEY] = sessionData.timestamp;
|
|
323
|
+
return;
|
|
324
|
+
}
|
|
325
|
+
attributes[key] = value;
|
|
326
|
+
}
|
|
327
|
+
function removeAggregateValue(attributes, key) {
|
|
328
|
+
if (key === SESSION_STORAGE_KEY) {
|
|
329
|
+
delete attributes[SESSION_ID_KEY];
|
|
330
|
+
delete attributes[SESSION_TIMESTAMP_KEY];
|
|
331
|
+
return;
|
|
332
|
+
}
|
|
333
|
+
delete attributes[key];
|
|
334
|
+
}
|
|
335
|
+
function createDmdAttributesPersistence(base) {
|
|
336
|
+
return {
|
|
337
|
+
getItem(key) {
|
|
338
|
+
if (key === DMD_ATTRIBUTES_STORAGE_KEY) return base.getItem(key);
|
|
339
|
+
const attributes = readAttributes(base);
|
|
340
|
+
const aggregateValue = getAggregateValue(attributes, key);
|
|
341
|
+
if (aggregateValue !== null) return aggregateValue;
|
|
342
|
+
const legacyValue = base.getItem(key);
|
|
343
|
+
if (isBlankValue(legacyValue)) return null;
|
|
344
|
+
setAggregateValue(attributes, key, String(legacyValue));
|
|
345
|
+
writeAttributes(base, attributes);
|
|
346
|
+
return legacyValue;
|
|
347
|
+
},
|
|
348
|
+
setItem(key, value) {
|
|
349
|
+
if (key === DMD_ATTRIBUTES_STORAGE_KEY) return base.setItem(key, value);
|
|
350
|
+
const attributes = readAttributes(base);
|
|
351
|
+
if (isBlankValue(value)) {
|
|
352
|
+
removeAggregateValue(attributes, key);
|
|
353
|
+
writeAttributes(base, attributes);
|
|
354
|
+
base.removeItem(key);
|
|
355
|
+
return true;
|
|
356
|
+
}
|
|
357
|
+
setAggregateValue(attributes, key, value);
|
|
358
|
+
writeAttributes(base, attributes);
|
|
359
|
+
base.setItem(key, value);
|
|
360
|
+
return true;
|
|
361
|
+
},
|
|
362
|
+
removeItem(key) {
|
|
363
|
+
if (key === DMD_ATTRIBUTES_STORAGE_KEY) {
|
|
364
|
+
base.removeItem(key);
|
|
365
|
+
return;
|
|
366
|
+
}
|
|
367
|
+
const attributes = readAttributes(base);
|
|
368
|
+
removeAggregateValue(attributes, key);
|
|
369
|
+
writeAttributes(base, attributes);
|
|
370
|
+
base.removeItem(key);
|
|
371
|
+
},
|
|
372
|
+
getHealth() {
|
|
373
|
+
return base.getHealth();
|
|
374
|
+
}
|
|
375
|
+
};
|
|
376
|
+
}
|
|
377
|
+
|
|
378
|
+
// src/core/attribution.ts
|
|
379
|
+
var dmdUtmKeys = [
|
|
380
|
+
"utm_source",
|
|
381
|
+
"utm_medium",
|
|
382
|
+
"utm_campaign",
|
|
383
|
+
"utm_term",
|
|
384
|
+
"utm_content",
|
|
385
|
+
"utm_id"
|
|
386
|
+
];
|
|
387
|
+
var dmdCampaignKeys = ["campaign_id", "ad_id"];
|
|
388
|
+
var dmdClickIdSources = [
|
|
389
|
+
["gclid", 2],
|
|
390
|
+
["fbclid", 3],
|
|
391
|
+
["ScCid", 1],
|
|
392
|
+
["li_fat_id", 4]
|
|
393
|
+
];
|
|
394
|
+
function cleanAttributionRecord(record) {
|
|
395
|
+
const cleaned = Object.fromEntries(
|
|
396
|
+
Object.entries(record).filter(([, value]) => value !== null && value !== void 0 && value !== "")
|
|
397
|
+
);
|
|
398
|
+
return Object.keys(cleaned).length > 0 ? cleaned : void 0;
|
|
399
|
+
}
|
|
400
|
+
function objectValue(value) {
|
|
401
|
+
return value && typeof value === "object" && !Array.isArray(value) ? value : void 0;
|
|
402
|
+
}
|
|
403
|
+
function mergeAttributionRecords(explicitProperties, stored) {
|
|
404
|
+
const attributionData = objectValue(explicitProperties.attributionData);
|
|
405
|
+
const utmParameter = objectValue(explicitProperties.utmParameter);
|
|
406
|
+
return {
|
|
407
|
+
...explicitProperties,
|
|
408
|
+
...stored.attributionData || attributionData ? { attributionData: { ...stored.attributionData ?? {}, ...attributionData ?? {} } } : {},
|
|
409
|
+
...stored.utmParameter || utmParameter ? { utmParameter: { ...stored.utmParameter ?? {}, ...utmParameter ?? {} } } : {}
|
|
410
|
+
};
|
|
411
|
+
}
|
|
412
|
+
|
|
413
|
+
// src/browser/core/attribution.ts
|
|
414
|
+
var DMD_CLICK_ID_QUERY_KEY = "click_id";
|
|
415
|
+
var DMD_CLICK_ID_LEGACY_QUERY_KEY = "dmd_click_id";
|
|
416
|
+
var DMD_CLICK_ID_STORAGE_KEY = "dmd_click_id";
|
|
417
|
+
var DMD_CLICK_ID_ATTRIBUTE_KEY = "click_id";
|
|
418
|
+
function getCurrentUrl() {
|
|
419
|
+
return getBrowserWindow()?.location?.href;
|
|
420
|
+
}
|
|
421
|
+
function getCookie(name) {
|
|
422
|
+
const cookie = getBrowserWindow()?.document?.cookie;
|
|
423
|
+
if (!cookie) return void 0;
|
|
424
|
+
const escapedName = name.replace(/[.*+?^${}()|[\]\\]/g, "\\$&");
|
|
425
|
+
const match = new RegExp(`(?:^|; )${escapedName}=([^;]*)`).exec(cookie);
|
|
426
|
+
return match ? decodeURIComponent(match[1] ?? "") : void 0;
|
|
427
|
+
}
|
|
428
|
+
function getParams(url) {
|
|
429
|
+
return new URL(url, "https://placeholder.local").searchParams;
|
|
430
|
+
}
|
|
431
|
+
function setIfPresent(persistence, key, value) {
|
|
432
|
+
if (value !== null && value !== "") {
|
|
433
|
+
persistence.setItem(key, value);
|
|
434
|
+
}
|
|
435
|
+
}
|
|
436
|
+
function getClickIdParam(params) {
|
|
437
|
+
return params.get(DMD_CLICK_ID_LEGACY_QUERY_KEY) || params.get(DMD_CLICK_ID_QUERY_KEY);
|
|
438
|
+
}
|
|
439
|
+
function getStoredString(persistence, key) {
|
|
440
|
+
const value = persistence.getItem(key);
|
|
441
|
+
return value === null || value === "" ? void 0 : value;
|
|
442
|
+
}
|
|
443
|
+
function getStoredNumberOrString(persistence, key) {
|
|
444
|
+
const value = getStoredString(persistence, key);
|
|
445
|
+
if (value === void 0) return void 0;
|
|
446
|
+
const parsed = Number.parseInt(value, 10);
|
|
447
|
+
return Number.isNaN(parsed) ? value : parsed;
|
|
448
|
+
}
|
|
449
|
+
function captureAttributionFromUrl(persistence, url = getCurrentUrl()) {
|
|
450
|
+
if (!url) return;
|
|
451
|
+
const params = getParams(url);
|
|
452
|
+
for (const key of dmdUtmKeys) {
|
|
453
|
+
setIfPresent(persistence, key, params.get(key));
|
|
454
|
+
}
|
|
455
|
+
for (const key of dmdCampaignKeys) {
|
|
456
|
+
setIfPresent(persistence, key, params.get(key));
|
|
457
|
+
}
|
|
458
|
+
const clickId = getClickIdParam(params);
|
|
459
|
+
setIfPresent(persistence, DMD_CLICK_ID_ATTRIBUTE_KEY, clickId);
|
|
460
|
+
setIfPresent(persistence, DMD_CLICK_ID_STORAGE_KEY, clickId);
|
|
461
|
+
for (const [param, sdkPubId] of dmdClickIdSources) {
|
|
462
|
+
const value = params.get(param);
|
|
463
|
+
if (value) {
|
|
464
|
+
persistence.setItem("unique_id", value);
|
|
465
|
+
persistence.setItem("sdk_pub_id", String(sdkPubId));
|
|
466
|
+
}
|
|
467
|
+
}
|
|
468
|
+
}
|
|
469
|
+
function getStoredAttributionData(persistence) {
|
|
470
|
+
return cleanAttributionRecord({
|
|
471
|
+
unique_id: getStoredString(persistence, "unique_id"),
|
|
472
|
+
sdk_pub_id: getStoredNumberOrString(persistence, "sdk_pub_id"),
|
|
473
|
+
fbc: getStoredString(persistence, "fbc") ?? getCookie("_fbc"),
|
|
474
|
+
fbp: getStoredString(persistence, "fbp") ?? getCookie("_fbp"),
|
|
475
|
+
campaign_id: getStoredString(persistence, "campaign_id"),
|
|
476
|
+
ad_id: getStoredString(persistence, "ad_id"),
|
|
477
|
+
click_id: getStoredString(persistence, DMD_CLICK_ID_STORAGE_KEY) ?? getStoredString(persistence, DMD_CLICK_ID_ATTRIBUTE_KEY)
|
|
478
|
+
});
|
|
479
|
+
}
|
|
480
|
+
function getStoredUtmParameter(persistence) {
|
|
481
|
+
return cleanAttributionRecord(Object.fromEntries(dmdUtmKeys.map((key) => [key, getStoredString(persistence, key)])));
|
|
482
|
+
}
|
|
483
|
+
function mergeStoredAttribution(properties, persistence) {
|
|
484
|
+
const stored = {};
|
|
485
|
+
const attributionData = getStoredAttributionData(persistence);
|
|
486
|
+
const utmParameter = getStoredUtmParameter(persistence);
|
|
487
|
+
if (attributionData !== void 0) stored.attributionData = attributionData;
|
|
488
|
+
if (utmParameter !== void 0) stored.utmParameter = utmParameter;
|
|
489
|
+
return mergeAttributionRecords(properties, stored);
|
|
490
|
+
}
|
|
491
|
+
|
|
492
|
+
// src/browser/core/autocapture.ts
|
|
493
|
+
function installAutocapture(config) {
|
|
494
|
+
const trackedPageUrls = /* @__PURE__ */ new Set();
|
|
495
|
+
const timers = /* @__PURE__ */ new Set();
|
|
496
|
+
const pageviewDelayMs = config.pageviewDelayMs ?? 500;
|
|
497
|
+
const history = config.browserWindow.history;
|
|
498
|
+
const originalPushState = history?.pushState;
|
|
499
|
+
const originalReplaceState = history?.replaceState;
|
|
500
|
+
function clearTimer(timer) {
|
|
501
|
+
timers.delete(timer);
|
|
502
|
+
clearTimeout(timer);
|
|
503
|
+
}
|
|
504
|
+
function canonicalUrl() {
|
|
505
|
+
return config.browserWindow.location.href;
|
|
506
|
+
}
|
|
507
|
+
function trackCurrentPageview() {
|
|
508
|
+
if (!config.capturePageview) return;
|
|
509
|
+
const url = canonicalUrl();
|
|
510
|
+
if (trackedPageUrls.has(url)) return;
|
|
511
|
+
trackedPageUrls.add(url);
|
|
512
|
+
config.onPageView();
|
|
513
|
+
}
|
|
514
|
+
function schedulePageview(delayMs) {
|
|
515
|
+
if (!config.capturePageview) return;
|
|
516
|
+
const timer = setTimeout(() => {
|
|
517
|
+
timers.delete(timer);
|
|
518
|
+
trackCurrentPageview();
|
|
519
|
+
}, delayMs);
|
|
520
|
+
timers.add(timer);
|
|
521
|
+
}
|
|
522
|
+
function handleRouteChange() {
|
|
523
|
+
config.onRouteChange?.();
|
|
524
|
+
trackCurrentPageview();
|
|
525
|
+
}
|
|
526
|
+
function wrapHistoryMethod(method) {
|
|
527
|
+
if (!history) return;
|
|
528
|
+
const original = history[method];
|
|
529
|
+
if (typeof original !== "function") return;
|
|
530
|
+
history[method] = function wrappedHistoryMethod(...args) {
|
|
531
|
+
const result = original.apply(this, args);
|
|
532
|
+
const timer = setTimeout(() => {
|
|
533
|
+
timers.delete(timer);
|
|
534
|
+
handleRouteChange();
|
|
535
|
+
}, 0);
|
|
536
|
+
timers.add(timer);
|
|
537
|
+
return result;
|
|
538
|
+
};
|
|
539
|
+
}
|
|
540
|
+
function handlePopOrHashChange() {
|
|
541
|
+
handleRouteChange();
|
|
542
|
+
}
|
|
543
|
+
function handlePageLeave() {
|
|
544
|
+
if (config.capturePageleave) {
|
|
545
|
+
config.onPageLeave();
|
|
546
|
+
}
|
|
547
|
+
}
|
|
548
|
+
schedulePageview(pageviewDelayMs);
|
|
549
|
+
wrapHistoryMethod("pushState");
|
|
550
|
+
wrapHistoryMethod("replaceState");
|
|
551
|
+
const canListen = typeof config.browserWindow.addEventListener === "function" && typeof config.browserWindow.removeEventListener === "function";
|
|
552
|
+
if (canListen) {
|
|
553
|
+
config.browserWindow.addEventListener("popstate", handlePopOrHashChange);
|
|
554
|
+
config.browserWindow.addEventListener("hashchange", handlePopOrHashChange);
|
|
555
|
+
config.browserWindow.addEventListener("beforeunload", handlePageLeave);
|
|
556
|
+
}
|
|
557
|
+
return {
|
|
558
|
+
cleanup() {
|
|
559
|
+
for (const timer of Array.from(timers)) {
|
|
560
|
+
clearTimer(timer);
|
|
561
|
+
}
|
|
562
|
+
if (history && originalPushState) history.pushState = originalPushState;
|
|
563
|
+
if (history && originalReplaceState) history.replaceState = originalReplaceState;
|
|
564
|
+
if (canListen) {
|
|
565
|
+
config.browserWindow.removeEventListener("popstate", handlePopOrHashChange);
|
|
566
|
+
config.browserWindow.removeEventListener("hashchange", handlePopOrHashChange);
|
|
567
|
+
config.browserWindow.removeEventListener("beforeunload", handlePageLeave);
|
|
568
|
+
}
|
|
569
|
+
}
|
|
570
|
+
};
|
|
571
|
+
}
|
|
572
|
+
|
|
573
|
+
// src/core/payload-size.ts
|
|
574
|
+
var preserveStringKeys = /* @__PURE__ */ new Set([
|
|
575
|
+
"requestId",
|
|
576
|
+
"eventType",
|
|
577
|
+
"requestFrom",
|
|
578
|
+
"clientId",
|
|
579
|
+
"workspaceId",
|
|
580
|
+
"anonymousId",
|
|
581
|
+
"sessionId",
|
|
582
|
+
"token"
|
|
583
|
+
]);
|
|
584
|
+
function payloadByteLength(payload) {
|
|
585
|
+
const serialized = JSON.stringify(payload);
|
|
586
|
+
if (typeof TextEncoder !== "undefined") {
|
|
587
|
+
return new TextEncoder().encode(serialized).length;
|
|
588
|
+
}
|
|
589
|
+
return serialized.length;
|
|
590
|
+
}
|
|
591
|
+
function clonePayload(payload) {
|
|
592
|
+
try {
|
|
593
|
+
return JSON.parse(JSON.stringify(payload));
|
|
594
|
+
} catch {
|
|
595
|
+
return void 0;
|
|
596
|
+
}
|
|
597
|
+
}
|
|
598
|
+
function truncateValue(value, truncateStringLength, key) {
|
|
599
|
+
if (typeof value === "string") {
|
|
600
|
+
if (key && preserveStringKeys.has(key)) return value;
|
|
601
|
+
if (value.length <= truncateStringLength) return value;
|
|
602
|
+
return `${value.slice(0, truncateStringLength)}...[TRUNCATED]`;
|
|
603
|
+
}
|
|
604
|
+
if (Array.isArray(value)) {
|
|
605
|
+
return value.map((item) => truncateValue(item, truncateStringLength));
|
|
606
|
+
}
|
|
607
|
+
if (value && typeof value === "object") {
|
|
608
|
+
return Object.fromEntries(
|
|
609
|
+
Object.entries(value).map(([childKey, childValue]) => [
|
|
610
|
+
childKey,
|
|
611
|
+
truncateValue(childValue, truncateStringLength, childKey)
|
|
612
|
+
])
|
|
613
|
+
);
|
|
614
|
+
}
|
|
615
|
+
return value;
|
|
616
|
+
}
|
|
617
|
+
function markPayloadTruncated(payload) {
|
|
618
|
+
if (payload.metaData && typeof payload.metaData === "object" && !Array.isArray(payload.metaData)) {
|
|
619
|
+
return {
|
|
620
|
+
...payload,
|
|
621
|
+
metaData: {
|
|
622
|
+
...payload.metaData,
|
|
623
|
+
payloadTruncated: true
|
|
624
|
+
}
|
|
625
|
+
};
|
|
626
|
+
}
|
|
627
|
+
return {
|
|
628
|
+
...payload,
|
|
629
|
+
payloadTruncated: true
|
|
630
|
+
};
|
|
631
|
+
}
|
|
632
|
+
function truncatePayload(payload, truncateStringLength) {
|
|
633
|
+
const cloned = clonePayload(payload);
|
|
634
|
+
if (!cloned) return void 0;
|
|
635
|
+
return markPayloadTruncated(truncateValue(cloned, truncateStringLength));
|
|
636
|
+
}
|
|
637
|
+
function getPayloadMessageId(payload) {
|
|
638
|
+
const value = payload.metaData?.requestId ?? payload.messageId;
|
|
639
|
+
return value === void 0 ? void 0 : String(value);
|
|
640
|
+
}
|
|
641
|
+
function preparePayloadForSizePolicy(payload, options = {}) {
|
|
642
|
+
const maxPayloadBytes = options.maxPayloadBytes ?? 64e3;
|
|
643
|
+
const payloadSizePolicy = options.payloadSizePolicy ?? "drop";
|
|
644
|
+
const payloadTruncateStringLength = options.payloadTruncateStringLength ?? 1024;
|
|
645
|
+
if (payloadByteLength(payload) <= maxPayloadBytes) {
|
|
646
|
+
return { ok: true, payload, truncated: false };
|
|
647
|
+
}
|
|
648
|
+
if (payloadSizePolicy === "truncate") {
|
|
649
|
+
const truncatedPayload = truncatePayload(payload, payloadTruncateStringLength);
|
|
650
|
+
if (truncatedPayload && payloadByteLength(truncatedPayload) <= maxPayloadBytes) {
|
|
651
|
+
return { ok: true, payload: truncatedPayload, truncated: true };
|
|
652
|
+
}
|
|
653
|
+
}
|
|
654
|
+
const messageId = getPayloadMessageId(payload);
|
|
655
|
+
return messageId === void 0 ? { ok: false, reason: "payload_too_large" } : { ok: false, reason: "payload_too_large", messageId };
|
|
656
|
+
}
|
|
657
|
+
|
|
101
658
|
// src/browser/core/delivery.ts
|
|
102
659
|
function createId(prefix) {
|
|
103
660
|
return `${prefix}_${Math.random().toString(36).slice(2)}${Date.now().toString(36)}`;
|
|
@@ -129,7 +686,6 @@ function createDeliveryManager(config) {
|
|
|
129
686
|
const lockTtlMs = config.lockTtlMs ?? 5e3;
|
|
130
687
|
const tabId = config.tabId ?? createId("tab");
|
|
131
688
|
const batchSize = config.batchSize ?? 25;
|
|
132
|
-
const maxPayloadBytes = config.maxPayloadBytes ?? 64e3;
|
|
133
689
|
function recordDrop(event) {
|
|
134
690
|
diagnostics.dropped.push(event);
|
|
135
691
|
config.onDrop?.(event);
|
|
@@ -138,12 +694,22 @@ function createDeliveryManager(config) {
|
|
|
138
694
|
diagnostics.lastError = error.message;
|
|
139
695
|
config.onError?.(error);
|
|
140
696
|
}
|
|
141
|
-
function
|
|
142
|
-
const
|
|
143
|
-
if (
|
|
144
|
-
|
|
697
|
+
function preparePayloadForSend(payload) {
|
|
698
|
+
const sizePolicyOptions = {};
|
|
699
|
+
if (config.maxPayloadBytes !== void 0) sizePolicyOptions.maxPayloadBytes = config.maxPayloadBytes;
|
|
700
|
+
if (config.payloadSizePolicy !== void 0) sizePolicyOptions.payloadSizePolicy = config.payloadSizePolicy;
|
|
701
|
+
if (config.payloadTruncateStringLength !== void 0) {
|
|
702
|
+
sizePolicyOptions.payloadTruncateStringLength = config.payloadTruncateStringLength;
|
|
145
703
|
}
|
|
146
|
-
|
|
704
|
+
const prepared = preparePayloadForSizePolicy(payload, sizePolicyOptions);
|
|
705
|
+
if (prepared.ok) return prepared.payload;
|
|
706
|
+
const diagnostic = {
|
|
707
|
+
reason: prepared.reason,
|
|
708
|
+
timestamp: (/* @__PURE__ */ new Date()).toISOString()
|
|
709
|
+
};
|
|
710
|
+
if (prepared.messageId !== void 0) diagnostic.messageId = prepared.messageId;
|
|
711
|
+
recordDrop(diagnostic);
|
|
712
|
+
return void 0;
|
|
147
713
|
}
|
|
148
714
|
function recordStorageUnavailable() {
|
|
149
715
|
recordDrop({
|
|
@@ -233,7 +799,19 @@ function createDeliveryManager(config) {
|
|
|
233
799
|
idempotencyKey: String(payload.idempotencyKey ?? createIdempotencyKey(payload, messageId))
|
|
234
800
|
};
|
|
235
801
|
}
|
|
802
|
+
function tryBeacon(body) {
|
|
803
|
+
if (!config.useBeacon) return false;
|
|
804
|
+
const sendBeacon = globalThis.navigator?.sendBeacon;
|
|
805
|
+
if (typeof sendBeacon !== "function") return false;
|
|
806
|
+
try {
|
|
807
|
+
const blob = new Blob([JSON.stringify(body)], { type: "application/json" });
|
|
808
|
+
return sendBeacon.call(globalThis.navigator, config.endpoint, blob);
|
|
809
|
+
} catch {
|
|
810
|
+
return false;
|
|
811
|
+
}
|
|
812
|
+
}
|
|
236
813
|
async function deliver(body) {
|
|
814
|
+
if (tryBeacon(body)) return;
|
|
237
815
|
const fetchImpl = config.fetch ?? globalThis.fetch;
|
|
238
816
|
if (typeof fetchImpl !== "function") {
|
|
239
817
|
throw new Error("fetch_unavailable");
|
|
@@ -250,26 +828,22 @@ function createDeliveryManager(config) {
|
|
|
250
828
|
return {
|
|
251
829
|
async send(payload) {
|
|
252
830
|
const body = withEnvelope(payload);
|
|
253
|
-
|
|
254
|
-
|
|
255
|
-
messageId: String(body.metaData?.requestId ?? body.messageId),
|
|
256
|
-
reason: "payload_too_large",
|
|
257
|
-
timestamp: (/* @__PURE__ */ new Date()).toISOString()
|
|
258
|
-
});
|
|
831
|
+
const preparedBody = preparePayloadForSend(body);
|
|
832
|
+
if (!preparedBody) {
|
|
259
833
|
return;
|
|
260
834
|
}
|
|
261
835
|
diagnostics.inFlight += 1;
|
|
262
836
|
try {
|
|
263
|
-
await deliver(
|
|
837
|
+
await deliver(preparedBody);
|
|
264
838
|
} catch (error) {
|
|
265
839
|
const deliveryError = error instanceof Error ? error : new Error(String(error));
|
|
266
840
|
recordError(deliveryError);
|
|
267
841
|
enqueue({
|
|
268
|
-
messageId: String(body
|
|
842
|
+
messageId: String(getPayloadMessageId(body)),
|
|
269
843
|
savedAt: Date.now(),
|
|
270
844
|
attempts: 1,
|
|
271
845
|
lastError: deliveryError.message,
|
|
272
|
-
payload:
|
|
846
|
+
payload: preparedBody
|
|
273
847
|
});
|
|
274
848
|
} finally {
|
|
275
849
|
diagnostics.inFlight -= 1;
|
|
@@ -382,60 +956,286 @@ function createDeliveryManager(config) {
|
|
|
382
956
|
};
|
|
383
957
|
}
|
|
384
958
|
|
|
385
|
-
// src/browser/core/
|
|
386
|
-
var
|
|
387
|
-
|
|
388
|
-
|
|
389
|
-
|
|
390
|
-
|
|
391
|
-
|
|
392
|
-
|
|
393
|
-
|
|
394
|
-
|
|
395
|
-
"name",
|
|
396
|
-
"token",
|
|
397
|
-
"secret",
|
|
398
|
-
"password",
|
|
399
|
-
"session",
|
|
400
|
-
"cookie"
|
|
401
|
-
]);
|
|
402
|
-
function sanitizeValue(value, allow) {
|
|
403
|
-
if (Array.isArray(value)) {
|
|
404
|
-
return value.map((item) => sanitizeValue(item, allow));
|
|
959
|
+
// src/browser/core/identity.ts
|
|
960
|
+
var ANONYMOUS_ID_STORAGE_KEY = "dmd_anonymous_id";
|
|
961
|
+
var LEGACY_ANONYMOUS_ID_STORAGE_KEY = "anonymousId";
|
|
962
|
+
function getUrlParam(name) {
|
|
963
|
+
const href = getBrowserWindow()?.location?.href;
|
|
964
|
+
if (!href) return null;
|
|
965
|
+
try {
|
|
966
|
+
return new URL(href).searchParams.get(name);
|
|
967
|
+
} catch {
|
|
968
|
+
return null;
|
|
405
969
|
}
|
|
406
|
-
|
|
407
|
-
|
|
408
|
-
|
|
409
|
-
|
|
970
|
+
}
|
|
971
|
+
function resolveAnonymousId(persistence) {
|
|
972
|
+
const urlAnonymousId = getUrlParam("aid");
|
|
973
|
+
if (isUuid(urlAnonymousId)) {
|
|
974
|
+
persistence.setItem(ANONYMOUS_ID_STORAGE_KEY, urlAnonymousId);
|
|
975
|
+
return urlAnonymousId;
|
|
410
976
|
}
|
|
411
|
-
|
|
977
|
+
const storedAnonymousId = persistence.getItem(ANONYMOUS_ID_STORAGE_KEY);
|
|
978
|
+
if (isUuid(storedAnonymousId)) {
|
|
979
|
+
return storedAnonymousId;
|
|
980
|
+
}
|
|
981
|
+
const legacyAnonymousId = persistence.getItem(LEGACY_ANONYMOUS_ID_STORAGE_KEY);
|
|
982
|
+
if (isUuid(legacyAnonymousId)) {
|
|
983
|
+
persistence.setItem(ANONYMOUS_ID_STORAGE_KEY, legacyAnonymousId);
|
|
984
|
+
return legacyAnonymousId;
|
|
985
|
+
}
|
|
986
|
+
const anonymousId = createUuid();
|
|
987
|
+
persistence.setItem(ANONYMOUS_ID_STORAGE_KEY, anonymousId);
|
|
988
|
+
return anonymousId;
|
|
412
989
|
}
|
|
413
|
-
function
|
|
414
|
-
const
|
|
415
|
-
|
|
990
|
+
function resetAnonymousId(persistence) {
|
|
991
|
+
const anonymousId = createUuid();
|
|
992
|
+
persistence.setItem(ANONYMOUS_ID_STORAGE_KEY, anonymousId);
|
|
993
|
+
return anonymousId;
|
|
416
994
|
}
|
|
417
995
|
|
|
418
|
-
// src/browser/core/
|
|
419
|
-
|
|
420
|
-
|
|
421
|
-
|
|
422
|
-
|
|
423
|
-
|
|
424
|
-
|
|
425
|
-
|
|
996
|
+
// src/browser/core/page-context.ts
|
|
997
|
+
function redactSearch(search) {
|
|
998
|
+
const redacted = redactUrl(search);
|
|
999
|
+
return redacted.startsWith("/?") ? redacted.slice(1) : redacted;
|
|
1000
|
+
}
|
|
1001
|
+
function getBrowserPageContext() {
|
|
1002
|
+
const browserWindow = getBrowserWindow();
|
|
1003
|
+
const documentRef = browserWindow?.document ?? globalThis.document;
|
|
1004
|
+
const location = browserWindow?.location;
|
|
1005
|
+
const page2 = {};
|
|
1006
|
+
if (location?.href) page2.url = location.href;
|
|
1007
|
+
if (location?.pathname) page2.path = location.pathname;
|
|
1008
|
+
if (location?.search) page2.search = redactSearch(location.search);
|
|
1009
|
+
if (documentRef?.title) page2.title = documentRef.title;
|
|
1010
|
+
if (documentRef?.referrer) page2.referrer = redactUrl(documentRef.referrer);
|
|
1011
|
+
return page2;
|
|
1012
|
+
}
|
|
1013
|
+
|
|
1014
|
+
// src/browser/core/persistence.ts
|
|
1015
|
+
function createPersistenceHealth(requested) {
|
|
1016
|
+
return {
|
|
1017
|
+
requested,
|
|
1018
|
+
cookieFallbackUsed: false,
|
|
1019
|
+
memoryFallbackUsed: requested === "memory",
|
|
1020
|
+
failures: []
|
|
1021
|
+
};
|
|
1022
|
+
}
|
|
1023
|
+
function recordFailure(health, backend, operation, error) {
|
|
1024
|
+
health.failures.push({
|
|
1025
|
+
backend,
|
|
1026
|
+
operation,
|
|
1027
|
+
message: error instanceof Error ? error.message : String(error)
|
|
1028
|
+
});
|
|
1029
|
+
if (health.failures.length > 25) {
|
|
1030
|
+
health.failures.shift();
|
|
426
1031
|
}
|
|
427
|
-
|
|
428
|
-
|
|
429
|
-
|
|
430
|
-
|
|
1032
|
+
}
|
|
1033
|
+
function createMemoryPersistence(health = createPersistenceHealth("memory")) {
|
|
1034
|
+
const memory = {};
|
|
1035
|
+
return {
|
|
1036
|
+
getItem(key) {
|
|
1037
|
+
return Object.prototype.hasOwnProperty.call(memory, key) ? memory[key] ?? null : null;
|
|
1038
|
+
},
|
|
1039
|
+
setItem(key, value) {
|
|
1040
|
+
memory[key] = value;
|
|
1041
|
+
return true;
|
|
1042
|
+
},
|
|
1043
|
+
removeItem(key) {
|
|
1044
|
+
delete memory[key];
|
|
1045
|
+
},
|
|
1046
|
+
getHealth() {
|
|
1047
|
+
return {
|
|
1048
|
+
...health,
|
|
1049
|
+
failures: health.failures.map((failure) => ({ ...failure }))
|
|
1050
|
+
};
|
|
1051
|
+
}
|
|
1052
|
+
};
|
|
1053
|
+
}
|
|
1054
|
+
function getCookie2(name) {
|
|
1055
|
+
const browserWindow = getBrowserWindow();
|
|
1056
|
+
const cookie = browserWindow?.document?.cookie;
|
|
1057
|
+
if (!cookie) return null;
|
|
1058
|
+
const escapedName = name.replace(/[.*+?^${}()|[\]\\]/g, "\\$&");
|
|
1059
|
+
const match = new RegExp(`(?:^|; )${escapedName}=([^;]*)`).exec(cookie);
|
|
1060
|
+
return match ? decodeURIComponent(match[1] ?? "") : null;
|
|
1061
|
+
}
|
|
1062
|
+
function setCookie(name, value) {
|
|
1063
|
+
const browserWindow = getBrowserWindow();
|
|
1064
|
+
if (!browserWindow?.document) return false;
|
|
1065
|
+
try {
|
|
1066
|
+
const expires = new Date(Date.now() + 365 * 24 * 60 * 60 * 1e3).toUTCString();
|
|
1067
|
+
const secure = browserWindow.location?.protocol === "https:" ? "; Secure" : "";
|
|
1068
|
+
browserWindow.document.cookie = `${name}=${encodeURIComponent(value)}; expires=${expires}; path=/${secure}; SameSite=Lax`;
|
|
1069
|
+
return true;
|
|
1070
|
+
} catch {
|
|
1071
|
+
return false;
|
|
431
1072
|
}
|
|
432
|
-
|
|
1073
|
+
}
|
|
1074
|
+
function removeCookie(name) {
|
|
1075
|
+
const browserWindow = getBrowserWindow();
|
|
1076
|
+
if (!browserWindow?.document) return;
|
|
1077
|
+
browserWindow.document.cookie = `${name}=; expires=Thu, 01 Jan 1970 00:00:00 GMT; path=/`;
|
|
1078
|
+
}
|
|
1079
|
+
function getLocalStorage() {
|
|
1080
|
+
const browserWindow = getBrowserWindow();
|
|
1081
|
+
try {
|
|
1082
|
+
return browserWindow?.localStorage;
|
|
1083
|
+
} catch {
|
|
1084
|
+
return void 0;
|
|
1085
|
+
}
|
|
1086
|
+
}
|
|
1087
|
+
function getSessionStorage() {
|
|
1088
|
+
const browserWindow = getBrowserWindow();
|
|
1089
|
+
try {
|
|
1090
|
+
return browserWindow?.sessionStorage;
|
|
1091
|
+
} catch {
|
|
1092
|
+
return void 0;
|
|
1093
|
+
}
|
|
1094
|
+
}
|
|
1095
|
+
function createBrowserPersistence(mode = "localStorage+cookie") {
|
|
1096
|
+
const health = createPersistenceHealth(mode);
|
|
1097
|
+
const memory = createMemoryPersistence(health);
|
|
1098
|
+
if (mode === "none") {
|
|
1099
|
+
return {
|
|
1100
|
+
getItem() {
|
|
1101
|
+
return null;
|
|
1102
|
+
},
|
|
1103
|
+
setItem() {
|
|
1104
|
+
return false;
|
|
1105
|
+
},
|
|
1106
|
+
removeItem() {
|
|
1107
|
+
},
|
|
1108
|
+
getHealth() {
|
|
1109
|
+
return {
|
|
1110
|
+
...health,
|
|
1111
|
+
failures: health.failures.map((failure) => ({ ...failure }))
|
|
1112
|
+
};
|
|
1113
|
+
}
|
|
1114
|
+
};
|
|
1115
|
+
}
|
|
1116
|
+
if (mode === "memory") return memory;
|
|
1117
|
+
const primary = mode === "sessionStorage" ? getSessionStorage() : getLocalStorage();
|
|
1118
|
+
const useCookie = mode === "cookie" || mode === "localStorage+cookie" || !primary;
|
|
1119
|
+
return {
|
|
1120
|
+
getItem(key) {
|
|
1121
|
+
try {
|
|
1122
|
+
const stored = primary?.getItem(key);
|
|
1123
|
+
if (stored) return stored;
|
|
1124
|
+
} catch (error) {
|
|
1125
|
+
recordFailure(health, mode === "sessionStorage" ? "sessionStorage" : "localStorage", "get", error);
|
|
1126
|
+
}
|
|
1127
|
+
if (useCookie) {
|
|
1128
|
+
const cookie = getCookie2(key);
|
|
1129
|
+
if (cookie) {
|
|
1130
|
+
health.cookieFallbackUsed = true;
|
|
1131
|
+
return cookie;
|
|
1132
|
+
}
|
|
1133
|
+
}
|
|
1134
|
+
const value = memory.getItem(key);
|
|
1135
|
+
if (value !== null) health.memoryFallbackUsed = true;
|
|
1136
|
+
return value;
|
|
1137
|
+
},
|
|
1138
|
+
setItem(key, value) {
|
|
1139
|
+
let wrote = false;
|
|
1140
|
+
try {
|
|
1141
|
+
primary?.setItem(key, value);
|
|
1142
|
+
wrote = primary !== void 0;
|
|
1143
|
+
} catch (error) {
|
|
1144
|
+
recordFailure(health, mode === "sessionStorage" ? "sessionStorage" : "localStorage", "set", error);
|
|
1145
|
+
wrote = false;
|
|
1146
|
+
}
|
|
1147
|
+
if (useCookie) {
|
|
1148
|
+
const cookieWrote = setCookie(key, value);
|
|
1149
|
+
if (cookieWrote) health.cookieFallbackUsed = true;
|
|
1150
|
+
wrote = cookieWrote || wrote;
|
|
1151
|
+
}
|
|
1152
|
+
if (!wrote) {
|
|
1153
|
+
health.memoryFallbackUsed = true;
|
|
1154
|
+
return memory.setItem(key, value);
|
|
1155
|
+
}
|
|
1156
|
+
if (mode === "localStorage+cookie") {
|
|
1157
|
+
memory.setItem(key, value);
|
|
1158
|
+
}
|
|
1159
|
+
return true;
|
|
1160
|
+
},
|
|
1161
|
+
removeItem(key) {
|
|
1162
|
+
try {
|
|
1163
|
+
primary?.removeItem(key);
|
|
1164
|
+
} catch (error) {
|
|
1165
|
+
recordFailure(health, mode === "sessionStorage" ? "sessionStorage" : "localStorage", "remove", error);
|
|
1166
|
+
}
|
|
1167
|
+
if (useCookie) removeCookie(key);
|
|
1168
|
+
memory.removeItem(key);
|
|
1169
|
+
},
|
|
1170
|
+
getHealth() {
|
|
1171
|
+
return {
|
|
1172
|
+
...health,
|
|
1173
|
+
failures: health.failures.map((failure) => ({ ...failure }))
|
|
1174
|
+
};
|
|
1175
|
+
}
|
|
1176
|
+
};
|
|
433
1177
|
}
|
|
434
1178
|
|
|
435
|
-
// src/browser/core/
|
|
436
|
-
|
|
437
|
-
|
|
1179
|
+
// src/browser/core/session.ts
|
|
1180
|
+
var SESSION_STORAGE_KEY2 = "sessionData";
|
|
1181
|
+
function getUrlParam2(name) {
|
|
1182
|
+
const href = getBrowserWindow()?.location?.href;
|
|
1183
|
+
if (!href) return null;
|
|
1184
|
+
try {
|
|
1185
|
+
return new URL(href).searchParams.get(name);
|
|
1186
|
+
} catch {
|
|
1187
|
+
return null;
|
|
1188
|
+
}
|
|
438
1189
|
}
|
|
1190
|
+
function readStoredSession(persistence) {
|
|
1191
|
+
const rawSession = persistence.getItem(SESSION_STORAGE_KEY2);
|
|
1192
|
+
if (!rawSession) return void 0;
|
|
1193
|
+
try {
|
|
1194
|
+
const parsed = JSON.parse(rawSession);
|
|
1195
|
+
if (isUuid(parsed.sessionId) && typeof parsed.timestamp === "number") {
|
|
1196
|
+
return {
|
|
1197
|
+
sessionId: parsed.sessionId,
|
|
1198
|
+
timestamp: parsed.timestamp
|
|
1199
|
+
};
|
|
1200
|
+
}
|
|
1201
|
+
} catch {
|
|
1202
|
+
persistence.removeItem(SESSION_STORAGE_KEY2);
|
|
1203
|
+
}
|
|
1204
|
+
return void 0;
|
|
1205
|
+
}
|
|
1206
|
+
function writeStoredSession(persistence, sessionId, timestamp) {
|
|
1207
|
+
persistence.setItem(SESSION_STORAGE_KEY2, JSON.stringify({ sessionId, timestamp }));
|
|
1208
|
+
}
|
|
1209
|
+
function createSessionManager(persistence, idleTimeoutSeconds = 30 * 60) {
|
|
1210
|
+
function resolveSessionId() {
|
|
1211
|
+
const now = Date.now();
|
|
1212
|
+
const urlSessionId = getUrlParam2("sid") ?? getUrlParam2("session_id");
|
|
1213
|
+
if (isUuid(urlSessionId)) {
|
|
1214
|
+
writeStoredSession(persistence, urlSessionId, now);
|
|
1215
|
+
return urlSessionId;
|
|
1216
|
+
}
|
|
1217
|
+
const storedSession = readStoredSession(persistence);
|
|
1218
|
+
if (storedSession && now - storedSession.timestamp <= idleTimeoutSeconds * 1e3) {
|
|
1219
|
+
writeStoredSession(persistence, storedSession.sessionId, now);
|
|
1220
|
+
return storedSession.sessionId;
|
|
1221
|
+
}
|
|
1222
|
+
const sessionId = createUuid();
|
|
1223
|
+
writeStoredSession(persistence, sessionId, now);
|
|
1224
|
+
return sessionId;
|
|
1225
|
+
}
|
|
1226
|
+
return {
|
|
1227
|
+
getSessionId() {
|
|
1228
|
+
return resolveSessionId();
|
|
1229
|
+
},
|
|
1230
|
+
reset() {
|
|
1231
|
+
const sessionId = createUuid();
|
|
1232
|
+
writeStoredSession(persistence, sessionId, Date.now());
|
|
1233
|
+
return sessionId;
|
|
1234
|
+
}
|
|
1235
|
+
};
|
|
1236
|
+
}
|
|
1237
|
+
|
|
1238
|
+
// src/browser/core/DriveMetaDataSDK.ts
|
|
439
1239
|
function endpointFromConfig(config) {
|
|
440
1240
|
const host = config.apiHost ?? "https://sdk.drivemetadata.com/v2";
|
|
441
1241
|
return `${host.replace(/\/$/, "")}/data-collector`;
|
|
@@ -446,14 +1246,6 @@ function requireConfigString(value, field) {
|
|
|
446
1246
|
}
|
|
447
1247
|
return value;
|
|
448
1248
|
}
|
|
449
|
-
function getBrowserStorage() {
|
|
450
|
-
const browserWindow = getBrowserWindow();
|
|
451
|
-
try {
|
|
452
|
-
return browserWindow?.localStorage;
|
|
453
|
-
} catch {
|
|
454
|
-
return void 0;
|
|
455
|
-
}
|
|
456
|
-
}
|
|
457
1249
|
var DriveMetaDataSDK = class {
|
|
458
1250
|
constructor(config) {
|
|
459
1251
|
this.initialized = true;
|
|
@@ -466,30 +1258,36 @@ var DriveMetaDataSDK = class {
|
|
|
466
1258
|
requireConfigString(config.writeKey || config.token, "writeKey or token");
|
|
467
1259
|
this.config = config;
|
|
468
1260
|
this.endpoint = endpointFromConfig(config);
|
|
469
|
-
const
|
|
1261
|
+
const storagePersistence = createBrowserPersistence(config.persistence);
|
|
1262
|
+
this.persistence = createDmdAttributesPersistence(storagePersistence);
|
|
1263
|
+
this.session = createSessionManager(this.persistence, config.sessionIdleTimeoutSeconds);
|
|
470
1264
|
const deliveryConfig = {
|
|
471
|
-
endpoint: this.endpoint
|
|
1265
|
+
endpoint: this.endpoint,
|
|
1266
|
+
storage: storagePersistence
|
|
472
1267
|
};
|
|
473
1268
|
if (config.delivery?.maxQueueSize !== void 0) deliveryConfig.maxQueueSize = config.delivery.maxQueueSize;
|
|
474
1269
|
if (config.delivery?.queueTtlMs !== void 0) deliveryConfig.queueTtlMs = config.delivery.queueTtlMs;
|
|
475
1270
|
if (config.delivery?.retryDelayMs !== void 0) deliveryConfig.retryDelayMs = config.delivery.retryDelayMs;
|
|
476
1271
|
if (config.delivery?.maxRetryDelayMs !== void 0) deliveryConfig.maxRetryDelayMs = config.delivery.maxRetryDelayMs;
|
|
477
1272
|
if (config.delivery?.maxPayloadBytes !== void 0) deliveryConfig.maxPayloadBytes = config.delivery.maxPayloadBytes;
|
|
1273
|
+
if (config.delivery?.payloadSizePolicy !== void 0) deliveryConfig.payloadSizePolicy = config.delivery.payloadSizePolicy;
|
|
1274
|
+
if (config.delivery?.payloadTruncateStringLength !== void 0) {
|
|
1275
|
+
deliveryConfig.payloadTruncateStringLength = config.delivery.payloadTruncateStringLength;
|
|
1276
|
+
}
|
|
1277
|
+
if (config.delivery?.useBeacon !== void 0) deliveryConfig.useBeacon = config.delivery.useBeacon;
|
|
478
1278
|
if (config.delivery?.batchSize !== void 0) deliveryConfig.batchSize = config.delivery.batchSize;
|
|
479
1279
|
if (config.onDrop !== void 0) deliveryConfig.onDrop = config.onDrop;
|
|
480
1280
|
if (config.onError !== void 0) deliveryConfig.onError = config.onError;
|
|
481
|
-
this.delivery = createDeliveryManager(
|
|
482
|
-
...deliveryConfig,
|
|
483
|
-
storage
|
|
484
|
-
} : deliveryConfig);
|
|
1281
|
+
this.delivery = createDeliveryManager(deliveryConfig);
|
|
485
1282
|
this.initialRetryDelayMs = config.delivery?.retryDelayMs ?? 1e3;
|
|
486
1283
|
this.retryDelayMs = this.initialRetryDelayMs;
|
|
487
1284
|
this.maxRetryDelayMs = config.delivery?.maxRetryDelayMs ?? 3e4;
|
|
488
1285
|
this.writeKey = config.writeKey || config.token || "";
|
|
489
|
-
this.identity = { anonymousId:
|
|
490
|
-
this.
|
|
1286
|
+
this.identity = { anonymousId: resolveAnonymousId(this.persistence) };
|
|
1287
|
+
captureAttributionFromUrl(this.persistence);
|
|
491
1288
|
this.consentState = normalizeConsent(config.gdprConsent ?? config.consent);
|
|
492
1289
|
this.gdprConsent = this.consentState.analytics;
|
|
1290
|
+
this.installAutocapture();
|
|
493
1291
|
if (!config.delivery?.disableLifecycleFlush) {
|
|
494
1292
|
this.installLifecycleFlush();
|
|
495
1293
|
}
|
|
@@ -529,7 +1327,8 @@ var DriveMetaDataSDK = class {
|
|
|
529
1327
|
}
|
|
530
1328
|
}
|
|
531
1329
|
reset() {
|
|
532
|
-
this.identity = { anonymousId:
|
|
1330
|
+
this.identity = { anonymousId: resetAnonymousId(this.persistence) };
|
|
1331
|
+
this.session.reset();
|
|
533
1332
|
this.queue = [];
|
|
534
1333
|
this.offline = false;
|
|
535
1334
|
if (this.retryTimer !== void 0) {
|
|
@@ -538,8 +1337,20 @@ var DriveMetaDataSDK = class {
|
|
|
538
1337
|
}
|
|
539
1338
|
this.lifecycleCleanup?.();
|
|
540
1339
|
this.lifecycleCleanup = void 0;
|
|
1340
|
+
this.autocaptureCleanup?.();
|
|
1341
|
+
this.autocaptureCleanup = void 0;
|
|
541
1342
|
this.delivery.clearQueue("manual_clear");
|
|
542
1343
|
}
|
|
1344
|
+
disposeForTests() {
|
|
1345
|
+
if (this.retryTimer !== void 0) {
|
|
1346
|
+
clearTimeout(this.retryTimer);
|
|
1347
|
+
this.retryTimer = void 0;
|
|
1348
|
+
}
|
|
1349
|
+
this.lifecycleCleanup?.();
|
|
1350
|
+
this.lifecycleCleanup = void 0;
|
|
1351
|
+
this.autocaptureCleanup?.();
|
|
1352
|
+
this.autocaptureCleanup = void 0;
|
|
1353
|
+
}
|
|
543
1354
|
setConsent(consent2) {
|
|
544
1355
|
this.consentState = typeof consent2 === "object" ? mergeConsent(this.consentState, consent2) : normalizeConsent(consent2);
|
|
545
1356
|
this.gdprConsent = this.consentState.analytics;
|
|
@@ -554,6 +1365,7 @@ var DriveMetaDataSDK = class {
|
|
|
554
1365
|
initialized: this.initialized,
|
|
555
1366
|
consent: this.gdprConsent,
|
|
556
1367
|
consentPurposes: this.consentState,
|
|
1368
|
+
persistence: this.persistence.getHealth(),
|
|
557
1369
|
queueSize: deliveryDiagnostics.queued,
|
|
558
1370
|
offline: this.offline || deliveryDiagnostics.queued > 0,
|
|
559
1371
|
droppedEvents: this.droppedEvents + deliveryDiagnostics.dropped.length,
|
|
@@ -568,7 +1380,9 @@ var DriveMetaDataSDK = class {
|
|
|
568
1380
|
void this.delivery.send(payload).then(() => {
|
|
569
1381
|
const diagnostics = this.delivery.getDiagnostics();
|
|
570
1382
|
this.offline = diagnostics.queued > 0;
|
|
571
|
-
|
|
1383
|
+
if (diagnostics.lastError !== void 0) {
|
|
1384
|
+
this.lastError = diagnostics.lastError;
|
|
1385
|
+
}
|
|
572
1386
|
if (diagnostics.queued > 0) {
|
|
573
1387
|
this.scheduleRetryFlush();
|
|
574
1388
|
}
|
|
@@ -600,6 +1414,28 @@ var DriveMetaDataSDK = class {
|
|
|
600
1414
|
}
|
|
601
1415
|
};
|
|
602
1416
|
}
|
|
1417
|
+
installAutocapture() {
|
|
1418
|
+
const browserWindow = getBrowserWindow();
|
|
1419
|
+
if (!browserWindow) return;
|
|
1420
|
+
if (this.config.autocapture === false) return;
|
|
1421
|
+
const capturePageview = this.config.capturePageview !== false;
|
|
1422
|
+
const capturePageleave = this.config.capturePageleave !== false;
|
|
1423
|
+
const controller = installAutocapture({
|
|
1424
|
+
browserWindow,
|
|
1425
|
+
capturePageview,
|
|
1426
|
+
capturePageleave,
|
|
1427
|
+
onPageView: () => {
|
|
1428
|
+
this.page();
|
|
1429
|
+
},
|
|
1430
|
+
onPageLeave: () => {
|
|
1431
|
+
this.trackEvent("page_leave", { url: browserWindow.location.href });
|
|
1432
|
+
},
|
|
1433
|
+
onRouteChange: () => {
|
|
1434
|
+
captureAttributionFromUrl(this.persistence);
|
|
1435
|
+
}
|
|
1436
|
+
});
|
|
1437
|
+
this.autocaptureCleanup = controller.cleanup;
|
|
1438
|
+
}
|
|
603
1439
|
scheduleRetryFlush() {
|
|
604
1440
|
if (this.retryTimer !== void 0) return;
|
|
605
1441
|
const delay = Math.min(this.retryDelayMs, this.maxRetryDelayMs);
|
|
@@ -625,7 +1461,7 @@ var DriveMetaDataSDK = class {
|
|
|
625
1461
|
type,
|
|
626
1462
|
event,
|
|
627
1463
|
properties: sanitizeProperties(properties),
|
|
628
|
-
messageId: options.messageId
|
|
1464
|
+
messageId: ensureUuid(options.messageId),
|
|
629
1465
|
timestamp: options.timestamp ?? (/* @__PURE__ */ new Date()).toISOString(),
|
|
630
1466
|
context: options.context ?? {},
|
|
631
1467
|
anonymousId: this.identity.anonymousId,
|
|
@@ -634,7 +1470,7 @@ var DriveMetaDataSDK = class {
|
|
|
634
1470
|
appId: this.config.appId,
|
|
635
1471
|
writeKey: this.writeKey,
|
|
636
1472
|
consent: this.consentState,
|
|
637
|
-
sessionId: this.
|
|
1473
|
+
sessionId: this.session.getSessionId()
|
|
638
1474
|
};
|
|
639
1475
|
if (this.identity.userId !== void 0) prepared.userId = this.identity.userId;
|
|
640
1476
|
if (this.identity.groupId !== void 0) prepared.groupId = this.identity.groupId;
|
|
@@ -658,10 +1494,21 @@ var DriveMetaDataSDK = class {
|
|
|
658
1494
|
if (!validation.ok) {
|
|
659
1495
|
this.lastError = `DMD SDK schema warning: ${validation.errors.join(", ")}`;
|
|
660
1496
|
}
|
|
661
|
-
this.
|
|
1497
|
+
const collectorPayload = this.toCollectorPayload(prepared);
|
|
1498
|
+
const backendValidation = validateBackendCollectorPayload(collectorPayload);
|
|
1499
|
+
if (!backendValidation.ok && this.config.schemaValidation === "strict") {
|
|
1500
|
+
this.lastError = `DMD SDK backend schema warning: ${backendValidation.errors.join(", ")}`;
|
|
1501
|
+
this.recordDrop(type, "invalid_payload", event);
|
|
1502
|
+
return;
|
|
1503
|
+
}
|
|
1504
|
+
if (!backendValidation.ok) {
|
|
1505
|
+
this.lastError = `DMD SDK backend schema warning: ${backendValidation.errors.join(", ")}`;
|
|
1506
|
+
}
|
|
1507
|
+
this.sendEvent(collectorPayload);
|
|
662
1508
|
}
|
|
663
1509
|
toCollectorPayload(prepared) {
|
|
664
1510
|
const browserWindow = getBrowserWindow();
|
|
1511
|
+
const pageContext = getBrowserPageContext();
|
|
665
1512
|
return createBackendCollectorPayload({
|
|
666
1513
|
requestId: prepared.messageId,
|
|
667
1514
|
timestamp: prepared.timestamp,
|
|
@@ -673,15 +1520,19 @@ var DriveMetaDataSDK = class {
|
|
|
673
1520
|
sessionId: prepared.sessionId,
|
|
674
1521
|
ua: browserWindow?.navigator?.userAgent,
|
|
675
1522
|
appId: prepared.appId,
|
|
676
|
-
pageUrl: browserWindow?.location?.href,
|
|
677
|
-
eventData: {
|
|
1523
|
+
pageUrl: pageContext.url ?? browserWindow?.location?.href,
|
|
1524
|
+
eventData: mergeStoredAttribution({
|
|
678
1525
|
...prepared.properties,
|
|
1526
|
+
page: {
|
|
1527
|
+
...pageContext,
|
|
1528
|
+
...prepared.properties.page && typeof prepared.properties.page === "object" ? prepared.properties.page : {}
|
|
1529
|
+
},
|
|
679
1530
|
anonymousId: prepared.anonymousId,
|
|
680
1531
|
sessionId: prepared.sessionId,
|
|
681
1532
|
timestamp: prepared.timestamp,
|
|
682
1533
|
requestSentAt: prepared.timestamp,
|
|
683
1534
|
requestReceivedAt: prepared.timestamp
|
|
684
|
-
}
|
|
1535
|
+
}, this.persistence)
|
|
685
1536
|
});
|
|
686
1537
|
}
|
|
687
1538
|
recordDrop(type, reason, event) {
|
|
@@ -757,7 +1608,7 @@ function initDmdSDK(config) {
|
|
|
757
1608
|
return publicSingleton;
|
|
758
1609
|
}
|
|
759
1610
|
try {
|
|
760
|
-
const instance = new DriveMetaDataSDK(config);
|
|
1611
|
+
const instance = new DriveMetaDataSDK(normalizeBrowserConfig(config));
|
|
761
1612
|
return setSingleton(instance);
|
|
762
1613
|
} catch (error) {
|
|
763
1614
|
lastError = error instanceof Error ? error.message : String(error);
|
|
@@ -851,7 +1702,7 @@ function getDmdHealth() {
|
|
|
851
1702
|
return health;
|
|
852
1703
|
}
|
|
853
1704
|
function resetDmdSDKForTests() {
|
|
854
|
-
singleton?.
|
|
1705
|
+
singleton?.disposeForTests();
|
|
855
1706
|
singleton = void 0;
|
|
856
1707
|
publicSingleton = void 0;
|
|
857
1708
|
droppedEvents = 0;
|