@braze/web-sdk
Version:
Braze SDK for web sites and other JS platforms.
222 lines (221 loc) • 6.37 kB
JavaScript
import {
isArray as D,
isDate as Nt,
isObject as It,
keys as C,
} from "./code-utils.js";
import { getByteLength as rr } from "./string-utils.js";
import { logger as N } from "../../shared-lib/index.js";
import { toValidBackendTimeString as Lt } from "./date-utils.js";
import { BRAZE_ACTIONS as oo } from "./braze-actions.js";
import { SET_CUSTOM_USER_ATTRIBUTE_STRING as Ft } from "../common/constants.js";
export const CUSTOM_DATA_REGEX = /^[^\x00-\x1F\x22]+$/;
export const CUSTOM_ATTRIBUTE_SPECIAL_CHARS_REGEX = /[$.]/;
export const CUSTOM_ATTRIBUTE_RESERVED_OPERATORS = [
"$add",
"$update",
"$remove",
"$identifier_key",
"$identifier_value",
"$new_object",
"$time",
"$google_ad_personalization",
"$google_ad_user_data",
];
export const EMAIL_ADDRESS_REGEX = new RegExp(/^.+@.+\..+$/);
export const CUSTOM_PROPERTIES_MAX_SIZE_BYTES = 51200;
export const CUSTOM_PROPERTIES_MAX_SIZE_STRING = "50KB";
export const CUSTOM_ATTRIBUTES_MAX_SIZE_BYTES = 76800;
export const CUSTOM_ATTRIBUTES_MAX_SIZE_STRING = "75KB";
export const CUSTOM_ATTRIBUTE_MAX_DEPTH = 50;
export const BRAZE_ACTION_URI_REGEX = /^brazeActions:\/\/v\d+\//;
export const VALID_UTF8_STRING_NO_WHITESPACES_REGEX = /^[^\s]+$/;
export function validateCustomString(t, e, r) {
const n =
null != t &&
"string" == typeof t &&
("" === t || null != t.match(CUSTOM_DATA_REGEX));
return n || N.error(`Cannot ${e} because ${r} "${t}" is invalid.`), n;
}
export function validateCustomAttributeKey(t) {
return (
null != t &&
t.match(CUSTOM_ATTRIBUTE_SPECIAL_CHARS_REGEX) &&
-1 === CUSTOM_ATTRIBUTE_RESERVED_OPERATORS.indexOf(t) &&
N.warn("Custom attribute keys cannot contain '$' or '.'"),
validateCustomString(t, "set custom user attribute", "the given key")
);
}
export function validatePropertyType(t) {
const e = typeof t;
return (
null == t || "number" === e || "boolean" === e || Nt(t) || "string" === e
);
}
export function _validateNestedProperties(t, e, r) {
const n = -1 !== r;
if (n && r > 50)
return N.error("Nested attributes cannot be more than 50 levels deep."), !1;
const o = n ? r + 1 : -1;
if (D(t) && D(e)) {
for (let r = 0; r < t.length && r < e.length; r++)
if (
(Nt(t[r]) && (e[r] = Lt(t[r])),
!_validateNestedProperties(t[r], e[r], o))
)
return !1;
} else {
if (!It(t)) return validatePropertyType(t);
for (const r of C(t)) {
const i = t[r];
if (n && !validateCustomAttributeKey(r)) return !1;
if (Nt(i)) {
e[r] = Lt(i);
}
if (!_validateNestedProperties(i, e[r], o)) return !1;
}
}
return !0;
}
export function _validateEventPropertyValue(t, e, r, n, o) {
let i;
return (
(i =
It(t) || D(t)
? _validateNestedProperties(t, e, o ? 1 : -1)
: validatePropertyType(t)),
i || N.error(`Cannot ${r} because ${n} "${t}" is invalid.`),
i
);
}
export function validateStandardString(t, e, r, n = !1) {
const o = "string" == typeof t || (null === t && n);
return o || N.error(`Cannot ${e} because ${r} "${t}" is invalid.`), o;
}
export function validateCustomProperties(t, e, r, n, o) {
if ((null == t && (t = {}), "object" != typeof t || D(t)))
return (
N.error(`${e} requires that ${r} be an object. Ignoring ${o}.`),
[!1, null]
);
let i, a;
e === Ft ? ((i = 76800), (a = "75KB")) : ((i = 51200), (a = "50KB"));
const s = JSON.stringify(t);
if (rr(s) > i)
return (
N.error(
`Could not ${n} because ${r} was greater than the max size of ${a}.`,
),
[!1, null]
);
let u;
try {
u = JSON.parse(s);
} catch (t) {
return (
N.error(`Could not ${n} because ${r} did not contain valid JSON.`),
[!1, null]
);
}
for (const r in t) {
if (e === Ft && !validateCustomAttributeKey(r)) return [!1, null];
if (!validateCustomString(r, n, `the ${o} property name`))
return [!1, null];
const i = t[r];
if (e !== Ft && null == i) {
delete t[r], delete u[r];
continue;
}
Nt(i) && (u[r] = Lt(i));
if (
!_validateEventPropertyValue(
i,
u[r],
n,
`the ${o} property "${r}"`,
e === Ft,
)
)
return [!1, null];
}
return [!0, u];
}
export function validateCustomAttributeArrayType(t, e) {
let r = !1,
n = !1;
const o = () => {
N.error(
"Custom attribute arrays must be either string arrays or object arrays.",
);
};
for (const i of e)
if ("string" == typeof i) {
if (n) return o(), [!1, !1];
if (
!validateCustomString(
i,
`set custom user attribute "${t}"`,
"the element in the given array",
)
)
return [!1, !1];
r = !0;
} else {
if (!It(i)) return o(), [!1, !1];
if (r) return o(), [!1, !1];
if (
!validateCustomProperties(
i,
Ft,
"attribute value",
`set custom user attribute "${t}"`,
"custom user attribute",
)
)
return [!1, !1];
n = !0;
}
return [r, n];
}
export function isValidEmail(t) {
return (
"string" == typeof t && null != t.toLowerCase().match(EMAIL_ADDRESS_REGEX)
);
}
export function isValidBrazeActionJson(t) {
if (!(oo.properties.type in t)) return !1;
switch (t[oo.properties.type]) {
case oo.types.io:
if (oo.properties.eo in t) return !0;
break;
case oo.types.logCustomEvent:
case oo.types.setEmailNotificationSubscriptionType:
case oo.types.setPushNotificationSubscriptionType:
case oo.types.setCustomUserAttribute:
case oo.types.addToSubscriptionGroup:
case oo.types.removeFromSubscriptionGroup:
case oo.types.addToCustomAttributeArray:
case oo.types.removeFromCustomAttributeArray:
case oo.types.mo:
case oo.types.uo:
if (oo.properties.so in t) return !0;
break;
case oo.types.requestPushPermission:
return !0;
default:
return !1;
}
return !1;
}
export function isValidBrazeActionType(t) {
let e = !1;
return (
Object.keys(oo.types).forEach((r) => {
oo.types[r] !== t.toString() || (e = !0);
}),
e
);
}
export function isValidBannerPlacementId(t) {
return VALID_UTF8_STRING_NO_WHITESPACES_REGEX.test(t);
}