@braze/web-sdk 6.7.0 → 6.8.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/index.d.ts +74 -27
- package/package.json +1 -1
- package/shared-lib/encoding-utils.js +2 -2
- package/shared-lib/event-types.js +13 -13
- package/shared-lib/indexed-db-adapter.js +3 -3
- package/shared-lib/logger.js +2 -2
- package/shared-lib/supported-options.js +8 -8
- package/src/Banner/log-banner-impressions.js +20 -11
- package/src/ContentCards/content-cards-provider-factory.js +13 -11
- package/src/ContentCards/content-cards-provider.js +4 -4
- package/src/ContentCards/get-cached-content-cards.js +2 -2
- package/src/ContentCards/request-content-cards-refresh.js +2 -2
- package/src/ContentCards/subscribe-to-content-cards-updates.js +10 -10
- package/src/ContentCards/ui/show-content-cards.js +3 -3
- package/src/Core/change-user.js +2 -2
- package/src/Core/index.js +1 -0
- package/src/Core/log-ecommerce-event.js +29 -0
- package/src/Core/log-purchase.js +17 -192
- package/src/Core/open-session.js +6 -6
- package/src/Core/set-sdk-authentication-signature.js +1 -1
- package/src/Core/subscribe-to-sdk-authentication-failures.js +1 -1
- package/src/DUST/dust-connection-core.js +1 -0
- package/src/DUST/dust-provider-factory.js +10 -10
- package/src/DUST/dust-provider.js +181 -158
- package/src/DUST/dust-shared-worker-code.js +1 -1
- package/src/DUST/dust-shared-worker-impl.js +93 -100
- package/src/DUST/dust-worker-bridge.js +27 -27
- package/src/DUST/subscribe-to-dust.js +7 -7
- package/src/InAppMessage/defer-in-app-message.js +1 -1
- package/src/InAppMessage/display/in-app-message-to-html.js +16 -16
- package/src/InAppMessage/display/modal-utils.js +2 -2
- package/src/InAppMessage/in-app-message-manager.js +64 -64
- package/src/InAppMessage/log-in-app-message-button-click.js +1 -1
- package/src/InAppMessage/log-in-app-message-click.js +1 -1
- package/src/InAppMessage/log-in-app-message-html-click.js +2 -2
- package/src/InAppMessage/log-in-app-message-impression.js +1 -1
- package/src/InAppMessage/models/full-screen-message.js +7 -7
- package/src/InAppMessage/models/html-message.js +1 -1
- package/src/InAppMessage/models/in-app-message-button.js +4 -4
- package/src/InAppMessage/models/in-app-message.js +22 -22
- package/src/InAppMessage/models/modal-message.js +5 -5
- package/src/InAppMessage/models/slide-up-message.js +6 -6
- package/src/InAppMessage/models/templated-in-app-message.js +8 -8
- package/src/InAppMessage/subscribe-to-in-app-message.js +1 -1
- package/src/InAppMessage/ui/automatically-show-in-app-messages.js +3 -3
- package/src/InAppMessage/ui/show-in-app-message.js +20 -20
- package/src/Push/push-manager-factory.js +2 -2
- package/src/Push/push-manager.js +8 -8
- package/src/Push/utils/push-utils.js +6 -6
- package/src/User/user-manager.js +5 -5
- package/src/User/user.js +8 -8
- package/src/common/constants.js +1 -0
- package/src/common/content-cards-display.js +2 -2
- package/src/l10n/l10n-manager-factory.js +1 -1
- package/src/l10n/l10n-manager.js +1 -1
- package/src/managers/braze-instance.js +21 -21
- package/src/managers/device-manager.js +6 -6
- package/src/managers/network-manager.js +93 -92
- package/src/managers/server-config-manager.js +68 -68
- package/src/managers/session-manager.js +2 -2
- package/src/managers/storage-manager-factory.js +4 -4
- package/src/managers/storage-manager.js +120 -120
- package/src/managers/subscription-manager.js +1 -1
- package/src/managers/utils.js +1 -1
- package/src/models/backend-errors.js +5 -5
- package/src/models/braze-event.js +3 -3
- package/src/models/device.js +1 -1
- package/src/models/identifier.js +3 -3
- package/src/models/push-token.js +5 -5
- package/src/models/server-config.js +27 -27
- package/src/request-controller.js +99 -99
- package/src/triggers/models/custom-event-data.js +4 -4
- package/src/triggers/models/custom-event-property-data.js +5 -5
- package/src/triggers/models/filter-set.js +2 -2
- package/src/triggers/models/filter.js +1 -1
- package/src/triggers/models/in-app-message-click-data.js +5 -5
- package/src/triggers/models/purchase-data.js +1 -1
- package/src/triggers/models/purchase-property-data.js +2 -2
- package/src/triggers/models/push-click-data.js +5 -5
- package/src/triggers/models/trigger-condition.js +42 -42
- package/src/triggers/models/trigger-events.js +2 -2
- package/src/triggers/models/trigger.js +10 -10
- package/src/triggers/triggers-provider-factory.js +1 -1
- package/src/triggers/triggers-provider.js +30 -30
- package/src/types.js +5 -1
- package/src/ui/js/attach-css.js +1 -1
- package/src/util/braze-actions.js +5 -5
- package/src/util/browser-detector.js +13 -13
- package/src/util/client-hints-parser.js +2 -2
- package/src/util/dom-utils.js +2 -2
- package/src/util/ecommerce-event-validation.js +326 -0
- package/src/util/iso-4217-currency-codes.js +176 -0
- package/src/util/net.js +3 -3
- package/src/util/request-header-utils.js +18 -18
- package/src/util/user-agent-parser.js +14 -14
- package/src/util/validation-utils.js +2 -2
- package/src/util/window-utils.js +2 -2
|
@@ -12,14 +12,15 @@ import {
|
|
|
12
12
|
} from "../common/constants.js";
|
|
13
13
|
import { randomInclusive as a } from "../util/math.js";
|
|
14
14
|
import {
|
|
15
|
-
|
|
16
|
-
|
|
15
|
+
CONNECTION_VALID_THRESHOLD_MS as ii,
|
|
16
|
+
MAX_RETRIES as ti,
|
|
17
|
+
buildSseUrl as si,
|
|
17
18
|
} from "./dust-connection-core.js";
|
|
18
19
|
import {
|
|
19
|
-
DustWorkerBridge as
|
|
20
|
-
isSharedWorkerSupported as
|
|
20
|
+
DustWorkerBridge as ei,
|
|
21
|
+
isSharedWorkerSupported as ni,
|
|
21
22
|
} from "./dust-worker-bridge.js";
|
|
22
|
-
export default class
|
|
23
|
+
export default class sr extends t {
|
|
23
24
|
constructor(i, t, s, e, n = !0) {
|
|
24
25
|
super(),
|
|
25
26
|
(this.B = i),
|
|
@@ -34,30 +35,31 @@ export default class nr extends t {
|
|
|
34
35
|
(this.Hi = null),
|
|
35
36
|
(this.Oi = e || null),
|
|
36
37
|
(this.Ki = null),
|
|
37
|
-
(this.
|
|
38
|
+
(this.Vi = null),
|
|
38
39
|
(this.T = null),
|
|
39
|
-
(this.
|
|
40
|
-
(this.
|
|
40
|
+
(this._i = 0),
|
|
41
|
+
(this.Qi = ti),
|
|
42
|
+
(this.Xi = null),
|
|
41
43
|
(this.Yi = null),
|
|
42
|
-
(this.Zi =
|
|
43
|
-
(this._i = !0),
|
|
44
|
+
(this.Zi = !0),
|
|
44
45
|
(this.we = null),
|
|
45
46
|
(this.Se = null),
|
|
46
47
|
(this.ke = null),
|
|
47
48
|
(this.ye = null),
|
|
48
49
|
(this.Re = !1),
|
|
49
|
-
(this.
|
|
50
|
+
(this.De = new Map()),
|
|
51
|
+
(this.Me = null),
|
|
50
52
|
(this.xe = null),
|
|
51
|
-
(this.De = null),
|
|
52
53
|
(this.We = null),
|
|
53
54
|
(this.Fe = this.Ue(n)),
|
|
54
55
|
(this.Ne = !1),
|
|
55
|
-
(this.
|
|
56
|
+
(this.Be = 0),
|
|
57
|
+
(this.Te = null),
|
|
56
58
|
this.ze();
|
|
57
59
|
}
|
|
58
60
|
Ue(i) {
|
|
59
61
|
return i
|
|
60
|
-
?
|
|
62
|
+
? ni()
|
|
61
63
|
? "sharedworker"
|
|
62
64
|
: (E.info(
|
|
63
65
|
"SharedWorker not supported, using direct EventSource (multi-tab will gracefully degrade)",
|
|
@@ -67,15 +69,17 @@ export default class nr extends t {
|
|
|
67
69
|
"direct");
|
|
68
70
|
}
|
|
69
71
|
Ae() {
|
|
70
|
-
this.We = new
|
|
71
|
-
|
|
72
|
-
this.
|
|
72
|
+
this.We = new ei({
|
|
73
|
+
Ge: (i) => {
|
|
74
|
+
this.Pe(i);
|
|
73
75
|
},
|
|
74
|
-
|
|
75
|
-
this.
|
|
76
|
+
qe: () => {
|
|
77
|
+
this.He(), (this.Te = new Date().valueOf());
|
|
76
78
|
},
|
|
77
|
-
|
|
78
|
-
|
|
79
|
+
Je: () => {
|
|
80
|
+
this.Te = null;
|
|
81
|
+
},
|
|
82
|
+
Le: (i) => {
|
|
79
83
|
E.error(`Real-time messaging SharedWorker error: ${i}`);
|
|
80
84
|
},
|
|
81
85
|
});
|
|
@@ -86,22 +90,32 @@ export default class nr extends t {
|
|
|
86
90
|
(this.Fe = "direct"),
|
|
87
91
|
(this.We = null));
|
|
88
92
|
}
|
|
89
|
-
|
|
90
|
-
(this.
|
|
93
|
+
He() {
|
|
94
|
+
(this._i = 0),
|
|
91
95
|
(this.we = null),
|
|
92
|
-
(this.
|
|
96
|
+
(this.Zi = !0),
|
|
93
97
|
(this.Ne = !1),
|
|
94
|
-
(this.
|
|
98
|
+
(this.Be = 0);
|
|
99
|
+
}
|
|
100
|
+
Oe() {
|
|
101
|
+
var i;
|
|
102
|
+
return (
|
|
103
|
+
!(
|
|
104
|
+
!("sharedworker" === this.Fe
|
|
105
|
+
? Boolean(null === (i = this.We) || void 0 === i ? void 0 : i.Ie())
|
|
106
|
+
: Boolean(this.Vi)) || null === this.Te
|
|
107
|
+
) && new Date().valueOf() - this.Te >= ii
|
|
108
|
+
);
|
|
95
109
|
}
|
|
96
|
-
|
|
110
|
+
Pe(i) {
|
|
97
111
|
if (!i.type)
|
|
98
112
|
return void E.warn(
|
|
99
113
|
`Received real-time message without type: ${JSON.stringify(i)}`,
|
|
100
114
|
);
|
|
101
115
|
const t = "sharedworker" === this.Fe ? "SharedWorker" : "Direct";
|
|
102
116
|
E.info(`Received real-time message of type '${i.type}' via ${t}`);
|
|
103
|
-
const s = this.
|
|
104
|
-
if (s && s.
|
|
117
|
+
const s = this.De.get(i.type);
|
|
118
|
+
if (s && s.Ke() > 0)
|
|
105
119
|
try {
|
|
106
120
|
s.A(i);
|
|
107
121
|
} catch (t) {
|
|
@@ -111,18 +125,18 @@ export default class nr extends t {
|
|
|
111
125
|
}
|
|
112
126
|
else E.info(`No subscribers for real-time message type '${i.type}'`);
|
|
113
127
|
}
|
|
114
|
-
|
|
128
|
+
Ve() {
|
|
115
129
|
return "sharedworker" === this.Fe;
|
|
116
130
|
}
|
|
117
|
-
|
|
131
|
+
_e() {
|
|
118
132
|
return this.Fe;
|
|
119
133
|
}
|
|
120
134
|
ze() {
|
|
121
135
|
if (this.C) {
|
|
122
|
-
const i = this.C.Rt(s.Tt.
|
|
123
|
-
t = this.C.Rt(s.Tt.
|
|
124
|
-
e = this.C.Rt(s.Tt.
|
|
125
|
-
n = this.C.Rt(s.Tt.
|
|
136
|
+
const i = this.C.Rt(s.Tt.Qe),
|
|
137
|
+
t = this.C.Rt(s.Tt.Xe),
|
|
138
|
+
e = this.C.Rt(s.Tt.Ye),
|
|
139
|
+
n = this.C.Rt(s.Tt.Ze);
|
|
126
140
|
i && t
|
|
127
141
|
? ((this.mite = i),
|
|
128
142
|
(this.Wi = t),
|
|
@@ -133,63 +147,70 @@ export default class nr extends t {
|
|
|
133
147
|
(E.warn(
|
|
134
148
|
"Incomplete real-time messaging configuration in storage, clearing",
|
|
135
149
|
),
|
|
136
|
-
this.
|
|
150
|
+
this.sn());
|
|
137
151
|
}
|
|
138
152
|
}
|
|
139
153
|
Hr() {
|
|
140
|
-
this.
|
|
141
|
-
this.
|
|
142
|
-
((this.
|
|
143
|
-
|
|
144
|
-
const t = Math.random() * i.body._e * 0.3,
|
|
145
|
-
s = Math.round(i.body._e + t),
|
|
146
|
-
e = i.body.e ? ` (${i.body.e})` : "";
|
|
147
|
-
E.info(`Admin requested disconnect${e}, reconnecting in ${s}ms`),
|
|
148
|
-
this.sn(),
|
|
149
|
-
setTimeout(() => this.en(), s);
|
|
150
|
-
})),
|
|
151
|
-
(this.De = this.Ze("ttl", (i) => {
|
|
154
|
+
this.Me ||
|
|
155
|
+
this.xe ||
|
|
156
|
+
((this.Me = this.en("ddr", (i) => {
|
|
157
|
+
var t, s, e;
|
|
152
158
|
if (!i.body || "number" != typeof i.body.on) return;
|
|
153
|
-
const
|
|
159
|
+
const n =
|
|
160
|
+
(null === (t = this.h) || void 0 === t ? void 0 : t.vt()) || d,
|
|
161
|
+
r = (null === (s = this.h) || void 0 === s ? void 0 : s.gt()) || m,
|
|
162
|
+
o = (null === (e = this.h) || void 0 === e ? void 0 : e.bt()) || c,
|
|
163
|
+
h = Math.min(o, a(n, n * r)),
|
|
164
|
+
l = Math.round(i.body.on + h),
|
|
165
|
+
u = i.body.e ? ` (${i.body.e})` : "";
|
|
166
|
+
E.info(
|
|
167
|
+
`Admin requested disconnect${u}, reconnecting in ${l}ms (r_ms=${i.body.on} + backoff=${h})`,
|
|
168
|
+
),
|
|
169
|
+
this.hn(),
|
|
170
|
+
setTimeout(() => this.an(), l);
|
|
171
|
+
})),
|
|
172
|
+
(this.xe = this.en("ttl", (i) => {
|
|
173
|
+
if (!i.body || "number" != typeof i.body.ln) return;
|
|
174
|
+
const t = i.body.ln;
|
|
154
175
|
E.info(`Time to live set to ${t}ms, will reconnect when expired`),
|
|
155
176
|
"sharedworker" !== this.Fe &&
|
|
156
|
-
("string" == typeof i.body.
|
|
157
|
-
null !== this.
|
|
158
|
-
(this.
|
|
159
|
-
(this.
|
|
177
|
+
("string" == typeof i.body.cn && (this.Ki = i.body.cn),
|
|
178
|
+
null !== this.Yi && window.clearTimeout(this.Yi),
|
|
179
|
+
(this.Yi = window.setTimeout(() => {
|
|
180
|
+
(this.Yi = null),
|
|
160
181
|
E.info("Time to live expired, performing gapless reconnection"),
|
|
161
|
-
this.
|
|
182
|
+
this.un();
|
|
162
183
|
}, t)));
|
|
163
184
|
})));
|
|
164
185
|
}
|
|
165
|
-
|
|
186
|
+
dn() {
|
|
166
187
|
this.Se ||
|
|
167
188
|
this.ke ||
|
|
168
189
|
((this.ye = () => {
|
|
169
|
-
(this.Re = !0), (this.
|
|
190
|
+
(this.Re = !0), (this.Zi = !1);
|
|
170
191
|
}),
|
|
171
192
|
window.addEventListener("beforeunload", this.ye),
|
|
172
193
|
(this.Se = () => {
|
|
173
194
|
var i;
|
|
174
195
|
this.Re = !0;
|
|
175
|
-
(this.
|
|
176
|
-
(null === (i = this.We) || void 0 === i ? void 0 : i.
|
|
196
|
+
(this.Vi ||
|
|
197
|
+
(null === (i = this.We) || void 0 === i ? void 0 : i.Ie())) &&
|
|
177
198
|
(E.info("Page unloading, closing real-time connection gracefully"),
|
|
178
|
-
(this.
|
|
179
|
-
this.
|
|
199
|
+
(this.Zi = !1),
|
|
200
|
+
this.hn());
|
|
180
201
|
}),
|
|
181
202
|
window.addEventListener("pagehide", this.Se),
|
|
182
203
|
(this.ke = (i) => {
|
|
183
204
|
var t;
|
|
184
205
|
const s =
|
|
185
|
-
this.
|
|
206
|
+
this.Vi || (null === (t = this.We) || void 0 === t ? void 0 : t.Ie());
|
|
186
207
|
i.persisted &&
|
|
187
|
-
this.
|
|
208
|
+
this.gn() &&
|
|
188
209
|
!s &&
|
|
189
210
|
(E.info("Page restored from bfcache, reconnecting"),
|
|
190
211
|
(this.Re = !1),
|
|
191
|
-
this.
|
|
192
|
-
this.
|
|
212
|
+
this.He(),
|
|
213
|
+
this.an());
|
|
193
214
|
}),
|
|
194
215
|
window.addEventListener("pageshow", this.ke));
|
|
195
216
|
}
|
|
@@ -199,35 +220,35 @@ export default class nr extends t {
|
|
|
199
220
|
$t(i) {
|
|
200
221
|
this.T = i;
|
|
201
222
|
}
|
|
202
|
-
|
|
223
|
+
en(i, t) {
|
|
203
224
|
if ("function" != typeof t) return null;
|
|
204
|
-
let s = this.
|
|
205
|
-
return s || ((s = new f()), this.
|
|
225
|
+
let s = this.De.get(i);
|
|
226
|
+
return s || ((s = new f()), this.De.set(i, s), r.S(s)), s.Kt(t);
|
|
206
227
|
}
|
|
207
|
-
|
|
208
|
-
const s = this.
|
|
228
|
+
mn(i, t) {
|
|
229
|
+
const s = this.De.get(i);
|
|
209
230
|
s && s.removeSubscription(t);
|
|
210
231
|
}
|
|
211
|
-
|
|
232
|
+
gn() {
|
|
212
233
|
return Boolean(this.mite && this.Wi);
|
|
213
234
|
}
|
|
214
|
-
|
|
235
|
+
fn() {
|
|
215
236
|
if (!this.Hi) return !1;
|
|
216
237
|
return Math.floor(new Date().valueOf() / 1e3) >= this.Hi;
|
|
217
238
|
}
|
|
218
|
-
|
|
239
|
+
sn() {
|
|
219
240
|
(this.mite = null),
|
|
220
241
|
(this.Wi = null),
|
|
221
242
|
(this.Gi = null),
|
|
222
243
|
(this.Hi = null),
|
|
223
244
|
(this.Ki = null),
|
|
224
245
|
this.C &&
|
|
225
|
-
(this.C.Qt(s.Tt.
|
|
226
|
-
this.C.Qt(s.Tt.
|
|
227
|
-
this.C.Qt(s.Tt.
|
|
228
|
-
this.C.Qt(s.Tt.
|
|
246
|
+
(this.C.Qt(s.Tt.Qe),
|
|
247
|
+
this.C.Qt(s.Tt.Xe),
|
|
248
|
+
this.C.Qt(s.Tt.Ye),
|
|
249
|
+
this.C.Qt(s.Tt.Ze));
|
|
229
250
|
}
|
|
230
|
-
|
|
251
|
+
pn(i, t) {
|
|
231
252
|
const e = () => {
|
|
232
253
|
"function" == typeof t && t();
|
|
233
254
|
},
|
|
@@ -237,17 +258,17 @@ export default class nr extends t {
|
|
|
237
258
|
return (
|
|
238
259
|
E.error("NetworkManager or StorageManager not available"), void e()
|
|
239
260
|
);
|
|
240
|
-
if (!this.h || !this.h.
|
|
261
|
+
if (!this.h || !this.h.vn())
|
|
241
262
|
return (
|
|
242
263
|
E.info("Real-time messaging is not enabled, skipping refresh"), void e()
|
|
243
264
|
);
|
|
244
|
-
this.
|
|
265
|
+
this.gn()
|
|
245
266
|
? E.info("Refreshing real-time messaging configuration")
|
|
246
267
|
: E.info("Fetching initial real-time messaging configuration");
|
|
247
268
|
const o = n.Z({}, !0),
|
|
248
|
-
a = n.tt(o, h.it.
|
|
269
|
+
a = n.tt(o, h.it.wn),
|
|
249
270
|
c = new Date().valueOf();
|
|
250
|
-
h.nt(r, h.it.
|
|
271
|
+
h.nt(r, h.it.wn, c),
|
|
251
272
|
l.ot({
|
|
252
273
|
url: `${n.ht()}/dust/config`,
|
|
253
274
|
headers: a,
|
|
@@ -269,16 +290,16 @@ export default class nr extends t {
|
|
|
269
290
|
E.info(
|
|
270
291
|
"Received real-time messaging configuration from server",
|
|
271
292
|
),
|
|
272
|
-
r.It(s.Tt.
|
|
273
|
-
r.It(s.Tt.
|
|
274
|
-
t.auth ? r.It(s.Tt.
|
|
275
|
-
t.expiration ? r.It(s.Tt.
|
|
276
|
-
this.
|
|
293
|
+
r.It(s.Tt.Qe, t.mite),
|
|
294
|
+
r.It(s.Tt.Xe, t.host),
|
|
295
|
+
t.auth ? r.It(s.Tt.Ye, t.auth) : r.Qt(s.Tt.Ye),
|
|
296
|
+
t.expiration ? r.It(s.Tt.Ze, t.expiration) : r.Qt(s.Tt.Ze),
|
|
297
|
+
this.an(),
|
|
277
298
|
"function" == typeof i && i())
|
|
278
299
|
: (E.info(
|
|
279
300
|
"Real-time messaging configuration not available - this SDK version may not be supported",
|
|
280
301
|
),
|
|
281
|
-
this.
|
|
302
|
+
this.sn(),
|
|
282
303
|
e());
|
|
283
304
|
},
|
|
284
305
|
error: (i) => {
|
|
@@ -286,20 +307,20 @@ export default class nr extends t {
|
|
|
286
307
|
},
|
|
287
308
|
});
|
|
288
309
|
}
|
|
289
|
-
|
|
290
|
-
if (!this.h || !this.h.
|
|
291
|
-
if (!this.
|
|
310
|
+
an() {
|
|
311
|
+
if (!this.h || !this.h.vn()) return;
|
|
312
|
+
if (!this.gn())
|
|
292
313
|
return void E.error(
|
|
293
314
|
"Cannot start real-time subscription without configuration",
|
|
294
315
|
);
|
|
295
|
-
if (this.
|
|
316
|
+
if (this.fn())
|
|
296
317
|
return (
|
|
297
318
|
E.info(
|
|
298
319
|
"Real-time messaging auth token has expired, refreshing configuration",
|
|
299
320
|
),
|
|
300
|
-
void this.
|
|
321
|
+
void this.pn(
|
|
301
322
|
() => {
|
|
302
|
-
this.
|
|
323
|
+
this.an();
|
|
303
324
|
},
|
|
304
325
|
() => {
|
|
305
326
|
E.error(
|
|
@@ -313,25 +334,25 @@ export default class nr extends t {
|
|
|
313
334
|
if (i && t)
|
|
314
335
|
switch (this.Fe) {
|
|
315
336
|
case "sharedworker":
|
|
316
|
-
this.
|
|
337
|
+
this.bn(i, t);
|
|
317
338
|
break;
|
|
318
339
|
case "direct":
|
|
319
|
-
this.
|
|
340
|
+
this.Vi &&
|
|
320
341
|
(E.info(
|
|
321
342
|
"Real-time connection already exists, closing before starting new subscription",
|
|
322
343
|
),
|
|
323
|
-
this.
|
|
324
|
-
this.
|
|
344
|
+
this.hn()),
|
|
345
|
+
this.Sn();
|
|
325
346
|
}
|
|
326
347
|
}
|
|
327
|
-
|
|
348
|
+
kn() {
|
|
328
349
|
const i = this.mite,
|
|
329
350
|
t = this.Oi || this.Wi;
|
|
330
351
|
return i && t
|
|
331
|
-
?
|
|
352
|
+
? si(t, i, this._i, this.Gi || void 0, this.Ki || void 0)
|
|
332
353
|
: null;
|
|
333
354
|
}
|
|
334
|
-
|
|
355
|
+
bn(i, t) {
|
|
335
356
|
var s, e, n;
|
|
336
357
|
if ((this.We || this.Ae(), !this.We))
|
|
337
358
|
return (
|
|
@@ -339,7 +360,7 @@ export default class nr extends t {
|
|
|
339
360
|
"SharedWorker initialization failed, falling back to direct EventSource",
|
|
340
361
|
),
|
|
341
362
|
(this.Fe = "direct"),
|
|
342
|
-
void this.
|
|
363
|
+
void this.yn()
|
|
343
364
|
);
|
|
344
365
|
this.Oi && E.info(`Using custom real-time messaging host: ${this.Oi}`),
|
|
345
366
|
E.info("Starting real-time subscription via SharedWorker");
|
|
@@ -350,19 +371,19 @@ export default class nr extends t {
|
|
|
350
371
|
mite: i,
|
|
351
372
|
Wi: t,
|
|
352
373
|
auth: this.Gi || void 0,
|
|
353
|
-
|
|
374
|
+
$n: { Rn: r, Cn: o, Dn: h },
|
|
354
375
|
});
|
|
355
376
|
}
|
|
356
|
-
|
|
357
|
-
this.
|
|
377
|
+
yn() {
|
|
378
|
+
this.Vi &&
|
|
358
379
|
(E.info(
|
|
359
380
|
"Real-time connection already exists, closing before starting new subscription",
|
|
360
381
|
),
|
|
361
|
-
this.
|
|
362
|
-
this.
|
|
382
|
+
this.Mn()),
|
|
383
|
+
this.Sn();
|
|
363
384
|
}
|
|
364
|
-
|
|
365
|
-
const t = this.
|
|
385
|
+
Sn(i) {
|
|
386
|
+
const t = this.kn();
|
|
366
387
|
if (t) {
|
|
367
388
|
this.Oi && E.info(`Using custom real-time messaging host: ${this.Oi}`);
|
|
368
389
|
try {
|
|
@@ -374,14 +395,15 @@ export default class nr extends t {
|
|
|
374
395
|
),
|
|
375
396
|
i.close())
|
|
376
397
|
: E.info("Real-time messaging connection established"),
|
|
377
|
-
(this.
|
|
378
|
-
(this.
|
|
398
|
+
(this.Vi = s),
|
|
399
|
+
(this._i = 0),
|
|
379
400
|
(this.we = null),
|
|
380
|
-
(this.
|
|
381
|
-
(this.Ne = !0)
|
|
401
|
+
(this.Zi = !0),
|
|
402
|
+
(this.Ne = !0),
|
|
403
|
+
(this.Te = new Date().valueOf());
|
|
382
404
|
}),
|
|
383
405
|
s.addEventListener("msg", (i) => {
|
|
384
|
-
this.
|
|
406
|
+
this.xn(i.data);
|
|
385
407
|
}),
|
|
386
408
|
(s.onerror = () => {
|
|
387
409
|
const t = s.readyState;
|
|
@@ -390,25 +412,25 @@ export default class nr extends t {
|
|
|
390
412
|
(0 === t
|
|
391
413
|
? E.info("Real-time messaging failed to connect")
|
|
392
414
|
: E.info("Real-time messaging connection lost")),
|
|
393
|
-
i && this.
|
|
415
|
+
i && this.Vi !== s
|
|
394
416
|
? (E.info(
|
|
395
417
|
"Gapless reconnection failed, keeping old connection",
|
|
396
418
|
),
|
|
397
419
|
s.close(),
|
|
398
|
-
void (this.
|
|
399
|
-
: (this.
|
|
400
|
-
this.Ne && (this.
|
|
420
|
+
void (this.Zi && this._i < this.Qi && this.jn()))
|
|
421
|
+
: (this.Mn(),
|
|
422
|
+
this.Ne && (this.Be++, this.Be > 1)
|
|
401
423
|
? (E.info(
|
|
402
424
|
"Real-time messaging connection lost twice after successful connect (likely multi-tab conflict), yielding to other tab",
|
|
403
425
|
),
|
|
404
|
-
void (this.
|
|
405
|
-
: void (this.
|
|
406
|
-
? this.
|
|
407
|
-
: (this.
|
|
426
|
+
void (this.Zi = !1))
|
|
427
|
+
: void (this.Zi && this._i < this.Qi
|
|
428
|
+
? this.jn()
|
|
429
|
+
: (this._i >= this.Qi &&
|
|
408
430
|
E.error(
|
|
409
|
-
`Max retry attempts (${this.
|
|
431
|
+
`Max retry attempts (${this.Qi}) reached for real-time messaging, giving up for current session`,
|
|
410
432
|
),
|
|
411
|
-
(this.
|
|
433
|
+
(this.Zi = !1))))
|
|
412
434
|
);
|
|
413
435
|
});
|
|
414
436
|
} catch (i) {
|
|
@@ -420,9 +442,9 @@ export default class nr extends t {
|
|
|
420
442
|
}
|
|
421
443
|
}
|
|
422
444
|
}
|
|
423
|
-
|
|
445
|
+
jn() {
|
|
424
446
|
var i, t, s;
|
|
425
|
-
this.
|
|
447
|
+
this._i++;
|
|
426
448
|
const e = (null === (i = this.h) || void 0 === i ? void 0 : i.vt()) || d,
|
|
427
449
|
n = (null === (t = this.h) || void 0 === t ? void 0 : t.gt()) || m,
|
|
428
450
|
r = (null === (s = this.h) || void 0 === s ? void 0 : s.bt()) || c;
|
|
@@ -431,48 +453,49 @@ export default class nr extends t {
|
|
|
431
453
|
const h = Math.min(r, a(e, o * n));
|
|
432
454
|
(this.we = h),
|
|
433
455
|
E.info(
|
|
434
|
-
`Retrying real-time messaging connection in ${h}ms (attempt ${this.
|
|
456
|
+
`Retrying real-time messaging connection in ${h}ms (attempt ${this._i}/${this.Qi})`,
|
|
435
457
|
),
|
|
436
|
-
(this.
|
|
437
|
-
(this.
|
|
458
|
+
(this.Xi = window.setTimeout(() => {
|
|
459
|
+
(this.Xi = null), this.an();
|
|
438
460
|
}, h));
|
|
439
461
|
}
|
|
440
|
-
|
|
441
|
-
if (this.
|
|
442
|
-
if (this.
|
|
462
|
+
un() {
|
|
463
|
+
if (this.gn()) {
|
|
464
|
+
if (this.fn())
|
|
443
465
|
return (
|
|
444
466
|
E.info(
|
|
445
467
|
"Auth token expired during gapless reconnection, falling back to regular reconnection",
|
|
446
468
|
),
|
|
447
|
-
this.
|
|
448
|
-
void this.
|
|
469
|
+
this.hn(),
|
|
470
|
+
void this.an()
|
|
449
471
|
);
|
|
450
|
-
null !== this.
|
|
451
|
-
this.
|
|
472
|
+
null !== this.Yi && (window.clearTimeout(this.Yi), (this.Yi = null)),
|
|
473
|
+
this.Sn(this.Vi || void 0);
|
|
452
474
|
} else E.error("Cannot perform gapless reconnection without configuration");
|
|
453
475
|
}
|
|
454
|
-
|
|
476
|
+
hn() {
|
|
455
477
|
var i;
|
|
456
|
-
switch (this.Fe) {
|
|
478
|
+
switch (((this.Te = null), this.Fe)) {
|
|
457
479
|
case "sharedworker":
|
|
458
480
|
null === (i = this.We) || void 0 === i || i.disconnect();
|
|
459
481
|
break;
|
|
460
482
|
case "direct":
|
|
461
|
-
this.
|
|
483
|
+
this.Mn();
|
|
462
484
|
}
|
|
463
485
|
}
|
|
464
|
-
|
|
465
|
-
null !== this.
|
|
466
|
-
null !== this.
|
|
467
|
-
this.
|
|
468
|
-
|
|
469
|
-
(this.
|
|
486
|
+
Mn() {
|
|
487
|
+
null !== this.Xi && (window.clearTimeout(this.Xi), (this.Xi = null)),
|
|
488
|
+
null !== this.Yi && (window.clearTimeout(this.Yi), (this.Yi = null)),
|
|
489
|
+
(this.Te = null),
|
|
490
|
+
this.Vi &&
|
|
491
|
+
(this.Vi.close(),
|
|
492
|
+
(this.Vi = null),
|
|
470
493
|
E.info("Real-time messaging connection closed"));
|
|
471
494
|
}
|
|
472
|
-
|
|
495
|
+
xn(i) {
|
|
473
496
|
try {
|
|
474
497
|
const t = JSON.parse(i);
|
|
475
|
-
this.
|
|
498
|
+
this.Pe(t);
|
|
476
499
|
} catch (i) {
|
|
477
500
|
E.warn(
|
|
478
501
|
`Failed to parse real-time message: ${
|
|
@@ -482,33 +505,33 @@ export default class nr extends t {
|
|
|
482
505
|
}
|
|
483
506
|
}
|
|
484
507
|
changeUser(i = !1) {
|
|
485
|
-
this.
|
|
508
|
+
this.hn(),
|
|
486
509
|
i ||
|
|
487
|
-
(this.
|
|
510
|
+
(this.gn() &&
|
|
488
511
|
E.info(
|
|
489
512
|
"Clearing cached real-time messaging configuration for user change",
|
|
490
513
|
),
|
|
491
|
-
this.
|
|
492
|
-
this.
|
|
514
|
+
this.sn()),
|
|
515
|
+
this.He();
|
|
493
516
|
}
|
|
494
517
|
clearData(i = !1) {
|
|
495
|
-
(this.
|
|
496
|
-
this.
|
|
518
|
+
(this.Zi = !1),
|
|
519
|
+
this.hn(),
|
|
497
520
|
i &&
|
|
498
|
-
(this.
|
|
521
|
+
(this.gn() &&
|
|
499
522
|
E.info(
|
|
500
523
|
"Clearing cached real-time messaging configuration (wipeData)",
|
|
501
524
|
),
|
|
502
|
-
this.
|
|
503
|
-
this.
|
|
525
|
+
this.sn()),
|
|
526
|
+
this.He();
|
|
504
527
|
}
|
|
505
528
|
destroy() {
|
|
506
|
-
(this.
|
|
529
|
+
(this.Zi = !1),
|
|
530
|
+
this.hn(),
|
|
507
531
|
this.sn(),
|
|
508
|
-
this.Ye(),
|
|
509
532
|
this.We && (this.We.destroy(), (this.We = null)),
|
|
510
|
-
this.
|
|
511
|
-
this.
|
|
533
|
+
this.Me && (this.mn("ddr", this.Me), (this.Me = null)),
|
|
534
|
+
this.xe && (this.mn("ttl", this.xe), (this.xe = null)),
|
|
512
535
|
this.ye &&
|
|
513
536
|
(window.removeEventListener("beforeunload", this.ye), (this.ye = null)),
|
|
514
537
|
this.Se &&
|
|
@@ -1,2 +1,2 @@
|
|
|
1
1
|
export const DUST_SHARED_WORKER_CODE =
|
|
2
|
-
'\n"use strict";\nconst workerSelf = self;\nlet eventSource = null;\nlet currentConfig = null;\nlet retryCount = 0;\nlet retryTimeoutId = null;\nlet connectionInProgress = false;\nconst maxRetries = 5;\nconst connectedPorts = new Map();\nlet lastSleepMs = null;\nlet currentRcs = null;\nlet ttlTimeoutId = null;\nlet leaderPortId = null;\nlet ddrTimeoutId = null;\nconst fn = {\n startConnection: null,\n handleMessage: null,\n};\nfunction broadcast(message) {\n connectedPorts.forEach((portInfo, portId) => {\n try {\n portInfo.port.postMessage(message);\n }\n catch (_a) {\n connectedPorts.delete(portId);\n }\n });\n}\nfunction randomInclusive(min, max) {\n return Math.floor(Math.random() * (max - min + 1)) + min;\n}\nfunction electLeader() {\n if (leaderPortId && connectedPorts.has(leaderPortId)) {\n return;\n }\n const firstPortId = connectedPorts.keys().next().value;\n leaderPortId = firstPortId || null;\n if (leaderPortId) {\n console.log("[Braze Real-Time] Elected leader port:", leaderPortId);\n }\n}\nfunction promoteToLeader(portId) {\n if (connectedPorts.has(portId) && leaderPortId !== portId) {\n leaderPortId = portId;\n console.log("[Braze Real-Time] Promoted to leader (tab became active):", portId);\n }\n}\nfunction sendToLeader(message) {\n electLeader();\n if (!leaderPortId) {\n console.warn("[Braze Real-Time] No leader to send message to");\n return;\n }\n const leader = connectedPorts.get(leaderPortId);\n if (leader) {\n try {\n leader.port.postMessage(message);\n }\n catch (_a) {\n connectedPorts.delete(leaderPortId);\n leaderPortId = null;\n sendToLeader(message);\n }\n }\n}\nfunction closeConnection() {\n connectionInProgress = false;\n if (retryTimeoutId !== null) {\n clearTimeout(retryTimeoutId);\n retryTimeoutId = null;\n }\n if (ttlTimeoutId !== null) {\n clearTimeout(ttlTimeoutId);\n ttlTimeoutId = null;\n }\n if (ddrTimeoutId !== null) {\n clearTimeout(ddrTimeoutId);\n ddrTimeoutId = null;\n }\n if (eventSource) {\n eventSource.close();\n eventSource = null;\n broadcast({ type: "disconnected" });\n }\n}\nfunction retryWithBackoff() {\n if (!currentConfig) {\n return;\n }\n retryCount++;\n const { minSleepMs, maxSleepMs, scaleFactor } = currentConfig.backoff;\n let previousSleepMs = lastSleepMs;\n if (previousSleepMs == null || previousSleepMs < minSleepMs) {\n previousSleepMs = minSleepMs;\n }\n const backoffMs = Math.min(maxSleepMs, randomInclusive(minSleepMs, previousSleepMs * scaleFactor));\n lastSleepMs = backoffMs;\n console.log("[Braze Real-Time] Retrying in " + backoffMs + "ms (attempt " + retryCount + "/" + maxRetries + ")");\n retryTimeoutId = setTimeout(function () {\n retryTimeoutId = null;\n fn.startConnection();\n }, backoffMs);\n}\nfunction startConnection(oldEventSourceToClose) {\n if (!currentConfig) {\n return;\n }\n if (eventSource && !oldEventSourceToClose) {\n console.warn("[Braze Real-Time] Connection already exists");\n return;\n }\n if (connectionInProgress && !oldEventSourceToClose) {\n console.warn("[Braze Real-Time] Connection attempt already in progress");\n return;\n }\n connectionInProgress = true;\n const { dustHost, mite, auth } = currentConfig;\n const dustHostWithScheme = /^https?:\\/\\//i.test(dustHost) ? dustHost : "https://" + dustHost;\n let queryString = "mite=" + encodeURIComponent(mite) + "&attempts=" + retryCount;\n if (auth) {\n queryString += "&auth=" + encodeURIComponent(auth);\n }\n if (currentRcs) {\n queryString += "&rcs=" + encodeURIComponent(currentRcs);\n }\n const subscribeUrl = dustHostWithScheme + "/sse?" + queryString;\n try {\n const newEventSource = new EventSource(subscribeUrl);\n newEventSource.onopen = function () {\n if (oldEventSourceToClose) {\n console.log("[Braze Real-Time] Gapless reconnection: new connection established, closing old connection");\n oldEventSourceToClose.close();\n }\n else {\n console.log("[Braze Real-Time] Connection established");\n }\n eventSource = newEventSource;\n connectionInProgress = false;\n retryCount = 0;\n lastSleepMs = null;\n broadcast({ type: "connected" });\n };\n newEventSource.addEventListener("msg", function (event) {\n fn.handleMessage(event.data);\n });\n newEventSource.onerror = function () {\n const readyState = newEventSource ? newEventSource.readyState : -1;\n if (readyState === 0) {\n console.log("[Braze Real-Time] Failed to connect");\n }\n else {\n console.log("[Braze Real-Time] Connection lost");\n }\n if (oldEventSourceToClose && eventSource !== newEventSource) {\n console.log("[Braze Real-Time] Gapless reconnection failed, keeping old connection");\n newEventSource.close();\n connectionInProgress = false;\n if (retryCount < maxRetries) {\n retryWithBackoff();\n }\n return;\n }\n closeConnection();\n if (retryCount < maxRetries) {\n retryWithBackoff();\n }\n else {\n console.error("[Braze Real-Time] Max retries reached");\n broadcast({ type: "error", error: "Max retry attempts reached" });\n }\n };\n }\n catch (error) {\n connectionInProgress = false;\n console.error("[Braze Real-Time] Failed to create EventSource:", error);\n broadcast({ type: "error", error: String(error) });\n }\n}\nfunction handleTtlMessage(tMs, rcs) {\n if (typeof tMs !== "number") {\n return;\n }\n if (typeof rcs === "string") {\n currentRcs = rcs;\n }\n console.log("[Braze Real-Time] TTL set to " + tMs + "ms, will perform gapless reconnection when expired");\n if (ttlTimeoutId !== null) {\n clearTimeout(ttlTimeoutId);\n }\n ttlTimeoutId = setTimeout(function () {\n ttlTimeoutId = null;\n console.log("[Braze Real-Time] TTL expired, performing gapless reconnection");\n startConnection(eventSource || undefined);\n }, tMs);\n}\nfunction handleDdrMessage(rMs, reason) {\n if (typeof rMs !== "number") {\n return;\n }\n const jitter = Math.random() * rMs * 0.3;\n const waitMs = Math.round(rMs + jitter);\n const reasonStr = reason ? " (" + reason + ")" : "";\n console.log("[Braze Real-Time] Admin requested disconnect" + reasonStr + ", reconnecting in " + waitMs + "ms");\n if (ddrTimeoutId !== null) {\n clearTimeout(ddrTimeoutId);\n }\n closeConnection();\n ddrTimeoutId = setTimeout(function () {\n ddrTimeoutId = null;\n fn.startConnection();\n }, waitMs);\n}\nfunction handleMessage(data) {\n try {\n const message = JSON.parse(data);\n if (!message.type) {\n console.warn("[Braze Real-Time] Message without type:", message);\n return;\n }\n if (message.type === "ttl" && message.body) {\n handleTtlMessage(message.body.t_ms, message.body.rcs);\n return;\n }\n if (message.type === "ddr" && message.body) {\n handleDdrMessage(message.body.r_ms, message.body.e);\n return;\n }\n console.log("[Braze Real-Time] Routing \'" + message.type + "\' message to leader");\n sendToLeader({ type: "message", data: message });\n }\n catch (error) {\n console.warn("[Braze Real-Time] Failed to parse message:", error);\n }\n}\nfn.startConnection = startConnection;\nfn.handleMessage = handleMessage;\nfunction handlePortMessage(port, portId, message) {\n switch (message.type) {\n case "connect":\n if (currentConfig &&\n (currentConfig.mite !== message.config.mite || currentConfig.dustHost !== message.config.dustHost)) {\n console.log("[Braze Real-Time] Config changed, reconnecting");\n closeConnection();\n retryCount = 0;\n lastSleepMs = null;\n currentRcs = null;\n }\n currentConfig = message.config;\n electLeader();\n if (!eventSource && !connectionInProgress) {\n startConnection();\n }\n else if (eventSource) {\n port.postMessage({ type: "connected" });\n }\n break;\n case "disconnect":\n connectedPorts.delete(portId);\n if (portId === leaderPortId) {\n leaderPortId = null;\n electLeader();\n }\n if (connectedPorts.size === 0) {\n console.log("[Braze Real-Time] No more ports, closing connection");\n closeConnection();\n currentConfig = null;\n currentRcs = null;\n leaderPortId = null;\n }\n break;\n case "tab_active":\n promoteToLeader(portId);\n break;\n case "ping":\n port.postMessage({ type: "pong" });\n break;\n default:\n console.warn("[Braze Real-Time] Unknown message type:", message.type);\n }\n}\nworkerSelf.onconnect = function (event) {\n const port = event.ports[0];\n const portId = "port-" + Date.now() + "-" + Math.random().toString(36).substr(2, 9);\n connectedPorts.set(portId, { port: port });\n port.onmessage = function (messageEvent) {\n try {\n handlePortMessage(port, portId, messageEvent.data);\n }\n catch (error) {\n console.error("[Braze Real-Time] Error handling message:", error);\n }\n };\n port.onmessageerror = function () {\n console.warn("[Braze Real-Time] Message error from port:", portId);\n connectedPorts.delete(portId);\n };\n port.start();\n};\n';
|
|
2
|
+
'\n"use strict";\nconst workerSelf = self;\nlet eventSource = null;\nlet currentConfig = null;\nlet retryCount = 0;\nlet retryTimeoutId = null;\nlet connectionInProgress = false;\nconst maxRetries = 5;\nconst connectedPorts = new Map();\nlet lastSleepMs = null;\nlet currentRcs = null;\nlet ttlTimeoutId = null;\nlet leaderPortId = null;\nlet ddrTimeoutId = null;\nconst fn = {\n startConnection: null,\n handleMessage: null,\n};\nfunction broadcast(message) {\n connectedPorts.forEach((portInfo, portId) => {\n try {\n portInfo.port.postMessage(message);\n }\n catch (_a) {\n connectedPorts.delete(portId);\n }\n });\n}\nfunction randomInclusive(min, max) {\n return Math.floor(Math.random() * (max - min + 1)) + min;\n}\nfunction electLeader() {\n if (leaderPortId && connectedPorts.has(leaderPortId)) {\n return;\n }\n const firstPortId = connectedPorts.keys().next().value;\n leaderPortId = firstPortId || null;\n if (leaderPortId) {\n console.log("[Braze Real-Time] Elected leader port:", leaderPortId);\n }\n}\nfunction promoteToLeader(portId) {\n if (connectedPorts.has(portId) && leaderPortId !== portId) {\n leaderPortId = portId;\n console.log("[Braze Real-Time] Promoted to leader (tab became active):", portId);\n }\n}\nfunction sendToLeader(message) {\n electLeader();\n if (!leaderPortId) {\n console.warn("[Braze Real-Time] No leader to send message to");\n return;\n }\n const leader = connectedPorts.get(leaderPortId);\n if (leader) {\n try {\n leader.port.postMessage(message);\n }\n catch (_a) {\n connectedPorts.delete(leaderPortId);\n leaderPortId = null;\n sendToLeader(message);\n }\n }\n}\nfunction closeConnection() {\n connectionInProgress = false;\n if (retryTimeoutId !== null) {\n clearTimeout(retryTimeoutId);\n retryTimeoutId = null;\n }\n if (ttlTimeoutId !== null) {\n clearTimeout(ttlTimeoutId);\n ttlTimeoutId = null;\n }\n if (ddrTimeoutId !== null) {\n clearTimeout(ddrTimeoutId);\n ddrTimeoutId = null;\n }\n if (eventSource) {\n eventSource.close();\n eventSource = null;\n broadcast({ type: "disconnected" });\n }\n}\nfunction retryWithBackoff() {\n if (!currentConfig) {\n return;\n }\n retryCount++;\n const { minSleepMs, maxSleepMs, scaleFactor } = currentConfig.backoff;\n let previousSleepMs = lastSleepMs;\n if (previousSleepMs == null || previousSleepMs < minSleepMs) {\n previousSleepMs = minSleepMs;\n }\n const backoffMs = Math.min(maxSleepMs, randomInclusive(minSleepMs, previousSleepMs * scaleFactor));\n lastSleepMs = backoffMs;\n console.log(`[Braze Real-Time] Retrying in ${backoffMs}ms (attempt ${retryCount}/${maxRetries})`);\n retryTimeoutId = setTimeout(function () {\n retryTimeoutId = null;\n fn.startConnection();\n }, backoffMs);\n}\nfunction startConnection(oldEventSourceToClose) {\n if (!currentConfig) {\n return;\n }\n if (eventSource && !oldEventSourceToClose) {\n console.warn("[Braze Real-Time] Connection already exists");\n return;\n }\n if (connectionInProgress && !oldEventSourceToClose) {\n console.warn("[Braze Real-Time] Connection attempt already in progress");\n return;\n }\n connectionInProgress = true;\n const { dustHost, mite, auth } = currentConfig;\n const dustHostWithScheme = /^https?:\\/\\//i.test(dustHost) ? dustHost : `https://${dustHost}`;\n let queryString = `mite=${encodeURIComponent(mite)}&attempts=${retryCount}`;\n if (auth) {\n queryString += `&auth=${encodeURIComponent(auth)}`;\n }\n if (currentRcs) {\n queryString += `&rcs=${encodeURIComponent(currentRcs)}`;\n }\n const subscribeUrl = `${dustHostWithScheme}/sse?${queryString}`;\n try {\n const newEventSource = new EventSource(subscribeUrl);\n newEventSource.onopen = function () {\n if (oldEventSourceToClose) {\n console.log("[Braze Real-Time] Gapless reconnection: new connection established, closing old connection");\n oldEventSourceToClose.close();\n }\n else {\n console.log("[Braze Real-Time] Connection established");\n }\n eventSource = newEventSource;\n connectionInProgress = false;\n retryCount = 0;\n lastSleepMs = null;\n broadcast({ type: "connected" });\n };\n newEventSource.addEventListener("msg", function (event) {\n fn.handleMessage(event.data);\n });\n newEventSource.onerror = function () {\n const readyState = newEventSource ? newEventSource.readyState : -1;\n if (readyState === 0) {\n console.log("[Braze Real-Time] Failed to connect");\n }\n else {\n console.log("[Braze Real-Time] Connection lost");\n }\n if (oldEventSourceToClose && eventSource !== newEventSource) {\n console.log("[Braze Real-Time] Gapless reconnection failed, keeping old connection");\n newEventSource.close();\n connectionInProgress = false;\n if (retryCount < maxRetries) {\n retryWithBackoff();\n }\n return;\n }\n closeConnection();\n if (retryCount < maxRetries) {\n retryWithBackoff();\n }\n else {\n console.error("[Braze Real-Time] Max retries reached");\n broadcast({ type: "error", error: "Max retry attempts reached" });\n }\n };\n }\n catch (error) {\n connectionInProgress = false;\n console.error("[Braze Real-Time] Failed to create EventSource:", error);\n broadcast({ type: "error", error: String(error) });\n }\n}\nfunction handleTtlMessage(tMs, rcs) {\n if (typeof tMs !== "number") {\n return;\n }\n if (typeof rcs === "string") {\n currentRcs = rcs;\n }\n console.log(`[Braze Real-Time] TTL set to ${tMs}ms, will perform gapless reconnection when expired`);\n if (ttlTimeoutId !== null) {\n clearTimeout(ttlTimeoutId);\n }\n ttlTimeoutId = setTimeout(function () {\n ttlTimeoutId = null;\n console.log("[Braze Real-Time] TTL expired, performing gapless reconnection");\n startConnection(eventSource || undefined);\n }, tMs);\n}\nfunction handleDdrMessage(rMs, reason) {\n if (typeof rMs !== "number") {\n return;\n }\n const backoffConfig = currentConfig === null || currentConfig === void 0 ? void 0 : currentConfig.backoff;\n const minSleepMs = (backoffConfig === null || backoffConfig === void 0 ? void 0 : backoffConfig.minSleepMs) || 10000;\n const scaleFactor = (backoffConfig === null || backoffConfig === void 0 ? void 0 : backoffConfig.scaleFactor) || 3;\n const maxSleepMs = (backoffConfig === null || backoffConfig === void 0 ? void 0 : backoffConfig.maxSleepMs) || 300000;\n const backoffMs = Math.min(maxSleepMs, randomInclusive(minSleepMs, minSleepMs * scaleFactor));\n const waitMs = Math.round(rMs + backoffMs);\n const reasonStr = reason ? ` (${reason})` : "";\n console.log(`[Braze Real-Time] Admin requested disconnect${reasonStr}, reconnecting in ${waitMs}ms (r_ms=${rMs} + backoff=${backoffMs})`);\n if (ddrTimeoutId !== null) {\n clearTimeout(ddrTimeoutId);\n }\n closeConnection();\n ddrTimeoutId = setTimeout(function () {\n ddrTimeoutId = null;\n fn.startConnection();\n }, waitMs);\n}\nfunction handleMessage(data) {\n try {\n const message = JSON.parse(data);\n if (!message.type) {\n console.warn("[Braze Real-Time] Message without type:", message);\n return;\n }\n if (message.type === "ttl" && message.body) {\n handleTtlMessage(message.body.t_ms, message.body.rcs);\n return;\n }\n if (message.type === "ddr" && message.body) {\n handleDdrMessage(message.body.r_ms, message.body.e);\n return;\n }\n console.log(`[Braze Real-Time] Routing \'${message.type}\' message to leader`);\n sendToLeader({ type: "message", data: message });\n }\n catch (error) {\n console.warn("[Braze Real-Time] Failed to parse message:", error);\n }\n}\nfn.startConnection = startConnection;\nfn.handleMessage = handleMessage;\nfunction handlePortMessage(port, portId, message) {\n switch (message.type) {\n case "connect":\n if (currentConfig &&\n (currentConfig.mite !== message.config.mite || currentConfig.dustHost !== message.config.dustHost)) {\n console.log("[Braze Real-Time] Config changed, reconnecting");\n closeConnection();\n retryCount = 0;\n lastSleepMs = null;\n currentRcs = null;\n }\n currentConfig = message.config;\n electLeader();\n if (!eventSource && !connectionInProgress) {\n startConnection();\n }\n else if (eventSource) {\n port.postMessage({ type: "connected" });\n }\n break;\n case "disconnect":\n connectedPorts.delete(portId);\n if (portId === leaderPortId) {\n leaderPortId = null;\n electLeader();\n }\n if (connectedPorts.size === 0) {\n console.log("[Braze Real-Time] No more ports, closing connection");\n closeConnection();\n currentConfig = null;\n currentRcs = null;\n leaderPortId = null;\n }\n break;\n case "tab_active":\n promoteToLeader(portId);\n break;\n case "ping":\n port.postMessage({ type: "pong" });\n break;\n default:\n console.warn("[Braze Real-Time] Unknown message type:", message.type);\n }\n}\nworkerSelf.onconnect = function (event) {\n const port = event.ports[0];\n const portId = `port-${Date.now()}-${Math.random().toString(36).substr(2, 9)}`;\n connectedPorts.set(portId, { port: port });\n port.onmessage = function (messageEvent) {\n try {\n handlePortMessage(port, portId, messageEvent.data);\n }\n catch (error) {\n console.error("[Braze Real-Time] Error handling message:", error);\n }\n };\n port.onmessageerror = function () {\n console.warn("[Braze Real-Time] Message error from port:", portId);\n connectedPorts.delete(portId);\n };\n port.start();\n};\n';
|