UNPKG

@braze/web-sdk

Version:

Braze SDK for web sites and other JS platforms.

289 lines (288 loc) 8.36 kB
import t from "../common/base-provider.js"; import r from "../managers/braze-instance.js"; import { STORAGE_KEYS as s } from "../managers/storage-manager.js"; import u from "../managers/subscription-manager.js"; import a from "../util/net.js"; import h from "../util/request-header-utils.js"; import { logger as E } from "../../shared-lib/index.js"; export default class tr extends t { constructor(i, t, s) { super(), (this.B = i), (this.j = t), (this.B = i), (this.j = t), (this.mite = null), (this.yi = null), (this.$i = s || null), (this.Ri = null), (this.D = null), (this.Mi = 0), (this.ji = 5), (this.Fi = null), (this.Ui = !0), (this.xi = null), (this.Pi = null), (this.ki = null), (this.Bi = !1), (this.Ji = new Map()), this.Oi(); } Oi() { if (this.j) { const i = this.j.lt(s.ct.qi), t = this.j.lt(s.ct.zi); i && t ? ((this.mite = i), (this.yi = t), E.info("Restored DUST configuration from storage")) : (i || t) && (E.warn("Incomplete DUST configuration in storage, clearing"), this.j.Nt(s.ct.qi), this.j.Nt(s.ct.zi)); } } Hi() { this.xi || this.Pi || ((this.ki = () => { (this.Bi = !0), (this.Ui = !1); }), window.addEventListener("beforeunload", this.ki), (this.xi = () => { (this.Bi = !0), this.Ri && (E.info("Page unloading, closing real-time connection gracefully"), (this.Ui = !1), this.Li()); }), window.addEventListener("pagehide", this.xi), (this.Pi = (i) => { i.persisted && this.Wi() && !this.Ri && (E.info("Page restored from bfcache, reconnecting"), (this.Bi = !1), (this.Ui = !0), (this.Mi = 0), this.Gi()); }), window.addEventListener("pageshow", this.Pi)); } jt() { return this.D; } yt(i) { this.D = i; } Ki(i, t) { if ("function" != typeof t) return null; let s = this.Ji.get(i); return s || ((s = new u()), this.Ji.set(i, s), r.q(s)), s.wt(t); } Qi(i, t) { const s = this.Ji.get(i); s && s.removeSubscription(t); } Wi() { return Boolean(this.mite && this.yi); } Vi(i, t) { const e = () => { "function" == typeof t && t(); }, n = this.B, o = this.j; if (!n || !o) return ( E.error("NetworkManager or StorageManager not available"), void e() ); const l = r.l(); if (l && !l.Xi()) return ( E.info("Real-time messaging is not enabled, skipping refresh"), void e() ); this.Wi() ? E.info("Refreshing real-time messaging configuration") : E.info("Fetching initial real-time messaging configuration"); const g = n.$({}, !0), c = n.A(g, h.H.Yi, !1), u = new Date().valueOf(); h.K(o, h.H.Yi, u), a.O({ url: `${n.V()}/dust/config`, headers: c, data: g, W: (t) => { if (!n.Y(g, t, c)) return ( E.error( "Failed to validate server response for real-time messaging configuration", ), void e() ); n.Z(), t.mite && t.host ? ((this.mite = t.mite), (this.yi = t.host), E.info( "Received real-time messaging configuration from server", ), o.ft(s.ct.qi, t.mite), o.ft(s.ct.zi, t.host), this.Gi(), "function" == typeof i && i()) : (t.mite || E.error("Missing messaging identifier in server response"), t.host || E.error("Missing messaging host in server response"), e()); }, error: (i) => { n._(i, "retrieving DUST config"), e(); }, }); } Gi() { const i = r.l(); if (i && !i.Xi()) return void E.info( "Real-time messaging is not enabled, skipping connection", ); if (!this.Wi()) return void E.error( "Cannot start real-time subscription without configuration", ); this.Ri && (E.info( "Real-time connection already exists, closing before starting new subscription", ), this.Li()); const t = this.mite, s = this.$i || this.yi; if (!t || !s) return; const e = `${ /^https?:\/\//i.test(s) ? s : `https://${s}` }/sse?mite=${encodeURIComponent(t)}&attempts=${this.Mi}`; this.$i && E.info(`Using custom real-time messaging host: ${this.$i}`); try { (this.Ri = new EventSource(e)), (this.Ri.onopen = () => { E.info("Real-time messaging connection established"), (this.Mi = 0), (this.Ui = !0); }), this.Ri.addEventListener("msg", (i) => { this.Zi(i.data); }), (this.Ri.onerror = (i) => { var t; const s = null === (t = this.Ri) || void 0 === t ? void 0 : t.readyState; this.Bi || E.error( `Real-time messaging connection error (readyState: ${s}, eventPhase: ${ null == i ? void 0 : i.eventPhase })`, ), this.Li(), this.Ui && this.Mi < this.ji ? this._i() : (this.Mi >= this.ji && E.error( `Max retry attempts (${this.ji}) reached for real-time messaging, giving up for current session`, ), (this.Ui = !1)); }); } catch (i) { E.error( `Failed to create real-time messaging connection: ${ i instanceof Error ? i.message : String(i) }`, ); } } _i() { this.Mi++; const i = Math.min(1e3 * Math.pow(2, this.Mi), 6e4); E.info( `Retrying real-time messaging connection in ${i}ms (attempt ${this.Mi}/${this.ji})`, ), (this.Fi = window.setTimeout(() => { (this.Fi = null), this.Gi(); }, i)); } Li() { null !== this.Fi && (window.clearTimeout(this.Fi), (this.Fi = null)), this.Ri && (this.Ri.close(), (this.Ri = null), E.info("Real-time messaging connection closed")); } Zi(i) { try { const t = JSON.parse(i); if (!t.type) return void E.error( `Received real-time message without type: ${JSON.stringify(t)}`, ); E.info(`Received real-time message of type '${t.type}'`); const s = this.Ji.get(t.type); s && s.he() > 0 ? s.L(t) : E.info(`No subscribers for real-time message type '${t.type}'`); } catch (i) { E.error( `Failed to parse real-time message: ${ i instanceof Error ? i.message : String(i) }`, ); } } changeUser(i = !1) { this.Li(), !i && this.j ? (this.Wi() && E.info( "Clearing cached real-time messaging configuration for user change", ), this.j.Nt(s.ct.qi), this.j.Nt(s.ct.zi), (this.mite = null), (this.yi = null)) : i && this.Wi() && E.info( "Preserving cached real-time messaging configuration for anonymous->identified user transition", ), (this.Mi = 0), (this.Ui = !0); } clearData(i = !1) { (this.Ui = !1), this.Li(), i && this.j && (this.Wi() && E.info( "Clearing cached real-time messaging configuration (wipeData)", ), this.j.Nt(s.ct.qi), this.j.Nt(s.ct.zi), (this.mite = null), (this.yi = null)), (this.Mi = 0); } destroy() { (this.Ui = !1), this.Li(), (this.mite = null), (this.Mi = 0), this.ki && (window.removeEventListener("beforeunload", this.ki), (this.ki = null)), this.xi && (window.removeEventListener("pagehide", this.xi), (this.xi = null)), this.Pi && (window.removeEventListener("pageshow", this.Pi), (this.Pi = null)), this.D && (r.removeSubscription(this.D), (this.D = null)); } }