@braze/web-sdk
Version:
Braze SDK for web sites and other JS platforms.
344 lines (343 loc) • 10.2 kB
JavaScript
import { logger as b } from "../../shared-lib/index.js";
import { isValidIso4217CurrencyCode as or } from "./iso-4217-currency-codes.js";
import { CoreStrings as R } from "../common/constants.js";
import { CartUpdatedActions as un } from "../types.js";
import {
isArray as g,
isObject as Ct,
validateValueIsFromEnum as ta,
} from "./code-utils.js";
import {
validateCustomProperties as nt,
validateCustomString as mt,
} from "./validation-utils.js";
const ln = "log eCommerce event";
function dn(n, t, e) {
if (null == n) {
if (!e) return;
return b.error(`Cannot ${ln} because ${t} must be a non-empty string.`), !1;
}
return "string" != typeof n || (e && n.length <= 0)
? (b.error(
`Cannot ${ln} because ${t} must be a string${
e ? "" : " when provided"
}.`,
),
!1)
: n.length > 255
? (b.error(`Cannot ${ln} because ${t} must be at most 255 characters.`), !1)
: !!mt(n, ln, t) && n;
}
function mn(n, t) {
return "number" != typeof n || isNaN(n) || !isFinite(n)
? (b.error(`Cannot ${ln} because ${t} must be a finite number.`), !1)
: n;
}
function pn(n, t) {
const e = mn(n, t);
return (
!1 !== e &&
(e < 0 ? (b.error(`Cannot ${ln} because ${t} must be at least 0.`), !1) : e)
);
}
const bn = /^[A-Za-z0-9\-_.,:;!?@#%&*()+={}[\]|\\/'`~^<>]+$/;
function _n(n, t) {
return 0 === n.length || n.length > 255
? (b.error(
`Cannot ${ln} because each ${t} key must be between 1 and 255 characters.`,
),
!1)
: "$" === n.charAt(0)
? (b.error(`Cannot ${ln} because ${t} keys cannot begin with "$".`), !1)
: !!bn.test(n) ||
(b.error(
`Cannot ${ln} because ${t} key "${n}" contains invalid characters.`,
),
!1);
}
function $n(n, t, e) {
if (e > 50)
return b.error(`Cannot ${ln} because ${t} is nested too deeply.`), !1;
if (null == n || "object" != typeof n) return !0;
if (g(n)) {
const r = n;
for (let n = 0; n < r.length; n++) {
const u = r[n];
if ("string" == typeof u) {
if (u.length > 255)
return (
b.error(
`Cannot ${ln} because a ${t} string value exceeds 255 characters.`,
),
!1
);
} else if (!$n(u, t, e + 1)) return !1;
}
return !0;
}
if (!Ct(n)) return !0;
const r = n;
for (const n in r) {
if (!Object.prototype.hasOwnProperty.call(r, n)) continue;
if (!_n(n, t)) return !1;
const u = r[n];
if ("string" == typeof u) {
if (u.length > 255)
return (
b.error(
`Cannot ${ln} because a ${t} string value exceeds 255 characters.`,
),
!1
);
} else if (null != u && "object" == typeof u && !$n(u, t, e + 1)) return !1;
}
return !0;
}
function vn(n, t) {
if (!g(n))
return (
b.error(`Cannot ${ln} because ${t} must be an array of strings.`), !1
);
for (const e of n) if (!1 === dn(e, t, !0)) return !1;
return !0;
}
function yn(n, t) {
if (void 0 === n) return;
const [e, r] = nt(null != n ? n : {}, R.QE, "metadata", ln, t);
return !!e && !(null != r && !$n(r, t, 0)) && r;
}
function gn(n) {
if (null == n || "object" != typeof n || g(n))
return (
b.error(`Cannot ${ln} because each product must be an object.`), null
);
const t = n,
e = dn(t.product_id, "product_id", !0),
r = dn(t.product_name, "product_name", !0),
u = dn(t.variant_id, "variant_id", !0),
o = (function (n) {
if (!1 === mn(n, "product quantity")) return !1;
const t = parseInt(n.toString(), 10);
return t !== n
? (b.error(`Cannot ${ln} because product quantity must be an integer.`),
!1)
: n < 0 || n > Number.MAX_SAFE_INTEGER
? (b.error(
`Cannot ${ln} because product quantity must be between 0 and Number.MAX_SAFE_INTEGER.`,
),
!1)
: t;
})(t.quantity),
c = pn(t.price, "product price");
if (!1 === e || !1 === r || !1 === u || !1 === o || !1 === c) return null;
const i = dn(t.image_url, "image_url", !1),
a = dn(t.product_url, "product_url", !1);
if (!1 === i || !1 === a) return null;
const s = yn(t.metadata, "eCommerce product metadata");
if (!1 === s) return null;
const l = {
product_id: e,
product_name: r,
variant_id: u,
quantity: o,
price: c,
};
return (
null != i && (l.image_url = i),
null != a && (l.product_url = a),
null != s && (l.metadata = s),
l
);
}
function Cn(n) {
if (null == n || !g(n))
return b.error(`Cannot ${ln} because products must be an array.`), null;
const t = [],
e = n;
for (const n of e) {
const e = gn(n);
if (null == e) return null;
t.push(e);
}
return t;
}
function hn(n) {
const t = (function (n) {
if (null == n || "string" != typeof n || n.length <= 0)
return (
b.error(`Cannot ${ln} because currency must be a non-empty string.`),
!1
);
const t = n.toUpperCase();
return or(t)
? t
: (b.error(
`${R.QE} requires a valid ISO 4217 currency code, got "${n}". Ignoring event.`,
),
!1);
})(n.currency),
e = dn(n.source, "source", !0);
return !1 === t || !1 === e ? null : { currency: t, source: e };
}
function jn(n, t) {
const e = ["subtotal_value", "tax", "shipping"];
for (const r of e)
if (null != t[r]) {
const e = pn(t[r], r);
if (!1 === e) return !1;
n[r] = e;
}
return !0;
}
function wn(n, t) {
const e = yn(t, "eCommerce event metadata");
return !1 !== e && (null != e && (n.metadata = e), !0);
}
function kn(n, t) {
const e = dn(n.cart_id, "cart_id", !0),
r =
void 0 === n.action
? un.REPLACE
: ((u = n.action),
!!ta(
un,
u,
`Cannot ${ln} because action is invalid.`,
"CartUpdatedActions",
) && u);
var u;
const o = Cn(n.products);
if (!1 === e || !1 === r || null == o) return null;
const c = r === un.Ld || r === un.Md,
i =
void 0 === n.total_value && c ? void 0 : pn(n.total_value, "total_value");
if (!1 === i) return null;
const a = {
cart_id: e,
action: r,
currency: t.currency,
products: o,
source: t.source,
};
return (
void 0 !== i && (a.total_value = i),
jn(a, n) && wn(a, n.metadata) ? a : null
);
}
export function sanitizeEcommerceEvent(n) {
const t = n.properties;
if (null == t || "object" != typeof t || g(t))
return b.error(`${R.QE} requires a properties object.`), null;
const e = t,
r = hn(e);
if (null == r) return null;
switch (n.name) {
case "ecommerce.product_viewed":
return (function (n, t) {
const e = n.metadata;
if (void 0 !== n.type && !vn(n.type, "type")) return null;
const r = dn(n.product_id, "product_id", !0),
u = dn(n.product_name, "product_name", !0),
o = dn(n.variant_id, "variant_id", !0),
c = pn(n.price, "price"),
i = dn(n.image_url, "image_url", !1),
a = dn(n.product_url, "product_url", !1);
if (
!1 === r ||
!1 === u ||
!1 === o ||
!1 === c ||
!1 === i ||
!1 === a
)
return null;
const s = {
product_id: r,
product_name: u,
variant_id: o,
price: c,
currency: t.currency,
source: t.source,
};
return (
null != i && (s.image_url = i),
null != a && (s.product_url = a),
void 0 !== n.type && (s.type = n.type),
wn(s, e) ? s : null
);
})(e, r);
case "ecommerce.cart_updated":
return kn(e, r);
case "ecommerce.checkout_started":
return (function (n, t) {
const e = dn(n.checkout_id, "checkout_id", !0),
r = pn(n.total_value, "total_value"),
u = Cn(n.products),
o = dn(n.cart_id, "cart_id", !1);
if (!1 === e || !1 === r || null == u || !1 === o) return null;
const c = {
checkout_id: e,
total_value: r,
currency: t.currency,
products: u,
source: t.source,
};
return (
null != o && (c.cart_id = o), jn(c, n) && wn(c, n.metadata) ? c : null
);
})(e, r);
case "ecommerce.order_placed":
return (function (n, t) {
const e = n.metadata;
if (null != e && "object" == typeof e && !g(e)) {
const n = e;
if (void 0 !== n.tags && !vn(n.tags, "metadata.tags")) return null;
if (
void 0 !== n.payment_gateway_names &&
!vn(n.payment_gateway_names, "metadata.payment_gateway_names")
)
return null;
}
const r = dn(n.order_id, "order_id", !0),
u = pn(n.total_value, "total_value"),
o = Cn(n.products),
c = dn(n.cart_id, "cart_id", !1);
if (!1 === r || !1 === u || null == o || !1 === c) return null;
const i = {
order_id: r,
total_value: u,
currency: t.currency,
products: o,
source: t.source,
};
if ((null != c && (i.cart_id = c), null != n.total_discounts)) {
const t = pn(n.total_discounts, "total_discounts");
if (!1 === t) return null;
i.total_discounts = t;
}
if (void 0 !== n.discounts) {
if (!g(n.discounts))
return (
b.error(`Cannot ${ln} because discounts must be an array.`), null
);
const [t, e] = nt(
{ discounts: n.discounts },
R.QE,
"discounts",
ln,
"eCommerce order discounts",
);
if (!t || null == e) return null;
i.discounts = e.discounts;
}
return jn(i, n) && wn(i, n.metadata) ? i : null;
})(e, r);
default:
return (
b.error(
"logEcommerceEvent received an unknown event name. Ignoring event.",
),
null
);
}
}