UNPKG

@braze/web-sdk

Version:

Braze SDK for web sites and other JS platforms.

344 lines (343 loc) 10.2 kB
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 ); } }