@mparticle/web-sdk 3.6.1 → 3.7.0

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/src/types.ts CHANGED
@@ -558,6 +558,20 @@ export function getEventCategoryFromCustomEventType(
558
558
  }
559
559
  }
560
560
 
561
+ // A stored `ui` key is the decimal string of an IdentityType; anything else was
562
+ // not written by this SDK. The round-trip comparison is load bearing: parseNumber
563
+ // returns 0 for any non-numeric key and IdentityType.Other is 0, so after parsing
564
+ // alone a stored "hasOwnProperty" is indistinguishable from a genuine Other entry.
565
+ export function getIdentityTypeFromStoredKey(key: string): number | null {
566
+ const identityType = parseNumber(key);
567
+
568
+ if (String(identityType) !== key || !IdentityType.isValid(identityType)) {
569
+ return null;
570
+ }
571
+
572
+ return identityType;
573
+ }
574
+
561
575
  export function getIdentityTypeFromBatchKey(
562
576
  key: string
563
577
  ): number {
package/src/utils.ts CHANGED
@@ -44,7 +44,7 @@ const findKeyInObject = (obj: any, key: string): string => {
44
44
  if (key && obj) {
45
45
  for (var prop in obj) {
46
46
  if (
47
- obj.hasOwnProperty(prop) &&
47
+ hasOwnProp(obj, prop) &&
48
48
  prop.toLowerCase() === key.toLowerCase()
49
49
  ) {
50
50
  return prop;
@@ -246,8 +246,13 @@ const WEB_SAFE_BASE64_REPLACEMENTS: Dictionary<string> = {
246
246
  '=': '',
247
247
  };
248
248
 
249
- const toWebSafeBase64 = (value: string): string =>
250
- btoa(value).replace(/[+/=]/g, c => WEB_SAFE_BASE64_REPLACEMENTS[c]);
249
+ // btoa is defined only over Latin-1 and throws InvalidCharacterError above U+00FF
250
+ const isLatin1 = (value: string): boolean => !/[^\u0000-\u00ff]/.test(value);
251
+
252
+ const toWebSafeBase64 = (value: string): string | undefined =>
253
+ isLatin1(value)
254
+ ? btoa(value).replace(/[+/=]/g, c => WEB_SAFE_BASE64_REPLACEMENTS[c])
255
+ : undefined;
251
256
 
252
257
  // FIXME: REFACTOR for V3
253
258
  // only used in store.js to sanitize server-side formatting of
@@ -316,9 +321,26 @@ const moveElementToEnd = <T>(array: T[], index: number): T[] =>
316
321
  // does not compile under this project's `lib: ["es5", "es6", "dom"]`; widening that
317
322
  // would emit a call absent from every browser before 2021, and this same file still
318
323
  // carries a fallback for browsers with no URLSearchParams.
319
- const hasOwnProp = (obj: object, key: string): boolean =>
324
+ const hasOwnProp = (obj: object, key: PropertyKey): boolean =>
320
325
  Object.prototype.hasOwnProperty.call(obj, key);
321
326
 
327
+ // Assigning `__proto__` replaces the target's prototype instead of adding an own
328
+ // property; `constructor` is reserved alongside it by the stored-record contract.
329
+ // `prototype` is deliberately absent: isValidKeyValue accepts it, so setUserAttribute
330
+ // persists it and the getters must hand it back.
331
+ const isReservedStoredPropertyName = (name: string): boolean =>
332
+ name === '__proto__' || name === 'constructor';
333
+
334
+ // extend's historical set, which additionally refuses `prototype` when merging.
335
+ const isUncopyableMergeName = (name: string): boolean =>
336
+ isReservedStoredPropertyName(name) || name === 'prototype';
337
+
338
+ // Kit-facing copies stay compatible with conventional own-property iteration, such as
339
+ // attributes.hasOwnProperty(key), which is the one read pattern an attribute of that name
340
+ // interferes with. The public getters keep the name; only this filter drops it.
341
+ const isReservedKitPropertyName = (name: string): boolean =>
342
+ isReservedStoredPropertyName(name) || name === 'hasOwnProperty';
343
+
322
344
  const queryStringParser = (
323
345
  url: string,
324
346
  keys: string[] = []
@@ -446,7 +468,7 @@ const filterDictionaryWithHash = <T>(
446
468
 
447
469
  if (!isEmpty(dictionary)) {
448
470
  for (const key in dictionary) {
449
- if (dictionary.hasOwnProperty(key)) {
471
+ if (hasOwnProp(dictionary, key) && !isReservedKitPropertyName(key)) {
450
472
  const hashedKey = hashFn(key);
451
473
  if (!inArray(filterList, hashedKey)) {
452
474
  filtered[key] = dictionary[key];
@@ -612,11 +634,7 @@ function extend(...args: any[]): any {
612
634
  for (; i < length; i++) {
613
635
  if ((options = args[i]) != null) {
614
636
  for (name in options) {
615
- if (
616
- name === '__proto__' ||
617
- name === 'constructor' ||
618
- name === 'prototype'
619
- ) {
637
+ if (isUncopyableMergeName(name)) {
620
638
  continue;
621
639
  }
622
640
 
@@ -721,6 +739,7 @@ export {
721
739
  moveElementToEnd,
722
740
  queryStringParser,
723
741
  hasOwnProp,
742
+ isReservedStoredPropertyName,
724
743
  getCookies,
725
744
  getHref,
726
745
  replaceMPID,