@arsel.sa/web-sdk 1.0.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/CHANGELOG.md +56 -0
- package/LICENSE +21 -0
- package/README.md +90 -0
- package/dist/arsel.js +600 -0
- package/dist/arsel.js.map +1 -0
- package/dist/arsel.umd.cjs +2 -0
- package/dist/arsel.umd.cjs.map +1 -0
- package/dist/events.d.ts +23 -0
- package/dist/index.d.ts +81 -0
- package/dist/push.d.ts +39 -0
- package/dist/session.d.ts +21 -0
- package/dist/store.d.ts +52 -0
- package/dist/transport.d.ts +22 -0
- package/dist/types.d.ts +68 -0
- package/dist/version.d.ts +5 -0
- package/package.json +60 -0
- package/sw/arsel-sw.js +278 -0
package/dist/arsel.js
ADDED
|
@@ -0,0 +1,600 @@
|
|
|
1
|
+
const G = "arsel";
|
|
2
|
+
const w = "events";
|
|
3
|
+
let I = null;
|
|
4
|
+
function Q() {
|
|
5
|
+
return I || (I = new Promise((e, t) => {
|
|
6
|
+
const n = indexedDB.open(G, 1);
|
|
7
|
+
n.onupgradeneeded = () => {
|
|
8
|
+
const i = n.result;
|
|
9
|
+
i.objectStoreNames.contains("kv") || i.createObjectStore("kv"), i.objectStoreNames.contains(w) || i.createObjectStore(w, { keyPath: "id", autoIncrement: !0 });
|
|
10
|
+
}, n.onsuccess = () => e(n.result), n.onerror = () => t(n.error);
|
|
11
|
+
}), I);
|
|
12
|
+
}
|
|
13
|
+
function y(e, t, n) {
|
|
14
|
+
return Q().then(
|
|
15
|
+
(i) => new Promise((s, a) => {
|
|
16
|
+
const o = n(i.transaction(e, t).objectStore(e));
|
|
17
|
+
o.onsuccess = () => s(o.result), o.onerror = () => a(o.error);
|
|
18
|
+
})
|
|
19
|
+
);
|
|
20
|
+
}
|
|
21
|
+
function c(e) {
|
|
22
|
+
return y("kv", "readonly", (t) => t.get(e)).then(
|
|
23
|
+
(t) => t ?? null
|
|
24
|
+
);
|
|
25
|
+
}
|
|
26
|
+
function u(e, t) {
|
|
27
|
+
return y("kv", "readwrite", (n) => n.put(t, e));
|
|
28
|
+
}
|
|
29
|
+
function A(e) {
|
|
30
|
+
return y("kv", "readwrite", (t) => t.delete(e));
|
|
31
|
+
}
|
|
32
|
+
function ee(e, t) {
|
|
33
|
+
return y(
|
|
34
|
+
w,
|
|
35
|
+
"readwrite",
|
|
36
|
+
(n) => n.add({ body: e, idempotencyKey: t, createdAtMs: Date.now() })
|
|
37
|
+
);
|
|
38
|
+
}
|
|
39
|
+
function te() {
|
|
40
|
+
return y(w, "readonly", (e) => e.getAll());
|
|
41
|
+
}
|
|
42
|
+
function ne(e) {
|
|
43
|
+
return y(w, "readwrite", (t) => t.delete(e));
|
|
44
|
+
}
|
|
45
|
+
function re() {
|
|
46
|
+
return y(w, "readonly", (e) => e.count());
|
|
47
|
+
}
|
|
48
|
+
const r = {
|
|
49
|
+
clientKey: "client_key",
|
|
50
|
+
baseUrl: "base_url",
|
|
51
|
+
anonymousId: "anonymous_id",
|
|
52
|
+
externalId: "external_id",
|
|
53
|
+
email: "email",
|
|
54
|
+
phoneNumber: "phone_number",
|
|
55
|
+
installationId: "installation_id",
|
|
56
|
+
deviceSecret: "device_secret",
|
|
57
|
+
vapidKeyVersion: "vapid_key_version",
|
|
58
|
+
endpoint: "endpoint",
|
|
59
|
+
sessionStartedAt: "session_started_at",
|
|
60
|
+
backgroundedAt: "backgrounded_at",
|
|
61
|
+
lastResponseCode: "last_response_code",
|
|
62
|
+
lastResponsePath: "last_response_path",
|
|
63
|
+
lastResponseAtMs: "last_response_at"
|
|
64
|
+
};
|
|
65
|
+
async function T() {
|
|
66
|
+
const e = await c(r.anonymousId);
|
|
67
|
+
if (e) return e;
|
|
68
|
+
const t = crypto.randomUUID();
|
|
69
|
+
return await u(r.anonymousId, t), t;
|
|
70
|
+
}
|
|
71
|
+
async function ie() {
|
|
72
|
+
const e = crypto.randomUUID();
|
|
73
|
+
return await u(r.anonymousId, e), e;
|
|
74
|
+
}
|
|
75
|
+
const K = "1.0.0", W = { "X-Arsel-SDK": `web/${K}` }, f = {
|
|
76
|
+
success: "success",
|
|
77
|
+
retryable: "retryable",
|
|
78
|
+
permanent: "permanent",
|
|
79
|
+
reauth: "reauth"
|
|
80
|
+
}, O = -1;
|
|
81
|
+
function se(e, t) {
|
|
82
|
+
return e >= 200 && e <= 299 ? f.success : e === 408 || e === 429 || e >= 500 && e <= 599 ? f.retryable : t && (e === 401 || e === 403 || e === 404) ? f.reauth : e === 404 ? f.retryable : f.permanent;
|
|
83
|
+
}
|
|
84
|
+
async function N(e, t) {
|
|
85
|
+
try {
|
|
86
|
+
await Promise.all([
|
|
87
|
+
u(r.lastResponseCode, t),
|
|
88
|
+
u(r.lastResponsePath, e),
|
|
89
|
+
u(r.lastResponseAtMs, Date.now())
|
|
90
|
+
]);
|
|
91
|
+
} catch {
|
|
92
|
+
}
|
|
93
|
+
}
|
|
94
|
+
async function R(e, t, n, i = {}, s = !1) {
|
|
95
|
+
let a;
|
|
96
|
+
try {
|
|
97
|
+
a = await fetch(e + t, {
|
|
98
|
+
method: "POST",
|
|
99
|
+
headers: { "Content-Type": "application/json", ...W, ...i },
|
|
100
|
+
body: JSON.stringify(n),
|
|
101
|
+
// The SDK never relies on cookies, and sending them would attach a
|
|
102
|
+
// first-party session to a cross-origin call for no reason.
|
|
103
|
+
credentials: "omit",
|
|
104
|
+
keepalive: !0
|
|
105
|
+
});
|
|
106
|
+
} catch {
|
|
107
|
+
return await N(t, O), { result: f.retryable, code: O, body: null };
|
|
108
|
+
}
|
|
109
|
+
await N(t, a.status);
|
|
110
|
+
const o = se(a.status, s);
|
|
111
|
+
let l = null;
|
|
112
|
+
try {
|
|
113
|
+
l = await a.json();
|
|
114
|
+
} catch {
|
|
115
|
+
}
|
|
116
|
+
return { result: o, code: a.status, body: l };
|
|
117
|
+
}
|
|
118
|
+
async function B(e, t) {
|
|
119
|
+
try {
|
|
120
|
+
const n = await fetch(e + t, {
|
|
121
|
+
credentials: "omit",
|
|
122
|
+
headers: W
|
|
123
|
+
});
|
|
124
|
+
return await N(t, n.status), n.ok ? await n.json() : null;
|
|
125
|
+
} catch {
|
|
126
|
+
return await N(t, O), null;
|
|
127
|
+
}
|
|
128
|
+
}
|
|
129
|
+
const ae = "/v1/events/send", v = "arsel.", oe = `${v}session_start`, ce = `${v}session_end`, le = `${v}identify`, ue = 80, de = 128, fe = 255, U = 50, pe = 8, V = 64 * 1024;
|
|
130
|
+
function D(e, t) {
|
|
131
|
+
if (e === null) return null;
|
|
132
|
+
const n = typeof e;
|
|
133
|
+
if (n === "string" || n === "boolean") return e;
|
|
134
|
+
if (n === "number") return Number.isFinite(e) ? e : String(e);
|
|
135
|
+
if (n === "bigint") return String(e);
|
|
136
|
+
if (e instanceof Date)
|
|
137
|
+
return Number.isNaN(e.getTime()) ? void 0 : e.toISOString();
|
|
138
|
+
if (n !== "object" || t >= pe) return;
|
|
139
|
+
if (Array.isArray(e))
|
|
140
|
+
return e.map((s) => D(s, t + 1) ?? null);
|
|
141
|
+
const i = {};
|
|
142
|
+
for (const [s, a] of Object.entries(e)) {
|
|
143
|
+
if (!s) continue;
|
|
144
|
+
const o = D(a, t + 1);
|
|
145
|
+
o !== void 0 && (i[s] = o);
|
|
146
|
+
}
|
|
147
|
+
return i;
|
|
148
|
+
}
|
|
149
|
+
function ye(e) {
|
|
150
|
+
const t = {};
|
|
151
|
+
let n = 2, i = !1;
|
|
152
|
+
for (const [s, a] of Object.entries(e ?? {})) {
|
|
153
|
+
if (!s) continue;
|
|
154
|
+
const o = D(a, 0);
|
|
155
|
+
if (o === void 0) continue;
|
|
156
|
+
const l = s.length + JSON.stringify(o).length + 6;
|
|
157
|
+
if (n + l > V) {
|
|
158
|
+
i = !0;
|
|
159
|
+
continue;
|
|
160
|
+
}
|
|
161
|
+
n += l, t[s] = o;
|
|
162
|
+
}
|
|
163
|
+
return i && console.warn(
|
|
164
|
+
`[arsel] event data exceeded ${V} serialized bytes — oversized properties were dropped`
|
|
165
|
+
), t;
|
|
166
|
+
}
|
|
167
|
+
async function we(e, t, n) {
|
|
168
|
+
const [i, s, a, o] = await Promise.all([
|
|
169
|
+
T(),
|
|
170
|
+
c(r.externalId),
|
|
171
|
+
c(r.email),
|
|
172
|
+
c(r.phoneNumber)
|
|
173
|
+
]), l = {
|
|
174
|
+
event: e.slice(0, ue),
|
|
175
|
+
// Always sent, even once identified: it is what the backend merges FROM.
|
|
176
|
+
anonymous_id: i.slice(0, de),
|
|
177
|
+
data: ye(t),
|
|
178
|
+
timestamp: new Date(n).toISOString()
|
|
179
|
+
};
|
|
180
|
+
return s && (l.external_id = s.slice(0, fe)), a && (l.email = a), o && (l.phone_number = o), JSON.stringify(l);
|
|
181
|
+
}
|
|
182
|
+
async function g(e, t, n = Date.now()) {
|
|
183
|
+
await ee(await we(e, t, n), crypto.randomUUID()), S().catch(() => {
|
|
184
|
+
});
|
|
185
|
+
}
|
|
186
|
+
let h = null;
|
|
187
|
+
function S() {
|
|
188
|
+
return h || (h = he().finally(() => {
|
|
189
|
+
h = null;
|
|
190
|
+
}), h);
|
|
191
|
+
}
|
|
192
|
+
function me(e) {
|
|
193
|
+
const t = e[0].idempotencyKey;
|
|
194
|
+
return e.length === 1 ? t : `${t}:${e[e.length - 1].idempotencyKey}:${e.length}`;
|
|
195
|
+
}
|
|
196
|
+
function be(e, t, n) {
|
|
197
|
+
e.some(
|
|
198
|
+
(s) => s.external_id || s.email || s.phone_number
|
|
199
|
+
) && console.error(
|
|
200
|
+
`[arsel] ${e.length} event(s) carrying identifiers were rejected permanently (HTTP ${t}) and dropped. Response: ${JSON.stringify(n)}`
|
|
201
|
+
);
|
|
202
|
+
}
|
|
203
|
+
async function he() {
|
|
204
|
+
const [e, t] = await Promise.all([
|
|
205
|
+
c(r.clientKey),
|
|
206
|
+
c(r.baseUrl)
|
|
207
|
+
]);
|
|
208
|
+
if (!(!e || !t))
|
|
209
|
+
for (; ; ) {
|
|
210
|
+
const n = await te();
|
|
211
|
+
if (n.length === 0) return;
|
|
212
|
+
for (let i = 0; i < n.length; i += U) {
|
|
213
|
+
const s = n.slice(i, i + U), a = s.map(
|
|
214
|
+
(l) => JSON.parse(l.body)
|
|
215
|
+
), o = await R(
|
|
216
|
+
t,
|
|
217
|
+
ae,
|
|
218
|
+
s.length === 1 ? a[0] : { events: a },
|
|
219
|
+
{
|
|
220
|
+
Authorization: `Bearer ${e}`,
|
|
221
|
+
"Idempotency-Key": me(s)
|
|
222
|
+
}
|
|
223
|
+
);
|
|
224
|
+
if (o.result === f.retryable) return;
|
|
225
|
+
o.result !== f.success && be(a, o.code, o.body);
|
|
226
|
+
for (const l of s)
|
|
227
|
+
l.id !== void 0 && await ne(l.id);
|
|
228
|
+
}
|
|
229
|
+
}
|
|
230
|
+
}
|
|
231
|
+
function C(e) {
|
|
232
|
+
const t = e.replace(/-/g, "+").replace(/_/g, "/"), n = atob(t + "=".repeat((4 - t.length % 4) % 4)), i = new Uint8Array(n.length);
|
|
233
|
+
for (let s = 0; s < n.length; s += 1) i[s] = n.charCodeAt(s);
|
|
234
|
+
return i.buffer;
|
|
235
|
+
}
|
|
236
|
+
function b() {
|
|
237
|
+
return typeof navigator < "u" && "serviceWorker" in navigator && typeof PushManager < "u" && typeof Notification < "u";
|
|
238
|
+
}
|
|
239
|
+
function F(e) {
|
|
240
|
+
return `/api/v1/orgs/${e}/push/web/config`;
|
|
241
|
+
}
|
|
242
|
+
function X(e) {
|
|
243
|
+
return `/api/v1/orgs/${e}/push/subscriptions`;
|
|
244
|
+
}
|
|
245
|
+
const H = 1e4;
|
|
246
|
+
let m = "none", E = null, k = null;
|
|
247
|
+
function ve() {
|
|
248
|
+
m = "external";
|
|
249
|
+
}
|
|
250
|
+
async function ge(e) {
|
|
251
|
+
if (b()) {
|
|
252
|
+
m = "managed";
|
|
253
|
+
try {
|
|
254
|
+
E = await navigator.serviceWorker.register(e), k = null;
|
|
255
|
+
} catch (t) {
|
|
256
|
+
E = null, k = `service worker registration failed for '${e}': ${String(t)}. Check that the file is deployed and served with a JavaScript content type.`;
|
|
257
|
+
}
|
|
258
|
+
}
|
|
259
|
+
}
|
|
260
|
+
function Se(e, t) {
|
|
261
|
+
return e.active ? Promise.resolve(e) : new Promise((n, i) => {
|
|
262
|
+
const s = setTimeout(() => {
|
|
263
|
+
i(
|
|
264
|
+
new Error(
|
|
265
|
+
`service worker did not activate within ${t}ms — check the worker script for load errors in DevTools → Application → Service Workers`
|
|
266
|
+
)
|
|
267
|
+
);
|
|
268
|
+
}, t), a = (l) => {
|
|
269
|
+
l.addEventListener("statechange", () => {
|
|
270
|
+
l.state === "activated" ? (clearTimeout(s), n(e)) : l.state === "redundant" && (clearTimeout(s), i(
|
|
271
|
+
new Error(
|
|
272
|
+
"service worker became redundant before activating — its script likely failed to parse"
|
|
273
|
+
)
|
|
274
|
+
));
|
|
275
|
+
});
|
|
276
|
+
}, o = e.installing ?? e.waiting;
|
|
277
|
+
o ? a(o) : e.addEventListener("updatefound", () => {
|
|
278
|
+
e.installing && a(e.installing);
|
|
279
|
+
});
|
|
280
|
+
});
|
|
281
|
+
}
|
|
282
|
+
function Ee(e, t, n) {
|
|
283
|
+
return Promise.race([
|
|
284
|
+
e,
|
|
285
|
+
new Promise((i, s) => {
|
|
286
|
+
setTimeout(() => s(new Error(n)), t);
|
|
287
|
+
})
|
|
288
|
+
]);
|
|
289
|
+
}
|
|
290
|
+
async function $(e = H) {
|
|
291
|
+
if (m === "none")
|
|
292
|
+
throw new Error(
|
|
293
|
+
"push is not configured — pass serviceWorkerPath to init(), or serviceWorker: 'external' if your own service worker imports arsel-sw.js"
|
|
294
|
+
);
|
|
295
|
+
if (m === "external")
|
|
296
|
+
return Ee(
|
|
297
|
+
navigator.serviceWorker.ready,
|
|
298
|
+
e,
|
|
299
|
+
`no service worker became active within ${e}ms — with serviceWorker: 'external', your own worker must be registered and must importScripts arsel-sw.js`
|
|
300
|
+
);
|
|
301
|
+
if (k) throw new Error(k);
|
|
302
|
+
if (!E)
|
|
303
|
+
throw new Error("service worker registration has not completed");
|
|
304
|
+
return Se(E, e);
|
|
305
|
+
}
|
|
306
|
+
async function _e(e = H) {
|
|
307
|
+
try {
|
|
308
|
+
return await $(e), null;
|
|
309
|
+
} catch (t) {
|
|
310
|
+
return t instanceof Error ? t.message : String(t);
|
|
311
|
+
}
|
|
312
|
+
}
|
|
313
|
+
async function Ie() {
|
|
314
|
+
const [e, t] = await Promise.all([
|
|
315
|
+
c(r.clientKey),
|
|
316
|
+
c(r.baseUrl)
|
|
317
|
+
]);
|
|
318
|
+
if (!e || !t || !b()) return !1;
|
|
319
|
+
const n = await B(t, F(e));
|
|
320
|
+
if (!(n != null && n.vapidPublicKey)) return !1;
|
|
321
|
+
let i;
|
|
322
|
+
try {
|
|
323
|
+
i = await $();
|
|
324
|
+
} catch (a) {
|
|
325
|
+
return console.error(`[arsel] ${a instanceof Error ? a.message : a}`), !1;
|
|
326
|
+
}
|
|
327
|
+
const s = await i.pushManager.subscribe({
|
|
328
|
+
// Non-negotiable: the Push API only accepts a userVisibleOnly subscription
|
|
329
|
+
// in Chrome, and silent push is what the restriction exists to prevent.
|
|
330
|
+
userVisibleOnly: !0,
|
|
331
|
+
applicationServerKey: C(n.vapidPublicKey)
|
|
332
|
+
});
|
|
333
|
+
return L(s, n.keyVersion);
|
|
334
|
+
}
|
|
335
|
+
async function L(e, t) {
|
|
336
|
+
var _;
|
|
337
|
+
const [n, i, s] = await Promise.all([
|
|
338
|
+
c(r.clientKey),
|
|
339
|
+
c(r.baseUrl),
|
|
340
|
+
T()
|
|
341
|
+
]);
|
|
342
|
+
if (!n || !i) return !1;
|
|
343
|
+
let a = await c(r.installationId);
|
|
344
|
+
a || (a = crypto.randomUUID(), await u(r.installationId, a));
|
|
345
|
+
const o = e.toJSON(), l = await R(
|
|
346
|
+
i,
|
|
347
|
+
X(n),
|
|
348
|
+
{
|
|
349
|
+
installationId: a,
|
|
350
|
+
platform: "web",
|
|
351
|
+
endpoint: o.endpoint,
|
|
352
|
+
keys: o.keys,
|
|
353
|
+
// The same id the events API sends — it is what binds this subscription
|
|
354
|
+
// to the contact the browser's events resolve to.
|
|
355
|
+
anonymousId: s,
|
|
356
|
+
enablementStatus: Notification.permission === "granted" ? "AUTHORIZED" : "DENIED",
|
|
357
|
+
deviceTimezone: Intl.DateTimeFormat().resolvedOptions().timeZone,
|
|
358
|
+
deviceLocale: navigator.language
|
|
359
|
+
}
|
|
360
|
+
);
|
|
361
|
+
return l.result !== f.success ? !1 : ((_ = l.body) != null && _.deviceSecret && await u(r.deviceSecret, l.body.deviceSecret), await u(r.vapidKeyVersion, t), await u(r.endpoint, o.endpoint ?? null), !0);
|
|
362
|
+
}
|
|
363
|
+
async function Ae() {
|
|
364
|
+
const [e, t, n, i] = await Promise.all([
|
|
365
|
+
c(r.clientKey),
|
|
366
|
+
c(r.baseUrl),
|
|
367
|
+
c(r.installationId),
|
|
368
|
+
c(r.deviceSecret)
|
|
369
|
+
]);
|
|
370
|
+
return !e || !t || !n || !i ? !1 : (await R(
|
|
371
|
+
t,
|
|
372
|
+
`${X(e)}/unsubscribe`,
|
|
373
|
+
{ installationId: n },
|
|
374
|
+
{ "X-Arsel-Device-Auth": i },
|
|
375
|
+
!0
|
|
376
|
+
)).result === f.success;
|
|
377
|
+
}
|
|
378
|
+
async function Ne() {
|
|
379
|
+
if (m === "none" || !b() || Notification.permission !== "granted") return;
|
|
380
|
+
const [e, t] = await Promise.all([
|
|
381
|
+
c(r.clientKey),
|
|
382
|
+
c(r.baseUrl)
|
|
383
|
+
]);
|
|
384
|
+
if (!e || !t) return;
|
|
385
|
+
const n = await B(t, F(e));
|
|
386
|
+
if (!(n != null && n.vapidPublicKey)) return;
|
|
387
|
+
let i;
|
|
388
|
+
try {
|
|
389
|
+
i = await $();
|
|
390
|
+
} catch {
|
|
391
|
+
return;
|
|
392
|
+
}
|
|
393
|
+
const s = await i.pushManager.getSubscription(), a = await c(r.vapidKeyVersion);
|
|
394
|
+
if (s && a === n.keyVersion) return;
|
|
395
|
+
s && await s.unsubscribe().catch(() => !1);
|
|
396
|
+
const o = await i.pushManager.subscribe({
|
|
397
|
+
userVisibleOnly: !0,
|
|
398
|
+
applicationServerKey: C(n.vapidPublicKey)
|
|
399
|
+
});
|
|
400
|
+
await L(o, n.keyVersion);
|
|
401
|
+
}
|
|
402
|
+
async function ke() {
|
|
403
|
+
if (!b()) return !1;
|
|
404
|
+
try {
|
|
405
|
+
const e = m === "managed" ? E : await navigator.serviceWorker.getRegistration();
|
|
406
|
+
return e ? await e.pushManager.getSubscription() !== null : !1;
|
|
407
|
+
} catch {
|
|
408
|
+
return !1;
|
|
409
|
+
}
|
|
410
|
+
}
|
|
411
|
+
const Pe = 30 * 6e4;
|
|
412
|
+
async function z(e = Date.now()) {
|
|
413
|
+
const t = await c(r.sessionStartedAt) ?? 0, n = await c(r.backgroundedAt) ?? 0;
|
|
414
|
+
if (t !== 0) {
|
|
415
|
+
if (n === 0 || e - n < Pe) return;
|
|
416
|
+
await g(
|
|
417
|
+
ce,
|
|
418
|
+
{ duration_seconds: Math.round((n - t) / 1e3) },
|
|
419
|
+
n
|
|
420
|
+
);
|
|
421
|
+
}
|
|
422
|
+
await u(r.sessionStartedAt, e), await u(r.backgroundedAt, 0), await g(oe, {}, e);
|
|
423
|
+
}
|
|
424
|
+
async function x(e = Date.now()) {
|
|
425
|
+
(await c(r.sessionStartedAt) ?? 0) !== 0 && await u(r.backgroundedAt, e);
|
|
426
|
+
}
|
|
427
|
+
function Te() {
|
|
428
|
+
typeof document > "u" || (document.addEventListener("visibilitychange", () => {
|
|
429
|
+
document.visibilityState === "visible" ? z() : x();
|
|
430
|
+
}), window.addEventListener("pagehide", () => void x()));
|
|
431
|
+
}
|
|
432
|
+
let d = null, J = !1;
|
|
433
|
+
function p(e) {
|
|
434
|
+
J && console.info(`[arsel] ${e}`);
|
|
435
|
+
}
|
|
436
|
+
const Ke = /^\+[1-9]\d{6,14}$/, Oe = /^[^\s@]+@[^\s@]+\.[^\s@]+$/, M = 100;
|
|
437
|
+
let P = [], j = !1;
|
|
438
|
+
function De() {
|
|
439
|
+
typeof window < "u" && window.addEventListener("online", () => void S().catch(() => {
|
|
440
|
+
})), typeof document < "u" && document.addEventListener("visibilitychange", () => {
|
|
441
|
+
document.visibilityState === "visible" && S().catch(() => {
|
|
442
|
+
});
|
|
443
|
+
});
|
|
444
|
+
}
|
|
445
|
+
function Re(e) {
|
|
446
|
+
return d || (d = (async () => {
|
|
447
|
+
var a;
|
|
448
|
+
if (!e.clientKey) throw new Error("Arsel: clientKey is required");
|
|
449
|
+
const t = /^http:\/\/(localhost|127\.0\.0\.1)(:\d+)?(\/|$)/.test(
|
|
450
|
+
e.baseUrl ?? ""
|
|
451
|
+
);
|
|
452
|
+
if (!((a = e.baseUrl) != null && a.startsWith("https://")) && !t)
|
|
453
|
+
throw new Error("Arsel: baseUrl must be HTTPS (http is allowed for localhost only)");
|
|
454
|
+
J = e.debug ?? !1;
|
|
455
|
+
const n = e.baseUrl.replace(/\/+$/, "");
|
|
456
|
+
await Promise.all([
|
|
457
|
+
u(r.clientKey, e.clientKey),
|
|
458
|
+
u(r.baseUrl, n)
|
|
459
|
+
]), await T();
|
|
460
|
+
const i = P;
|
|
461
|
+
P = [];
|
|
462
|
+
for (const o of i)
|
|
463
|
+
await g(o.name, o.properties, o.timestampMs);
|
|
464
|
+
e.serviceWorker === "external" ? ve() : e.serviceWorkerPath && await ge(e.serviceWorkerPath), Te(), De();
|
|
465
|
+
const s = typeof document < "u" ? document : void 0;
|
|
466
|
+
(s == null ? void 0 : s.visibilityState) === "visible" && s.prerendering !== !0 && await z(), S(), Ne(), p(`initialized (sdk ${K})`);
|
|
467
|
+
})(), d);
|
|
468
|
+
}
|
|
469
|
+
async function $e(e, t = {}) {
|
|
470
|
+
const n = e == null ? void 0 : e.trim();
|
|
471
|
+
if (!n) {
|
|
472
|
+
p("track() called with a blank event name — ignoring");
|
|
473
|
+
return;
|
|
474
|
+
}
|
|
475
|
+
if (n.startsWith(v)) {
|
|
476
|
+
p(`'${v}' is reserved for the SDK — ignoring '${n}'`);
|
|
477
|
+
return;
|
|
478
|
+
}
|
|
479
|
+
if (!d) {
|
|
480
|
+
if (P.length >= M) {
|
|
481
|
+
j || (j = !0, console.warn(
|
|
482
|
+
`[arsel] more than ${M} events tracked before init() — dropping the rest. Call init() earlier.`
|
|
483
|
+
));
|
|
484
|
+
return;
|
|
485
|
+
}
|
|
486
|
+
P.push({ name: n, properties: t, timestampMs: Date.now() });
|
|
487
|
+
return;
|
|
488
|
+
}
|
|
489
|
+
await d, await g(n, t);
|
|
490
|
+
}
|
|
491
|
+
async function Ue(e) {
|
|
492
|
+
await d;
|
|
493
|
+
let { email: t, phoneNumber: n } = e ?? {};
|
|
494
|
+
const i = e == null ? void 0 : e.externalId;
|
|
495
|
+
if (t && !Oe.test(t) && (console.error(`[arsel] identify(): '${t}' is not a valid email address — ignored`), t = void 0), n && !Ke.test(n) && (console.error(
|
|
496
|
+
`[arsel] identify(): '${n}' is not E.164 (e.g. +966501234567) — ignored`
|
|
497
|
+
), n = void 0), !i && !t && !n) {
|
|
498
|
+
p("identify() needs at least one of externalId, email or phoneNumber");
|
|
499
|
+
return;
|
|
500
|
+
}
|
|
501
|
+
i && await u(r.externalId, i), t && await u(r.email, t), n && await u(r.phoneNumber, n), await g(le, {});
|
|
502
|
+
}
|
|
503
|
+
async function Ve() {
|
|
504
|
+
await d, await Promise.all([
|
|
505
|
+
A(r.externalId),
|
|
506
|
+
A(r.email),
|
|
507
|
+
A(r.phoneNumber),
|
|
508
|
+
A(r.sessionStartedAt)
|
|
509
|
+
]), await ie(), p("identity reset");
|
|
510
|
+
}
|
|
511
|
+
async function xe() {
|
|
512
|
+
await d;
|
|
513
|
+
const e = await Ae();
|
|
514
|
+
return p(e ? "push opt-out recorded" : "push opt-out not sent — no registration to revoke"), e;
|
|
515
|
+
}
|
|
516
|
+
async function Me() {
|
|
517
|
+
if (await d, !b()) return !1;
|
|
518
|
+
const e = await _e();
|
|
519
|
+
if (e)
|
|
520
|
+
return console.error(`[arsel] promptForPush(): ${e}`), !1;
|
|
521
|
+
const t = await Notification.requestPermission();
|
|
522
|
+
return t !== "granted" ? (p(`notification permission: ${t}`), !1) : Ie();
|
|
523
|
+
}
|
|
524
|
+
async function je() {
|
|
525
|
+
return await d, T();
|
|
526
|
+
}
|
|
527
|
+
async function We() {
|
|
528
|
+
const [
|
|
529
|
+
e,
|
|
530
|
+
t,
|
|
531
|
+
n,
|
|
532
|
+
i,
|
|
533
|
+
s,
|
|
534
|
+
a,
|
|
535
|
+
o,
|
|
536
|
+
l,
|
|
537
|
+
_,
|
|
538
|
+
q,
|
|
539
|
+
Y,
|
|
540
|
+
Z
|
|
541
|
+
] = await Promise.all([
|
|
542
|
+
c(r.anonymousId),
|
|
543
|
+
c(r.externalId),
|
|
544
|
+
c(r.email),
|
|
545
|
+
c(r.phoneNumber),
|
|
546
|
+
c(r.installationId),
|
|
547
|
+
c(r.deviceSecret),
|
|
548
|
+
c(r.vapidKeyVersion),
|
|
549
|
+
re(),
|
|
550
|
+
ke(),
|
|
551
|
+
c(r.lastResponseCode),
|
|
552
|
+
c(r.lastResponsePath),
|
|
553
|
+
c(r.lastResponseAtMs)
|
|
554
|
+
]);
|
|
555
|
+
return {
|
|
556
|
+
sdkVersion: K,
|
|
557
|
+
initialized: d !== null,
|
|
558
|
+
anonymousId: e,
|
|
559
|
+
hasAssertedIdentity: !!(t || n || i),
|
|
560
|
+
installationId: s,
|
|
561
|
+
hasDeviceSecret: !!a,
|
|
562
|
+
pendingEvents: l,
|
|
563
|
+
permission: b() ? Notification.permission : "unsupported",
|
|
564
|
+
isSubscribed: _,
|
|
565
|
+
vapidKeyVersion: o,
|
|
566
|
+
lastResponseCode: q,
|
|
567
|
+
lastResponsePath: Y,
|
|
568
|
+
lastResponseAtMs: Z
|
|
569
|
+
};
|
|
570
|
+
}
|
|
571
|
+
async function Be() {
|
|
572
|
+
await d, await S();
|
|
573
|
+
}
|
|
574
|
+
const Ce = {
|
|
575
|
+
init: Re,
|
|
576
|
+
track: $e,
|
|
577
|
+
identify: Ue,
|
|
578
|
+
reset: Ve,
|
|
579
|
+
optOut: xe,
|
|
580
|
+
promptForPush: Me,
|
|
581
|
+
getAnonymousId: je,
|
|
582
|
+
diagnostics: We,
|
|
583
|
+
flushNow: Be,
|
|
584
|
+
SDK_VERSION: K
|
|
585
|
+
};
|
|
586
|
+
export {
|
|
587
|
+
Ce as Arsel,
|
|
588
|
+
K as SDK_VERSION,
|
|
589
|
+
Ce as default,
|
|
590
|
+
We as diagnostics,
|
|
591
|
+
Be as flushNow,
|
|
592
|
+
je as getAnonymousId,
|
|
593
|
+
Ue as identify,
|
|
594
|
+
Re as init,
|
|
595
|
+
xe as optOut,
|
|
596
|
+
Me as promptForPush,
|
|
597
|
+
Ve as reset,
|
|
598
|
+
$e as track
|
|
599
|
+
};
|
|
600
|
+
//# sourceMappingURL=arsel.js.map
|