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