UNPKG

@braze/service-worker

Version:

Braze service worker to be used with the Braze Web SDK.

882 lines (881 loc) 23.6 kB
/* * Braze Web SDK v6.0.0 * (c) Braze, Inc. 2025 - http://braze.com * License available at https://github.com/braze-inc/braze-web-sdk/blob/master/LICENSE * Compiled on 2025-07-11 */ const h = { A: function (a) { if (void 0 !== a || void 0 === h.m) h.m = !!a; h.D || (h.D = !0); }, M: function () { h.D = !1; h.m = void 0; h.j = void 0; }, O: function (a) { "function" !== typeof a ? h.info("Ignoring setLogger call since logger is not a function") : (h.A(), (h.j = a)); }, P: function () { h.A(); h.m ? (console.log("Disabling Braze logging"), (h.m = !1)) : (console.log("Enabled Braze logging"), (h.m = !0)); }, info: function (a) { h.m && ((a = "Braze: " + a), null != h.j ? h.j(a) : console.log(a)); }, warn: function (a) { h.m && ((a = "Braze SDK Warning: " + a + " (v6.0.0)"), null != h.j ? h.j(a) : console.warn(a)); }, error: function (a) { h.m && ((a = "Braze SDK Error: " + a + " (v6.0.0)"), null != h.j ? h.j(a) : console.error(a)); }, }; function l() { const a = (c = !1) => { const e = (Math.random().toString(16) + "000000000").substr(2, 8); return c ? "-" + e.substr(0, 4) + "-" + e.substr(4, 4) : e; }; return a() + a(!0) + a(!0) + a(); } function q(a) { if ("indexedDB" in a.parent) return a.parent.indexedDB; } function r(a) { var c; try { if (null == q(a)) return !1; const e = null === (c = q(a)) || void 0 === c ? void 0 : c.open("Braze IndexedDB Support Test"); e && ((e.onupgradeneeded = () => e.result.close()), (e.onsuccess = () => e.result.close())); if ("undefined" !== typeof window) { c = window; const g = c.L || c.K || c.N; if (g && g.J && g.J.id) return ( a.j.info( "Not using IndexedDB for storage because we are running inside an extension", ), !1 ); } return !0; } catch (e) { return ( a.j.info("Not using IndexedDB for storage due to following error: " + e), !1 ); } } function v(a, c, e) { var g; const d = null === (g = q(a)) || void 0 === g ? void 0 : g.open(a.h.l, a.h.VERSION); if (null == d) return "function" === typeof e && e(), !1; d.onupgradeneeded = (f) => { var b; a.j.info("Upgrading indexedDB " + a.h.l + " to v" + a.h.VERSION + "..."); f = null === (b = f.target) || void 0 === b ? void 0 : b.result; for (const k in a.h.g) (b = k), a.h.g.hasOwnProperty(k) && !f.objectStoreNames.contains(a.h.g[b]) && f.createObjectStore(a.h.g[b]); }; d.onsuccess = (f) => { var b; const k = null === (b = f.target) || void 0 === b ? void 0 : b.result; k.onversionchange = () => { k.close(); "function" === typeof e && e(); a.j.error( "Needed to close the database unexpectedly because of an upgrade in another tab", ); }; c(k); }; d.onerror = (f) => { var b; a.j.info( "Could not open indexedDB " + a.h.l + " v" + a.h.VERSION + ": " + (null === (b = f.target) || void 0 === b ? void 0 : b.errorCode), ); "function" === typeof e && e(); return !0; }; return !0; } function w(a, c, e, g) { r(a) ? v( a, (d) => { if (d.objectStoreNames.contains(c)) { var f = d.transaction([c], "readonly"); f.oncomplete = () => d.close(); f = f.objectStore(c).openCursor(null, "prev"); f.onerror = () => { a.j.error( "Could not open cursor for " + c + " on indexedDB " + a.h.l, ); "function" === typeof g && g(); }; f.onsuccess = (b) => { var k; b = null === (k = b.target) || void 0 === k ? void 0 : k.result; null != b && null != b.value && null != b.key ? e(b.key, b.value) : "function" === typeof g && g(); }; } else a.j.error( "Could not retrieve last record from " + c + " on indexedDB " + a.h.l + " - " + c + " is not a valid objectStore", ), "function" === typeof g && g(), d.close(); }, g, ) : "function" === typeof g && g(); } class x { constructor() { var a = y, c = h; this.h = a; this.j = c; this.parent = "undefined" === typeof window ? self : window; this.h = a; this.j = c; } setItem(a, c, e, g, d) { if (!r(this)) return "function" === typeof d && d(), !1; const f = this; return v( this, (b) => { if (b.objectStoreNames.contains(a)) { var k = b.transaction([a], "readwrite"); k.oncomplete = () => b.close(); k = k.objectStore(a).put(e, c); k.onerror = () => { f.j.error( "Could not store object " + c + " in " + a + " on indexedDB " + f.h.l, ); "function" === typeof d && d(); }; k.onsuccess = () => { "function" === typeof g && g(); }; } else f.j.error( "Could not store object " + c + " in " + a + " on indexedDB " + f.h.l + " - " + a + " is not a valid objectStore", ), "function" === typeof d && d(), b.close(); }, d, ); } getItem(a, c, e) { if (!r(this)) return !1; const g = this; return v(this, (d) => { if (d.objectStoreNames.contains(a)) { var f = d.transaction([a], "readonly"); f.oncomplete = () => d.close(); f = f.objectStore(a).get(c); f.onerror = () => { g.j.error( "Could not retrieve object " + c + " in " + a + " on indexedDB " + g.h.l, ); }; f.onsuccess = (b) => { var k; b = null === (k = b.target) || void 0 === k ? void 0 : k.result; null != b && e(b); }; } else g.j.error( "Could not retrieve object " + c + " in " + a + " on indexedDB " + g.h.l + " - " + a + " is not a valid objectStore", ), d.close(); }); } clearData() { if (!r(this)) return !1; const a = []; for (const e in this.h.g) { const g = e; this.h.g.hasOwnProperty(e) && this.h.g[g] !== this.h.g.B && a.push(this.h.g[g]); } const c = this; return v(this, function (e) { const g = e.transaction(a, "readwrite"); g.oncomplete = () => e.close(); for (let d = 0; d < a.length; d++) g.objectStore(a[d]).clear().onerror = function () { c.j.error( "Could not clear " + this.source.name + " on indexedDB " + c.h.l, ); }; g.onerror = function () { c.j.error("Could not clear object stores on indexedDB " + c.h.l); }; }); } } var y = { l: "AppboyServiceWorkerAsyncStorage", VERSION: 6, g: { o: "data", H: "pushClicks", C: "pushSubscribed", v: "fallbackDevice", F: "cardUpdates", B: "optOut", G: "pendingData", I: "sdkAuthenticationSignature", }, s: 1, }; function z() { return new Promise(function (a, c) { w(new x(), y.g.B, c, a); }); } function A() { return new Promise((a) => { w( new x(), y.g.I, (c, e) => { a(e); }, () => { a(null); }, ); }); } function C(a, c, e) { h.info( `${c} due to SDK Authentication failure with error code ${e.error_code}. The data will be logged on the user's next session start.`, ); new x().setItem(y.g.G, l(), a); } function D(a, c, e) { return new Promise(function (g, d) { const f = {}; f.time = Math.floor(new Date().valueOf() / 1e3); f.device_id = e; f.api_key = a; f.sdk_version = "6.0.0"; f.sdk_flavor = "amp"; f.respond_with = { config: { config_time: 0 } }; fetch(c + "/data/", { method: "POST", headers: { "Content-type": "application/json", "X-Braze-Api-Key": a, "X-Braze-Last-Req-Ms-Ago": 72e5, "X-Braze-Req-Attempt": 1, }, body: JSON.stringify(f), }) .then(function (b) { b.ok || h.error("Unable to get config: " + b.status); return b.json(); }) .then(function (b) { b.error && (h.error("Unable to get config: " + b.error), d()); b.auth_error && (h.error( "Unable to get config due to authentication error. SDK Authentication does not support AMP pages.", ), d()); if (!b.error && !b.auth_error) { b = b.config.vapid_public_key; var k = "=".repeat((4 - (b.length % 4)) % 4); b = (b + k).replace(/\-/g, "+").replace(/_/g, "/"); b = atob(b); k = new Uint8Array(b.length); for (let m = 0; m < b.length; ++m) k[m] = b.charCodeAt(m); g({ userVisibleOnly: !0, applicationServerKey: k }); } }) .catch(function (b) { h.error("Unable to get config: " + b); d(); }); }); } function E(a, c, e, g, d, f, b, k, m) { return A().then( (p) => new Promise(function (O, B) { const t = {}; t.device_id = e; t.api_key = a; t.sdk_version = "6.0.0"; null != f && (t.sdk_flavor = f); var u = null; let H = null, I = null; d && ((I = d.endpoint), d.getKey && ((u = btoa( String.fromCharCode.apply( null, new Uint8Array(d.getKey("p256dh")), ), )), (H = btoa( String.fromCharCode.apply(null, new Uint8Array(d.getKey("auth"))), )))); t.time = Math.floor(new Date().valueOf() / 1e3); t.attributes = [ { user_id: g, push_token: I, custom_push_public_key: u, custom_push_user_auth: H, }, ]; u = { "Content-type": "application/json", "X-Braze-Api-Key": t.api_key, "X-Braze-Last-Req-Ms-Ago": 72e5, "X-Braze-Req-Attempt": 1, }; p && m && (u["X-Braze-Auth-Signature"] = p); fetch(c + "/data/", { method: "POST", headers: u, body: JSON.stringify(t), }) .then(function (n) { n.ok || h.error(k + " " + n.status); return n.json(); }) .then(function (n) { n.error && (h.error(k + " " + n.error), B()); n.auth_error && (C(t, k, n.auth_error), B()); n.error || n.auth_error || (h.info(b), O()); }) .catch(function (n) { h.error(k + " " + n); B(); }); }), ); } function F(a, c) { return z() .then(function () { return A(); }) .then(function (e) { w(new x(), y.g.o, function (g, d) { g = Math.floor(new Date().valueOf() / 1e3); const f = d.data; f.time = g; a.time = g; a.user_id = d.userId; f.events = [a]; f.sdk_version = "6.0.0"; g = { "Content-Type": "application/json", "X-Braze-Api-Key": f.api_key, "X-Braze-Last-Req-Ms-Ago": 72e5, "X-Braze-Req-Attempt": 1, }; e && d.sdkAuthEnabled && (g["X-Braze-Auth-Signature"] = e); fetch(d.baseUrl + "/data/", { method: "POST", headers: g, body: JSON.stringify(f), }) .then(function (b) { b.ok || h.error("Unable to log " + c + ": " + b.status); return b.json(); }) .then(function (b) { b.error && h.error("Unable to log " + c + ":", b.error); b.auth_error && C(f, "Unable to log " + c, b.auth_error); b.error || b.auth_error || h.info("Successfully logged " + c); return Promise.resolve(); }) .catch(function (b) { h.error("Unable to log " + c + ":", b); return Promise.resolve(); }); }); }) .catch(function () { return Promise.reject( "Not sending data to Braze backend due to opt-out.", ); }); } function G() { const a = self.location.search.match(/apiKey=([^&]+)/i); if (a) return a[1]; h.error("Missing API key in query params."); return null; } function J() { const a = self.location.search.match(/baseUrl=([^&]+)/i); if (a) return a[1]; h.error("Missing base URL in query params."); return null; } function K(a, c) { self.clients.matchAll().then(function (e) { for (let g = 0; g < e.length; g++) e[g].postMessage({ command: a, payload: c }); }); } function L(a, c, e, g, d) { return D(a, c, e) .then(function (f) { return self.registration.pushManager.subscribe(f); }) .then(function (f) { K("amp-web-push-subscribe", null); return E( a, c, e, g, f, "amp", "Successfully sent AMP push subscription to Braze backend.", "Unable to send AMP push subscription to Braze backend.", d, ); }) .catch(function () { h.error("Failed to subscribe for AMP push."); return Promise.reject(); }); } function M() { self.registration.pushManager .getSubscription() .then(function (a) { return a ? self.registration.pushManager.permissionState(a.options) : null; }) .then(function (a) { K("amp-web-push-subscription-state", "granted" === a); }); } function N() { const a = new x(); return new Promise(function (c, e) { w( a, y.g.o, function (g, d) { L( d.data.api_key, d.baseUrl, d.data.device_id, d.userId, d.sdkAuthEnabled, ) .then(function () { c(); }) .catch(function () { e(); }); }, function () { const g = G(), d = J(); w( a, y.g.v, function (f, b) { L(g, d, b, null) .then(function () { c(); }) .catch(function () { e(); }); }, function () { const f = l(); new Promise(function (b, k) { a.setItem(y.g.v, y.s, f, b, k); }) .then(function () { return L(g, d, f, null); }) .then(function () { c(); }) .catch(function () { e(); }); }, ); }, ); }).then(function () { return new Promise(function (c, e) { a.setItem(y.g.C, y.s, !0, c, e); }); }); } function P() { return self.registration.pushManager .getSubscription() .then(function (a) { return a.unsubscribe(); }) .then(function () { K("amp-web-push-unsubscribe", null); const a = new x(); return new Promise(function (c, e) { w( a, y.g.o, function (g, d) { E( d.data.api_key, d.baseUrl, d.data.device_id, d.userId, null, "amp", "Successfully sent AMP push unsubscription to Braze backend.", "Unable to send AMP push unsubscription to Braze backend.", d.sdkAuthEnabled, ) .then(function () { c(); }) .catch(function () { e(); }); }, function () { w( a, y.g.v, function (g, d) { g = G(); const f = J(); E( g, f, d, null, null, "amp", "Successfully sent AMP push unsubscription to Braze backend.", "Unable to send AMP push unsubscription to Braze backend.", null, ) .then(function () { c(); }) .catch(function () { e(); }); }, function () { h.error("No device found during unsubscription."); e(); }, ); }, ); }).then(function () { return new Promise(function (c, e) { a.setItem(y.g.C, y.s, !1, c, e); }); }); }) .catch(function () { h.error("Failed to unsubscribe for AMP push."); return Promise.reject(); }); } function Q(a, c) { a.waitUntil( c.catch(function (e) { e && h.info(e); }), ); } h.A(!0); function R(a) { if (null == a || 0 === Object.keys(a).length) return Promise.reject( "Server has no pending push message for this registration. Ignoring push event.", ); const c = a.t, e = a.a, g = a.i, d = a.img, f = { url: a.u, ab_ids: { cid: a.cid }, extra: a.e }, b = a.ri; a.ab_push_fetch_test_triggers_key && (h.info("Service worker 6.0.0 found trigger fetch key in push payload."), (f.fetchTriggers = !0)); var k = a.ab_cd; null != k && new x().setItem(y.g.F, new Date().valueOf(), { userId: a.ab_cd_uid, card: k, }); a = a.pab || []; k = {}; for (let m = 0; m < a.length; m++) if (null != a[m] && null != a[m].action) { let p; switch (a[m].a) { case "ab_none": p = null; break; case "ab_uri": if (((p = a[m].u), null == p || "" === p)) p = "/"; } k[a[m].action] = p; } f.actionTargets = k; h.info("Displaying push notification!"); return self.registration .showNotification(c, { body: e, icon: g, image: d, data: f, actions: a, requireInteraction: b, }) .catch(function (m) { h.info(m); }); } self.addEventListener("install", function (a) { a.waitUntil(self.skipWaiting()); }); self.addEventListener("activate", function () { return self.clients.claim(); }); self.addEventListener("push", function (a) { h.info("Service worker 6.0.0 received push"); null != a.data && null != a.data.json ? Q(a, R(a.data.json())) : Q( a, new Promise(function (c, e) { w(new x(), y.g.o, function (g, d) { const f = d.data; z() .then(function () { return fetch(d.baseUrl + "/web_push/", { method: "POST", headers: { "Content-type": "application/json", "X-Braze-Api-Key": f.api_key, }, body: JSON.stringify(f), }); }) .then(function (b) { return b.ok ? b.json() : (h.error( "Unable to retrieve push payload from server: " + b.status, ), Promise.reject()); }) .then(function (b) { h.info("Retrieved push payload from server"); c(R(b)); }) .catch(function (b) { e( "Unable to retrieve push payload from server or user has opt-out: " + b, ); }); }); }), ); }); self.addEventListener("notificationclick", function (a) { if ( a && a.notification && (a.notification.close(), null != Notification && Notification.prototype.hasOwnProperty("data") && a.notification.data && a.notification.data.ab_ids) ) { var c = null != a.action && "" !== a.action; var e = c ? F( { name: "ca", data: { cid: a.notification.data.ab_ids.cid, a: a.action }, }, "push button click", ) : F( { name: "pc", data: { cid: a.notification.data.ab_ids.cid } }, "push click", ); if (!c) { const b = { lastClick: new Date().valueOf(), trackingString: a.notification.data.ab_ids.cid, }; a.notification.data.fetchTriggers && (b.fetchTriggers = !0); const k = new x(); var g = e .then(function () { return new Promise(function (m, p) { k.setItem(y.g.H, y.s, b, m, p); }); }) .catch(function () { h.info("Not storing push click due to no click event being created."); return Promise.resolve(); }); } if (c) var d = a.notification.data.actionTargets[a.action]; else if (((d = a.notification.data.url), null == d || "" === d)) d = "/"; var f; null != d && "" !== d && (f = clients.matchAll({ type: "window" }).then(function () { if (clients.openWindow) return clients.openWindow(d); })); Q(a, Promise.all([f, g])); } }); self.addEventListener("pushsubscriptionchange", function (a) { Q( a, z() .then(function () { let c = { userVisibleOnly: !0 }; null != a.oldSubscription && (c = a.oldSubscription.options); return self.registration.pushManager.subscribe(c); }) .then(function (c) { return new Promise(function (e, g) { w(new x(), y.g.o, function (d, f) { E( f.data.api_key, f.baseUrl, f.data.device_id, f.userId, c, null, "Successfully resubscribed user after expiration", "Unable to resubscribe user", f.sdkAuthEnabled, ) .then(function () { e(); }) .catch(function () { g(); }); }); }); }) .catch(function () { return Promise.reject( "Not resubscribing user for push due to opt-out.", ); }), ); }); self.addEventListener("message", function (a) { a.waitUntil && a.data.command && a.waitUntil( z() .then(function () { switch (a.data.command) { case "amp-web-push-subscription-state": return M(), Promise.resolve(); case "amp-web-push-subscribe": return N(); case "amp-web-push-unsubscribe": return P(); default: return Promise.resolve(); } }) .catch(function () { h.info("Ignoring message from amp-web-push due to opt-out."); return Promise.resolve(); }), ); });