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